podman
1// Copyright 2014 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
5package x86asm6
7import (8"fmt"9"strings"10)
11
12type SymLookup func(uint64) (string, uint64)13
14// GoSyntax returns the Go assembler syntax for the instruction.
15// The syntax was originally defined by Plan 9.
16// The pc is the program counter of the instruction, used for expanding
17// PC-relative addresses into absolute ones.
18// The symname function queries the symbol table for the program
19// being disassembled. Given a target address it returns the name and base
20// address of the symbol containing the target, if any; otherwise it returns "", 0.
21func GoSyntax(inst Inst, pc uint64, symname SymLookup) string {22if symname == nil {23symname = func(uint64) (string, uint64) { return "", 0 }24}25var args []string26for i := len(inst.Args) - 1; i >= 0; i-- {27a := inst.Args[i]28if a == nil {29continue30}31args = append(args, plan9Arg(&inst, pc, symname, a))32}33
34var rep string35var last Prefix36for _, p := range inst.Prefix {37if p == 0 || p.IsREX() || p.IsVEX() {38break39}40
41switch {42// Don't show prefixes implied by the instruction text.43case p&0xFF00 == PrefixImplicit:44continue45// Only REP and REPN are recognized repeaters. Plan 9 syntax46// treats them as separate opcodes.47case p&0xFF == PrefixREP:48rep = "REP; "49case p&0xFF == PrefixREPN:50rep = "REPNE; "51default:52last = p53}54}55
56prefix := ""57switch last & 0xFF {58case 0, 0x66, 0x67:59// ignore60default:61prefix += last.String() + " "62}63
64op := inst.Op.String()65if plan9Suffix[inst.Op] {66s := inst.DataSize67if inst.MemBytes != 0 {68s = inst.MemBytes * 869} else if inst.Args[1] == nil { // look for register-only 64-bit instruction, like PUSHQ AX70if r, ok := inst.Args[0].(Reg); ok && RAX <= r && r <= R15 {71s = 6472}73}74switch s {75case 8:76op += "B"77case 16:78op += "W"79case 32:80op += "L"81case 64:82op += "Q"83}84}85
86if inst.Op == CMP {87// Use reads-left-to-right ordering for comparisons.88// See issue 60920.89args[0], args[1] = args[1], args[0]90}91
92if args != nil {93op += " " + strings.Join(args, ", ")94}95
96return rep + prefix + op97}
98
99func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string {100switch a := arg.(type) {101case Reg:102return plan9Reg[a]103case Rel:104if pc == 0 {105break106}107// If the absolute address is the start of a symbol, use the name.108// Otherwise use the raw address, so that things like relative109// jumps show up as JMP 0x123 instead of JMP f+10(SB).110// It is usually easier to search for 0x123 than to do the mental111// arithmetic to find f+10.112addr := pc + uint64(inst.Len) + uint64(a)113if s, base := symname(addr); s != "" && addr == base {114return fmt.Sprintf("%s(SB)", s)115}116return fmt.Sprintf("%#x", addr)117
118case Imm:119if s, base := symname(uint64(a)); s != "" {120suffix := ""121if uint64(a) != base {122suffix = fmt.Sprintf("%+d", uint64(a)-base)123}124return fmt.Sprintf("$%s%s(SB)", s, suffix)125}126if inst.Mode == 32 {127return fmt.Sprintf("$%#x", uint32(a))128}129if Imm(int32(a)) == a {130return fmt.Sprintf("$%#x", int64(a))131}132return fmt.Sprintf("$%#x", uint64(a))133case Mem:134if s, disp := memArgToSymbol(a, pc, inst.Len, symname); s != "" {135suffix := ""136if disp != 0 {137suffix = fmt.Sprintf("%+d", disp)138}139return fmt.Sprintf("%s%s(SB)", s, suffix)140}141s := ""142if a.Segment != 0 {143s += fmt.Sprintf("%s:", plan9Reg[a.Segment])144}145if a.Disp != 0 {146s += fmt.Sprintf("%#x", a.Disp)147} else {148s += "0"149}150if a.Base != 0 {151s += fmt.Sprintf("(%s)", plan9Reg[a.Base])152}153if a.Index != 0 && a.Scale != 0 {154s += fmt.Sprintf("(%s*%d)", plan9Reg[a.Index], a.Scale)155}156return s157}158return arg.String()159}
160
161func memArgToSymbol(a Mem, pc uint64, instrLen int, symname SymLookup) (string, int64) {162if a.Segment != 0 || a.Disp == 0 || a.Index != 0 || a.Scale != 0 {163return "", 0164}165
166var disp uint64167switch a.Base {168case IP, EIP, RIP:169disp = uint64(a.Disp + int64(pc) + int64(instrLen))170case 0:171disp = uint64(a.Disp)172default:173return "", 0174}175
176s, base := symname(disp)177return s, int64(disp) - int64(base)178}
179
180var plan9Suffix = [maxOp + 1]bool{181ADC: true,182ADD: true,183AND: true,184BSF: true,185BSR: true,186BT: true,187BTC: true,188BTR: true,189BTS: true,190CMP: true,191CMPXCHG: true,192CVTSI2SD: true,193CVTSI2SS: true,194CVTSD2SI: true,195CVTSS2SI: true,196CVTTSD2SI: true,197CVTTSS2SI: true,198DEC: true,199DIV: true,200FLDENV: true,201FRSTOR: true,202IDIV: true,203IMUL: true,204IN: true,205INC: true,206LEA: true,207MOV: true,208MOVNTI: true,209MUL: true,210NEG: true,211NOP: true,212NOT: true,213OR: true,214OUT: true,215POP: true,216POPA: true,217POPCNT: true,218PUSH: true,219PUSHA: true,220RCL: true,221RCR: true,222ROL: true,223ROR: true,224SAR: true,225SBB: true,226SHL: true,227SHLD: true,228SHR: true,229SHRD: true,230SUB: true,231TEST: true,232XADD: true,233XCHG: true,234XOR: true,235}
236
237var plan9Reg = [...]string{238AL: "AL",239CL: "CL",240BL: "BL",241DL: "DL",242AH: "AH",243CH: "CH",244BH: "BH",245DH: "DH",246SPB: "SP",247BPB: "BP",248SIB: "SI",249DIB: "DI",250R8B: "R8",251R9B: "R9",252R10B: "R10",253R11B: "R11",254R12B: "R12",255R13B: "R13",256R14B: "R14",257R15B: "R15",258AX: "AX",259CX: "CX",260BX: "BX",261DX: "DX",262SP: "SP",263BP: "BP",264SI: "SI",265DI: "DI",266R8W: "R8",267R9W: "R9",268R10W: "R10",269R11W: "R11",270R12W: "R12",271R13W: "R13",272R14W: "R14",273R15W: "R15",274EAX: "AX",275ECX: "CX",276EDX: "DX",277EBX: "BX",278ESP: "SP",279EBP: "BP",280ESI: "SI",281EDI: "DI",282R8L: "R8",283R9L: "R9",284R10L: "R10",285R11L: "R11",286R12L: "R12",287R13L: "R13",288R14L: "R14",289R15L: "R15",290RAX: "AX",291RCX: "CX",292RDX: "DX",293RBX: "BX",294RSP: "SP",295RBP: "BP",296RSI: "SI",297RDI: "DI",298R8: "R8",299R9: "R9",300R10: "R10",301R11: "R11",302R12: "R12",303R13: "R13",304R14: "R14",305R15: "R15",306IP: "IP",307EIP: "IP",308RIP: "IP",309F0: "F0",310F1: "F1",311F2: "F2",312F3: "F3",313F4: "F4",314F5: "F5",315F6: "F6",316F7: "F7",317M0: "M0",318M1: "M1",319M2: "M2",320M3: "M3",321M4: "M4",322M5: "M5",323M6: "M6",324M7: "M7",325X0: "X0",326X1: "X1",327X2: "X2",328X3: "X3",329X4: "X4",330X5: "X5",331X6: "X6",332X7: "X7",333X8: "X8",334X9: "X9",335X10: "X10",336X11: "X11",337X12: "X12",338X13: "X13",339X14: "X14",340X15: "X15",341CS: "CS",342SS: "SS",343DS: "DS",344ES: "ES",345FS: "FS",346GS: "GS",347GDTR: "GDTR",348IDTR: "IDTR",349LDTR: "LDTR",350MSW: "MSW",351TASK: "TASK",352CR0: "CR0",353CR1: "CR1",354CR2: "CR2",355CR3: "CR3",356CR4: "CR4",357CR5: "CR5",358CR6: "CR6",359CR7: "CR7",360CR8: "CR8",361CR9: "CR9",362CR10: "CR10",363CR11: "CR11",364CR12: "CR12",365CR13: "CR13",366CR14: "CR14",367CR15: "CR15",368DR0: "DR0",369DR1: "DR1",370DR2: "DR2",371DR3: "DR3",372DR4: "DR4",373DR5: "DR5",374DR6: "DR6",375DR7: "DR7",376DR8: "DR8",377DR9: "DR9",378DR10: "DR10",379DR11: "DR11",380DR12: "DR12",381DR13: "DR13",382DR14: "DR14",383DR15: "DR15",384TR0: "TR0",385TR1: "TR1",386TR2: "TR2",387TR3: "TR3",388TR4: "TR4",389TR5: "TR5",390TR6: "TR6",391TR7: "TR7",392}
393