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