github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/cmd/6l/pass.c (about)

     1  // Inferno utils/6l/pass.c
     2  // http://code.google.com/p/inferno-os/source/browse/utils/6l/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  // Code and data passes.
    32  
    33  #include	"l.h"
    34  #include	"../ld/lib.h"
    35  #include "../../pkg/runtime/stack.h"
    36  
    37  static void xfol(Prog*, Prog**);
    38  
    39  Prog*
    40  brchain(Prog *p)
    41  {
    42  	int i;
    43  
    44  	for(i=0; i<20; i++) {
    45  		if(p == P || p->as != AJMP)
    46  			return p;
    47  		p = p->pcond;
    48  	}
    49  	return P;
    50  }
    51  
    52  void
    53  follow(void)
    54  {
    55  	Prog *firstp, *lastp;
    56  
    57  	if(debug['v'])
    58  		Bprint(&bso, "%5.2f follow\n", cputime());
    59  	Bflush(&bso);
    60  	
    61  	for(cursym = textp; cursym != nil; cursym = cursym->next) {
    62  		firstp = prg();
    63  		lastp = firstp;
    64  		xfol(cursym->text, &lastp);
    65  		lastp->link = nil;
    66  		cursym->text = firstp->link;
    67  	}
    68  }
    69  
    70  static int
    71  nofollow(int a)
    72  {
    73  	switch(a) {
    74  	case AJMP:
    75  	case ARET:
    76  	case AIRETL:
    77  	case AIRETQ:
    78  	case AIRETW:
    79  	case ARETFL:
    80  	case ARETFQ:
    81  	case ARETFW:
    82  	case AUNDEF:
    83  		return 1;
    84  	}
    85  	return 0;
    86  }
    87  
    88  static int
    89  pushpop(int a)
    90  {
    91  	switch(a) {
    92  	case APUSHL:
    93  	case APUSHFL:
    94  	case APUSHQ:
    95  	case APUSHFQ:
    96  	case APUSHW:
    97  	case APUSHFW:
    98  	case APOPL:
    99  	case APOPFL:
   100  	case APOPQ:
   101  	case APOPFQ:
   102  	case APOPW:
   103  	case APOPFW:
   104  		return 1;
   105  	}
   106  	return 0;
   107  }
   108  
   109  static void
   110  xfol(Prog *p, Prog **last)
   111  {
   112  	Prog *q;
   113  	int i;
   114  	enum as a;
   115  
   116  loop:
   117  	if(p == P)
   118  		return;
   119  	if(p->as == AJMP)
   120  	if((q = p->pcond) != P && q->as != ATEXT) {
   121  		/* mark instruction as done and continue layout at target of jump */
   122  		p->mark = 1;
   123  		p = q;
   124  		if(p->mark == 0)
   125  			goto loop;
   126  	}
   127  	if(p->mark) {
   128  		/* 
   129  		 * p goes here, but already used it elsewhere.
   130  		 * copy up to 4 instructions or else branch to other copy.
   131  		 */
   132  		for(i=0,q=p; i<4; i++,q=q->link) {
   133  			if(q == P)
   134  				break;
   135  			if(q == *last)
   136  				break;
   137  			a = q->as;
   138  			if(a == ANOP) {
   139  				i--;
   140  				continue;
   141  			}
   142  			if(nofollow(a) || pushpop(a))	
   143  				break;	// NOTE(rsc): arm does goto copy
   144  			if(q->pcond == P || q->pcond->mark)
   145  				continue;
   146  			if(a == ACALL || a == ALOOP)
   147  				continue;
   148  			for(;;) {
   149  				if(p->as == ANOP) {
   150  					p = p->link;
   151  					continue;
   152  				}
   153  				q = copyp(p);
   154  				p = p->link;
   155  				q->mark = 1;
   156  				(*last)->link = q;
   157  				*last = q;
   158  				if(q->as != a || q->pcond == P || q->pcond->mark)
   159  					continue;
   160  
   161  				q->as = relinv(q->as);
   162  				p = q->pcond;
   163  				q->pcond = q->link;
   164  				q->link = p;
   165  				xfol(q->link, last);
   166  				p = q->link;
   167  				if(p->mark)
   168  					return;
   169  				goto loop;
   170  			}
   171  		} /* */
   172  		q = prg();
   173  		q->as = AJMP;
   174  		q->line = p->line;
   175  		q->to.type = D_BRANCH;
   176  		q->to.offset = p->pc;
   177  		q->pcond = p;
   178  		p = q;
   179  	}
   180  	
   181  	/* emit p */
   182  	p->mark = 1;
   183  	(*last)->link = p;
   184  	*last = p;
   185  	a = p->as;
   186  
   187  	/* continue loop with what comes after p */
   188  	if(nofollow(a))
   189  		return;
   190  	if(p->pcond != P && a != ACALL) {
   191  		/*
   192  		 * some kind of conditional branch.
   193  		 * recurse to follow one path.
   194  		 * continue loop on the other.
   195  		 */
   196  		if((q = brchain(p->pcond)) != P)
   197  			p->pcond = q;
   198  		if((q = brchain(p->link)) != P)
   199  			p->link = q;
   200  		if(p->from.type == D_CONST) {
   201  			if(p->from.offset == 1) {
   202  				/*
   203  				 * expect conditional jump to be taken.
   204  				 * rewrite so that's the fall-through case.
   205  				 */
   206  				p->as = relinv(a);
   207  				q = p->link;
   208  				p->link = p->pcond;
   209  				p->pcond = q;
   210  			}
   211  		} else {			
   212  			q = p->link;
   213  			if(q->mark)
   214  			if(a != ALOOP) {
   215  				p->as = relinv(a);
   216  				p->link = p->pcond;
   217  				p->pcond = q;
   218  			}
   219  		}
   220  		xfol(p->link, last);
   221  		if(p->pcond->mark)
   222  			return;
   223  		p = p->pcond;
   224  		goto loop;
   225  	}
   226  	p = p->link;
   227  	goto loop;
   228  }
   229  
   230  Prog*
   231  byteq(int v)
   232  {
   233  	Prog *p;
   234  
   235  	p = prg();
   236  	p->as = ABYTE;
   237  	p->from.type = D_CONST;
   238  	p->from.offset = v&0xff;
   239  	return p;
   240  }
   241  
   242  int
   243  relinv(int a)
   244  {
   245  
   246  	switch(a) {
   247  	case AJEQ:	return AJNE;
   248  	case AJNE:	return AJEQ;
   249  	case AJLE:	return AJGT;
   250  	case AJLS:	return AJHI;
   251  	case AJLT:	return AJGE;
   252  	case AJMI:	return AJPL;
   253  	case AJGE:	return AJLT;
   254  	case AJPL:	return AJMI;
   255  	case AJGT:	return AJLE;
   256  	case AJHI:	return AJLS;
   257  	case AJCS:	return AJCC;
   258  	case AJCC:	return AJCS;
   259  	case AJPS:	return AJPC;
   260  	case AJPC:	return AJPS;
   261  	case AJOS:	return AJOC;
   262  	case AJOC:	return AJOS;
   263  	}
   264  	diag("unknown relation: %s in %s", anames[a], TNAME);
   265  	errorexit();
   266  	return a;
   267  }
   268  
   269  void
   270  patch(void)
   271  {
   272  	int32 c;
   273  	Prog *p, *q;
   274  	Sym *s;
   275  	int32 vexit;
   276  	Sym *gmsym;
   277  
   278  	if(debug['v'])
   279  		Bprint(&bso, "%5.2f mkfwd\n", cputime());
   280  	Bflush(&bso);
   281  	mkfwd();
   282  	if(debug['v'])
   283  		Bprint(&bso, "%5.2f patch\n", cputime());
   284  	Bflush(&bso);
   285  
   286  	if(flag_shared) {
   287  		s = lookup("init_array", 0);
   288  		s->type = SINITARR;
   289  		s->reachable = 1;
   290  		s->hide = 1;
   291  		addaddr(s, lookup(INITENTRY, 0));
   292  	}
   293  
   294  	gmsym = lookup("runtime.tlsgm", 0);
   295  	if(linkmode != LinkExternal)
   296  		gmsym->reachable = 0;
   297  	s = lookup("exit", 0);
   298  	vexit = s->value;
   299  	for(cursym = textp; cursym != nil; cursym = cursym->next)
   300  	for(p = cursym->text; p != P; p = p->link) {
   301  		if(HEADTYPE == Hwindows) { 
   302  			// Windows
   303  			// Convert
   304  			//   op	  n(GS), reg
   305  			// to
   306  			//   MOVL 0x28(GS), reg
   307  			//   op	  n(reg), reg
   308  			// The purpose of this patch is to fix some accesses
   309  			// to extern register variables (TLS) on Windows, as
   310  			// a different method is used to access them.
   311  			if(p->from.type == D_INDIR+D_GS
   312  			&& p->to.type >= D_AX && p->to.type <= D_DI 
   313  			&& p->from.offset <= 8) {
   314  				q = appendp(p);
   315  				q->from = p->from;
   316  				q->from.type = D_INDIR + p->to.type;
   317  				q->to = p->to;
   318  				q->as = p->as;
   319  				p->as = AMOVQ;
   320  				p->from.type = D_INDIR+D_GS;
   321  				p->from.offset = 0x28;
   322  			}
   323  		}
   324  		if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd
   325  		|| HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd
   326  		|| HEADTYPE == Hplan9x64 || HEADTYPE == Hdragonfly) {
   327  			// ELF uses FS instead of GS.
   328  			if(p->from.type == D_INDIR+D_GS)
   329  				p->from.type = D_INDIR+D_FS;
   330  			if(p->to.type == D_INDIR+D_GS)
   331  				p->to.type = D_INDIR+D_FS;
   332  			if(p->from.index == D_GS)
   333  				p->from.index = D_FS;
   334  			if(p->to.index == D_GS)
   335  				p->to.index = D_FS;
   336  		}
   337  		if(!flag_shared) {
   338  			// Convert g() or m() accesses of the form
   339  			//   op n(reg)(GS*1), reg
   340  			// to
   341  			//   op n(GS*1), reg
   342  			if(p->from.index == D_FS || p->from.index == D_GS) {
   343  				p->from.type = D_INDIR + p->from.index;
   344  				p->from.index = D_NONE;
   345  			}
   346  			// Convert g() or m() accesses of the form
   347  			//   op reg, n(reg)(GS*1)
   348  			// to
   349  			//   op reg, n(GS*1)
   350  			if(p->to.index == D_FS || p->to.index == D_GS) {
   351  				p->to.type = D_INDIR + p->to.index;
   352  				p->to.index = D_NONE;
   353  			}
   354  			// Convert get_tls access of the form
   355  			//   op runtime.tlsgm(SB), reg
   356  			// to
   357  			//   NOP
   358  			if(gmsym != S && p->from.sym == gmsym) {
   359  				p->as = ANOP;
   360  				p->from.type = D_NONE;
   361  				p->to.type = D_NONE;
   362  				p->from.sym = nil;
   363  				p->to.sym = nil;
   364  				continue;
   365  			}
   366  		} else {
   367  			// Convert TLS reads of the form
   368  			//   op n(GS), reg
   369  			// to
   370  			//   MOVQ $runtime.tlsgm(SB), reg
   371  			//   op n(reg)(GS*1), reg
   372  			if((p->from.type == D_INDIR+D_FS || p->from.type == D_INDIR + D_GS) && p->to.type >= D_AX && p->to.type <= D_DI) {
   373  				q = appendp(p);
   374  				q->to = p->to;
   375  				q->as = p->as;
   376  				q->from.type = D_INDIR+p->to.type;
   377  				q->from.index = p->from.type - D_INDIR;
   378  				q->from.scale = 1;
   379  				q->from.offset = p->from.offset;
   380  				p->as = AMOVQ;
   381  				p->from.type = D_EXTERN;
   382  				p->from.sym = gmsym;
   383  				p->from.offset = 0;
   384  			}
   385  		}
   386  		if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH) || (p->as == ARET && p->to.sym != nil)) {
   387  			s = p->to.sym;
   388  			if(s) {
   389  				if(debug['c'])
   390  					Bprint(&bso, "%s calls %s\n", TNAME, s->name);
   391  				if((s->type&SMASK) != STEXT) {
   392  					/* diag prints TNAME first */
   393  					diag("undefined: %s", s->name);
   394  					s->type = STEXT;
   395  					s->value = vexit;
   396  					continue;	// avoid more error messages
   397  				}
   398  				if(s->text == nil)
   399  					continue;
   400  				p->to.type = D_BRANCH;
   401  				p->to.offset = s->text->pc;
   402  				p->pcond = s->text;
   403  				continue;
   404  			}
   405  		}
   406  		if(p->to.type != D_BRANCH)
   407  			continue;
   408  		c = p->to.offset;
   409  		for(q = cursym->text; q != P;) {
   410  			if(c == q->pc)
   411  				break;
   412  			if(q->forwd != P && c >= q->forwd->pc)
   413  				q = q->forwd;
   414  			else
   415  				q = q->link;
   416  		}
   417  		if(q == P) {
   418  			diag("branch out of range in %s (%#ux)\n%P [%s]",
   419  				TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>");
   420  			p->to.type = D_NONE;
   421  		}
   422  		p->pcond = q;
   423  	}
   424  
   425  	for(cursym = textp; cursym != nil; cursym = cursym->next)
   426  	for(p = cursym->text; p != P; p = p->link) {
   427  		p->mark = 0;	/* initialization for follow */
   428  		if(p->pcond != P) {
   429  			p->pcond = brloop(p->pcond);
   430  			if(p->pcond != P)
   431  			if(p->to.type == D_BRANCH)
   432  				p->to.offset = p->pcond->pc;
   433  		}
   434  	}
   435  }
   436  
   437  Prog*
   438  brloop(Prog *p)
   439  {
   440  	int c;
   441  	Prog *q;
   442  
   443  	c = 0;
   444  	for(q = p; q != P; q = q->pcond) {
   445  		if(q->as != AJMP)
   446  			break;
   447  		c++;
   448  		if(c >= 5000)
   449  			return P;
   450  	}
   451  	return q;
   452  }
   453  
   454  static char*
   455  morename[] =
   456  {
   457  	"runtime.morestack00",
   458  	"runtime.morestack10",
   459  	"runtime.morestack01",
   460  	"runtime.morestack11",
   461  
   462  	"runtime.morestack8",
   463  	"runtime.morestack16",
   464  	"runtime.morestack24",
   465  	"runtime.morestack32",
   466  	"runtime.morestack40",
   467  	"runtime.morestack48",
   468  };
   469  Prog*	pmorestack[nelem(morename)];
   470  Sym*	symmorestack[nelem(morename)];
   471  Sym*	gmsym;
   472  
   473  static Prog*	load_g_cx(Prog*);
   474  static Prog*	stacksplit(Prog*, int32, Prog**);
   475  
   476  void
   477  dostkoff(void)
   478  {
   479  	Prog *p, *q, *q1;
   480  	int32 autoffset, deltasp;
   481  	int a, pcsize;
   482  	uint32 i;
   483  
   484  	gmsym = lookup("runtime.tlsgm", 0);
   485  	for(i=0; i<nelem(morename); i++) {
   486  		symmorestack[i] = lookup(morename[i], 0);
   487  		if(symmorestack[i]->type != STEXT)
   488  			diag("morestack trampoline not defined - %s", morename[i]);
   489  		pmorestack[i] = symmorestack[i]->text;
   490  	}
   491  
   492  	for(cursym = textp; cursym != nil; cursym = cursym->next) {
   493  		if(cursym->text == nil || cursym->text->link == nil)
   494  			continue;				
   495  
   496  		p = cursym->text;
   497  		parsetextconst(p->to.offset);
   498  		autoffset = textstksiz;
   499  		if(autoffset < 0)
   500  			autoffset = 0;
   501  
   502  		if(autoffset < StackSmall && !(p->from.scale & NOSPLIT)) {
   503  			for(q = p; q != P; q = q->link)
   504  				if(q->as == ACALL)
   505  					goto noleaf;
   506  			p->from.scale |= NOSPLIT;
   507  		noleaf:;
   508  		}
   509  
   510  		if((p->from.scale & NOSPLIT) && autoffset >= StackSmall)
   511  			diag("nosplit func likely to overflow stack");
   512  
   513  		q = P;
   514  		if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) {
   515  			p = appendp(p);
   516  			p = load_g_cx(p); // load g into CX
   517  		}
   518  		if(!(cursym->text->from.scale & NOSPLIT))
   519  			p = stacksplit(p, autoffset, &q); // emit split check
   520  
   521  		if(autoffset) {
   522  			p = appendp(p);
   523  			p->as = AADJSP;
   524  			p->from.type = D_CONST;
   525  			p->from.offset = autoffset;
   526  			p->spadj = autoffset;
   527  		} else {
   528  			// zero-byte stack adjustment.
   529  			// Insert a fake non-zero adjustment so that stkcheck can
   530  			// recognize the end of the stack-splitting prolog.
   531  			p = appendp(p);
   532  			p->as = ANOP;
   533  			p->spadj = -PtrSize;
   534  			p = appendp(p);
   535  			p->as = ANOP;
   536  			p->spadj = PtrSize;
   537  		}
   538  		if(q != P)
   539  			q->pcond = p;
   540  		deltasp = autoffset;
   541  		
   542  		if(cursym->text->from.scale & WRAPPER) {
   543  			// g->panicwrap += autoffset + PtrSize;
   544  			p = appendp(p);
   545  			p->as = AADDL;
   546  			p->from.type = D_CONST;
   547  			p->from.offset = autoffset + PtrSize;
   548  			p->to.type = D_INDIR+D_CX;
   549  			p->to.offset = 2*PtrSize;
   550  		}
   551  
   552  		if(debug['K'] > 1 && autoffset) {
   553  			// 6l -KK means double-check for stack overflow
   554  			// even after calling morestack and even if the
   555  			// function is marked as nosplit.
   556  			p = appendp(p);
   557  			p->as = AMOVQ;
   558  			p->from.type = D_INDIR+D_CX;
   559  			p->from.offset = 0;
   560  			p->to.type = D_BX;
   561  
   562  			p = appendp(p);
   563  			p->as = ASUBQ;
   564  			p->from.type = D_CONST;
   565  			p->from.offset = StackSmall+32;
   566  			p->to.type = D_BX;
   567  
   568  			p = appendp(p);
   569  			p->as = ACMPQ;
   570  			p->from.type = D_SP;
   571  			p->to.type = D_BX;
   572  
   573  			p = appendp(p);
   574  			p->as = AJHI;
   575  			p->to.type = D_BRANCH;
   576  			q1 = p;
   577  
   578  			p = appendp(p);
   579  			p->as = AINT;
   580  			p->from.type = D_CONST;
   581  			p->from.offset = 3;
   582  
   583  			p = appendp(p);
   584  			p->as = ANOP;
   585  			q1->pcond = p;
   586  		}
   587  		
   588  		if(debug['Z'] && autoffset && !(cursym->text->from.scale&NOSPLIT)) {
   589  			// 6l -Z means zero the stack frame on entry.
   590  			// This slows down function calls but can help avoid
   591  			// false positives in garbage collection.
   592  			p = appendp(p);
   593  			p->as = AMOVQ;
   594  			p->from.type = D_SP;
   595  			p->to.type = D_DI;
   596  			
   597  			p = appendp(p);
   598  			p->as = AMOVQ;
   599  			p->from.type = D_CONST;
   600  			p->from.offset = autoffset/8;
   601  			p->to.type = D_CX;
   602  			
   603  			p = appendp(p);
   604  			p->as = AMOVQ;
   605  			p->from.type = D_CONST;
   606  			p->from.offset = 0;
   607  			p->to.type = D_AX;
   608  			
   609  			p = appendp(p);
   610  			p->as = AREP;
   611  			
   612  			p = appendp(p);
   613  			p->as = ASTOSQ;
   614  		}
   615  		
   616  		for(; p != P; p = p->link) {
   617  			pcsize = p->mode/8;
   618  			a = p->from.type;
   619  			if(a == D_AUTO)
   620  				p->from.offset += deltasp;
   621  			if(a == D_PARAM)
   622  				p->from.offset += deltasp + pcsize;
   623  			a = p->to.type;
   624  			if(a == D_AUTO)
   625  				p->to.offset += deltasp;
   626  			if(a == D_PARAM)
   627  				p->to.offset += deltasp + pcsize;
   628  	
   629  			switch(p->as) {
   630  			default:
   631  				continue;
   632  			case APUSHL:
   633  			case APUSHFL:
   634  				deltasp += 4;
   635  				p->spadj = 4;
   636  				continue;
   637  			case APUSHQ:
   638  			case APUSHFQ:
   639  				deltasp += 8;
   640  				p->spadj = 8;
   641  				continue;
   642  			case APUSHW:
   643  			case APUSHFW:
   644  				deltasp += 2;
   645  				p->spadj = 2;
   646  				continue;
   647  			case APOPL:
   648  			case APOPFL:
   649  				deltasp -= 4;
   650  				p->spadj = -4;
   651  				continue;
   652  			case APOPQ:
   653  			case APOPFQ:
   654  				deltasp -= 8;
   655  				p->spadj = -8;
   656  				continue;
   657  			case APOPW:
   658  			case APOPFW:
   659  				deltasp -= 2;
   660  				p->spadj = -2;
   661  				continue;
   662  			case ARET:
   663  				break;
   664  			}
   665  	
   666  			if(autoffset != deltasp)
   667  				diag("unbalanced PUSH/POP");
   668  
   669  			if(cursym->text->from.scale & WRAPPER) {
   670  				p = load_g_cx(p);
   671  				p = appendp(p);
   672  				// g->panicwrap -= autoffset + PtrSize;
   673  				p->as = ASUBL;
   674  				p->from.type = D_CONST;
   675  				p->from.offset = autoffset + PtrSize;
   676  				p->to.type = D_INDIR+D_CX;
   677  				p->to.offset = 2*PtrSize;
   678  				p = appendp(p);
   679  				p->as = ARET;
   680  			}
   681  	
   682  			if(autoffset) {
   683  				p->as = AADJSP;
   684  				p->from.type = D_CONST;
   685  				p->from.offset = -autoffset;
   686  				p->spadj = -autoffset;
   687  				p = appendp(p);
   688  				p->as = ARET;
   689  				// If there are instructions following
   690  				// this ARET, they come from a branch
   691  				// with the same stackframe, so undo
   692  				// the cleanup.
   693  				p->spadj = +autoffset;
   694  			}
   695  			if(p->to.sym) // retjmp
   696  				p->as = AJMP;
   697  		}
   698  	}
   699  }
   700  
   701  // Append code to p to load g into cx.
   702  // Overwrites p with the first instruction (no first appendp).
   703  // Overwriting p is unusual but it lets use this in both the
   704  // prologue (caller must call appendp first) and in the epilogue.
   705  // Returns last new instruction.
   706  static Prog*
   707  load_g_cx(Prog *p)
   708  {
   709  	if(flag_shared) {
   710  		// Load TLS offset with MOVQ $runtime.tlsgm(SB), CX
   711  		p->as = AMOVQ;
   712  		p->from.type = D_EXTERN;
   713  		p->from.sym = gmsym;
   714  		p->to.type = D_CX;
   715  		p = appendp(p);
   716  	}
   717  	p->as = AMOVQ;
   718  	if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd
   719  	|| HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd
   720  	|| HEADTYPE == Hplan9x64 || HEADTYPE == Hdragonfly)
   721  		// ELF uses FS
   722  		p->from.type = D_INDIR+D_FS;
   723  	else
   724  		p->from.type = D_INDIR+D_GS;
   725  	if(flag_shared) {
   726  		// Add TLS offset stored in CX
   727  		p->from.index = p->from.type - D_INDIR;
   728  		p->from.type = D_INDIR + D_CX;
   729  	}
   730  	p->from.offset = tlsoffset+0;
   731  	p->to.type = D_CX;
   732  	if(HEADTYPE == Hwindows) {
   733  		// movq %gs:0x28, %rcx
   734  		// movq (%rcx), %rcx
   735  		p->as = AMOVQ;
   736  		p->from.type = D_INDIR+D_GS;
   737  		p->from.offset = 0x28;
   738  		p->to.type = D_CX;
   739  
   740  		p = appendp(p);
   741  		p->as = AMOVQ;
   742  		p->from.type = D_INDIR+D_CX;
   743  		p->from.offset = 0;
   744  		p->to.type = D_CX;
   745  	}
   746  	return p;
   747  }
   748  
   749  // Append code to p to check for stack split.
   750  // Appends to (does not overwrite) p.
   751  // Assumes g is in CX.
   752  // Returns last new instruction.
   753  // On return, *jmpok is the instruction that should jump
   754  // to the stack frame allocation if no split is needed.
   755  static Prog*
   756  stacksplit(Prog *p, int32 framesize, Prog **jmpok)
   757  {
   758  	Prog *q, *q1;
   759  	uint32 moreconst1, moreconst2, i;
   760  
   761  	if(debug['K']) {
   762  		// 6l -K means check not only for stack
   763  		// overflow but stack underflow.
   764  		// On underflow, INT 3 (breakpoint).
   765  		// Underflow itself is rare but this also
   766  		// catches out-of-sync stack guard info
   767  
   768  		p = appendp(p);
   769  		p->as = ACMPQ;
   770  		p->from.type = D_INDIR+D_CX;
   771  		p->from.offset = 8;
   772  		p->to.type = D_SP;
   773  
   774  		p = appendp(p);
   775  		p->as = AJHI;
   776  		p->to.type = D_BRANCH;
   777  		p->to.offset = 4;
   778  		q1 = p;
   779  
   780  		p = appendp(p);
   781  		p->as = AINT;
   782  		p->from.type = D_CONST;
   783  		p->from.offset = 3;
   784  
   785  		p = appendp(p);
   786  		p->as = ANOP;
   787  		q1->pcond = p;
   788  	}
   789  
   790  	q = P;
   791  	q1 = P;
   792  	if(framesize <= StackSmall) {
   793  		// small stack: SP <= stackguard
   794  		//	CMPQ SP, stackguard
   795  		p = appendp(p);
   796  		p->as = ACMPQ;
   797  		p->from.type = D_SP;
   798  		p->to.type = D_INDIR+D_CX;
   799  	} else if(framesize <= StackBig) {
   800  		// large stack: SP-framesize <= stackguard-StackSmall
   801  		//	LEAQ -xxx(SP), AX
   802  		//	CMPQ AX, stackguard
   803  		p = appendp(p);
   804  		p->as = ALEAQ;
   805  		p->from.type = D_INDIR+D_SP;
   806  		p->from.offset = -(framesize-StackSmall);
   807  		p->to.type = D_AX;
   808  
   809  		p = appendp(p);
   810  		p->as = ACMPQ;
   811  		p->from.type = D_AX;
   812  		p->to.type = D_INDIR+D_CX;
   813  	} else {
   814  		// Such a large stack we need to protect against wraparound.
   815  		// If SP is close to zero:
   816  		//	SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
   817  		// The +StackGuard on both sides is required to keep the left side positive:
   818  		// SP is allowed to be slightly below stackguard. See stack.h.
   819  		//
   820  		// Preemption sets stackguard to StackPreempt, a very large value.
   821  		// That breaks the math above, so we have to check for that explicitly.
   822  		//	MOVQ	stackguard, CX
   823  		//	CMPQ	CX, $StackPreempt
   824  		//	JEQ	label-of-call-to-morestack
   825  		//	LEAQ	StackGuard(SP), AX
   826  		//	SUBQ	CX, AX
   827  		//	CMPQ	AX, $(framesize+(StackGuard-StackSmall))
   828  
   829  		p = appendp(p);
   830  		p->as = AMOVQ;
   831  		p->from.type = D_INDIR+D_CX;
   832  		p->from.offset = 0;
   833  		p->to.type = D_SI;
   834  
   835  		p = appendp(p);
   836  		p->as = ACMPQ;
   837  		p->from.type = D_SI;
   838  		p->to.type = D_CONST;
   839  		p->to.offset = StackPreempt;
   840  
   841  		p = appendp(p);
   842  		p->as = AJEQ;
   843  		p->to.type = D_BRANCH;
   844  		q1 = p;
   845  
   846  		p = appendp(p);
   847  		p->as = ALEAQ;
   848  		p->from.type = D_INDIR+D_SP;
   849  		p->from.offset = StackGuard;
   850  		p->to.type = D_AX;
   851  		
   852  		p = appendp(p);
   853  		p->as = ASUBQ;
   854  		p->from.type = D_SI;
   855  		p->to.type = D_AX;
   856  		
   857  		p = appendp(p);
   858  		p->as = ACMPQ;
   859  		p->from.type = D_AX;
   860  		p->to.type = D_CONST;
   861  		p->to.offset = framesize+(StackGuard-StackSmall);
   862  	}					
   863  
   864  	// common
   865  	p = appendp(p);
   866  	p->as = AJHI;
   867  	p->to.type = D_BRANCH;
   868  	q = p;
   869  
   870  	// If we ask for more stack, we'll get a minimum of StackMin bytes.
   871  	// We need a stack frame large enough to hold the top-of-stack data,
   872  	// the function arguments+results, our caller's PC, our frame,
   873  	// a word for the return PC of the next call, and then the StackLimit bytes
   874  	// that must be available on entry to any function called from a function
   875  	// that did a stack check.  If StackMin is enough, don't ask for a specific
   876  	// amount: then we can use the custom functions and save a few
   877  	// instructions.
   878  	moreconst1 = 0;
   879  	if(StackTop + textarg + PtrSize + framesize + PtrSize + StackLimit >= StackMin)
   880  		moreconst1 = framesize;
   881  	moreconst2 = textarg;
   882  	if(moreconst2 == 1) // special marker
   883  		moreconst2 = 0;
   884  	if((moreconst2&7) != 0)
   885  		diag("misaligned argument size in stack split");
   886  	// 4 varieties varieties (const1==0 cross const2==0)
   887  	// and 6 subvarieties of (const1==0 and const2!=0)
   888  	p = appendp(p);
   889  	if(moreconst1 == 0 && moreconst2 == 0) {
   890  		p->as = ACALL;
   891  		p->to.type = D_BRANCH;
   892  		p->pcond = pmorestack[0];
   893  		p->to.sym = symmorestack[0];
   894  	} else
   895  	if(moreconst1 != 0 && moreconst2 == 0) {
   896  		p->as = AMOVL;
   897  		p->from.type = D_CONST;
   898  		p->from.offset = moreconst1;
   899  		p->to.type = D_AX;
   900  
   901  		p = appendp(p);
   902  		p->as = ACALL;
   903  		p->to.type = D_BRANCH;
   904  		p->pcond = pmorestack[1];
   905  		p->to.sym = symmorestack[1];
   906  	} else
   907  	if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) {
   908  		i = moreconst2/8 + 3;
   909  		p->as = ACALL;
   910  		p->to.type = D_BRANCH;
   911  		p->pcond = pmorestack[i];
   912  		p->to.sym = symmorestack[i];
   913  	} else
   914  	if(moreconst1 == 0 && moreconst2 != 0) {
   915  		p->as = AMOVL;
   916  		p->from.type = D_CONST;
   917  		p->from.offset = moreconst2;
   918  		p->to.type = D_AX;
   919  
   920  		p = appendp(p);
   921  		p->as = ACALL;
   922  		p->to.type = D_BRANCH;
   923  		p->pcond = pmorestack[2];
   924  		p->to.sym = symmorestack[2];
   925  	} else {
   926  		p->as = AMOVQ;
   927  		p->from.type = D_CONST;
   928  		p->from.offset = (uint64)moreconst2 << 32;
   929  		p->from.offset |= moreconst1;
   930  		p->to.type = D_AX;
   931  
   932  		p = appendp(p);
   933  		p->as = ACALL;
   934  		p->to.type = D_BRANCH;
   935  		p->pcond = pmorestack[3];
   936  		p->to.sym = symmorestack[3];
   937  	}
   938  	
   939  	p = appendp(p);
   940  	p->as = AJMP;
   941  	p->to.type = D_BRANCH;
   942  	p->pcond = cursym->text->link;
   943  	
   944  	if(q != P)
   945  		q->pcond = p->link;
   946  	if(q1 != P)
   947  		q1->pcond = q->link;
   948  
   949  	*jmpok = q;
   950  	return p;
   951  }
   952  
   953  vlong
   954  atolwhex(char *s)
   955  {
   956  	vlong n;
   957  	int f;
   958  
   959  	n = 0;
   960  	f = 0;
   961  	while(*s == ' ' || *s == '\t')
   962  		s++;
   963  	if(*s == '-' || *s == '+') {
   964  		if(*s++ == '-')
   965  			f = 1;
   966  		while(*s == ' ' || *s == '\t')
   967  			s++;
   968  	}
   969  	if(s[0]=='0' && s[1]){
   970  		if(s[1]=='x' || s[1]=='X'){
   971  			s += 2;
   972  			for(;;){
   973  				if(*s >= '0' && *s <= '9')
   974  					n = n*16 + *s++ - '0';
   975  				else if(*s >= 'a' && *s <= 'f')
   976  					n = n*16 + *s++ - 'a' + 10;
   977  				else if(*s >= 'A' && *s <= 'F')
   978  					n = n*16 + *s++ - 'A' + 10;
   979  				else
   980  					break;
   981  			}
   982  		} else
   983  			while(*s >= '0' && *s <= '7')
   984  				n = n*8 + *s++ - '0';
   985  	} else
   986  		while(*s >= '0' && *s <= '9')
   987  			n = n*10 + *s++ - '0';
   988  	if(f)
   989  		n = -n;
   990  	return n;
   991  }