Subversion Repositories HelenOS

Rev

Rev 3688 | 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. #include <stdlib.h>
  39.  
  40. #include <arch.h>
  41. #include <elf_dyn.h>
  42. #include <symbol.h>
  43. #include <rtld.h>
  44. #include <smc.h>
  45.  
  46. #define __L(ptr) ((uint32_t)(ptr) & 0x0000ffff)
  47. #define __HA(ptr) ((uint32_t)(ptr) >> 16)
  48.  
  49. // ldis r11, .PLTtable@ha
  50. static inline uint32_t _ldis(unsigned rD, uint16_t imm16)
  51. {
  52.     /* Special case of addis: ldis rD,SIMM == addis rD,0,SIMM */
  53.     return 0x3C000000 | (rD << 21) | imm16;
  54. }
  55.  
  56. static inline uint32_t _lwz(unsigned rD, uint16_t disp16, unsigned rA)
  57. {
  58.     return 0x80000000 | (rD << 21) | (rA << 16) | disp16;
  59. }
  60.  
  61. static inline uint32_t _mtctr(unsigned rS)
  62. {
  63.     /* mtctr rD == mtspr 9, rD */
  64.     return 0x7c0003a6 | (rS << 21) | (9/*CTR*/ << 16);
  65. }
  66.  
  67. static inline uint32_t _bctr()
  68. {
  69.     /* bcctr 0x1f, 0 */
  70.     return 0x4c000420 | (0x1f/*always*/ << 21);
  71. }
  72.  
  73. /* branch */
  74. static inline uint32_t _b(uint32_t *addr, uint32_t *location)
  75. {
  76.     uint32_t raddr = ((uint32_t)addr - (uint32_t)location) & 0x03fffffc;
  77.     return 0x48000000 | raddr;
  78. }
  79.  
  80.  
  81. /*
  82.  * Fill in PLT
  83.  */
  84. void module_process_pre_arch(module_t *m)
  85. {
  86.     uint32_t *plt;
  87.     uint32_t *_plt_ent;
  88.    
  89.     /* No lazy linking -- no pre-processing yet. */
  90.     return;
  91.  
  92.     plt = m->dyn.plt_got;
  93.     if (!plt) {
  94.         /* Module has no PLT */
  95.         return;
  96.     }
  97.  
  98.     // PLT entries start here. However, each occupies 2 words
  99.     _plt_ent = plt + 18;
  100.  
  101.     // By definition of the ppc ABI, there's 1:1 correspondence
  102.     // between JMPREL entries and PLT entries
  103.     unsigned plt_n = m->dyn.plt_rel_sz / sizeof(elf_rela_t);
  104.  
  105.     uint32_t *_plt_table;
  106.     uint32_t *_plt_call;
  107.     uint32_t *_plt_resolve;
  108.  
  109.     _plt_resolve = plt;
  110.     _plt_call = plt + 6;
  111.     _plt_table = plt + 18 + plt_n;
  112.  
  113. /* .PLTcall: */
  114.     plt[6] = _ldis(11, __HA(_plt_table));   // ldis r11, .PLTtable@ha
  115.     plt[7] = _lwz(11, __L(_plt_table), 11); // lwz r11, .PLTtable@l(r11)
  116.     plt[8] = _mtctr(11);            // mtctr r11
  117.     plt[9] = _bctr();
  118.  
  119. /* .PLTi, i = 0..N-1 */
  120. //  kputint(-4);
  121. /*  for (i = 0; i < plt_n; ++i) {
  122.         //_plt_table[i] == function address;
  123.         plt[18+i] = _b(_plt_call, &plt[18+i]);  // b .PLTcall
  124.     }*/
  125. }
  126.  
  127. void rel_table_process(module_t *m, elf_rel_t *rt, size_t rt_size)
  128. {
  129.     /* Unused */
  130.     (void)m; (void)rt; (void)rt_size;
  131. }
  132.  
  133. /**
  134.  * Process (fixup) all relocations in a relocation table.
  135.  */
  136. void rela_table_process(module_t *m, elf_rela_t *rt, size_t rt_size)
  137. {
  138.     int i;
  139.  
  140.     size_t rt_entries;
  141.     size_t r_offset;
  142.     elf_word r_info;
  143.     unsigned rel_type;
  144.     elf_word sym_idx;
  145.     uintptr_t sym_addr;
  146.     uintptr_t r_addend;
  147.    
  148.     elf_symbol_t *sym_table;
  149.     elf_symbol_t *sym;
  150.     uint32_t *r_ptr;
  151.     uint16_t *r_ptr16;
  152.     char *str_tab;
  153.    
  154.     elf_symbol_t *sym_def;
  155.     module_t *dest;
  156.  
  157.     uint32_t *plt;
  158.     uint32_t *_plt_table;
  159.     uint32_t *_plt_ent;
  160.     uint32_t plt_n;
  161.     uint32_t pidx;
  162.     uint32_t t_addr;
  163.     uint32_t sym_size;
  164.  
  165.     plt = m->dyn.plt_got;
  166.     plt_n = m->dyn.plt_rel_sz / sizeof(elf_rela_t);
  167.     _plt_ent = plt+ 18;
  168.     _plt_table = plt + 18 + plt_n;
  169.  
  170.     DPRINTF("parse relocation table\n");
  171.  
  172.     sym_table = m->dyn.sym_tab;
  173.     rt_entries = rt_size / sizeof(elf_rela_t);
  174.     str_tab = m->dyn.str_tab;
  175.  
  176.     DPRINTF("address: 0x%x, entries: %d\n", (uintptr_t)rt, rt_entries);
  177.    
  178.     for (i = 0; i < rt_entries; ++i) {
  179.         DPRINTF("symbol %d: ", i);
  180.         r_offset = rt[i].r_offset;
  181.         r_info = rt[i].r_info;
  182.         r_addend = rt[i].r_addend;
  183.  
  184.         sym_idx = ELF32_R_SYM(r_info);
  185.         sym = &sym_table[sym_idx];
  186.  
  187.         DPRINTF("name '%s', value 0x%x, size 0x%x\n",
  188.             str_tab + sym->st_name,
  189.             sym->st_value,
  190.             sym->st_size);
  191.  
  192.         rel_type = ELF32_R_TYPE(r_info);
  193.         r_ptr = (uint32_t *)(r_offset + m->bias);
  194.         r_ptr16 = (uint16_t *)(r_offset + m->bias);
  195.  
  196.         if (sym->st_name != 0) {
  197.             DPRINTF("rel_type: %x, rel_offset: 0x%x\n", rel_type, r_offset);
  198.             sym_def = symbol_def_find(str_tab + sym->st_name,
  199.                 m, &dest);
  200.             DPRINTF("dest name: '%s'\n", dest->dyn.soname);
  201.             DPRINTF("dest bias: 0x%x\n", dest->bias);
  202.             if (sym_def) {
  203.                 sym_addr = symbol_get_addr(sym_def, dest);
  204.                 DPRINTF("symbol definition found, addr=0x%x\n", sym_addr);
  205.             } else {
  206.                 DPRINTF("symbol definition not found\n");
  207.                 continue;
  208.             }
  209.         }
  210.  
  211.         switch (rel_type) {
  212.         case R_PPC_ADDR16_LO:
  213.             DPRINTF("fixup R_PPC_ADDR16_LO (#lo(s+a))\n");
  214.             *r_ptr16 = (sym_addr + r_addend) & 0xffff;
  215.             break;
  216.  
  217.         case R_PPC_ADDR16_HI:
  218.             DPRINTF("fixup R_PPC_ADDR16_HI (#hi(s+a))\n");
  219.             *r_ptr16 = (sym_addr + r_addend) >> 16;
  220.             break;
  221.  
  222.         case R_PPC_ADDR16_HA:
  223.             DPRINTF("fixup R_PPC_ADDR16_HA (#ha(s+a))\n");
  224.             t_addr = sym_addr + r_addend;
  225.             *r_ptr16 = (t_addr >> 16) + ((t_addr & 0x8000) ? 1 : 0);
  226.             break;
  227.  
  228.         case R_PPC_JMP_SLOT:
  229.             DPRINTF("fixup R_PPC_JMP_SLOT (b+v)\n");
  230.             pidx = (r_ptr - _plt_ent) / 2;
  231.             if (pidx >= plt_n) {
  232.                 DPRINTF("error: proc index out of range\n");
  233.                 exit(1);
  234.             }
  235.             plt[18+2*pidx] = _b((void *)sym_addr, &plt[18+2*pidx]);
  236.             break;
  237.  
  238.         case R_PPC_ADDR32:
  239.             DPRINTF("fixup R_PPC_ADDR32 (b+v+a)\n");
  240.             *r_ptr = r_addend + sym_addr;
  241.             break;
  242.  
  243.         case R_PPC_COPY:
  244.             /*
  245.              * Copy symbol data from shared object to specified
  246.              * location.
  247.              */
  248.             DPRINTF("fixup R_PPC_COPY (s)\n");
  249.             sym_size = sym->st_size;
  250.             if (sym_size != sym_def->st_size) {
  251.                 printf("warning: mismatched symbol sizes\n");
  252.                 /* Take the lower value. */
  253.                 if (sym_size > sym_def->st_size)
  254.                     sym_size = sym_def->st_size;
  255.             }
  256.             memcpy(r_ptr, (const void *)sym_addr, sym_size);
  257.             break;
  258.            
  259.         case R_PPC_RELATIVE:
  260.             DPRINTF("fixup R_PPC_RELATIVE (b+a)\n");
  261.             *r_ptr = r_addend + m->bias;
  262.             break;
  263.  
  264.         case R_PPC_REL24:
  265.             DPRINTF("fixup R_PPC_REL24 (s+a-p)>>2\n");
  266.             *r_ptr = (sym_addr + r_addend - (uint32_t)r_ptr) >> 2;
  267.             break;
  268.  
  269.         case R_PPC_DTPMOD32:
  270.             /*
  271.              * We can ignore this as long as the only module
  272.              * with TLS variables is libc.so.
  273.              */
  274.             DPRINTF("Ignoring R_PPC_DTPMOD32\n");
  275.             break;
  276.  
  277.         default:
  278.             printf("Error: Unknown relocation type %d.\n",
  279.                 rel_type);
  280.             exit(1);
  281.             break;
  282.         }
  283.     }
  284.  
  285.     /*
  286.      * Synchronize the used portion of PLT. This is necessary since
  287.      * we are writing instructions.
  288.      */
  289.     smc_coherence(&plt[18], plt_n * 2 * sizeof(uint32_t));
  290. }
  291.  
  292. /** @}
  293.  */
  294.