obj6.go raw

   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  	"github.com/twitchyliquid64/golang-asm/obj"
  35  	"github.com/twitchyliquid64/golang-asm/objabi"
  36  	"github.com/twitchyliquid64/golang-asm/src"
  37  	"github.com/twitchyliquid64/golang-asm/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.Lookup("runtime.duffzero")
 328  		} else {
 329  			sym = ctxt.Lookup("runtime.duffcopy")
 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