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