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