Subversion Repositories HelenOS

Rev

Rev 2999 | 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.  
  44. #define __L(ptr) ((uint32_t)(ptr) & 0x0000ffff)
  45. #define __HA(ptr) ((uint32_t)(ptr) >> 16)
  46.  
  47. // ldis r11, .PLTtable@ha
  48. static inline uint32_t _ldis(unsigned rD, uint16_t imm16)
  49. {
  50.     /* Special case of addis: ldis rD,SIMM == addis rD,0,SIMM */
  51.     return 0x3C000000 | (rD << 21) | imm16;
  52. }
  53.  
  54. static inline uint32_t _lwz(unsigned rD, uint16_t disp16, unsigned rA)
  55. {
  56.     return 0x80000000 | (rD << 21) | (rA << 16) | disp16;
  57. }
  58.  
  59. static inline uint32_t _mtctr(unsigned rS)
  60. {
  61.     /* mtctr rD == mtspr 9, rD */
  62.     return 0x7c0003a6 | (rS << 21) | (9/*CTR*/ << 16);
  63. }
  64.  
  65. static inline uint32_t _bctr()
  66. {
  67.     /* bcctr 0x1f, 0 */
  68.     return 0x4c000420 | (0x1f/*always*/ << 21);
  69. }
  70.  
  71. /* branch */
  72. static inline uint32_t _b(uint32_t *addr, uint32_t *location)
  73. {
  74.     uint32_t raddr = ((uint32_t)addr - (uint32_t)location) & 0x03fffffc;
  75.     return 0x48000000 | raddr;
  76. }
  77.  
  78.  
  79. /*
  80.  * Fill in PLT
  81.  */
  82. void module_process_pre_arch(module_t *m)
  83. {
  84.     uint32_t *plt;
  85.     uint32_t *_plt_ent;
  86.  
  87.     plt = m->dyn.plt_got;
  88.     if (!plt) {
  89.         /* Module has no PLT */
  90.         return;
  91.     }
  92.  
  93.     // PLT entries start here. However, each occupies 2 words
  94.     _plt_ent = plt + 18;
  95.  
  96.     // By definition of the ppc ABI, there's 1:1 correspondence
  97.     // between JMPREL entries and PLT entries
  98.     unsigned plt_n = m->dyn.plt_rel_sz / sizeof(elf_rela_t);
  99.  
  100.     uint32_t *_plt_table;
  101.     uint32_t *_plt_call;
  102.     uint32_t *_plt_resolve;
  103.  
  104.     _plt_resolve = plt;
  105.     _plt_call = plt + 6;
  106.     _plt_table = plt + 18 + plt_n;
  107.  
  108. /* .PLTcall: */
  109.     plt[6] = _ldis(11, __HA(_plt_table));   // ldis r11, .PLTtable@ha
  110.     plt[7] = _lwz(11, __L(_plt_table), 11); // lwz r11, .PLTtable@l(r11)
  111.     plt[8] = _mtctr(11);            // mtctr r11
  112.     plt[9] = _bctr();
  113.  
  114. /* .PLTi, i = 0..N-1 */
  115. //  kputint(-4);
  116. /*  for (i = 0; i < plt_n; ++i) {
  117.         //_plt_table[i] == function address;
  118.         plt[18+i] = _b(_plt_call, &plt[18+i]);  // b .PLTcall
  119.     }*/
  120. }
  121.  
  122. void rel_table_process(module_t *m, elf_rel_t *rt, size_t rt_size)
  123. {
  124.     /* Unused */
  125.     (void)m; (void)rt; (void)rt_size;
  126. }
  127.  
  128. /**
  129.  * Process (fixup) all relocations in a relocation table.
  130.  */
  131. void rela_table_process(module_t *m, elf_rela_t *rt, size_t rt_size)
  132. {
  133.     int i;
  134.  
  135.     size_t rt_entries;
  136.     size_t r_offset;
  137.     elf_word r_info;
  138.     unsigned rel_type;
  139.     elf_word sym_idx;
  140.     uintptr_t sym_addr;
  141.     uintptr_t r_addend;
  142.    
  143.     elf_symbol_t *sym_table;
  144.     elf_symbol_t *sym;
  145.     uint32_t *r_ptr;
  146.     char *str_tab;
  147.    
  148.     elf_symbol_t *sym_def;
  149.     module_t *dest;
  150.  
  151.     uint32_t *plt;
  152.     uint32_t *_plt_table;
  153.     uint32_t *_plt_ent;
  154.     uint32_t plt_n;
  155.     uint32_t pidx;
  156.  
  157.     plt = m->dyn.plt_got;
  158.     plt_n = m->dyn.plt_rel_sz / sizeof(elf_rela_t);
  159.     _plt_ent = plt+ 18;
  160.     _plt_table = plt + 18 + plt_n;
  161.  
  162.     DPRINTF("parse relocation table\n");
  163.  
  164.     sym_table = m->dyn.sym_tab;
  165.     rt_entries = rt_size / sizeof(elf_rela_t);
  166.     str_tab = m->dyn.str_tab;
  167.  
  168.     DPRINTF("address: 0x%x, entries: %d\n", (uintptr_t)rt, rt_entries);
  169.    
  170.     for (i = 0; i < rt_entries; ++i) {
  171.         DPRINTF("symbol %d: ", i);
  172.         r_offset = rt[i].r_offset;
  173.         r_info = rt[i].r_info;
  174.         r_addend = rt[i].r_addend;
  175.  
  176.         sym_idx = ELF32_R_SYM(r_info);
  177.         sym = &sym_table[sym_idx];
  178.  
  179.         DPRINTF("name '%s', value 0x%x, size 0x%x\n",
  180.             str_tab + sym->st_name,
  181.             sym->st_value,
  182.             sym->st_size);
  183.  
  184.         rel_type = ELF32_R_TYPE(r_info);
  185.         r_ptr = (uint32_t *)(r_offset + m->bias);
  186.  
  187.         if (sym->st_name != 0) {
  188.             DPRINTF("rel_type: %x, rel_offset: 0x%x\n", rel_type, r_offset);
  189.             sym_def = symbol_def_find(str_tab + sym->st_name,
  190.                 m, &dest);
  191.             DPRINTF("dest name: '%s'\n", dest->dyn.soname);
  192.             DPRINTF("dest bias: 0x%x\n", dest->bias);
  193.             if (sym_def) {
  194.                 sym_addr = symbol_get_addr(sym_def, dest);
  195.                 DPRINTF("symbol definition found, addr=0x%x\n", sym_addr);
  196.             } else {
  197.                 DPRINTF("symbol definition not found\n");
  198.                 continue;
  199.             }
  200.         }
  201.  
  202.         switch (rel_type) {
  203.         case R_PPC_JMP_SLOT:
  204.             DPRINTF("fixup R_PPC_JMP_SLOT (b+v)\n");
  205.             pidx = (r_ptr - _plt_ent) / 2;
  206.             if (pidx >= plt_n) {
  207.                 DPRINTF("error: proc index out of range\n");
  208.                 //kputint(0xee00ee0ee00);
  209.                 while(1);
  210.             }
  211.             //_plt_table[pidx] = sym_addr;
  212.             plt[18+2*pidx] = _b((void *)sym_addr, &plt[18+2*pidx]);
  213.             break;
  214.  
  215.         case R_PPC_ADDR32:
  216.             DPRINTF("fixup R_PPC_ADDR32 (b+v+a)\n");
  217.             *r_ptr = r_addend + sym_addr;
  218.             break;
  219.            
  220.         case R_PPC_RELATIVE:
  221.             DPRINTF("fixup R_PPC_RELATIVE (b+a)\n");
  222.             *r_ptr = r_addend + m->bias;
  223.             break;
  224.         case R_PPC_REL24:
  225. //          printf("ignore R_PPC_REL24 at 0x%04x\n", (uintptr_t) r_ptr);
  226.             *r_ptr = (sym_addr + r_addend - (uint32_t)r_ptr) >> 2;
  227.             DPRINTF("fixup R_PPC_REL24 (s+a-p)>>2\n");
  228.             /*TODO*/
  229.             break;
  230.         default:
  231.             printf("unknown relocation type\n");
  232.             break;
  233.         }
  234.     }
  235.  
  236. }
  237.  
  238. /** @}
  239.  */
  240.