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

     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/abi"
    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 and Windows use a tls offset determined at runtime. Rewrite
   163  	//	MOVQ TLS, BX
   164  	// to
   165  	//	MOVQ runtime.tls_g(SB), BX
   166  	if (isAndroid || ctxt.Headtype == objabi.Hwindows) &&
   167  		(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 {
   168  		p.From.Type = obj.TYPE_MEM
   169  		p.From.Name = obj.NAME_EXTERN
   170  		p.From.Reg = REG_NONE
   171  		p.From.Sym = ctxt.Lookup("runtime.tls_g")
   172  		p.From.Index = REG_NONE
   173  		if ctxt.Headtype == objabi.Hwindows {
   174  			// Windows requires an additional indirection
   175  			// to retrieve the TLS pointer,
   176  			// as runtime.tls_g contains the TLS offset from GS or FS.
   177  			// on AMD64 add
   178  			//	MOVQ 0(BX)(GS*1), BX
   179  			// on 386 add
   180  			//	MOVQ 0(BX)(FS*1), BX4
   181  			q := obj.Appendp(p, newprog)
   182  			q.As = p.As
   183  			q.From = obj.Addr{}
   184  			q.From.Type = obj.TYPE_MEM
   185  			q.From.Reg = p.To.Reg
   186  			if ctxt.Arch.Family == sys.AMD64 {
   187  				q.From.Index = REG_GS
   188  			} else {
   189  				q.From.Index = REG_FS
   190  			}
   191  			q.From.Scale = 1
   192  			q.From.Offset = 0
   193  			q.To = p.To
   194  		}
   195  	}
   196  
   197  	// TODO: Remove.
   198  	if ctxt.Headtype == objabi.Hwindows && ctxt.Arch.Family == sys.AMD64 || ctxt.Headtype == objabi.Hplan9 {
   199  		if p.From.Scale == 1 && p.From.Index == REG_TLS {
   200  			p.From.Scale = 2
   201  		}
   202  		if p.To.Scale == 1 && p.To.Index == REG_TLS {
   203  			p.To.Scale = 2
   204  		}
   205  	}
   206  
   207  	// Rewrite 0 to $0 in 3rd argument to CMPPS etc.
   208  	// That's what the tables expect.
   209  	switch p.As {
   210  	case ACMPPD, ACMPPS, ACMPSD, ACMPSS:
   211  		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 {
   212  			p.To.Type = obj.TYPE_CONST
   213  		}
   214  	}
   215  
   216  	// Rewrite CALL/JMP/RET to symbol as TYPE_BRANCH.
   217  	switch p.As {
   218  	case obj.ACALL, obj.AJMP, obj.ARET:
   219  		if p.To.Type == obj.TYPE_MEM && (p.To.Name == obj.NAME_EXTERN || p.To.Name == obj.NAME_STATIC) && p.To.Sym != nil {
   220  			p.To.Type = obj.TYPE_BRANCH
   221  		}
   222  	}
   223  
   224  	// Rewrite MOVL/MOVQ $XXX(FP/SP) as LEAL/LEAQ.
   225  	if p.From.Type == obj.TYPE_ADDR && (ctxt.Arch.Family == sys.AMD64 || p.From.Name != obj.NAME_EXTERN && p.From.Name != obj.NAME_STATIC) {
   226  		switch p.As {
   227  		case AMOVL:
   228  			p.As = ALEAL
   229  			p.From.Type = obj.TYPE_MEM
   230  		case AMOVQ:
   231  			p.As = ALEAQ
   232  			p.From.Type = obj.TYPE_MEM
   233  		}
   234  	}
   235  
   236  	// Rewrite float constants to values stored in memory.
   237  	switch p.As {
   238  	// Convert AMOVSS $(0), Xx to AXORPS Xx, Xx
   239  	case AMOVSS, AVMOVSS:
   240  		if p.From.Type == obj.TYPE_FCONST {
   241  			//  f == 0 can't be used here due to -0, so use Float64bits
   242  			if f := p.From.Val.(float64); math.Float64bits(f) == 0 {
   243  				if p.To.Type == obj.TYPE_REG && REG_X0 <= p.To.Reg && p.To.Reg <= REG_X15 {
   244  					p.As = AXORPS
   245  					p.From = p.To
   246  					break
   247  				}
   248  			}
   249  		}
   250  		fallthrough
   251  
   252  	case AFMOVF,
   253  		AFADDF,
   254  		AFSUBF,
   255  		AFSUBRF,
   256  		AFMULF,
   257  		AFDIVF,
   258  		AFDIVRF,
   259  		AFCOMF,
   260  		AFCOMFP,
   261  		AADDSS,
   262  		ASUBSS,
   263  		AMULSS,
   264  		ADIVSS,
   265  		ACOMISS,
   266  		AUCOMISS:
   267  		if p.From.Type == obj.TYPE_FCONST {
   268  			f32 := float32(p.From.Val.(float64))
   269  			p.From.Type = obj.TYPE_MEM
   270  			p.From.Name = obj.NAME_EXTERN
   271  			p.From.Sym = ctxt.Float32Sym(f32)
   272  			p.From.Offset = 0
   273  		}
   274  
   275  	case AMOVSD, AVMOVSD:
   276  		// Convert AMOVSD $(0), Xx to AXORPS Xx, Xx
   277  		if p.From.Type == obj.TYPE_FCONST {
   278  			//  f == 0 can't be used here due to -0, so use Float64bits
   279  			if f := p.From.Val.(float64); math.Float64bits(f) == 0 {
   280  				if p.To.Type == obj.TYPE_REG && REG_X0 <= p.To.Reg && p.To.Reg <= REG_X15 {
   281  					p.As = AXORPS
   282  					p.From = p.To
   283  					break
   284  				}
   285  			}
   286  		}
   287  		fallthrough
   288  
   289  	case AFMOVD,
   290  		AFADDD,
   291  		AFSUBD,
   292  		AFSUBRD,
   293  		AFMULD,
   294  		AFDIVD,
   295  		AFDIVRD,
   296  		AFCOMD,
   297  		AFCOMDP,
   298  		AADDSD,
   299  		ASUBSD,
   300  		AMULSD,
   301  		ADIVSD,
   302  		ACOMISD,
   303  		AUCOMISD:
   304  		if p.From.Type == obj.TYPE_FCONST {
   305  			f64 := p.From.Val.(float64)
   306  			p.From.Type = obj.TYPE_MEM
   307  			p.From.Name = obj.NAME_EXTERN
   308  			p.From.Sym = ctxt.Float64Sym(f64)
   309  			p.From.Offset = 0
   310  		}
   311  	}
   312  
   313  	if ctxt.Flag_dynlink {
   314  		rewriteToUseGot(ctxt, p, newprog)
   315  	}
   316  
   317  	if ctxt.Flag_shared && ctxt.Arch.Family == sys.I386 {
   318  		rewriteToPcrel(ctxt, p, newprog)
   319  	}
   320  }
   321  
   322  // Rewrite p, if necessary, to access global data via the global offset table.
   323  func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
   324  	var lea, mov obj.As
   325  	var reg int16
   326  	if ctxt.Arch.Family == sys.AMD64 {
   327  		lea = ALEAQ
   328  		mov = AMOVQ
   329  		reg = REG_R15
   330  	} else {
   331  		lea = ALEAL
   332  		mov = AMOVL
   333  		reg = REG_CX
   334  		if p.As == ALEAL && p.To.Reg != p.From.Reg && p.To.Reg != p.From.Index {
   335  			// Special case: clobber the destination register with
   336  			// the PC so we don't have to clobber CX.
   337  			// The SSA backend depends on CX not being clobbered across LEAL.
   338  			// See cmd/compile/internal/ssa/gen/386.rules (search for Flag_shared).
   339  			reg = p.To.Reg
   340  		}
   341  	}
   342  
   343  	if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
   344  		//     ADUFFxxx $offset
   345  		// becomes
   346  		//     $MOV runtime.duffxxx@GOT, $reg
   347  		//     $LEA $offset($reg), $reg
   348  		//     CALL $reg
   349  		// (we use LEAx rather than ADDx because ADDx clobbers
   350  		// flags and duffzero on 386 does not otherwise do so).
   351  		var sym *obj.LSym
   352  		if p.As == obj.ADUFFZERO {
   353  			sym = ctxt.LookupABI("runtime.duffzero", obj.ABIInternal)
   354  		} else {
   355  			sym = ctxt.LookupABI("runtime.duffcopy", obj.ABIInternal)
   356  		}
   357  		offset := p.To.Offset
   358  		p.As = mov
   359  		p.From.Type = obj.TYPE_MEM
   360  		p.From.Name = obj.NAME_GOTREF
   361  		p.From.Sym = sym
   362  		p.To.Type = obj.TYPE_REG
   363  		p.To.Reg = reg
   364  		p.To.Offset = 0
   365  		p.To.Sym = nil
   366  		p1 := obj.Appendp(p, newprog)
   367  		p1.As = lea
   368  		p1.From.Type = obj.TYPE_MEM
   369  		p1.From.Offset = offset
   370  		p1.From.Reg = reg
   371  		p1.To.Type = obj.TYPE_REG
   372  		p1.To.Reg = reg
   373  		p2 := obj.Appendp(p1, newprog)
   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 ctxt.Arch.Family == sys.AMD64 {
   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(p, newprog)
   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(q, newprog)
   420  			q.As = pAs
   421  			q.To = dest
   422  			q.From.Type = obj.TYPE_REG
   423  			q.From.Reg = reg
   424  		}
   425  	}
   426  	from3 := p.GetFrom3()
   427  	for i := range p.RestArgs {
   428  		a := &p.RestArgs[i].Addr
   429  		if a != from3 && a.Name == obj.NAME_EXTERN && !a.Sym.Local() {
   430  			ctxt.Diag("don't know how to handle %v with -dynlink", p)
   431  		}
   432  	}
   433  	var source *obj.Addr
   434  	// MOVx sym, Ry becomes $MOV sym@GOT, R15; MOVx (R15), Ry
   435  	// MOVx Ry, sym becomes $MOV sym@GOT, R15; MOVx Ry, (R15)
   436  	// An addition may be inserted between the two MOVs if there is an offset.
   437  	if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
   438  		if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
   439  			ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
   440  		}
   441  		if from3 != nil && from3.Name == obj.NAME_EXTERN && !from3.Sym.Local() {
   442  			ctxt.Diag("cannot handle NAME_EXTERN on multiple operands in %v with -dynlink", p)
   443  		}
   444  		source = &p.From
   445  	} else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
   446  		if from3 != nil && from3.Name == obj.NAME_EXTERN && !from3.Sym.Local() {
   447  			ctxt.Diag("cannot handle NAME_EXTERN on multiple operands in %v with -dynlink", p)
   448  		}
   449  		source = &p.To
   450  	} else if from3 != nil && from3.Name == obj.NAME_EXTERN && !from3.Sym.Local() {
   451  		source = from3
   452  	} else {
   453  		return
   454  	}
   455  	if p.As == obj.ACALL {
   456  		// When dynlinking on 386, almost any call might end up being a call
   457  		// to a PLT, so make sure the GOT pointer is loaded into BX.
   458  		// RegTo2 is set on the replacement call insn to stop it being
   459  		// processed when it is in turn passed to progedit.
   460  		//
   461  		// We disable open-coded defers in buildssa() on 386 ONLY with shared
   462  		// libraries because of this extra code added before deferreturn calls.
   463  		//
   464  		// computeDeferReturn in cmd/link/internal/ld/pcln.go depends
   465  		// on the size of these instructions.
   466  		if ctxt.Arch.Family == sys.AMD64 || (p.To.Sym != nil && p.To.Sym.Local()) || p.RegTo2 != 0 {
   467  			return
   468  		}
   469  		p1 := obj.Appendp(p, newprog)
   470  		p2 := obj.Appendp(p1, newprog)
   471  
   472  		p1.As = ALEAL
   473  		p1.From.Type = obj.TYPE_MEM
   474  		p1.From.Name = obj.NAME_STATIC
   475  		p1.From.Sym = ctxt.Lookup("_GLOBAL_OFFSET_TABLE_")
   476  		p1.To.Type = obj.TYPE_REG
   477  		p1.To.Reg = REG_BX
   478  
   479  		p2.As = p.As
   480  		p2.Scond = p.Scond
   481  		p2.From = p.From
   482  		if p.RestArgs != nil {
   483  			p2.RestArgs = append(p2.RestArgs, p.RestArgs...)
   484  		}
   485  		p2.Reg = p.Reg
   486  		p2.To = p.To
   487  		// p.To.Type was set to TYPE_BRANCH above, but that makes checkaddr
   488  		// in ../pass.go complain, so set it back to TYPE_MEM here, until p2
   489  		// itself gets passed to progedit.
   490  		p2.To.Type = obj.TYPE_MEM
   491  		p2.RegTo2 = 1
   492  
   493  		obj.Nopout(p)
   494  		return
   495  
   496  	}
   497  	if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ARET || p.As == obj.AJMP {
   498  		return
   499  	}
   500  	if source.Type != obj.TYPE_MEM {
   501  		ctxt.Diag("don't know how to handle %v with -dynlink", p)
   502  	}
   503  	p1 := obj.Appendp(p, newprog)
   504  	p2 := obj.Appendp(p1, newprog)
   505  
   506  	p1.As = mov
   507  	p1.From.Type = obj.TYPE_MEM
   508  	p1.From.Sym = source.Sym
   509  	p1.From.Name = obj.NAME_GOTREF
   510  	p1.To.Type = obj.TYPE_REG
   511  	p1.To.Reg = reg
   512  
   513  	p2.As = p.As
   514  	p2.From = p.From
   515  	p2.To = p.To
   516  	p2.RestArgs = p.RestArgs
   517  	if p.From.Name == obj.NAME_EXTERN {
   518  		p2.From.Reg = reg
   519  		p2.From.Name = obj.NAME_NONE
   520  		p2.From.Sym = nil
   521  	} else if p.To.Name == obj.NAME_EXTERN {
   522  		p2.To.Reg = reg
   523  		p2.To.Name = obj.NAME_NONE
   524  		p2.To.Sym = nil
   525  	} else if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
   526  		from3 = p2.GetFrom3()
   527  		from3.Reg = reg
   528  		from3.Name = obj.NAME_NONE
   529  		from3.Sym = nil
   530  	} else {
   531  		return
   532  	}
   533  	obj.Nopout(p)
   534  }
   535  
   536  func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
   537  	// RegTo2 is set on the instructions we insert here so they don't get
   538  	// processed twice.
   539  	if p.RegTo2 != 0 {
   540  		return
   541  	}
   542  	if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
   543  		return
   544  	}
   545  	// Any Prog (aside from the above special cases) with an Addr with Name ==
   546  	// NAME_EXTERN, NAME_STATIC or NAME_GOTREF has a CALL __x86.get_pc_thunk.XX
   547  	// inserted before it.
   548  	isName := func(a *obj.Addr) bool {
   549  		if a.Sym == nil || (a.Type != obj.TYPE_MEM && a.Type != obj.TYPE_ADDR) || a.Reg != 0 {
   550  			return false
   551  		}
   552  		if a.Sym.Type == objabi.STLSBSS {
   553  			return false
   554  		}
   555  		return a.Name == obj.NAME_EXTERN || a.Name == obj.NAME_STATIC || a.Name == obj.NAME_GOTREF
   556  	}
   557  
   558  	if isName(&p.From) && p.From.Type == obj.TYPE_ADDR {
   559  		// Handle things like "MOVL $sym, (SP)" or "PUSHL $sym" by rewriting
   560  		// to "MOVL $sym, CX; MOVL CX, (SP)" or "MOVL $sym, CX; PUSHL CX"
   561  		// respectively.
   562  		if p.To.Type != obj.TYPE_REG {
   563  			q := obj.Appendp(p, newprog)
   564  			q.As = p.As
   565  			q.From.Type = obj.TYPE_REG
   566  			q.From.Reg = REG_CX
   567  			q.To = p.To
   568  			p.As = AMOVL
   569  			p.To.Type = obj.TYPE_REG
   570  			p.To.Reg = REG_CX
   571  			p.To.Sym = nil
   572  			p.To.Name = obj.NAME_NONE
   573  		}
   574  	}
   575  
   576  	if !isName(&p.From) && !isName(&p.To) && (p.GetFrom3() == nil || !isName(p.GetFrom3())) {
   577  		return
   578  	}
   579  	var dst int16 = REG_CX
   580  	if (p.As == ALEAL || p.As == AMOVL) && p.To.Reg != p.From.Reg && p.To.Reg != p.From.Index {
   581  		dst = p.To.Reg
   582  		// Why? See the comment near the top of rewriteToUseGot above.
   583  		// AMOVLs might be introduced by the GOT rewrites.
   584  	}
   585  	q := obj.Appendp(p, newprog)
   586  	q.RegTo2 = 1
   587  	r := obj.Appendp(q, newprog)
   588  	r.RegTo2 = 1
   589  	q.As = obj.ACALL
   590  	thunkname := "__x86.get_pc_thunk." + strings.ToLower(rconv(int(dst)))
   591  	q.To.Sym = ctxt.LookupInit(thunkname, func(s *obj.LSym) { s.Set(obj.AttrLocal, true) })
   592  	q.To.Type = obj.TYPE_MEM
   593  	q.To.Name = obj.NAME_EXTERN
   594  	r.As = p.As
   595  	r.Scond = p.Scond
   596  	r.From = p.From
   597  	r.RestArgs = p.RestArgs
   598  	r.Reg = p.Reg
   599  	r.To = p.To
   600  	if isName(&p.From) {
   601  		r.From.Reg = dst
   602  	}
   603  	if isName(&p.To) {
   604  		r.To.Reg = dst
   605  	}
   606  	if p.GetFrom3() != nil && isName(p.GetFrom3()) {
   607  		r.GetFrom3().Reg = dst
   608  	}
   609  	obj.Nopout(p)
   610  }
   611  
   612  // Prog.mark
   613  const (
   614  	markBit = 1 << 0 // used in errorCheck to avoid duplicate work
   615  )
   616  
   617  func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
   618  	if cursym.Func().Text == nil || cursym.Func().Text.Link == nil {
   619  		return
   620  	}
   621  
   622  	p := cursym.Func().Text
   623  	autoffset := int32(p.To.Offset)
   624  	if autoffset < 0 {
   625  		autoffset = 0
   626  	}
   627  
   628  	var hasCall, mightCallABI0 bool
   629  	for q := p; q != nil && !(hasCall && mightCallABI0); q = q.Link {
   630  		switch q.As {
   631  		case obj.ACALL:
   632  			hasCall = true
   633  			if q.To.Sym != nil {
   634  				if q.To.Sym.ABI() == obj.ABI0 {
   635  					mightCallABI0 = true
   636  				}
   637  			} else {
   638  				if ctxt.IsAsm {
   639  					// We have no idea what this indirect call looks like, so assume the worst.
   640  					mightCallABI0 = true
   641  				} else {
   642  					// The compiler always use ABIInternal for indirect calls
   643  					// since otherwise it goes through an ABIInternal → ABI0 wrapper.
   644  				}
   645  			}
   646  		case obj.ADUFFCOPY, obj.ADUFFZERO:
   647  			hasCall = true
   648  		}
   649  	}
   650  
   651  	var bpsize int
   652  	if ctxt.Arch.Family == sys.AMD64 &&
   653  		!p.From.Sym.NoFrame() && // (1) below
   654  		!(autoffset == 0 && !hasCall) { // (2) below
   655  		// Make room to save a base pointer.
   656  		// There are 2 cases we must avoid:
   657  		// 1) If noframe is set (which we do for functions which tail call).
   658  		// For performance, we also want to avoid:
   659  		// 2) Frameless leaf functions
   660  		bpsize = ctxt.Arch.PtrSize
   661  		autoffset += int32(bpsize)
   662  		p.To.Offset += int64(bpsize)
   663  	} else {
   664  		bpsize = 0
   665  		p.From.Sym.Set(obj.AttrNoFrame, true)
   666  	}
   667  
   668  	textarg := int64(p.To.Val.(int32))
   669  	cursym.Func().Args = int32(textarg)
   670  	cursym.Func().Locals = int32(p.To.Offset)
   671  
   672  	// TODO(rsc): Remove.
   673  	if ctxt.Arch.Family == sys.I386 && cursym.Func().Locals < 0 {
   674  		cursym.Func().Locals = 0
   675  	}
   676  
   677  	// TODO(rsc): Remove 'ctxt.Arch.Family == sys.AMD64 &&'.
   678  	if ctxt.Arch.Family == sys.AMD64 && autoffset < abi.StackSmall && !p.From.Sym.NoSplit() {
   679  		leaf := true
   680  	LeafSearch:
   681  		for q := p; q != nil; q = q.Link {
   682  			switch q.As {
   683  			case obj.ACALL:
   684  				// Treat common runtime calls that take no arguments
   685  				// the same as duffcopy and duffzero.
   686  
   687  				// Note that of these functions, panicBounds does
   688  				// use some stack, but its stack together with the
   689  				// < StackSmall used by this function is still
   690  				// less than stackNosplit. See issue 31219.
   691  				if !isZeroArgRuntimeCall(q.To.Sym) {
   692  					leaf = false
   693  					break LeafSearch
   694  				}
   695  				fallthrough
   696  			case obj.ADUFFCOPY, obj.ADUFFZERO:
   697  				if autoffset >= abi.StackSmall-8 {
   698  					leaf = false
   699  					break LeafSearch
   700  				}
   701  			}
   702  		}
   703  
   704  		if leaf {
   705  			p.From.Sym.Set(obj.AttrNoSplit, true)
   706  		}
   707  	}
   708  
   709  	if !p.From.Sym.NoSplit() {
   710  		// Emit split check.
   711  		p = stacksplit(ctxt, cursym, p, newprog, autoffset, int32(textarg))
   712  	}
   713  
   714  	if bpsize > 0 {
   715  		// Save caller's BP
   716  		p = obj.Appendp(p, newprog)
   717  
   718  		p.As = APUSHQ
   719  		p.From.Type = obj.TYPE_REG
   720  		p.From.Reg = REG_BP
   721  
   722  		// Move current frame to BP
   723  		p = obj.Appendp(p, newprog)
   724  
   725  		p.As = AMOVQ
   726  		p.From.Type = obj.TYPE_REG
   727  		p.From.Reg = REG_SP
   728  		p.To.Type = obj.TYPE_REG
   729  		p.To.Reg = REG_BP
   730  	}
   731  
   732  	if autoffset%int32(ctxt.Arch.RegSize) != 0 {
   733  		ctxt.Diag("unaligned stack size %d", autoffset)
   734  	}
   735  
   736  	// localoffset is autoffset discounting the frame pointer,
   737  	// which has already been allocated in the stack.
   738  	localoffset := autoffset - int32(bpsize)
   739  	if localoffset != 0 {
   740  		p = obj.Appendp(p, newprog)
   741  		p.As = AADJSP
   742  		p.From.Type = obj.TYPE_CONST
   743  		p.From.Offset = int64(localoffset)
   744  		p.Spadj = localoffset
   745  	}
   746  
   747  	// Delve debugger would like the next instruction to be noted as the end of the function prologue.
   748  	// TODO: are there other cases (e.g., wrapper functions) that need marking?
   749  	if autoffset != 0 {
   750  		p.Pos = p.Pos.WithXlogue(src.PosPrologueEnd)
   751  	}
   752  
   753  	var deltasp int32
   754  	for p = cursym.Func().Text; p != nil; p = p.Link {
   755  		pcsize := ctxt.Arch.RegSize
   756  		switch p.From.Name {
   757  		case obj.NAME_AUTO:
   758  			p.From.Offset += int64(deltasp) - int64(bpsize)
   759  		case obj.NAME_PARAM:
   760  			p.From.Offset += int64(deltasp) + int64(pcsize)
   761  		}
   762  		if p.GetFrom3() != nil {
   763  			switch p.GetFrom3().Name {
   764  			case obj.NAME_AUTO:
   765  				p.GetFrom3().Offset += int64(deltasp) - int64(bpsize)
   766  			case obj.NAME_PARAM:
   767  				p.GetFrom3().Offset += int64(deltasp) + int64(pcsize)
   768  			}
   769  		}
   770  		switch p.To.Name {
   771  		case obj.NAME_AUTO:
   772  			p.To.Offset += int64(deltasp) - int64(bpsize)
   773  		case obj.NAME_PARAM:
   774  			p.To.Offset += int64(deltasp) + int64(pcsize)
   775  		}
   776  
   777  		switch p.As {
   778  		default:
   779  			if p.To.Type == obj.TYPE_REG && p.To.Reg == REG_SP && p.As != ACMPL && p.As != ACMPQ {
   780  				f := cursym.Func()
   781  				if f.FuncFlag&abi.FuncFlagSPWrite == 0 {
   782  					f.FuncFlag |= abi.FuncFlagSPWrite
   783  					if ctxt.Debugvlog || !ctxt.IsAsm {
   784  						ctxt.Logf("auto-SPWRITE: %s %v\n", cursym.Name, p)
   785  						if !ctxt.IsAsm {
   786  							ctxt.Diag("invalid auto-SPWRITE in non-assembly")
   787  							ctxt.DiagFlush()
   788  							log.Fatalf("bad SPWRITE")
   789  						}
   790  					}
   791  				}
   792  			}
   793  			continue
   794  
   795  		case APUSHL, APUSHFL:
   796  			deltasp += 4
   797  			p.Spadj = 4
   798  			continue
   799  
   800  		case APUSHQ, APUSHFQ:
   801  			deltasp += 8
   802  			p.Spadj = 8
   803  			continue
   804  
   805  		case APUSHW, APUSHFW:
   806  			deltasp += 2
   807  			p.Spadj = 2
   808  			continue
   809  
   810  		case APOPL, APOPFL:
   811  			deltasp -= 4
   812  			p.Spadj = -4
   813  			continue
   814  
   815  		case APOPQ, APOPFQ:
   816  			deltasp -= 8
   817  			p.Spadj = -8
   818  			continue
   819  
   820  		case APOPW, APOPFW:
   821  			deltasp -= 2
   822  			p.Spadj = -2
   823  			continue
   824  
   825  		case AADJSP:
   826  			p.Spadj = int32(p.From.Offset)
   827  			deltasp += int32(p.From.Offset)
   828  			continue
   829  
   830  		case obj.ARET:
   831  			// do nothing
   832  		}
   833  
   834  		if autoffset != deltasp {
   835  			ctxt.Diag("%s: unbalanced PUSH/POP", cursym)
   836  		}
   837  
   838  		if autoffset != 0 {
   839  			to := p.To // Keep To attached to RET for retjmp below
   840  			p.To = obj.Addr{}
   841  
   842  			needSpRestore, needBpRestore := localoffset != 0, bpsize > 0
   843  			// We can't use LEAVE with ABI0 assembly because the go
   844  			// asm promise it will insert save and restores for BP.
   845  			// Thus many pieces of code use BP as a scratch register.
   846  			// Due to ABI0 NOFRAME functions not restoring BP we can't
   847  			// use LEAVE there either. See https://go.dev/issue/80710
   848  			asmSafe := !ctxt.IsAsm || cursym.ABI() == obj.ABIInternal
   849  			if asmSafe && !mightCallABI0 && needSpRestore && needBpRestore {
   850  				p.As = ALEAVEQ
   851  				p.Spadj = -localoffset - int32(bpsize)
   852  				p = obj.Appendp(p, newprog)
   853  			} else {
   854  				if needSpRestore {
   855  					p.As = AADJSP
   856  					p.From.Type = obj.TYPE_CONST
   857  					p.From.Offset = int64(-localoffset)
   858  					p.Spadj = -localoffset
   859  					p = obj.Appendp(p, newprog)
   860  				}
   861  				if needBpRestore {
   862  					p.As = APOPQ
   863  					p.To.Type = obj.TYPE_REG
   864  					p.To.Reg = REG_BP
   865  					p.Spadj = -int32(bpsize)
   866  					p = obj.Appendp(p, newprog)
   867  				}
   868  			}
   869  
   870  			p.As = obj.ARET
   871  			p.To = to
   872  
   873  			// If there are instructions following
   874  			// this ARET, they come from a branch
   875  			// with the same stackframe, so undo
   876  			// the cleanup.
   877  			p.Spadj = +autoffset
   878  		}
   879  
   880  		if p.As == obj.ARET && (p.To.Sym != nil || p.To.Type == obj.TYPE_REG) { // retjmp
   881  			p.As = obj.AJMP
   882  		}
   883  	}
   884  }
   885  
   886  func isZeroArgRuntimeCall(s *obj.LSym) bool {
   887  	if s == nil {
   888  		return false
   889  	}
   890  	switch s.Name {
   891  	case "runtime.panicdivide", "runtime.panicwrap", "runtime.panicshift", "runtime.panicBounds", "runtime.panicExtend":
   892  		return true
   893  	}
   894  	return false
   895  }
   896  
   897  // loadG ensures the G is loaded into a register (either CX or REGG),
   898  // appending instructions to p if necessary. It returns the new last
   899  // instruction and the G register.
   900  func loadG(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgAlloc) (*obj.Prog, int16) {
   901  	if ctxt.Arch.Family == sys.AMD64 && cursym.ABI() == obj.ABIInternal {
   902  		// Use the G register directly in ABIInternal
   903  		return p, REGG
   904  	}
   905  
   906  	var regg int16 = REG_CX
   907  	if ctxt.Arch.Family == sys.AMD64 {
   908  		regg = REGG // == REG_R14
   909  	}
   910  
   911  	p = obj.Appendp(p, newprog)
   912  	p.As = AMOVQ
   913  	if ctxt.Arch.PtrSize == 4 {
   914  		p.As = AMOVL
   915  	}
   916  	p.From.Type = obj.TYPE_MEM
   917  	p.From.Reg = REG_TLS
   918  	p.From.Offset = 0
   919  	p.To.Type = obj.TYPE_REG
   920  	p.To.Reg = regg
   921  
   922  	// Rewrite TLS instruction if necessary.
   923  	next := p.Link
   924  	progedit(ctxt, p, newprog)
   925  	for p.Link != next {
   926  		p = p.Link
   927  		progedit(ctxt, p, newprog)
   928  	}
   929  
   930  	if p.From.Index == REG_TLS {
   931  		p.From.Scale = 2
   932  	}
   933  
   934  	return p, regg
   935  }
   936  
   937  // Append code to p to check for stack split.
   938  // Appends to (does not overwrite) p.
   939  // Assumes g is in rg.
   940  // Returns last new instruction.
   941  func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgAlloc, framesize int32, textarg int32) *obj.Prog {
   942  	cmp := ACMPQ
   943  	lea := ALEAQ
   944  	mov := AMOVQ
   945  	sub := ASUBQ
   946  	push, pop := APUSHQ, APOPQ
   947  
   948  	if ctxt.Arch.Family == sys.I386 {
   949  		cmp = ACMPL
   950  		lea = ALEAL
   951  		mov = AMOVL
   952  		sub = ASUBL
   953  		push, pop = APUSHL, APOPL
   954  	}
   955  
   956  	tmp := int16(REG_AX) // use AX for 32-bit
   957  	if ctxt.Arch.Family == sys.AMD64 {
   958  		// Avoid register parameters.
   959  		tmp = int16(REGENTRYTMP0)
   960  	}
   961  
   962  	if ctxt.Flag_maymorestack != "" {
   963  		p = cursym.Func().SpillRegisterArgs(p, newprog)
   964  
   965  		if cursym.Func().Text.From.Sym.NeedCtxt() {
   966  			p = obj.Appendp(p, newprog)
   967  			p.As = push
   968  			p.From.Type = obj.TYPE_REG
   969  			p.From.Reg = REGCTXT
   970  		}
   971  
   972  		// We call maymorestack with an ABI matching the
   973  		// caller's ABI. Since this is the first thing that
   974  		// happens in the function, we have to be consistent
   975  		// with the caller about CPU state (notably,
   976  		// fixed-meaning registers).
   977  
   978  		p = obj.Appendp(p, newprog)
   979  		p.As = obj.ACALL
   980  		p.To.Type = obj.TYPE_BRANCH
   981  		p.To.Name = obj.NAME_EXTERN
   982  		p.To.Sym = ctxt.LookupABI(ctxt.Flag_maymorestack, cursym.ABI())
   983  
   984  		if cursym.Func().Text.From.Sym.NeedCtxt() {
   985  			p = obj.Appendp(p, newprog)
   986  			p.As = pop
   987  			p.To.Type = obj.TYPE_REG
   988  			p.To.Reg = REGCTXT
   989  		}
   990  
   991  		p = cursym.Func().UnspillRegisterArgs(p, newprog)
   992  	}
   993  
   994  	// Jump back to here after morestack returns.
   995  	startPred := p
   996  
   997  	// Load G register
   998  	var rg int16
   999  	p, rg = loadG(ctxt, cursym, p, newprog)
  1000  
  1001  	var q1 *obj.Prog
  1002  	if framesize <= abi.StackSmall {
  1003  		// small stack: SP <= stackguard
  1004  		//	CMPQ SP, stackguard
  1005  		p = obj.Appendp(p, newprog)
  1006  
  1007  		p.As = cmp
  1008  		p.From.Type = obj.TYPE_REG
  1009  		p.From.Reg = REG_SP
  1010  		p.To.Type = obj.TYPE_MEM
  1011  		p.To.Reg = rg
  1012  		p.To.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
  1013  		if cursym.CFunc() {
  1014  			p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
  1015  		}
  1016  
  1017  		// Mark the stack bound check and morestack call async nonpreemptible.
  1018  		// If we get preempted here, when resumed the preemption request is
  1019  		// cleared, but we'll still call morestack, which will double the stack
  1020  		// unnecessarily. See issue #35470.
  1021  		p = ctxt.StartUnsafePoint(p, newprog)
  1022  	} else if framesize <= abi.StackBig {
  1023  		// large stack: SP-framesize <= stackguard-StackSmall
  1024  		//	LEAQ -xxx(SP), tmp
  1025  		//	CMPQ tmp, stackguard
  1026  		p = obj.Appendp(p, newprog)
  1027  
  1028  		p.As = lea
  1029  		p.From.Type = obj.TYPE_MEM
  1030  		p.From.Reg = REG_SP
  1031  		p.From.Offset = -(int64(framesize) - abi.StackSmall)
  1032  		p.To.Type = obj.TYPE_REG
  1033  		p.To.Reg = tmp
  1034  
  1035  		p = obj.Appendp(p, newprog)
  1036  		p.As = cmp
  1037  		p.From.Type = obj.TYPE_REG
  1038  		p.From.Reg = tmp
  1039  		p.To.Type = obj.TYPE_MEM
  1040  		p.To.Reg = rg
  1041  		p.To.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
  1042  		if cursym.CFunc() {
  1043  			p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
  1044  		}
  1045  
  1046  		p = ctxt.StartUnsafePoint(p, newprog) // see the comment above
  1047  	} else {
  1048  		// Such a large stack we need to protect against underflow.
  1049  		// The runtime guarantees SP > objabi.StackBig, but
  1050  		// framesize is large enough that SP-framesize may
  1051  		// underflow, causing a direct comparison with the
  1052  		// stack guard to incorrectly succeed. We explicitly
  1053  		// guard against underflow.
  1054  		//
  1055  		//	MOVQ	SP, tmp
  1056  		//	SUBQ	$(framesize - StackSmall), tmp
  1057  		//	// If subtraction wrapped (carry set), morestack.
  1058  		//	JCS	label-of-call-to-morestack
  1059  		//	CMPQ	tmp, stackguard
  1060  
  1061  		p = obj.Appendp(p, newprog)
  1062  
  1063  		p.As = mov
  1064  		p.From.Type = obj.TYPE_REG
  1065  		p.From.Reg = REG_SP
  1066  		p.To.Type = obj.TYPE_REG
  1067  		p.To.Reg = tmp
  1068  
  1069  		p = ctxt.StartUnsafePoint(p, newprog) // see the comment above
  1070  
  1071  		p = obj.Appendp(p, newprog)
  1072  		p.As = sub
  1073  		p.From.Type = obj.TYPE_CONST
  1074  		p.From.Offset = int64(framesize) - abi.StackSmall
  1075  		p.To.Type = obj.TYPE_REG
  1076  		p.To.Reg = tmp
  1077  
  1078  		p = obj.Appendp(p, newprog)
  1079  		p.As = AJCS
  1080  		p.To.Type = obj.TYPE_BRANCH
  1081  		q1 = p
  1082  
  1083  		p = obj.Appendp(p, newprog)
  1084  		p.As = cmp
  1085  		p.From.Type = obj.TYPE_REG
  1086  		p.From.Reg = tmp
  1087  		p.To.Type = obj.TYPE_MEM
  1088  		p.To.Reg = rg
  1089  		p.To.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
  1090  		if cursym.CFunc() {
  1091  			p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
  1092  		}
  1093  	}
  1094  
  1095  	// common
  1096  	jls := obj.Appendp(p, newprog)
  1097  	jls.As = AJLS
  1098  	jls.To.Type = obj.TYPE_BRANCH
  1099  
  1100  	end := ctxt.EndUnsafePoint(jls, newprog, -1)
  1101  
  1102  	var last *obj.Prog
  1103  	for last = cursym.Func().Text; last.Link != nil; last = last.Link {
  1104  	}
  1105  
  1106  	// Now we are at the end of the function, but logically
  1107  	// we are still in function prologue. We need to fix the
  1108  	// SP data and PCDATA.
  1109  	spfix := obj.Appendp(last, newprog)
  1110  	spfix.As = obj.ANOP
  1111  	spfix.Spadj = -framesize
  1112  
  1113  	pcdata := ctxt.EmitEntryStackMap(cursym, spfix, newprog)
  1114  	spill := ctxt.StartUnsafePoint(pcdata, newprog)
  1115  	pcdata = cursym.Func().SpillRegisterArgs(spill, newprog)
  1116  
  1117  	call := obj.Appendp(pcdata, newprog)
  1118  	call.Pos = cursym.Func().Text.Pos
  1119  	call.As = obj.ACALL
  1120  	call.To.Type = obj.TYPE_BRANCH
  1121  	call.To.Name = obj.NAME_EXTERN
  1122  	morestack := "runtime.morestack"
  1123  	switch {
  1124  	case cursym.CFunc():
  1125  		morestack = "runtime.morestackc"
  1126  	case !cursym.Func().Text.From.Sym.NeedCtxt():
  1127  		morestack = "runtime.morestack_noctxt"
  1128  	}
  1129  	call.To.Sym = ctxt.Lookup(morestack)
  1130  	// When compiling 386 code for dynamic linking, the call needs to be adjusted
  1131  	// to follow PIC rules. This in turn can insert more instructions, so we need
  1132  	// to keep track of the start of the call (where the jump will be to) and the
  1133  	// end (which following instructions are appended to).
  1134  	callend := call
  1135  	progedit(ctxt, callend, newprog)
  1136  	for ; callend.Link != nil; callend = callend.Link {
  1137  		progedit(ctxt, callend.Link, newprog)
  1138  	}
  1139  
  1140  	// The instructions which unspill regs should be preemptible.
  1141  	pcdata = ctxt.EndUnsafePoint(callend, newprog, -1)
  1142  	unspill := cursym.Func().UnspillRegisterArgs(pcdata, newprog)
  1143  
  1144  	jmp := obj.Appendp(unspill, newprog)
  1145  	jmp.As = obj.AJMP
  1146  	jmp.To.Type = obj.TYPE_BRANCH
  1147  	jmp.To.SetTarget(startPred.Link)
  1148  	jmp.Spadj = +framesize
  1149  
  1150  	jls.To.SetTarget(spill)
  1151  	if q1 != nil {
  1152  		q1.To.SetTarget(spill)
  1153  	}
  1154  
  1155  	return end
  1156  }
  1157  
  1158  func isR15(r int16) bool {
  1159  	return r == REG_R15 || r == REG_R15B
  1160  }
  1161  func addrMentionsR15(a *obj.Addr) bool {
  1162  	if a == nil {
  1163  		return false
  1164  	}
  1165  	return isR15(a.Reg) || isR15(a.Index)
  1166  }
  1167  func progMentionsR15(p *obj.Prog) bool {
  1168  	return addrMentionsR15(&p.From) || addrMentionsR15(&p.To) || isR15(p.Reg) || addrMentionsR15(p.GetFrom3())
  1169  }
  1170  
  1171  func addrUsesGlobal(a *obj.Addr) bool {
  1172  	if a == nil {
  1173  		return false
  1174  	}
  1175  	return a.Name == obj.NAME_EXTERN && !a.Sym.Local()
  1176  }
  1177  func progUsesGlobal(p *obj.Prog) bool {
  1178  	if p.As == obj.ACALL || p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ARET || p.As == obj.AJMP {
  1179  		// These opcodes don't use a GOT to access their argument (see rewriteToUseGot),
  1180  		// or R15 would be dead at them anyway.
  1181  		return false
  1182  	}
  1183  	if p.As == ALEAQ {
  1184  		// The GOT entry is placed directly in the destination register; R15 is not used.
  1185  		return false
  1186  	}
  1187  	return addrUsesGlobal(&p.From) || addrUsesGlobal(&p.To) || addrUsesGlobal(p.GetFrom3())
  1188  }
  1189  
  1190  type rwMask int
  1191  
  1192  const (
  1193  	readFrom rwMask = 1 << iota
  1194  	readTo
  1195  	readReg
  1196  	readFrom3
  1197  	writeFrom
  1198  	writeTo
  1199  	writeReg
  1200  	writeFrom3
  1201  )
  1202  
  1203  // progRW returns a mask describing the effects of the instruction p.
  1204  // Note: this isn't exhaustively accurate. It is only currently used for detecting
  1205  // reads/writes to R15, so SSE register behavior isn't fully correct, and
  1206  // other weird cases (e.g. writes to DX by CLD) also aren't captured.
  1207  func progRW(p *obj.Prog) rwMask {
  1208  	var m rwMask
  1209  	// Default for most instructions
  1210  	if p.From.Type != obj.TYPE_NONE {
  1211  		m |= readFrom
  1212  	}
  1213  	if p.To.Type != obj.TYPE_NONE {
  1214  		// Most x86 instructions update the To value
  1215  		m |= readTo | writeTo
  1216  	}
  1217  	if p.Reg != 0 {
  1218  		m |= readReg
  1219  	}
  1220  	if p.GetFrom3() != nil {
  1221  		m |= readFrom3
  1222  	}
  1223  
  1224  	// Lots of exceptions to the above defaults.
  1225  	name := p.As.String()
  1226  	if strings.HasPrefix(name, "MOV") || strings.HasPrefix(name, "PMOV") {
  1227  		// MOV instructions don't read To.
  1228  		m &^= readTo
  1229  	}
  1230  	switch p.As {
  1231  	case APOPW, APOPL, APOPQ,
  1232  		ALEAL, ALEAQ,
  1233  		AIMUL3W, AIMUL3L, AIMUL3Q,
  1234  		APEXTRB, APEXTRW, APEXTRD, APEXTRQ, AVPEXTRB, AVPEXTRW, AVPEXTRD, AVPEXTRQ, AEXTRACTPS,
  1235  		ABSFW, ABSFL, ABSFQ, ABSRW, ABSRL, ABSRQ, APOPCNTW, APOPCNTL, APOPCNTQ, ALZCNTW, ALZCNTL, ALZCNTQ,
  1236  		ASHLXL, ASHLXQ, ASHRXL, ASHRXQ, ASARXL, ASARXQ:
  1237  		// These instructions are pure writes to To. They don't use its old value.
  1238  		m &^= readTo
  1239  	case AXORL, AXORQ:
  1240  		// Register-clearing idiom doesn't read previous value.
  1241  		if p.From.Type == obj.TYPE_REG && p.To.Type == obj.TYPE_REG && p.From.Reg == p.To.Reg {
  1242  			m &^= readFrom | readTo
  1243  		}
  1244  	case AMULXL, AMULXQ:
  1245  		// These are write-only to both To and From3.
  1246  		m &^= readTo | readFrom3
  1247  		m |= writeFrom3
  1248  	}
  1249  	return m
  1250  }
  1251  
  1252  // progReadsR15 reports whether p reads the register R15.
  1253  func progReadsR15(p *obj.Prog) bool {
  1254  	m := progRW(p)
  1255  	if m&readFrom != 0 && p.From.Type == obj.TYPE_REG && isR15(p.From.Reg) {
  1256  		return true
  1257  	}
  1258  	if m&readTo != 0 && p.To.Type == obj.TYPE_REG && isR15(p.To.Reg) {
  1259  		return true
  1260  	}
  1261  	if m&readReg != 0 && isR15(p.Reg) {
  1262  		return true
  1263  	}
  1264  	if m&readFrom3 != 0 && p.GetFrom3().Type == obj.TYPE_REG && isR15(p.GetFrom3().Reg) {
  1265  		return true
  1266  	}
  1267  	// reads of the index registers
  1268  	if p.From.Type == obj.TYPE_MEM && (isR15(p.From.Reg) || isR15(p.From.Index)) {
  1269  		return true
  1270  	}
  1271  	if p.To.Type == obj.TYPE_MEM && (isR15(p.To.Reg) || isR15(p.To.Index)) {
  1272  		return true
  1273  	}
  1274  	if f3 := p.GetFrom3(); f3 != nil && f3.Type == obj.TYPE_MEM && (isR15(f3.Reg) || isR15(f3.Index)) {
  1275  		return true
  1276  	}
  1277  	return false
  1278  }
  1279  
  1280  // progWritesR15 reports whether p writes the register R15.
  1281  func progWritesR15(p *obj.Prog) bool {
  1282  	m := progRW(p)
  1283  	if m&writeFrom != 0 && p.From.Type == obj.TYPE_REG && isR15(p.From.Reg) {
  1284  		return true
  1285  	}
  1286  	if m&writeTo != 0 && p.To.Type == obj.TYPE_REG && isR15(p.To.Reg) {
  1287  		return true
  1288  	}
  1289  	if m&writeReg != 0 && isR15(p.Reg) {
  1290  		return true
  1291  	}
  1292  	if m&writeFrom3 != 0 && p.GetFrom3().Type == obj.TYPE_REG && isR15(p.GetFrom3().Reg) {
  1293  		return true
  1294  	}
  1295  	return false
  1296  }
  1297  
  1298  func errorCheck(ctxt *obj.Link, s *obj.LSym) {
  1299  	// When dynamic linking, R15 is used to access globals. Reject code that
  1300  	// uses R15 after a global variable access.
  1301  	if !ctxt.Flag_dynlink {
  1302  		return
  1303  	}
  1304  
  1305  	// Flood fill all the instructions where R15's value is junk.
  1306  	// If there are any uses of R15 in that set, report an error.
  1307  	var work []*obj.Prog
  1308  	var mentionsR15 bool
  1309  	for p := s.Func().Text; p != nil; p = p.Link {
  1310  		if progUsesGlobal(p) {
  1311  			work = append(work, p)
  1312  			p.Mark |= markBit
  1313  		}
  1314  		if progMentionsR15(p) {
  1315  			mentionsR15 = true
  1316  		}
  1317  	}
  1318  	if mentionsR15 {
  1319  		for len(work) > 0 {
  1320  			p := work[len(work)-1]
  1321  			work = work[:len(work)-1]
  1322  			if progReadsR15(p) {
  1323  				pos := ctxt.PosTable.Pos(p.Pos)
  1324  				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)
  1325  				break // only report one error
  1326  			}
  1327  			if progWritesR15(p) {
  1328  				// R15 is overwritten by this instruction. Its value is not junk any more.
  1329  				continue
  1330  			}
  1331  			if q := p.To.Target(); q != nil && q.Mark&markBit == 0 {
  1332  				q.Mark |= markBit
  1333  				work = append(work, q)
  1334  			}
  1335  			if p.As == obj.AJMP || p.As == obj.ARET {
  1336  				continue // no fallthrough
  1337  			}
  1338  			if q := p.Link; q != nil && q.Mark&markBit == 0 {
  1339  				q.Mark |= markBit
  1340  				work = append(work, q)
  1341  			}
  1342  		}
  1343  	}
  1344  
  1345  	// Clean up.
  1346  	for p := s.Func().Text; p != nil; p = p.Link {
  1347  		p.Mark &^= markBit
  1348  	}
  1349  }
  1350  
  1351  var unaryDst = map[obj.As]bool{
  1352  	ABSWAPL:     true,
  1353  	ABSWAPQ:     true,
  1354  	ACLDEMOTE:   true,
  1355  	ACLFLUSH:    true,
  1356  	ACLFLUSHOPT: true,
  1357  	ACLWB:       true,
  1358  	ACMPXCHG16B: true,
  1359  	ACMPXCHG8B:  true,
  1360  	ADECB:       true,
  1361  	ADECL:       true,
  1362  	ADECQ:       true,
  1363  	ADECW:       true,
  1364  	AFBSTP:      true,
  1365  	AFFREE:      true,
  1366  	AFLDENV:     true,
  1367  	AFSAVE:      true,
  1368  	AFSTCW:      true,
  1369  	AFSTENV:     true,
  1370  	AFSTSW:      true,
  1371  	AFXSAVE64:   true,
  1372  	AFXSAVE:     true,
  1373  	AINCB:       true,
  1374  	AINCL:       true,
  1375  	AINCQ:       true,
  1376  	AINCW:       true,
  1377  	ANEGB:       true,
  1378  	ANEGL:       true,
  1379  	ANEGQ:       true,
  1380  	ANEGW:       true,
  1381  	ANOTB:       true,
  1382  	ANOTL:       true,
  1383  	ANOTQ:       true,
  1384  	ANOTW:       true,
  1385  	APOPL:       true,
  1386  	APOPQ:       true,
  1387  	APOPW:       true,
  1388  	ARDFSBASEL:  true,
  1389  	ARDFSBASEQ:  true,
  1390  	ARDGSBASEL:  true,
  1391  	ARDGSBASEQ:  true,
  1392  	ARDPID:      true,
  1393  	ARDRANDL:    true,
  1394  	ARDRANDQ:    true,
  1395  	ARDRANDW:    true,
  1396  	ARDSEEDL:    true,
  1397  	ARDSEEDQ:    true,
  1398  	ARDSEEDW:    true,
  1399  	ASETCC:      true,
  1400  	ASETCS:      true,
  1401  	ASETEQ:      true,
  1402  	ASETGE:      true,
  1403  	ASETGT:      true,
  1404  	ASETHI:      true,
  1405  	ASETLE:      true,
  1406  	ASETLS:      true,
  1407  	ASETLT:      true,
  1408  	ASETMI:      true,
  1409  	ASETNE:      true,
  1410  	ASETOC:      true,
  1411  	ASETOS:      true,
  1412  	ASETPC:      true,
  1413  	ASETPL:      true,
  1414  	ASETPS:      true,
  1415  	ASGDT:       true,
  1416  	ASIDT:       true,
  1417  	ASLDTL:      true,
  1418  	ASLDTQ:      true,
  1419  	ASLDTW:      true,
  1420  	ASMSWL:      true,
  1421  	ASMSWQ:      true,
  1422  	ASMSWW:      true,
  1423  	ASTMXCSR:    true,
  1424  	ASTRL:       true,
  1425  	ASTRQ:       true,
  1426  	ASTRW:       true,
  1427  	AXSAVE64:    true,
  1428  	AXSAVE:      true,
  1429  	AXSAVEC64:   true,
  1430  	AXSAVEC:     true,
  1431  	AXSAVEOPT64: true,
  1432  	AXSAVEOPT:   true,
  1433  	AXSAVES64:   true,
  1434  	AXSAVES:     true,
  1435  }
  1436  
  1437  var Linkamd64 = obj.LinkArch{
  1438  	Arch:           sys.ArchAMD64,
  1439  	Init:           instinit,
  1440  	ErrorCheck:     errorCheck,
  1441  	Preprocess:     preprocess,
  1442  	Assemble:       span6,
  1443  	Progedit:       progedit,
  1444  	SEH:            populateSeh,
  1445  	UnaryDst:       unaryDst,
  1446  	DWARFRegisters: AMD64DWARFRegisters,
  1447  }
  1448  
  1449  var Link386 = obj.LinkArch{
  1450  	Arch:           sys.Arch386,
  1451  	Init:           instinit,
  1452  	Preprocess:     preprocess,
  1453  	Assemble:       span6,
  1454  	Progedit:       progedit,
  1455  	UnaryDst:       unaryDst,
  1456  	DWARFRegisters: X86DWARFRegisters,
  1457  }
  1458  

View as plain text