123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562 |
- // 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 (inst.Op == MOV || inst.Op == PUSH) && inst.DataSize == 32 { // See comment in plan9x.go.
- 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",
- }
|