github.com/golang-haiku/go-1.4.3@v0.0.0-20190609233734-1f5ae41cc308/src/cmd/5l/asm.c (about)

     1  // Inferno utils/5l/asm.c
     2  // http://code.google.com/p/inferno-os/source/browse/utils/5l/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  
    38  
    39  char linuxdynld[] = "/lib/ld-linux.so.3"; // 2 for OABI, 3 for EABI
    40  char freebsddynld[] = "/usr/libexec/ld-elf.so.1";
    41  char haikudynld[] = "XXX";
    42  char openbsddynld[] = "XXX";
    43  char netbsddynld[] = "/libexec/ld.elf_so";
    44  char dragonflydynld[] = "XXX";
    45  char solarisdynld[] = "XXX";
    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  static void	addgotsyminternal(Link*, LSym*);
    72  
    73  // Preserve highest 8 bits of a, and do addition to lower 24-bit
    74  // of a and b; used to adjust ARM branch intruction's target
    75  static int32
    76  braddoff(int32 a, int32 b)
    77  {
    78  	return (((uint32)a) & 0xff000000U) | (0x00ffffffU & (uint32)(a + b));
    79  }
    80  
    81  void
    82  adddynrela(LSym *rel, LSym *s, Reloc *r)
    83  {
    84  	addaddrplus(ctxt, rel, s, r->off);
    85  	adduint32(ctxt, rel, R_ARM_RELATIVE);
    86  }
    87  
    88  void
    89  adddynrel(LSym *s, Reloc *r)
    90  {
    91  	LSym *targ, *rel;
    92  
    93  	targ = r->sym;
    94  	ctxt->cursym = s;
    95  
    96  	switch(r->type) {
    97  	default:
    98  		if(r->type >= 256) {
    99  			diag("unexpected relocation type %d", r->type);
   100  			return;
   101  		}
   102  		break;
   103  
   104  	// Handle relocations found in ELF object files.
   105  	case 256 + R_ARM_PLT32:
   106  		r->type = R_CALLARM;
   107  		if(targ->type == SDYNIMPORT) {
   108  			addpltsym(ctxt, targ);
   109  			r->sym = linklookup(ctxt, ".plt", 0);
   110  			r->add = braddoff(r->add, targ->plt / 4);
   111  		}
   112  		return;
   113  
   114  	case 256 + R_ARM_THM_PC22: // R_ARM_THM_CALL
   115  		diag("R_ARM_THM_CALL, are you using -marm?");
   116  		errorexit();
   117  		return;
   118  
   119  	case 256 + R_ARM_GOT32: // R_ARM_GOT_BREL
   120  		if(targ->type != SDYNIMPORT) {
   121  			addgotsyminternal(ctxt, targ);
   122  		} else {
   123  			addgotsym(ctxt, targ);
   124  		}
   125  		r->type = R_CONST;	// write r->add during relocsym
   126  		r->sym = S;
   127  		r->add += targ->got;
   128  		return;
   129  
   130  	case 256 + R_ARM_GOT_PREL: // GOT(S) + A - P
   131  		if(targ->type != SDYNIMPORT) {
   132  			addgotsyminternal(ctxt, targ);
   133  		} else {
   134  			addgotsym(ctxt, targ);
   135  		}
   136  		r->type = R_PCREL;
   137  		r->sym = linklookup(ctxt, ".got", 0);
   138  		r->add += targ->got + 4;
   139  		return;
   140  
   141  	case 256 + R_ARM_GOTOFF: // R_ARM_GOTOFF32
   142  		r->type = R_GOTOFF;
   143  		return;
   144  
   145  	case 256 + R_ARM_GOTPC: // R_ARM_BASE_PREL
   146  		r->type = R_PCREL;
   147  		r->sym = linklookup(ctxt, ".got", 0);
   148  		r->add += 4;
   149  		return;
   150  
   151  	case 256 + R_ARM_CALL:
   152  		r->type = R_CALLARM;
   153  		if(targ->type == SDYNIMPORT) {
   154  			addpltsym(ctxt, targ);
   155  			r->sym = linklookup(ctxt, ".plt", 0);
   156  			r->add = braddoff(r->add, targ->plt / 4);
   157  		}
   158  		return;
   159  
   160  	case 256 + R_ARM_REL32: // R_ARM_REL32
   161  		r->type = R_PCREL;
   162  		r->add += 4;
   163  		return;
   164  
   165  	case 256 + R_ARM_ABS32: 
   166  		if(targ->type == SDYNIMPORT)
   167  			diag("unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ->name);
   168  		r->type = R_ADDR;
   169  		return;
   170  
   171  	case 256 + R_ARM_V4BX:
   172  		// we can just ignore this, because we are targeting ARM V5+ anyway
   173  		if(r->sym) {
   174  			// R_ARM_V4BX is ABS relocation, so this symbol is a dummy symbol, ignore it
   175  			r->sym->type = 0;
   176  		}
   177  		r->sym = S;
   178  		return;
   179  
   180  	case 256 + R_ARM_PC24:
   181  	case 256 + R_ARM_JUMP24:
   182  		r->type = R_CALLARM;
   183  		if(targ->type == SDYNIMPORT) {
   184  			addpltsym(ctxt, targ);
   185  			r->sym = linklookup(ctxt, ".plt", 0);
   186  			r->add = braddoff(r->add, targ->plt / 4);
   187  		}
   188  		return;
   189  	}
   190  	
   191  	// Handle references to ELF symbols from our own object files.
   192  	if(targ->type != SDYNIMPORT)
   193  		return;
   194  
   195  	switch(r->type) {
   196  	case R_CALLARM:
   197  		addpltsym(ctxt, targ);
   198  		r->sym = linklookup(ctxt, ".plt", 0);
   199  		r->add = targ->plt;
   200  		return;
   201  	
   202  	case R_ADDR:
   203  		if(s->type != SDATA)
   204  			break;
   205  		if(iself) {
   206  			adddynsym(ctxt, targ);
   207  			rel = linklookup(ctxt, ".rel", 0);
   208  			addaddrplus(ctxt, rel, s, r->off);
   209  			adduint32(ctxt, rel, ELF32_R_INFO(targ->dynid, R_ARM_GLOB_DAT)); // we need a S + A dynmic reloc
   210  			r->type = R_CONST;	// write r->add during relocsym
   211  			r->sym = S;
   212  			return;
   213  		}
   214  		break;
   215  	}
   216  
   217  	ctxt->cursym = s;
   218  	diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
   219  }
   220  
   221  int
   222  elfreloc1(Reloc *r, vlong sectoff)
   223  {
   224  	int32 elfsym;
   225  	
   226  	LPUT(sectoff);
   227  
   228  	elfsym = r->xsym->elfsym;
   229  	switch(r->type) {
   230  	default:
   231  		return -1;
   232  
   233  	case R_ADDR:
   234  		if(r->siz == 4)
   235  			LPUT(R_ARM_ABS32 | elfsym<<8);
   236  		else
   237  			return -1;
   238  		break;
   239  
   240  	case R_PCREL:
   241  		if(r->siz == 4)
   242  			LPUT(R_ARM_REL32 | elfsym<<8);
   243  		else
   244  			return -1;
   245  		break;
   246  
   247  	case R_CALLARM:
   248  		if(r->siz == 4) {
   249  			if((r->add & 0xff000000) == 0xeb000000) // BL
   250  				LPUT(R_ARM_CALL | elfsym<<8);
   251  			else
   252  				LPUT(R_ARM_JUMP24 | elfsym<<8);
   253  		} else
   254  			return -1;
   255  		break;
   256  
   257  	case R_TLS:
   258  		if(r->siz == 4) {
   259  			if(flag_shared)
   260  				LPUT(R_ARM_TLS_IE32 | elfsym<<8);
   261  			else
   262  				LPUT(R_ARM_TLS_LE32 | elfsym<<8);
   263  		} else
   264  			return -1;
   265  		break;
   266  	}
   267  
   268  	return 0;
   269  }
   270  
   271  void
   272  elfsetupplt(void)
   273  {
   274  	LSym *plt, *got;
   275  	
   276  	plt = linklookup(ctxt, ".plt", 0);
   277  	got = linklookup(ctxt, ".got.plt", 0);
   278  	if(plt->size == 0) {
   279  		// str lr, [sp, #-4]!
   280  		adduint32(ctxt, plt, 0xe52de004);
   281  		// ldr lr, [pc, #4]
   282  		adduint32(ctxt, plt, 0xe59fe004);
   283  		// add lr, pc, lr
   284  		adduint32(ctxt, plt, 0xe08fe00e);
   285  		// ldr pc, [lr, #8]!
   286  		adduint32(ctxt, plt, 0xe5bef008);
   287  		// .word &GLOBAL_OFFSET_TABLE[0] - .
   288  		addpcrelplus(ctxt, plt, got, 4);
   289  
   290  		// the first .plt entry requires 3 .plt.got entries
   291  		adduint32(ctxt, got, 0);
   292  		adduint32(ctxt, got, 0);
   293  		adduint32(ctxt, got, 0);
   294  	}
   295  }
   296  
   297  int
   298  machoreloc1(Reloc *r, vlong sectoff)
   299  {
   300  	USED(r);
   301  	USED(sectoff);
   302  
   303  	return -1;
   304  }
   305  
   306  
   307  int
   308  archreloc(Reloc *r, LSym *s, vlong *val)
   309  {
   310  	LSym *rs;
   311  
   312  	if(linkmode == LinkExternal) {
   313  		switch(r->type) {
   314  		case R_CALLARM:
   315  			r->done = 0;
   316  
   317  			// set up addend for eventual relocation via outer symbol.
   318  			rs = r->sym;
   319  			r->xadd = r->add;
   320  			if(r->xadd & 0x800000)
   321  				r->xadd |= ~0xffffff;
   322  			r->xadd *= 4;
   323  			while(rs->outer != nil) {
   324  				r->xadd += symaddr(rs) - symaddr(rs->outer);
   325  				rs = rs->outer;
   326  			}
   327  
   328  			if(rs->type != SHOSTOBJ && rs->sect == nil)
   329  				diag("missing section for %s", rs->name);
   330  			r->xsym = rs;
   331  
   332  			*val = braddoff((0xff000000U & (uint32)r->add), 
   333  							(0xffffff & (uint32)(r->xadd / 4)));
   334  			return 0;
   335  		}
   336  		return -1;
   337  	}
   338  	switch(r->type) {
   339  	case R_CONST:
   340  		*val = r->add;
   341  		return 0;
   342  	case R_GOTOFF:
   343  		*val = symaddr(r->sym) + r->add - symaddr(linklookup(ctxt, ".got", 0));
   344  		return 0;
   345  	// The following three arch specific relocations are only for generation of 
   346  	// Linux/ARM ELF's PLT entry (3 assembler instruction)
   347  	case R_PLT0: // add ip, pc, #0xXX00000
   348  		if (symaddr(linklookup(ctxt, ".got.plt", 0)) < symaddr(linklookup(ctxt, ".plt", 0)))
   349  			diag(".got.plt should be placed after .plt section.");
   350  		*val = 0xe28fc600U +
   351  			(0xff & ((uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add) >> 20));
   352  		return 0;
   353  	case R_PLT1: // add ip, ip, #0xYY000
   354  		*val = 0xe28cca00U +
   355  			(0xff & ((uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add + 4) >> 12));
   356  		return 0;
   357  	case R_PLT2: // ldr pc, [ip, #0xZZZ]!
   358  		*val = 0xe5bcf000U +
   359  			(0xfff & (uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add + 8));
   360  		return 0;
   361  	case R_CALLARM: // bl XXXXXX or b YYYYYY
   362  		*val = braddoff((0xff000000U & (uint32)r->add), 
   363  		                (0xffffff & (uint32)
   364  		                   ((symaddr(r->sym) + ((uint32)r->add) * 4 - (s->value + r->off)) / 4)));
   365  		return 0;
   366  	}
   367  	return -1;
   368  }
   369  
   370  static Reloc *
   371  addpltreloc(Link *ctxt, LSym *plt, LSym *got, LSym *sym, int typ)
   372  {
   373  	Reloc *r;
   374  
   375  	r = addrel(plt);
   376  	r->sym = got;
   377  	r->off = plt->size;
   378  	r->siz = 4;
   379  	r->type = typ;
   380  	r->add = sym->got - 8;
   381  
   382  	plt->reachable = 1;
   383  	plt->size += 4;
   384  	symgrow(ctxt, plt, plt->size);
   385  
   386  	return r;
   387  }
   388  
   389  static void
   390  addpltsym(Link *ctxt, LSym *s)
   391  {
   392  	LSym *plt, *got, *rel;
   393  	
   394  	if(s->plt >= 0)
   395  		return;
   396  
   397  	adddynsym(ctxt, s);
   398  	
   399  	if(iself) {
   400  		plt = linklookup(ctxt, ".plt", 0);
   401  		got = linklookup(ctxt, ".got.plt", 0);
   402  		rel = linklookup(ctxt, ".rel.plt", 0);
   403  		if(plt->size == 0)
   404  			elfsetupplt();
   405  		
   406  		// .got entry
   407  		s->got = got->size;
   408  		// In theory, all GOT should point to the first PLT entry,
   409  		// Linux/ARM's dynamic linker will do that for us, but FreeBSD/ARM's
   410  		// dynamic linker won't, so we'd better do it ourselves.
   411  		addaddrplus(ctxt, got, plt, 0);
   412  
   413  		// .plt entry, this depends on the .got entry
   414  		s->plt = plt->size;
   415  		addpltreloc(ctxt, plt, got, s, R_PLT0); // add lr, pc, #0xXX00000
   416  		addpltreloc(ctxt, plt, got, s, R_PLT1); // add lr, lr, #0xYY000
   417  		addpltreloc(ctxt, plt, got, s, R_PLT2); // ldr pc, [lr, #0xZZZ]!
   418  
   419  		// rel
   420  		addaddrplus(ctxt, rel, got, s->got);
   421  		adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_ARM_JUMP_SLOT));
   422  	} else {
   423  		diag("addpltsym: unsupported binary format");
   424  	}
   425  }
   426  
   427  static void
   428  addgotsyminternal(Link *ctxt, LSym *s)
   429  {
   430  	LSym *got;
   431  	
   432  	if(s->got >= 0)
   433  		return;
   434  
   435  	got = linklookup(ctxt, ".got", 0);
   436  	s->got = got->size;
   437  
   438  	addaddrplus(ctxt, got, s, 0);
   439  
   440  	if(iself) {
   441  		;
   442  	} else {
   443  		diag("addgotsyminternal: unsupported binary format");
   444  	}
   445  }
   446  
   447  static void
   448  addgotsym(Link *ctxt, LSym *s)
   449  {
   450  	LSym *got, *rel;
   451  	
   452  	if(s->got >= 0)
   453  		return;
   454  	
   455  	adddynsym(ctxt, s);
   456  	got = linklookup(ctxt, ".got", 0);
   457  	s->got = got->size;
   458  	adduint32(ctxt, got, 0);
   459  	
   460  	if(iself) {
   461  		rel = linklookup(ctxt, ".rel", 0);
   462  		addaddrplus(ctxt, rel, got, s->got);
   463  		adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_ARM_GLOB_DAT));
   464  	} else {
   465  		diag("addgotsym: unsupported binary format");
   466  	}
   467  }
   468  
   469  void
   470  adddynsym(Link *ctxt, LSym *s)
   471  {
   472  	LSym *d;
   473  	int t;
   474  	char *name;
   475  
   476  	if(s->dynid >= 0)
   477  		return;
   478  
   479  	if(iself) {
   480  		s->dynid = nelfsym++;
   481  
   482  		d = linklookup(ctxt, ".dynsym", 0);
   483  
   484  		/* name */
   485  		name = s->extname;
   486  		adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name));
   487  
   488  		/* value */
   489  		if(s->type == SDYNIMPORT)
   490  			adduint32(ctxt, d, 0);
   491  		else
   492  			addaddr(ctxt, d, s);
   493  
   494  		/* size */
   495  		adduint32(ctxt, d, 0);
   496  
   497  		/* type */
   498  		t = STB_GLOBAL << 4;
   499  		if((s->cgoexport & CgoExportDynamic) && (s->type&SMASK) == STEXT)
   500  			t |= STT_FUNC;
   501  		else
   502  			t |= STT_OBJECT;
   503  		adduint8(ctxt, d, t);
   504  		adduint8(ctxt, d, 0);
   505  
   506  		/* shndx */
   507  		if(s->type == SDYNIMPORT)
   508  			adduint16(ctxt, d, SHN_UNDEF);
   509  		else {
   510  			switch(s->type) {
   511  			default:
   512  			case STEXT:
   513  				t = 11;
   514  				break;
   515  			case SRODATA:
   516  				t = 12;
   517  				break;
   518  			case SDATA:
   519  				t = 13;
   520  				break;
   521  			case SBSS:
   522  				t = 14;
   523  				break;
   524  			}
   525  			adduint16(ctxt, d, t);
   526  		}
   527  	} else {
   528  		diag("adddynsym: unsupported binary format");
   529  	}
   530  }
   531  
   532  void
   533  adddynlib(char *lib)
   534  {
   535  	LSym *s;
   536  	
   537  	if(!needlib(lib))
   538  		return;
   539  	
   540  	if(iself) {
   541  		s = linklookup(ctxt, ".dynstr", 0);
   542  		if(s->size == 0)
   543  			addstring(s, "");
   544  		elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib));
   545  	} else {
   546  		diag("adddynlib: unsupported binary format");
   547  	}
   548  }
   549  
   550  void
   551  asmb(void)
   552  {
   553  	uint32 symo;
   554  	Section *sect;
   555  	LSym *sym;
   556  	int i;
   557  
   558  	if(debug['v'])
   559  		Bprint(&bso, "%5.2f asmb\n", cputime());
   560  	Bflush(&bso);
   561  
   562  	if(iself)
   563  		asmbelfsetup();
   564  
   565  	sect = segtext.sect;
   566  	cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
   567  	codeblk(sect->vaddr, sect->len);
   568  	for(sect = sect->next; sect != nil; sect = sect->next) {
   569  		cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
   570  		datblk(sect->vaddr, sect->len);
   571  	}
   572  
   573  	if(segrodata.filelen > 0) {
   574  		if(debug['v'])
   575  			Bprint(&bso, "%5.2f rodatblk\n", cputime());
   576  		Bflush(&bso);
   577  
   578  		cseek(segrodata.fileoff);
   579  		datblk(segrodata.vaddr, segrodata.filelen);
   580  	}
   581  
   582  	if(debug['v'])
   583  		Bprint(&bso, "%5.2f datblk\n", cputime());
   584  	Bflush(&bso);
   585  
   586  	cseek(segdata.fileoff);
   587  	datblk(segdata.vaddr, segdata.filelen);
   588  
   589  	/* output symbol table */
   590  	symsize = 0;
   591  	lcsize = 0;
   592  	symo = 0;
   593  	if(!debug['s']) {
   594  		// TODO: rationalize
   595  		if(debug['v'])
   596  			Bprint(&bso, "%5.2f sym\n", cputime());
   597  		Bflush(&bso);
   598  		switch(HEADTYPE) {
   599  		default:
   600  			if(iself)
   601  				goto ElfSym;
   602  		case Hplan9:
   603  			symo = segdata.fileoff+segdata.filelen;
   604  			break;
   605  		ElfSym:
   606  			symo = segdata.fileoff+segdata.filelen;
   607  			symo = rnd(symo, INITRND);
   608  			break;
   609  		}
   610  		cseek(symo);
   611  		switch(HEADTYPE) {
   612  		default:
   613  			if(iself) {
   614  				if(debug['v'])
   615  					Bprint(&bso, "%5.2f elfsym\n", cputime());
   616  				asmelfsym();
   617  				cflush();
   618  				cwrite(elfstrdat, elfstrsize);
   619  	
   620  				if(debug['v'])
   621  					Bprint(&bso, "%5.2f dwarf\n", cputime());
   622  				dwarfemitdebugsections();
   623  				
   624  				if(linkmode == LinkExternal)
   625  					elfemitreloc();
   626  			}
   627  			break;
   628  		case Hplan9:
   629  			asmplan9sym();
   630  			cflush();
   631  
   632  			sym = linklookup(ctxt, "pclntab", 0);
   633  			if(sym != nil) {
   634  				lcsize = sym->np;
   635  				for(i=0; i < lcsize; i++)
   636  					cput(sym->p[i]);
   637  
   638  				cflush();
   639  			}
   640  			break;
   641  		}
   642  	}
   643  
   644  	ctxt->cursym = nil;
   645  	if(debug['v'])
   646  		Bprint(&bso, "%5.2f header\n", cputime());
   647  	Bflush(&bso);
   648  	cseek(0L);
   649  	switch(HEADTYPE) {
   650  	default:
   651  	case Hplan9:	/* plan 9 */
   652  		LPUT(0x647);			/* magic */
   653  		LPUT(segtext.filelen);			/* sizes */
   654  		LPUT(segdata.filelen);
   655  		LPUT(segdata.len - segdata.filelen);
   656  		LPUT(symsize);			/* nsyms */
   657  		LPUT(entryvalue());		/* va of entry */
   658  		LPUT(0L);
   659  		LPUT(lcsize);
   660  		break;
   661  	case Hlinux:
   662  	case Hfreebsd:
   663  	case Hnetbsd:
   664  	case Hopenbsd:
   665  	case Hnacl:
   666  		asmbelf(symo);
   667  		break;
   668  	}
   669  	cflush();
   670  	if(debug['c']){
   671  		print("textsize=%ulld\n", segtext.filelen);
   672  		print("datsize=%ulld\n", segdata.filelen);
   673  		print("bsssize=%ulld\n", segdata.len - segdata.filelen);
   674  		print("symsize=%d\n", symsize);
   675  		print("lcsize=%d\n", lcsize);
   676  		print("total=%lld\n", segtext.filelen+segdata.len+symsize+lcsize);
   677  	}
   678  }
   679  
   680  int32
   681  rnd(int32 v, int32 r)
   682  {
   683  	int32 c;
   684  
   685  	if(r <= 0)
   686  		return v;
   687  	v += r - 1;
   688  	c = v % r;
   689  	if(c < 0)
   690  		c += r;
   691  	v -= c;
   692  	return v;
   693  }