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