Subversion Repositories HelenOS

Rev

Rev 3589 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2008 Jiri Svoboda
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * - Redistributions of source code must retain the above copyright
  10.  *   notice, this list of conditions and the following disclaimer.
  11.  * - Redistributions in binary form must reproduce the above copyright
  12.  *   notice, this list of conditions and the following disclaimer in the
  13.  *   documentation and/or other materials provided with the distribution.
  14.  * - The name of the author may not be used to endorse or promote products
  15.  *   derived from this software without specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  */
  28.  
  29. /** @addtogroup rtld rtld
  30.  * @brief
  31.  * @{
  32.  */
  33. /**
  34.  * @file
  35.  */
  36.  
  37. #include <stdio.h>
  38.  
  39. #include <arch.h>
  40. #include <elf_dyn.h>
  41. #include <symbol.h>
  42. #include <rtld.h>
  43. #include <smc.h>
  44.  
  45. #define __L(ptr) ((uint32_t)(ptr) & 0x0000ffff)
  46. #define __HA(ptr) ((uint32_t)(ptr) >> 16)
  47.  
  48. // ldis r11, .PLTtable@ha
  49. static inline uint32_t _ldis(unsigned rD, uint16_t imm16)
  50. {
  51.     /* Special case of addis: ldis rD,SIMM == addis rD,0,SIMM */
  52.     return 0x3C000000 | (rD << 21) | imm16;
  53. }
  54.  
  55. static inline uint32_t _lwz(unsigned rD, uint16_t disp16, unsigned rA)
  56. {
  57.     return 0x80000000 | (rD << 21) | (rA << 16) | disp16;
  58. }
  59.  
  60. static inline uint32_t _mtctr(unsigned rS)
  61. {
  62.     /* mtctr rD == mtspr 9, rD */
  63.     return 0x7c0003a6 | (rS << 21) | (9/*CTR*/ << 16);
  64. }
  65.  
  66. static inline uint32_t _bctr()
  67. {
  68.     /* bcctr 0x1f, 0 */
  69.     return 0x4c000420 | (0x1f/*always*/ << 21);
  70. }
  71.  
  72. /* branch */
  73. static inline uint32_t _b(uint32_t *addr, uint32_t *location)
  74. {
  75.     uint32_t raddr = ((uint32_t)addr - (uint32_t)location) & 0x03fffffc;
  76.     return 0x48000000 | raddr;
  77. }
  78.  
  79.  
  80. /*
  81.  * Fill in PLT
  82.  */
  83. void module_process_pre_arch(module_t *m)
  84. {
  85.     uint32_t *plt;
  86.     uint32_t *_plt_ent;
  87.  
  88.     plt = m->dyn.plt_got;
  89.     if (!plt) {
  90.         /* Module has no PLT */
  91.         return;
  92.     }
  93.  
  94.     // PLT entries start here. However, each occupies 2 words
  95.     _plt_ent = plt + 18;
  96.  
  97.     // By definition of the ppc ABI, there's 1:1 correspondence
  98.     // between JMPREL entries and PLT entries
  99.     unsigned plt_n = m->dyn.plt_rel_sz / sizeof(elf_rela_t);
  100.  
  101.     uint32_t *_plt_table;
  102.     uint32_t *_plt_call;
  103.     uint32_t *_plt_resolve;
  104.  
  105.     _plt_resolve = plt;
  106.     _plt_call = plt + 6;
  107.     _plt_table = plt + 18 + plt_n;
  108.  
  109. /* .PLTcall: */
  110.     plt[6] = _ldis(11, __HA(_plt_table));   // ldis r11, .PLTtable@ha
  111.     plt[7] = _lwz(11, __L(_plt_table), 11); // lwz r11, .PLTtable@l(r11)
  112.     plt[8] = _mtctr(11);            // mtctr r11
  113.     plt[9] = _bctr();
  114.  
  115. /* .PLTi, i = 0..N-1 */
  116. //  kputint(-4);
  117. /*  for (i = 0; i < plt_n; ++i) {
  118.         //_plt_table[i] == function address;
  119.         plt[18+i] = _b(_plt_call, &plt[18+i]);  // b .PLTcall
  120.     }*/
  121. }
  122.  
  123. void rel_table_process(module_t *m, elf_rel_t *rt, size_t rt_size)
  124. {
  125.     /* Unused */
  126.     (void)m; (void)rt; (void)rt_size;
  127. }
  128.  
  129. /**
  130.  * Process (fixup) all relocations in a relocation table.
  131.  */
  132. void rela_table_process(module_t *m, elf_rela_t *rt, size_t rt_size)
  133. {
  134.     int i;
  135.  
  136.     size_t rt_entries;
  137.     size_t r_offset;
  138.     elf_word r_info;
  139.     unsigned rel_type;
  140.     elf_word sym_idx;
  141.     uintptr_t sym_addr;
  142.     uintptr_t r_addend;
  143.    
  144.     elf_symbol_t *sym_table;
  145.     elf_symbol_t *sym;
  146.     uint32_t *r_ptr;
  147.     char *str_tab;
  148.    
  149.     elf_symbol_t *sym_def;
  150.     module_t *dest;
  151.  
  152.     uint32_t *plt;
  153.     uint32_t *_plt_table;
  154.     uint32_t *_plt_ent;
  155.     uint32_t plt_n;
  156.     uint32_t pidx;
  157.  
  158.     plt = m->dyn.plt_got;
  159.     plt_n = m->dyn.plt_rel_sz / sizeof(elf_rela_t);
  160.     _plt_ent = plt+ 18;
  161.     _plt_table = plt + 18 + plt_n;
  162.  
  163.     DPRINTF("parse relocation table\n");
  164.  
  165.     sym_table = m->dyn.sym_tab;
  166.     rt_entries = rt_size / sizeof(elf_rela_t);
  167.     str_tab = m->dyn.str_tab;
  168.  
  169.     DPRINTF("address: 0x%x, entries: %d\n", (uintptr_t)rt, rt_entries);
  170.    
  171.     for (i = 0; i < rt_entries; ++i) {
  172.         DPRINTF("symbol %d: ", i);
  173.         r_offset = rt[i].r_offset;
  174.         r_info = rt[i].r_info;
  175.         r_addend = rt[i].r_addend;
  176.  
  177.         sym_idx = ELF32_R_SYM(r_info);
  178.         sym = &sym_table[sym_idx];
  179.  
  180.         DPRINTF("name '%s', value 0x%x, size 0x%x\n",
  181.             str_tab + sym->st_name,
  182.             sym->st_value,
  183.             sym->st_size);
  184.  
  185.         rel_type = ELF32_R_TYPE(r_info);
  186.         r_ptr = (uint32_t *)(r_offset + m->bias);
  187.  
  188.         if (sym->st_name != 0) {
  189.             DPRINTF("rel_type: %x, rel_offset: 0x%x\n", rel_type, r_offset);
  190.             sym_def = symbol_def_find(str_tab + sym->st_name,
  191.                 m, &dest);
  192.             DPRINTF("dest name: '%s'\n", dest->dyn.soname);
  193.             DPRINTF("dest bias: 0x%x\n", dest->bias);
  194.             if (sym_def) {
  195.                 sym_addr = symbol_get_addr(sym_def, dest);
  196.                 DPRINTF("symbol definition found, addr=0x%x\n", sym_addr);
  197.             } else {
  198.                 DPRINTF("symbol definition not found\n");
  199.                 continue;
  200.             }
  201.         }
  202.  
  203.         switch (rel_type) {
  204.         case R_PPC_JMP_SLOT:
  205.             DPRINTF("fixup R_PPC_JMP_SLOT (b+v)\n");
  206.             pidx = (r_ptr - _plt_ent) / 2;
  207.             if (pidx >= plt_n) {
  208.                 DPRINTF("error: proc index out of range\n");
  209.                 //kputint(0xee00ee0ee00);
  210.                 while(1);
  211.             }
  212.             //_plt_table[pidx] = sym_addr;
  213.             plt[18+2*pidx] = _b((void *)sym_addr, &plt[18+2*pidx]);
  214.             break;
  215.  
  216.         case R_PPC_ADDR32:
  217.             DPRINTF("fixup R_PPC_ADDR32 (b+v+a)\n");
  218.             *r_ptr = r_addend + sym_addr;
  219.             break;
  220.            
  221.         case R_PPC_RELATIVE:
  222.             DPRINTF("fixup R_PPC_RELATIVE (b+a)\n");
  223.             *r_ptr = r_addend + m->bias;
  224.             break;
  225.         case R_PPC_REL24:
  226. //          printf("ignore R_PPC_REL24 at 0x%04x\n", (uintptr_t) r_ptr);
  227.             *r_ptr = (sym_addr + r_addend - (uint32_t)r_ptr) >> 2;
  228.             DPRINTF("fixup R_PPC_REL24 (s+a-p)>>2\n");
  229.             /*TODO*/
  230.             break;
  231.         default:
  232.             printf("unknown relocation type\n");
  233.             break;
  234.         }
  235.     }
  236.  
  237.     /*
  238.      * Synchronize the used portion of PLT. This is necessary since
  239.      * we are writing instructions.
  240.      */
  241.     smc_coherence(&plt[18], plt_n * 2 * sizeof(uint32_t));
  242. }
  243.  
  244. /** @}
  245.  */
  246.