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