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