github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/cmd/ld/macho.c (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Mach-O file writing 6 // http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html 7 8 #include "l.h" 9 #include "../ld/dwarf.h" 10 #include "../ld/lib.h" 11 #include "../ld/macho.h" 12 13 static int macho64; 14 static MachoHdr hdr; 15 static MachoLoad *load; 16 static MachoSeg seg[16]; 17 static int nload, mload, nseg, ndebug, nsect; 18 19 enum 20 { 21 SymKindLocal = 0, 22 SymKindExtdef, 23 SymKindUndef, 24 NumSymKind 25 }; 26 27 static int nkind[NumSymKind]; 28 static Sym** sortsym; 29 static int nsortsym; 30 31 // Amount of space left for adding load commands 32 // that refer to dynamic libraries. Because these have 33 // to go in the Mach-O header, we can't just pick a 34 // "big enough" header size. The initial header is 35 // one page, the non-dynamic library stuff takes 36 // up about 1300 bytes; we overestimate that as 2k. 37 static int load_budget = INITIAL_MACHO_HEADR - 2*1024; 38 39 static void machodysymtab(void); 40 41 void 42 machoinit(void) 43 { 44 switch(thechar) { 45 // 64-bit architectures 46 case '6': 47 macho64 = 1; 48 break; 49 50 // 32-bit architectures 51 default: 52 break; 53 } 54 } 55 56 MachoHdr* 57 getMachoHdr(void) 58 { 59 return &hdr; 60 } 61 62 MachoLoad* 63 newMachoLoad(uint32 type, uint32 ndata) 64 { 65 MachoLoad *l; 66 67 if(nload >= mload) { 68 if(mload == 0) 69 mload = 1; 70 else 71 mload *= 2; 72 load = erealloc(load, mload*sizeof load[0]); 73 } 74 75 if(macho64 && (ndata & 1)) 76 ndata++; 77 78 l = &load[nload++]; 79 l->type = type; 80 l->ndata = ndata; 81 l->data = mal(ndata*4); 82 return l; 83 } 84 85 MachoSeg* 86 newMachoSeg(char *name, int msect) 87 { 88 MachoSeg *s; 89 90 if(nseg >= nelem(seg)) { 91 diag("too many segs"); 92 errorexit(); 93 } 94 s = &seg[nseg++]; 95 s->name = name; 96 s->msect = msect; 97 s->sect = mal(msect*sizeof s->sect[0]); 98 return s; 99 } 100 101 MachoSect* 102 newMachoSect(MachoSeg *seg, char *name, char *segname) 103 { 104 MachoSect *s; 105 106 if(seg->nsect >= seg->msect) { 107 diag("too many sects in segment %s", seg->name); 108 errorexit(); 109 } 110 s = &seg->sect[seg->nsect++]; 111 s->name = name; 112 s->segname = segname; 113 nsect++; 114 return s; 115 } 116 117 // Generic linking code. 118 119 static char **dylib; 120 static int ndylib; 121 122 static vlong linkoff; 123 124 int 125 machowrite(void) 126 { 127 vlong o1; 128 int loadsize; 129 int i, j; 130 MachoSeg *s; 131 MachoSect *t; 132 MachoLoad *l; 133 134 o1 = cpos(); 135 136 loadsize = 4*4*ndebug; 137 for(i=0; i<nload; i++) 138 loadsize += 4*(load[i].ndata+2); 139 if(macho64) { 140 loadsize += 18*4*nseg; 141 loadsize += 20*4*nsect; 142 } else { 143 loadsize += 14*4*nseg; 144 loadsize += 17*4*nsect; 145 } 146 147 if(macho64) 148 LPUT(0xfeedfacf); 149 else 150 LPUT(0xfeedface); 151 LPUT(hdr.cpu); 152 LPUT(hdr.subcpu); 153 if(linkmode == LinkExternal) 154 LPUT(1); /* file type - mach object */ 155 else 156 LPUT(2); /* file type - mach executable */ 157 LPUT(nload+nseg+ndebug); 158 LPUT(loadsize); 159 LPUT(1); /* flags - no undefines */ 160 if(macho64) 161 LPUT(0); /* reserved */ 162 163 for(i=0; i<nseg; i++) { 164 s = &seg[i]; 165 if(macho64) { 166 LPUT(25); /* segment 64 */ 167 LPUT(72+80*s->nsect); 168 strnput(s->name, 16); 169 VPUT(s->vaddr); 170 VPUT(s->vsize); 171 VPUT(s->fileoffset); 172 VPUT(s->filesize); 173 LPUT(s->prot1); 174 LPUT(s->prot2); 175 LPUT(s->nsect); 176 LPUT(s->flag); 177 } else { 178 LPUT(1); /* segment 32 */ 179 LPUT(56+68*s->nsect); 180 strnput(s->name, 16); 181 LPUT(s->vaddr); 182 LPUT(s->vsize); 183 LPUT(s->fileoffset); 184 LPUT(s->filesize); 185 LPUT(s->prot1); 186 LPUT(s->prot2); 187 LPUT(s->nsect); 188 LPUT(s->flag); 189 } 190 for(j=0; j<s->nsect; j++) { 191 t = &s->sect[j]; 192 if(macho64) { 193 strnput(t->name, 16); 194 strnput(t->segname, 16); 195 VPUT(t->addr); 196 VPUT(t->size); 197 LPUT(t->off); 198 LPUT(t->align); 199 LPUT(t->reloc); 200 LPUT(t->nreloc); 201 LPUT(t->flag); 202 LPUT(t->res1); /* reserved */ 203 LPUT(t->res2); /* reserved */ 204 LPUT(0); /* reserved */ 205 } else { 206 strnput(t->name, 16); 207 strnput(t->segname, 16); 208 LPUT(t->addr); 209 LPUT(t->size); 210 LPUT(t->off); 211 LPUT(t->align); 212 LPUT(t->reloc); 213 LPUT(t->nreloc); 214 LPUT(t->flag); 215 LPUT(t->res1); /* reserved */ 216 LPUT(t->res2); /* reserved */ 217 } 218 } 219 } 220 221 for(i=0; i<nload; i++) { 222 l = &load[i]; 223 LPUT(l->type); 224 LPUT(4*(l->ndata+2)); 225 for(j=0; j<l->ndata; j++) 226 LPUT(l->data[j]); 227 } 228 229 return cpos() - o1; 230 } 231 232 void 233 domacho(void) 234 { 235 Sym *s; 236 237 if(debug['d']) 238 return; 239 240 // empirically, string table must begin with " \x00". 241 s = lookup(".machosymstr", 0); 242 s->type = SMACHOSYMSTR; 243 s->reachable = 1; 244 adduint8(s, ' '); 245 adduint8(s, '\0'); 246 247 s = lookup(".machosymtab", 0); 248 s->type = SMACHOSYMTAB; 249 s->reachable = 1; 250 251 if(linkmode != LinkExternal) { 252 s = lookup(".plt", 0); // will be __symbol_stub 253 s->type = SMACHOPLT; 254 s->reachable = 1; 255 256 s = lookup(".got", 0); // will be __nl_symbol_ptr 257 s->type = SMACHOGOT; 258 s->reachable = 1; 259 s->align = 4; 260 261 s = lookup(".linkedit.plt", 0); // indirect table for .plt 262 s->type = SMACHOINDIRECTPLT; 263 s->reachable = 1; 264 265 s = lookup(".linkedit.got", 0); // indirect table for .got 266 s->type = SMACHOINDIRECTGOT; 267 s->reachable = 1; 268 } 269 } 270 271 void 272 machoadddynlib(char *lib) 273 { 274 // Will need to store the library name rounded up 275 // and 24 bytes of header metadata. If not enough 276 // space, grab another page of initial space at the 277 // beginning of the output file. 278 load_budget -= (strlen(lib)+7)/8*8 + 24; 279 if(load_budget < 0) { 280 HEADR += 4096; 281 INITTEXT += 4096; 282 load_budget += 4096; 283 } 284 285 if(ndylib%32 == 0) 286 dylib = erealloc(dylib, (ndylib+32)*sizeof dylib[0]); 287 dylib[ndylib++] = lib; 288 } 289 290 static void 291 machoshbits(MachoSeg *mseg, Section *sect, char *segname) 292 { 293 MachoSect *msect; 294 char buf[40]; 295 char *p; 296 297 snprint(buf, sizeof buf, "__%s", sect->name+1); 298 for(p=buf; *p; p++) 299 if(*p == '.') 300 *p = '_'; 301 302 msect = newMachoSect(mseg, estrdup(buf), segname); 303 if(sect->rellen > 0) { 304 msect->reloc = sect->reloff; 305 msect->nreloc = sect->rellen / 8; 306 } 307 308 while(1<<msect->align < sect->align) 309 msect->align++; 310 msect->addr = sect->vaddr; 311 msect->size = sect->len; 312 313 if(sect->vaddr < sect->seg->vaddr + sect->seg->filelen) { 314 // data in file 315 if(sect->len > sect->seg->vaddr + sect->seg->filelen - sect->vaddr) 316 diag("macho cannot represent section %s crossing data and bss", sect->name); 317 msect->off = sect->seg->fileoff + sect->vaddr - sect->seg->vaddr; 318 } else { 319 // zero fill 320 msect->off = 0; 321 msect->flag |= 1; 322 } 323 324 if(sect->rwx & 1) 325 msect->flag |= 0x400; /* has instructions */ 326 327 if(strcmp(sect->name, ".plt") == 0) { 328 msect->name = "__symbol_stub1"; 329 msect->flag = 0x80000408; /* only instructions, code, symbol stubs */ 330 msect->res1 = 0;//nkind[SymKindLocal]; 331 msect->res2 = 6; 332 } 333 334 if(strcmp(sect->name, ".got") == 0) { 335 msect->name = "__nl_symbol_ptr"; 336 msect->flag = 6; /* section with nonlazy symbol pointers */ 337 msect->res1 = lookup(".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */ 338 } 339 } 340 341 void 342 asmbmacho(void) 343 { 344 vlong v, w; 345 vlong va; 346 int a, i; 347 MachoHdr *mh; 348 MachoSeg *ms; 349 MachoLoad *ml; 350 Section *sect; 351 352 /* apple MACH */ 353 va = INITTEXT - HEADR; 354 mh = getMachoHdr(); 355 switch(thechar){ 356 default: 357 diag("unknown mach architecture"); 358 errorexit(); 359 case '6': 360 mh->cpu = MACHO_CPU_AMD64; 361 mh->subcpu = MACHO_SUBCPU_X86; 362 break; 363 case '8': 364 mh->cpu = MACHO_CPU_386; 365 mh->subcpu = MACHO_SUBCPU_X86; 366 break; 367 } 368 369 ms = nil; 370 if(linkmode == LinkExternal) { 371 /* segment for entire file */ 372 ms = newMachoSeg("", 40); 373 ms->fileoffset = segtext.fileoff; 374 ms->filesize = segdata.fileoff + segdata.filelen - segtext.fileoff; 375 } 376 377 /* segment for zero page */ 378 if(linkmode != LinkExternal) { 379 ms = newMachoSeg("__PAGEZERO", 0); 380 ms->vsize = va; 381 } 382 383 /* text */ 384 v = rnd(HEADR+segtext.len, INITRND); 385 if(linkmode != LinkExternal) { 386 ms = newMachoSeg("__TEXT", 20); 387 ms->vaddr = va; 388 ms->vsize = v; 389 ms->fileoffset = 0; 390 ms->filesize = v; 391 ms->prot1 = 7; 392 ms->prot2 = 5; 393 } 394 395 for(sect=segtext.sect; sect!=nil; sect=sect->next) 396 machoshbits(ms, sect, "__TEXT"); 397 398 /* data */ 399 if(linkmode != LinkExternal) { 400 w = segdata.len; 401 ms = newMachoSeg("__DATA", 20); 402 ms->vaddr = va+v; 403 ms->vsize = w; 404 ms->fileoffset = v; 405 ms->filesize = segdata.filelen; 406 ms->prot1 = 3; 407 ms->prot2 = 3; 408 } 409 410 for(sect=segdata.sect; sect!=nil; sect=sect->next) 411 machoshbits(ms, sect, "__DATA"); 412 413 if(linkmode != LinkExternal) { 414 switch(thechar) { 415 default: 416 diag("unknown macho architecture"); 417 errorexit(); 418 case '6': 419 ml = newMachoLoad(5, 42+2); /* unix thread */ 420 ml->data[0] = 4; /* thread type */ 421 ml->data[1] = 42; /* word count */ 422 ml->data[2+32] = entryvalue(); /* start pc */ 423 ml->data[2+32+1] = entryvalue()>>16>>16; // hide >>32 for 8l 424 break; 425 case '8': 426 ml = newMachoLoad(5, 16+2); /* unix thread */ 427 ml->data[0] = 1; /* thread type */ 428 ml->data[1] = 16; /* word count */ 429 ml->data[2+10] = entryvalue(); /* start pc */ 430 break; 431 } 432 } 433 434 if(!debug['d']) { 435 Sym *s1, *s2, *s3, *s4; 436 437 // must match domacholink below 438 s1 = lookup(".machosymtab", 0); 439 s2 = lookup(".linkedit.plt", 0); 440 s3 = lookup(".linkedit.got", 0); 441 s4 = lookup(".machosymstr", 0); 442 443 if(linkmode != LinkExternal) { 444 ms = newMachoSeg("__LINKEDIT", 0); 445 ms->vaddr = va+v+rnd(segdata.len, INITRND); 446 ms->vsize = s1->size + s2->size + s3->size + s4->size; 447 ms->fileoffset = linkoff; 448 ms->filesize = ms->vsize; 449 ms->prot1 = 7; 450 ms->prot2 = 3; 451 } 452 453 ml = newMachoLoad(2, 4); /* LC_SYMTAB */ 454 ml->data[0] = linkoff; /* symoff */ 455 ml->data[1] = nsortsym; /* nsyms */ 456 ml->data[2] = linkoff + s1->size + s2->size + s3->size; /* stroff */ 457 ml->data[3] = s4->size; /* strsize */ 458 459 machodysymtab(); 460 461 if(linkmode != LinkExternal) { 462 ml = newMachoLoad(14, 6); /* LC_LOAD_DYLINKER */ 463 ml->data[0] = 12; /* offset to string */ 464 strcpy((char*)&ml->data[1], "/usr/lib/dyld"); 465 466 for(i=0; i<ndylib; i++) { 467 ml = newMachoLoad(12, 4+(strlen(dylib[i])+1+7)/8*2); /* LC_LOAD_DYLIB */ 468 ml->data[0] = 24; /* offset of string from beginning of load */ 469 ml->data[1] = 0; /* time stamp */ 470 ml->data[2] = 0; /* version */ 471 ml->data[3] = 0; /* compatibility version */ 472 strcpy((char*)&ml->data[4], dylib[i]); 473 } 474 } 475 } 476 477 // TODO: dwarf headers go in ms too 478 if(!debug['s'] && linkmode != LinkExternal) 479 dwarfaddmachoheaders(); 480 481 a = machowrite(); 482 if(a > HEADR) 483 diag("HEADR too small: %d > %d", a, HEADR); 484 } 485 486 static int 487 symkind(Sym *s) 488 { 489 if(s->type == SDYNIMPORT) 490 return SymKindUndef; 491 if(s->cgoexport) 492 return SymKindExtdef; 493 return SymKindLocal; 494 } 495 496 static void 497 addsym(Sym *s, char *name, int type, vlong addr, vlong size, int ver, Sym *gotype) 498 { 499 USED(name); 500 USED(addr); 501 USED(size); 502 USED(ver); 503 USED(gotype); 504 505 if(s == nil) 506 return; 507 508 switch(type) { 509 default: 510 return; 511 case 'D': 512 case 'B': 513 case 'T': 514 break; 515 } 516 517 if(sortsym) { 518 sortsym[nsortsym] = s; 519 nkind[symkind(s)]++; 520 } 521 nsortsym++; 522 } 523 524 static int 525 scmp(const void *p1, const void *p2) 526 { 527 Sym *s1, *s2; 528 int k1, k2; 529 530 s1 = *(Sym**)p1; 531 s2 = *(Sym**)p2; 532 533 k1 = symkind(s1); 534 k2 = symkind(s2); 535 if(k1 != k2) 536 return k1 - k2; 537 538 return strcmp(s1->extname, s2->extname); 539 } 540 541 static void 542 machogenasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) 543 { 544 Sym *s; 545 546 genasmsym(put); 547 for(s=allsym; s; s=s->allsym) 548 if(s->type == SDYNIMPORT || s->type == SHOSTOBJ) 549 if(s->reachable) 550 put(s, nil, 'D', 0, 0, 0, nil); 551 } 552 553 void 554 machosymorder(void) 555 { 556 int i; 557 558 // On Mac OS X Mountain Lion, we must sort exported symbols 559 // So we sort them here and pre-allocate dynid for them 560 // See http://golang.org/issue/4029 561 for(i=0; i<ndynexp; i++) 562 dynexp[i]->reachable = 1; 563 machogenasmsym(addsym); 564 sortsym = mal(nsortsym * sizeof sortsym[0]); 565 nsortsym = 0; 566 machogenasmsym(addsym); 567 qsort(sortsym, nsortsym, sizeof sortsym[0], scmp); 568 for(i=0; i<nsortsym; i++) 569 sortsym[i]->dynid = i; 570 } 571 572 static void 573 machosymtab(void) 574 { 575 int i; 576 Sym *symtab, *symstr, *s, *o; 577 578 symtab = lookup(".machosymtab", 0); 579 symstr = lookup(".machosymstr", 0); 580 581 for(i=0; i<nsortsym; i++) { 582 s = sortsym[i]; 583 adduint32(symtab, symstr->size); 584 585 // Only add _ to C symbols. Go symbols have dot in the name. 586 if(strstr(s->extname, ".") == nil) 587 adduint8(symstr, '_'); 588 addstring(symstr, s->extname); 589 if(s->type == SDYNIMPORT || s->type == SHOSTOBJ) { 590 adduint8(symtab, 0x01); // type N_EXT, external symbol 591 adduint8(symtab, 0); // no section 592 adduint16(symtab, 0); // desc 593 adduintxx(symtab, 0, PtrSize); // no value 594 } else { 595 if(s->cgoexport) 596 adduint8(symtab, 0x0f); 597 else 598 adduint8(symtab, 0x0e); 599 o = s; 600 while(o->outer != nil) 601 o = o->outer; 602 if(o->sect == nil) { 603 diag("missing section for %s", s->name); 604 adduint8(symtab, 0); 605 } else 606 adduint8(symtab, o->sect->extnum); 607 adduint16(symtab, 0); // desc 608 adduintxx(symtab, symaddr(s), PtrSize); 609 } 610 } 611 } 612 613 static void 614 machodysymtab(void) 615 { 616 int n; 617 MachoLoad *ml; 618 Sym *s1, *s2, *s3; 619 620 ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */ 621 622 n = 0; 623 ml->data[0] = n; /* ilocalsym */ 624 ml->data[1] = nkind[SymKindLocal]; /* nlocalsym */ 625 n += nkind[SymKindLocal]; 626 627 ml->data[2] = n; /* iextdefsym */ 628 ml->data[3] = nkind[SymKindExtdef]; /* nextdefsym */ 629 n += nkind[SymKindExtdef]; 630 631 ml->data[4] = n; /* iundefsym */ 632 ml->data[5] = nkind[SymKindUndef]; /* nundefsym */ 633 634 ml->data[6] = 0; /* tocoffset */ 635 ml->data[7] = 0; /* ntoc */ 636 ml->data[8] = 0; /* modtaboff */ 637 ml->data[9] = 0; /* nmodtab */ 638 ml->data[10] = 0; /* extrefsymoff */ 639 ml->data[11] = 0; /* nextrefsyms */ 640 641 // must match domacholink below 642 s1 = lookup(".machosymtab", 0); 643 s2 = lookup(".linkedit.plt", 0); 644 s3 = lookup(".linkedit.got", 0); 645 ml->data[12] = linkoff + s1->size; /* indirectsymoff */ 646 ml->data[13] = (s2->size + s3->size) / 4; /* nindirectsyms */ 647 648 ml->data[14] = 0; /* extreloff */ 649 ml->data[15] = 0; /* nextrel */ 650 ml->data[16] = 0; /* locreloff */ 651 ml->data[17] = 0; /* nlocrel */ 652 } 653 654 vlong 655 domacholink(void) 656 { 657 int size; 658 Sym *s1, *s2, *s3, *s4; 659 660 machosymtab(); 661 662 // write data that will be linkedit section 663 s1 = lookup(".machosymtab", 0); 664 s2 = lookup(".linkedit.plt", 0); 665 s3 = lookup(".linkedit.got", 0); 666 s4 = lookup(".machosymstr", 0); 667 668 // Force the linkedit section to end on a 16-byte 669 // boundary. This allows pure (non-cgo) Go binaries 670 // to be code signed correctly. 671 // 672 // Apple's codesign_allocate (a helper utility for 673 // the codesign utility) can do this fine itself if 674 // it is run on a dynamic Mach-O binary. However, 675 // when it is run on a pure (non-cgo) Go binary, where 676 // the linkedit section is mostly empty, it fails to 677 // account for the extra padding that it itself adds 678 // when adding the LC_CODE_SIGNATURE load command 679 // (which must be aligned on a 16-byte boundary). 680 // 681 // By forcing the linkedit section to end on a 16-byte 682 // boundary, codesign_allocate will not need to apply 683 // any alignment padding itself, working around the 684 // issue. 685 while(s4->size%16) 686 adduint8(s4, 0); 687 688 size = s1->size + s2->size + s3->size + s4->size; 689 690 if(size > 0) { 691 linkoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND) + rnd(segdwarf.filelen, INITRND); 692 cseek(linkoff); 693 694 cwrite(s1->p, s1->size); 695 cwrite(s2->p, s2->size); 696 cwrite(s3->p, s3->size); 697 cwrite(s4->p, s4->size); 698 } 699 700 return rnd(size, INITRND); 701 } 702 703 704 void 705 machorelocsect(Section *sect, Sym *first) 706 { 707 Sym *sym; 708 int32 eaddr; 709 Reloc *r; 710 711 // If main section has no bits, nothing to relocate. 712 if(sect->vaddr >= sect->seg->vaddr + sect->seg->filelen) 713 return; 714 715 sect->reloff = cpos(); 716 for(sym = first; sym != nil; sym = sym->next) { 717 if(!sym->reachable) 718 continue; 719 if(sym->value >= sect->vaddr) 720 break; 721 } 722 723 eaddr = sect->vaddr + sect->len; 724 for(; sym != nil; sym = sym->next) { 725 if(!sym->reachable) 726 continue; 727 if(sym->value >= eaddr) 728 break; 729 cursym = sym; 730 731 for(r = sym->r; r < sym->r+sym->nr; r++) { 732 if(r->done) 733 continue; 734 if(machoreloc1(r, sym->value+r->off - sect->vaddr) < 0) 735 diag("unsupported obj reloc %d/%d to %s", r->type, r->siz, r->sym->name); 736 } 737 } 738 739 sect->rellen = cpos() - sect->reloff; 740 } 741 742 void 743 machoemitreloc(void) 744 { 745 Section *sect; 746 747 while(cpos()&7) 748 cput(0); 749 750 machorelocsect(segtext.sect, textp); 751 for(sect=segtext.sect->next; sect!=nil; sect=sect->next) 752 machorelocsect(sect, datap); 753 for(sect=segdata.sect; sect!=nil; sect=sect->next) 754 machorelocsect(sect, datap); 755 }