1 /* $NetBSD: mdreloc.c,v 1.20 2005/05/31 19:30:38 skrll 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 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr); 11 caddr_t _rtld_bind(const Obj_Entry *, Elf_Word); 12 static inline int _rtld_relocate_plt_object(const Obj_Entry *, 13 const Elf_Rela *, Elf_Addr *); 14 15 void 16 _rtld_setup_pltgot(const Obj_Entry *obj) 17 { 18 obj->pltgot[1] = (Elf_Addr) obj; 19 obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start; 20 } 21 22 void 23 _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 24 { 25 const Elf_Rela *rela = 0, *relalim; 26 Elf_Addr relasz = 0; 27 Elf_Addr *where; 28 29 for (; dynp->d_tag != DT_NULL; dynp++) { 30 switch (dynp->d_tag) { 31 case DT_RELA: 32 rela = (const Elf_Rela *)(relocbase + dynp->d_un.d_ptr); 33 break; 34 case DT_RELASZ: 35 relasz = dynp->d_un.d_val; 36 break; 37 } 38 } 39 relalim = (const Elf_Rela *)((caddr_t)rela + relasz); 40 for (; rela < relalim; rela++) { 41 where = (Elf_Addr *)(relocbase + rela->r_offset); 42 *where = (Elf_Addr)(relocbase + rela->r_addend); 43 } 44 } 45 46 int 47 _rtld_relocate_nonplt_objects(const Obj_Entry *obj) 48 { 49 const Elf_Rela *rela; 50 51 for (rela = obj->rela; rela < obj->relalim; rela++) { 52 Elf_Addr *where; 53 const Elf_Sym *def; 54 const Obj_Entry *defobj; 55 Elf_Addr tmp; 56 unsigned long symnum; 57 58 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 59 symnum = ELF_R_SYM(rela->r_info); 60 61 switch (ELF_R_TYPE(rela->r_info)) { 62 case R_TYPE(NONE): 63 break; 64 65 #if 1 /* XXX should not occur */ 66 case R_TYPE(GOT32): 67 def = _rtld_find_symdef(symnum, obj, &defobj, false); 68 if (def == NULL) 69 return -1; 70 71 tmp = (Elf_Addr)(defobj->relocbase + def->st_value + 72 rela->r_addend); 73 if (*where != tmp) 74 *where = tmp; 75 rdbg(("GOT32 %s in %s --> %p in %s", 76 obj->strtab + obj->symtab[symnum].st_name, 77 obj->path, (void *)*where, defobj->path)); 78 break; 79 80 case R_TYPE(REL32): 81 def = _rtld_find_symdef(symnum, obj, &defobj, false); 82 if (def == NULL) 83 return -1; 84 85 tmp = (Elf_Addr)(defobj->relocbase + def->st_value + 86 rela->r_addend) - (Elf_Addr)where; 87 if (*where != tmp) 88 *where = tmp; 89 rdbg(("PC32 %s in %s --> %p in %s", 90 obj->strtab + obj->symtab[symnum].st_name, 91 obj->path, (void *)*where, defobj->path)); 92 break; 93 #endif 94 95 case R_TYPE(DIR32): 96 def = _rtld_find_symdef(symnum, obj, &defobj, false); 97 if (def == NULL) 98 return -1; 99 100 tmp = (Elf_Addr)(defobj->relocbase + def->st_value + 101 rela->r_addend); 102 if (*where != tmp) 103 *where = tmp; 104 rdbg(("32 %s in %s --> %p in %s", 105 obj->strtab + obj->symtab[symnum].st_name, 106 obj->path, (void *)*where, defobj->path)); 107 break; 108 109 case R_TYPE(GLOB_DAT): 110 def = _rtld_find_symdef(symnum, obj, &defobj, false); 111 if (def == NULL) 112 return -1; 113 114 tmp = (Elf_Addr)(defobj->relocbase + def->st_value) + 115 rela->r_addend; 116 if (*where != tmp) 117 *where = tmp; 118 rdbg(("GLOB_DAT %s in %s --> %p in %s", 119 obj->strtab + obj->symtab[symnum].st_name, 120 obj->path, (void *)*where, defobj->path)); 121 break; 122 123 case R_TYPE(RELATIVE): 124 if (rela->r_addend) 125 *where = (Elf_Addr)obj->relocbase + rela->r_addend; 126 else 127 *where += (Elf_Addr)obj->relocbase; 128 rdbg(("RELATIVE in %s --> %p", obj->path, 129 (void *)*where)); 130 break; 131 132 case R_TYPE(COPY): 133 /* 134 * These are deferred until all other relocations have 135 * been done. All we do here is make sure that the 136 * COPY relocation is not in a shared library. They 137 * are allowed only in executable files. 138 */ 139 if (obj->isdynamic) { 140 _rtld_error( 141 "%s: Unexpected R_COPY relocation in shared library", 142 obj->path); 143 return -1; 144 } 145 rdbg(("COPY (avoid in main)")); 146 break; 147 148 default: 149 rdbg(("sym = %lu, type = %lu, offset = %p, " 150 "addend = %p, contents = %p, symbol = %s", 151 symnum, (u_long)ELF_R_TYPE(rela->r_info), 152 (void *)rela->r_offset, (void *)rela->r_addend, 153 (void *)*where, 154 obj->strtab + obj->symtab[symnum].st_name)); 155 _rtld_error("%s: Unsupported relocation type %ld " 156 "in non-PLT relocations\n", 157 obj->path, (u_long) ELF_R_TYPE(rela->r_info)); 158 return -1; 159 } 160 } 161 return 0; 162 } 163 164 int 165 _rtld_relocate_plt_lazy(const Obj_Entry *obj) 166 { 167 const Elf_Rela *rela; 168 169 if (!obj->relocbase) 170 return 0; 171 172 for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) { 173 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 174 175 assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT)); 176 177 /* Just relocate the GOT slots pointing into the PLT */ 178 *where += (Elf_Addr)obj->relocbase; 179 rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where)); 180 } 181 182 return 0; 183 } 184 185 caddr_t 186 _rtld_bind(const Obj_Entry *obj, Elf_Word reloff) 187 { 188 const Elf_Rela *rela = (const Elf_Rela *)((caddr_t)obj->pltrela + reloff); 189 Elf_Addr new_value; 190 int err; 191 192 err = _rtld_relocate_plt_object(obj, rela, &new_value); 193 if (err) 194 _rtld_die(); 195 196 return (caddr_t)new_value; 197 } 198 199 int 200 _rtld_relocate_plt_objects(const Obj_Entry *obj) 201 { 202 const Elf_Rela *rela = obj->pltrela; 203 204 for (; rela < obj->pltrelalim; rela++) 205 if (_rtld_relocate_plt_object(obj, rela, NULL) < 0) 206 return -1; 207 208 return 0; 209 } 210 211 static inline int 212 _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *tp) 213 { 214 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 215 Elf_Addr new_value; 216 const Elf_Sym *def; 217 const Obj_Entry *defobj; 218 219 assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT)); 220 221 def = _rtld_find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, true); 222 if (def == NULL) 223 return -1; 224 225 new_value = (Elf_Addr)(defobj->relocbase + def->st_value); 226 rdbg(("bind now/fixup in %s --> old=%p new=%p", 227 defobj->strtab + def->st_name, (void *)*where, (void *)new_value)); 228 if (*where != new_value) 229 *where = new_value; 230 231 if (tp) 232 *tp = new_value; 233 234 return 0; 235 } 236