1 /* $NetBSD: mdreloc.c,v 1.37 2025/04/18 12:56:47 riastradh Exp $ */ 2 3 /* 4 * Copyright 1996 John D. Polstra. 5 * Copyright 1996 Matt Thomas <matt (at) 3am-software.com> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by John Polstra. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * m68k ELF relocations. 36 * 37 * References: 38 * 39 * [M68KSYSVABI] System V Application Binary Interface: Motorola 40 * 68000 Processor Family Supplement, 1990, AT&T. 41 * https://people.debian.org/~glaubitz/m68k-sysv-abi.pdf 42 * https://web.archive.org/web/20250317195959/https://people.debian.org/~glaubitz/m68k-sysv-abi.pdf 43 */ 44 45 #include <sys/cdefs.h> 46 #ifndef lint 47 __RCSID("$NetBSD: mdreloc.c,v 1.37 2025/04/18 12:56:47 riastradh Exp $"); 48 #endif /* not lint */ 49 50 #include <sys/types.h> 51 52 #include "debug.h" 53 #include "rtld.h" 54 55 #include <machine/lwp_private.h> 56 57 void _rtld_bind_start(void); 58 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr); 59 caddr_t _rtld_bind(const Obj_Entry *, Elf_Word); 60 static inline int _rtld_relocate_plt_object(const Obj_Entry *, 61 const Elf_Rela *, Elf_Addr *); 62 63 64 void 65 _rtld_setup_pltgot(const Obj_Entry *obj) 66 { 67 obj->pltgot[1] = (Elf_Addr) obj; 68 obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start; 69 } 70 71 void 72 _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 73 { 74 const Elf_Rela *rela = 0, *relalim; 75 Elf_Addr relasz = 0; 76 Elf_Addr *where; 77 78 for (; dynp->d_tag != DT_NULL; dynp++) { 79 switch (dynp->d_tag) { 80 case DT_RELA: 81 rela = (const Elf_Rela *)(relocbase + dynp->d_un.d_ptr); 82 break; 83 case DT_RELASZ: 84 relasz = dynp->d_un.d_val; 85 break; 86 } 87 } 88 relalim = (const Elf_Rela *)((const uint8_t *)rela + relasz); 89 for (; rela < relalim; rela++) { 90 where = (Elf_Addr *)(relocbase + rela->r_offset); 91 *where += (Elf_Addr)relocbase; 92 } 93 } 94 95 int 96 _rtld_relocate_nonplt_objects(Obj_Entry *obj) 97 { 98 const Elf_Rela *rela; 99 const Elf_Sym *def = NULL; 100 const Obj_Entry *defobj = NULL; 101 unsigned long last_symnum = ULONG_MAX; 102 103 for (rela = obj->rela; rela < obj->relalim; rela++) { 104 Elf_Addr *where; 105 Elf_Addr tmp; 106 unsigned long symnum; 107 108 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 109 110 switch (ELF_R_TYPE(rela->r_info)) { 111 case R_TYPE(PC32): 112 case R_TYPE(GOT32): 113 case R_TYPE(32): 114 case R_TYPE(GLOB_DAT): 115 case R_TYPE(TLS_DTPMOD32): 116 case R_TYPE(TLS_DTPREL32): 117 case R_TYPE(TLS_TPREL32): 118 symnum = ELF_R_SYM(rela->r_info); 119 if (last_symnum != symnum) { 120 last_symnum = symnum; 121 def = _rtld_find_symdef(symnum, obj, &defobj, 122 false); 123 if (def == NULL) 124 return -1; 125 } 126 break; 127 default: 128 break; 129 } 130 131 switch (ELF_R_TYPE(rela->r_info)) { 132 case R_TYPE(NONE): 133 break; 134 135 #if 1 /* XXX should not occur */ 136 case R_TYPE(PC32): 137 tmp = (Elf_Addr)(defobj->relocbase + def->st_value + 138 rela->r_addend) - (Elf_Addr)where; 139 if (*where != tmp) 140 *where = tmp; 141 rdbg(("PC32 %s in %s --> %p in %s", 142 obj->strtab + obj->symtab[symnum].st_name, 143 obj->path, (void *)*where, defobj->path)); 144 break; 145 146 case R_TYPE(GOT32): 147 #endif 148 case R_TYPE(32): 149 case R_TYPE(GLOB_DAT): 150 tmp = (Elf_Addr)(defobj->relocbase + def->st_value + 151 rela->r_addend); 152 if (*where != tmp) 153 *where = tmp; 154 rdbg(("32/GLOB_DAT %s in %s --> %p in %s", 155 obj->strtab + obj->symtab[symnum].st_name, 156 obj->path, (void *)*where, defobj->path)); 157 break; 158 159 case R_TYPE(RELATIVE): 160 *where += (Elf_Addr)obj->relocbase; 161 rdbg(("RELATIVE in %s --> %p", obj->path, 162 (void *)*where)); 163 break; 164 165 case R_TYPE(COPY): 166 /* 167 * These are deferred until all other relocations have 168 * been done. All we do here is make sure that the 169 * COPY relocation is not in a shared library. They 170 * are allowed only in executable files. 171 */ 172 if (obj->isdynamic) { 173 _rtld_error( 174 "%s: Unexpected R_COPY relocation in shared library", 175 obj->path); 176 return -1; 177 } 178 rdbg(("COPY (avoid in main)")); 179 break; 180 181 case R_TYPE(TLS_DTPMOD32): 182 *where = (Elf_Addr)defobj->tlsindex; 183 rdbg(("DTPMOD32 %s in %s --> %p in %s", 184 obj->strtab + obj->symtab[symnum].st_name, 185 obj->path, (void *)*where, defobj->path)); 186 break; 187 188 case R_TYPE(TLS_DTPREL32): 189 *where = (Elf_Addr)(def->st_value + rela->r_addend 190 - TLS_DTV_OFFSET); 191 rdbg(("DTPREL32 %s in %s --> %p in %s", 192 obj->strtab + obj->symtab[symnum].st_name, 193 obj->path, (void *)*where, defobj->path)); 194 break; 195 196 case R_TYPE(TLS_TPREL32): 197 if (!defobj->tls_static && 198 _rtld_tls_offset_allocate(__UNCONST(defobj))) 199 return -1; 200 201 *where = (Elf_Addr)(def->st_value + rela->r_addend 202 + defobj->tlsoffset - TLS_TP_OFFSET); 203 rdbg(("TPREL32 %s in %s --> %p in %s", 204 obj->strtab + obj->symtab[symnum].st_name, 205 obj->path, (void *)*where, defobj->path)); 206 break; 207 208 default: 209 rdbg(("sym = %lu, type = %lu, offset = %p, " 210 "addend = %p, contents = %p, symbol = %s", 211 (u_long)ELF_R_SYM(rela->r_info), 212 (u_long)ELF_R_TYPE(rela->r_info), 213 (void *)rela->r_offset, (void *)rela->r_addend, 214 (void *)*where, 215 obj->strtab + obj->symtab[symnum].st_name)); 216 _rtld_error("%s: Unsupported relocation type %ld " 217 "in non-PLT relocations", 218 obj->path, (u_long) ELF_R_TYPE(rela->r_info)); 219 return -1; 220 } 221 } 222 return 0; 223 } 224 225 int 226 _rtld_relocate_plt_lazy(Obj_Entry *obj) 227 { 228 const Elf_Rela *rela; 229 230 if (!obj->relocbase) 231 return 0; 232 233 for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) { 234 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 235 236 assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT)); 237 238 /* Just relocate the GOT slots pointing into the PLT */ 239 *where += (Elf_Addr)obj->relocbase; 240 rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where)); 241 } 242 243 return 0; 244 } 245 246 static inline int 247 _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, 248 Elf_Addr *tp) 249 { 250 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 251 Elf_Addr new_value; 252 const Elf_Sym *def; 253 const Obj_Entry *defobj; 254 unsigned long info = rela->r_info; 255 256 assert(ELF_R_TYPE(info) == R_TYPE(JMP_SLOT)); 257 258 def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj, tp != NULL); 259 if (__predict_false(def == NULL)) 260 return -1; 261 if (__predict_false(def == &_rtld_sym_zero)) 262 return 0; 263 264 assert(rela->r_addend == 0); 265 if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 266 if (tp == NULL) 267 return 0; 268 new_value = _rtld_resolve_ifunc(defobj, def); 269 } else { 270 new_value = (Elf_Addr)(defobj->relocbase + def->st_value + 271 rela->r_addend); 272 } 273 rdbg(("bind now/fixup in %s --> old=%p new=%p", 274 defobj->strtab + def->st_name, (void *)*where, (void *)new_value)); 275 if (*where != new_value) 276 *where = new_value; 277 278 if (tp) 279 *tp = new_value - rela->r_addend; 280 281 return 0; 282 } 283 284 caddr_t 285 _rtld_bind(const Obj_Entry *obj, Elf_Word reloff) 286 { 287 const Elf_Rela *rela = (const Elf_Rela *)((const uint8_t *)obj->pltrela + reloff); 288 Elf_Addr result; 289 int err; 290 291 result = 0; /* XXX gcc */ 292 293 _rtld_shared_enter(); 294 err = _rtld_relocate_plt_object(obj, rela, &result); 295 if (err) 296 _rtld_die(); 297 _rtld_shared_exit(); 298 299 return (caddr_t)result; 300 } 301 302 int 303 _rtld_relocate_plt_objects(const Obj_Entry *obj) 304 { 305 const Elf_Rela *rela; 306 307 for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) 308 if (_rtld_relocate_plt_object(obj, rela, NULL) < 0) 309 return -1; 310 311 return 0; 312 } 313