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