github.com/rakyll/go@v0.0.0-20170216000551-64c02460d703/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.PosTable.Pos(p.Pos).String()
    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 Getcallerpc(interface{}) uintptr {
   185  	return 1
   186  }
   187  
   188  func (ctxt *Link) Dconv(a *Addr) string {
   189  	return Dconv(nil, a)
   190  }
   191  
   192  func Dconv(p *Prog, a *Addr) string {
   193  	var str string
   194  
   195  	switch a.Type {
   196  	default:
   197  		str = fmt.Sprintf("type=%d", a.Type)
   198  
   199  	case TYPE_NONE:
   200  		str = ""
   201  		if a.Name != NAME_NONE || a.Reg != 0 || a.Sym != nil {
   202  			str = fmt.Sprintf("%v(%v)(NONE)", Mconv(a), Rconv(int(a.Reg)))
   203  		}
   204  
   205  	case TYPE_REG:
   206  		// TODO(rsc): This special case is for x86 instructions like
   207  		//	PINSRQ	CX,$1,X6
   208  		// where the $1 is included in the p->to Addr.
   209  		// Move into a new field.
   210  		if a.Offset != 0 {
   211  			str = fmt.Sprintf("$%d,%v", a.Offset, Rconv(int(a.Reg)))
   212  			break
   213  		}
   214  
   215  		str = Rconv(int(a.Reg))
   216  		if a.Name != NAME_NONE || a.Sym != nil {
   217  			str = fmt.Sprintf("%v(%v)(REG)", Mconv(a), Rconv(int(a.Reg)))
   218  		}
   219  
   220  	case TYPE_BRANCH:
   221  		if a.Sym != nil {
   222  			str = fmt.Sprintf("%s(SB)", a.Sym.Name)
   223  		} else if p != nil && p.Pcond != nil {
   224  			str = fmt.Sprint(p.Pcond.Pc)
   225  		} else if a.Val != nil {
   226  			str = fmt.Sprint(a.Val.(*Prog).Pc)
   227  		} else {
   228  			str = fmt.Sprintf("%d(PC)", a.Offset)
   229  		}
   230  
   231  	case TYPE_INDIR:
   232  		str = fmt.Sprintf("*%s", Mconv(a))
   233  
   234  	case TYPE_MEM:
   235  		str = Mconv(a)
   236  		if a.Index != REG_NONE {
   237  			str += fmt.Sprintf("(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
   238  		}
   239  
   240  	case TYPE_CONST:
   241  		if a.Reg != 0 {
   242  			str = fmt.Sprintf("$%v(%v)", Mconv(a), Rconv(int(a.Reg)))
   243  		} else {
   244  			str = fmt.Sprintf("$%v", Mconv(a))
   245  		}
   246  
   247  	case TYPE_TEXTSIZE:
   248  		if a.Val.(int32) == ArgsSizeUnknown {
   249  			str = fmt.Sprintf("$%d", a.Offset)
   250  		} else {
   251  			str = fmt.Sprintf("$%d-%d", a.Offset, a.Val.(int32))
   252  		}
   253  
   254  	case TYPE_FCONST:
   255  		str = fmt.Sprintf("%.17g", a.Val.(float64))
   256  		// Make sure 1 prints as 1.0
   257  		if !strings.ContainsAny(str, ".e") {
   258  			str += ".0"
   259  		}
   260  		str = fmt.Sprintf("$(%s)", str)
   261  
   262  	case TYPE_SCONST:
   263  		str = fmt.Sprintf("$%q", a.Val.(string))
   264  
   265  	case TYPE_ADDR:
   266  		str = fmt.Sprintf("$%s", Mconv(a))
   267  
   268  	case TYPE_SHIFT:
   269  		v := int(a.Offset)
   270  		ops := "<<>>->@>"
   271  		switch GOARCH {
   272  		case "arm":
   273  			op := ops[((v>>5)&3)<<1:]
   274  			if v&(1<<4) != 0 {
   275  				str = fmt.Sprintf("R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
   276  			} else {
   277  				str = fmt.Sprintf("R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
   278  			}
   279  			if a.Reg != 0 {
   280  				str += fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
   281  			}
   282  		case "arm64":
   283  			op := ops[((v>>22)&3)<<1:]
   284  			str = fmt.Sprintf("R%d%c%c%d", (v>>16)&31, op[0], op[1], (v>>10)&63)
   285  		default:
   286  			panic("TYPE_SHIFT is not supported on " + GOARCH)
   287  		}
   288  
   289  	case TYPE_REGREG:
   290  		str = fmt.Sprintf("(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
   291  
   292  	case TYPE_REGREG2:
   293  		str = fmt.Sprintf("%v, %v", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
   294  
   295  	case TYPE_REGLIST:
   296  		str = regListConv(int(a.Offset))
   297  	}
   298  
   299  	return str
   300  }
   301  
   302  func Mconv(a *Addr) string {
   303  	var str string
   304  
   305  	switch a.Name {
   306  	default:
   307  		str = fmt.Sprintf("name=%d", a.Name)
   308  
   309  	case NAME_NONE:
   310  		switch {
   311  		case a.Reg == REG_NONE:
   312  			str = fmt.Sprint(a.Offset)
   313  		case a.Offset == 0:
   314  			str = fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
   315  		case a.Offset != 0:
   316  			str = fmt.Sprintf("%d(%v)", a.Offset, Rconv(int(a.Reg)))
   317  		}
   318  
   319  	case NAME_EXTERN:
   320  		if a.Sym != nil {
   321  			str = fmt.Sprintf("%s%s(SB)", a.Sym.Name, offConv(a.Offset))
   322  		} else {
   323  			str = fmt.Sprintf("%s(SB)", offConv(a.Offset))
   324  		}
   325  
   326  	case NAME_GOTREF:
   327  		if a.Sym != nil {
   328  			str = fmt.Sprintf("%s%s@GOT(SB)", a.Sym.Name, offConv(a.Offset))
   329  		} else {
   330  			str = fmt.Sprintf("%s@GOT(SB)", offConv(a.Offset))
   331  		}
   332  
   333  	case NAME_STATIC:
   334  		if a.Sym != nil {
   335  			str = fmt.Sprintf("%s<>%s(SB)", a.Sym.Name, offConv(a.Offset))
   336  		} else {
   337  			str = fmt.Sprintf("<>%s(SB)", offConv(a.Offset))
   338  		}
   339  
   340  	case NAME_AUTO:
   341  		if a.Sym != nil {
   342  			str = fmt.Sprintf("%s%s(SP)", a.Sym.Name, offConv(a.Offset))
   343  		} else {
   344  			str = fmt.Sprintf("%s(SP)", offConv(a.Offset))
   345  		}
   346  
   347  	case NAME_PARAM:
   348  		if a.Sym != nil {
   349  			str = fmt.Sprintf("%s%s(FP)", a.Sym.Name, offConv(a.Offset))
   350  		} else {
   351  			str = fmt.Sprintf("%s(FP)", offConv(a.Offset))
   352  		}
   353  	}
   354  	return str
   355  }
   356  
   357  func offConv(off int64) string {
   358  	if off == 0 {
   359  		return ""
   360  	}
   361  	return fmt.Sprintf("%+d", off)
   362  }
   363  
   364  type regSet struct {
   365  	lo    int
   366  	hi    int
   367  	Rconv func(int) string
   368  }
   369  
   370  // Few enough architectures that a linear scan is fastest.
   371  // Not even worth sorting.
   372  var regSpace []regSet
   373  
   374  /*
   375  	Each architecture defines a register space as a unique
   376  	integer range.
   377  	Here is the list of architectures and the base of their register spaces.
   378  */
   379  
   380  const (
   381  	// Because of masking operations in the encodings, each register
   382  	// space should start at 0 modulo some power of 2.
   383  	RBase386   = 1 * 1024
   384  	RBaseAMD64 = 2 * 1024
   385  	RBaseARM   = 3 * 1024
   386  	RBasePPC64 = 4 * 1024  // range [4k, 8k)
   387  	RBaseARM64 = 8 * 1024  // range [8k, 13k)
   388  	RBaseMIPS  = 13 * 1024 // range [13k, 14k)
   389  	RBaseS390X = 14 * 1024 // range [14k, 15k)
   390  )
   391  
   392  // RegisterRegister binds a pretty-printer (Rconv) for register
   393  // numbers to a given register number range. Lo is inclusive,
   394  // hi exclusive (valid registers are lo through hi-1).
   395  func RegisterRegister(lo, hi int, Rconv func(int) string) {
   396  	regSpace = append(regSpace, regSet{lo, hi, Rconv})
   397  }
   398  
   399  func Rconv(reg int) string {
   400  	if reg == REG_NONE {
   401  		return "NONE"
   402  	}
   403  	for i := range regSpace {
   404  		rs := &regSpace[i]
   405  		if rs.lo <= reg && reg < rs.hi {
   406  			return rs.Rconv(reg)
   407  		}
   408  	}
   409  	return fmt.Sprintf("R???%d", reg)
   410  }
   411  
   412  func regListConv(list int) string {
   413  	str := ""
   414  
   415  	for i := 0; i < 16; i++ { // TODO: 16 is ARM-specific.
   416  		if list&(1<<uint(i)) != 0 {
   417  			if str == "" {
   418  				str += "["
   419  			} else {
   420  				str += ","
   421  			}
   422  			// This is ARM-specific; R10 is g.
   423  			if i == 10 {
   424  				str += "g"
   425  			} else {
   426  				str += fmt.Sprintf("R%d", i)
   427  			}
   428  		}
   429  	}
   430  
   431  	str += "]"
   432  	return str
   433  }
   434  
   435  type opSet struct {
   436  	lo    As
   437  	names []string
   438  }
   439  
   440  // Not even worth sorting
   441  var aSpace []opSet
   442  
   443  // RegisterOpcode binds a list of instruction names
   444  // to a given instruction number range.
   445  func RegisterOpcode(lo As, Anames []string) {
   446  	if len(Anames) > AllowedOpCodes {
   447  		panic(fmt.Sprintf("too many instructions, have %d max %d", len(Anames), AllowedOpCodes))
   448  	}
   449  	aSpace = append(aSpace, opSet{lo, Anames})
   450  }
   451  
   452  func (a As) String() string {
   453  	if 0 <= a && int(a) < len(Anames) {
   454  		return Anames[a]
   455  	}
   456  	for i := range aSpace {
   457  		as := &aSpace[i]
   458  		if as.lo <= a && int(a-as.lo) < len(as.names) {
   459  			return as.names[a-as.lo]
   460  		}
   461  	}
   462  	return fmt.Sprintf("A???%d", a)
   463  }
   464  
   465  var Anames = []string{
   466  	"XXX",
   467  	"CALL",
   468  	"DUFFCOPY",
   469  	"DUFFZERO",
   470  	"END",
   471  	"FUNCDATA",
   472  	"JMP",
   473  	"NOP",
   474  	"PCDATA",
   475  	"RET",
   476  	"TEXT",
   477  	"UNDEF",
   478  	"USEFIELD",
   479  	"VARDEF",
   480  	"VARKILL",
   481  	"VARLIVE",
   482  }
   483  
   484  func Bool2int(b bool) int {
   485  	// The compiler currently only optimizes this form.
   486  	// See issue 6011.
   487  	var i int
   488  	if b {
   489  		i = 1
   490  	} else {
   491  		i = 0
   492  	}
   493  	return i
   494  }