mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-11-27 14:16:39 +00:00
561 lines
12 KiB
Go
561 lines
12 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"
|
|
)
|
|
|
|
// IntelSyntax returns the Intel assembler syntax for the instruction, as defined by Intel's XED tool.
|
|
func IntelSyntax(inst Inst, pc uint64, symname SymLookup) string {
|
|
if symname == nil {
|
|
symname = func(uint64) (string, uint64) { return "", 0 }
|
|
}
|
|
|
|
var iargs []Arg
|
|
for _, a := range inst.Args {
|
|
if a == nil {
|
|
break
|
|
}
|
|
iargs = append(iargs, a)
|
|
}
|
|
|
|
switch inst.Op {
|
|
case INSB, INSD, INSW, OUTSB, OUTSD, OUTSW, LOOPNE, JCXZ, JECXZ, JRCXZ, LOOP, LOOPE, MOV, XLATB:
|
|
if inst.Op == MOV && (inst.Opcode>>16)&0xFFFC != 0x0F20 {
|
|
break
|
|
}
|
|
for i, p := range inst.Prefix {
|
|
if p&0xFF == PrefixAddrSize {
|
|
inst.Prefix[i] &^= PrefixImplicit
|
|
}
|
|
}
|
|
}
|
|
|
|
switch inst.Op {
|
|
case MOV:
|
|
dst, _ := inst.Args[0].(Reg)
|
|
src, _ := inst.Args[1].(Reg)
|
|
if ES <= dst && dst <= GS && EAX <= src && src <= R15L {
|
|
src -= EAX - AX
|
|
iargs[1] = src
|
|
}
|
|
if ES <= dst && dst <= GS && RAX <= src && src <= R15 {
|
|
src -= RAX - AX
|
|
iargs[1] = src
|
|
}
|
|
|
|
if inst.Opcode>>24&^3 == 0xA0 {
|
|
for i, p := range inst.Prefix {
|
|
if p&0xFF == PrefixAddrSize {
|
|
inst.Prefix[i] |= PrefixImplicit
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
switch inst.Op {
|
|
case AAM, AAD:
|
|
if imm, ok := iargs[0].(Imm); ok {
|
|
if inst.DataSize == 32 {
|
|
iargs[0] = Imm(uint32(int8(imm)))
|
|
} else if inst.DataSize == 16 {
|
|
iargs[0] = Imm(uint16(int8(imm)))
|
|
}
|
|
}
|
|
|
|
case PUSH:
|
|
if imm, ok := iargs[0].(Imm); ok {
|
|
iargs[0] = Imm(uint32(imm))
|
|
}
|
|
}
|
|
|
|
for _, p := range inst.Prefix {
|
|
if p&PrefixImplicit != 0 {
|
|
for j, pj := range inst.Prefix {
|
|
if pj&0xFF == p&0xFF {
|
|
inst.Prefix[j] |= PrefixImplicit
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if inst.Op != 0 {
|
|
for i, p := range inst.Prefix {
|
|
switch p &^ PrefixIgnored {
|
|
case PrefixData16, PrefixData32, PrefixCS, PrefixDS, PrefixES, PrefixSS:
|
|
inst.Prefix[i] |= PrefixImplicit
|
|
}
|
|
if p.IsREX() {
|
|
inst.Prefix[i] |= PrefixImplicit
|
|
}
|
|
if p.IsVEX() {
|
|
if p == PrefixVEX3Bytes {
|
|
inst.Prefix[i+2] |= PrefixImplicit
|
|
}
|
|
inst.Prefix[i] |= PrefixImplicit
|
|
inst.Prefix[i+1] |= PrefixImplicit
|
|
}
|
|
}
|
|
}
|
|
|
|
if isLoop[inst.Op] || inst.Op == JCXZ || inst.Op == JECXZ || inst.Op == JRCXZ {
|
|
for i, p := range inst.Prefix {
|
|
if p == PrefixPT || p == PrefixPN {
|
|
inst.Prefix[i] |= PrefixImplicit
|
|
}
|
|
}
|
|
}
|
|
|
|
switch inst.Op {
|
|
case AAA, AAS, CBW, CDQE, CLC, CLD, CLI, CLTS, CMC, CPUID, CQO, CWD, DAA, DAS,
|
|
FDECSTP, FINCSTP, FNCLEX, FNINIT, FNOP, FWAIT, HLT,
|
|
ICEBP, INSB, INSD, INSW, INT, INTO, INVD, IRET, IRETQ,
|
|
LAHF, LEAVE, LRET, MONITOR, MWAIT, NOP, OUTSB, OUTSD, OUTSW,
|
|
PAUSE, POPA, POPF, POPFQ, PUSHA, PUSHF, PUSHFQ,
|
|
RDMSR, RDPMC, RDTSC, RDTSCP, RET, RSM,
|
|
SAHF, STC, STD, STI, SYSENTER, SYSEXIT, SYSRET,
|
|
UD2, WBINVD, WRMSR, XEND, XLATB, XTEST:
|
|
|
|
if inst.Op == NOP && inst.Opcode>>24 != 0x90 {
|
|
break
|
|
}
|
|
if inst.Op == RET && inst.Opcode>>24 != 0xC3 {
|
|
break
|
|
}
|
|
if inst.Op == INT && inst.Opcode>>24 != 0xCC {
|
|
break
|
|
}
|
|
if inst.Op == LRET && inst.Opcode>>24 != 0xcb {
|
|
break
|
|
}
|
|
for i, p := range inst.Prefix {
|
|
if p&0xFF == PrefixDataSize {
|
|
inst.Prefix[i] &^= PrefixImplicit | PrefixIgnored
|
|
}
|
|
}
|
|
|
|
case 0:
|
|
// ok
|
|
}
|
|
|
|
switch inst.Op {
|
|
case INSB, INSD, INSW, OUTSB, OUTSD, OUTSW, MONITOR, MWAIT, XLATB:
|
|
iargs = nil
|
|
|
|
case STOSB, STOSW, STOSD, STOSQ:
|
|
iargs = iargs[:1]
|
|
|
|
case LODSB, LODSW, LODSD, LODSQ, SCASB, SCASW, SCASD, SCASQ:
|
|
iargs = iargs[1:]
|
|
}
|
|
|
|
const (
|
|
haveData16 = 1 << iota
|
|
haveData32
|
|
haveAddr16
|
|
haveAddr32
|
|
haveXacquire
|
|
haveXrelease
|
|
haveLock
|
|
haveHintTaken
|
|
haveHintNotTaken
|
|
haveBnd
|
|
)
|
|
var prefixBits uint32
|
|
prefix := ""
|
|
for _, p := range inst.Prefix {
|
|
if p == 0 {
|
|
break
|
|
}
|
|
if p&0xFF == 0xF3 {
|
|
prefixBits &^= haveBnd
|
|
}
|
|
if p&(PrefixImplicit|PrefixIgnored) != 0 {
|
|
continue
|
|
}
|
|
switch p {
|
|
default:
|
|
prefix += strings.ToLower(p.String()) + " "
|
|
case PrefixCS, PrefixDS, PrefixES, PrefixFS, PrefixGS, PrefixSS:
|
|
if inst.Op == 0 {
|
|
prefix += strings.ToLower(p.String()) + " "
|
|
}
|
|
case PrefixREPN:
|
|
prefix += "repne "
|
|
case PrefixLOCK:
|
|
prefixBits |= haveLock
|
|
case PrefixData16, PrefixDataSize:
|
|
prefixBits |= haveData16
|
|
case PrefixData32:
|
|
prefixBits |= haveData32
|
|
case PrefixAddrSize, PrefixAddr16:
|
|
prefixBits |= haveAddr16
|
|
case PrefixAddr32:
|
|
prefixBits |= haveAddr32
|
|
case PrefixXACQUIRE:
|
|
prefixBits |= haveXacquire
|
|
case PrefixXRELEASE:
|
|
prefixBits |= haveXrelease
|
|
case PrefixPT:
|
|
prefixBits |= haveHintTaken
|
|
case PrefixPN:
|
|
prefixBits |= haveHintNotTaken
|
|
case PrefixBND:
|
|
prefixBits |= haveBnd
|
|
}
|
|
}
|
|
switch inst.Op {
|
|
case JMP:
|
|
if inst.Opcode>>24 == 0xEB {
|
|
prefixBits &^= haveBnd
|
|
}
|
|
case RET, LRET:
|
|
prefixBits &^= haveData16 | haveData32
|
|
}
|
|
|
|
if prefixBits&haveXacquire != 0 {
|
|
prefix += "xacquire "
|
|
}
|
|
if prefixBits&haveXrelease != 0 {
|
|
prefix += "xrelease "
|
|
}
|
|
if prefixBits&haveLock != 0 {
|
|
prefix += "lock "
|
|
}
|
|
if prefixBits&haveBnd != 0 {
|
|
prefix += "bnd "
|
|
}
|
|
if prefixBits&haveHintTaken != 0 {
|
|
prefix += "hint-taken "
|
|
}
|
|
if prefixBits&haveHintNotTaken != 0 {
|
|
prefix += "hint-not-taken "
|
|
}
|
|
if prefixBits&haveAddr16 != 0 {
|
|
prefix += "addr16 "
|
|
}
|
|
if prefixBits&haveAddr32 != 0 {
|
|
prefix += "addr32 "
|
|
}
|
|
if prefixBits&haveData16 != 0 {
|
|
prefix += "data16 "
|
|
}
|
|
if prefixBits&haveData32 != 0 {
|
|
prefix += "data32 "
|
|
}
|
|
|
|
if inst.Op == 0 {
|
|
if prefix == "" {
|
|
return "<no instruction>"
|
|
}
|
|
return prefix[:len(prefix)-1]
|
|
}
|
|
|
|
var args []string
|
|
for _, a := range iargs {
|
|
if a == nil {
|
|
break
|
|
}
|
|
args = append(args, intelArg(&inst, pc, symname, a))
|
|
}
|
|
|
|
var op string
|
|
switch inst.Op {
|
|
case NOP:
|
|
if inst.Opcode>>24 == 0x0F {
|
|
if inst.DataSize == 16 {
|
|
args = append(args, "ax")
|
|
} else {
|
|
args = append(args, "eax")
|
|
}
|
|
}
|
|
|
|
case BLENDVPD, BLENDVPS, PBLENDVB:
|
|
args = args[:2]
|
|
|
|
case INT:
|
|
if inst.Opcode>>24 == 0xCC {
|
|
args = nil
|
|
op = "int3"
|
|
}
|
|
|
|
case LCALL, LJMP:
|
|
if len(args) == 2 {
|
|
args[0], args[1] = args[1], args[0]
|
|
}
|
|
|
|
case FCHS, FABS, FTST, FLDPI, FLDL2E, FLDLG2, F2XM1, FXAM, FLD1, FLDL2T, FSQRT, FRNDINT, FCOS, FSIN:
|
|
if len(args) == 0 {
|
|
args = append(args, "st0")
|
|
}
|
|
|
|
case FPTAN, FSINCOS, FUCOMPP, FCOMPP, FYL2X, FPATAN, FXTRACT, FPREM1, FPREM, FYL2XP1, FSCALE:
|
|
if len(args) == 0 {
|
|
args = []string{"st0", "st1"}
|
|
}
|
|
|
|
case FST, FSTP, FISTTP, FIST, FISTP, FBSTP:
|
|
if len(args) == 1 {
|
|
args = append(args, "st0")
|
|
}
|
|
|
|
case FLD, FXCH, FCOM, FCOMP, FIADD, FIMUL, FICOM, FICOMP, FISUBR, FIDIV, FUCOM, FUCOMP, FILD, FBLD, FADD, FMUL, FSUB, FSUBR, FISUB, FDIV, FDIVR, FIDIVR:
|
|
if len(args) == 1 {
|
|
args = []string{"st0", args[0]}
|
|
}
|
|
|
|
case MASKMOVDQU, MASKMOVQ, XLATB, OUTSB, OUTSW, OUTSD:
|
|
FixSegment:
|
|
for i := len(inst.Prefix) - 1; i >= 0; i-- {
|
|
p := inst.Prefix[i] & 0xFF
|
|
switch p {
|
|
case PrefixCS, PrefixES, PrefixFS, PrefixGS, PrefixSS:
|
|
if inst.Mode != 64 || p == PrefixFS || p == PrefixGS {
|
|
args = append(args, strings.ToLower((inst.Prefix[i] & 0xFF).String()))
|
|
break FixSegment
|
|
}
|
|
case PrefixDS:
|
|
if inst.Mode != 64 {
|
|
break FixSegment
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if op == "" {
|
|
op = intelOp[inst.Op]
|
|
}
|
|
if op == "" {
|
|
op = strings.ToLower(inst.Op.String())
|
|
}
|
|
if args != nil {
|
|
op += " " + strings.Join(args, ", ")
|
|
}
|
|
return prefix + op
|
|
}
|
|
|
|
func intelArg(inst *Inst, pc uint64, symname SymLookup, arg Arg) string {
|
|
switch a := arg.(type) {
|
|
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", 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 a.Base == EIP {
|
|
a.Base = RIP
|
|
}
|
|
prefix := ""
|
|
switch inst.MemBytes {
|
|
case 1:
|
|
prefix = "byte "
|
|
case 2:
|
|
prefix = "word "
|
|
case 4:
|
|
prefix = "dword "
|
|
case 8:
|
|
prefix = "qword "
|
|
case 16:
|
|
prefix = "xmmword "
|
|
case 32:
|
|
prefix = "ymmword "
|
|
}
|
|
switch inst.Op {
|
|
case INVLPG:
|
|
prefix = "byte "
|
|
case STOSB, MOVSB, CMPSB, LODSB, SCASB:
|
|
prefix = "byte "
|
|
case STOSW, MOVSW, CMPSW, LODSW, SCASW:
|
|
prefix = "word "
|
|
case STOSD, MOVSD, CMPSD, LODSD, SCASD:
|
|
prefix = "dword "
|
|
case STOSQ, MOVSQ, CMPSQ, LODSQ, SCASQ:
|
|
prefix = "qword "
|
|
case LAR:
|
|
prefix = "word "
|
|
case BOUND:
|
|
if inst.Mode == 32 {
|
|
prefix = "qword "
|
|
} else {
|
|
prefix = "dword "
|
|
}
|
|
case PREFETCHW, PREFETCHNTA, PREFETCHT0, PREFETCHT1, PREFETCHT2, CLFLUSH:
|
|
prefix = "zmmword "
|
|
}
|
|
switch inst.Op {
|
|
case MOVSB, MOVSW, MOVSD, MOVSQ, CMPSB, CMPSW, CMPSD, CMPSQ, STOSB, STOSW, STOSD, STOSQ, SCASB, SCASW, SCASD, SCASQ, LODSB, LODSW, LODSD, LODSQ:
|
|
switch a.Base {
|
|
case DI, EDI, RDI:
|
|
if a.Segment == ES {
|
|
a.Segment = 0
|
|
}
|
|
case SI, ESI, RSI:
|
|
if a.Segment == DS {
|
|
a.Segment = 0
|
|
}
|
|
}
|
|
case LEA:
|
|
a.Segment = 0
|
|
default:
|
|
switch a.Base {
|
|
case SP, ESP, RSP, BP, EBP, RBP:
|
|
if a.Segment == SS {
|
|
a.Segment = 0
|
|
}
|
|
default:
|
|
if a.Segment == DS {
|
|
a.Segment = 0
|
|
}
|
|
}
|
|
}
|
|
|
|
if inst.Mode == 64 && a.Segment != FS && a.Segment != GS {
|
|
a.Segment = 0
|
|
}
|
|
|
|
prefix += "ptr "
|
|
if s, disp := memArgToSymbol(a, pc, inst.Len, symname); s != "" {
|
|
suffix := ""
|
|
if disp != 0 {
|
|
suffix = fmt.Sprintf("%+d", disp)
|
|
}
|
|
return prefix + fmt.Sprintf("[%s%s]", s, suffix)
|
|
}
|
|
if a.Segment != 0 {
|
|
prefix += strings.ToLower(a.Segment.String()) + ":"
|
|
}
|
|
prefix += "["
|
|
if a.Base != 0 {
|
|
prefix += intelArg(inst, pc, symname, a.Base)
|
|
}
|
|
if a.Scale != 0 && a.Index != 0 {
|
|
if a.Base != 0 {
|
|
prefix += "+"
|
|
}
|
|
prefix += fmt.Sprintf("%s*%d", intelArg(inst, pc, symname, a.Index), a.Scale)
|
|
}
|
|
if a.Disp != 0 {
|
|
if prefix[len(prefix)-1] == '[' && (a.Disp >= 0 || int64(int32(a.Disp)) != a.Disp) {
|
|
prefix += fmt.Sprintf("%#x", uint64(a.Disp))
|
|
} else {
|
|
prefix += fmt.Sprintf("%+#x", a.Disp)
|
|
}
|
|
}
|
|
prefix += "]"
|
|
return prefix
|
|
case Rel:
|
|
if pc == 0 {
|
|
return fmt.Sprintf(".%+#x", int64(a))
|
|
} else {
|
|
addr := pc + uint64(inst.Len) + uint64(a)
|
|
if s, base := symname(addr); s != "" && addr == base {
|
|
return fmt.Sprintf("%s", s)
|
|
} else {
|
|
addr := pc + uint64(inst.Len) + uint64(a)
|
|
return fmt.Sprintf("%#x", addr)
|
|
}
|
|
}
|
|
case Reg:
|
|
if int(a) < len(intelReg) && intelReg[a] != "" {
|
|
switch inst.Op {
|
|
case VMOVDQA, VMOVDQU, VMOVNTDQA, VMOVNTDQ:
|
|
return strings.Replace(intelReg[a], "xmm", "ymm", -1)
|
|
default:
|
|
return intelReg[a]
|
|
}
|
|
}
|
|
}
|
|
return strings.ToLower(arg.String())
|
|
}
|
|
|
|
var intelOp = map[Op]string{
|
|
JAE: "jnb",
|
|
JA: "jnbe",
|
|
JGE: "jnl",
|
|
JNE: "jnz",
|
|
JG: "jnle",
|
|
JE: "jz",
|
|
SETAE: "setnb",
|
|
SETA: "setnbe",
|
|
SETGE: "setnl",
|
|
SETNE: "setnz",
|
|
SETG: "setnle",
|
|
SETE: "setz",
|
|
CMOVAE: "cmovnb",
|
|
CMOVA: "cmovnbe",
|
|
CMOVGE: "cmovnl",
|
|
CMOVNE: "cmovnz",
|
|
CMOVG: "cmovnle",
|
|
CMOVE: "cmovz",
|
|
LCALL: "call far",
|
|
LJMP: "jmp far",
|
|
LRET: "ret far",
|
|
ICEBP: "int1",
|
|
MOVSD_XMM: "movsd",
|
|
XLATB: "xlat",
|
|
}
|
|
|
|
var intelReg = [...]string{
|
|
F0: "st0",
|
|
F1: "st1",
|
|
F2: "st2",
|
|
F3: "st3",
|
|
F4: "st4",
|
|
F5: "st5",
|
|
F6: "st6",
|
|
F7: "st7",
|
|
M0: "mmx0",
|
|
M1: "mmx1",
|
|
M2: "mmx2",
|
|
M3: "mmx3",
|
|
M4: "mmx4",
|
|
M5: "mmx5",
|
|
M6: "mmx6",
|
|
M7: "mmx7",
|
|
X0: "xmm0",
|
|
X1: "xmm1",
|
|
X2: "xmm2",
|
|
X3: "xmm3",
|
|
X4: "xmm4",
|
|
X5: "xmm5",
|
|
X6: "xmm6",
|
|
X7: "xmm7",
|
|
X8: "xmm8",
|
|
X9: "xmm9",
|
|
X10: "xmm10",
|
|
X11: "xmm11",
|
|
X12: "xmm12",
|
|
X13: "xmm13",
|
|
X14: "xmm14",
|
|
X15: "xmm15",
|
|
|
|
// TODO: Maybe the constants are named wrong.
|
|
SPB: "spl",
|
|
BPB: "bpl",
|
|
SIB: "sil",
|
|
DIB: "dil",
|
|
|
|
R8L: "r8d",
|
|
R9L: "r9d",
|
|
R10L: "r10d",
|
|
R11L: "r11d",
|
|
R12L: "r12d",
|
|
R13L: "r13d",
|
|
R14L: "r14d",
|
|
R15L: "r15d",
|
|
}
|