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