github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/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)) {
   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  void
   409  dostkoff(void)
   410  {
   411  	Prog *p, *q, *q1;
   412  	int32 autoffset, deltasp;
   413  	int a;
   414  	Prog *pmorestack;
   415  	Sym *symmorestack;
   416  	Sym *plan9_tos;
   417  
   418  	pmorestack = P;
   419  	symmorestack = lookup("runtime.morestack", 0);
   420  
   421  	if(symmorestack->type != STEXT)
   422  		diag("runtime.morestack not defined");
   423  	else {
   424  		pmorestack = symmorestack->text;
   425  		symmorestack->text->from.scale |= NOSPLIT;
   426  	}
   427  	
   428  	plan9_tos = S;
   429  	if(HEADTYPE == Hplan9x32)
   430  		plan9_tos = lookup("_tos", 0);
   431  
   432  	for(cursym = textp; cursym != nil; cursym = cursym->next) {
   433  		if(cursym->text == nil || cursym->text->link == nil)
   434  			continue;
   435  
   436  		p = cursym->text;
   437  		autoffset = p->to.offset;
   438  		if(autoffset < 0)
   439  			autoffset = 0;
   440  
   441  		q = P;
   442  		if(pmorestack != P)
   443  		if(!(p->from.scale & NOSPLIT)) {
   444  			p = appendp(p);	// load g into CX
   445  			switch(HEADTYPE) {
   446  			case Hwindows:
   447  				p->as = AMOVL;
   448  				p->from.type = D_INDIR+D_FS;
   449  				p->from.offset = 0x14;
   450  				p->to.type = D_CX;
   451  
   452  				p = appendp(p);
   453  				p->as = AMOVL;
   454  				p->from.type = D_INDIR+D_CX;
   455  				p->from.offset = 0;
   456  				p->to.type = D_CX;
   457  				break;
   458  			
   459  			case Hlinux:
   460  				if(linkmode != LinkExternal) {
   461  					p->as = AMOVL;
   462  					p->from.type = D_INDIR+D_GS;
   463  					p->from.offset = 0;
   464  					p->to.type = D_CX;
   465  
   466  					p = appendp(p);
   467  					p->as = AMOVL;
   468  					p->from.type = D_INDIR+D_CX;
   469  					p->from.offset = tlsoffset + 0;
   470  					p->to.type = D_CX;
   471  				} else {
   472  					p->as = AMOVL;
   473  					p->from.type = D_INDIR+D_GS;
   474  					p->from.offset = tlsoffset + 0;
   475  					p->to.type = D_CX;
   476  					p->from.index = D_GS;
   477  					p->from.scale = 1;
   478  				}
   479  				break;
   480  			
   481  			case Hplan9x32:
   482  				p->as = AMOVL;
   483  				p->from.type = D_EXTERN;
   484  				p->from.sym = plan9_tos;
   485  				p->to.type = D_CX;
   486  				
   487  				p = appendp(p);
   488  				p->as = AMOVL;
   489  				p->from.type = D_INDIR+D_CX;
   490  				p->from.offset = tlsoffset + 0;
   491  				p->to.type = D_CX;				
   492  				break;
   493  			
   494  			default:
   495  				p->as = AMOVL;
   496  				p->from.type = D_INDIR+D_GS;
   497  				p->from.offset = tlsoffset + 0;
   498  				p->to.type = D_CX;
   499  			}
   500  
   501  			if(debug['K']) {
   502  				// 8l -K means check not only for stack
   503  				// overflow but stack underflow.
   504  				// On underflow, INT 3 (breakpoint).
   505  				// Underflow itself is rare but this also
   506  				// catches out-of-sync stack guard info.
   507  				p = appendp(p);
   508  				p->as = ACMPL;
   509  				p->from.type = D_INDIR+D_CX;
   510  				p->from.offset = 4;
   511  				p->to.type = D_SP;
   512  
   513  				p = appendp(p);
   514  				p->as = AJCC;
   515  				p->to.type = D_BRANCH;
   516  				p->to.offset = 4;
   517  				q1 = p;
   518  
   519  				p = appendp(p);
   520  				p->as = AINT;
   521  				p->from.type = D_CONST;
   522  				p->from.offset = 3;
   523  				
   524  				p = appendp(p);
   525  				p->as = ANOP;
   526  				q1->pcond = p;
   527  			}
   528  
   529  			if(autoffset < StackBig) {  // do we need to call morestack
   530  				if(autoffset <= StackSmall) {
   531  					// small stack
   532  					p = appendp(p);
   533  					p->as = ACMPL;
   534  					p->from.type = D_SP;
   535  					p->to.type = D_INDIR+D_CX;
   536  				} else {
   537  					// large stack
   538  					p = appendp(p);
   539  					p->as = ALEAL;
   540  					p->from.type = D_INDIR+D_SP;
   541  					p->from.offset = -(autoffset-StackSmall);
   542  					p->to.type = D_AX;
   543  
   544  					p = appendp(p);
   545  					p->as = ACMPL;
   546  					p->from.type = D_AX;
   547  					p->to.type = D_INDIR+D_CX;
   548  				}
   549  
   550  				// common
   551  				p = appendp(p);
   552  				p->as = AJHI;
   553  				p->to.type = D_BRANCH;
   554  				p->to.offset = 4;
   555  				q = p;
   556  			}
   557  
   558  			p = appendp(p);	// save frame size in DI
   559  			p->as = AMOVL;
   560  			p->to.type = D_DI;
   561  			p->from.type = D_CONST;
   562  
   563  			// If we ask for more stack, we'll get a minimum of StackMin bytes.
   564  			// We need a stack frame large enough to hold the top-of-stack data,
   565  			// the function arguments+results, our caller's PC, our frame,
   566  			// a word for the return PC of the next call, and then the StackLimit bytes
   567  			// that must be available on entry to any function called from a function
   568  			// that did a stack check.  If StackMin is enough, don't ask for a specific
   569  			// amount: then we can use the custom functions and save a few
   570  			// instructions.
   571  			if(StackTop + cursym->text->to.offset2 + PtrSize + autoffset + PtrSize + StackLimit >= StackMin)
   572  				p->from.offset = (autoffset+7) & ~7LL;
   573  
   574  			p = appendp(p);	// save arg size in AX
   575  			p->as = AMOVL;
   576  			p->to.type = D_AX;
   577  			p->from.type = D_CONST;
   578  			p->from.offset = cursym->text->to.offset2;
   579  
   580  			p = appendp(p);
   581  			p->as = ACALL;
   582  			p->to.type = D_BRANCH;
   583  			p->pcond = pmorestack;
   584  			p->to.sym = symmorestack;
   585  
   586  		}
   587  
   588  		if(q != P)
   589  			q->pcond = p->link;
   590  
   591  		if(autoffset) {
   592  			p = appendp(p);
   593  			p->as = AADJSP;
   594  			p->from.type = D_CONST;
   595  			p->from.offset = autoffset;
   596  			p->spadj = autoffset;
   597  			if(q != P)
   598  				q->pcond = p;
   599  		} else {
   600  			// zero-byte stack adjustment.
   601  			// Insert a fake non-zero adjustment so that stkcheck can
   602  			// recognize the end of the stack-splitting prolog.
   603  			p = appendp(p);
   604  			p->as = ANOP;
   605  			p->spadj = -PtrSize;
   606  			p = appendp(p);
   607  			p->as = ANOP;
   608  			p->spadj = PtrSize;
   609  		}
   610  		deltasp = autoffset;
   611  		
   612  		if(debug['Z'] && autoffset && !(cursym->text->from.scale&NOSPLIT)) {
   613  			// 8l -Z means zero the stack frame on entry.
   614  			// This slows down function calls but can help avoid
   615  			// false positives in garbage collection.
   616  			p = appendp(p);
   617  			p->as = AMOVL;
   618  			p->from.type = D_SP;
   619  			p->to.type = D_DI;
   620  			
   621  			p = appendp(p);
   622  			p->as = AMOVL;
   623  			p->from.type = D_CONST;
   624  			p->from.offset = autoffset/4;
   625  			p->to.type = D_CX;
   626  			
   627  			p = appendp(p);
   628  			p->as = AMOVL;
   629  			p->from.type = D_CONST;
   630  			p->from.offset = 0;
   631  			p->to.type = D_AX;
   632  			
   633  			p = appendp(p);
   634  			p->as = AREP;
   635  			
   636  			p = appendp(p);
   637  			p->as = ASTOSL;
   638  		}
   639  		
   640  		for(; p != P; p = p->link) {
   641  			a = p->from.type;
   642  			if(a == D_AUTO)
   643  				p->from.offset += deltasp;
   644  			if(a == D_PARAM)
   645  				p->from.offset += deltasp + 4;
   646  			a = p->to.type;
   647  			if(a == D_AUTO)
   648  				p->to.offset += deltasp;
   649  			if(a == D_PARAM)
   650  				p->to.offset += deltasp + 4;
   651  	
   652  			switch(p->as) {
   653  			default:
   654  				continue;
   655  			case APUSHL:
   656  			case APUSHFL:
   657  				deltasp += 4;
   658  				p->spadj = 4;
   659  				continue;
   660  			case APUSHW:
   661  			case APUSHFW:
   662  				deltasp += 2;
   663  				p->spadj = 2;
   664  				continue;
   665  			case APOPL:
   666  			case APOPFL:
   667  				deltasp -= 4;
   668  				p->spadj = -4;
   669  				continue;
   670  			case APOPW:
   671  			case APOPFW:
   672  				deltasp -= 2;
   673  				p->spadj = -2;
   674  				continue;
   675  			case ARET:
   676  				break;
   677  			}
   678  	
   679  			if(autoffset != deltasp)
   680  				diag("unbalanced PUSH/POP");
   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  		}
   696  	}
   697  }
   698  
   699  int32
   700  atolwhex(char *s)
   701  {
   702  	int32 n;
   703  	int f;
   704  
   705  	n = 0;
   706  	f = 0;
   707  	while(*s == ' ' || *s == '\t')
   708  		s++;
   709  	if(*s == '-' || *s == '+') {
   710  		if(*s++ == '-')
   711  			f = 1;
   712  		while(*s == ' ' || *s == '\t')
   713  			s++;
   714  	}
   715  	if(s[0]=='0' && s[1]){
   716  		if(s[1]=='x' || s[1]=='X'){
   717  			s += 2;
   718  			for(;;){
   719  				if(*s >= '0' && *s <= '9')
   720  					n = n*16 + *s++ - '0';
   721  				else if(*s >= 'a' && *s <= 'f')
   722  					n = n*16 + *s++ - 'a' + 10;
   723  				else if(*s >= 'A' && *s <= 'F')
   724  					n = n*16 + *s++ - 'A' + 10;
   725  				else
   726  					break;
   727  			}
   728  		} else
   729  			while(*s >= '0' && *s <= '7')
   730  				n = n*8 + *s++ - '0';
   731  	} else
   732  		while(*s >= '0' && *s <= '9')
   733  			n = n*10 + *s++ - '0';
   734  	if(f)
   735  		n = -n;
   736  	return n;
   737  }