github.com/riscv/riscv-go@v0.0.0-20200123204226-124ebd6fcc8e/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  	RBaseRISCV = 15 * 1024 // range [15k, 16k)
   391  )
   392  
   393  // RegisterRegister binds a pretty-printer (Rconv) for register
   394  // numbers to a given register number range. Lo is inclusive,
   395  // hi exclusive (valid registers are lo through hi-1).
   396  func RegisterRegister(lo, hi int, Rconv func(int) string) {
   397  	regSpace = append(regSpace, regSet{lo, hi, Rconv})
   398  }
   399  
   400  func Rconv(reg int) string {
   401  	if reg == REG_NONE {
   402  		return "NONE"
   403  	}
   404  	for i := range regSpace {
   405  		rs := &regSpace[i]
   406  		if rs.lo <= reg && reg < rs.hi {
   407  			return rs.Rconv(reg)
   408  		}
   409  	}
   410  	return fmt.Sprintf("R???%d", reg)
   411  }
   412  
   413  func regListConv(list int) string {
   414  	str := ""
   415  
   416  	for i := 0; i < 16; i++ { // TODO: 16 is ARM-specific.
   417  		if list&(1<<uint(i)) != 0 {
   418  			if str == "" {
   419  				str += "["
   420  			} else {
   421  				str += ","
   422  			}
   423  			// This is ARM-specific; R10 is g.
   424  			if i == 10 {
   425  				str += "g"
   426  			} else {
   427  				str += fmt.Sprintf("R%d", i)
   428  			}
   429  		}
   430  	}
   431  
   432  	str += "]"
   433  	return str
   434  }
   435  
   436  type opSet struct {
   437  	lo    As
   438  	names []string
   439  }
   440  
   441  // Not even worth sorting
   442  var aSpace []opSet
   443  
   444  // RegisterOpcode binds a list of instruction names
   445  // to a given instruction number range.
   446  func RegisterOpcode(lo As, Anames []string) {
   447  	if len(Anames) > AllowedOpCodes {
   448  		panic(fmt.Sprintf("too many instructions, have %d max %d", len(Anames), AllowedOpCodes))
   449  	}
   450  	aSpace = append(aSpace, opSet{lo, Anames})
   451  }
   452  
   453  func (a As) String() string {
   454  	if 0 <= a && int(a) < len(Anames) {
   455  		return Anames[a]
   456  	}
   457  	for i := range aSpace {
   458  		as := &aSpace[i]
   459  		if as.lo <= a && int(a-as.lo) < len(as.names) {
   460  			return as.names[a-as.lo]
   461  		}
   462  	}
   463  	return fmt.Sprintf("A???%d", a)
   464  }
   465  
   466  var Anames = []string{
   467  	"XXX",
   468  	"CALL",
   469  	"DUFFCOPY",
   470  	"DUFFZERO",
   471  	"END",
   472  	"FUNCDATA",
   473  	"JMP",
   474  	"NOP",
   475  	"PCDATA",
   476  	"RET",
   477  	"TEXT",
   478  	"TYPE",
   479  	"UNDEF",
   480  	"USEFIELD",
   481  	"VARDEF",
   482  	"VARKILL",
   483  	"VARLIVE",
   484  }
   485  
   486  func Bool2int(b bool) int {
   487  	// The compiler currently only optimizes this form.
   488  	// See issue 6011.
   489  	var i int
   490  	if b {
   491  		i = 1
   492  	} else {
   493  		i = 0
   494  	}
   495  	return i
   496  }