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

     1  // Inferno utils/5l/noop.c
     2  // http://code.google.com/p/inferno-os/source/browse/utils/5l/noop.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 transformations.
    32  
    33  #include	"l.h"
    34  #include	"../ld/lib.h"
    35  #include	"../../pkg/runtime/stack.h"
    36  
    37  static	Sym*	sym_div;
    38  static	Sym*	sym_divu;
    39  static	Sym*	sym_mod;
    40  static	Sym*	sym_modu;
    41  static	Sym*	symmorestack;
    42  static	Prog*	pmorestack;
    43  
    44  static	Prog*	stacksplit(Prog*, int32);
    45  
    46  static void
    47  linkcase(Prog *casep)
    48  {
    49  	Prog *p;
    50  
    51  	for(p = casep; p != P; p = p->link){
    52  		if(p->as == ABCASE) {
    53  			for(; p != P && p->as == ABCASE; p = p->link)
    54  				p->pcrel = casep;
    55  			break;
    56  		}
    57  	}
    58  }
    59  
    60  void
    61  noops(void)
    62  {
    63  	Prog *p, *q, *q1, *q2;
    64  	int o;
    65  	Sym *tlsfallback, *gmsym;
    66  
    67  	/*
    68  	 * find leaf subroutines
    69  	 * strip NOPs
    70  	 * expand RET
    71  	 * expand BECOME pseudo
    72  	 * fixup TLS
    73  	 */
    74  
    75  	if(debug['v'])
    76  		Bprint(&bso, "%5.2f noops\n", cputime());
    77  	Bflush(&bso);
    78  
    79  	symmorestack = lookup("runtime.morestack", 0);
    80  	if(symmorestack->type != STEXT) {
    81  		diag("runtime·morestack not defined");
    82  		errorexit();
    83  	}
    84  	pmorestack = symmorestack->text;
    85  	pmorestack->reg |= NOSPLIT;
    86  
    87  	tlsfallback = lookup("runtime.read_tls_fallback", 0);
    88  	gmsym = S;
    89  	if(linkmode == LinkExternal)
    90  		gmsym = lookup("runtime.tlsgm", 0);
    91  	q = P;
    92  	for(cursym = textp; cursym != nil; cursym = cursym->next) {
    93  		for(p = cursym->text; p != P; p = p->link) {
    94  			switch(p->as) {
    95  			case ACASE:
    96  				if(flag_shared)
    97  					linkcase(p);
    98  				break;
    99  
   100  			case ATEXT:
   101  				p->mark |= LEAF;
   102  				break;
   103  	
   104  			case ARET:
   105  				break;
   106  	
   107  			case ADIV:
   108  			case ADIVU:
   109  			case AMOD:
   110  			case AMODU:
   111  				q = p;
   112  				if(prog_div == P)
   113  					initdiv();
   114  				cursym->text->mark &= ~LEAF;
   115  				continue;
   116  	
   117  			case ANOP:
   118  				q1 = p->link;
   119  				q->link = q1;		/* q is non-nop */
   120  				if(q1 != P)
   121  					q1->mark |= p->mark;
   122  				continue;
   123  	
   124  			case ABL:
   125  			case ABX:
   126  				cursym->text->mark &= ~LEAF;
   127  	
   128  			case ABCASE:
   129  			case AB:
   130  	
   131  			case ABEQ:
   132  			case ABNE:
   133  			case ABCS:
   134  			case ABHS:
   135  			case ABCC:
   136  			case ABLO:
   137  			case ABMI:
   138  			case ABPL:
   139  			case ABVS:
   140  			case ABVC:
   141  			case ABHI:
   142  			case ABLS:
   143  			case ABGE:
   144  			case ABLT:
   145  			case ABGT:
   146  			case ABLE:
   147  				q1 = p->cond;
   148  				if(q1 != P) {
   149  					while(q1->as == ANOP) {
   150  						q1 = q1->link;
   151  						p->cond = q1;
   152  					}
   153  				}
   154  				break;
   155  			case AWORD:
   156  				// Rewrite TLS register fetch: MRC 15, 0, <reg>, C13, C0, 3
   157  				if((p->to.offset & 0xffff0fff) == 0xee1d0f70) {
   158  					if(HEADTYPE == Hopenbsd) {
   159  						p->as = ARET;
   160  					} else if(goarm < 7) {
   161  						if(tlsfallback->type != STEXT) {
   162  							diag("runtime·read_tls_fallback not defined");
   163  							errorexit();
   164  						}
   165  						// BL runtime.read_tls_fallback(SB)
   166  						p->as = ABL;
   167  						p->to.type = D_BRANCH;
   168  						p->to.sym = tlsfallback;
   169  						p->cond = tlsfallback->text;
   170  						p->to.offset = 0;
   171  						cursym->text->mark &= ~LEAF;
   172  					}
   173  					if(linkmode == LinkExternal) {
   174  						// runtime.tlsgm is relocated with R_ARM_TLS_LE32
   175  						// and $runtime.tlsgm will contain the TLS offset.
   176  						//
   177  						// MOV $runtime.tlsgm+tlsoffset(SB), REGTMP
   178  						// ADD REGTMP, <reg>
   179  						//
   180  						// In shared mode, runtime.tlsgm is relocated with
   181  						// R_ARM_TLS_IE32 and runtime.tlsgm(SB) will point
   182  						// to the GOT entry containing the TLS offset.
   183  						//
   184  						// MOV runtime.tlsgm(SB), REGTMP
   185  						// ADD REGTMP, <reg>
   186  						// SUB -tlsoffset, <reg>
   187  						//
   188  						// The SUB compensates for tlsoffset
   189  						// used in runtime.save_gm and runtime.load_gm.
   190  						q = p;
   191  						p = appendp(p);
   192  						p->as = AMOVW;
   193  						p->scond = 14;
   194  						p->reg = NREG;
   195  						if(flag_shared) {
   196  							p->from.type = D_OREG;
   197  							p->from.offset = 0;
   198  						} else {
   199  							p->from.type = D_CONST;
   200  							p->from.offset = tlsoffset;
   201  						}
   202  						p->from.sym = gmsym;
   203  						p->from.name = D_EXTERN;
   204  						p->to.type = D_REG;
   205  						p->to.reg = REGTMP;
   206  						p->to.offset = 0;
   207  
   208  						p = appendp(p);
   209  						p->as = AADD;
   210  						p->scond = 14;
   211  						p->reg = NREG;
   212  						p->from.type = D_REG;
   213  						p->from.reg = REGTMP;
   214  						p->to.type = D_REG;
   215  						p->to.reg = (q->to.offset & 0xf000) >> 12;
   216  						p->to.offset = 0;
   217  
   218  						if(flag_shared) {
   219  							p = appendp(p);
   220  							p->as = ASUB;
   221  							p->scond = 14;
   222  							p->reg = NREG;
   223  							p->from.type = D_CONST;
   224  							p->from.offset = -tlsoffset;
   225  							p->to.type = D_REG;
   226  							p->to.reg = (q->to.offset & 0xf000) >> 12;
   227  							p->to.offset = 0;
   228  						}
   229  					}
   230  				}
   231  			}
   232  			q = p;
   233  		}
   234  	}
   235  
   236  	for(cursym = textp; cursym != nil; cursym = cursym->next) {
   237  		for(p = cursym->text; p != P; p = p->link) {
   238  			o = p->as;
   239  			switch(o) {
   240  			case ATEXT:
   241  				autosize = p->to.offset + 4;
   242  				if(autosize <= 4)
   243  				if(cursym->text->mark & LEAF) {
   244  					p->to.offset = -4;
   245  					autosize = 0;
   246  				}
   247  	
   248  				if(!autosize && !(cursym->text->mark & LEAF)) {
   249  					if(debug['v'])
   250  						Bprint(&bso, "save suppressed in: %s\n",
   251  							cursym->name);
   252  					Bflush(&bso);
   253  					cursym->text->mark |= LEAF;
   254  				}
   255  				if(cursym->text->mark & LEAF) {
   256  					cursym->leaf = 1;
   257  					if(!autosize)
   258  						break;
   259  				}
   260  	
   261  				if(!(p->reg & NOSPLIT))
   262  					p = stacksplit(p, autosize); // emit split check
   263  				
   264  				// MOVW.W		R14,$-autosize(SP)
   265  				p = appendp(p);
   266  				p->as = AMOVW;
   267  				p->scond |= C_WBIT;
   268  				p->from.type = D_REG;
   269  				p->from.reg = REGLINK;
   270  				p->to.type = D_OREG;
   271  				p->to.offset = -autosize;
   272  				p->to.reg = REGSP;
   273  				p->spadj = autosize;
   274  				
   275  				if(cursym->text->reg & WRAPPER) {
   276  					// g->panicwrap += autosize;
   277  					// MOVW panicwrap_offset(g), R3
   278  					// ADD $autosize, R3
   279  					// MOVW R3 panicwrap_offset(g)
   280  					p = appendp(p);
   281  					p->as = AMOVW;
   282  					p->from.type = D_OREG;
   283  					p->from.reg = REGG;
   284  					p->from.offset = 2*PtrSize;
   285  					p->to.type = D_REG;
   286  					p->to.reg = 3;
   287  				
   288  					p = appendp(p);
   289  					p->as = AADD;
   290  					p->from.type = D_CONST;
   291  					p->from.offset = autosize;
   292  					p->to.type = D_REG;
   293  					p->to.reg = 3;
   294  					
   295  					p = appendp(p);
   296  					p->as = AMOVW;
   297  					p->from.type = D_REG;
   298  					p->from.reg = 3;
   299  					p->to.type = D_OREG;
   300  					p->to.reg = REGG;
   301  					p->to.offset = 2*PtrSize;
   302  				}
   303  				break;
   304  	
   305  			case ARET:
   306  				nocache(p);
   307  				if(cursym->text->mark & LEAF) {
   308  					if(!autosize) {
   309  						p->as = AB;
   310  						p->from = zprg.from;
   311  						if(p->to.sym) { // retjmp
   312  							p->to.type = D_BRANCH;
   313  							p->cond = p->to.sym->text;
   314  						} else {
   315  							p->to.type = D_OREG;
   316  							p->to.offset = 0;
   317  							p->to.reg = REGLINK;
   318  						}
   319  						break;
   320  					}
   321  				}
   322  
   323  				if(cursym->text->reg & WRAPPER) {
   324  					int cond;
   325  					
   326  					// Preserve original RET's cond, to allow RET.EQ
   327  					// in the implementation of reflect.call.
   328  					cond = p->scond;
   329  					p->scond = C_SCOND_NONE;
   330  
   331  					// g->panicwrap -= autosize;
   332  					// MOVW panicwrap_offset(g), R3
   333  					// SUB $autosize, R3
   334  					// MOVW R3 panicwrap_offset(g)
   335  					p->as = AMOVW;
   336  					p->from.type = D_OREG;
   337  					p->from.reg = REGG;
   338  					p->from.offset = 2*PtrSize;
   339  					p->to.type = D_REG;
   340  					p->to.reg = 3;
   341  					p = appendp(p);
   342  				
   343  					p->as = ASUB;
   344  					p->from.type = D_CONST;
   345  					p->from.offset = autosize;
   346  					p->to.type = D_REG;
   347  					p->to.reg = 3;
   348  					p = appendp(p);
   349  
   350  					p->as = AMOVW;
   351  					p->from.type = D_REG;
   352  					p->from.reg = 3;
   353  					p->to.type = D_OREG;
   354  					p->to.reg = REGG;
   355  					p->to.offset = 2*PtrSize;
   356  					p = appendp(p);
   357  
   358  					p->scond = cond;
   359  				}
   360  
   361  				p->as = AMOVW;
   362  				p->scond |= C_PBIT;
   363  				p->from.type = D_OREG;
   364  				p->from.offset = autosize;
   365  				p->from.reg = REGSP;
   366  				p->to.type = D_REG;
   367  				p->to.reg = REGPC;
   368  				// If there are instructions following
   369  				// this ARET, they come from a branch
   370  				// with the same stackframe, so no spadj.
   371  				
   372  				if(p->to.sym) { // retjmp
   373  					p->to.reg = REGLINK;
   374  					q2 = appendp(p);
   375  					q2->as = AB;
   376  					q2->to.type = D_BRANCH;
   377  					q2->to.sym = p->to.sym;
   378  					q2->cond = p->to.sym->text;
   379  					p->to.sym = nil;
   380  					p = q2;
   381  				}
   382  				break;
   383  	
   384  			case AADD:
   385  				if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP)
   386  					p->spadj = -p->from.offset;
   387  				break;
   388  
   389  			case ASUB:
   390  				if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP)
   391  					p->spadj = p->from.offset;
   392  				break;
   393  
   394  			case ADIV:
   395  			case ADIVU:
   396  			case AMOD:
   397  			case AMODU:
   398  				if(debug['M'])
   399  					break;
   400  				if(p->from.type != D_REG)
   401  					break;
   402  				if(p->to.type != D_REG)
   403  					break;
   404  				q1 = p;
   405  	
   406  				/* MOV a,4(SP) */
   407  				p = appendp(p);
   408  				p->as = AMOVW;
   409  				p->line = q1->line;
   410  				p->from.type = D_REG;
   411  				p->from.reg = q1->from.reg;
   412  				p->to.type = D_OREG;
   413  				p->to.reg = REGSP;
   414  				p->to.offset = 4;
   415  	
   416  				/* MOV b,REGTMP */
   417  				p = appendp(p);
   418  				p->as = AMOVW;
   419  				p->line = q1->line;
   420  				p->from.type = D_REG;
   421  				p->from.reg = q1->reg;
   422  				if(q1->reg == NREG)
   423  					p->from.reg = q1->to.reg;
   424  				p->to.type = D_REG;
   425  				p->to.reg = REGTMP;
   426  				p->to.offset = 0;
   427  	
   428  				/* CALL appropriate */
   429  				p = appendp(p);
   430  				p->as = ABL;
   431  				p->line = q1->line;
   432  				p->to.type = D_BRANCH;
   433  				p->cond = p;
   434  				switch(o) {
   435  				case ADIV:
   436  					p->cond = prog_div;
   437  					p->to.sym = sym_div;
   438  					break;
   439  				case ADIVU:
   440  					p->cond = prog_divu;
   441  					p->to.sym = sym_divu;
   442  					break;
   443  				case AMOD:
   444  					p->cond = prog_mod;
   445  					p->to.sym = sym_mod;
   446  					break;
   447  				case AMODU:
   448  					p->cond = prog_modu;
   449  					p->to.sym = sym_modu;
   450  					break;
   451  				}
   452  	
   453  				/* MOV REGTMP, b */
   454  				p = appendp(p);
   455  				p->as = AMOVW;
   456  				p->line = q1->line;
   457  				p->from.type = D_REG;
   458  				p->from.reg = REGTMP;
   459  				p->from.offset = 0;
   460  				p->to.type = D_REG;
   461  				p->to.reg = q1->to.reg;
   462  	
   463  				/* ADD $8,SP */
   464  				p = appendp(p);
   465  				p->as = AADD;
   466  				p->line = q1->line;
   467  				p->from.type = D_CONST;
   468  				p->from.reg = NREG;
   469  				p->from.offset = 8;
   470  				p->reg = NREG;
   471  				p->to.type = D_REG;
   472  				p->to.reg = REGSP;
   473  				p->spadj = -8;
   474  	
   475  				/* Keep saved LR at 0(SP) after SP change. */
   476  				/* MOVW 0(SP), REGTMP; MOVW REGTMP, -8!(SP) */
   477  				/* TODO: Remove SP adjustments; see issue 6699. */
   478  				q1->as = AMOVW;
   479  				q1->from.type = D_OREG;
   480  				q1->from.reg = REGSP;
   481  				q1->from.offset = 0;
   482  				q1->reg = NREG;
   483  				q1->to.type = D_REG;
   484  				q1->to.reg = REGTMP;
   485  
   486  				/* SUB $8,SP */
   487  				q1 = appendp(q1);
   488  				q1->as = AMOVW;
   489  				q1->from.type = D_REG;
   490  				q1->from.reg = REGTMP;
   491  				q1->reg = NREG;
   492  				q1->to.type = D_OREG;
   493  				q1->to.reg = REGSP;
   494  				q1->to.offset = -8;
   495  				q1->scond |= C_WBIT;
   496  				q1->spadj = 8;
   497  	
   498  				break;
   499  			case AMOVW:
   500  				if((p->scond & C_WBIT) && p->to.type == D_OREG && p->to.reg == REGSP)
   501  					p->spadj = -p->to.offset;
   502  				if((p->scond & C_PBIT) && p->from.type == D_OREG && p->from.reg == REGSP && p->to.reg != REGPC)
   503  					p->spadj = -p->from.offset;
   504  				if(p->from.type == D_CONST && p->from.reg == REGSP && p->to.type == D_REG && p->to.reg == REGSP)
   505  					p->spadj = -p->from.offset;
   506  				break;
   507  			}
   508  		}
   509  	}
   510  }
   511  
   512  static Prog*
   513  stacksplit(Prog *p, int32 framesize)
   514  {
   515  	int32 arg;
   516  
   517  	// MOVW			g_stackguard(g), R1
   518  	p = appendp(p);
   519  	p->as = AMOVW;
   520  	p->from.type = D_OREG;
   521  	p->from.reg = REGG;
   522  	p->to.type = D_REG;
   523  	p->to.reg = 1;
   524  	
   525  	if(framesize <= StackSmall) {
   526  		// small stack: SP < stackguard
   527  		//	CMP	stackguard, SP
   528  		p = appendp(p);
   529  		p->as = ACMP;
   530  		p->from.type = D_REG;
   531  		p->from.reg = 1;
   532  		p->reg = REGSP;
   533  	} else if(framesize <= StackBig) {
   534  		// large stack: SP-framesize < stackguard-StackSmall
   535  		//	MOVW $-framesize(SP), R2
   536  		//	CMP stackguard, R2
   537  		p = appendp(p);
   538  		p->as = AMOVW;
   539  		p->from.type = D_CONST;
   540  		p->from.reg = REGSP;
   541  		p->from.offset = -framesize;
   542  		p->to.type = D_REG;
   543  		p->to.reg = 2;
   544  		
   545  		p = appendp(p);
   546  		p->as = ACMP;
   547  		p->from.type = D_REG;
   548  		p->from.reg = 1;
   549  		p->reg = 2;
   550  	} else {
   551  		// Such a large stack we need to protect against wraparound
   552  		// if SP is close to zero.
   553  		//	SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall)
   554  		// The +StackGuard on both sides is required to keep the left side positive:
   555  		// SP is allowed to be slightly below stackguard. See stack.h.
   556  		//	CMP $StackPreempt, R1
   557  		//	MOVW.NE $StackGuard(SP), R2
   558  		//	SUB.NE R1, R2
   559  		//	MOVW.NE $(framesize+(StackGuard-StackSmall)), R3
   560  		//	CMP.NE R3, R2
   561  		p = appendp(p);
   562  		p->as = ACMP;
   563  		p->from.type = D_CONST;
   564  		p->from.offset = (uint32)StackPreempt;
   565  		p->reg = 1;
   566  
   567  		p = appendp(p);
   568  		p->as = AMOVW;
   569  		p->from.type = D_CONST;
   570  		p->from.reg = REGSP;
   571  		p->from.offset = StackGuard;
   572  		p->to.type = D_REG;
   573  		p->to.reg = 2;
   574  		p->scond = C_SCOND_NE;
   575  		
   576  		p = appendp(p);
   577  		p->as = ASUB;
   578  		p->from.type = D_REG;
   579  		p->from.reg = 1;
   580  		p->to.type = D_REG;
   581  		p->to.reg = 2;
   582  		p->scond = C_SCOND_NE;
   583  		
   584  		p = appendp(p);
   585  		p->as = AMOVW;
   586  		p->from.type = D_CONST;
   587  		p->from.offset = framesize + (StackGuard - StackSmall);
   588  		p->to.type = D_REG;
   589  		p->to.reg = 3;
   590  		p->scond = C_SCOND_NE;
   591  		
   592  		p = appendp(p);
   593  		p->as = ACMP;
   594  		p->from.type = D_REG;
   595  		p->from.reg = 3;
   596  		p->reg = 2;
   597  		p->scond = C_SCOND_NE;
   598  	}
   599  	
   600  	// MOVW.LS		$framesize, R1
   601  	p = appendp(p);
   602  	p->as = AMOVW;
   603  	p->scond = C_SCOND_LS;
   604  	p->from.type = D_CONST;
   605  	p->from.offset = framesize;
   606  	p->to.type = D_REG;
   607  	p->to.reg = 1;
   608  
   609  	// MOVW.LS		$args, R2
   610  	p = appendp(p);
   611  	p->as = AMOVW;
   612  	p->scond = C_SCOND_LS;
   613  	p->from.type = D_CONST;
   614  	arg = cursym->text->to.offset2;
   615  	if(arg == 1) // special marker for known 0
   616  		arg = 0;
   617  	if(arg&3)
   618  		diag("misaligned argument size in stack split");
   619  	p->from.offset = arg;
   620  	p->to.type = D_REG;
   621  	p->to.reg = 2;
   622  
   623  	// MOVW.LS	R14, R3
   624  	p = appendp(p);
   625  	p->as = AMOVW;
   626  	p->scond = C_SCOND_LS;
   627  	p->from.type = D_REG;
   628  	p->from.reg = REGLINK;
   629  	p->to.type = D_REG;
   630  	p->to.reg = 3;
   631  
   632  	// BL.LS		runtime.morestack(SB) // modifies LR, returns with LO still asserted
   633  	p = appendp(p);
   634  	p->as = ABL;
   635  	p->scond = C_SCOND_LS;
   636  	p->to.type = D_BRANCH;
   637  	p->to.sym = symmorestack;
   638  	p->cond = pmorestack;
   639  	
   640  	// BLS	start
   641  	p = appendp(p);
   642  	p->as = ABLS;
   643  	p->to.type = D_BRANCH;
   644  	p->cond = cursym->text->link;
   645  	
   646  	return p;
   647  }
   648  
   649  static void
   650  sigdiv(char *n)
   651  {
   652  	Sym *s;
   653  
   654  	s = lookup(n, 0);
   655  	if(s->type == STEXT)
   656  		if(s->sig == 0)
   657  			s->sig = SIGNINTERN;
   658  }
   659  
   660  void
   661  divsig(void)
   662  {
   663  	sigdiv("_div");
   664  	sigdiv("_divu");
   665  	sigdiv("_mod");
   666  	sigdiv("_modu");
   667  }
   668  
   669  void
   670  initdiv(void)
   671  {
   672  	Sym *s2, *s3, *s4, *s5;
   673  
   674  	if(prog_div != P)
   675  		return;
   676  	sym_div = s2 = lookup("_div", 0);
   677  	sym_divu = s3 = lookup("_divu", 0);
   678  	sym_mod = s4 = lookup("_mod", 0);
   679  	sym_modu = s5 = lookup("_modu", 0);
   680  	prog_div = s2->text;
   681  	prog_divu = s3->text;
   682  	prog_mod = s4->text;
   683  	prog_modu = s5->text;
   684  	if(prog_div == P) {
   685  		diag("undefined: %s", s2->name);
   686  		prog_div = cursym->text;
   687  	}
   688  	if(prog_divu == P) {
   689  		diag("undefined: %s", s3->name);
   690  		prog_divu = cursym->text;
   691  	}
   692  	if(prog_mod == P) {
   693  		diag("undefined: %s", s4->name);
   694  		prog_mod = cursym->text;
   695  	}
   696  	if(prog_modu == P) {
   697  		diag("undefined: %s", s5->name);
   698  		prog_modu = cursym->text;
   699  	}
   700  }
   701  
   702  void
   703  nocache(Prog *p)
   704  {
   705  	p->optab = 0;
   706  	p->from.class = 0;
   707  	p->to.class = 0;
   708  }