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