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