1 /* $NetBSD: mdreloc.c,v 1.11 2024/12/01 09:27:12 skrll 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.11 2024/12/01 09:27:12 skrll Exp $"); 35 #endif /* not lint */ 36 37 /* 38 * RISC-V ELF relocations. 39 * 40 * Reference: 41 * 42 * [RISCVELF] RISC-V ELF Specification, 2024-07-17. 43 * https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/9fec6080d15e7f009c9e714d1e9b8dd7177b0b67/riscv-elf.adoc 44 */ 45 46 #include <sys/types.h> 47 #include <sys/endian.h> 48 #include <sys/tls.h> 49 50 #include <machine/lwp_private.h> 51 52 #include <stdlib.h> 53 #include <string.h> 54 55 #include "debug.h" 56 #include "rtld.h" 57 58 void _rtld_bind_start(void); 59 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr); 60 void *_rtld_bind(const Obj_Entry *, Elf_Word); 61 62 void 63 _rtld_setup_pltgot(const Obj_Entry *obj) 64 { 65 obj->pltgot[0] = (Elf_Addr) &_rtld_bind_start; 66 obj->pltgot[1] = (Elf_Addr) obj; 67 } 68 69 void 70 _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 71 { 72 const Elf_Rela *rela = NULL, *relalim; 73 Elf_Addr relasz = 0; 74 75 for (; dynp->d_tag != DT_NULL; dynp++) { 76 switch (dynp->d_tag) { 77 case DT_RELA: 78 rela = (const Elf_Rela *)(relocbase + dynp->d_un.d_ptr); 79 break; 80 case DT_RELASZ: 81 relasz = dynp->d_un.d_val; 82 break; 83 } 84 } 85 86 relalim = (const Elf_Rela *)((uintptr_t)rela + relasz); 87 for (; rela < relalim; rela++) { 88 Elf_Word r_type = ELF_R_TYPE(rela->r_info); 89 Elf_Addr *where = (Elf_Addr *)(relocbase + rela->r_offset); 90 91 switch (r_type) { 92 case R_TYPE(RELATIVE): { 93 Elf_Addr val = relocbase + rela->r_addend; 94 *where = val; 95 rdbg(("RELATIVE/L(%p) -> %p in <self>", 96 where, (void *)val)); 97 break; 98 } 99 100 case R_TYPE(NONE): 101 break; 102 103 default: 104 abort(); 105 } 106 } 107 } 108 109 int 110 _rtld_relocate_nonplt_objects(Obj_Entry *obj) 111 { 112 const Elf_Rela *rela; 113 const Elf_Sym *def = NULL; 114 const Obj_Entry *defobj = NULL; 115 unsigned long last_symnum = ULONG_MAX; 116 117 for (rela = obj->rela; rela < obj->relalim; rela++) { 118 Elf_Addr * const where = 119 (Elf_Addr *)(obj->relocbase + rela->r_offset); 120 const Elf_Word r_type = ELF_R_TYPE(rela->r_info); 121 unsigned long symnum; 122 123 switch (r_type) { 124 case R_TYPESZ(ADDR): 125 case R_TYPESZ(TLS_DTPMOD): 126 case R_TYPESZ(TLS_DTPREL): 127 case R_TYPESZ(TLS_TPREL): 128 symnum = ELF_R_SYM(rela->r_info); 129 if (last_symnum != symnum) { 130 last_symnum = symnum; 131 def = _rtld_find_symdef(symnum, obj, &defobj, 132 false); 133 if (def == NULL) 134 return -1; 135 } 136 break; 137 default: 138 break; 139 } 140 141 switch (r_type) { 142 case R_TYPE(NONE): 143 break; 144 145 case R_TYPE(RELATIVE): { 146 const Elf_Addr val = (Elf_Addr)obj->relocbase + 147 rela->r_addend; 148 149 rdbg(("RELATIVE(%p) -> %p (%s) in %s", 150 where, (void *)val, 151 obj->strtab + 152 obj->symtab[ELF_R_SYM(rela->r_info)].st_name, 153 obj->path)); 154 155 *where = val; 156 break; 157 } 158 159 case R_TYPESZ(ADDR): { 160 const Elf_Addr val = (Elf_Addr)defobj->relocbase + 161 def->st_value + rela->r_addend; 162 163 rdbg(("ADDR(%p) -> %p (%s) in %s%s", 164 where, (void *)val, 165 obj->strtab + 166 obj->symtab[ELF_R_SYM(rela->r_info)].st_name, 167 obj->path, 168 def == &_rtld_sym_zero ? " (symzero)" : "")); 169 170 *where = val; 171 break; 172 } 173 174 case R_TYPE(COPY): 175 /* 176 * These are deferred until all other relocations have 177 * been done. All we do here is make sure that the 178 * COPY relocation is not in a shared library. They 179 * are allowed only in executable files. 180 */ 181 if (obj->isdynamic) { 182 _rtld_error("%s: Unexpected R_COPY relocation" 183 " in shared library", obj->path); 184 return -1; 185 } 186 rdbg(("COPY (avoid in main)")); 187 break; 188 189 case R_TYPESZ(TLS_DTPMOD): { 190 const Elf_Addr val = (Elf_Addr)defobj->tlsindex; 191 192 rdbg(("TLS_DTPMOD(%p) -> %p (%s) in %s", 193 where, (void *)val, 194 obj->strtab + 195 obj->symtab[ELF_R_SYM(rela->r_info)].st_name, 196 obj->path)); 197 198 *where = val; 199 break; 200 } 201 202 case R_TYPESZ(TLS_DTPREL): { 203 const Elf_Addr val = (Elf_Addr)(def->st_value + 204 rela->r_addend - TLS_DTV_OFFSET); 205 206 rdbg(("TLS_DTPREL(%p) -> %p (%s) in %s", 207 where, (void *)val, 208 obj->strtab + 209 obj->symtab[ELF_R_SYM(rela->r_info)].st_name, 210 defobj->path)); 211 212 *where = val; 213 break; 214 } 215 216 case R_TYPESZ(TLS_TPREL): 217 if (!defobj->tls_static && 218 _rtld_tls_offset_allocate(__UNCONST(defobj))) 219 return -1; 220 221 *where = (Elf_Addr)(def->st_value + defobj->tlsoffset + 222 rela->r_addend); 223 224 rdbg(("TLS_TPREL %s in %s --> %p in %s", 225 obj->strtab + 226 obj->symtab[ELF_R_SYM(rela->r_info)].st_name, 227 obj->path, (void *)*where, defobj->path)); 228 break; 229 230 default: 231 rdbg(("sym = %lu, type = %lu, offset = %p, " 232 "addend = %p, contents = %p", 233 (u_long)ELF_R_SYM(rela->r_info), 234 (u_long)ELF_R_TYPE(rela->r_info), 235 (void *)rela->r_offset, (void *)rela->r_addend, 236 (void *)*where)); 237 _rtld_error("%s: Unsupported relocation type %ld " 238 "in non-PLT relocations", 239 obj->path, (u_long)r_type); 240 return -1; 241 } 242 } 243 244 return 0; 245 } 246 247 int 248 _rtld_relocate_plt_lazy(Obj_Entry *obj) 249 { 250 251 if (!obj->relocbase) 252 return 0; 253 254 for (const Elf_Rela *rela = obj->pltrela; rela < obj->pltrelalim; rela++) { 255 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 256 switch (ELF_R_TYPE(rela->r_info)) { 257 case R_TYPE(JMP_SLOT): 258 /* Just relocate the GOT slots pointing into the PLT */ 259 *where += (Elf_Addr)obj->relocbase; 260 rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where)); 261 break; 262 default: 263 rdbg(("not yet... %d", (int)ELF_R_TYPE(rela->r_info) )); 264 } 265 } 266 267 return 0; 268 } 269 270 static int 271 _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, 272 Elf_Addr *tp) 273 { 274 Elf_Addr * const where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 275 const Obj_Entry *defobj; 276 Elf_Addr new_value; 277 278 assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT)); 279 280 const Elf_Sym *def = _rtld_find_plt_symdef(ELF_R_SYM(rela->r_info), 281 obj, &defobj, tp != NULL); 282 if (__predict_false(def == NULL)) 283 return -1; 284 if (__predict_false(def == &_rtld_sym_zero)) 285 return -1; 286 287 if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 288 if (tp == NULL) 289 return 0; 290 new_value = _rtld_resolve_ifunc(defobj, def); 291 } else { 292 new_value = (Elf_Addr)(defobj->relocbase + def->st_value); 293 } 294 rdbg(("bind now/fixup in %s --> old=%p new=%p", 295 defobj->strtab + def->st_name, (void *)*where, 296 (void *)new_value)); 297 if (*where != new_value) 298 *where = new_value; 299 if (tp) 300 *tp = new_value; 301 302 return 0; 303 } 304 305 void * 306 _rtld_bind(const Obj_Entry *obj, Elf_Word gotoff) 307 { 308 const Elf_Addr relidx = (gotoff / sizeof(Elf_Addr)); 309 const Elf_Rela *pltrela = obj->pltrela + relidx; 310 311 Elf_Addr new_value = 0; 312 313 _rtld_shared_enter(); 314 const int err = _rtld_relocate_plt_object(obj, pltrela, &new_value); 315 if (err) 316 _rtld_die(); 317 _rtld_shared_exit(); 318 319 return (void *)new_value; 320 } 321 322 int 323 _rtld_relocate_plt_objects(const Obj_Entry *obj) 324 { 325 326 for (const Elf_Rela *rela = obj->pltrela; rela < obj->pltrelalim; rela++) { 327 if (_rtld_relocate_plt_object(obj, rela, NULL) < 0) 328 return -1; 329 } 330 331 return 0; 332 } 333