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() {
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 plan9Suffix[inst.Op] {
66 s := inst.DataSize
67 if inst.MemBytes != 0 {
68 s = inst.MemBytes * 8
69 } else if inst.Args[1] == nil {
70 if r, ok := inst.Args[0].(Reg); ok && RAX <= r && r <= R15 {
71 s = 64
72 }
73 }
74 switch s {
75 case 8:
76 op += "B"
77 case 16:
78 op += "W"
79 case 32:
80 op += "L"
81 case 64:
82 op += "Q"
83 }
84 }
85
86 if inst.Op == CMP {
87
88
89 args[0], args[1] = args[1], args[0]
90 }
91
92 if args != nil {
93 op += " " + strings.Join(args, ", ")
94 }
95
96 return rep + prefix + op
97 }
98
99 func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string {
100 switch a := arg.(type) {
101 case Reg:
102 return plan9Reg[a]
103 case Rel:
104 if pc == 0 {
105 break
106 }
107
108
109
110
111
112 addr := pc + uint64(inst.Len) + uint64(a)
113 if s, base := symname(addr); s != "" && addr == base {
114 return fmt.Sprintf("%s(SB)", s)
115 }
116 return fmt.Sprintf("%#x", addr)
117
118 case Imm:
119 if (inst.Op == MOV || inst.Op == PUSH) && inst.DataSize == 32 {
120
121
122
123
124
125
126
127
128
129 if s, base := symname(uint64(a)); s != "" {
130 suffix := ""
131 if uint64(a) != base {
132 suffix = fmt.Sprintf("%+d", uint64(a)-base)
133 }
134 return fmt.Sprintf("$%s%s(SB)", s, suffix)
135 }
136 }
137 if inst.Mode == 32 {
138 return fmt.Sprintf("$%#x", uint32(a))
139 }
140 if Imm(int32(a)) == a {
141 return fmt.Sprintf("$%#x", int64(a))
142 }
143 return fmt.Sprintf("$%#x", uint64(a))
144 case Mem:
145 if s, disp := memArgToSymbol(a, pc, inst.Len, symname); s != "" {
146 suffix := ""
147 if disp != 0 {
148 suffix = fmt.Sprintf("%+d", disp)
149 }
150 return fmt.Sprintf("%s%s(SB)", s, suffix)
151 }
152 s := ""
153 if a.Segment != 0 {
154 s += fmt.Sprintf("%s:", plan9Reg[a.Segment])
155 }
156 if a.Disp != 0 {
157 s += fmt.Sprintf("%#x", a.Disp)
158 } else {
159 s += "0"
160 }
161 if a.Base != 0 {
162 s += fmt.Sprintf("(%s)", plan9Reg[a.Base])
163 }
164 if a.Index != 0 && a.Scale != 0 {
165 s += fmt.Sprintf("(%s*%d)", plan9Reg[a.Index], a.Scale)
166 }
167 return s
168 }
169 return arg.String()
170 }
171
172 func memArgToSymbol(a Mem, pc uint64, instrLen int, symname SymLookup) (string, int64) {
173 if a.Segment != 0 || a.Disp == 0 || a.Index != 0 || a.Scale != 0 {
174 return "", 0
175 }
176
177 var disp uint64
178 switch a.Base {
179 case IP, EIP, RIP:
180 disp = uint64(a.Disp + int64(pc) + int64(instrLen))
181 case 0:
182 disp = uint64(a.Disp)
183 default:
184 return "", 0
185 }
186
187 s, base := symname(disp)
188 return s, int64(disp) - int64(base)
189 }
190
191 var plan9Suffix = [maxOp + 1]bool{
192 ADC: true,
193 ADD: true,
194 AND: true,
195 BSF: true,
196 BSR: true,
197 BT: true,
198 BTC: true,
199 BTR: true,
200 BTS: true,
201 CMP: true,
202 CMPXCHG: true,
203 CVTSI2SD: true,
204 CVTSI2SS: true,
205 CVTSD2SI: true,
206 CVTSS2SI: true,
207 CVTTSD2SI: true,
208 CVTTSS2SI: true,
209 DEC: true,
210 DIV: true,
211 FLDENV: true,
212 FRSTOR: true,
213 IDIV: true,
214 IMUL: true,
215 IN: true,
216 INC: true,
217 LEA: true,
218 MOV: true,
219 MOVNTI: true,
220 MUL: true,
221 NEG: true,
222 NOP: true,
223 NOT: true,
224 OR: true,
225 OUT: true,
226 POP: true,
227 POPA: true,
228 POPCNT: true,
229 PUSH: true,
230 PUSHA: true,
231 RCL: true,
232 RCR: true,
233 ROL: true,
234 ROR: true,
235 SAR: true,
236 SBB: true,
237 SHL: true,
238 SHLD: true,
239 SHR: true,
240 SHRD: true,
241 SUB: true,
242 TEST: true,
243 XADD: true,
244 XCHG: true,
245 XOR: true,
246 }
247
248 var plan9Reg = [...]string{
249 AL: "AL",
250 CL: "CL",
251 BL: "BL",
252 DL: "DL",
253 AH: "AH",
254 CH: "CH",
255 BH: "BH",
256 DH: "DH",
257 SPB: "SP",
258 BPB: "BP",
259 SIB: "SI",
260 DIB: "DI",
261 R8B: "R8",
262 R9B: "R9",
263 R10B: "R10",
264 R11B: "R11",
265 R12B: "R12",
266 R13B: "R13",
267 R14B: "R14",
268 R15B: "R15",
269 AX: "AX",
270 CX: "CX",
271 BX: "BX",
272 DX: "DX",
273 SP: "SP",
274 BP: "BP",
275 SI: "SI",
276 DI: "DI",
277 R8W: "R8",
278 R9W: "R9",
279 R10W: "R10",
280 R11W: "R11",
281 R12W: "R12",
282 R13W: "R13",
283 R14W: "R14",
284 R15W: "R15",
285 EAX: "AX",
286 ECX: "CX",
287 EDX: "DX",
288 EBX: "BX",
289 ESP: "SP",
290 EBP: "BP",
291 ESI: "SI",
292 EDI: "DI",
293 R8L: "R8",
294 R9L: "R9",
295 R10L: "R10",
296 R11L: "R11",
297 R12L: "R12",
298 R13L: "R13",
299 R14L: "R14",
300 R15L: "R15",
301 RAX: "AX",
302 RCX: "CX",
303 RDX: "DX",
304 RBX: "BX",
305 RSP: "SP",
306 RBP: "BP",
307 RSI: "SI",
308 RDI: "DI",
309 R8: "R8",
310 R9: "R9",
311 R10: "R10",
312 R11: "R11",
313 R12: "R12",
314 R13: "R13",
315 R14: "R14",
316 R15: "R15",
317 IP: "IP",
318 EIP: "IP",
319 RIP: "IP",
320 F0: "F0",
321 F1: "F1",
322 F2: "F2",
323 F3: "F3",
324 F4: "F4",
325 F5: "F5",
326 F6: "F6",
327 F7: "F7",
328 M0: "M0",
329 M1: "M1",
330 M2: "M2",
331 M3: "M3",
332 M4: "M4",
333 M5: "M5",
334 M6: "M6",
335 M7: "M7",
336 X0: "X0",
337 X1: "X1",
338 X2: "X2",
339 X3: "X3",
340 X4: "X4",
341 X5: "X5",
342 X6: "X6",
343 X7: "X7",
344 X8: "X8",
345 X9: "X9",
346 X10: "X10",
347 X11: "X11",
348 X12: "X12",
349 X13: "X13",
350 X14: "X14",
351 X15: "X15",
352 CS: "CS",
353 SS: "SS",
354 DS: "DS",
355 ES: "ES",
356 FS: "FS",
357 GS: "GS",
358 GDTR: "GDTR",
359 IDTR: "IDTR",
360 LDTR: "LDTR",
361 MSW: "MSW",
362 TASK: "TASK",
363 CR0: "CR0",
364 CR1: "CR1",
365 CR2: "CR2",
366 CR3: "CR3",
367 CR4: "CR4",
368 CR5: "CR5",
369 CR6: "CR6",
370 CR7: "CR7",
371 CR8: "CR8",
372 CR9: "CR9",
373 CR10: "CR10",
374 CR11: "CR11",
375 CR12: "CR12",
376 CR13: "CR13",
377 CR14: "CR14",
378 CR15: "CR15",
379 DR0: "DR0",
380 DR1: "DR1",
381 DR2: "DR2",
382 DR3: "DR3",
383 DR4: "DR4",
384 DR5: "DR5",
385 DR6: "DR6",
386 DR7: "DR7",
387 DR8: "DR8",
388 DR9: "DR9",
389 DR10: "DR10",
390 DR11: "DR11",
391 DR12: "DR12",
392 DR13: "DR13",
393 DR14: "DR14",
394 DR15: "DR15",
395 TR0: "TR0",
396 TR1: "TR1",
397 TR2: "TR2",
398 TR3: "TR3",
399 TR4: "TR4",
400 TR5: "TR5",
401 TR6: "TR6",
402 TR7: "TR7",
403 }
404
View as plain text