1 /* $OpenBSD: rtld_machine.c,v 1.59 2016/06/21 15:25:37 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 1999 Dale Rahn 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 */ 28 29 #define _DYN_LOADER 30 31 #include <sys/types.h> 32 #include <sys/mman.h> 33 #include <sys/syscall.h> 34 #include <sys/unistd.h> 35 36 #include <nlist.h> 37 #include <link.h> 38 39 #include "syscall.h" 40 #include "archdep.h" 41 #include "resolve.h" 42 43 #define DT_PROC(n) ((n) - DT_LOPROC + DT_NUM) 44 45 void _dl_syncicache(char *from, size_t len); 46 47 int64_t pcookie __attribute__((section(".openbsd.randomdata"))) __dso_hidden; 48 49 /* relocation bits */ 50 #define HA(x) (((Elf_Addr)(x) >> 16) + (((Elf_Addr)(x) & 0x00008000) >> 15)) 51 #define L(x) (((Elf_Addr)x) & 0x0000ffff) 52 #define ADDIS_R11_R11 0x3d6b0000 53 #define ADDIS_R11_R0 0x3d600000 54 #define ADDI_R11_R11 0x396b0000 55 #define LWZ_R11_R11 0x816b0000 56 #define LI_R11 0x39600000 57 58 #define ADDIS_R12_R0 0x3d800000 59 #define ADDI_R12_R12 0x398c0000 60 #define MCTR_R11 0x7d6903a6 61 #define MCTR_R12 0x7d8903a6 62 #define BCTR 0x4e800420 63 #define BRVAL(from, to) \ 64 ((((Elf32_Addr)(to) - (Elf32_Addr)(&(from))) \ 65 & ~0xfc000000) | 0x48000000) 66 #define BR(from, to) ((from) = BRVAL(from, to)) 67 68 69 #define SLWI_R12_R11_1 0x556c083c 70 #define ADD_R11_R12_R11 0x7d6c5a14 71 72 /* these are structures/functions offset from PLT region */ 73 #define PLT_CALL_OFFSET 8 74 #define PLT_INFO_OFFSET 12 75 #define PLT_1STRELA_OFFSET 18 76 #define B24_VALID_RANGE(x) \ 77 ((((x) & 0xfe000000) == 0x00000000) || (((x) & 0xfe000000) == 0xfe000000)) 78 79 void _dl_bind_start(void); /* XXX */ 80 Elf_Addr _dl_bind(elf_object_t *object, int reloff); 81 82 int 83 _dl_md_reloc(elf_object_t *object, int rel, int relasz) 84 { 85 int i; 86 int numrela; 87 long relrel; 88 int fails = 0; 89 struct load_list *llist; 90 Elf32_Addr loff; 91 Elf32_Rela *relas; 92 /* for jmp table relocations */ 93 Elf32_Addr *pltresolve; 94 Elf32_Addr *pltcall; 95 Elf32_Addr *plttable; 96 Elf32_Addr *pltinfo; 97 Elf32_Addr *first_rela; 98 Elf32_Addr prev_value = 0, prev_ooff = 0; 99 const Elf32_Sym *prev_sym = NULL; 100 101 loff = object->obj_base; 102 numrela = object->Dyn.info[relasz] / sizeof(Elf32_Rela); 103 relrel = rel == DT_RELA ? object->relacount : 0; 104 relas = (Elf32_Rela *)(object->Dyn.info[rel]); 105 106 #ifdef DL_PRINTF_DEBUG 107 _dl_printf("object relocation size %x, numrela %x\n", 108 object->Dyn.info[relasz], numrela); 109 #endif 110 111 if (relas == NULL) 112 return(0); 113 114 if (relrel > numrela) { 115 _dl_printf("relcount > numrel: %ld > %ld\n", relrel, numrela); 116 _dl_exit(20); 117 } 118 119 pltresolve = NULL; 120 pltcall = NULL; 121 plttable = NULL; 122 123 /* for plt relocation usage */ 124 if (object->Dyn.info[DT_JMPREL] != 0 && 125 object->Dyn.info[DT_PROC(DT_PPC_GOT)] == 0) { 126 /* resolver stub not set up */ 127 int nplt; 128 129 /* Need to construct table to do jumps */ 130 pltresolve = (Elf32_Addr *)(object->Dyn.info[DT_PLTGOT]); 131 pltcall = (Elf32_Addr *)(pltresolve) + PLT_CALL_OFFSET; 132 pltinfo = (Elf32_Addr *)(pltresolve) + PLT_INFO_OFFSET; 133 first_rela = (Elf32_Addr *)(pltresolve) + PLT_1STRELA_OFFSET; 134 135 nplt = object->Dyn.info[DT_PLTRELSZ]/sizeof(Elf32_Rela); 136 137 if (nplt >= (2<<12)) { 138 plttable = (Elf32_Addr *) ((Elf32_Addr)first_rela) 139 + (2 * (2<<12)) + (4 * (nplt - (2<<12))); 140 } else { 141 plttable = (Elf32_Addr *) ((Elf32_Addr)first_rela) 142 + (2 * nplt); 143 } 144 145 pltinfo[0] = (Elf32_Addr)plttable; 146 147 #ifdef DL_PRINTF_DEBUG 148 _dl_printf("md_reloc: plttbl size %x\n", 149 (object->Dyn.info[DT_PLTRELSZ]/sizeof(Elf32_Rela))); 150 _dl_printf("md_reloc: plttable %x\n", plttable); 151 #endif 152 pltresolve[0] = SLWI_R12_R11_1; 153 pltresolve[1] = ADD_R11_R12_R11; 154 pltresolve[2] = ADDIS_R12_R0 | HA(_dl_bind_start); 155 pltresolve[3] = ADDI_R12_R12 | L(_dl_bind_start); 156 pltresolve[4] = MCTR_R12; 157 pltresolve[5] = ADDIS_R12_R0 | HA(object); 158 pltresolve[6] = ADDI_R12_R12 | L(object); 159 pltresolve[7] = BCTR; 160 _dl_dcbf(&pltresolve[0]); 161 _dl_dcbf(&pltresolve[7]); 162 163 /* addis r11,r11,.PLTtable@ha*/ 164 pltcall[0] = ADDIS_R11_R11 | HA(plttable); 165 /* lwz r11,plttable@l(r11) */ 166 pltcall[1] = LWZ_R11_R11 | L(plttable); 167 pltcall[2] = MCTR_R11; /* mtctr r11 */ 168 pltcall[3] = BCTR; /* bctr */ 169 _dl_dcbf(&pltcall[0]); 170 _dl_dcbf(&pltcall[3]); 171 } else { 172 first_rela = NULL; 173 } 174 175 /* 176 * Change protection of all write protected segments in the object 177 * so we can do relocations such as REL24, REL16 etc. After 178 * relocation restore protection. 179 */ 180 if ((object->dyn.textrel == 1) && (rel == DT_REL || rel == DT_RELA)) { 181 for (llist = object->load_list; llist != NULL; llist = llist->next) { 182 if (!(llist->prot & PROT_WRITE)) { 183 _dl_mprotect(llist->start, llist->size, 184 PROT_READ | PROT_WRITE); 185 } 186 } 187 } 188 189 /* tight loop for leading RELATIVE relocs */ 190 for (i = 0; i < relrel; i++, relas++) { 191 Elf_Addr *r_addr; 192 #ifdef DEBUG 193 const Elf32_Sym *sym; 194 195 if (ELF32_R_TYPE(relas->r_info) != RELOC_RELATIVE) { 196 _dl_printf("RELCOUNT wrong\n"); 197 _dl_exit(20); 198 } 199 sym = object->dyn.symtab; 200 sym += ELF32_R_SYM(relas->r_info); 201 if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || 202 (ELF32_ST_TYPE(sym->st_info) != STT_SECTION && 203 ELF32_ST_TYPE(sym->st_info) != STT_NOTYPE)) { 204 _dl_printf("RELATIVE relocation against symbol\n"); 205 _dl_exit(20); 206 } 207 #endif 208 r_addr = (Elf_Addr *)(relas->r_offset + loff); 209 *r_addr = loff + relas->r_addend; 210 } 211 for (; i < numrela; i++, relas++) { 212 Elf32_Addr *r_addr = (Elf32_Addr *)(relas->r_offset + loff); 213 Elf32_Addr ooff; 214 const Elf32_Sym *sym, *this; 215 const char *symn; 216 int type; 217 218 if (ELF32_R_SYM(relas->r_info) == 0xffffff) 219 continue; 220 221 type = ELF32_R_TYPE(relas->r_info); 222 223 if (type == RELOC_JMP_SLOT && rel != DT_JMPREL) 224 continue; 225 226 sym = object->dyn.symtab; 227 sym += ELF32_R_SYM(relas->r_info); 228 symn = object->dyn.strtab + sym->st_name; 229 230 ooff = 0; 231 this = NULL; 232 if (ELF32_R_SYM(relas->r_info) && 233 !(ELF32_ST_BIND(sym->st_info) == STB_LOCAL && 234 ELF32_ST_TYPE (sym->st_info) == STT_NOTYPE)) { 235 if (sym == prev_sym) { 236 this = sym; /* XXX any non-NULL */ 237 ooff = prev_ooff; 238 } else { 239 ooff = _dl_find_symbol_bysym(object, 240 ELF32_R_SYM(relas->r_info), &this, 241 SYM_SEARCH_ALL|SYM_WARNNOTFOUND| 242 ((type == RELOC_JMP_SLOT) ? 243 SYM_PLT:SYM_NOTPLT), sym, NULL); 244 245 if (this == NULL) { 246 if (ELF_ST_BIND(sym->st_info) != 247 STB_WEAK) 248 fails++; 249 continue; 250 } 251 prev_sym = sym; 252 prev_value = this->st_value; 253 prev_ooff = ooff; 254 } 255 } 256 257 /* 258 * For Secure-PLT, RELOC_JMP_SLOT simply sets PLT 259 * slots similarly to how RELOC_GLOB_DAT updates GOT 260 * slots. 261 */ 262 if (type == RELOC_JMP_SLOT && 263 object->Dyn.info[DT_PROC(DT_PPC_GOT)]) 264 type = RELOC_GLOB_DAT; 265 266 switch (type) { 267 case RELOC_32: 268 if (ELF32_ST_BIND(sym->st_info) == STB_LOCAL && 269 (ELF32_ST_TYPE(sym->st_info) == STT_SECTION || 270 ELF32_ST_TYPE(sym->st_info) == STT_NOTYPE) ) { 271 *r_addr = ooff + relas->r_addend; 272 } else { 273 *r_addr = ooff + prev_value + 274 relas->r_addend; 275 } 276 break; 277 case RELOC_RELATIVE: 278 if (ELF32_ST_BIND(sym->st_info) == STB_LOCAL && 279 (ELF32_ST_TYPE(sym->st_info) == STT_SECTION || 280 ELF32_ST_TYPE(sym->st_info) == STT_NOTYPE) ) { 281 *r_addr = loff + relas->r_addend; 282 283 #ifdef DL_PRINTF_DEBUG 284 _dl_printf("rel1 r_addr %x val %x loff %x ooff %x addend %x\n", r_addr, 285 loff + relas->r_addend, loff, ooff, relas->r_addend); 286 #endif 287 288 } else { 289 *r_addr = loff + prev_value + 290 relas->r_addend; 291 } 292 break; 293 case RELOC_JMP_SLOT: 294 { 295 Elf32_Addr target = ooff + prev_value + 296 relas->r_addend; 297 Elf32_Addr val = target - (Elf32_Addr)r_addr; 298 299 if (!B24_VALID_RANGE(val)){ 300 int index; 301 #ifdef DL_PRINTF_DEBUG 302 _dl_printf(" ooff %x, sym val %x, addend %x" 303 " r_addr %x symn [%s] -> %x\n", 304 ooff, prev_value, relas->r_addend, 305 r_addr, symn, val); 306 #endif 307 /* if offset is > RELOC_24 deal with it */ 308 index = (r_addr - first_rela) >> 1; 309 310 if (index >= (2 << 12)) { 311 /* addis r11,r11,.PLTtable@ha*/ 312 r_addr[0] = ADDIS_R11_R0 | HA(index*4); 313 r_addr[1] = ADDI_R11_R11 | L(index*4); 314 BR(r_addr[2], pltcall); 315 } else { 316 r_addr[0] = LI_R11 | (index * 4); 317 BR(r_addr[1], pltcall); 318 319 } 320 _dl_dcbf(&r_addr[0]); 321 _dl_dcbf(&r_addr[2]); 322 val= ooff + prev_value + 323 relas->r_addend; 324 #ifdef DL_PRINTF_DEBUG 325 _dl_printf(" symn [%s] val 0x%x\n", symn, val); 326 #endif 327 plttable[index] = val; 328 } else { 329 /* if the offset is small enough, 330 * branch directly to the dest 331 */ 332 BR(r_addr[0], target); 333 _dl_dcbf(&r_addr[0]); 334 } 335 } 336 337 break; 338 case RELOC_GLOB_DAT: 339 *r_addr = ooff + prev_value + relas->r_addend; 340 break; 341 #if 1 342 /* should not be supported ??? */ 343 case RELOC_REL24: 344 { 345 Elf32_Addr val = ooff + prev_value + 346 relas->r_addend - (Elf32_Addr)r_addr; 347 if (!B24_VALID_RANGE(val)){ 348 /* invalid offset */ 349 _dl_exit(20); 350 } 351 val &= ~0xfc000003; 352 val |= (*r_addr & 0xfc000003); 353 *r_addr = val; 354 355 _dl_dcbf(r_addr); 356 } 357 break; 358 #endif 359 #if 1 360 case RELOC_16_LO: 361 { 362 Elf32_Addr val; 363 364 val = loff + relas->r_addend; 365 *(Elf32_Half *)r_addr = val; 366 367 _dl_dcbf(r_addr); 368 } 369 break; 370 #endif 371 #if 1 372 case RELOC_16_HI: 373 { 374 Elf32_Addr val; 375 376 val = loff + relas->r_addend; 377 *(Elf32_Half *)r_addr = (val >> 16); 378 379 _dl_dcbf(r_addr); 380 } 381 break; 382 #endif 383 #if 1 384 case RELOC_16_HA: 385 { 386 Elf32_Addr val; 387 388 val = loff + relas->r_addend; 389 *(Elf32_Half *)r_addr = ((val + 0x8000) >> 16); 390 391 _dl_dcbf(r_addr); 392 } 393 break; 394 #endif 395 case RELOC_REL14_TAKEN: 396 /* val |= 1 << (31-10) XXX? */ 397 case RELOC_REL14: 398 case RELOC_REL14_NTAKEN: 399 { 400 Elf32_Addr val = ooff + prev_value + 401 relas->r_addend - (Elf32_Addr)r_addr; 402 if (((val & 0xffff8000) != 0) && 403 ((val & 0xffff8000) != 0xffff8000)) { 404 /* invalid offset */ 405 _dl_exit(20); 406 } 407 val &= ~0xffff0003; 408 val |= (*r_addr & 0xffff0003); 409 *r_addr = val; 410 #ifdef DL_PRINTF_DEBUG 411 _dl_printf("rel 14 %x val %x\n", r_addr, val); 412 #endif 413 414 _dl_dcbf(r_addr); 415 } 416 break; 417 case RELOC_COPY: 418 { 419 #ifdef DL_PRINTF_DEBUG 420 _dl_printf("copy r_addr %x, sym %x [%s] size %d val %x\n", 421 r_addr, sym, symn, sym->st_size, 422 (ooff + prev_value+ 423 relas->r_addend)); 424 #endif 425 /* 426 * we need to find a symbol, that is not in the current 427 * object, start looking at the beginning of the list, 428 * searching all objects but _not_ the current object, 429 * first one found wins. 430 */ 431 const Elf32_Sym *cpysrc = NULL; 432 Elf32_Addr src_loff; 433 int size; 434 435 src_loff = 0; 436 src_loff = _dl_find_symbol(symn, &cpysrc, 437 SYM_SEARCH_OTHER|SYM_WARNNOTFOUND| SYM_NOTPLT, 438 sym, object, NULL); 439 if (cpysrc != NULL) { 440 size = sym->st_size; 441 if (sym->st_size != cpysrc->st_size) { 442 _dl_printf("symbols size differ [%s] \n", 443 symn); 444 size = sym->st_size < cpysrc->st_size ? 445 sym->st_size : cpysrc->st_size; 446 } 447 #ifdef DL_PRINTF_DEBUG 448 _dl_printf(" found other symbol at %x size %d\n", 449 src_loff + cpysrc->st_value, cpysrc->st_size); 450 #endif 451 _dl_bcopy((void *)(src_loff + cpysrc->st_value), 452 r_addr, size); 453 } else 454 fails++; 455 } 456 break; 457 case RELOC_NONE: 458 break; 459 460 default: 461 _dl_printf("%s:" 462 " %s: unsupported relocation '%s' %d at %x\n", 463 __progname, object->load_name, symn, 464 ELF32_R_TYPE(relas->r_info), r_addr ); 465 _dl_exit(1); 466 } 467 } 468 469 /* reprotect the unprotected segments */ 470 if ((object->dyn.textrel == 1) && (rel == DT_REL || rel == DT_RELA)) { 471 for (llist = object->load_list; llist != NULL; llist = llist->next) { 472 if (!(llist->prot & PROT_WRITE)) 473 _dl_mprotect(llist->start, llist->size, 474 llist->prot); 475 } 476 } 477 return(fails); 478 } 479 480 void 481 _dl_setup_secure_plt(elf_object_t *object) 482 { 483 Elf32_Addr *got; 484 Elf32_Addr *plt; 485 int numplt, i; 486 487 /* Relocate processor-specific tags. */ 488 object->Dyn.info[DT_PROC(DT_PPC_GOT)] += object->obj_base; 489 490 got = (Elf32_Addr *) 491 (Elf32_Rela *)(object->Dyn.info[DT_PROC(DT_PPC_GOT)]); 492 got[1] = (Elf32_Addr)_dl_bind_start; 493 got[2] = (Elf32_Addr)object; 494 495 plt = (Elf32_Addr *) 496 (Elf32_Rela *)(object->Dyn.info[DT_PLTGOT]); 497 numplt = object->Dyn.info[DT_PLTRELSZ] / sizeof(Elf32_Rela); 498 for (i = 0; i < numplt; i++) 499 plt[i] += object->obj_base; 500 } 501 502 void 503 _dl_setup_bss_plt(elf_object_t *object) 504 { 505 Elf_Addr *pltresolve; 506 Elf_Addr *first_rela; 507 Elf_RelA *relas; 508 Elf32_Addr *r_addr; 509 int numrela, i; 510 int index; 511 512 first_rela = (Elf32_Addr *) 513 (((Elf32_Rela *)(object->Dyn.info[DT_JMPREL]))->r_offset + 514 object->obj_base); 515 pltresolve = (Elf32_Addr *)(first_rela) - 18; 516 517 relas = (Elf32_Rela *)(object->Dyn.info[DT_JMPREL]); 518 numrela = object->Dyn.info[DT_PLTRELSZ] / sizeof(Elf32_Rela); 519 r_addr = (Elf32_Addr *)(relas->r_offset + object->obj_base); 520 521 for (i = 0, index = 0; i < numrela; i++, r_addr+=2, index++) { 522 if (index >= (2 << 12)) { 523 /* addis r11,r0,.PLTtable@ha*/ 524 r_addr[0] = ADDIS_R11_R0 | HA(index*4); 525 r_addr[1] = ADDI_R11_R11 | L(index*4); 526 BR(r_addr[2], pltresolve); 527 /* only every other slot is used after 528 * index == 2^14 529 */ 530 r_addr += 2; 531 } else { 532 r_addr[0] = LI_R11 | (index * 4); 533 BR(r_addr[1], pltresolve); 534 } 535 _dl_dcbf(&r_addr[0]); 536 _dl_dcbf(&r_addr[2]); 537 } 538 } 539 540 /* 541 * Relocate the Global Offset Table (GOT). 542 * This is done by calling _dl_md_reloc on DT_JMPREL for DL_BIND_NOW, 543 * otherwise the lazy binding plt initialization is performed. 544 */ 545 int 546 _dl_md_reloc_got(elf_object_t *object, int lazy) 547 { 548 void *got_addr; 549 int fails = 0; 550 int prot_exec = 0; 551 552 if (object->Dyn.info[DT_PLTREL] != DT_RELA) 553 return (0); 554 555 /* 556 * For BSS-PLT, both the GOT and the PLT need to be 557 * executable. Yuck! 558 */ 559 if (object->Dyn.info[DT_PROC(DT_PPC_GOT)] == 0) 560 prot_exec = PROT_EXEC; 561 562 if (object->traced) 563 lazy = 1; 564 565 if (!lazy) { 566 fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ); 567 } else { 568 if (object->Dyn.info[DT_PROC(DT_PPC_GOT)]) 569 _dl_setup_secure_plt(object); 570 else 571 _dl_setup_bss_plt(object); 572 } 573 574 /* mprotect the GOT */ 575 got_addr = _dl_protect_segment(object, 0, "__got_start", "__got_end", 576 PROT_READ|prot_exec); 577 if (prot_exec != 0 && got_addr != NULL) 578 _dl_syncicache(got_addr, 4); 579 580 /* mprotect the PLT */ 581 _dl_protect_segment(object, 0, "__plt_start", "__plt_end", 582 PROT_READ|prot_exec); 583 584 return (fails); 585 } 586 587 Elf_Addr 588 _dl_bind(elf_object_t *object, int reloff) 589 { 590 const Elf_Sym *sym, *this; 591 Elf_Addr *r_addr, ooff; 592 const char *symn; 593 const elf_object_t *sobj; 594 Elf_Addr value; 595 Elf_RelA *relas; 596 Elf32_Addr val; 597 Elf32_Addr *pltresolve; 598 Elf32_Addr *pltcall; 599 Elf32_Addr *pltinfo; 600 Elf32_Addr *plttable; 601 int64_t cookie = pcookie; 602 struct { 603 struct __kbind param[2]; 604 Elf_Addr newval[2]; 605 } buf; 606 struct __kbind *param; 607 size_t psize; 608 609 relas = (Elf_RelA *)(object->Dyn.info[DT_JMPREL] + reloff); 610 611 sym = object->dyn.symtab; 612 sym += ELF_R_SYM(relas->r_info); 613 symn = object->dyn.strtab + sym->st_name; 614 615 this = NULL; 616 ooff = _dl_find_symbol(symn, &this, 617 SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, sym, object, &sobj); 618 if (this == NULL) { 619 _dl_printf("lazy binding failed!\n"); 620 *(volatile int *)0 = 0; /* XXX */ 621 } 622 623 value = ooff + this->st_value; 624 625 if (__predict_false(sobj->traced) && _dl_trace_plt(sobj, symn)) 626 return (value); 627 628 r_addr = (Elf_Addr *)(object->obj_base + relas->r_offset); 629 val = value - (Elf32_Addr)r_addr; 630 631 if (object->Dyn.info[DT_PROC(DT_PPC_GOT)] == 0) { 632 if (!B24_VALID_RANGE(val)) { 633 int index, addr_off; 634 635 /* if offset is > RELOC_24 deal with it */ 636 index = reloff / sizeof(Elf32_Rela); 637 638 pltresolve = (Elf32_Addr *) 639 (Elf32_Rela *)(object->Dyn.info[DT_PLTGOT]); 640 pltcall = (Elf32_Addr *)(pltresolve) + PLT_CALL_OFFSET; 641 642 /* 643 * Early plt entries can make short jumps; later ones 644 * use a 3 word sequence. c.f. _dl_md_reloc_got() 645 */ 646 addr_off = (index >= (2 << 12)) ? 2 : 1; 647 648 /* 649 * Update plttable before pltcall branch, to make 650 * this a safe race for threads 651 */ 652 pltinfo = (Elf32_Addr *)(pltresolve) + PLT_INFO_OFFSET; 653 plttable = (Elf32_Addr *)pltinfo[0]; 654 655 buf.param[0].kb_addr = &plttable[index]; 656 buf.param[0].kb_size = sizeof(Elf_Addr); 657 buf.param[1].kb_addr = &r_addr[addr_off]; 658 buf.param[1].kb_size = sizeof(Elf_Addr); 659 buf.newval[0] = value + relas->r_addend; 660 buf.newval[1] = BRVAL(r_addr[addr_off], pltcall); 661 param = &buf.param[0]; 662 psize = sizeof(buf); 663 } else { 664 /* 665 * If the offset is small enough, branch directly to 666 * the dest. We use the _second_ kbind params only. 667 */ 668 buf.param[1].kb_addr = &r_addr[0]; 669 buf.param[1].kb_size = sizeof(Elf_Addr); 670 buf.newval[0] = BRVAL(r_addr[0], value); 671 param = &buf.param[1]; 672 psize = sizeof(struct __kbind) + sizeof(Elf_Addr); 673 } 674 } else { 675 int index = reloff / sizeof(Elf32_Rela); 676 677 /* 678 * Secure PLT; only needs one update so use the 679 * second kbind params. 680 */ 681 plttable = (Elf32_Addr *) 682 (Elf32_Rela *)(object->Dyn.info[DT_PLTGOT]); 683 buf.param[1].kb_addr = &plttable[index]; 684 buf.param[1].kb_size = sizeof(Elf_Addr); 685 buf.newval[0] = value; 686 param = &buf.param[1]; 687 psize = sizeof(struct __kbind) + sizeof(Elf_Addr); 688 } 689 690 { 691 register long syscall_num __asm("r0") = SYS_kbind; 692 register void *arg1 __asm("r3") = param; 693 register long arg2 __asm("r4") = psize; 694 register long arg3 __asm("r5") = 0xffffffff & (cookie >> 32); 695 register long arg4 __asm("r6") = 0xffffffff & cookie; 696 697 __asm volatile("sc" : "+r" (syscall_num), "+r" (arg1), 698 "+r" (arg2) : "r" (arg3), "r" (arg4) : "cc", "memory"); 699 } 700 701 return (value); 702 } 703 704 /* should not be defined here, but it is 32 for all powerpc 603-G4 */ 705 #define CACHELINESIZE 32 706 void 707 _dl_syncicache(char *from, size_t len) 708 { 709 unsigned int off = 0; 710 int l = len + ((int)from & (CACHELINESIZE-1)); 711 712 while (off < l) { 713 asm volatile ("dcbst %1,%0" :: "r"(from), "r"(off)); 714 asm volatile ("sync"); 715 asm volatile ("icbi %1, %0" :: "r"(from), "r"(off)); 716 asm volatile ("sync"); 717 asm volatile ("isync"); 718 719 off += CACHELINESIZE; 720 } 721 } 722