1 /* $OpenBSD: rtld_machine.c,v 1.52 2014/07/05 17:06:18 miod 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 34 #include <nlist.h> 35 #include <link.h> 36 #include <signal.h> 37 38 #include "syscall.h" 39 #include "archdep.h" 40 #include "resolve.h" 41 42 void _dl_syncicache(char *from, size_t len); 43 44 /* relocation bits */ 45 #define HA(x) (((Elf_Addr)(x) >> 16) + (((Elf_Addr)(x) & 0x00008000) >> 15)) 46 #define L(x) (((Elf_Addr)x) & 0x0000ffff) 47 #define ADDIS_R11_R11 0x3d6b0000 48 #define ADDIS_R11_R0 0x3d600000 49 #define ADDI_R11_R11 0x396b0000 50 #define LWZ_R11_R11 0x816b0000 51 #define LI_R11 0x39600000 52 53 #define ADDIS_R12_R0 0x3d800000 54 #define ADDI_R12_R12 0x398c0000 55 #define MCTR_R11 0x7d6903a6 56 #define MCTR_R12 0x7d8903a6 57 #define BCTR 0x4e800420 58 #define BR(from, to) do { \ 59 int lval = (Elf32_Addr)(to) - (Elf32_Addr)(&(from)); \ 60 lval &= ~0xfc000000; \ 61 lval |= 0x48000000; \ 62 (from) = lval; \ 63 } while (0) 64 65 /* these are structures/functions offset from PLT region */ 66 #define PLT_CALL_OFFSET 6 67 #define PLT_INFO_OFFSET 10 68 #define PLT_1STRELA_OFFSET 18 69 #define B24_VALID_RANGE(x) \ 70 ((((x) & 0xfe000000) == 0x00000000) || (((x) & 0xfe000000) == 0xfe000000)) 71 72 void _dl_bind_start(void); /* XXX */ 73 Elf_Addr _dl_bind(elf_object_t *object, int reloff); 74 75 int 76 _dl_md_reloc(elf_object_t *object, int rel, int relasz) 77 { 78 int i; 79 int numrela; 80 long relrel; 81 int fails = 0; 82 struct load_list *llist; 83 Elf32_Addr loff; 84 Elf32_Rela *relas; 85 /* for jmp table relocations */ 86 Elf32_Addr *pltresolve; 87 Elf32_Addr *pltcall; 88 Elf32_Addr *plttable; 89 Elf32_Addr *pltinfo; 90 Elf32_Addr *first_rela; 91 92 loff = object->obj_base; 93 numrela = object->Dyn.info[relasz] / sizeof(Elf32_Rela); 94 relrel = rel == DT_RELA ? object->relacount : 0; 95 relas = (Elf32_Rela *)(object->Dyn.info[rel]); 96 97 #ifdef DL_PRINTF_DEBUG 98 _dl_printf("object relocation size %x, numrela %x\n", 99 object->Dyn.info[relasz], numrela); 100 #endif 101 102 if (relas == NULL) 103 return(0); 104 105 if (relrel > numrela) { 106 _dl_printf("relcount > numrel: %ld > %ld\n", relrel, numrela); 107 _dl_exit(20); 108 } 109 110 pltresolve = NULL; 111 pltcall = NULL; 112 plttable = NULL; 113 114 /* for plt relocation usage */ 115 if (object->Dyn.info[DT_JMPREL] != 0) { 116 /* resolver stub not set up */ 117 int nplt; 118 119 /* Need to construct table to do jumps */ 120 pltresolve = (Elf32_Addr *)(object->Dyn.info[DT_PLTGOT]); 121 pltcall = (Elf32_Addr *)(pltresolve) + PLT_CALL_OFFSET; 122 pltinfo = (Elf32_Addr *)(pltresolve) + PLT_INFO_OFFSET; 123 first_rela = (Elf32_Addr *)(pltresolve) + PLT_1STRELA_OFFSET; 124 125 nplt = object->Dyn.info[DT_PLTRELSZ]/sizeof(Elf32_Rela); 126 127 if (nplt >= (2<<12)) { 128 plttable = (Elf32_Addr *) ((Elf32_Addr)first_rela) 129 + (2 * (2<<12)) + (4 * (nplt - (2<<12))); 130 } else { 131 plttable = (Elf32_Addr *) ((Elf32_Addr)first_rela) 132 + (2 * nplt); 133 } 134 135 pltinfo[0] = (Elf32_Addr)plttable; 136 137 #ifdef DL_PRINTF_DEBUG 138 _dl_printf("md_reloc: plttbl size %x\n", 139 (object->Dyn.info[DT_PLTRELSZ]/sizeof(Elf32_Rela))); 140 _dl_printf("md_reloc: plttable %x\n", plttable); 141 #endif 142 pltresolve[0] = ADDIS_R12_R0 | HA(_dl_bind_start); 143 pltresolve[1] = ADDI_R12_R12 | L(_dl_bind_start); 144 pltresolve[2] = MCTR_R12; 145 pltresolve[3] = ADDIS_R12_R0 | HA(object); 146 pltresolve[4] = ADDI_R12_R12 | L(object); 147 pltresolve[5] = BCTR; 148 _dl_dcbf(&pltresolve[0]); 149 _dl_dcbf(&pltresolve[5]); 150 151 /* addis r11,r11,.PLTtable@ha*/ 152 pltcall[0] = ADDIS_R11_R11 | HA(plttable); 153 /* lwz r11,plttable@l(r11) */ 154 pltcall[1] = LWZ_R11_R11 | L(plttable); 155 pltcall[2] = MCTR_R11; /* mtctr r11 */ 156 pltcall[3] = BCTR; /* bctr */ 157 _dl_dcbf(&pltcall[0]); 158 _dl_dcbf(&pltcall[3]); 159 } else { 160 first_rela = NULL; 161 } 162 163 /* 164 * Change protection of all write protected segments in the object 165 * so we can do relocations such as REL24, REL16 etc. After 166 * relocation restore protection. 167 */ 168 if ((object->dyn.textrel == 1) && (rel == DT_REL || rel == DT_RELA)) { 169 for (llist = object->load_list; llist != NULL; llist = llist->next) { 170 if (!(llist->prot & PROT_WRITE)) { 171 _dl_mprotect(llist->start, llist->size, 172 llist->prot|PROT_WRITE); 173 } 174 } 175 } 176 177 /* tight loop for leading RELATIVE relocs */ 178 for (i = 0; i < relrel; i++, relas++) { 179 Elf_Addr *r_addr; 180 #ifdef DEBUG 181 const Elf32_Sym *sym; 182 183 if (ELF32_R_TYPE(relas->r_info) != RELOC_RELATIVE) { 184 _dl_printf("RELCOUNT wrong\n"); 185 _dl_exit(20); 186 } 187 sym = object->dyn.symtab; 188 sym += ELF32_R_SYM(relas->r_info); 189 if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || 190 (ELF32_ST_TYPE(sym->st_info) != STT_SECTION && 191 ELF32_ST_TYPE(sym->st_info) != STT_NOTYPE)) { 192 _dl_printf("RELATIVE relocation against symbol\n"); 193 _dl_exit(20); 194 } 195 #endif 196 r_addr = (Elf_Addr *)(relas->r_offset + loff); 197 *r_addr = loff + relas->r_addend; 198 } 199 for (; i < numrela; i++, relas++) { 200 Elf32_Addr *r_addr = (Elf32_Addr *)(relas->r_offset + loff); 201 Elf32_Addr ooff; 202 const Elf32_Sym *sym, *this; 203 const char *symn; 204 int type; 205 Elf32_Addr prev_value = 0, prev_ooff = 0; 206 const Elf32_Sym *prev_sym = NULL; 207 208 if (ELF32_R_SYM(relas->r_info) == 0xffffff) 209 continue; 210 211 type = ELF32_R_TYPE(relas->r_info); 212 213 if (type == RELOC_JMP_SLOT && rel != DT_JMPREL) 214 continue; 215 216 sym = object->dyn.symtab; 217 sym += ELF32_R_SYM(relas->r_info); 218 symn = object->dyn.strtab + sym->st_name; 219 220 ooff = 0; 221 this = NULL; 222 if (ELF32_R_SYM(relas->r_info) && 223 !(ELF32_ST_BIND(sym->st_info) == STB_LOCAL && 224 ELF32_ST_TYPE (sym->st_info) == STT_NOTYPE)) { 225 if (sym == prev_sym) { 226 this = sym; /* XXX any non-NULL */ 227 ooff = prev_ooff; 228 } else { 229 ooff = _dl_find_symbol_bysym(object, 230 ELF32_R_SYM(relas->r_info), &this, 231 SYM_SEARCH_ALL|SYM_WARNNOTFOUND| 232 ((type == RELOC_JMP_SLOT) ? 233 SYM_PLT:SYM_NOTPLT), sym, NULL); 234 235 if (this == NULL) { 236 if (ELF_ST_BIND(sym->st_info) != 237 STB_WEAK) 238 fails++; 239 continue; 240 } 241 prev_sym = sym; 242 prev_value = this->st_value; 243 prev_ooff = ooff; 244 } 245 } 246 247 switch (type) { 248 #if 1 249 case RELOC_32: 250 if (ELF32_ST_BIND(sym->st_info) == STB_LOCAL && 251 (ELF32_ST_TYPE(sym->st_info) == STT_SECTION || 252 ELF32_ST_TYPE(sym->st_info) == STT_NOTYPE) ) { 253 *r_addr = ooff + relas->r_addend; 254 } else { 255 *r_addr = ooff + prev_value + 256 relas->r_addend; 257 } 258 break; 259 #endif 260 case RELOC_RELATIVE: 261 if (ELF32_ST_BIND(sym->st_info) == STB_LOCAL && 262 (ELF32_ST_TYPE(sym->st_info) == STT_SECTION || 263 ELF32_ST_TYPE(sym->st_info) == STT_NOTYPE) ) { 264 *r_addr = loff + relas->r_addend; 265 266 #ifdef DL_PRINTF_DEBUG 267 _dl_printf("rel1 r_addr %x val %x loff %x ooff %x addend %x\n", r_addr, 268 loff + relas->r_addend, loff, ooff, relas->r_addend); 269 #endif 270 271 } else { 272 *r_addr = loff + prev_value + 273 relas->r_addend; 274 } 275 break; 276 case RELOC_JMP_SLOT: 277 { 278 Elf32_Addr target = ooff + prev_value + 279 relas->r_addend; 280 Elf32_Addr val = target - (Elf32_Addr)r_addr; 281 282 if (!B24_VALID_RANGE(val)){ 283 int index; 284 #ifdef DL_PRINTF_DEBUG 285 _dl_printf(" ooff %x, sym val %x, addend %x" 286 " r_addr %x symn [%s] -> %x\n", 287 ooff, prev_value, relas->r_addend, 288 r_addr, symn, val); 289 #endif 290 /* if offset is > RELOC_24 deal with it */ 291 index = (r_addr - first_rela) >> 1; 292 293 if (index >= (2 << 12)) { 294 /* addis r11,r11,.PLTtable@ha*/ 295 r_addr[0] = ADDIS_R11_R0 | HA(index*4); 296 r_addr[1] = ADDI_R11_R11 | L(index*4); 297 BR(r_addr[2], pltcall); 298 } else { 299 r_addr[0] = LI_R11 | (index * 4); 300 BR(r_addr[1], pltcall); 301 302 } 303 _dl_dcbf(&r_addr[0]); 304 _dl_dcbf(&r_addr[2]); 305 val= ooff + prev_value + 306 relas->r_addend; 307 #ifdef DL_PRINTF_DEBUG 308 _dl_printf(" symn [%s] val 0x%x\n", symn, val); 309 #endif 310 plttable[index] = val; 311 } else { 312 /* if the offset is small enough, 313 * branch directly to the dest 314 */ 315 BR(r_addr[0], target); 316 _dl_dcbf(&r_addr[0]); 317 } 318 } 319 320 break; 321 case RELOC_GLOB_DAT: 322 *r_addr = ooff + prev_value + relas->r_addend; 323 break; 324 #if 1 325 /* should not be supported ??? */ 326 case RELOC_REL24: 327 { 328 Elf32_Addr val = ooff + prev_value + 329 relas->r_addend - (Elf32_Addr)r_addr; 330 if (!B24_VALID_RANGE(val)){ 331 /* invalid offset */ 332 _dl_exit(20); 333 } 334 val &= ~0xfc000003; 335 val |= (*r_addr & 0xfc000003); 336 *r_addr = val; 337 338 _dl_dcbf(r_addr); 339 } 340 break; 341 #endif 342 #if 1 343 case RELOC_16_LO: 344 { 345 Elf32_Addr val; 346 347 val = loff + relas->r_addend; 348 *(Elf32_Half *)r_addr = val; 349 350 _dl_dcbf(r_addr); 351 } 352 break; 353 #endif 354 #if 1 355 case RELOC_16_HI: 356 { 357 Elf32_Addr val; 358 359 val = loff + relas->r_addend; 360 *(Elf32_Half *)r_addr = (val >> 16); 361 362 _dl_dcbf(r_addr); 363 } 364 break; 365 #endif 366 #if 1 367 case RELOC_16_HA: 368 { 369 Elf32_Addr val; 370 371 val = loff + relas->r_addend; 372 *(Elf32_Half *)r_addr = ((val + 0x8000) >> 16); 373 374 _dl_dcbf(r_addr); 375 } 376 break; 377 #endif 378 case RELOC_REL14_TAKEN: 379 /* val |= 1 << (31-10) XXX? */ 380 case RELOC_REL14: 381 case RELOC_REL14_NTAKEN: 382 { 383 Elf32_Addr val = ooff + prev_value + 384 relas->r_addend - (Elf32_Addr)r_addr; 385 if (((val & 0xffff8000) != 0) && 386 ((val & 0xffff8000) != 0xffff8000)) { 387 /* invalid offset */ 388 _dl_exit(20); 389 } 390 val &= ~0xffff0003; 391 val |= (*r_addr & 0xffff0003); 392 *r_addr = val; 393 #ifdef DL_PRINTF_DEBUG 394 _dl_printf("rel 14 %x val %x\n", r_addr, val); 395 #endif 396 397 _dl_dcbf(r_addr); 398 } 399 break; 400 case RELOC_COPY: 401 { 402 #ifdef DL_PRINTF_DEBUG 403 _dl_printf("copy r_addr %x, sym %x [%s] size %d val %x\n", 404 r_addr, sym, symn, sym->st_size, 405 (ooff + prev_value+ 406 relas->r_addend)); 407 #endif 408 /* 409 * we need to find a symbol, that is not in the current 410 * object, start looking at the beginning of the list, 411 * searching all objects but _not_ the current object, 412 * first one found wins. 413 */ 414 const Elf32_Sym *cpysrc = NULL; 415 Elf32_Addr src_loff; 416 int size; 417 418 src_loff = 0; 419 src_loff = _dl_find_symbol(symn, &cpysrc, 420 SYM_SEARCH_OTHER|SYM_WARNNOTFOUND| SYM_NOTPLT, 421 sym, object, NULL); 422 if (cpysrc != NULL) { 423 size = sym->st_size; 424 if (sym->st_size != cpysrc->st_size) { 425 _dl_printf("symbols size differ [%s] \n", 426 symn); 427 size = sym->st_size < cpysrc->st_size ? 428 sym->st_size : cpysrc->st_size; 429 } 430 #ifdef DL_PRINTF_DEBUG 431 _dl_printf(" found other symbol at %x size %d\n", 432 src_loff + cpysrc->st_value, cpysrc->st_size); 433 #endif 434 _dl_bcopy((void *)(src_loff + cpysrc->st_value), 435 r_addr, size); 436 } else 437 fails++; 438 } 439 break; 440 case RELOC_NONE: 441 break; 442 443 default: 444 _dl_printf("%s:" 445 " %s: unsupported relocation '%s' %d at %x\n", 446 _dl_progname, object->load_name, symn, 447 ELF32_R_TYPE(relas->r_info), r_addr ); 448 _dl_exit(1); 449 } 450 } 451 452 /* reprotect the unprotected segments */ 453 if ((object->dyn.textrel == 1) && (rel == DT_REL || rel == DT_RELA)) { 454 for (llist = object->load_list; llist != NULL; llist = llist->next) { 455 if (!(llist->prot & PROT_WRITE)) 456 _dl_mprotect(llist->start, llist->size, 457 llist->prot); 458 } 459 } 460 return(fails); 461 } 462 463 /* 464 * Relocate the Global Offset Table (GOT). 465 * This is done by calling _dl_md_reloc on DT_JMPREL for DL_BIND_NOW, 466 * otherwise the lazy binding plt initialization is performed. 467 */ 468 int 469 _dl_md_reloc_got(elf_object_t *object, int lazy) 470 { 471 Elf_Addr *pltresolve; 472 Elf_Addr *first_rela; 473 Elf_RelA *relas; 474 Elf_Addr plt_addr; 475 int i; 476 int numrela; 477 int fails = 0; 478 int index; 479 Elf32_Addr *r_addr; 480 Elf_Addr ooff; 481 const Elf_Sym *this; 482 483 if (object->Dyn.info[DT_PLTREL] != DT_RELA) 484 return (0); 485 486 object->got_addr = 0; 487 object->got_size = 0; 488 this = NULL; 489 ooff = _dl_find_symbol("__got_start", &this, 490 SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, 491 object, NULL); 492 if (this != NULL) 493 object->got_addr = ooff + this->st_value; 494 495 this = NULL; 496 ooff = _dl_find_symbol("__got_end", &this, 497 SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, 498 object, NULL); 499 if (this != NULL) 500 object->got_size = ooff + this->st_value - object->got_addr; 501 502 plt_addr = 0; 503 object->plt_size = 0; 504 this = NULL; 505 ooff = _dl_find_symbol("__plt_start", &this, 506 SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, 507 object, NULL); 508 if (this != NULL) 509 plt_addr = ooff + this->st_value; 510 511 this = NULL; 512 ooff = _dl_find_symbol("__plt_end", &this, 513 SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, 514 object, NULL); 515 if (this != NULL) 516 object->plt_size = ooff + this->st_value - plt_addr; 517 518 if (object->got_addr == 0) 519 object->got_start = 0; 520 else { 521 object->got_start = ELF_TRUNC(object->got_addr, _dl_pagesz); 522 object->got_size += object->got_addr - object->got_start; 523 object->got_size = ELF_ROUND(object->got_size, _dl_pagesz); 524 } 525 if (plt_addr == 0) 526 object->plt_start = 0; 527 else { 528 object->plt_start = ELF_TRUNC(plt_addr, _dl_pagesz); 529 object->plt_size += plt_addr - object->plt_start; 530 object->plt_size = ELF_ROUND(object->plt_size, _dl_pagesz); 531 } 532 533 if (object->traced) 534 lazy = 1; 535 536 if (!lazy) { 537 fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ); 538 } else { 539 first_rela = (Elf32_Addr *) 540 (((Elf32_Rela *)(object->Dyn.info[DT_JMPREL]))->r_offset + 541 object->obj_base); 542 pltresolve = (Elf32_Addr *)(first_rela) - 18; 543 544 relas = (Elf32_Rela *)(object->Dyn.info[DT_JMPREL]); 545 numrela = object->Dyn.info[DT_PLTRELSZ] / sizeof(Elf32_Rela); 546 r_addr = (Elf32_Addr *)(relas->r_offset + object->obj_base); 547 548 for (i = 0, index = 0; i < numrela; i++, r_addr+=2, index++) { 549 if (index >= (2 << 12)) { 550 /* addis r11,r0,.PLTtable@ha*/ 551 r_addr[0] = ADDIS_R11_R0 | HA(index*4); 552 r_addr[1] = ADDI_R11_R11 | L(index*4); 553 BR(r_addr[2], pltresolve); 554 /* only every other slot is used after 555 * index == 2^14 556 */ 557 r_addr += 2; 558 } else { 559 r_addr[0] = LI_R11 | (index * 4); 560 BR(r_addr[1], pltresolve); 561 } 562 _dl_dcbf(&r_addr[0]); 563 _dl_dcbf(&r_addr[2]); 564 } 565 } 566 if (object->got_size != 0) { 567 568 _dl_mprotect((void*)object->got_start, object->got_size, 569 PROT_READ|PROT_EXEC); /* only PPC is PROT_EXE */ 570 _dl_syncicache((void*)object->got_addr, 4); 571 } 572 if (object->plt_size != 0) 573 _dl_mprotect((void*)object->plt_start, object->plt_size, 574 PROT_READ|PROT_EXEC); 575 576 return (fails); 577 } 578 579 Elf_Addr 580 _dl_bind(elf_object_t *object, int reloff) 581 { 582 const Elf_Sym *sym, *this; 583 Elf_Addr *r_addr, ooff; 584 const char *symn; 585 const elf_object_t *sobj; 586 Elf_Addr value; 587 Elf_RelA *relas; 588 Elf32_Addr val; 589 Elf32_Addr *pltresolve; 590 Elf32_Addr *pltcall; 591 Elf32_Addr *pltinfo; 592 Elf32_Addr *plttable; 593 sigset_t savedmask; 594 595 relas = ((Elf_RelA *)object->Dyn.info[DT_JMPREL]) + (reloff>>2); 596 597 sym = object->dyn.symtab; 598 sym += ELF_R_SYM(relas->r_info); 599 symn = object->dyn.strtab + sym->st_name; 600 601 r_addr = (Elf_Addr *)(object->obj_base + relas->r_offset); 602 this = NULL; 603 ooff = _dl_find_symbol(symn, &this, 604 SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, sym, object, &sobj); 605 if (this == NULL) { 606 _dl_printf("lazy binding failed!\n"); 607 *(volatile int *)0 = 0; /* XXX */ 608 } 609 610 value = ooff + this->st_value; 611 612 if (sobj->traced && _dl_trace_plt(sobj, symn)) 613 return value; 614 615 /* if PLT is protected, allow the write */ 616 if (object->plt_size != 0) { 617 _dl_thread_bind_lock(0, &savedmask); 618 _dl_mprotect((void*)object->plt_start, object->plt_size, 619 PROT_READ|PROT_WRITE|PROT_EXEC); 620 } 621 622 val = value - (Elf32_Addr)r_addr; 623 624 pltresolve = (Elf32_Addr *) 625 (Elf32_Rela *)(object->Dyn.info[DT_PLTGOT]); 626 pltcall = (Elf32_Addr *)(pltresolve) + PLT_CALL_OFFSET; 627 628 if (!B24_VALID_RANGE(val)) { 629 int index; 630 /* if offset is > RELOC_24 deal with it */ 631 index = reloff >> 2; 632 633 /* update plttable before pltcall branch, to make 634 * this a safe race for threads 635 */ 636 val = ooff + this->st_value + relas->r_addend; 637 638 pltinfo = (Elf32_Addr *)(pltresolve) + PLT_INFO_OFFSET; 639 plttable = (Elf32_Addr *)pltinfo[0]; 640 plttable[index] = val; 641 642 if (index >= (2 << 12)) { 643 /* r_addr[0,1] is initialized to correct 644 * value in reloc_got. 645 */ 646 BR(r_addr[2], pltcall); 647 _dl_dcbf(&r_addr[2]); 648 } else { 649 /* r_addr[0] is initialized to correct 650 * value in reloc_got. 651 */ 652 BR(r_addr[1], pltcall); 653 _dl_dcbf(&r_addr[1]); 654 } 655 } else { 656 /* if the offset is small enough, 657 * branch directly to the dest 658 */ 659 BR(r_addr[0], value); 660 _dl_dcbf(&r_addr[0]); 661 } 662 663 /* if PLT is to be protected, change back to RO/X */ 664 if (object->plt_size != 0) { 665 _dl_mprotect((void*)object->plt_start, object->plt_size, 666 PROT_READ|PROT_EXEC); /* only PPC is PROT_EXE */ 667 _dl_thread_bind_lock(1, &savedmask); 668 } 669 return (value); 670 } 671 672 /* should not be defined here, but it is 32 for all powerpc 603-G4 */ 673 #define CACHELINESIZE 32 674 void 675 _dl_syncicache(char *from, size_t len) 676 { 677 unsigned int off = 0; 678 int l = len + ((int)from & (CACHELINESIZE-1)); 679 680 while (off < l) { 681 asm volatile ("dcbst %1,%0" :: "r"(from), "r"(off)); 682 asm volatile ("sync"); 683 asm volatile ("icbi %1, %0" :: "r"(from), "r"(off)); 684 asm volatile ("sync"); 685 asm volatile ("isync"); 686 687 off += CACHELINESIZE; 688 } 689 } 690