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