Subversion Repositories HelenOS

Rev

Rev 3663 | 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.     uint16_t *r_ptr16;
  148.     char *str_tab;
  149.    
  150.     elf_symbol_t *sym_def;
  151.     module_t *dest;
  152.  
  153.     uint32_t *plt;
  154.     uint32_t *_plt_table;
  155.     uint32_t *_plt_ent;
  156.     uint32_t plt_n;
  157.     uint32_t pidx;
  158.     uint32_t t_addr;
  159.     uint32_t sym_size;
  160.  
  161.     plt = m->dyn.plt_got;
  162.     plt_n = m->dyn.plt_rel_sz / sizeof(elf_rela_t);
  163.     _plt_ent = plt+ 18;
  164.     _plt_table = plt + 18 + plt_n;
  165.  
  166.     DPRINTF("parse relocation table\n");
  167.  
  168.     sym_table = m->dyn.sym_tab;
  169.     rt_entries = rt_size / sizeof(elf_rela_t);
  170.     str_tab = m->dyn.str_tab;
  171.  
  172.     DPRINTF("address: 0x%x, entries: %d\n", (uintptr_t)rt, rt_entries);
  173.    
  174.     for (i = 0; i < rt_entries; ++i) {
  175.         DPRINTF("symbol %d: ", i);
  176.         r_offset = rt[i].r_offset;
  177.         r_info = rt[i].r_info;
  178.         r_addend = rt[i].r_addend;
  179.  
  180.         sym_idx = ELF32_R_SYM(r_info);
  181.         sym = &sym_table[sym_idx];
  182.  
  183.         DPRINTF("name '%s', value 0x%x, size 0x%x\n",
  184.             str_tab + sym->st_name,
  185.             sym->st_value,
  186.             sym->st_size);
  187.  
  188.         rel_type = ELF32_R_TYPE(r_info);
  189.         r_ptr = (uint32_t *)(r_offset + m->bias);
  190.         r_ptr16 = (uint16_t *)(r_offset + m->bias);
  191.  
  192.         if (sym->st_name != 0) {
  193.             DPRINTF("rel_type: %x, rel_offset: 0x%x\n", rel_type, r_offset);
  194.             sym_def = symbol_def_find(str_tab + sym->st_name,
  195.                 m, &dest);
  196.             DPRINTF("dest name: '%s'\n", dest->dyn.soname);
  197.             DPRINTF("dest bias: 0x%x\n", dest->bias);
  198.             if (sym_def) {
  199.                 sym_addr = symbol_get_addr(sym_def, dest);
  200.                 DPRINTF("symbol definition found, addr=0x%x\n", sym_addr);
  201.             } else {
  202.                 DPRINTF("symbol definition not found\n");
  203.                 continue;
  204.             }
  205.         }
  206.  
  207.         switch (rel_type) {
  208.         case R_PPC_ADDR16_LO:
  209.             DPRINTF("fixup R_PPC_ADDR16_LO (#lo(s+a))\n");
  210.             *r_ptr16 = (sym_addr + r_addend) & 0xffff;
  211.             break;
  212.  
  213.         case R_PPC_ADDR16_HI:
  214.             DPRINTF("fixup R_PPC_ADDR16_HI (#hi(s+a))\n");
  215.             *r_ptr16 = (sym_addr + r_addend) >> 16;
  216.             break;
  217.  
  218.         case R_PPC_ADDR16_HA:
  219.             DPRINTF("fixup R_PPC_ADDR16_HA (#ha(s+a))\n");
  220.             t_addr = sym_addr + r_addend;
  221.             *r_ptr16 = (t_addr >> 16) + ((t_addr & 0x8000) ? 1 : 0);
  222.             break;
  223.  
  224.         case R_PPC_JMP_SLOT:
  225.             DPRINTF("fixup R_PPC_JMP_SLOT (b+v)\n");
  226.             pidx = (r_ptr - _plt_ent) / 2;
  227.             if (pidx >= plt_n) {
  228.                 DPRINTF("error: proc index out of range\n");
  229.                 //kputint(0xee00ee0ee00);
  230.                 while(1);
  231.             }
  232.             //_plt_table[pidx] = sym_addr;
  233.             plt[18+2*pidx] = _b((void *)sym_addr, &plt[18+2*pidx]);
  234.             break;
  235.  
  236.         case R_PPC_ADDR32:
  237.             DPRINTF("fixup R_PPC_ADDR32 (b+v+a)\n");
  238.             *r_ptr = r_addend + sym_addr;
  239.             break;
  240.  
  241.         case R_PPC_COPY:
  242.             /*
  243.              * Copy symbol data from shared object to specified
  244.              * location.
  245.              */
  246.             DPRINTF("fixup R_PPC_COPY (s)\n");
  247.             sym_size = sym->st_size;
  248.             if (sym_size != sym_def->st_size) {
  249.                 printf("warning: mismatched symbol sizes\n");
  250.                 /* Take the lower value. */
  251.                 if (sym_size > sym_def->st_size)
  252.                     sym_size = sym_def->st_size;
  253.             }
  254.             memcpy(r_ptr, (const void *)sym_addr, sym_size);
  255.             break;
  256.            
  257.         case R_PPC_RELATIVE:
  258.             DPRINTF("fixup R_PPC_RELATIVE (b+a)\n");
  259.             *r_ptr = r_addend + m->bias;
  260.             break;
  261.         case R_PPC_REL24:
  262. //          printf("ignore R_PPC_REL24 at 0x%04x\n", (uintptr_t) r_ptr);
  263.             *r_ptr = (sym_addr + r_addend - (uint32_t)r_ptr) >> 2;
  264.             DPRINTF("fixup R_PPC_REL24 (s+a-p)>>2\n");
  265.             /*TODO*/
  266.             break;
  267.         default:
  268.             printf("unknown relocation type %d\n", rel_type);
  269.             break;
  270.         }
  271.     }
  272.  
  273.     /*
  274.      * Synchronize the used portion of PLT. This is necessary since
  275.      * we are writing instructions.
  276.      */
  277.     smc_coherence(&plt[18], plt_n * 2 * sizeof(uint32_t));
  278. }
  279.  
  280. /** @}
  281.  */
  282.