github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/5l/obj.c (about)

     1  // Inferno utils/5l/obj.c
     2  // http://code.google.com/p/inferno-os/source/browse/utils/5l/obj.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  // Reading object files.
    32  
    33  #define	EXTERN
    34  #include	"l.h"
    35  #include	"../ld/lib.h"
    36  #include	"../ld/elf.h"
    37  #include	"../ld/dwarf.h"
    38  #include	<ar.h>
    39  
    40  #ifndef	DEFAULT
    41  #define	DEFAULT	'9'
    42  #endif
    43  
    44  char	*noname		= "<none>";
    45  char	*thestring 	= "arm";
    46  
    47  Header headers[] = {
    48     "noheader", Hnoheader,
    49     "risc", Hrisc,
    50     "plan9", Hplan9x32,
    51     "ixp1200", Hixp1200,
    52     "ipaq", Hipaq,
    53     "linux", Hlinux,
    54     "freebsd", Hfreebsd,
    55     "netbsd", Hnetbsd,
    56     0, 0
    57  };
    58  
    59  /*
    60   *	-Hrisc -T0x10005000 -R4		is aif for risc os
    61   *	-Hplan9 -T4128 -R4096		is plan9 format
    62   *	-Hixp1200			is IXP1200 (raw)
    63   *	-Hipaq -T0xC0008010 -R1024	is ipaq
    64   *	-Hlinux -Tx -Rx			is linux elf
    65   *	-Hfreebsd			is freebsd elf
    66   *	-Hnetbsd			is netbsd elf
    67   */
    68  
    69  void
    70  main(int argc, char *argv[])
    71  {
    72  	char *p;
    73  	Sym *s;
    74  
    75  	Binit(&bso, 1, OWRITE);
    76  	listinit();
    77  	nerrors = 0;
    78  	outfile = "5.out";
    79  	HEADTYPE = -1;
    80  	INITTEXT = -1;
    81  	INITDAT = -1;
    82  	INITRND = -1;
    83  	INITENTRY = 0;
    84  	LIBINITENTRY = 0;
    85  	linkmode = LinkInternal; // TODO: LinkAuto once everything works.
    86  	nuxiinit();
    87  	
    88  	p = getgoarm();
    89  	if(p != nil)
    90  		goarm = atoi(p);
    91  	else
    92  		goarm = 6;
    93  	if(goarm == 5)
    94  		debug['F'] = 1;
    95  
    96  	flagcount("1", "use alternate profiling code", &debug['1']);
    97  	flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo);
    98  	flagstr("E", "sym: entry symbol", &INITENTRY);
    99  	flagint32("D", "addr: data address", &INITDAT);
   100  	flagcount("G", "debug pseudo-ops", &debug['G']);
   101  	flagfn1("I", "interp: set ELF interp", setinterp);
   102  	flagfn1("L", "dir: add dir to library path", Lflag);
   103  	flagfn1("H", "head: header type", setheadtype);
   104  	flagcount("K", "add stack underflow checks", &debug['K']);
   105  	flagcount("M", "disable software div/mod", &debug['M']);
   106  	flagcount("O", "print pc-line tables", &debug['O']);
   107  	flagcount("P", "debug code generation", &debug['P']);
   108  	flagint32("R", "rnd: address rounding", &INITRND);
   109  	flagint32("T", "addr: text address", &INITTEXT);
   110  	flagfn0("V", "print version and exit", doversion);
   111  	flagcount("W", "disassemble input", &debug['W']);
   112  	flagfn2("X", "name value: define string data", addstrdata);
   113  	flagcount("Z", "clear stack frame on entry", &debug['Z']);
   114  	flagcount("a", "disassemble output", &debug['a']);
   115  	flagcount("c", "dump call graph", &debug['c']);
   116  	flagcount("d", "disable dynamic executable", &debug['d']);
   117  	flagstr("extld", "linker to run in external mode", &extld);
   118  	flagstr("extldflags", "flags for external linker", &extldflags);
   119  	flagcount("f", "ignore version mismatch", &debug['f']);
   120  	flagcount("g", "disable go package data checks", &debug['g']);
   121  	flagstr("k", "sym: set field tracking symbol", &tracksym);
   122  	flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode);
   123  	flagcount("n", "dump symbol table", &debug['n']);
   124  	flagstr("o", "outfile: set output file", &outfile);
   125  	flagcount("p", "insert profiling code", &debug['p']);
   126  	flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath);
   127  	flagcount("race", "enable race detector", &flag_race);
   128  	flagcount("s", "disable symbol table", &debug['s']);
   129  	flagstr("tmpdir", "leave temporary files in this directory", &tmpdir);
   130  	flagcount("u", "reject unsafe packages", &debug['u']);
   131  	flagcount("v", "print link trace", &debug['v']);
   132  	flagcount("w", "disable DWARF generation", &debug['w']);
   133  	flagcount("shared", "generate shared object", &flag_shared);
   134  	// TODO: link mode flag
   135  	
   136  	flagparse(&argc, &argv, usage);
   137  
   138  	if(argc != 1)
   139  		usage();
   140  
   141  	// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
   142  	// Go was built; see ../../make.bash.
   143  	if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0)
   144  		linkmode = LinkInternal;
   145  
   146  	if(linkmode == LinkExternal) {
   147  		diag("only -linkmode=internal is supported");
   148  		errorexit();
   149  	} else if(linkmode == LinkAuto) {
   150  		linkmode = LinkInternal;
   151  	}
   152  
   153  	libinit();
   154  
   155  	if(HEADTYPE == -1)
   156  		HEADTYPE = headtype(goos);
   157  	switch(HEADTYPE) {
   158  	default:
   159  		diag("unknown -H option");
   160  		errorexit();
   161  	case Hnoheader:	/* no header */
   162  		HEADR = 0L;
   163  		if(INITTEXT == -1)
   164  			INITTEXT = 0;
   165  		if(INITDAT == -1)
   166  			INITDAT = 0;
   167  		if(INITRND == -1)
   168  			INITRND = 4;
   169  		break;
   170  	case Hrisc:	/* aif for risc os */
   171  		HEADR = 128L;
   172  		if(INITTEXT == -1)
   173  			INITTEXT = 0x10005000 + HEADR;
   174  		if(INITDAT == -1)
   175  			INITDAT = 0;
   176  		if(INITRND == -1)
   177  			INITRND = 4;
   178  		break;
   179  	case Hplan9x32:	/* plan 9 */
   180  		HEADR = 32L;
   181  		if(INITTEXT == -1)
   182  			INITTEXT = 4128;
   183  		if(INITDAT == -1)
   184  			INITDAT = 0;
   185  		if(INITRND == -1)
   186  			INITRND = 4096;
   187  		break;
   188  	case Hixp1200: /* boot for IXP1200 */
   189  		HEADR = 0L;
   190  		if(INITTEXT == -1)
   191  			INITTEXT = 0x0;
   192  		if(INITDAT == -1)
   193  			INITDAT = 0;
   194  		if(INITRND == -1)
   195  			INITRND = 4;
   196  		break;
   197  	case Hipaq: /* boot for ipaq */
   198  		HEADR = 16L;
   199  		if(INITTEXT == -1)
   200  			INITTEXT = 0xC0008010;
   201  		if(INITDAT == -1)
   202  			INITDAT = 0;
   203  		if(INITRND == -1)
   204  			INITRND = 1024;
   205  		break;
   206  	case Hlinux:	/* arm elf */
   207  	case Hfreebsd:
   208  	case Hnetbsd:
   209  		debug['d'] = 0;	// with dynamic linking
   210  		tlsoffset = -8; // hardcoded number, first 4-byte word for g, and then 4-byte word for m
   211  		                // this number is known to ../../pkg/runtime/cgo/gcc_linux_arm.c
   212  		elfinit();
   213  		HEADR = ELFRESERVE;
   214  		if(INITTEXT == -1)
   215  			INITTEXT = 0x10000 + HEADR;
   216  		if(INITDAT == -1)
   217  			INITDAT = 0;
   218  		if(INITRND == -1)
   219  			INITRND = 4096;
   220  		break;
   221  	}
   222  	if(INITDAT != 0 && INITRND != 0)
   223  		print("warning: -D0x%ux is ignored because of -R0x%ux\n",
   224  			INITDAT, INITRND);
   225  	if(debug['v'])
   226  		Bprint(&bso, "HEADER = -H0x%d -T0x%ux -D0x%ux -R0x%ux\n",
   227  			HEADTYPE, INITTEXT, INITDAT, INITRND);
   228  	Bflush(&bso);
   229  	zprg.as = AGOK;
   230  	zprg.scond = 14;
   231  	zprg.reg = NREG;
   232  	zprg.from.name = D_NONE;
   233  	zprg.from.type = D_NONE;
   234  	zprg.from.reg = NREG;
   235  	zprg.to = zprg.from;
   236  	buildop();
   237  	histgen = 0;
   238  	pc = 0;
   239  	dtype = 4;
   240  
   241  	version = 0;
   242  	cbp = buf.cbuf;
   243  	cbc = sizeof(buf.cbuf);
   244  
   245  	// embed goarm to runtime.goarm
   246  	s = lookup("runtime.goarm", 0);
   247  	s->dupok = 1;
   248  	adduint8(s, goarm);
   249  
   250  	addlibpath("command line", "command line", argv[0], "main");
   251  	loadlib();
   252  
   253  	// mark some functions that are only referenced after linker code editing
   254  	if(debug['F'])
   255  		mark(rlookup("_sfloat", 0));
   256  	deadcode();
   257  	if(textp == nil) {
   258  		diag("no code");
   259  		errorexit();
   260  	}
   261  
   262  	patch();
   263  	if(debug['p'])
   264  		if(debug['1'])
   265  			doprof1();
   266  		else
   267  			doprof2();
   268  	doelf();
   269  	follow();
   270  	softfloat();
   271  	// 5l -Z means zero the stack frame on entry.
   272  	// This slows down function calls but can help avoid
   273  	// false positives in garbage collection.
   274  	if(debug['Z'])
   275  		dozerostk();
   276  	noops(); // generate stack split prolog, handle div/mod, etc.
   277  	dostkcheck();
   278  	span();
   279  	addexport();
   280  	// textaddress() functionality is handled in span()
   281  	pclntab();
   282  	symtab();
   283  	dodata();
   284  	address();
   285  	doweak();
   286  	reloc();
   287  	asmb();
   288  	undef();
   289  	hostlink();
   290  
   291  	if(debug['c'])
   292  		print("ARM size = %d\n", armsize);
   293  	if(debug['v']) {
   294  		Bprint(&bso, "%5.2f cpu time\n", cputime());
   295  		Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
   296  		Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
   297  	}
   298  	Bflush(&bso);
   299  	errorexit();
   300  }
   301  
   302  static Sym*
   303  zsym(char *pn, Biobuf *f, Sym *h[])
   304  {	
   305  	int o;
   306  	
   307  	o = BGETC(f);
   308  	if(o == 0)
   309  		return S;
   310  	if(o < 0 || o >= NSYM || h[o] == nil)
   311  		mangle(pn);
   312  	return h[o];
   313  }
   314  
   315  static void
   316  zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[])
   317  {
   318  	int i, c;
   319  	int32 l;
   320  	Sym *s;
   321  	Auto *u;
   322  
   323  	a->type = BGETC(f);
   324  	a->reg = BGETC(f);
   325  	c = BGETC(f);
   326  	if(c < 0 || c > NSYM){
   327  		print("sym out of range: %d\n", c);
   328  		Bputc(f, ALAST+1);
   329  		return;
   330  	}
   331  	a->sym = h[c];
   332  	a->name = BGETC(f);
   333  	adrgotype = zsym(pn, f, h);
   334  
   335  	if((schar)a->reg < 0 || a->reg > NREG) {
   336  		print("register out of range %d\n", a->reg);
   337  		Bputc(f, ALAST+1);
   338  		return;	/*  force real diagnostic */
   339  	}
   340  
   341  	if(a->type == D_CONST || a->type == D_OCONST) {
   342  		if(a->name == D_EXTERN || a->name == D_STATIC) {
   343  			s = a->sym;
   344  			if(s != S && (s->type == STEXT || s->type == SCONST || s->type == SXREF)) {
   345  				if(0 && !s->fnptr && s->name[0] != '.')
   346  					print("%s used as function pointer\n", s->name);
   347  				s->fnptr = 1;	// over the top cos of SXREF
   348  			}
   349  		}
   350  	}
   351  
   352  	switch(a->type) {
   353  	default:
   354  		print("unknown type %d\n", a->type);
   355  		Bputc(f, ALAST+1);
   356  		return;	/*  force real diagnostic */
   357  
   358  	case D_NONE:
   359  	case D_REG:
   360  	case D_FREG:
   361  	case D_PSR:
   362  	case D_FPCR:
   363  		break;
   364  
   365  	case D_REGREG:
   366  	case D_REGREG2:
   367  		a->offset = BGETC(f);
   368  		break;
   369  
   370  	case D_CONST2:
   371  		a->offset2 = Bget4(f);	// fall through
   372  	case D_BRANCH:
   373  	case D_OREG:
   374  	case D_CONST:
   375  	case D_OCONST:
   376  	case D_SHIFT:
   377  		a->offset = Bget4(f);
   378  		break;
   379  
   380  	case D_SCONST:
   381  		a->sval = mal(NSNAME);
   382  		Bread(f, a->sval, NSNAME);
   383  		break;
   384  
   385  	case D_FCONST:
   386  		a->ieee.l = Bget4(f);
   387  		a->ieee.h = Bget4(f);
   388  		break;
   389  	}
   390  	s = a->sym;
   391  	if(s == S)
   392  		return;
   393  	i = a->name;
   394  	if(i != D_AUTO && i != D_PARAM) {
   395  		if(s && adrgotype)
   396  			s->gotype = adrgotype;
   397  		return;
   398  	}
   399  
   400  	l = a->offset;
   401  	for(u=curauto; u; u=u->link)
   402  		if(u->asym == s)
   403  		if(u->type == i) {
   404  			if(u->aoffset > l)
   405  				u->aoffset = l;
   406  			if(adrgotype)
   407  				u->gotype = adrgotype;
   408  			return;
   409  		}
   410  
   411  	u = mal(sizeof(Auto));
   412  	u->link = curauto;
   413  	curauto = u;
   414  	u->asym = s;
   415  	u->aoffset = l;
   416  	u->type = i;
   417  	u->gotype = adrgotype;
   418  }
   419  
   420  void
   421  nopout(Prog *p)
   422  {
   423  	p->as = ANOP;
   424  	p->from.type = D_NONE;
   425  	p->to.type = D_NONE;
   426  }
   427  
   428  void
   429  ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
   430  {
   431  	int32 ipc;
   432  	Prog *p;
   433  	Sym *h[NSYM], *s;
   434  	int v, o, r, skip;
   435  	uint32 sig;
   436  	char *name;
   437  	int ntext;
   438  	int32 eof;
   439  	char src[1024], *x;
   440  	Prog *lastp;
   441  
   442  	lastp = nil;
   443  	ntext = 0;
   444  	eof = Boffset(f) + len;
   445  	src[0] = 0;
   446  	pn = estrdup(pn); // we keep it in Sym* references
   447  
   448  newloop:
   449  	memset(h, 0, sizeof(h));
   450  	version++;
   451  	histfrogp = 0;
   452  	ipc = pc;
   453  	skip = 0;
   454  
   455  loop:
   456  	if(f->state == Bracteof || Boffset(f) >= eof)
   457  		goto eof;
   458  	o = BGETC(f);
   459  	if(o == Beof)
   460  		goto eof;
   461  
   462  	if(o <= AXXX || o >= ALAST) {
   463  		diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o);
   464  		print("	probably not a .5 file\n");
   465  		errorexit();
   466  	}
   467  	if(o == ANAME || o == ASIGNAME) {
   468  		sig = 0;
   469  		if(o == ASIGNAME)
   470  			sig = Bget4(f);
   471  		v = BGETC(f); /* type */
   472  		o = BGETC(f); /* sym */
   473  		r = 0;
   474  		if(v == D_STATIC)
   475  			r = version;
   476  		name = Brdline(f, '\0');
   477  		if(name == nil) {
   478  			if(Blinelen(f) > 0) {
   479  				fprint(2, "%s: name too long\n", pn);
   480  				errorexit();
   481  			}
   482  			goto eof;
   483  		}
   484  		x = expandpkg(name, pkg);
   485  		s = lookup(x, r);
   486  		if(x != name)
   487  			free(x);
   488  
   489  		if(sig != 0){
   490  			if(s->sig != 0 && s->sig != sig)
   491  				diag("incompatible type signatures %ux(%s) and %ux(%s) for %s", s->sig, s->file, sig, pn, s->name);
   492  			s->sig = sig;
   493  			s->file = pn;
   494  		}
   495  
   496  		if(debug['W'])
   497  			print("	ANAME	%s\n", s->name);
   498  		if(o < 0 || o >= nelem(h)) {
   499  			fprint(2, "%s: mangled input file\n", pn);
   500  			errorexit();
   501  		}
   502  		h[o] = s;
   503  		if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
   504  			s->type = SXREF;
   505  		if(v == D_FILE) {
   506  			if(s->type != SFILE) {
   507  				histgen++;
   508  				s->type = SFILE;
   509  				s->value = histgen;
   510  			}
   511  			if(histfrogp < MAXHIST) {
   512  				histfrog[histfrogp] = s;
   513  				histfrogp++;
   514  			} else
   515  				collapsefrog(s);
   516  			dwarfaddfrag(s->value, s->name);
   517  		}
   518  		goto loop;
   519  	}
   520  
   521  	p = mal(sizeof(Prog));
   522  	p->as = o;
   523  	p->scond = BGETC(f);
   524  	p->reg = BGETC(f);
   525  	p->line = Bget4(f);
   526  
   527  	zaddr(pn, f, &p->from, h);
   528  	fromgotype = adrgotype;
   529  	zaddr(pn, f, &p->to, h);
   530  
   531  	if(p->as != ATEXT && p->as != AGLOBL && p->reg > NREG)
   532  		diag("register out of range %A %d", p->as, p->reg);
   533  
   534  	p->link = P;
   535  	p->cond = P;
   536  
   537  	if(debug['W'])
   538  		print("%P\n", p);
   539  
   540  	switch(o) {
   541  	case AHISTORY:
   542  		if(p->to.offset == -1) {
   543  			addlib(src, pn);
   544  			histfrogp = 0;
   545  			goto loop;
   546  		}
   547  		if(src[0] == '\0')
   548  			copyhistfrog(src, sizeof src);
   549  		addhist(p->line, D_FILE);		/* 'z' */
   550  		if(p->to.offset)
   551  			addhist(p->to.offset, D_FILE1);	/* 'Z' */
   552  		histfrogp = 0;
   553  		goto loop;
   554  
   555  	case AEND:
   556  		histtoauto();
   557  		if(cursym != nil && cursym->text)
   558  			cursym->autom = curauto;
   559  		curauto = 0;
   560  		cursym = nil;
   561  		if(Boffset(f) == eof)
   562  			return;
   563  		goto newloop;
   564  
   565  	case AGLOBL:
   566  		s = p->from.sym;
   567  		if(s == S) {
   568  			diag("GLOBL must have a name\n%P", p);
   569  			errorexit();
   570  		}
   571  		if(s->type == 0 || s->type == SXREF) {
   572  			s->type = SBSS;
   573  			s->value = 0;
   574  		}
   575  		if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) {
   576  			diag("redefinition: %s\n%P", s->name, p);
   577  			s->type = SBSS;
   578  			s->value = 0;
   579  		}
   580  		if(p->to.offset > s->size)
   581  			s->size = p->to.offset;
   582  		if(p->reg & DUPOK)
   583  			s->dupok = 1;
   584  		if(p->reg & RODATA)
   585  			s->type = SRODATA;
   586  		else if(p->reg & NOPTR)
   587  			s->type = SNOPTRBSS;
   588  		break;
   589  
   590  	case ADATA:
   591  		// Assume that AGLOBL comes after ADATA.
   592  		// If we've seen an AGLOBL that said this sym was DUPOK,
   593  		// ignore any more ADATA we see, which must be
   594  		// redefinitions.
   595  		s = p->from.sym;
   596  		if(s->dupok) {
   597  //			if(debug['v'])
   598  //				Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
   599  			goto loop;
   600  		}
   601  		if(s->file == nil)
   602  			s->file = pn;
   603  		else if(s->file != pn) {
   604  			diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
   605  			errorexit();
   606  		}
   607  		savedata(s, p, pn);
   608  		unmal(p, sizeof *p);
   609  		break;
   610  
   611  	case AGOK:
   612  		diag("unknown opcode\n%P", p);
   613  		p->pc = pc;
   614  		pc++;
   615  		break;
   616  
   617  	case ALOCALS:
   618  		if(skip)
   619  			goto casedef;
   620  		cursym->locals = p->to.offset;
   621  		pc++;
   622  		break;
   623  
   624  	case ATYPE:
   625  		if(skip)
   626  			goto casedef;
   627  		pc++;
   628  		goto loop;
   629  
   630  	case ATEXT:
   631  		if(cursym != nil && cursym->text) {
   632  			histtoauto();
   633  			cursym->autom = curauto;
   634  			curauto = 0;
   635  		}
   636  		s = p->from.sym;
   637  		if(s == S) {
   638  			diag("TEXT must have a name\n%P", p);
   639  			errorexit();
   640  		}
   641  		cursym = s;
   642  		if(s->type != 0 && s->type != SXREF && (p->reg & DUPOK)) {
   643  			skip = 1;
   644  			goto casedef;
   645  		}
   646  		if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
   647  			/* redefinition, so file has probably been seen before */
   648  			if(debug['v'])
   649  				Bprint(&bso, "skipping: %s: redefinition: %s", pn, s->name);
   650  			return;
   651  		}
   652  		skip = 0;
   653  		if(s->type != 0 && s->type != SXREF)
   654  			diag("redefinition: %s\n%P", s->name, p);
   655  		if(etextp)
   656  			etextp->next = s;
   657  		else
   658  			textp = s;
   659  		if(fromgotype) {
   660  			if(s->gotype && s->gotype != fromgotype)
   661  				diag("%s: type mismatch for %s", pn, s->name);
   662  			s->gotype = fromgotype;
   663  		}
   664  		etextp = s;
   665  		p->align = 4;
   666  		autosize = (p->to.offset+3L) & ~3L;
   667  		p->to.offset = autosize;
   668  		autosize += 4;
   669  		s->type = STEXT;
   670  		s->text = p;
   671  		s->value = pc;
   672  		s->args = p->to.offset2;
   673  		lastp = p;
   674  		p->pc = pc;
   675  		pc++;
   676  		break;
   677  
   678  	case ASUB:
   679  		if(p->from.type == D_CONST)
   680  		if(p->from.name == D_NONE)
   681  		if(p->from.offset < 0) {
   682  			p->from.offset = -p->from.offset;
   683  			p->as = AADD;
   684  		}
   685  		goto casedef;
   686  
   687  	case AADD:
   688  		if(p->from.type == D_CONST)
   689  		if(p->from.name == D_NONE)
   690  		if(p->from.offset < 0) {
   691  			p->from.offset = -p->from.offset;
   692  			p->as = ASUB;
   693  		}
   694  		goto casedef;
   695  
   696  	case AMOVWD:
   697  	case AMOVWF:
   698  	case AMOVDW:
   699  	case AMOVFW:
   700  	case AMOVFD:
   701  	case AMOVDF:
   702  	// case AMOVF:
   703  	// case AMOVD:
   704  	case ACMPF:
   705  	case ACMPD:
   706  	case AADDF:
   707  	case AADDD:
   708  	case ASUBF:
   709  	case ASUBD:
   710  	case AMULF:
   711  	case AMULD:
   712  	case ADIVF:
   713  	case ADIVD:
   714  		goto casedef;
   715  
   716  	case AMOVF:
   717  		if(skip)
   718  			goto casedef;
   719  
   720  		if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0 &&
   721  		   (chipzero(&p->from.ieee) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
   722  			/* size sb 9 max */
   723  			sprint(literal, "$%ux", ieeedtof(&p->from.ieee));
   724  			s = lookup(literal, 0);
   725  			if(s->type == 0) {
   726  				s->type = SRODATA;
   727  				adduint32(s, ieeedtof(&p->from.ieee));
   728  				s->reachable = 0;
   729  			}
   730  			p->from.type = D_OREG;
   731  			p->from.sym = s;
   732  			p->from.name = D_EXTERN;
   733  			p->from.offset = 0;
   734  		}
   735  		goto casedef;
   736  
   737  	case AMOVD:
   738  		if(skip)
   739  			goto casedef;
   740  
   741  		if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0 &&
   742  		   (chipzero(&p->from.ieee) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
   743  			/* size sb 18 max */
   744  			sprint(literal, "$%ux.%ux",
   745  				p->from.ieee.l, p->from.ieee.h);
   746  			s = lookup(literal, 0);
   747  			if(s->type == 0) {
   748  				s->type = SRODATA;
   749  				adduint32(s, p->from.ieee.l);
   750  				adduint32(s, p->from.ieee.h);
   751  				s->reachable = 0;
   752  			}
   753  			p->from.type = D_OREG;
   754  			p->from.sym = s;
   755  			p->from.name = D_EXTERN;
   756  			p->from.offset = 0;
   757  		}
   758  		goto casedef;
   759  
   760  	default:
   761  	casedef:
   762  		if(skip)
   763  			nopout(p);
   764  		p->pc = pc;
   765  		pc++;
   766  		if(p->to.type == D_BRANCH)
   767  			p->to.offset += ipc;
   768  		if(lastp == nil) {
   769  			if(p->as != ANOP)
   770  				diag("unexpected instruction: %P", p);
   771  			break;
   772  		}
   773  		lastp->link = p;
   774  		lastp = p;
   775  		break;
   776  	}
   777  	goto loop;
   778  
   779  eof:
   780  	diag("truncated object file: %s", pn);
   781  }
   782  
   783  Prog*
   784  prg(void)
   785  {
   786  	Prog *p;
   787  
   788  	p = mal(sizeof(Prog));
   789  	*p = zprg;
   790  	return p;
   791  }
   792  
   793  Prog*
   794  appendp(Prog *q)
   795  {
   796  	Prog *p;
   797  
   798  	p = prg();
   799  	p->link = q->link;
   800  	q->link = p;
   801  	p->line = q->line;
   802  	return p;
   803  }