1 1.11 skrll /* $NetBSD: mdreloc.c,v 1.11 2024/12/01 09:27:12 skrll Exp $ */ 2 1.1 matt 3 1.1 matt /*- 4 1.1 matt * Copyright (c) 2014 The NetBSD Foundation, Inc. 5 1.1 matt * All rights reserved. 6 1.1 matt * 7 1.1 matt * This code is derived from software contributed to The NetBSD Foundation 8 1.1 matt * by Matt Thomas of 3am Software Foundry. 9 1.1 matt * 10 1.1 matt * Redistribution and use in source and binary forms, with or without 11 1.1 matt * modification, are permitted provided that the following conditions 12 1.1 matt * are met: 13 1.1 matt * 1. Redistributions of source code must retain the above copyright 14 1.1 matt * notice, this list of conditions and the following disclaimer. 15 1.1 matt * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 matt * notice, this list of conditions and the following disclaimer in the 17 1.1 matt * documentation and/or other materials provided with the distribution. 18 1.1 matt * 19 1.1 matt * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 matt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 matt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 matt * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 matt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 matt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 matt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 matt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 matt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 matt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 matt * POSSIBILITY OF SUCH DAMAGE. 30 1.1 matt */ 31 1.1 matt 32 1.1 matt #include <sys/cdefs.h> 33 1.1 matt #ifndef lint 34 1.11 skrll __RCSID("$NetBSD: mdreloc.c,v 1.11 2024/12/01 09:27:12 skrll Exp $"); 35 1.1 matt #endif /* not lint */ 36 1.1 matt 37 1.10 riastrad /* 38 1.10 riastrad * RISC-V ELF relocations. 39 1.10 riastrad * 40 1.10 riastrad * Reference: 41 1.10 riastrad * 42 1.10 riastrad * [RISCVELF] RISC-V ELF Specification, 2024-07-17. 43 1.10 riastrad * https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/9fec6080d15e7f009c9e714d1e9b8dd7177b0b67/riscv-elf.adoc 44 1.10 riastrad */ 45 1.10 riastrad 46 1.1 matt #include <sys/types.h> 47 1.1 matt #include <sys/endian.h> 48 1.1 matt #include <sys/tls.h> 49 1.1 matt 50 1.11 skrll #include <machine/lwp_private.h> 51 1.11 skrll 52 1.1 matt #include <stdlib.h> 53 1.1 matt #include <string.h> 54 1.1 matt 55 1.1 matt #include "debug.h" 56 1.1 matt #include "rtld.h" 57 1.1 matt 58 1.1 matt void _rtld_bind_start(void); 59 1.1 matt void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr); 60 1.1 matt void *_rtld_bind(const Obj_Entry *, Elf_Word); 61 1.1 matt 62 1.1 matt void 63 1.1 matt _rtld_setup_pltgot(const Obj_Entry *obj) 64 1.1 matt { 65 1.1 matt obj->pltgot[0] = (Elf_Addr) &_rtld_bind_start; 66 1.1 matt obj->pltgot[1] = (Elf_Addr) obj; 67 1.1 matt } 68 1.1 matt 69 1.1 matt void 70 1.1 matt _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 71 1.1 matt { 72 1.2 matt const Elf_Rela *rela = NULL, *relalim; 73 1.2 matt Elf_Addr relasz = 0; 74 1.1 matt 75 1.1 matt for (; dynp->d_tag != DT_NULL; dynp++) { 76 1.1 matt switch (dynp->d_tag) { 77 1.2 matt case DT_RELA: 78 1.2 matt rela = (const Elf_Rela *)(relocbase + dynp->d_un.d_ptr); 79 1.1 matt break; 80 1.2 matt case DT_RELASZ: 81 1.2 matt relasz = dynp->d_un.d_val; 82 1.1 matt break; 83 1.1 matt } 84 1.1 matt } 85 1.1 matt 86 1.2 matt relalim = (const Elf_Rela *)((uintptr_t)rela + relasz); 87 1.2 matt for (; rela < relalim; rela++) { 88 1.2 matt Elf_Word r_type = ELF_R_TYPE(rela->r_info); 89 1.2 matt Elf_Addr *where = (Elf_Addr *)(relocbase + rela->r_offset); 90 1.1 matt 91 1.2 matt switch (r_type) { 92 1.2 matt case R_TYPE(RELATIVE): { 93 1.2 matt Elf_Addr val = relocbase + rela->r_addend; 94 1.2 matt *where = val; 95 1.2 matt rdbg(("RELATIVE/L(%p) -> %p in <self>", 96 1.2 matt where, (void *)val)); 97 1.1 matt break; 98 1.8 skrll } 99 1.1 matt 100 1.1 matt case R_TYPE(NONE): 101 1.1 matt break; 102 1.1 matt 103 1.1 matt default: 104 1.1 matt abort(); 105 1.1 matt } 106 1.1 matt } 107 1.1 matt } 108 1.1 matt 109 1.1 matt int 110 1.1 matt _rtld_relocate_nonplt_objects(Obj_Entry *obj) 111 1.1 matt { 112 1.2 matt const Elf_Rela *rela; 113 1.3 joerg const Elf_Sym *def = NULL; 114 1.3 joerg const Obj_Entry *defobj = NULL; 115 1.3 joerg unsigned long last_symnum = ULONG_MAX; 116 1.1 matt 117 1.2 matt for (rela = obj->rela; rela < obj->relalim; rela++) { 118 1.1 matt Elf_Addr * const where = 119 1.2 matt (Elf_Addr *)(obj->relocbase + rela->r_offset); 120 1.2 matt const Elf_Word r_type = ELF_R_TYPE(rela->r_info); 121 1.3 joerg unsigned long symnum; 122 1.3 joerg 123 1.3 joerg switch (r_type) { 124 1.3 joerg case R_TYPESZ(ADDR): 125 1.3 joerg case R_TYPESZ(TLS_DTPMOD): 126 1.3 joerg case R_TYPESZ(TLS_DTPREL): 127 1.8 skrll case R_TYPESZ(TLS_TPREL): 128 1.3 joerg symnum = ELF_R_SYM(rela->r_info); 129 1.3 joerg if (last_symnum != symnum) { 130 1.3 joerg last_symnum = symnum; 131 1.3 joerg def = _rtld_find_symdef(symnum, obj, &defobj, 132 1.3 joerg false); 133 1.3 joerg if (def == NULL) 134 1.3 joerg return -1; 135 1.3 joerg } 136 1.3 joerg break; 137 1.3 joerg default: 138 1.3 joerg break; 139 1.3 joerg } 140 1.1 matt 141 1.1 matt switch (r_type) { 142 1.1 matt case R_TYPE(NONE): 143 1.1 matt break; 144 1.1 matt 145 1.2 matt case R_TYPE(RELATIVE): { 146 1.8 skrll const Elf_Addr val = (Elf_Addr)obj->relocbase + 147 1.8 skrll rela->r_addend; 148 1.1 matt 149 1.2 matt rdbg(("RELATIVE(%p) -> %p (%s) in %s", 150 1.2 matt where, (void *)val, 151 1.8 skrll obj->strtab + 152 1.8 skrll obj->symtab[ELF_R_SYM(rela->r_info)].st_name, 153 1.8 skrll obj->path)); 154 1.1 matt 155 1.1 matt *where = val; 156 1.1 matt break; 157 1.8 skrll } 158 1.1 matt 159 1.2 matt case R_TYPESZ(ADDR): { 160 1.8 skrll const Elf_Addr val = (Elf_Addr)defobj->relocbase + 161 1.8 skrll def->st_value + rela->r_addend; 162 1.8 skrll 163 1.8 skrll rdbg(("ADDR(%p) -> %p (%s) in %s%s", 164 1.8 skrll where, (void *)val, 165 1.8 skrll obj->strtab + 166 1.8 skrll obj->symtab[ELF_R_SYM(rela->r_info)].st_name, 167 1.8 skrll obj->path, 168 1.8 skrll def == &_rtld_sym_zero ? " (symzero)" : "")); 169 1.2 matt 170 1.2 matt *where = val; 171 1.2 matt break; 172 1.8 skrll } 173 1.8 skrll 174 1.8 skrll case R_TYPE(COPY): 175 1.8 skrll /* 176 1.8 skrll * These are deferred until all other relocations have 177 1.8 skrll * been done. All we do here is make sure that the 178 1.8 skrll * COPY relocation is not in a shared library. They 179 1.8 skrll * are allowed only in executable files. 180 1.8 skrll */ 181 1.8 skrll if (obj->isdynamic) { 182 1.8 skrll _rtld_error("%s: Unexpected R_COPY relocation" 183 1.8 skrll " in shared library", obj->path); 184 1.8 skrll return -1; 185 1.8 skrll } 186 1.8 skrll rdbg(("COPY (avoid in main)")); 187 1.8 skrll break; 188 1.1 matt 189 1.2 matt case R_TYPESZ(TLS_DTPMOD): { 190 1.8 skrll const Elf_Addr val = (Elf_Addr)defobj->tlsindex; 191 1.8 skrll 192 1.8 skrll rdbg(("TLS_DTPMOD(%p) -> %p (%s) in %s", 193 1.8 skrll where, (void *)val, 194 1.8 skrll obj->strtab + 195 1.8 skrll obj->symtab[ELF_R_SYM(rela->r_info)].st_name, 196 1.8 skrll obj->path)); 197 1.1 matt 198 1.1 matt *where = val; 199 1.1 matt break; 200 1.8 skrll } 201 1.1 matt 202 1.2 matt case R_TYPESZ(TLS_DTPREL): { 203 1.8 skrll const Elf_Addr val = (Elf_Addr)(def->st_value + 204 1.8 skrll rela->r_addend - TLS_DTV_OFFSET); 205 1.8 skrll 206 1.8 skrll rdbg(("TLS_DTPREL(%p) -> %p (%s) in %s", 207 1.8 skrll where, (void *)val, 208 1.8 skrll obj->strtab + 209 1.8 skrll obj->symtab[ELF_R_SYM(rela->r_info)].st_name, 210 1.8 skrll defobj->path)); 211 1.1 matt 212 1.8 skrll *where = val; 213 1.8 skrll break; 214 1.8 skrll } 215 1.8 skrll 216 1.8 skrll case R_TYPESZ(TLS_TPREL): 217 1.9 joerg if (!defobj->tls_static && 218 1.9 joerg _rtld_tls_offset_allocate(__UNCONST(defobj))) 219 1.1 matt return -1; 220 1.1 matt 221 1.8 skrll *where = (Elf_Addr)(def->st_value + defobj->tlsoffset + 222 1.8 skrll rela->r_addend); 223 1.1 matt 224 1.8 skrll rdbg(("TLS_TPREL %s in %s --> %p in %s", 225 1.8 skrll obj->strtab + 226 1.8 skrll obj->symtab[ELF_R_SYM(rela->r_info)].st_name, 227 1.8 skrll obj->path, (void *)*where, defobj->path)); 228 1.1 matt break; 229 1.1 matt 230 1.1 matt default: 231 1.1 matt rdbg(("sym = %lu, type = %lu, offset = %p, " 232 1.8 skrll "addend = %p, contents = %p", 233 1.3 joerg (u_long)ELF_R_SYM(rela->r_info), 234 1.3 joerg (u_long)ELF_R_TYPE(rela->r_info), 235 1.2 matt (void *)rela->r_offset, (void *)rela->r_addend, 236 1.8 skrll (void *)*where)); 237 1.1 matt _rtld_error("%s: Unsupported relocation type %ld " 238 1.1 matt "in non-PLT relocations", 239 1.2 matt obj->path, (u_long)r_type); 240 1.1 matt return -1; 241 1.1 matt } 242 1.1 matt } 243 1.1 matt 244 1.1 matt return 0; 245 1.1 matt } 246 1.1 matt 247 1.1 matt int 248 1.4 joerg _rtld_relocate_plt_lazy(Obj_Entry *obj) 249 1.1 matt { 250 1.8 skrll 251 1.8 skrll if (!obj->relocbase) 252 1.8 skrll return 0; 253 1.8 skrll 254 1.8 skrll for (const Elf_Rela *rela = obj->pltrela; rela < obj->pltrelalim; rela++) { 255 1.8 skrll Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 256 1.8 skrll switch (ELF_R_TYPE(rela->r_info)) { 257 1.8 skrll case R_TYPE(JMP_SLOT): 258 1.8 skrll /* Just relocate the GOT slots pointing into the PLT */ 259 1.8 skrll *where += (Elf_Addr)obj->relocbase; 260 1.8 skrll rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where)); 261 1.8 skrll break; 262 1.8 skrll default: 263 1.8 skrll rdbg(("not yet... %d", (int)ELF_R_TYPE(rela->r_info) )); 264 1.8 skrll } 265 1.8 skrll } 266 1.8 skrll 267 1.1 matt return 0; 268 1.1 matt } 269 1.1 matt 270 1.1 matt static int 271 1.7 skrll _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, 272 1.1 matt Elf_Addr *tp) 273 1.1 matt { 274 1.8 skrll Elf_Addr * const where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 275 1.1 matt const Obj_Entry *defobj; 276 1.1 matt Elf_Addr new_value; 277 1.1 matt 278 1.7 skrll assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT)); 279 1.1 matt 280 1.7 skrll const Elf_Sym *def = _rtld_find_plt_symdef(ELF_R_SYM(rela->r_info), 281 1.1 matt obj, &defobj, tp != NULL); 282 1.1 matt if (__predict_false(def == NULL)) 283 1.1 matt return -1; 284 1.1 matt if (__predict_false(def == &_rtld_sym_zero)) 285 1.1 matt return -1; 286 1.1 matt 287 1.1 matt if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 288 1.1 matt if (tp == NULL) 289 1.1 matt return 0; 290 1.1 matt new_value = _rtld_resolve_ifunc(defobj, def); 291 1.1 matt } else { 292 1.1 matt new_value = (Elf_Addr)(defobj->relocbase + def->st_value); 293 1.1 matt } 294 1.8 skrll rdbg(("bind now/fixup in %s --> old=%p new=%p", 295 1.8 skrll defobj->strtab + def->st_name, (void *)*where, 296 1.8 skrll (void *)new_value)); 297 1.8 skrll if (*where != new_value) 298 1.8 skrll *where = new_value; 299 1.1 matt if (tp) 300 1.1 matt *tp = new_value; 301 1.8 skrll 302 1.1 matt return 0; 303 1.1 matt } 304 1.1 matt 305 1.1 matt void * 306 1.8 skrll _rtld_bind(const Obj_Entry *obj, Elf_Word gotoff) 307 1.1 matt { 308 1.8 skrll const Elf_Addr relidx = (gotoff / sizeof(Elf_Addr)); 309 1.8 skrll const Elf_Rela *pltrela = obj->pltrela + relidx; 310 1.8 skrll 311 1.8 skrll Elf_Addr new_value = 0; 312 1.1 matt 313 1.1 matt _rtld_shared_enter(); 314 1.8 skrll const int err = _rtld_relocate_plt_object(obj, pltrela, &new_value); 315 1.1 matt if (err) 316 1.1 matt _rtld_die(); 317 1.1 matt _rtld_shared_exit(); 318 1.1 matt 319 1.8 skrll return (void *)new_value; 320 1.1 matt } 321 1.1 matt 322 1.1 matt int 323 1.1 matt _rtld_relocate_plt_objects(const Obj_Entry *obj) 324 1.1 matt { 325 1.6 skrll 326 1.7 skrll for (const Elf_Rela *rela = obj->pltrela; rela < obj->pltrelalim; rela++) { 327 1.7 skrll if (_rtld_relocate_plt_object(obj, rela, NULL) < 0) 328 1.1 matt return -1; 329 1.1 matt } 330 1.1 matt 331 1.1 matt return 0; 332 1.1 matt } 333