github.com/Rookout/GoSDK@v0.1.48/pkg/services/assembler/internal/obj/x86/obj6.go (about)

     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  	"github.com/Rookout/GoSDK/pkg/services/assembler/internal/obj"
    35  	"github.com/Rookout/GoSDK/pkg/services/assembler/internal/objabi"
    36  	"github.com/Rookout/GoSDK/pkg/services/assembler/internal/src"
    37  	"github.com/Rookout/GoSDK/pkg/services/assembler/internal/sys"
    38  	"github.com/Rookout/GoSDK/pkg/services/assembler/internal/abi"
    39  	"log"
    40  	"math"
    41  	"path"
    42  	"strings"
    43  )
    44  
    45  func CanUse1InsnTLS(ctxt *obj.Link) bool {
    46  	if isAndroid {
    47  		
    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  	
    74  	
    75  	
    76  	
    77  	
    78  	
    79  	
    80  	
    81  	
    82  	
    83  	
    84  	
    85  	
    86  	
    87  	
    88  	
    89  	
    90  	
    91  	
    92  	
    93  	
    94  	
    95  	
    96  	
    97  	
    98  	
    99  	
   100  	
   101  	
   102  	
   103  	
   104  	
   105  	
   106  	
   107  	
   108  	
   109  	
   110  	
   111  	
   112  
   113  	if CanUse1InsnTLS(ctxt) {
   114  		
   115  		
   116  		
   117  		
   118  		
   119  		
   120  		
   121  		
   122  		
   123  		
   124  		
   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  		
   141  		
   142  		
   143  		
   144  		
   145  		
   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 
   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  	
   163  	
   164  	
   165  	
   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  			
   175  			
   176  			
   177  			
   178  			
   179  			
   180  			
   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  	
   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  	
   208  	
   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  	
   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  	
   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  	
   237  	switch p.As {
   238  	
   239  	case AMOVSS:
   240  		if p.From.Type == obj.TYPE_FCONST {
   241  			
   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:
   276  		
   277  		if p.From.Type == obj.TYPE_FCONST {
   278  			
   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  
   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  			
   336  			
   337  			
   338  			
   339  			reg = p.To.Reg
   340  		}
   341  	}
   342  
   343  	if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
   344  		
   345  		
   346  		
   347  		
   348  		
   349  		
   350  		
   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  	
   380  	
   381  	
   382  	if p.As == lea && p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
   383  		
   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  		
   389  		
   390  		
   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  	if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
   427  		ctxt.Diag("don't know how to handle %v with -dynlink", p)
   428  	}
   429  	var source *obj.Addr
   430  	
   431  	
   432  	
   433  	if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
   434  		if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
   435  			ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
   436  		}
   437  		source = &p.From
   438  	} else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
   439  		source = &p.To
   440  	} else {
   441  		return
   442  	}
   443  	if p.As == obj.ACALL {
   444  		
   445  		
   446  		
   447  		
   448  		
   449  		
   450  		
   451  		if ctxt.Arch.Family == sys.AMD64 || (p.To.Sym != nil && p.To.Sym.Local()) || p.RegTo2 != 0 {
   452  			return
   453  		}
   454  		p1 := obj.Appendp(p, newprog)
   455  		p2 := obj.Appendp(p1, newprog)
   456  
   457  		p1.As = ALEAL
   458  		p1.From.Type = obj.TYPE_MEM
   459  		p1.From.Name = obj.NAME_STATIC
   460  		p1.From.Sym = ctxt.Lookup("_GLOBAL_OFFSET_TABLE_")
   461  		p1.To.Type = obj.TYPE_REG
   462  		p1.To.Reg = REG_BX
   463  
   464  		p2.As = p.As
   465  		p2.Scond = p.Scond
   466  		p2.From = p.From
   467  		if p.RestArgs != nil {
   468  			p2.RestArgs = append(p2.RestArgs, p.RestArgs...)
   469  		}
   470  		p2.Reg = p.Reg
   471  		p2.To = p.To
   472  		
   473  		
   474  		
   475  		p2.To.Type = obj.TYPE_MEM
   476  		p2.RegTo2 = 1
   477  
   478  		obj.Nopout(p)
   479  		return
   480  
   481  	}
   482  	if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ARET || p.As == obj.AJMP {
   483  		return
   484  	}
   485  	if source.Type != obj.TYPE_MEM {
   486  		ctxt.Diag("don't know how to handle %v with -dynlink", p)
   487  	}
   488  	p1 := obj.Appendp(p, newprog)
   489  	p2 := obj.Appendp(p1, newprog)
   490  
   491  	p1.As = mov
   492  	p1.From.Type = obj.TYPE_MEM
   493  	p1.From.Sym = source.Sym
   494  	p1.From.Name = obj.NAME_GOTREF
   495  	p1.To.Type = obj.TYPE_REG
   496  	p1.To.Reg = reg
   497  
   498  	p2.As = p.As
   499  	p2.From = p.From
   500  	p2.To = p.To
   501  	if from3 := p.GetFrom3(); from3 != nil {
   502  		p2.SetFrom3(*from3)
   503  	}
   504  	if p.From.Name == obj.NAME_EXTERN {
   505  		p2.From.Reg = reg
   506  		p2.From.Name = obj.NAME_NONE
   507  		p2.From.Sym = nil
   508  	} else if p.To.Name == obj.NAME_EXTERN {
   509  		p2.To.Reg = reg
   510  		p2.To.Name = obj.NAME_NONE
   511  		p2.To.Sym = nil
   512  	} else {
   513  		return
   514  	}
   515  	obj.Nopout(p)
   516  }
   517  
   518  func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
   519  	
   520  	
   521  	if p.RegTo2 != 0 {
   522  		return
   523  	}
   524  	if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
   525  		return
   526  	}
   527  	
   528  	
   529  	
   530  	isName := func(a *obj.Addr) bool {
   531  		if a.Sym == nil || (a.Type != obj.TYPE_MEM && a.Type != obj.TYPE_ADDR) || a.Reg != 0 {
   532  			return false
   533  		}
   534  		if a.Sym.Type == objabi.STLSBSS {
   535  			return false
   536  		}
   537  		return a.Name == obj.NAME_EXTERN || a.Name == obj.NAME_STATIC || a.Name == obj.NAME_GOTREF
   538  	}
   539  
   540  	if isName(&p.From) && p.From.Type == obj.TYPE_ADDR {
   541  		
   542  		
   543  		
   544  		if p.To.Type != obj.TYPE_REG {
   545  			q := obj.Appendp(p, newprog)
   546  			q.As = p.As
   547  			q.From.Type = obj.TYPE_REG
   548  			q.From.Reg = REG_CX
   549  			q.To = p.To
   550  			p.As = AMOVL
   551  			p.To.Type = obj.TYPE_REG
   552  			p.To.Reg = REG_CX
   553  			p.To.Sym = nil
   554  			p.To.Name = obj.NAME_NONE
   555  		}
   556  	}
   557  
   558  	if !isName(&p.From) && !isName(&p.To) && (p.GetFrom3() == nil || !isName(p.GetFrom3())) {
   559  		return
   560  	}
   561  	var dst int16 = REG_CX
   562  	if (p.As == ALEAL || p.As == AMOVL) && p.To.Reg != p.From.Reg && p.To.Reg != p.From.Index {
   563  		dst = p.To.Reg
   564  		
   565  		
   566  	}
   567  	q := obj.Appendp(p, newprog)
   568  	q.RegTo2 = 1
   569  	r := obj.Appendp(q, newprog)
   570  	r.RegTo2 = 1
   571  	q.As = obj.ACALL
   572  	thunkname := "__x86.get_pc_thunk." + strings.ToLower(rconv(int(dst)))
   573  	q.To.Sym = ctxt.LookupInit(thunkname, func(s *obj.LSym) { s.Set(obj.AttrLocal, true) })
   574  	q.To.Type = obj.TYPE_MEM
   575  	q.To.Name = obj.NAME_EXTERN
   576  	r.As = p.As
   577  	r.Scond = p.Scond
   578  	r.From = p.From
   579  	r.RestArgs = p.RestArgs
   580  	r.Reg = p.Reg
   581  	r.To = p.To
   582  	if isName(&p.From) {
   583  		r.From.Reg = dst
   584  	}
   585  	if isName(&p.To) {
   586  		r.To.Reg = dst
   587  	}
   588  	if p.GetFrom3() != nil && isName(p.GetFrom3()) {
   589  		r.GetFrom3().Reg = dst
   590  	}
   591  	obj.Nopout(p)
   592  }
   593  
   594  
   595  const (
   596  	markBit = 1 << 0 
   597  )
   598  
   599  func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
   600  	if cursym.Func().Text == nil || cursym.Func().Text.Link == nil {
   601  		return
   602  	}
   603  
   604  	p := cursym.Func().Text
   605  	autoffset := int32(p.To.Offset)
   606  	if autoffset < 0 {
   607  		autoffset = 0
   608  	}
   609  
   610  	hasCall := false
   611  	for q := p; q != nil; q = q.Link {
   612  		if q.As == obj.ACALL || q.As == obj.ADUFFCOPY || q.As == obj.ADUFFZERO {
   613  			hasCall = true
   614  			break
   615  		}
   616  	}
   617  
   618  	var bpsize int
   619  	if ctxt.Arch.Family == sys.AMD64 &&
   620  		!p.From.Sym.NoFrame() && 
   621  		!(autoffset == 0 && !hasCall) { 
   622  		
   623  		
   624  		
   625  		
   626  		
   627  		bpsize = ctxt.Arch.PtrSize
   628  		autoffset += int32(bpsize)
   629  		p.To.Offset += int64(bpsize)
   630  	} else {
   631  		bpsize = 0
   632  		p.From.Sym.Set(obj.AttrNoFrame, true)
   633  	}
   634  
   635  	textarg := int64(p.To.Val.(int32))
   636  	cursym.Func().Args = int32(textarg)
   637  	cursym.Func().Locals = int32(p.To.Offset)
   638  
   639  	
   640  	if ctxt.Arch.Family == sys.I386 && cursym.Func().Locals < 0 {
   641  		cursym.Func().Locals = 0
   642  	}
   643  
   644  	
   645  	if ctxt.Arch.Family == sys.AMD64 && autoffset < abi.StackSmall && !p.From.Sym.NoSplit() {
   646  		leaf := true
   647  	LeafSearch:
   648  		for q := p; q != nil; q = q.Link {
   649  			switch q.As {
   650  			case obj.ACALL:
   651  				
   652  				
   653  				if !isZeroArgRuntimeCall(q.To.Sym) {
   654  					leaf = false
   655  					break LeafSearch
   656  				}
   657  				fallthrough
   658  			case obj.ADUFFCOPY, obj.ADUFFZERO:
   659  				if autoffset >= abi.StackSmall-8 {
   660  					leaf = false
   661  					break LeafSearch
   662  				}
   663  			}
   664  		}
   665  
   666  		if leaf {
   667  			p.From.Sym.Set(obj.AttrNoSplit, true)
   668  		}
   669  	}
   670  
   671  	var regEntryTmp0, regEntryTmp1 int16
   672  	if ctxt.Arch.Family == sys.AMD64 {
   673  		regEntryTmp0, regEntryTmp1 = REGENTRYTMP0, REGENTRYTMP1
   674  	} else {
   675  		regEntryTmp0, regEntryTmp1 = REG_BX, REG_DI
   676  	}
   677  
   678  	var regg int16
   679  	if !p.From.Sym.NoSplit() {
   680  		
   681  		p, regg = stacksplit(ctxt, cursym, p, newprog, autoffset, int32(textarg))
   682  	} else if p.From.Sym.Wrapper() {
   683  		
   684  		p, regg = loadG(ctxt, cursym, p, newprog)
   685  	}
   686  
   687  	if bpsize > 0 {
   688  		
   689  		p = obj.Appendp(p, newprog)
   690  
   691  		p.As = APUSHQ
   692  		p.From.Type = obj.TYPE_REG
   693  		p.From.Reg = REG_BP
   694  
   695  		
   696  		p = obj.Appendp(p, newprog)
   697  
   698  		p.As = AMOVQ
   699  		p.From.Type = obj.TYPE_REG
   700  		p.From.Reg = REG_SP
   701  		p.To.Type = obj.TYPE_REG
   702  		p.To.Reg = REG_BP
   703  	}
   704  
   705  	if autoffset%int32(ctxt.Arch.RegSize) != 0 {
   706  		ctxt.Diag("unaligned stack size %d", autoffset)
   707  	}
   708  
   709  	
   710  	
   711  	localoffset := autoffset - int32(bpsize)
   712  	if localoffset != 0 {
   713  		p = obj.Appendp(p, newprog)
   714  		p.As = AADJSP
   715  		p.From.Type = obj.TYPE_CONST
   716  		p.From.Offset = int64(localoffset)
   717  		p.Spadj = localoffset
   718  	}
   719  
   720  	
   721  	
   722  	if autoffset != 0 {
   723  		p.Pos = p.Pos.WithXlogue(src.PosPrologueEnd)
   724  	}
   725  
   726  	if cursym.Func().Text.From.Sym.Wrapper() {
   727  		
   728  		
   729  		
   730  		
   731  		
   732  		
   733  		
   734  		
   735  		
   736  		
   737  		
   738  		
   739  		
   740  		
   741  		
   742  		
   743  		
   744  		
   745  		
   746  		
   747  		
   748  		
   749  
   750  		
   751  		p = obj.Appendp(p, newprog)
   752  		p.As = AMOVQ
   753  		p.From.Type = obj.TYPE_MEM
   754  		p.From.Reg = regg
   755  		p.From.Offset = 4 * int64(ctxt.Arch.PtrSize) 
   756  		p.To.Type = obj.TYPE_REG
   757  		p.To.Reg = regEntryTmp0
   758  		if ctxt.Arch.Family == sys.I386 {
   759  			p.As = AMOVL
   760  		}
   761  
   762  		
   763  		p = obj.Appendp(p, newprog)
   764  		p.As = ATESTQ
   765  		p.From.Type = obj.TYPE_REG
   766  		p.From.Reg = regEntryTmp0
   767  		p.To.Type = obj.TYPE_REG
   768  		p.To.Reg = regEntryTmp0
   769  		if ctxt.Arch.Family == sys.I386 {
   770  			p.As = ATESTL
   771  		}
   772  
   773  		
   774  		jne := obj.Appendp(p, newprog)
   775  		jne.As = AJNE
   776  		jne.To.Type = obj.TYPE_BRANCH
   777  
   778  		
   779  		
   780  		end := obj.Appendp(jne, newprog)
   781  		end.As = obj.ANOP
   782  
   783  		
   784  		var last *obj.Prog
   785  		for last = end; last.Link != nil; last = last.Link {
   786  		}
   787  
   788  		
   789  		p = obj.Appendp(last, newprog)
   790  		p.As = ALEAQ
   791  		p.From.Type = obj.TYPE_MEM
   792  		p.From.Reg = REG_SP
   793  		p.From.Offset = int64(autoffset) + int64(ctxt.Arch.RegSize)
   794  		p.To.Type = obj.TYPE_REG
   795  		p.To.Reg = regEntryTmp1
   796  		if ctxt.Arch.Family == sys.I386 {
   797  			p.As = ALEAL
   798  		}
   799  
   800  		
   801  		jne.To.SetTarget(p)
   802  
   803  		
   804  		p = obj.Appendp(p, newprog)
   805  		p.As = ACMPQ
   806  		p.From.Type = obj.TYPE_MEM
   807  		p.From.Reg = regEntryTmp0
   808  		p.From.Offset = 0 
   809  		p.To.Type = obj.TYPE_REG
   810  		p.To.Reg = regEntryTmp1
   811  		if ctxt.Arch.Family == sys.I386 {
   812  			p.As = ACMPL
   813  		}
   814  
   815  		
   816  		p = obj.Appendp(p, newprog)
   817  		p.As = AJNE
   818  		p.To.Type = obj.TYPE_BRANCH
   819  		p.To.SetTarget(end)
   820  
   821  		
   822  		p = obj.Appendp(p, newprog)
   823  		p.As = AMOVQ
   824  		p.From.Type = obj.TYPE_REG
   825  		p.From.Reg = REG_SP
   826  		p.To.Type = obj.TYPE_MEM
   827  		p.To.Reg = regEntryTmp0
   828  		p.To.Offset = 0 
   829  		if ctxt.Arch.Family == sys.I386 {
   830  			p.As = AMOVL
   831  		}
   832  
   833  		
   834  		p = obj.Appendp(p, newprog)
   835  		p.As = obj.AJMP
   836  		p.To.Type = obj.TYPE_BRANCH
   837  		p.To.SetTarget(end)
   838  
   839  		
   840  		p = end
   841  	}
   842  
   843  	var deltasp int32
   844  	for p = cursym.Func().Text; p != nil; p = p.Link {
   845  		pcsize := ctxt.Arch.RegSize
   846  		switch p.From.Name {
   847  		case obj.NAME_AUTO:
   848  			p.From.Offset += int64(deltasp) - int64(bpsize)
   849  		case obj.NAME_PARAM:
   850  			p.From.Offset += int64(deltasp) + int64(pcsize)
   851  		}
   852  		if p.GetFrom3() != nil {
   853  			switch p.GetFrom3().Name {
   854  			case obj.NAME_AUTO:
   855  				p.GetFrom3().Offset += int64(deltasp) - int64(bpsize)
   856  			case obj.NAME_PARAM:
   857  				p.GetFrom3().Offset += int64(deltasp) + int64(pcsize)
   858  			}
   859  		}
   860  		switch p.To.Name {
   861  		case obj.NAME_AUTO:
   862  			p.To.Offset += int64(deltasp) - int64(bpsize)
   863  		case obj.NAME_PARAM:
   864  			p.To.Offset += int64(deltasp) + int64(pcsize)
   865  		}
   866  
   867  		switch p.As {
   868  		default:
   869  			if p.To.Type == obj.TYPE_REG && p.To.Reg == REG_SP && p.As != ACMPL && p.As != ACMPQ {
   870  				f := cursym.Func()
   871  				if f.FuncFlag&abi.FuncFlagSPWrite == 0 {
   872  					f.FuncFlag |= abi.FuncFlagSPWrite
   873  					if ctxt.Debugvlog || !ctxt.IsAsm {
   874  						ctxt.Logf("auto-SPWRITE: %s %v\n", cursym.Name, p)
   875  						if !ctxt.IsAsm {
   876  							ctxt.Diag("invalid auto-SPWRITE in non-assembly")
   877  							ctxt.DiagFlush()
   878  							log.Fatalf("bad SPWRITE")
   879  						}
   880  					}
   881  				}
   882  			}
   883  			continue
   884  
   885  		case APUSHL, APUSHFL:
   886  			deltasp += 4
   887  			p.Spadj = 4
   888  			continue
   889  
   890  		case APUSHQ, APUSHFQ:
   891  			deltasp += 8
   892  			p.Spadj = 8
   893  			continue
   894  
   895  		case APUSHW, APUSHFW:
   896  			deltasp += 2
   897  			p.Spadj = 2
   898  			continue
   899  
   900  		case APOPL, APOPFL:
   901  			deltasp -= 4
   902  			p.Spadj = -4
   903  			continue
   904  
   905  		case APOPQ, APOPFQ:
   906  			deltasp -= 8
   907  			p.Spadj = -8
   908  			continue
   909  
   910  		case APOPW, APOPFW:
   911  			deltasp -= 2
   912  			p.Spadj = -2
   913  			continue
   914  
   915  		case AADJSP:
   916  			p.Spadj = int32(p.From.Offset)
   917  			deltasp += int32(p.From.Offset)
   918  			continue
   919  
   920  		case obj.ARET:
   921  			
   922  		}
   923  
   924  		if autoffset != deltasp {
   925  			ctxt.Diag("%s: unbalanced PUSH/POP", cursym)
   926  		}
   927  
   928  		if autoffset != 0 {
   929  			to := p.To 
   930  			p.To = obj.Addr{}
   931  			if localoffset != 0 {
   932  				p.As = AADJSP
   933  				p.From.Type = obj.TYPE_CONST
   934  				p.From.Offset = int64(-localoffset)
   935  				p.Spadj = -localoffset
   936  				p = obj.Appendp(p, newprog)
   937  			}
   938  
   939  			if bpsize > 0 {
   940  				
   941  				p.As = APOPQ
   942  				p.To.Type = obj.TYPE_REG
   943  				p.To.Reg = REG_BP
   944  				p.Spadj = -int32(bpsize)
   945  				p = obj.Appendp(p, newprog)
   946  			}
   947  
   948  			p.As = obj.ARET
   949  			p.To = to
   950  
   951  			
   952  			
   953  			
   954  			
   955  			p.Spadj = +autoffset
   956  		}
   957  
   958  		if p.To.Sym != nil { 
   959  			p.As = obj.AJMP
   960  		}
   961  	}
   962  }
   963  
   964  func isZeroArgRuntimeCall(s *obj.LSym) bool {
   965  	if s == nil {
   966  		return false
   967  	}
   968  	switch s.Name {
   969  	case "runtime.panicdivide", "runtime.panicwrap", "runtime.panicshift":
   970  		return true
   971  	}
   972  	if strings.HasPrefix(s.Name, "runtime.panicIndex") || strings.HasPrefix(s.Name, "runtime.panicSlice") {
   973  		
   974  		
   975  		
   976  		return true
   977  	}
   978  	return false
   979  }
   980  
   981  func indir_cx(ctxt *obj.Link, a *obj.Addr) {
   982  	a.Type = obj.TYPE_MEM
   983  	a.Reg = REG_CX
   984  }
   985  
   986  
   987  
   988  
   989  func loadG(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgAlloc) (*obj.Prog, int16) {
   990  	if ctxt.Arch.Family == sys.AMD64 && cursym.ABI() == obj.ABIInternal {
   991  		
   992  		return p, REGG
   993  	}
   994  
   995  	var regg int16 = REG_CX
   996  	if ctxt.Arch.Family == sys.AMD64 {
   997  		regg = REGG 
   998  	}
   999  
  1000  	p = obj.Appendp(p, newprog)
  1001  	p.As = AMOVQ
  1002  	if ctxt.Arch.PtrSize == 4 {
  1003  		p.As = AMOVL
  1004  	}
  1005  	p.From.Type = obj.TYPE_MEM
  1006  	p.From.Reg = REG_TLS
  1007  	p.From.Offset = 0
  1008  	p.To.Type = obj.TYPE_REG
  1009  	p.To.Reg = regg
  1010  
  1011  	
  1012  	next := p.Link
  1013  	progedit(ctxt, p, newprog)
  1014  	for p.Link != next {
  1015  		p = p.Link
  1016  		progedit(ctxt, p, newprog)
  1017  	}
  1018  
  1019  	if p.From.Index == REG_TLS {
  1020  		p.From.Scale = 2
  1021  	}
  1022  
  1023  	return p, regg
  1024  }
  1025  
  1026  
  1027  
  1028  
  1029  
  1030  func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgAlloc, framesize int32, textarg int32) (*obj.Prog, int16) {
  1031  	cmp := ACMPQ
  1032  	lea := ALEAQ
  1033  	mov := AMOVQ
  1034  	sub := ASUBQ
  1035  	push, pop := APUSHQ, APOPQ
  1036  
  1037  	if ctxt.Arch.Family == sys.I386 {
  1038  		cmp = ACMPL
  1039  		lea = ALEAL
  1040  		mov = AMOVL
  1041  		sub = ASUBL
  1042  		push, pop = APUSHL, APOPL
  1043  	}
  1044  
  1045  	tmp := int16(REG_AX) 
  1046  	if ctxt.Arch.Family == sys.AMD64 {
  1047  		
  1048  		tmp = int16(REGENTRYTMP0)
  1049  	}
  1050  
  1051  	if ctxt.Flag_maymorestack != "" {
  1052  		p = cursym.Func().SpillRegisterArgs(p, newprog)
  1053  
  1054  		if cursym.Func().Text.From.Sym.NeedCtxt() {
  1055  			p = obj.Appendp(p, newprog)
  1056  			p.As = push
  1057  			p.From.Type = obj.TYPE_REG
  1058  			p.From.Reg = REGCTXT
  1059  		}
  1060  
  1061  		
  1062  		
  1063  		
  1064  		
  1065  		
  1066  
  1067  		p = obj.Appendp(p, newprog)
  1068  		p.As = obj.ACALL
  1069  		p.To.Type = obj.TYPE_BRANCH
  1070  		p.To.Name = obj.NAME_EXTERN
  1071  		p.To.Sym = ctxt.LookupABI(ctxt.Flag_maymorestack, cursym.ABI())
  1072  
  1073  		if cursym.Func().Text.From.Sym.NeedCtxt() {
  1074  			p = obj.Appendp(p, newprog)
  1075  			p.As = pop
  1076  			p.To.Type = obj.TYPE_REG
  1077  			p.To.Reg = REGCTXT
  1078  		}
  1079  
  1080  		p = cursym.Func().UnspillRegisterArgs(p, newprog)
  1081  	}
  1082  
  1083  	
  1084  	startPred := p
  1085  
  1086  	
  1087  	var rg int16
  1088  	p, rg = loadG(ctxt, cursym, p, newprog)
  1089  
  1090  	var q1 *obj.Prog
  1091  	if framesize <= abi.StackSmall {
  1092  		
  1093  		
  1094  		p = obj.Appendp(p, newprog)
  1095  
  1096  		p.As = cmp
  1097  		p.From.Type = obj.TYPE_REG
  1098  		p.From.Reg = REG_SP
  1099  		p.To.Type = obj.TYPE_MEM
  1100  		p.To.Reg = rg
  1101  		p.To.Offset = 2 * int64(ctxt.Arch.PtrSize) 
  1102  		if cursym.CFunc() {
  1103  			p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) 
  1104  		}
  1105  
  1106  		
  1107  		
  1108  		
  1109  		
  1110  		p = ctxt.StartUnsafePoint(p, newprog)
  1111  	} else if framesize <= abi.StackBig {
  1112  		
  1113  		
  1114  		
  1115  		p = obj.Appendp(p, newprog)
  1116  
  1117  		p.As = lea
  1118  		p.From.Type = obj.TYPE_MEM
  1119  		p.From.Reg = REG_SP
  1120  		p.From.Offset = -(int64(framesize) - abi.StackSmall)
  1121  		p.To.Type = obj.TYPE_REG
  1122  		p.To.Reg = tmp
  1123  
  1124  		p = obj.Appendp(p, newprog)
  1125  		p.As = cmp
  1126  		p.From.Type = obj.TYPE_REG
  1127  		p.From.Reg = tmp
  1128  		p.To.Type = obj.TYPE_MEM
  1129  		p.To.Reg = rg
  1130  		p.To.Offset = 2 * int64(ctxt.Arch.PtrSize) 
  1131  		if cursym.CFunc() {
  1132  			p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) 
  1133  		}
  1134  
  1135  		p = ctxt.StartUnsafePoint(p, newprog) 
  1136  	} else {
  1137  		
  1138  		
  1139  		
  1140  		
  1141  		
  1142  		
  1143  		
  1144  		
  1145  		
  1146  		
  1147  		
  1148  		
  1149  
  1150  		p = obj.Appendp(p, newprog)
  1151  
  1152  		p.As = mov
  1153  		p.From.Type = obj.TYPE_REG
  1154  		p.From.Reg = REG_SP
  1155  		p.To.Type = obj.TYPE_REG
  1156  		p.To.Reg = tmp
  1157  
  1158  		p = ctxt.StartUnsafePoint(p, newprog) 
  1159  
  1160  		p = obj.Appendp(p, newprog)
  1161  		p.As = sub
  1162  		p.From.Type = obj.TYPE_CONST
  1163  		p.From.Offset = int64(framesize) - abi.StackSmall
  1164  		p.To.Type = obj.TYPE_REG
  1165  		p.To.Reg = tmp
  1166  
  1167  		p = obj.Appendp(p, newprog)
  1168  		p.As = AJCS
  1169  		p.To.Type = obj.TYPE_BRANCH
  1170  		q1 = p
  1171  
  1172  		p = obj.Appendp(p, newprog)
  1173  		p.As = cmp
  1174  		p.From.Type = obj.TYPE_REG
  1175  		p.From.Reg = tmp
  1176  		p.To.Type = obj.TYPE_MEM
  1177  		p.To.Reg = rg
  1178  		p.To.Offset = 2 * int64(ctxt.Arch.PtrSize) 
  1179  		if cursym.CFunc() {
  1180  			p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) 
  1181  		}
  1182  	}
  1183  
  1184  	
  1185  	jls := obj.Appendp(p, newprog)
  1186  	jls.As = AJLS
  1187  	jls.To.Type = obj.TYPE_BRANCH
  1188  
  1189  	end := ctxt.EndUnsafePoint(jls, newprog, -1)
  1190  
  1191  	var last *obj.Prog
  1192  	for last = cursym.Func().Text; last.Link != nil; last = last.Link {
  1193  	}
  1194  
  1195  	
  1196  	
  1197  	
  1198  	spfix := obj.Appendp(last, newprog)
  1199  	spfix.As = obj.ANOP
  1200  	spfix.Spadj = -framesize
  1201  
  1202  	pcdata := ctxt.EmitEntryStackMap(cursym, spfix, newprog)
  1203  	spill := ctxt.StartUnsafePoint(pcdata, newprog)
  1204  	pcdata = cursym.Func().SpillRegisterArgs(spill, newprog)
  1205  
  1206  	call := obj.Appendp(pcdata, newprog)
  1207  	call.Pos = cursym.Func().Text.Pos
  1208  	call.As = obj.ACALL
  1209  	call.To.Type = obj.TYPE_BRANCH
  1210  	call.To.Name = obj.NAME_EXTERN
  1211  	morestack := "runtime.morestack"
  1212  	switch {
  1213  	case cursym.CFunc():
  1214  		morestack = "runtime.morestackc"
  1215  	case !cursym.Func().Text.From.Sym.NeedCtxt():
  1216  		morestack = "runtime.morestack_noctxt"
  1217  	}
  1218  	call.To.Sym = ctxt.Lookup(morestack)
  1219  	
  1220  	
  1221  	
  1222  	
  1223  	callend := call
  1224  	progedit(ctxt, callend, newprog)
  1225  	for ; callend.Link != nil; callend = callend.Link {
  1226  		progedit(ctxt, callend.Link, newprog)
  1227  	}
  1228  
  1229  	pcdata = cursym.Func().UnspillRegisterArgs(callend, newprog)
  1230  	pcdata = ctxt.EndUnsafePoint(pcdata, newprog, -1)
  1231  
  1232  	jmp := obj.Appendp(pcdata, newprog)
  1233  	jmp.As = obj.AJMP
  1234  	jmp.To.Type = obj.TYPE_BRANCH
  1235  	jmp.To.SetTarget(startPred.Link)
  1236  	jmp.Spadj = +framesize
  1237  
  1238  	jls.To.SetTarget(spill)
  1239  	if q1 != nil {
  1240  		q1.To.SetTarget(spill)
  1241  	}
  1242  
  1243  	return end, rg
  1244  }
  1245  
  1246  func isR15(r int16) bool {
  1247  	return r == REG_R15 || r == REG_R15B
  1248  }
  1249  func addrMentionsR15(a *obj.Addr) bool {
  1250  	if a == nil {
  1251  		return false
  1252  	}
  1253  	return isR15(a.Reg) || isR15(a.Index)
  1254  }
  1255  func progMentionsR15(p *obj.Prog) bool {
  1256  	return addrMentionsR15(&p.From) || addrMentionsR15(&p.To) || isR15(p.Reg) || addrMentionsR15(p.GetFrom3())
  1257  }
  1258  
  1259  func addrUsesGlobal(a *obj.Addr) bool {
  1260  	if a == nil {
  1261  		return false
  1262  	}
  1263  	return a.Name == obj.NAME_EXTERN && !a.Sym.Local()
  1264  }
  1265  func progUsesGlobal(p *obj.Prog) bool {
  1266  	if p.As == obj.ACALL || p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ARET || p.As == obj.AJMP {
  1267  		
  1268  		
  1269  		return false
  1270  	}
  1271  	if p.As == ALEAQ {
  1272  		
  1273  		return false
  1274  	}
  1275  	return addrUsesGlobal(&p.From) || addrUsesGlobal(&p.To) || addrUsesGlobal(p.GetFrom3())
  1276  }
  1277  
  1278  type rwMask int
  1279  
  1280  const (
  1281  	readFrom rwMask = 1 << iota
  1282  	readTo
  1283  	readReg
  1284  	readFrom3
  1285  	writeFrom
  1286  	writeTo
  1287  	writeReg
  1288  	writeFrom3
  1289  )
  1290  
  1291  
  1292  
  1293  
  1294  
  1295  func progRW(p *obj.Prog) rwMask {
  1296  	var m rwMask
  1297  	
  1298  	if p.From.Type != obj.TYPE_NONE {
  1299  		m |= readFrom
  1300  	}
  1301  	if p.To.Type != obj.TYPE_NONE {
  1302  		
  1303  		m |= readTo | writeTo
  1304  	}
  1305  	if p.Reg != 0 {
  1306  		m |= readReg
  1307  	}
  1308  	if p.GetFrom3() != nil {
  1309  		m |= readFrom3
  1310  	}
  1311  
  1312  	
  1313  	name := p.As.String()
  1314  	if strings.HasPrefix(name, "MOV") || strings.HasPrefix(name, "PMOV") {
  1315  		
  1316  		m &^= readTo
  1317  	}
  1318  	switch p.As {
  1319  	case APOPW, APOPL, APOPQ,
  1320  		ALEAL, ALEAQ,
  1321  		AIMUL3W, AIMUL3L, AIMUL3Q,
  1322  		APEXTRB, APEXTRW, APEXTRD, APEXTRQ, AVPEXTRB, AVPEXTRW, AVPEXTRD, AVPEXTRQ, AEXTRACTPS,
  1323  		ABSFW, ABSFL, ABSFQ, ABSRW, ABSRL, ABSRQ, APOPCNTW, APOPCNTL, APOPCNTQ, ALZCNTW, ALZCNTL, ALZCNTQ,
  1324  		ASHLXL, ASHLXQ, ASHRXL, ASHRXQ, ASARXL, ASARXQ:
  1325  		
  1326  		m &^= readTo
  1327  	case AXORL, AXORQ:
  1328  		
  1329  		if p.From.Type == obj.TYPE_REG && p.To.Type == obj.TYPE_REG && p.From.Reg == p.To.Reg {
  1330  			m &^= readFrom | readTo
  1331  		}
  1332  	case AMULXL, AMULXQ:
  1333  		
  1334  		m &^= readTo | readFrom3
  1335  		m |= writeFrom3
  1336  	}
  1337  	return m
  1338  }
  1339  
  1340  
  1341  func progReadsR15(p *obj.Prog) bool {
  1342  	m := progRW(p)
  1343  	if m&readFrom != 0 && p.From.Type == obj.TYPE_REG && isR15(p.From.Reg) {
  1344  		return true
  1345  	}
  1346  	if m&readTo != 0 && p.To.Type == obj.TYPE_REG && isR15(p.To.Reg) {
  1347  		return true
  1348  	}
  1349  	if m&readReg != 0 && isR15(p.Reg) {
  1350  		return true
  1351  	}
  1352  	if m&readFrom3 != 0 && p.GetFrom3().Type == obj.TYPE_REG && isR15(p.GetFrom3().Reg) {
  1353  		return true
  1354  	}
  1355  	
  1356  	if p.From.Type == obj.TYPE_MEM && (isR15(p.From.Reg) || isR15(p.From.Index)) {
  1357  		return true
  1358  	}
  1359  	if p.To.Type == obj.TYPE_MEM && (isR15(p.To.Reg) || isR15(p.To.Index)) {
  1360  		return true
  1361  	}
  1362  	if f3 := p.GetFrom3(); f3 != nil && f3.Type == obj.TYPE_MEM && (isR15(f3.Reg) || isR15(f3.Index)) {
  1363  		return true
  1364  	}
  1365  	return false
  1366  }
  1367  
  1368  
  1369  func progWritesR15(p *obj.Prog) bool {
  1370  	m := progRW(p)
  1371  	if m&writeFrom != 0 && p.From.Type == obj.TYPE_REG && isR15(p.From.Reg) {
  1372  		return true
  1373  	}
  1374  	if m&writeTo != 0 && p.To.Type == obj.TYPE_REG && isR15(p.To.Reg) {
  1375  		return true
  1376  	}
  1377  	if m&writeReg != 0 && isR15(p.Reg) {
  1378  		return true
  1379  	}
  1380  	if m&writeFrom3 != 0 && p.GetFrom3().Type == obj.TYPE_REG && isR15(p.GetFrom3().Reg) {
  1381  		return true
  1382  	}
  1383  	return false
  1384  }
  1385  
  1386  func errorCheck(ctxt *obj.Link, s *obj.LSym) {
  1387  	
  1388  	
  1389  	if !ctxt.Flag_dynlink {
  1390  		return
  1391  	}
  1392  
  1393  	
  1394  	
  1395  	var work []*obj.Prog
  1396  	var mentionsR15 bool
  1397  	for p := s.Func().Text; p != nil; p = p.Link {
  1398  		if progUsesGlobal(p) {
  1399  			work = append(work, p)
  1400  			p.Mark |= markBit
  1401  		}
  1402  		if progMentionsR15(p) {
  1403  			mentionsR15 = true
  1404  		}
  1405  	}
  1406  	if mentionsR15 {
  1407  		for len(work) > 0 {
  1408  			p := work[len(work)-1]
  1409  			work = work[:len(work)-1]
  1410  			if progReadsR15(p) {
  1411  				pos := ctxt.PosTable.Pos(p.Pos)
  1412  				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)
  1413  				break 
  1414  			}
  1415  			if progWritesR15(p) {
  1416  				
  1417  				continue
  1418  			}
  1419  			if q := p.To.Target(); q != nil && q.Mark&markBit == 0 {
  1420  				q.Mark |= markBit
  1421  				work = append(work, q)
  1422  			}
  1423  			if p.As == obj.AJMP || p.As == obj.ARET {
  1424  				continue 
  1425  			}
  1426  			if q := p.Link; q != nil && q.Mark&markBit == 0 {
  1427  				q.Mark |= markBit
  1428  				work = append(work, q)
  1429  			}
  1430  		}
  1431  	}
  1432  
  1433  	
  1434  	for p := s.Func().Text; p != nil; p = p.Link {
  1435  		p.Mark &^= markBit
  1436  	}
  1437  }
  1438  
  1439  var unaryDst = map[obj.As]bool{
  1440  	ABSWAPL:     true,
  1441  	ABSWAPQ:     true,
  1442  	ACLDEMOTE:   true,
  1443  	ACLFLUSH:    true,
  1444  	ACLFLUSHOPT: true,
  1445  	ACLWB:       true,
  1446  	ACMPXCHG16B: true,
  1447  	ACMPXCHG8B:  true,
  1448  	ADECB:       true,
  1449  	ADECL:       true,
  1450  	ADECQ:       true,
  1451  	ADECW:       true,
  1452  	AFBSTP:      true,
  1453  	AFFREE:      true,
  1454  	AFLDENV:     true,
  1455  	AFSAVE:      true,
  1456  	AFSTCW:      true,
  1457  	AFSTENV:     true,
  1458  	AFSTSW:      true,
  1459  	AFXSAVE64:   true,
  1460  	AFXSAVE:     true,
  1461  	AINCB:       true,
  1462  	AINCL:       true,
  1463  	AINCQ:       true,
  1464  	AINCW:       true,
  1465  	ANEGB:       true,
  1466  	ANEGL:       true,
  1467  	ANEGQ:       true,
  1468  	ANEGW:       true,
  1469  	ANOTB:       true,
  1470  	ANOTL:       true,
  1471  	ANOTQ:       true,
  1472  	ANOTW:       true,
  1473  	APOPL:       true,
  1474  	APOPQ:       true,
  1475  	APOPW:       true,
  1476  	ARDFSBASEL:  true,
  1477  	ARDFSBASEQ:  true,
  1478  	ARDGSBASEL:  true,
  1479  	ARDGSBASEQ:  true,
  1480  	ARDPID:      true,
  1481  	ARDRANDL:    true,
  1482  	ARDRANDQ:    true,
  1483  	ARDRANDW:    true,
  1484  	ARDSEEDL:    true,
  1485  	ARDSEEDQ:    true,
  1486  	ARDSEEDW:    true,
  1487  	ASETCC:      true,
  1488  	ASETCS:      true,
  1489  	ASETEQ:      true,
  1490  	ASETGE:      true,
  1491  	ASETGT:      true,
  1492  	ASETHI:      true,
  1493  	ASETLE:      true,
  1494  	ASETLS:      true,
  1495  	ASETLT:      true,
  1496  	ASETMI:      true,
  1497  	ASETNE:      true,
  1498  	ASETOC:      true,
  1499  	ASETOS:      true,
  1500  	ASETPC:      true,
  1501  	ASETPL:      true,
  1502  	ASETPS:      true,
  1503  	ASGDT:       true,
  1504  	ASIDT:       true,
  1505  	ASLDTL:      true,
  1506  	ASLDTQ:      true,
  1507  	ASLDTW:      true,
  1508  	ASMSWL:      true,
  1509  	ASMSWQ:      true,
  1510  	ASMSWW:      true,
  1511  	ASTMXCSR:    true,
  1512  	ASTRL:       true,
  1513  	ASTRQ:       true,
  1514  	ASTRW:       true,
  1515  	AXSAVE64:    true,
  1516  	AXSAVE:      true,
  1517  	AXSAVEC64:   true,
  1518  	AXSAVEC:     true,
  1519  	AXSAVEOPT64: true,
  1520  	AXSAVEOPT:   true,
  1521  	AXSAVES64:   true,
  1522  	AXSAVES:     true,
  1523  }
  1524  
  1525  var Linkamd64 = obj.LinkArch{
  1526  	Arch:           sys.ArchAMD64,
  1527  	Init:           instinit,
  1528  	ErrorCheck:     errorCheck,
  1529  	Preprocess:     preprocess,
  1530  	Assemble:       span6,
  1531  	Progedit:       progedit,
  1532  	SEH:            populateSeh,
  1533  	UnaryDst:       unaryDst,
  1534  	DWARFRegisters: AMD64DWARFRegisters,
  1535  }
  1536  
  1537  var Link386 = obj.LinkArch{
  1538  	Arch:           sys.Arch386,
  1539  	Init:           instinit,
  1540  	Preprocess:     preprocess,
  1541  	Assemble:       span6,
  1542  	Progedit:       progedit,
  1543  	UnaryDst:       unaryDst,
  1544  	DWARFRegisters: X86DWARFRegisters,
  1545  }