1
2
3
4
5 package x86asm
6
7 import (
8 "fmt"
9 "strings"
10 )
11
12 type SymLookup func(uint64) (string, uint64)
13
14
15
16
17
18
19
20
21 func GoSyntax(inst Inst, pc uint64, symname SymLookup) string {
22 if symname == nil {
23 symname = func(uint64) (string, uint64) { return "", 0 }
24 }
25 var args []string
26 for i := len(inst.Args) - 1; i >= 0; i-- {
27 a := inst.Args[i]
28 if a == nil {
29 continue
30 }
31 args = append(args, plan9Arg(&inst, pc, symname, a))
32 }
33
34 var rep string
35 var last Prefix
36 for _, p := range inst.Prefix {
37 if p == 0 || p.IsREX() || p.IsVEX() || p.IsEVEX() {
38 break
39 }
40
41 switch {
42
43 case p&0xFF00 == PrefixImplicit:
44 continue
45
46
47 case p&0xFF == PrefixREP:
48 rep = "REP; "
49 case p&0xFF == PrefixREPN:
50 rep = "REPNE; "
51 default:
52 last = p
53 }
54 }
55
56 prefix := ""
57 switch last & 0xFF {
58 case 0, 0x66, 0x67:
59
60 default:
61 prefix += last.String() + " "
62 }
63
64 op := inst.Op.String()
65 if inst.Op == VFPCLASSPD || inst.Op == VFPCLASSPS || inst.Op == VCVTTPD2DQ || inst.Op == VCVTTPD2UDQ || inst.Op == VCVTTPD2QQ || inst.Op == VCVTTPD2UQQ || inst.Op == VCVTPD2DQ || inst.Op == VCVTPD2UDQ || inst.Op == VCVTPD2QQ || inst.Op == VCVTPD2UQQ || inst.Op == VCVTPD2PS {
66 vexL := 0
67 isEvex := false
68 for i, p := range inst.Prefix {
69 if p.IsEVEX() && i+3 < len(inst.Prefix) && inst.Prefix[i+3] != 0 {
70 vexL = int((inst.Prefix[i+3]&0xFF)>>5) & 3
71 isEvex = true
72 break
73 } else if p.IsVEX() && i+2 < len(inst.Prefix) {
74 if p&0xFF == 0xC4 {
75 vexL = int((inst.Prefix[i+2]&0xFF)>>2) & 1
76 } else if p&0xFF == 0xC5 {
77 vexL = int((inst.Prefix[i+1]&0xFF)>>2) & 1
78 }
79 break
80 }
81 }
82 if !isEvex || inst.Op == VFPCLASSPD || inst.Op == VFPCLASSPS || inst.Op == VCVTPD2DQ {
83 switch vexL {
84 case 0:
85 op += "X"
86 case 1:
87 if inst.Op != VCMPPD && inst.Op != VCMPPS && inst.Op != VCMPPH && inst.Op != VCMPBF16 {
88 op += "Y"
89 }
90 case 2:
91 if inst.Op != VCMPPD && inst.Op != VCMPPS && inst.Op != VCMPPH && inst.Op != VCMPBF16 {
92 op += "Z"
93 }
94 }
95 }
96 } else if inst.Op == VCVTTSD2SI || inst.Op == VCVTTSS2SI || inst.Op == VCVTSD2SI || inst.Op == VCVTSS2SI || inst.Op == VCVTSI2SD || inst.Op == VCVTSI2SS {
97 is64 := false
98 if (inst.Op == VCVTSI2SD || inst.Op == VCVTSI2SS) && inst.MemBytes == 8 {
99 is64 = true
100 } else {
101 for _, a := range inst.Args {
102 if r, ok := a.(Reg); ok && RAX <= r && r <= R15 {
103 is64 = true
104 break
105 }
106 }
107 }
108 if inst.Op == VCVTSI2SD || inst.Op == VCVTSI2SS {
109 if is64 {
110 op += "Q"
111 } else {
112 op += "L"
113 }
114 } else {
115 if is64 {
116 op += "Q"
117 }
118 }
119 } else if plan9Suffix[inst.Op] {
120 s := inst.DataSize
121 if inst.MemBytes != 0 {
122 s = inst.MemBytes * 8
123 } else if inst.Args[1] == nil {
124 if r, ok := inst.Args[0].(Reg); ok && RAX <= r && r <= R15 {
125 s = 64
126 }
127 }
128 switch s {
129 case 8:
130 op += "B"
131 case 16:
132 op += "W"
133 case 32:
134 op += "L"
135 case 64:
136 op += "Q"
137 }
138 }
139
140 if inst.Broadcast {
141 op += ".BCST"
142 }
143 if inst.SAE {
144 if hasRC(inst.Op) {
145 switch inst.Rounding {
146 case 0:
147 op += ".RN_SAE"
148 case 1:
149 op += ".RD_SAE"
150 case 2:
151 op += ".RU_SAE"
152 case 3:
153 op += ".RZ_SAE"
154 }
155 } else {
156 op += ".SAE"
157 }
158 }
159 if inst.Zeroing {
160 op += ".Z"
161 }
162
163 if inst.Op == CMP {
164
165
166 args[0], args[1] = args[1], args[0]
167 }
168
169 if args != nil {
170 op += " " + strings.Join(args, ", ")
171 }
172
173 return rep + prefix + op
174 }
175
176 func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string {
177 switch a := arg.(type) {
178 case Reg:
179 return plan9Reg[a]
180 case Rel:
181 if pc == 0 {
182 break
183 }
184
185
186
187
188
189 addr := pc + uint64(inst.Len) + uint64(a)
190 if s, base := symname(addr); s != "" && addr == base {
191 return fmt.Sprintf("%s(SB)", s)
192 }
193 return fmt.Sprintf("%#x", addr)
194
195 case Imm:
196 if (inst.Op == MOV || inst.Op == PUSH) && inst.DataSize == 32 {
197
198
199
200
201
202
203
204
205
206 if s, base := symname(uint64(a)); s != "" {
207 suffix := ""
208 if uint64(a) != base {
209 suffix = fmt.Sprintf("%+d", uint64(a)-base)
210 }
211 return fmt.Sprintf("$%s%s(SB)", s, suffix)
212 }
213 }
214 if inst.Mode == 32 {
215 return fmt.Sprintf("$%#x", uint32(a))
216 }
217 if Imm(int32(a)) == a {
218 return fmt.Sprintf("$%#x", int64(a))
219 }
220 return fmt.Sprintf("$%#x", uint64(a))
221 case Mem:
222 if s, disp := memArgToSymbol(a, pc, inst.Len, symname); s != "" {
223 suffix := ""
224 if disp != 0 {
225 suffix = fmt.Sprintf("%+d", disp)
226 }
227 return fmt.Sprintf("%s%s(SB)", s, suffix)
228 }
229 s := ""
230 if a.Segment != 0 {
231 s += fmt.Sprintf("%s:", plan9Reg[a.Segment])
232 }
233 if a.Disp != 0 {
234 s += fmt.Sprintf("%#x", a.Disp)
235 } else {
236 s += "0"
237 }
238 if a.Base != 0 {
239 s += fmt.Sprintf("(%s)", plan9Reg[a.Base])
240 }
241 if a.Index != 0 && a.Scale != 0 {
242 s += fmt.Sprintf("(%s*%d)", plan9Reg[a.Index], a.Scale)
243 }
244 return s
245 }
246 return arg.String()
247 }
248
249 func memArgToSymbol(a Mem, pc uint64, instrLen int, symname SymLookup) (string, int64) {
250 if a.Segment != 0 || a.Disp == 0 || a.Index != 0 || a.Scale != 0 {
251 return "", 0
252 }
253
254 var disp uint64
255 switch a.Base {
256 case IP, EIP, RIP:
257 disp = uint64(a.Disp + int64(pc) + int64(instrLen))
258 case 0:
259 disp = uint64(a.Disp)
260 default:
261 return "", 0
262 }
263
264 s, base := symname(disp)
265 return s, int64(disp) - int64(base)
266 }
267
268 var plan9Suffix = [maxOp + 1]bool{
269 ADC: true,
270 ADD: true,
271 AND: true,
272 BSF: true,
273 BSR: true,
274 BT: true,
275 BTC: true,
276 BTR: true,
277 BTS: true,
278 CMP: true,
279 CMPXCHG: true,
280 CVTSI2SD: true,
281 CVTSI2SS: true,
282 CVTSD2SI: true,
283 CVTSS2SI: true,
284 CVTTSD2SI: true,
285 CVTTSS2SI: true,
286 DEC: true,
287 DIV: true,
288 FLDENV: true,
289 FRSTOR: true,
290 IDIV: true,
291 IMUL: true,
292 IN: true,
293 INC: true,
294 LEA: true,
295 MOV: true,
296 MOVNTI: true,
297 MUL: true,
298 NEG: true,
299 NOP: true,
300 NOT: true,
301 OR: true,
302 OUT: true,
303 POP: true,
304 POPA: true,
305 POPCNT: true,
306 PUSH: true,
307 PUSHA: true,
308 RCL: true,
309 RCR: true,
310 ROL: true,
311 ROR: true,
312 SAR: true,
313 SBB: true,
314 SHL: true,
315 SHLD: true,
316 SHR: true,
317 SHRD: true,
318 SUB: true,
319 TEST: true,
320 XADD: true,
321 XCHG: true,
322 XOR: true,
323 }
324
325 var plan9Reg = [...]string{
326 AL: "AL",
327 CL: "CL",
328 BL: "BL",
329 DL: "DL",
330 AH: "AH",
331 CH: "CH",
332 BH: "BH",
333 DH: "DH",
334 SPB: "SP",
335 BPB: "BP",
336 SIB: "SI",
337 DIB: "DI",
338 R8B: "R8",
339 R9B: "R9",
340 R10B: "R10",
341 R11B: "R11",
342 R12B: "R12",
343 R13B: "R13",
344 R14B: "R14",
345 R15B: "R15",
346 AX: "AX",
347 CX: "CX",
348 BX: "BX",
349 DX: "DX",
350 SP: "SP",
351 BP: "BP",
352 SI: "SI",
353 DI: "DI",
354 R8W: "R8",
355 R9W: "R9",
356 R10W: "R10",
357 R11W: "R11",
358 R12W: "R12",
359 R13W: "R13",
360 R14W: "R14",
361 R15W: "R15",
362 EAX: "AX",
363 ECX: "CX",
364 EDX: "DX",
365 EBX: "BX",
366 ESP: "SP",
367 EBP: "BP",
368 ESI: "SI",
369 EDI: "DI",
370 R8L: "R8",
371 R9L: "R9",
372 R10L: "R10",
373 R11L: "R11",
374 R12L: "R12",
375 R13L: "R13",
376 R14L: "R14",
377 R15L: "R15",
378 RAX: "AX",
379 RCX: "CX",
380 RDX: "DX",
381 RBX: "BX",
382 RSP: "SP",
383 RBP: "BP",
384 RSI: "SI",
385 RDI: "DI",
386 R8: "R8",
387 R9: "R9",
388 R10: "R10",
389 R11: "R11",
390 R12: "R12",
391 R13: "R13",
392 R14: "R14",
393 R15: "R15",
394 IP: "IP",
395 EIP: "IP",
396 RIP: "IP",
397 F0: "F0",
398 F1: "F1",
399 F2: "F2",
400 F3: "F3",
401 F4: "F4",
402 F5: "F5",
403 F6: "F6",
404 F7: "F7",
405 M0: "M0",
406 M1: "M1",
407 M2: "M2",
408 M3: "M3",
409 M4: "M4",
410 M5: "M5",
411 M6: "M6",
412 M7: "M7",
413 X0: "X0",
414 X1: "X1",
415 X2: "X2",
416 X3: "X3",
417 X4: "X4",
418 X5: "X5",
419 X6: "X6",
420 X7: "X7",
421 X8: "X8",
422 X9: "X9",
423 X10: "X10",
424 X11: "X11",
425 X12: "X12",
426 X13: "X13",
427 X14: "X14",
428 X15: "X15",
429 X16: "X16",
430 X17: "X17",
431 X18: "X18",
432 X19: "X19",
433 X20: "X20",
434 X21: "X21",
435 X22: "X22",
436 X23: "X23",
437 X24: "X24",
438 X25: "X25",
439 X26: "X26",
440 X27: "X27",
441 X28: "X28",
442 X29: "X29",
443 X30: "X30",
444 X31: "X31",
445 Y0: "Y0",
446 Y1: "Y1",
447 Y2: "Y2",
448 Y3: "Y3",
449 Y4: "Y4",
450 Y5: "Y5",
451 Y6: "Y6",
452 Y7: "Y7",
453 Y8: "Y8",
454 Y9: "Y9",
455 Y10: "Y10",
456 Y11: "Y11",
457 Y12: "Y12",
458 Y13: "Y13",
459 Y14: "Y14",
460 Y15: "Y15",
461 Y16: "Y16",
462 Y17: "Y17",
463 Y18: "Y18",
464 Y19: "Y19",
465 Y20: "Y20",
466 Y21: "Y21",
467 Y22: "Y22",
468 Y23: "Y23",
469 Y24: "Y24",
470 Y25: "Y25",
471 Y26: "Y26",
472 Y27: "Y27",
473 Y28: "Y28",
474 Y29: "Y29",
475 Y30: "Y30",
476 Y31: "Y31",
477 Z0: "Z0",
478 Z1: "Z1",
479 Z2: "Z2",
480 Z3: "Z3",
481 Z4: "Z4",
482 Z5: "Z5",
483 Z6: "Z6",
484 Z7: "Z7",
485 Z8: "Z8",
486 Z9: "Z9",
487 Z10: "Z10",
488 Z11: "Z11",
489 Z12: "Z12",
490 Z13: "Z13",
491 Z14: "Z14",
492 Z15: "Z15",
493 Z16: "Z16",
494 Z17: "Z17",
495 Z18: "Z18",
496 Z19: "Z19",
497 Z20: "Z20",
498 Z21: "Z21",
499 Z22: "Z22",
500 Z23: "Z23",
501 Z24: "Z24",
502 Z25: "Z25",
503 Z26: "Z26",
504 Z27: "Z27",
505 Z28: "Z28",
506 Z29: "Z29",
507 Z30: "Z30",
508 Z31: "Z31",
509 K0: "K0",
510 K1: "K1",
511 K2: "K2",
512 K3: "K3",
513 K4: "K4",
514 K5: "K5",
515 K6: "K6",
516 K7: "K7",
517 CS: "CS",
518 SS: "SS",
519 DS: "DS",
520 ES: "ES",
521 FS: "FS",
522 GS: "GS",
523 GDTR: "GDTR",
524 IDTR: "IDTR",
525 LDTR: "LDTR",
526 MSW: "MSW",
527 TASK: "TASK",
528 CR0: "CR0",
529 CR1: "CR1",
530 CR2: "CR2",
531 CR3: "CR3",
532 CR4: "CR4",
533 CR5: "CR5",
534 CR6: "CR6",
535 CR7: "CR7",
536 CR8: "CR8",
537 CR9: "CR9",
538 CR10: "CR10",
539 CR11: "CR11",
540 CR12: "CR12",
541 CR13: "CR13",
542 CR14: "CR14",
543 CR15: "CR15",
544 DR0: "DR0",
545 DR1: "DR1",
546 DR2: "DR2",
547 DR3: "DR3",
548 DR4: "DR4",
549 DR5: "DR5",
550 DR6: "DR6",
551 DR7: "DR7",
552 DR8: "DR8",
553 DR9: "DR9",
554 DR10: "DR10",
555 DR11: "DR11",
556 DR12: "DR12",
557 DR13: "DR13",
558 DR14: "DR14",
559 DR15: "DR15",
560 TR0: "TR0",
561 TR1: "TR1",
562 TR2: "TR2",
563 TR3: "TR3",
564 TR4: "TR4",
565 TR5: "TR5",
566 TR6: "TR6",
567 TR7: "TR7",
568 }
569
View as plain text