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