mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-12-04 22:20:53 +01:00
55aacaf4b0
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
387 lines
7.1 KiB
Go
387 lines
7.1 KiB
Go
// Copyright 2014 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 x86asm
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
type SymLookup func(uint64) (string, uint64)
|
|
|
|
// GoSyntax returns the Go assembler syntax for the instruction.
|
|
// The syntax was originally defined by Plan 9.
|
|
// The pc is the program counter of the instruction, used for expanding
|
|
// PC-relative addresses into absolute ones.
|
|
// The symname function queries the symbol table for the program
|
|
// being disassembled. Given a target address it returns the name and base
|
|
// address of the symbol containing the target, if any; otherwise it returns "", 0.
|
|
func GoSyntax(inst Inst, pc uint64, symname SymLookup) string {
|
|
if symname == nil {
|
|
symname = func(uint64) (string, uint64) { return "", 0 }
|
|
}
|
|
var args []string
|
|
for i := len(inst.Args) - 1; i >= 0; i-- {
|
|
a := inst.Args[i]
|
|
if a == nil {
|
|
continue
|
|
}
|
|
args = append(args, plan9Arg(&inst, pc, symname, a))
|
|
}
|
|
|
|
var rep string
|
|
var last Prefix
|
|
for _, p := range inst.Prefix {
|
|
if p == 0 || p.IsREX() || p.IsVEX() {
|
|
break
|
|
}
|
|
|
|
switch {
|
|
// Don't show prefixes implied by the instruction text.
|
|
case p&0xFF00 == PrefixImplicit:
|
|
continue
|
|
// Only REP and REPN are recognized repeaters. Plan 9 syntax
|
|
// treats them as separate opcodes.
|
|
case p&0xFF == PrefixREP:
|
|
rep = "REP; "
|
|
case p&0xFF == PrefixREPN:
|
|
rep = "REPNE; "
|
|
default:
|
|
last = p
|
|
}
|
|
}
|
|
|
|
prefix := ""
|
|
switch last & 0xFF {
|
|
case 0, 0x66, 0x67:
|
|
// ignore
|
|
default:
|
|
prefix += last.String() + " "
|
|
}
|
|
|
|
op := inst.Op.String()
|
|
if plan9Suffix[inst.Op] {
|
|
s := inst.DataSize
|
|
if inst.MemBytes != 0 {
|
|
s = inst.MemBytes * 8
|
|
} else if inst.Args[1] == nil { // look for register-only 64-bit instruction, like PUSHQ AX
|
|
if r, ok := inst.Args[0].(Reg); ok && RAX <= r && r <= R15 {
|
|
s = 64
|
|
}
|
|
}
|
|
switch s {
|
|
case 8:
|
|
op += "B"
|
|
case 16:
|
|
op += "W"
|
|
case 32:
|
|
op += "L"
|
|
case 64:
|
|
op += "Q"
|
|
}
|
|
}
|
|
|
|
if args != nil {
|
|
op += " " + strings.Join(args, ", ")
|
|
}
|
|
|
|
return rep + prefix + op
|
|
}
|
|
|
|
func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string {
|
|
switch a := arg.(type) {
|
|
case Reg:
|
|
return plan9Reg[a]
|
|
case Rel:
|
|
if pc == 0 {
|
|
break
|
|
}
|
|
// If the absolute address is the start of a symbol, use the name.
|
|
// Otherwise use the raw address, so that things like relative
|
|
// jumps show up as JMP 0x123 instead of JMP f+10(SB).
|
|
// It is usually easier to search for 0x123 than to do the mental
|
|
// arithmetic to find f+10.
|
|
addr := pc + uint64(inst.Len) + uint64(a)
|
|
if s, base := symname(addr); s != "" && addr == base {
|
|
return fmt.Sprintf("%s(SB)", s)
|
|
}
|
|
return fmt.Sprintf("%#x", addr)
|
|
|
|
case Imm:
|
|
if s, base := symname(uint64(a)); s != "" {
|
|
suffix := ""
|
|
if uint64(a) != base {
|
|
suffix = fmt.Sprintf("%+d", uint64(a)-base)
|
|
}
|
|
return fmt.Sprintf("$%s%s(SB)", s, suffix)
|
|
}
|
|
if inst.Mode == 32 {
|
|
return fmt.Sprintf("$%#x", uint32(a))
|
|
}
|
|
if Imm(int32(a)) == a {
|
|
return fmt.Sprintf("$%#x", int64(a))
|
|
}
|
|
return fmt.Sprintf("$%#x", uint64(a))
|
|
case Mem:
|
|
if s, disp := memArgToSymbol(a, pc, inst.Len, symname); s != "" {
|
|
suffix := ""
|
|
if disp != 0 {
|
|
suffix = fmt.Sprintf("%+d", disp)
|
|
}
|
|
return fmt.Sprintf("%s%s(SB)", s, suffix)
|
|
}
|
|
s := ""
|
|
if a.Segment != 0 {
|
|
s += fmt.Sprintf("%s:", plan9Reg[a.Segment])
|
|
}
|
|
if a.Disp != 0 {
|
|
s += fmt.Sprintf("%#x", a.Disp)
|
|
} else {
|
|
s += "0"
|
|
}
|
|
if a.Base != 0 {
|
|
s += fmt.Sprintf("(%s)", plan9Reg[a.Base])
|
|
}
|
|
if a.Index != 0 && a.Scale != 0 {
|
|
s += fmt.Sprintf("(%s*%d)", plan9Reg[a.Index], a.Scale)
|
|
}
|
|
return s
|
|
}
|
|
return arg.String()
|
|
}
|
|
|
|
func memArgToSymbol(a Mem, pc uint64, instrLen int, symname SymLookup) (string, int64) {
|
|
if a.Segment != 0 || a.Disp == 0 || a.Index != 0 || a.Scale != 0 {
|
|
return "", 0
|
|
}
|
|
|
|
var disp uint64
|
|
switch a.Base {
|
|
case IP, EIP, RIP:
|
|
disp = uint64(a.Disp + int64(pc) + int64(instrLen))
|
|
case 0:
|
|
disp = uint64(a.Disp)
|
|
default:
|
|
return "", 0
|
|
}
|
|
|
|
s, base := symname(disp)
|
|
return s, int64(disp) - int64(base)
|
|
}
|
|
|
|
var plan9Suffix = [maxOp + 1]bool{
|
|
ADC: true,
|
|
ADD: true,
|
|
AND: true,
|
|
BSF: true,
|
|
BSR: true,
|
|
BT: true,
|
|
BTC: true,
|
|
BTR: true,
|
|
BTS: true,
|
|
CMP: true,
|
|
CMPXCHG: true,
|
|
CVTSI2SD: true,
|
|
CVTSI2SS: true,
|
|
CVTSD2SI: true,
|
|
CVTSS2SI: true,
|
|
CVTTSD2SI: true,
|
|
CVTTSS2SI: true,
|
|
DEC: true,
|
|
DIV: true,
|
|
FLDENV: true,
|
|
FRSTOR: true,
|
|
IDIV: true,
|
|
IMUL: true,
|
|
IN: true,
|
|
INC: true,
|
|
LEA: true,
|
|
MOV: true,
|
|
MOVNTI: true,
|
|
MUL: true,
|
|
NEG: true,
|
|
NOP: true,
|
|
NOT: true,
|
|
OR: true,
|
|
OUT: true,
|
|
POP: true,
|
|
POPA: true,
|
|
POPCNT: true,
|
|
PUSH: true,
|
|
PUSHA: true,
|
|
RCL: true,
|
|
RCR: true,
|
|
ROL: true,
|
|
ROR: true,
|
|
SAR: true,
|
|
SBB: true,
|
|
SHL: true,
|
|
SHLD: true,
|
|
SHR: true,
|
|
SHRD: true,
|
|
SUB: true,
|
|
TEST: true,
|
|
XADD: true,
|
|
XCHG: true,
|
|
XOR: true,
|
|
}
|
|
|
|
var plan9Reg = [...]string{
|
|
AL: "AL",
|
|
CL: "CL",
|
|
BL: "BL",
|
|
DL: "DL",
|
|
AH: "AH",
|
|
CH: "CH",
|
|
BH: "BH",
|
|
DH: "DH",
|
|
SPB: "SP",
|
|
BPB: "BP",
|
|
SIB: "SI",
|
|
DIB: "DI",
|
|
R8B: "R8",
|
|
R9B: "R9",
|
|
R10B: "R10",
|
|
R11B: "R11",
|
|
R12B: "R12",
|
|
R13B: "R13",
|
|
R14B: "R14",
|
|
R15B: "R15",
|
|
AX: "AX",
|
|
CX: "CX",
|
|
BX: "BX",
|
|
DX: "DX",
|
|
SP: "SP",
|
|
BP: "BP",
|
|
SI: "SI",
|
|
DI: "DI",
|
|
R8W: "R8",
|
|
R9W: "R9",
|
|
R10W: "R10",
|
|
R11W: "R11",
|
|
R12W: "R12",
|
|
R13W: "R13",
|
|
R14W: "R14",
|
|
R15W: "R15",
|
|
EAX: "AX",
|
|
ECX: "CX",
|
|
EDX: "DX",
|
|
EBX: "BX",
|
|
ESP: "SP",
|
|
EBP: "BP",
|
|
ESI: "SI",
|
|
EDI: "DI",
|
|
R8L: "R8",
|
|
R9L: "R9",
|
|
R10L: "R10",
|
|
R11L: "R11",
|
|
R12L: "R12",
|
|
R13L: "R13",
|
|
R14L: "R14",
|
|
R15L: "R15",
|
|
RAX: "AX",
|
|
RCX: "CX",
|
|
RDX: "DX",
|
|
RBX: "BX",
|
|
RSP: "SP",
|
|
RBP: "BP",
|
|
RSI: "SI",
|
|
RDI: "DI",
|
|
R8: "R8",
|
|
R9: "R9",
|
|
R10: "R10",
|
|
R11: "R11",
|
|
R12: "R12",
|
|
R13: "R13",
|
|
R14: "R14",
|
|
R15: "R15",
|
|
IP: "IP",
|
|
EIP: "IP",
|
|
RIP: "IP",
|
|
F0: "F0",
|
|
F1: "F1",
|
|
F2: "F2",
|
|
F3: "F3",
|
|
F4: "F4",
|
|
F5: "F5",
|
|
F6: "F6",
|
|
F7: "F7",
|
|
M0: "M0",
|
|
M1: "M1",
|
|
M2: "M2",
|
|
M3: "M3",
|
|
M4: "M4",
|
|
M5: "M5",
|
|
M6: "M6",
|
|
M7: "M7",
|
|
X0: "X0",
|
|
X1: "X1",
|
|
X2: "X2",
|
|
X3: "X3",
|
|
X4: "X4",
|
|
X5: "X5",
|
|
X6: "X6",
|
|
X7: "X7",
|
|
X8: "X8",
|
|
X9: "X9",
|
|
X10: "X10",
|
|
X11: "X11",
|
|
X12: "X12",
|
|
X13: "X13",
|
|
X14: "X14",
|
|
X15: "X15",
|
|
CS: "CS",
|
|
SS: "SS",
|
|
DS: "DS",
|
|
ES: "ES",
|
|
FS: "FS",
|
|
GS: "GS",
|
|
GDTR: "GDTR",
|
|
IDTR: "IDTR",
|
|
LDTR: "LDTR",
|
|
MSW: "MSW",
|
|
TASK: "TASK",
|
|
CR0: "CR0",
|
|
CR1: "CR1",
|
|
CR2: "CR2",
|
|
CR3: "CR3",
|
|
CR4: "CR4",
|
|
CR5: "CR5",
|
|
CR6: "CR6",
|
|
CR7: "CR7",
|
|
CR8: "CR8",
|
|
CR9: "CR9",
|
|
CR10: "CR10",
|
|
CR11: "CR11",
|
|
CR12: "CR12",
|
|
CR13: "CR13",
|
|
CR14: "CR14",
|
|
CR15: "CR15",
|
|
DR0: "DR0",
|
|
DR1: "DR1",
|
|
DR2: "DR2",
|
|
DR3: "DR3",
|
|
DR4: "DR4",
|
|
DR5: "DR5",
|
|
DR6: "DR6",
|
|
DR7: "DR7",
|
|
DR8: "DR8",
|
|
DR9: "DR9",
|
|
DR10: "DR10",
|
|
DR11: "DR11",
|
|
DR12: "DR12",
|
|
DR13: "DR13",
|
|
DR14: "DR14",
|
|
DR15: "DR15",
|
|
TR0: "TR0",
|
|
TR1: "TR1",
|
|
TR2: "TR2",
|
|
TR3: "TR3",
|
|
TR4: "TR4",
|
|
TR5: "TR5",
|
|
TR6: "TR6",
|
|
TR7: "TR7",
|
|
}
|