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