Source file src/cmd/internal/obj/util.go

     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  	"internal/abi"
    12  	"internal/buildcfg"
    13  	"io"
    14  	"strings"
    15  )
    16  
    17  const REG_NONE = 0
    18  
    19  // Line returns a string containing the filename and line number for p
    20  func (p *Prog) Line() string {
    21  	return p.Ctxt.OutermostPos(p.Pos).Format(false, true)
    22  }
    23  func (p *Prog) InnermostLine(w io.Writer) {
    24  	p.Ctxt.InnermostPos(p.Pos).WriteTo(w, false, true)
    25  }
    26  
    27  // InnermostLineNumber returns a string containing the line number for the
    28  // innermost inlined function (if any inlining) at p's position
    29  func (p *Prog) InnermostLineNumber() string {
    30  	return p.Ctxt.InnermostPos(p.Pos).LineNumber()
    31  }
    32  
    33  // InnermostLineNumberHTML returns a string containing the line number for the
    34  // innermost inlined function (if any inlining) at p's position
    35  func (p *Prog) InnermostLineNumberHTML() string {
    36  	return p.Ctxt.InnermostPos(p.Pos).LineNumberHTML()
    37  }
    38  
    39  // InnermostFilename returns a string containing the innermost
    40  // (in inlining) filename at p's position
    41  func (p *Prog) InnermostFilename() string {
    42  	// TODO For now, this is only used for debugging output, and if we need more/better information, it might change.
    43  	// 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.
    44  	pos := p.Ctxt.InnermostPos(p.Pos)
    45  	if !pos.IsKnown() {
    46  		return "<unknown file name>"
    47  	}
    48  	return pos.Filename()
    49  }
    50  
    51  var armCondCode = []string{
    52  	".EQ",
    53  	".NE",
    54  	".CS",
    55  	".CC",
    56  	".MI",
    57  	".PL",
    58  	".VS",
    59  	".VC",
    60  	".HI",
    61  	".LS",
    62  	".GE",
    63  	".LT",
    64  	".GT",
    65  	".LE",
    66  	"",
    67  	".NV",
    68  }
    69  
    70  /* ARM scond byte */
    71  const (
    72  	C_SCOND     = (1 << 4) - 1
    73  	C_SBIT      = 1 << 4
    74  	C_PBIT      = 1 << 5
    75  	C_WBIT      = 1 << 6
    76  	C_FBIT      = 1 << 7
    77  	C_UBIT      = 1 << 7
    78  	C_SCOND_XOR = 14
    79  )
    80  
    81  // CConv formats opcode suffix bits (Prog.Scond).
    82  func CConv(s uint8) string {
    83  	if s == 0 {
    84  		return ""
    85  	}
    86  	for i := range opSuffixSpace {
    87  		sset := &opSuffixSpace[i]
    88  		if sset.arch == buildcfg.GOARCH {
    89  			return sset.cconv(s)
    90  		}
    91  	}
    92  	return fmt.Sprintf("SC???%d", s)
    93  }
    94  
    95  // CConvARM formats ARM opcode suffix bits (mostly condition codes).
    96  func CConvARM(s uint8) string {
    97  	// TODO: could be great to move suffix-related things into
    98  	// ARM asm backends some day.
    99  	// obj/x86 can be used as an example.
   100  
   101  	sc := armCondCode[(s&C_SCOND)^C_SCOND_XOR]
   102  	if s&C_SBIT != 0 {
   103  		sc += ".S"
   104  	}
   105  	if s&C_PBIT != 0 {
   106  		sc += ".P"
   107  	}
   108  	if s&C_WBIT != 0 {
   109  		sc += ".W"
   110  	}
   111  	if s&C_UBIT != 0 { /* ambiguous with FBIT */
   112  		sc += ".U"
   113  	}
   114  	return sc
   115  }
   116  
   117  func (p *Prog) String() string {
   118  	if p == nil {
   119  		return "<nil Prog>"
   120  	}
   121  	if p.Ctxt == nil {
   122  		return "<Prog without ctxt>"
   123  	}
   124  	return fmt.Sprintf("%.5d (%v)\t%s", p.Pc, p.Line(), p.InstructionString())
   125  }
   126  
   127  func (p *Prog) InnermostString(w io.Writer) {
   128  	if p == nil {
   129  		io.WriteString(w, "<nil Prog>")
   130  		return
   131  	}
   132  	if p.Ctxt == nil {
   133  		io.WriteString(w, "<Prog without ctxt>")
   134  		return
   135  	}
   136  	fmt.Fprintf(w, "%.5d (", p.Pc)
   137  	p.InnermostLine(w)
   138  	io.WriteString(w, ")\t")
   139  	p.WriteInstructionString(w)
   140  }
   141  
   142  // InstructionString returns a string representation of the instruction without preceding
   143  // program counter or file and line number.
   144  func (p *Prog) InstructionString() string {
   145  	buf := new(bytes.Buffer)
   146  	p.WriteInstructionString(buf)
   147  	return buf.String()
   148  }
   149  
   150  // WriteInstructionString writes a string representation of the instruction without preceding
   151  // program counter or file and line number.
   152  func (p *Prog) WriteInstructionString(w io.Writer) {
   153  	if p == nil {
   154  		io.WriteString(w, "<nil Prog>")
   155  		return
   156  	}
   157  
   158  	if p.Ctxt == nil {
   159  		io.WriteString(w, "<Prog without ctxt>")
   160  		return
   161  	}
   162  
   163  	sc := CConv(p.Scond)
   164  
   165  	io.WriteString(w, p.As.String())
   166  	io.WriteString(w, sc)
   167  	sep := "\t"
   168  
   169  	if p.From.Type != TYPE_NONE {
   170  		io.WriteString(w, sep)
   171  		WriteDconv(w, p, &p.From)
   172  		sep = ", "
   173  	}
   174  	if p.Reg != REG_NONE {
   175  		// Should not happen but might as well show it if it does.
   176  		fmt.Fprintf(w, "%s%v", sep, Rconv(int(p.Reg)))
   177  		sep = ", "
   178  	}
   179  	for i := range p.RestArgs {
   180  		if p.RestArgs[i].Pos == Source {
   181  			io.WriteString(w, sep)
   182  			WriteDconv(w, p, &p.RestArgs[i].Addr)
   183  			sep = ", "
   184  		}
   185  	}
   186  
   187  	if p.As == ATEXT {
   188  		// If there are attributes, print them. Otherwise, skip the comma.
   189  		// In short, print one of these two:
   190  		// TEXT	foo(SB), DUPOK|NOSPLIT, $0
   191  		// TEXT	foo(SB), $0
   192  		s := p.From.Sym.TextAttrString()
   193  		if s != "" {
   194  			fmt.Fprintf(w, "%s%s", sep, s)
   195  			sep = ", "
   196  		}
   197  	}
   198  	if p.To.Type != TYPE_NONE {
   199  		io.WriteString(w, sep)
   200  		WriteDconv(w, p, &p.To)
   201  		sep = ", "
   202  	}
   203  	if p.RegTo2 != REG_NONE {
   204  		fmt.Fprintf(w, "%s%v", sep, Rconv(int(p.RegTo2)))
   205  	}
   206  	for i := range p.RestArgs {
   207  		if p.RestArgs[i].Pos == Destination {
   208  			io.WriteString(w, sep)
   209  			WriteDconv(w, p, &p.RestArgs[i].Addr)
   210  			sep = ", "
   211  		}
   212  	}
   213  }
   214  
   215  func (ctxt *Link) NewProg() *Prog {
   216  	p := new(Prog)
   217  	p.Ctxt = ctxt
   218  	return p
   219  }
   220  
   221  func (ctxt *Link) CanReuseProgs() bool {
   222  	return ctxt.Debugasm == 0
   223  }
   224  
   225  // Dconv accepts an argument 'a' within a prog 'p' and returns a string
   226  // with a formatted version of the argument.
   227  func Dconv(p *Prog, a *Addr) string {
   228  	buf := new(bytes.Buffer)
   229  	writeDconv(buf, p, a, false)
   230  	return buf.String()
   231  }
   232  
   233  // DconvWithABIDetail accepts an argument 'a' within a prog 'p'
   234  // and returns a string with a formatted version of the argument, in
   235  // which text symbols are rendered with explicit ABI selectors.
   236  func DconvWithABIDetail(p *Prog, a *Addr) string {
   237  	buf := new(bytes.Buffer)
   238  	writeDconv(buf, p, a, true)
   239  	return buf.String()
   240  }
   241  
   242  // WriteDconv accepts an argument 'a' within a prog 'p'
   243  // and writes a formatted version of the arg to the writer.
   244  func WriteDconv(w io.Writer, p *Prog, a *Addr) {
   245  	writeDconv(w, p, a, false)
   246  }
   247  
   248  func writeDconv(w io.Writer, p *Prog, a *Addr, abiDetail bool) {
   249  	switch a.Type {
   250  	default:
   251  		fmt.Fprintf(w, "type=%d", a.Type)
   252  
   253  	case TYPE_NONE:
   254  		if a.Name != NAME_NONE || a.Reg != 0 || a.Sym != nil {
   255  			a.WriteNameTo(w)
   256  			fmt.Fprintf(w, "(%v)(NONE)", Rconv(int(a.Reg)))
   257  		}
   258  
   259  	case TYPE_REG:
   260  		// TODO(rsc): This special case is for x86 instructions like
   261  		//	PINSRQ	CX,$1,X6
   262  		// where the $1 is included in the p->to Addr.
   263  		// Move into a new field.
   264  		if a.Offset != 0 && (a.Reg < RBaseARM64 || a.Reg >= RBaseMIPS) {
   265  			fmt.Fprintf(w, "$%d,%v", a.Offset, Rconv(int(a.Reg)))
   266  			return
   267  		}
   268  
   269  		if a.Name != NAME_NONE || a.Sym != nil {
   270  			a.WriteNameTo(w)
   271  			fmt.Fprintf(w, "(%v)(REG)", Rconv(int(a.Reg)))
   272  		} else {
   273  			io.WriteString(w, Rconv(int(a.Reg)))
   274  		}
   275  
   276  		if (RBaseARM64+1<<10+1<<9) /* arm64.REG_ELEM */ <= a.Reg &&
   277  			a.Reg < (RBaseARM64+1<<11) /* arm64.REG_ELEM_END */ {
   278  			fmt.Fprintf(w, "[%d]", a.Index)
   279  		}
   280  
   281  		if (RBaseLOONG64+(1<<10)+(1<<11)) /* loong64.REG_ELEM */ <= a.Reg &&
   282  			a.Reg < (RBaseLOONG64+(1<<10)+(2<<11)) /* loong64.REG_ELEM_END */ {
   283  			fmt.Fprintf(w, "[%d]", a.Index)
   284  		}
   285  
   286  	case TYPE_BRANCH:
   287  		if a.Sym != nil {
   288  			fmt.Fprintf(w, "%s%s(SB)", a.Sym.Name, abiDecorate(a, abiDetail))
   289  		} else if a.Target() != nil {
   290  			fmt.Fprint(w, a.Target().Pc)
   291  		} else {
   292  			fmt.Fprintf(w, "%d(PC)", a.Offset)
   293  		}
   294  
   295  	case TYPE_INDIR:
   296  		io.WriteString(w, "*")
   297  		a.writeNameTo(w, abiDetail)
   298  
   299  	case TYPE_MEM:
   300  		a.WriteNameTo(w)
   301  		if a.Index != REG_NONE {
   302  			if a.Scale == 0 {
   303  				// arm64 shifted or extended register offset, scale = 0.
   304  				fmt.Fprintf(w, "(%v)", Rconv(int(a.Index)))
   305  			} else {
   306  				fmt.Fprintf(w, "(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
   307  			}
   308  		}
   309  
   310  	case TYPE_CONST:
   311  		io.WriteString(w, "$")
   312  		a.WriteNameTo(w)
   313  		if a.Reg != 0 {
   314  			fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg)))
   315  		}
   316  
   317  	case TYPE_TEXTSIZE:
   318  		if a.Val.(int32) == abi.ArgsSizeUnknown {
   319  			fmt.Fprintf(w, "$%d", a.Offset)
   320  		} else {
   321  			fmt.Fprintf(w, "$%d-%d", a.Offset, a.Val.(int32))
   322  		}
   323  
   324  	case TYPE_FCONST:
   325  		str := fmt.Sprintf("%.17g", a.Val.(float64))
   326  		// Make sure 1 prints as 1.0
   327  		if !strings.ContainsAny(str, ".e") {
   328  			str += ".0"
   329  		}
   330  		fmt.Fprintf(w, "$(%s)", str)
   331  
   332  	case TYPE_SCONST:
   333  		fmt.Fprintf(w, "$%q", a.Val.(string))
   334  
   335  	case TYPE_ADDR:
   336  		io.WriteString(w, "$")
   337  		a.writeNameTo(w, abiDetail)
   338  
   339  	case TYPE_SHIFT:
   340  		v := int(a.Offset)
   341  		ops := "<<>>->@>"
   342  		switch buildcfg.GOARCH {
   343  		case "arm":
   344  			op := ops[((v>>5)&3)<<1:]
   345  			if v&(1<<4) != 0 {
   346  				fmt.Fprintf(w, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
   347  			} else {
   348  				fmt.Fprintf(w, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
   349  			}
   350  			if a.Reg != 0 {
   351  				fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg)))
   352  			}
   353  		case "arm64":
   354  			op := ops[((v>>22)&3)<<1:]
   355  			r := (v >> 16) & 31
   356  			fmt.Fprintf(w, "%s%c%c%d", Rconv(r+RBaseARM64), op[0], op[1], (v>>10)&63)
   357  		default:
   358  			panic("TYPE_SHIFT is not supported on " + buildcfg.GOARCH)
   359  		}
   360  
   361  	case TYPE_REGREG:
   362  		fmt.Fprintf(w, "(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
   363  
   364  	case TYPE_REGREG2:
   365  		fmt.Fprintf(w, "%v, %v", Rconv(int(a.Offset)), Rconv(int(a.Reg)))
   366  
   367  	case TYPE_REGLIST:
   368  		io.WriteString(w, RLconv(a.Offset))
   369  
   370  	case TYPE_SPECIAL:
   371  		io.WriteString(w, SPCconv(a.Offset))
   372  	}
   373  }
   374  
   375  func (a *Addr) WriteNameTo(w io.Writer) {
   376  	a.writeNameTo(w, false)
   377  }
   378  
   379  func (a *Addr) writeNameTo(w io.Writer, abiDetail bool) {
   380  
   381  	switch a.Name {
   382  	default:
   383  		fmt.Fprintf(w, "name=%d", a.Name)
   384  
   385  	case NAME_NONE:
   386  		switch {
   387  		case a.Reg == REG_NONE:
   388  			fmt.Fprint(w, a.Offset)
   389  		case a.Offset == 0:
   390  			fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg)))
   391  		case a.Offset != 0:
   392  			fmt.Fprintf(w, "%d(%v)", a.Offset, Rconv(int(a.Reg)))
   393  		}
   394  
   395  		// Note: a.Reg == REG_NONE encodes the default base register for the NAME_ type.
   396  	case NAME_EXTERN:
   397  		reg := "SB"
   398  		if a.Reg != REG_NONE {
   399  			reg = Rconv(int(a.Reg))
   400  		}
   401  		if a.Sym != nil {
   402  			fmt.Fprintf(w, "%s%s%s(%s)", a.Sym.Name, abiDecorate(a, abiDetail), offConv(a.Offset), reg)
   403  		} else {
   404  			fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
   405  		}
   406  
   407  	case NAME_GOTREF:
   408  		reg := "SB"
   409  		if a.Reg != REG_NONE {
   410  			reg = Rconv(int(a.Reg))
   411  		}
   412  		if a.Sym != nil {
   413  			fmt.Fprintf(w, "%s%s@GOT(%s)", a.Sym.Name, offConv(a.Offset), reg)
   414  		} else {
   415  			fmt.Fprintf(w, "%s@GOT(%s)", offConv(a.Offset), reg)
   416  		}
   417  
   418  	case NAME_STATIC:
   419  		reg := "SB"
   420  		if a.Reg != REG_NONE {
   421  			reg = Rconv(int(a.Reg))
   422  		}
   423  		if a.Sym != nil {
   424  			fmt.Fprintf(w, "%s<>%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
   425  		} else {
   426  			fmt.Fprintf(w, "<>%s(%s)", offConv(a.Offset), reg)
   427  		}
   428  
   429  	case NAME_AUTO:
   430  		reg := "SP"
   431  		if a.Reg != REG_NONE {
   432  			reg = Rconv(int(a.Reg))
   433  		}
   434  		if a.Sym != nil {
   435  			fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
   436  		} else {
   437  			fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
   438  		}
   439  
   440  	case NAME_PARAM:
   441  		reg := "FP"
   442  		if a.Reg != REG_NONE {
   443  			reg = Rconv(int(a.Reg))
   444  		}
   445  		if a.Sym != nil {
   446  			fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
   447  		} else {
   448  			fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
   449  		}
   450  	case NAME_TOCREF:
   451  		reg := "SB"
   452  		if a.Reg != REG_NONE {
   453  			reg = Rconv(int(a.Reg))
   454  		}
   455  		if a.Sym != nil {
   456  			fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
   457  		} else {
   458  			fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
   459  		}
   460  	}
   461  }
   462  
   463  func offConv(off int64) string {
   464  	if off == 0 {
   465  		return ""
   466  	}
   467  	return fmt.Sprintf("%+d", off)
   468  }
   469  
   470  // opSuffixSet is like regListSet, but for opcode suffixes.
   471  //
   472  // Unlike some other similar structures, uint8 space is not
   473  // divided by its own values set (because there are only 256 of them).
   474  // Instead, every arch may interpret/format all 8 bits as they like,
   475  // as long as they register proper cconv function for it.
   476  type opSuffixSet struct {
   477  	arch  string
   478  	cconv func(suffix uint8) string
   479  }
   480  
   481  var opSuffixSpace []opSuffixSet
   482  
   483  // RegisterOpSuffix assigns cconv function for formatting opcode suffixes
   484  // when compiling for GOARCH=arch.
   485  //
   486  // cconv is never called with 0 argument.
   487  func RegisterOpSuffix(arch string, cconv func(uint8) string) {
   488  	opSuffixSpace = append(opSuffixSpace, opSuffixSet{
   489  		arch:  arch,
   490  		cconv: cconv,
   491  	})
   492  }
   493  
   494  type regSet struct {
   495  	lo    int
   496  	hi    int
   497  	Rconv func(int) string
   498  }
   499  
   500  // Few enough architectures that a linear scan is fastest.
   501  // Not even worth sorting.
   502  var regSpace []regSet
   503  
   504  /*
   505  	Each architecture defines a register space as a unique
   506  	integer range.
   507  	Here is the list of architectures and the base of their register spaces.
   508  */
   509  
   510  const (
   511  	// Because of masking operations in the encodings, each register
   512  	// space should start at 0 modulo some power of 2.
   513  	RBase386     = 1 * 1024
   514  	RBaseAMD64   = 2 * 1024
   515  	RBaseARM     = 3 * 1024
   516  	RBasePPC64   = 4 * 1024  // range [4k, 8k)
   517  	RBaseARM64   = 8 * 1024  // range [8k, 13k)
   518  	RBaseMIPS    = 13 * 1024 // range [13k, 14k)
   519  	RBaseS390X   = 14 * 1024 // range [14k, 15k)
   520  	RBaseRISCV   = 15 * 1024 // range [15k, 16k)
   521  	RBaseWasm    = 16 * 1024
   522  	RBaseLOONG64 = 19 * 1024 // range [19K, 22k)
   523  )
   524  
   525  // RegisterRegister binds a pretty-printer (Rconv) for register
   526  // numbers to a given register number range. Lo is inclusive,
   527  // hi exclusive (valid registers are lo through hi-1).
   528  func RegisterRegister(lo, hi int, Rconv func(int) string) {
   529  	regSpace = append(regSpace, regSet{lo, hi, Rconv})
   530  }
   531  
   532  func Rconv(reg int) string {
   533  	if reg == REG_NONE {
   534  		return "NONE"
   535  	}
   536  	for i := range regSpace {
   537  		rs := &regSpace[i]
   538  		if rs.lo <= reg && reg < rs.hi {
   539  			return rs.Rconv(reg)
   540  		}
   541  	}
   542  	return fmt.Sprintf("R???%d", reg)
   543  }
   544  
   545  type regListSet struct {
   546  	lo     int64
   547  	hi     int64
   548  	RLconv func(int64) string
   549  }
   550  
   551  var regListSpace []regListSet
   552  
   553  // Each architecture is allotted a distinct subspace: [Lo, Hi) for declaring its
   554  // arch-specific register list numbers.
   555  const (
   556  	RegListARMLo = 0
   557  	RegListARMHi = 1 << 16
   558  
   559  	// arm64 uses the 60th bit to differentiate from other archs
   560  	RegListARM64Lo = 1 << 60
   561  	RegListARM64Hi = 1<<61 - 1
   562  
   563  	// x86 uses the 61th bit to differentiate from other archs
   564  	RegListX86Lo = 1 << 61
   565  	RegListX86Hi = 1<<62 - 1
   566  )
   567  
   568  // RegisterRegisterList binds a pretty-printer (RLconv) for register list
   569  // numbers to a given register list number range. Lo is inclusive,
   570  // hi exclusive (valid register list are lo through hi-1).
   571  func RegisterRegisterList(lo, hi int64, rlconv func(int64) string) {
   572  	regListSpace = append(regListSpace, regListSet{lo, hi, rlconv})
   573  }
   574  
   575  func RLconv(list int64) string {
   576  	for i := range regListSpace {
   577  		rls := &regListSpace[i]
   578  		if rls.lo <= list && list < rls.hi {
   579  			return rls.RLconv(list)
   580  		}
   581  	}
   582  	return fmt.Sprintf("RL???%d", list)
   583  }
   584  
   585  // Special operands
   586  type spcSet struct {
   587  	lo      int64
   588  	hi      int64
   589  	SPCconv func(int64) string
   590  }
   591  
   592  var spcSpace []spcSet
   593  
   594  // RegisterSpecialOperands binds a pretty-printer (SPCconv) for special
   595  // operand numbers to a given special operand number range. Lo is inclusive,
   596  // hi is exclusive (valid special operands are lo through hi-1).
   597  func RegisterSpecialOperands(lo, hi int64, rlconv func(int64) string) {
   598  	spcSpace = append(spcSpace, spcSet{lo, hi, rlconv})
   599  }
   600  
   601  // SPCconv returns the string representation of the special operand spc.
   602  func SPCconv(spc int64) string {
   603  	for i := range spcSpace {
   604  		spcs := &spcSpace[i]
   605  		if spcs.lo <= spc && spc < spcs.hi {
   606  			return spcs.SPCconv(spc)
   607  		}
   608  	}
   609  	return fmt.Sprintf("SPC???%d", spc)
   610  }
   611  
   612  type opSet struct {
   613  	lo    As
   614  	names []string
   615  }
   616  
   617  // Not even worth sorting
   618  var aSpace []opSet
   619  
   620  // RegisterOpcode binds a list of instruction names
   621  // to a given instruction number range.
   622  func RegisterOpcode(lo As, Anames []string) {
   623  	if len(Anames) > AllowedOpCodes {
   624  		panic(fmt.Sprintf("too many instructions, have %d max %d", len(Anames), AllowedOpCodes))
   625  	}
   626  	aSpace = append(aSpace, opSet{lo, Anames})
   627  }
   628  
   629  func (a As) String() string {
   630  	if 0 <= a && int(a) < len(Anames) {
   631  		return Anames[a]
   632  	}
   633  	for i := range aSpace {
   634  		as := &aSpace[i]
   635  		if as.lo <= a && int(a-as.lo) < len(as.names) {
   636  			return as.names[a-as.lo]
   637  		}
   638  	}
   639  	return fmt.Sprintf("A???%d", a)
   640  }
   641  
   642  var Anames = []string{
   643  	"XXX",
   644  	"CALL",
   645  	"DUFFCOPY",
   646  	"DUFFZERO",
   647  	"END",
   648  	"FUNCDATA",
   649  	"JMP",
   650  	"NOP",
   651  	"PCALIGN",
   652  	"PCALIGNMAX",
   653  	"PCDATA",
   654  	"RET",
   655  	"GETCALLERPC",
   656  	"TEXT",
   657  	"UNDEF",
   658  }
   659  
   660  func Bool2int(b bool) int {
   661  	// The compiler currently only optimizes this form.
   662  	// See issue 6011.
   663  	var i int
   664  	if b {
   665  		i = 1
   666  	} else {
   667  		i = 0
   668  	}
   669  	return i
   670  }
   671  
   672  func abiDecorate(a *Addr, abiDetail bool) string {
   673  	if !abiDetail || a.Sym == nil {
   674  		return ""
   675  	}
   676  	return fmt.Sprintf("<%s>", a.Sym.ABI())
   677  }
   678  
   679  // AlignmentPadding bytes to add to align code as requested.
   680  // Alignment is restricted to powers of 2 between 8 and 2048 inclusive.
   681  //
   682  // pc_: current offset in function, in bytes
   683  // p:  a PCALIGN or PCALIGNMAX prog
   684  // ctxt: the context, for current function
   685  // cursym: current function being assembled
   686  // returns number of bytes of padding needed,
   687  // updates minimum alignment for the function.
   688  func AlignmentPadding(pc int32, p *Prog, ctxt *Link, cursym *LSym) int {
   689  	v := AlignmentPaddingLength(pc, p, ctxt)
   690  	requireAlignment(p.From.Offset, ctxt, cursym)
   691  	return v
   692  }
   693  
   694  // AlignmentPaddingLength is the number of bytes to add to align code as requested.
   695  // Alignment is restricted to powers of 2 between 8 and 2048 inclusive.
   696  // This only computes the length and does not update the (missing parameter)
   697  // current function's own required alignment.
   698  //
   699  // pc: current offset in function, in bytes
   700  // p:  a PCALIGN or PCALIGNMAX prog
   701  // ctxt: the context, for current function
   702  // returns number of bytes of padding needed,
   703  func AlignmentPaddingLength(pc int32, p *Prog, ctxt *Link) int {
   704  	a := p.From.Offset
   705  	if !((a&(a-1) == 0) && 8 <= a && a <= 2048) {
   706  		ctxt.Diag("alignment value of an instruction must be a power of two and in the range [8, 2048], got %d\n", a)
   707  		return 0
   708  	}
   709  	pc64 := int64(pc)
   710  	lob := pc64 & (a - 1) // Low Order Bits -- if not zero, then not aligned
   711  	if p.As == APCALIGN {
   712  		if lob != 0 {
   713  			return int(a - lob)
   714  		}
   715  		return 0
   716  	}
   717  	// emit as many as s bytes of padding to obtain alignment
   718  	s := p.To.Offset
   719  	if s < 0 || s >= a {
   720  		ctxt.Diag("PCALIGNMAX 'amount' %d must be non-negative and smaller than the aligment %d\n", s, a)
   721  		return 0
   722  	}
   723  	if s >= a-lob {
   724  		return int(a - lob)
   725  	}
   726  	return 0
   727  }
   728  
   729  // requireAlignment ensures that the function is aligned enough to support
   730  // the required code alignment
   731  func requireAlignment(a int64, ctxt *Link, cursym *LSym) {
   732  	// TODO remove explicit knowledge about AIX.
   733  	if ctxt.Headtype != objabi.Haix && cursym.Func().Align < int32(a) {
   734  		cursym.Func().Align = int32(a)
   735  	}
   736  }
   737  

View as plain text