1 /* $OpenBSD: rtld_machine.c,v 1.34 2016/08/27 22:52:21 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_exit(5); 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 i, numrela, fails = 0; 109 size_t size; 110 struct load_list *llist; 111 112 loff = object->obj_base; 113 numrela = object->Dyn.info[relasz] / sizeof(Elf_RelA); 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 * unprotect some segments if we need it. 152 */ 153 if ((object->dyn.textrel == 1) && (rel == DT_REL || rel == DT_RELA)) { 154 for (llist = object->load_list; llist != NULL; llist = llist->next) { 155 if (!(llist->prot & PROT_WRITE)) 156 _dl_mprotect(llist->start, llist->size, 157 PROT_READ|PROT_WRITE); 158 } 159 } 160 161 /* 162 * this is normally done by the crt0 code but we have to make 163 * sure it's set here to allow constructors to call functions 164 * that are overridden in the user binary (that are un-pic) 165 */ 166 if (object->obj_type == OBJTYPE_EXE) 167 _hppa_dl_set_dp(object->dyn.pltgot); 168 169 for (i = 0; i < numrela; i++, rela++) { 170 const elf_object_t *sobj; 171 const Elf_Sym *sym, *this; 172 Elf_Addr *pt, ooff; 173 const char *symn; 174 int type; 175 176 type = ELF_R_TYPE(rela->r_info); 177 if (type == RELOC_NONE) 178 continue; 179 180 sym = object->dyn.symtab + ELF_R_SYM(rela->r_info); 181 sobj = object; 182 symn = object->dyn.strtab + sym->st_name; 183 pt = (Elf_Addr *)(rela->r_offset + loff); 184 185 ooff = 0; 186 this = NULL; 187 if (ELF_R_SYM(rela->r_info) && sym->st_name) { 188 ooff = _dl_find_symbol_bysym(object, 189 ELF_R_SYM(rela->r_info), &this, 190 SYM_SEARCH_ALL|SYM_WARNNOTFOUND| 191 ((type == RELOC_IPLT) ? SYM_PLT: SYM_NOTPLT), 192 sym, &sobj); 193 if (this == NULL) { 194 if (ELF_ST_BIND(sym->st_info) != STB_WEAK) 195 fails++; 196 continue; 197 } 198 } 199 200 #ifdef DEBUG 201 DL_DEB(("*pt=%x r_addend=%x r_sym=%x\n", 202 *pt, rela->r_addend, ELF_R_SYM(rela->r_info))); 203 #endif 204 205 switch (type) { 206 case RELOC_DIR32: 207 if (ELF_R_SYM(rela->r_info) && sym->st_name) { 208 *pt = ooff + this->st_value + rela->r_addend; 209 #ifdef DEBUG 210 DL_DEB(("[%x]DIR32: %s:%s -> 0x%x in %s\n", 211 i, symn, object->load_name, 212 *pt, sobj->load_name)); 213 #endif 214 } else { 215 /* 216 * XXX should objects ever get their 217 * sections loaded insequential this 218 * would have to get a section number 219 * (ELF_R_SYM(rela->r_info))-1 and then: 220 * *pt = sect->addr + rela->r_addend; 221 */ 222 if (ELF_R_SYM(rela->r_info)) 223 *pt += loff; 224 else 225 *pt += loff + rela->r_addend; 226 #ifdef DEBUG 227 DL_DEB(("[%x]DIR32: %s @ 0x%x\n", i, 228 object->load_name, *pt)); 229 #endif 230 } 231 break; 232 233 case RELOC_PLABEL32: 234 if (ELF_R_SYM(rela->r_info)) { 235 if (ELF_ST_TYPE(this->st_info) != STT_FUNC) { 236 DL_DEB(("[%x]PLABEL32: bad\n", i)); 237 break; 238 } 239 *pt = _dl_md_plabel(sobj->obj_base + 240 this->st_value + rela->r_addend, 241 sobj->dyn.pltgot); 242 #ifdef DEBUG 243 DL_DEB(("[%x]PLABEL32: %s:%s -> 0x%x in %s\n", 244 i, symn, object->load_name, 245 *pt, sobj->load_name)); 246 #endif 247 } else { 248 *pt = loff + rela->r_addend; 249 #ifdef DEBUG 250 DL_DEB(("[%x]PLABEL32: %s @ 0x%x\n", i, 251 object->load_name, *pt)); 252 #endif 253 } 254 break; 255 256 case RELOC_IPLT: 257 if (ELF_R_SYM(rela->r_info)) { 258 pt[0] = ooff + this->st_value + rela->r_addend; 259 pt[1] = (Elf_Addr)sobj->dyn.pltgot; 260 #ifdef DEBUG 261 DL_DEB(("[%x]IPLT: %s:%s -> 0x%x:0x%x in %s\n", 262 i, symn, object->load_name, 263 pt[0], pt[1], sobj->load_name)); 264 #endif 265 } else { 266 pt[0] = loff + rela->r_addend; 267 pt[1] = (Elf_Addr)object->dyn.pltgot; 268 #ifdef DEBUG 269 DL_DEB(("[%x]IPLT: %s @ 0x%x:0x%x\n", i, 270 object->load_name, pt[0], pt[1])); 271 #endif 272 } 273 break; 274 275 case RELOC_COPY: 276 { 277 const Elf32_Sym *cpysrc = NULL; 278 size = sym->st_size; 279 ooff = _dl_find_symbol(symn, &cpysrc, 280 SYM_SEARCH_OTHER|SYM_WARNNOTFOUND|SYM_NOTPLT, 281 sym, object, NULL); 282 if (cpysrc) { 283 _dl_bcopy((void *)(ooff + cpysrc->st_value), 284 pt, sym->st_size); 285 #ifdef DEBUG 286 DL_DEB(("[%x]COPY: %s[%x]:%s -> %p[%x] in %s\n", 287 i, symn, ooff + cpysrc->st_value, 288 object->load_name, pt, sym->st_size, 289 sobj->load_name)); 290 #endif 291 } else 292 DL_DEB(("[%x]COPY: no sym\n", i)); 293 break; 294 } 295 default: 296 DL_DEB(("[%x]UNKNOWN(%d): type=%d off=0x%lx " 297 "addend=0x%lx rel=0x%x\n", i, type, 298 ELF_R_TYPE(rela->r_info), rela->r_offset, 299 rela->r_addend, *pt)); 300 break; 301 } 302 } 303 304 /* reprotect the unprotected segments */ 305 if ((object->dyn.textrel == 1) && (rel == DT_REL || rel == DT_RELA)) { 306 for (llist = object->load_list; llist != NULL; llist = llist->next) { 307 if (!(llist->prot & PROT_WRITE)) 308 _dl_mprotect(llist->start, llist->size, 309 llist->prot); 310 } 311 } 312 313 return (fails); 314 } 315 316 extern void _dl_bind_start(void); 317 318 #define PLT_STUB_SIZE (7 * 4) 319 #define PLT_ENTRY_SIZE (2 * 4) 320 #define PLT_STUB_GOTOFF (4 * 4) 321 322 #define PLT_STUB_MAGIC1 0x00c0ffee 323 #define PLT_STUB_MAGIC2 0xdeadbeef 324 325 #define PLT_STUB_INSN1 0x0e801081 /* ldw 0(%r20), %r1 */ 326 #define PLT_STUB_INSN2 0xe820c000 /* bv %r0(%r1) */ 327 328 int 329 _dl_md_reloc_got(elf_object_t *object, int lazy) 330 { 331 Elf_RelA *rela; 332 Elf_Addr ooff; 333 int i, numrela, fails = 0; 334 335 if (object->dyn.pltrel != DT_RELA) 336 return (0); 337 338 if (object->traced) 339 lazy = 1; 340 341 if (!lazy) { 342 fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ); 343 } else { 344 register Elf_Addr ltp __asm ("%r19"); 345 Elf_Addr *got = NULL; 346 347 rela = (Elf_RelA *)(object->dyn.jmprel); 348 numrela = object->dyn.pltrelsz / sizeof(Elf_RelA); 349 ooff = object->obj_base; 350 351 /* 352 * Find the PLT stub by looking at all the 353 * relocations. The PLT stub should be at the end of 354 * the .plt section so we start with the last 355 * relocation, since the linker should have emitted 356 * them in order. 357 */ 358 for (i = numrela - 1; i >= 0; i--) { 359 got = (Elf_Addr *)(ooff + rela[i].r_offset + 360 PLT_ENTRY_SIZE + PLT_STUB_SIZE); 361 if (got[-2] == PLT_STUB_MAGIC1 || 362 got[-1] == PLT_STUB_MAGIC2) 363 break; 364 got = NULL; 365 } 366 if (got == NULL) 367 return (1); 368 369 /* 370 * Patch up the PLT stub such that it doesn't clobber 371 * %r22, which is used to pass on the errno values 372 * from failed system calls to __cerrno() in libc. 373 */ 374 got[-7] = PLT_STUB_INSN1; 375 got[-6] = PLT_STUB_INSN2; 376 __asm volatile("fdc 0(%0)" :: "r" (&got[-7])); 377 __asm volatile("fdc 0(%0)" :: "r" (&got[-6])); 378 __asm volatile("sync"); 379 __asm volatile("fic 0(%%sr0,%0)" :: "r" (&got[-7])); 380 __asm volatile("fic 0(%%sr0,%0)" :: "r" (&got[-6])); 381 __asm volatile("sync"); 382 383 /* 384 * Fill in the PLT stub such that it invokes the 385 * _dl_bind_start() trampoline to fix up the 386 * relocation. 387 */ 388 got[1] = (Elf_Addr)object; 389 got[-2] = (Elf_Addr)&_dl_bind_start; 390 got[-1] = ltp; 391 /* 392 * We need the real address of the trampoline. Get it 393 * from the function descriptor if that's what we got. 394 */ 395 if (got[-2] & 2) { 396 hppa_plabel_t *p = (hppa_plabel_t *)(got[-2] & ~2); 397 got[-2] = p->pc; 398 } 399 /* 400 * Even though we didn't modify any instructions it 401 * seems we still need to synchronize the caches. 402 * There may be instructions in the same cache line 403 * and they end up being corrupted otherwise. 404 */ 405 __asm volatile("fdc 0(%0)" :: "r" (&got[-2])); 406 __asm volatile("fdc 0(%0)" :: "r" (&got[-1])); 407 __asm volatile("sync"); 408 __asm volatile("fic 0(%%sr0,%0)" :: "r" (&got[-2])); 409 __asm volatile("fic 0(%%sr0,%0)" :: "r" (&got[-1])); 410 __asm volatile("sync"); 411 for (i = 0; i < numrela; i++, rela++) { 412 Elf_Addr *r_addr = (Elf_Addr *)(ooff + rela->r_offset); 413 414 if (ELF_R_TYPE(rela->r_info) != RELOC_IPLT) { 415 _dl_printf("unexpected reloc 0x%x\n", 416 ELF_R_TYPE(rela->r_info)); 417 return (1); 418 } 419 420 if (ELF_R_SYM(rela->r_info)) { 421 r_addr[0] = (Elf_Addr)got - PLT_STUB_GOTOFF; 422 r_addr[1] = (Elf_Addr) (rela - 423 (Elf_RelA *)object->dyn.jmprel); 424 } else { 425 r_addr[0] = ooff + rela->r_addend; 426 r_addr[1] = (Elf_Addr)object->dyn.pltgot; 427 } 428 } 429 } 430 431 /* mprotect the GOT */ 432 _dl_protect_segment(object, 0, "__got_start", "__got_end", 433 GOT_PERMS|PROT_EXEC); 434 435 return (fails); 436 } 437 438 /* 439 * Resolve a symbol at run-time. 440 */ 441 uint64_t 442 _dl_bind(elf_object_t *object, int reloff) 443 { 444 const elf_object_t *sobj; 445 const Elf_Sym *sym, *this; 446 Elf_Addr ooff; 447 const char *symn; 448 Elf_Addr value; 449 Elf_RelA *rela; 450 uint64_t cookie = pcookie; 451 struct { 452 struct __kbind param; 453 uint64_t newval; 454 } buf; 455 456 rela = (Elf_RelA *)object->dyn.jmprel + reloff; 457 458 sym = object->dyn.symtab; 459 sym += ELF_R_SYM(rela->r_info); 460 symn = object->dyn.strtab + sym->st_name; 461 462 this = NULL; 463 ooff = _dl_find_symbol(symn, &this, 464 SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, sym, object, &sobj); 465 if (this == NULL) { 466 _dl_printf("lazy binding failed!\n"); 467 *(volatile int *)0 = 0; /* XXX */ 468 } 469 470 value = ooff + this->st_value + rela->r_addend; 471 472 buf.newval = ((uint64_t)value << 32) | (Elf_Addr)sobj->dyn.pltgot; 473 474 if (__predict_false(sobj->traced) && _dl_trace_plt(sobj, symn)) 475 return (buf.newval); 476 477 buf.param.kb_addr = (Elf_Addr *)(object->obj_base + rela->r_offset); 478 buf.param.kb_size = sizeof(uint64_t); 479 480 /* directly code the syscall, so that it's actually inline here */ 481 { 482 register long r1 __asm__("r1") = SYSCALLGATE; 483 register void *arg0 __asm__("r26") = &buf; 484 register long arg1 __asm__("r25") = sizeof(buf); 485 register long arg2 __asm__("r24") = 0xffffffff & (cookie >> 32); 486 register long arg3 __asm__("r23") = 0xffffffff & cookie; 487 __asm__ __volatile__ ("ble 4(%%sr7, %%r1) ! ldi %0, %%r22" 488 : 489 : "i" (SYS_kbind), "r" (r1), "r"(arg0), "r"(arg1), 490 "r"(arg2), "r"(arg3) 491 : "r22", "r28", "r29", "cc", "memory"); 492 } 493 494 return (buf.newval); 495 } 496