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