github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/cmd/8l/pass.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  // 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 AIRETW:
    78  	case AUNDEF:
    79  		return 1;
    80  	}
    81  	return 0;
    82  }
    83  
    84  static int
    85  pushpop(int a)
    86  {
    87  	switch(a) {
    88  	case APUSHL:
    89  	case APUSHFL:
    90  	case APUSHW:
    91  	case APUSHFW:
    92  	case APOPL:
    93  	case APOPFL:
    94  	case APOPW:
    95  	case APOPFW:
    96  		return 1;
    97  	}
    98  	return 0;
    99  }
   100  
   101  static void
   102  xfol(Prog *p, Prog **last)
   103  {
   104  	Prog *q;
   105  	int i;
   106  	enum as a;
   107  
   108  loop:
   109  	if(p == P)
   110  		return;
   111  	if(p->as == AJMP)
   112  	if((q = p->pcond) != P && q->as != ATEXT) {
   113  		/* mark instruction as done and continue layout at target of jump */
   114  		p->mark = 1;
   115  		p = q;
   116  		if(p->mark == 0)
   117  			goto loop;
   118  	}
   119  	if(p->mark) {
   120  		/* 
   121  		 * p goes here, but already used it elsewhere.
   122  		 * copy up to 4 instructions or else branch to other copy.
   123  		 */
   124  		for(i=0,q=p; i<4; i++,q=q->link) {
   125  			if(q == P)
   126  				break;
   127  			if(q == *last)
   128  				break;
   129  			a = q->as;
   130  			if(a == ANOP) {
   131  				i--;
   132  				continue;
   133  			}
   134  			if(nofollow(a) || pushpop(a))	
   135  				break;	// NOTE(rsc): arm does goto copy
   136  			if(q->pcond == P || q->pcond->mark)
   137  				continue;
   138  			if(a == ACALL || a == ALOOP)
   139  				continue;
   140  			for(;;) {
   141  				if(p->as == ANOP) {
   142  					p = p->link;
   143  					continue;
   144  				}
   145  				q = copyp(p);
   146  				p = p->link;
   147  				q->mark = 1;
   148  				(*last)->link = q;
   149  				*last = q;
   150  				if(q->as != a || q->pcond == P || q->pcond->mark)
   151  					continue;
   152  
   153  				q->as = relinv(q->as);
   154  				p = q->pcond;
   155  				q->pcond = q->link;
   156  				q->link = p;
   157  				xfol(q->link, last);
   158  				p = q->link;
   159  				if(p->mark)
   160  					return;
   161  				goto loop;
   162  			}
   163  		} /* */
   164  		q = prg();
   165  		q->as = AJMP;
   166  		q->line = p->line;
   167  		q->to.type = D_BRANCH;
   168  		q->to.offset = p->pc;
   169  		q->pcond = p;
   170  		p = q;
   171  	}
   172  	
   173  	/* emit p */
   174  	p->mark = 1;
   175  	(*last)->link = p;
   176  	*last = p;
   177  	a = p->as;
   178  
   179  	/* continue loop with what comes after p */
   180  	if(nofollow(a))
   181  		return;
   182  	if(p->pcond != P && a != ACALL) {
   183  		/*
   184  		 * some kind of conditional branch.
   185  		 * recurse to follow one path.
   186  		 * continue loop on the other.
   187  		 */
   188  		if((q = brchain(p->pcond)) != P)
   189  			p->pcond = q;
   190  		if((q = brchain(p->link)) != P)
   191  			p->link = q;
   192  		if(p->from.type == D_CONST) {
   193  			if(p->from.offset == 1) {
   194  				/*
   195  				 * expect conditional jump to be taken.
   196  				 * rewrite so that's the fall-through case.
   197  				 */
   198  				p->as = relinv(a);
   199  				q = p->link;
   200  				p->link = p->pcond;
   201  				p->pcond = q;
   202  			}
   203  		} else {
   204  			q = p->link;
   205  			if(q->mark)
   206  			if(a != ALOOP) {
   207  				p->as = relinv(a);
   208  				p->link = p->pcond;
   209  				p->pcond = q;
   210  			}
   211  		}
   212  		xfol(p->link, last);
   213  		if(p->pcond->mark)
   214  			return;
   215  		p = p->pcond;
   216  		goto loop;
   217  	}
   218  	p = p->link;
   219  	goto loop;
   220  }
   221  
   222  int
   223  relinv(int a)
   224  {
   225  
   226  	switch(a) {
   227  	case AJEQ:	return AJNE;
   228  	case AJNE:	return AJEQ;
   229  	case AJLE:	return AJGT;
   230  	case AJLS:	return AJHI;
   231  	case AJLT:	return AJGE;
   232  	case AJMI:	return AJPL;
   233  	case AJGE:	return AJLT;
   234  	case AJPL:	return AJMI;
   235  	case AJGT:	return AJLE;
   236  	case AJHI:	return AJLS;
   237  	case AJCS:	return AJCC;
   238  	case AJCC:	return AJCS;
   239  	case AJPS:	return AJPC;
   240  	case AJPC:	return AJPS;
   241  	case AJOS:	return AJOC;
   242  	case AJOC:	return AJOS;
   243  	}
   244  	diag("unknown relation: %s in %s", anames[a], TNAME);
   245  	return a;
   246  }
   247  
   248  void
   249  patch(void)
   250  {
   251  	int32 c;
   252  	Prog *p, *q;
   253  	Sym *s;
   254  	int32 vexit;
   255  	Sym *plan9_tos;
   256  
   257  	if(debug['v'])
   258  		Bprint(&bso, "%5.2f mkfwd\n", cputime());
   259  	Bflush(&bso);
   260  	mkfwd();
   261  	if(debug['v'])
   262  		Bprint(&bso, "%5.2f patch\n", cputime());
   263  	Bflush(&bso);
   264  	s = lookup("exit", 0);
   265  	vexit = s->value;
   266  	
   267  	plan9_tos = S;
   268  	if(HEADTYPE == Hplan9x32)
   269  		plan9_tos = lookup("_tos", 0);
   270  	
   271  	for(cursym = textp; cursym != nil; cursym = cursym->next) {
   272  		for(p = cursym->text; p != P; p = p->link) {
   273  			if(HEADTYPE == Hwindows) {
   274  				// Convert
   275  				//   op	  n(GS), reg
   276  				// to
   277  				//   MOVL 0x14(FS), reg
   278  				//   op	  n(reg), reg
   279  				// The purpose of this patch is to fix some accesses
   280  				// to extern register variables (TLS) on Windows, as
   281  				// a different method is used to access them.
   282  				if(p->from.type == D_INDIR+D_GS
   283  				&& p->to.type >= D_AX && p->to.type <= D_DI) {
   284  					q = appendp(p);
   285  					q->from = p->from;
   286  					q->from.type = D_INDIR + p->to.type;
   287  					q->to = p->to;
   288  					q->as = p->as;
   289  					p->as = AMOVL;
   290  					p->from.type = D_INDIR+D_FS;
   291  					p->from.offset = 0x14;
   292  				}
   293  			}
   294  			if(HEADTYPE == Hlinux) {
   295  				// Running binaries under Xen requires using
   296  				//	MOVL 0(GS), reg
   297  				// and then off(reg) instead of saying off(GS) directly
   298  				// when the offset is negative.
   299  				// In external mode we just produce a reloc.
   300  				if(p->from.type == D_INDIR+D_GS && p->from.offset < 0
   301  				&& p->to.type >= D_AX && p->to.type <= D_DI) {
   302  					if(linkmode != LinkExternal) {
   303  						q = appendp(p);
   304  						q->from = p->from;
   305  						q->from.type = D_INDIR + p->to.type;
   306  						q->to = p->to;
   307  						q->as = p->as;
   308  						p->as = AMOVL;
   309  						p->from.type = D_INDIR+D_GS;
   310  						p->from.offset = 0;
   311  					} else {
   312  						// Add signals to relocate.
   313  						p->from.index = D_GS;
   314  						p->from.scale = 1;
   315  					}
   316  				}
   317  			}
   318  			if(HEADTYPE == Hplan9x32) {
   319  				if(p->from.type == D_INDIR+D_GS
   320  				&& p->to.type >= D_AX && p->to.type <= D_DI) {
   321  					q = appendp(p);
   322  					q->from = p->from;
   323  					q->from.type = D_INDIR + p->to.type;
   324  					q->to = p->to;
   325  					q->as = p->as;
   326  					p->as = AMOVL;
   327  					p->from.type = D_EXTERN;
   328  					p->from.sym = plan9_tos;
   329  					p->from.offset = 0;
   330  				}
   331  			}
   332  			if((p->as == ACALL && p->to.type != D_BRANCH) || (p->as == AJMP && p->to.type != D_BRANCH) || (p->as == ARET && p->to.sym != nil)) {
   333  				s = p->to.sym;
   334  				if(p->to.type == D_INDIR+D_ADDR) {
   335  					 /* skip check if this is an indirect call (CALL *symbol(SB)) */
   336  					 continue;
   337  				} else if(s) {
   338  					if(debug['c'])
   339  						Bprint(&bso, "%s calls %s\n", TNAME, s->name);
   340  					if((s->type&SMASK) != STEXT) {
   341  						/* diag prints TNAME first */
   342  						diag("undefined: %s", s->name);
   343  						s->type = STEXT;
   344  						s->value = vexit;
   345  						continue;	// avoid more error messages
   346  					}
   347  					if(s->text == nil)
   348  						continue;
   349  					p->to.type = D_BRANCH;
   350  					p->to.offset = s->text->pc;
   351  					p->pcond = s->text;
   352  					continue;
   353  				}
   354  			}
   355  			if(p->to.type != D_BRANCH)
   356  				continue;
   357  			c = p->to.offset;
   358  			for(q = cursym->text; q != P;) {
   359  				if(c == q->pc)
   360  					break;
   361  				if(q->forwd != P && c >= q->forwd->pc)
   362  					q = q->forwd;
   363  				else
   364  					q = q->link;
   365  			}
   366  			if(q == P) {
   367  				diag("branch out of range in %s (%#ux)\n%P [%s]",
   368  					TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>");
   369  				p->to.type = D_NONE;
   370  			}
   371  			p->pcond = q;
   372  		}
   373  	}
   374  
   375  	for(cursym = textp; cursym != nil; cursym = cursym->next) {
   376  		if(cursym->text == nil || cursym->p != nil)
   377  			continue;
   378  
   379  		for(p = cursym->text; p != P; p = p->link) {
   380  			p->mark = 0;	/* initialization for follow */
   381  			if(p->pcond != P) {
   382  				p->pcond = brloop(p->pcond);
   383  				if(p->pcond != P)
   384  				if(p->to.type == D_BRANCH)
   385  					p->to.offset = p->pcond->pc;
   386  			}
   387  		}
   388  	}
   389  }
   390  
   391  Prog*
   392  brloop(Prog *p)
   393  {
   394  	int c;
   395  	Prog *q;
   396  
   397  	c = 0;
   398  	for(q = p; q != P; q = q->pcond) {
   399  		if(q->as != AJMP)
   400  			break;
   401  		c++;
   402  		if(c >= 5000)
   403  			return P;
   404  	}
   405  	return q;
   406  }
   407  
   408  static Prog*	load_g_cx(Prog*);
   409  static Prog*	stacksplit(Prog*, int32, Prog**);
   410  
   411  static Sym *plan9_tos;
   412  static Prog *pmorestack;
   413  static Sym *symmorestack;
   414  
   415  void
   416  dostkoff(void)
   417  {
   418  	Prog *p, *q;
   419  	int32 autoffset, deltasp;
   420  	int a;
   421  
   422  	pmorestack = P;
   423  	symmorestack = lookup("runtime.morestack", 0);
   424  
   425  	if(symmorestack->type != STEXT)
   426  		diag("runtime.morestack not defined");
   427  	else {
   428  		pmorestack = symmorestack->text;
   429  		symmorestack->text->from.scale |= NOSPLIT;
   430  	}
   431  	
   432  	plan9_tos = S;
   433  	if(HEADTYPE == Hplan9x32)
   434  		plan9_tos = lookup("_tos", 0);
   435  
   436  	for(cursym = textp; cursym != nil; cursym = cursym->next) {
   437  		if(cursym->text == nil || cursym->text->link == nil)
   438  			continue;
   439  
   440  		p = cursym->text;
   441  		autoffset = p->to.offset;
   442  		if(autoffset < 0)
   443  			autoffset = 0;
   444  
   445  		q = P;
   446  
   447  		if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) {
   448  			p = appendp(p);
   449  			p = load_g_cx(p); // load g into CX
   450  		}
   451  		if(!(cursym->text->from.scale & NOSPLIT))
   452  			p = stacksplit(p, autoffset, &q); // emit split check
   453  
   454  		if(autoffset) {
   455  			p = appendp(p);
   456  			p->as = AADJSP;
   457  			p->from.type = D_CONST;
   458  			p->from.offset = autoffset;
   459  			p->spadj = autoffset;
   460  		} else {
   461  			// zero-byte stack adjustment.
   462  			// Insert a fake non-zero adjustment so that stkcheck can
   463  			// recognize the end of the stack-splitting prolog.
   464  			p = appendp(p);
   465  			p->as = ANOP;
   466  			p->spadj = -PtrSize;
   467  			p = appendp(p);
   468  			p->as = ANOP;
   469  			p->spadj = PtrSize;
   470  		}
   471  		if(q != P)
   472  			q->pcond = p;
   473  		deltasp = autoffset;
   474  		
   475  		if(cursym->text->from.scale & WRAPPER) {
   476  			// g->panicwrap += autoffset + PtrSize;
   477  			p = appendp(p);
   478  			p->as = AADDL;
   479  			p->from.type = D_CONST;
   480  			p->from.offset = autoffset + PtrSize;
   481  			p->to.type = D_INDIR+D_CX;
   482  			p->to.offset = 2*PtrSize;
   483  		}
   484  		
   485  		if(debug['Z'] && autoffset && !(cursym->text->from.scale&NOSPLIT)) {
   486  			// 8l -Z means zero the stack frame on entry.
   487  			// This slows down function calls but can help avoid
   488  			// false positives in garbage collection.
   489  			p = appendp(p);
   490  			p->as = AMOVL;
   491  			p->from.type = D_SP;
   492  			p->to.type = D_DI;
   493  			
   494  			p = appendp(p);
   495  			p->as = AMOVL;
   496  			p->from.type = D_CONST;
   497  			p->from.offset = autoffset/4;
   498  			p->to.type = D_CX;
   499  			
   500  			p = appendp(p);
   501  			p->as = AMOVL;
   502  			p->from.type = D_CONST;
   503  			p->from.offset = 0;
   504  			p->to.type = D_AX;
   505  			
   506  			p = appendp(p);
   507  			p->as = AREP;
   508  			
   509  			p = appendp(p);
   510  			p->as = ASTOSL;
   511  		}
   512  		
   513  		for(; p != P; p = p->link) {
   514  			a = p->from.type;
   515  			if(a == D_AUTO)
   516  				p->from.offset += deltasp;
   517  			if(a == D_PARAM)
   518  				p->from.offset += deltasp + 4;
   519  			a = p->to.type;
   520  			if(a == D_AUTO)
   521  				p->to.offset += deltasp;
   522  			if(a == D_PARAM)
   523  				p->to.offset += deltasp + 4;
   524  	
   525  			switch(p->as) {
   526  			default:
   527  				continue;
   528  			case APUSHL:
   529  			case APUSHFL:
   530  				deltasp += 4;
   531  				p->spadj = 4;
   532  				continue;
   533  			case APUSHW:
   534  			case APUSHFW:
   535  				deltasp += 2;
   536  				p->spadj = 2;
   537  				continue;
   538  			case APOPL:
   539  			case APOPFL:
   540  				deltasp -= 4;
   541  				p->spadj = -4;
   542  				continue;
   543  			case APOPW:
   544  			case APOPFW:
   545  				deltasp -= 2;
   546  				p->spadj = -2;
   547  				continue;
   548  			case ARET:
   549  				break;
   550  			}
   551  	
   552  			if(autoffset != deltasp)
   553  				diag("unbalanced PUSH/POP");
   554  
   555  			if(cursym->text->from.scale & WRAPPER) {
   556  				p = load_g_cx(p);
   557  				p = appendp(p);
   558  				// g->panicwrap -= autoffset + PtrSize;
   559  				p->as = ASUBL;
   560  				p->from.type = D_CONST;
   561  				p->from.offset = autoffset + PtrSize;
   562  				p->to.type = D_INDIR+D_CX;
   563  				p->to.offset = 2*PtrSize;
   564  				p = appendp(p);
   565  				p->as = ARET;
   566  			}
   567  	
   568  			if(autoffset) {
   569  				p->as = AADJSP;
   570  				p->from.type = D_CONST;
   571  				p->from.offset = -autoffset;
   572  				p->spadj = -autoffset;
   573  				p = appendp(p);
   574  				p->as = ARET;
   575  				// If there are instructions following
   576  				// this ARET, they come from a branch
   577  				// with the same stackframe, so undo
   578  				// the cleanup.
   579  				p->spadj = +autoffset;
   580  			}
   581  			if(p->to.sym) // retjmp
   582  				p->as = AJMP;
   583  		}
   584  	}
   585  }
   586  
   587  // Append code to p to load g into cx.
   588  // Overwrites p with the first instruction (no first appendp).
   589  // Overwriting p is unusual but it lets use this in both the
   590  // prologue (caller must call appendp first) and in the epilogue.
   591  // Returns last new instruction.
   592  static Prog*
   593  load_g_cx(Prog *p)
   594  {
   595  	switch(HEADTYPE) {
   596  	case Hwindows:
   597  		p->as = AMOVL;
   598  		p->from.type = D_INDIR+D_FS;
   599  		p->from.offset = 0x14;
   600  		p->to.type = D_CX;
   601  
   602  		p = appendp(p);
   603  		p->as = AMOVL;
   604  		p->from.type = D_INDIR+D_CX;
   605  		p->from.offset = 0;
   606  		p->to.type = D_CX;
   607  		break;
   608  	
   609  	case Hlinux:
   610  		if(linkmode != LinkExternal) {
   611  			p->as = AMOVL;
   612  			p->from.type = D_INDIR+D_GS;
   613  			p->from.offset = 0;
   614  			p->to.type = D_CX;
   615  
   616  			p = appendp(p);
   617  			p->as = AMOVL;
   618  			p->from.type = D_INDIR+D_CX;
   619  			p->from.offset = tlsoffset + 0;
   620  			p->to.type = D_CX;
   621  		} else {
   622  			p->as = AMOVL;
   623  			p->from.type = D_INDIR+D_GS;
   624  			p->from.offset = tlsoffset + 0;
   625  			p->to.type = D_CX;
   626  			p->from.index = D_GS;
   627  			p->from.scale = 1;
   628  		}
   629  		break;
   630  	
   631  	case Hplan9x32:
   632  		p->as = AMOVL;
   633  		p->from.type = D_EXTERN;
   634  		p->from.sym = plan9_tos;
   635  		p->to.type = D_CX;
   636  		
   637  		p = appendp(p);
   638  		p->as = AMOVL;
   639  		p->from.type = D_INDIR+D_CX;
   640  		p->from.offset = tlsoffset + 0;
   641  		p->to.type = D_CX;				
   642  		break;
   643  	
   644  	default:
   645  		p->as = AMOVL;
   646  		p->from.type = D_INDIR+D_GS;
   647  		p->from.offset = tlsoffset + 0;
   648  		p->to.type = D_CX;
   649  	}
   650  	return p;
   651  }
   652  
   653  // Append code to p to check for stack split.
   654  // Appends to (does not overwrite) p.
   655  // Assumes g is in CX.
   656  // Returns last new instruction.
   657  // On return, *jmpok is the instruction that should jump
   658  // to the stack frame allocation if no split is needed.
   659  static Prog*
   660  stacksplit(Prog *p, int32 framesize, Prog **jmpok)
   661  {
   662  	Prog *q, *q1;
   663  	int arg;
   664  
   665  	if(debug['K']) {
   666  		// 8l -K means check not only for stack
   667  		// overflow but stack underflow.
   668  		// On underflow, INT 3 (breakpoint).
   669  		// Underflow itself is rare but this also
   670  		// catches out-of-sync stack guard info.
   671  		p = appendp(p);
   672  		p->as = ACMPL;
   673  		p->from.type = D_INDIR+D_CX;
   674  		p->from.offset = 4;
   675  		p->to.type = D_SP;
   676  
   677  		p = appendp(p);
   678  		p->as = AJCC;
   679  		p->to.type = D_BRANCH;
   680  		p->to.offset = 4;
   681  		q1 = p;
   682  
   683  		p = appendp(p);
   684  		p->as = AINT;
   685  		p->from.type = D_CONST;
   686  		p->from.offset = 3;
   687  		
   688  		p = appendp(p);
   689  		p->as = ANOP;
   690  		q1->pcond = p;
   691  	}
   692  	q1 = P;
   693  
   694  	if(framesize <= StackSmall) {
   695  		// small stack: SP <= stackguard
   696  		//	CMPL SP, stackguard
   697  		p = appendp(p);
   698  		p->as = ACMPL;
   699  		p->from.type = D_SP;
   700  		p->to.type = D_INDIR+D_CX;
   701  	} else if(framesize <= StackBig) {
   702  		// large stack: SP-framesize <= stackguard-StackSmall
   703  		//	LEAL -(framesize-StackSmall)(SP), AX
   704  		//	CMPL AX, stackguard
   705  		p = appendp(p);
   706  		p->as = ALEAL;
   707  		p->from.type = D_INDIR+D_SP;
   708  		p->from.offset = -(framesize-StackSmall);
   709  		p->to.type = D_AX;
   710  
   711  		p = appendp(p);
   712  		p->as = ACMPL;
   713  		p->from.type = D_AX;
   714  		p->to.type = D_INDIR+D_CX;
   715  	} else {
   716  		// Such a large stack we need to protect against wraparound
   717  		// if SP is close to zero.
   718  		//	SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
   719  		// The +StackGuard on both sides is required to keep the left side positive:
   720  		// SP is allowed to be slightly below stackguard. See stack.h.
   721  		//
   722  		// Preemption sets stackguard to StackPreempt, a very large value.
   723  		// That breaks the math above, so we have to check for that explicitly.
   724  		//	MOVL	stackguard, CX
   725  		//	CMPL	CX, $StackPreempt
   726  		//	JEQ	label-of-call-to-morestack
   727  		//	LEAL	StackGuard(SP), AX
   728  		//	SUBL	stackguard, AX
   729  		//	CMPL	AX, $(framesize+(StackGuard-StackSmall))
   730  		p = appendp(p);
   731  		p->as = AMOVL;
   732  		p->from.type = D_INDIR+D_CX;
   733  		p->from.offset = 0;
   734  		p->to.type = D_SI;
   735  
   736  		p = appendp(p);
   737  		p->as = ACMPL;
   738  		p->from.type = D_SI;
   739  		p->to.type = D_CONST;
   740  		p->to.offset = (uint32)StackPreempt;
   741  
   742  		p = appendp(p);
   743  		p->as = AJEQ;
   744  		p->to.type = D_BRANCH;
   745  		q1 = p;
   746  
   747  		p = appendp(p);
   748  		p->as = ALEAL;
   749  		p->from.type = D_INDIR+D_SP;
   750  		p->from.offset = StackGuard;
   751  		p->to.type = D_AX;
   752  		
   753  		p = appendp(p);
   754  		p->as = ASUBL;
   755  		p->from.type = D_SI;
   756  		p->from.offset = 0;
   757  		p->to.type = D_AX;
   758  		
   759  		p = appendp(p);
   760  		p->as = ACMPL;
   761  		p->from.type = D_AX;
   762  		p->to.type = D_CONST;
   763  		p->to.offset = framesize+(StackGuard-StackSmall);
   764  	}		
   765  			
   766  	// common
   767  	p = appendp(p);
   768  	p->as = AJHI;
   769  	p->to.type = D_BRANCH;
   770  	p->to.offset = 4;
   771  	q = p;
   772  
   773  	p = appendp(p);	// save frame size in DI
   774  	p->as = AMOVL;
   775  	p->to.type = D_DI;
   776  	p->from.type = D_CONST;
   777  
   778  	// If we ask for more stack, we'll get a minimum of StackMin bytes.
   779  	// We need a stack frame large enough to hold the top-of-stack data,
   780  	// the function arguments+results, our caller's PC, our frame,
   781  	// a word for the return PC of the next call, and then the StackLimit bytes
   782  	// that must be available on entry to any function called from a function
   783  	// that did a stack check.  If StackMin is enough, don't ask for a specific
   784  	// amount: then we can use the custom functions and save a few
   785  	// instructions.
   786  	if(StackTop + cursym->text->to.offset2 + PtrSize + framesize + PtrSize + StackLimit >= StackMin)
   787  		p->from.offset = (framesize+7) & ~7LL;
   788  
   789  	arg = cursym->text->to.offset2;
   790  	if(arg == 1) // special marker for known 0
   791  		arg = 0;
   792  	if(arg&3)
   793  		diag("misaligned argument size in stack split");
   794  	p = appendp(p);	// save arg size in AX
   795  	p->as = AMOVL;
   796  	p->to.type = D_AX;
   797  	p->from.type = D_CONST;
   798  	p->from.offset = arg;
   799  
   800  	p = appendp(p);
   801  	p->as = ACALL;
   802  	p->to.type = D_BRANCH;
   803  	p->pcond = pmorestack;
   804  	p->to.sym = symmorestack;
   805  
   806  	p = appendp(p);
   807  	p->as = AJMP;
   808  	p->to.type = D_BRANCH;
   809  	p->pcond = cursym->text->link;
   810  
   811  	if(q != P)
   812  		q->pcond = p->link;
   813  	if(q1 != P)
   814  		q1->pcond = q->link;
   815  	
   816  	*jmpok = q;
   817  	return p;
   818  }
   819  
   820  int32
   821  atolwhex(char *s)
   822  {
   823  	int32 n;
   824  	int f;
   825  
   826  	n = 0;
   827  	f = 0;
   828  	while(*s == ' ' || *s == '\t')
   829  		s++;
   830  	if(*s == '-' || *s == '+') {
   831  		if(*s++ == '-')
   832  			f = 1;
   833  		while(*s == ' ' || *s == '\t')
   834  			s++;
   835  	}
   836  	if(s[0]=='0' && s[1]){
   837  		if(s[1]=='x' || s[1]=='X'){
   838  			s += 2;
   839  			for(;;){
   840  				if(*s >= '0' && *s <= '9')
   841  					n = n*16 + *s++ - '0';
   842  				else if(*s >= 'a' && *s <= 'f')
   843  					n = n*16 + *s++ - 'a' + 10;
   844  				else if(*s >= 'A' && *s <= 'F')
   845  					n = n*16 + *s++ - 'A' + 10;
   846  				else
   847  					break;
   848  			}
   849  		} else
   850  			while(*s >= '0' && *s <= '7')
   851  				n = n*8 + *s++ - '0';
   852  	} else
   853  		while(*s >= '0' && *s <= '9')
   854  			n = n*10 + *s++ - '0';
   855  	if(f)
   856  		n = -n;
   857  	return n;
   858  }