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