github.com/yanyiwu/go@v0.0.0-20150106053140-03d6637dbb7f/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 void 368 elfsetupplt(void) 369 { 370 LSym *plt, *got; 371 372 plt = linklookup(ctxt, ".plt", 0); 373 got = linklookup(ctxt, ".got.plt", 0); 374 if(plt->size == 0) { 375 // pushl got+4 376 adduint8(ctxt, plt, 0xff); 377 adduint8(ctxt, plt, 0x35); 378 addaddrplus(ctxt, plt, got, 4); 379 380 // jmp *got+8 381 adduint8(ctxt, plt, 0xff); 382 adduint8(ctxt, plt, 0x25); 383 addaddrplus(ctxt, plt, got, 8); 384 385 // zero pad 386 adduint32(ctxt, plt, 0); 387 388 // assume got->size == 0 too 389 addaddrplus(ctxt, got, linklookup(ctxt, ".dynamic", 0), 0); 390 adduint32(ctxt, got, 0); 391 adduint32(ctxt, got, 0); 392 } 393 } 394 395 static void 396 addpltsym(Link *ctxt, LSym *s) 397 { 398 LSym *plt, *got, *rel; 399 400 if(s->plt >= 0) 401 return; 402 403 adddynsym(ctxt, s); 404 405 if(iself) { 406 plt = linklookup(ctxt, ".plt", 0); 407 got = linklookup(ctxt, ".got.plt", 0); 408 rel = linklookup(ctxt, ".rel.plt", 0); 409 if(plt->size == 0) 410 elfsetupplt(); 411 412 // jmpq *got+size 413 adduint8(ctxt, plt, 0xff); 414 adduint8(ctxt, plt, 0x25); 415 addaddrplus(ctxt, plt, got, got->size); 416 417 // add to got: pointer to current pos in plt 418 addaddrplus(ctxt, got, plt, plt->size); 419 420 // pushl $x 421 adduint8(ctxt, plt, 0x68); 422 adduint32(ctxt, plt, rel->size); 423 424 // jmp .plt 425 adduint8(ctxt, plt, 0xe9); 426 adduint32(ctxt, plt, -(plt->size+4)); 427 428 // rel 429 addaddrplus(ctxt, rel, got, got->size-4); 430 adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_386_JMP_SLOT)); 431 432 s->plt = plt->size - 16; 433 } else if(HEADTYPE == Hdarwin) { 434 // Same laziness as in 6l. 435 436 LSym *plt; 437 438 plt = linklookup(ctxt, ".plt", 0); 439 440 addgotsym(ctxt, s); 441 442 adduint32(ctxt, linklookup(ctxt, ".linkedit.plt", 0), s->dynid); 443 444 // jmpq *got+size(IP) 445 s->plt = plt->size; 446 447 adduint8(ctxt, plt, 0xff); 448 adduint8(ctxt, plt, 0x25); 449 addaddrplus(ctxt, plt, linklookup(ctxt, ".got", 0), s->got); 450 } else { 451 diag("addpltsym: unsupported binary format"); 452 } 453 } 454 455 static void 456 addgotsym(Link *ctxt, LSym *s) 457 { 458 LSym *got, *rel; 459 460 if(s->got >= 0) 461 return; 462 463 adddynsym(ctxt, s); 464 got = linklookup(ctxt, ".got", 0); 465 s->got = got->size; 466 adduint32(ctxt, got, 0); 467 468 if(iself) { 469 rel = linklookup(ctxt, ".rel", 0); 470 addaddrplus(ctxt, rel, got, s->got); 471 adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_386_GLOB_DAT)); 472 } else if(HEADTYPE == Hdarwin) { 473 adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), s->dynid); 474 } else { 475 diag("addgotsym: unsupported binary format"); 476 } 477 } 478 479 void 480 adddynsym(Link *ctxt, LSym *s) 481 { 482 LSym *d; 483 int t; 484 char *name; 485 486 if(s->dynid >= 0) 487 return; 488 489 if(iself) { 490 s->dynid = nelfsym++; 491 492 d = linklookup(ctxt, ".dynsym", 0); 493 494 /* name */ 495 name = s->extname; 496 adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name)); 497 498 /* value */ 499 if(s->type == SDYNIMPORT) 500 adduint32(ctxt, d, 0); 501 else 502 addaddr(ctxt, d, s); 503 504 /* size */ 505 adduint32(ctxt, d, 0); 506 507 /* type */ 508 t = STB_GLOBAL << 4; 509 if(s->cgoexport && (s->type&SMASK) == STEXT) 510 t |= STT_FUNC; 511 else 512 t |= STT_OBJECT; 513 adduint8(ctxt, d, t); 514 adduint8(ctxt, d, 0); 515 516 /* shndx */ 517 if(s->type == SDYNIMPORT) 518 adduint16(ctxt, d, SHN_UNDEF); 519 else 520 adduint16(ctxt, d, 1); 521 } else if(HEADTYPE == Hdarwin) { 522 diag("adddynsym: missed symbol %s (%s)", s->name, s->extname); 523 } else if(HEADTYPE == Hwindows) { 524 // already taken care of 525 } else { 526 diag("adddynsym: unsupported binary format"); 527 } 528 } 529 530 void 531 adddynlib(char *lib) 532 { 533 LSym *s; 534 535 if(!needlib(lib)) 536 return; 537 538 if(iself) { 539 s = linklookup(ctxt, ".dynstr", 0); 540 if(s->size == 0) 541 addstring(s, ""); 542 elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib)); 543 } else if(HEADTYPE == Hdarwin) { 544 machoadddynlib(lib); 545 } else if(HEADTYPE != Hwindows) { 546 diag("adddynlib: unsupported binary format"); 547 } 548 } 549 550 void 551 asmb(void) 552 { 553 int32 magic; 554 uint32 symo, dwarfoff, machlink; 555 Section *sect; 556 LSym *sym; 557 int i; 558 559 if(debug['v']) 560 Bprint(&bso, "%5.2f asmb\n", cputime()); 561 Bflush(&bso); 562 563 if(iself) 564 asmbelfsetup(); 565 566 sect = segtext.sect; 567 cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); 568 codeblk(sect->vaddr, sect->len); 569 for(sect = sect->next; sect != nil; sect = sect->next) { 570 cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); 571 datblk(sect->vaddr, sect->len); 572 } 573 574 if(segrodata.filelen > 0) { 575 if(debug['v']) 576 Bprint(&bso, "%5.2f rodatblk\n", cputime()); 577 Bflush(&bso); 578 579 cseek(segrodata.fileoff); 580 datblk(segrodata.vaddr, segrodata.filelen); 581 } 582 583 if(debug['v']) 584 Bprint(&bso, "%5.2f datblk\n", cputime()); 585 Bflush(&bso); 586 587 cseek(segdata.fileoff); 588 datblk(segdata.vaddr, segdata.filelen); 589 590 machlink = 0; 591 if(HEADTYPE == Hdarwin) { 592 if(debug['v']) 593 Bprint(&bso, "%5.2f dwarf\n", cputime()); 594 595 dwarfoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND); 596 cseek(dwarfoff); 597 598 segdwarf.fileoff = cpos(); 599 dwarfemitdebugsections(); 600 segdwarf.filelen = cpos() - segdwarf.fileoff; 601 602 machlink = domacholink(); 603 } 604 605 symsize = 0; 606 spsize = 0; 607 lcsize = 0; 608 symo = 0; 609 if(!debug['s']) { 610 // TODO: rationalize 611 if(debug['v']) 612 Bprint(&bso, "%5.2f sym\n", cputime()); 613 Bflush(&bso); 614 switch(HEADTYPE) { 615 default: 616 if(iself) 617 goto Elfsym; 618 case Hplan9: 619 symo = segdata.fileoff+segdata.filelen; 620 break; 621 case Hdarwin: 622 symo = segdata.fileoff+rnd(segdata.filelen, INITRND)+machlink; 623 break; 624 Elfsym: 625 symo = segdata.fileoff+segdata.filelen; 626 symo = rnd(symo, INITRND); 627 break; 628 case Hwindows: 629 symo = segdata.fileoff+segdata.filelen; 630 symo = rnd(symo, PEFILEALIGN); 631 break; 632 } 633 cseek(symo); 634 switch(HEADTYPE) { 635 default: 636 if(iself) { 637 if(debug['v']) 638 Bprint(&bso, "%5.2f elfsym\n", cputime()); 639 asmelfsym(); 640 cflush(); 641 cwrite(elfstrdat, elfstrsize); 642 643 if(debug['v']) 644 Bprint(&bso, "%5.2f dwarf\n", cputime()); 645 dwarfemitdebugsections(); 646 647 if(linkmode == LinkExternal) 648 elfemitreloc(); 649 } 650 break; 651 case Hplan9: 652 asmplan9sym(); 653 cflush(); 654 655 sym = linklookup(ctxt, "pclntab", 0); 656 if(sym != nil) { 657 lcsize = sym->np; 658 for(i=0; i < lcsize; i++) 659 cput(sym->p[i]); 660 661 cflush(); 662 } 663 break; 664 case Hwindows: 665 if(debug['v']) 666 Bprint(&bso, "%5.2f dwarf\n", cputime()); 667 dwarfemitdebugsections(); 668 break; 669 case Hdarwin: 670 if(linkmode == LinkExternal) 671 machoemitreloc(); 672 break; 673 } 674 } 675 if(debug['v']) 676 Bprint(&bso, "%5.2f headr\n", cputime()); 677 Bflush(&bso); 678 cseek(0L); 679 switch(HEADTYPE) { 680 default: 681 case Hplan9: /* plan9 */ 682 magic = 4*11*11+7; 683 lputb(magic); /* magic */ 684 lputb(segtext.filelen); /* sizes */ 685 lputb(segdata.filelen); 686 lputb(segdata.len - segdata.filelen); 687 lputb(symsize); /* nsyms */ 688 lputb(entryvalue()); /* va of entry */ 689 lputb(spsize); /* sp offsets */ 690 lputb(lcsize); /* line offsets */ 691 break; 692 case Hdarwin: 693 asmbmacho(); 694 break; 695 case Hlinux: 696 case Hfreebsd: 697 case Hnetbsd: 698 case Hopenbsd: 699 case Hdragonfly: 700 case Hnacl: 701 asmbelf(symo); 702 break; 703 case Hwindows: 704 asmbpe(); 705 break; 706 } 707 cflush(); 708 } 709 710 void 711 s8put(char *n) 712 { 713 char name[8]; 714 int i; 715 716 strncpy(name, n, sizeof(name)); 717 for(i=0; i<sizeof(name); i++) 718 cput(name[i]); 719 } 720 721 int32 722 rnd(int32 v, int32 r) 723 { 724 int32 c; 725 726 if(r <= 0) 727 return v; 728 v += r - 1; 729 c = v % r; 730 if(c < 0) 731 c += r; 732 v -= c; 733 return v; 734 }