github.com/ccccaoqing/test@v0.0.0-20220510085219-3985d23445c0/src/cmd/5l/asm.c (about) 1 // Inferno utils/5l/asm.c 2 // http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c 3 // 4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) 6 // Portions Copyright © 1997-1999 Vita Nuova Limited 7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) 8 // Portions Copyright © 2004,2006 Bruce Ellis 9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) 10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others 11 // Portions Copyright © 2009 The Go Authors. All rights reserved. 12 // 13 // Permission is hereby granted, free of charge, to any person obtaining a copy 14 // of this software and associated documentation files (the "Software"), to deal 15 // in the Software without restriction, including without limitation the rights 16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 // copies of the Software, and to permit persons to whom the Software is 18 // furnished to do so, subject to the following conditions: 19 // 20 // The above copyright notice and this permission notice shall be included in 21 // all copies or substantial portions of the Software. 22 // 23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 // THE SOFTWARE. 30 31 // Writing object files. 32 33 #include "l.h" 34 #include "../ld/lib.h" 35 #include "../ld/elf.h" 36 #include "../ld/dwarf.h" 37 38 39 char linuxdynld[] = "/lib/ld-linux.so.3"; // 2 for OABI, 3 for EABI 40 char freebsddynld[] = "/usr/libexec/ld-elf.so.1"; 41 char openbsddynld[] = "XXX"; 42 char netbsddynld[] = "/libexec/ld.elf_so"; 43 char dragonflydynld[] = "XXX"; 44 char solarisdynld[] = "XXX"; 45 46 static int 47 needlib(char *name) 48 { 49 char *p; 50 LSym *s; 51 52 if(*name == '\0') 53 return 0; 54 55 /* reuse hash code in symbol table */ 56 p = smprint(".dynlib.%s", name); 57 s = linklookup(ctxt, p, 0); 58 free(p); 59 if(s->type == 0) { 60 s->type = 100; // avoid SDATA, etc. 61 return 1; 62 } 63 return 0; 64 } 65 66 int nelfsym = 1; 67 68 static void addpltsym(Link*, LSym*); 69 static void addgotsym(Link*, LSym*); 70 static void addgotsyminternal(Link*, LSym*); 71 72 // Preserve highest 8 bits of a, and do addition to lower 24-bit 73 // of a and b; used to adjust ARM branch intruction's target 74 static int32 75 braddoff(int32 a, int32 b) 76 { 77 return (((uint32)a) & 0xff000000U) | (0x00ffffffU & (uint32)(a + b)); 78 } 79 80 void 81 adddynrela(LSym *rel, LSym *s, Reloc *r) 82 { 83 addaddrplus(ctxt, rel, s, r->off); 84 adduint32(ctxt, rel, R_ARM_RELATIVE); 85 } 86 87 void 88 adddynrel(LSym *s, Reloc *r) 89 { 90 LSym *targ, *rel; 91 92 targ = r->sym; 93 ctxt->cursym = s; 94 95 switch(r->type) { 96 default: 97 if(r->type >= 256) { 98 diag("unexpected relocation type %d", r->type); 99 return; 100 } 101 break; 102 103 // Handle relocations found in ELF object files. 104 case 256 + R_ARM_PLT32: 105 r->type = R_CALLARM; 106 if(targ->type == SDYNIMPORT) { 107 addpltsym(ctxt, targ); 108 r->sym = linklookup(ctxt, ".plt", 0); 109 r->add = braddoff(r->add, targ->plt / 4); 110 } 111 return; 112 113 case 256 + R_ARM_THM_PC22: // R_ARM_THM_CALL 114 diag("R_ARM_THM_CALL, are you using -marm?"); 115 errorexit(); 116 return; 117 118 case 256 + R_ARM_GOT32: // R_ARM_GOT_BREL 119 if(targ->type != SDYNIMPORT) { 120 addgotsyminternal(ctxt, targ); 121 } else { 122 addgotsym(ctxt, targ); 123 } 124 r->type = R_CONST; // write r->add during relocsym 125 r->sym = S; 126 r->add += targ->got; 127 return; 128 129 case 256 + R_ARM_GOT_PREL: // GOT(S) + A - P 130 if(targ->type != SDYNIMPORT) { 131 addgotsyminternal(ctxt, targ); 132 } else { 133 addgotsym(ctxt, targ); 134 } 135 r->type = R_PCREL; 136 r->sym = linklookup(ctxt, ".got", 0); 137 r->add += targ->got + 4; 138 return; 139 140 case 256 + R_ARM_GOTOFF: // R_ARM_GOTOFF32 141 r->type = R_GOTOFF; 142 return; 143 144 case 256 + R_ARM_GOTPC: // R_ARM_BASE_PREL 145 r->type = R_PCREL; 146 r->sym = linklookup(ctxt, ".got", 0); 147 r->add += 4; 148 return; 149 150 case 256 + R_ARM_CALL: 151 r->type = R_CALLARM; 152 if(targ->type == SDYNIMPORT) { 153 addpltsym(ctxt, targ); 154 r->sym = linklookup(ctxt, ".plt", 0); 155 r->add = braddoff(r->add, targ->plt / 4); 156 } 157 return; 158 159 case 256 + R_ARM_REL32: // R_ARM_REL32 160 r->type = R_PCREL; 161 r->add += 4; 162 return; 163 164 case 256 + R_ARM_ABS32: 165 if(targ->type == SDYNIMPORT) 166 diag("unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ->name); 167 r->type = R_ADDR; 168 return; 169 170 case 256 + R_ARM_V4BX: 171 // we can just ignore this, because we are targeting ARM V5+ anyway 172 if(r->sym) { 173 // R_ARM_V4BX is ABS relocation, so this symbol is a dummy symbol, ignore it 174 r->sym->type = 0; 175 } 176 r->sym = S; 177 return; 178 179 case 256 + R_ARM_PC24: 180 case 256 + R_ARM_JUMP24: 181 r->type = R_CALLARM; 182 if(targ->type == SDYNIMPORT) { 183 addpltsym(ctxt, targ); 184 r->sym = linklookup(ctxt, ".plt", 0); 185 r->add = braddoff(r->add, targ->plt / 4); 186 } 187 return; 188 } 189 190 // Handle references to ELF symbols from our own object files. 191 if(targ->type != SDYNIMPORT) 192 return; 193 194 switch(r->type) { 195 case R_CALLARM: 196 addpltsym(ctxt, targ); 197 r->sym = linklookup(ctxt, ".plt", 0); 198 r->add = targ->plt; 199 return; 200 201 case R_ADDR: 202 if(s->type != SDATA) 203 break; 204 if(iself) { 205 adddynsym(ctxt, targ); 206 rel = linklookup(ctxt, ".rel", 0); 207 addaddrplus(ctxt, rel, s, r->off); 208 adduint32(ctxt, rel, ELF32_R_INFO(targ->dynid, R_ARM_GLOB_DAT)); // we need a S + A dynmic reloc 209 r->type = R_CONST; // write r->add during relocsym 210 r->sym = S; 211 return; 212 } 213 break; 214 } 215 216 ctxt->cursym = s; 217 diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type); 218 } 219 220 int 221 elfreloc1(Reloc *r, vlong sectoff) 222 { 223 int32 elfsym; 224 225 LPUT(sectoff); 226 227 elfsym = r->xsym->elfsym; 228 switch(r->type) { 229 default: 230 return -1; 231 232 case R_ADDR: 233 if(r->siz == 4) 234 LPUT(R_ARM_ABS32 | elfsym<<8); 235 else 236 return -1; 237 break; 238 239 case R_PCREL: 240 if(r->siz == 4) 241 LPUT(R_ARM_REL32 | elfsym<<8); 242 else 243 return -1; 244 break; 245 246 case R_CALLARM: 247 if(r->siz == 4) { 248 if((r->add & 0xff000000) == 0xeb000000) // BL 249 LPUT(R_ARM_CALL | elfsym<<8); 250 else 251 LPUT(R_ARM_JUMP24 | elfsym<<8); 252 } else 253 return -1; 254 break; 255 256 case R_TLS: 257 if(r->siz == 4) { 258 if(flag_shared) 259 LPUT(R_ARM_TLS_IE32 | elfsym<<8); 260 else 261 LPUT(R_ARM_TLS_LE32 | elfsym<<8); 262 } else 263 return -1; 264 break; 265 } 266 267 return 0; 268 } 269 270 void 271 elfsetupplt(void) 272 { 273 LSym *plt, *got; 274 275 plt = linklookup(ctxt, ".plt", 0); 276 got = linklookup(ctxt, ".got.plt", 0); 277 if(plt->size == 0) { 278 // str lr, [sp, #-4]! 279 adduint32(ctxt, plt, 0xe52de004); 280 // ldr lr, [pc, #4] 281 adduint32(ctxt, plt, 0xe59fe004); 282 // add lr, pc, lr 283 adduint32(ctxt, plt, 0xe08fe00e); 284 // ldr pc, [lr, #8]! 285 adduint32(ctxt, plt, 0xe5bef008); 286 // .word &GLOBAL_OFFSET_TABLE[0] - . 287 addpcrelplus(ctxt, plt, got, 4); 288 289 // the first .plt entry requires 3 .plt.got entries 290 adduint32(ctxt, got, 0); 291 adduint32(ctxt, got, 0); 292 adduint32(ctxt, got, 0); 293 } 294 } 295 296 int 297 machoreloc1(Reloc *r, vlong sectoff) 298 { 299 USED(r); 300 USED(sectoff); 301 302 return -1; 303 } 304 305 306 int 307 archreloc(Reloc *r, LSym *s, vlong *val) 308 { 309 LSym *rs; 310 311 if(linkmode == LinkExternal) { 312 switch(r->type) { 313 case R_CALLARM: 314 r->done = 0; 315 316 // set up addend for eventual relocation via outer symbol. 317 rs = r->sym; 318 r->xadd = r->add; 319 if(r->xadd & 0x800000) 320 r->xadd |= ~0xffffff; 321 r->xadd *= 4; 322 while(rs->outer != nil) { 323 r->xadd += symaddr(rs) - symaddr(rs->outer); 324 rs = rs->outer; 325 } 326 327 if(rs->type != SHOSTOBJ && rs->sect == nil) 328 diag("missing section for %s", rs->name); 329 r->xsym = rs; 330 331 *val = braddoff((0xff000000U & (uint32)r->add), 332 (0xffffff & (uint32)(r->xadd / 4))); 333 return 0; 334 } 335 return -1; 336 } 337 switch(r->type) { 338 case R_CONST: 339 *val = r->add; 340 return 0; 341 case R_GOTOFF: 342 *val = symaddr(r->sym) + r->add - symaddr(linklookup(ctxt, ".got", 0)); 343 return 0; 344 // The following three arch specific relocations are only for generation of 345 // Linux/ARM ELF's PLT entry (3 assembler instruction) 346 case R_PLT0: // add ip, pc, #0xXX00000 347 if (symaddr(linklookup(ctxt, ".got.plt", 0)) < symaddr(linklookup(ctxt, ".plt", 0))) 348 diag(".got.plt should be placed after .plt section."); 349 *val = 0xe28fc600U + 350 (0xff & ((uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add) >> 20)); 351 return 0; 352 case R_PLT1: // add ip, ip, #0xYY000 353 *val = 0xe28cca00U + 354 (0xff & ((uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add + 4) >> 12)); 355 return 0; 356 case R_PLT2: // ldr pc, [ip, #0xZZZ]! 357 *val = 0xe5bcf000U + 358 (0xfff & (uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add + 8)); 359 return 0; 360 case R_CALLARM: // bl XXXXXX or b YYYYYY 361 *val = braddoff((0xff000000U & (uint32)r->add), 362 (0xffffff & (uint32) 363 ((symaddr(r->sym) + ((uint32)r->add) * 4 - (s->value + r->off)) / 4))); 364 return 0; 365 } 366 return -1; 367 } 368 369 static Reloc * 370 addpltreloc(Link *ctxt, LSym *plt, LSym *got, LSym *sym, int typ) 371 { 372 Reloc *r; 373 374 r = addrel(plt); 375 r->sym = got; 376 r->off = plt->size; 377 r->siz = 4; 378 r->type = typ; 379 r->add = sym->got - 8; 380 381 plt->reachable = 1; 382 plt->size += 4; 383 symgrow(ctxt, plt, plt->size); 384 385 return r; 386 } 387 388 static void 389 addpltsym(Link *ctxt, LSym *s) 390 { 391 LSym *plt, *got, *rel; 392 393 if(s->plt >= 0) 394 return; 395 396 adddynsym(ctxt, s); 397 398 if(iself) { 399 plt = linklookup(ctxt, ".plt", 0); 400 got = linklookup(ctxt, ".got.plt", 0); 401 rel = linklookup(ctxt, ".rel.plt", 0); 402 if(plt->size == 0) 403 elfsetupplt(); 404 405 // .got entry 406 s->got = got->size; 407 // In theory, all GOT should point to the first PLT entry, 408 // Linux/ARM's dynamic linker will do that for us, but FreeBSD/ARM's 409 // dynamic linker won't, so we'd better do it ourselves. 410 addaddrplus(ctxt, got, plt, 0); 411 412 // .plt entry, this depends on the .got entry 413 s->plt = plt->size; 414 addpltreloc(ctxt, plt, got, s, R_PLT0); // add lr, pc, #0xXX00000 415 addpltreloc(ctxt, plt, got, s, R_PLT1); // add lr, lr, #0xYY000 416 addpltreloc(ctxt, plt, got, s, R_PLT2); // ldr pc, [lr, #0xZZZ]! 417 418 // rel 419 addaddrplus(ctxt, rel, got, s->got); 420 adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_ARM_JUMP_SLOT)); 421 } else { 422 diag("addpltsym: unsupported binary format"); 423 } 424 } 425 426 static void 427 addgotsyminternal(Link *ctxt, LSym *s) 428 { 429 LSym *got; 430 431 if(s->got >= 0) 432 return; 433 434 got = linklookup(ctxt, ".got", 0); 435 s->got = got->size; 436 437 addaddrplus(ctxt, got, s, 0); 438 439 if(iself) { 440 ; 441 } else { 442 diag("addgotsyminternal: unsupported binary format"); 443 } 444 } 445 446 static void 447 addgotsym(Link *ctxt, LSym *s) 448 { 449 LSym *got, *rel; 450 451 if(s->got >= 0) 452 return; 453 454 adddynsym(ctxt, s); 455 got = linklookup(ctxt, ".got", 0); 456 s->got = got->size; 457 adduint32(ctxt, got, 0); 458 459 if(iself) { 460 rel = linklookup(ctxt, ".rel", 0); 461 addaddrplus(ctxt, rel, got, s->got); 462 adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_ARM_GLOB_DAT)); 463 } else { 464 diag("addgotsym: unsupported binary format"); 465 } 466 } 467 468 void 469 adddynsym(Link *ctxt, LSym *s) 470 { 471 LSym *d; 472 int t; 473 char *name; 474 475 if(s->dynid >= 0) 476 return; 477 478 if(iself) { 479 s->dynid = nelfsym++; 480 481 d = linklookup(ctxt, ".dynsym", 0); 482 483 /* name */ 484 name = s->extname; 485 adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name)); 486 487 /* value */ 488 if(s->type == SDYNIMPORT) 489 adduint32(ctxt, d, 0); 490 else 491 addaddr(ctxt, d, s); 492 493 /* size */ 494 adduint32(ctxt, d, 0); 495 496 /* type */ 497 t = STB_GLOBAL << 4; 498 if((s->cgoexport & CgoExportDynamic) && (s->type&SMASK) == STEXT) 499 t |= STT_FUNC; 500 else 501 t |= STT_OBJECT; 502 adduint8(ctxt, d, t); 503 adduint8(ctxt, d, 0); 504 505 /* shndx */ 506 if(s->type == SDYNIMPORT) 507 adduint16(ctxt, d, SHN_UNDEF); 508 else { 509 switch(s->type) { 510 default: 511 case STEXT: 512 t = 11; 513 break; 514 case SRODATA: 515 t = 12; 516 break; 517 case SDATA: 518 t = 13; 519 break; 520 case SBSS: 521 t = 14; 522 break; 523 } 524 adduint16(ctxt, d, t); 525 } 526 } else { 527 diag("adddynsym: unsupported binary format"); 528 } 529 } 530 531 void 532 adddynlib(char *lib) 533 { 534 LSym *s; 535 536 if(!needlib(lib)) 537 return; 538 539 if(iself) { 540 s = linklookup(ctxt, ".dynstr", 0); 541 if(s->size == 0) 542 addstring(s, ""); 543 elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib)); 544 } else { 545 diag("adddynlib: unsupported binary format"); 546 } 547 } 548 549 void 550 asmb(void) 551 { 552 uint32 symo; 553 Section *sect; 554 LSym *sym; 555 int i; 556 557 if(debug['v']) 558 Bprint(&bso, "%5.2f asmb\n", cputime()); 559 Bflush(&bso); 560 561 if(iself) 562 asmbelfsetup(); 563 564 sect = segtext.sect; 565 cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); 566 codeblk(sect->vaddr, sect->len); 567 for(sect = sect->next; sect != nil; sect = sect->next) { 568 cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); 569 datblk(sect->vaddr, sect->len); 570 } 571 572 if(segrodata.filelen > 0) { 573 if(debug['v']) 574 Bprint(&bso, "%5.2f rodatblk\n", cputime()); 575 Bflush(&bso); 576 577 cseek(segrodata.fileoff); 578 datblk(segrodata.vaddr, segrodata.filelen); 579 } 580 581 if(debug['v']) 582 Bprint(&bso, "%5.2f datblk\n", cputime()); 583 Bflush(&bso); 584 585 cseek(segdata.fileoff); 586 datblk(segdata.vaddr, segdata.filelen); 587 588 /* output symbol table */ 589 symsize = 0; 590 lcsize = 0; 591 symo = 0; 592 if(!debug['s']) { 593 // TODO: rationalize 594 if(debug['v']) 595 Bprint(&bso, "%5.2f sym\n", cputime()); 596 Bflush(&bso); 597 switch(HEADTYPE) { 598 default: 599 if(iself) 600 goto ElfSym; 601 case Hplan9: 602 symo = segdata.fileoff+segdata.filelen; 603 break; 604 ElfSym: 605 symo = segdata.fileoff+segdata.filelen; 606 symo = rnd(symo, INITRND); 607 break; 608 } 609 cseek(symo); 610 switch(HEADTYPE) { 611 default: 612 if(iself) { 613 if(debug['v']) 614 Bprint(&bso, "%5.2f elfsym\n", cputime()); 615 asmelfsym(); 616 cflush(); 617 cwrite(elfstrdat, elfstrsize); 618 619 if(debug['v']) 620 Bprint(&bso, "%5.2f dwarf\n", cputime()); 621 dwarfemitdebugsections(); 622 623 if(linkmode == LinkExternal) 624 elfemitreloc(); 625 } 626 break; 627 case Hplan9: 628 asmplan9sym(); 629 cflush(); 630 631 sym = linklookup(ctxt, "pclntab", 0); 632 if(sym != nil) { 633 lcsize = sym->np; 634 for(i=0; i < lcsize; i++) 635 cput(sym->p[i]); 636 637 cflush(); 638 } 639 break; 640 } 641 } 642 643 ctxt->cursym = nil; 644 if(debug['v']) 645 Bprint(&bso, "%5.2f header\n", cputime()); 646 Bflush(&bso); 647 cseek(0L); 648 switch(HEADTYPE) { 649 default: 650 case Hplan9: /* plan 9 */ 651 LPUT(0x647); /* magic */ 652 LPUT(segtext.filelen); /* sizes */ 653 LPUT(segdata.filelen); 654 LPUT(segdata.len - segdata.filelen); 655 LPUT(symsize); /* nsyms */ 656 LPUT(entryvalue()); /* va of entry */ 657 LPUT(0L); 658 LPUT(lcsize); 659 break; 660 case Hlinux: 661 case Hfreebsd: 662 case Hnetbsd: 663 case Hopenbsd: 664 case Hnacl: 665 asmbelf(symo); 666 break; 667 } 668 cflush(); 669 if(debug['c']){ 670 print("textsize=%ulld\n", segtext.filelen); 671 print("datsize=%ulld\n", segdata.filelen); 672 print("bsssize=%ulld\n", segdata.len - segdata.filelen); 673 print("symsize=%d\n", symsize); 674 print("lcsize=%d\n", lcsize); 675 print("total=%lld\n", segtext.filelen+segdata.len+symsize+lcsize); 676 } 677 } 678 679 int32 680 rnd(int32 v, int32 r) 681 { 682 int32 c; 683 684 if(r <= 0) 685 return v; 686 v += r - 1; 687 c = v % r; 688 if(c < 0) 689 c += r; 690 v -= c; 691 return v; 692 }