github.com/huandu/go@v0.0.0-20151114150818-04e615e41150/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  	"bufio"
     9  	"bytes"
    10  	"fmt"
    11  	"io"
    12  	"log"
    13  	"os"
    14  	"strconv"
    15  	"strings"
    16  	"time"
    17  )
    18  
    19  const REG_NONE = 0
    20  
    21  var start time.Time
    22  
    23  func Cputime() float64 {
    24  	if start.IsZero() {
    25  		start = time.Now()
    26  	}
    27  	return time.Since(start).Seconds()
    28  }
    29  
    30  type Biobuf struct {
    31  	f       *os.File
    32  	r       *bufio.Reader
    33  	w       *bufio.Writer
    34  	linelen int
    35  }
    36  
    37  func Bopenw(name string) (*Biobuf, error) {
    38  	f, err := os.Create(name)
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  	return &Biobuf{f: f, w: bufio.NewWriter(f)}, nil
    43  }
    44  
    45  func Bopenr(name string) (*Biobuf, error) {
    46  	f, err := os.Open(name)
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  	return &Biobuf{f: f, r: bufio.NewReader(f)}, nil
    51  }
    52  
    53  func Binitw(w io.Writer) *Biobuf {
    54  	return &Biobuf{w: bufio.NewWriter(w)}
    55  }
    56  
    57  func (b *Biobuf) Write(p []byte) (int, error) {
    58  	return b.w.Write(p)
    59  }
    60  
    61  func Bwritestring(b *Biobuf, p string) (int, error) {
    62  	return b.w.WriteString(p)
    63  }
    64  
    65  func Bseek(b *Biobuf, offset int64, whence int) int64 {
    66  	if b.w != nil {
    67  		if err := b.w.Flush(); err != nil {
    68  			log.Fatalf("writing output: %v", err)
    69  		}
    70  	} else if b.r != nil {
    71  		if whence == 1 {
    72  			offset -= int64(b.r.Buffered())
    73  		}
    74  	}
    75  	off, err := b.f.Seek(offset, whence)
    76  	if err != nil {
    77  		log.Fatalf("seeking in output: %v", err)
    78  	}
    79  	if b.r != nil {
    80  		b.r.Reset(b.f)
    81  	}
    82  	return off
    83  }
    84  
    85  func Boffset(b *Biobuf) int64 {
    86  	if b.w != nil {
    87  		if err := b.w.Flush(); err != nil {
    88  			log.Fatalf("writing output: %v", err)
    89  		}
    90  	}
    91  	off, err := b.f.Seek(0, 1)
    92  	if err != nil {
    93  		log.Fatalf("seeking in output [0, 1]: %v", err)
    94  	}
    95  	if b.r != nil {
    96  		off -= int64(b.r.Buffered())
    97  	}
    98  	return off
    99  }
   100  
   101  func (b *Biobuf) Flush() error {
   102  	return b.w.Flush()
   103  }
   104  
   105  func Bputc(b *Biobuf, c byte) {
   106  	b.w.WriteByte(c)
   107  }
   108  
   109  const Beof = -1
   110  
   111  func Bread(b *Biobuf, p []byte) int {
   112  	n, err := io.ReadFull(b.r, p)
   113  	if n == 0 {
   114  		if err != nil && err != io.EOF {
   115  			n = -1
   116  		}
   117  	}
   118  	return n
   119  }
   120  
   121  func Bgetc(b *Biobuf) int {
   122  	c, err := b.r.ReadByte()
   123  	if err != nil {
   124  		return -1
   125  	}
   126  	return int(c)
   127  }
   128  
   129  func Bgetrune(b *Biobuf) int {
   130  	r, _, err := b.r.ReadRune()
   131  	if err != nil {
   132  		return -1
   133  	}
   134  	return int(r)
   135  }
   136  
   137  func Bungetrune(b *Biobuf) {
   138  	b.r.UnreadRune()
   139  }
   140  
   141  func (b *Biobuf) Read(p []byte) (int, error) {
   142  	return b.r.Read(p)
   143  }
   144  
   145  func (b *Biobuf) Peek(n int) ([]byte, error) {
   146  	return b.r.Peek(n)
   147  }
   148  
   149  func Brdline(b *Biobuf, delim int) string {
   150  	s, err := b.r.ReadBytes(byte(delim))
   151  	if err != nil {
   152  		log.Fatalf("reading input: %v", err)
   153  	}
   154  	b.linelen = len(s)
   155  	return string(s)
   156  }
   157  
   158  func Brdstr(b *Biobuf, delim int, cut int) string {
   159  	s, err := b.r.ReadString(byte(delim))
   160  	if err != nil {
   161  		log.Fatalf("reading input: %v", err)
   162  	}
   163  	if len(s) > 0 && cut > 0 {
   164  		s = s[:len(s)-1]
   165  	}
   166  	return s
   167  }
   168  
   169  func Access(name string, mode int) int {
   170  	if mode != 0 {
   171  		panic("bad access")
   172  	}
   173  	_, err := os.Stat(name)
   174  	if err != nil {
   175  		return -1
   176  	}
   177  	return 0
   178  }
   179  
   180  func Blinelen(b *Biobuf) int {
   181  	return b.linelen
   182  }
   183  
   184  func Bterm(b *Biobuf) error {
   185  	var err error
   186  	if b.w != nil {
   187  		err = b.w.Flush()
   188  	}
   189  	err1 := b.f.Close()
   190  	if err == nil {
   191  		err = err1
   192  	}
   193  	return err
   194  }
   195  
   196  func envOr(key, value string) string {
   197  	if x := os.Getenv(key); x != "" {
   198  		return x
   199  	}
   200  	return value
   201  }
   202  
   203  func Getgoroot() string {
   204  	return envOr("GOROOT", defaultGOROOT)
   205  }
   206  
   207  func Getgoarch() string {
   208  	return envOr("GOARCH", defaultGOARCH)
   209  }
   210  
   211  func Getgoos() string {
   212  	return envOr("GOOS", defaultGOOS)
   213  }
   214  
   215  func Getgoarm() string {
   216  	switch v := envOr("GOARM", defaultGOARM); v {
   217  	case "5", "6", "7":
   218  		return v
   219  	}
   220  	// Fail here, rather than validate at multiple call sites.
   221  	log.Fatalf("Invalid GOARM value. Must be 5, 6, or 7.")
   222  	panic("unreachable")
   223  }
   224  
   225  func Getgo386() string {
   226  	// Validated by cmd/compile.
   227  	return envOr("GO386", defaultGO386)
   228  }
   229  
   230  func Getgoextlinkenabled() string {
   231  	return envOr("GO_EXTLINK_ENABLED", defaultGO_EXTLINK_ENABLED)
   232  }
   233  
   234  func Getgoversion() string {
   235  	return version
   236  }
   237  
   238  func Atoi(s string) int {
   239  	i, _ := strconv.Atoi(s)
   240  	return i
   241  }
   242  
   243  func (p *Prog) Line() string {
   244  	return p.Ctxt.LineHist.LineString(int(p.Lineno))
   245  }
   246  
   247  var armCondCode = []string{
   248  	".EQ",
   249  	".NE",
   250  	".CS",
   251  	".CC",
   252  	".MI",
   253  	".PL",
   254  	".VS",
   255  	".VC",
   256  	".HI",
   257  	".LS",
   258  	".GE",
   259  	".LT",
   260  	".GT",
   261  	".LE",
   262  	"",
   263  	".NV",
   264  }
   265  
   266  /* ARM scond byte */
   267  const (
   268  	C_SCOND     = (1 << 4) - 1
   269  	C_SBIT      = 1 << 4
   270  	C_PBIT      = 1 << 5
   271  	C_WBIT      = 1 << 6
   272  	C_FBIT      = 1 << 7
   273  	C_UBIT      = 1 << 7
   274  	C_SCOND_XOR = 14
   275  )
   276  
   277  // CConv formats ARM condition codes.
   278  func CConv(s uint8) string {
   279  	if s == 0 {
   280  		return ""
   281  	}
   282  	sc := armCondCode[(s&C_SCOND)^C_SCOND_XOR]
   283  	if s&C_SBIT != 0 {
   284  		sc += ".S"
   285  	}
   286  	if s&C_PBIT != 0 {
   287  		sc += ".P"
   288  	}
   289  	if s&C_WBIT != 0 {
   290  		sc += ".W"
   291  	}
   292  	if s&C_UBIT != 0 { /* ambiguous with FBIT */
   293  		sc += ".U"
   294  	}
   295  	return sc
   296  }
   297  
   298  func (p *Prog) String() string {
   299  	if p.Ctxt == nil {
   300  		return "<Prog without ctxt>"
   301  	}
   302  
   303  	sc := CConv(p.Scond)
   304  
   305  	var buf bytes.Buffer
   306  
   307  	fmt.Fprintf(&buf, "%.5d (%v)\t%v%s", p.Pc, p.Line(), Aconv(int(p.As)), sc)
   308  	sep := "\t"
   309  	if p.From.Type != TYPE_NONE {
   310  		fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.From))
   311  		sep = ", "
   312  	}
   313  	if p.Reg != REG_NONE {
   314  		// Should not happen but might as well show it if it does.
   315  		fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.Reg)))
   316  		sep = ", "
   317  	}
   318  	if p.From3Type() != TYPE_NONE {
   319  		if p.From3.Type == TYPE_CONST && (p.As == ADATA || p.As == ATEXT || p.As == AGLOBL) {
   320  			// Special case - omit $.
   321  			fmt.Fprintf(&buf, "%s%d", sep, p.From3.Offset)
   322  		} else {
   323  			fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, p.From3))
   324  		}
   325  		sep = ", "
   326  	}
   327  	if p.To.Type != TYPE_NONE {
   328  		fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To))
   329  	}
   330  	if p.RegTo2 != REG_NONE {
   331  		fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.RegTo2)))
   332  	}
   333  	return buf.String()
   334  }
   335  
   336  func (ctxt *Link) NewProg() *Prog {
   337  	p := new(Prog) // should be the only call to this; all others should use ctxt.NewProg
   338  	p.Ctxt = ctxt
   339  	return p
   340  }
   341  
   342  func (ctxt *Link) Line(n int) string {
   343  	return ctxt.LineHist.LineString(n)
   344  }
   345  
   346  func Getcallerpc(interface{}) uintptr {
   347  	return 1
   348  }
   349  
   350  func (ctxt *Link) Dconv(a *Addr) string {
   351  	return Dconv(nil, a)
   352  }
   353  
   354  func Dconv(p *Prog, a *Addr) string {
   355  	var str string
   356  
   357  	switch a.Type {
   358  	default:
   359  		str = fmt.Sprintf("type=%d", a.Type)
   360  
   361  	case TYPE_NONE:
   362  		str = ""
   363  		if a.Name != NAME_NONE || a.Reg != 0 || a.Sym != nil {
   364  			str = fmt.Sprintf("%v(%v)(NONE)", Mconv(a), Rconv(int(a.Reg)))
   365  		}
   366  
   367  	case TYPE_REG:
   368  		// TODO(rsc): This special case is for x86 instructions like
   369  		//	PINSRQ	CX,$1,X6
   370  		// where the $1 is included in the p->to Addr.
   371  		// Move into a new field.
   372  		if a.Offset != 0 {
   373  			str = fmt.Sprintf("$%d,%v", a.Offset, Rconv(int(a.Reg)))
   374  			break
   375  		}
   376  
   377  		str = Rconv(int(a.Reg))
   378  		if a.Name != TYPE_NONE || a.Sym != nil {
   379  			str = fmt.Sprintf("%v(%v)(REG)", Mconv(a), Rconv(int(a.Reg)))
   380  		}
   381  
   382  	case TYPE_BRANCH:
   383  		if a.Sym != nil {
   384  			str = fmt.Sprintf("%s(SB)", a.Sym.Name)
   385  		} else if p != nil && p.Pcond != nil {
   386  			str = fmt.Sprint(p.Pcond.Pc)
   387  		} else if a.Val != nil {
   388  			str = fmt.Sprint(a.Val.(*Prog).Pc)
   389  		} else {
   390  			str = fmt.Sprintf("%d(PC)", a.Offset)
   391  		}
   392  
   393  	case TYPE_INDIR:
   394  		str = fmt.Sprintf("*%s", Mconv(a))
   395  
   396  	case TYPE_MEM:
   397  		str = Mconv(a)
   398  		if a.Index != REG_NONE {
   399  			str += fmt.Sprintf("(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
   400  		}
   401  
   402  	case TYPE_CONST:
   403  		if a.Reg != 0 {
   404  			str = fmt.Sprintf("$%v(%v)", Mconv(a), Rconv(int(a.Reg)))
   405  		} else {
   406  			str = fmt.Sprintf("$%v", Mconv(a))
   407  		}
   408  
   409  	case TYPE_TEXTSIZE:
   410  		if a.Val.(int32) == ArgsSizeUnknown {
   411  			str = fmt.Sprintf("$%d", a.Offset)
   412  		} else {
   413  			str = fmt.Sprintf("$%d-%d", a.Offset, a.Val.(int32))
   414  		}
   415  
   416  	case TYPE_FCONST:
   417  		str = fmt.Sprintf("%.17g", a.Val.(float64))
   418  		// Make sure 1 prints as 1.0
   419  		if !strings.ContainsAny(str, ".e") {
   420  			str += ".0"
   421  		}
   422  		str = fmt.Sprintf("$(%s)", str)
   423  
   424  	case TYPE_SCONST:
   425  		str = fmt.Sprintf("$%q", a.Val.(string))
   426  
   427  	case TYPE_ADDR:
   428  		str = fmt.Sprintf("$%s", Mconv(a))
   429  
   430  	case TYPE_SHIFT:
   431  		v := int(a.Offset)
   432  		op := string("<<>>->@>"[((v>>5)&3)<<1:])
   433  		if v&(1<<4) != 0 {
   434  			str = fmt.Sprintf("R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
   435  		} else {
   436  			str = fmt.Sprintf("R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
   437  		}
   438  		if a.Reg != 0 {
   439  			str += fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
   440  		}
   441  
   442  	case TYPE_REGREG:
   443  		str = fmt.Sprintf("(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
   444  
   445  	case TYPE_REGREG2:
   446  		str = fmt.Sprintf("%v, %v", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
   447  
   448  	case TYPE_REGLIST:
   449  		str = regListConv(int(a.Offset))
   450  	}
   451  
   452  	return str
   453  }
   454  
   455  func Mconv(a *Addr) string {
   456  	var str string
   457  
   458  	switch a.Name {
   459  	default:
   460  		str = fmt.Sprintf("name=%d", a.Name)
   461  
   462  	case NAME_NONE:
   463  		switch {
   464  		case a.Reg == REG_NONE:
   465  			str = fmt.Sprint(a.Offset)
   466  		case a.Offset == 0:
   467  			str = fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
   468  		case a.Offset != 0:
   469  			str = fmt.Sprintf("%d(%v)", a.Offset, Rconv(int(a.Reg)))
   470  		}
   471  
   472  	case NAME_EXTERN:
   473  		str = fmt.Sprintf("%s%s(SB)", a.Sym.Name, offConv(a.Offset))
   474  
   475  	case NAME_GOTREF:
   476  		str = fmt.Sprintf("%s%s@GOT(SB)", a.Sym.Name, offConv(a.Offset))
   477  
   478  	case NAME_STATIC:
   479  		str = fmt.Sprintf("%s<>%s(SB)", a.Sym.Name, offConv(a.Offset))
   480  
   481  	case NAME_AUTO:
   482  		if a.Sym != nil {
   483  			str = fmt.Sprintf("%s%s(SP)", a.Sym.Name, offConv(a.Offset))
   484  		} else {
   485  			str = fmt.Sprintf("%s(SP)", offConv(a.Offset))
   486  		}
   487  
   488  	case NAME_PARAM:
   489  		if a.Sym != nil {
   490  			str = fmt.Sprintf("%s%s(FP)", a.Sym.Name, offConv(a.Offset))
   491  		} else {
   492  			str = fmt.Sprintf("%s(FP)", offConv(a.Offset))
   493  		}
   494  	}
   495  	return str
   496  }
   497  
   498  func offConv(off int64) string {
   499  	if off == 0 {
   500  		return ""
   501  	}
   502  	return fmt.Sprintf("%+d", off)
   503  }
   504  
   505  type regSet struct {
   506  	lo    int
   507  	hi    int
   508  	Rconv func(int) string
   509  }
   510  
   511  // Few enough architectures that a linear scan is fastest.
   512  // Not even worth sorting.
   513  var regSpace []regSet
   514  
   515  /*
   516  	Each architecture defines a register space as a unique
   517  	integer range.
   518  	Here is the list of architectures and the base of their register spaces.
   519  */
   520  
   521  const (
   522  	// Because of masking operations in the encodings, each register
   523  	// space should start at 0 modulo some power of 2.
   524  	RBase386   = 1 * 1024
   525  	RBaseAMD64 = 2 * 1024
   526  	RBaseARM   = 3 * 1024
   527  	RBasePPC64 = 4 * 1024 // range [4k, 8k)
   528  	RBaseARM64 = 8 * 1024 // range [8k, 12k)
   529  )
   530  
   531  // RegisterRegister binds a pretty-printer (Rconv) for register
   532  // numbers to a given register number range.  Lo is inclusive,
   533  // hi exclusive (valid registers are lo through hi-1).
   534  func RegisterRegister(lo, hi int, Rconv func(int) string) {
   535  	regSpace = append(regSpace, regSet{lo, hi, Rconv})
   536  }
   537  
   538  func Rconv(reg int) string {
   539  	if reg == REG_NONE {
   540  		return "NONE"
   541  	}
   542  	for i := range regSpace {
   543  		rs := &regSpace[i]
   544  		if rs.lo <= reg && reg < rs.hi {
   545  			return rs.Rconv(reg)
   546  		}
   547  	}
   548  	return fmt.Sprintf("R???%d", reg)
   549  }
   550  
   551  func regListConv(list int) string {
   552  	str := ""
   553  
   554  	for i := 0; i < 16; i++ { // TODO: 16 is ARM-specific.
   555  		if list&(1<<uint(i)) != 0 {
   556  			if str == "" {
   557  				str += "["
   558  			} else {
   559  				str += ","
   560  			}
   561  			// This is ARM-specific; R10 is g.
   562  			if i == 10 {
   563  				str += "g"
   564  			} else {
   565  				str += fmt.Sprintf("R%d", i)
   566  			}
   567  		}
   568  	}
   569  
   570  	str += "]"
   571  	return str
   572  }
   573  
   574  /*
   575  	Each architecture defines an instruction (A*) space as a unique
   576  	integer range.
   577  	Global opcodes like CALL start at 0; the architecture-specific ones
   578  	start at a distinct, big-maskable offsets.
   579  	Here is the list of architectures and the base of their opcode spaces.
   580  */
   581  
   582  const (
   583  	ABase386 = (1 + iota) << 12
   584  	ABaseARM
   585  	ABaseAMD64
   586  	ABasePPC64
   587  	ABaseARM64
   588  	AMask = 1<<12 - 1 // AND with this to use the opcode as an array index.
   589  )
   590  
   591  type opSet struct {
   592  	lo    int
   593  	names []string
   594  }
   595  
   596  // Not even worth sorting
   597  var aSpace []opSet
   598  
   599  // RegisterOpcode binds a list of instruction names
   600  // to a given instruction number range.
   601  func RegisterOpcode(lo int, Anames []string) {
   602  	aSpace = append(aSpace, opSet{lo, Anames})
   603  }
   604  
   605  func Aconv(a int) string {
   606  	if a < A_ARCHSPECIFIC {
   607  		return Anames[a]
   608  	}
   609  	for i := range aSpace {
   610  		as := &aSpace[i]
   611  		if as.lo <= a && a < as.lo+len(as.names) {
   612  			return as.names[a-as.lo]
   613  		}
   614  	}
   615  	return fmt.Sprintf("A???%d", a)
   616  }
   617  
   618  var Anames = []string{
   619  	"XXX",
   620  	"CALL",
   621  	"CHECKNIL",
   622  	"DATA",
   623  	"DUFFCOPY",
   624  	"DUFFZERO",
   625  	"END",
   626  	"FUNCDATA",
   627  	"GLOBL",
   628  	"JMP",
   629  	"NOP",
   630  	"PCDATA",
   631  	"RET",
   632  	"TEXT",
   633  	"TYPE",
   634  	"UNDEF",
   635  	"USEFIELD",
   636  	"VARDEF",
   637  	"VARKILL",
   638  }
   639  
   640  func Bool2int(b bool) int {
   641  	if b {
   642  		return 1
   643  	}
   644  	return 0
   645  }