github.com/zxy12/go_duplicate_1_12@v0.0.0-20200217043740-b1636fc0368b/src/cmd/internal/obj/x86/obj6.go (about)

     1  // Inferno utils/6l/pass.c
     2  // https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/pass.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 x86
    32  
    33  import (
    34  	"cmd/internal/obj"
    35  	"cmd/internal/objabi"
    36  	"cmd/internal/src"
    37  	"cmd/internal/sys"
    38  	"math"
    39  	"strings"
    40  )
    41  
    42  func CanUse1InsnTLS(ctxt *obj.Link) bool {
    43  	if isAndroid {
    44  		// For android, we use a disgusting hack that assumes
    45  		// the thread-local storage slot for g is allocated
    46  		// using pthread_key_create with a fixed offset
    47  		// (see src/runtime/cgo/gcc_android_amd64.c).
    48  		// This makes access to the TLS storage (for g) doable
    49  		// with 1 instruction.
    50  		return true
    51  	}
    52  
    53  	if ctxt.Arch.Family == sys.I386 {
    54  		switch ctxt.Headtype {
    55  		case objabi.Hlinux,
    56  			objabi.Hnacl,
    57  			objabi.Hplan9,
    58  			objabi.Hwindows:
    59  			return false
    60  		}
    61  
    62  		return true
    63  	}
    64  
    65  	switch ctxt.Headtype {
    66  	case objabi.Hplan9, objabi.Hwindows:
    67  		return false
    68  	case objabi.Hlinux, objabi.Hfreebsd:
    69  		return !ctxt.Flag_shared
    70  	}
    71  
    72  	return true
    73  }
    74  
    75  func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
    76  	// Thread-local storage references use the TLS pseudo-register.
    77  	// As a register, TLS refers to the thread-local storage base, and it
    78  	// can only be loaded into another register:
    79  	//
    80  	//         MOVQ TLS, AX
    81  	//
    82  	// An offset from the thread-local storage base is written off(reg)(TLS*1).
    83  	// Semantically it is off(reg), but the (TLS*1) annotation marks this as
    84  	// indexing from the loaded TLS base. This emits a relocation so that
    85  	// if the linker needs to adjust the offset, it can. For example:
    86  	//
    87  	//         MOVQ TLS, AX
    88  	//         MOVQ 0(AX)(TLS*1), CX // load g into CX
    89  	//
    90  	// On systems that support direct access to the TLS memory, this
    91  	// pair of instructions can be reduced to a direct TLS memory reference:
    92  	//
    93  	//         MOVQ 0(TLS), CX // load g into CX
    94  	//
    95  	// The 2-instruction and 1-instruction forms correspond to the two code
    96  	// sequences for loading a TLS variable in the local exec model given in "ELF
    97  	// Handling For Thread-Local Storage".
    98  	//
    99  	// We apply this rewrite on systems that support the 1-instruction form.
   100  	// The decision is made using only the operating system and the -shared flag,
   101  	// not the link mode. If some link modes on a particular operating system
   102  	// require the 2-instruction form, then all builds for that operating system
   103  	// will use the 2-instruction form, so that the link mode decision can be
   104  	// delayed to link time.
   105  	//
   106  	// In this way, all supported systems use identical instructions to
   107  	// access TLS, and they are rewritten appropriately first here in
   108  	// liblink and then finally using relocations in the linker.
   109  	//
   110  	// When -shared is passed, we leave the code in the 2-instruction form but
   111  	// assemble (and relocate) them in different ways to generate the initial
   112  	// exec code sequence. It's a bit of a fluke that this is possible without
   113  	// rewriting the instructions more comprehensively, and it only does because
   114  	// we only support a single TLS variable (g).
   115  
   116  	if CanUse1InsnTLS(ctxt) {
   117  		// Reduce 2-instruction sequence to 1-instruction sequence.
   118  		// Sequences like
   119  		//	MOVQ TLS, BX
   120  		//	... off(BX)(TLS*1) ...
   121  		// become
   122  		//	NOP
   123  		//	... off(TLS) ...
   124  		//
   125  		// TODO(rsc): Remove the Hsolaris special case. It exists only to
   126  		// guarantee we are producing byte-identical binaries as before this code.
   127  		// But it should be unnecessary.
   128  		if (p.As == AMOVQ || p.As == AMOVL) && p.From.Type == obj.TYPE_REG && p.From.Reg == REG_TLS && p.To.Type == obj.TYPE_REG && REG_AX <= p.To.Reg && p.To.Reg <= REG_R15 && ctxt.Headtype != objabi.Hsolaris {
   129  			obj.Nopout(p)
   130  		}
   131  		if p.From.Type == obj.TYPE_MEM && p.From.Index == REG_TLS && REG_AX <= p.From.Reg && p.From.Reg <= REG_R15 {
   132  			p.From.Reg = REG_TLS
   133  			p.From.Scale = 0
   134  			p.From.Index = REG_NONE
   135  		}
   136  
   137  		if p.To.Type == obj.TYPE_MEM && p.To.Index == REG_TLS && REG_AX <= p.To.Reg && p.To.Reg <= REG_R15 {
   138  			p.To.Reg = REG_TLS
   139  			p.To.Scale = 0
   140  			p.To.Index = REG_NONE
   141  		}
   142  	} else {
   143  		// load_g_cx, below, always inserts the 1-instruction sequence. Rewrite it
   144  		// as the 2-instruction sequence if necessary.
   145  		//	MOVQ 0(TLS), BX
   146  		// becomes
   147  		//	MOVQ TLS, BX
   148  		//	MOVQ 0(BX)(TLS*1), BX
   149  		if (p.As == AMOVQ || p.As == AMOVL) && p.From.Type == obj.TYPE_MEM && p.From.Reg == REG_TLS && p.To.Type == obj.TYPE_REG && REG_AX <= p.To.Reg && p.To.Reg <= REG_R15 {
   150  			q := obj.Appendp(p, newprog)
   151  			q.As = p.As
   152  			q.From = p.From
   153  			q.From.Type = obj.TYPE_MEM
   154  			q.From.Reg = p.To.Reg
   155  			q.From.Index = REG_TLS
   156  			q.From.Scale = 2 // TODO: use 1
   157  			q.To = p.To
   158  			p.From.Type = obj.TYPE_REG
   159  			p.From.Reg = REG_TLS
   160  			p.From.Index = REG_NONE
   161  			p.From.Offset = 0
   162  		}
   163  	}
   164  
   165  	// TODO: Remove.
   166  	if ctxt.Headtype == objabi.Hwindows && ctxt.Arch.Family == sys.AMD64 || ctxt.Headtype == objabi.Hplan9 {
   167  		if p.From.Scale == 1 && p.From.Index == REG_TLS {
   168  			p.From.Scale = 2
   169  		}
   170  		if p.To.Scale == 1 && p.To.Index == REG_TLS {
   171  			p.To.Scale = 2
   172  		}
   173  	}
   174  
   175  	// Rewrite 0 to $0 in 3rd argument to CMPPS etc.
   176  	// That's what the tables expect.
   177  	switch p.As {
   178  	case ACMPPD, ACMPPS, ACMPSD, ACMPSS:
   179  		if p.To.Type == obj.TYPE_MEM && p.To.Name == obj.NAME_NONE && p.To.Reg == REG_NONE && p.To.Index == REG_NONE && p.To.Sym == nil {
   180  			p.To.Type = obj.TYPE_CONST
   181  		}
   182  	}
   183  
   184  	// Rewrite CALL/JMP/RET to symbol as TYPE_BRANCH.
   185  	switch p.As {
   186  	case obj.ACALL, obj.AJMP, obj.ARET:
   187  		if p.To.Type == obj.TYPE_MEM && (p.To.Name == obj.NAME_EXTERN || p.To.Name == obj.NAME_STATIC) && p.To.Sym != nil {
   188  			p.To.Type = obj.TYPE_BRANCH
   189  		}
   190  	}
   191  
   192  	// Rewrite MOVL/MOVQ $XXX(FP/SP) as LEAL/LEAQ.
   193  	if p.From.Type == obj.TYPE_ADDR && (ctxt.Arch.Family == sys.AMD64 || p.From.Name != obj.NAME_EXTERN && p.From.Name != obj.NAME_STATIC) {
   194  		switch p.As {
   195  		case AMOVL:
   196  			p.As = ALEAL
   197  			p.From.Type = obj.TYPE_MEM
   198  		case AMOVQ:
   199  			p.As = ALEAQ
   200  			p.From.Type = obj.TYPE_MEM
   201  		}
   202  	}
   203  
   204  	if ctxt.Headtype == objabi.Hnacl && ctxt.Arch.Family == sys.AMD64 {
   205  		if p.GetFrom3() != nil {
   206  			nacladdr(ctxt, p, p.GetFrom3())
   207  		}
   208  		nacladdr(ctxt, p, &p.From)
   209  		nacladdr(ctxt, p, &p.To)
   210  	}
   211  
   212  	// Rewrite float constants to values stored in memory.
   213  	switch p.As {
   214  	// Convert AMOVSS $(0), Xx to AXORPS Xx, Xx
   215  	case AMOVSS:
   216  		if p.From.Type == obj.TYPE_FCONST {
   217  			//  f == 0 can't be used here due to -0, so use Float64bits
   218  			if f := p.From.Val.(float64); math.Float64bits(f) == 0 {
   219  				if p.To.Type == obj.TYPE_REG && REG_X0 <= p.To.Reg && p.To.Reg <= REG_X15 {
   220  					p.As = AXORPS
   221  					p.From = p.To
   222  					break
   223  				}
   224  			}
   225  		}
   226  		fallthrough
   227  
   228  	case AFMOVF,
   229  		AFADDF,
   230  		AFSUBF,
   231  		AFSUBRF,
   232  		AFMULF,
   233  		AFDIVF,
   234  		AFDIVRF,
   235  		AFCOMF,
   236  		AFCOMFP,
   237  		AADDSS,
   238  		ASUBSS,
   239  		AMULSS,
   240  		ADIVSS,
   241  		ACOMISS,
   242  		AUCOMISS:
   243  		if p.From.Type == obj.TYPE_FCONST {
   244  			f32 := float32(p.From.Val.(float64))
   245  			p.From.Type = obj.TYPE_MEM
   246  			p.From.Name = obj.NAME_EXTERN
   247  			p.From.Sym = ctxt.Float32Sym(f32)
   248  			p.From.Offset = 0
   249  		}
   250  
   251  	case AMOVSD:
   252  		// Convert AMOVSD $(0), Xx to AXORPS Xx, Xx
   253  		if p.From.Type == obj.TYPE_FCONST {
   254  			//  f == 0 can't be used here due to -0, so use Float64bits
   255  			if f := p.From.Val.(float64); math.Float64bits(f) == 0 {
   256  				if p.To.Type == obj.TYPE_REG && REG_X0 <= p.To.Reg && p.To.Reg <= REG_X15 {
   257  					p.As = AXORPS
   258  					p.From = p.To
   259  					break
   260  				}
   261  			}
   262  		}
   263  		fallthrough
   264  
   265  	case AFMOVD,
   266  		AFADDD,
   267  		AFSUBD,
   268  		AFSUBRD,
   269  		AFMULD,
   270  		AFDIVD,
   271  		AFDIVRD,
   272  		AFCOMD,
   273  		AFCOMDP,
   274  		AADDSD,
   275  		ASUBSD,
   276  		AMULSD,
   277  		ADIVSD,
   278  		ACOMISD,
   279  		AUCOMISD:
   280  		if p.From.Type == obj.TYPE_FCONST {
   281  			f64 := p.From.Val.(float64)
   282  			p.From.Type = obj.TYPE_MEM
   283  			p.From.Name = obj.NAME_EXTERN
   284  			p.From.Sym = ctxt.Float64Sym(f64)
   285  			p.From.Offset = 0
   286  		}
   287  	}
   288  
   289  	if ctxt.Flag_dynlink {
   290  		rewriteToUseGot(ctxt, p, newprog)
   291  	}
   292  
   293  	if ctxt.Flag_shared && ctxt.Arch.Family == sys.I386 {
   294  		rewriteToPcrel(ctxt, p, newprog)
   295  	}
   296  }
   297  
   298  // Rewrite p, if necessary, to access global data via the global offset table.
   299  func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
   300  	var lea, mov obj.As
   301  	var reg int16
   302  	if ctxt.Arch.Family == sys.AMD64 {
   303  		lea = ALEAQ
   304  		mov = AMOVQ
   305  		reg = REG_R15
   306  	} else {
   307  		lea = ALEAL
   308  		mov = AMOVL
   309  		reg = REG_CX
   310  		if p.As == ALEAL && p.To.Reg != p.From.Reg && p.To.Reg != p.From.Index {
   311  			// Special case: clobber the destination register with
   312  			// the PC so we don't have to clobber CX.
   313  			// The SSA backend depends on CX not being clobbered across LEAL.
   314  			// See cmd/compile/internal/ssa/gen/386.rules (search for Flag_shared).
   315  			reg = p.To.Reg
   316  		}
   317  	}
   318  
   319  	if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
   320  		//     ADUFFxxx $offset
   321  		// becomes
   322  		//     $MOV runtime.duffxxx@GOT, $reg
   323  		//     $LEA $offset($reg), $reg
   324  		//     CALL $reg
   325  		// (we use LEAx rather than ADDx because ADDx clobbers
   326  		// flags and duffzero on 386 does not otherwise do so).
   327  		var sym *obj.LSym
   328  		if p.As == obj.ADUFFZERO {
   329  			sym = ctxt.Lookup("runtime.duffzero")
   330  		} else {
   331  			sym = ctxt.Lookup("runtime.duffcopy")
   332  		}
   333  		offset := p.To.Offset
   334  		p.As = mov
   335  		p.From.Type = obj.TYPE_MEM
   336  		p.From.Name = obj.NAME_GOTREF
   337  		p.From.Sym = sym
   338  		p.To.Type = obj.TYPE_REG
   339  		p.To.Reg = reg
   340  		p.To.Offset = 0
   341  		p.To.Sym = nil
   342  		p1 := obj.Appendp(p, newprog)
   343  		p1.As = lea
   344  		p1.From.Type = obj.TYPE_MEM
   345  		p1.From.Offset = offset
   346  		p1.From.Reg = reg
   347  		p1.To.Type = obj.TYPE_REG
   348  		p1.To.Reg = reg
   349  		p2 := obj.Appendp(p1, newprog)
   350  		p2.As = obj.ACALL
   351  		p2.To.Type = obj.TYPE_REG
   352  		p2.To.Reg = reg
   353  	}
   354  
   355  	// We only care about global data: NAME_EXTERN means a global
   356  	// symbol in the Go sense, and p.Sym.Local is true for a few
   357  	// internally defined symbols.
   358  	if p.As == lea && p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
   359  		// $LEA sym, Rx becomes $MOV $sym, Rx which will be rewritten below
   360  		p.As = mov
   361  		p.From.Type = obj.TYPE_ADDR
   362  	}
   363  	if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
   364  		// $MOV $sym, Rx becomes $MOV sym@GOT, Rx
   365  		// $MOV $sym+<off>, Rx becomes $MOV sym@GOT, Rx; $LEA <off>(Rx), Rx
   366  		// On 386 only, more complicated things like PUSHL $sym become $MOV sym@GOT, CX; PUSHL CX
   367  		cmplxdest := false
   368  		pAs := p.As
   369  		var dest obj.Addr
   370  		if p.To.Type != obj.TYPE_REG || pAs != mov {
   371  			if ctxt.Arch.Family == sys.AMD64 {
   372  				ctxt.Diag("do not know how to handle LEA-type insn to non-register in %v with -dynlink", p)
   373  			}
   374  			cmplxdest = true
   375  			dest = p.To
   376  			p.As = mov
   377  			p.To.Type = obj.TYPE_REG
   378  			p.To.Reg = reg
   379  			p.To.Sym = nil
   380  			p.To.Name = obj.NAME_NONE
   381  		}
   382  		p.From.Type = obj.TYPE_MEM
   383  		p.From.Name = obj.NAME_GOTREF
   384  		q := p
   385  		if p.From.Offset != 0 {
   386  			q = obj.Appendp(p, newprog)
   387  			q.As = lea
   388  			q.From.Type = obj.TYPE_MEM
   389  			q.From.Reg = p.To.Reg
   390  			q.From.Offset = p.From.Offset
   391  			q.To = p.To
   392  			p.From.Offset = 0
   393  		}
   394  		if cmplxdest {
   395  			q = obj.Appendp(q, newprog)
   396  			q.As = pAs
   397  			q.To = dest
   398  			q.From.Type = obj.TYPE_REG
   399  			q.From.Reg = reg
   400  		}
   401  	}
   402  	if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
   403  		ctxt.Diag("don't know how to handle %v with -dynlink", p)
   404  	}
   405  	var source *obj.Addr
   406  	// MOVx sym, Ry becomes $MOV sym@GOT, R15; MOVx (R15), Ry
   407  	// MOVx Ry, sym becomes $MOV sym@GOT, R15; MOVx Ry, (R15)
   408  	// An addition may be inserted between the two MOVs if there is an offset.
   409  	if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
   410  		if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
   411  			ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
   412  		}
   413  		source = &p.From
   414  	} else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
   415  		source = &p.To
   416  	} else {
   417  		return
   418  	}
   419  	if p.As == obj.ACALL {
   420  		// When dynlinking on 386, almost any call might end up being a call
   421  		// to a PLT, so make sure the GOT pointer is loaded into BX.
   422  		// RegTo2 is set on the replacement call insn to stop it being
   423  		// processed when it is in turn passed to progedit.
   424  		if ctxt.Arch.Family == sys.AMD64 || (p.To.Sym != nil && p.To.Sym.Local()) || p.RegTo2 != 0 {
   425  			return
   426  		}
   427  		p1 := obj.Appendp(p, newprog)
   428  		p2 := obj.Appendp(p1, newprog)
   429  
   430  		p1.As = ALEAL
   431  		p1.From.Type = obj.TYPE_MEM
   432  		p1.From.Name = obj.NAME_STATIC
   433  		p1.From.Sym = ctxt.Lookup("_GLOBAL_OFFSET_TABLE_")
   434  		p1.To.Type = obj.TYPE_REG
   435  		p1.To.Reg = REG_BX
   436  
   437  		p2.As = p.As
   438  		p2.Scond = p.Scond
   439  		p2.From = p.From
   440  		if p.RestArgs != nil {
   441  			p2.RestArgs = append(p2.RestArgs, p.RestArgs...)
   442  		}
   443  		p2.Reg = p.Reg
   444  		p2.To = p.To
   445  		// p.To.Type was set to TYPE_BRANCH above, but that makes checkaddr
   446  		// in ../pass.go complain, so set it back to TYPE_MEM here, until p2
   447  		// itself gets passed to progedit.
   448  		p2.To.Type = obj.TYPE_MEM
   449  		p2.RegTo2 = 1
   450  
   451  		obj.Nopout(p)
   452  		return
   453  
   454  	}
   455  	if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ARET || p.As == obj.AJMP {
   456  		return
   457  	}
   458  	if source.Type != obj.TYPE_MEM {
   459  		ctxt.Diag("don't know how to handle %v with -dynlink", p)
   460  	}
   461  	p1 := obj.Appendp(p, newprog)
   462  	p2 := obj.Appendp(p1, newprog)
   463  
   464  	p1.As = mov
   465  	p1.From.Type = obj.TYPE_MEM
   466  	p1.From.Sym = source.Sym
   467  	p1.From.Name = obj.NAME_GOTREF
   468  	p1.To.Type = obj.TYPE_REG
   469  	p1.To.Reg = reg
   470  
   471  	p2.As = p.As
   472  	p2.From = p.From
   473  	p2.To = p.To
   474  	if p.From.Name == obj.NAME_EXTERN {
   475  		p2.From.Reg = reg
   476  		p2.From.Name = obj.NAME_NONE
   477  		p2.From.Sym = nil
   478  	} else if p.To.Name == obj.NAME_EXTERN {
   479  		p2.To.Reg = reg
   480  		p2.To.Name = obj.NAME_NONE
   481  		p2.To.Sym = nil
   482  	} else {
   483  		return
   484  	}
   485  	obj.Nopout(p)
   486  }
   487  
   488  func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
   489  	// RegTo2 is set on the instructions we insert here so they don't get
   490  	// processed twice.
   491  	if p.RegTo2 != 0 {
   492  		return
   493  	}
   494  	if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
   495  		return
   496  	}
   497  	// Any Prog (aside from the above special cases) with an Addr with Name ==
   498  	// NAME_EXTERN, NAME_STATIC or NAME_GOTREF has a CALL __x86.get_pc_thunk.XX
   499  	// inserted before it.
   500  	isName := func(a *obj.Addr) bool {
   501  		if a.Sym == nil || (a.Type != obj.TYPE_MEM && a.Type != obj.TYPE_ADDR) || a.Reg != 0 {
   502  			return false
   503  		}
   504  		if a.Sym.Type == objabi.STLSBSS {
   505  			return false
   506  		}
   507  		return a.Name == obj.NAME_EXTERN || a.Name == obj.NAME_STATIC || a.Name == obj.NAME_GOTREF
   508  	}
   509  
   510  	if isName(&p.From) && p.From.Type == obj.TYPE_ADDR {
   511  		// Handle things like "MOVL $sym, (SP)" or "PUSHL $sym" by rewriting
   512  		// to "MOVL $sym, CX; MOVL CX, (SP)" or "MOVL $sym, CX; PUSHL CX"
   513  		// respectively.
   514  		if p.To.Type != obj.TYPE_REG {
   515  			q := obj.Appendp(p, newprog)
   516  			q.As = p.As
   517  			q.From.Type = obj.TYPE_REG
   518  			q.From.Reg = REG_CX
   519  			q.To = p.To
   520  			p.As = AMOVL
   521  			p.To.Type = obj.TYPE_REG
   522  			p.To.Reg = REG_CX
   523  			p.To.Sym = nil
   524  			p.To.Name = obj.NAME_NONE
   525  		}
   526  	}
   527  
   528  	if !isName(&p.From) && !isName(&p.To) && (p.GetFrom3() == nil || !isName(p.GetFrom3())) {
   529  		return
   530  	}
   531  	var dst int16 = REG_CX
   532  	if (p.As == ALEAL || p.As == AMOVL) && p.To.Reg != p.From.Reg && p.To.Reg != p.From.Index {
   533  		dst = p.To.Reg
   534  		// Why? See the comment near the top of rewriteToUseGot above.
   535  		// AMOVLs might be introduced by the GOT rewrites.
   536  	}
   537  	q := obj.Appendp(p, newprog)
   538  	q.RegTo2 = 1
   539  	r := obj.Appendp(q, newprog)
   540  	r.RegTo2 = 1
   541  	q.As = obj.ACALL
   542  	thunkname := "__x86.get_pc_thunk." + strings.ToLower(rconv(int(dst)))
   543  	q.To.Sym = ctxt.LookupInit(thunkname, func(s *obj.LSym) { s.Set(obj.AttrLocal, true) })
   544  	q.To.Type = obj.TYPE_MEM
   545  	q.To.Name = obj.NAME_EXTERN
   546  	r.As = p.As
   547  	r.Scond = p.Scond
   548  	r.From = p.From
   549  	r.RestArgs = p.RestArgs
   550  	r.Reg = p.Reg
   551  	r.To = p.To
   552  	if isName(&p.From) {
   553  		r.From.Reg = dst
   554  	}
   555  	if isName(&p.To) {
   556  		r.To.Reg = dst
   557  	}
   558  	if p.GetFrom3() != nil && isName(p.GetFrom3()) {
   559  		r.GetFrom3().Reg = dst
   560  	}
   561  	obj.Nopout(p)
   562  }
   563  
   564  func nacladdr(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
   565  	if p.As == ALEAL || p.As == ALEAQ {
   566  		return
   567  	}
   568  
   569  	if a.Reg == REG_BP {
   570  		ctxt.Diag("invalid address: %v", p)
   571  		return
   572  	}
   573  
   574  	if a.Reg == REG_TLS {
   575  		a.Reg = REG_BP
   576  	}
   577  	if a.Type == obj.TYPE_MEM && a.Name == obj.NAME_NONE {
   578  		switch a.Reg {
   579  		// all ok
   580  		case REG_BP, REG_SP, REG_R15:
   581  			break
   582  
   583  		default:
   584  			if a.Index != REG_NONE {
   585  				ctxt.Diag("invalid address %v", p)
   586  			}
   587  			a.Index = a.Reg
   588  			if a.Index != REG_NONE {
   589  				a.Scale = 1
   590  			}
   591  			a.Reg = REG_R15
   592  		}
   593  	}
   594  }
   595  
   596  func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
   597  	if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
   598  		return
   599  	}
   600  
   601  	p := cursym.Func.Text
   602  	autoffset := int32(p.To.Offset)
   603  	if autoffset < 0 {
   604  		autoffset = 0
   605  	}
   606  
   607  	hasCall := false
   608  	for q := p; q != nil; q = q.Link {
   609  		if q.As == obj.ACALL || q.As == obj.ADUFFCOPY || q.As == obj.ADUFFZERO {
   610  			hasCall = true
   611  			break
   612  		}
   613  	}
   614  
   615  	var bpsize int
   616  	if ctxt.Arch.Family == sys.AMD64 && ctxt.Framepointer_enabled &&
   617  		!p.From.Sym.NoFrame() && // (1) below
   618  		!(autoffset == 0 && p.From.Sym.NoSplit()) && // (2) below
   619  		!(autoffset == 0 && !hasCall) { // (3) below
   620  		// Make room to save a base pointer.
   621  		// There are 2 cases we must avoid:
   622  		// 1) If noframe is set (which we do for functions which tail call).
   623  		// 2) Scary runtime internals which would be all messed up by frame pointers.
   624  		//    We detect these using a heuristic: frameless nosplit functions.
   625  		//    TODO: Maybe someday we label them all with NOFRAME and get rid of this heuristic.
   626  		// For performance, we also want to avoid:
   627  		// 3) Frameless leaf functions
   628  		bpsize = ctxt.Arch.PtrSize
   629  		autoffset += int32(bpsize)
   630  		p.To.Offset += int64(bpsize)
   631  	} else {
   632  		bpsize = 0
   633  	}
   634  
   635  	textarg := int64(p.To.Val.(int32))
   636  	cursym.Func.Args = int32(textarg)
   637  	cursym.Func.Locals = int32(p.To.Offset)
   638  
   639  	// TODO(rsc): Remove.
   640  	if ctxt.Arch.Family == sys.I386 && cursym.Func.Locals < 0 {
   641  		cursym.Func.Locals = 0
   642  	}
   643  
   644  	// TODO(rsc): Remove 'ctxt.Arch.Family == sys.AMD64 &&'.
   645  	if ctxt.Arch.Family == sys.AMD64 && autoffset < objabi.StackSmall && !p.From.Sym.NoSplit() {
   646  		leaf := true
   647  	LeafSearch:
   648  		for q := p; q != nil; q = q.Link {
   649  			switch q.As {
   650  			case obj.ACALL:
   651  				// Treat common runtime calls that take no arguments
   652  				// the same as duffcopy and duffzero.
   653  				if !isZeroArgRuntimeCall(q.To.Sym) {
   654  					leaf = false
   655  					break LeafSearch
   656  				}
   657  				fallthrough
   658  			case obj.ADUFFCOPY, obj.ADUFFZERO:
   659  				if autoffset >= objabi.StackSmall-8 {
   660  					leaf = false
   661  					break LeafSearch
   662  				}
   663  			}
   664  		}
   665  
   666  		if leaf {
   667  			p.From.Sym.Set(obj.AttrNoSplit, true)
   668  		}
   669  	}
   670  
   671  	if !p.From.Sym.NoSplit() || p.From.Sym.Wrapper() {
   672  		p = obj.Appendp(p, newprog)
   673  		p = load_g_cx(ctxt, p, newprog) // load g into CX
   674  	}
   675  
   676  	if !cursym.Func.Text.From.Sym.NoSplit() {
   677  		p = stacksplit(ctxt, cursym, p, newprog, autoffset, int32(textarg)) // emit split check
   678  	}
   679  
   680  	// Delve debugger would like the next instruction to be noted as the end of the function prologue.
   681  	// TODO: are there other cases (e.g., wrapper functions) that need marking?
   682  	markedPrologue := false
   683  
   684  	if autoffset != 0 {
   685  		if autoffset%int32(ctxt.Arch.RegSize) != 0 {
   686  			ctxt.Diag("unaligned stack size %d", autoffset)
   687  		}
   688  		p = obj.Appendp(p, newprog)
   689  		p.As = AADJSP
   690  		p.From.Type = obj.TYPE_CONST
   691  		p.From.Offset = int64(autoffset)
   692  		p.Spadj = autoffset
   693  		p.Pos = p.Pos.WithXlogue(src.PosPrologueEnd)
   694  		markedPrologue = true
   695  	}
   696  
   697  	deltasp := autoffset
   698  
   699  	if bpsize > 0 {
   700  		// Save caller's BP
   701  		p = obj.Appendp(p, newprog)
   702  
   703  		p.As = AMOVQ
   704  		p.From.Type = obj.TYPE_REG
   705  		p.From.Reg = REG_BP
   706  		p.To.Type = obj.TYPE_MEM
   707  		p.To.Reg = REG_SP
   708  		p.To.Scale = 1
   709  		p.To.Offset = int64(autoffset) - int64(bpsize)
   710  		if !markedPrologue {
   711  			p.Pos = p.Pos.WithXlogue(src.PosPrologueEnd)
   712  		}
   713  
   714  		// Move current frame to BP
   715  		p = obj.Appendp(p, newprog)
   716  
   717  		p.As = ALEAQ
   718  		p.From.Type = obj.TYPE_MEM
   719  		p.From.Reg = REG_SP
   720  		p.From.Scale = 1
   721  		p.From.Offset = int64(autoffset) - int64(bpsize)
   722  		p.To.Type = obj.TYPE_REG
   723  		p.To.Reg = REG_BP
   724  	}
   725  
   726  	if cursym.Func.Text.From.Sym.Wrapper() {
   727  		// if g._panic != nil && g._panic.argp == FP {
   728  		//   g._panic.argp = bottom-of-frame
   729  		// }
   730  		//
   731  		//	MOVQ g_panic(CX), BX
   732  		//	TESTQ BX, BX
   733  		//	JNE checkargp
   734  		// end:
   735  		//	NOP
   736  		//  ... rest of function ...
   737  		// checkargp:
   738  		//	LEAQ (autoffset+8)(SP), DI
   739  		//	CMPQ panic_argp(BX), DI
   740  		//	JNE end
   741  		//  MOVQ SP, panic_argp(BX)
   742  		//  JMP end
   743  		//
   744  		// The NOP is needed to give the jumps somewhere to land.
   745  		// It is a liblink NOP, not an x86 NOP: it encodes to 0 instruction bytes.
   746  		//
   747  		// The layout is chosen to help static branch prediction:
   748  		// Both conditional jumps are unlikely, so they are arranged to be forward jumps.
   749  
   750  		// MOVQ g_panic(CX), BX
   751  		p = obj.Appendp(p, newprog)
   752  		p.As = AMOVQ
   753  		p.From.Type = obj.TYPE_MEM
   754  		p.From.Reg = REG_CX
   755  		p.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // g_panic
   756  		p.To.Type = obj.TYPE_REG
   757  		p.To.Reg = REG_BX
   758  		if ctxt.Headtype == objabi.Hnacl && ctxt.Arch.Family == sys.AMD64 {
   759  			p.As = AMOVL
   760  			p.From.Type = obj.TYPE_MEM
   761  			p.From.Reg = REG_R15
   762  			p.From.Scale = 1
   763  			p.From.Index = REG_CX
   764  		}
   765  		if ctxt.Arch.Family == sys.I386 {
   766  			p.As = AMOVL
   767  		}
   768  
   769  		// TESTQ BX, BX
   770  		p = obj.Appendp(p, newprog)
   771  		p.As = ATESTQ
   772  		p.From.Type = obj.TYPE_REG
   773  		p.From.Reg = REG_BX
   774  		p.To.Type = obj.TYPE_REG
   775  		p.To.Reg = REG_BX
   776  		if ctxt.Headtype == objabi.Hnacl || ctxt.Arch.Family == sys.I386 {
   777  			p.As = ATESTL
   778  		}
   779  
   780  		// JNE checkargp (checkargp to be resolved later)
   781  		jne := obj.Appendp(p, newprog)
   782  		jne.As = AJNE
   783  		jne.To.Type = obj.TYPE_BRANCH
   784  
   785  		// end:
   786  		//  NOP
   787  		end := obj.Appendp(jne, newprog)
   788  		end.As = obj.ANOP
   789  
   790  		// Fast forward to end of function.
   791  		var last *obj.Prog
   792  		for last = end; last.Link != nil; last = last.Link {
   793  		}
   794  
   795  		// LEAQ (autoffset+8)(SP), DI
   796  		p = obj.Appendp(last, newprog)
   797  		p.As = ALEAQ
   798  		p.From.Type = obj.TYPE_MEM
   799  		p.From.Reg = REG_SP
   800  		p.From.Offset = int64(autoffset) + int64(ctxt.Arch.RegSize)
   801  		p.To.Type = obj.TYPE_REG
   802  		p.To.Reg = REG_DI
   803  		if ctxt.Headtype == objabi.Hnacl || ctxt.Arch.Family == sys.I386 {
   804  			p.As = ALEAL
   805  		}
   806  
   807  		// Set jne branch target.
   808  		jne.Pcond = p
   809  
   810  		// CMPQ panic_argp(BX), DI
   811  		p = obj.Appendp(p, newprog)
   812  		p.As = ACMPQ
   813  		p.From.Type = obj.TYPE_MEM
   814  		p.From.Reg = REG_BX
   815  		p.From.Offset = 0 // Panic.argp
   816  		p.To.Type = obj.TYPE_REG
   817  		p.To.Reg = REG_DI
   818  		if ctxt.Headtype == objabi.Hnacl && ctxt.Arch.Family == sys.AMD64 {
   819  			p.As = ACMPL
   820  			p.From.Type = obj.TYPE_MEM
   821  			p.From.Reg = REG_R15
   822  			p.From.Scale = 1
   823  			p.From.Index = REG_BX
   824  		}
   825  		if ctxt.Arch.Family == sys.I386 {
   826  			p.As = ACMPL
   827  		}
   828  
   829  		// JNE end
   830  		p = obj.Appendp(p, newprog)
   831  		p.As = AJNE
   832  		p.To.Type = obj.TYPE_BRANCH
   833  		p.Pcond = end
   834  
   835  		// MOVQ SP, panic_argp(BX)
   836  		p = obj.Appendp(p, newprog)
   837  		p.As = AMOVQ
   838  		p.From.Type = obj.TYPE_REG
   839  		p.From.Reg = REG_SP
   840  		p.To.Type = obj.TYPE_MEM
   841  		p.To.Reg = REG_BX
   842  		p.To.Offset = 0 // Panic.argp
   843  		if ctxt.Headtype == objabi.Hnacl && ctxt.Arch.Family == sys.AMD64 {
   844  			p.As = AMOVL
   845  			p.To.Type = obj.TYPE_MEM
   846  			p.To.Reg = REG_R15
   847  			p.To.Scale = 1
   848  			p.To.Index = REG_BX
   849  		}
   850  		if ctxt.Arch.Family == sys.I386 {
   851  			p.As = AMOVL
   852  		}
   853  
   854  		// JMP end
   855  		p = obj.Appendp(p, newprog)
   856  		p.As = obj.AJMP
   857  		p.To.Type = obj.TYPE_BRANCH
   858  		p.Pcond = end
   859  
   860  		// Reset p for following code.
   861  		p = end
   862  	}
   863  
   864  	for ; p != nil; p = p.Link {
   865  		pcsize := ctxt.Arch.RegSize
   866  		switch p.From.Name {
   867  		case obj.NAME_AUTO:
   868  			p.From.Offset += int64(deltasp) - int64(bpsize)
   869  		case obj.NAME_PARAM:
   870  			p.From.Offset += int64(deltasp) + int64(pcsize)
   871  		}
   872  		if p.GetFrom3() != nil {
   873  			switch p.GetFrom3().Name {
   874  			case obj.NAME_AUTO:
   875  				p.GetFrom3().Offset += int64(deltasp) - int64(bpsize)
   876  			case obj.NAME_PARAM:
   877  				p.GetFrom3().Offset += int64(deltasp) + int64(pcsize)
   878  			}
   879  		}
   880  		switch p.To.Name {
   881  		case obj.NAME_AUTO:
   882  			p.To.Offset += int64(deltasp) - int64(bpsize)
   883  		case obj.NAME_PARAM:
   884  			p.To.Offset += int64(deltasp) + int64(pcsize)
   885  		}
   886  
   887  		switch p.As {
   888  		default:
   889  			continue
   890  
   891  		case APUSHL, APUSHFL:
   892  			deltasp += 4
   893  			p.Spadj = 4
   894  			continue
   895  
   896  		case APUSHQ, APUSHFQ:
   897  			deltasp += 8
   898  			p.Spadj = 8
   899  			continue
   900  
   901  		case APUSHW, APUSHFW:
   902  			deltasp += 2
   903  			p.Spadj = 2
   904  			continue
   905  
   906  		case APOPL, APOPFL:
   907  			deltasp -= 4
   908  			p.Spadj = -4
   909  			continue
   910  
   911  		case APOPQ, APOPFQ:
   912  			deltasp -= 8
   913  			p.Spadj = -8
   914  			continue
   915  
   916  		case APOPW, APOPFW:
   917  			deltasp -= 2
   918  			p.Spadj = -2
   919  			continue
   920  
   921  		case obj.ARET:
   922  			// do nothing
   923  		}
   924  
   925  		if autoffset != deltasp {
   926  			ctxt.Diag("unbalanced PUSH/POP")
   927  		}
   928  
   929  		if autoffset != 0 {
   930  			to := p.To // Keep To attached to RET for retjmp below
   931  			p.To = obj.Addr{}
   932  			if bpsize > 0 {
   933  				// Restore caller's BP
   934  				p.As = AMOVQ
   935  
   936  				p.From.Type = obj.TYPE_MEM
   937  				p.From.Reg = REG_SP
   938  				p.From.Scale = 1
   939  				p.From.Offset = int64(autoffset) - int64(bpsize)
   940  				p.To.Type = obj.TYPE_REG
   941  				p.To.Reg = REG_BP
   942  				p = obj.Appendp(p, newprog)
   943  			}
   944  
   945  			p.As = AADJSP
   946  			p.From.Type = obj.TYPE_CONST
   947  			p.From.Offset = int64(-autoffset)
   948  			p.Spadj = -autoffset
   949  			p = obj.Appendp(p, newprog)
   950  			p.As = obj.ARET
   951  			p.To = to
   952  
   953  			// If there are instructions following
   954  			// this ARET, they come from a branch
   955  			// with the same stackframe, so undo
   956  			// the cleanup.
   957  			p.Spadj = +autoffset
   958  		}
   959  
   960  		if p.To.Sym != nil { // retjmp
   961  			p.As = obj.AJMP
   962  		}
   963  	}
   964  }
   965  
   966  func isZeroArgRuntimeCall(s *obj.LSym) bool {
   967  	if s == nil {
   968  		return false
   969  	}
   970  	switch s.Name {
   971  	case "runtime.panicindex", "runtime.panicslice", "runtime.panicdivide", "runtime.panicwrap":
   972  		return true
   973  	}
   974  	return false
   975  }
   976  
   977  func indir_cx(ctxt *obj.Link, a *obj.Addr) {
   978  	if ctxt.Headtype == objabi.Hnacl && ctxt.Arch.Family == sys.AMD64 {
   979  		a.Type = obj.TYPE_MEM
   980  		a.Reg = REG_R15
   981  		a.Index = REG_CX
   982  		a.Scale = 1
   983  		return
   984  	}
   985  
   986  	a.Type = obj.TYPE_MEM
   987  	a.Reg = REG_CX
   988  }
   989  
   990  // Append code to p to load g into cx.
   991  // Overwrites p with the first instruction (no first appendp).
   992  // Overwriting p is unusual but it lets use this in both the
   993  // prologue (caller must call appendp first) and in the epilogue.
   994  // Returns last new instruction.
   995  func load_g_cx(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) *obj.Prog {
   996  	p.As = AMOVQ
   997  	if ctxt.Arch.PtrSize == 4 {
   998  		p.As = AMOVL
   999  	}
  1000  	p.From.Type = obj.TYPE_MEM
  1001  	p.From.Reg = REG_TLS
  1002  	p.From.Offset = 0
  1003  	p.To.Type = obj.TYPE_REG
  1004  	p.To.Reg = REG_CX
  1005  
  1006  	next := p.Link
  1007  	progedit(ctxt, p, newprog)
  1008  	for p.Link != next {
  1009  		p = p.Link
  1010  	}
  1011  
  1012  	if p.From.Index == REG_TLS {
  1013  		p.From.Scale = 2
  1014  	}
  1015  
  1016  	return p
  1017  }
  1018  
  1019  // Append code to p to check for stack split.
  1020  // Appends to (does not overwrite) p.
  1021  // Assumes g is in CX.
  1022  // Returns last new instruction.
  1023  func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgAlloc, framesize int32, textarg int32) *obj.Prog {
  1024  	cmp := ACMPQ
  1025  	lea := ALEAQ
  1026  	mov := AMOVQ
  1027  	sub := ASUBQ
  1028  
  1029  	if ctxt.Headtype == objabi.Hnacl || ctxt.Arch.Family == sys.I386 {
  1030  		cmp = ACMPL
  1031  		lea = ALEAL
  1032  		mov = AMOVL
  1033  		sub = ASUBL
  1034  	}
  1035  
  1036  	var q1 *obj.Prog
  1037  	if framesize <= objabi.StackSmall {
  1038  		// small stack: SP <= stackguard
  1039  		//	CMPQ SP, stackguard
  1040  		p = obj.Appendp(p, newprog)
  1041  
  1042  		p.As = cmp
  1043  		p.From.Type = obj.TYPE_REG
  1044  		p.From.Reg = REG_SP
  1045  		indir_cx(ctxt, &p.To)
  1046  		p.To.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
  1047  		if cursym.CFunc() {
  1048  			p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
  1049  		}
  1050  	} else if framesize <= objabi.StackBig {
  1051  		// large stack: SP-framesize <= stackguard-StackSmall
  1052  		//	LEAQ -xxx(SP), AX
  1053  		//	CMPQ AX, stackguard
  1054  		p = obj.Appendp(p, newprog)
  1055  
  1056  		p.As = lea
  1057  		p.From.Type = obj.TYPE_MEM
  1058  		p.From.Reg = REG_SP
  1059  		p.From.Offset = -(int64(framesize) - objabi.StackSmall)
  1060  		p.To.Type = obj.TYPE_REG
  1061  		p.To.Reg = REG_AX
  1062  
  1063  		p = obj.Appendp(p, newprog)
  1064  		p.As = cmp
  1065  		p.From.Type = obj.TYPE_REG
  1066  		p.From.Reg = REG_AX
  1067  		indir_cx(ctxt, &p.To)
  1068  		p.To.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
  1069  		if cursym.CFunc() {
  1070  			p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
  1071  		}
  1072  	} else {
  1073  		// Such a large stack we need to protect against wraparound.
  1074  		// If SP is close to zero:
  1075  		//	SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
  1076  		// The +StackGuard on both sides is required to keep the left side positive:
  1077  		// SP is allowed to be slightly below stackguard. See stack.h.
  1078  		//
  1079  		// Preemption sets stackguard to StackPreempt, a very large value.
  1080  		// That breaks the math above, so we have to check for that explicitly.
  1081  		//	MOVQ	stackguard, CX
  1082  		//	CMPQ	CX, $StackPreempt
  1083  		//	JEQ	label-of-call-to-morestack
  1084  		//	LEAQ	StackGuard(SP), AX
  1085  		//	SUBQ	CX, AX
  1086  		//	CMPQ	AX, $(framesize+(StackGuard-StackSmall))
  1087  
  1088  		p = obj.Appendp(p, newprog)
  1089  
  1090  		p.As = mov
  1091  		indir_cx(ctxt, &p.From)
  1092  		p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
  1093  		if cursym.CFunc() {
  1094  			p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
  1095  		}
  1096  		p.To.Type = obj.TYPE_REG
  1097  		p.To.Reg = REG_SI
  1098  
  1099  		p = obj.Appendp(p, newprog)
  1100  		p.As = cmp
  1101  		p.From.Type = obj.TYPE_REG
  1102  		p.From.Reg = REG_SI
  1103  		p.To.Type = obj.TYPE_CONST
  1104  		p.To.Offset = objabi.StackPreempt
  1105  		if ctxt.Arch.Family == sys.I386 {
  1106  			p.To.Offset = int64(uint32(objabi.StackPreempt & (1<<32 - 1)))
  1107  		}
  1108  
  1109  		p = obj.Appendp(p, newprog)
  1110  		p.As = AJEQ
  1111  		p.To.Type = obj.TYPE_BRANCH
  1112  		q1 = p
  1113  
  1114  		p = obj.Appendp(p, newprog)
  1115  		p.As = lea
  1116  		p.From.Type = obj.TYPE_MEM
  1117  		p.From.Reg = REG_SP
  1118  		p.From.Offset = int64(objabi.StackGuard)
  1119  		p.To.Type = obj.TYPE_REG
  1120  		p.To.Reg = REG_AX
  1121  
  1122  		p = obj.Appendp(p, newprog)
  1123  		p.As = sub
  1124  		p.From.Type = obj.TYPE_REG
  1125  		p.From.Reg = REG_SI
  1126  		p.To.Type = obj.TYPE_REG
  1127  		p.To.Reg = REG_AX
  1128  
  1129  		p = obj.Appendp(p, newprog)
  1130  		p.As = cmp
  1131  		p.From.Type = obj.TYPE_REG
  1132  		p.From.Reg = REG_AX
  1133  		p.To.Type = obj.TYPE_CONST
  1134  		p.To.Offset = int64(framesize) + (int64(objabi.StackGuard) - objabi.StackSmall)
  1135  	}
  1136  
  1137  	// common
  1138  	jls := obj.Appendp(p, newprog)
  1139  	jls.As = AJLS
  1140  	jls.To.Type = obj.TYPE_BRANCH
  1141  
  1142  	var last *obj.Prog
  1143  	for last = cursym.Func.Text; last.Link != nil; last = last.Link {
  1144  	}
  1145  
  1146  	// Now we are at the end of the function, but logically
  1147  	// we are still in function prologue. We need to fix the
  1148  	// SP data and PCDATA.
  1149  	spfix := obj.Appendp(last, newprog)
  1150  	spfix.As = obj.ANOP
  1151  	spfix.Spadj = -framesize
  1152  
  1153  	pcdata := ctxt.EmitEntryLiveness(cursym, spfix, newprog)
  1154  
  1155  	call := obj.Appendp(pcdata, newprog)
  1156  	call.Pos = cursym.Func.Text.Pos
  1157  	call.As = obj.ACALL
  1158  	call.To.Type = obj.TYPE_BRANCH
  1159  	call.To.Name = obj.NAME_EXTERN
  1160  	morestack := "runtime.morestack"
  1161  	switch {
  1162  	case cursym.CFunc():
  1163  		morestack = "runtime.morestackc"
  1164  	case !cursym.Func.Text.From.Sym.NeedCtxt():
  1165  		morestack = "runtime.morestack_noctxt"
  1166  	}
  1167  	call.To.Sym = ctxt.Lookup(morestack)
  1168  	// When compiling 386 code for dynamic linking, the call needs to be adjusted
  1169  	// to follow PIC rules. This in turn can insert more instructions, so we need
  1170  	// to keep track of the start of the call (where the jump will be to) and the
  1171  	// end (which following instructions are appended to).
  1172  	callend := call
  1173  	progedit(ctxt, callend, newprog)
  1174  	for ; callend.Link != nil; callend = callend.Link {
  1175  		progedit(ctxt, callend.Link, newprog)
  1176  	}
  1177  
  1178  	jmp := obj.Appendp(callend, newprog)
  1179  	jmp.As = obj.AJMP
  1180  	jmp.To.Type = obj.TYPE_BRANCH
  1181  	jmp.Pcond = cursym.Func.Text.Link
  1182  	jmp.Spadj = +framesize
  1183  
  1184  	jls.Pcond = call
  1185  	if q1 != nil {
  1186  		q1.Pcond = call
  1187  	}
  1188  
  1189  	return jls
  1190  }
  1191  
  1192  var unaryDst = map[obj.As]bool{
  1193  	ABSWAPL:     true,
  1194  	ABSWAPQ:     true,
  1195  	ABSWAPW:     true,
  1196  	ACLFLUSH:    true,
  1197  	ACLFLUSHOPT: true,
  1198  	ACMPXCHG16B: true,
  1199  	ACMPXCHG8B:  true,
  1200  	ADECB:       true,
  1201  	ADECL:       true,
  1202  	ADECQ:       true,
  1203  	ADECW:       true,
  1204  	AFBSTP:      true,
  1205  	AFFREE:      true,
  1206  	AFLDENV:     true,
  1207  	AFSAVE:      true,
  1208  	AFSTCW:      true,
  1209  	AFSTENV:     true,
  1210  	AFSTSW:      true,
  1211  	AFXSAVE64:   true,
  1212  	AFXSAVE:     true,
  1213  	AINCB:       true,
  1214  	AINCL:       true,
  1215  	AINCQ:       true,
  1216  	AINCW:       true,
  1217  	ANEGB:       true,
  1218  	ANEGL:       true,
  1219  	ANEGQ:       true,
  1220  	ANEGW:       true,
  1221  	ANOTB:       true,
  1222  	ANOTL:       true,
  1223  	ANOTQ:       true,
  1224  	ANOTW:       true,
  1225  	APOPL:       true,
  1226  	APOPQ:       true,
  1227  	APOPW:       true,
  1228  	ARDFSBASEL:  true,
  1229  	ARDFSBASEQ:  true,
  1230  	ARDGSBASEL:  true,
  1231  	ARDGSBASEQ:  true,
  1232  	ARDRANDL:    true,
  1233  	ARDRANDQ:    true,
  1234  	ARDRANDW:    true,
  1235  	ARDSEEDL:    true,
  1236  	ARDSEEDQ:    true,
  1237  	ARDSEEDW:    true,
  1238  	ASETCC:      true,
  1239  	ASETCS:      true,
  1240  	ASETEQ:      true,
  1241  	ASETGE:      true,
  1242  	ASETGT:      true,
  1243  	ASETHI:      true,
  1244  	ASETLE:      true,
  1245  	ASETLS:      true,
  1246  	ASETLT:      true,
  1247  	ASETMI:      true,
  1248  	ASETNE:      true,
  1249  	ASETOC:      true,
  1250  	ASETOS:      true,
  1251  	ASETPC:      true,
  1252  	ASETPL:      true,
  1253  	ASETPS:      true,
  1254  	ASGDT:       true,
  1255  	ASIDT:       true,
  1256  	ASLDTL:      true,
  1257  	ASLDTQ:      true,
  1258  	ASLDTW:      true,
  1259  	ASMSWL:      true,
  1260  	ASMSWQ:      true,
  1261  	ASMSWW:      true,
  1262  	ASTMXCSR:    true,
  1263  	ASTRL:       true,
  1264  	ASTRQ:       true,
  1265  	ASTRW:       true,
  1266  	AXSAVE64:    true,
  1267  	AXSAVE:      true,
  1268  	AXSAVEC64:   true,
  1269  	AXSAVEC:     true,
  1270  	AXSAVEOPT64: true,
  1271  	AXSAVEOPT:   true,
  1272  	AXSAVES64:   true,
  1273  	AXSAVES:     true,
  1274  }
  1275  
  1276  var Linkamd64 = obj.LinkArch{
  1277  	Arch:           sys.ArchAMD64,
  1278  	Init:           instinit,
  1279  	Preprocess:     preprocess,
  1280  	Assemble:       span6,
  1281  	Progedit:       progedit,
  1282  	UnaryDst:       unaryDst,
  1283  	DWARFRegisters: AMD64DWARFRegisters,
  1284  }
  1285  
  1286  var Linkamd64p32 = obj.LinkArch{
  1287  	Arch:           sys.ArchAMD64P32,
  1288  	Init:           instinit,
  1289  	Preprocess:     preprocess,
  1290  	Assemble:       span6,
  1291  	Progedit:       progedit,
  1292  	UnaryDst:       unaryDst,
  1293  	DWARFRegisters: AMD64DWARFRegisters,
  1294  }
  1295  
  1296  var Link386 = obj.LinkArch{
  1297  	Arch:           sys.Arch386,
  1298  	Init:           instinit,
  1299  	Preprocess:     preprocess,
  1300  	Assemble:       span6,
  1301  	Progedit:       progedit,
  1302  	UnaryDst:       unaryDst,
  1303  	DWARFRegisters: X86DWARFRegisters,
  1304  }