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