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