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

View as plain text