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