1
2
3
4
5 package x86asm
6
7 import (
8 "fmt"
9 "strings"
10 )
11
12
13 func IntelSyntax(inst Inst, pc uint64, symname SymLookup) string {
14 if symname == nil {
15 symname = func(uint64) (string, uint64) { return "", 0 }
16 }
17
18 var iargs []Arg
19 for _, a := range inst.Args {
20 if a == nil {
21 break
22 }
23 iargs = append(iargs, a)
24 }
25
26 switch inst.Op {
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 {
29 break
30 }
31 for i, p := range inst.Prefix {
32 if p&0xFF == PrefixAddrSize {
33 inst.Prefix[i] &^= PrefixImplicit
34 }
35 }
36 }
37
38 switch inst.Op {
39 case MOV:
40 dst, _ := inst.Args[0].(Reg)
41 src, _ := inst.Args[1].(Reg)
42 if ES <= dst && dst <= GS && EAX <= src && src <= R15L {
43 src -= EAX - AX
44 iargs[1] = src
45 }
46 if ES <= dst && dst <= GS && RAX <= src && src <= R15 {
47 src -= RAX - AX
48 iargs[1] = src
49 }
50
51 if inst.Opcode>>24&^3 == 0xA0 {
52 for i, p := range inst.Prefix {
53 if p&0xFF == PrefixAddrSize {
54 inst.Prefix[i] |= PrefixImplicit
55 }
56 }
57 }
58 }
59
60 switch inst.Op {
61 case AAM, AAD:
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)))
67 }
68 }
69
70 case PUSH:
71 if imm, ok := iargs[0].(Imm); ok {
72 iargs[0] = Imm(uint32(imm))
73 }
74 }
75
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
81 }
82 }
83 }
84 }
85
86 if inst.Op != 0 {
87 for i, p := range inst.Prefix {
88 switch p &^ PrefixIgnored {
89 case PrefixData16, PrefixData32, PrefixCS, PrefixDS, PrefixES, PrefixSS:
90 inst.Prefix[i] |= PrefixImplicit
91 }
92 if p.IsREX() {
93 inst.Prefix[i] |= PrefixImplicit
94 }
95 if p.IsVEX() {
96 if p == PrefixVEX3Bytes {
97 inst.Prefix[i+2] |= PrefixImplicit
98 }
99 inst.Prefix[i] |= PrefixImplicit
100 inst.Prefix[i+1] |= PrefixImplicit
101 }
102 }
103 }
104
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
109 }
110 }
111 }
112
113 switch inst.Op {
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:
122
123 if inst.Op == NOP && inst.Opcode>>24 != 0x90 {
124 break
125 }
126 if inst.Op == RET && inst.Opcode>>24 != 0xC3 {
127 break
128 }
129 if inst.Op == INT && inst.Opcode>>24 != 0xCC {
130 break
131 }
132 if inst.Op == LRET && inst.Opcode>>24 != 0xcb {
133 break
134 }
135 for i, p := range inst.Prefix {
136 if p&0xFF == PrefixDataSize {
137 inst.Prefix[i] &^= PrefixImplicit | PrefixIgnored
138 }
139 }
140
141 case 0:
142
143 }
144
145 switch inst.Op {
146 case INSB, INSD, INSW, OUTSB, OUTSD, OUTSW, MONITOR, MWAIT, XLATB:
147 iargs = nil
148
149 case STOSB, STOSW, STOSD, STOSQ:
150 iargs = iargs[:1]
151
152 case LODSB, LODSW, LODSD, LODSQ, SCASB, SCASW, SCASD, SCASQ:
153 iargs = iargs[1:]
154 }
155
156 const (
157 haveData16 = 1 << iota
158 haveData32
159 haveAddr16
160 haveAddr32
161 haveXacquire
162 haveXrelease
163 haveLock
164 haveHintTaken
165 haveHintNotTaken
166 haveBnd
167 )
168 var prefixBits uint32
169 prefix := ""
170 for _, p := range inst.Prefix {
171 if p == 0 {
172 break
173 }
174 if p&0xFF == 0xF3 {
175 prefixBits &^= haveBnd
176 }
177 if p&(PrefixImplicit|PrefixIgnored) != 0 {
178 continue
179 }
180 switch p {
181 default:
182 prefix += strings.ToLower(p.String()) + " "
183 case PrefixCS, PrefixDS, PrefixES, PrefixFS, PrefixGS, PrefixSS:
184 if inst.Op == 0 {
185 prefix += strings.ToLower(p.String()) + " "
186 }
187 case PrefixREPN:
188 prefix += "repne "
189 case PrefixLOCK:
190 prefixBits |= haveLock
191 case PrefixData16, PrefixDataSize:
192 prefixBits |= haveData16
193 case PrefixData32:
194 prefixBits |= haveData32
195 case PrefixAddrSize, PrefixAddr16:
196 prefixBits |= haveAddr16
197 case PrefixAddr32:
198 prefixBits |= haveAddr32
199 case PrefixXACQUIRE:
200 prefixBits |= haveXacquire
201 case PrefixXRELEASE:
202 prefixBits |= haveXrelease
203 case PrefixPT:
204 prefixBits |= haveHintTaken
205 case PrefixPN:
206 prefixBits |= haveHintNotTaken
207 case PrefixBND:
208 prefixBits |= haveBnd
209 }
210 }
211 switch inst.Op {
212 case JMP:
213 if inst.Opcode>>24 == 0xEB {
214 prefixBits &^= haveBnd
215 }
216 case RET, LRET:
217 prefixBits &^= haveData16 | haveData32
218 }
219
220 if prefixBits&haveXacquire != 0 {
221 prefix += "xacquire "
222 }
223 if prefixBits&haveXrelease != 0 {
224 prefix += "xrelease "
225 }
226 if prefixBits&haveLock != 0 {
227 prefix += "lock "
228 }
229 if prefixBits&haveBnd != 0 {
230 prefix += "bnd "
231 }
232 if prefixBits&haveHintTaken != 0 {
233 prefix += "hint-taken "
234 }
235 if prefixBits&haveHintNotTaken != 0 {
236 prefix += "hint-not-taken "
237 }
238 if prefixBits&haveAddr16 != 0 {
239 prefix += "addr16 "
240 }
241 if prefixBits&haveAddr32 != 0 {
242 prefix += "addr32 "
243 }
244 if prefixBits&haveData16 != 0 {
245 prefix += "data16 "
246 }
247 if prefixBits&haveData32 != 0 {
248 prefix += "data32 "
249 }
250
251 if inst.Op == 0 {
252 if prefix == "" {
253 return "<no instruction>"
254 }
255 return prefix[:len(prefix)-1]
256 }
257
258 var args []string
259 for _, a := range iargs {
260 if a == nil {
261 break
262 }
263 args = append(args, intelArg(&inst, pc, symname, a))
264 }
265
266 var op string
267 switch inst.Op {
268 case NOP:
269 if inst.Opcode>>24 == 0x0F {
270 if inst.DataSize == 16 {
271 args = append(args, "ax")
272 } else {
273 args = append(args, "eax")
274 }
275 }
276
277 case BLENDVPD, BLENDVPS, PBLENDVB:
278 args = args[:2]
279
280 case INT:
281 if inst.Opcode>>24 == 0xCC {
282 args = nil
283 op = "int3"
284 }
285
286 case LCALL, LJMP:
287 if len(args) == 2 {
288 args[0], args[1] = args[1], args[0]
289 }
290
291 case FCHS, FABS, FTST, FLDPI, FLDL2E, FLDLG2, F2XM1, FXAM, FLD1, FLDL2T, FSQRT, FRNDINT, FCOS, FSIN:
292 if len(args) == 0 {
293 args = append(args, "st0")
294 }
295
296 case FPTAN, FSINCOS, FUCOMPP, FCOMPP, FYL2X, FPATAN, FXTRACT, FPREM1, FPREM, FYL2XP1, FSCALE:
297 if len(args) == 0 {
298 args = []string{"st0", "st1"}
299 }
300
301 case FST, FSTP, FISTTP, FIST, FISTP, FBSTP:
302 if len(args) == 1 {
303 args = append(args, "st0")
304 }
305
306 case FLD, FXCH, FCOM, FCOMP, FIADD, FIMUL, FICOM, FICOMP, FISUBR, FIDIV, FUCOM, FUCOMP, FILD, FBLD, FADD, FMUL, FSUB, FSUBR, FISUB, FDIV, FDIVR, FIDIVR:
307 if len(args) == 1 {
308 args = []string{"st0", args[0]}
309 }
310
311 case MASKMOVDQU, MASKMOVQ, XLATB, OUTSB, OUTSW, OUTSD:
312 FixSegment:
313 for i := len(inst.Prefix) - 1; i >= 0; i-- {
314 p := inst.Prefix[i] & 0xFF
315 switch p {
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()))
319 break FixSegment
320 }
321 case PrefixDS:
322 if inst.Mode != 64 {
323 break FixSegment
324 }
325 }
326 }
327 }
328
329 if op == "" {
330 op = intelOp[inst.Op]
331 }
332 if op == "" {
333 op = strings.ToLower(inst.Op.String())
334 }
335 if args != nil {
336 op += " " + strings.Join(args, ", ")
337 }
338 return prefix + op
339 }
340
341 func intelArg(inst *Inst, pc uint64, symname SymLookup, arg Arg) string {
342 switch a := arg.(type) {
343 case Imm:
344 if (inst.Op == MOV || inst.Op == PUSH) && inst.DataSize == 32 {
345 if s, base := symname(uint64(a)); s != "" {
346 suffix := ""
347 if uint64(a) != base {
348 suffix = fmt.Sprintf("%+d", uint64(a)-base)
349 }
350 return fmt.Sprintf("$%s%s", s, suffix)
351 }
352 }
353 if inst.Mode == 32 {
354 return fmt.Sprintf("%#x", uint32(a))
355 }
356 if Imm(int32(a)) == a {
357 return fmt.Sprintf("%#x", int64(a))
358 }
359 return fmt.Sprintf("%#x", uint64(a))
360 case Mem:
361 if a.Base == EIP {
362 a.Base = RIP
363 }
364 prefix := ""
365 switch inst.MemBytes {
366 case 1:
367 prefix = "byte "
368 case 2:
369 prefix = "word "
370 case 4:
371 prefix = "dword "
372 case 8:
373 prefix = "qword "
374 case 16:
375 prefix = "xmmword "
376 case 32:
377 prefix = "ymmword "
378 }
379 switch inst.Op {
380 case INVLPG:
381 prefix = "byte "
382 case STOSB, MOVSB, CMPSB, LODSB, SCASB:
383 prefix = "byte "
384 case STOSW, MOVSW, CMPSW, LODSW, SCASW:
385 prefix = "word "
386 case STOSD, MOVSD, CMPSD, LODSD, SCASD:
387 prefix = "dword "
388 case STOSQ, MOVSQ, CMPSQ, LODSQ, SCASQ:
389 prefix = "qword "
390 case LAR:
391 prefix = "word "
392 case BOUND:
393 if inst.Mode == 32 {
394 prefix = "qword "
395 } else {
396 prefix = "dword "
397 }
398 case PREFETCHW, PREFETCHNTA, PREFETCHT0, PREFETCHT1, PREFETCHT2, CLFLUSH:
399 prefix = "zmmword "
400 }
401 switch inst.Op {
402 case MOVSB, MOVSW, MOVSD, MOVSQ, CMPSB, CMPSW, CMPSD, CMPSQ, STOSB, STOSW, STOSD, STOSQ, SCASB, SCASW, SCASD, SCASQ, LODSB, LODSW, LODSD, LODSQ:
403 switch a.Base {
404 case DI, EDI, RDI:
405 if a.Segment == ES {
406 a.Segment = 0
407 }
408 case SI, ESI, RSI:
409 if a.Segment == DS {
410 a.Segment = 0
411 }
412 }
413 case LEA:
414 a.Segment = 0
415 default:
416 switch a.Base {
417 case SP, ESP, RSP, BP, EBP, RBP:
418 if a.Segment == SS {
419 a.Segment = 0
420 }
421 default:
422 if a.Segment == DS {
423 a.Segment = 0
424 }
425 }
426 }
427
428 if inst.Mode == 64 && a.Segment != FS && a.Segment != GS {
429 a.Segment = 0
430 }
431
432 prefix += "ptr "
433 if s, disp := memArgToSymbol(a, pc, inst.Len, symname); s != "" {
434 suffix := ""
435 if disp != 0 {
436 suffix = fmt.Sprintf("%+d", disp)
437 }
438 return prefix + fmt.Sprintf("[%s%s]", s, suffix)
439 }
440 if a.Segment != 0 {
441 prefix += strings.ToLower(a.Segment.String()) + ":"
442 }
443 prefix += "["
444 if a.Base != 0 {
445 prefix += intelArg(inst, pc, symname, a.Base)
446 }
447 if a.Scale != 0 && a.Index != 0 {
448 if a.Base != 0 {
449 prefix += "+"
450 }
451 prefix += fmt.Sprintf("%s*%d", intelArg(inst, pc, symname, a.Index), a.Scale)
452 }
453 if a.Disp != 0 {
454 if prefix[len(prefix)-1] == '[' && (a.Disp >= 0 || int64(int32(a.Disp)) != a.Disp) {
455 prefix += fmt.Sprintf("%#x", uint64(a.Disp))
456 } else {
457 prefix += fmt.Sprintf("%+#x", a.Disp)
458 }
459 }
460 prefix += "]"
461 return prefix
462 case Rel:
463 if pc == 0 {
464 return fmt.Sprintf(".%+#x", int64(a))
465 } else {
466 addr := pc + uint64(inst.Len) + uint64(a)
467 if s, base := symname(addr); s != "" && addr == base {
468 return fmt.Sprintf("%s", s)
469 } else {
470 addr := pc + uint64(inst.Len) + uint64(a)
471 return fmt.Sprintf("%#x", addr)
472 }
473 }
474 case Reg:
475 if int(a) < len(intelReg) && intelReg[a] != "" {
476 switch inst.Op {
477 case VMOVDQA, VMOVDQU, VMOVNTDQA, VMOVNTDQ:
478 return strings.Replace(intelReg[a], "xmm", "ymm", -1)
479 default:
480 return intelReg[a]
481 }
482 }
483 }
484 return strings.ToLower(arg.String())
485 }
486
487 var intelOp = map[Op]string{
488 JAE: "jnb",
489 JA: "jnbe",
490 JGE: "jnl",
491 JNE: "jnz",
492 JG: "jnle",
493 JE: "jz",
494 SETAE: "setnb",
495 SETA: "setnbe",
496 SETGE: "setnl",
497 SETNE: "setnz",
498 SETG: "setnle",
499 SETE: "setz",
500 CMOVAE: "cmovnb",
501 CMOVA: "cmovnbe",
502 CMOVGE: "cmovnl",
503 CMOVNE: "cmovnz",
504 CMOVG: "cmovnle",
505 CMOVE: "cmovz",
506 LCALL: "call far",
507 LJMP: "jmp far",
508 LRET: "ret far",
509 ICEBP: "int1",
510 MOVSD_XMM: "movsd",
511 XLATB: "xlat",
512 }
513
514 var intelReg = [...]string{
515 F0: "st0",
516 F1: "st1",
517 F2: "st2",
518 F3: "st3",
519 F4: "st4",
520 F5: "st5",
521 F6: "st6",
522 F7: "st7",
523 M0: "mmx0",
524 M1: "mmx1",
525 M2: "mmx2",
526 M3: "mmx3",
527 M4: "mmx4",
528 M5: "mmx5",
529 M6: "mmx6",
530 M7: "mmx7",
531 X0: "xmm0",
532 X1: "xmm1",
533 X2: "xmm2",
534 X3: "xmm3",
535 X4: "xmm4",
536 X5: "xmm5",
537 X6: "xmm6",
538 X7: "xmm7",
539 X8: "xmm8",
540 X9: "xmm9",
541 X10: "xmm10",
542 X11: "xmm11",
543 X12: "xmm12",
544 X13: "xmm13",
545 X14: "xmm14",
546 X15: "xmm15",
547
548
549 SPB: "spl",
550 BPB: "bpl",
551 SIB: "sil",
552 DIB: "dil",
553
554 R8L: "r8d",
555 R9L: "r9d",
556 R10L: "r10d",
557 R11L: "r11d",
558 R12L: "r12d",
559 R13L: "r13d",
560 R14L: "r14d",
561 R15L: "r15d",
562 }
563
View as plain text