1 /* $NetBSD: mdreloc.c,v 1.2 2014/08/25 20:40:52 joerg Exp $ */ 2 3 /*- 4 * Copyright (c) 2014 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Matt Thomas of 3am Software Foundry. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 __RCSID("$NetBSD: mdreloc.c,v 1.2 2014/08/25 20:40:52 joerg Exp $"); 35 #endif /* not lint */ 36 37 #include <sys/types.h> 38 #include <string.h> 39 40 #include "debug.h" 41 #include "rtld.h" 42 43 void _rtld_bind_start(void); 44 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr); 45 caddr_t _rtld_bind(const Obj_Entry *, Elf_Word); 46 47 void 48 _rtld_setup_pltgot(const Obj_Entry *obj) 49 { 50 obj->pltgot[1] = (Elf_Addr) obj; 51 obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start; 52 } 53 54 void 55 _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 56 { 57 const Elf_Rel *rel = 0, *rellim; 58 Elf_Addr relsz = 0; 59 Elf_Addr *where; 60 61 for (; dynp->d_tag != DT_NULL; dynp++) { 62 switch (dynp->d_tag) { 63 case DT_REL: 64 rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr); 65 break; 66 case DT_RELSZ: 67 relsz = dynp->d_un.d_val; 68 break; 69 } 70 } 71 rellim = (const Elf_Rel *)((const uint8_t *)rel + relsz); 72 for (; rel < rellim; rel++) { 73 where = (Elf_Addr *)(relocbase + rel->r_offset); 74 *where += (Elf_Addr)relocbase; 75 } 76 } 77 78 int 79 _rtld_relocate_nonplt_objects(Obj_Entry *obj) 80 { 81 82 for (const Elf_Rela *rela = obj->rela; rela < obj->relalim; rela++) { 83 Elf_Addr *where; 84 const Elf_Sym *def; 85 const Obj_Entry *defobj; 86 unsigned long symnum; 87 Elf_Addr addend; 88 89 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 90 symnum = ELF_R_SYM(rela->r_info); 91 addend = rela->r_addend; 92 93 switch (ELF_R_TYPE(rela->r_info)) { 94 case R_TYPE(NONE): 95 break; 96 97 case R_TYPE(ABS64): /* word B + S + A */ 98 case R_TYPE(GLOB_DAT): /* word B + S */ 99 def = _rtld_find_symdef(symnum, obj, &defobj, false); 100 if (def == NULL) 101 return -1; 102 *where = addend + (Elf_Addr)defobj->relocbase + 103 def->st_value; 104 rdbg(("ABS64/GLOB_DAT %s in %s --> %p @ %p in %s", 105 obj->strtab + obj->symtab[symnum].st_name, 106 obj->path, (void *)tmp, where, defobj->path)); 107 break; 108 109 case R_TYPE(RELATIVE): /* word B + A */ 110 *where = addend + (Elf_Addr)obj->relocbase; 111 rdbg(("RELATIVE in %s --> %p", obj->path, 112 (void *)tmp)); 113 break; 114 115 case R_TYPE(COPY): 116 /* 117 * These are deferred until all other relocations have 118 * been done. All we do here is make sure that the 119 * COPY relocation is not in a shared library. They 120 * are allowed only in executable files. 121 */ 122 if (obj->isdynamic) { 123 _rtld_error( 124 "%s: Unexpected R_COPY relocation in shared library", 125 obj->path); 126 return -1; 127 } 128 rdbg(("COPY (avoid in main)")); 129 break; 130 131 case R_TLS_TYPE(TLS_DTPREL): 132 def = _rtld_find_symdef(symnum, obj, &defobj, false); 133 if (def == NULL) 134 return -1; 135 136 *where = addend + (Elf_Addr)(def->st_value); 137 138 rdbg(("TLS_DTPOFF32 %s in %s --> %p", 139 obj->strtab + obj->symtab[symnum].st_name, 140 obj->path, (void *)tmp)); 141 142 break; 143 case R_TLS_TYPE(TLS_DTPMOD): 144 def = _rtld_find_symdef(symnum, obj, &defobj, false); 145 if (def == NULL) 146 return -1; 147 148 *where = (Elf_Addr)(defobj->tlsindex); 149 150 rdbg(("TLS_DTPMOD %s in %s --> %p", 151 obj->strtab + obj->symtab[symnum].st_name, 152 obj->path, (void *)tmp)); 153 154 break; 155 156 case R_TLS_TYPE(TLS_TPREL): 157 def = _rtld_find_symdef(symnum, obj, &defobj, false); 158 if (def == NULL) 159 return -1; 160 161 if (!defobj->tls_done && 162 _rtld_tls_offset_allocate(obj)) 163 return -1; 164 165 *where = (Elf_Addr)def->st_value + defobj->tlsoffset + 166 sizeof(struct tls_tcb); 167 rdbg(("TLS_TPOFF32 %s in %s --> %p", 168 obj->strtab + obj->symtab[symnum].st_name, 169 obj->path, (void *)tmp)); 170 break; 171 172 default: 173 rdbg(("sym = %lu, type = %lu, offset = %p, " 174 "contents = %p, symbol = %s", 175 symnum, (u_long)ELF_R_TYPE(rela->r_info), 176 (void *)rela->r_offset, *where, 177 obj->strtab + obj->symtab[symnum].st_name)); 178 _rtld_error("%s: Unsupported relocation type %ld " 179 "in non-PLT relocations", 180 obj->path, (u_long) ELF_R_TYPE(rela->r_info)); 181 return -1; 182 } 183 } 184 return 0; 185 } 186 187 int 188 _rtld_relocate_plt_lazy(const Obj_Entry *obj) 189 { 190 191 if (!obj->relocbase) 192 return 0; 193 194 for (const Elf_Rel *rel = obj->pltrel; rel < obj->pltrellim; rel++) { 195 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rel->r_offset); 196 197 assert(ELF_R_TYPE(rel->r_info) == R_TYPE(JUMP_SLOT)); 198 199 /* Just relocate the GOT slots pointing into the PLT */ 200 *where += (Elf_Addr)obj->relocbase; 201 rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where)); 202 } 203 204 return 0; 205 } 206 207 static int 208 _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rel *rel, 209 Elf_Addr *tp) 210 { 211 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rel->r_offset); 212 Elf_Addr new_value; 213 const Elf_Sym *def; 214 const Obj_Entry *defobj; 215 unsigned long info = rel->r_info; 216 217 assert(ELF_R_TYPE(info) == R_TYPE(JUMP_SLOT)); 218 219 def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj, tp != NULL); 220 if (__predict_false(def == NULL)) 221 return -1; 222 if (__predict_false(def == &_rtld_sym_zero)) 223 return 0; 224 225 if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 226 if (tp == NULL) 227 return 0; 228 new_value = _rtld_resolve_ifunc(defobj, def); 229 } else { 230 new_value = (Elf_Addr)(defobj->relocbase + def->st_value); 231 } 232 rdbg(("bind now/fixup in %s --> old=%p new=%p", 233 defobj->strtab + def->st_name, (void *)*where, (void *)new_value)); 234 if (*where != new_value) 235 *where = new_value; 236 if (tp) 237 *tp = new_value; 238 239 return 0; 240 } 241 242 caddr_t 243 _rtld_bind(const Obj_Entry *obj, Elf_Word reloff) 244 { 245 const Elf_Rel *rel = obj->pltrel + reloff; 246 Elf_Addr new_value = 0; /* XXX gcc */ 247 248 _rtld_shared_enter(); 249 int err = _rtld_relocate_plt_object(obj, rel, &new_value); 250 if (err) 251 _rtld_die(); 252 _rtld_shared_exit(); 253 254 return (caddr_t)new_value; 255 } 256 int 257 _rtld_relocate_plt_objects(const Obj_Entry *obj) 258 { 259 const Elf_Rel *rel; 260 int err = 0; 261 262 for (rel = obj->pltrel; rel < obj->pltrellim; rel++) { 263 err = _rtld_relocate_plt_object(obj, rel, NULL); 264 if (err) 265 break; 266 } 267 268 return err; 269 } 270