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