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