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