...

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

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

View as plain text