github.com/reiver/go@v0.0.0-20150109200633-1d0c7792f172/src/cmd/9l/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 // TODO(austin): ABI v1 uses /usr/lib/ld.so.1 40 char linuxdynld[] = "/lib64/ld64.so.1"; 41 char freebsddynld[] = "XXX"; 42 char openbsddynld[] = "XXX"; 43 char netbsddynld[] = "XXX"; 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 gencallstub(int abicase, LSym *stub, LSym *targ); 70 static void addpltsym(Link*, LSym*); 71 static LSym* ensureglinkresolver(void); 72 73 void 74 gentext(void) 75 { 76 LSym *s, *stub, **pprevtextp; 77 Reloc *r; 78 char *n; 79 uint32 o1; 80 uchar *cast; 81 int i; 82 83 // The ppc64 ABI PLT has similar concepts to other 84 // architectures, but is laid out quite differently. When we 85 // see an R_PPC64_REL24 relocation to a dynamic symbol 86 // (indicating that the call needs to go through the PLT), we 87 // generate up to three stubs and reserve a PLT slot. 88 // 89 // 1) The call site will be bl x; nop (where the relocation 90 // applies to the bl). We rewrite this to bl x_stub; ld 91 // r2,24(r1). The ld is necessary because x_stub will save 92 // r2 (the TOC pointer) at 24(r1) (the "TOC save slot"). 93 // 94 // 2) We reserve space for a pointer in the .plt section (once 95 // per referenced dynamic function). .plt is a data 96 // section filled solely by the dynamic linker (more like 97 // .plt.got on other architectures). Initially, the 98 // dynamic linker will fill each slot with a pointer to the 99 // corresponding x@plt entry point. 100 // 101 // 3) We generate the "call stub" x_stub (once per dynamic 102 // function/object file pair). This saves the TOC in the 103 // TOC save slot, reads the function pointer from x's .plt 104 // slot and calls it like any other global entry point 105 // (including setting r12 to the function address). 106 // 107 // 4) We generate the "symbol resolver stub" x@plt (once per 108 // dynamic function). This is solely a branch to the glink 109 // resolver stub. 110 // 111 // 5) We generate the glink resolver stub (only once). This 112 // computes which symbol resolver stub we came through and 113 // invokes the dynamic resolver via a pointer provided by 114 // the dynamic linker. This will patch up the .plt slot to 115 // point directly at the function so future calls go 116 // straight from the call stub to the real function, and 117 // then call the function. 118 119 // NOTE: It's possible we could make ppc64 closer to other 120 // architectures: ppc64's .plt is like .plt.got on other 121 // platforms and ppc64's .glink is like .plt on other 122 // platforms. 123 124 // Find all R_PPC64_REL24 relocations that reference dynamic 125 // imports. Reserve PLT entries for these symbols and 126 // generate call stubs. The call stubs need to live in .text, 127 // which is why we need to do this pass this early. 128 // 129 // This assumes "case 1" from the ABI, where the caller needs 130 // us to save and restore the TOC pointer. 131 pprevtextp = &ctxt->textp; 132 for(s=*pprevtextp; s!=S; pprevtextp=&s->next, s=*pprevtextp) { 133 for(r=s->r; r<s->r+s->nr; r++) { 134 if(!(r->type == 256 + R_PPC64_REL24 && 135 r->sym->type == SDYNIMPORT)) 136 continue; 137 138 // Reserve PLT entry and generate symbol 139 // resolver 140 addpltsym(ctxt, r->sym); 141 142 // Generate call stub 143 n = smprint("%s.%s", s->name, r->sym->name); 144 stub = linklookup(ctxt, n, 0); 145 free(n); 146 stub->reachable |= s->reachable; 147 if(stub->size == 0) { 148 // Need outer to resolve .TOC. 149 stub->outer = s; 150 151 // Link in to textp before s (we could 152 // do it after, but would have to skip 153 // the subsymbols) 154 *pprevtextp = stub; 155 stub->next = s; 156 pprevtextp = &stub->next; 157 158 gencallstub(1, stub, r->sym); 159 } 160 161 // Update the relocation to use the call stub 162 r->sym = stub; 163 164 // Restore TOC after bl. The compiler put a 165 // nop here for us to overwrite. 166 o1 = 0xe8410018; // ld r2,24(r1) 167 cast = (uchar*)&o1; 168 for(i=0; i<4; i++) 169 s->p[r->off+4+i] = cast[inuxi4[i]]; 170 } 171 } 172 } 173 174 // Construct a call stub in stub that calls symbol targ via its PLT 175 // entry. 176 static void 177 gencallstub(int abicase, LSym *stub, LSym *targ) 178 { 179 LSym *plt; 180 Reloc *r; 181 182 if(abicase != 1) 183 // If we see R_PPC64_TOCSAVE or R_PPC64_REL24_NOTOC 184 // relocations, we'll need to implement cases 2 and 3. 185 sysfatal("gencallstub only implements case 1 calls"); 186 187 plt = linklookup(ctxt, ".plt", 0); 188 189 stub->type = STEXT; 190 191 // Save TOC pointer in TOC save slot 192 adduint32(ctxt, stub, 0xf8410018); // std r2,24(r1) 193 194 // Load the function pointer from the PLT. 195 r = addrel(stub); 196 r->off = stub->size; 197 r->sym = plt; 198 r->add = targ->plt; 199 r->siz = 2; 200 if(ctxt->arch->endian == BigEndian) 201 r->off += r->siz; 202 r->type = R_POWER_TOC; 203 r->variant = RV_POWER_HA; 204 adduint32(ctxt, stub, 0x3d820000); // addis r12,r2,targ@plt@toc@ha 205 r = addrel(stub); 206 r->off = stub->size; 207 r->sym = plt; 208 r->add = targ->plt; 209 r->siz = 2; 210 if(ctxt->arch->endian == BigEndian) 211 r->off += r->siz; 212 r->type = R_POWER_TOC; 213 r->variant = RV_POWER_LO; 214 adduint32(ctxt, stub, 0xe98c0000); // ld r12,targ@plt@toc@l(r12) 215 216 // Jump to the loaded pointer 217 adduint32(ctxt, stub, 0x7d8903a6); // mtctr r12 218 adduint32(ctxt, stub, 0x4e800420); // bctr 219 } 220 221 void 222 adddynrela(LSym *rel, LSym *s, Reloc *r) 223 { 224 USED(rel); USED(s); USED(r); 225 sysfatal("adddynrela not implemented"); 226 } 227 228 void 229 adddynrel(LSym *s, Reloc *r) 230 { 231 LSym *targ, *rela; 232 233 targ = r->sym; 234 ctxt->cursym = s; 235 236 switch(r->type) { 237 default: 238 if(r->type >= 256) { 239 diag("unexpected relocation type %d", r->type); 240 return; 241 } 242 break; 243 244 // Handle relocations found in ELF object files. 245 case 256 + R_PPC64_REL24: 246 r->type = R_CALLPOWER; 247 // This is a local call, so the caller isn't setting 248 // up r12 and r2 is the same for the caller and 249 // callee. Hence, we need to go to the local entry 250 // point. (If we don't do this, the callee will try 251 // to use r12 to compute r2.) 252 r->add += r->sym->localentry * 4; 253 if(targ->type == SDYNIMPORT) 254 // Should have been handled in elfsetupplt 255 diag("unexpected R_PPC64_REL24 for dyn import"); 256 return; 257 258 case 256 + R_PPC64_ADDR64: 259 r->type = R_ADDR; 260 if(targ->type == SDYNIMPORT) { 261 // These happen in .toc sections 262 adddynsym(ctxt, targ); 263 264 rela = linklookup(ctxt, ".rela", 0); 265 addaddrplus(ctxt, rela, s, r->off); 266 adduint64(ctxt, rela, ELF64_R_INFO(targ->dynid, R_PPC64_ADDR64)); 267 adduint64(ctxt, rela, r->add); 268 r->type = 256; // ignore during relocsym 269 } 270 return; 271 272 case 256 + R_PPC64_TOC16: 273 r->type = R_POWER_TOC; 274 r->variant = RV_POWER_LO | RV_CHECK_OVERFLOW; 275 return; 276 277 case 256 + R_PPC64_TOC16_LO: 278 r->type = R_POWER_TOC; 279 r->variant = RV_POWER_LO; 280 return; 281 282 case 256 + R_PPC64_TOC16_HA: 283 r->type = R_POWER_TOC; 284 r->variant = RV_POWER_HA | RV_CHECK_OVERFLOW; 285 return; 286 287 case 256 + R_PPC64_TOC16_HI: 288 r->type = R_POWER_TOC; 289 r->variant = RV_POWER_HI | RV_CHECK_OVERFLOW; 290 return; 291 292 case 256 + R_PPC64_TOC16_DS: 293 r->type = R_POWER_TOC; 294 r->variant = RV_POWER_DS | RV_CHECK_OVERFLOW; 295 return; 296 297 case 256 + R_PPC64_TOC16_LO_DS: 298 r->type = R_POWER_TOC; 299 r->variant = RV_POWER_DS; 300 return; 301 302 case 256 + R_PPC64_REL16_LO: 303 r->type = R_PCREL; 304 r->variant = RV_POWER_LO; 305 r->add += 2; // Compensate for relocation size of 2 306 return; 307 308 case 256 + R_PPC64_REL16_HI: 309 r->type = R_PCREL; 310 r->variant = RV_POWER_HI | RV_CHECK_OVERFLOW; 311 r->add += 2; 312 return; 313 314 case 256 + R_PPC64_REL16_HA: 315 r->type = R_PCREL; 316 r->variant = RV_POWER_HA | RV_CHECK_OVERFLOW; 317 r->add += 2; 318 return; 319 } 320 321 // Handle references to ELF symbols from our own object files. 322 if(targ->type != SDYNIMPORT) 323 return; 324 325 // TODO(austin): Translate our relocations to ELF 326 327 diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type); 328 } 329 330 int 331 elfreloc1(Reloc *r, vlong sectoff) 332 { 333 USED(r); USED(sectoff); 334 // TODO(minux) 335 return -1; 336 } 337 338 void 339 elfsetupplt(void) 340 { 341 LSym *plt; 342 343 plt = linklookup(ctxt, ".plt", 0); 344 if(plt->size == 0) { 345 // The dynamic linker stores the address of the 346 // dynamic resolver and the DSO identifier in the two 347 // doublewords at the beginning of the .plt section 348 // before the PLT array. Reserve space for these. 349 plt->size = 16; 350 } 351 } 352 353 int 354 machoreloc1(Reloc *r, vlong sectoff) 355 { 356 USED(r); 357 USED(sectoff); 358 359 return -1; 360 } 361 362 // Return the value of .TOC. for symbol s 363 static vlong 364 symtoc(LSym *s) 365 { 366 LSym *toc; 367 368 if(s->outer != nil) 369 toc = linkrlookup(ctxt, ".TOC.", s->outer->version); 370 else 371 toc = linkrlookup(ctxt, ".TOC.", s->version); 372 373 if(toc == nil) { 374 diag("TOC-relative relocation in object without .TOC."); 375 return 0; 376 } 377 return toc->value; 378 } 379 380 int 381 archreloc(Reloc *r, LSym *s, vlong *val) 382 { 383 uint32 o1, o2; 384 vlong t; 385 386 if(linkmode == LinkExternal) { 387 // TODO(minux): translate R_ADDRPOWER and R_CALLPOWER into standard ELF relocations. 388 // R_ADDRPOWER corresponds to R_PPC_ADDR16_HA and R_PPC_ADDR16_LO. 389 // R_CALLPOWER corresponds to R_PPC_REL24. 390 return -1; 391 } 392 switch(r->type) { 393 case R_CONST: 394 *val = r->add; 395 return 0; 396 case R_GOTOFF: 397 *val = symaddr(r->sym) + r->add - symaddr(linklookup(ctxt, ".got", 0)); 398 return 0; 399 case R_ADDRPOWER: 400 // r->add is two ppc64 instructions holding an immediate 32-bit constant. 401 // We want to add r->sym's address to that constant. 402 // The encoding of the immediate x<<16 + y, 403 // where x is the low 16 bits of the first instruction and y is the low 16 404 // bits of the second. Both x and y are signed (int16, not uint16). 405 o1 = r->add >> 32; 406 o2 = r->add; 407 t = symaddr(r->sym); 408 if(t < 0) { 409 ctxt->diag("relocation for %s is too big (>=2G): %lld", s->name, symaddr(r->sym)); 410 } 411 t += ((o1 & 0xffff) << 16) + ((int32)o2 << 16 >> 16); 412 if(t & 0x8000) 413 t += 0x10000; 414 o1 = (o1 & 0xffff0000) | ((t >> 16) & 0xffff); 415 o2 = (o2 & 0xffff0000) | (t & 0xffff); 416 // when laid out, the instruction order must always be o1, o2. 417 if(ctxt->arch->endian == BigEndian) 418 *val = ((vlong)o1 << 32) | o2; 419 else 420 *val = ((vlong)o2 << 32) | o1; 421 return 0; 422 case R_CALLPOWER: 423 // Bits 6 through 29 = (S + A - P) >> 2 424 if(ctxt->arch->endian == BigEndian) 425 o1 = be32(s->p + r->off); 426 else 427 o1 = le32(s->p + r->off); 428 429 t = symaddr(r->sym) + r->add - (s->value + r->off); 430 if(t & 3) 431 ctxt->diag("relocation for %s+%d is not aligned: %lld", r->sym->name, r->off, t); 432 if((int32)(t << 6) >> 6 != t) 433 // TODO(austin) This can happen if text > 32M. 434 // Add a call trampoline to .text in that case. 435 ctxt->diag("relocation for %s+%d is too big: %lld", r->sym->name, r->off, t); 436 437 *val = (o1 & 0xfc000003U) | (t & ~0xfc000003U); 438 return 0; 439 case R_POWER_TOC: // S + A - .TOC. 440 *val = symaddr(r->sym) + r->add - symtoc(s); 441 return 0; 442 } 443 return -1; 444 } 445 446 vlong 447 archrelocvariant(Reloc *r, LSym *s, vlong t) 448 { 449 uint32 o1; 450 switch(r->variant & RV_TYPE_MASK) { 451 default: 452 diag("unexpected relocation variant %d", r->variant); 453 454 case RV_NONE: 455 return t; 456 457 case RV_POWER_LO: 458 if(r->variant & RV_CHECK_OVERFLOW) { 459 // Whether to check for signed or unsigned 460 // overflow depends on the instruction 461 if(ctxt->arch->endian == BigEndian) 462 o1 = be32(s->p + r->off - 2); 463 else 464 o1 = le32(s->p + r->off); 465 switch(o1 >> 26) { 466 case 24: // ori 467 case 26: // xori 468 case 28: // andi 469 if((t >> 16) != 0) 470 goto overflow; 471 break; 472 default: 473 if((int16)t != t) 474 goto overflow; 475 break; 476 } 477 } 478 return (int16)t; 479 480 case RV_POWER_HA: 481 t += 0x8000; 482 // Fallthrough 483 case RV_POWER_HI: 484 t >>= 16; 485 if(r->variant & RV_CHECK_OVERFLOW) { 486 // Whether to check for signed or unsigned 487 // overflow depends on the instruction 488 if(ctxt->arch->endian == BigEndian) 489 o1 = be32(s->p + r->off - 2); 490 else 491 o1 = le32(s->p + r->off); 492 switch(o1 >> 26) { 493 case 25: // oris 494 case 27: // xoris 495 case 29: // andis 496 if((t >> 16) != 0) 497 goto overflow; 498 break; 499 default: 500 if((int16)t != t) 501 goto overflow; 502 break; 503 } 504 } 505 return (int16)t; 506 507 case RV_POWER_DS: 508 if(ctxt->arch->endian == BigEndian) 509 o1 = be16(s->p + r->off); 510 else 511 o1 = le16(s->p + r->off); 512 if(t & 3) 513 diag("relocation for %s+%d is not aligned: %lld", r->sym->name, r->off, t); 514 if((r->variant & RV_CHECK_OVERFLOW) && (int16)t != t) 515 goto overflow; 516 return (o1 & 0x3) | (vlong)(int16)t; 517 } 518 519 overflow: 520 diag("relocation for %s+%d is too big: %lld", r->sym->name, r->off, t); 521 return t; 522 } 523 524 static void 525 addpltsym(Link *ctxt, LSym *s) 526 { 527 if(s->plt >= 0) 528 return; 529 530 adddynsym(ctxt, s); 531 532 if(iself) { 533 LSym *plt, *rela, *glink; 534 Reloc *r; 535 536 plt = linklookup(ctxt, ".plt", 0); 537 rela = linklookup(ctxt, ".rela.plt", 0); 538 if(plt->size == 0) 539 elfsetupplt(); 540 541 // Create the glink resolver if necessary 542 glink = ensureglinkresolver(); 543 544 // Write symbol resolver stub (just a branch to the 545 // glink resolver stub) 546 r = addrel(glink); 547 r->sym = glink; 548 r->off = glink->size; 549 r->siz = 4; 550 r->type = R_CALLPOWER; 551 adduint32(ctxt, glink, 0x48000000); // b .glink 552 553 // In the ppc64 ABI, the dynamic linker is responsible 554 // for writing the entire PLT. We just need to 555 // reserve 8 bytes for each PLT entry and generate a 556 // JMP_SLOT dynamic relocation for it. 557 // 558 // TODO(austin): ABI v1 is different 559 s->plt = plt->size; 560 plt->size += 8; 561 562 addaddrplus(ctxt, rela, plt, s->plt); 563 adduint64(ctxt, rela, ELF64_R_INFO(s->dynid, R_PPC64_JMP_SLOT)); 564 adduint64(ctxt, rela, 0); 565 } else { 566 diag("addpltsym: unsupported binary format"); 567 } 568 } 569 570 // Generate the glink resolver stub if necessary and return the .glink section 571 static LSym* 572 ensureglinkresolver(void) 573 { 574 LSym *glink, *s; 575 Reloc *r; 576 577 glink = linklookup(ctxt, ".glink", 0); 578 if(glink->size != 0) 579 return glink; 580 581 // This is essentially the resolver from the ppc64 ELF ABI. 582 // At entry, r12 holds the address of the symbol resolver stub 583 // for the target routine and the argument registers hold the 584 // arguments for the target routine. 585 // 586 // This stub is PIC, so first get the PC of label 1 into r11. 587 // Other things will be relative to this. 588 adduint32(ctxt, glink, 0x7c0802a6); // mflr r0 589 adduint32(ctxt, glink, 0x429f0005); // bcl 20,31,1f 590 adduint32(ctxt, glink, 0x7d6802a6); // 1: mflr r11 591 adduint32(ctxt, glink, 0x7c0803a6); // mtlf r0 592 593 // Compute the .plt array index from the entry point address. 594 // Because this is PIC, everything is relative to label 1b (in 595 // r11): 596 // r0 = ((r12 - r11) - (res_0 - r11)) / 4 = (r12 - res_0) / 4 597 adduint32(ctxt, glink, 0x3800ffd0); // li r0,-(res_0-1b)=-48 598 adduint32(ctxt, glink, 0x7c006214); // add r0,r0,r12 599 adduint32(ctxt, glink, 0x7c0b0050); // sub r0,r0,r11 600 adduint32(ctxt, glink, 0x7800f082); // srdi r0,r0,2 601 602 // r11 = address of the first byte of the PLT 603 r = addrel(glink); 604 r->off = glink->size; 605 r->sym = linklookup(ctxt, ".plt", 0); 606 r->siz = 8; 607 r->type = R_ADDRPOWER; 608 // addis r11,0,.plt@ha; addi r11,r11,.plt@l 609 r->add = (0x3d600000ull << 32) | 0x396b0000; 610 glink->size += 8; 611 612 // Load r12 = dynamic resolver address and r11 = DSO 613 // identifier from the first two doublewords of the PLT. 614 adduint32(ctxt, glink, 0xe98b0000); // ld r12,0(r11) 615 adduint32(ctxt, glink, 0xe96b0008); // ld r11,8(r11) 616 617 // Jump to the dynamic resolver 618 adduint32(ctxt, glink, 0x7d8903a6); // mtctr r12 619 adduint32(ctxt, glink, 0x4e800420); // bctr 620 621 // The symbol resolvers must immediately follow. 622 // res_0: 623 624 // Add DT_PPC64_GLINK .dynamic entry, which points to 32 bytes 625 // before the first symbol resolver stub. 626 s = linklookup(ctxt, ".dynamic", 0); 627 elfwritedynentsymplus(s, DT_PPC64_GLINK, glink, glink->size - 32); 628 629 return glink; 630 } 631 632 void 633 adddynsym(Link *ctxt, LSym *s) 634 { 635 LSym *d; 636 int t; 637 char *name; 638 639 if(s->dynid >= 0) 640 return; 641 642 if(iself) { 643 s->dynid = nelfsym++; 644 645 d = linklookup(ctxt, ".dynsym", 0); 646 647 name = s->extname; 648 adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name)); 649 650 /* type */ 651 t = STB_GLOBAL << 4; 652 if(s->cgoexport && (s->type&SMASK) == STEXT) 653 t |= STT_FUNC; 654 else 655 t |= STT_OBJECT; 656 adduint8(ctxt, d, t); 657 658 /* reserved */ 659 adduint8(ctxt, d, 0); 660 661 /* section where symbol is defined */ 662 if(s->type == SDYNIMPORT) 663 adduint16(ctxt, d, SHN_UNDEF); 664 else 665 adduint16(ctxt, d, 1); 666 667 /* value */ 668 if(s->type == SDYNIMPORT) 669 adduint64(ctxt, d, 0); 670 else 671 addaddr(ctxt, d, s); 672 673 /* size of object */ 674 adduint64(ctxt, d, s->size); 675 } else { 676 diag("adddynsym: unsupported binary format"); 677 } 678 } 679 680 void 681 adddynlib(char *lib) 682 { 683 LSym *s; 684 685 if(!needlib(lib)) 686 return; 687 688 if(iself) { 689 s = linklookup(ctxt, ".dynstr", 0); 690 if(s->size == 0) 691 addstring(s, ""); 692 elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib)); 693 } else { 694 diag("adddynlib: unsupported binary format"); 695 } 696 } 697 698 void 699 asmb(void) 700 { 701 uint32 symo; 702 Section *sect; 703 LSym *sym; 704 int i; 705 706 if(debug['v']) 707 Bprint(&bso, "%5.2f asmb\n", cputime()); 708 Bflush(&bso); 709 710 if(iself) 711 asmbelfsetup(); 712 713 sect = segtext.sect; 714 cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); 715 codeblk(sect->vaddr, sect->len); 716 for(sect = sect->next; sect != nil; sect = sect->next) { 717 cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); 718 datblk(sect->vaddr, sect->len); 719 } 720 721 if(segrodata.filelen > 0) { 722 if(debug['v']) 723 Bprint(&bso, "%5.2f rodatblk\n", cputime()); 724 Bflush(&bso); 725 726 cseek(segrodata.fileoff); 727 datblk(segrodata.vaddr, segrodata.filelen); 728 } 729 730 if(debug['v']) 731 Bprint(&bso, "%5.2f datblk\n", cputime()); 732 Bflush(&bso); 733 734 cseek(segdata.fileoff); 735 datblk(segdata.vaddr, segdata.filelen); 736 737 /* output symbol table */ 738 symsize = 0; 739 lcsize = 0; 740 symo = 0; 741 if(!debug['s']) { 742 // TODO: rationalize 743 if(debug['v']) 744 Bprint(&bso, "%5.2f sym\n", cputime()); 745 Bflush(&bso); 746 switch(HEADTYPE) { 747 default: 748 if(iself) 749 goto ElfSym; 750 case Hplan9: 751 symo = segdata.fileoff+segdata.filelen; 752 break; 753 ElfSym: 754 symo = segdata.fileoff+segdata.filelen; 755 symo = rnd(symo, INITRND); 756 break; 757 } 758 cseek(symo); 759 switch(HEADTYPE) { 760 default: 761 if(iself) { 762 if(debug['v']) 763 Bprint(&bso, "%5.2f elfsym\n", cputime()); 764 asmelfsym(); 765 cflush(); 766 cwrite(elfstrdat, elfstrsize); 767 768 if(debug['v']) 769 Bprint(&bso, "%5.2f dwarf\n", cputime()); 770 dwarfemitdebugsections(); 771 772 if(linkmode == LinkExternal) 773 elfemitreloc(); 774 } 775 break; 776 case Hplan9: 777 asmplan9sym(); 778 cflush(); 779 780 sym = linklookup(ctxt, "pclntab", 0); 781 if(sym != nil) { 782 lcsize = sym->np; 783 for(i=0; i < lcsize; i++) 784 cput(sym->p[i]); 785 786 cflush(); 787 } 788 break; 789 } 790 } 791 792 ctxt->cursym = nil; 793 if(debug['v']) 794 Bprint(&bso, "%5.2f header\n", cputime()); 795 Bflush(&bso); 796 cseek(0L); 797 switch(HEADTYPE) { 798 default: 799 case Hplan9: /* plan 9 */ 800 LPUT(0x647); /* magic */ 801 LPUT(segtext.filelen); /* sizes */ 802 LPUT(segdata.filelen); 803 LPUT(segdata.len - segdata.filelen); 804 LPUT(symsize); /* nsyms */ 805 LPUT(entryvalue()); /* va of entry */ 806 LPUT(0L); 807 LPUT(lcsize); 808 break; 809 case Hlinux: 810 case Hfreebsd: 811 case Hnetbsd: 812 case Hopenbsd: 813 case Hnacl: 814 asmbelf(symo); 815 break; 816 } 817 cflush(); 818 if(debug['c']){ 819 print("textsize=%ulld\n", segtext.filelen); 820 print("datsize=%ulld\n", segdata.filelen); 821 print("bsssize=%ulld\n", segdata.len - segdata.filelen); 822 print("symsize=%d\n", symsize); 823 print("lcsize=%d\n", lcsize); 824 print("total=%lld\n", segtext.filelen+segdata.len+symsize+lcsize); 825 } 826 } 827 828 vlong 829 rnd(vlong v, int32 r) 830 { 831 vlong c; 832 833 if(r <= 0) 834 return v; 835 v += r - 1; 836 c = v % r; 837 if(c < 0) 838 c += r; 839 v -= c; 840 return v; 841 }