github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/src/cmd/internal/obj/x86/obj6.go (about)

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