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