github.com/bgentry/go@v0.0.0-20150121062915-6cf5a733d54d/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  char solarisdynld[] = "/lib/ld.so.1";
    46  
    47  static int
    48  needlib(char *name)
    49  {
    50  	char *p;
    51  	LSym *s;
    52  
    53  	if(*name == '\0')
    54  		return 0;
    55  
    56  	/* reuse hash code in symbol table */
    57  	p = smprint(".dynlib.%s", name);
    58  	s = linklookup(ctxt, p, 0);
    59  	free(p);
    60  	if(s->type == 0) {
    61  		s->type = 100;	// avoid SDATA, etc.
    62  		return 1;
    63  	}
    64  	return 0;
    65  }
    66  
    67  int	nelfsym = 1;
    68  
    69  static void	addpltsym(Link*, LSym*);
    70  static void	addgotsym(Link*, LSym*);
    71  
    72  void
    73  gentext(void)
    74  {
    75  }
    76  
    77  void
    78  adddynrela(LSym *rela, LSym *s, Reloc *r)
    79  {
    80  	USED(rela);
    81  	USED(s);
    82  	USED(r);
    83  	sysfatal("adddynrela not implemented");
    84  }
    85  
    86  void
    87  adddynrel(LSym *s, Reloc *r)
    88  {
    89  	LSym *targ, *rel, *got;
    90  
    91  	targ = r->sym;
    92  	ctxt->cursym = s;
    93  
    94  	switch(r->type) {
    95  	default:
    96  		if(r->type >= 256) {
    97  			diag("unexpected relocation type %d", r->type);
    98  			return;
    99  		}
   100  		break;
   101  
   102  	// Handle relocations found in ELF object files.
   103  	case 256 + R_386_PC32:
   104  		if(targ->type == SDYNIMPORT)
   105  			diag("unexpected R_386_PC32 relocation for dynamic symbol %s", targ->name);
   106  		if(targ->type == 0 || targ->type == SXREF)
   107  			diag("unknown symbol %s in pcrel", targ->name);
   108  		r->type = R_PCREL;
   109  		r->add += 4;
   110  		return;
   111  
   112  	case 256 + R_386_PLT32:
   113  		r->type = R_PCREL;
   114  		r->add += 4;
   115  		if(targ->type == SDYNIMPORT) {
   116  			addpltsym(ctxt, targ);
   117  			r->sym = linklookup(ctxt, ".plt", 0);
   118  			r->add += targ->plt;
   119  		}
   120  		return;		
   121  	
   122  	case 256 + R_386_GOT32:
   123  		if(targ->type != SDYNIMPORT) {
   124  			// have symbol
   125  			if(r->off >= 2 && s->p[r->off-2] == 0x8b) {
   126  				// turn MOVL of GOT entry into LEAL of symbol address, relative to GOT.
   127  				s->p[r->off-2] = 0x8d;
   128  				r->type = R_GOTOFF;
   129  				return;
   130  			}
   131  			if(r->off >= 2 && s->p[r->off-2] == 0xff && s->p[r->off-1] == 0xb3) {
   132  				// turn PUSHL of GOT entry into PUSHL of symbol itself.
   133  				// use unnecessary SS prefix to keep instruction same length.
   134  				s->p[r->off-2] = 0x36;
   135  				s->p[r->off-1] = 0x68;
   136  				r->type = R_ADDR;
   137  				return;
   138  			}
   139  			diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
   140  			return;
   141  		}
   142  		addgotsym(ctxt, targ);
   143  		r->type = R_CONST;	// write r->add during relocsym
   144  		r->sym = S;
   145  		r->add += targ->got;
   146  		return;
   147  	
   148  	case 256 + R_386_GOTOFF:
   149  		r->type = R_GOTOFF;
   150  		return;
   151  	
   152  	case 256 + R_386_GOTPC:
   153  		r->type = R_PCREL;
   154  		r->sym = linklookup(ctxt, ".got", 0);
   155  		r->add += 4;
   156  		return;
   157  
   158  	case 256 + R_386_32:
   159  		if(targ->type == SDYNIMPORT)
   160  			diag("unexpected R_386_32 relocation for dynamic symbol %s", targ->name);
   161  		r->type = R_ADDR;
   162  		return;
   163  	
   164  	case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 0:
   165  		r->type = R_ADDR;
   166  		if(targ->type == SDYNIMPORT)
   167  			diag("unexpected reloc for dynamic symbol %s", targ->name);
   168  		return;
   169  	
   170  	case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 1:
   171  		if(targ->type == SDYNIMPORT) {
   172  			addpltsym(ctxt, targ);
   173  			r->sym = linklookup(ctxt, ".plt", 0);
   174  			r->add = targ->plt;
   175  			r->type = R_PCREL;
   176  			return;
   177  		}
   178  		r->type = R_PCREL;
   179  		return;
   180  	
   181  	case 512 + MACHO_FAKE_GOTPCREL:
   182  		if(targ->type != SDYNIMPORT) {
   183  			// have symbol
   184  			// turn MOVL of GOT entry into LEAL of symbol itself
   185  			if(r->off < 2 || s->p[r->off-2] != 0x8b) {
   186  				diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
   187  				return;
   188  			}
   189  			s->p[r->off-2] = 0x8d;
   190  			r->type = R_PCREL;
   191  			return;
   192  		}
   193  		addgotsym(ctxt, targ);
   194  		r->sym = linklookup(ctxt, ".got", 0);
   195  		r->add += targ->got;
   196  		r->type = R_PCREL;
   197  		return;
   198  	}
   199  	
   200  	// Handle references to ELF symbols from our own object files.
   201  	if(targ->type != SDYNIMPORT)
   202  		return;
   203  
   204  	switch(r->type) {
   205  	case R_CALL:
   206  	case R_PCREL:
   207  		addpltsym(ctxt, targ);
   208  		r->sym = linklookup(ctxt, ".plt", 0);
   209  		r->add = targ->plt;
   210  		return;
   211  	
   212  	case R_ADDR:
   213  		if(s->type != SDATA)
   214  			break;
   215  		if(iself) {
   216  			adddynsym(ctxt, targ);
   217  			rel = linklookup(ctxt, ".rel", 0);
   218  			addaddrplus(ctxt, rel, s, r->off);
   219  			adduint32(ctxt, rel, ELF32_R_INFO(targ->dynid, R_386_32));
   220  			r->type = R_CONST;	// write r->add during relocsym
   221  			r->sym = S;
   222  			return;
   223  		}
   224  		if(HEADTYPE == Hdarwin && s->size == PtrSize && r->off == 0) {
   225  			// Mach-O relocations are a royal pain to lay out.
   226  			// They use a compact stateful bytecode representation
   227  			// that is too much bother to deal with.
   228  			// Instead, interpret the C declaration
   229  			//	void *_Cvar_stderr = &stderr;
   230  			// as making _Cvar_stderr the name of a GOT entry
   231  			// for stderr.  This is separate from the usual GOT entry,
   232  			// just in case the C code assigns to the variable,
   233  			// and of course it only works for single pointers,
   234  			// but we only need to support cgo and that's all it needs.
   235  			adddynsym(ctxt, targ);
   236  			got = linklookup(ctxt, ".got", 0);
   237  			s->type = got->type | SSUB;
   238  			s->outer = got;
   239  			s->sub = got->sub;
   240  			got->sub = s;
   241  			s->value = got->size;
   242  			adduint32(ctxt, got, 0);
   243  			adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), targ->dynid);
   244  			r->type = 256;	// ignore during relocsym
   245  			return;
   246  		}
   247  		break;
   248  	}
   249  	
   250  	ctxt->cursym = s;
   251  	diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
   252  }
   253  
   254  int
   255  elfreloc1(Reloc *r, vlong sectoff)
   256  {
   257  	int32 elfsym;
   258  
   259  	LPUT(sectoff);
   260  
   261  	elfsym = r->xsym->elfsym;
   262  	switch(r->type) {
   263  	default:
   264  		return -1;
   265  
   266  	case R_ADDR:
   267  		if(r->siz == 4)
   268  			LPUT(R_386_32 | elfsym<<8);
   269  		else
   270  			return -1;
   271  		break;
   272  
   273  	case R_CALL:
   274  	case R_PCREL:
   275  		if(r->siz == 4)
   276  			LPUT(R_386_PC32 | elfsym<<8);
   277  		else
   278  			return -1;
   279  		break;
   280  	
   281  	case R_TLS_LE:
   282  	case R_TLS_IE:
   283  		if(r->siz == 4)
   284  			LPUT(R_386_TLS_LE | elfsym<<8);
   285  		else
   286  			return -1;
   287  	}
   288  
   289  	return 0;
   290  }
   291  
   292  int
   293  machoreloc1(Reloc *r, vlong sectoff)
   294  {
   295  	uint32 v;
   296  	LSym *rs;
   297  	
   298  	rs = r->xsym;
   299  
   300  	if(rs->type == SHOSTOBJ) {
   301  		if(rs->dynid < 0) {
   302  			diag("reloc %d to non-macho symbol %s type=%d", r->type, rs->name, rs->type);
   303  			return -1;
   304  		}
   305  		v = rs->dynid;			
   306  		v |= 1<<27; // external relocation
   307  	} else {
   308  		v = rs->sect->extnum;
   309  		if(v == 0) {
   310  			diag("reloc %d to symbol %s in non-macho section %s type=%d", r->type, rs->name, rs->sect->name, rs->type);
   311  			return -1;
   312  		}
   313  	}
   314  
   315  	switch(r->type) {
   316  	default:
   317  		return -1;
   318  	case R_ADDR:
   319  		v |= MACHO_GENERIC_RELOC_VANILLA<<28;
   320  		break;
   321  	case R_CALL:
   322  	case R_PCREL:
   323  		v |= 1<<24; // pc-relative bit
   324  		v |= MACHO_GENERIC_RELOC_VANILLA<<28;
   325  		break;
   326  	}
   327  	
   328  	switch(r->siz) {
   329  	default:
   330  		return -1;
   331  	case 1:
   332  		v |= 0<<25;
   333  		break;
   334  	case 2:
   335  		v |= 1<<25;
   336  		break;
   337  	case 4:
   338  		v |= 2<<25;
   339  		break;
   340  	case 8:
   341  		v |= 3<<25;
   342  		break;
   343  	}
   344  
   345  	LPUT(sectoff);
   346  	LPUT(v);
   347  	return 0;
   348  }
   349  
   350  int
   351  archreloc(Reloc *r, LSym *s, vlong *val)
   352  {
   353  	USED(s);
   354  	if(linkmode == LinkExternal)
   355  		return -1;
   356  	switch(r->type) {
   357  	case R_CONST:
   358  		*val = r->add;
   359  		return 0;
   360  	case R_GOTOFF:
   361  		*val = symaddr(r->sym) + r->add - symaddr(linklookup(ctxt, ".got", 0));
   362  		return 0;
   363  	}
   364  	return -1;
   365  }
   366  
   367  vlong
   368  archrelocvariant(Reloc *r, LSym *s, vlong t)
   369  {
   370  	USED(r);
   371  	USED(s);
   372  	sysfatal("unexpected relocation variant");
   373  	return t;
   374  }
   375  
   376  void
   377  elfsetupplt(void)
   378  {
   379  	LSym *plt, *got;
   380  	
   381  	plt = linklookup(ctxt, ".plt", 0);
   382  	got = linklookup(ctxt, ".got.plt", 0);
   383  	if(plt->size == 0) {
   384  		// pushl got+4
   385  		adduint8(ctxt, plt, 0xff);
   386  		adduint8(ctxt, plt, 0x35);
   387  		addaddrplus(ctxt, plt, got, 4);
   388  		
   389  		// jmp *got+8
   390  		adduint8(ctxt, plt, 0xff);
   391  		adduint8(ctxt, plt, 0x25);
   392  		addaddrplus(ctxt, plt, got, 8);
   393  
   394  		// zero pad
   395  		adduint32(ctxt, plt, 0);
   396  		
   397  		// assume got->size == 0 too
   398  		addaddrplus(ctxt, got, linklookup(ctxt, ".dynamic", 0), 0);
   399  		adduint32(ctxt, got, 0);
   400  		adduint32(ctxt, got, 0);
   401  	}
   402  }
   403  
   404  static void
   405  addpltsym(Link *ctxt, LSym *s)
   406  {
   407  	LSym *plt, *got, *rel;
   408  	
   409  	if(s->plt >= 0)
   410  		return;
   411  
   412  	adddynsym(ctxt, s);
   413  	
   414  	if(iself) {
   415  		plt = linklookup(ctxt, ".plt", 0);
   416  		got = linklookup(ctxt, ".got.plt", 0);
   417  		rel = linklookup(ctxt, ".rel.plt", 0);
   418  		if(plt->size == 0)
   419  			elfsetupplt();
   420  		
   421  		// jmpq *got+size
   422  		adduint8(ctxt, plt, 0xff);
   423  		adduint8(ctxt, plt, 0x25);
   424  		addaddrplus(ctxt, plt, got, got->size);
   425  		
   426  		// add to got: pointer to current pos in plt
   427  		addaddrplus(ctxt, got, plt, plt->size);
   428  		
   429  		// pushl $x
   430  		adduint8(ctxt, plt, 0x68);
   431  		adduint32(ctxt, plt, rel->size);
   432  		
   433  		// jmp .plt
   434  		adduint8(ctxt, plt, 0xe9);
   435  		adduint32(ctxt, plt, -(plt->size+4));
   436  		
   437  		// rel
   438  		addaddrplus(ctxt, rel, got, got->size-4);
   439  		adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_386_JMP_SLOT));
   440  		
   441  		s->plt = plt->size - 16;
   442  	} else if(HEADTYPE == Hdarwin) {
   443  		// Same laziness as in 6l.
   444  		
   445  		LSym *plt;
   446  
   447  		plt = linklookup(ctxt, ".plt", 0);
   448  
   449  		addgotsym(ctxt, s);
   450  
   451  		adduint32(ctxt, linklookup(ctxt, ".linkedit.plt", 0), s->dynid);
   452  
   453  		// jmpq *got+size(IP)
   454  		s->plt = plt->size;
   455  
   456  		adduint8(ctxt, plt, 0xff);
   457  		adduint8(ctxt, plt, 0x25);
   458  		addaddrplus(ctxt, plt, linklookup(ctxt, ".got", 0), s->got);
   459  	} else {
   460  		diag("addpltsym: unsupported binary format");
   461  	}
   462  }
   463  
   464  static void
   465  addgotsym(Link *ctxt, LSym *s)
   466  {
   467  	LSym *got, *rel;
   468  	
   469  	if(s->got >= 0)
   470  		return;
   471  	
   472  	adddynsym(ctxt, s);
   473  	got = linklookup(ctxt, ".got", 0);
   474  	s->got = got->size;
   475  	adduint32(ctxt, got, 0);
   476  	
   477  	if(iself) {
   478  		rel = linklookup(ctxt, ".rel", 0);
   479  		addaddrplus(ctxt, rel, got, s->got);
   480  		adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_386_GLOB_DAT));
   481  	} else if(HEADTYPE == Hdarwin) {
   482  		adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), s->dynid);
   483  	} else {
   484  		diag("addgotsym: unsupported binary format");
   485  	}
   486  }
   487  
   488  void
   489  adddynsym(Link *ctxt, LSym *s)
   490  {
   491  	LSym *d;
   492  	int t;
   493  	char *name;
   494  	
   495  	if(s->dynid >= 0)
   496  		return;
   497  	
   498  	if(iself) {
   499  		s->dynid = nelfsym++;
   500  		
   501  		d = linklookup(ctxt, ".dynsym", 0);
   502  
   503  		/* name */
   504  		name = s->extname;
   505  		adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name));
   506  		
   507  		/* value */
   508  		if(s->type == SDYNIMPORT)
   509  			adduint32(ctxt, d, 0);
   510  		else
   511  			addaddr(ctxt, d, s);
   512  		
   513  		/* size */
   514  		adduint32(ctxt, d, 0);
   515  	
   516  		/* type */
   517  		t = STB_GLOBAL << 4;
   518  		if(s->cgoexport && (s->type&SMASK) == STEXT)
   519  			t |= STT_FUNC;
   520  		else
   521  			t |= STT_OBJECT;
   522  		adduint8(ctxt, d, t);
   523  		adduint8(ctxt, d, 0);
   524  	
   525  		/* shndx */
   526  		if(s->type == SDYNIMPORT)
   527  			adduint16(ctxt, d, SHN_UNDEF);
   528  		else
   529  			adduint16(ctxt, d, 1);
   530  	} else if(HEADTYPE == Hdarwin) {
   531  		diag("adddynsym: missed symbol %s (%s)", s->name, s->extname);
   532  	} else if(HEADTYPE == Hwindows) {
   533  		// already taken care of
   534  	} else {
   535  		diag("adddynsym: unsupported binary format");
   536  	}
   537  }
   538  
   539  void
   540  adddynlib(char *lib)
   541  {
   542  	LSym *s;
   543  	
   544  	if(!needlib(lib))
   545  		return;
   546  	
   547  	if(iself) {
   548  		s = linklookup(ctxt, ".dynstr", 0);
   549  		if(s->size == 0)
   550  			addstring(s, "");
   551  		elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib));
   552  	} else if(HEADTYPE == Hdarwin) {
   553  		machoadddynlib(lib);
   554  	} else if(HEADTYPE != Hwindows) {
   555  		diag("adddynlib: unsupported binary format");
   556  	}
   557  }
   558  
   559  void
   560  asmb(void)
   561  {
   562  	int32 magic;
   563  	uint32 symo, dwarfoff, machlink;
   564  	Section *sect;
   565  	LSym *sym;
   566  	int i;
   567  
   568  	if(debug['v'])
   569  		Bprint(&bso, "%5.2f asmb\n", cputime());
   570  	Bflush(&bso);
   571  
   572  	if(iself)
   573  		asmbelfsetup();
   574  
   575  	sect = segtext.sect;
   576  	cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
   577  	codeblk(sect->vaddr, sect->len);
   578  	for(sect = sect->next; sect != nil; sect = sect->next) {
   579  		cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
   580  		datblk(sect->vaddr, sect->len);
   581  	}
   582  	
   583  	if(segrodata.filelen > 0) {
   584  		if(debug['v'])
   585  			Bprint(&bso, "%5.2f rodatblk\n", cputime());
   586  		Bflush(&bso);
   587  
   588  		cseek(segrodata.fileoff);
   589  		datblk(segrodata.vaddr, segrodata.filelen);
   590  	}
   591  
   592  	if(debug['v'])
   593  		Bprint(&bso, "%5.2f datblk\n", cputime());
   594  	Bflush(&bso);
   595  
   596  	cseek(segdata.fileoff);
   597  	datblk(segdata.vaddr, segdata.filelen);
   598  
   599  	machlink = 0;
   600  	if(HEADTYPE == Hdarwin) {
   601  		if(debug['v'])
   602  			Bprint(&bso, "%5.2f dwarf\n", cputime());
   603  
   604  		dwarfoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND);
   605  		cseek(dwarfoff);
   606  
   607  		segdwarf.fileoff = cpos();
   608  		dwarfemitdebugsections();
   609  		segdwarf.filelen = cpos() - segdwarf.fileoff;
   610  
   611  		machlink = domacholink();
   612  	}
   613  
   614  	symsize = 0;
   615  	spsize = 0;
   616  	lcsize = 0;
   617  	symo = 0;
   618  	if(!debug['s']) {
   619  		// TODO: rationalize
   620  		if(debug['v'])
   621  			Bprint(&bso, "%5.2f sym\n", cputime());
   622  		Bflush(&bso);
   623  		switch(HEADTYPE) {
   624  		default:
   625  			if(iself)
   626  				goto Elfsym;
   627  		case Hplan9:
   628  			symo = segdata.fileoff+segdata.filelen;
   629  			break;
   630  		case Hdarwin:
   631  			symo = segdata.fileoff+rnd(segdata.filelen, INITRND)+machlink;
   632  			break;
   633  		Elfsym:
   634  			symo = segdata.fileoff+segdata.filelen;
   635  			symo = rnd(symo, INITRND);
   636  			break;
   637  		case Hwindows:
   638  			symo = segdata.fileoff+segdata.filelen;
   639  			symo = rnd(symo, PEFILEALIGN);
   640  			break;
   641  		}
   642  		cseek(symo);
   643  		switch(HEADTYPE) {
   644  		default:
   645  			if(iself) {
   646  				if(debug['v'])
   647  					Bprint(&bso, "%5.2f elfsym\n", cputime());
   648  				asmelfsym();
   649  				cflush();
   650  				cwrite(elfstrdat, elfstrsize);
   651  
   652  				if(debug['v'])
   653  					Bprint(&bso, "%5.2f dwarf\n", cputime());
   654  				dwarfemitdebugsections();
   655  				
   656  				if(linkmode == LinkExternal)
   657  					elfemitreloc();
   658  			}
   659  			break;
   660  		case Hplan9:
   661  			asmplan9sym();
   662  			cflush();
   663  
   664  			sym = linklookup(ctxt, "pclntab", 0);
   665  			if(sym != nil) {
   666  				lcsize = sym->np;
   667  				for(i=0; i < lcsize; i++)
   668  					cput(sym->p[i]);
   669  				
   670  				cflush();
   671  			}
   672  			break;
   673  		case Hwindows:
   674  			if(debug['v'])
   675  				Bprint(&bso, "%5.2f dwarf\n", cputime());
   676  			dwarfemitdebugsections();
   677  			break;
   678  		case Hdarwin:
   679  			if(linkmode == LinkExternal)
   680  				machoemitreloc();
   681  			break;
   682  		}
   683  	}
   684  	if(debug['v'])
   685  		Bprint(&bso, "%5.2f headr\n", cputime());
   686  	Bflush(&bso);
   687  	cseek(0L);
   688  	switch(HEADTYPE) {
   689  	default:
   690  	case Hplan9:	/* plan9 */
   691  		magic = 4*11*11+7;
   692  		lputb(magic);		/* magic */
   693  		lputb(segtext.filelen);			/* sizes */
   694  		lputb(segdata.filelen);
   695  		lputb(segdata.len - segdata.filelen);
   696  		lputb(symsize);			/* nsyms */
   697  		lputb(entryvalue());		/* va of entry */
   698  		lputb(spsize);			/* sp offsets */
   699  		lputb(lcsize);			/* line offsets */
   700  		break;
   701  	case Hdarwin:
   702  		asmbmacho();
   703  		break;
   704  	case Hlinux:
   705  	case Hfreebsd:
   706  	case Hnetbsd:
   707  	case Hopenbsd:
   708  	case Hdragonfly:
   709  	case Hnacl:
   710  		asmbelf(symo);
   711  		break;
   712  	case Hwindows:
   713  		asmbpe();
   714  		break;
   715  	}
   716  	cflush();
   717  }
   718  
   719  void
   720  s8put(char *n)
   721  {
   722  	char name[8];
   723  	int i;
   724  
   725  	strncpy(name, n, sizeof(name));
   726  	for(i=0; i<sizeof(name); i++)
   727  		cput(name[i]);
   728  }
   729  
   730  int32
   731  rnd(int32 v, int32 r)
   732  {
   733  	int32 c;
   734  
   735  	if(r <= 0)
   736  		return v;
   737  	v += r - 1;
   738  	c = v % r;
   739  	if(c < 0)
   740  		c += r;
   741  	v -= c;
   742  	return v;
   743  }