github.com/golang-haiku/go-1.4.3@v0.0.0-20190609233734-1f5ae41cc308/src/cmd/8l/asm.c (about) 1 // Inferno utils/8l/asm.c 2 // http://code.google.com/p/inferno-os/source/browse/utils/8l/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 #include "../ld/macho.h" 38 #include "../ld/pe.h" 39 40 char linuxdynld[] = "/lib/ld-linux.so.2"; 41 char freebsddynld[] = "/usr/libexec/ld-elf.so.1"; 42 char haikudynld[] = "/system/runtime_loader"; 43 char openbsddynld[] = "/usr/libexec/ld.so"; 44 char netbsddynld[] = "/usr/libexec/ld.elf_so"; 45 char dragonflydynld[] = "/usr/libexec/ld-elf.so.2"; 46 char solarisdynld[] = "/lib/ld.so.1"; 47 48 static int 49 needlib(char *name) 50 { 51 char *p; 52 LSym *s; 53 54 if(*name == '\0') 55 return 0; 56 57 /* reuse hash code in symbol table */ 58 p = smprint(".dynlib.%s", name); 59 s = linklookup(ctxt, p, 0); 60 free(p); 61 if(s->type == 0) { 62 s->type = 100; // avoid SDATA, etc. 63 return 1; 64 } 65 return 0; 66 } 67 68 int nelfsym = 1; 69 70 static void addpltsym(Link*, LSym*); 71 static void addgotsym(Link*, LSym*); 72 73 void 74 adddynrela(LSym *rela, LSym *s, Reloc *r) 75 { 76 USED(rela); 77 USED(s); 78 USED(r); 79 sysfatal("adddynrela not implemented"); 80 } 81 82 void 83 adddynrel(LSym *s, Reloc *r) 84 { 85 LSym *targ, *rel, *got; 86 87 targ = r->sym; 88 ctxt->cursym = s; 89 90 switch(r->type) { 91 default: 92 if(r->type >= 256) { 93 diag("unexpected relocation type %d", r->type); 94 return; 95 } 96 break; 97 98 // Handle relocations found in ELF object files. 99 case 256 + R_386_PC32: 100 if(targ->type == SDYNIMPORT) 101 diag("unexpected R_386_PC32 relocation for dynamic symbol %s", targ->name); 102 if(targ->type == 0 || targ->type == SXREF) 103 diag("unknown symbol %s in pcrel", targ->name); 104 r->type = R_PCREL; 105 r->add += 4; 106 return; 107 108 case 256 + R_386_PLT32: 109 r->type = R_PCREL; 110 r->add += 4; 111 if(targ->type == SDYNIMPORT) { 112 addpltsym(ctxt, targ); 113 r->sym = linklookup(ctxt, ".plt", 0); 114 r->add += targ->plt; 115 } 116 return; 117 118 case 256 + R_386_GOT32: 119 case 256 + R_386_GOT32X: 120 if(targ->type != SDYNIMPORT) { 121 // have symbol 122 if(r->off >= 2 && s->p[r->off-2] == 0x8b) { 123 // turn MOVL of GOT entry into LEAL of symbol address, relative to GOT. 124 s->p[r->off-2] = 0x8d; 125 r->type = R_GOTOFF; 126 return; 127 } 128 if(r->off >= 2 && s->p[r->off-2] == 0xff && s->p[r->off-1] == 0xb3) { 129 // turn PUSHL of GOT entry into PUSHL of symbol itself. 130 // use unnecessary SS prefix to keep instruction same length. 131 s->p[r->off-2] = 0x36; 132 s->p[r->off-1] = 0x68; 133 r->type = R_ADDR; 134 return; 135 } 136 diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name); 137 return; 138 } 139 addgotsym(ctxt, targ); 140 r->type = R_CONST; // write r->add during relocsym 141 r->sym = S; 142 r->add += targ->got; 143 return; 144 145 case 256 + R_386_GOTOFF: 146 r->type = R_GOTOFF; 147 return; 148 149 case 256 + R_386_GOTPC: 150 r->type = R_PCREL; 151 r->sym = linklookup(ctxt, ".got", 0); 152 r->add += 4; 153 return; 154 155 case 256 + R_386_32: 156 if(targ->type == SDYNIMPORT) 157 diag("unexpected R_386_32 relocation for dynamic symbol %s", targ->name); 158 r->type = R_ADDR; 159 return; 160 161 case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 0: 162 r->type = R_ADDR; 163 if(targ->type == SDYNIMPORT) 164 diag("unexpected reloc for dynamic symbol %s", targ->name); 165 return; 166 167 case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 1: 168 if(targ->type == SDYNIMPORT) { 169 addpltsym(ctxt, targ); 170 r->sym = linklookup(ctxt, ".plt", 0); 171 r->add = targ->plt; 172 r->type = R_PCREL; 173 return; 174 } 175 r->type = R_PCREL; 176 return; 177 178 case 512 + MACHO_FAKE_GOTPCREL: 179 if(targ->type != SDYNIMPORT) { 180 // have symbol 181 // turn MOVL of GOT entry into LEAL of symbol itself 182 if(r->off < 2 || s->p[r->off-2] != 0x8b) { 183 diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name); 184 return; 185 } 186 s->p[r->off-2] = 0x8d; 187 r->type = R_PCREL; 188 return; 189 } 190 addgotsym(ctxt, targ); 191 r->sym = linklookup(ctxt, ".got", 0); 192 r->add += targ->got; 193 r->type = R_PCREL; 194 return; 195 } 196 197 // Handle references to ELF symbols from our own object files. 198 if(targ->type != SDYNIMPORT) 199 return; 200 201 switch(r->type) { 202 case R_CALL: 203 case R_PCREL: 204 addpltsym(ctxt, targ); 205 r->sym = linklookup(ctxt, ".plt", 0); 206 r->add = targ->plt; 207 return; 208 209 case R_ADDR: 210 if(s->type != SDATA) 211 break; 212 if(iself) { 213 adddynsym(ctxt, targ); 214 rel = linklookup(ctxt, ".rel", 0); 215 addaddrplus(ctxt, rel, s, r->off); 216 adduint32(ctxt, rel, ELF32_R_INFO(targ->dynid, R_386_32)); 217 r->type = R_CONST; // write r->add during relocsym 218 r->sym = S; 219 return; 220 } 221 if(HEADTYPE == Hdarwin && s->size == PtrSize && r->off == 0) { 222 // Mach-O relocations are a royal pain to lay out. 223 // They use a compact stateful bytecode representation 224 // that is too much bother to deal with. 225 // Instead, interpret the C declaration 226 // void *_Cvar_stderr = &stderr; 227 // as making _Cvar_stderr the name of a GOT entry 228 // for stderr. This is separate from the usual GOT entry, 229 // just in case the C code assigns to the variable, 230 // and of course it only works for single pointers, 231 // but we only need to support cgo and that's all it needs. 232 adddynsym(ctxt, targ); 233 got = linklookup(ctxt, ".got", 0); 234 s->type = got->type | SSUB; 235 s->outer = got; 236 s->sub = got->sub; 237 got->sub = s; 238 s->value = got->size; 239 adduint32(ctxt, got, 0); 240 adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), targ->dynid); 241 r->type = 256; // ignore during relocsym 242 return; 243 } 244 break; 245 } 246 247 ctxt->cursym = s; 248 diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type); 249 } 250 251 int 252 elfreloc1(Reloc *r, vlong sectoff) 253 { 254 int32 elfsym; 255 256 LPUT(sectoff); 257 258 elfsym = r->xsym->elfsym; 259 switch(r->type) { 260 default: 261 return -1; 262 263 case R_ADDR: 264 if(r->siz == 4) 265 LPUT(R_386_32 | elfsym<<8); 266 else 267 return -1; 268 break; 269 270 case R_CALL: 271 case R_PCREL: 272 if(r->siz == 4) 273 LPUT(R_386_PC32 | elfsym<<8); 274 else 275 return -1; 276 break; 277 278 case R_TLS_LE: 279 case R_TLS_IE: 280 if(r->siz == 4) 281 LPUT(R_386_TLS_LE | elfsym<<8); 282 else 283 return -1; 284 } 285 286 return 0; 287 } 288 289 int 290 machoreloc1(Reloc *r, vlong sectoff) 291 { 292 uint32 v; 293 LSym *rs; 294 295 rs = r->xsym; 296 297 if(rs->type == SHOSTOBJ) { 298 if(rs->dynid < 0) { 299 diag("reloc %d to non-macho symbol %s type=%d", r->type, rs->name, rs->type); 300 return -1; 301 } 302 v = rs->dynid; 303 v |= 1<<27; // external relocation 304 } else { 305 v = rs->sect->extnum; 306 if(v == 0) { 307 diag("reloc %d to symbol %s in non-macho section %s type=%d", r->type, rs->name, rs->sect->name, rs->type); 308 return -1; 309 } 310 } 311 312 switch(r->type) { 313 default: 314 return -1; 315 case R_ADDR: 316 v |= MACHO_GENERIC_RELOC_VANILLA<<28; 317 break; 318 case R_CALL: 319 case R_PCREL: 320 v |= 1<<24; // pc-relative bit 321 v |= MACHO_GENERIC_RELOC_VANILLA<<28; 322 break; 323 } 324 325 switch(r->siz) { 326 default: 327 return -1; 328 case 1: 329 v |= 0<<25; 330 break; 331 case 2: 332 v |= 1<<25; 333 break; 334 case 4: 335 v |= 2<<25; 336 break; 337 case 8: 338 v |= 3<<25; 339 break; 340 } 341 342 LPUT(sectoff); 343 LPUT(v); 344 return 0; 345 } 346 347 int 348 archreloc(Reloc *r, LSym *s, vlong *val) 349 { 350 USED(s); 351 if(linkmode == LinkExternal) 352 return -1; 353 switch(r->type) { 354 case R_CONST: 355 *val = r->add; 356 return 0; 357 case R_GOTOFF: 358 *val = symaddr(r->sym) + r->add - symaddr(linklookup(ctxt, ".got", 0)); 359 return 0; 360 } 361 return -1; 362 } 363 364 void 365 elfsetupplt(void) 366 { 367 LSym *plt, *got; 368 369 plt = linklookup(ctxt, ".plt", 0); 370 got = linklookup(ctxt, ".got.plt", 0); 371 if(plt->size == 0) { 372 // pushl got+4 373 adduint8(ctxt, plt, 0xff); 374 adduint8(ctxt, plt, 0x35); 375 addaddrplus(ctxt, plt, got, 4); 376 377 // jmp *got+8 378 adduint8(ctxt, plt, 0xff); 379 adduint8(ctxt, plt, 0x25); 380 addaddrplus(ctxt, plt, got, 8); 381 382 // zero pad 383 adduint32(ctxt, plt, 0); 384 385 // assume got->size == 0 too 386 addaddrplus(ctxt, got, linklookup(ctxt, ".dynamic", 0), 0); 387 adduint32(ctxt, got, 0); 388 adduint32(ctxt, got, 0); 389 } 390 } 391 392 static void 393 addpltsym(Link *ctxt, LSym *s) 394 { 395 LSym *plt, *got, *rel; 396 397 if(s->plt >= 0) 398 return; 399 400 adddynsym(ctxt, s); 401 402 if(iself) { 403 plt = linklookup(ctxt, ".plt", 0); 404 got = linklookup(ctxt, ".got.plt", 0); 405 rel = linklookup(ctxt, ".rel.plt", 0); 406 if(plt->size == 0) 407 elfsetupplt(); 408 409 // jmpq *got+size 410 adduint8(ctxt, plt, 0xff); 411 adduint8(ctxt, plt, 0x25); 412 addaddrplus(ctxt, plt, got, got->size); 413 414 // add to got: pointer to current pos in plt 415 addaddrplus(ctxt, got, plt, plt->size); 416 417 // pushl $x 418 adduint8(ctxt, plt, 0x68); 419 adduint32(ctxt, plt, rel->size); 420 421 // jmp .plt 422 adduint8(ctxt, plt, 0xe9); 423 adduint32(ctxt, plt, -(plt->size+4)); 424 425 // rel 426 addaddrplus(ctxt, rel, got, got->size-4); 427 adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_386_JMP_SLOT)); 428 429 s->plt = plt->size - 16; 430 } else if(HEADTYPE == Hdarwin) { 431 // Same laziness as in 6l. 432 433 LSym *plt; 434 435 plt = linklookup(ctxt, ".plt", 0); 436 437 addgotsym(ctxt, s); 438 439 adduint32(ctxt, linklookup(ctxt, ".linkedit.plt", 0), s->dynid); 440 441 // jmpq *got+size(IP) 442 s->plt = plt->size; 443 444 adduint8(ctxt, plt, 0xff); 445 adduint8(ctxt, plt, 0x25); 446 addaddrplus(ctxt, plt, linklookup(ctxt, ".got", 0), s->got); 447 } else { 448 diag("addpltsym: unsupported binary format"); 449 } 450 } 451 452 static void 453 addgotsym(Link *ctxt, LSym *s) 454 { 455 LSym *got, *rel; 456 457 if(s->got >= 0) 458 return; 459 460 adddynsym(ctxt, s); 461 got = linklookup(ctxt, ".got", 0); 462 s->got = got->size; 463 adduint32(ctxt, got, 0); 464 465 if(iself) { 466 rel = linklookup(ctxt, ".rel", 0); 467 addaddrplus(ctxt, rel, got, s->got); 468 adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_386_GLOB_DAT)); 469 } else if(HEADTYPE == Hdarwin) { 470 adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), s->dynid); 471 } else { 472 diag("addgotsym: unsupported binary format"); 473 } 474 } 475 476 void 477 adddynsym(Link *ctxt, LSym *s) 478 { 479 LSym *d; 480 int t; 481 char *name; 482 483 if(s->dynid >= 0) 484 return; 485 486 if(iself) { 487 s->dynid = nelfsym++; 488 489 d = linklookup(ctxt, ".dynsym", 0); 490 491 /* name */ 492 name = s->extname; 493 adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name)); 494 495 /* value */ 496 if(s->type == SDYNIMPORT) 497 adduint32(ctxt, d, 0); 498 else 499 addaddr(ctxt, d, s); 500 501 /* size */ 502 adduint32(ctxt, d, s->size); 503 504 /* type */ 505 t = STB_GLOBAL << 4; 506 if(s->cgoexport && (s->type&SMASK) == STEXT) 507 t |= STT_FUNC; 508 else 509 t |= STT_OBJECT; 510 adduint8(ctxt, d, t); 511 adduint8(ctxt, d, 0); 512 513 /* shndx */ 514 if(s->type == SDYNIMPORT) 515 adduint16(ctxt, d, SHN_UNDEF); 516 else { 517 switch(s->type) { 518 default: 519 case STEXT: 520 t = 11; 521 break; 522 case SRODATA: 523 t = 12; 524 break; 525 case SDATA: 526 t = 13; 527 break; 528 case SBSS: 529 t = 14; 530 break; 531 } 532 adduint16(ctxt, d, t); 533 } 534 } else if(HEADTYPE == Hdarwin) { 535 diag("adddynsym: missed symbol %s (%s)", s->name, s->extname); 536 } else if(HEADTYPE == Hwindows) { 537 // already taken care of 538 } else { 539 diag("adddynsym: unsupported binary format"); 540 } 541 } 542 543 void 544 adddynlib(char *lib) 545 { 546 LSym *s; 547 548 if(!needlib(lib)) 549 return; 550 551 if(iself) { 552 s = linklookup(ctxt, ".dynstr", 0); 553 if(s->size == 0) 554 addstring(s, ""); 555 elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib)); 556 } else if(HEADTYPE == Hdarwin) { 557 machoadddynlib(lib); 558 } else if(HEADTYPE != Hwindows) { 559 diag("adddynlib: unsupported binary format"); 560 } 561 } 562 563 void 564 asmb(void) 565 { 566 int32 magic; 567 uint32 symo, dwarfoff, machlink; 568 Section *sect; 569 LSym *sym; 570 int i; 571 572 if(debug['v']) 573 Bprint(&bso, "%5.2f asmb\n", cputime()); 574 Bflush(&bso); 575 576 if(iself) 577 asmbelfsetup(); 578 579 sect = segtext.sect; 580 cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); 581 codeblk(sect->vaddr, sect->len); 582 for(sect = sect->next; sect != nil; sect = sect->next) { 583 cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); 584 datblk(sect->vaddr, sect->len); 585 } 586 587 if(segrodata.filelen > 0) { 588 if(debug['v']) 589 Bprint(&bso, "%5.2f rodatblk\n", cputime()); 590 Bflush(&bso); 591 592 cseek(segrodata.fileoff); 593 datblk(segrodata.vaddr, segrodata.filelen); 594 } 595 596 if(debug['v']) 597 Bprint(&bso, "%5.2f datblk\n", cputime()); 598 Bflush(&bso); 599 600 cseek(segdata.fileoff); 601 datblk(segdata.vaddr, segdata.filelen); 602 603 machlink = 0; 604 if(HEADTYPE == Hdarwin) { 605 if(debug['v']) 606 Bprint(&bso, "%5.2f dwarf\n", cputime()); 607 608 dwarfoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND); 609 cseek(dwarfoff); 610 611 segdwarf.fileoff = cpos(); 612 dwarfemitdebugsections(); 613 segdwarf.filelen = cpos() - segdwarf.fileoff; 614 615 machlink = domacholink(); 616 } 617 618 symsize = 0; 619 spsize = 0; 620 lcsize = 0; 621 symo = 0; 622 if(!debug['s']) { 623 // TODO: rationalize 624 if(debug['v']) 625 Bprint(&bso, "%5.2f sym\n", cputime()); 626 Bflush(&bso); 627 switch(HEADTYPE) { 628 default: 629 if(iself) 630 goto Elfsym; 631 case Hplan9: 632 symo = segdata.fileoff+segdata.filelen; 633 break; 634 case Hdarwin: 635 symo = segdata.fileoff+rnd(segdata.filelen, INITRND)+machlink; 636 break; 637 Elfsym: 638 symo = segdata.fileoff+segdata.filelen; 639 symo = rnd(symo, INITRND); 640 break; 641 case Hwindows: 642 symo = segdata.fileoff+segdata.filelen; 643 symo = rnd(symo, PEFILEALIGN); 644 break; 645 } 646 cseek(symo); 647 switch(HEADTYPE) { 648 default: 649 if(iself) { 650 if(debug['v']) 651 Bprint(&bso, "%5.2f elfsym\n", cputime()); 652 asmelfsym(); 653 cflush(); 654 cwrite(elfstrdat, elfstrsize); 655 656 if(debug['v']) 657 Bprint(&bso, "%5.2f dwarf\n", cputime()); 658 dwarfemitdebugsections(); 659 660 if(linkmode == LinkExternal) 661 elfemitreloc(); 662 } 663 break; 664 case Hplan9: 665 asmplan9sym(); 666 cflush(); 667 668 sym = linklookup(ctxt, "pclntab", 0); 669 if(sym != nil) { 670 lcsize = sym->np; 671 for(i=0; i < lcsize; i++) 672 cput(sym->p[i]); 673 674 cflush(); 675 } 676 break; 677 case Hwindows: 678 if(debug['v']) 679 Bprint(&bso, "%5.2f dwarf\n", cputime()); 680 dwarfemitdebugsections(); 681 break; 682 case Hdarwin: 683 if(linkmode == LinkExternal) 684 machoemitreloc(); 685 break; 686 } 687 } 688 if(debug['v']) 689 Bprint(&bso, "%5.2f headr\n", cputime()); 690 Bflush(&bso); 691 cseek(0L); 692 switch(HEADTYPE) { 693 default: 694 case Hplan9: /* plan9 */ 695 magic = 4*11*11+7; 696 lputb(magic); /* magic */ 697 lputb(segtext.filelen); /* sizes */ 698 lputb(segdata.filelen); 699 lputb(segdata.len - segdata.filelen); 700 lputb(symsize); /* nsyms */ 701 lputb(entryvalue()); /* va of entry */ 702 lputb(spsize); /* sp offsets */ 703 lputb(lcsize); /* line offsets */ 704 break; 705 case Hdarwin: 706 asmbmacho(); 707 break; 708 case Hlinux: 709 case Hfreebsd: 710 case Hnetbsd: 711 case Hopenbsd: 712 case Hdragonfly: 713 case Hnacl: 714 asmbelf(symo); 715 break; 716 case Hwindows: 717 asmbpe(); 718 break; 719 } 720 cflush(); 721 } 722 723 void 724 s8put(char *n) 725 { 726 char name[8]; 727 int i; 728 729 strncpy(name, n, sizeof(name)); 730 for(i=0; i<sizeof(name); i++) 731 cput(name[i]); 732 } 733 734 int32 735 rnd(int32 v, int32 r) 736 { 737 int32 c; 738 739 if(r <= 0) 740 return v; 741 v += r - 1; 742 c = v % r; 743 if(c < 0) 744 c += r; 745 v -= c; 746 return v; 747 }