/src/capstonenext/arch/X86/X86ATTInstPrinter.c
Line | Count | Source |
1 | | //===-- X86ATTInstPrinter.cpp - AT&T assembly instruction printing --------===// |
2 | | // |
3 | | // The LLVM Compiler Infrastructure |
4 | | // |
5 | | // This file is distributed under the University of Illinois Open Source |
6 | | // License. See LICENSE.TXT for details. |
7 | | // |
8 | | //===----------------------------------------------------------------------===// |
9 | | // |
10 | | // This file includes code for rendering MCInst instances as AT&T-style |
11 | | // assembly. |
12 | | // |
13 | | //===----------------------------------------------------------------------===// |
14 | | |
15 | | /* Capstone Disassembly Engine */ |
16 | | /* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2019 */ |
17 | | |
18 | | // this code is only relevant when DIET mode is disable |
19 | | #if defined(CAPSTONE_HAS_X86) && !defined(CAPSTONE_DIET) && \ |
20 | | !defined(CAPSTONE_X86_ATT_DISABLE) |
21 | | |
22 | | #ifdef _MSC_VER |
23 | | // disable MSVC's warning on strncpy() |
24 | | #pragma warning(disable : 4996) |
25 | | // disable MSVC's warning on strncpy() |
26 | | #pragma warning(disable : 28719) |
27 | | #endif |
28 | | |
29 | | #if !defined(CAPSTONE_HAS_OSXKERNEL) |
30 | | #include <ctype.h> |
31 | | #endif |
32 | | #include <capstone/platform.h> |
33 | | |
34 | | #if defined(CAPSTONE_HAS_OSXKERNEL) |
35 | | #include <Availability.h> |
36 | | #include <libkern/libkern.h> |
37 | | #else |
38 | | #include <stdio.h> |
39 | | #include <stdlib.h> |
40 | | #endif |
41 | | |
42 | | #include <string.h> |
43 | | |
44 | | #include "../../utils.h" |
45 | | #include "../../MCInst.h" |
46 | | #include "../../SStream.h" |
47 | | #include "../../MCRegisterInfo.h" |
48 | | #include "X86Mapping.h" |
49 | | #include "X86BaseInfo.h" |
50 | | #include "X86InstPrinterCommon.h" |
51 | | |
52 | | #define GET_INSTRINFO_ENUM |
53 | | #ifdef CAPSTONE_X86_REDUCE |
54 | | #include "X86GenInstrInfo_reduce.inc" |
55 | | #else |
56 | | #include "X86GenInstrInfo.inc" |
57 | | #endif |
58 | | |
59 | | #define GET_REGINFO_ENUM |
60 | | #include "X86GenRegisterInfo.inc" |
61 | | |
62 | | static void printMemReference(MCInst *MI, unsigned Op, SStream *O); |
63 | | static void printOperand(MCInst *MI, unsigned OpNo, SStream *O); |
64 | | |
65 | | static void set_mem_access(MCInst *MI, bool status) |
66 | 23.7k | { |
67 | 23.7k | if (MI->csh->detail_opt != CS_OPT_ON) |
68 | 0 | return; |
69 | | |
70 | 23.7k | MI->csh->doing_mem = status; |
71 | 23.7k | if (!status) |
72 | | // done, create the next operand slot |
73 | 11.8k | MI->flat_insn->detail->x86.op_count++; |
74 | 23.7k | } |
75 | | |
76 | | static void printopaquemem(MCInst *MI, unsigned OpNo, SStream *O) |
77 | 2.62k | { |
78 | 2.62k | switch (MI->csh->mode) { |
79 | 1.14k | case CS_MODE_16: |
80 | 1.14k | switch (MI->flat_insn->id) { |
81 | 296 | default: |
82 | 296 | MI->x86opsize = 2; |
83 | 296 | break; |
84 | 201 | case X86_INS_LJMP: |
85 | 389 | case X86_INS_LCALL: |
86 | 389 | MI->x86opsize = 4; |
87 | 389 | break; |
88 | 147 | case X86_INS_SGDT: |
89 | 165 | case X86_INS_SIDT: |
90 | 311 | case X86_INS_LGDT: |
91 | 461 | case X86_INS_LIDT: |
92 | 461 | MI->x86opsize = 6; |
93 | 461 | break; |
94 | 1.14k | } |
95 | 1.14k | break; |
96 | 1.14k | case CS_MODE_32: |
97 | 790 | switch (MI->flat_insn->id) { |
98 | 253 | default: |
99 | 253 | MI->x86opsize = 4; |
100 | 253 | break; |
101 | 31 | case X86_INS_LJMP: |
102 | 289 | case X86_INS_JMP: |
103 | 293 | case X86_INS_LCALL: |
104 | 335 | case X86_INS_SGDT: |
105 | 356 | case X86_INS_SIDT: |
106 | 395 | case X86_INS_LGDT: |
107 | 537 | case X86_INS_LIDT: |
108 | 537 | MI->x86opsize = 6; |
109 | 537 | break; |
110 | 790 | } |
111 | 790 | break; |
112 | 790 | case CS_MODE_64: |
113 | 688 | switch (MI->flat_insn->id) { |
114 | 92 | default: |
115 | 92 | MI->x86opsize = 8; |
116 | 92 | break; |
117 | 173 | case X86_INS_LJMP: |
118 | 305 | case X86_INS_LCALL: |
119 | 321 | case X86_INS_SGDT: |
120 | 331 | case X86_INS_SIDT: |
121 | 464 | case X86_INS_LGDT: |
122 | 596 | case X86_INS_LIDT: |
123 | 596 | MI->x86opsize = 10; |
124 | 596 | break; |
125 | 688 | } |
126 | 688 | break; |
127 | 688 | default: // never reach |
128 | 0 | break; |
129 | 2.62k | } |
130 | | |
131 | 2.62k | printMemReference(MI, OpNo, O); |
132 | 2.62k | } |
133 | | |
134 | | static void printi8mem(MCInst *MI, unsigned OpNo, SStream *O) |
135 | 17.6k | { |
136 | 17.6k | MI->x86opsize = 1; |
137 | 17.6k | printMemReference(MI, OpNo, O); |
138 | 17.6k | } |
139 | | |
140 | | static void printi16mem(MCInst *MI, unsigned OpNo, SStream *O) |
141 | 6.36k | { |
142 | 6.36k | MI->x86opsize = 2; |
143 | | |
144 | 6.36k | printMemReference(MI, OpNo, O); |
145 | 6.36k | } |
146 | | |
147 | | static void printi32mem(MCInst *MI, unsigned OpNo, SStream *O) |
148 | 7.45k | { |
149 | 7.45k | MI->x86opsize = 4; |
150 | | |
151 | 7.45k | printMemReference(MI, OpNo, O); |
152 | 7.45k | } |
153 | | |
154 | | static void printi64mem(MCInst *MI, unsigned OpNo, SStream *O) |
155 | 4.41k | { |
156 | 4.41k | MI->x86opsize = 8; |
157 | 4.41k | printMemReference(MI, OpNo, O); |
158 | 4.41k | } |
159 | | |
160 | | static void printi128mem(MCInst *MI, unsigned OpNo, SStream *O) |
161 | 1.91k | { |
162 | 1.91k | MI->x86opsize = 16; |
163 | 1.91k | printMemReference(MI, OpNo, O); |
164 | 1.91k | } |
165 | | |
166 | | static void printi512mem(MCInst *MI, unsigned OpNo, SStream *O) |
167 | 1.08k | { |
168 | 1.08k | MI->x86opsize = 64; |
169 | 1.08k | printMemReference(MI, OpNo, O); |
170 | 1.08k | } |
171 | | |
172 | | #ifndef CAPSTONE_X86_REDUCE |
173 | | static void printi256mem(MCInst *MI, unsigned OpNo, SStream *O) |
174 | 732 | { |
175 | 732 | MI->x86opsize = 32; |
176 | 732 | printMemReference(MI, OpNo, O); |
177 | 732 | } |
178 | | |
179 | | static void printf32mem(MCInst *MI, unsigned OpNo, SStream *O) |
180 | 1.40k | { |
181 | 1.40k | switch (MCInst_getOpcode(MI)) { |
182 | 1.23k | default: |
183 | 1.23k | MI->x86opsize = 4; |
184 | 1.23k | break; |
185 | 17 | case X86_FSTENVm: |
186 | 173 | case X86_FLDENVm: |
187 | | // TODO: fix this in tablegen instead |
188 | 173 | switch (MI->csh->mode) { |
189 | 0 | default: // never reach |
190 | 0 | break; |
191 | 20 | case CS_MODE_16: |
192 | 20 | MI->x86opsize = 14; |
193 | 20 | break; |
194 | 141 | case CS_MODE_32: |
195 | 153 | case CS_MODE_64: |
196 | 153 | MI->x86opsize = 28; |
197 | 153 | break; |
198 | 173 | } |
199 | 173 | break; |
200 | 1.40k | } |
201 | | |
202 | 1.40k | printMemReference(MI, OpNo, O); |
203 | 1.40k | } |
204 | | |
205 | | static void printf64mem(MCInst *MI, unsigned OpNo, SStream *O) |
206 | 1.26k | { |
207 | 1.26k | MI->x86opsize = 8; |
208 | 1.26k | printMemReference(MI, OpNo, O); |
209 | 1.26k | } |
210 | | |
211 | | static void printf80mem(MCInst *MI, unsigned OpNo, SStream *O) |
212 | 77 | { |
213 | 77 | MI->x86opsize = 10; |
214 | 77 | printMemReference(MI, OpNo, O); |
215 | 77 | } |
216 | | |
217 | | static void printf128mem(MCInst *MI, unsigned OpNo, SStream *O) |
218 | 992 | { |
219 | 992 | MI->x86opsize = 16; |
220 | 992 | printMemReference(MI, OpNo, O); |
221 | 992 | } |
222 | | |
223 | | static void printf256mem(MCInst *MI, unsigned OpNo, SStream *O) |
224 | 1.18k | { |
225 | 1.18k | MI->x86opsize = 32; |
226 | 1.18k | printMemReference(MI, OpNo, O); |
227 | 1.18k | } |
228 | | |
229 | | static void printf512mem(MCInst *MI, unsigned OpNo, SStream *O) |
230 | 255 | { |
231 | 255 | MI->x86opsize = 64; |
232 | 255 | printMemReference(MI, OpNo, O); |
233 | 255 | } |
234 | | |
235 | | #endif |
236 | | |
237 | | static void printRegName(SStream *OS, unsigned RegNo); |
238 | | |
239 | | // local printOperand, without updating public operands |
240 | | static void _printOperand(MCInst *MI, unsigned OpNo, SStream *O) |
241 | 65.9k | { |
242 | 65.9k | MCOperand *Op = MCInst_getOperand(MI, OpNo); |
243 | 65.9k | if (MCOperand_isReg(Op)) { |
244 | 65.9k | printRegName(O, MCOperand_getReg(Op)); |
245 | 65.9k | } else if (MCOperand_isImm(Op)) { |
246 | 0 | uint8_t encsize; |
247 | 0 | uint8_t opsize = |
248 | 0 | X86_immediate_size(MCInst_getOpcode(MI), &encsize); |
249 | | |
250 | | // Print X86 immediates as signed values. |
251 | 0 | int64_t imm = MCOperand_getImm(Op); |
252 | 0 | if (imm < 0) { |
253 | 0 | if (MI->csh->imm_unsigned) { |
254 | 0 | if (opsize) { |
255 | 0 | switch (opsize) { |
256 | 0 | default: |
257 | 0 | break; |
258 | 0 | case 1: |
259 | 0 | imm &= 0xff; |
260 | 0 | break; |
261 | 0 | case 2: |
262 | 0 | imm &= 0xffff; |
263 | 0 | break; |
264 | 0 | case 4: |
265 | 0 | imm &= 0xffffffff; |
266 | 0 | break; |
267 | 0 | } |
268 | 0 | } |
269 | | |
270 | 0 | SStream_concat(O, "$0x%" PRIx64, imm); |
271 | 0 | } else { |
272 | 0 | if (imm < -HEX_THRESHOLD) |
273 | 0 | SStream_concat(O, "$-0x%" PRIx64, -imm); |
274 | 0 | else |
275 | 0 | SStream_concat(O, "$-%" PRIu64, -imm); |
276 | 0 | } |
277 | 0 | } else { |
278 | 0 | if (imm > HEX_THRESHOLD) |
279 | 0 | SStream_concat(O, "$0x%" PRIx64, imm); |
280 | 0 | else |
281 | 0 | SStream_concat(O, "$%" PRIu64, imm); |
282 | 0 | } |
283 | 0 | } |
284 | 65.9k | } |
285 | | |
286 | | // convert Intel access info to AT&T access info |
287 | | static void get_op_access(cs_struct *h, unsigned int id, uint8_t *access, |
288 | | uint64_t *eflags) |
289 | 281k | { |
290 | 281k | uint8_t count, i; |
291 | 281k | const uint8_t *arr = X86_get_op_access(h, id, eflags); |
292 | | |
293 | | // initialize access |
294 | 281k | memset(access, 0, CS_X86_MAXIMUM_OPERAND_SIZE * sizeof(access[0])); |
295 | 281k | if (!arr) { |
296 | 0 | return; |
297 | 0 | } |
298 | | |
299 | | // find the non-zero last entry |
300 | 825k | for (count = 0; arr[count]; count++) |
301 | 544k | ; |
302 | | |
303 | 281k | if (count == 0) |
304 | 20.0k | return; |
305 | | |
306 | | // copy in reverse order this access array from Intel syntax -> AT&T syntax |
307 | 261k | count--; |
308 | 805k | for (i = 0; i <= count && ((count - i) < CS_X86_MAXIMUM_OPERAND_SIZE) && |
309 | 544k | i < CS_X86_MAXIMUM_OPERAND_SIZE; |
310 | 544k | i++) { |
311 | 544k | if (arr[count - i] != CS_AC_IGNORE) |
312 | 465k | access[i] = arr[count - i]; |
313 | 78.7k | else |
314 | 78.7k | access[i] = 0; |
315 | 544k | } |
316 | 261k | } |
317 | | |
318 | | static void printSrcIdx(MCInst *MI, unsigned Op, SStream *O) |
319 | 4.73k | { |
320 | 4.73k | MCOperand *SegReg; |
321 | 4.73k | int reg; |
322 | | |
323 | 4.73k | if (MI->csh->detail_opt) { |
324 | 4.73k | uint8_t access[CS_X86_MAXIMUM_OPERAND_SIZE]; |
325 | | |
326 | 4.73k | MI->flat_insn->detail->x86 |
327 | 4.73k | .operands[MI->flat_insn->detail->x86.op_count] |
328 | 4.73k | .type = X86_OP_MEM; |
329 | 4.73k | MI->flat_insn->detail->x86 |
330 | 4.73k | .operands[MI->flat_insn->detail->x86.op_count] |
331 | 4.73k | .size = MI->x86opsize; |
332 | 4.73k | MI->flat_insn->detail->x86 |
333 | 4.73k | .operands[MI->flat_insn->detail->x86.op_count] |
334 | 4.73k | .mem.segment = X86_REG_INVALID; |
335 | 4.73k | MI->flat_insn->detail->x86 |
336 | 4.73k | .operands[MI->flat_insn->detail->x86.op_count] |
337 | 4.73k | .mem.base = X86_REG_INVALID; |
338 | 4.73k | MI->flat_insn->detail->x86 |
339 | 4.73k | .operands[MI->flat_insn->detail->x86.op_count] |
340 | 4.73k | .mem.index = X86_REG_INVALID; |
341 | 4.73k | MI->flat_insn->detail->x86 |
342 | 4.73k | .operands[MI->flat_insn->detail->x86.op_count] |
343 | 4.73k | .mem.scale = 1; |
344 | 4.73k | MI->flat_insn->detail->x86 |
345 | 4.73k | .operands[MI->flat_insn->detail->x86.op_count] |
346 | 4.73k | .mem.disp = 0; |
347 | | |
348 | 4.73k | get_op_access(MI->csh, MCInst_getOpcode(MI), access, |
349 | 4.73k | &MI->flat_insn->detail->x86.eflags); |
350 | 4.73k | MI->flat_insn->detail->x86 |
351 | 4.73k | .operands[MI->flat_insn->detail->x86.op_count] |
352 | 4.73k | .access = access[MI->flat_insn->detail->x86.op_count]; |
353 | 4.73k | } |
354 | | |
355 | 4.73k | SegReg = MCInst_getOperand(MI, Op + 1); |
356 | 4.73k | reg = MCOperand_getReg(SegReg); |
357 | | // If this has a segment register, print it. |
358 | 4.73k | if (reg) { |
359 | 96 | _printOperand(MI, Op + 1, O); |
360 | 96 | SStream_concat0(O, ":"); |
361 | | |
362 | 96 | if (MI->csh->detail_opt) { |
363 | 96 | MI->flat_insn->detail->x86 |
364 | 96 | .operands[MI->flat_insn->detail->x86.op_count] |
365 | 96 | .mem.segment = X86_register_map(reg); |
366 | 96 | } |
367 | 96 | } |
368 | | |
369 | 4.73k | SStream_concat0(O, "("); |
370 | 4.73k | set_mem_access(MI, true); |
371 | | |
372 | 4.73k | printOperand(MI, Op, O); |
373 | | |
374 | 4.73k | SStream_concat0(O, ")"); |
375 | 4.73k | set_mem_access(MI, false); |
376 | 4.73k | } |
377 | | |
378 | | static void printDstIdx(MCInst *MI, unsigned Op, SStream *O) |
379 | 7.16k | { |
380 | 7.16k | if (MI->csh->detail_opt) { |
381 | 7.16k | uint8_t access[CS_X86_MAXIMUM_OPERAND_SIZE]; |
382 | | |
383 | 7.16k | MI->flat_insn->detail->x86 |
384 | 7.16k | .operands[MI->flat_insn->detail->x86.op_count] |
385 | 7.16k | .type = X86_OP_MEM; |
386 | 7.16k | MI->flat_insn->detail->x86 |
387 | 7.16k | .operands[MI->flat_insn->detail->x86.op_count] |
388 | 7.16k | .size = MI->x86opsize; |
389 | 7.16k | MI->flat_insn->detail->x86 |
390 | 7.16k | .operands[MI->flat_insn->detail->x86.op_count] |
391 | 7.16k | .mem.segment = X86_REG_INVALID; |
392 | 7.16k | MI->flat_insn->detail->x86 |
393 | 7.16k | .operands[MI->flat_insn->detail->x86.op_count] |
394 | 7.16k | .mem.base = X86_REG_INVALID; |
395 | 7.16k | MI->flat_insn->detail->x86 |
396 | 7.16k | .operands[MI->flat_insn->detail->x86.op_count] |
397 | 7.16k | .mem.index = X86_REG_INVALID; |
398 | 7.16k | MI->flat_insn->detail->x86 |
399 | 7.16k | .operands[MI->flat_insn->detail->x86.op_count] |
400 | 7.16k | .mem.scale = 1; |
401 | 7.16k | MI->flat_insn->detail->x86 |
402 | 7.16k | .operands[MI->flat_insn->detail->x86.op_count] |
403 | 7.16k | .mem.disp = 0; |
404 | | |
405 | 7.16k | get_op_access(MI->csh, MCInst_getOpcode(MI), access, |
406 | 7.16k | &MI->flat_insn->detail->x86.eflags); |
407 | 7.16k | MI->flat_insn->detail->x86 |
408 | 7.16k | .operands[MI->flat_insn->detail->x86.op_count] |
409 | 7.16k | .access = access[MI->flat_insn->detail->x86.op_count]; |
410 | 7.16k | } |
411 | | |
412 | | // DI accesses are always ES-based on non-64bit mode |
413 | 7.16k | if (MI->csh->mode != CS_MODE_64) { |
414 | 4.61k | SStream_concat0(O, "%es:("); |
415 | 4.61k | if (MI->csh->detail_opt) { |
416 | 4.61k | MI->flat_insn->detail->x86 |
417 | 4.61k | .operands[MI->flat_insn->detail->x86.op_count] |
418 | 4.61k | .mem.segment = X86_REG_ES; |
419 | 4.61k | } |
420 | 4.61k | } else |
421 | 2.54k | SStream_concat0(O, "("); |
422 | | |
423 | 7.16k | set_mem_access(MI, true); |
424 | | |
425 | 7.16k | printOperand(MI, Op, O); |
426 | | |
427 | 7.16k | SStream_concat0(O, ")"); |
428 | 7.16k | set_mem_access(MI, false); |
429 | 7.16k | } |
430 | | |
431 | | static void printSrcIdx8(MCInst *MI, unsigned OpNo, SStream *O) |
432 | 1.56k | { |
433 | 1.56k | MI->x86opsize = 1; |
434 | 1.56k | printSrcIdx(MI, OpNo, O); |
435 | 1.56k | } |
436 | | |
437 | | static void printSrcIdx16(MCInst *MI, unsigned OpNo, SStream *O) |
438 | 1.17k | { |
439 | 1.17k | MI->x86opsize = 2; |
440 | 1.17k | printSrcIdx(MI, OpNo, O); |
441 | 1.17k | } |
442 | | |
443 | | static void printSrcIdx32(MCInst *MI, unsigned OpNo, SStream *O) |
444 | 1.01k | { |
445 | 1.01k | MI->x86opsize = 4; |
446 | 1.01k | printSrcIdx(MI, OpNo, O); |
447 | 1.01k | } |
448 | | |
449 | | static void printSrcIdx64(MCInst *MI, unsigned OpNo, SStream *O) |
450 | 986 | { |
451 | 986 | MI->x86opsize = 8; |
452 | 986 | printSrcIdx(MI, OpNo, O); |
453 | 986 | } |
454 | | |
455 | | static void printDstIdx8(MCInst *MI, unsigned OpNo, SStream *O) |
456 | 2.53k | { |
457 | 2.53k | MI->x86opsize = 1; |
458 | 2.53k | printDstIdx(MI, OpNo, O); |
459 | 2.53k | } |
460 | | |
461 | | static void printDstIdx16(MCInst *MI, unsigned OpNo, SStream *O) |
462 | 2.26k | { |
463 | 2.26k | MI->x86opsize = 2; |
464 | 2.26k | printDstIdx(MI, OpNo, O); |
465 | 2.26k | } |
466 | | |
467 | | static void printDstIdx32(MCInst *MI, unsigned OpNo, SStream *O) |
468 | 1.48k | { |
469 | 1.48k | MI->x86opsize = 4; |
470 | 1.48k | printDstIdx(MI, OpNo, O); |
471 | 1.48k | } |
472 | | |
473 | | static void printDstIdx64(MCInst *MI, unsigned OpNo, SStream *O) |
474 | 871 | { |
475 | 871 | MI->x86opsize = 8; |
476 | 871 | printDstIdx(MI, OpNo, O); |
477 | 871 | } |
478 | | |
479 | | static void printMemOffset(MCInst *MI, unsigned Op, SStream *O) |
480 | 1.23k | { |
481 | 1.23k | MCOperand *DispSpec = MCInst_getOperand(MI, Op); |
482 | 1.23k | MCOperand *SegReg = MCInst_getOperand(MI, Op + 1); |
483 | 1.23k | int reg; |
484 | | |
485 | 1.23k | if (MI->csh->detail_opt) { |
486 | 1.23k | uint8_t access[CS_X86_MAXIMUM_OPERAND_SIZE]; |
487 | | |
488 | 1.23k | MI->flat_insn->detail->x86 |
489 | 1.23k | .operands[MI->flat_insn->detail->x86.op_count] |
490 | 1.23k | .type = X86_OP_MEM; |
491 | 1.23k | MI->flat_insn->detail->x86 |
492 | 1.23k | .operands[MI->flat_insn->detail->x86.op_count] |
493 | 1.23k | .size = MI->x86opsize; |
494 | 1.23k | MI->flat_insn->detail->x86 |
495 | 1.23k | .operands[MI->flat_insn->detail->x86.op_count] |
496 | 1.23k | .mem.segment = X86_REG_INVALID; |
497 | 1.23k | MI->flat_insn->detail->x86 |
498 | 1.23k | .operands[MI->flat_insn->detail->x86.op_count] |
499 | 1.23k | .mem.base = X86_REG_INVALID; |
500 | 1.23k | MI->flat_insn->detail->x86 |
501 | 1.23k | .operands[MI->flat_insn->detail->x86.op_count] |
502 | 1.23k | .mem.index = X86_REG_INVALID; |
503 | 1.23k | MI->flat_insn->detail->x86 |
504 | 1.23k | .operands[MI->flat_insn->detail->x86.op_count] |
505 | 1.23k | .mem.scale = 1; |
506 | 1.23k | MI->flat_insn->detail->x86 |
507 | 1.23k | .operands[MI->flat_insn->detail->x86.op_count] |
508 | 1.23k | .mem.disp = 0; |
509 | | |
510 | 1.23k | get_op_access(MI->csh, MCInst_getOpcode(MI), access, |
511 | 1.23k | &MI->flat_insn->detail->x86.eflags); |
512 | 1.23k | MI->flat_insn->detail->x86 |
513 | 1.23k | .operands[MI->flat_insn->detail->x86.op_count] |
514 | 1.23k | .access = access[MI->flat_insn->detail->x86.op_count]; |
515 | 1.23k | } |
516 | | |
517 | | // If this has a segment register, print it. |
518 | 1.23k | reg = MCOperand_getReg(SegReg); |
519 | 1.23k | if (reg) { |
520 | 16 | _printOperand(MI, Op + 1, O); |
521 | 16 | SStream_concat0(O, ":"); |
522 | | |
523 | 16 | if (MI->csh->detail_opt) { |
524 | 16 | MI->flat_insn->detail->x86 |
525 | 16 | .operands[MI->flat_insn->detail->x86.op_count] |
526 | 16 | .mem.segment = X86_register_map(reg); |
527 | 16 | } |
528 | 16 | } |
529 | | |
530 | 1.23k | if (MCOperand_isImm(DispSpec)) { |
531 | 1.23k | int64_t imm = MCOperand_getImm(DispSpec); |
532 | 1.23k | if (MI->csh->detail_opt) |
533 | 1.23k | MI->flat_insn->detail->x86 |
534 | 1.23k | .operands[MI->flat_insn->detail->x86.op_count] |
535 | 1.23k | .mem.disp = imm; |
536 | 1.23k | if (imm < 0) { |
537 | 248 | SStream_concat(O, "0x%" PRIx64, |
538 | 248 | arch_masks[MI->csh->mode] & imm); |
539 | 984 | } else { |
540 | 984 | if (imm > HEX_THRESHOLD) |
541 | 768 | SStream_concat(O, "0x%" PRIx64, imm); |
542 | 216 | else |
543 | 216 | SStream_concat(O, "%" PRIu64, imm); |
544 | 984 | } |
545 | 1.23k | } |
546 | | |
547 | 1.23k | if (MI->csh->detail_opt) |
548 | 1.23k | MI->flat_insn->detail->x86.op_count++; |
549 | 1.23k | } |
550 | | |
551 | | static void printU8Imm(MCInst *MI, unsigned Op, SStream *O) |
552 | 9.56k | { |
553 | 9.56k | uint8_t val = MCOperand_getImm(MCInst_getOperand(MI, Op)) & 0xff; |
554 | | |
555 | 9.56k | if (val > HEX_THRESHOLD) |
556 | 8.48k | SStream_concat(O, "$0x%x", val); |
557 | 1.07k | else |
558 | 1.07k | SStream_concat(O, "$%u", val); |
559 | | |
560 | 9.56k | if (MI->csh->detail_opt) { |
561 | 9.56k | MI->flat_insn->detail->x86 |
562 | 9.56k | .operands[MI->flat_insn->detail->x86.op_count] |
563 | 9.56k | .type = X86_OP_IMM; |
564 | 9.56k | MI->flat_insn->detail->x86 |
565 | 9.56k | .operands[MI->flat_insn->detail->x86.op_count] |
566 | 9.56k | .imm = val; |
567 | 9.56k | MI->flat_insn->detail->x86 |
568 | 9.56k | .operands[MI->flat_insn->detail->x86.op_count] |
569 | 9.56k | .size = 1; |
570 | 9.56k | MI->flat_insn->detail->x86.op_count++; |
571 | 9.56k | } |
572 | 9.56k | } |
573 | | |
574 | | static void printMemOffs8(MCInst *MI, unsigned OpNo, SStream *O) |
575 | 798 | { |
576 | 798 | MI->x86opsize = 1; |
577 | 798 | printMemOffset(MI, OpNo, O); |
578 | 798 | } |
579 | | |
580 | | static void printMemOffs16(MCInst *MI, unsigned OpNo, SStream *O) |
581 | 205 | { |
582 | 205 | MI->x86opsize = 2; |
583 | 205 | printMemOffset(MI, OpNo, O); |
584 | 205 | } |
585 | | |
586 | | static void printMemOffs32(MCInst *MI, unsigned OpNo, SStream *O) |
587 | 228 | { |
588 | 228 | MI->x86opsize = 4; |
589 | 228 | printMemOffset(MI, OpNo, O); |
590 | 228 | } |
591 | | |
592 | | static void printMemOffs64(MCInst *MI, unsigned OpNo, SStream *O) |
593 | 1 | { |
594 | 1 | MI->x86opsize = 8; |
595 | 1 | printMemOffset(MI, OpNo, O); |
596 | 1 | } |
597 | | |
598 | | /// printPCRelImm - This is used to print an immediate value that ends up |
599 | | /// being encoded as a pc-relative value (e.g. for jumps and calls). These |
600 | | /// print slightly differently than normal immediates. For example, a $ is not |
601 | | /// emitted. |
602 | | static void printPCRelImm(MCInst *MI, unsigned OpNo, SStream *O) |
603 | 8.05k | { |
604 | 8.05k | MCOperand *Op = MCInst_getOperand(MI, OpNo); |
605 | 8.05k | if (MCOperand_isImm(Op)) { |
606 | 8.05k | int64_t imm = MCOperand_getImm(Op) + MI->flat_insn->size + |
607 | 8.05k | MI->address; |
608 | | |
609 | | // truncate imm for non-64bit |
610 | 8.05k | if (MI->csh->mode != CS_MODE_64) { |
611 | 5.99k | imm = imm & 0xffffffff; |
612 | 5.99k | } |
613 | | |
614 | 8.05k | if (imm < 0) { |
615 | 331 | SStream_concat(O, "0x%" PRIx64, imm); |
616 | 7.72k | } else { |
617 | 7.72k | if (imm > HEX_THRESHOLD) |
618 | 7.72k | SStream_concat(O, "0x%" PRIx64, imm); |
619 | 1 | else |
620 | 1 | SStream_concat(O, "%" PRIu64, imm); |
621 | 7.72k | } |
622 | 8.05k | if (MI->csh->detail_opt) { |
623 | 8.05k | MI->flat_insn->detail->x86 |
624 | 8.05k | .operands[MI->flat_insn->detail->x86.op_count] |
625 | 8.05k | .type = X86_OP_IMM; |
626 | 8.05k | MI->has_imm = true; |
627 | 8.05k | MI->flat_insn->detail->x86 |
628 | 8.05k | .operands[MI->flat_insn->detail->x86.op_count] |
629 | 8.05k | .imm = imm; |
630 | 8.05k | MI->flat_insn->detail->x86.op_count++; |
631 | 8.05k | } |
632 | 8.05k | } |
633 | 8.05k | } |
634 | | |
635 | | static void printOperand(MCInst *MI, unsigned OpNo, SStream *O) |
636 | 122k | { |
637 | 122k | MCOperand *Op = MCInst_getOperand(MI, OpNo); |
638 | 122k | if (MCOperand_isReg(Op)) { |
639 | 107k | unsigned int reg = MCOperand_getReg(Op); |
640 | 107k | printRegName(O, reg); |
641 | 107k | if (MI->csh->detail_opt) { |
642 | 107k | if (MI->csh->doing_mem) { |
643 | 11.8k | MI->flat_insn->detail->x86 |
644 | 11.8k | .operands[MI->flat_insn->detail->x86 |
645 | 11.8k | .op_count] |
646 | 11.8k | .mem.base = X86_register_map(reg); |
647 | 95.8k | } else { |
648 | 95.8k | uint8_t access[CS_X86_MAXIMUM_OPERAND_SIZE]; |
649 | | |
650 | 95.8k | MI->flat_insn->detail->x86 |
651 | 95.8k | .operands[MI->flat_insn->detail->x86 |
652 | 95.8k | .op_count] |
653 | 95.8k | .type = X86_OP_REG; |
654 | 95.8k | MI->flat_insn->detail->x86 |
655 | 95.8k | .operands[MI->flat_insn->detail->x86 |
656 | 95.8k | .op_count] |
657 | 95.8k | .reg = X86_register_map(reg); |
658 | 95.8k | MI->flat_insn->detail->x86 |
659 | 95.8k | .operands[MI->flat_insn->detail->x86 |
660 | 95.8k | .op_count] |
661 | 95.8k | .size = |
662 | 95.8k | MI->csh->regsize_map[X86_register_map( |
663 | 95.8k | reg)]; |
664 | | |
665 | 95.8k | get_op_access( |
666 | 95.8k | MI->csh, MCInst_getOpcode(MI), access, |
667 | 95.8k | &MI->flat_insn->detail->x86.eflags); |
668 | 95.8k | MI->flat_insn->detail->x86 |
669 | 95.8k | .operands[MI->flat_insn->detail->x86 |
670 | 95.8k | .op_count] |
671 | 95.8k | .access = |
672 | 95.8k | access[MI->flat_insn->detail->x86 |
673 | 95.8k | .op_count]; |
674 | | |
675 | 95.8k | MI->flat_insn->detail->x86.op_count++; |
676 | 95.8k | } |
677 | 107k | } |
678 | 107k | } else if (MCOperand_isImm(Op)) { |
679 | | // Print X86 immediates as signed values. |
680 | 14.3k | uint8_t encsize; |
681 | 14.3k | int64_t imm = MCOperand_getImm(Op); |
682 | 14.3k | uint8_t opsize = |
683 | 14.3k | X86_immediate_size(MCInst_getOpcode(MI), &encsize); |
684 | | |
685 | 14.3k | if (opsize == 1) { // print 1 byte immediate in positive form |
686 | 6.86k | imm = imm & 0xff; |
687 | 6.86k | } |
688 | | |
689 | 14.3k | switch (MI->flat_insn->id) { |
690 | 6.65k | default: |
691 | 6.65k | if (imm >= 0) { |
692 | 6.15k | if (imm > HEX_THRESHOLD) |
693 | 5.36k | SStream_concat(O, "$0x%" PRIx64, imm); |
694 | 793 | else |
695 | 793 | SStream_concat(O, "$%" PRIu64, imm); |
696 | 6.15k | } else { |
697 | 504 | if (MI->csh->imm_unsigned) { |
698 | 0 | if (opsize) { |
699 | 0 | switch (opsize) { |
700 | 0 | default: |
701 | 0 | break; |
702 | | // case 1 cannot occur because above imm was ANDed with 0xff, |
703 | | // making it effectively always positive. |
704 | | // So this switch is never reached. |
705 | 0 | case 2: |
706 | 0 | imm &= 0xffff; |
707 | 0 | break; |
708 | 0 | case 4: |
709 | 0 | imm &= 0xffffffff; |
710 | 0 | break; |
711 | 0 | } |
712 | 0 | } |
713 | | |
714 | 0 | SStream_concat(O, "$0x%" PRIx64, imm); |
715 | 504 | } else { |
716 | 504 | if (imm == |
717 | 504 | 0x8000000000000000LL) // imm == -imm |
718 | 0 | SStream_concat0( |
719 | 0 | O, |
720 | 0 | "$0x8000000000000000"); |
721 | 504 | else if (imm < -HEX_THRESHOLD) |
722 | 484 | SStream_concat(O, |
723 | 484 | "$-0x%" PRIx64, |
724 | 484 | -imm); |
725 | 20 | else |
726 | 20 | SStream_concat(O, "$-%" PRIu64, |
727 | 20 | -imm); |
728 | 504 | } |
729 | 504 | } |
730 | 6.65k | break; |
731 | | |
732 | 6.65k | case X86_INS_MOVABS: |
733 | 2.91k | case X86_INS_MOV: |
734 | | // do not print number in negative form |
735 | 2.91k | if (imm > HEX_THRESHOLD) |
736 | 2.40k | SStream_concat(O, "$0x%" PRIx64, imm); |
737 | 516 | else |
738 | 516 | SStream_concat(O, "$%" PRIu64, imm); |
739 | 2.91k | break; |
740 | | |
741 | 0 | case X86_INS_IN: |
742 | 0 | case X86_INS_OUT: |
743 | 0 | case X86_INS_INT: |
744 | | // do not print number in negative form |
745 | 0 | imm = imm & 0xff; |
746 | 0 | if (imm >= 0 && imm <= HEX_THRESHOLD) |
747 | 0 | SStream_concat(O, "$%u", imm); |
748 | 0 | else { |
749 | 0 | SStream_concat(O, "$0x%x", imm); |
750 | 0 | } |
751 | 0 | break; |
752 | | |
753 | 416 | case X86_INS_LCALL: |
754 | 656 | case X86_INS_LJMP: |
755 | 656 | case X86_INS_JMP: |
756 | | // always print address in positive form |
757 | 656 | if (OpNo == 1) { // selector is ptr16 |
758 | 328 | imm = imm & 0xffff; |
759 | 328 | opsize = 2; |
760 | 328 | } else |
761 | 328 | opsize = 4; |
762 | 656 | SStream_concat(O, "$0x%" PRIx64, imm); |
763 | 656 | break; |
764 | | |
765 | 1.41k | case X86_INS_AND: |
766 | 1.93k | case X86_INS_OR: |
767 | 2.67k | case X86_INS_XOR: |
768 | | // do not print number in negative form |
769 | 2.67k | if (imm >= 0 && imm <= HEX_THRESHOLD) |
770 | 396 | SStream_concat(O, "$%u", imm); |
771 | 2.28k | else { |
772 | 2.28k | imm = arch_masks[opsize ? opsize : MI->imm_size] & |
773 | 2.28k | imm; |
774 | 2.28k | SStream_concat(O, "$0x%" PRIx64, imm); |
775 | 2.28k | } |
776 | 2.67k | break; |
777 | | |
778 | 938 | case X86_INS_RET: |
779 | 1.40k | case X86_INS_RETF: |
780 | | // RET imm16 |
781 | 1.40k | if (imm >= 0 && imm <= HEX_THRESHOLD) |
782 | 170 | SStream_concat(O, "$%u", imm); |
783 | 1.23k | else { |
784 | 1.23k | imm = 0xffff & imm; |
785 | 1.23k | SStream_concat(O, "$0x%x", imm); |
786 | 1.23k | } |
787 | 1.40k | break; |
788 | 14.3k | } |
789 | | |
790 | 14.3k | if (MI->csh->detail_opt) { |
791 | 14.3k | if (MI->csh->doing_mem) { |
792 | 0 | MI->flat_insn->detail->x86 |
793 | 0 | .operands[MI->flat_insn->detail->x86 |
794 | 0 | .op_count] |
795 | 0 | .type = X86_OP_MEM; |
796 | 0 | MI->flat_insn->detail->x86 |
797 | 0 | .operands[MI->flat_insn->detail->x86 |
798 | 0 | .op_count] |
799 | 0 | .mem.disp = imm; |
800 | 14.3k | } else { |
801 | 14.3k | MI->flat_insn->detail->x86 |
802 | 14.3k | .operands[MI->flat_insn->detail->x86 |
803 | 14.3k | .op_count] |
804 | 14.3k | .type = X86_OP_IMM; |
805 | 14.3k | MI->has_imm = true; |
806 | 14.3k | MI->flat_insn->detail->x86 |
807 | 14.3k | .operands[MI->flat_insn->detail->x86 |
808 | 14.3k | .op_count] |
809 | 14.3k | .imm = imm; |
810 | | |
811 | 14.3k | if (opsize > 0) { |
812 | 12.6k | MI->flat_insn->detail->x86 |
813 | 12.6k | .operands[MI->flat_insn->detail |
814 | 12.6k | ->x86.op_count] |
815 | 12.6k | .size = opsize; |
816 | 12.6k | MI->flat_insn->detail->x86.encoding |
817 | 12.6k | .imm_size = encsize; |
818 | 12.6k | } else if (MI->op1_size > 0) |
819 | 0 | MI->flat_insn->detail->x86 |
820 | 0 | .operands[MI->flat_insn->detail |
821 | 0 | ->x86.op_count] |
822 | 0 | .size = MI->op1_size; |
823 | 1.61k | else |
824 | 1.61k | MI->flat_insn->detail->x86 |
825 | 1.61k | .operands[MI->flat_insn->detail |
826 | 1.61k | ->x86.op_count] |
827 | 1.61k | .size = MI->imm_size; |
828 | | |
829 | 14.3k | MI->flat_insn->detail->x86.op_count++; |
830 | 14.3k | } |
831 | 14.3k | } |
832 | 14.3k | } |
833 | 122k | } |
834 | | |
835 | | static void printMemReference(MCInst *MI, unsigned Op, SStream *O) |
836 | 48.4k | { |
837 | 48.4k | MCOperand *BaseReg = MCInst_getOperand(MI, Op + X86_AddrBaseReg); |
838 | 48.4k | MCOperand *IndexReg = MCInst_getOperand(MI, Op + X86_AddrIndexReg); |
839 | 48.4k | MCOperand *DispSpec = MCInst_getOperand(MI, Op + X86_AddrDisp); |
840 | 48.4k | MCOperand *SegReg = MCInst_getOperand(MI, Op + X86_AddrSegmentReg); |
841 | 48.4k | uint64_t ScaleVal; |
842 | 48.4k | int segreg; |
843 | 48.4k | int64_t DispVal = 1; |
844 | | |
845 | 48.4k | if (MI->csh->detail_opt) { |
846 | 48.4k | uint8_t access[CS_X86_MAXIMUM_OPERAND_SIZE]; |
847 | | |
848 | 48.4k | MI->flat_insn->detail->x86 |
849 | 48.4k | .operands[MI->flat_insn->detail->x86.op_count] |
850 | 48.4k | .type = X86_OP_MEM; |
851 | 48.4k | MI->flat_insn->detail->x86 |
852 | 48.4k | .operands[MI->flat_insn->detail->x86.op_count] |
853 | 48.4k | .size = MI->x86opsize; |
854 | 48.4k | MI->flat_insn->detail->x86 |
855 | 48.4k | .operands[MI->flat_insn->detail->x86.op_count] |
856 | 48.4k | .mem.segment = X86_REG_INVALID; |
857 | 48.4k | MI->flat_insn->detail->x86 |
858 | 48.4k | .operands[MI->flat_insn->detail->x86.op_count] |
859 | 48.4k | .mem.base = X86_register_map(MCOperand_getReg(BaseReg)); |
860 | 48.4k | if (MCOperand_getReg(IndexReg) != X86_EIZ) { |
861 | 48.2k | MI->flat_insn->detail->x86 |
862 | 48.2k | .operands[MI->flat_insn->detail->x86.op_count] |
863 | 48.2k | .mem.index = |
864 | 48.2k | X86_register_map(MCOperand_getReg(IndexReg)); |
865 | 48.2k | } |
866 | 48.4k | MI->flat_insn->detail->x86 |
867 | 48.4k | .operands[MI->flat_insn->detail->x86.op_count] |
868 | 48.4k | .mem.scale = 1; |
869 | 48.4k | MI->flat_insn->detail->x86 |
870 | 48.4k | .operands[MI->flat_insn->detail->x86.op_count] |
871 | 48.4k | .mem.disp = 0; |
872 | | |
873 | 48.4k | get_op_access(MI->csh, MCInst_getOpcode(MI), access, |
874 | 48.4k | &MI->flat_insn->detail->x86.eflags); |
875 | 48.4k | MI->flat_insn->detail->x86 |
876 | 48.4k | .operands[MI->flat_insn->detail->x86.op_count] |
877 | 48.4k | .access = access[MI->flat_insn->detail->x86.op_count]; |
878 | 48.4k | } |
879 | | |
880 | | // If this has a segment register, print it. |
881 | 48.4k | segreg = MCOperand_getReg(SegReg); |
882 | 48.4k | if (segreg) { |
883 | 1.15k | _printOperand(MI, Op + X86_AddrSegmentReg, O); |
884 | 1.15k | SStream_concat0(O, ":"); |
885 | | |
886 | 1.15k | if (MI->csh->detail_opt) { |
887 | 1.15k | MI->flat_insn->detail->x86 |
888 | 1.15k | .operands[MI->flat_insn->detail->x86.op_count] |
889 | 1.15k | .mem.segment = X86_register_map(segreg); |
890 | 1.15k | } |
891 | 1.15k | } |
892 | | |
893 | 48.4k | if (MCOperand_isImm(DispSpec)) { |
894 | 48.4k | DispVal = MCOperand_getImm(DispSpec); |
895 | 48.4k | if (MI->csh->detail_opt) |
896 | 48.4k | MI->flat_insn->detail->x86 |
897 | 48.4k | .operands[MI->flat_insn->detail->x86.op_count] |
898 | 48.4k | .mem.disp = DispVal; |
899 | 48.4k | if (DispVal) { |
900 | 15.9k | if (MCOperand_getReg(IndexReg) || |
901 | 15.2k | MCOperand_getReg(BaseReg)) { |
902 | 15.2k | printInt64(O, DispVal); |
903 | 15.2k | } else { |
904 | | // only immediate as address of memory |
905 | 743 | if (DispVal < 0) { |
906 | 332 | SStream_concat( |
907 | 332 | O, "0x%" PRIx64, |
908 | 332 | arch_masks[MI->csh->mode] & |
909 | 332 | DispVal); |
910 | 411 | } else { |
911 | 411 | if (DispVal > HEX_THRESHOLD) |
912 | 403 | SStream_concat(O, "0x%" PRIx64, |
913 | 403 | DispVal); |
914 | 8 | else |
915 | 8 | SStream_concat(O, "%" PRIu64, |
916 | 8 | DispVal); |
917 | 411 | } |
918 | 743 | } |
919 | 15.9k | } |
920 | 48.4k | } |
921 | | |
922 | 48.4k | if (MCOperand_getReg(IndexReg) || MCOperand_getReg(BaseReg)) { |
923 | 47.7k | SStream_concat0(O, "("); |
924 | | |
925 | 47.7k | if (MCOperand_getReg(BaseReg)) |
926 | 47.5k | _printOperand(MI, Op + X86_AddrBaseReg, O); |
927 | | |
928 | 47.7k | if (MCOperand_getReg(IndexReg) && |
929 | 17.4k | MCOperand_getReg(IndexReg) != X86_EIZ) { |
930 | 17.1k | SStream_concat0(O, ", "); |
931 | 17.1k | _printOperand(MI, Op + X86_AddrIndexReg, O); |
932 | 17.1k | ScaleVal = MCOperand_getImm( |
933 | 17.1k | MCInst_getOperand(MI, Op + X86_AddrScaleAmt)); |
934 | 17.1k | if (MI->csh->detail_opt) |
935 | 17.1k | MI->flat_insn->detail->x86 |
936 | 17.1k | .operands[MI->flat_insn->detail->x86 |
937 | 17.1k | .op_count] |
938 | 17.1k | .mem.scale = (int)ScaleVal; |
939 | 17.1k | if (ScaleVal != 1) { |
940 | 1.74k | SStream_concat(O, ", %u", ScaleVal); |
941 | 1.74k | } |
942 | 17.1k | } |
943 | | |
944 | 47.7k | SStream_concat0(O, ")"); |
945 | 47.7k | } else { |
946 | 747 | if (!DispVal) |
947 | 4 | SStream_concat0(O, "0"); |
948 | 747 | } |
949 | | |
950 | 48.4k | if (MI->csh->detail_opt) |
951 | 48.4k | MI->flat_insn->detail->x86.op_count++; |
952 | 48.4k | } |
953 | | |
954 | | static void printanymem(MCInst *MI, unsigned OpNo, SStream *O) |
955 | 1.01k | { |
956 | 1.01k | switch (MI->Opcode) { |
957 | 41 | default: |
958 | 41 | break; |
959 | 105 | case X86_LEA16r: |
960 | 105 | MI->x86opsize = 2; |
961 | 105 | break; |
962 | 197 | case X86_LEA32r: |
963 | 211 | case X86_LEA64_32r: |
964 | 211 | MI->x86opsize = 4; |
965 | 211 | break; |
966 | 20 | case X86_LEA64r: |
967 | 20 | MI->x86opsize = 8; |
968 | 20 | break; |
969 | 0 | #ifndef CAPSTONE_X86_REDUCE |
970 | 10 | case X86_BNDCL32rm: |
971 | 12 | case X86_BNDCN32rm: |
972 | 42 | case X86_BNDCU32rm: |
973 | 313 | case X86_BNDSTXmr: |
974 | 409 | case X86_BNDLDXrm: |
975 | 577 | case X86_BNDCL64rm: |
976 | 584 | case X86_BNDCN64rm: |
977 | 640 | case X86_BNDCU64rm: |
978 | 640 | MI->x86opsize = 16; |
979 | 640 | break; |
980 | 1.01k | #endif |
981 | 1.01k | } |
982 | | |
983 | 1.01k | printMemReference(MI, OpNo, O); |
984 | 1.01k | } |
985 | | |
986 | | #include "X86InstPrinter.h" |
987 | | |
988 | | // Include the auto-generated portion of the assembly writer. |
989 | | #ifdef CAPSTONE_X86_REDUCE |
990 | | #include "X86GenAsmWriter_reduce.inc" |
991 | | #else |
992 | | #include "X86GenAsmWriter.inc" |
993 | | #endif |
994 | | |
995 | | #include "X86GenRegisterName.inc" |
996 | | |
997 | | static void printRegName(SStream *OS, unsigned RegNo) |
998 | 173k | { |
999 | 173k | SStream_concat(OS, "%%%s", getRegisterName(RegNo)); |
1000 | 173k | } |
1001 | | |
1002 | | void X86_ATT_printInst(MCInst *MI, SStream *OS, void *info) |
1003 | 123k | { |
1004 | 123k | x86_reg reg, reg2; |
1005 | 123k | enum cs_ac_type access1, access2; |
1006 | 123k | int i; |
1007 | | |
1008 | | // perhaps this instruction does not need printer |
1009 | 123k | if (MI->assembly[0]) { |
1010 | 0 | strncpy(OS->buffer, MI->assembly, sizeof(OS->buffer)); |
1011 | 0 | return; |
1012 | 0 | } |
1013 | | |
1014 | | // Output CALLpcrel32 as "callq" in 64-bit mode. |
1015 | | // In Intel annotation it's always emitted as "call". |
1016 | | // |
1017 | | // TODO: Probably this hack should be redesigned via InstAlias in |
1018 | | // InstrInfo.td as soon as Requires clause is supported properly |
1019 | | // for InstAlias. |
1020 | 123k | if (MI->csh->mode == CS_MODE_64 && |
1021 | 41.9k | MCInst_getOpcode(MI) == X86_CALLpcrel32) { |
1022 | 0 | SStream_concat0(OS, "callq\t"); |
1023 | 0 | MCInst_setOpcodePub(MI, X86_INS_CALL); |
1024 | 0 | printPCRelImm(MI, 0, OS); |
1025 | 0 | return; |
1026 | 0 | } |
1027 | | |
1028 | 123k | X86_lockrep(MI, OS); |
1029 | 123k | printInstruction(MI, OS); |
1030 | | |
1031 | 123k | if (MI->has_imm) { |
1032 | | // if op_count > 1, then this operand's size is taken from the destination op |
1033 | 21.9k | if (MI->flat_insn->detail->x86.op_count > 1) { |
1034 | 11.6k | if (MI->flat_insn->id != X86_INS_LCALL && |
1035 | 11.4k | MI->flat_insn->id != X86_INS_LJMP && |
1036 | 11.3k | MI->flat_insn->id != X86_INS_JMP) { |
1037 | 11.3k | for (i = 0; |
1038 | 34.1k | i < MI->flat_insn->detail->x86.op_count; |
1039 | 22.8k | i++) { |
1040 | 22.8k | if (MI->flat_insn->detail->x86 |
1041 | 22.8k | .operands[i] |
1042 | 22.8k | .type == X86_OP_IMM) |
1043 | 11.4k | MI->flat_insn->detail->x86 |
1044 | 11.4k | .operands[i] |
1045 | 11.4k | .size = |
1046 | 11.4k | MI->flat_insn->detail |
1047 | 11.4k | ->x86 |
1048 | 11.4k | .operands |
1049 | 11.4k | [MI->flat_insn |
1050 | 11.4k | ->detail |
1051 | 11.4k | ->x86 |
1052 | 11.4k | .op_count - |
1053 | 11.4k | 1] |
1054 | 11.4k | .size; |
1055 | 22.8k | } |
1056 | 11.3k | } |
1057 | 11.6k | } else |
1058 | 10.3k | MI->flat_insn->detail->x86.operands[0].size = |
1059 | 10.3k | MI->imm_size; |
1060 | 21.9k | } |
1061 | | |
1062 | 123k | if (MI->csh->detail_opt) { |
1063 | 123k | uint8_t access[CS_X86_MAXIMUM_OPERAND_SIZE] = { 0 }; |
1064 | | |
1065 | | // some instructions need to supply immediate 1 in the first op |
1066 | 123k | switch (MCInst_getOpcode(MI)) { |
1067 | 116k | default: |
1068 | 116k | break; |
1069 | 116k | case X86_SHL8r1: |
1070 | 165 | case X86_SHL16r1: |
1071 | 313 | case X86_SHL32r1: |
1072 | 316 | case X86_SHL64r1: |
1073 | 471 | case X86_SAL8r1: |
1074 | 494 | case X86_SAL16r1: |
1075 | 629 | case X86_SAL32r1: |
1076 | 642 | case X86_SAL64r1: |
1077 | 721 | case X86_SHR8r1: |
1078 | 981 | case X86_SHR16r1: |
1079 | 1.35k | case X86_SHR32r1: |
1080 | 1.37k | case X86_SHR64r1: |
1081 | 1.38k | case X86_SAR8r1: |
1082 | 1.43k | case X86_SAR16r1: |
1083 | 1.52k | case X86_SAR32r1: |
1084 | 1.59k | case X86_SAR64r1: |
1085 | 1.65k | case X86_RCL8r1: |
1086 | 1.87k | case X86_RCL16r1: |
1087 | 2.16k | case X86_RCL32r1: |
1088 | 2.25k | case X86_RCL64r1: |
1089 | 2.30k | case X86_RCR8r1: |
1090 | 2.71k | case X86_RCR16r1: |
1091 | 2.75k | case X86_RCR32r1: |
1092 | 2.78k | case X86_RCR64r1: |
1093 | 2.96k | case X86_ROL8r1: |
1094 | 3.12k | case X86_ROL16r1: |
1095 | 3.25k | case X86_ROL32r1: |
1096 | 3.37k | case X86_ROL64r1: |
1097 | 3.40k | case X86_ROR8r1: |
1098 | 3.61k | case X86_ROR16r1: |
1099 | 3.67k | case X86_ROR32r1: |
1100 | 3.68k | case X86_ROR64r1: |
1101 | 3.92k | case X86_SHL8m1: |
1102 | 3.96k | case X86_SHL16m1: |
1103 | 4.15k | case X86_SHL32m1: |
1104 | 4.24k | case X86_SHL64m1: |
1105 | 4.45k | case X86_SAL8m1: |
1106 | 4.47k | case X86_SAL16m1: |
1107 | 4.64k | case X86_SAL32m1: |
1108 | 4.70k | case X86_SAL64m1: |
1109 | 4.73k | case X86_SHR8m1: |
1110 | 4.81k | case X86_SHR16m1: |
1111 | 4.86k | case X86_SHR32m1: |
1112 | 4.86k | case X86_SHR64m1: |
1113 | 4.88k | case X86_SAR8m1: |
1114 | 4.92k | case X86_SAR16m1: |
1115 | 5.22k | case X86_SAR32m1: |
1116 | 5.48k | case X86_SAR64m1: |
1117 | 5.65k | case X86_RCL8m1: |
1118 | 5.69k | case X86_RCL16m1: |
1119 | 5.93k | case X86_RCL32m1: |
1120 | 6.10k | case X86_RCL64m1: |
1121 | 6.13k | case X86_RCR8m1: |
1122 | 6.30k | case X86_RCR16m1: |
1123 | 6.31k | case X86_RCR32m1: |
1124 | 6.45k | case X86_RCR64m1: |
1125 | 6.63k | case X86_ROL8m1: |
1126 | 6.71k | case X86_ROL16m1: |
1127 | 6.77k | case X86_ROL32m1: |
1128 | 6.81k | case X86_ROL64m1: |
1129 | 6.84k | case X86_ROR8m1: |
1130 | 7.01k | case X86_ROR16m1: |
1131 | 7.07k | case X86_ROR32m1: |
1132 | 7.13k | case X86_ROR64m1: |
1133 | | // shift all the ops right to leave 1st slot for this new register op |
1134 | 7.13k | memmove(&(MI->flat_insn->detail->x86.operands[1]), |
1135 | 7.13k | &(MI->flat_insn->detail->x86.operands[0]), |
1136 | 7.13k | sizeof(MI->flat_insn->detail->x86.operands[0]) * |
1137 | 7.13k | (ARR_SIZE(MI->flat_insn->detail->x86 |
1138 | 7.13k | .operands) - |
1139 | 7.13k | 1)); |
1140 | 7.13k | MI->flat_insn->detail->x86.operands[0].type = |
1141 | 7.13k | X86_OP_IMM; |
1142 | 7.13k | MI->flat_insn->detail->x86.operands[0].imm = 1; |
1143 | 7.13k | MI->flat_insn->detail->x86.operands[0].size = 1; |
1144 | 7.13k | MI->flat_insn->detail->x86.op_count++; |
1145 | 123k | } |
1146 | | |
1147 | | // special instruction needs to supply register op |
1148 | | // first op can be embedded in the asm by llvm. |
1149 | | // so we have to add the missing register as the first operand |
1150 | | |
1151 | | //printf(">>> opcode = %u\n", MCInst_getOpcode(MI)); |
1152 | | |
1153 | 123k | reg = X86_insn_reg_att(MCInst_getOpcode(MI), &access1); |
1154 | 123k | if (reg) { |
1155 | | // shift all the ops right to leave 1st slot for this new register op |
1156 | 8.42k | memmove(&(MI->flat_insn->detail->x86.operands[1]), |
1157 | 8.42k | &(MI->flat_insn->detail->x86.operands[0]), |
1158 | 8.42k | sizeof(MI->flat_insn->detail->x86.operands[0]) * |
1159 | 8.42k | (ARR_SIZE(MI->flat_insn->detail->x86 |
1160 | 8.42k | .operands) - |
1161 | 8.42k | 1)); |
1162 | 8.42k | MI->flat_insn->detail->x86.operands[0].type = |
1163 | 8.42k | X86_OP_REG; |
1164 | 8.42k | MI->flat_insn->detail->x86.operands[0].reg = reg; |
1165 | 8.42k | MI->flat_insn->detail->x86.operands[0].size = |
1166 | 8.42k | MI->csh->regsize_map[reg]; |
1167 | 8.42k | MI->flat_insn->detail->x86.operands[0].access = access1; |
1168 | | |
1169 | 8.42k | MI->flat_insn->detail->x86.op_count++; |
1170 | 115k | } else { |
1171 | 115k | if (X86_insn_reg_att2(MCInst_getOpcode(MI), ®, |
1172 | 115k | &access1, ®2, &access2)) { |
1173 | 3.45k | MI->flat_insn->detail->x86.operands[0].type = |
1174 | 3.45k | X86_OP_REG; |
1175 | 3.45k | MI->flat_insn->detail->x86.operands[0].reg = |
1176 | 3.45k | reg; |
1177 | 3.45k | MI->flat_insn->detail->x86.operands[0].size = |
1178 | 3.45k | MI->csh->regsize_map[reg]; |
1179 | 3.45k | MI->flat_insn->detail->x86.operands[0].access = |
1180 | 3.45k | access1; |
1181 | 3.45k | MI->flat_insn->detail->x86.operands[1].type = |
1182 | 3.45k | X86_OP_REG; |
1183 | 3.45k | MI->flat_insn->detail->x86.operands[1].reg = |
1184 | 3.45k | reg2; |
1185 | 3.45k | MI->flat_insn->detail->x86.operands[1].size = |
1186 | 3.45k | MI->csh->regsize_map[reg2]; |
1187 | 3.45k | MI->flat_insn->detail->x86.operands[1].access = |
1188 | 3.45k | access2; |
1189 | 3.45k | MI->flat_insn->detail->x86.op_count = 2; |
1190 | 3.45k | } |
1191 | 115k | } |
1192 | | |
1193 | 123k | #ifndef CAPSTONE_DIET |
1194 | 123k | get_op_access(MI->csh, MCInst_getOpcode(MI), access, |
1195 | 123k | &MI->flat_insn->detail->x86.eflags); |
1196 | 123k | MI->flat_insn->detail->x86.operands[0].access = access[0]; |
1197 | 123k | MI->flat_insn->detail->x86.operands[1].access = access[1]; |
1198 | 123k | #endif |
1199 | 123k | } |
1200 | 123k | } |
1201 | | |
1202 | | #endif |