1/* $OpenBSD: rtld_machine.c,v 1.44 2022/08/29 02:08:13 jsg Exp $ */ 2 3/* 4 * Copyright (c) 2004 Michael Shalayeff 5 * Copyright (c) 2001 Niklas Hallqvist 6 * Copyright (c) 2001 Artur Grabowski 7 * Copyright (c) 1999 Dale Rahn 8 * All rights reserved. 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 23 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 28 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 29 * THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#define _DYN_LOADER 33 34#include <sys/types.h> 35#include <sys/exec_elf.h> 36#include <sys/syscall.h> 37#include <sys/tree.h> 38#include <sys/unistd.h> 39 40#include <machine/reloc.h> 41#include <machine/vmparam.h> /* SYSCALLGATE */ 42 43#include "util.h" 44#define _dl_bind XXX_dl_bind 45#include "resolve.h" 46#undef _dl_bind 47uint64_t _dl_bind(elf_object_t *object, int reloff); 48 49typedef 50struct hppa_plabel { 51 Elf_Addr pc; 52 Elf_Addr *sl; 53 SPLAY_ENTRY(hppa_plabel) node; 54} hppa_plabel_t; 55SPLAY_HEAD(_dl_md_plabels, hppa_plabel) _dl_md_plabel_root; 56 57void _hppa_dl_set_dp(Elf_Addr *dp); /* from ldasm.S */ 58 59int64_t pcookie __attribute__((section(".openbsd.randomdata"))) __dso_hidden; 60 61static __inline int 62_dl_md_plcmp(hppa_plabel_t *a, hppa_plabel_t *b) 63{ 64 if (a->sl < b->sl) 65 return -1; 66 else if (a->sl > b->sl) 67 return 1; 68 else if (a->pc < b->pc) 69 return -1; 70 else if (a->pc > b->pc) 71 return 1; 72 else 73 return 0; 74} 75 76SPLAY_PROTOTYPE(_dl_md_plabels, hppa_plabel, node, _dl_md_plcmp); 77SPLAY_GENERATE(_dl_md_plabels, hppa_plabel, node, _dl_md_plcmp); 78 79Elf_Addr 80_dl_md_plabel(Elf_Addr pc, Elf_Addr *sl) 81{ 82 hppa_plabel_t key, *p; 83 84 key.pc = pc; 85 key.sl = sl; 86 p = SPLAY_FIND(_dl_md_plabels, &_dl_md_plabel_root, &key); 87 if (p == NULL) { 88 p = _dl_malloc(sizeof(*p)); 89 if (p == NULL) 90 _dl_oom(); 91 p->pc = pc; 92 p->sl = sl; 93 SPLAY_INSERT(_dl_md_plabels, &_dl_md_plabel_root, p); 94 } 95 96 return (Elf_Addr)p | 2; 97} 98 99int 100_dl_md_reloc(elf_object_t *object, int rel, int relasz) 101{ 102 Elf_RelA *rela; 103 Elf_Addr loff; 104 int num_relative; 105 int i, numrela, fails = 0; 106 107 loff = object->obj_base; 108 numrela = object->Dyn.info[relasz] / sizeof(Elf_RelA); 109 num_relative = rel == DT_RELA ? object->relacount : 0; 110 rela = (Elf_RelA *)(object->Dyn.info[rel]); 111 112#ifdef DEBUG 113 DL_DEB(("object %s relasz %x, numrela %x loff %x\n", 114 object->load_name, object->Dyn.info[relasz], numrela, loff)); 115#endif 116 117 if (rela == NULL) 118 return 0; 119 120 /* either it's an ld bug or a wacky hpux abi */ 121 if (!object->dyn.pltgot) 122 object->Dyn.info[DT_PLTGOT] += loff; 123 124 if (object->dyn.init && !((Elf_Addr)object->dyn.init & 2)) { 125 Elf_Addr addr = _dl_md_plabel((Elf_Addr)object->dyn.init, 126 object->dyn.pltgot); 127#ifdef DEBUG 128 DL_DEB(("PLABEL32: %p:%p(_init) -> 0x%x in %s\n", 129 object->dyn.init, object->dyn.pltgot, 130 addr, object->load_name)); 131#endif 132 object->dyn.init = (void *)addr; 133 } 134 135 if (object->dyn.fini && !((Elf_Addr)object->dyn.fini & 2)) { 136 Elf_Addr addr = _dl_md_plabel((Elf_Addr)object->dyn.fini, 137 object->dyn.pltgot); 138#ifdef DEBUG 139 DL_DEB(("PLABEL32: %p:%p(_fini) -> 0x%x in %s\n", 140 object->dyn.fini, object->dyn.pltgot, 141 addr, object->load_name)); 142#endif 143 object->dyn.fini = (void *)addr; 144 } 145 146 /* 147 * this is normally done by the crt0 code but we have to make 148 * sure it's set here to allow constructors to call functions 149 * that are overridden in the user binary (that are un-pic) 150 */ 151 if (object->obj_type == OBJTYPE_EXE) 152 _hppa_dl_set_dp(object->dyn.pltgot); 153 154 /* tight loop for leading relative relocs */ 155 for (i = 0; i < num_relative; i++, rela++) { 156 Elf_Addr *where = (Elf_Addr *)(rela->r_offset + loff); 157 *where = rela->r_addend + loff; 158 } 159 for (; i < numrela; i++, rela++) { 160 struct sym_res sr; 161 const Elf_Sym *sym; 162 Elf_Addr *pt; 163 const char *symn; 164 int type; 165 166 type = ELF_R_TYPE(rela->r_info); 167 if (type == RELOC_NONE) 168 continue; 169 170 sym = object->dyn.symtab + ELF_R_SYM(rela->r_info); 171 symn = object->dyn.strtab + sym->st_name; 172 pt = (Elf_Addr *)(rela->r_offset + loff); 173 174 if (ELF_R_SYM(rela->r_info) && sym->st_name) { 175 sr = _dl_find_symbol(symn, 176 SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT, 177 sym, object); 178 if (sr.sym == NULL) { 179 if (ELF_ST_BIND(sym->st_info) != STB_WEAK) 180 fails++; 181 continue; 182 } 183 } else { 184 sr.sym = NULL; 185 sr.obj = object; 186 } 187 188#ifdef DEBUG 189 DL_DEB(("*pt=%x r_addend=%x r_sym=%x\n", 190 *pt, rela->r_addend, ELF_R_SYM(rela->r_info))); 191#endif 192 193 switch (type) { 194 case RELOC_DIR32: 195 if (ELF_R_SYM(rela->r_info) && sym->st_name) { 196 *pt = sr.obj->obj_base + sr.sym->st_value + 197 rela->r_addend; 198#ifdef DEBUG 199 DL_DEB(("[%x]DIR32: %s:%s -> 0x%x in %s\n", 200 i, symn, object->load_name, 201 *pt, sr.obj->load_name)); 202#endif 203 } else { 204 /* 205 * Either a relative relocation (symbol 0) 206 * or a relocation against a local section 207 */ 208 *pt = loff + sym->st_value + rela->r_addend; 209#ifdef DEBUG 210 DL_DEB(("[%x]DIR32: %s @ 0x%x\n", i, 211 object->load_name, *pt)); 212#endif 213 } 214 break; 215 216 case RELOC_PLABEL32: 217 if (ELF_R_SYM(rela->r_info)) { 218 if (ELF_ST_TYPE(sr.sym->st_info) != STT_FUNC) { 219 DL_DEB(("[%x]PLABEL32: bad\n", i)); 220 break; 221 } 222 *pt = _dl_md_plabel(sr.obj->obj_base + 223 sr.sym->st_value + rela->r_addend, 224 sr.obj->dyn.pltgot); 225#ifdef DEBUG 226 DL_DEB(("[%x]PLABEL32: %s:%s -> 0x%x in %s\n", 227 i, symn, object->load_name, 228 *pt, sr.obj->load_name)); 229#endif 230 } else { 231 *pt = loff + rela->r_addend; 232#ifdef DEBUG 233 DL_DEB(("[%x]PLABEL32: %s @ 0x%x\n", i, 234 object->load_name, *pt)); 235#endif 236 } 237 break; 238 239 case RELOC_IPLT: 240 if (ELF_R_SYM(rela->r_info)) { 241 pt[0] = sr.obj->obj_base + sr.sym->st_value + 242 rela->r_addend; 243 pt[1] = (Elf_Addr)sr.obj->dyn.pltgot; 244#ifdef DEBUG 245 DL_DEB(("[%x]IPLT: %s:%s -> 0x%x:0x%x in %s\n", 246 i, symn, object->load_name, 247 pt[0], pt[1], sr.obj->load_name)); 248#endif 249 } else { 250 pt[0] = loff + rela->r_addend; 251 pt[1] = (Elf_Addr)object->dyn.pltgot; 252#ifdef DEBUG 253 DL_DEB(("[%x]IPLT: %s @ 0x%x:0x%x\n", i, 254 object->load_name, pt[0], pt[1])); 255#endif 256 } 257 break; 258 259 case RELOC_COPY: 260 { 261 sr = _dl_find_symbol(symn, 262 SYM_SEARCH_OTHER|SYM_WARNNOTFOUND|SYM_NOTPLT, 263 sym, object); 264 if (sr.sym) { 265 _dl_bcopy((void *)(sr.obj->obj_base + 266 sr.sym->st_value), pt, sym->st_size); 267#ifdef DEBUG 268 DL_DEB(("[%x]COPY: %s[%x]:%s -> %p[%x] in %s\n", 269 i, symn, sr.obj->obj_base + 270 sr.sym->st_value, object->load_name, 271 pt, sym->st_size, sr.obj->load_name)); 272#endif 273 } else 274 DL_DEB(("[%x]COPY: no sym\n", i)); 275 break; 276 } 277 default: 278 DL_DEB(("[%x]UNKNOWN(%d): type=%d off=0x%lx " 279 "addend=0x%lx rel=0x%x\n", i, type, 280 ELF_R_TYPE(rela->r_info), rela->r_offset, 281 rela->r_addend, *pt)); 282 break; 283 } 284 } 285 286 return fails; 287} 288 289extern void _dl_bind_start(void); 290 291#define PLT_STUB_SIZE (7 * 4) 292#define PLT_ENTRY_SIZE (2 * 4) 293#define PLT_STUB_GOTOFF (4 * 4) 294 295#define PLT_STUB_MAGIC1 0x00c0ffee 296#define PLT_STUB_MAGIC2 0xdeadbeef 297 298#define PLT_STUB_INSN1 0x0e801081 /* ldw 0(%r20), %r1 */ 299#define PLT_STUB_INSN2 0xe820c000 /* bv %r0(%r1) */ 300 301int 302_dl_md_reloc_got(elf_object_t *object, int lazy) 303{ 304 Elf_RelA *rela; 305 Elf_Addr ooff; 306 int i, numrela, fails = 0; 307 308 if (object->dyn.pltrel != DT_RELA) 309 return 0; 310 311 if (!lazy) { 312 fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ); 313 } else { 314 register Elf_Addr ltp __asm ("%r19"); 315 Elf_Addr *got = NULL; 316 317 rela = (Elf_RelA *)(object->dyn.jmprel); 318 numrela = object->dyn.pltrelsz / sizeof(Elf_RelA); 319 ooff = object->obj_base; 320 321 /* 322 * Find the PLT stub by looking at all the 323 * relocations. The PLT stub should be at the end of 324 * the .plt section so we start with the last 325 * relocation, since the linker should have emitted 326 * them in order. 327 */ 328 for (i = numrela - 1; i >= 0; i--) { 329 got = (Elf_Addr *)(ooff + rela[i].r_offset + 330 PLT_ENTRY_SIZE + PLT_STUB_SIZE); 331 if (got[-2] == PLT_STUB_MAGIC1 || 332 got[-1] == PLT_STUB_MAGIC2) 333 break; 334 got = NULL; 335 } 336 if (got == NULL) 337 return 1; 338 339 /* 340 * Patch up the PLT stub such that it doesn't clobber 341 * %r22, which is used to pass on the errno values 342 * from failed system calls to __cerrno() in libc. 343 */ 344 got[-7] = PLT_STUB_INSN1; 345 got[-6] = PLT_STUB_INSN2; 346 __asm volatile("fdc 0(%0)" :: "r" (&got[-7])); 347 __asm volatile("fdc 0(%0)" :: "r" (&got[-6])); 348 __asm volatile("sync"); 349 __asm volatile("fic 0(%%sr0,%0)" :: "r" (&got[-7])); 350 __asm volatile("fic 0(%%sr0,%0)" :: "r" (&got[-6])); 351 __asm volatile("sync"); 352 353 /* 354 * Fill in the PLT stub such that it invokes the 355 * _dl_bind_start() trampoline to fix up the 356 * relocation. 357 */ 358 got[1] = (Elf_Addr)object; 359 got[-2] = (Elf_Addr)&_dl_bind_start; 360 got[-1] = ltp; 361 /* 362 * We need the real address of the trampoline. Get it 363 * from the function descriptor if that's what we got. 364 */ 365 if (got[-2] & 2) { 366 hppa_plabel_t *p = (hppa_plabel_t *)(got[-2] & ~2); 367 got[-2] = p->pc; 368 } 369 /* 370 * Even though we didn't modify any instructions it 371 * seems we still need to synchronize the caches. 372 * There may be instructions in the same cache line 373 * and they end up being corrupted otherwise. 374 */ 375 __asm volatile("fdc 0(%0)" :: "r" (&got[-2])); 376 __asm volatile("fdc 0(%0)" :: "r" (&got[-1])); 377 __asm volatile("sync"); 378 __asm volatile("fic 0(%%sr0,%0)" :: "r" (&got[-2])); 379 __asm volatile("fic 0(%%sr0,%0)" :: "r" (&got[-1])); 380 __asm volatile("sync"); 381 for (i = 0; i < numrela; i++, rela++) { 382 Elf_Addr *r_addr = (Elf_Addr *)(ooff + rela->r_offset); 383 384 if (ELF_R_TYPE(rela->r_info) != RELOC_IPLT) { 385 _dl_printf("unexpected reloc 0x%x\n", 386 ELF_R_TYPE(rela->r_info)); 387 return 1; 388 } 389 390 if (ELF_R_SYM(rela->r_info)) { 391 r_addr[0] = (Elf_Addr)got - PLT_STUB_GOTOFF; 392 r_addr[1] = (Elf_Addr) (rela - 393 (Elf_RelA *)object->dyn.jmprel); 394 } else { 395 r_addr[0] = ooff + rela->r_addend; 396 r_addr[1] = (Elf_Addr)object->dyn.pltgot; 397 } 398 } 399 } 400 401 return fails; 402} 403 404/* 405 * Resolve a symbol at run-time. 406 */ 407uint64_t 408_dl_bind(elf_object_t *object, int reloff) 409{ 410 struct sym_res sr; 411 const Elf_Sym *sym; 412 const char *symn; 413 Elf_Addr value; 414 Elf_RelA *rela; 415 uint64_t cookie = pcookie; 416 struct { 417 struct __kbind param; 418 uint64_t newval; 419 } buf; 420 421 rela = (Elf_RelA *)object->dyn.jmprel + reloff; 422 423 sym = object->dyn.symtab; 424 sym += ELF_R_SYM(rela->r_info); 425 symn = object->dyn.strtab + sym->st_name; 426 427 sr = _dl_find_symbol(symn, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, 428 sym, object); 429 if (sr.sym == NULL) 430 _dl_die("lazy binding failed!"); 431 432 value = sr.obj->obj_base + sr.sym->st_value + rela->r_addend; 433 434 buf.newval = ((uint64_t)value << 32) | (Elf_Addr)sr.obj->dyn.pltgot; 435 436 if (__predict_false(sr.obj->traced) && _dl_trace_plt(sr.obj, symn)) 437 return buf.newval; 438 439 buf.param.kb_addr = (Elf_Addr *)(object->obj_base + rela->r_offset); 440 buf.param.kb_size = sizeof(uint64_t); 441 442 /* directly code the syscall, so that it's actually inline here */ 443 { 444 register long r1 __asm__("r1") = SYSCALLGATE; 445 register void *arg0 __asm__("r26") = &buf; 446 register long arg1 __asm__("r25") = sizeof(buf); 447 register long arg2 __asm__("r24") = 0xffffffff & (cookie >> 32); 448 register long arg3 __asm__("r23") = 0xffffffff & cookie; 449 __asm__ volatile ("ble 4(%%sr7, %%r1) ! ldi %0, %%r22" 450 : 451 : "i" (SYS_kbind), "r" (r1), "r"(arg0), "r"(arg1), 452 "r"(arg2), "r"(arg3) 453 : "r22", "r28", "r29", "cc", "memory"); 454 } 455 456 return buf.newval; 457} 458