github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/6l/asm.c (about) 1 // Inferno utils/6l/asm.c 2 // http://code.google.com/p/inferno-os/source/browse/utils/6l/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 #define PADDR(a) ((uint32)(a) & ~0x80000000) 41 42 char linuxdynld[] = "/lib64/ld-linux-x86-64.so.2"; 43 char freebsddynld[] = "/libexec/ld-elf.so.1"; 44 char openbsddynld[] = "/usr/libexec/ld.so"; 45 char netbsddynld[] = "/libexec/ld.elf_so"; 46 47 char zeroes[32]; 48 49 vlong 50 entryvalue(void) 51 { 52 char *a; 53 Sym *s; 54 55 a = INITENTRY; 56 if(*a >= '0' && *a <= '9') 57 return atolwhex(a); 58 s = lookup(a, 0); 59 if(s->type == 0) 60 return INITTEXT; 61 if(s->type != STEXT) 62 diag("entry not text: %s", s->name); 63 return s->value; 64 } 65 66 vlong 67 datoff(vlong addr) 68 { 69 if(addr >= segdata.vaddr) 70 return addr - segdata.vaddr + segdata.fileoff; 71 if(addr >= segtext.vaddr) 72 return addr - segtext.vaddr + segtext.fileoff; 73 diag("datoff %#llx", addr); 74 return 0; 75 } 76 77 static int 78 needlib(char *name) 79 { 80 char *p; 81 Sym *s; 82 83 if(*name == '\0') 84 return 0; 85 86 /* reuse hash code in symbol table */ 87 p = smprint(".elfload.%s", name); 88 s = lookup(p, 0); 89 free(p); 90 if(s->type == 0) { 91 s->type = 100; // avoid SDATA, etc. 92 return 1; 93 } 94 return 0; 95 } 96 97 int nelfsym = 1; 98 99 static void addpltsym(Sym*); 100 static void addgotsym(Sym*); 101 102 Sym * 103 lookuprel(void) 104 { 105 return lookup(".rela", 0); 106 } 107 108 void 109 adddynrela(Sym *rela, Sym *s, Reloc *r) 110 { 111 addaddrplus(rela, s, r->off); 112 adduint64(rela, R_X86_64_RELATIVE); 113 addaddrplus(rela, r->sym, r->add); // Addend 114 } 115 116 void 117 adddynrel(Sym *s, Reloc *r) 118 { 119 Sym *targ, *rela, *got; 120 121 targ = r->sym; 122 cursym = s; 123 124 switch(r->type) { 125 default: 126 if(r->type >= 256) { 127 diag("unexpected relocation type %d", r->type); 128 return; 129 } 130 break; 131 132 // Handle relocations found in ELF object files. 133 case 256 + R_X86_64_PC32: 134 if(targ->type == SDYNIMPORT) 135 diag("unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ->name); 136 if(targ->type == 0 || targ->type == SXREF) 137 diag("unknown symbol %s in pcrel", targ->name); 138 r->type = D_PCREL; 139 r->add += 4; 140 return; 141 142 case 256 + R_X86_64_PLT32: 143 r->type = D_PCREL; 144 r->add += 4; 145 if(targ->type == SDYNIMPORT) { 146 addpltsym(targ); 147 r->sym = lookup(".plt", 0); 148 r->add += targ->plt; 149 } 150 return; 151 152 case 256 + R_X86_64_GOTPCREL: 153 if(targ->type != SDYNIMPORT) { 154 // have symbol 155 if(r->off >= 2 && s->p[r->off-2] == 0x8b) { 156 // turn MOVQ of GOT entry into LEAQ of symbol itself 157 s->p[r->off-2] = 0x8d; 158 r->type = D_PCREL; 159 r->add += 4; 160 return; 161 } 162 // fall back to using GOT and hope for the best (CMOV*) 163 // TODO: just needs relocation, no need to put in .dynsym 164 } 165 addgotsym(targ); 166 r->type = D_PCREL; 167 r->sym = lookup(".got", 0); 168 r->add += 4; 169 r->add += targ->got; 170 return; 171 172 case 256 + R_X86_64_64: 173 if(targ->type == SDYNIMPORT) 174 diag("unexpected R_X86_64_64 relocation for dynamic symbol %s", targ->name); 175 r->type = D_ADDR; 176 return; 177 178 // Handle relocations found in Mach-O object files. 179 case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 0: 180 case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 0: 181 case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 0: 182 // TODO: What is the difference between all these? 183 r->type = D_ADDR; 184 if(targ->type == SDYNIMPORT) 185 diag("unexpected reloc for dynamic symbol %s", targ->name); 186 return; 187 188 case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 1: 189 if(targ->type == SDYNIMPORT) { 190 addpltsym(targ); 191 r->sym = lookup(".plt", 0); 192 r->add = targ->plt; 193 r->type = D_PCREL; 194 return; 195 } 196 // fall through 197 case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 1: 198 case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 1: 199 case 512 + MACHO_X86_64_RELOC_SIGNED_1*2 + 1: 200 case 512 + MACHO_X86_64_RELOC_SIGNED_2*2 + 1: 201 case 512 + MACHO_X86_64_RELOC_SIGNED_4*2 + 1: 202 r->type = D_PCREL; 203 if(targ->type == SDYNIMPORT) 204 diag("unexpected pc-relative reloc for dynamic symbol %s", targ->name); 205 return; 206 207 case 512 + MACHO_X86_64_RELOC_GOT_LOAD*2 + 1: 208 if(targ->type != SDYNIMPORT) { 209 // have symbol 210 // turn MOVQ of GOT entry into LEAQ of symbol itself 211 if(r->off < 2 || s->p[r->off-2] != 0x8b) { 212 diag("unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ->name); 213 return; 214 } 215 s->p[r->off-2] = 0x8d; 216 r->type = D_PCREL; 217 return; 218 } 219 // fall through 220 case 512 + MACHO_X86_64_RELOC_GOT*2 + 1: 221 if(targ->type != SDYNIMPORT) 222 diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name); 223 addgotsym(targ); 224 r->type = D_PCREL; 225 r->sym = lookup(".got", 0); 226 r->add += targ->got; 227 return; 228 } 229 230 // Handle references to ELF symbols from our own object files. 231 if(targ->type != SDYNIMPORT) 232 return; 233 234 switch(r->type) { 235 case D_PCREL: 236 addpltsym(targ); 237 r->sym = lookup(".plt", 0); 238 r->add = targ->plt; 239 return; 240 241 case D_ADDR: 242 if(s->type != SDATA) 243 break; 244 if(iself) { 245 adddynsym(targ); 246 rela = lookup(".rela", 0); 247 addaddrplus(rela, s, r->off); 248 if(r->siz == 8) 249 adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_64)); 250 else 251 adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_32)); 252 adduint64(rela, r->add); 253 r->type = 256; // ignore during relocsym 254 return; 255 } 256 if(HEADTYPE == Hdarwin && s->size == PtrSize && r->off == 0) { 257 // Mach-O relocations are a royal pain to lay out. 258 // They use a compact stateful bytecode representation 259 // that is too much bother to deal with. 260 // Instead, interpret the C declaration 261 // void *_Cvar_stderr = &stderr; 262 // as making _Cvar_stderr the name of a GOT entry 263 // for stderr. This is separate from the usual GOT entry, 264 // just in case the C code assigns to the variable, 265 // and of course it only works for single pointers, 266 // but we only need to support cgo and that's all it needs. 267 adddynsym(targ); 268 got = lookup(".got", 0); 269 s->type = got->type | SSUB; 270 s->outer = got; 271 s->sub = got->sub; 272 got->sub = s; 273 s->value = got->size; 274 adduint64(got, 0); 275 adduint32(lookup(".linkedit.got", 0), targ->dynid); 276 r->type = 256; // ignore during relocsym 277 return; 278 } 279 break; 280 } 281 282 cursym = s; 283 diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type); 284 } 285 286 int 287 elfreloc1(Reloc *r, vlong sectoff) 288 { 289 int32 elfsym; 290 291 VPUT(sectoff); 292 293 elfsym = r->xsym->elfsym; 294 switch(r->type) { 295 default: 296 return -1; 297 298 case D_ADDR: 299 if(r->siz == 4) 300 VPUT(R_X86_64_32 | (uint64)elfsym<<32); 301 else if(r->siz == 8) 302 VPUT(R_X86_64_64 | (uint64)elfsym<<32); 303 else 304 return -1; 305 break; 306 307 case D_PCREL: 308 if(r->siz == 4) 309 VPUT(R_X86_64_PC32 | (uint64)elfsym<<32); 310 else 311 return -1; 312 break; 313 314 case D_TLS: 315 if(r->siz == 4) 316 VPUT(R_X86_64_TPOFF32 | (uint64)elfsym<<32); 317 else 318 return -1; 319 break; 320 } 321 322 VPUT(r->xadd); 323 return 0; 324 } 325 326 int 327 machoreloc1(Reloc *r, vlong sectoff) 328 { 329 uint32 v; 330 Sym *rs; 331 332 rs = r->xsym; 333 334 if(rs->type == SHOSTOBJ) { 335 if(rs->dynid < 0) { 336 diag("reloc %d to non-macho symbol %s type=%d", r->type, rs->name, rs->type); 337 return -1; 338 } 339 v = rs->dynid; 340 v |= 1<<27; // external relocation 341 } else { 342 v = rs->sect->extnum; 343 if(v == 0) { 344 diag("reloc %d to symbol %s in non-macho section %s type=%d", r->type, rs->name, rs->sect->name, rs->type); 345 return -1; 346 } 347 } 348 349 switch(r->type) { 350 default: 351 return -1; 352 case D_ADDR: 353 v |= MACHO_X86_64_RELOC_UNSIGNED<<28; 354 break; 355 case D_PCREL: 356 v |= 1<<24; // pc-relative bit 357 v |= MACHO_X86_64_RELOC_BRANCH<<28; 358 break; 359 } 360 361 switch(r->siz) { 362 default: 363 return -1; 364 case 1: 365 v |= 0<<25; 366 break; 367 case 2: 368 v |= 1<<25; 369 break; 370 case 4: 371 v |= 2<<25; 372 break; 373 case 8: 374 v |= 3<<25; 375 break; 376 } 377 378 LPUT(sectoff); 379 LPUT(v); 380 return 0; 381 } 382 383 int 384 archreloc(Reloc *r, Sym *s, vlong *val) 385 { 386 USED(r); 387 USED(s); 388 USED(val); 389 return -1; 390 } 391 392 void 393 elfsetupplt(void) 394 { 395 Sym *plt, *got; 396 397 plt = lookup(".plt", 0); 398 got = lookup(".got.plt", 0); 399 if(plt->size == 0) { 400 // pushq got+8(IP) 401 adduint8(plt, 0xff); 402 adduint8(plt, 0x35); 403 addpcrelplus(plt, got, 8); 404 405 // jmpq got+16(IP) 406 adduint8(plt, 0xff); 407 adduint8(plt, 0x25); 408 addpcrelplus(plt, got, 16); 409 410 // nopl 0(AX) 411 adduint32(plt, 0x00401f0f); 412 413 // assume got->size == 0 too 414 addaddrplus(got, lookup(".dynamic", 0), 0); 415 adduint64(got, 0); 416 adduint64(got, 0); 417 } 418 } 419 420 static void 421 addpltsym(Sym *s) 422 { 423 if(s->plt >= 0) 424 return; 425 426 adddynsym(s); 427 428 if(iself) { 429 Sym *plt, *got, *rela; 430 431 plt = lookup(".plt", 0); 432 got = lookup(".got.plt", 0); 433 rela = lookup(".rela.plt", 0); 434 if(plt->size == 0) 435 elfsetupplt(); 436 437 // jmpq *got+size(IP) 438 adduint8(plt, 0xff); 439 adduint8(plt, 0x25); 440 addpcrelplus(plt, got, got->size); 441 442 // add to got: pointer to current pos in plt 443 addaddrplus(got, plt, plt->size); 444 445 // pushq $x 446 adduint8(plt, 0x68); 447 adduint32(plt, (got->size-24-8)/8); 448 449 // jmpq .plt 450 adduint8(plt, 0xe9); 451 adduint32(plt, -(plt->size+4)); 452 453 // rela 454 addaddrplus(rela, got, got->size-8); 455 adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_JMP_SLOT)); 456 adduint64(rela, 0); 457 458 s->plt = plt->size - 16; 459 } else if(HEADTYPE == Hdarwin) { 460 // To do lazy symbol lookup right, we're supposed 461 // to tell the dynamic loader which library each 462 // symbol comes from and format the link info 463 // section just so. I'm too lazy (ha!) to do that 464 // so for now we'll just use non-lazy pointers, 465 // which don't need to be told which library to use. 466 // 467 // http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html 468 // has details about what we're avoiding. 469 470 Sym *plt; 471 472 addgotsym(s); 473 plt = lookup(".plt", 0); 474 475 adduint32(lookup(".linkedit.plt", 0), s->dynid); 476 477 // jmpq *got+size(IP) 478 s->plt = plt->size; 479 480 adduint8(plt, 0xff); 481 adduint8(plt, 0x25); 482 addpcrelplus(plt, lookup(".got", 0), s->got); 483 } else { 484 diag("addpltsym: unsupported binary format"); 485 } 486 } 487 488 static void 489 addgotsym(Sym *s) 490 { 491 Sym *got, *rela; 492 493 if(s->got >= 0) 494 return; 495 496 adddynsym(s); 497 got = lookup(".got", 0); 498 s->got = got->size; 499 adduint64(got, 0); 500 501 if(iself) { 502 rela = lookup(".rela", 0); 503 addaddrplus(rela, got, s->got); 504 adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_GLOB_DAT)); 505 adduint64(rela, 0); 506 } else if(HEADTYPE == Hdarwin) { 507 adduint32(lookup(".linkedit.got", 0), s->dynid); 508 } else { 509 diag("addgotsym: unsupported binary format"); 510 } 511 } 512 513 void 514 adddynsym(Sym *s) 515 { 516 Sym *d; 517 int t; 518 char *name; 519 520 if(s->dynid >= 0) 521 return; 522 523 if(iself) { 524 s->dynid = nelfsym++; 525 526 d = lookup(".dynsym", 0); 527 528 name = s->extname; 529 adduint32(d, addstring(lookup(".dynstr", 0), name)); 530 /* type */ 531 t = STB_GLOBAL << 4; 532 if(s->cgoexport && (s->type&SMASK) == STEXT) 533 t |= STT_FUNC; 534 else 535 t |= STT_OBJECT; 536 adduint8(d, t); 537 538 /* reserved */ 539 adduint8(d, 0); 540 541 /* section where symbol is defined */ 542 if(s->type == SDYNIMPORT) 543 adduint16(d, SHN_UNDEF); 544 else { 545 switch(s->type) { 546 default: 547 case STEXT: 548 t = 11; 549 break; 550 case SRODATA: 551 t = 12; 552 break; 553 case SDATA: 554 t = 13; 555 break; 556 case SBSS: 557 t = 14; 558 break; 559 } 560 adduint16(d, t); 561 } 562 563 /* value */ 564 if(s->type == SDYNIMPORT) 565 adduint64(d, 0); 566 else 567 addaddr(d, s); 568 569 /* size of object */ 570 adduint64(d, s->size); 571 572 if(!(s->cgoexport & CgoExportDynamic) && s->dynimplib && needlib(s->dynimplib)) { 573 elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, 574 addstring(lookup(".dynstr", 0), s->dynimplib)); 575 } 576 } else if(HEADTYPE == Hdarwin) { 577 diag("adddynsym: missed symbol %s (%s)", s->name, s->extname); 578 } else if(HEADTYPE == Hwindows) { 579 // already taken care of 580 } else { 581 diag("adddynsym: unsupported binary format"); 582 } 583 } 584 585 void 586 adddynlib(char *lib) 587 { 588 Sym *s; 589 590 if(!needlib(lib)) 591 return; 592 593 if(iself) { 594 s = lookup(".dynstr", 0); 595 if(s->size == 0) 596 addstring(s, ""); 597 elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib)); 598 } else if(HEADTYPE == Hdarwin) { 599 machoadddynlib(lib); 600 } else { 601 diag("adddynlib: unsupported binary format"); 602 } 603 } 604 605 void 606 asmb(void) 607 { 608 int32 magic; 609 int i; 610 vlong vl, symo, dwarfoff, machlink; 611 Section *sect; 612 Sym *sym; 613 614 if(debug['v']) 615 Bprint(&bso, "%5.2f asmb\n", cputime()); 616 Bflush(&bso); 617 618 if(debug['v']) 619 Bprint(&bso, "%5.2f codeblk\n", cputime()); 620 Bflush(&bso); 621 622 if(iself) 623 asmbelfsetup(); 624 625 sect = segtext.sect; 626 cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); 627 codeblk(sect->vaddr, sect->len); 628 629 /* output read-only data in text segment (rodata, gosymtab, pclntab, ...) */ 630 for(sect = sect->next; sect != nil; sect = sect->next) { 631 cseek(sect->vaddr - segtext.vaddr + segtext.fileoff); 632 datblk(sect->vaddr, sect->len); 633 } 634 635 if(debug['v']) 636 Bprint(&bso, "%5.2f datblk\n", cputime()); 637 Bflush(&bso); 638 639 cseek(segdata.fileoff); 640 datblk(segdata.vaddr, segdata.filelen); 641 642 machlink = 0; 643 if(HEADTYPE == Hdarwin) { 644 if(debug['v']) 645 Bprint(&bso, "%5.2f dwarf\n", cputime()); 646 647 dwarfoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND); 648 cseek(dwarfoff); 649 650 segdwarf.fileoff = cpos(); 651 dwarfemitdebugsections(); 652 segdwarf.filelen = cpos() - segdwarf.fileoff; 653 654 machlink = domacholink(); 655 } 656 657 switch(HEADTYPE) { 658 default: 659 diag("unknown header type %d", HEADTYPE); 660 case Hplan9x32: 661 case Hplan9x64: 662 case Helf: 663 break; 664 case Hdarwin: 665 debug['8'] = 1; /* 64-bit addresses */ 666 break; 667 case Hlinux: 668 case Hfreebsd: 669 case Hnetbsd: 670 case Hopenbsd: 671 debug['8'] = 1; /* 64-bit addresses */ 672 break; 673 case Hwindows: 674 break; 675 } 676 677 symsize = 0; 678 spsize = 0; 679 lcsize = 0; 680 symo = 0; 681 if(!debug['s']) { 682 if(debug['v']) 683 Bprint(&bso, "%5.2f sym\n", cputime()); 684 Bflush(&bso); 685 switch(HEADTYPE) { 686 default: 687 case Hplan9x64: 688 case Helf: 689 debug['s'] = 1; 690 symo = HEADR+segtext.len+segdata.filelen; 691 break; 692 case Hdarwin: 693 symo = rnd(HEADR+segtext.len, INITRND)+rnd(segdata.filelen, INITRND)+machlink; 694 break; 695 case Hlinux: 696 case Hfreebsd: 697 case Hnetbsd: 698 case Hopenbsd: 699 symo = rnd(HEADR+segtext.len, INITRND)+segdata.filelen; 700 symo = rnd(symo, INITRND); 701 break; 702 case Hwindows: 703 symo = rnd(HEADR+segtext.filelen, PEFILEALIGN)+segdata.filelen; 704 symo = rnd(symo, PEFILEALIGN); 705 break; 706 } 707 cseek(symo); 708 switch(HEADTYPE) { 709 default: 710 if(iself) { 711 cseek(symo); 712 asmelfsym(); 713 cflush(); 714 cwrite(elfstrdat, elfstrsize); 715 716 if(debug['v']) 717 Bprint(&bso, "%5.2f dwarf\n", cputime()); 718 719 dwarfemitdebugsections(); 720 721 if(linkmode == LinkExternal) 722 elfemitreloc(); 723 } 724 break; 725 case Hplan9x64: 726 asmplan9sym(); 727 cflush(); 728 729 sym = lookup("pclntab", 0); 730 if(sym != nil) { 731 lcsize = sym->np; 732 for(i=0; i < lcsize; i++) 733 cput(sym->p[i]); 734 735 cflush(); 736 } 737 break; 738 case Hwindows: 739 if(debug['v']) 740 Bprint(&bso, "%5.2f dwarf\n", cputime()); 741 742 dwarfemitdebugsections(); 743 break; 744 case Hdarwin: 745 if(linkmode == LinkExternal) 746 machoemitreloc(); 747 break; 748 } 749 } 750 751 if(debug['v']) 752 Bprint(&bso, "%5.2f headr\n", cputime()); 753 Bflush(&bso); 754 cseek(0L); 755 switch(HEADTYPE) { 756 default: 757 case Hplan9x64: /* plan9 */ 758 magic = 4*26*26+7; 759 magic |= 0x00008000; /* fat header */ 760 lputb(magic); /* magic */ 761 lputb(segtext.filelen); /* sizes */ 762 lputb(segdata.filelen); 763 lputb(segdata.len - segdata.filelen); 764 lputb(symsize); /* nsyms */ 765 vl = entryvalue(); 766 lputb(PADDR(vl)); /* va of entry */ 767 lputb(spsize); /* sp offsets */ 768 lputb(lcsize); /* line offsets */ 769 vputb(vl); /* va of entry */ 770 break; 771 case Hplan9x32: /* plan9 */ 772 magic = 4*26*26+7; 773 lputb(magic); /* magic */ 774 lputb(segtext.filelen); /* sizes */ 775 lputb(segdata.filelen); 776 lputb(segdata.len - segdata.filelen); 777 lputb(symsize); /* nsyms */ 778 lputb(entryvalue()); /* va of entry */ 779 lputb(spsize); /* sp offsets */ 780 lputb(lcsize); /* line offsets */ 781 break; 782 case Hdarwin: 783 asmbmacho(); 784 break; 785 case Hlinux: 786 case Hfreebsd: 787 case Hnetbsd: 788 case Hopenbsd: 789 asmbelf(symo); 790 break; 791 case Hwindows: 792 asmbpe(); 793 break; 794 } 795 cflush(); 796 } 797 798 vlong 799 rnd(vlong v, vlong r) 800 { 801 vlong c; 802 803 if(r <= 0) 804 return v; 805 v += r - 1; 806 c = v % r; 807 if(c < 0) 808 c += r; 809 v -= c; 810 return v; 811 }