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 s, base := symname(uint64(a)); s != "" {
345 suffix := ""
346 if uint64(a) != base {
347 suffix = fmt.Sprintf("%+d", uint64(a)-base)
348 }
349 return fmt.Sprintf("$%s%s", s, suffix)
350 }
351 if inst.Mode == 32 {
352 return fmt.Sprintf("%#x", uint32(a))
353 }
354 if Imm(int32(a)) == a {
355 return fmt.Sprintf("%#x", int64(a))
356 }
357 return fmt.Sprintf("%#x", uint64(a))
358 case Mem:
359 if a.Base == EIP {
360 a.Base = RIP
361 }
362 prefix := ""
363 switch inst.MemBytes {
364 case 1:
365 prefix = "byte "
366 case 2:
367 prefix = "word "
368 case 4:
369 prefix = "dword "
370 case 8:
371 prefix = "qword "
372 case 16:
373 prefix = "xmmword "
374 case 32:
375 prefix = "ymmword "
376 }
377 switch inst.Op {
378 case INVLPG:
379 prefix = "byte "
380 case STOSB, MOVSB, CMPSB, LODSB, SCASB:
381 prefix = "byte "
382 case STOSW, MOVSW, CMPSW, LODSW, SCASW:
383 prefix = "word "
384 case STOSD, MOVSD, CMPSD, LODSD, SCASD:
385 prefix = "dword "
386 case STOSQ, MOVSQ, CMPSQ, LODSQ, SCASQ:
387 prefix = "qword "
388 case LAR:
389 prefix = "word "
390 case BOUND:
391 if inst.Mode == 32 {
392 prefix = "qword "
393 } else {
394 prefix = "dword "
395 }
396 case PREFETCHW, PREFETCHNTA, PREFETCHT0, PREFETCHT1, PREFETCHT2, CLFLUSH:
397 prefix = "zmmword "
398 }
399 switch inst.Op {
400 case MOVSB, MOVSW, MOVSD, MOVSQ, CMPSB, CMPSW, CMPSD, CMPSQ, STOSB, STOSW, STOSD, STOSQ, SCASB, SCASW, SCASD, SCASQ, LODSB, LODSW, LODSD, LODSQ:
401 switch a.Base {
402 case DI, EDI, RDI:
403 if a.Segment == ES {
404 a.Segment = 0
405 }
406 case SI, ESI, RSI:
407 if a.Segment == DS {
408 a.Segment = 0
409 }
410 }
411 case LEA:
412 a.Segment = 0
413 default:
414 switch a.Base {
415 case SP, ESP, RSP, BP, EBP, RBP:
416 if a.Segment == SS {
417 a.Segment = 0
418 }
419 default:
420 if a.Segment == DS {
421 a.Segment = 0
422 }
423 }
424 }
425
426 if inst.Mode == 64 && a.Segment != FS && a.Segment != GS {
427 a.Segment = 0
428 }
429
430 prefix += "ptr "
431 if s, disp := memArgToSymbol(a, pc, inst.Len, symname); s != "" {
432 suffix := ""
433 if disp != 0 {
434 suffix = fmt.Sprintf("%+d", disp)
435 }
436 return prefix + fmt.Sprintf("[%s%s]", s, suffix)
437 }
438 if a.Segment != 0 {
439 prefix += strings.ToLower(a.Segment.String()) + ":"
440 }
441 prefix += "["
442 if a.Base != 0 {
443 prefix += intelArg(inst, pc, symname, a.Base)
444 }
445 if a.Scale != 0 && a.Index != 0 {
446 if a.Base != 0 {
447 prefix += "+"
448 }
449 prefix += fmt.Sprintf("%s*%d", intelArg(inst, pc, symname, a.Index), a.Scale)
450 }
451 if a.Disp != 0 {
452 if prefix[len(prefix)-1] == '[' && (a.Disp >= 0 || int64(int32(a.Disp)) != a.Disp) {
453 prefix += fmt.Sprintf("%#x", uint64(a.Disp))
454 } else {
455 prefix += fmt.Sprintf("%+#x", a.Disp)
456 }
457 }
458 prefix += "]"
459 return prefix
460 case Rel:
461 if pc == 0 {
462 return fmt.Sprintf(".%+#x", int64(a))
463 } else {
464 addr := pc + uint64(inst.Len) + uint64(a)
465 if s, base := symname(addr); s != "" && addr == base {
466 return fmt.Sprintf("%s", s)
467 } else {
468 addr := pc + uint64(inst.Len) + uint64(a)
469 return fmt.Sprintf("%#x", addr)
470 }
471 }
472 case Reg:
473 if int(a) < len(intelReg) && intelReg[a] != "" {
474 switch inst.Op {
475 case VMOVDQA, VMOVDQU, VMOVNTDQA, VMOVNTDQ:
476 return strings.Replace(intelReg[a], "xmm", "ymm", -1)
477 default:
478 return intelReg[a]
479 }
480 }
481 }
482 return strings.ToLower(arg.String())
483 }
484
485 var intelOp = map[Op]string{
486 JAE: "jnb",
487 JA: "jnbe",
488 JGE: "jnl",
489 JNE: "jnz",
490 JG: "jnle",
491 JE: "jz",
492 SETAE: "setnb",
493 SETA: "setnbe",
494 SETGE: "setnl",
495 SETNE: "setnz",
496 SETG: "setnle",
497 SETE: "setz",
498 CMOVAE: "cmovnb",
499 CMOVA: "cmovnbe",
500 CMOVGE: "cmovnl",
501 CMOVNE: "cmovnz",
502 CMOVG: "cmovnle",
503 CMOVE: "cmovz",
504 LCALL: "call far",
505 LJMP: "jmp far",
506 LRET: "ret far",
507 ICEBP: "int1",
508 MOVSD_XMM: "movsd",
509 XLATB: "xlat",
510 }
511
512 var intelReg = [...]string{
513 F0: "st0",
514 F1: "st1",
515 F2: "st2",
516 F3: "st3",
517 F4: "st4",
518 F5: "st5",
519 F6: "st6",
520 F7: "st7",
521 M0: "mmx0",
522 M1: "mmx1",
523 M2: "mmx2",
524 M3: "mmx3",
525 M4: "mmx4",
526 M5: "mmx5",
527 M6: "mmx6",
528 M7: "mmx7",
529 X0: "xmm0",
530 X1: "xmm1",
531 X2: "xmm2",
532 X3: "xmm3",
533 X4: "xmm4",
534 X5: "xmm5",
535 X6: "xmm6",
536 X7: "xmm7",
537 X8: "xmm8",
538 X9: "xmm9",
539 X10: "xmm10",
540 X11: "xmm11",
541 X12: "xmm12",
542 X13: "xmm13",
543 X14: "xmm14",
544 X15: "xmm15",
545
546
547 SPB: "spl",
548 BPB: "bpl",
549 SIB: "sil",
550 DIB: "dil",
551
552 R8L: "r8d",
553 R9L: "r9d",
554 R10L: "r10d",
555 R11L: "r11d",
556 R12L: "r12d",
557 R13L: "r13d",
558 R14L: "r14d",
559 R15L: "r15d",
560 }
561
View as plain text