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