Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/internal/obj/ppc64/obj9.go

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

View as plain text