The Go Programming Language

Text file src/cmd/8g/gobj.c

     1	// Derived from Inferno utils/8c/swt.c
     2	// http://code.google.com/p/inferno-os/source/browse/utils/8c/swt.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	#include "gg.h"
    32	
    33	void
    34	zname(Biobuf *b, Sym *s, int t)
    35	{
    36		Bputc(b, ANAME);	/* as */
    37		Bputc(b, ANAME>>8);	/* as */
    38		Bputc(b, t);		/* type */
    39		Bputc(b, s->sym);	/* sym */
    40	
    41		Bputname(b, s);
    42	}
    43	
    44	void
    45	zfile(Biobuf *b, char *p, int n)
    46	{
    47		Bputc(b, ANAME);
    48		Bputc(b, ANAME>>8);
    49		Bputc(b, D_FILE);
    50		Bputc(b, 1);
    51		Bputc(b, '<');
    52		Bwrite(b, p, n);
    53		Bputc(b, 0);
    54	}
    55	
    56	void
    57	zhist(Biobuf *b, int line, vlong offset)
    58	{
    59		Addr a;
    60	
    61		Bputc(b, AHISTORY);
    62		Bputc(b, AHISTORY>>8);
    63		Bputc(b, line);
    64		Bputc(b, line>>8);
    65		Bputc(b, line>>16);
    66		Bputc(b, line>>24);
    67		zaddr(b, &zprog.from, 0, 0);
    68		a = zprog.to;
    69		if(offset != 0) {
    70			a.offset = offset;
    71			a.type = D_CONST;
    72		}
    73		zaddr(b, &a, 0, 0);
    74	}
    75	
    76	void
    77	zaddr(Biobuf *b, Addr *a, int s, int gotype)
    78	{
    79		int32 l;
    80		uint64 e;
    81		int i, t;
    82		char *n;
    83	
    84		t = 0;
    85		if(a->index != D_NONE || a->scale != 0)
    86			t |= T_INDEX;
    87		if(s != 0)
    88			t |= T_SYM;
    89		if(gotype != 0)
    90			t |= T_GOTYPE;
    91	
    92		switch(a->type) {
    93	
    94		case D_BRANCH:
    95			if(a->branch == nil)
    96				fatal("unpatched branch");
    97			a->offset = a->branch->loc;
    98	
    99		default:
   100			t |= T_TYPE;
   101	
   102		case D_NONE:
   103			if(a->offset != 0)
   104				t |= T_OFFSET;
   105			if(a->offset2 != 0)
   106				t |= T_OFFSET2;
   107			break;
   108		case D_FCONST:
   109			t |= T_FCONST;
   110			break;
   111		case D_SCONST:
   112			t |= T_SCONST;
   113			break;
   114		}
   115		Bputc(b, t);
   116	
   117		if(t & T_INDEX) {	/* implies index, scale */
   118			Bputc(b, a->index);
   119			Bputc(b, a->scale);
   120		}
   121		if(t & T_OFFSET) {	/* implies offset */
   122			l = a->offset;
   123			Bputc(b, l);
   124			Bputc(b, l>>8);
   125			Bputc(b, l>>16);
   126			Bputc(b, l>>24);
   127		}
   128		if(t & T_OFFSET2) {	/* implies offset */
   129			l = a->offset2;
   130			Bputc(b, l);
   131			Bputc(b, l>>8);
   132			Bputc(b, l>>16);
   133			Bputc(b, l>>24);
   134		}
   135		if(t & T_SYM)		/* implies sym */
   136			Bputc(b, s);
   137		if(t & T_FCONST) {
   138			ieeedtod(&e, a->dval);
   139			l = e;
   140			Bputc(b, l);
   141			Bputc(b, l>>8);
   142			Bputc(b, l>>16);
   143			Bputc(b, l>>24);
   144			l = e >> 32;
   145			Bputc(b, l);
   146			Bputc(b, l>>8);
   147			Bputc(b, l>>16);
   148			Bputc(b, l>>24);
   149			return;
   150		}
   151		if(t & T_SCONST) {
   152			n = a->sval;
   153			for(i=0; i<NSNAME; i++) {
   154				Bputc(b, *n);
   155				n++;
   156			}
   157			return;
   158		}
   159		if(t & T_TYPE)
   160			Bputc(b, a->type);
   161		if(t & T_GOTYPE)
   162			Bputc(b, gotype);
   163	}
   164	
   165	static struct {
   166		struct { Sym *sym; short type; } h[NSYM];
   167		int sym;
   168	} z;
   169	
   170	static void
   171	zsymreset(void)
   172	{
   173		for(z.sym=0; z.sym<NSYM; z.sym++) {
   174			z.h[z.sym].sym = S;
   175			z.h[z.sym].type = 0;
   176		}
   177		z.sym = 1;
   178	}
   179	
   180	static int
   181	zsym(Sym *s, int t, int *new)
   182	{
   183		int i;
   184	
   185		*new = 0;
   186		if(s == S)
   187			return 0;
   188	
   189		i = s->sym;
   190		if(i < 0 || i >= NSYM)
   191			i = 0;
   192		if(z.h[i].type == t && z.h[i].sym == s)
   193			return i;
   194		i = z.sym;
   195		s->sym = i;
   196		zname(bout, s, t);
   197		z.h[i].sym = s;
   198		z.h[i].type = t;
   199		if(++z.sym >= NSYM)
   200			z.sym = 1;
   201		*new = 1;
   202		return i;
   203	}
   204	
   205	static int
   206	zsymaddr(Addr *a, int *new)
   207	{
   208		int t;
   209	
   210		t = a->type;
   211		if(t == D_ADDR)
   212			t = a->index;
   213		return zsym(a->sym, t, new);
   214	}
   215	
   216	void
   217	dumpfuncs(void)
   218	{
   219		Plist *pl;
   220		int sf, st, gf, gt, new;
   221		Sym *s;
   222		Prog *p;
   223	
   224		zsymreset();
   225	
   226		// fix up pc
   227		pcloc = 0;
   228		for(pl=plist; pl!=nil; pl=pl->link) {
   229			if(isblank(pl->name))
   230				continue;
   231			for(p=pl->firstpc; p!=P; p=p->link) {
   232				p->loc = pcloc;
   233				if(p->as != ADATA && p->as != AGLOBL)
   234					pcloc++;
   235			}
   236		}
   237	
   238		// put out functions
   239		for(pl=plist; pl!=nil; pl=pl->link) {
   240			if(isblank(pl->name))
   241				continue;
   242	
   243			if(debug['S']) {
   244				s = S;
   245				if(pl->name != N)
   246					s = pl->name->sym;
   247				print("\n--- prog list \"%S\" ---\n", s);
   248				for(p=pl->firstpc; p!=P; p=p->link)
   249					print("%P\n", p);
   250			}
   251	
   252			for(p=pl->firstpc; p!=P; p=p->link) {
   253				for(;;) {
   254					sf = zsymaddr(&p->from, &new);
   255					gf = zsym(p->from.gotype, D_EXTERN, &new);
   256					if(new && sf == gf)
   257						continue;
   258					st = zsymaddr(&p->to, &new);
   259					if(new && (st == sf || st == gf))
   260						continue;
   261					gt = zsym(p->to.gotype, D_EXTERN, &new);
   262					if(new && (gt == sf || gt == gf || gt == st))
   263						continue;
   264					break;
   265				}
   266	
   267				Bputc(bout, p->as);
   268				Bputc(bout, p->as>>8);
   269				Bputc(bout, p->lineno);
   270				Bputc(bout, p->lineno>>8);
   271				Bputc(bout, p->lineno>>16);
   272				Bputc(bout, p->lineno>>24);
   273				zaddr(bout, &p->from, sf, gf);
   274				zaddr(bout, &p->to, st, gt);
   275			}
   276		}
   277	}
   278	
   279	/* deferred DATA output */
   280	static Prog *strdat;
   281	static Prog *estrdat;
   282	static int gflag;
   283	static Prog *savepc;
   284	
   285	void
   286	data(void)
   287	{
   288		gflag = debug['g'];
   289		debug['g'] = 0;
   290	
   291		if(estrdat == nil) {
   292			strdat = mal(sizeof(*pc));
   293			clearp(strdat);
   294			estrdat = strdat;
   295		}
   296		if(savepc)
   297			fatal("data phase error");
   298		savepc = pc;
   299		pc = estrdat;
   300	}
   301	
   302	void
   303	text(void)
   304	{
   305		if(!savepc)
   306			fatal("text phase error");
   307		debug['g'] = gflag;
   308		estrdat = pc;
   309		pc = savepc;
   310		savepc = nil;
   311	}
   312	
   313	void
   314	dumpdata(void)
   315	{
   316		Prog *p;
   317	
   318		if(estrdat == nil)
   319			return;
   320		*pc = *strdat;
   321		if(gflag)
   322			for(p=pc; p!=estrdat; p=p->link)
   323				print("%P\n", p);
   324		pc = estrdat;
   325	}
   326	
   327	int
   328	dsname(Sym *s, int off, char *t, int n)
   329	{
   330		Prog *p;
   331	
   332		p = gins(ADATA, N, N);
   333		p->from.type = D_EXTERN;
   334		p->from.index = D_NONE;
   335		p->from.offset = off;
   336		p->from.scale = n;
   337		p->from.sym = s;
   338		
   339		p->to.type = D_SCONST;
   340		p->to.index = D_NONE;
   341		memmove(p->to.sval, t, n);
   342		return off + n;
   343	}
   344	
   345	/*
   346	 * make a refer to the data s, s+len
   347	 * emitting DATA if needed.
   348	 */
   349	void
   350	datastring(char *s, int len, Addr *a)
   351	{
   352		Sym *sym;
   353		
   354		sym = stringsym(s, len);
   355		a->type = D_EXTERN;
   356		a->sym = sym;
   357		a->offset = widthptr+4;  // skip header
   358		a->etype = TINT32;
   359	}
   360	
   361	/*
   362	 * make a refer to the string sval,
   363	 * emitting DATA if needed.
   364	 */
   365	void
   366	datagostring(Strlit *sval, Addr *a)
   367	{
   368		Sym *sym;
   369		
   370		sym = stringsym(sval->s, sval->len);
   371		a->type = D_EXTERN;
   372		a->sym = sym;
   373		a->offset = 0;  // header
   374		a->etype = TINT32;
   375	}
   376	
   377	void
   378	gdata(Node *nam, Node *nr, int wid)
   379	{
   380		Prog *p;
   381		vlong v;
   382	
   383		if(wid == 8 && is64(nr->type)) {
   384			v = mpgetfix(nr->val.u.xval);
   385			p = gins(ADATA, nam, nodintconst(v));
   386			p->from.scale = 4;
   387			p = gins(ADATA, nam, nodintconst(v>>32));
   388			p->from.scale = 4;
   389			p->from.offset += 4;
   390			return;
   391		}
   392		p = gins(ADATA, nam, nr);
   393		p->from.scale = wid;
   394	}
   395	
   396	void
   397	gdatacomplex(Node *nam, Mpcplx *cval)
   398	{
   399		Prog *p;
   400		int w;
   401	
   402		w = cplxsubtype(nam->type->etype);
   403		w = types[w]->width;
   404	
   405		p = gins(ADATA, nam, N);
   406		p->from.scale = w;
   407		p->to.type = D_FCONST;
   408		p->to.dval = mpgetflt(&cval->real);
   409	
   410		p = gins(ADATA, nam, N);
   411		p->from.scale = w;
   412		p->from.offset += w;
   413		p->to.type = D_FCONST;
   414		p->to.dval = mpgetflt(&cval->imag);
   415	}
   416	
   417	void
   418	gdatastring(Node *nam, Strlit *sval)
   419	{
   420		Prog *p;
   421		Node nod1;
   422	
   423		p = gins(ADATA, nam, N);
   424		datastring(sval->s, sval->len, &p->to);
   425		p->from.scale = types[tptr]->width;
   426		p->to.index = p->to.type;
   427		p->to.type = D_ADDR;
   428	//print("%P\n", p);
   429	
   430		nodconst(&nod1, types[TINT32], sval->len);
   431		p = gins(ADATA, nam, &nod1);
   432		p->from.scale = types[TINT32]->width;
   433		p->from.offset += types[tptr]->width;
   434	}
   435	
   436	int
   437	dstringptr(Sym *s, int off, char *str)
   438	{
   439		Prog *p;
   440	
   441		off = rnd(off, widthptr);
   442		p = gins(ADATA, N, N);
   443		p->from.type = D_EXTERN;
   444		p->from.index = D_NONE;
   445		p->from.sym = s;
   446		p->from.offset = off;
   447		p->from.scale = widthptr;
   448	
   449		datastring(str, strlen(str)+1, &p->to);
   450		p->to.index = p->to.type;
   451		p->to.type = D_ADDR;
   452		p->to.etype = TINT32;
   453		off += widthptr;
   454	
   455		return off;
   456	}
   457	
   458	int
   459	dgostrlitptr(Sym *s, int off, Strlit *lit)
   460	{
   461		Prog *p;
   462	
   463		if(lit == nil)
   464			return duintptr(s, off, 0);
   465	
   466		off = rnd(off, widthptr);
   467		p = gins(ADATA, N, N);
   468		p->from.type = D_EXTERN;
   469		p->from.index = D_NONE;
   470		p->from.sym = s;
   471		p->from.offset = off;
   472		p->from.scale = widthptr;
   473		datagostring(lit, &p->to);
   474		p->to.index = p->to.type;
   475		p->to.type = D_ADDR;
   476		p->to.etype = TINT32;
   477		off += widthptr;
   478	
   479		return off;
   480	}
   481	
   482	int
   483	dgostringptr(Sym *s, int off, char *str)
   484	{
   485		int n;
   486		Strlit *lit;
   487	
   488		if(str == nil)
   489			return duintptr(s, off, 0);
   490	
   491		n = strlen(str);
   492		lit = mal(sizeof *lit + n);
   493		strcpy(lit->s, str);
   494		lit->len = n;
   495		return dgostrlitptr(s, off, lit);
   496	}
   497	
   498	
   499	int
   500	duintxx(Sym *s, int off, uint64 v, int wid)
   501	{
   502		Prog *p;
   503	
   504		off = rnd(off, wid);
   505	
   506		p = gins(ADATA, N, N);
   507		p->from.type = D_EXTERN;
   508		p->from.index = D_NONE;
   509		p->from.sym = s;
   510		p->from.offset = off;
   511		p->from.scale = wid;
   512		p->to.type = D_CONST;
   513		p->to.index = D_NONE;
   514		p->to.offset = v;
   515		off += wid;
   516	
   517		return off;
   518	}
   519	
   520	int
   521	dsymptr(Sym *s, int off, Sym *x, int xoff)
   522	{
   523		Prog *p;
   524	
   525		off = rnd(off, widthptr);
   526	
   527		p = gins(ADATA, N, N);
   528		p->from.type = D_EXTERN;
   529		p->from.index = D_NONE;
   530		p->from.sym = s;
   531		p->from.offset = off;
   532		p->from.scale = widthptr;
   533		p->to.type = D_ADDR;
   534		p->to.index = D_EXTERN;
   535		p->to.sym = x;
   536		p->to.offset = xoff;
   537		off += widthptr;
   538	
   539		return off;
   540	}
   541	
   542	void
   543	genembedtramp(Type *rcvr, Type *method, Sym *newnam, int iface)
   544	{
   545		Sym *e;
   546		int c, d, o, mov, add, loaded;
   547		Prog *p;
   548		Type *f;
   549	
   550		e = method->sym;
   551		for(d=0; d<nelem(dotlist); d++) {
   552			c = adddot1(e, rcvr, d, nil, 0);
   553			if(c == 1)
   554				goto out;
   555		}
   556		fatal("genembedtramp %T.%S", rcvr, method->sym);
   557	
   558	out:
   559		newplist()->name = newname(newnam);
   560	
   561		//TEXT	main·S_test2(SB),7,$0
   562		p = pc;
   563		gins(ATEXT, N, N);
   564		p->from.type = D_EXTERN;
   565		p->from.sym = newnam;
   566		p->to.type = D_CONST;
   567		p->to.offset = 0;
   568		p->from.scale = 7;
   569	//print("1. %P\n", p);
   570	
   571		mov = AMOVL;
   572		add = AADDL;
   573	
   574		loaded = 0;
   575		o = 0;
   576		for(c=d-1; c>=0; c--) {
   577			f = dotlist[c].field;
   578			o += f->width;
   579			if(!isptr[f->type->etype])
   580				continue;
   581			if(!loaded) {
   582				loaded = 1;
   583				//MOVL	4(SP), AX
   584				p = pc;
   585				gins(mov, N, N);
   586				p->from.type = D_INDIR+D_SP;
   587				p->from.offset = widthptr;
   588				p->to.type = D_AX;
   589	//print("2. %P\n", p);
   590			}
   591	
   592			//MOVL	o(AX), AX
   593			p = pc;
   594			gins(mov, N, N);
   595			p->from.type = D_INDIR+D_AX;
   596			p->from.offset = o;
   597			p->to.type = D_AX;
   598	//print("3. %P\n", p);
   599			o = 0;
   600		}
   601		if(o != 0) {
   602			//ADDL	$XX, AX
   603			p = pc;
   604			gins(add, N, N);
   605			p->from.type = D_CONST;
   606			p->from.offset = o;
   607			if(loaded)
   608				p->to.type = D_AX;
   609			else {
   610				p->to.type = D_INDIR+D_SP;
   611				p->to.offset = widthptr;
   612			}
   613	//print("4. %P\n", p);
   614		}
   615	
   616		//MOVL	AX, 4(SP)
   617		if(loaded) {
   618			p = pc;
   619			gins(mov, N, N);
   620			p->from.type = D_AX;
   621			p->to.type = D_INDIR+D_SP;
   622			p->to.offset = widthptr;
   623	//print("5. %P\n", p);
   624		} else {
   625			// TODO(rsc): obviously this is unnecessary,
   626			// but 6l has a bug, and it can't handle
   627			// JMP instructions too close to the top of
   628			// a new function.
   629			p = pc;
   630			gins(ANOP, N, N);
   631		}
   632	
   633		f = dotlist[0].field;
   634		//JMP	main·*Sub_test2(SB)
   635		if(isptr[f->type->etype])
   636			f = f->type;
   637		p = pc;
   638		gins(AJMP, N, N);
   639		p->to.type = D_EXTERN;
   640		p->to.sym = methodsym(method->sym, ptrto(f->type), 0);
   641	//print("6. %P\n", p);
   642	
   643		pc->as = ARET;	// overwrite AEND
   644	}
   645	
   646	void
   647	nopout(Prog *p)
   648	{
   649		p->as = ANOP;
   650	}
   651	

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