github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/src/cmd/internal/obj/util.go (about)

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package obj
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"log"
    11  	"os"
    12  	"strings"
    13  	"time"
    14  )
    15  
    16  const REG_NONE = 0
    17  
    18  var start time.Time
    19  
    20  func Cputime() float64 {
    21  	if start.IsZero() {
    22  		start = time.Now()
    23  	}
    24  	return time.Since(start).Seconds()
    25  }
    26  
    27  func envOr(key, value string) string {
    28  	if x := os.Getenv(key); x != "" {
    29  		return x
    30  	}
    31  	return value
    32  }
    33  
    34  var (
    35  	GOROOT  = envOr("GOROOT", defaultGOROOT)
    36  	GOARCH  = envOr("GOARCH", defaultGOARCH)
    37  	GOOS    = envOr("GOOS", defaultGOOS)
    38  	GO386   = envOr("GO386", defaultGO386)
    39  	GOARM   = goarm()
    40  	Version = version
    41  )
    42  
    43  func goarm() int {
    44  	switch v := envOr("GOARM", defaultGOARM); v {
    45  	case "5":
    46  		return 5
    47  	case "6":
    48  		return 6
    49  	case "7":
    50  		return 7
    51  	}
    52  	// Fail here, rather than validate at multiple call sites.
    53  	log.Fatalf("Invalid GOARM value. Must be 5, 6, or 7.")
    54  	panic("unreachable")
    55  }
    56  
    57  func Getgoextlinkenabled() string {
    58  	return envOr("GO_EXTLINK_ENABLED", defaultGO_EXTLINK_ENABLED)
    59  }
    60  
    61  func (p *Prog) Line() string {
    62  	return p.Ctxt.LineHist.LineString(int(p.Lineno))
    63  }
    64  
    65  var armCondCode = []string{
    66  	".EQ",
    67  	".NE",
    68  	".CS",
    69  	".CC",
    70  	".MI",
    71  	".PL",
    72  	".VS",
    73  	".VC",
    74  	".HI",
    75  	".LS",
    76  	".GE",
    77  	".LT",
    78  	".GT",
    79  	".LE",
    80  	"",
    81  	".NV",
    82  }
    83  
    84  /* ARM scond byte */
    85  const (
    86  	C_SCOND     = (1 << 4) - 1
    87  	C_SBIT      = 1 << 4
    88  	C_PBIT      = 1 << 5
    89  	C_WBIT      = 1 << 6
    90  	C_FBIT      = 1 << 7
    91  	C_UBIT      = 1 << 7
    92  	C_SCOND_XOR = 14
    93  )
    94  
    95  // CConv formats ARM condition codes.
    96  func CConv(s uint8) string {
    97  	if s == 0 {
    98  		return ""
    99  	}
   100  	sc := armCondCode[(s&C_SCOND)^C_SCOND_XOR]
   101  	if s&C_SBIT != 0 {
   102  		sc += ".S"
   103  	}
   104  	if s&C_PBIT != 0 {
   105  		sc += ".P"
   106  	}
   107  	if s&C_WBIT != 0 {
   108  		sc += ".W"
   109  	}
   110  	if s&C_UBIT != 0 { /* ambiguous with FBIT */
   111  		sc += ".U"
   112  	}
   113  	return sc
   114  }
   115  
   116  func (p *Prog) String() string {
   117  	if p == nil {
   118  		return "<nil Prog>"
   119  	}
   120  
   121  	if p.Ctxt == nil {
   122  		return "<Prog without ctxt>"
   123  	}
   124  
   125  	sc := CConv(p.Scond)
   126  
   127  	var buf bytes.Buffer
   128  
   129  	fmt.Fprintf(&buf, "%.5d (%v)\t%v%s", p.Pc, p.Line(), p.As, sc)
   130  	sep := "\t"
   131  	quadOpAmd64 := p.RegTo2 == -1
   132  	if quadOpAmd64 {
   133  		fmt.Fprintf(&buf, "%s$%d", sep, p.From3.Offset)
   134  		sep = ", "
   135  	}
   136  	if p.From.Type != TYPE_NONE {
   137  		fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.From))
   138  		sep = ", "
   139  	}
   140  	if p.Reg != REG_NONE {
   141  		// Should not happen but might as well show it if it does.
   142  		fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.Reg)))
   143  		sep = ", "
   144  	}
   145  	if p.From3Type() != TYPE_NONE {
   146  		if p.From3.Type == TYPE_CONST && p.As == ATEXT {
   147  			// Special case - omit $.
   148  			fmt.Fprintf(&buf, "%s%d", sep, p.From3.Offset)
   149  		} else if quadOpAmd64 {
   150  			fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.From3.Reg)))
   151  		} else {
   152  			fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, p.From3))
   153  		}
   154  		sep = ", "
   155  	}
   156  	if p.To.Type != TYPE_NONE {
   157  		fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To))
   158  	}
   159  	if p.RegTo2 != REG_NONE && !quadOpAmd64 {
   160  		fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.RegTo2)))
   161  	}
   162  	return buf.String()
   163  }
   164  
   165  func (ctxt *Link) NewProg() *Prog {
   166  	var p *Prog
   167  	if i := ctxt.allocIdx; i < len(ctxt.progs) {
   168  		p = &ctxt.progs[i]
   169  		ctxt.allocIdx = i + 1
   170  	} else {
   171  		p = new(Prog) // should be the only call to this; all others should use ctxt.NewProg
   172  	}
   173  	p.Ctxt = ctxt
   174  	return p
   175  }
   176  func (ctxt *Link) freeProgs() {
   177  	s := ctxt.progs[:ctxt.allocIdx]
   178  	for i := range s {
   179  		s[i] = Prog{}
   180  	}
   181  	ctxt.allocIdx = 0
   182  }
   183  
   184  func (ctxt *Link) Line(n int) string {
   185  	return ctxt.LineHist.LineString(n)
   186  }
   187  
   188  func Getcallerpc(interface{}) uintptr {
   189  	return 1
   190  }
   191  
   192  func (ctxt *Link) Dconv(a *Addr) string {
   193  	return Dconv(nil, a)
   194  }
   195  
   196  func Dconv(p *Prog, a *Addr) string {
   197  	var str string
   198  
   199  	switch a.Type {
   200  	default:
   201  		str = fmt.Sprintf("type=%d", a.Type)
   202  
   203  	case TYPE_NONE:
   204  		str = ""
   205  		if a.Name != NAME_NONE || a.Reg != 0 || a.Sym != nil {
   206  			str = fmt.Sprintf("%v(%v)(NONE)", Mconv(a), Rconv(int(a.Reg)))
   207  		}
   208  
   209  	case TYPE_REG:
   210  		// TODO(rsc): This special case is for x86 instructions like
   211  		//	PINSRQ	CX,$1,X6
   212  		// where the $1 is included in the p->to Addr.
   213  		// Move into a new field.
   214  		if a.Offset != 0 {
   215  			str = fmt.Sprintf("$%d,%v", a.Offset, Rconv(int(a.Reg)))
   216  			break
   217  		}
   218  
   219  		str = Rconv(int(a.Reg))
   220  		if a.Name != NAME_NONE || a.Sym != nil {
   221  			str = fmt.Sprintf("%v(%v)(REG)", Mconv(a), Rconv(int(a.Reg)))
   222  		}
   223  
   224  	case TYPE_BRANCH:
   225  		if a.Sym != nil {
   226  			str = fmt.Sprintf("%s(SB)", a.Sym.Name)
   227  		} else if p != nil && p.Pcond != nil {
   228  			str = fmt.Sprint(p.Pcond.Pc)
   229  		} else if a.Val != nil {
   230  			str = fmt.Sprint(a.Val.(*Prog).Pc)
   231  		} else {
   232  			str = fmt.Sprintf("%d(PC)", a.Offset)
   233  		}
   234  
   235  	case TYPE_INDIR:
   236  		str = fmt.Sprintf("*%s", Mconv(a))
   237  
   238  	case TYPE_MEM:
   239  		str = Mconv(a)
   240  		if a.Index != REG_NONE {
   241  			str += fmt.Sprintf("(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
   242  		}
   243  
   244  	case TYPE_CONST:
   245  		if a.Reg != 0 {
   246  			str = fmt.Sprintf("$%v(%v)", Mconv(a), Rconv(int(a.Reg)))
   247  		} else {
   248  			str = fmt.Sprintf("$%v", Mconv(a))
   249  		}
   250  
   251  	case TYPE_TEXTSIZE:
   252  		if a.Val.(int32) == ArgsSizeUnknown {
   253  			str = fmt.Sprintf("$%d", a.Offset)
   254  		} else {
   255  			str = fmt.Sprintf("$%d-%d", a.Offset, a.Val.(int32))
   256  		}
   257  
   258  	case TYPE_FCONST:
   259  		str = fmt.Sprintf("%.17g", a.Val.(float64))
   260  		// Make sure 1 prints as 1.0
   261  		if !strings.ContainsAny(str, ".e") {
   262  			str += ".0"
   263  		}
   264  		str = fmt.Sprintf("$(%s)", str)
   265  
   266  	case TYPE_SCONST:
   267  		str = fmt.Sprintf("$%q", a.Val.(string))
   268  
   269  	case TYPE_ADDR:
   270  		str = fmt.Sprintf("$%s", Mconv(a))
   271  
   272  	case TYPE_SHIFT:
   273  		v := int(a.Offset)
   274  		ops := "<<>>->@>"
   275  		switch GOARCH {
   276  		case "arm":
   277  			op := ops[((v>>5)&3)<<1:]
   278  			if v&(1<<4) != 0 {
   279  				str = fmt.Sprintf("R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
   280  			} else {
   281  				str = fmt.Sprintf("R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
   282  			}
   283  			if a.Reg != 0 {
   284  				str += fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
   285  			}
   286  		case "arm64":
   287  			op := ops[((v>>22)&3)<<1:]
   288  			str = fmt.Sprintf("R%d%c%c%d", (v>>16)&31, op[0], op[1], (v>>10)&63)
   289  		default:
   290  			panic("TYPE_SHIFT is not supported on " + GOARCH)
   291  		}
   292  
   293  	case TYPE_REGREG:
   294  		str = fmt.Sprintf("(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
   295  
   296  	case TYPE_REGREG2:
   297  		str = fmt.Sprintf("%v, %v", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
   298  
   299  	case TYPE_REGLIST:
   300  		str = regListConv(int(a.Offset))
   301  	}
   302  
   303  	return str
   304  }
   305  
   306  func Mconv(a *Addr) string {
   307  	var str string
   308  
   309  	switch a.Name {
   310  	default:
   311  		str = fmt.Sprintf("name=%d", a.Name)
   312  
   313  	case NAME_NONE:
   314  		switch {
   315  		case a.Reg == REG_NONE:
   316  			str = fmt.Sprint(a.Offset)
   317  		case a.Offset == 0:
   318  			str = fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
   319  		case a.Offset != 0:
   320  			str = fmt.Sprintf("%d(%v)", a.Offset, Rconv(int(a.Reg)))
   321  		}
   322  
   323  	case NAME_EXTERN:
   324  		if a.Sym != nil {
   325  			str = fmt.Sprintf("%s%s(SB)", a.Sym.Name, offConv(a.Offset))
   326  		} else {
   327  			str = fmt.Sprintf("%s(SB)", offConv(a.Offset))
   328  		}
   329  
   330  	case NAME_GOTREF:
   331  		if a.Sym != nil {
   332  			str = fmt.Sprintf("%s%s@GOT(SB)", a.Sym.Name, offConv(a.Offset))
   333  		} else {
   334  			str = fmt.Sprintf("%s@GOT(SB)", offConv(a.Offset))
   335  		}
   336  
   337  	case NAME_STATIC:
   338  		if a.Sym != nil {
   339  			str = fmt.Sprintf("%s<>%s(SB)", a.Sym.Name, offConv(a.Offset))
   340  		} else {
   341  			str = fmt.Sprintf("<>%s(SB)", offConv(a.Offset))
   342  		}
   343  
   344  	case NAME_AUTO:
   345  		if a.Sym != nil {
   346  			str = fmt.Sprintf("%s%s(SP)", a.Sym.Name, offConv(a.Offset))
   347  		} else {
   348  			str = fmt.Sprintf("%s(SP)", offConv(a.Offset))
   349  		}
   350  
   351  	case NAME_PARAM:
   352  		if a.Sym != nil {
   353  			str = fmt.Sprintf("%s%s(FP)", a.Sym.Name, offConv(a.Offset))
   354  		} else {
   355  			str = fmt.Sprintf("%s(FP)", offConv(a.Offset))
   356  		}
   357  	}
   358  	return str
   359  }
   360  
   361  func offConv(off int64) string {
   362  	if off == 0 {
   363  		return ""
   364  	}
   365  	return fmt.Sprintf("%+d", off)
   366  }
   367  
   368  type regSet struct {
   369  	lo    int
   370  	hi    int
   371  	Rconv func(int) string
   372  }
   373  
   374  // Few enough architectures that a linear scan is fastest.
   375  // Not even worth sorting.
   376  var regSpace []regSet
   377  
   378  /*
   379  	Each architecture defines a register space as a unique
   380  	integer range.
   381  	Here is the list of architectures and the base of their register spaces.
   382  */
   383  
   384  const (
   385  	// Because of masking operations in the encodings, each register
   386  	// space should start at 0 modulo some power of 2.
   387  	RBase386   = 1 * 1024
   388  	RBaseAMD64 = 2 * 1024
   389  	RBaseARM   = 3 * 1024
   390  	RBasePPC64 = 4 * 1024  // range [4k, 8k)
   391  	RBaseARM64 = 8 * 1024  // range [8k, 13k)
   392  	RBaseMIPS  = 13 * 1024 // range [13k, 14k)
   393  	RBaseS390X = 14 * 1024 // range [14k, 15k)
   394  )
   395  
   396  // RegisterRegister binds a pretty-printer (Rconv) for register
   397  // numbers to a given register number range. Lo is inclusive,
   398  // hi exclusive (valid registers are lo through hi-1).
   399  func RegisterRegister(lo, hi int, Rconv func(int) string) {
   400  	regSpace = append(regSpace, regSet{lo, hi, Rconv})
   401  }
   402  
   403  func Rconv(reg int) string {
   404  	if reg == REG_NONE {
   405  		return "NONE"
   406  	}
   407  	for i := range regSpace {
   408  		rs := &regSpace[i]
   409  		if rs.lo <= reg && reg < rs.hi {
   410  			return rs.Rconv(reg)
   411  		}
   412  	}
   413  	return fmt.Sprintf("R???%d", reg)
   414  }
   415  
   416  func regListConv(list int) string {
   417  	str := ""
   418  
   419  	for i := 0; i < 16; i++ { // TODO: 16 is ARM-specific.
   420  		if list&(1<<uint(i)) != 0 {
   421  			if str == "" {
   422  				str += "["
   423  			} else {
   424  				str += ","
   425  			}
   426  			// This is ARM-specific; R10 is g.
   427  			if i == 10 {
   428  				str += "g"
   429  			} else {
   430  				str += fmt.Sprintf("R%d", i)
   431  			}
   432  		}
   433  	}
   434  
   435  	str += "]"
   436  	return str
   437  }
   438  
   439  type opSet struct {
   440  	lo    As
   441  	names []string
   442  }
   443  
   444  // Not even worth sorting
   445  var aSpace []opSet
   446  
   447  // RegisterOpcode binds a list of instruction names
   448  // to a given instruction number range.
   449  func RegisterOpcode(lo As, Anames []string) {
   450  	if len(Anames) > AllowedOpCodes {
   451  		panic(fmt.Sprintf("too many instructions, have %d max %d", len(Anames), AllowedOpCodes))
   452  	}
   453  	aSpace = append(aSpace, opSet{lo, Anames})
   454  }
   455  
   456  func (a As) String() string {
   457  	if 0 <= a && int(a) < len(Anames) {
   458  		return Anames[a]
   459  	}
   460  	for i := range aSpace {
   461  		as := &aSpace[i]
   462  		if as.lo <= a && int(a-as.lo) < len(as.names) {
   463  			return as.names[a-as.lo]
   464  		}
   465  	}
   466  	return fmt.Sprintf("A???%d", a)
   467  }
   468  
   469  var Anames = []string{
   470  	"XXX",
   471  	"CALL",
   472  	"DUFFCOPY",
   473  	"DUFFZERO",
   474  	"END",
   475  	"FUNCDATA",
   476  	"JMP",
   477  	"NOP",
   478  	"PCDATA",
   479  	"RET",
   480  	"TEXT",
   481  	"TYPE",
   482  	"UNDEF",
   483  	"USEFIELD",
   484  	"VARDEF",
   485  	"VARKILL",
   486  	"VARLIVE",
   487  }
   488  
   489  func Bool2int(b bool) int {
   490  	// The compiler currently only optimizes this form.
   491  	// See issue 6011.
   492  	var i int
   493  	if b {
   494  		i = 1
   495  	} else {
   496  		i = 0
   497  	}
   498  	return i
   499  }