github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/cmd/8l/asm.c (about)

     1  // Inferno utils/8l/asm.c
     2  // http://code.google.com/p/inferno-os/source/browse/utils/8l/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  char linuxdynld[] = "/lib/ld-linux.so.2";
    41  char freebsddynld[] = "/usr/libexec/ld-elf.so.1";
    42  char openbsddynld[] = "/usr/libexec/ld.so";
    43  char netbsddynld[] = "/usr/libexec/ld.elf_so";
    44  char dragonflydynld[] = "/usr/libexec/ld-elf.so.2";
    45  
    46  int32
    47  entryvalue(void)
    48  {
    49  	char *a;
    50  	Sym *s;
    51  
    52  	a = INITENTRY;
    53  	if(*a >= '0' && *a <= '9')
    54  		return atolwhex(a);
    55  	s = lookup(a, 0);
    56  	if(s->type == 0)
    57  		return INITTEXT;
    58  	if(s->type != STEXT)
    59  		diag("entry not text: %s", s->name);
    60  	return s->value;
    61  }
    62  
    63  vlong
    64  datoff(vlong addr)
    65  {
    66  	if(addr >= segdata.vaddr)
    67  		return addr - segdata.vaddr + segdata.fileoff;
    68  	if(addr >= segtext.vaddr)
    69  		return addr - segtext.vaddr + segtext.fileoff;
    70  	diag("datoff %#llx", addr);
    71  	return 0;
    72  }
    73  
    74  static int
    75  needlib(char *name)
    76  {
    77  	char *p;
    78  	Sym *s;
    79  
    80  	if(*name == '\0')
    81  		return 0;
    82  
    83  	/* reuse hash code in symbol table */
    84  	p = smprint(".dynlib.%s", name);
    85  	s = lookup(p, 0);
    86  	free(p);
    87  	if(s->type == 0) {
    88  		s->type = 100;	// avoid SDATA, etc.
    89  		return 1;
    90  	}
    91  	return 0;
    92  }
    93  
    94  int	nelfsym = 1;
    95  
    96  static void	addpltsym(Sym*);
    97  static void	addgotsym(Sym*);
    98  
    99  void
   100  adddynrela(Sym *rela, Sym *s, Reloc *r)
   101  {
   102  	USED(rela);
   103  	USED(s);
   104  	USED(r);
   105  	sysfatal("adddynrela not implemented");
   106  }
   107  
   108  void
   109  adddynrel(Sym *s, Reloc *r)
   110  {
   111  	Sym *targ, *rel, *got;
   112  
   113  	targ = r->sym;
   114  	cursym = s;
   115  
   116  	switch(r->type) {
   117  	default:
   118  		if(r->type >= 256) {
   119  			diag("unexpected relocation type %d", r->type);
   120  			return;
   121  		}
   122  		break;
   123  
   124  	// Handle relocations found in ELF object files.
   125  	case 256 + R_386_PC32:
   126  		if(targ->type == SDYNIMPORT)
   127  			diag("unexpected R_386_PC32 relocation for dynamic symbol %s", targ->name);
   128  		if(targ->type == 0 || targ->type == SXREF)
   129  			diag("unknown symbol %s in pcrel", targ->name);
   130  		r->type = D_PCREL;
   131  		r->add += 4;
   132  		return;
   133  
   134  	case 256 + R_386_PLT32:
   135  		r->type = D_PCREL;
   136  		r->add += 4;
   137  		if(targ->type == SDYNIMPORT) {
   138  			addpltsym(targ);
   139  			r->sym = lookup(".plt", 0);
   140  			r->add += targ->plt;
   141  		}
   142  		return;		
   143  	
   144  	case 256 + R_386_GOT32:
   145  		if(targ->type != SDYNIMPORT) {
   146  			// have symbol
   147  			// turn MOVL of GOT entry into LEAL of symbol itself
   148  			if(r->off < 2 || s->p[r->off-2] != 0x8b) {
   149  				diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
   150  				return;
   151  			}
   152  			s->p[r->off-2] = 0x8d;
   153  			r->type = D_GOTOFF;
   154  			return;
   155  		}
   156  		addgotsym(targ);
   157  		r->type = D_CONST;	// write r->add during relocsym
   158  		r->sym = S;
   159  		r->add += targ->got;
   160  		return;
   161  	
   162  	case 256 + R_386_GOTOFF:
   163  		r->type = D_GOTOFF;
   164  		return;
   165  	
   166  	case 256 + R_386_GOTPC:
   167  		r->type = D_PCREL;
   168  		r->sym = lookup(".got", 0);
   169  		r->add += 4;
   170  		return;
   171  
   172  	case 256 + R_386_32:
   173  		if(targ->type == SDYNIMPORT)
   174  			diag("unexpected R_386_32 relocation for dynamic symbol %s", targ->name);
   175  		r->type = D_ADDR;
   176  		return;
   177  	
   178  	case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 0:
   179  		r->type = D_ADDR;
   180  		if(targ->type == SDYNIMPORT)
   181  			diag("unexpected reloc for dynamic symbol %s", targ->name);
   182  		return;
   183  	
   184  	case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 1:
   185  		if(targ->type == SDYNIMPORT) {
   186  			addpltsym(targ);
   187  			r->sym = lookup(".plt", 0);
   188  			r->add = targ->plt;
   189  			r->type = D_PCREL;
   190  			return;
   191  		}
   192  		r->type = D_PCREL;
   193  		return;
   194  	
   195  	case 512 + MACHO_FAKE_GOTPCREL:
   196  		if(targ->type != SDYNIMPORT) {
   197  			// have symbol
   198  			// turn MOVL of GOT entry into LEAL of symbol itself
   199  			if(r->off < 2 || s->p[r->off-2] != 0x8b) {
   200  				diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
   201  				return;
   202  			}
   203  			s->p[r->off-2] = 0x8d;
   204  			r->type = D_PCREL;
   205  			return;
   206  		}
   207  		addgotsym(targ);
   208  		r->sym = lookup(".got", 0);
   209  		r->add += targ->got;
   210  		r->type = D_PCREL;
   211  		return;
   212  	}
   213  	
   214  	// Handle references to ELF symbols from our own object files.
   215  	if(targ->type != SDYNIMPORT)
   216  		return;
   217  
   218  	switch(r->type) {
   219  	case D_PCREL:
   220  		addpltsym(targ);
   221  		r->sym = lookup(".plt", 0);
   222  		r->add = targ->plt;
   223  		return;
   224  	
   225  	case D_ADDR:
   226  		if(s->type != SDATA)
   227  			break;
   228  		if(iself) {
   229  			adddynsym(targ);
   230  			rel = lookup(".rel", 0);
   231  			addaddrplus(rel, s, r->off);
   232  			adduint32(rel, ELF32_R_INFO(targ->dynid, R_386_32));
   233  			r->type = D_CONST;	// write r->add during relocsym
   234  			r->sym = S;
   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(targ);
   249  			got = lookup(".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  			adduint32(got, 0);
   256  			adduint32(lookup(".linkedit.got", 0), targ->dynid);
   257  			r->type = 256;	// ignore during relocsym
   258  			return;
   259  		}
   260  		break;
   261  	}
   262  	
   263  	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  	LPUT(sectoff);
   273  
   274  	elfsym = r->xsym->elfsym;
   275  	switch(r->type) {
   276  	default:
   277  		return -1;
   278  
   279  	case D_ADDR:
   280  		if(r->siz == 4)
   281  			LPUT(R_386_32 | elfsym<<8);
   282  		else
   283  			return -1;
   284  		break;
   285  
   286  	case D_PCREL:
   287  		if(r->siz == 4)
   288  			LPUT(R_386_PC32 | elfsym<<8);
   289  		else
   290  			return -1;
   291  		break;
   292  	
   293  	case D_TLS:
   294  		if(r->siz == 4)
   295  			LPUT(R_386_TLS_LE | elfsym<<8);
   296  		else
   297  			return -1;
   298  	}
   299  
   300  	return 0;
   301  }
   302  
   303  int
   304  machoreloc1(Reloc *r, vlong sectoff)
   305  {
   306  	uint32 v;
   307  	Sym *rs;
   308  	
   309  	rs = r->xsym;
   310  
   311  	if(rs->type == SHOSTOBJ) {
   312  		if(rs->dynid < 0) {
   313  			diag("reloc %d to non-macho symbol %s type=%d", r->type, rs->name, rs->type);
   314  			return -1;
   315  		}
   316  		v = rs->dynid;			
   317  		v |= 1<<27; // external relocation
   318  	} else {
   319  		v = rs->sect->extnum;
   320  		if(v == 0) {
   321  			diag("reloc %d to symbol %s in non-macho section %s type=%d", r->type, rs->name, rs->sect->name, rs->type);
   322  			return -1;
   323  		}
   324  	}
   325  
   326  	switch(r->type) {
   327  	default:
   328  		return -1;
   329  	case D_ADDR:
   330  		v |= MACHO_GENERIC_RELOC_VANILLA<<28;
   331  		break;
   332  	case D_PCREL:
   333  		v |= 1<<24; // pc-relative bit
   334  		v |= MACHO_GENERIC_RELOC_VANILLA<<28;
   335  		break;
   336  	}
   337  	
   338  	switch(r->siz) {
   339  	default:
   340  		return -1;
   341  	case 1:
   342  		v |= 0<<25;
   343  		break;
   344  	case 2:
   345  		v |= 1<<25;
   346  		break;
   347  	case 4:
   348  		v |= 2<<25;
   349  		break;
   350  	case 8:
   351  		v |= 3<<25;
   352  		break;
   353  	}
   354  
   355  	LPUT(sectoff);
   356  	LPUT(v);
   357  	return 0;
   358  }
   359  
   360  int
   361  archreloc(Reloc *r, Sym *s, vlong *val)
   362  {
   363  	USED(s);
   364  	if(linkmode == LinkExternal)
   365  		return -1;
   366  	switch(r->type) {
   367  	case D_CONST:
   368  		*val = r->add;
   369  		return 0;
   370  	case D_GOTOFF:
   371  		*val = symaddr(r->sym) + r->add - symaddr(lookup(".got", 0));
   372  		return 0;
   373  	}
   374  	return -1;
   375  }
   376  
   377  void
   378  elfsetupplt(void)
   379  {
   380  	Sym *plt, *got;
   381  	
   382  	plt = lookup(".plt", 0);
   383  	got = lookup(".got.plt", 0);
   384  	if(plt->size == 0) {
   385  		// pushl got+4
   386  		adduint8(plt, 0xff);
   387  		adduint8(plt, 0x35);
   388  		addaddrplus(plt, got, 4);
   389  		
   390  		// jmp *got+8
   391  		adduint8(plt, 0xff);
   392  		adduint8(plt, 0x25);
   393  		addaddrplus(plt, got, 8);
   394  
   395  		// zero pad
   396  		adduint32(plt, 0);
   397  		
   398  		// assume got->size == 0 too
   399  		addaddrplus(got, lookup(".dynamic", 0), 0);
   400  		adduint32(got, 0);
   401  		adduint32(got, 0);
   402  	}
   403  }
   404  
   405  static void
   406  addpltsym(Sym *s)
   407  {
   408  	Sym *plt, *got, *rel;
   409  	
   410  	if(s->plt >= 0)
   411  		return;
   412  
   413  	adddynsym(s);
   414  	
   415  	if(iself) {
   416  		plt = lookup(".plt", 0);
   417  		got = lookup(".got.plt", 0);
   418  		rel = lookup(".rel.plt", 0);
   419  		if(plt->size == 0)
   420  			elfsetupplt();
   421  		
   422  		// jmpq *got+size
   423  		adduint8(plt, 0xff);
   424  		adduint8(plt, 0x25);
   425  		addaddrplus(plt, got, got->size);
   426  		
   427  		// add to got: pointer to current pos in plt
   428  		addaddrplus(got, plt, plt->size);
   429  		
   430  		// pushl $x
   431  		adduint8(plt, 0x68);
   432  		adduint32(plt, rel->size);
   433  		
   434  		// jmp .plt
   435  		adduint8(plt, 0xe9);
   436  		adduint32(plt, -(plt->size+4));
   437  		
   438  		// rel
   439  		addaddrplus(rel, got, got->size-4);
   440  		adduint32(rel, ELF32_R_INFO(s->dynid, R_386_JMP_SLOT));
   441  		
   442  		s->plt = plt->size - 16;
   443  	} else if(HEADTYPE == Hdarwin) {
   444  		// Same laziness as in 6l.
   445  		
   446  		Sym *plt;
   447  
   448  		plt = lookup(".plt", 0);
   449  
   450  		addgotsym(s);
   451  
   452  		adduint32(lookup(".linkedit.plt", 0), s->dynid);
   453  
   454  		// jmpq *got+size(IP)
   455  		s->plt = plt->size;
   456  
   457  		adduint8(plt, 0xff);
   458  		adduint8(plt, 0x25);
   459  		addaddrplus(plt, lookup(".got", 0), s->got);
   460  	} else {
   461  		diag("addpltsym: unsupported binary format");
   462  	}
   463  }
   464  
   465  static void
   466  addgotsym(Sym *s)
   467  {
   468  	Sym *got, *rel;
   469  	
   470  	if(s->got >= 0)
   471  		return;
   472  	
   473  	adddynsym(s);
   474  	got = lookup(".got", 0);
   475  	s->got = got->size;
   476  	adduint32(got, 0);
   477  	
   478  	if(iself) {
   479  		rel = lookup(".rel", 0);
   480  		addaddrplus(rel, got, s->got);
   481  		adduint32(rel, ELF32_R_INFO(s->dynid, R_386_GLOB_DAT));
   482  	} else if(HEADTYPE == Hdarwin) {
   483  		adduint32(lookup(".linkedit.got", 0), s->dynid);
   484  	} else {
   485  		diag("addgotsym: unsupported binary format");
   486  	}
   487  }
   488  
   489  void
   490  adddynsym(Sym *s)
   491  {
   492  	Sym *d;
   493  	int t;
   494  	char *name;
   495  	
   496  	if(s->dynid >= 0)
   497  		return;
   498  	
   499  	if(iself) {
   500  		s->dynid = nelfsym++;
   501  		
   502  		d = lookup(".dynsym", 0);
   503  
   504  		/* name */
   505  		name = s->extname;
   506  		adduint32(d, addstring(lookup(".dynstr", 0), name));
   507  		
   508  		/* value */
   509  		if(s->type == SDYNIMPORT)
   510  			adduint32(d, 0);
   511  		else
   512  			addaddr(d, s);
   513  		
   514  		/* size */
   515  		adduint32(d, 0);
   516  	
   517  		/* type */
   518  		t = STB_GLOBAL << 4;
   519  		if(s->cgoexport && (s->type&SMASK) == STEXT)
   520  			t |= STT_FUNC;
   521  		else
   522  			t |= STT_OBJECT;
   523  		adduint8(d, t);
   524  		adduint8(d, 0);
   525  	
   526  		/* shndx */
   527  		if(s->type == SDYNIMPORT)
   528  			adduint16(d, SHN_UNDEF);
   529  		else {
   530  			switch(s->type) {
   531  			default:
   532  			case STEXT:
   533  				t = 11;
   534  				break;
   535  			case SRODATA:
   536  				t = 12;
   537  				break;
   538  			case SDATA:
   539  				t = 13;
   540  				break;
   541  			case SBSS:
   542  				t = 14;
   543  				break;
   544  			}
   545  			adduint16(d, t);
   546  		}
   547  	} else if(HEADTYPE == Hdarwin) {
   548  		diag("adddynsym: missed symbol %s (%s)", s->name, s->extname);
   549  	} else if(HEADTYPE == Hwindows) {
   550  		// already taken care of
   551  	} else {
   552  		diag("adddynsym: unsupported binary format");
   553  	}
   554  }
   555  
   556  void
   557  adddynlib(char *lib)
   558  {
   559  	Sym *s;
   560  	
   561  	if(!needlib(lib))
   562  		return;
   563  	
   564  	if(iself) {
   565  		s = lookup(".dynstr", 0);
   566  		if(s->size == 0)
   567  			addstring(s, "");
   568  		elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib));
   569  	} else if(HEADTYPE == Hdarwin) {
   570  		machoadddynlib(lib);
   571  	} else if(HEADTYPE != Hwindows) {
   572  		diag("adddynlib: unsupported binary format");
   573  	}
   574  }
   575  
   576  void
   577  asmb(void)
   578  {
   579  	int32 v, magic;
   580  	uint32 symo, dwarfoff, machlink;
   581  	Section *sect;
   582  	Sym *sym;
   583  	int i;
   584  
   585  	if(debug['v'])
   586  		Bprint(&bso, "%5.2f asmb\n", cputime());
   587  	Bflush(&bso);
   588  
   589  	if(iself)
   590  		asmbelfsetup();
   591  
   592  	sect = segtext.sect;
   593  	cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
   594  	codeblk(sect->vaddr, sect->len);
   595  	for(sect = sect->next; sect != nil; sect = sect->next) {
   596  		cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
   597  		datblk(sect->vaddr, sect->len);
   598  	}
   599  	
   600  	if(segrodata.filelen > 0) {
   601  		if(debug['v'])
   602  			Bprint(&bso, "%5.2f rodatblk\n", cputime());
   603  		Bflush(&bso);
   604  
   605  		cseek(segrodata.fileoff);
   606  		datblk(segrodata.vaddr, segrodata.filelen);
   607  	}
   608  
   609  	if(debug['v'])
   610  		Bprint(&bso, "%5.2f datblk\n", cputime());
   611  	Bflush(&bso);
   612  
   613  	cseek(segdata.fileoff);
   614  	datblk(segdata.vaddr, segdata.filelen);
   615  
   616  	machlink = 0;
   617  	if(HEADTYPE == Hdarwin) {
   618  		if(debug['v'])
   619  			Bprint(&bso, "%5.2f dwarf\n", cputime());
   620  
   621  		dwarfoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND);
   622  		cseek(dwarfoff);
   623  
   624  		segdwarf.fileoff = cpos();
   625  		dwarfemitdebugsections();
   626  		segdwarf.filelen = cpos() - segdwarf.fileoff;
   627  
   628  		machlink = domacholink();
   629  	}
   630  
   631  	symsize = 0;
   632  	spsize = 0;
   633  	lcsize = 0;
   634  	symo = 0;
   635  	if(!debug['s']) {
   636  		// TODO: rationalize
   637  		if(debug['v'])
   638  			Bprint(&bso, "%5.2f sym\n", cputime());
   639  		Bflush(&bso);
   640  		switch(HEADTYPE) {
   641  		default:
   642  			if(iself)
   643  				goto Elfsym;
   644  		case Hgarbunix:
   645  			symo = rnd(HEADR+segtext.filelen, 8192)+segdata.filelen;
   646  			break;
   647  		case Hunixcoff:
   648  			symo = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
   649  			break;
   650  		case Hplan9x32:
   651  			symo = HEADR+segtext.filelen+segdata.filelen;
   652  			break;
   653  		case Hmsdoscom:
   654  		case Hmsdosexe:
   655  			debug['s'] = 1;
   656  			symo = HEADR+segtext.filelen+segdata.filelen;
   657  			break;
   658  		case Hdarwin:
   659  			symo = rnd(HEADR+segtext.filelen, INITRND)+rnd(segdata.filelen, INITRND)+machlink;
   660  			break;
   661  		Elfsym:
   662  			symo = rnd(HEADR+segtext.filelen, INITRND)+rnd(HEADR+segrodata.filelen, INITRND)+segdata.filelen;
   663  			symo = rnd(symo, INITRND);
   664  			break;
   665  		case Hwindows:
   666  			symo = rnd(HEADR+segtext.filelen, PEFILEALIGN)+segdata.filelen;
   667  			symo = rnd(symo, PEFILEALIGN);
   668  			break;
   669  		}
   670  		cseek(symo);
   671  		switch(HEADTYPE) {
   672  		default:
   673  			if(iself) {
   674  				if(debug['v'])
   675  					Bprint(&bso, "%5.2f elfsym\n", cputime());
   676  				asmelfsym();
   677  				cflush();
   678  				cwrite(elfstrdat, elfstrsize);
   679  
   680  				if(debug['v'])
   681  					Bprint(&bso, "%5.2f dwarf\n", cputime());
   682  				dwarfemitdebugsections();
   683  				
   684  				if(linkmode == LinkExternal)
   685  					elfemitreloc();
   686  			}
   687  			break;
   688  		case Hplan9x32:
   689  			asmplan9sym();
   690  			cflush();
   691  
   692  			sym = lookup("pclntab", 0);
   693  			if(sym != nil) {
   694  				lcsize = sym->np;
   695  				for(i=0; i < lcsize; i++)
   696  					cput(sym->p[i]);
   697  				
   698  				cflush();
   699  			}
   700  			break;
   701  		case Hwindows:
   702  			if(debug['v'])
   703  				Bprint(&bso, "%5.2f dwarf\n", cputime());
   704  			dwarfemitdebugsections();
   705  			break;
   706  		case Hdarwin:
   707  			if(linkmode == LinkExternal)
   708  				machoemitreloc();
   709  			break;
   710  		}
   711  	}
   712  	if(debug['v'])
   713  		Bprint(&bso, "%5.2f headr\n", cputime());
   714  	Bflush(&bso);
   715  	cseek(0L);
   716  	switch(HEADTYPE) {
   717  	default:
   718  	case Hgarbunix:	/* garbage */
   719  		lputb(0x160L<<16);		/* magic and sections */
   720  		lputb(0L);			/* time and date */
   721  		lputb(rnd(HEADR+segtext.filelen, 4096)+segdata.filelen);
   722  		lputb(symsize);			/* nsyms */
   723  		lputb((0x38L<<16)|7L);		/* size of optional hdr and flags */
   724  		lputb((0413<<16)|0437L);		/* magic and version */
   725  		lputb(rnd(HEADR+segtext.filelen, 4096));	/* sizes */
   726  		lputb(segdata.filelen);
   727  		lputb(segdata.len - segdata.filelen);
   728  		lputb(entryvalue());		/* va of entry */
   729  		lputb(INITTEXT-HEADR);		/* va of base of text */
   730  		lputb(segdata.vaddr);			/* va of base of data */
   731  		lputb(segdata.vaddr+segdata.filelen);		/* va of base of bss */
   732  		lputb(~0L);			/* gp reg mask */
   733  		lputb(0L);
   734  		lputb(0L);
   735  		lputb(0L);
   736  		lputb(0L);
   737  		lputb(~0L);			/* gp value ?? */
   738  		break;
   739  	case Hunixcoff:	/* unix coff */
   740  		/*
   741  		 * file header
   742  		 */
   743  		lputl(0x0004014c);		/* 4 sections, magic */
   744  		lputl(0);			/* unix time stamp */
   745  		lputl(0);			/* symbol table */
   746  		lputl(0);			/* nsyms */
   747  		lputl(0x0003001c);		/* flags, sizeof a.out header */
   748  		/*
   749  		 * a.out header
   750  		 */
   751  		lputl(0x10b);			/* magic, version stamp */
   752  		lputl(rnd(segtext.filelen, INITRND));	/* text sizes */
   753  		lputl(segdata.filelen);			/* data sizes */
   754  		lputl(segdata.len - segdata.filelen);			/* bss sizes */
   755  		lputb(entryvalue());		/* va of entry */
   756  		lputl(INITTEXT);		/* text start */
   757  		lputl(segdata.vaddr);			/* data start */
   758  		/*
   759  		 * text section header
   760  		 */
   761  		s8put(".text");
   762  		lputl(HEADR);			/* pa */
   763  		lputl(HEADR);			/* va */
   764  		lputl(segtext.filelen);		/* text size */
   765  		lputl(HEADR);			/* file offset */
   766  		lputl(0);			/* relocation */
   767  		lputl(0);			/* line numbers */
   768  		lputl(0);			/* relocation, line numbers */
   769  		lputl(0x20);			/* flags text only */
   770  		/*
   771  		 * data section header
   772  		 */
   773  		s8put(".data");
   774  		lputl(segdata.vaddr);			/* pa */
   775  		lputl(segdata.vaddr);			/* va */
   776  		lputl(segdata.filelen);			/* data size */
   777  		lputl(HEADR+segtext.filelen);		/* file offset */
   778  		lputl(0);			/* relocation */
   779  		lputl(0);			/* line numbers */
   780  		lputl(0);			/* relocation, line numbers */
   781  		lputl(0x40);			/* flags data only */
   782  		/*
   783  		 * bss section header
   784  		 */
   785  		s8put(".bss");
   786  		lputl(segdata.vaddr+segdata.filelen);		/* pa */
   787  		lputl(segdata.vaddr+segdata.filelen);		/* va */
   788  		lputl(segdata.len - segdata.filelen);			/* bss size */
   789  		lputl(0);			/* file offset */
   790  		lputl(0);			/* relocation */
   791  		lputl(0);			/* line numbers */
   792  		lputl(0);			/* relocation, line numbers */
   793  		lputl(0x80);			/* flags bss only */
   794  		/*
   795  		 * comment section header
   796  		 */
   797  		s8put(".comment");
   798  		lputl(0);			/* pa */
   799  		lputl(0);			/* va */
   800  		lputl(symsize+lcsize);		/* comment size */
   801  		lputl(HEADR+segtext.filelen+segdata.filelen);	/* file offset */
   802  		lputl(HEADR+segtext.filelen+segdata.filelen);	/* offset of syms */
   803  		lputl(HEADR+segtext.filelen+segdata.filelen+symsize);/* offset of line numbers */
   804  		lputl(0);			/* relocation, line numbers */
   805  		lputl(0x200);			/* flags comment only */
   806  		break;
   807  	case Hplan9x32:	/* plan9 */
   808  		magic = 4*11*11+7;
   809  		lputb(magic);		/* magic */
   810  		lputb(segtext.filelen);			/* sizes */
   811  		lputb(segdata.filelen);
   812  		lputb(segdata.len - segdata.filelen);
   813  		lputb(symsize);			/* nsyms */
   814  		lputb(entryvalue());		/* va of entry */
   815  		lputb(spsize);			/* sp offsets */
   816  		lputb(lcsize);			/* line offsets */
   817  		break;
   818  	case Hmsdoscom:
   819  		/* MS-DOS .COM */
   820  		break;
   821  	case Hmsdosexe:
   822  		/* fake MS-DOS .EXE */
   823  		v = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
   824  		wputl(0x5A4D);			/* 'MZ' */
   825  		wputl(v % 512);			/* bytes in last page */
   826  		wputl(rnd(v, 512)/512);		/* total number of pages */
   827  		wputl(0x0000);			/* number of reloc items */
   828  		v = rnd(HEADR-(INITTEXT & 0xFFFF), 16);
   829  		wputl(v/16);			/* size of header */
   830  		wputl(0x0000);			/* minimum allocation */
   831  		wputl(0xFFFF);			/* maximum allocation */
   832  		wputl(0x0000);			/* initial ss value */
   833  		wputl(0x0100);			/* initial sp value */
   834  		wputl(0x0000);			/* complemented checksum */
   835  		v = entryvalue();
   836  		wputl(v);			/* initial ip value (!) */
   837  		wputl(0x0000);			/* initial cs value */
   838  		wputl(0x0000);
   839  		wputl(0x0000);
   840  		wputl(0x003E);			/* reloc table offset */
   841  		wputl(0x0000);			/* overlay number */
   842  		break;
   843  	case Hdarwin:
   844  		asmbmacho();
   845  		break;
   846  	case Hlinux:
   847  	case Hfreebsd:
   848  	case Hnetbsd:
   849  	case Hopenbsd:
   850  	case Hdragonfly:
   851  		asmbelf(symo);
   852  		break;
   853  	case Hwindows:
   854  		asmbpe();
   855  		break;
   856  	}
   857  	cflush();
   858  }
   859  
   860  void
   861  s8put(char *n)
   862  {
   863  	char name[8];
   864  	int i;
   865  
   866  	strncpy(name, n, sizeof(name));
   867  	for(i=0; i<sizeof(name); i++)
   868  		cput(name[i]);
   869  }
   870  
   871  int32
   872  rnd(int32 v, int32 r)
   873  {
   874  	int32 c;
   875  
   876  	if(r <= 0)
   877  		return v;
   878  	v += r - 1;
   879  	c = v % r;
   880  	if(c < 0)
   881  		c += r;
   882  	v -= c;
   883  	return v;
   884  }