1 /* $NetBSD: mdreloc.c,v 1.26 2010/01/13 20:17:23 christos Exp $ */ 2 3 #include <sys/cdefs.h> 4 #ifndef lint 5 __RCSID("$NetBSD: mdreloc.c,v 1.26 2010/01/13 20:17:23 christos Exp $"); 6 #endif /* not lint */ 7 8 #include <sys/cdefs.h> 9 #ifndef lint 10 __RCSID("$NetBSD: mdreloc.c,v 1.26 2010/01/13 20:17:23 christos Exp $"); 11 #endif /* not lint */ 12 13 #include <sys/types.h> 14 #include <sys/stat.h> 15 16 #include "debug.h" 17 #include "rtld.h" 18 19 void _rtld_bind_start(void); 20 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr); 21 caddr_t _rtld_bind(const Obj_Entry *, Elf_Word); 22 static inline int _rtld_relocate_plt_object(const Obj_Entry *, 23 const Elf_Rela *, Elf_Addr *); 24 25 void 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 32 void 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 56 int 57 _rtld_relocate_nonplt_objects(const 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 case R_TYPE(32): /* word32 S + A */ 76 case R_TYPE(GLOB_DAT): /* word32 S + A */ 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 84 if (*where != tmp) 85 *where = tmp; 86 rdbg(("32/GLOB_DAT %s in %s --> %p in %s", 87 obj->strtab + obj->symtab[symnum].st_name, 88 obj->path, (void *)*where, defobj->path)); 89 break; 90 91 case R_TYPE(RELATIVE): /* word32 B + A */ 92 tmp = (Elf_Addr)(obj->relocbase + rela->r_addend); 93 if (*where != tmp) 94 *where = tmp; 95 rdbg(("RELATIVE in %s --> %p", obj->path, 96 (void *)*where)); 97 break; 98 99 case R_TYPE(COPY): 100 /* 101 * These are deferred until all other relocations have 102 * been done. All we do here is make sure that the 103 * COPY relocation is not in a shared library. They 104 * are allowed only in executable files. 105 */ 106 if (obj->isdynamic) { 107 _rtld_error( 108 "%s: Unexpected R_COPY relocation in shared library", 109 obj->path); 110 return -1; 111 } 112 rdbg(("COPY (avoid in main)")); 113 break; 114 115 default: 116 rdbg(("sym = %lu, type = %lu, offset = %p, " 117 "addend = %p, contents = %p, symbol = %s", 118 symnum, (u_long)ELF_R_TYPE(rela->r_info), 119 (void *)rela->r_offset, (void *)rela->r_addend, 120 (void *)*where, 121 obj->strtab + obj->symtab[symnum].st_name)); 122 _rtld_error("%s: Unsupported relocation type %ld " 123 "in non-PLT relocations", 124 obj->path, (u_long) ELF_R_TYPE(rela->r_info)); 125 return -1; 126 } 127 } 128 return 0; 129 } 130 131 int 132 _rtld_relocate_plt_lazy(const Obj_Entry *obj) 133 { 134 const Elf_Rela *rela; 135 136 if (!obj->relocbase) 137 return 0; 138 139 for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) { 140 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 141 142 assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT)); 143 144 /* Just relocate the GOT slots pointing into the PLT */ 145 *where += (Elf_Addr)obj->relocbase; 146 rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where)); 147 } 148 149 return 0; 150 } 151 152 static inline int 153 _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *tp) 154 { 155 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 156 Elf_Addr new_value; 157 const Elf_Sym *def; 158 const Obj_Entry *defobj; 159 unsigned long info = rela->r_info; 160 161 assert(ELF_R_TYPE(info) == R_TYPE(JMP_SLOT)); 162 163 def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj, tp != NULL); 164 if (__predict_false(def == NULL)) 165 return -1; 166 if (__predict_false(def == &_rtld_sym_zero)) 167 return 0; 168 169 new_value = (Elf_Addr)(defobj->relocbase + def->st_value + 170 rela->r_addend); 171 rdbg(("bind now/fixup in %s --> old=%p new=%p", 172 defobj->strtab + def->st_name, (void *)*where, (void *)new_value)); 173 if (*where != new_value) 174 *where = new_value; 175 176 if (tp) 177 *tp = new_value - rela->r_addend; 178 179 return 0; 180 } 181 182 caddr_t 183 _rtld_bind(const Obj_Entry *obj, Elf_Word reloff) 184 { 185 const Elf_Rela *rela = (const Elf_Rela *)((const uint8_t *)obj->pltrela + reloff); 186 Elf_Addr result; 187 int err; 188 189 result = 0; /* XXX gcc */ 190 191 err = _rtld_relocate_plt_object(obj, rela, &result); 192 if (err) 193 _rtld_die(); 194 195 return (caddr_t)result; 196 } 197 198 int 199 _rtld_relocate_plt_objects(const Obj_Entry *obj) 200 { 201 const Elf_Rela *rela; 202 203 for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) 204 if (_rtld_relocate_plt_object(obj, rela, NULL) < 0) 205 return -1; 206 207 return 0; 208 } 209