github.com/Rookout/GoSDK@v0.1.48/pkg/services/assembler/internal/obj/arm/obj5.go (about)

     1  // Derived from Inferno utils/5c/swt.c
     2  // https://bitbucket.org/inferno-os/inferno-os/src/master/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  package arm
    32  
    33  import (
    34  	"github.com/Rookout/GoSDK/pkg/services/assembler/internal/obj"
    35  	"github.com/Rookout/GoSDK/pkg/services/assembler/internal/objabi"
    36  	"github.com/Rookout/GoSDK/pkg/services/assembler/internal/sys"
    37  	"github.com/Rookout/GoSDK/pkg/services/assembler/internal/abi"
    38  	"github.com/Rookout/GoSDK/pkg/services/assembler/internal/buildcfg"
    39  	"log"
    40  )
    41  
    42  var progedit_tlsfallback *obj.LSym
    43  
    44  func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
    45  	p.From.Class = 0
    46  	p.To.Class = 0
    47  
    48  	c := ctxt5{ctxt: ctxt, newprog: newprog}
    49  
    50  	
    51  	switch p.As {
    52  	case AB, ABL, obj.ADUFFZERO, obj.ADUFFCOPY:
    53  		if p.To.Type == obj.TYPE_MEM && (p.To.Name == obj.NAME_EXTERN || p.To.Name == obj.NAME_STATIC) && p.To.Sym != nil {
    54  			p.To.Type = obj.TYPE_BRANCH
    55  		}
    56  	}
    57  
    58  	
    59  	switch p.As {
    60  	
    61  	case AMRC:
    62  		if p.To.Offset&0xffff0fff == 0xee1d0f70 {
    63  			
    64  			
    65  			if p.To.Offset&0xf000 != 0 {
    66  				ctxt.Diag("%v: TLS MRC instruction must write to R0 as it might get translated into a BL instruction", p.Line())
    67  			}
    68  
    69  			if buildcfg.GOARM < 7 {
    70  				
    71  				if progedit_tlsfallback == nil {
    72  					progedit_tlsfallback = ctxt.Lookup("runtime.read_tls_fallback")
    73  				}
    74  
    75  				
    76  				p.As = AMOVW
    77  
    78  				p.From.Type = obj.TYPE_REG
    79  				p.From.Reg = REGLINK
    80  				p.To.Type = obj.TYPE_REG
    81  				p.To.Reg = REGTMP
    82  
    83  				
    84  				p = obj.Appendp(p, newprog)
    85  
    86  				p.As = ABL
    87  				p.To.Type = obj.TYPE_BRANCH
    88  				p.To.Sym = progedit_tlsfallback
    89  				p.To.Offset = 0
    90  
    91  				
    92  				p = obj.Appendp(p, newprog)
    93  
    94  				p.As = AMOVW
    95  				p.From.Type = obj.TYPE_REG
    96  				p.From.Reg = REGTMP
    97  				p.To.Type = obj.TYPE_REG
    98  				p.To.Reg = REGLINK
    99  				break
   100  			}
   101  		}
   102  
   103  		
   104  		p.As = AWORD
   105  	}
   106  
   107  	
   108  	switch p.As {
   109  	case AMOVF:
   110  		if p.From.Type == obj.TYPE_FCONST && c.chipfloat5(p.From.Val.(float64)) < 0 && (c.chipzero5(p.From.Val.(float64)) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) {
   111  			f32 := float32(p.From.Val.(float64))
   112  			p.From.Type = obj.TYPE_MEM
   113  			p.From.Sym = ctxt.Float32Sym(f32)
   114  			p.From.Name = obj.NAME_EXTERN
   115  			p.From.Offset = 0
   116  		}
   117  
   118  	case AMOVD:
   119  		if p.From.Type == obj.TYPE_FCONST && c.chipfloat5(p.From.Val.(float64)) < 0 && (c.chipzero5(p.From.Val.(float64)) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) {
   120  			p.From.Type = obj.TYPE_MEM
   121  			p.From.Sym = ctxt.Float64Sym(p.From.Val.(float64))
   122  			p.From.Name = obj.NAME_EXTERN
   123  			p.From.Offset = 0
   124  		}
   125  	}
   126  
   127  	if ctxt.Flag_dynlink {
   128  		c.rewriteToUseGot(p)
   129  	}
   130  }
   131  
   132  
   133  func (c *ctxt5) rewriteToUseGot(p *obj.Prog) {
   134  	if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
   135  		
   136  		
   137  		
   138  		
   139  		
   140  		var sym *obj.LSym
   141  		if p.As == obj.ADUFFZERO {
   142  			sym = c.ctxt.Lookup("runtime.duffzero")
   143  		} else {
   144  			sym = c.ctxt.Lookup("runtime.duffcopy")
   145  		}
   146  		offset := p.To.Offset
   147  		p.As = AMOVW
   148  		p.From.Type = obj.TYPE_MEM
   149  		p.From.Name = obj.NAME_GOTREF
   150  		p.From.Sym = sym
   151  		p.To.Type = obj.TYPE_REG
   152  		p.To.Reg = REG_R9
   153  		p.To.Name = obj.NAME_NONE
   154  		p.To.Offset = 0
   155  		p.To.Sym = nil
   156  		p1 := obj.Appendp(p, c.newprog)
   157  		p1.As = AADD
   158  		p1.From.Type = obj.TYPE_CONST
   159  		p1.From.Offset = offset
   160  		p1.To.Type = obj.TYPE_REG
   161  		p1.To.Reg = REG_R9
   162  		p2 := obj.Appendp(p1, c.newprog)
   163  		p2.As = obj.ACALL
   164  		p2.To.Type = obj.TYPE_MEM
   165  		p2.To.Reg = REG_R9
   166  		return
   167  	}
   168  
   169  	
   170  	
   171  	
   172  	if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
   173  		
   174  		
   175  		if p.As != AMOVW {
   176  			c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
   177  		}
   178  		if p.To.Type != obj.TYPE_REG {
   179  			c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
   180  		}
   181  		p.From.Type = obj.TYPE_MEM
   182  		p.From.Name = obj.NAME_GOTREF
   183  		if p.From.Offset != 0 {
   184  			q := obj.Appendp(p, c.newprog)
   185  			q.As = AADD
   186  			q.From.Type = obj.TYPE_CONST
   187  			q.From.Offset = p.From.Offset
   188  			q.To = p.To
   189  			p.From.Offset = 0
   190  		}
   191  	}
   192  	if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
   193  		c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
   194  	}
   195  	var source *obj.Addr
   196  	
   197  	
   198  	
   199  	if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
   200  		if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
   201  			c.ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
   202  		}
   203  		source = &p.From
   204  	} else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
   205  		source = &p.To
   206  	} else {
   207  		return
   208  	}
   209  	if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
   210  		return
   211  	}
   212  	if source.Sym.Type == objabi.STLSBSS {
   213  		return
   214  	}
   215  	if source.Type != obj.TYPE_MEM {
   216  		c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
   217  	}
   218  	p1 := obj.Appendp(p, c.newprog)
   219  	p2 := obj.Appendp(p1, c.newprog)
   220  
   221  	p1.As = AMOVW
   222  	p1.From.Type = obj.TYPE_MEM
   223  	p1.From.Sym = source.Sym
   224  	p1.From.Name = obj.NAME_GOTREF
   225  	p1.To.Type = obj.TYPE_REG
   226  	p1.To.Reg = REG_R9
   227  
   228  	p2.As = p.As
   229  	p2.From = p.From
   230  	p2.To = p.To
   231  	if p.From.Name == obj.NAME_EXTERN {
   232  		p2.From.Reg = REG_R9
   233  		p2.From.Name = obj.NAME_NONE
   234  		p2.From.Sym = nil
   235  	} else if p.To.Name == obj.NAME_EXTERN {
   236  		p2.To.Reg = REG_R9
   237  		p2.To.Name = obj.NAME_NONE
   238  		p2.To.Sym = nil
   239  	} else {
   240  		return
   241  	}
   242  	obj.Nopout(p)
   243  }
   244  
   245  
   246  const (
   247  	FOLL  = 1 << 0
   248  	LABEL = 1 << 1
   249  	LEAF  = 1 << 2
   250  )
   251  
   252  func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
   253  	autosize := int32(0)
   254  
   255  	if cursym.Func().Text == nil || cursym.Func().Text.Link == nil {
   256  		return
   257  	}
   258  
   259  	c := ctxt5{ctxt: ctxt, cursym: cursym, newprog: newprog}
   260  
   261  	p := c.cursym.Func().Text
   262  	autoffset := int32(p.To.Offset)
   263  	if autoffset == -4 {
   264  		
   265  		p.From.Sym.Set(obj.AttrNoFrame, true)
   266  		autoffset = 0
   267  	}
   268  	if autoffset < 0 || autoffset%4 != 0 {
   269  		c.ctxt.Diag("frame size %d not 0 or a positive multiple of 4", autoffset)
   270  	}
   271  	if p.From.Sym.NoFrame() {
   272  		if autoffset != 0 {
   273  			c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", autoffset)
   274  		}
   275  	}
   276  
   277  	cursym.Func().Locals = autoffset
   278  	cursym.Func().Args = p.To.Val.(int32)
   279  
   280  	
   281  	for p := cursym.Func().Text; p != nil; p = p.Link {
   282  		switch p.As {
   283  		case obj.ATEXT:
   284  			p.Mark |= LEAF
   285  
   286  		case ADIV, ADIVU, AMOD, AMODU:
   287  			cursym.Func().Text.Mark &^= LEAF
   288  
   289  		case ABL,
   290  			ABX,
   291  			obj.ADUFFZERO,
   292  			obj.ADUFFCOPY:
   293  			cursym.Func().Text.Mark &^= LEAF
   294  		}
   295  	}
   296  
   297  	var q2 *obj.Prog
   298  	for p := cursym.Func().Text; p != nil; p = p.Link {
   299  		o := p.As
   300  		switch o {
   301  		case obj.ATEXT:
   302  			autosize = autoffset
   303  
   304  			if p.Mark&LEAF != 0 && autosize == 0 {
   305  				
   306  				p.From.Sym.Set(obj.AttrNoFrame, true)
   307  			}
   308  
   309  			if !p.From.Sym.NoFrame() {
   310  				
   311  				
   312  				autosize += 4
   313  			}
   314  
   315  			if autosize == 0 && cursym.Func().Text.Mark&LEAF == 0 {
   316  				
   317  				
   318  				if ctxt.Debugvlog {
   319  					ctxt.Logf("save suppressed in: %s\n", cursym.Name)
   320  				}
   321  
   322  				cursym.Func().Text.Mark |= LEAF
   323  			}
   324  
   325  			
   326  			p.To.Offset = int64(autosize) - 4
   327  
   328  			if cursym.Func().Text.Mark&LEAF != 0 {
   329  				cursym.Set(obj.AttrLeaf, true)
   330  				if p.From.Sym.NoFrame() {
   331  					break
   332  				}
   333  			}
   334  
   335  			if !p.From.Sym.NoSplit() {
   336  				p = c.stacksplit(p, autosize) 
   337  			}
   338  
   339  			
   340  			p = obj.Appendp(p, c.newprog)
   341  
   342  			p.As = AMOVW
   343  			p.Scond |= C_WBIT
   344  			p.From.Type = obj.TYPE_REG
   345  			p.From.Reg = REGLINK
   346  			p.To.Type = obj.TYPE_MEM
   347  			p.To.Offset = int64(-autosize)
   348  			p.To.Reg = REGSP
   349  			p.Spadj = autosize
   350  
   351  			if cursym.Func().Text.From.Sym.Wrapper() {
   352  				
   353  				
   354  				
   355  				
   356  				
   357  				
   358  				
   359  				
   360  				
   361  				
   362  				
   363  				
   364  				
   365  				
   366  				
   367  				
   368  				
   369  				
   370  				
   371  
   372  				p = obj.Appendp(p, newprog)
   373  				p.As = AMOVW
   374  				p.From.Type = obj.TYPE_MEM
   375  				p.From.Reg = REGG
   376  				p.From.Offset = 4 * int64(ctxt.Arch.PtrSize) 
   377  				p.To.Type = obj.TYPE_REG
   378  				p.To.Reg = REG_R1
   379  
   380  				p = obj.Appendp(p, newprog)
   381  				p.As = ACMP
   382  				p.From.Type = obj.TYPE_CONST
   383  				p.From.Offset = 0
   384  				p.Reg = REG_R1
   385  
   386  				
   387  				bne := obj.Appendp(p, newprog)
   388  				bne.As = ABNE
   389  				bne.To.Type = obj.TYPE_BRANCH
   390  
   391  				
   392  				end := obj.Appendp(bne, newprog)
   393  				end.As = obj.ANOP
   394  
   395  				
   396  				var last *obj.Prog
   397  				for last = end; last.Link != nil; last = last.Link {
   398  				}
   399  
   400  				
   401  				mov := obj.Appendp(last, newprog)
   402  				mov.As = AMOVW
   403  				mov.From.Type = obj.TYPE_MEM
   404  				mov.From.Reg = REG_R1
   405  				mov.From.Offset = 0 
   406  				mov.To.Type = obj.TYPE_REG
   407  				mov.To.Reg = REG_R2
   408  
   409  				
   410  				bne.To.SetTarget(mov)
   411  
   412  				
   413  				p = obj.Appendp(mov, newprog)
   414  				p.As = AADD
   415  				p.From.Type = obj.TYPE_CONST
   416  				p.From.Offset = int64(autosize) + 4
   417  				p.Reg = REG_R13
   418  				p.To.Type = obj.TYPE_REG
   419  				p.To.Reg = REG_R3
   420  
   421  				
   422  				p = obj.Appendp(p, newprog)
   423  				p.As = ACMP
   424  				p.From.Type = obj.TYPE_REG
   425  				p.From.Reg = REG_R2
   426  				p.Reg = REG_R3
   427  
   428  				
   429  				p = obj.Appendp(p, newprog)
   430  				p.As = ABNE
   431  				p.To.Type = obj.TYPE_BRANCH
   432  				p.To.SetTarget(end)
   433  
   434  				
   435  				p = obj.Appendp(p, newprog)
   436  				p.As = AADD
   437  				p.From.Type = obj.TYPE_CONST
   438  				p.From.Offset = 4
   439  				p.Reg = REG_R13
   440  				p.To.Type = obj.TYPE_REG
   441  				p.To.Reg = REG_R4
   442  
   443  				
   444  				p = obj.Appendp(p, newprog)
   445  				p.As = AMOVW
   446  				p.From.Type = obj.TYPE_REG
   447  				p.From.Reg = REG_R4
   448  				p.To.Type = obj.TYPE_MEM
   449  				p.To.Reg = REG_R1
   450  				p.To.Offset = 0 
   451  
   452  				
   453  				p = obj.Appendp(p, newprog)
   454  				p.As = AB
   455  				p.To.Type = obj.TYPE_BRANCH
   456  				p.To.SetTarget(end)
   457  
   458  				
   459  				p = end
   460  			}
   461  
   462  		case obj.ARET:
   463  			nocache(p)
   464  			if cursym.Func().Text.Mark&LEAF != 0 {
   465  				if autosize == 0 {
   466  					p.As = AB
   467  					p.From = obj.Addr{}
   468  					if p.To.Sym != nil { 
   469  						p.To.Type = obj.TYPE_BRANCH
   470  					} else {
   471  						p.To.Type = obj.TYPE_MEM
   472  						p.To.Offset = 0
   473  						p.To.Reg = REGLINK
   474  					}
   475  
   476  					break
   477  				}
   478  			}
   479  
   480  			p.As = AMOVW
   481  			p.Scond |= C_PBIT
   482  			p.From.Type = obj.TYPE_MEM
   483  			p.From.Offset = int64(autosize)
   484  			p.From.Reg = REGSP
   485  			p.To.Type = obj.TYPE_REG
   486  			p.To.Reg = REGPC
   487  
   488  			
   489  			
   490  			
   491  
   492  			if p.To.Sym != nil { 
   493  				p.To.Reg = REGLINK
   494  				q2 = obj.Appendp(p, newprog)
   495  				q2.As = AB
   496  				q2.To.Type = obj.TYPE_BRANCH
   497  				q2.To.Sym = p.To.Sym
   498  				p.To.Sym = nil
   499  				p.To.Name = obj.NAME_NONE
   500  				p = q2
   501  			}
   502  
   503  		case AADD:
   504  			if p.From.Type == obj.TYPE_CONST && p.From.Reg == 0 && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP {
   505  				p.Spadj = int32(-p.From.Offset)
   506  			}
   507  
   508  		case ASUB:
   509  			if p.From.Type == obj.TYPE_CONST && p.From.Reg == 0 && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP {
   510  				p.Spadj = int32(p.From.Offset)
   511  			}
   512  
   513  		case ADIV, ADIVU, AMOD, AMODU:
   514  			if cursym.Func().Text.From.Sym.NoSplit() {
   515  				ctxt.Diag("cannot divide in NOSPLIT function")
   516  			}
   517  			const debugdivmod = false
   518  			if debugdivmod {
   519  				break
   520  			}
   521  			if p.From.Type != obj.TYPE_REG {
   522  				break
   523  			}
   524  			if p.To.Type != obj.TYPE_REG {
   525  				break
   526  			}
   527  
   528  			
   529  			q1 := *p
   530  			if q1.Reg == REGTMP || q1.Reg == 0 && q1.To.Reg == REGTMP {
   531  				ctxt.Diag("div already using REGTMP: %v", p)
   532  			}
   533  
   534  			
   535  			p.As = AMOVW
   536  			p.Pos = q1.Pos
   537  			p.From.Type = obj.TYPE_MEM
   538  			p.From.Reg = REGG
   539  			p.From.Offset = 6 * 4 
   540  			p.Reg = 0
   541  			p.To.Type = obj.TYPE_REG
   542  			p.To.Reg = REGTMP
   543  
   544  			
   545  			p = obj.Appendp(p, newprog)
   546  			p.As = AMOVW
   547  			p.Pos = q1.Pos
   548  			p.From.Type = obj.TYPE_REG
   549  			p.From.Reg = q1.From.Reg
   550  			p.To.Type = obj.TYPE_MEM
   551  			p.To.Reg = REGTMP
   552  			p.To.Offset = 8 * 4 
   553  
   554  			
   555  			p = obj.Appendp(p, newprog)
   556  			p.As = AMOVW
   557  			p.Pos = q1.Pos
   558  			p.From.Type = obj.TYPE_REG
   559  			p.From.Reg = q1.Reg
   560  			if q1.Reg == 0 {
   561  				p.From.Reg = q1.To.Reg
   562  			}
   563  			p.To.Type = obj.TYPE_REG
   564  			p.To.Reg = REG_R8
   565  			p.To.Offset = 0
   566  
   567  			
   568  			p = obj.Appendp(p, newprog)
   569  			p.As = ABL
   570  			p.Pos = q1.Pos
   571  			p.To.Type = obj.TYPE_BRANCH
   572  			switch o {
   573  			case ADIV:
   574  				p.To.Sym = symdiv
   575  			case ADIVU:
   576  				p.To.Sym = symdivu
   577  			case AMOD:
   578  				p.To.Sym = symmod
   579  			case AMODU:
   580  				p.To.Sym = symmodu
   581  			}
   582  
   583  			
   584  			p = obj.Appendp(p, newprog)
   585  			p.As = AMOVW
   586  			p.Pos = q1.Pos
   587  			p.From.Type = obj.TYPE_REG
   588  			p.From.Reg = REGTMP
   589  			p.From.Offset = 0
   590  			p.To.Type = obj.TYPE_REG
   591  			p.To.Reg = q1.To.Reg
   592  
   593  		case AMOVW:
   594  			if (p.Scond&C_WBIT != 0) && p.To.Type == obj.TYPE_MEM && p.To.Reg == REGSP {
   595  				p.Spadj = int32(-p.To.Offset)
   596  			}
   597  			if (p.Scond&C_PBIT != 0) && p.From.Type == obj.TYPE_MEM && p.From.Reg == REGSP && p.To.Reg != REGPC {
   598  				p.Spadj = int32(-p.From.Offset)
   599  			}
   600  			if p.From.Type == obj.TYPE_ADDR && p.From.Reg == REGSP && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP {
   601  				p.Spadj = int32(-p.From.Offset)
   602  			}
   603  
   604  		case obj.AGETCALLERPC:
   605  			if cursym.Leaf() {
   606  				
   607  				p.As = AMOVW
   608  				p.From.Type = obj.TYPE_REG
   609  				p.From.Reg = REGLINK
   610  			} else {
   611  				
   612  				p.As = AMOVW
   613  				p.From.Type = obj.TYPE_MEM
   614  				p.From.Reg = REGSP
   615  			}
   616  		}
   617  
   618  		if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 {
   619  			f := c.cursym.Func()
   620  			if f.FuncFlag&abi.FuncFlagSPWrite == 0 {
   621  				c.cursym.Func().FuncFlag |= abi.FuncFlagSPWrite
   622  				if ctxt.Debugvlog || !ctxt.IsAsm {
   623  					ctxt.Logf("auto-SPWRITE: %s %v\n", c.cursym.Name, p)
   624  					if !ctxt.IsAsm {
   625  						ctxt.Diag("invalid auto-SPWRITE in non-assembly")
   626  						ctxt.DiagFlush()
   627  						log.Fatalf("bad SPWRITE")
   628  					}
   629  				}
   630  			}
   631  		}
   632  	}
   633  }
   634  
   635  func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
   636  	if c.ctxt.Flag_maymorestack != "" {
   637  		
   638  		const frameSize = 8
   639  		
   640  		p = obj.Appendp(p, c.newprog)
   641  		p.As = AMOVW
   642  		p.Scond |= C_WBIT
   643  		p.From.Type = obj.TYPE_REG
   644  		p.From.Reg = REGLINK
   645  		p.To.Type = obj.TYPE_MEM
   646  		p.To.Offset = -frameSize
   647  		p.To.Reg = REGSP
   648  		p.Spadj = frameSize
   649  
   650  		
   651  		p = obj.Appendp(p, c.newprog)
   652  		p.As = AMOVW
   653  		p.From.Type = obj.TYPE_REG
   654  		p.From.Reg = REGCTXT
   655  		p.To.Type = obj.TYPE_MEM
   656  		p.To.Offset = 4
   657  		p.To.Reg = REGSP
   658  
   659  		
   660  		p = obj.Appendp(p, c.newprog)
   661  		p.As = obj.ACALL
   662  		p.To.Type = obj.TYPE_BRANCH
   663  		
   664  		p.To.Sym = c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
   665  
   666  		
   667  
   668  		
   669  		p = obj.Appendp(p, c.newprog)
   670  		p.As = AMOVW
   671  		p.From.Type = obj.TYPE_MEM
   672  		p.From.Offset = 4
   673  		p.From.Reg = REGSP
   674  		p.To.Type = obj.TYPE_REG
   675  		p.To.Reg = REGCTXT
   676  
   677  		
   678  		p.As = AMOVW
   679  		p.Scond |= C_PBIT
   680  		p.From.Type = obj.TYPE_MEM
   681  		p.From.Offset = frameSize
   682  		p.From.Reg = REGSP
   683  		p.To.Type = obj.TYPE_REG
   684  		p.To.Reg = REGLINK
   685  		p.Spadj = -frameSize
   686  	}
   687  
   688  	
   689  	startPred := p
   690  
   691  	
   692  	p = obj.Appendp(p, c.newprog)
   693  
   694  	p.As = AMOVW
   695  	p.From.Type = obj.TYPE_MEM
   696  	p.From.Reg = REGG
   697  	p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) 
   698  	if c.cursym.CFunc() {
   699  		p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) 
   700  	}
   701  	p.To.Type = obj.TYPE_REG
   702  	p.To.Reg = REG_R1
   703  
   704  	
   705  	
   706  	
   707  	
   708  	p = c.ctxt.StartUnsafePoint(p, c.newprog)
   709  
   710  	if framesize <= abi.StackSmall {
   711  		
   712  		
   713  		p = obj.Appendp(p, c.newprog)
   714  
   715  		p.As = ACMP
   716  		p.From.Type = obj.TYPE_REG
   717  		p.From.Reg = REG_R1
   718  		p.Reg = REGSP
   719  	} else if framesize <= abi.StackBig {
   720  		
   721  		
   722  		
   723  		p = obj.Appendp(p, c.newprog)
   724  
   725  		p.As = AMOVW
   726  		p.From.Type = obj.TYPE_ADDR
   727  		p.From.Reg = REGSP
   728  		p.From.Offset = -(int64(framesize) - abi.StackSmall)
   729  		p.To.Type = obj.TYPE_REG
   730  		p.To.Reg = REG_R2
   731  
   732  		p = obj.Appendp(p, c.newprog)
   733  		p.As = ACMP
   734  		p.From.Type = obj.TYPE_REG
   735  		p.From.Reg = REG_R1
   736  		p.Reg = REG_R2
   737  	} else {
   738  		
   739  		
   740  		
   741  		
   742  		
   743  		
   744  		
   745  		
   746  		
   747  		
   748  		
   749  		
   750  
   751  		p = obj.Appendp(p, c.newprog)
   752  		p.As = ASUB
   753  		p.Scond = C_SBIT
   754  		p.From.Type = obj.TYPE_CONST
   755  		p.From.Offset = int64(framesize) - abi.StackSmall
   756  		p.Reg = REGSP
   757  		p.To.Type = obj.TYPE_REG
   758  		p.To.Reg = REG_R2
   759  
   760  		p = obj.Appendp(p, c.newprog)
   761  		p.As = ACMP
   762  		p.Scond = C_SCOND_HS
   763  		p.From.Type = obj.TYPE_REG
   764  		p.From.Reg = REG_R1
   765  		p.Reg = REG_R2
   766  	}
   767  
   768  	
   769  	bls := obj.Appendp(p, c.newprog)
   770  	bls.As = ABLS
   771  	bls.To.Type = obj.TYPE_BRANCH
   772  
   773  	end := c.ctxt.EndUnsafePoint(bls, c.newprog, -1)
   774  
   775  	var last *obj.Prog
   776  	for last = c.cursym.Func().Text; last.Link != nil; last = last.Link {
   777  	}
   778  
   779  	
   780  	
   781  	
   782  	spfix := obj.Appendp(last, c.newprog)
   783  	spfix.As = obj.ANOP
   784  	spfix.Spadj = -framesize
   785  
   786  	pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
   787  	pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
   788  
   789  	
   790  	movw := obj.Appendp(pcdata, c.newprog)
   791  	movw.As = AMOVW
   792  	movw.From.Type = obj.TYPE_REG
   793  	movw.From.Reg = REGLINK
   794  	movw.To.Type = obj.TYPE_REG
   795  	movw.To.Reg = REG_R3
   796  
   797  	bls.To.SetTarget(movw)
   798  
   799  	
   800  	call := obj.Appendp(movw, c.newprog)
   801  	call.As = obj.ACALL
   802  	call.To.Type = obj.TYPE_BRANCH
   803  	morestack := "runtime.morestack"
   804  	switch {
   805  	case c.cursym.CFunc():
   806  		morestack = "runtime.morestackc"
   807  	case !c.cursym.Func().Text.From.Sym.NeedCtxt():
   808  		morestack = "runtime.morestack_noctxt"
   809  	}
   810  	call.To.Sym = c.ctxt.Lookup(morestack)
   811  
   812  	pcdata = c.ctxt.EndUnsafePoint(call, c.newprog, -1)
   813  
   814  	
   815  	b := obj.Appendp(pcdata, c.newprog)
   816  	b.As = obj.AJMP
   817  	b.To.Type = obj.TYPE_BRANCH
   818  	b.To.SetTarget(startPred.Link)
   819  	b.Spadj = +framesize
   820  
   821  	return end
   822  }
   823  
   824  var unaryDst = map[obj.As]bool{
   825  	ASWI:  true,
   826  	AWORD: true,
   827  }
   828  
   829  var Linkarm = obj.LinkArch{
   830  	Arch:           sys.ArchARM,
   831  	Init:           buildop,
   832  	Preprocess:     preprocess,
   833  	Assemble:       span5,
   834  	Progedit:       progedit,
   835  	UnaryDst:       unaryDst,
   836  	DWARFRegisters: ARMDWARFRegisters,
   837  }