1 /* $NetBSD: mdreloc.c,v 1.4 2017/08/10 19:03:26 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.4 2017/08/10 19:03:26 joerg Exp $"); 35 #endif /* not lint */ 36 37 #include <sys/types.h> 38 #include <sys/endian.h> 39 #include <sys/tls.h> 40 41 #include <stdlib.h> 42 #include <string.h> 43 44 #include "debug.h" 45 #include "rtld.h" 46 47 void _rtld_bind_start(void); 48 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr); 49 void *_rtld_bind(const Obj_Entry *, Elf_Word); 50 51 void 52 _rtld_setup_pltgot(const Obj_Entry *obj) 53 { 54 obj->pltgot[0] = (Elf_Addr) &_rtld_bind_start; 55 obj->pltgot[1] = (Elf_Addr) obj; 56 } 57 58 void 59 _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 60 { 61 const Elf_Rela *rela = NULL, *relalim; 62 Elf_Addr relasz = 0; 63 64 for (; dynp->d_tag != DT_NULL; dynp++) { 65 switch (dynp->d_tag) { 66 case DT_RELA: 67 rela = (const Elf_Rela *)(relocbase + dynp->d_un.d_ptr); 68 break; 69 case DT_RELASZ: 70 relasz = dynp->d_un.d_val; 71 break; 72 } 73 } 74 75 relalim = (const Elf_Rela *)((uintptr_t)rela + relasz); 76 for (; rela < relalim; rela++) { 77 Elf_Word r_type = ELF_R_TYPE(rela->r_info); 78 Elf_Addr *where = (Elf_Addr *)(relocbase + rela->r_offset); 79 80 switch (r_type) { 81 case R_TYPE(RELATIVE): { 82 Elf_Addr val = relocbase + rela->r_addend; 83 *where = val; 84 rdbg(("RELATIVE/L(%p) -> %p in <self>", 85 where, (void *)val)); 86 break; 87 } 88 89 case R_TYPE(NONE): 90 break; 91 92 default: 93 abort(); 94 } 95 } 96 } 97 98 int 99 _rtld_relocate_nonplt_objects(Obj_Entry *obj) 100 { 101 const Elf_Rela *rela; 102 const Elf_Sym *def = NULL; 103 const Obj_Entry *defobj = NULL; 104 unsigned long last_symnum = ULONG_MAX; 105 106 for (rela = obj->rela; rela < obj->relalim; rela++) { 107 Elf_Addr * const where = 108 (Elf_Addr *)(obj->relocbase + rela->r_offset); 109 const Elf_Word r_type = ELF_R_TYPE(rela->r_info); 110 unsigned long symnum; 111 112 switch (r_type) { 113 case R_TYPESZ(ADDR): 114 case R_TYPESZ(TLS_DTPMOD): 115 case R_TYPESZ(TLS_DTPREL): 116 symnum = ELF_R_SYM(rela->r_info); 117 if (last_symnum != symnum) { 118 last_symnum = symnum; 119 def = _rtld_find_symdef(symnum, obj, &defobj, 120 false); 121 if (def == NULL) 122 return -1; 123 } 124 break; 125 default: 126 break; 127 } 128 129 switch (r_type) { 130 case R_TYPE(NONE): 131 break; 132 133 case R_TYPE(RELATIVE): { 134 def = obj->symtab + r_symndx; 135 136 Elf_Addr val = (Elf_Addr)obj->relocbase + rela->r_addend; 137 138 rdbg(("RELATIVE(%p) -> %p (%s) in %s", 139 where, (void *)val, 140 obj->strtab + def->st_name, obj->path)); 141 142 *where = val; 143 break; 144 } 145 146 case R_TYPESZ(ADDR): { 147 Elf_Addr val = (Elf_Addr)defobj->relocbase + rela->r_addend; 148 149 *where = val; 150 rdbg(("ADDR %s in %s --> %p in %s", 151 obj->strtab + obj->symtab[r_symndx].st_name, 152 obj->path, (void *)val, defobj->path)); 153 break; 154 } 155 156 case R_TYPESZ(TLS_DTPMOD): { 157 Elf_Addr val = (Elf_Addr)defobj->tlsindex + rela->r_addend; 158 159 *where = val; 160 rdbg(("DTPMOD %s in %s --> %p in %s", 161 obj->strtab + obj->symtab[r_symndx].st_name, 162 obj->path, (void *)val, defobj->path)); 163 break; 164 } 165 166 case R_TYPESZ(TLS_DTPREL): { 167 Elf_Addr old = *where; 168 Elf_Addr val = old; 169 170 if (!defobj->tls_done && _rtld_tls_offset_allocate(obj)) 171 return -1; 172 173 val = (Elf_Addr)def->st_value - TLS_DTV_OFFSET; 174 *where = val; 175 176 rdbg(("DTPREL %s in %s --> %p in %s", 177 obj->strtab + obj->symtab[r_symndx].st_name, 178 obj->path, (void *)val, defobj->path)); 179 break; 180 } 181 182 default: 183 rdbg(("sym = %lu, type = %lu, offset = %p, " 184 "addend = %p, contents = %p, symbol = %s", 185 (u_long)ELF_R_SYM(rela->r_info), 186 (u_long)ELF_R_TYPE(rela->r_info), 187 (void *)rela->r_offset, (void *)rela->r_addend, 188 (void *)load_ptr(where, sizeof(Elf_Addr)), 189 obj->strtab + obj->symtab[r_symndx].st_name)); 190 _rtld_error("%s: Unsupported relocation type %ld " 191 "in non-PLT relocations", 192 obj->path, (u_long)r_type); 193 return -1; 194 } 195 } 196 197 return 0; 198 } 199 200 int 201 _rtld_relocate_plt_lazy(Obj_Entry *obj) 202 { 203 /* PLT fixups were done above in the GOT relocation. */ 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 const Obj_Entry *defobj; 212 Elf_Addr new_value; 213 214 assert(ELF_R_TYPE(rel->r_info) == R_TYPE(JMP_SLOT)); 215 216 const Elf_Sym *def = _rtld_find_plt_symdef(ELF_R_SYM(rel->r_info), 217 obj, &defobj, tp != NULL); 218 if (__predict_false(def == NULL)) 219 return -1; 220 if (__predict_false(def == &_rtld_sym_zero)) 221 return -1; 222 223 if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 224 if (tp == NULL) 225 return 0; 226 new_value = _rtld_resolve_ifunc(defobj, def); 227 } else { 228 new_value = (Elf_Addr)(defobj->relocbase + def->st_value); 229 } 230 rdbg(("bind now/fixup in %s --> new=%p", 231 defobj->strtab + def->st_name, (void *)new_value)); 232 *(Elf_Addr *)(obj->relocbase + rel->r_offset) = new_value; 233 234 if (tp) 235 *tp = new_value; 236 return 0; 237 } 238 239 void * 240 _rtld_bind(const Obj_Entry *obj, Elf_Word reloff) 241 { 242 const Elf_Rel *pltrel = (const Elf_Rel *)(obj->pltrel + reloff); 243 Elf_Addr new_value; 244 int err; 245 246 _rtld_shared_enter(); 247 err = _rtld_relocate_plt_object(obj, pltrel, &new_value); 248 if (err) 249 _rtld_die(); 250 _rtld_shared_exit(); 251 252 return (caddr_t)new_value; 253 } 254 255 int 256 _rtld_relocate_plt_objects(const Obj_Entry *obj) 257 { 258 259 for (const Elf_Rel *rel = obj->pltrel; rel < obj->pltrellim; rel++) { 260 if (_rtld_relocate_plt_object(obj, rel, NULL) < 0) 261 return -1; 262 } 263 264 return 0; 265 } 266