github.com/ccccaoqing/test@v0.0.0-20220510085219-3985d23445c0/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  		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  	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  
   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 = linklookup(ctxt, ".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  		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  
   486  static int
   487  symkind(LSym *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(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  	
   524  static int
   525  scmp(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  
   541  static void
   542  machogenasmsym(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  			
   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  	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  
   627  static void
   628  machodysymtab(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  
   668  vlong
   669  domacholink(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  
   718  void
   719  machorelocsect(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  
   756  void
   757  machoemitreloc(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  }