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