Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/internal/obj/x86/obj6.go

Documentation: cmd/internal/obj/x86

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

View as plain text