github.com/reiver/go@v0.0.0-20150109200633-1d0c7792f172/src/liblink/obj8.c (about)

     1  // Inferno utils/8l/pass.c
     2  // http://code.google.com/p/inferno-os/source/browse/utils/8l/pass.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 <u.h>
    32  #include <libc.h>
    33  #include <bio.h>
    34  #include <link.h>
    35  #include "../cmd/8l/8.out.h"
    36  #include "../runtime/stack.h"
    37  
    38  static Prog zprg = {
    39  	.back = 2,
    40  	.as = AGOK,
    41  	.from = {
    42  		.type = D_NONE,
    43  		.index = D_NONE,
    44  		.scale = 1,
    45  	},
    46  	.to = {
    47  		.type = D_NONE,
    48  		.index = D_NONE,
    49  		.scale = 1,
    50  	},
    51  };
    52  
    53  static int
    54  symtype(Addr *a)
    55  {
    56  	int t;
    57  
    58  	t = a->type;
    59  	if(t == D_ADDR)
    60  		t = a->index;
    61  	return t;
    62  }
    63  
    64  static int
    65  isdata(Prog *p)
    66  {
    67  	return p->as == ADATA || p->as == AGLOBL;
    68  }
    69  
    70  static int
    71  iscall(Prog *p)
    72  {
    73  	return p->as == ACALL;
    74  }
    75  
    76  static int
    77  datasize(Prog *p)
    78  {
    79  	return p->from.scale;
    80  }
    81  
    82  static int
    83  textflag(Prog *p)
    84  {
    85  	return p->from.scale;
    86  }
    87  
    88  static void
    89  settextflag(Prog *p, int f)
    90  {
    91  	p->from.scale = f;
    92  }
    93  
    94  static int
    95  canuselocaltls(Link *ctxt)
    96  {
    97  	switch(ctxt->headtype) {
    98  	case Hlinux:
    99  	case Hnacl:
   100  	case Hplan9:
   101  	case Hwindows:
   102  		return 0;
   103  	}
   104  	return 1;
   105  }
   106  
   107  static void
   108  progedit(Link *ctxt, Prog *p)
   109  {
   110  	char literal[64];
   111  	LSym *s;
   112  	Prog *q;
   113  	
   114  	// See obj6.c for discussion of TLS.
   115  	if(canuselocaltls(ctxt)) {
   116  		// Reduce TLS initial exec model to TLS local exec model.
   117  		// Sequences like
   118  		//	MOVL TLS, BX
   119  		//	... off(BX)(TLS*1) ...
   120  		// become
   121  		//	NOP
   122  		//	... off(TLS) ...
   123  		if(p->as == AMOVL && p->from.type == D_TLS && D_AX <= p->to.type && p->to.type <= D_DI) {
   124  			p->as = ANOP;
   125  			p->from.type = D_NONE;
   126  			p->to.type = D_NONE;
   127  		}
   128  		if(p->from.index == D_TLS && D_INDIR+D_AX <= p->from.type && p->from.type <= D_INDIR+D_DI) {
   129  			p->from.type = D_INDIR+D_TLS;
   130  			p->from.scale = 0;
   131  			p->from.index = D_NONE;
   132  		}
   133  		if(p->to.index == D_TLS && D_INDIR+D_AX <= p->to.type && p->to.type <= D_INDIR+D_DI) {
   134  			p->to.type = D_INDIR+D_TLS;
   135  			p->to.scale = 0;
   136  			p->to.index = D_NONE;
   137  		}
   138  	} else {
   139  		// As a courtesy to the C compilers, rewrite TLS local exec load as TLS initial exec load.
   140  		// The instruction
   141  		//	MOVL off(TLS), BX
   142  		// becomes the sequence
   143  		//	MOVL TLS, BX
   144  		//	MOVL off(BX)(TLS*1), BX
   145  		// This allows the C compilers to emit references to m and g using the direct off(TLS) form.
   146  		if(p->as == AMOVL && p->from.type == D_INDIR+D_TLS && D_AX <= p->to.type && p->to.type <= D_DI) {
   147  			q = appendp(ctxt, p);
   148  			q->as = p->as;
   149  			q->from = p->from;
   150  			q->from.type = D_INDIR + p->to.type;
   151  			q->from.index = D_TLS;
   152  			q->from.scale = 2; // TODO: use 1
   153  			q->to = p->to;
   154  			p->from.type = D_TLS;
   155  			p->from.index = D_NONE;
   156  			p->from.offset = 0;
   157  		}
   158  	}
   159  
   160  	// TODO: Remove.
   161  	if(ctxt->headtype == Hplan9) {
   162  		if(p->from.scale == 1 && p->from.index == D_TLS)
   163  			p->from.scale = 2;
   164  		if(p->to.scale == 1 && p->to.index == D_TLS)
   165  			p->to.scale = 2;
   166  	}
   167  
   168  	// Rewrite CALL/JMP/RET to symbol as D_BRANCH.
   169  	switch(p->as) {
   170  	case ACALL:
   171  	case AJMP:
   172  	case ARET:
   173  		if((p->to.type == D_EXTERN || p->to.type == D_STATIC) && p->to.sym != nil)
   174  			p->to.type = D_BRANCH;
   175  		break;
   176  	}
   177  
   178  	// Rewrite float constants to values stored in memory.
   179  	switch(p->as) {
   180  	case AMOVSS:
   181  		// Convert AMOVSS $(0), Xx to AXORPS Xx, Xx
   182  		if(p->from.type == D_FCONST)
   183  		if(p->from.u.dval == 0)
   184  		if(p->to.type >= D_X0)
   185  		if(p->to.type <= D_X7) {
   186  			p->as = AXORPS;
   187  			p->from.type = p->to.type;
   188  			p->from.index = p->to.index;
   189  			break;
   190  		}
   191  		// fallthrough
   192  
   193  	case AFMOVF:
   194  	case AFADDF:
   195  	case AFSUBF:
   196  	case AFSUBRF:
   197  	case AFMULF:
   198  	case AFDIVF:
   199  	case AFDIVRF:
   200  	case AFCOMF:
   201  	case AFCOMFP:
   202  	case AADDSS:
   203  	case ASUBSS:
   204  	case AMULSS:
   205  	case ADIVSS:
   206  	case ACOMISS:
   207  	case AUCOMISS:
   208  		if(p->from.type == D_FCONST) {
   209  			int32 i32;
   210  			float32 f32;
   211  			f32 = p->from.u.dval;
   212  			memmove(&i32, &f32, 4);
   213  			sprint(literal, "$f32.%08ux", (uint32)i32);
   214  			s = linklookup(ctxt, literal, 0);
   215  			if(s->type == 0) {
   216  				s->type = SRODATA;
   217  				adduint32(ctxt, s, i32);
   218  				s->reachable = 0;
   219  			}
   220  			p->from.type = D_EXTERN;
   221  			p->from.sym = s;
   222  			p->from.offset = 0;
   223  		}
   224  		break;
   225  
   226  	case AMOVSD:
   227  		// Convert AMOVSD $(0), Xx to AXORPS Xx, Xx
   228  		if(p->from.type == D_FCONST)
   229  		if(p->from.u.dval == 0)
   230  		if(p->to.type >= D_X0)
   231  		if(p->to.type <= D_X7) {
   232  			p->as = AXORPS;
   233  			p->from.type = p->to.type;
   234  			p->from.index = p->to.index;
   235  			break;
   236  		}
   237  		// fallthrough
   238  
   239  	case AFMOVD:
   240  	case AFADDD:
   241  	case AFSUBD:
   242  	case AFSUBRD:
   243  	case AFMULD:
   244  	case AFDIVD:
   245  	case AFDIVRD:
   246  	case AFCOMD:
   247  	case AFCOMDP:
   248  	case AADDSD:
   249  	case ASUBSD:
   250  	case AMULSD:
   251  	case ADIVSD:
   252  	case ACOMISD:
   253  	case AUCOMISD:
   254  		if(p->from.type == D_FCONST) {
   255  			int64 i64;
   256  			memmove(&i64, &p->from.u.dval, 8);
   257  			sprint(literal, "$f64.%016llux", (uvlong)i64);
   258  			s = linklookup(ctxt, literal, 0);
   259  			if(s->type == 0) {
   260  				s->type = SRODATA;
   261  				adduint64(ctxt, s, i64);
   262  				s->reachable = 0;
   263  			}
   264  			p->from.type = D_EXTERN;
   265  			p->from.sym = s;
   266  			p->from.offset = 0;
   267  		}
   268  		break;
   269  	}
   270  }
   271  
   272  static Prog*
   273  prg(void)
   274  {
   275  	Prog *p;
   276  
   277  	p = emallocz(sizeof(*p));
   278  	*p = zprg;
   279  	return p;
   280  }
   281  
   282  static Prog*	load_g_cx(Link*, Prog*);
   283  static Prog*	stacksplit(Link*, Prog*, int32, int, Prog**);
   284  
   285  static void
   286  addstacksplit(Link *ctxt, LSym *cursym)
   287  {
   288  	Prog *p, *q, *p1, *p2;
   289  	int32 autoffset, deltasp;
   290  	int a;
   291  
   292  	if(ctxt->symmorestack[0] == nil) {
   293  		ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0);
   294  		ctxt->symmorestack[1] = linklookup(ctxt, "runtime.morestack_noctxt", 0);
   295  	}
   296  
   297  	if(ctxt->headtype == Hplan9 && ctxt->plan9privates == nil)
   298  		ctxt->plan9privates = linklookup(ctxt, "_privates", 0);
   299  
   300  	ctxt->cursym = cursym;
   301  
   302  	if(cursym->text == nil || cursym->text->link == nil)
   303  		return;
   304  
   305  	p = cursym->text;
   306  	autoffset = p->to.offset;
   307  	if(autoffset < 0)
   308  		autoffset = 0;
   309  	
   310  	cursym->locals = autoffset;
   311  	cursym->args = p->to.offset2;
   312  
   313  	q = nil;
   314  
   315  	if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) {
   316  		p = appendp(ctxt, p);
   317  		p = load_g_cx(ctxt, p); // load g into CX
   318  	}
   319  	if(!(cursym->text->from.scale & NOSPLIT))
   320  		p = stacksplit(ctxt, p, autoffset, !(cursym->text->from.scale&NEEDCTXT), &q); // emit split check
   321  
   322  	if(autoffset) {
   323  		p = appendp(ctxt, p);
   324  		p->as = AADJSP;
   325  		p->from.type = D_CONST;
   326  		p->from.offset = autoffset;
   327  		p->spadj = autoffset;
   328  	} else {
   329  		// zero-byte stack adjustment.
   330  		// Insert a fake non-zero adjustment so that stkcheck can
   331  		// recognize the end of the stack-splitting prolog.
   332  		p = appendp(ctxt, p);
   333  		p->as = ANOP;
   334  		p->spadj = -ctxt->arch->ptrsize;
   335  		p = appendp(ctxt, p);
   336  		p->as = ANOP;
   337  		p->spadj = ctxt->arch->ptrsize;
   338  	}
   339  	if(q != nil)
   340  		q->pcond = p;
   341  	deltasp = autoffset;
   342  	
   343  	if(cursym->text->from.scale & WRAPPER) {
   344  		// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
   345  		//
   346  		//	MOVL g_panic(CX), BX
   347  		//	TESTL BX, BX
   348  		//	JEQ end
   349  		//	LEAL (autoffset+4)(SP), DI
   350  		//	CMPL panic_argp(BX), DI
   351  		//	JNE end
   352  		//	MOVL SP, panic_argp(BX)
   353  		// end:
   354  		//	NOP
   355  		//
   356  		// The NOP is needed to give the jumps somewhere to land.
   357  		// It is a liblink NOP, not an x86 NOP: it encodes to 0 instruction bytes.
   358  
   359  		p = appendp(ctxt, p);
   360  		p->as = AMOVL;
   361  		p->from.type = D_INDIR+D_CX;
   362  		p->from.offset = 4*ctxt->arch->ptrsize; // G.panic
   363  		p->to.type = D_BX;
   364  
   365  		p = appendp(ctxt, p);
   366  		p->as = ATESTL;
   367  		p->from.type = D_BX;
   368  		p->to.type = D_BX;
   369  
   370  		p = appendp(ctxt, p);
   371  		p->as = AJEQ;
   372  		p->to.type = D_BRANCH;
   373  		p1 = p;
   374  
   375  		p = appendp(ctxt, p);
   376  		p->as = ALEAL;
   377  		p->from.type = D_INDIR+D_SP;
   378  		p->from.offset = autoffset+4;
   379  		p->to.type = D_DI;
   380  
   381  		p = appendp(ctxt, p);
   382  		p->as = ACMPL;
   383  		p->from.type = D_INDIR+D_BX;
   384  		p->from.offset = 0; // Panic.argp
   385  		p->to.type = D_DI;
   386  
   387  		p = appendp(ctxt, p);
   388  		p->as = AJNE;
   389  		p->to.type = D_BRANCH;
   390  		p2 = p;
   391  
   392  		p = appendp(ctxt, p);
   393  		p->as = AMOVL;
   394  		p->from.type = D_SP;
   395  		p->to.type = D_INDIR+D_BX;
   396  		p->to.offset = 0; // Panic.argp
   397  
   398  		p = appendp(ctxt, p);
   399  		p->as = ANOP;
   400  		p1->pcond = p;
   401  		p2->pcond = p;
   402  	}
   403  	
   404  	if(ctxt->debugzerostack && autoffset && !(cursym->text->from.scale&NOSPLIT)) {
   405  		// 8l -Z means zero the stack frame on entry.
   406  		// This slows down function calls but can help avoid
   407  		// false positives in garbage collection.
   408  		p = appendp(ctxt, p);
   409  		p->as = AMOVL;
   410  		p->from.type = D_SP;
   411  		p->to.type = D_DI;
   412  		
   413  		p = appendp(ctxt, p);
   414  		p->as = AMOVL;
   415  		p->from.type = D_CONST;
   416  		p->from.offset = autoffset/4;
   417  		p->to.type = D_CX;
   418  		
   419  		p = appendp(ctxt, p);
   420  		p->as = AMOVL;
   421  		p->from.type = D_CONST;
   422  		p->from.offset = 0;
   423  		p->to.type = D_AX;
   424  		
   425  		p = appendp(ctxt, p);
   426  		p->as = AREP;
   427  		
   428  		p = appendp(ctxt, p);
   429  		p->as = ASTOSL;
   430  	}
   431  	
   432  	for(; p != nil; p = p->link) {
   433  		a = p->from.type;
   434  		if(a == D_AUTO)
   435  			p->from.offset += deltasp;
   436  		if(a == D_PARAM)
   437  			p->from.offset += deltasp + 4;
   438  		a = p->to.type;
   439  		if(a == D_AUTO)
   440  			p->to.offset += deltasp;
   441  		if(a == D_PARAM)
   442  			p->to.offset += deltasp + 4;
   443  
   444  		switch(p->as) {
   445  		default:
   446  			continue;
   447  		case APUSHL:
   448  		case APUSHFL:
   449  			deltasp += 4;
   450  			p->spadj = 4;
   451  			continue;
   452  		case APUSHW:
   453  		case APUSHFW:
   454  			deltasp += 2;
   455  			p->spadj = 2;
   456  			continue;
   457  		case APOPL:
   458  		case APOPFL:
   459  			deltasp -= 4;
   460  			p->spadj = -4;
   461  			continue;
   462  		case APOPW:
   463  		case APOPFW:
   464  			deltasp -= 2;
   465  			p->spadj = -2;
   466  			continue;
   467  		case ARET:
   468  			break;
   469  		}
   470  
   471  		if(autoffset != deltasp)
   472  			ctxt->diag("unbalanced PUSH/POP");
   473  
   474  		if(autoffset) {
   475  			p->as = AADJSP;
   476  			p->from.type = D_CONST;
   477  			p->from.offset = -autoffset;
   478  			p->spadj = -autoffset;
   479  			p = appendp(ctxt, p);
   480  			p->as = ARET;
   481  			// If there are instructions following
   482  			// this ARET, they come from a branch
   483  			// with the same stackframe, so undo
   484  			// the cleanup.
   485  			p->spadj = +autoffset;
   486  		}
   487  		if(p->to.sym) // retjmp
   488  			p->as = AJMP;
   489  	}
   490  }
   491  
   492  // Append code to p to load g into cx.
   493  // Overwrites p with the first instruction (no first appendp).
   494  // Overwriting p is unusual but it lets use this in both the
   495  // prologue (caller must call appendp first) and in the epilogue.
   496  // Returns last new instruction.
   497  static Prog*
   498  load_g_cx(Link *ctxt, Prog *p)
   499  {
   500  	Prog *next;
   501  
   502  	p->as = AMOVL;
   503  	p->from.type = D_INDIR+D_TLS;
   504  	p->from.offset = 0;
   505  	p->to.type = D_CX;
   506  
   507  	next = p->link;
   508  	progedit(ctxt, p);
   509  	while(p->link != next)
   510  		p = p->link;
   511  	
   512  	if(p->from.index == D_TLS)
   513  		p->from.scale = 2;
   514  
   515  	return p;
   516  }
   517  
   518  // Append code to p to check for stack split.
   519  // Appends to (does not overwrite) p.
   520  // Assumes g is in CX.
   521  // Returns last new instruction.
   522  // On return, *jmpok is the instruction that should jump
   523  // to the stack frame allocation if no split is needed.
   524  static Prog*
   525  stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt, Prog **jmpok)
   526  {
   527  	Prog *q, *q1;
   528  
   529  	if(ctxt->debugstack) {
   530  		// 8l -K means check not only for stack
   531  		// overflow but stack underflow.
   532  		// On underflow, INT 3 (breakpoint).
   533  		// Underflow itself is rare but this also
   534  		// catches out-of-sync stack guard info.
   535  		p = appendp(ctxt, p);
   536  		p->as = ACMPL;
   537  		p->from.type = D_INDIR+D_CX;
   538  		p->from.offset = 4;
   539  		p->to.type = D_SP;
   540  
   541  		p = appendp(ctxt, p);
   542  		p->as = AJCC;
   543  		p->to.type = D_BRANCH;
   544  		p->to.offset = 4;
   545  		q1 = p;
   546  
   547  		p = appendp(ctxt, p);
   548  		p->as = AINT;
   549  		p->from.type = D_CONST;
   550  		p->from.offset = 3;
   551  		
   552  		p = appendp(ctxt, p);
   553  		p->as = ANOP;
   554  		q1->pcond = p;
   555  	}
   556  	q1 = nil;
   557  
   558  	if(framesize <= StackSmall) {
   559  		// small stack: SP <= stackguard
   560  		//	CMPL SP, stackguard
   561  		p = appendp(ctxt, p);
   562  		p->as = ACMPL;
   563  		p->from.type = D_SP;
   564  		p->to.type = D_INDIR+D_CX;
   565  		p->to.offset = 2*ctxt->arch->ptrsize;	// G.stackguard0
   566  		if(ctxt->cursym->cfunc)
   567  			p->to.offset = 3*ctxt->arch->ptrsize;	// G.stackguard1
   568  	} else if(framesize <= StackBig) {
   569  		// large stack: SP-framesize <= stackguard-StackSmall
   570  		//	LEAL -(framesize-StackSmall)(SP), AX
   571  		//	CMPL AX, stackguard
   572  		p = appendp(ctxt, p);
   573  		p->as = ALEAL;
   574  		p->from.type = D_INDIR+D_SP;
   575  		p->from.offset = -(framesize-StackSmall);
   576  		p->to.type = D_AX;
   577  
   578  		p = appendp(ctxt, p);
   579  		p->as = ACMPL;
   580  		p->from.type = D_AX;
   581  		p->to.type = D_INDIR+D_CX;
   582  		p->to.offset = 2*ctxt->arch->ptrsize;	// G.stackguard0
   583  		if(ctxt->cursym->cfunc)
   584  			p->to.offset = 3*ctxt->arch->ptrsize;	// G.stackguard1
   585  	} else {
   586  		// Such a large stack we need to protect against wraparound
   587  		// if SP is close to zero.
   588  		//	SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
   589  		// The +StackGuard on both sides is required to keep the left side positive:
   590  		// SP is allowed to be slightly below stackguard. See stack.h.
   591  		//
   592  		// Preemption sets stackguard to StackPreempt, a very large value.
   593  		// That breaks the math above, so we have to check for that explicitly.
   594  		//	MOVL	stackguard, CX
   595  		//	CMPL	CX, $StackPreempt
   596  		//	JEQ	label-of-call-to-morestack
   597  		//	LEAL	StackGuard(SP), AX
   598  		//	SUBL	stackguard, AX
   599  		//	CMPL	AX, $(framesize+(StackGuard-StackSmall))
   600  		p = appendp(ctxt, p);
   601  		p->as = AMOVL;
   602  		p->from.type = D_INDIR+D_CX;
   603  		p->from.offset = 0;
   604  		p->from.offset = 2*ctxt->arch->ptrsize;	// G.stackguard0
   605  		if(ctxt->cursym->cfunc)
   606  			p->from.offset = 3*ctxt->arch->ptrsize;	// G.stackguard1
   607  		p->to.type = D_SI;
   608  
   609  		p = appendp(ctxt, p);
   610  		p->as = ACMPL;
   611  		p->from.type = D_SI;
   612  		p->to.type = D_CONST;
   613  		p->to.offset = (uint32)StackPreempt;
   614  
   615  		p = appendp(ctxt, p);
   616  		p->as = AJEQ;
   617  		p->to.type = D_BRANCH;
   618  		q1 = p;
   619  
   620  		p = appendp(ctxt, p);
   621  		p->as = ALEAL;
   622  		p->from.type = D_INDIR+D_SP;
   623  		p->from.offset = StackGuard;
   624  		p->to.type = D_AX;
   625  		
   626  		p = appendp(ctxt, p);
   627  		p->as = ASUBL;
   628  		p->from.type = D_SI;
   629  		p->from.offset = 0;
   630  		p->to.type = D_AX;
   631  		
   632  		p = appendp(ctxt, p);
   633  		p->as = ACMPL;
   634  		p->from.type = D_AX;
   635  		p->to.type = D_CONST;
   636  		p->to.offset = framesize+(StackGuard-StackSmall);
   637  	}		
   638  			
   639  	// common
   640  	p = appendp(ctxt, p);
   641  	p->as = AJHI;
   642  	p->to.type = D_BRANCH;
   643  	p->to.offset = 4;
   644  	q = p;
   645  
   646  	p = appendp(ctxt, p);
   647  	p->as = ACALL;
   648  	p->to.type = D_BRANCH;
   649  	if(ctxt->cursym->cfunc)
   650  		p->to.sym = linklookup(ctxt, "runtime.morestackc", 0);
   651  	else
   652  		p->to.sym = ctxt->symmorestack[noctxt];
   653  
   654  	p = appendp(ctxt, p);
   655  	p->as = AJMP;
   656  	p->to.type = D_BRANCH;
   657  	p->pcond = ctxt->cursym->text->link;
   658  
   659  	if(q != nil)
   660  		q->pcond = p->link;
   661  	if(q1 != nil)
   662  		q1->pcond = q->link;
   663  	
   664  	*jmpok = q;
   665  	return p;
   666  }
   667  
   668  static void xfol(Link*, Prog*, Prog**);
   669  
   670  static void
   671  follow(Link *ctxt, LSym *s)
   672  {
   673  	Prog *firstp, *lastp;
   674  
   675  	ctxt->cursym = s;
   676  
   677  	firstp = ctxt->arch->prg();
   678  	lastp = firstp;
   679  	xfol(ctxt, s->text, &lastp);
   680  	lastp->link = nil;
   681  	s->text = firstp->link;
   682  }
   683  
   684  static int
   685  nofollow(int a)
   686  {
   687  	switch(a) {
   688  	case AJMP:
   689  	case ARET:
   690  	case AIRETL:
   691  	case AIRETW:
   692  	case AUNDEF:
   693  		return 1;
   694  	}
   695  	return 0;
   696  }
   697  
   698  static int
   699  pushpop(int a)
   700  {
   701  	switch(a) {
   702  	case APUSHL:
   703  	case APUSHFL:
   704  	case APUSHW:
   705  	case APUSHFW:
   706  	case APOPL:
   707  	case APOPFL:
   708  	case APOPW:
   709  	case APOPFW:
   710  		return 1;
   711  	}
   712  	return 0;
   713  }
   714  
   715  static int
   716  relinv(int a)
   717  {
   718  
   719  	switch(a) {
   720  	case AJEQ:	return AJNE;
   721  	case AJNE:	return AJEQ;
   722  	case AJLE:	return AJGT;
   723  	case AJLS:	return AJHI;
   724  	case AJLT:	return AJGE;
   725  	case AJMI:	return AJPL;
   726  	case AJGE:	return AJLT;
   727  	case AJPL:	return AJMI;
   728  	case AJGT:	return AJLE;
   729  	case AJHI:	return AJLS;
   730  	case AJCS:	return AJCC;
   731  	case AJCC:	return AJCS;
   732  	case AJPS:	return AJPC;
   733  	case AJPC:	return AJPS;
   734  	case AJOS:	return AJOC;
   735  	case AJOC:	return AJOS;
   736  	}
   737  	sysfatal("unknown relation: %s", anames8[a]);
   738  	return 0;
   739  }
   740  
   741  static void
   742  xfol(Link *ctxt, Prog *p, Prog **last)
   743  {
   744  	Prog *q;
   745  	int i;
   746  	int a;
   747  
   748  loop:
   749  	if(p == nil)
   750  		return;
   751  	if(p->as == AJMP)
   752  	if((q = p->pcond) != nil && q->as != ATEXT) {
   753  		/* mark instruction as done and continue layout at target of jump */
   754  		p->mark = 1;
   755  		p = q;
   756  		if(p->mark == 0)
   757  			goto loop;
   758  	}
   759  	if(p->mark) {
   760  		/* 
   761  		 * p goes here, but already used it elsewhere.
   762  		 * copy up to 4 instructions or else branch to other copy.
   763  		 */
   764  		for(i=0,q=p; i<4; i++,q=q->link) {
   765  			if(q == nil)
   766  				break;
   767  			if(q == *last)
   768  				break;
   769  			a = q->as;
   770  			if(a == ANOP) {
   771  				i--;
   772  				continue;
   773  			}
   774  			if(nofollow(a) || pushpop(a))	
   775  				break;	// NOTE(rsc): arm does goto copy
   776  			if(q->pcond == nil || q->pcond->mark)
   777  				continue;
   778  			if(a == ACALL || a == ALOOP)
   779  				continue;
   780  			for(;;) {
   781  				if(p->as == ANOP) {
   782  					p = p->link;
   783  					continue;
   784  				}
   785  				q = copyp(ctxt, p);
   786  				p = p->link;
   787  				q->mark = 1;
   788  				(*last)->link = q;
   789  				*last = q;
   790  				if(q->as != a || q->pcond == nil || q->pcond->mark)
   791  					continue;
   792  
   793  				q->as = relinv(q->as);
   794  				p = q->pcond;
   795  				q->pcond = q->link;
   796  				q->link = p;
   797  				xfol(ctxt, q->link, last);
   798  				p = q->link;
   799  				if(p->mark)
   800  					return;
   801  				goto loop;
   802  			}
   803  		} /* */
   804  		q = ctxt->arch->prg();
   805  		q->as = AJMP;
   806  		q->lineno = p->lineno;
   807  		q->to.type = D_BRANCH;
   808  		q->to.offset = p->pc;
   809  		q->pcond = p;
   810  		p = q;
   811  	}
   812  	
   813  	/* emit p */
   814  	p->mark = 1;
   815  	(*last)->link = p;
   816  	*last = p;
   817  	a = p->as;
   818  
   819  	/* continue loop with what comes after p */
   820  	if(nofollow(a))
   821  		return;
   822  	if(p->pcond != nil && a != ACALL) {
   823  		/*
   824  		 * some kind of conditional branch.
   825  		 * recurse to follow one path.
   826  		 * continue loop on the other.
   827  		 */
   828  		if((q = brchain(ctxt, p->pcond)) != nil)
   829  			p->pcond = q;
   830  		if((q = brchain(ctxt, p->link)) != nil)
   831  			p->link = q;
   832  		if(p->from.type == D_CONST) {
   833  			if(p->from.offset == 1) {
   834  				/*
   835  				 * expect conditional jump to be taken.
   836  				 * rewrite so that's the fall-through case.
   837  				 */
   838  				p->as = relinv(a);
   839  				q = p->link;
   840  				p->link = p->pcond;
   841  				p->pcond = q;
   842  			}
   843  		} else {
   844  			q = p->link;
   845  			if(q->mark)
   846  			if(a != ALOOP) {
   847  				p->as = relinv(a);
   848  				p->link = p->pcond;
   849  				p->pcond = q;
   850  			}
   851  		}
   852  		xfol(ctxt, p->link, last);
   853  		if(p->pcond->mark)
   854  			return;
   855  		p = p->pcond;
   856  		goto loop;
   857  	}
   858  	p = p->link;
   859  	goto loop;
   860  }
   861  
   862  LinkArch link386 = {
   863  	.name = "386",
   864  	.thechar = '8',
   865  	.endian = LittleEndian,
   866  
   867  	.addstacksplit = addstacksplit,
   868  	.assemble = span8,
   869  	.datasize = datasize,
   870  	.follow = follow,
   871  	.iscall = iscall,
   872  	.isdata = isdata,
   873  	.prg = prg,
   874  	.progedit = progedit,
   875  	.settextflag = settextflag,
   876  	.symtype = symtype,
   877  	.textflag = textflag,
   878  
   879  	.minlc = 1,
   880  	.ptrsize = 4,
   881  	.regsize = 4,
   882  
   883  	.D_ADDR = D_ADDR,
   884  	.D_AUTO = D_AUTO,
   885  	.D_BRANCH = D_BRANCH,
   886  	.D_CONST = D_CONST,
   887  	.D_EXTERN = D_EXTERN,
   888  	.D_FCONST = D_FCONST,
   889  	.D_NONE = D_NONE,
   890  	.D_PARAM = D_PARAM,
   891  	.D_SCONST = D_SCONST,
   892  	.D_STATIC = D_STATIC,
   893  
   894  	.ACALL = ACALL,
   895  	.ADATA = ADATA,
   896  	.AEND = AEND,
   897  	.AFUNCDATA = AFUNCDATA,
   898  	.AGLOBL = AGLOBL,
   899  	.AJMP = AJMP,
   900  	.ANOP = ANOP,
   901  	.APCDATA = APCDATA,
   902  	.ARET = ARET,
   903  	.ATEXT = ATEXT,
   904  	.ATYPE = ATYPE,
   905  	.AUSEFIELD = AUSEFIELD,
   906  };