1/* $NetBSD: mdreloc.c,v 1.29 2011/03/12 22:54:36 joerg Exp $ */ 2 3#include <sys/cdefs.h> 4#ifndef lint 5__RCSID("$NetBSD: mdreloc.c,v 1.29 2011/03/12 22:54:36 joerg Exp $"); 6#endif /* not lint */ 7 8#include <sys/cdefs.h> 9#ifndef lint 10__RCSID("$NetBSD: mdreloc.c,v 1.29 2011/03/12 22:54:36 joerg Exp $"); 11#endif /* not lint */ 12 13#include <sys/types.h> 14#include <sys/tls.h> 15 16#include "debug.h" 17#include "rtld.h" 18 19void _rtld_bind_start(void); 20void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr); 21caddr_t _rtld_bind(const Obj_Entry *, Elf_Word); 22static inline int _rtld_relocate_plt_object(const Obj_Entry *, 23 const Elf_Rela *, Elf_Addr *); 24 25void 26_rtld_setup_pltgot(const Obj_Entry *obj) 27{ 28 obj->pltgot[1] = (Elf_Addr) obj; 29 obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start; 30} 31 32void 33_rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 34{ 35 const Elf_Rela *rela = 0, *relalim; 36 Elf_Addr relasz = 0; 37 Elf_Addr *where; 38 39 for (; dynp->d_tag != DT_NULL; dynp++) { 40 switch (dynp->d_tag) { 41 case DT_RELA: 42 rela = (const Elf_Rela *)(relocbase + dynp->d_un.d_ptr); 43 break; 44 case DT_RELASZ: 45 relasz = dynp->d_un.d_val; 46 break; 47 } 48 } 49 relalim = (const Elf_Rela *)((const uint8_t *)rela + relasz); 50 for (; rela < relalim; rela++) { 51 where = (Elf_Addr *)(relocbase + rela->r_offset); 52 *where = (Elf_Addr)(relocbase + rela->r_addend); 53 } 54} 55 56int 57_rtld_relocate_nonplt_objects(Obj_Entry *obj) 58{ 59 const Elf_Rela *rela; 60 61 for (rela = obj->rela; rela < obj->relalim; rela++) { 62 Elf_Addr *where; 63 const Elf_Sym *def; 64 const Obj_Entry *defobj; 65 Elf_Addr tmp; 66 unsigned long symnum; 67 68 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 69 symnum = ELF_R_SYM(rela->r_info); 70 71 switch (ELF_R_TYPE(rela->r_info)) { 72 case R_TYPE(NONE): 73 break; 74 75#if 1 /* XXX should not occur */ 76 case R_TYPE(GOT32): 77 def = _rtld_find_symdef(symnum, obj, &defobj, false); 78 if (def == NULL) 79 return -1; 80 81 tmp = (Elf_Addr)(defobj->relocbase + def->st_value + 82 rela->r_addend); 83 if (*where != tmp) 84 *where = tmp; 85 rdbg(("GOT32 %s in %s --> %p in %s", 86 obj->strtab + obj->symtab[symnum].st_name, 87 obj->path, (void *)*where, defobj->path)); 88 break; 89 90 case R_TYPE(REL32): 91 def = _rtld_find_symdef(symnum, obj, &defobj, false); 92 if (def == NULL) 93 return -1; 94 95 tmp = (Elf_Addr)(defobj->relocbase + def->st_value + 96 rela->r_addend) - (Elf_Addr)where; 97 if (*where != tmp) 98 *where = tmp; 99 rdbg(("PC32 %s in %s --> %p in %s", 100 obj->strtab + obj->symtab[symnum].st_name, 101 obj->path, (void *)*where, defobj->path)); 102 break; 103#endif 104 105 case R_TYPE(DIR32): 106 def = _rtld_find_symdef(symnum, obj, &defobj, false); 107 if (def == NULL) 108 return -1; 109 110 tmp = (Elf_Addr)(defobj->relocbase + def->st_value + 111 rela->r_addend); 112 if (*where != tmp) 113 *where = tmp; 114 rdbg(("32 %s in %s --> %p in %s", 115 obj->strtab + obj->symtab[symnum].st_name, 116 obj->path, (void *)*where, defobj->path)); 117 break; 118 119 case R_TYPE(GLOB_DAT): 120 def = _rtld_find_symdef(symnum, obj, &defobj, false); 121 if (def == NULL) 122 return -1; 123 124 tmp = (Elf_Addr)(defobj->relocbase + def->st_value) + 125 rela->r_addend; 126 if (*where != tmp) 127 *where = tmp; 128 rdbg(("GLOB_DAT %s in %s --> %p in %s", 129 obj->strtab + obj->symtab[symnum].st_name, 130 obj->path, (void *)*where, defobj->path)); 131 break; 132 133 case R_TYPE(RELATIVE): 134 if (rela->r_addend) 135 *where = (Elf_Addr)obj->relocbase + rela->r_addend; 136 else 137 *where += (Elf_Addr)obj->relocbase; 138 rdbg(("RELATIVE in %s --> %p", obj->path, 139 (void *)*where)); 140 break; 141 142 case R_TYPE(COPY): 143 /* 144 * These are deferred until all other relocations have 145 * been done. All we do here is make sure that the 146 * COPY relocation is not in a shared library. They 147 * are allowed only in executable files. 148 */ 149 if (obj->isdynamic) { 150 _rtld_error( 151 "%s: Unexpected R_COPY relocation in shared library", 152 obj->path); 153 return -1; 154 } 155 rdbg(("COPY (avoid in main)")); 156 break; 157 158 case R_TYPE(TLS_DTPOFF32): 159 def = _rtld_find_symdef(symnum, obj, &defobj, false); 160 if (def == NULL) 161 return -1; 162 163 *where = (Elf_Addr)(def->st_value); 164 165 rdbg(("TLS_DTPOFF32 %s in %s --> %p", 166 obj->strtab + obj->symtab[symnum].st_name, 167 obj->path, (void *)*where)); 168 169 break; 170 case R_TYPE(TLS_DTPMOD32): 171 def = _rtld_find_symdef(symnum, obj, &defobj, false); 172 if (def == NULL) 173 return -1; 174 175 *where = (Elf_Addr)(defobj->tlsindex); 176 177 rdbg(("TLS_DTPMOD32 %s in %s --> %p", 178 obj->strtab + obj->symtab[symnum].st_name, 179 obj->path, (void *)*where)); 180 181 break; 182 183 case R_TYPE(TLS_TPOFF32): 184 def = _rtld_find_symdef(symnum, obj, &defobj, false); 185 if (def == NULL) 186 return -1; 187 188 if (!defobj->tls_done && 189 _rtld_tls_offset_allocate(obj)) 190 return -1; 191 192 *where = (Elf_Addr)def->st_value + 193 rela->r_addend + defobj->tlsoffset + 194 sizeof(struct tls_tcb); 195 196 rdbg(("TLS_TPOFF32 %s in %s --> %p", 197 obj->strtab + obj->symtab[symnum].st_name, 198 obj->path, (void *)*where)); 199 break; 200 201 default: 202 rdbg(("sym = %lu, type = %lu, offset = %p, " 203 "addend = %p, contents = %p, symbol = %s", 204 symnum, (u_long)ELF_R_TYPE(rela->r_info), 205 (void *)rela->r_offset, (void *)rela->r_addend, 206 (void *)*where, 207 obj->strtab + obj->symtab[symnum].st_name)); 208 _rtld_error("%s: Unsupported relocation type %ld " 209 "in non-PLT relocations", 210 obj->path, (u_long) ELF_R_TYPE(rela->r_info)); 211 return -1; 212 } 213 } 214 return 0; 215} 216 217int 218_rtld_relocate_plt_lazy(const Obj_Entry *obj) 219{ 220 const Elf_Rela *rela; 221 222 if (!obj->relocbase) 223 return 0; 224 225 for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) { 226 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 227 228 assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT)); 229 230 /* Just relocate the GOT slots pointing into the PLT */ 231 *where += (Elf_Addr)obj->relocbase; 232 rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where)); 233 } 234 235 return 0; 236} 237 238caddr_t 239_rtld_bind(const Obj_Entry *obj, Elf_Word reloff) 240{ 241 const Elf_Rela *rela = (const Elf_Rela *)((const uint8_t *)obj->pltrela + reloff); 242 Elf_Addr new_value; 243 int err; 244 245 new_value = 0; /* XXX gcc */ 246 247 _rtld_shared_enter(); 248 err = _rtld_relocate_plt_object(obj, rela, &new_value); 249 if (err) 250 _rtld_die(); 251 _rtld_shared_exit(); 252 253 return (caddr_t)new_value; 254} 255 256int 257_rtld_relocate_plt_objects(const Obj_Entry *obj) 258{ 259 const Elf_Rela *rela = obj->pltrela; 260 261 for (; rela < obj->pltrelalim; rela++) 262 if (_rtld_relocate_plt_object(obj, rela, NULL) < 0) 263 return -1; 264 265 return 0; 266} 267 268static inline int 269_rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *tp) 270{ 271 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 272 Elf_Addr new_value; 273 const Elf_Sym *def; 274 const Obj_Entry *defobj; 275 unsigned long info = rela->r_info; 276 277 assert(ELF_R_TYPE(info) == R_TYPE(JMP_SLOT)); 278 279 def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj, tp != NULL); 280 if (__predict_false(def == NULL)) 281 return -1; 282 if (__predict_false(def == &_rtld_sym_zero)) 283 return 0; 284 285 new_value = (Elf_Addr)(defobj->relocbase + def->st_value); 286 rdbg(("bind now/fixup in %s --> old=%p new=%p", 287 defobj->strtab + def->st_name, (void *)*where, (void *)new_value)); 288 if (*where != new_value) 289 *where = new_value; 290 291 if (tp) 292 *tp = new_value; 293 294 return 0; 295} 296