1 /* $NetBSD: mdreloc.c,v 1.14 2002/10/03 20:39:23 mycroft Exp $ */ 2 3 #include <sys/types.h> 4 #include <sys/stat.h> 5 6 #include "debug.h" 7 #include "rtld.h" 8 9 void _rtld_bind_start(void); 10 11 void 12 _rtld_setup_pltgot(const Obj_Entry *obj) 13 { 14 obj->pltgot[1] = (Elf_Addr) obj; 15 obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start; 16 } 17 18 int 19 _rtld_relocate_nonplt_objects(obj) 20 const Obj_Entry *obj; 21 { 22 const Elf_Rela *rela; 23 24 for (rela = obj->rela; rela < obj->relalim; rela++) { 25 Elf_Addr *where; 26 const Elf_Sym *def; 27 const Obj_Entry *defobj; 28 Elf_Addr tmp; 29 unsigned long symnum; 30 31 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 32 symnum = ELF_R_SYM(rela->r_info); 33 34 switch (ELF_R_TYPE(rela->r_info)) { 35 case R_TYPE(NONE): 36 break; 37 38 #if 1 /* XXX should not occur */ 39 case R_TYPE(GOT32): 40 def = _rtld_find_symdef(symnum, obj, &defobj, false); 41 if (def == NULL) 42 return -1; 43 44 tmp = (Elf_Addr)(defobj->relocbase + def->st_value + 45 rela->r_addend); 46 if (*where != tmp) 47 *where = tmp; 48 rdbg(("GOT32 %s in %s --> %p in %s", 49 obj->strtab + obj->symtab[symnum].st_name, 50 obj->path, (void *)*where, defobj->path)); 51 break; 52 53 case R_TYPE(REL32): 54 def = _rtld_find_symdef(symnum, obj, &defobj, false); 55 if (def == NULL) 56 return -1; 57 58 *where += (Elf_Addr)(defobj->relocbase + def->st_value + 59 rela->r_addend) - (Elf_Addr)where; 60 rdbg(("PC32 %s in %s --> %p in %s", 61 obj->strtab + obj->symtab[symnum].st_name, 62 obj->path, (void *)*where, defobj->path)); 63 break; 64 #endif 65 66 case R_TYPE(DIR32): 67 def = _rtld_find_symdef(symnum, obj, &defobj, false); 68 if (def == NULL) 69 return -1; 70 71 *where += (Elf_Addr)(defobj->relocbase + def->st_value + 72 rela->r_addend); 73 rdbg(("32 %s in %s --> %p in %s", 74 obj->strtab + obj->symtab[symnum].st_name, 75 obj->path, (void *)*where, defobj->path)); 76 break; 77 78 case R_TYPE(GLOB_DAT): 79 def = _rtld_find_symdef(symnum, obj, &defobj, false); 80 if (def == NULL) 81 return -1; 82 83 tmp = (Elf_Addr)(defobj->relocbase + def->st_value) + 84 rela->r_addend; 85 if (*where != tmp) 86 *where = tmp; 87 rdbg(("GLOB_DAT %s in %s --> %p in %s", 88 obj->strtab + obj->symtab[symnum].st_name, 89 obj->path, (void *)*where, defobj->path)); 90 break; 91 92 case R_TYPE(RELATIVE): 93 if (rela->r_addend) 94 *where = (Elf_Addr)obj->relocbase + rela->r_addend; 95 else 96 *where += (Elf_Addr)obj->relocbase; 97 rdbg(("RELATIVE in %s --> %p", obj->path, 98 (void *)*where)); 99 break; 100 101 case R_TYPE(COPY): 102 /* 103 * These are deferred until all other relocations have 104 * been done. All we do here is make sure that the 105 * COPY relocation is not in a shared library. They 106 * are allowed only in executable files. 107 */ 108 if (obj->isdynamic) { 109 _rtld_error( 110 "%s: Unexpected R_COPY relocation in shared library", 111 obj->path); 112 return -1; 113 } 114 rdbg(("COPY (avoid in main)")); 115 break; 116 117 default: 118 rdbg(("sym = %lu, type = %lu, offset = %p, " 119 "addend = %p, contents = %p, symbol = %s", 120 symnum, (u_long)ELF_R_TYPE(rela->r_info), 121 (void *)rela->r_offset, (void *)rela->r_addend, 122 (void *)*where, 123 obj->strtab + obj->symtab[symnum].st_name)); 124 _rtld_error("%s: Unsupported relocation type %ld " 125 "in non-PLT relocations\n", 126 obj->path, (u_long) ELF_R_TYPE(rela->r_info)); 127 return -1; 128 } 129 } 130 return 0; 131 } 132 133 int 134 _rtld_relocate_plt_lazy(obj) 135 const Obj_Entry *obj; 136 { 137 const Elf_Rela *rela; 138 139 if (!obj->relocbase) 140 return 0; 141 142 for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) { 143 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 144 145 assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT)); 146 147 /* Just relocate the GOT slots pointing into the PLT */ 148 *where += (Elf_Addr)obj->relocbase; 149 rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where)); 150 } 151 152 return 0; 153 } 154 155 int 156 _rtld_relocate_plt_object(obj, rela, addrp) 157 const Obj_Entry *obj; 158 const Elf_Rela *rela; 159 caddr_t *addrp; 160 { 161 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 162 Elf_Addr new_value; 163 const Elf_Sym *def; 164 const Obj_Entry *defobj; 165 166 assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT)); 167 168 def = _rtld_find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, true); 169 if (def == NULL) 170 return -1; 171 172 new_value = (Elf_Addr)(defobj->relocbase + def->st_value + 173 rela->r_addend); 174 rdbg(("bind now/fixup in %s --> old=%p new=%p", 175 defobj->strtab + def->st_name, (void *)*where, (void *)new_value)); 176 if (*where != new_value) 177 *where = new_value; 178 179 *addrp = (caddr_t)new_value; 180 return 0; 181 } 182