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.
12
// IntelSyntax returns the Intel assembler syntax for the instruction, as defined by Intel's XED tool.
13
func IntelSyntax(inst Inst, pc uint64, symname SymLookup) string {
15
symname = func(uint64) (string, uint64) { return "", 0 }
19
for _, a := range inst.Args {
23
iargs = append(iargs, a)
27
case INSB, INSD, INSW, OUTSB, OUTSD, OUTSW, LOOPNE, JCXZ, JECXZ, JRCXZ, LOOP, LOOPE, MOV, XLATB:
28
if inst.Op == MOV && (inst.Opcode>>16)&0xFFFC != 0x0F20 {
31
for i, p := range inst.Prefix {
32
if p&0xFF == PrefixAddrSize {
33
inst.Prefix[i] &^= PrefixImplicit
40
dst, _ := inst.Args[0].(Reg)
41
src, _ := inst.Args[1].(Reg)
42
if ES <= dst && dst <= GS && EAX <= src && src <= R15L {
46
if ES <= dst && dst <= GS && RAX <= src && src <= R15 {
51
if inst.Opcode>>24&^3 == 0xA0 {
52
for i, p := range inst.Prefix {
53
if p&0xFF == PrefixAddrSize {
54
inst.Prefix[i] |= PrefixImplicit
62
if imm, ok := iargs[0].(Imm); ok {
63
if inst.DataSize == 32 {
64
iargs[0] = Imm(uint32(int8(imm)))
65
} else if inst.DataSize == 16 {
66
iargs[0] = Imm(uint16(int8(imm)))
71
if imm, ok := iargs[0].(Imm); ok {
72
iargs[0] = Imm(uint32(imm))
76
for _, p := range inst.Prefix {
77
if p&PrefixImplicit != 0 {
78
for j, pj := range inst.Prefix {
79
if pj&0xFF == p&0xFF {
80
inst.Prefix[j] |= PrefixImplicit
87
for i, p := range inst.Prefix {
88
switch p &^ PrefixIgnored {
89
case PrefixData16, PrefixData32, PrefixCS, PrefixDS, PrefixES, PrefixSS:
90
inst.Prefix[i] |= PrefixImplicit
93
inst.Prefix[i] |= PrefixImplicit
96
if p == PrefixVEX3Bytes {
97
inst.Prefix[i+2] |= PrefixImplicit
99
inst.Prefix[i] |= PrefixImplicit
100
inst.Prefix[i+1] |= PrefixImplicit
105
if isLoop[inst.Op] || inst.Op == JCXZ || inst.Op == JECXZ || inst.Op == JRCXZ {
106
for i, p := range inst.Prefix {
107
if p == PrefixPT || p == PrefixPN {
108
inst.Prefix[i] |= PrefixImplicit
114
case AAA, AAS, CBW, CDQE, CLC, CLD, CLI, CLTS, CMC, CPUID, CQO, CWD, DAA, DAS,
115
FDECSTP, FINCSTP, FNCLEX, FNINIT, FNOP, FWAIT, HLT,
116
ICEBP, INSB, INSD, INSW, INT, INTO, INVD, IRET, IRETQ,
117
LAHF, LEAVE, LRET, MONITOR, MWAIT, NOP, OUTSB, OUTSD, OUTSW,
118
PAUSE, POPA, POPF, POPFQ, PUSHA, PUSHF, PUSHFQ,
119
RDMSR, RDPMC, RDTSC, RDTSCP, RET, RSM,
120
SAHF, STC, STD, STI, SYSENTER, SYSEXIT, SYSRET,
121
UD2, WBINVD, WRMSR, XEND, XLATB, XTEST:
123
if inst.Op == NOP && inst.Opcode>>24 != 0x90 {
126
if inst.Op == RET && inst.Opcode>>24 != 0xC3 {
129
if inst.Op == INT && inst.Opcode>>24 != 0xCC {
132
if inst.Op == LRET && inst.Opcode>>24 != 0xcb {
135
for i, p := range inst.Prefix {
136
if p&0xFF == PrefixDataSize {
137
inst.Prefix[i] &^= PrefixImplicit | PrefixIgnored
146
case INSB, INSD, INSW, OUTSB, OUTSD, OUTSW, MONITOR, MWAIT, XLATB:
149
case STOSB, STOSW, STOSD, STOSQ:
152
case LODSB, LODSW, LODSD, LODSQ, SCASB, SCASW, SCASD, SCASQ:
157
haveData16 = 1 << iota
168
var prefixBits uint32
170
for _, p := range inst.Prefix {
175
prefixBits &^= haveBnd
177
if p&(PrefixImplicit|PrefixIgnored) != 0 {
182
prefix += strings.ToLower(p.String()) + " "
183
case PrefixCS, PrefixDS, PrefixES, PrefixFS, PrefixGS, PrefixSS:
185
prefix += strings.ToLower(p.String()) + " "
190
prefixBits |= haveLock
191
case PrefixData16, PrefixDataSize:
192
prefixBits |= haveData16
194
prefixBits |= haveData32
195
case PrefixAddrSize, PrefixAddr16:
196
prefixBits |= haveAddr16
198
prefixBits |= haveAddr32
200
prefixBits |= haveXacquire
202
prefixBits |= haveXrelease
204
prefixBits |= haveHintTaken
206
prefixBits |= haveHintNotTaken
208
prefixBits |= haveBnd
213
if inst.Opcode>>24 == 0xEB {
214
prefixBits &^= haveBnd
217
prefixBits &^= haveData16 | haveData32
220
if prefixBits&haveXacquire != 0 {
221
prefix += "xacquire "
223
if prefixBits&haveXrelease != 0 {
224
prefix += "xrelease "
226
if prefixBits&haveLock != 0 {
229
if prefixBits&haveBnd != 0 {
232
if prefixBits&haveHintTaken != 0 {
233
prefix += "hint-taken "
235
if prefixBits&haveHintNotTaken != 0 {
236
prefix += "hint-not-taken "
238
if prefixBits&haveAddr16 != 0 {
241
if prefixBits&haveAddr32 != 0 {
244
if prefixBits&haveData16 != 0 {
247
if prefixBits&haveData32 != 0 {
253
return "<no instruction>"
255
return prefix[:len(prefix)-1]
259
for _, a := range iargs {
263
args = append(args, intelArg(&inst, pc, symname, a))
269
if inst.Opcode>>24 == 0x0F {
270
if inst.DataSize == 16 {
271
args = append(args, "ax")
273
args = append(args, "eax")
277
case BLENDVPD, BLENDVPS, PBLENDVB:
281
if inst.Opcode>>24 == 0xCC {
288
args[0], args[1] = args[1], args[0]
291
case FCHS, FABS, FTST, FLDPI, FLDL2E, FLDLG2, F2XM1, FXAM, FLD1, FLDL2T, FSQRT, FRNDINT, FCOS, FSIN:
293
args = append(args, "st0")
296
case FPTAN, FSINCOS, FUCOMPP, FCOMPP, FYL2X, FPATAN, FXTRACT, FPREM1, FPREM, FYL2XP1, FSCALE:
298
args = []string{"st0", "st1"}
301
case FST, FSTP, FISTTP, FIST, FISTP, FBSTP:
303
args = append(args, "st0")
306
case FLD, FXCH, FCOM, FCOMP, FIADD, FIMUL, FICOM, FICOMP, FISUBR, FIDIV, FUCOM, FUCOMP, FILD, FBLD, FADD, FMUL, FSUB, FSUBR, FISUB, FDIV, FDIVR, FIDIVR:
308
args = []string{"st0", args[0]}
311
case MASKMOVDQU, MASKMOVQ, XLATB, OUTSB, OUTSW, OUTSD:
313
for i := len(inst.Prefix) - 1; i >= 0; i-- {
314
p := inst.Prefix[i] & 0xFF
316
case PrefixCS, PrefixES, PrefixFS, PrefixGS, PrefixSS:
317
if inst.Mode != 64 || p == PrefixFS || p == PrefixGS {
318
args = append(args, strings.ToLower((inst.Prefix[i] & 0xFF).String()))
330
op = intelOp[inst.Op]
333
op = strings.ToLower(inst.Op.String())
336
op += " " + strings.Join(args, ", ")
341
func intelArg(inst *Inst, pc uint64, symname SymLookup, arg Arg) string {
342
switch a := arg.(type) {
344
if s, base := symname(uint64(a)); s != "" {
346
if uint64(a) != base {
347
suffix = fmt.Sprintf("%+d", uint64(a)-base)
349
return fmt.Sprintf("$%s%s", s, suffix)
352
return fmt.Sprintf("%#x", uint32(a))
354
if Imm(int32(a)) == a {
355
return fmt.Sprintf("%#x", int64(a))
357
return fmt.Sprintf("%#x", uint64(a))
363
switch inst.MemBytes {
380
case STOSB, MOVSB, CMPSB, LODSB, SCASB:
382
case STOSW, MOVSW, CMPSW, LODSW, SCASW:
384
case STOSD, MOVSD, CMPSD, LODSD, SCASD:
386
case STOSQ, MOVSQ, CMPSQ, LODSQ, SCASQ:
396
case PREFETCHW, PREFETCHNTA, PREFETCHT0, PREFETCHT1, PREFETCHT2, CLFLUSH:
400
case MOVSB, MOVSW, MOVSD, MOVSQ, CMPSB, CMPSW, CMPSD, CMPSQ, STOSB, STOSW, STOSD, STOSQ, SCASB, SCASW, SCASD, SCASQ, LODSB, LODSW, LODSD, LODSQ:
415
case SP, ESP, RSP, BP, EBP, RBP:
426
if inst.Mode == 64 && a.Segment != FS && a.Segment != GS {
431
if s, disp := memArgToSymbol(a, pc, inst.Len, symname); s != "" {
434
suffix = fmt.Sprintf("%+d", disp)
436
return prefix + fmt.Sprintf("[%s%s]", s, suffix)
439
prefix += strings.ToLower(a.Segment.String()) + ":"
443
prefix += intelArg(inst, pc, symname, a.Base)
445
if a.Scale != 0 && a.Index != 0 {
449
prefix += fmt.Sprintf("%s*%d", intelArg(inst, pc, symname, a.Index), a.Scale)
452
if prefix[len(prefix)-1] == '[' && (a.Disp >= 0 || int64(int32(a.Disp)) != a.Disp) {
453
prefix += fmt.Sprintf("%#x", uint64(a.Disp))
455
prefix += fmt.Sprintf("%+#x", a.Disp)
462
return fmt.Sprintf(".%+#x", int64(a))
464
addr := pc + uint64(inst.Len) + uint64(a)
465
if s, base := symname(addr); s != "" && addr == base {
466
return fmt.Sprintf("%s", s)
468
addr := pc + uint64(inst.Len) + uint64(a)
469
return fmt.Sprintf("%#x", addr)
473
if int(a) < len(intelReg) && intelReg[a] != "" {
475
case VMOVDQA, VMOVDQU, VMOVNTDQA, VMOVNTDQ:
476
return strings.Replace(intelReg[a], "xmm", "ymm", -1)
482
return strings.ToLower(arg.String())
485
var intelOp = map[Op]string{
512
var intelReg = [...]string{
546
// TODO: Maybe the constants are named wrong.