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  		if (RBaseARM64+1<<10+1<<9) /* arm64.REG_ELEM */ <= a.Reg &&
   276  			a.Reg < (RBaseARM64+1<<11) /* arm64.REG_ELEM_END */ {
   277  			fmt.Fprintf(w, "[%d]", a.Index)
   278  		}
   279  
   280  	case TYPE_BRANCH:
   281  		if a.Sym != nil {
   282  			fmt.Fprintf(w, "%s%s(SB)", a.Sym.Name, abiDecorate(a, abiDetail))
   283  		} else if a.Target() != nil {
   284  			fmt.Fprint(w, a.Target().Pc)
   285  		} else {
   286  			fmt.Fprintf(w, "%d(PC)", a.Offset)
   287  		}
   288  
   289  	case TYPE_INDIR:
   290  		io.WriteString(w, "*")
   291  		a.writeNameTo(w, abiDetail)
   292  
   293  	case TYPE_MEM:
   294  		a.WriteNameTo(w)
   295  		if a.Index != REG_NONE {
   296  			if a.Scale == 0 {
   297  				// arm64 shifted or extended register offset, scale = 0.
   298  				fmt.Fprintf(w, "(%v)", Rconv(int(a.Index)))
   299  			} else {
   300  				fmt.Fprintf(w, "(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
   301  			}
   302  		}
   303  
   304  	case TYPE_CONST:
   305  		io.WriteString(w, "$")
   306  		a.WriteNameTo(w)
   307  		if a.Reg != 0 {
   308  			fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg)))
   309  		}
   310  
   311  	case TYPE_TEXTSIZE:
   312  		if a.Val.(int32) == abi.ArgsSizeUnknown {
   313  			fmt.Fprintf(w, "$%d", a.Offset)
   314  		} else {
   315  			fmt.Fprintf(w, "$%d-%d", a.Offset, a.Val.(int32))
   316  		}
   317  
   318  	case TYPE_FCONST:
   319  		str := fmt.Sprintf("%.17g", a.Val.(float64))
   320  		// Make sure 1 prints as 1.0
   321  		if !strings.ContainsAny(str, ".e") {
   322  			str += ".0"
   323  		}
   324  		fmt.Fprintf(w, "$(%s)", str)
   325  
   326  	case TYPE_SCONST:
   327  		fmt.Fprintf(w, "$%q", a.Val.(string))
   328  
   329  	case TYPE_ADDR:
   330  		io.WriteString(w, "$")
   331  		a.writeNameTo(w, abiDetail)
   332  
   333  	case TYPE_SHIFT:
   334  		v := int(a.Offset)
   335  		ops := "<<>>->@>"
   336  		switch buildcfg.GOARCH {
   337  		case "arm":
   338  			op := ops[((v>>5)&3)<<1:]
   339  			if v&(1<<4) != 0 {
   340  				fmt.Fprintf(w, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
   341  			} else {
   342  				fmt.Fprintf(w, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
   343  			}
   344  			if a.Reg != 0 {
   345  				fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg)))
   346  			}
   347  		case "arm64":
   348  			op := ops[((v>>22)&3)<<1:]
   349  			r := (v >> 16) & 31
   350  			fmt.Fprintf(w, "%s%c%c%d", Rconv(r+RBaseARM64), op[0], op[1], (v>>10)&63)
   351  		default:
   352  			panic("TYPE_SHIFT is not supported on " + buildcfg.GOARCH)
   353  		}
   354  
   355  	case TYPE_REGREG:
   356  		fmt.Fprintf(w, "(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
   357  
   358  	case TYPE_REGREG2:
   359  		fmt.Fprintf(w, "%v, %v", Rconv(int(a.Offset)), Rconv(int(a.Reg)))
   360  
   361  	case TYPE_REGLIST:
   362  		io.WriteString(w, RLconv(a.Offset))
   363  
   364  	case TYPE_SPECIAL:
   365  		io.WriteString(w, SPCconv(a.Offset))
   366  	}
   367  }
   368  
   369  func (a *Addr) WriteNameTo(w io.Writer) {
   370  	a.writeNameTo(w, false)
   371  }
   372  
   373  func (a *Addr) writeNameTo(w io.Writer, abiDetail bool) {
   374  
   375  	switch a.Name {
   376  	default:
   377  		fmt.Fprintf(w, "name=%d", a.Name)
   378  
   379  	case NAME_NONE:
   380  		switch {
   381  		case a.Reg == REG_NONE:
   382  			fmt.Fprint(w, a.Offset)
   383  		case a.Offset == 0:
   384  			fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg)))
   385  		case a.Offset != 0:
   386  			fmt.Fprintf(w, "%d(%v)", a.Offset, Rconv(int(a.Reg)))
   387  		}
   388  
   389  		// Note: a.Reg == REG_NONE encodes the default base register for the NAME_ type.
   390  	case NAME_EXTERN:
   391  		reg := "SB"
   392  		if a.Reg != REG_NONE {
   393  			reg = Rconv(int(a.Reg))
   394  		}
   395  		if a.Sym != nil {
   396  			fmt.Fprintf(w, "%s%s%s(%s)", a.Sym.Name, abiDecorate(a, abiDetail), offConv(a.Offset), reg)
   397  		} else {
   398  			fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
   399  		}
   400  
   401  	case NAME_GOTREF:
   402  		reg := "SB"
   403  		if a.Reg != REG_NONE {
   404  			reg = Rconv(int(a.Reg))
   405  		}
   406  		if a.Sym != nil {
   407  			fmt.Fprintf(w, "%s%s@GOT(%s)", a.Sym.Name, offConv(a.Offset), reg)
   408  		} else {
   409  			fmt.Fprintf(w, "%s@GOT(%s)", offConv(a.Offset), reg)
   410  		}
   411  
   412  	case NAME_STATIC:
   413  		reg := "SB"
   414  		if a.Reg != REG_NONE {
   415  			reg = Rconv(int(a.Reg))
   416  		}
   417  		if a.Sym != nil {
   418  			fmt.Fprintf(w, "%s<>%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
   419  		} else {
   420  			fmt.Fprintf(w, "<>%s(%s)", offConv(a.Offset), reg)
   421  		}
   422  
   423  	case NAME_AUTO:
   424  		reg := "SP"
   425  		if a.Reg != REG_NONE {
   426  			reg = Rconv(int(a.Reg))
   427  		}
   428  		if a.Sym != nil {
   429  			fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
   430  		} else {
   431  			fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
   432  		}
   433  
   434  	case NAME_PARAM:
   435  		reg := "FP"
   436  		if a.Reg != REG_NONE {
   437  			reg = Rconv(int(a.Reg))
   438  		}
   439  		if a.Sym != nil {
   440  			fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
   441  		} else {
   442  			fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
   443  		}
   444  	case NAME_TOCREF:
   445  		reg := "SB"
   446  		if a.Reg != REG_NONE {
   447  			reg = Rconv(int(a.Reg))
   448  		}
   449  		if a.Sym != nil {
   450  			fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
   451  		} else {
   452  			fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
   453  		}
   454  	}
   455  }
   456  
   457  func offConv(off int64) string {
   458  	if off == 0 {
   459  		return ""
   460  	}
   461  	return fmt.Sprintf("%+d", off)
   462  }
   463  
   464  // opSuffixSet is like regListSet, but for opcode suffixes.
   465  //
   466  // Unlike some other similar structures, uint8 space is not
   467  // divided by its own values set (because there are only 256 of them).
   468  // Instead, every arch may interpret/format all 8 bits as they like,
   469  // as long as they register proper cconv function for it.
   470  type opSuffixSet struct {
   471  	arch  string
   472  	cconv func(suffix uint8) string
   473  }
   474  
   475  var opSuffixSpace []opSuffixSet
   476  
   477  // RegisterOpSuffix assigns cconv function for formatting opcode suffixes
   478  // when compiling for GOARCH=arch.
   479  //
   480  // cconv is never called with 0 argument.
   481  func RegisterOpSuffix(arch string, cconv func(uint8) string) {
   482  	opSuffixSpace = append(opSuffixSpace, opSuffixSet{
   483  		arch:  arch,
   484  		cconv: cconv,
   485  	})
   486  }
   487  
   488  type regSet struct {
   489  	lo    int
   490  	hi    int
   491  	Rconv func(int) string
   492  }
   493  
   494  // Few enough architectures that a linear scan is fastest.
   495  // Not even worth sorting.
   496  var regSpace []regSet
   497  
   498  /*
   499  	Each architecture defines a register space as a unique
   500  	integer range.
   501  	Here is the list of architectures and the base of their register spaces.
   502  */
   503  
   504  const (
   505  	// Because of masking operations in the encodings, each register
   506  	// space should start at 0 modulo some power of 2.
   507  	RBase386     = 1 * 1024
   508  	RBaseAMD64   = 2 * 1024
   509  	RBaseARM     = 3 * 1024
   510  	RBasePPC64   = 4 * 1024  // range [4k, 8k)
   511  	RBaseARM64   = 8 * 1024  // range [8k, 13k)
   512  	RBaseMIPS    = 13 * 1024 // range [13k, 14k)
   513  	RBaseS390X   = 14 * 1024 // range [14k, 15k)
   514  	RBaseRISCV   = 15 * 1024 // range [15k, 16k)
   515  	RBaseWasm    = 16 * 1024
   516  	RBaseLOONG64 = 17 * 1024
   517  )
   518  
   519  // RegisterRegister binds a pretty-printer (Rconv) for register
   520  // numbers to a given register number range. Lo is inclusive,
   521  // hi exclusive (valid registers are lo through hi-1).
   522  func RegisterRegister(lo, hi int, Rconv func(int) string) {
   523  	regSpace = append(regSpace, regSet{lo, hi, Rconv})
   524  }
   525  
   526  func Rconv(reg int) string {
   527  	if reg == REG_NONE {
   528  		return "NONE"
   529  	}
   530  	for i := range regSpace {
   531  		rs := &regSpace[i]
   532  		if rs.lo <= reg && reg < rs.hi {
   533  			return rs.Rconv(reg)
   534  		}
   535  	}
   536  	return fmt.Sprintf("R???%d", reg)
   537  }
   538  
   539  type regListSet struct {
   540  	lo     int64
   541  	hi     int64
   542  	RLconv func(int64) string
   543  }
   544  
   545  var regListSpace []regListSet
   546  
   547  // Each architecture is allotted a distinct subspace: [Lo, Hi) for declaring its
   548  // arch-specific register list numbers.
   549  const (
   550  	RegListARMLo = 0
   551  	RegListARMHi = 1 << 16
   552  
   553  	// arm64 uses the 60th bit to differentiate from other archs
   554  	RegListARM64Lo = 1 << 60
   555  	RegListARM64Hi = 1<<61 - 1
   556  
   557  	// x86 uses the 61th bit to differentiate from other archs
   558  	RegListX86Lo = 1 << 61
   559  	RegListX86Hi = 1<<62 - 1
   560  )
   561  
   562  // RegisterRegisterList binds a pretty-printer (RLconv) for register list
   563  // numbers to a given register list number range. Lo is inclusive,
   564  // hi exclusive (valid register list are lo through hi-1).
   565  func RegisterRegisterList(lo, hi int64, rlconv func(int64) string) {
   566  	regListSpace = append(regListSpace, regListSet{lo, hi, rlconv})
   567  }
   568  
   569  func RLconv(list int64) string {
   570  	for i := range regListSpace {
   571  		rls := &regListSpace[i]
   572  		if rls.lo <= list && list < rls.hi {
   573  			return rls.RLconv(list)
   574  		}
   575  	}
   576  	return fmt.Sprintf("RL???%d", list)
   577  }
   578  
   579  // Special operands
   580  type spcSet struct {
   581  	lo      int64
   582  	hi      int64
   583  	SPCconv func(int64) string
   584  }
   585  
   586  var spcSpace []spcSet
   587  
   588  // RegisterSpecialOperands binds a pretty-printer (SPCconv) for special
   589  // operand numbers to a given special operand number range. Lo is inclusive,
   590  // hi is exclusive (valid special operands are lo through hi-1).
   591  func RegisterSpecialOperands(lo, hi int64, rlconv func(int64) string) {
   592  	spcSpace = append(spcSpace, spcSet{lo, hi, rlconv})
   593  }
   594  
   595  // SPCconv returns the string representation of the special operand spc.
   596  func SPCconv(spc int64) string {
   597  	for i := range spcSpace {
   598  		spcs := &spcSpace[i]
   599  		if spcs.lo <= spc && spc < spcs.hi {
   600  			return spcs.SPCconv(spc)
   601  		}
   602  	}
   603  	return fmt.Sprintf("SPC???%d", spc)
   604  }
   605  
   606  type opSet struct {
   607  	lo    As
   608  	names []string
   609  }
   610  
   611  // Not even worth sorting
   612  var aSpace []opSet
   613  
   614  // RegisterOpcode binds a list of instruction names
   615  // to a given instruction number range.
   616  func RegisterOpcode(lo As, Anames []string) {
   617  	if len(Anames) > AllowedOpCodes {
   618  		panic(fmt.Sprintf("too many instructions, have %d max %d", len(Anames), AllowedOpCodes))
   619  	}
   620  	aSpace = append(aSpace, opSet{lo, Anames})
   621  }
   622  
   623  func (a As) String() string {
   624  	if 0 <= a && int(a) < len(Anames) {
   625  		return Anames[a]
   626  	}
   627  	for i := range aSpace {
   628  		as := &aSpace[i]
   629  		if as.lo <= a && int(a-as.lo) < len(as.names) {
   630  			return as.names[a-as.lo]
   631  		}
   632  	}
   633  	return fmt.Sprintf("A???%d", a)
   634  }
   635  
   636  var Anames = []string{
   637  	"XXX",
   638  	"CALL",
   639  	"DUFFCOPY",
   640  	"DUFFZERO",
   641  	"END",
   642  	"FUNCDATA",
   643  	"JMP",
   644  	"NOP",
   645  	"PCALIGN",
   646  	"PCALIGNMAX",
   647  	"PCDATA",
   648  	"RET",
   649  	"GETCALLERPC",
   650  	"TEXT",
   651  	"UNDEF",
   652  }
   653  
   654  func Bool2int(b bool) int {
   655  	// The compiler currently only optimizes this form.
   656  	// See issue 6011.
   657  	var i int
   658  	if b {
   659  		i = 1
   660  	} else {
   661  		i = 0
   662  	}
   663  	return i
   664  }
   665  
   666  func abiDecorate(a *Addr, abiDetail bool) string {
   667  	if !abiDetail || a.Sym == nil {
   668  		return ""
   669  	}
   670  	return fmt.Sprintf("<%s>", a.Sym.ABI())
   671  }
   672  
   673  // AlignmentPadding bytes to add to align code as requested.
   674  // Alignment is restricted to powers of 2 between 8 and 2048 inclusive.
   675  //
   676  // pc_: current offset in function, in bytes
   677  // p:  a PCALIGN or PCALIGNMAX prog
   678  // ctxt: the context, for current function
   679  // cursym: current function being assembled
   680  // returns number of bytes of padding needed,
   681  // updates minimum alignment for the function.
   682  func AlignmentPadding(pc int32, p *Prog, ctxt *Link, cursym *LSym) int {
   683  	v := AlignmentPaddingLength(pc, p, ctxt)
   684  	requireAlignment(p.From.Offset, ctxt, cursym)
   685  	return v
   686  }
   687  
   688  // AlignmentPaddingLength is the number of bytes to add to align code as requested.
   689  // Alignment is restricted to powers of 2 between 8 and 2048 inclusive.
   690  // This only computes the length and does not update the (missing parameter)
   691  // current function's own required alignment.
   692  //
   693  // pc: current offset in function, in bytes
   694  // p:  a PCALIGN or PCALIGNMAX prog
   695  // ctxt: the context, for current function
   696  // returns number of bytes of padding needed,
   697  func AlignmentPaddingLength(pc int32, p *Prog, ctxt *Link) int {
   698  	a := p.From.Offset
   699  	if !((a&(a-1) == 0) && 8 <= a && a <= 2048) {
   700  		ctxt.Diag("alignment value of an instruction must be a power of two and in the range [8, 2048], got %d\n", a)
   701  		return 0
   702  	}
   703  	pc64 := int64(pc)
   704  	lob := pc64 & (a - 1) // Low Order Bits -- if not zero, then not aligned
   705  	if p.As == APCALIGN {
   706  		if lob != 0 {
   707  			return int(a - lob)
   708  		}
   709  		return 0
   710  	}
   711  	// emit as many as s bytes of padding to obtain alignment
   712  	s := p.To.Offset
   713  	if s < 0 || s >= a {
   714  		ctxt.Diag("PCALIGNMAX 'amount' %d must be non-negative and smaller than the aligment %d\n", s, a)
   715  		return 0
   716  	}
   717  	if s >= a-lob {
   718  		return int(a - lob)
   719  	}
   720  	return 0
   721  }
   722  
   723  // requireAlignment ensures that the function is aligned enough to support
   724  // the required code alignment
   725  func requireAlignment(a int64, ctxt *Link, cursym *LSym) {
   726  	// TODO remove explicit knowledge about AIX.
   727  	if ctxt.Headtype != objabi.Haix && cursym.Func().Align < int32(a) {
   728  		cursym.Func().Align = int32(a)
   729  	}
   730  }
   731  

View as plain text