github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/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  
   277  	if(debug['v'])
   278  		Bprint(&bso, "%5.2f mkfwd\n", cputime());
   279  	Bflush(&bso);
   280  	mkfwd();
   281  	if(debug['v'])
   282  		Bprint(&bso, "%5.2f patch\n", cputime());
   283  	Bflush(&bso);
   284  
   285  	s = lookup("exit", 0);
   286  	vexit = s->value;
   287  	for(cursym = textp; cursym != nil; cursym = cursym->next)
   288  	for(p = cursym->text; p != P; p = p->link) {
   289  		if(HEADTYPE == Hwindows) { 
   290  			// Windows
   291  			// Convert
   292  			//   op	  n(GS), reg
   293  			// to
   294  			//   MOVL 0x28(GS), reg
   295  			//   op	  n(reg), reg
   296  			// The purpose of this patch is to fix some accesses
   297  			// to extern register variables (TLS) on Windows, as
   298  			// a different method is used to access them.
   299  			if(p->from.type == D_INDIR+D_GS
   300  			&& p->to.type >= D_AX && p->to.type <= D_DI 
   301  			&& p->from.offset <= 8) {
   302  				q = appendp(p);
   303  				q->from = p->from;
   304  				q->from.type = D_INDIR + p->to.type;
   305  				q->to = p->to;
   306  				q->as = p->as;
   307  				p->as = AMOVQ;
   308  				p->from.type = D_INDIR+D_GS;
   309  				p->from.offset = 0x28;
   310  			}
   311  		}
   312  		if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd
   313  		|| HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd
   314  		|| HEADTYPE == Hplan9x64) {
   315  			// ELF uses FS instead of GS.
   316  			if(p->from.type == D_INDIR+D_GS)
   317  				p->from.type = D_INDIR+D_FS;
   318  			if(p->to.type == D_INDIR+D_GS)
   319  				p->to.type = D_INDIR+D_FS;
   320  		}
   321  		if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) {
   322  			s = p->to.sym;
   323  			if(s) {
   324  				if(debug['c'])
   325  					Bprint(&bso, "%s calls %s\n", TNAME, s->name);
   326  				if((s->type&SMASK) != STEXT) {
   327  					/* diag prints TNAME first */
   328  					diag("undefined: %s", s->name);
   329  					s->type = STEXT;
   330  					s->value = vexit;
   331  					continue;	// avoid more error messages
   332  				}
   333  				if(s->text == nil)
   334  					continue;
   335  				p->to.type = D_BRANCH;
   336  				p->to.offset = s->text->pc;
   337  				p->pcond = s->text;
   338  				continue;
   339  			}
   340  		}
   341  		if(p->to.type != D_BRANCH)
   342  			continue;
   343  		c = p->to.offset;
   344  		for(q = cursym->text; q != P;) {
   345  			if(c == q->pc)
   346  				break;
   347  			if(q->forwd != P && c >= q->forwd->pc)
   348  				q = q->forwd;
   349  			else
   350  				q = q->link;
   351  		}
   352  		if(q == P) {
   353  			diag("branch out of range in %s (%#ux)\n%P [%s]",
   354  				TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>");
   355  			p->to.type = D_NONE;
   356  		}
   357  		p->pcond = q;
   358  	}
   359  
   360  	for(cursym = textp; cursym != nil; cursym = cursym->next)
   361  	for(p = cursym->text; p != P; p = p->link) {
   362  		p->mark = 0;	/* initialization for follow */
   363  		if(p->pcond != P) {
   364  			p->pcond = brloop(p->pcond);
   365  			if(p->pcond != P)
   366  			if(p->to.type == D_BRANCH)
   367  				p->to.offset = p->pcond->pc;
   368  		}
   369  	}
   370  }
   371  
   372  Prog*
   373  brloop(Prog *p)
   374  {
   375  	int c;
   376  	Prog *q;
   377  
   378  	c = 0;
   379  	for(q = p; q != P; q = q->pcond) {
   380  		if(q->as != AJMP)
   381  			break;
   382  		c++;
   383  		if(c >= 5000)
   384  			return P;
   385  	}
   386  	return q;
   387  }
   388  
   389  static char*
   390  morename[] =
   391  {
   392  	"runtime.morestack00",
   393  	"runtime.morestack10",
   394  	"runtime.morestack01",
   395  	"runtime.morestack11",
   396  
   397  	"runtime.morestack8",
   398  	"runtime.morestack16",
   399  	"runtime.morestack24",
   400  	"runtime.morestack32",
   401  	"runtime.morestack40",
   402  	"runtime.morestack48",
   403  };
   404  Prog*	pmorestack[nelem(morename)];
   405  Sym*	symmorestack[nelem(morename)];
   406  
   407  void
   408  dostkoff(void)
   409  {
   410  	Prog *p, *q, *q1;
   411  	int32 autoffset, deltasp;
   412  	int a, pcsize;
   413  	uint32 moreconst1, moreconst2, i;
   414  
   415  	for(i=0; i<nelem(morename); i++) {
   416  		symmorestack[i] = lookup(morename[i], 0);
   417  		if(symmorestack[i]->type != STEXT)
   418  			diag("morestack trampoline not defined - %s", morename[i]);
   419  		pmorestack[i] = symmorestack[i]->text;
   420  	}
   421  
   422  	for(cursym = textp; cursym != nil; cursym = cursym->next) {
   423  		if(cursym->text == nil || cursym->text->link == nil)
   424  			continue;				
   425  
   426  		p = cursym->text;
   427  		parsetextconst(p->to.offset);
   428  		autoffset = textstksiz;
   429  		if(autoffset < 0)
   430  			autoffset = 0;
   431  
   432  		if(autoffset < StackSmall && !(p->from.scale & NOSPLIT)) {
   433  			for(q = p; q != P; q = q->link)
   434  				if(q->as == ACALL)
   435  					goto noleaf;
   436  			p->from.scale |= NOSPLIT;
   437  		noleaf:;
   438  		}
   439  
   440  		q = P;
   441  		if((p->from.scale & NOSPLIT) && autoffset >= StackSmall)
   442  			diag("nosplit func likely to overflow stack");
   443  
   444  		if(!(p->from.scale & NOSPLIT)) {
   445  			p = appendp(p);	// load g into CX
   446  			p->as = AMOVQ;
   447  			if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd
   448  			|| HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd
   449  			|| HEADTYPE == Hplan9x64)	// ELF uses FS
   450  				p->from.type = D_INDIR+D_FS;
   451  			else
   452  				p->from.type = D_INDIR+D_GS;
   453  			p->from.offset = tlsoffset+0;
   454  			p->to.type = D_CX;
   455  			if(HEADTYPE == Hwindows) {
   456  				// movq %gs:0x28, %rcx
   457  				// movq (%rcx), %rcx
   458  				p->as = AMOVQ;
   459  				p->from.type = D_INDIR+D_GS;
   460  				p->from.offset = 0x28;
   461  				p->to.type = D_CX;
   462  
   463  			
   464  				p = appendp(p);
   465  				p->as = AMOVQ;
   466  				p->from.type = D_INDIR+D_CX;
   467  				p->from.offset = 0;
   468  				p->to.type = D_CX;
   469  			}
   470  
   471  			if(debug['K']) {
   472  				// 6l -K means check not only for stack
   473  				// overflow but stack underflow.
   474  				// On underflow, INT 3 (breakpoint).
   475  				// Underflow itself is rare but this also
   476  				// catches out-of-sync stack guard info
   477  
   478  				p = appendp(p);
   479  				p->as = ACMPQ;
   480  				p->from.type = D_INDIR+D_CX;
   481  				p->from.offset = 8;
   482  				p->to.type = D_SP;
   483  
   484  				p = appendp(p);
   485  				p->as = AJHI;
   486  				p->to.type = D_BRANCH;
   487  				p->to.offset = 4;
   488  				q1 = p;
   489  
   490  				p = appendp(p);
   491  				p->as = AINT;
   492  				p->from.type = D_CONST;
   493  				p->from.offset = 3;
   494  
   495  				p = appendp(p);
   496  				p->as = ANOP;
   497  				q1->pcond = p;
   498  			}
   499  
   500  			if(autoffset < StackBig) {  // do we need to call morestack?
   501  				if(autoffset <= StackSmall) {
   502  					// small stack
   503  					p = appendp(p);
   504  					p->as = ACMPQ;
   505  					p->from.type = D_SP;
   506  					p->to.type = D_INDIR+D_CX;
   507  				} else {
   508  					// large stack
   509  					p = appendp(p);
   510  					p->as = ALEAQ;
   511  					p->from.type = D_INDIR+D_SP;
   512  					p->from.offset = -(autoffset-StackSmall);
   513  					p->to.type = D_AX;
   514  
   515  					p = appendp(p);
   516  					p->as = ACMPQ;
   517  					p->from.type = D_AX;
   518  					p->to.type = D_INDIR+D_CX;
   519  				}
   520  
   521  				// common
   522  				p = appendp(p);
   523  				p->as = AJHI;
   524  				p->to.type = D_BRANCH;
   525  				p->to.offset = 4;
   526  				q = p;
   527  			}
   528  
   529  			// If we ask for more stack, we'll get a minimum of StackMin bytes.
   530  			// We need a stack frame large enough to hold the top-of-stack data,
   531  			// the function arguments+results, our caller's PC, our frame,
   532  			// a word for the return PC of the next call, and then the StackLimit bytes
   533  			// that must be available on entry to any function called from a function
   534  			// that did a stack check.  If StackMin is enough, don't ask for a specific
   535  			// amount: then we can use the custom functions and save a few
   536  			// instructions.
   537  			moreconst1 = 0;
   538  			if(StackTop + textarg + PtrSize + autoffset + PtrSize + StackLimit >= StackMin)
   539  				moreconst1 = autoffset;
   540  			moreconst2 = textarg;
   541  
   542  			// 4 varieties varieties (const1==0 cross const2==0)
   543  			// and 6 subvarieties of (const1==0 and const2!=0)
   544  			p = appendp(p);
   545  			if(moreconst1 == 0 && moreconst2 == 0) {
   546  				p->as = ACALL;
   547  				p->to.type = D_BRANCH;
   548  				p->pcond = pmorestack[0];
   549  				p->to.sym = symmorestack[0];
   550  			} else
   551  			if(moreconst1 != 0 && moreconst2 == 0) {
   552  				p->as = AMOVL;
   553  				p->from.type = D_CONST;
   554  				p->from.offset = moreconst1;
   555  				p->to.type = D_AX;
   556  
   557  				p = appendp(p);
   558  				p->as = ACALL;
   559  				p->to.type = D_BRANCH;
   560  				p->pcond = pmorestack[1];
   561  				p->to.sym = symmorestack[1];
   562  			} else
   563  			if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) {
   564  				i = moreconst2/8 + 3;
   565  				p->as = ACALL;
   566  				p->to.type = D_BRANCH;
   567  				p->pcond = pmorestack[i];
   568  				p->to.sym = symmorestack[i];
   569  			} else
   570  			if(moreconst1 == 0 && moreconst2 != 0) {
   571  				p->as = AMOVL;
   572  				p->from.type = D_CONST;
   573  				p->from.offset = moreconst2;
   574  				p->to.type = D_AX;
   575  
   576  				p = appendp(p);
   577  				p->as = ACALL;
   578  				p->to.type = D_BRANCH;
   579  				p->pcond = pmorestack[2];
   580  				p->to.sym = symmorestack[2];
   581  			} else {
   582  				p->as = AMOVQ;
   583  				p->from.type = D_CONST;
   584  				p->from.offset = (uint64)moreconst2 << 32;
   585  				p->from.offset |= moreconst1;
   586  				p->to.type = D_AX;
   587  
   588  				p = appendp(p);
   589  				p->as = ACALL;
   590  				p->to.type = D_BRANCH;
   591  				p->pcond = pmorestack[3];
   592  				p->to.sym = symmorestack[3];
   593  			}
   594  		}
   595  
   596  		if(q != P)
   597  			q->pcond = p->link;
   598  
   599  		if(autoffset) {
   600  			p = appendp(p);
   601  			p->as = AADJSP;
   602  			p->from.type = D_CONST;
   603  			p->from.offset = autoffset;
   604  			p->spadj = autoffset;
   605  			if(q != P)
   606  				q->pcond = p;
   607  		} else {
   608  			// zero-byte stack adjustment.
   609  			// Insert a fake non-zero adjustment so that stkcheck can
   610  			// recognize the end of the stack-splitting prolog.
   611  			p = appendp(p);
   612  			p->as = ANOP;
   613  			p->spadj = -PtrSize;
   614  			p = appendp(p);
   615  			p->as = ANOP;
   616  			p->spadj = PtrSize;
   617  		}
   618  		deltasp = autoffset;
   619  
   620  		if(debug['K'] > 1 && autoffset) {
   621  			// 6l -KK means double-check for stack overflow
   622  			// even after calling morestack and even if the
   623  			// function is marked as nosplit.
   624  			p = appendp(p);
   625  			p->as = AMOVQ;
   626  			p->from.type = D_INDIR+D_CX;
   627  			p->from.offset = 0;
   628  			p->to.type = D_BX;
   629  
   630  			p = appendp(p);
   631  			p->as = ASUBQ;
   632  			p->from.type = D_CONST;
   633  			p->from.offset = StackSmall+32;
   634  			p->to.type = D_BX;
   635  
   636  			p = appendp(p);
   637  			p->as = ACMPQ;
   638  			p->from.type = D_SP;
   639  			p->to.type = D_BX;
   640  
   641  			p = appendp(p);
   642  			p->as = AJHI;
   643  			p->to.type = D_BRANCH;
   644  			q1 = p;
   645  
   646  			p = appendp(p);
   647  			p->as = AINT;
   648  			p->from.type = D_CONST;
   649  			p->from.offset = 3;
   650  
   651  			p = appendp(p);
   652  			p->as = ANOP;
   653  			q1->pcond = p;
   654  		}
   655  		
   656  		if(debug['Z'] && autoffset && !(cursym->text->from.scale&NOSPLIT)) {
   657  			// 6l -Z means zero the stack frame on entry.
   658  			// This slows down function calls but can help avoid
   659  			// false positives in garbage collection.
   660  			p = appendp(p);
   661  			p->as = AMOVQ;
   662  			p->from.type = D_SP;
   663  			p->to.type = D_DI;
   664  			
   665  			p = appendp(p);
   666  			p->as = AMOVQ;
   667  			p->from.type = D_CONST;
   668  			p->from.offset = autoffset/8;
   669  			p->to.type = D_CX;
   670  			
   671  			p = appendp(p);
   672  			p->as = AMOVQ;
   673  			p->from.type = D_CONST;
   674  			p->from.offset = 0;
   675  			p->to.type = D_AX;
   676  			
   677  			p = appendp(p);
   678  			p->as = AREP;
   679  			
   680  			p = appendp(p);
   681  			p->as = ASTOSQ;
   682  		}
   683  		
   684  		for(; p != P; p = p->link) {
   685  			pcsize = p->mode/8;
   686  			a = p->from.type;
   687  			if(a == D_AUTO)
   688  				p->from.offset += deltasp;
   689  			if(a == D_PARAM)
   690  				p->from.offset += deltasp + pcsize;
   691  			a = p->to.type;
   692  			if(a == D_AUTO)
   693  				p->to.offset += deltasp;
   694  			if(a == D_PARAM)
   695  				p->to.offset += deltasp + pcsize;
   696  	
   697  			switch(p->as) {
   698  			default:
   699  				continue;
   700  			case APUSHL:
   701  			case APUSHFL:
   702  				deltasp += 4;
   703  				p->spadj = 4;
   704  				continue;
   705  			case APUSHQ:
   706  			case APUSHFQ:
   707  				deltasp += 8;
   708  				p->spadj = 8;
   709  				continue;
   710  			case APUSHW:
   711  			case APUSHFW:
   712  				deltasp += 2;
   713  				p->spadj = 2;
   714  				continue;
   715  			case APOPL:
   716  			case APOPFL:
   717  				deltasp -= 4;
   718  				p->spadj = -4;
   719  				continue;
   720  			case APOPQ:
   721  			case APOPFQ:
   722  				deltasp -= 8;
   723  				p->spadj = -8;
   724  				continue;
   725  			case APOPW:
   726  			case APOPFW:
   727  				deltasp -= 2;
   728  				p->spadj = -2;
   729  				continue;
   730  			case ARET:
   731  				break;
   732  			}
   733  	
   734  			if(autoffset != deltasp)
   735  				diag("unbalanced PUSH/POP");
   736  	
   737  			if(autoffset) {
   738  				p->as = AADJSP;
   739  				p->from.type = D_CONST;
   740  				p->from.offset = -autoffset;
   741  				p->spadj = -autoffset;
   742  				p = appendp(p);
   743  				p->as = ARET;
   744  				// If there are instructions following
   745  				// this ARET, they come from a branch
   746  				// with the same stackframe, so undo
   747  				// the cleanup.
   748  				p->spadj = +autoffset;
   749  			}
   750  		}
   751  	}
   752  }
   753  
   754  vlong
   755  atolwhex(char *s)
   756  {
   757  	vlong n;
   758  	int f;
   759  
   760  	n = 0;
   761  	f = 0;
   762  	while(*s == ' ' || *s == '\t')
   763  		s++;
   764  	if(*s == '-' || *s == '+') {
   765  		if(*s++ == '-')
   766  			f = 1;
   767  		while(*s == ' ' || *s == '\t')
   768  			s++;
   769  	}
   770  	if(s[0]=='0' && s[1]){
   771  		if(s[1]=='x' || s[1]=='X'){
   772  			s += 2;
   773  			for(;;){
   774  				if(*s >= '0' && *s <= '9')
   775  					n = n*16 + *s++ - '0';
   776  				else if(*s >= 'a' && *s <= 'f')
   777  					n = n*16 + *s++ - 'a' + 10;
   778  				else if(*s >= 'A' && *s <= 'F')
   779  					n = n*16 + *s++ - 'A' + 10;
   780  				else
   781  					break;
   782  			}
   783  		} else
   784  			while(*s >= '0' && *s <= '7')
   785  				n = n*8 + *s++ - '0';
   786  	} else
   787  		while(*s >= '0' && *s <= '9')
   788  			n = n*10 + *s++ - '0';
   789  	if(f)
   790  		n = -n;
   791  	return n;
   792  }