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