github.com/razvanm/vanadium-go-1.3@v0.0.0-20160721203343-4a65068e5915/src/liblink/obj5.c (about)

     1  // Derived from Inferno utils/5c/swt.c
     2  // http://code.google.com/p/inferno-os/source/browse/utils/5c/swt.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  #include <u.h>
    32  #include <libc.h>
    33  #include <bio.h>
    34  #include <link.h>
    35  #include "../cmd/5l/5.out.h"
    36  #include "../runtime/stack.h"
    37  
    38  static Prog zprg = {
    39  	.as = AGOK,
    40  	.scond = C_SCOND_NONE,
    41  	.reg = NREG,
    42  	.from = {
    43  		.name = D_NONE,
    44  		.type = D_NONE,
    45  		.reg = NREG,
    46  	},
    47  	.to = {
    48  		.name = D_NONE,
    49  		.type = D_NONE,
    50  		.reg = NREG,
    51  	},
    52  };
    53  
    54  static int
    55  symtype(Addr *a)
    56  {
    57  	return a->name;
    58  }
    59  
    60  static int
    61  isdata(Prog *p)
    62  {
    63  	return p->as == ADATA || p->as == AGLOBL;
    64  }
    65  
    66  static int
    67  iscall(Prog *p)
    68  {
    69  	return p->as == ABL;
    70  }
    71  
    72  static int
    73  datasize(Prog *p)
    74  {
    75  	return p->reg;
    76  }
    77  
    78  static int
    79  textflag(Prog *p)
    80  {
    81  	return p->reg;
    82  }
    83  
    84  static void
    85  settextflag(Prog *p, int f)
    86  {
    87  	p->reg = f;
    88  }
    89  
    90  static void
    91  progedit(Link *ctxt, Prog *p)
    92  {
    93  	char literal[64];
    94  	LSym *s;
    95  	static LSym *tlsfallback;
    96  
    97  	p->from.class = 0;
    98  	p->to.class = 0;
    99  
   100  	// Rewrite B/BL to symbol as D_BRANCH.
   101  	switch(p->as) {
   102  	case AB:
   103  	case ABL:
   104  	case ADUFFZERO:
   105  	case ADUFFCOPY:
   106  		if(p->to.type == D_OREG && (p->to.name == D_EXTERN || p->to.name == D_STATIC) && p->to.sym != nil)
   107  			p->to.type = D_BRANCH;
   108  		break;
   109  	}
   110  
   111  	// Replace TLS register fetches on older ARM procesors.
   112  	switch(p->as) {
   113  	case AMRC:
   114  		// Treat MRC 15, 0, <reg>, C13, C0, 3 specially.
   115  		if((p->to.offset & 0xffff0fff) == 0xee1d0f70) {
   116  			// Because the instruction might be rewriten to a BL which returns in R0
   117  			// the register must be zero.
   118  		       	if ((p->to.offset & 0xf000) != 0)
   119  				ctxt->diag("%L: TLS MRC instruction must write to R0 as it might get translated into a BL instruction", p->lineno);
   120  
   121  			if(ctxt->goarm < 7) {
   122  				// Replace it with BL runtime.read_tls_fallback(SB) for ARM CPUs that lack the tls extension.
   123  				if(tlsfallback == nil)
   124  					tlsfallback = linklookup(ctxt, "runtime.read_tls_fallback", 0);
   125  				// MOVW	LR, R11
   126  				p->as = AMOVW;
   127  				p->from.type = D_REG;
   128  				p->from.reg = REGLINK;
   129  				p->to.type = D_REG;
   130  				p->to.reg = REGTMP;
   131  
   132  				// BL	runtime.read_tls_fallback(SB)
   133  				p = appendp(ctxt, p);
   134  				p->as = ABL;
   135  				p->to.type = D_BRANCH;
   136  				p->to.sym = tlsfallback;
   137  				p->to.offset = 0;
   138  
   139  				// MOVW	R11, LR
   140  				p = appendp(ctxt, p);
   141  				p->as = AMOVW;
   142  				p->from.type = D_REG;
   143  				p->from.reg = REGTMP;
   144  				p->to.type = D_REG;
   145  				p->to.reg = REGLINK;
   146  				break;
   147  			}
   148  		}
   149  		// Otherwise, MRC/MCR instructions need no further treatment.
   150  		p->as = AWORD;
   151  		break;
   152  	}
   153  
   154  	// Rewrite float constants to values stored in memory.
   155  	switch(p->as) {
   156  	case AMOVF:
   157  		if(p->from.type == D_FCONST && chipfloat5(ctxt, p->from.u.dval) < 0 &&
   158  		   (chipzero5(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
   159  			int32 i32;
   160  			float32 f32;
   161  			f32 = p->from.u.dval;
   162  			memmove(&i32, &f32, 4);
   163  			sprint(literal, "$f32.%08ux", (uint32)i32);
   164  			s = linklookup(ctxt, literal, 0);
   165  			if(s->type == 0) {
   166  				s->type = SRODATA;
   167  				adduint32(ctxt, s, i32);
   168  				s->reachable = 0;
   169  			}
   170  			p->from.type = D_OREG;
   171  			p->from.sym = s;
   172  			p->from.name = D_EXTERN;
   173  			p->from.offset = 0;
   174  		}
   175  		break;
   176  
   177  	case AMOVD:
   178  		if(p->from.type == D_FCONST && chipfloat5(ctxt, p->from.u.dval) < 0 &&
   179  		   (chipzero5(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
   180  			int64 i64;
   181  			memmove(&i64, &p->from.u.dval, 8);
   182  			sprint(literal, "$f64.%016llux", (uvlong)i64);
   183  			s = linklookup(ctxt, literal, 0);
   184  			if(s->type == 0) {
   185  				s->type = SRODATA;
   186  				adduint64(ctxt, s, i64);
   187  				s->reachable = 0;
   188  			}
   189  			p->from.type = D_OREG;
   190  			p->from.sym = s;
   191  			p->from.name = D_EXTERN;
   192  			p->from.offset = 0;
   193  		}
   194  		break;
   195  	}
   196  
   197  	if(ctxt->flag_shared) {
   198  		// Shared libraries use R_ARM_TLS_IE32 instead of 
   199  		// R_ARM_TLS_LE32, replacing the link time constant TLS offset in
   200  		// runtime.tlsg with an address to a GOT entry containing the 
   201  		// offset. Rewrite $runtime.tlsg(SB) to runtime.tlsg(SB) to
   202  		// compensate.
   203  		if(ctxt->tlsg == nil)
   204  			ctxt->tlsg = linklookup(ctxt, "runtime.tlsg", 0);
   205  
   206  		if(p->from.type == D_CONST && p->from.name == D_EXTERN && p->from.sym == ctxt->tlsg)
   207  			p->from.type = D_OREG;
   208  		if(p->to.type == D_CONST && p->to.name == D_EXTERN && p->to.sym == ctxt->tlsg)
   209  			p->to.type = D_OREG;
   210  	}
   211  }
   212  
   213  static Prog*
   214  prg(void)
   215  {
   216  	Prog *p;
   217  
   218  	p = emallocz(sizeof(*p));
   219  	*p = zprg;
   220  	return p;
   221  }
   222  
   223  static	Prog*	stacksplit(Link*, Prog*, int32, int);
   224  static	void		initdiv(Link*);
   225  static	void	softfloat(Link*, LSym*);
   226  
   227  // Prog.mark
   228  enum
   229  {
   230  	FOLL = 1<<0,
   231  	LABEL = 1<<1,
   232  	LEAF = 1<<2,
   233  };
   234  
   235  static void
   236  linkcase(Prog *casep)
   237  {
   238  	Prog *p;
   239  
   240  	for(p = casep; p != nil; p = p->link){
   241  		if(p->as == ABCASE) {
   242  			for(; p != nil && p->as == ABCASE; p = p->link)
   243  				p->pcrel = casep;
   244  			break;
   245  		}
   246  	}
   247  }
   248  
   249  static void
   250  nocache(Prog *p)
   251  {
   252  	p->optab = 0;
   253  	p->from.class = 0;
   254  	p->to.class = 0;
   255  }
   256  
   257  static void
   258  addstacksplit(Link *ctxt, LSym *cursym)
   259  {
   260  	Prog *p, *pl, *p1, *p2, *q, *q1, *q2;
   261  	int o;
   262  	int32 autosize, autoffset;
   263  	
   264  	autosize = 0;
   265  
   266  	if(ctxt->symmorestack[0] == nil) {
   267  		ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0);
   268  		ctxt->symmorestack[1] = linklookup(ctxt, "runtime.morestack_noctxt", 0);
   269  	}
   270  
   271  	q = nil;
   272  	
   273  	ctxt->cursym = cursym;
   274  
   275  	if(cursym->text == nil || cursym->text->link == nil)
   276  		return;				
   277  
   278  	softfloat(ctxt, cursym);
   279  
   280  	p = cursym->text;
   281  	autoffset = p->to.offset;
   282  	if(autoffset < 0)
   283  		autoffset = 0;
   284  	cursym->locals = autoffset;
   285  	cursym->args = p->to.offset2;
   286  
   287  	if(ctxt->debugzerostack) {
   288  		if(autoffset && !(p->reg&NOSPLIT)) {
   289  			// MOVW $4(R13), R1
   290  			p = appendp(ctxt, p);
   291  			p->as = AMOVW;
   292  			p->from.type = D_CONST;
   293  			p->from.reg = 13;
   294  			p->from.offset = 4;
   295  			p->to.type = D_REG;
   296  			p->to.reg = 1;
   297  	
   298  			// MOVW $n(R13), R2
   299  			p = appendp(ctxt, p);
   300  			p->as = AMOVW;
   301  			p->from.type = D_CONST;
   302  			p->from.reg = 13;
   303  			p->from.offset = 4 + autoffset;
   304  			p->to.type = D_REG;
   305  			p->to.reg = 2;
   306  	
   307  			// MOVW $0, R3
   308  			p = appendp(ctxt, p);
   309  			p->as = AMOVW;
   310  			p->from.type = D_CONST;
   311  			p->from.offset = 0;
   312  			p->to.type = D_REG;
   313  			p->to.reg = 3;
   314  	
   315  			// L:
   316  			//	MOVW.nil R3, 0(R1) +4
   317  			//	CMP R1, R2
   318  			//	BNE L
   319  			p = pl = appendp(ctxt, p);
   320  			p->as = AMOVW;
   321  			p->from.type = D_REG;
   322  			p->from.reg = 3;
   323  			p->to.type = D_OREG;
   324  			p->to.reg = 1;
   325  			p->to.offset = 4;
   326  			p->scond |= C_PBIT;
   327  	
   328  			p = appendp(ctxt, p);
   329  			p->as = ACMP;
   330  			p->from.type = D_REG;
   331  			p->from.reg = 1;
   332  			p->reg = 2;
   333  	
   334  			p = appendp(ctxt, p);
   335  			p->as = ABNE;
   336  			p->to.type = D_BRANCH;
   337  			p->pcond = pl;
   338  		}
   339  	}
   340  
   341  	/*
   342  	 * find leaf subroutines
   343  	 * strip NOPs
   344  	 * expand RET
   345  	 * expand BECOME pseudo
   346  	 */
   347  
   348  	for(p = cursym->text; p != nil; p = p->link) {
   349  		switch(p->as) {
   350  		case ACASE:
   351  			if(ctxt->flag_shared)
   352  				linkcase(p);
   353  			break;
   354  
   355  		case ATEXT:
   356  			p->mark |= LEAF;
   357  			break;
   358  
   359  		case ARET:
   360  			break;
   361  
   362  		case ADIV:
   363  		case ADIVU:
   364  		case AMOD:
   365  		case AMODU:
   366  			q = p;
   367  			if(ctxt->sym_div == nil)
   368  				initdiv(ctxt);
   369  			cursym->text->mark &= ~LEAF;
   370  			continue;
   371  
   372  		case ANOP:
   373  			q1 = p->link;
   374  			q->link = q1;		/* q is non-nop */
   375  			if(q1 != nil)
   376  				q1->mark |= p->mark;
   377  			continue;
   378  
   379  		case ABL:
   380  		case ABX:
   381  		case ADUFFZERO:
   382  		case ADUFFCOPY:
   383  			cursym->text->mark &= ~LEAF;
   384  
   385  		case ABCASE:
   386  		case AB:
   387  
   388  		case ABEQ:
   389  		case ABNE:
   390  		case ABCS:
   391  		case ABHS:
   392  		case ABCC:
   393  		case ABLO:
   394  		case ABMI:
   395  		case ABPL:
   396  		case ABVS:
   397  		case ABVC:
   398  		case ABHI:
   399  		case ABLS:
   400  		case ABGE:
   401  		case ABLT:
   402  		case ABGT:
   403  		case ABLE:
   404  			q1 = p->pcond;
   405  			if(q1 != nil) {
   406  				while(q1->as == ANOP) {
   407  					q1 = q1->link;
   408  					p->pcond = q1;
   409  				}
   410  			}
   411  			break;
   412  		}
   413  		q = p;
   414  	}
   415  
   416  	for(p = cursym->text; p != nil; p = p->link) {
   417  		o = p->as;
   418  		switch(o) {
   419  		case ATEXT:
   420  			autosize = p->to.offset + 4;
   421  			if(autosize <= 4)
   422  			if(cursym->text->mark & LEAF) {
   423  				p->to.offset = -4;
   424  				autosize = 0;
   425  			}
   426  
   427  			if(!autosize && !(cursym->text->mark & LEAF)) {
   428  				if(ctxt->debugvlog) {
   429  					Bprint(ctxt->bso, "save suppressed in: %s\n",
   430  						cursym->name);
   431  					Bflush(ctxt->bso);
   432  				}
   433  				cursym->text->mark |= LEAF;
   434  			}
   435  			if(cursym->text->mark & LEAF) {
   436  				cursym->leaf = 1;
   437  				if(!autosize)
   438  					break;
   439  			}
   440  
   441  			if(!(p->reg & NOSPLIT))
   442  				p = stacksplit(ctxt, p, autosize, !(cursym->text->reg&NEEDCTXT)); // emit split check
   443  			
   444  			// MOVW.W		R14,$-autosize(SP)
   445  			p = appendp(ctxt, p);
   446  			p->as = AMOVW;
   447  			p->scond |= C_WBIT;
   448  			p->from.type = D_REG;
   449  			p->from.reg = REGLINK;
   450  			p->to.type = D_OREG;
   451  			p->to.offset = -autosize;
   452  			p->to.reg = REGSP;
   453  			p->spadj = autosize;
   454  			
   455  			if(cursym->text->reg & WRAPPER) {
   456  				// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
   457  				//
   458  				//	MOVW g_panic(g), R1
   459  				//	CMP $0, R1
   460  				//	B.EQ end
   461  				//	MOVW panic_argp(R1), R2
   462  				//	ADD $(autosize+4), R13, R3
   463  				//	CMP R2, R3
   464  				//	B.NE end
   465  				//	ADD $4, R13, R4
   466  				//	MOVW R4, panic_argp(R1)
   467  				// end:
   468  				//	NOP
   469  				//
   470  				// The NOP is needed to give the jumps somewhere to land.
   471  				// It is a liblink NOP, not an ARM NOP: it encodes to 0 instruction bytes.
   472  
   473  				p = appendp(ctxt, p);
   474  				p->as = AMOVW;
   475  				p->from.type = D_OREG;
   476  				p->from.reg = REGG;
   477  				p->from.offset = 4*ctxt->arch->ptrsize; // G.panic
   478  				p->to.type = D_REG;
   479  				p->to.reg = 1;
   480  			
   481  				p = appendp(ctxt, p);
   482  				p->as = ACMP;
   483  				p->from.type = D_CONST;
   484  				p->from.offset = 0;
   485  				p->reg = 1;
   486  			
   487  				p = appendp(ctxt, p);
   488  				p->as = ABEQ;
   489  				p->to.type = D_BRANCH;
   490  				p1 = p;
   491  				
   492  				p = appendp(ctxt, p);
   493  				p->as = AMOVW;
   494  				p->from.type = D_OREG;
   495  				p->from.reg = 1;
   496  				p->from.offset = 0; // Panic.argp
   497  				p->to.type = D_REG;
   498  				p->to.reg = 2;
   499  			
   500  				p = appendp(ctxt, p);
   501  				p->as = AADD;
   502  				p->from.type = D_CONST;
   503  				p->from.offset = autosize+4;
   504  				p->reg = 13;
   505  				p->to.type = D_REG;
   506  				p->to.reg = 3;
   507  
   508  				p = appendp(ctxt, p);
   509  				p->as = ACMP;
   510  				p->from.type = D_REG;
   511  				p->from.reg = 2;
   512  				p->reg = 3;
   513  
   514  				p = appendp(ctxt, p);
   515  				p->as = ABNE;
   516  				p->to.type = D_BRANCH;
   517  				p2 = p;
   518  			
   519  				p = appendp(ctxt, p);
   520  				p->as = AADD;
   521  				p->from.type = D_CONST;
   522  				p->from.offset = 4;
   523  				p->reg = 13;
   524  				p->to.type = D_REG;
   525  				p->to.reg = 4;
   526  
   527  				p = appendp(ctxt, p);
   528  				p->as = AMOVW;
   529  				p->from.type = D_REG;
   530  				p->from.reg = 4;
   531  				p->to.type = D_OREG;
   532  				p->to.reg = 1;
   533  				p->to.offset = 0; // Panic.argp
   534  
   535  				p = appendp(ctxt, p);
   536  				p->as = ANOP;
   537  				p1->pcond = p;
   538  				p2->pcond = p;
   539  			}
   540  			break;
   541  
   542  		case ARET:
   543  			nocache(p);
   544  			if(cursym->text->mark & LEAF) {
   545  				if(!autosize) {
   546  					p->as = AB;
   547  					p->from = zprg.from;
   548  					if(p->to.sym) { // retjmp
   549  						p->to.type = D_BRANCH;
   550  					} else {
   551  						p->to.type = D_OREG;
   552  						p->to.offset = 0;
   553  						p->to.reg = REGLINK;
   554  					}
   555  					break;
   556  				}
   557  			}
   558  
   559  			p->as = AMOVW;
   560  			p->scond |= C_PBIT;
   561  			p->from.type = D_OREG;
   562  			p->from.offset = autosize;
   563  			p->from.reg = REGSP;
   564  			p->to.type = D_REG;
   565  			p->to.reg = REGPC;
   566  			// If there are instructions following
   567  			// this ARET, they come from a branch
   568  			// with the same stackframe, so no spadj.
   569  			
   570  			if(p->to.sym) { // retjmp
   571  				p->to.reg = REGLINK;
   572  				q2 = appendp(ctxt, p);
   573  				q2->as = AB;
   574  				q2->to.type = D_BRANCH;
   575  				q2->to.sym = p->to.sym;
   576  				p->to.sym = nil;
   577  				p = q2;
   578  			}
   579  			break;
   580  
   581  		case AADD:
   582  			if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP)
   583  				p->spadj = -p->from.offset;
   584  			break;
   585  
   586  		case ASUB:
   587  			if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP)
   588  				p->spadj = p->from.offset;
   589  			break;
   590  
   591  		case ADIV:
   592  		case ADIVU:
   593  		case AMOD:
   594  		case AMODU:
   595  			if(ctxt->debugdivmod)
   596  				break;
   597  			if(p->from.type != D_REG)
   598  				break;
   599  			if(p->to.type != D_REG)
   600  				break;
   601  			q1 = p;
   602  
   603  			/* MOV a,4(SP) */
   604  			p = appendp(ctxt, p);
   605  			p->as = AMOVW;
   606  			p->lineno = q1->lineno;
   607  			p->from.type = D_REG;
   608  			p->from.reg = q1->from.reg;
   609  			p->to.type = D_OREG;
   610  			p->to.reg = REGSP;
   611  			p->to.offset = 4;
   612  
   613  			/* MOV b,REGTMP */
   614  			p = appendp(ctxt, p);
   615  			p->as = AMOVW;
   616  			p->lineno = q1->lineno;
   617  			p->from.type = D_REG;
   618  			p->from.reg = q1->reg;
   619  			if(q1->reg == NREG)
   620  				p->from.reg = q1->to.reg;
   621  			p->to.type = D_REG;
   622  			p->to.reg = REGTMP;
   623  			p->to.offset = 0;
   624  
   625  			/* CALL appropriate */
   626  			p = appendp(ctxt, p);
   627  			p->as = ABL;
   628  			p->lineno = q1->lineno;
   629  			p->to.type = D_BRANCH;
   630  			switch(o) {
   631  			case ADIV:
   632  				p->to.sym = ctxt->sym_div;
   633  				break;
   634  			case ADIVU:
   635  				p->to.sym = ctxt->sym_divu;
   636  				break;
   637  			case AMOD:
   638  				p->to.sym = ctxt->sym_mod;
   639  				break;
   640  			case AMODU:
   641  				p->to.sym = ctxt->sym_modu;
   642  				break;
   643  			}
   644  
   645  			/* MOV REGTMP, b */
   646  			p = appendp(ctxt, p);
   647  			p->as = AMOVW;
   648  			p->lineno = q1->lineno;
   649  			p->from.type = D_REG;
   650  			p->from.reg = REGTMP;
   651  			p->from.offset = 0;
   652  			p->to.type = D_REG;
   653  			p->to.reg = q1->to.reg;
   654  
   655  			/* ADD $8,SP */
   656  			p = appendp(ctxt, p);
   657  			p->as = AADD;
   658  			p->lineno = q1->lineno;
   659  			p->from.type = D_CONST;
   660  			p->from.reg = NREG;
   661  			p->from.offset = 8;
   662  			p->reg = NREG;
   663  			p->to.type = D_REG;
   664  			p->to.reg = REGSP;
   665  			p->spadj = -8;
   666  
   667  			/* Keep saved LR at 0(SP) after SP change. */
   668  			/* MOVW 0(SP), REGTMP; MOVW REGTMP, -8!(SP) */
   669  			/* TODO: Remove SP adjustments; see issue 6699. */
   670  			q1->as = AMOVW;
   671  			q1->from.type = D_OREG;
   672  			q1->from.reg = REGSP;
   673  			q1->from.offset = 0;
   674  			q1->reg = NREG;
   675  			q1->to.type = D_REG;
   676  			q1->to.reg = REGTMP;
   677  
   678  			/* SUB $8,SP */
   679  			q1 = appendp(ctxt, q1);
   680  			q1->as = AMOVW;
   681  			q1->from.type = D_REG;
   682  			q1->from.reg = REGTMP;
   683  			q1->reg = NREG;
   684  			q1->to.type = D_OREG;
   685  			q1->to.reg = REGSP;
   686  			q1->to.offset = -8;
   687  			q1->scond |= C_WBIT;
   688  			q1->spadj = 8;
   689  
   690  			break;
   691  		case AMOVW:
   692  			if((p->scond & C_WBIT) && p->to.type == D_OREG && p->to.reg == REGSP)
   693  				p->spadj = -p->to.offset;
   694  			if((p->scond & C_PBIT) && p->from.type == D_OREG && p->from.reg == REGSP && p->to.reg != REGPC)
   695  				p->spadj = -p->from.offset;
   696  			if(p->from.type == D_CONST && p->from.reg == REGSP && p->to.type == D_REG && p->to.reg == REGSP)
   697  				p->spadj = -p->from.offset;
   698  			break;
   699  		}
   700  	}
   701  }
   702  
   703  static void
   704  softfloat(Link *ctxt, LSym *cursym)
   705  {
   706  	Prog *p, *next;
   707  	LSym *symsfloat;
   708  	int wasfloat;
   709  
   710  	if(ctxt->goarm > 5)
   711  		return;
   712  
   713  	symsfloat = linklookup(ctxt, "_sfloat", 0);
   714  
   715  	wasfloat = 0;
   716  	for(p = cursym->text; p != nil; p = p->link)
   717  		if(p->pcond != nil)
   718  			p->pcond->mark |= LABEL;
   719  	for(p = cursym->text; p != nil; p = p->link) {
   720  		switch(p->as) {
   721  		case AMOVW:
   722  			if(p->to.type == D_FREG || p->from.type == D_FREG)
   723  				goto soft;
   724  			goto notsoft;
   725  
   726  		case AMOVWD:
   727  		case AMOVWF:
   728  		case AMOVDW:
   729  		case AMOVFW:
   730  		case AMOVFD:
   731  		case AMOVDF:
   732  		case AMOVF:
   733  		case AMOVD:
   734  
   735  		case ACMPF:
   736  		case ACMPD:
   737  		case AADDF:
   738  		case AADDD:
   739  		case ASUBF:
   740  		case ASUBD:
   741  		case AMULF:
   742  		case AMULD:
   743  		case ADIVF:
   744  		case ADIVD:
   745  		case ASQRTF:
   746  		case ASQRTD:
   747  		case AABSF:
   748  		case AABSD:
   749  			goto soft;
   750  
   751  		default:
   752  			goto notsoft;
   753  		}
   754  
   755  	soft:
   756  		if (!wasfloat || (p->mark&LABEL)) {
   757  			next = ctxt->arch->prg();
   758  			*next = *p;
   759  
   760  			// BL _sfloat(SB)
   761  			*p = zprg;
   762  			p->link = next;
   763  			p->as = ABL;
   764   				p->to.type = D_BRANCH;
   765  			p->to.sym = symsfloat;
   766  			p->lineno = next->lineno;
   767  
   768  			p = next;
   769  			wasfloat = 1;
   770  		}
   771  		continue;
   772  
   773  	notsoft:
   774  		wasfloat = 0;
   775  	}
   776  }
   777  
   778  static Prog*
   779  stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt)
   780  {
   781  	// MOVW			g_stackguard(g), R1
   782  	p = appendp(ctxt, p);
   783  	p->as = AMOVW;
   784  	p->from.type = D_OREG;
   785  	p->from.reg = REGG;
   786  	p->from.offset = 2*ctxt->arch->ptrsize;	// G.stackguard0
   787  	if(ctxt->cursym->cfunc)
   788  		p->from.offset = 3*ctxt->arch->ptrsize;	// G.stackguard1
   789  	p->to.type = D_REG;
   790  	p->to.reg = 1;
   791  	
   792  	if(framesize <= StackSmall) {
   793  		// small stack: SP < stackguard
   794  		//	CMP	stackguard, SP
   795  		p = appendp(ctxt, p);
   796  		p->as = ACMP;
   797  		p->from.type = D_REG;
   798  		p->from.reg = 1;
   799  		p->reg = REGSP;
   800  	} else if(framesize <= StackBig) {
   801  		// large stack: SP-framesize < stackguard-StackSmall
   802  		//	MOVW $-framesize(SP), R2
   803  		//	CMP stackguard, R2
   804  		p = appendp(ctxt, p);
   805  		p->as = AMOVW;
   806  		p->from.type = D_CONST;
   807  		p->from.reg = REGSP;
   808  		p->from.offset = -framesize;
   809  		p->to.type = D_REG;
   810  		p->to.reg = 2;
   811  		
   812  		p = appendp(ctxt, p);
   813  		p->as = ACMP;
   814  		p->from.type = D_REG;
   815  		p->from.reg = 1;
   816  		p->reg = 2;
   817  	} else {
   818  		// Such a large stack we need to protect against wraparound
   819  		// if SP is close to zero.
   820  		//	SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall)
   821  		// The +StackGuard on both sides is required to keep the left side positive:
   822  		// SP is allowed to be slightly below stackguard. See stack.h.
   823  		//	CMP $StackPreempt, R1
   824  		//	MOVW.NE $StackGuard(SP), R2
   825  		//	SUB.NE R1, R2
   826  		//	MOVW.NE $(framesize+(StackGuard-StackSmall)), R3
   827  		//	CMP.NE R3, R2
   828  		p = appendp(ctxt, p);
   829  		p->as = ACMP;
   830  		p->from.type = D_CONST;
   831  		p->from.offset = (uint32)StackPreempt;
   832  		p->reg = 1;
   833  
   834  		p = appendp(ctxt, p);
   835  		p->as = AMOVW;
   836  		p->from.type = D_CONST;
   837  		p->from.reg = REGSP;
   838  		p->from.offset = StackGuard;
   839  		p->to.type = D_REG;
   840  		p->to.reg = 2;
   841  		p->scond = C_SCOND_NE;
   842  		
   843  		p = appendp(ctxt, p);
   844  		p->as = ASUB;
   845  		p->from.type = D_REG;
   846  		p->from.reg = 1;
   847  		p->to.type = D_REG;
   848  		p->to.reg = 2;
   849  		p->scond = C_SCOND_NE;
   850  		
   851  		p = appendp(ctxt, p);
   852  		p->as = AMOVW;
   853  		p->from.type = D_CONST;
   854  		p->from.offset = framesize + (StackGuard - StackSmall);
   855  		p->to.type = D_REG;
   856  		p->to.reg = 3;
   857  		p->scond = C_SCOND_NE;
   858  		
   859  		p = appendp(ctxt, p);
   860  		p->as = ACMP;
   861  		p->from.type = D_REG;
   862  		p->from.reg = 3;
   863  		p->reg = 2;
   864  		p->scond = C_SCOND_NE;
   865  	}
   866  	
   867  	// MOVW.LS	R14, R3
   868  	p = appendp(ctxt, p);
   869  	p->as = AMOVW;
   870  	p->scond = C_SCOND_LS;
   871  	p->from.type = D_REG;
   872  	p->from.reg = REGLINK;
   873  	p->to.type = D_REG;
   874  	p->to.reg = 3;
   875  
   876  	// BL.LS		runtime.morestack(SB) // modifies LR, returns with LO still asserted
   877  	p = appendp(ctxt, p);
   878  	p->as = ABL;
   879  	p->scond = C_SCOND_LS;
   880  	p->to.type = D_BRANCH;
   881  	if(ctxt->cursym->cfunc)
   882  		p->to.sym = linklookup(ctxt, "runtime.morestackc", 0);
   883  	else
   884  		p->to.sym = ctxt->symmorestack[noctxt];
   885  	
   886  	// BLS	start
   887  	p = appendp(ctxt, p);
   888  	p->as = ABLS;
   889  	p->to.type = D_BRANCH;
   890  	p->pcond = ctxt->cursym->text->link;
   891  	
   892  	return p;
   893  }
   894  
   895  static void
   896  initdiv(Link *ctxt)
   897  {
   898  	if(ctxt->sym_div != nil)
   899  		return;
   900  	ctxt->sym_div = linklookup(ctxt, "_div", 0);
   901  	ctxt->sym_divu = linklookup(ctxt, "_divu", 0);
   902  	ctxt->sym_mod = linklookup(ctxt, "_mod", 0);
   903  	ctxt->sym_modu = linklookup(ctxt, "_modu", 0);
   904  }
   905  
   906  static void xfol(Link*, Prog*, Prog**);
   907  
   908  static void
   909  follow(Link *ctxt, LSym *s)
   910  {
   911  	Prog *firstp, *lastp;
   912  
   913  	ctxt->cursym = s;
   914  
   915  	firstp = ctxt->arch->prg();
   916  	lastp = firstp;
   917  	xfol(ctxt, s->text, &lastp);
   918  	lastp->link = nil;
   919  	s->text = firstp->link;
   920  }
   921  
   922  static int
   923  relinv(int a)
   924  {
   925  	switch(a) {
   926  	case ABEQ:	return ABNE;
   927  	case ABNE:	return ABEQ;
   928  	case ABCS:	return ABCC;
   929  	case ABHS:	return ABLO;
   930  	case ABCC:	return ABCS;
   931  	case ABLO:	return ABHS;
   932  	case ABMI:	return ABPL;
   933  	case ABPL:	return ABMI;
   934  	case ABVS:	return ABVC;
   935  	case ABVC:	return ABVS;
   936  	case ABHI:	return ABLS;
   937  	case ABLS:	return ABHI;
   938  	case ABGE:	return ABLT;
   939  	case ABLT:	return ABGE;
   940  	case ABGT:	return ABLE;
   941  	case ABLE:	return ABGT;
   942  	}
   943  	sysfatal("unknown relation: %s", anames5[a]);
   944  	return 0;
   945  }
   946  
   947  static void
   948  xfol(Link *ctxt, Prog *p, Prog **last)
   949  {
   950  	Prog *q, *r;
   951  	int a, i;
   952  
   953  loop:
   954  	if(p == nil)
   955  		return;
   956  	a = p->as;
   957  	if(a == AB) {
   958  		q = p->pcond;
   959  		if(q != nil && q->as != ATEXT) {
   960  			p->mark |= FOLL;
   961  			p = q;
   962  			if(!(p->mark & FOLL))
   963  				goto loop;
   964  		}
   965  	}
   966  	if(p->mark & FOLL) {
   967  		for(i=0,q=p; i<4; i++,q=q->link) {
   968  			if(q == *last || q == nil)
   969  				break;
   970  			a = q->as;
   971  			if(a == ANOP) {
   972  				i--;
   973  				continue;
   974  			}
   975  			if(a == AB || (a == ARET && q->scond == C_SCOND_NONE) || a == ARFE || a == AUNDEF)
   976  				goto copy;
   977  			if(q->pcond == nil || (q->pcond->mark&FOLL))
   978  				continue;
   979  			if(a != ABEQ && a != ABNE)
   980  				continue;
   981  		copy:
   982  			for(;;) {
   983  				r = ctxt->arch->prg();
   984  				*r = *p;
   985  				if(!(r->mark&FOLL))
   986  					print("can't happen 1\n");
   987  				r->mark |= FOLL;
   988  				if(p != q) {
   989  					p = p->link;
   990  					(*last)->link = r;
   991  					*last = r;
   992  					continue;
   993  				}
   994  				(*last)->link = r;
   995  				*last = r;
   996  				if(a == AB || (a == ARET && q->scond == C_SCOND_NONE) || a == ARFE || a == AUNDEF)
   997  					return;
   998  				r->as = ABNE;
   999  				if(a == ABNE)
  1000  					r->as = ABEQ;
  1001  				r->pcond = p->link;
  1002  				r->link = p->pcond;
  1003  				if(!(r->link->mark&FOLL))
  1004  					xfol(ctxt, r->link, last);
  1005  				if(!(r->pcond->mark&FOLL))
  1006  					print("can't happen 2\n");
  1007  				return;
  1008  			}
  1009  		}
  1010  		a = AB;
  1011  		q = ctxt->arch->prg();
  1012  		q->as = a;
  1013  		q->lineno = p->lineno;
  1014  		q->to.type = D_BRANCH;
  1015  		q->to.offset = p->pc;
  1016  		q->pcond = p;
  1017  		p = q;
  1018  	}
  1019  	p->mark |= FOLL;
  1020  	(*last)->link = p;
  1021  	*last = p;
  1022  	if(a == AB || (a == ARET && p->scond == C_SCOND_NONE) || a == ARFE || a == AUNDEF){
  1023  		return;
  1024  	}
  1025  	if(p->pcond != nil)
  1026  	if(a != ABL && a != ABX && p->link != nil) {
  1027  		q = brchain(ctxt, p->link);
  1028  		if(a != ATEXT && a != ABCASE)
  1029  		if(q != nil && (q->mark&FOLL)) {
  1030  			p->as = relinv(a);
  1031  			p->link = p->pcond;
  1032  			p->pcond = q;
  1033  		}
  1034  		xfol(ctxt, p->link, last);
  1035  		q = brchain(ctxt, p->pcond);
  1036  		if(q == nil)
  1037  			q = p->pcond;
  1038  		if(q->mark&FOLL) {
  1039  			p->pcond = q;
  1040  			return;
  1041  		}
  1042  		p = q;
  1043  		goto loop;
  1044  	}
  1045  	p = p->link;
  1046  	goto loop;
  1047  }
  1048  
  1049  LinkArch linkarm = {
  1050  	.name = "arm",
  1051  	.thechar = '5',
  1052  	.endian = LittleEndian,
  1053  
  1054  	.addstacksplit = addstacksplit,
  1055  	.assemble = span5,
  1056  	.datasize = datasize,
  1057  	.follow = follow,
  1058  	.iscall = iscall,
  1059  	.isdata = isdata,
  1060  	.prg = prg,
  1061  	.progedit = progedit,
  1062  	.settextflag = settextflag,
  1063  	.symtype = symtype,
  1064  	.textflag = textflag,
  1065  
  1066  	.minlc = 4,
  1067  	.ptrsize = 4,
  1068  	.regsize = 4,
  1069  
  1070  	.D_ADDR = D_ADDR,
  1071  	.D_AUTO = D_AUTO,
  1072  	.D_BRANCH = D_BRANCH,
  1073  	.D_CONST = D_CONST,
  1074  	.D_EXTERN = D_EXTERN,
  1075  	.D_FCONST = D_FCONST,
  1076  	.D_NONE = D_NONE,
  1077  	.D_PARAM = D_PARAM,
  1078  	.D_SCONST = D_SCONST,
  1079  	.D_STATIC = D_STATIC,
  1080  	.D_OREG = D_OREG,
  1081  
  1082  	.ACALL = ABL,
  1083  	.ADATA = ADATA,
  1084  	.AEND = AEND,
  1085  	.AFUNCDATA = AFUNCDATA,
  1086  	.AGLOBL = AGLOBL,
  1087  	.AJMP = AB,
  1088  	.ANOP = ANOP,
  1089  	.APCDATA = APCDATA,
  1090  	.ARET = ARET,
  1091  	.ATEXT = ATEXT,
  1092  	.ATYPE = ATYPE,
  1093  	.AUSEFIELD = AUSEFIELD,
  1094  };