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