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