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