The Go Programming Language

Text file src/cmd/5l/obj.c

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

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.