1 1.48 riastrad /* $NetBSD: mdreloc.c,v 1.48 2025/04/16 17:37:48 riastradh Exp $ */ 2 1.48 riastrad 3 1.48 riastrad /* 4 1.48 riastrad * Copyright 1996 John D. Polstra. 5 1.48 riastrad * Copyright 1996 Matt Thomas <matt (at) 3am-software.com> 6 1.48 riastrad * All rights reserved. 7 1.48 riastrad * 8 1.48 riastrad * Redistribution and use in source and binary forms, with or without 9 1.48 riastrad * modification, are permitted provided that the following conditions 10 1.48 riastrad * are met: 11 1.48 riastrad * 1. Redistributions of source code must retain the above copyright 12 1.48 riastrad * notice, this list of conditions and the following disclaimer. 13 1.48 riastrad * 2. Redistributions in binary form must reproduce the above copyright 14 1.48 riastrad * notice, this list of conditions and the following disclaimer in the 15 1.48 riastrad * documentation and/or other materials provided with the distribution. 16 1.48 riastrad * 3. All advertising materials mentioning features or use of this software 17 1.48 riastrad * must display the following acknowledgement: 18 1.48 riastrad * This product includes software developed by John Polstra. 19 1.48 riastrad * 4. The name of the author may not be used to endorse or promote products 20 1.48 riastrad * derived from this software without specific prior written permission. 21 1.48 riastrad * 22 1.48 riastrad * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 1.48 riastrad * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 1.48 riastrad * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 1.48 riastrad * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 1.48 riastrad * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 1.48 riastrad * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 1.48 riastrad * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 1.48 riastrad * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 1.48 riastrad * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 1.48 riastrad * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 1.48 riastrad */ 33 1.48 riastrad 34 1.48 riastrad /* 35 1.48 riastrad * i386 ELF relocations. 36 1.48 riastrad * 37 1.48 riastrad * References: 38 1.48 riastrad * 39 1.48 riastrad * [ABI386-4] System V Application Binary Interface: Intel386 40 1.48 riastrad * Architecture Processor Supplement, Fourth Edition, 1997-03-19, 41 1.48 riastrad * The Santa Cruz Operation, Inc. 42 1.48 riastrad * https://www.sco.com/developers/devspecs/abi386-4.pdf 43 1.48 riastrad * https://web.archive.org/web/20250329184450/https://www.sco.com/developers/devspecs/abi386-4.pdf 44 1.48 riastrad * 45 1.48 riastrad * Note: Intel and SuSE have published an update to the i386 ELF 46 1.48 riastrad * supplement, but it is not entirely compatible (e.g., it requires 47 1.48 riastrad * 16-byte alignment for the stack pointer, not just 4-byte alignment), 48 1.48 riastrad * so it is not reliable as a normative reference: 49 1.48 riastrad * 50 1.48 riastrad * [ABI386-2015] System V Application Binary Interface: Intel386 51 1.48 riastrad * Architecture Processor Supplement, Version 1.0, 2015-02-03. 52 1.48 riastrad * https://uclibc.org/docs/psABI-i386.pdf 53 1.48 riastrad * https://web.archive.org/web/20250118211449/https://uclibc.org/docs/psABI-i386.pdf 54 1.48 riastrad * https://gitlab.com/x86-psABIs/i386-ABI 55 1.48 riastrad */ 56 1.21 skrll 57 1.21 skrll #include <sys/cdefs.h> 58 1.21 skrll #ifndef lint 59 1.48 riastrad __RCSID("$NetBSD: mdreloc.c,v 1.48 2025/04/16 17:37:48 riastradh Exp $"); 60 1.21 skrll #endif /* not lint */ 61 1.11 junyoung 62 1.1 mycroft #include <sys/types.h> 63 1.47 christos #include <machine/lwp_private.h> 64 1.1 mycroft 65 1.1 mycroft #include "debug.h" 66 1.1 mycroft #include "rtld.h" 67 1.1 mycroft 68 1.13 mycroft void _rtld_bind_start(void); 69 1.12 mycroft void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr); 70 1.19 skrll caddr_t _rtld_bind(const Obj_Entry *, Elf_Word); 71 1.12 mycroft 72 1.43 martin #define rdbg_symname(obj, rela) \ 73 1.43 martin ((obj)->strtab + (obj)->symtab[ELF_R_SYM((rela)->r_info)].st_name) 74 1.43 martin 75 1.1 mycroft void 76 1.1 mycroft _rtld_setup_pltgot(const Obj_Entry *obj) 77 1.1 mycroft { 78 1.1 mycroft obj->pltgot[1] = (Elf_Addr) obj; 79 1.1 mycroft obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start; 80 1.1 mycroft } 81 1.2 mycroft 82 1.12 mycroft void 83 1.19 skrll _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 84 1.12 mycroft { 85 1.12 mycroft const Elf_Rel *rel = 0, *rellim; 86 1.12 mycroft Elf_Addr relsz = 0; 87 1.12 mycroft Elf_Addr *where; 88 1.12 mycroft 89 1.12 mycroft for (; dynp->d_tag != DT_NULL; dynp++) { 90 1.12 mycroft switch (dynp->d_tag) { 91 1.12 mycroft case DT_REL: 92 1.12 mycroft rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr); 93 1.12 mycroft break; 94 1.12 mycroft case DT_RELSZ: 95 1.12 mycroft relsz = dynp->d_un.d_val; 96 1.12 mycroft break; 97 1.12 mycroft } 98 1.12 mycroft } 99 1.22 christos if (rel == 0 || relsz == 0) 100 1.22 christos return; 101 1.27 lukem rellim = (const Elf_Rel *)((const uint8_t *)rel + relsz); 102 1.12 mycroft for (; rel < rellim; rel++) { 103 1.12 mycroft where = (Elf_Addr *)(relocbase + rel->r_offset); 104 1.12 mycroft *where += (Elf_Addr)relocbase; 105 1.12 mycroft } 106 1.12 mycroft } 107 1.12 mycroft 108 1.2 mycroft int 109 1.32 joerg _rtld_relocate_nonplt_objects(Obj_Entry *obj) 110 1.2 mycroft { 111 1.3 mycroft const Elf_Rel *rel; 112 1.20 lukem Elf_Addr target = 0; 113 1.38 joerg const Elf_Sym *def = NULL; 114 1.38 joerg const Obj_Entry *defobj = NULL; 115 1.38 joerg unsigned long last_symnum = ULONG_MAX; 116 1.12 mycroft 117 1.3 mycroft for (rel = obj->rel; rel < obj->rellim; rel++) { 118 1.3 mycroft Elf_Addr *where; 119 1.3 mycroft Elf_Addr tmp; 120 1.4 mycroft unsigned long symnum; 121 1.3 mycroft 122 1.3 mycroft where = (Elf_Addr *)(obj->relocbase + rel->r_offset); 123 1.38 joerg 124 1.38 joerg switch (ELF_R_TYPE(rel->r_info)) { 125 1.38 joerg case R_TYPE(PC32): 126 1.38 joerg case R_TYPE(GOT32): 127 1.38 joerg case R_TYPE(32): 128 1.38 joerg case R_TYPE(GLOB_DAT): 129 1.38 joerg case R_TYPE(TLS_TPOFF): 130 1.38 joerg case R_TYPE(TLS_TPOFF32): 131 1.38 joerg case R_TYPE(TLS_DTPMOD32): 132 1.38 joerg case R_TYPE(TLS_DTPOFF32): 133 1.38 joerg symnum = ELF_R_SYM(rel->r_info); 134 1.38 joerg if (symnum != last_symnum) { 135 1.38 joerg last_symnum = symnum; 136 1.38 joerg def = _rtld_find_symdef(symnum, obj, &defobj, 137 1.38 joerg false); 138 1.38 joerg if (def == NULL) 139 1.38 joerg return -1; 140 1.38 joerg } 141 1.38 joerg break; 142 1.38 joerg default: 143 1.38 joerg break; 144 1.38 joerg } 145 1.38 joerg 146 1.3 mycroft 147 1.3 mycroft switch (ELF_R_TYPE(rel->r_info)) { 148 1.3 mycroft case R_TYPE(NONE): 149 1.3 mycroft break; 150 1.2 mycroft 151 1.2 mycroft #if 1 /* XXX should not occur */ 152 1.3 mycroft case R_TYPE(PC32): 153 1.23 matt target = (Elf_Addr)(defobj->relocbase + def->st_value); 154 1.3 mycroft 155 1.4 mycroft *where += target - (Elf_Addr)where; 156 1.14 mycroft rdbg(("PC32 %s in %s --> %p in %s", 157 1.43 martin rdbg_symname(obj, rel), 158 1.5 mycroft obj->path, (void *)*where, defobj->path)); 159 1.3 mycroft break; 160 1.2 mycroft 161 1.3 mycroft case R_TYPE(GOT32): 162 1.2 mycroft #endif 163 1.3 mycroft case R_TYPE(32): 164 1.3 mycroft case R_TYPE(GLOB_DAT): 165 1.23 matt target = (Elf_Addr)(defobj->relocbase + def->st_value); 166 1.3 mycroft 167 1.4 mycroft tmp = target + *where; 168 1.3 mycroft if (*where != tmp) 169 1.3 mycroft *where = tmp; 170 1.14 mycroft rdbg(("32/GLOB_DAT %s in %s --> %p in %s", 171 1.43 martin rdbg_symname(obj, rel), 172 1.5 mycroft obj->path, (void *)*where, defobj->path)); 173 1.3 mycroft break; 174 1.3 mycroft 175 1.41 joerg 176 1.41 joerg case R_TYPE(IRELATIVE): 177 1.41 joerg /* IFUNC relocations are handled in _rtld_call_ifunc */ 178 1.41 joerg if (obj->ifunc_remaining_nonplt == 0) { 179 1.41 joerg obj->ifunc_remaining_nonplt = 180 1.41 joerg obj->rellim - rel; 181 1.41 joerg } 182 1.41 joerg /* FALL-THROUGH */ 183 1.41 joerg 184 1.3 mycroft case R_TYPE(RELATIVE): 185 1.12 mycroft *where += (Elf_Addr)obj->relocbase; 186 1.14 mycroft rdbg(("RELATIVE in %s --> %p", obj->path, 187 1.12 mycroft (void *)*where)); 188 1.3 mycroft break; 189 1.3 mycroft 190 1.3 mycroft case R_TYPE(COPY): 191 1.3 mycroft /* 192 1.3 mycroft * These are deferred until all other relocations have 193 1.3 mycroft * been done. All we do here is make sure that the 194 1.3 mycroft * COPY relocation is not in a shared library. They 195 1.3 mycroft * are allowed only in executable files. 196 1.3 mycroft */ 197 1.8 mycroft if (obj->isdynamic) { 198 1.3 mycroft _rtld_error( 199 1.2 mycroft "%s: Unexpected R_COPY relocation in shared library", 200 1.3 mycroft obj->path); 201 1.3 mycroft return -1; 202 1.3 mycroft } 203 1.14 mycroft rdbg(("COPY (avoid in main)")); 204 1.3 mycroft break; 205 1.3 mycroft 206 1.33 joerg case R_TYPE(TLS_TPOFF): 207 1.42 joerg if (!defobj->tls_static && 208 1.42 joerg _rtld_tls_offset_allocate(__UNCONST(defobj))) 209 1.33 joerg return -1; 210 1.33 joerg 211 1.35 apb *where += (Elf_Addr)(def->st_value - defobj->tlsoffset); 212 1.33 joerg 213 1.33 joerg rdbg(("TLS_TPOFF %s in %s --> %p", 214 1.43 martin rdbg_symname(obj, rel), 215 1.33 joerg obj->path, (void *)*where)); 216 1.33 joerg break; 217 1.33 joerg 218 1.35 apb case R_TYPE(TLS_TPOFF32): 219 1.42 joerg if (!defobj->tls_static && 220 1.42 joerg _rtld_tls_offset_allocate(__UNCONST(defobj))) 221 1.35 apb return -1; 222 1.35 apb 223 1.35 apb *where += (Elf_Addr)(defobj->tlsoffset - def->st_value); 224 1.35 apb rdbg(("TLS_TPOFF32 %s in %s --> %p", 225 1.43 martin rdbg_symname(obj, rel), 226 1.35 apb obj->path, (void *)*where)); 227 1.35 apb break; 228 1.35 apb 229 1.33 joerg case R_TYPE(TLS_DTPMOD32): 230 1.33 joerg *where = (Elf_Addr)(defobj->tlsindex); 231 1.33 joerg 232 1.33 joerg rdbg(("TLS_DTPMOD32 %s in %s --> %p", 233 1.43 martin rdbg_symname(obj, rel), 234 1.33 joerg obj->path, (void *)*where)); 235 1.33 joerg break; 236 1.33 joerg 237 1.33 joerg case R_TYPE(TLS_DTPOFF32): 238 1.33 joerg *where = (Elf_Addr)(def->st_value); 239 1.33 joerg 240 1.33 joerg rdbg(("TLS_DTPOFF32 %s in %s --> %p", 241 1.43 martin rdbg_symname(obj, rel), 242 1.33 joerg obj->path, (void *)*where)); 243 1.33 joerg 244 1.33 joerg break; 245 1.33 joerg 246 1.3 mycroft default: 247 1.14 mycroft rdbg(("sym = %lu, type = %lu, offset = %p, " 248 1.3 mycroft "contents = %p, symbol = %s", 249 1.38 joerg (u_long)ELF_R_SYM(rel->r_info), 250 1.38 joerg (u_long)ELF_R_TYPE(rel->r_info), 251 1.3 mycroft (void *)rel->r_offset, (void *)*where, 252 1.43 martin rdbg_symname(obj, rel))); 253 1.3 mycroft _rtld_error("%s: Unsupported relocation type %ld " 254 1.28 jmmv "in non-PLT relocations", 255 1.3 mycroft obj->path, (u_long) ELF_R_TYPE(rel->r_info)); 256 1.2 mycroft return -1; 257 1.2 mycroft } 258 1.2 mycroft } 259 1.6 mycroft return 0; 260 1.6 mycroft } 261 1.6 mycroft 262 1.6 mycroft int 263 1.39 joerg _rtld_relocate_plt_lazy(Obj_Entry *obj) 264 1.6 mycroft { 265 1.6 mycroft const Elf_Rel *rel; 266 1.6 mycroft 267 1.39 joerg for (rel = obj->pltrellim; rel-- > obj->pltrel; ) { 268 1.6 mycroft Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rel->r_offset); 269 1.6 mycroft 270 1.39 joerg assert(ELF_R_TYPE(rel->r_info) == R_TYPE(JMP_SLOT) || 271 1.39 joerg ELF_R_TYPE(rel->r_info) == R_TYPE(IRELATIVE)); 272 1.39 joerg 273 1.39 joerg if (ELF_R_TYPE(rel->r_info) == R_TYPE(IRELATIVE)) 274 1.39 joerg obj->ifunc_remaining = obj->pltrellim - rel; 275 1.6 mycroft 276 1.6 mycroft /* Just relocate the GOT slots pointing into the PLT */ 277 1.6 mycroft *where += (Elf_Addr)obj->relocbase; 278 1.14 mycroft rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where)); 279 1.6 mycroft } 280 1.6 mycroft 281 1.6 mycroft return 0; 282 1.6 mycroft } 283 1.6 mycroft 284 1.26 matt static inline int 285 1.26 matt _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rel *rel, 286 1.26 matt Elf_Addr *tp) 287 1.6 mycroft { 288 1.16 mycroft Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rel->r_offset); 289 1.26 matt Elf_Addr target; 290 1.26 matt const Elf_Sym *def; 291 1.6 mycroft const Obj_Entry *defobj; 292 1.29 christos unsigned long info = rel->r_info; 293 1.6 mycroft 294 1.39 joerg if (ELF_R_TYPE(info) == R_TYPE(IRELATIVE)) 295 1.39 joerg return 0; 296 1.39 joerg 297 1.29 christos assert(ELF_R_TYPE(info) == R_TYPE(JMP_SLOT)); 298 1.6 mycroft 299 1.29 christos def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj, tp != NULL); 300 1.29 christos if (__predict_false(def == NULL)) 301 1.26 matt return -1; 302 1.29 christos if (__predict_false(def == &_rtld_sym_zero)) 303 1.29 christos return 0; 304 1.29 christos 305 1.36 joerg if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 306 1.36 joerg if (tp == NULL) 307 1.36 joerg return 0; 308 1.36 joerg target = _rtld_resolve_ifunc(defobj, def); 309 1.36 joerg } else { 310 1.36 joerg target = (Elf_Addr)(defobj->relocbase + def->st_value); 311 1.36 joerg } 312 1.36 joerg 313 1.26 matt rdbg(("bind now/fixup in %s --> old=%p new=%p", 314 1.44 riastrad defobj->strtab + def->st_name, (void *)*where, 315 1.26 matt (void *)target)); 316 1.26 matt if (*where != target) 317 1.26 matt *where = target; 318 1.26 matt if (tp) 319 1.26 matt *tp = target; 320 1.26 matt return 0; 321 1.26 matt } 322 1.26 matt 323 1.26 matt caddr_t 324 1.26 matt _rtld_bind(const Obj_Entry *obj, Elf_Word reloff) 325 1.26 matt { 326 1.31 skrll const Elf_Rel *rel = (const Elf_Rel *)((const uint8_t *)obj->pltrel 327 1.31 skrll + reloff); 328 1.26 matt Elf_Addr new_value; 329 1.26 matt int err; 330 1.26 matt 331 1.30 skrll new_value = 0; /* XXX gcc */ 332 1.30 skrll 333 1.34 joerg _rtld_shared_enter(); 334 1.26 matt err = _rtld_relocate_plt_object(obj, rel, &new_value); 335 1.29 christos if (err) 336 1.16 mycroft _rtld_die(); 337 1.34 joerg _rtld_shared_exit(); 338 1.6 mycroft 339 1.16 mycroft return (caddr_t)new_value; 340 1.15 junyoung } 341 1.15 junyoung 342 1.15 junyoung int 343 1.15 junyoung _rtld_relocate_plt_objects(const Obj_Entry *obj) 344 1.15 junyoung { 345 1.15 junyoung const Elf_Rel *rel; 346 1.26 matt int err = 0; 347 1.44 riastrad 348 1.15 junyoung for (rel = obj->pltrel; rel < obj->pltrellim; rel++) { 349 1.26 matt err = _rtld_relocate_plt_object(obj, rel, NULL); 350 1.26 matt if (err) 351 1.26 matt break; 352 1.15 junyoung } 353 1.26 matt return err; 354 1.2 mycroft } 355 1.33 joerg 356 1.33 joerg /* 357 1.33 joerg * i386 specific GNU variant of __tls_get_addr using register based 358 1.33 joerg * argument passing. 359 1.33 joerg */ 360 1.33 joerg #define DTV_MAX_INDEX(dtv) ((size_t)((dtv)[-1])) 361 1.33 joerg 362 1.33 joerg __dso_public __attribute__((__regparm__(1))) void * 363 1.33 joerg ___tls_get_addr(void *arg_) 364 1.33 joerg { 365 1.33 joerg size_t *arg = (size_t *)arg_; 366 1.33 joerg void **dtv; 367 1.33 joerg struct tls_tcb *tcb = __lwp_getprivate_fast(); 368 1.33 joerg size_t idx = arg[0], offset = arg[1]; 369 1.33 joerg 370 1.33 joerg dtv = tcb->tcb_dtv; 371 1.33 joerg 372 1.33 joerg if (__predict_true(idx < DTV_MAX_INDEX(dtv) && dtv[idx] != NULL)) 373 1.33 joerg return (uint8_t *)dtv[idx] + offset; 374 1.33 joerg 375 1.33 joerg return _rtld_tls_get_addr(tcb, idx, offset); 376 1.33 joerg } 377