...

Source file src/github.com/twitchyliquid64/golang-asm/obj/ppc64/obj9.go

Documentation: github.com/twitchyliquid64/golang-asm/obj/ppc64

     1  // cmd/9l/noop.c, cmd/9l/pass.c, cmd/9l/span.c from Vita Nuova.
     2  //
     3  //	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
     4  //	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     5  //	Portions Copyright © 1997-1999 Vita Nuova Limited
     6  //	Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
     7  //	Portions Copyright © 2004,2006 Bruce Ellis
     8  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
     9  //	Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
    10  //	Portions Copyright © 2009 The Go Authors. All rights reserved.
    11  //
    12  // Permission is hereby granted, free of charge, to any person obtaining a copy
    13  // of this software and associated documentation files (the "Software"), to deal
    14  // in the Software without restriction, including without limitation the rights
    15  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    16  // copies of the Software, and to permit persons to whom the Software is
    17  // furnished to do so, subject to the following conditions:
    18  //
    19  // The above copyright notice and this permission notice shall be included in
    20  // all copies or substantial portions of the Software.
    21  //
    22  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    23  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    24  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    25  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    26  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    27  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    28  // THE SOFTWARE.
    29  
    30  package ppc64
    31  
    32  import (
    33  	"github.com/twitchyliquid64/golang-asm/obj"
    34  	"github.com/twitchyliquid64/golang-asm/objabi"
    35  	"github.com/twitchyliquid64/golang-asm/sys"
    36  )
    37  
    38  func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
    39  	p.From.Class = 0
    40  	p.To.Class = 0
    41  
    42  	c := ctxt9{ctxt: ctxt, newprog: newprog}
    43  
    44  	// Rewrite BR/BL to symbol as TYPE_BRANCH.
    45  	switch p.As {
    46  	case ABR,
    47  		ABL,
    48  		obj.ARET,
    49  		obj.ADUFFZERO,
    50  		obj.ADUFFCOPY:
    51  		if p.To.Sym != nil {
    52  			p.To.Type = obj.TYPE_BRANCH
    53  		}
    54  	}
    55  
    56  	// Rewrite float constants to values stored in memory.
    57  	switch p.As {
    58  	case AFMOVS:
    59  		if p.From.Type == obj.TYPE_FCONST {
    60  			f32 := float32(p.From.Val.(float64))
    61  			p.From.Type = obj.TYPE_MEM
    62  			p.From.Sym = ctxt.Float32Sym(f32)
    63  			p.From.Name = obj.NAME_EXTERN
    64  			p.From.Offset = 0
    65  		}
    66  
    67  	case AFMOVD:
    68  		if p.From.Type == obj.TYPE_FCONST {
    69  			f64 := p.From.Val.(float64)
    70  			// Constant not needed in memory for float +/- 0
    71  			if f64 != 0 {
    72  				p.From.Type = obj.TYPE_MEM
    73  				p.From.Sym = ctxt.Float64Sym(f64)
    74  				p.From.Name = obj.NAME_EXTERN
    75  				p.From.Offset = 0
    76  			}
    77  		}
    78  
    79  		// Put >32-bit constants in memory and load them
    80  	case AMOVD:
    81  		if p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE && p.From.Reg == 0 && int64(int32(p.From.Offset)) != p.From.Offset {
    82  			p.From.Type = obj.TYPE_MEM
    83  			p.From.Sym = ctxt.Int64Sym(p.From.Offset)
    84  			p.From.Name = obj.NAME_EXTERN
    85  			p.From.Offset = 0
    86  		}
    87  	}
    88  
    89  	// Rewrite SUB constants into ADD.
    90  	switch p.As {
    91  	case ASUBC:
    92  		if p.From.Type == obj.TYPE_CONST {
    93  			p.From.Offset = -p.From.Offset
    94  			p.As = AADDC
    95  		}
    96  
    97  	case ASUBCCC:
    98  		if p.From.Type == obj.TYPE_CONST {
    99  			p.From.Offset = -p.From.Offset
   100  			p.As = AADDCCC
   101  		}
   102  
   103  	case ASUB:
   104  		if p.From.Type == obj.TYPE_CONST {
   105  			p.From.Offset = -p.From.Offset
   106  			p.As = AADD
   107  		}
   108  	}
   109  	if c.ctxt.Headtype == objabi.Haix {
   110  		c.rewriteToUseTOC(p)
   111  	} else if c.ctxt.Flag_dynlink {
   112  		c.rewriteToUseGot(p)
   113  	}
   114  }
   115  
   116  // Rewrite p, if necessary, to access a symbol using its TOC anchor.
   117  // This code is for AIX only.
   118  func (c *ctxt9) rewriteToUseTOC(p *obj.Prog) {
   119  	if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
   120  		return
   121  	}
   122  
   123  	if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
   124  		// ADUFFZERO/ADUFFCOPY is considered as an ABL except in dynamic
   125  		// link where it should be an indirect call.
   126  		if !c.ctxt.Flag_dynlink {
   127  			return
   128  		}
   129  		//     ADUFFxxx $offset
   130  		// becomes
   131  		//     MOVD runtime.duffxxx@TOC, R12
   132  		//     ADD $offset, R12
   133  		//     MOVD R12, LR
   134  		//     BL (LR)
   135  		var sym *obj.LSym
   136  		if p.As == obj.ADUFFZERO {
   137  			sym = c.ctxt.Lookup("runtime.duffzero")
   138  		} else {
   139  			sym = c.ctxt.Lookup("runtime.duffcopy")
   140  		}
   141  		// Retrieve or create the TOC anchor.
   142  		symtoc := c.ctxt.LookupInit("TOC."+sym.Name, func(s *obj.LSym) {
   143  			s.Type = objabi.SDATA
   144  			s.Set(obj.AttrDuplicateOK, true)
   145  			s.Set(obj.AttrStatic, true)
   146  			c.ctxt.Data = append(c.ctxt.Data, s)
   147  			s.WriteAddr(c.ctxt, 0, 8, sym, 0)
   148  		})
   149  
   150  		offset := p.To.Offset
   151  		p.As = AMOVD
   152  		p.From.Type = obj.TYPE_MEM
   153  		p.From.Name = obj.NAME_TOCREF
   154  		p.From.Sym = symtoc
   155  		p.To.Type = obj.TYPE_REG
   156  		p.To.Reg = REG_R12
   157  		p.To.Name = obj.NAME_NONE
   158  		p.To.Offset = 0
   159  		p.To.Sym = nil
   160  		p1 := obj.Appendp(p, c.newprog)
   161  		p1.As = AADD
   162  		p1.From.Type = obj.TYPE_CONST
   163  		p1.From.Offset = offset
   164  		p1.To.Type = obj.TYPE_REG
   165  		p1.To.Reg = REG_R12
   166  		p2 := obj.Appendp(p1, c.newprog)
   167  		p2.As = AMOVD
   168  		p2.From.Type = obj.TYPE_REG
   169  		p2.From.Reg = REG_R12
   170  		p2.To.Type = obj.TYPE_REG
   171  		p2.To.Reg = REG_LR
   172  		p3 := obj.Appendp(p2, c.newprog)
   173  		p3.As = obj.ACALL
   174  		p3.To.Type = obj.TYPE_REG
   175  		p3.To.Reg = REG_LR
   176  	}
   177  
   178  	var source *obj.Addr
   179  	if p.From.Name == obj.NAME_EXTERN || p.From.Name == obj.NAME_STATIC {
   180  		if p.From.Type == obj.TYPE_ADDR {
   181  			if p.As == ADWORD {
   182  				// ADWORD $sym doesn't need TOC anchor
   183  				return
   184  			}
   185  			if p.As != AMOVD {
   186  				c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v", p)
   187  				return
   188  			}
   189  			if p.To.Type != obj.TYPE_REG {
   190  				c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v", p)
   191  				return
   192  			}
   193  		} else if p.From.Type != obj.TYPE_MEM {
   194  			c.ctxt.Diag("do not know how to handle %v without TYPE_MEM", p)
   195  			return
   196  		}
   197  		source = &p.From
   198  
   199  	} else if p.To.Name == obj.NAME_EXTERN || p.To.Name == obj.NAME_STATIC {
   200  		if p.To.Type != obj.TYPE_MEM {
   201  			c.ctxt.Diag("do not know how to handle %v without TYPE_MEM", p)
   202  			return
   203  		}
   204  		if source != nil {
   205  			c.ctxt.Diag("cannot handle symbols on both sides in %v", p)
   206  			return
   207  		}
   208  		source = &p.To
   209  	} else {
   210  		return
   211  
   212  	}
   213  
   214  	if source.Sym == nil {
   215  		c.ctxt.Diag("do not know how to handle nil symbol in %v", p)
   216  		return
   217  	}
   218  
   219  	if source.Sym.Type == objabi.STLSBSS {
   220  		return
   221  	}
   222  
   223  	// Retrieve or create the TOC anchor.
   224  	symtoc := c.ctxt.LookupInit("TOC."+source.Sym.Name, func(s *obj.LSym) {
   225  		s.Type = objabi.SDATA
   226  		s.Set(obj.AttrDuplicateOK, true)
   227  		s.Set(obj.AttrStatic, true)
   228  		c.ctxt.Data = append(c.ctxt.Data, s)
   229  		s.WriteAddr(c.ctxt, 0, 8, source.Sym, 0)
   230  	})
   231  
   232  	if source.Type == obj.TYPE_ADDR {
   233  		// MOVD $sym, Rx becomes MOVD symtoc, Rx
   234  		// MOVD $sym+<off>, Rx becomes MOVD symtoc, Rx; ADD <off>, Rx
   235  		p.From.Type = obj.TYPE_MEM
   236  		p.From.Sym = symtoc
   237  		p.From.Name = obj.NAME_TOCREF
   238  
   239  		if p.From.Offset != 0 {
   240  			q := obj.Appendp(p, c.newprog)
   241  			q.As = AADD
   242  			q.From.Type = obj.TYPE_CONST
   243  			q.From.Offset = p.From.Offset
   244  			p.From.Offset = 0
   245  			q.To = p.To
   246  		}
   247  		return
   248  
   249  	}
   250  
   251  	// MOVx sym, Ry becomes MOVD symtoc, REGTMP; MOVx (REGTMP), Ry
   252  	// MOVx Ry, sym becomes MOVD symtoc, REGTMP; MOVx Ry, (REGTMP)
   253  	// An addition may be inserted between the two MOVs if there is an offset.
   254  
   255  	q := obj.Appendp(p, c.newprog)
   256  	q.As = AMOVD
   257  	q.From.Type = obj.TYPE_MEM
   258  	q.From.Sym = symtoc
   259  	q.From.Name = obj.NAME_TOCREF
   260  	q.To.Type = obj.TYPE_REG
   261  	q.To.Reg = REGTMP
   262  
   263  	q = obj.Appendp(q, c.newprog)
   264  	q.As = p.As
   265  	q.From = p.From
   266  	q.To = p.To
   267  	if p.From.Name != obj.NAME_NONE {
   268  		q.From.Type = obj.TYPE_MEM
   269  		q.From.Reg = REGTMP
   270  		q.From.Name = obj.NAME_NONE
   271  		q.From.Sym = nil
   272  	} else if p.To.Name != obj.NAME_NONE {
   273  		q.To.Type = obj.TYPE_MEM
   274  		q.To.Reg = REGTMP
   275  		q.To.Name = obj.NAME_NONE
   276  		q.To.Sym = nil
   277  	} else {
   278  		c.ctxt.Diag("unreachable case in rewriteToUseTOC with %v", p)
   279  	}
   280  
   281  	obj.Nopout(p)
   282  }
   283  
   284  // Rewrite p, if necessary, to access global data via the global offset table.
   285  func (c *ctxt9) rewriteToUseGot(p *obj.Prog) {
   286  	if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
   287  		//     ADUFFxxx $offset
   288  		// becomes
   289  		//     MOVD runtime.duffxxx@GOT, R12
   290  		//     ADD $offset, R12
   291  		//     MOVD R12, LR
   292  		//     BL (LR)
   293  		var sym *obj.LSym
   294  		if p.As == obj.ADUFFZERO {
   295  			sym = c.ctxt.Lookup("runtime.duffzero")
   296  		} else {
   297  			sym = c.ctxt.Lookup("runtime.duffcopy")
   298  		}
   299  		offset := p.To.Offset
   300  		p.As = AMOVD
   301  		p.From.Type = obj.TYPE_MEM
   302  		p.From.Name = obj.NAME_GOTREF
   303  		p.From.Sym = sym
   304  		p.To.Type = obj.TYPE_REG
   305  		p.To.Reg = REG_R12
   306  		p.To.Name = obj.NAME_NONE
   307  		p.To.Offset = 0
   308  		p.To.Sym = nil
   309  		p1 := obj.Appendp(p, c.newprog)
   310  		p1.As = AADD
   311  		p1.From.Type = obj.TYPE_CONST
   312  		p1.From.Offset = offset
   313  		p1.To.Type = obj.TYPE_REG
   314  		p1.To.Reg = REG_R12
   315  		p2 := obj.Appendp(p1, c.newprog)
   316  		p2.As = AMOVD
   317  		p2.From.Type = obj.TYPE_REG
   318  		p2.From.Reg = REG_R12
   319  		p2.To.Type = obj.TYPE_REG
   320  		p2.To.Reg = REG_LR
   321  		p3 := obj.Appendp(p2, c.newprog)
   322  		p3.As = obj.ACALL
   323  		p3.To.Type = obj.TYPE_REG
   324  		p3.To.Reg = REG_LR
   325  	}
   326  
   327  	// We only care about global data: NAME_EXTERN means a global
   328  	// symbol in the Go sense, and p.Sym.Local is true for a few
   329  	// internally defined symbols.
   330  	if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
   331  		// MOVD $sym, Rx becomes MOVD sym@GOT, Rx
   332  		// MOVD $sym+<off>, Rx becomes MOVD sym@GOT, Rx; ADD <off>, Rx
   333  		if p.As != AMOVD {
   334  			c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
   335  		}
   336  		if p.To.Type != obj.TYPE_REG {
   337  			c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
   338  		}
   339  		p.From.Type = obj.TYPE_MEM
   340  		p.From.Name = obj.NAME_GOTREF
   341  		if p.From.Offset != 0 {
   342  			q := obj.Appendp(p, c.newprog)
   343  			q.As = AADD
   344  			q.From.Type = obj.TYPE_CONST
   345  			q.From.Offset = p.From.Offset
   346  			q.To = p.To
   347  			p.From.Offset = 0
   348  		}
   349  	}
   350  	if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
   351  		c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
   352  	}
   353  	var source *obj.Addr
   354  	// MOVx sym, Ry becomes MOVD sym@GOT, REGTMP; MOVx (REGTMP), Ry
   355  	// MOVx Ry, sym becomes MOVD sym@GOT, REGTMP; MOVx Ry, (REGTMP)
   356  	// An addition may be inserted between the two MOVs if there is an offset.
   357  	if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
   358  		if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
   359  			c.ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
   360  		}
   361  		source = &p.From
   362  	} else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
   363  		source = &p.To
   364  	} else {
   365  		return
   366  	}
   367  	if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
   368  		return
   369  	}
   370  	if source.Sym.Type == objabi.STLSBSS {
   371  		return
   372  	}
   373  	if source.Type != obj.TYPE_MEM {
   374  		c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
   375  	}
   376  	p1 := obj.Appendp(p, c.newprog)
   377  	p2 := obj.Appendp(p1, c.newprog)
   378  
   379  	p1.As = AMOVD
   380  	p1.From.Type = obj.TYPE_MEM
   381  	p1.From.Sym = source.Sym
   382  	p1.From.Name = obj.NAME_GOTREF
   383  	p1.To.Type = obj.TYPE_REG
   384  	p1.To.Reg = REGTMP
   385  
   386  	p2.As = p.As
   387  	p2.From = p.From
   388  	p2.To = p.To
   389  	if p.From.Name == obj.NAME_EXTERN {
   390  		p2.From.Reg = REGTMP
   391  		p2.From.Name = obj.NAME_NONE
   392  		p2.From.Sym = nil
   393  	} else if p.To.Name == obj.NAME_EXTERN {
   394  		p2.To.Reg = REGTMP
   395  		p2.To.Name = obj.NAME_NONE
   396  		p2.To.Sym = nil
   397  	} else {
   398  		return
   399  	}
   400  	obj.Nopout(p)
   401  }
   402  
   403  func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
   404  	// TODO(minux): add morestack short-cuts with small fixed frame-size.
   405  	if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
   406  		return
   407  	}
   408  
   409  	c := ctxt9{ctxt: ctxt, cursym: cursym, newprog: newprog}
   410  
   411  	p := c.cursym.Func.Text
   412  	textstksiz := p.To.Offset
   413  	if textstksiz == -8 {
   414  		// Compatibility hack.
   415  		p.From.Sym.Set(obj.AttrNoFrame, true)
   416  		textstksiz = 0
   417  	}
   418  	if textstksiz%8 != 0 {
   419  		c.ctxt.Diag("frame size %d not a multiple of 8", textstksiz)
   420  	}
   421  	if p.From.Sym.NoFrame() {
   422  		if textstksiz != 0 {
   423  			c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
   424  		}
   425  	}
   426  
   427  	c.cursym.Func.Args = p.To.Val.(int32)
   428  	c.cursym.Func.Locals = int32(textstksiz)
   429  
   430  	/*
   431  	 * find leaf subroutines
   432  	 * expand RET
   433  	 * expand BECOME pseudo
   434  	 */
   435  
   436  	var q *obj.Prog
   437  	var q1 *obj.Prog
   438  	for p := c.cursym.Func.Text; p != nil; p = p.Link {
   439  		switch p.As {
   440  		/* too hard, just leave alone */
   441  		case obj.ATEXT:
   442  			q = p
   443  
   444  			p.Mark |= LABEL | LEAF | SYNC
   445  			if p.Link != nil {
   446  				p.Link.Mark |= LABEL
   447  			}
   448  
   449  		case ANOR:
   450  			q = p
   451  			if p.To.Type == obj.TYPE_REG {
   452  				if p.To.Reg == REGZERO {
   453  					p.Mark |= LABEL | SYNC
   454  				}
   455  			}
   456  
   457  		case ALWAR,
   458  			ALBAR,
   459  			ASTBCCC,
   460  			ASTWCCC,
   461  			AECIWX,
   462  			AECOWX,
   463  			AEIEIO,
   464  			AICBI,
   465  			AISYNC,
   466  			ATLBIE,
   467  			ATLBIEL,
   468  			ASLBIA,
   469  			ASLBIE,
   470  			ASLBMFEE,
   471  			ASLBMFEV,
   472  			ASLBMTE,
   473  			ADCBF,
   474  			ADCBI,
   475  			ADCBST,
   476  			ADCBT,
   477  			ADCBTST,
   478  			ADCBZ,
   479  			ASYNC,
   480  			ATLBSYNC,
   481  			APTESYNC,
   482  			ALWSYNC,
   483  			ATW,
   484  			AWORD,
   485  			ARFI,
   486  			ARFCI,
   487  			ARFID,
   488  			AHRFID:
   489  			q = p
   490  			p.Mark |= LABEL | SYNC
   491  			continue
   492  
   493  		case AMOVW, AMOVWZ, AMOVD:
   494  			q = p
   495  			if p.From.Reg >= REG_SPECIAL || p.To.Reg >= REG_SPECIAL {
   496  				p.Mark |= LABEL | SYNC
   497  			}
   498  			continue
   499  
   500  		case AFABS,
   501  			AFABSCC,
   502  			AFADD,
   503  			AFADDCC,
   504  			AFCTIW,
   505  			AFCTIWCC,
   506  			AFCTIWZ,
   507  			AFCTIWZCC,
   508  			AFDIV,
   509  			AFDIVCC,
   510  			AFMADD,
   511  			AFMADDCC,
   512  			AFMOVD,
   513  			AFMOVDU,
   514  			/* case AFMOVDS: */
   515  			AFMOVS,
   516  			AFMOVSU,
   517  
   518  			/* case AFMOVSD: */
   519  			AFMSUB,
   520  			AFMSUBCC,
   521  			AFMUL,
   522  			AFMULCC,
   523  			AFNABS,
   524  			AFNABSCC,
   525  			AFNEG,
   526  			AFNEGCC,
   527  			AFNMADD,
   528  			AFNMADDCC,
   529  			AFNMSUB,
   530  			AFNMSUBCC,
   531  			AFRSP,
   532  			AFRSPCC,
   533  			AFSUB,
   534  			AFSUBCC:
   535  			q = p
   536  
   537  			p.Mark |= FLOAT
   538  			continue
   539  
   540  		case ABL,
   541  			ABCL,
   542  			obj.ADUFFZERO,
   543  			obj.ADUFFCOPY:
   544  			c.cursym.Func.Text.Mark &^= LEAF
   545  			fallthrough
   546  
   547  		case ABC,
   548  			ABEQ,
   549  			ABGE,
   550  			ABGT,
   551  			ABLE,
   552  			ABLT,
   553  			ABNE,
   554  			ABR,
   555  			ABVC,
   556  			ABVS:
   557  			p.Mark |= BRANCH
   558  			q = p
   559  			q1 = p.To.Target()
   560  			if q1 != nil {
   561  				// NOPs are not removed due to #40689.
   562  
   563  				if q1.Mark&LEAF == 0 {
   564  					q1.Mark |= LABEL
   565  				}
   566  			} else {
   567  				p.Mark |= LABEL
   568  			}
   569  			q1 = p.Link
   570  			if q1 != nil {
   571  				q1.Mark |= LABEL
   572  			}
   573  			continue
   574  
   575  		case AFCMPO, AFCMPU:
   576  			q = p
   577  			p.Mark |= FCMP | FLOAT
   578  			continue
   579  
   580  		case obj.ARET:
   581  			q = p
   582  			if p.Link != nil {
   583  				p.Link.Mark |= LABEL
   584  			}
   585  			continue
   586  
   587  		case obj.ANOP:
   588  			// NOPs are not removed due to
   589  			// #40689
   590  			continue
   591  
   592  		default:
   593  			q = p
   594  			continue
   595  		}
   596  	}
   597  
   598  	autosize := int32(0)
   599  	var p1 *obj.Prog
   600  	var p2 *obj.Prog
   601  	for p := c.cursym.Func.Text; p != nil; p = p.Link {
   602  		o := p.As
   603  		switch o {
   604  		case obj.ATEXT:
   605  			autosize = int32(textstksiz)
   606  
   607  			if p.Mark&LEAF != 0 && autosize == 0 {
   608  				// A leaf function with no locals has no frame.
   609  				p.From.Sym.Set(obj.AttrNoFrame, true)
   610  			}
   611  
   612  			if !p.From.Sym.NoFrame() {
   613  				// If there is a stack frame at all, it includes
   614  				// space to save the LR.
   615  				autosize += int32(c.ctxt.FixedFrameSize())
   616  			}
   617  
   618  			if p.Mark&LEAF != 0 && autosize < objabi.StackSmall {
   619  				// A leaf function with a small stack can be marked
   620  				// NOSPLIT, avoiding a stack check.
   621  				p.From.Sym.Set(obj.AttrNoSplit, true)
   622  			}
   623  
   624  			p.To.Offset = int64(autosize)
   625  
   626  			q = p
   627  
   628  			if c.ctxt.Flag_shared && c.cursym.Name != "runtime.duffzero" && c.cursym.Name != "runtime.duffcopy" {
   629  				// When compiling Go into PIC, all functions must start
   630  				// with instructions to load the TOC pointer into r2:
   631  				//
   632  				//	addis r2, r12, .TOC.-func@ha
   633  				//	addi r2, r2, .TOC.-func@l+4
   634  				//
   635  				// We could probably skip this prologue in some situations
   636  				// but it's a bit subtle. However, it is both safe and
   637  				// necessary to leave the prologue off duffzero and
   638  				// duffcopy as we rely on being able to jump to a specific
   639  				// instruction offset for them.
   640  				//
   641  				// These are AWORDS because there is no (afaict) way to
   642  				// generate the addis instruction except as part of the
   643  				// load of a large constant, and in that case there is no
   644  				// way to use r12 as the source.
   645  				//
   646  				// Note that the same condition is tested in
   647  				// putelfsym in cmd/link/internal/ld/symtab.go
   648  				// where we set the st_other field to indicate
   649  				// the presence of these instructions.
   650  				q = obj.Appendp(q, c.newprog)
   651  				q.As = AWORD
   652  				q.Pos = p.Pos
   653  				q.From.Type = obj.TYPE_CONST
   654  				q.From.Offset = 0x3c4c0000
   655  				q = obj.Appendp(q, c.newprog)
   656  				q.As = AWORD
   657  				q.Pos = p.Pos
   658  				q.From.Type = obj.TYPE_CONST
   659  				q.From.Offset = 0x38420000
   660  				rel := obj.Addrel(c.cursym)
   661  				rel.Off = 0
   662  				rel.Siz = 8
   663  				rel.Sym = c.ctxt.Lookup(".TOC.")
   664  				rel.Type = objabi.R_ADDRPOWER_PCREL
   665  			}
   666  
   667  			if !c.cursym.Func.Text.From.Sym.NoSplit() {
   668  				q = c.stacksplit(q, autosize) // emit split check
   669  			}
   670  
   671  			// Special handling of the racecall thunk. Assume that its asm code will
   672  			// save the link register and update the stack, since that code is
   673  			// called directly from C/C++ and can't clobber REGTMP (R31).
   674  			if autosize != 0 && c.cursym.Name != "runtime.racecallbackthunk" {
   675  				// Save the link register and update the SP.  MOVDU is used unless
   676  				// the frame size is too large.  The link register must be saved
   677  				// even for non-empty leaf functions so that traceback works.
   678  				if autosize >= -BIG && autosize <= BIG {
   679  					// Use MOVDU to adjust R1 when saving R31, if autosize is small.
   680  					q = obj.Appendp(q, c.newprog)
   681  					q.As = AMOVD
   682  					q.Pos = p.Pos
   683  					q.From.Type = obj.TYPE_REG
   684  					q.From.Reg = REG_LR
   685  					q.To.Type = obj.TYPE_REG
   686  					q.To.Reg = REGTMP
   687  
   688  					q = obj.Appendp(q, c.newprog)
   689  					q.As = AMOVDU
   690  					q.Pos = p.Pos
   691  					q.From.Type = obj.TYPE_REG
   692  					q.From.Reg = REGTMP
   693  					q.To.Type = obj.TYPE_MEM
   694  					q.To.Offset = int64(-autosize)
   695  					q.To.Reg = REGSP
   696  					q.Spadj = autosize
   697  				} else {
   698  					// Frame size is too large for a MOVDU instruction.
   699  					// Store link register before decrementing SP, so if a signal comes
   700  					// during the execution of the function prologue, the traceback
   701  					// code will not see a half-updated stack frame.
   702  					// This sequence is not async preemptible, as if we open a frame
   703  					// at the current SP, it will clobber the saved LR.
   704  					q = obj.Appendp(q, c.newprog)
   705  					q.As = AMOVD
   706  					q.Pos = p.Pos
   707  					q.From.Type = obj.TYPE_REG
   708  					q.From.Reg = REG_LR
   709  					q.To.Type = obj.TYPE_REG
   710  					q.To.Reg = REG_R29 // REGTMP may be used to synthesize large offset in the next instruction
   711  
   712  					q = c.ctxt.StartUnsafePoint(q, c.newprog)
   713  
   714  					q = obj.Appendp(q, c.newprog)
   715  					q.As = AMOVD
   716  					q.Pos = p.Pos
   717  					q.From.Type = obj.TYPE_REG
   718  					q.From.Reg = REG_R29
   719  					q.To.Type = obj.TYPE_MEM
   720  					q.To.Offset = int64(-autosize)
   721  					q.To.Reg = REGSP
   722  
   723  					q = obj.Appendp(q, c.newprog)
   724  					q.As = AADD
   725  					q.Pos = p.Pos
   726  					q.From.Type = obj.TYPE_CONST
   727  					q.From.Offset = int64(-autosize)
   728  					q.To.Type = obj.TYPE_REG
   729  					q.To.Reg = REGSP
   730  					q.Spadj = +autosize
   731  
   732  					q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
   733  
   734  				}
   735  			} else if c.cursym.Func.Text.Mark&LEAF == 0 {
   736  				// A very few functions that do not return to their caller
   737  				// (e.g. gogo) are not identified as leaves but still have
   738  				// no frame.
   739  				c.cursym.Func.Text.Mark |= LEAF
   740  			}
   741  
   742  			if c.cursym.Func.Text.Mark&LEAF != 0 {
   743  				c.cursym.Set(obj.AttrLeaf, true)
   744  				break
   745  			}
   746  
   747  			if c.ctxt.Flag_shared {
   748  				q = obj.Appendp(q, c.newprog)
   749  				q.As = AMOVD
   750  				q.Pos = p.Pos
   751  				q.From.Type = obj.TYPE_REG
   752  				q.From.Reg = REG_R2
   753  				q.To.Type = obj.TYPE_MEM
   754  				q.To.Reg = REGSP
   755  				q.To.Offset = 24
   756  			}
   757  
   758  			if c.cursym.Func.Text.From.Sym.Wrapper() {
   759  				// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
   760  				//
   761  				//	MOVD g_panic(g), R3
   762  				//	CMP R0, R3
   763  				//	BEQ end
   764  				//	MOVD panic_argp(R3), R4
   765  				//	ADD $(autosize+8), R1, R5
   766  				//	CMP R4, R5
   767  				//	BNE end
   768  				//	ADD $8, R1, R6
   769  				//	MOVD R6, panic_argp(R3)
   770  				// end:
   771  				//	NOP
   772  				//
   773  				// The NOP is needed to give the jumps somewhere to land.
   774  				// It is a liblink NOP, not a ppc64 NOP: it encodes to 0 instruction bytes.
   775  
   776  				q = obj.Appendp(q, c.newprog)
   777  
   778  				q.As = AMOVD
   779  				q.From.Type = obj.TYPE_MEM
   780  				q.From.Reg = REGG
   781  				q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic
   782  				q.To.Type = obj.TYPE_REG
   783  				q.To.Reg = REG_R3
   784  
   785  				q = obj.Appendp(q, c.newprog)
   786  				q.As = ACMP
   787  				q.From.Type = obj.TYPE_REG
   788  				q.From.Reg = REG_R0
   789  				q.To.Type = obj.TYPE_REG
   790  				q.To.Reg = REG_R3
   791  
   792  				q = obj.Appendp(q, c.newprog)
   793  				q.As = ABEQ
   794  				q.To.Type = obj.TYPE_BRANCH
   795  				p1 = q
   796  
   797  				q = obj.Appendp(q, c.newprog)
   798  				q.As = AMOVD
   799  				q.From.Type = obj.TYPE_MEM
   800  				q.From.Reg = REG_R3
   801  				q.From.Offset = 0 // Panic.argp
   802  				q.To.Type = obj.TYPE_REG
   803  				q.To.Reg = REG_R4
   804  
   805  				q = obj.Appendp(q, c.newprog)
   806  				q.As = AADD
   807  				q.From.Type = obj.TYPE_CONST
   808  				q.From.Offset = int64(autosize) + c.ctxt.FixedFrameSize()
   809  				q.Reg = REGSP
   810  				q.To.Type = obj.TYPE_REG
   811  				q.To.Reg = REG_R5
   812  
   813  				q = obj.Appendp(q, c.newprog)
   814  				q.As = ACMP
   815  				q.From.Type = obj.TYPE_REG
   816  				q.From.Reg = REG_R4
   817  				q.To.Type = obj.TYPE_REG
   818  				q.To.Reg = REG_R5
   819  
   820  				q = obj.Appendp(q, c.newprog)
   821  				q.As = ABNE
   822  				q.To.Type = obj.TYPE_BRANCH
   823  				p2 = q
   824  
   825  				q = obj.Appendp(q, c.newprog)
   826  				q.As = AADD
   827  				q.From.Type = obj.TYPE_CONST
   828  				q.From.Offset = c.ctxt.FixedFrameSize()
   829  				q.Reg = REGSP
   830  				q.To.Type = obj.TYPE_REG
   831  				q.To.Reg = REG_R6
   832  
   833  				q = obj.Appendp(q, c.newprog)
   834  				q.As = AMOVD
   835  				q.From.Type = obj.TYPE_REG
   836  				q.From.Reg = REG_R6
   837  				q.To.Type = obj.TYPE_MEM
   838  				q.To.Reg = REG_R3
   839  				q.To.Offset = 0 // Panic.argp
   840  
   841  				q = obj.Appendp(q, c.newprog)
   842  
   843  				q.As = obj.ANOP
   844  				p1.To.SetTarget(q)
   845  				p2.To.SetTarget(q)
   846  			}
   847  
   848  		case obj.ARET:
   849  			if p.From.Type == obj.TYPE_CONST {
   850  				c.ctxt.Diag("using BECOME (%v) is not supported!", p)
   851  				break
   852  			}
   853  
   854  			retTarget := p.To.Sym
   855  
   856  			if c.cursym.Func.Text.Mark&LEAF != 0 {
   857  				if autosize == 0 || c.cursym.Name == "runtime.racecallbackthunk" {
   858  					p.As = ABR
   859  					p.From = obj.Addr{}
   860  					if retTarget == nil {
   861  						p.To.Type = obj.TYPE_REG
   862  						p.To.Reg = REG_LR
   863  					} else {
   864  						p.To.Type = obj.TYPE_BRANCH
   865  						p.To.Sym = retTarget
   866  					}
   867  					p.Mark |= BRANCH
   868  					break
   869  				}
   870  
   871  				p.As = AADD
   872  				p.From.Type = obj.TYPE_CONST
   873  				p.From.Offset = int64(autosize)
   874  				p.To.Type = obj.TYPE_REG
   875  				p.To.Reg = REGSP
   876  				p.Spadj = -autosize
   877  
   878  				q = c.newprog()
   879  				q.As = ABR
   880  				q.Pos = p.Pos
   881  				q.To.Type = obj.TYPE_REG
   882  				q.To.Reg = REG_LR
   883  				q.Mark |= BRANCH
   884  				q.Spadj = +autosize
   885  
   886  				q.Link = p.Link
   887  				p.Link = q
   888  				break
   889  			}
   890  
   891  			p.As = AMOVD
   892  			p.From.Type = obj.TYPE_MEM
   893  			p.From.Offset = 0
   894  			p.From.Reg = REGSP
   895  			p.To.Type = obj.TYPE_REG
   896  			p.To.Reg = REGTMP
   897  
   898  			q = c.newprog()
   899  			q.As = AMOVD
   900  			q.Pos = p.Pos
   901  			q.From.Type = obj.TYPE_REG
   902  			q.From.Reg = REGTMP
   903  			q.To.Type = obj.TYPE_REG
   904  			q.To.Reg = REG_LR
   905  
   906  			q.Link = p.Link
   907  			p.Link = q
   908  			p = q
   909  
   910  			if false {
   911  				// Debug bad returns
   912  				q = c.newprog()
   913  
   914  				q.As = AMOVD
   915  				q.Pos = p.Pos
   916  				q.From.Type = obj.TYPE_MEM
   917  				q.From.Offset = 0
   918  				q.From.Reg = REGTMP
   919  				q.To.Type = obj.TYPE_REG
   920  				q.To.Reg = REGTMP
   921  
   922  				q.Link = p.Link
   923  				p.Link = q
   924  				p = q
   925  			}
   926  			prev := p
   927  			if autosize != 0 && c.cursym.Name != "runtime.racecallbackthunk" {
   928  				q = c.newprog()
   929  				q.As = AADD
   930  				q.Pos = p.Pos
   931  				q.From.Type = obj.TYPE_CONST
   932  				q.From.Offset = int64(autosize)
   933  				q.To.Type = obj.TYPE_REG
   934  				q.To.Reg = REGSP
   935  				q.Spadj = -autosize
   936  
   937  				q.Link = p.Link
   938  				prev.Link = q
   939  				prev = q
   940  			}
   941  
   942  			q1 = c.newprog()
   943  			q1.As = ABR
   944  			q1.Pos = p.Pos
   945  			if retTarget == nil {
   946  				q1.To.Type = obj.TYPE_REG
   947  				q1.To.Reg = REG_LR
   948  			} else {
   949  				q1.To.Type = obj.TYPE_BRANCH
   950  				q1.To.Sym = retTarget
   951  			}
   952  			q1.Mark |= BRANCH
   953  			q1.Spadj = +autosize
   954  
   955  			q1.Link = q.Link
   956  			prev.Link = q1
   957  		case AADD:
   958  			if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
   959  				p.Spadj = int32(-p.From.Offset)
   960  			}
   961  		case AMOVDU:
   962  			if p.To.Type == obj.TYPE_MEM && p.To.Reg == REGSP {
   963  				p.Spadj = int32(-p.To.Offset)
   964  			}
   965  			if p.From.Type == obj.TYPE_MEM && p.From.Reg == REGSP {
   966  				p.Spadj = int32(-p.From.Offset)
   967  			}
   968  		case obj.AGETCALLERPC:
   969  			if cursym.Leaf() {
   970  				/* MOVD LR, Rd */
   971  				p.As = AMOVD
   972  				p.From.Type = obj.TYPE_REG
   973  				p.From.Reg = REG_LR
   974  			} else {
   975  				/* MOVD (RSP), Rd */
   976  				p.As = AMOVD
   977  				p.From.Type = obj.TYPE_MEM
   978  				p.From.Reg = REGSP
   979  			}
   980  		}
   981  	}
   982  }
   983  
   984  /*
   985  // instruction scheduling
   986  	if(debug['Q'] == 0)
   987  		return;
   988  
   989  	curtext = nil;
   990  	q = nil;	// p - 1
   991  	q1 = firstp;	// top of block
   992  	o = 0;		// count of instructions
   993  	for(p = firstp; p != nil; p = p1) {
   994  		p1 = p->link;
   995  		o++;
   996  		if(p->mark & NOSCHED){
   997  			if(q1 != p){
   998  				sched(q1, q);
   999  			}
  1000  			for(; p != nil; p = p->link){
  1001  				if(!(p->mark & NOSCHED))
  1002  					break;
  1003  				q = p;
  1004  			}
  1005  			p1 = p;
  1006  			q1 = p;
  1007  			o = 0;
  1008  			continue;
  1009  		}
  1010  		if(p->mark & (LABEL|SYNC)) {
  1011  			if(q1 != p)
  1012  				sched(q1, q);
  1013  			q1 = p;
  1014  			o = 1;
  1015  		}
  1016  		if(p->mark & (BRANCH|SYNC)) {
  1017  			sched(q1, p);
  1018  			q1 = p1;
  1019  			o = 0;
  1020  		}
  1021  		if(o >= NSCHED) {
  1022  			sched(q1, p);
  1023  			q1 = p1;
  1024  			o = 0;
  1025  		}
  1026  		q = p;
  1027  	}
  1028  */
  1029  func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
  1030  	p0 := p // save entry point, but skipping the two instructions setting R2 in shared mode
  1031  
  1032  	// MOVD	g_stackguard(g), R3
  1033  	p = obj.Appendp(p, c.newprog)
  1034  
  1035  	p.As = AMOVD
  1036  	p.From.Type = obj.TYPE_MEM
  1037  	p.From.Reg = REGG
  1038  	p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
  1039  	if c.cursym.CFunc() {
  1040  		p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
  1041  	}
  1042  	p.To.Type = obj.TYPE_REG
  1043  	p.To.Reg = REG_R3
  1044  
  1045  	// Mark the stack bound check and morestack call async nonpreemptible.
  1046  	// If we get preempted here, when resumed the preemption request is
  1047  	// cleared, but we'll still call morestack, which will double the stack
  1048  	// unnecessarily. See issue #35470.
  1049  	p = c.ctxt.StartUnsafePoint(p, c.newprog)
  1050  
  1051  	var q *obj.Prog
  1052  	if framesize <= objabi.StackSmall {
  1053  		// small stack: SP < stackguard
  1054  		//	CMP	stackguard, SP
  1055  		p = obj.Appendp(p, c.newprog)
  1056  
  1057  		p.As = ACMPU
  1058  		p.From.Type = obj.TYPE_REG
  1059  		p.From.Reg = REG_R3
  1060  		p.To.Type = obj.TYPE_REG
  1061  		p.To.Reg = REGSP
  1062  	} else if framesize <= objabi.StackBig {
  1063  		// large stack: SP-framesize < stackguard-StackSmall
  1064  		//	ADD $-(framesize-StackSmall), SP, R4
  1065  		//	CMP stackguard, R4
  1066  		p = obj.Appendp(p, c.newprog)
  1067  
  1068  		p.As = AADD
  1069  		p.From.Type = obj.TYPE_CONST
  1070  		p.From.Offset = -(int64(framesize) - objabi.StackSmall)
  1071  		p.Reg = REGSP
  1072  		p.To.Type = obj.TYPE_REG
  1073  		p.To.Reg = REG_R4
  1074  
  1075  		p = obj.Appendp(p, c.newprog)
  1076  		p.As = ACMPU
  1077  		p.From.Type = obj.TYPE_REG
  1078  		p.From.Reg = REG_R3
  1079  		p.To.Type = obj.TYPE_REG
  1080  		p.To.Reg = REG_R4
  1081  	} else {
  1082  		// Such a large stack we need to protect against wraparound.
  1083  		// If SP is close to zero:
  1084  		//	SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
  1085  		// The +StackGuard on both sides is required to keep the left side positive:
  1086  		// SP is allowed to be slightly below stackguard. See stack.h.
  1087  		//
  1088  		// Preemption sets stackguard to StackPreempt, a very large value.
  1089  		// That breaks the math above, so we have to check for that explicitly.
  1090  		//	// stackguard is R3
  1091  		//	CMP	R3, $StackPreempt
  1092  		//	BEQ	label-of-call-to-morestack
  1093  		//	ADD	$StackGuard, SP, R4
  1094  		//	SUB	R3, R4
  1095  		//	MOVD	$(framesize+(StackGuard-StackSmall)), R31
  1096  		//	CMPU	R31, R4
  1097  		p = obj.Appendp(p, c.newprog)
  1098  
  1099  		p.As = ACMP
  1100  		p.From.Type = obj.TYPE_REG
  1101  		p.From.Reg = REG_R3
  1102  		p.To.Type = obj.TYPE_CONST
  1103  		p.To.Offset = objabi.StackPreempt
  1104  
  1105  		p = obj.Appendp(p, c.newprog)
  1106  		q = p
  1107  		p.As = ABEQ
  1108  		p.To.Type = obj.TYPE_BRANCH
  1109  
  1110  		p = obj.Appendp(p, c.newprog)
  1111  		p.As = AADD
  1112  		p.From.Type = obj.TYPE_CONST
  1113  		p.From.Offset = int64(objabi.StackGuard)
  1114  		p.Reg = REGSP
  1115  		p.To.Type = obj.TYPE_REG
  1116  		p.To.Reg = REG_R4
  1117  
  1118  		p = obj.Appendp(p, c.newprog)
  1119  		p.As = ASUB
  1120  		p.From.Type = obj.TYPE_REG
  1121  		p.From.Reg = REG_R3
  1122  		p.To.Type = obj.TYPE_REG
  1123  		p.To.Reg = REG_R4
  1124  
  1125  		p = obj.Appendp(p, c.newprog)
  1126  		p.As = AMOVD
  1127  		p.From.Type = obj.TYPE_CONST
  1128  		p.From.Offset = int64(framesize) + int64(objabi.StackGuard) - objabi.StackSmall
  1129  		p.To.Type = obj.TYPE_REG
  1130  		p.To.Reg = REGTMP
  1131  
  1132  		p = obj.Appendp(p, c.newprog)
  1133  		p.As = ACMPU
  1134  		p.From.Type = obj.TYPE_REG
  1135  		p.From.Reg = REGTMP
  1136  		p.To.Type = obj.TYPE_REG
  1137  		p.To.Reg = REG_R4
  1138  	}
  1139  
  1140  	// q1: BLT	done
  1141  	p = obj.Appendp(p, c.newprog)
  1142  	q1 := p
  1143  
  1144  	p.As = ABLT
  1145  	p.To.Type = obj.TYPE_BRANCH
  1146  
  1147  	// MOVD	LR, R5
  1148  	p = obj.Appendp(p, c.newprog)
  1149  
  1150  	p.As = AMOVD
  1151  	p.From.Type = obj.TYPE_REG
  1152  	p.From.Reg = REG_LR
  1153  	p.To.Type = obj.TYPE_REG
  1154  	p.To.Reg = REG_R5
  1155  	if q != nil {
  1156  		q.To.SetTarget(p)
  1157  	}
  1158  
  1159  	p = c.ctxt.EmitEntryStackMap(c.cursym, p, c.newprog)
  1160  
  1161  	var morestacksym *obj.LSym
  1162  	if c.cursym.CFunc() {
  1163  		morestacksym = c.ctxt.Lookup("runtime.morestackc")
  1164  	} else if !c.cursym.Func.Text.From.Sym.NeedCtxt() {
  1165  		morestacksym = c.ctxt.Lookup("runtime.morestack_noctxt")
  1166  	} else {
  1167  		morestacksym = c.ctxt.Lookup("runtime.morestack")
  1168  	}
  1169  
  1170  	if c.ctxt.Flag_shared {
  1171  		// In PPC64 PIC code, R2 is used as TOC pointer derived from R12
  1172  		// which is the address of function entry point when entering
  1173  		// the function. We need to preserve R2 across call to morestack.
  1174  		// Fortunately, in shared mode, 8(SP) and 16(SP) are reserved in
  1175  		// the caller's frame, but not used (0(SP) is caller's saved LR,
  1176  		// 24(SP) is caller's saved R2). Use 8(SP) to save this function's R2.
  1177  
  1178  		// MOVD R12, 8(SP)
  1179  		p = obj.Appendp(p, c.newprog)
  1180  		p.As = AMOVD
  1181  		p.From.Type = obj.TYPE_REG
  1182  		p.From.Reg = REG_R2
  1183  		p.To.Type = obj.TYPE_MEM
  1184  		p.To.Reg = REGSP
  1185  		p.To.Offset = 8
  1186  	}
  1187  
  1188  	if c.ctxt.Flag_dynlink {
  1189  		// Avoid calling morestack via a PLT when dynamically linking. The
  1190  		// PLT stubs generated by the system linker on ppc64le when "std r2,
  1191  		// 24(r1)" to save the TOC pointer in their callers stack
  1192  		// frame. Unfortunately (and necessarily) morestack is called before
  1193  		// the function that calls it sets up its frame and so the PLT ends
  1194  		// up smashing the saved TOC pointer for its caller's caller.
  1195  		//
  1196  		// According to the ABI documentation there is a mechanism to avoid
  1197  		// the TOC save that the PLT stub does (put a R_PPC64_TOCSAVE
  1198  		// relocation on the nop after the call to morestack) but at the time
  1199  		// of writing it is not supported at all by gold and my attempt to
  1200  		// use it with ld.bfd caused an internal linker error. So this hack
  1201  		// seems preferable.
  1202  
  1203  		// MOVD $runtime.morestack(SB), R12
  1204  		p = obj.Appendp(p, c.newprog)
  1205  		p.As = AMOVD
  1206  		p.From.Type = obj.TYPE_MEM
  1207  		p.From.Sym = morestacksym
  1208  		p.From.Name = obj.NAME_GOTREF
  1209  		p.To.Type = obj.TYPE_REG
  1210  		p.To.Reg = REG_R12
  1211  
  1212  		// MOVD R12, LR
  1213  		p = obj.Appendp(p, c.newprog)
  1214  		p.As = AMOVD
  1215  		p.From.Type = obj.TYPE_REG
  1216  		p.From.Reg = REG_R12
  1217  		p.To.Type = obj.TYPE_REG
  1218  		p.To.Reg = REG_LR
  1219  
  1220  		// BL LR
  1221  		p = obj.Appendp(p, c.newprog)
  1222  		p.As = obj.ACALL
  1223  		p.To.Type = obj.TYPE_REG
  1224  		p.To.Reg = REG_LR
  1225  	} else {
  1226  		// BL	runtime.morestack(SB)
  1227  		p = obj.Appendp(p, c.newprog)
  1228  
  1229  		p.As = ABL
  1230  		p.To.Type = obj.TYPE_BRANCH
  1231  		p.To.Sym = morestacksym
  1232  	}
  1233  
  1234  	if c.ctxt.Flag_shared {
  1235  		// MOVD 8(SP), R2
  1236  		p = obj.Appendp(p, c.newprog)
  1237  		p.As = AMOVD
  1238  		p.From.Type = obj.TYPE_MEM
  1239  		p.From.Reg = REGSP
  1240  		p.From.Offset = 8
  1241  		p.To.Type = obj.TYPE_REG
  1242  		p.To.Reg = REG_R2
  1243  	}
  1244  
  1245  	p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
  1246  
  1247  	// BR	start
  1248  	p = obj.Appendp(p, c.newprog)
  1249  	p.As = ABR
  1250  	p.To.Type = obj.TYPE_BRANCH
  1251  	p.To.SetTarget(p0.Link)
  1252  
  1253  	// placeholder for q1's jump target
  1254  	p = obj.Appendp(p, c.newprog)
  1255  
  1256  	p.As = obj.ANOP // zero-width place holder
  1257  	q1.To.SetTarget(p)
  1258  
  1259  	return p
  1260  }
  1261  
  1262  var Linkppc64 = obj.LinkArch{
  1263  	Arch:           sys.ArchPPC64,
  1264  	Init:           buildop,
  1265  	Preprocess:     preprocess,
  1266  	Assemble:       span9,
  1267  	Progedit:       progedit,
  1268  	DWARFRegisters: PPC64DWARFRegisters,
  1269  }
  1270  
  1271  var Linkppc64le = obj.LinkArch{
  1272  	Arch:           sys.ArchPPC64LE,
  1273  	Init:           buildop,
  1274  	Preprocess:     preprocess,
  1275  	Assemble:       span9,
  1276  	Progedit:       progedit,
  1277  	DWARFRegisters: PPC64DWARFRegisters,
  1278  }
  1279  

View as plain text