blob: fe7e10e466691249f8dee517a7a3ad3c7c5114c2 [file] [log] [blame]
Colin Cross7bb052a2015-02-03 12:59:37 -08001// 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
13static int macho64;
14static MachoHdr hdr;
15static MachoLoad *load;
16static MachoSeg seg[16];
17static int nload, mload, nseg, ndebug, nsect;
18
19enum
20{
21 SymKindLocal = 0,
22 SymKindExtdef,
23 SymKindUndef,
24 NumSymKind
25};
26
27static int nkind[NumSymKind];
28static LSym** sortsym;
29static 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.
37static int load_budget = INITIAL_MACHO_HEADR - 2*1024;
38
39static void machodysymtab(void);
40
41void
42machoinit(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
56MachoHdr*
57getMachoHdr(void)
58{
59 return &hdr;
60}
61
62MachoLoad*
63newMachoLoad(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
85MachoSeg*
86newMachoSeg(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
101MachoSect*
102newMachoSect(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
119static char **dylib;
120static int ndylib;
121
122static vlong linkoff;
123
124int
125machowrite(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
232void
233domacho(void)
234{
235 LSym *s;
236
237 if(debug['d'])
238 return;
239
240 // empirically, string table must begin with " \x00".
241 s = linklookup(ctxt, ".machosymstr", 0);
242 s->type = SMACHOSYMSTR;
243 s->reachable = 1;
244 adduint8(ctxt, s, ' ');
245 adduint8(ctxt, s, '\0');
246
247 s = linklookup(ctxt, ".machosymtab", 0);
248 s->type = SMACHOSYMTAB;
249 s->reachable = 1;
250
251 if(linkmode != LinkExternal) {
252 s = linklookup(ctxt, ".plt", 0); // will be __symbol_stub
253 s->type = SMACHOPLT;
254 s->reachable = 1;
255
256 s = linklookup(ctxt, ".got", 0); // will be __nl_symbol_ptr
257 s->type = SMACHOGOT;
258 s->reachable = 1;
259 s->align = 4;
260
261 s = linklookup(ctxt, ".linkedit.plt", 0); // indirect table for .plt
262 s->type = SMACHOINDIRECTPLT;
263 s->reachable = 1;
264
265 s = linklookup(ctxt, ".linkedit.got", 0); // indirect table for .got
266 s->type = SMACHOINDIRECTGOT;
267 s->reachable = 1;
268 }
269}
270
271void
272machoadddynlib(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
290static void
291machoshbits(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 = linklookup(ctxt, ".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */
338 }
339}
340
341void
342asmbmacho(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 LSym *s1, *s2, *s3, *s4;
436
437 // must match domacholink below
438 s1 = linklookup(ctxt, ".machosymtab", 0);
439 s2 = linklookup(ctxt, ".linkedit.plt", 0);
440 s3 = linklookup(ctxt, ".linkedit.got", 0);
441 s4 = linklookup(ctxt, ".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
486static int
487symkind(LSym *s)
488{
489 if(s->type == SDYNIMPORT)
490 return SymKindUndef;
491 if(s->cgoexport)
492 return SymKindExtdef;
493 return SymKindLocal;
494}
495
496static void
497addsym(LSym *s, char *name, int type, vlong addr, vlong size, int ver, LSym *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
524static int
525scmp(const void *p1, const void *p2)
526{
527 LSym *s1, *s2;
528 int k1, k2;
529
530 s1 = *(LSym**)p1;
531 s2 = *(LSym**)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
541static void
542machogenasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*))
543{
544 LSym *s;
545
546 genasmsym(put);
547 for(s=ctxt->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
553void
554machosymorder(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
572static void
573machosymtab(void)
574{
575 int i;
576 LSym *symtab, *symstr, *s, *o;
577 char *p;
578
579 symtab = linklookup(ctxt, ".machosymtab", 0);
580 symstr = linklookup(ctxt, ".machosymstr", 0);
581
582 for(i=0; i<nsortsym; i++) {
583 s = sortsym[i];
584 adduint32(ctxt, symtab, symstr->size);
585
586 // Only add _ to C symbols. Go symbols have dot in the name.
587 if(strstr(s->extname, ".") == nil)
588 adduint8(ctxt, symstr, '_');
589 // replace "·" as ".", because DTrace cannot handle it.
590 if(strstr(s->extname, "·") == nil) {
591 addstring(symstr, s->extname);
592 } else {
593 for(p = s->extname; *p; p++) {
594 if((uchar)*p == 0xc2 && (uchar)*(p+1) == 0xb7) {
595 adduint8(ctxt, symstr, '.');
596 p++;
597 } else {
598 adduint8(ctxt, symstr, *p);
599 }
600 }
601 adduint8(ctxt, symstr, '\0');
602 }
603 if(s->type == SDYNIMPORT || s->type == SHOSTOBJ) {
604 adduint8(ctxt, symtab, 0x01); // type N_EXT, external symbol
605 adduint8(ctxt, symtab, 0); // no section
606 adduint16(ctxt, symtab, 0); // desc
607 adduintxx(ctxt, symtab, 0, PtrSize); // no value
608 } else {
609 if(s->cgoexport)
610 adduint8(ctxt, symtab, 0x0f);
611 else
612 adduint8(ctxt, symtab, 0x0e);
613 o = s;
614 while(o->outer != nil)
615 o = o->outer;
616 if(o->sect == nil) {
617 diag("missing section for %s", s->name);
618 adduint8(ctxt, symtab, 0);
619 } else
620 adduint8(ctxt, symtab, o->sect->extnum);
621 adduint16(ctxt, symtab, 0); // desc
622 adduintxx(ctxt, symtab, symaddr(s), PtrSize);
623 }
624 }
625}
626
627static void
628machodysymtab(void)
629{
630 int n;
631 MachoLoad *ml;
632 LSym *s1, *s2, *s3;
633
634 ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */
635
636 n = 0;
637 ml->data[0] = n; /* ilocalsym */
638 ml->data[1] = nkind[SymKindLocal]; /* nlocalsym */
639 n += nkind[SymKindLocal];
640
641 ml->data[2] = n; /* iextdefsym */
642 ml->data[3] = nkind[SymKindExtdef]; /* nextdefsym */
643 n += nkind[SymKindExtdef];
644
645 ml->data[4] = n; /* iundefsym */
646 ml->data[5] = nkind[SymKindUndef]; /* nundefsym */
647
648 ml->data[6] = 0; /* tocoffset */
649 ml->data[7] = 0; /* ntoc */
650 ml->data[8] = 0; /* modtaboff */
651 ml->data[9] = 0; /* nmodtab */
652 ml->data[10] = 0; /* extrefsymoff */
653 ml->data[11] = 0; /* nextrefsyms */
654
655 // must match domacholink below
656 s1 = linklookup(ctxt, ".machosymtab", 0);
657 s2 = linklookup(ctxt, ".linkedit.plt", 0);
658 s3 = linklookup(ctxt, ".linkedit.got", 0);
659 ml->data[12] = linkoff + s1->size; /* indirectsymoff */
660 ml->data[13] = (s2->size + s3->size) / 4; /* nindirectsyms */
661
662 ml->data[14] = 0; /* extreloff */
663 ml->data[15] = 0; /* nextrel */
664 ml->data[16] = 0; /* locreloff */
665 ml->data[17] = 0; /* nlocrel */
666}
667
668vlong
669domacholink(void)
670{
671 int size;
672 LSym *s1, *s2, *s3, *s4;
673
674 machosymtab();
675
676 // write data that will be linkedit section
677 s1 = linklookup(ctxt, ".machosymtab", 0);
678 s2 = linklookup(ctxt, ".linkedit.plt", 0);
679 s3 = linklookup(ctxt, ".linkedit.got", 0);
680 s4 = linklookup(ctxt, ".machosymstr", 0);
681
682 // Force the linkedit section to end on a 16-byte
683 // boundary. This allows pure (non-cgo) Go binaries
684 // to be code signed correctly.
685 //
686 // Apple's codesign_allocate (a helper utility for
687 // the codesign utility) can do this fine itself if
688 // it is run on a dynamic Mach-O binary. However,
689 // when it is run on a pure (non-cgo) Go binary, where
690 // the linkedit section is mostly empty, it fails to
691 // account for the extra padding that it itself adds
692 // when adding the LC_CODE_SIGNATURE load command
693 // (which must be aligned on a 16-byte boundary).
694 //
695 // By forcing the linkedit section to end on a 16-byte
696 // boundary, codesign_allocate will not need to apply
697 // any alignment padding itself, working around the
698 // issue.
699 while(s4->size%16)
700 adduint8(ctxt, s4, 0);
701
702 size = s1->size + s2->size + s3->size + s4->size;
703
704 if(size > 0) {
705 linkoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND) + rnd(segdwarf.filelen, INITRND);
706 cseek(linkoff);
707
708 cwrite(s1->p, s1->size);
709 cwrite(s2->p, s2->size);
710 cwrite(s3->p, s3->size);
711 cwrite(s4->p, s4->size);
712 }
713
714 return rnd(size, INITRND);
715}
716
717
718void
719machorelocsect(Section *sect, LSym *first)
720{
721 LSym *sym;
722 int32 eaddr;
723 Reloc *r;
724
725 // If main section has no bits, nothing to relocate.
726 if(sect->vaddr >= sect->seg->vaddr + sect->seg->filelen)
727 return;
728
729 sect->reloff = cpos();
730 for(sym = first; sym != nil; sym = sym->next) {
731 if(!sym->reachable)
732 continue;
733 if(sym->value >= sect->vaddr)
734 break;
735 }
736
737 eaddr = sect->vaddr + sect->len;
738 for(; sym != nil; sym = sym->next) {
739 if(!sym->reachable)
740 continue;
741 if(sym->value >= eaddr)
742 break;
743 ctxt->cursym = sym;
744
745 for(r = sym->r; r < sym->r+sym->nr; r++) {
746 if(r->done)
747 continue;
748 if(machoreloc1(r, sym->value+r->off - sect->vaddr) < 0)
749 diag("unsupported obj reloc %d/%d to %s", r->type, r->siz, r->sym->name);
750 }
751 }
752
753 sect->rellen = cpos() - sect->reloff;
754}
755
756void
757machoemitreloc(void)
758{
759 Section *sect;
760
761 while(cpos()&7)
762 cput(0);
763
764 machorelocsect(segtext.sect, ctxt->textp);
765 for(sect=segtext.sect->next; sect!=nil; sect=sect->next)
766 machorelocsect(sect, datap);
767 for(sect=segdata.sect; sect!=nil; sect=sect->next)
768 machorelocsect(sect, datap);
769}