diff options
Diffstat (limited to 'vendor/github.com/twitchyliquid64/golang-asm/obj/util.go')
-rw-r--r-- | vendor/github.com/twitchyliquid64/golang-asm/obj/util.go | 598 |
1 files changed, 0 insertions, 598 deletions
diff --git a/vendor/github.com/twitchyliquid64/golang-asm/obj/util.go b/vendor/github.com/twitchyliquid64/golang-asm/obj/util.go deleted file mode 100644 index 9d3030a68..000000000 --- a/vendor/github.com/twitchyliquid64/golang-asm/obj/util.go +++ /dev/null @@ -1,598 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package obj - -import ( - "bytes" - "github.com/twitchyliquid64/golang-asm/objabi" - "fmt" - "io" - "strings" -) - -const REG_NONE = 0 - -// Line returns a string containing the filename and line number for p -func (p *Prog) Line() string { - return p.Ctxt.OutermostPos(p.Pos).Format(false, true) -} -func (p *Prog) InnermostLine(w io.Writer) { - p.Ctxt.InnermostPos(p.Pos).WriteTo(w, false, true) -} - -// InnermostLineNumber returns a string containing the line number for the -// innermost inlined function (if any inlining) at p's position -func (p *Prog) InnermostLineNumber() string { - return p.Ctxt.InnermostPos(p.Pos).LineNumber() -} - -// InnermostLineNumberHTML returns a string containing the line number for the -// innermost inlined function (if any inlining) at p's position -func (p *Prog) InnermostLineNumberHTML() string { - return p.Ctxt.InnermostPos(p.Pos).LineNumberHTML() -} - -// InnermostFilename returns a string containing the innermost -// (in inlining) filename at p's position -func (p *Prog) InnermostFilename() string { - // TODO For now, this is only used for debugging output, and if we need more/better information, it might change. - // 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. - pos := p.Ctxt.InnermostPos(p.Pos) - if !pos.IsKnown() { - return "<unknown file name>" - } - return pos.Filename() -} - -var armCondCode = []string{ - ".EQ", - ".NE", - ".CS", - ".CC", - ".MI", - ".PL", - ".VS", - ".VC", - ".HI", - ".LS", - ".GE", - ".LT", - ".GT", - ".LE", - "", - ".NV", -} - -/* ARM scond byte */ -const ( - C_SCOND = (1 << 4) - 1 - C_SBIT = 1 << 4 - C_PBIT = 1 << 5 - C_WBIT = 1 << 6 - C_FBIT = 1 << 7 - C_UBIT = 1 << 7 - C_SCOND_XOR = 14 -) - -// CConv formats opcode suffix bits (Prog.Scond). -func CConv(s uint8) string { - if s == 0 { - return "" - } - for i := range opSuffixSpace { - sset := &opSuffixSpace[i] - if sset.arch == objabi.GOARCH { - return sset.cconv(s) - } - } - return fmt.Sprintf("SC???%d", s) -} - -// CConvARM formats ARM opcode suffix bits (mostly condition codes). -func CConvARM(s uint8) string { - // TODO: could be great to move suffix-related things into - // ARM asm backends some day. - // obj/x86 can be used as an example. - - sc := armCondCode[(s&C_SCOND)^C_SCOND_XOR] - if s&C_SBIT != 0 { - sc += ".S" - } - if s&C_PBIT != 0 { - sc += ".P" - } - if s&C_WBIT != 0 { - sc += ".W" - } - if s&C_UBIT != 0 { /* ambiguous with FBIT */ - sc += ".U" - } - return sc -} - -func (p *Prog) String() string { - if p == nil { - return "<nil Prog>" - } - if p.Ctxt == nil { - return "<Prog without ctxt>" - } - return fmt.Sprintf("%.5d (%v)\t%s", p.Pc, p.Line(), p.InstructionString()) -} - -func (p *Prog) InnermostString(w io.Writer) { - if p == nil { - io.WriteString(w, "<nil Prog>") - return - } - if p.Ctxt == nil { - io.WriteString(w, "<Prog without ctxt>") - return - } - fmt.Fprintf(w, "%.5d (", p.Pc) - p.InnermostLine(w) - io.WriteString(w, ")\t") - p.WriteInstructionString(w) -} - -// InstructionString returns a string representation of the instruction without preceding -// program counter or file and line number. -func (p *Prog) InstructionString() string { - buf := new(bytes.Buffer) - p.WriteInstructionString(buf) - return buf.String() -} - -// WriteInstructionString writes a string representation of the instruction without preceding -// program counter or file and line number. -func (p *Prog) WriteInstructionString(w io.Writer) { - if p == nil { - io.WriteString(w, "<nil Prog>") - return - } - - if p.Ctxt == nil { - io.WriteString(w, "<Prog without ctxt>") - return - } - - sc := CConv(p.Scond) - - io.WriteString(w, p.As.String()) - io.WriteString(w, sc) - sep := "\t" - - if p.From.Type != TYPE_NONE { - io.WriteString(w, sep) - WriteDconv(w, p, &p.From) - sep = ", " - } - if p.Reg != REG_NONE { - // Should not happen but might as well show it if it does. - fmt.Fprintf(w, "%s%v", sep, Rconv(int(p.Reg))) - sep = ", " - } - for i := range p.RestArgs { - io.WriteString(w, sep) - WriteDconv(w, p, &p.RestArgs[i]) - sep = ", " - } - - if p.As == ATEXT { - // If there are attributes, print them. Otherwise, skip the comma. - // In short, print one of these two: - // TEXT foo(SB), DUPOK|NOSPLIT, $0 - // TEXT foo(SB), $0 - s := p.From.Sym.Attribute.TextAttrString() - if s != "" { - fmt.Fprintf(w, "%s%s", sep, s) - sep = ", " - } - } - if p.To.Type != TYPE_NONE { - io.WriteString(w, sep) - WriteDconv(w, p, &p.To) - } - if p.RegTo2 != REG_NONE { - fmt.Fprintf(w, "%s%v", sep, Rconv(int(p.RegTo2))) - } -} - -func (ctxt *Link) NewProg() *Prog { - p := new(Prog) - p.Ctxt = ctxt - return p -} - -func (ctxt *Link) CanReuseProgs() bool { - return ctxt.Debugasm == 0 -} - -func Dconv(p *Prog, a *Addr) string { - buf := new(bytes.Buffer) - WriteDconv(buf, p, a) - return buf.String() -} - -func WriteDconv(w io.Writer, p *Prog, a *Addr) { - switch a.Type { - default: - fmt.Fprintf(w, "type=%d", a.Type) - - case TYPE_NONE: - if a.Name != NAME_NONE || a.Reg != 0 || a.Sym != nil { - a.WriteNameTo(w) - fmt.Fprintf(w, "(%v)(NONE)", Rconv(int(a.Reg))) - } - - case TYPE_REG: - // TODO(rsc): This special case is for x86 instructions like - // PINSRQ CX,$1,X6 - // where the $1 is included in the p->to Addr. - // Move into a new field. - if a.Offset != 0 && (a.Reg < RBaseARM64 || a.Reg >= RBaseMIPS) { - fmt.Fprintf(w, "$%d,%v", a.Offset, Rconv(int(a.Reg))) - return - } - - if a.Name != NAME_NONE || a.Sym != nil { - a.WriteNameTo(w) - fmt.Fprintf(w, "(%v)(REG)", Rconv(int(a.Reg))) - } else { - io.WriteString(w, Rconv(int(a.Reg))) - } - if (RBaseARM64+1<<10+1<<9) /* arm64.REG_ELEM */ <= a.Reg && - a.Reg < (RBaseARM64+1<<11) /* arm64.REG_ELEM_END */ { - fmt.Fprintf(w, "[%d]", a.Index) - } - - case TYPE_BRANCH: - if a.Sym != nil { - fmt.Fprintf(w, "%s(SB)", a.Sym.Name) - } else if a.Target() != nil { - fmt.Fprint(w, a.Target().Pc) - } else { - fmt.Fprintf(w, "%d(PC)", a.Offset) - } - - case TYPE_INDIR: - io.WriteString(w, "*") - a.WriteNameTo(w) - - case TYPE_MEM: - a.WriteNameTo(w) - if a.Index != REG_NONE { - if a.Scale == 0 { - // arm64 shifted or extended register offset, scale = 0. - fmt.Fprintf(w, "(%v)", Rconv(int(a.Index))) - } else { - fmt.Fprintf(w, "(%v*%d)", Rconv(int(a.Index)), int(a.Scale)) - } - } - - case TYPE_CONST: - io.WriteString(w, "$") - a.WriteNameTo(w) - if a.Reg != 0 { - fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg))) - } - - case TYPE_TEXTSIZE: - if a.Val.(int32) == objabi.ArgsSizeUnknown { - fmt.Fprintf(w, "$%d", a.Offset) - } else { - fmt.Fprintf(w, "$%d-%d", a.Offset, a.Val.(int32)) - } - - case TYPE_FCONST: - str := fmt.Sprintf("%.17g", a.Val.(float64)) - // Make sure 1 prints as 1.0 - if !strings.ContainsAny(str, ".e") { - str += ".0" - } - fmt.Fprintf(w, "$(%s)", str) - - case TYPE_SCONST: - fmt.Fprintf(w, "$%q", a.Val.(string)) - - case TYPE_ADDR: - io.WriteString(w, "$") - a.WriteNameTo(w) - - case TYPE_SHIFT: - v := int(a.Offset) - ops := "<<>>->@>" - switch objabi.GOARCH { - case "arm": - op := ops[((v>>5)&3)<<1:] - if v&(1<<4) != 0 { - fmt.Fprintf(w, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15) - } else { - fmt.Fprintf(w, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31) - } - if a.Reg != 0 { - fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg))) - } - case "arm64": - op := ops[((v>>22)&3)<<1:] - r := (v >> 16) & 31 - fmt.Fprintf(w, "%s%c%c%d", Rconv(r+RBaseARM64), op[0], op[1], (v>>10)&63) - default: - panic("TYPE_SHIFT is not supported on " + objabi.GOARCH) - } - - case TYPE_REGREG: - fmt.Fprintf(w, "(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset))) - - case TYPE_REGREG2: - fmt.Fprintf(w, "%v, %v", Rconv(int(a.Offset)), Rconv(int(a.Reg))) - - case TYPE_REGLIST: - io.WriteString(w, RLconv(a.Offset)) - } -} - -func (a *Addr) WriteNameTo(w io.Writer) { - switch a.Name { - default: - fmt.Fprintf(w, "name=%d", a.Name) - - case NAME_NONE: - switch { - case a.Reg == REG_NONE: - fmt.Fprint(w, a.Offset) - case a.Offset == 0: - fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg))) - case a.Offset != 0: - fmt.Fprintf(w, "%d(%v)", a.Offset, Rconv(int(a.Reg))) - } - - // Note: a.Reg == REG_NONE encodes the default base register for the NAME_ type. - case NAME_EXTERN: - reg := "SB" - if a.Reg != REG_NONE { - reg = Rconv(int(a.Reg)) - } - if a.Sym != nil { - fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg) - } else { - fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg) - } - - case NAME_GOTREF: - reg := "SB" - if a.Reg != REG_NONE { - reg = Rconv(int(a.Reg)) - } - if a.Sym != nil { - fmt.Fprintf(w, "%s%s@GOT(%s)", a.Sym.Name, offConv(a.Offset), reg) - } else { - fmt.Fprintf(w, "%s@GOT(%s)", offConv(a.Offset), reg) - } - - case NAME_STATIC: - reg := "SB" - if a.Reg != REG_NONE { - reg = Rconv(int(a.Reg)) - } - if a.Sym != nil { - fmt.Fprintf(w, "%s<>%s(%s)", a.Sym.Name, offConv(a.Offset), reg) - } else { - fmt.Fprintf(w, "<>%s(%s)", offConv(a.Offset), reg) - } - - case NAME_AUTO: - reg := "SP" - if a.Reg != REG_NONE { - reg = Rconv(int(a.Reg)) - } - if a.Sym != nil { - fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg) - } else { - fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg) - } - - case NAME_PARAM: - reg := "FP" - if a.Reg != REG_NONE { - reg = Rconv(int(a.Reg)) - } - if a.Sym != nil { - fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg) - } else { - fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg) - } - case NAME_TOCREF: - reg := "SB" - if a.Reg != REG_NONE { - reg = Rconv(int(a.Reg)) - } - if a.Sym != nil { - fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg) - } else { - fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg) - } - } -} - -func offConv(off int64) string { - if off == 0 { - return "" - } - return fmt.Sprintf("%+d", off) -} - -// opSuffixSet is like regListSet, but for opcode suffixes. -// -// Unlike some other similar structures, uint8 space is not -// divided by its own values set (because there are only 256 of them). -// Instead, every arch may interpret/format all 8 bits as they like, -// as long as they register proper cconv function for it. -type opSuffixSet struct { - arch string - cconv func(suffix uint8) string -} - -var opSuffixSpace []opSuffixSet - -// RegisterOpSuffix assigns cconv function for formatting opcode suffixes -// when compiling for GOARCH=arch. -// -// cconv is never called with 0 argument. -func RegisterOpSuffix(arch string, cconv func(uint8) string) { - opSuffixSpace = append(opSuffixSpace, opSuffixSet{ - arch: arch, - cconv: cconv, - }) -} - -type regSet struct { - lo int - hi int - Rconv func(int) string -} - -// Few enough architectures that a linear scan is fastest. -// Not even worth sorting. -var regSpace []regSet - -/* - Each architecture defines a register space as a unique - integer range. - Here is the list of architectures and the base of their register spaces. -*/ - -const ( - // Because of masking operations in the encodings, each register - // space should start at 0 modulo some power of 2. - RBase386 = 1 * 1024 - RBaseAMD64 = 2 * 1024 - RBaseARM = 3 * 1024 - RBasePPC64 = 4 * 1024 // range [4k, 8k) - RBaseARM64 = 8 * 1024 // range [8k, 13k) - RBaseMIPS = 13 * 1024 // range [13k, 14k) - RBaseS390X = 14 * 1024 // range [14k, 15k) - RBaseRISCV = 15 * 1024 // range [15k, 16k) - RBaseWasm = 16 * 1024 -) - -// RegisterRegister binds a pretty-printer (Rconv) for register -// numbers to a given register number range. Lo is inclusive, -// hi exclusive (valid registers are lo through hi-1). -func RegisterRegister(lo, hi int, Rconv func(int) string) { - regSpace = append(regSpace, regSet{lo, hi, Rconv}) -} - -func Rconv(reg int) string { - if reg == REG_NONE { - return "NONE" - } - for i := range regSpace { - rs := ®Space[i] - if rs.lo <= reg && reg < rs.hi { - return rs.Rconv(reg) - } - } - return fmt.Sprintf("R???%d", reg) -} - -type regListSet struct { - lo int64 - hi int64 - RLconv func(int64) string -} - -var regListSpace []regListSet - -// Each architecture is allotted a distinct subspace: [Lo, Hi) for declaring its -// arch-specific register list numbers. -const ( - RegListARMLo = 0 - RegListARMHi = 1 << 16 - - // arm64 uses the 60th bit to differentiate from other archs - RegListARM64Lo = 1 << 60 - RegListARM64Hi = 1<<61 - 1 - - // x86 uses the 61th bit to differentiate from other archs - RegListX86Lo = 1 << 61 - RegListX86Hi = 1<<62 - 1 -) - -// RegisterRegisterList binds a pretty-printer (RLconv) for register list -// numbers to a given register list number range. Lo is inclusive, -// hi exclusive (valid register list are lo through hi-1). -func RegisterRegisterList(lo, hi int64, rlconv func(int64) string) { - regListSpace = append(regListSpace, regListSet{lo, hi, rlconv}) -} - -func RLconv(list int64) string { - for i := range regListSpace { - rls := ®ListSpace[i] - if rls.lo <= list && list < rls.hi { - return rls.RLconv(list) - } - } - return fmt.Sprintf("RL???%d", list) -} - -type opSet struct { - lo As - names []string -} - -// Not even worth sorting -var aSpace []opSet - -// RegisterOpcode binds a list of instruction names -// to a given instruction number range. -func RegisterOpcode(lo As, Anames []string) { - if len(Anames) > AllowedOpCodes { - panic(fmt.Sprintf("too many instructions, have %d max %d", len(Anames), AllowedOpCodes)) - } - aSpace = append(aSpace, opSet{lo, Anames}) -} - -func (a As) String() string { - if 0 <= a && int(a) < len(Anames) { - return Anames[a] - } - for i := range aSpace { - as := &aSpace[i] - if as.lo <= a && int(a-as.lo) < len(as.names) { - return as.names[a-as.lo] - } - } - return fmt.Sprintf("A???%d", a) -} - -var Anames = []string{ - "XXX", - "CALL", - "DUFFCOPY", - "DUFFZERO", - "END", - "FUNCDATA", - "JMP", - "NOP", - "PCALIGN", - "PCDATA", - "RET", - "GETCALLERPC", - "TEXT", - "UNDEF", -} - -func Bool2int(b bool) int { - // The compiler currently only optimizes this form. - // See issue 6011. - var i int - if b { - i = 1 - } else { - i = 0 - } - return i -} |