/src/capstonenext/arch/X86/X86ATTInstPrinter.c
Line | Count | Source (jump to first uncovered line) |
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 | 149k | { |
67 | 149k | if (MI->csh->detail_opt != CS_OPT_ON) |
68 | 0 | return; |
69 | | |
70 | 149k | MI->csh->doing_mem = status; |
71 | 149k | if (!status) |
72 | | // done, create the next operand slot |
73 | 74.8k | MI->flat_insn->detail->x86.op_count++; |
74 | 149k | } |
75 | | |
76 | | static void printopaquemem(MCInst *MI, unsigned OpNo, SStream *O) |
77 | 13.0k | { |
78 | 13.0k | switch (MI->csh->mode) { |
79 | 4.28k | case CS_MODE_16: |
80 | 4.28k | switch (MI->flat_insn->id) { |
81 | 1.47k | default: |
82 | 1.47k | MI->x86opsize = 2; |
83 | 1.47k | break; |
84 | 559 | case X86_INS_LJMP: |
85 | 1.02k | case X86_INS_LCALL: |
86 | 1.02k | MI->x86opsize = 4; |
87 | 1.02k | break; |
88 | 568 | case X86_INS_SGDT: |
89 | 1.02k | case X86_INS_SIDT: |
90 | 1.37k | case X86_INS_LGDT: |
91 | 1.78k | case X86_INS_LIDT: |
92 | 1.78k | MI->x86opsize = 6; |
93 | 1.78k | break; |
94 | 4.28k | } |
95 | 4.28k | break; |
96 | 4.73k | case CS_MODE_32: |
97 | 4.73k | switch (MI->flat_insn->id) { |
98 | 1.26k | default: |
99 | 1.26k | MI->x86opsize = 4; |
100 | 1.26k | break; |
101 | 294 | case X86_INS_LJMP: |
102 | 1.20k | case X86_INS_JMP: |
103 | 1.59k | case X86_INS_LCALL: |
104 | 2.06k | case X86_INS_SGDT: |
105 | 2.53k | case X86_INS_SIDT: |
106 | 2.95k | case X86_INS_LGDT: |
107 | 3.47k | case X86_INS_LIDT: |
108 | 3.47k | MI->x86opsize = 6; |
109 | 3.47k | break; |
110 | 4.73k | } |
111 | 4.73k | break; |
112 | 4.73k | case CS_MODE_64: |
113 | 4.07k | switch (MI->flat_insn->id) { |
114 | 944 | default: |
115 | 944 | MI->x86opsize = 8; |
116 | 944 | break; |
117 | 866 | case X86_INS_LJMP: |
118 | 1.37k | case X86_INS_LCALL: |
119 | 1.83k | case X86_INS_SGDT: |
120 | 2.39k | case X86_INS_SIDT: |
121 | 2.69k | case X86_INS_LGDT: |
122 | 3.12k | case X86_INS_LIDT: |
123 | 3.12k | MI->x86opsize = 10; |
124 | 3.12k | break; |
125 | 4.07k | } |
126 | 4.07k | break; |
127 | 4.07k | default: // never reach |
128 | 0 | break; |
129 | 13.0k | } |
130 | | |
131 | 13.0k | printMemReference(MI, OpNo, O); |
132 | 13.0k | } |
133 | | |
134 | | static void printi8mem(MCInst *MI, unsigned OpNo, SStream *O) |
135 | 105k | { |
136 | 105k | MI->x86opsize = 1; |
137 | 105k | printMemReference(MI, OpNo, O); |
138 | 105k | } |
139 | | |
140 | | static void printi16mem(MCInst *MI, unsigned OpNo, SStream *O) |
141 | 37.1k | { |
142 | 37.1k | MI->x86opsize = 2; |
143 | | |
144 | 37.1k | printMemReference(MI, OpNo, O); |
145 | 37.1k | } |
146 | | |
147 | | static void printi32mem(MCInst *MI, unsigned OpNo, SStream *O) |
148 | 46.7k | { |
149 | 46.7k | MI->x86opsize = 4; |
150 | | |
151 | 46.7k | printMemReference(MI, OpNo, O); |
152 | 46.7k | } |
153 | | |
154 | | static void printi64mem(MCInst *MI, unsigned OpNo, SStream *O) |
155 | 20.3k | { |
156 | 20.3k | MI->x86opsize = 8; |
157 | 20.3k | printMemReference(MI, OpNo, O); |
158 | 20.3k | } |
159 | | |
160 | | static void printi128mem(MCInst *MI, unsigned OpNo, SStream *O) |
161 | 8.39k | { |
162 | 8.39k | MI->x86opsize = 16; |
163 | 8.39k | printMemReference(MI, OpNo, O); |
164 | 8.39k | } |
165 | | |
166 | | static void printi512mem(MCInst *MI, unsigned OpNo, SStream *O) |
167 | 5.01k | { |
168 | 5.01k | MI->x86opsize = 64; |
169 | 5.01k | printMemReference(MI, OpNo, O); |
170 | 5.01k | } |
171 | | |
172 | | #ifndef CAPSTONE_X86_REDUCE |
173 | | static void printi256mem(MCInst *MI, unsigned OpNo, SStream *O) |
174 | 4.88k | { |
175 | 4.88k | MI->x86opsize = 32; |
176 | 4.88k | printMemReference(MI, OpNo, O); |
177 | 4.88k | } |
178 | | |
179 | | static void printf32mem(MCInst *MI, unsigned OpNo, SStream *O) |
180 | 10.5k | { |
181 | 10.5k | switch (MCInst_getOpcode(MI)) { |
182 | 8.05k | default: |
183 | 8.05k | MI->x86opsize = 4; |
184 | 8.05k | break; |
185 | 960 | case X86_FSTENVm: |
186 | 2.47k | case X86_FLDENVm: |
187 | | // TODO: fix this in tablegen instead |
188 | 2.47k | switch (MI->csh->mode) { |
189 | 0 | default: // never reach |
190 | 0 | break; |
191 | 997 | case CS_MODE_16: |
192 | 997 | MI->x86opsize = 14; |
193 | 997 | break; |
194 | 543 | case CS_MODE_32: |
195 | 1.47k | case CS_MODE_64: |
196 | 1.47k | MI->x86opsize = 28; |
197 | 1.47k | break; |
198 | 2.47k | } |
199 | 2.47k | break; |
200 | 10.5k | } |
201 | | |
202 | 10.5k | printMemReference(MI, OpNo, O); |
203 | 10.5k | } |
204 | | |
205 | | static void printf64mem(MCInst *MI, unsigned OpNo, SStream *O) |
206 | 6.71k | { |
207 | 6.71k | MI->x86opsize = 8; |
208 | 6.71k | printMemReference(MI, OpNo, O); |
209 | 6.71k | } |
210 | | |
211 | | static void printf80mem(MCInst *MI, unsigned OpNo, SStream *O) |
212 | 640 | { |
213 | 640 | MI->x86opsize = 10; |
214 | 640 | printMemReference(MI, OpNo, O); |
215 | 640 | } |
216 | | |
217 | | static void printf128mem(MCInst *MI, unsigned OpNo, SStream *O) |
218 | 6.34k | { |
219 | 6.34k | MI->x86opsize = 16; |
220 | 6.34k | printMemReference(MI, OpNo, O); |
221 | 6.34k | } |
222 | | |
223 | | static void printf256mem(MCInst *MI, unsigned OpNo, SStream *O) |
224 | 5.60k | { |
225 | 5.60k | MI->x86opsize = 32; |
226 | 5.60k | printMemReference(MI, OpNo, O); |
227 | 5.60k | } |
228 | | |
229 | | static void printf512mem(MCInst *MI, unsigned OpNo, SStream *O) |
230 | 3.92k | { |
231 | 3.92k | MI->x86opsize = 64; |
232 | 3.92k | printMemReference(MI, OpNo, O); |
233 | 3.92k | } |
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 | 380k | { |
242 | 380k | MCOperand *Op = MCInst_getOperand(MI, OpNo); |
243 | 380k | if (MCOperand_isReg(Op)) { |
244 | 380k | printRegName(O, MCOperand_getReg(Op)); |
245 | 380k | } 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 | 380k | } |
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 | 846k | { |
290 | 846k | uint8_t count, i; |
291 | 846k | const uint8_t *arr = X86_get_op_access(h, id, eflags); |
292 | | |
293 | | // initialize access |
294 | 846k | memset(access, 0, CS_X86_MAXIMUM_OPERAND_SIZE * sizeof(access[0])); |
295 | 846k | if (!arr) { |
296 | 0 | return; |
297 | 0 | } |
298 | | |
299 | | // find the non-zero last entry |
300 | 2.47M | for (count = 0; arr[count]; count++) |
301 | 1.62M | ; |
302 | | |
303 | 846k | if (count == 0) |
304 | 53.4k | return; |
305 | | |
306 | | // copy in reverse order this access array from Intel syntax -> AT&T syntax |
307 | 792k | count--; |
308 | 2.41M | for (i = 0; i <= count && ((count - i) < CS_X86_MAXIMUM_OPERAND_SIZE) && |
309 | 2.41M | i < CS_X86_MAXIMUM_OPERAND_SIZE; |
310 | 1.62M | i++) { |
311 | 1.62M | if (arr[count - i] != CS_AC_IGNORE) |
312 | 1.39M | access[i] = arr[count - i]; |
313 | 224k | else |
314 | 224k | access[i] = 0; |
315 | 1.62M | } |
316 | 792k | } |
317 | | |
318 | | static void printSrcIdx(MCInst *MI, unsigned Op, SStream *O) |
319 | 32.9k | { |
320 | 32.9k | MCOperand *SegReg; |
321 | 32.9k | int reg; |
322 | | |
323 | 32.9k | if (MI->csh->detail_opt) { |
324 | 32.9k | uint8_t access[CS_X86_MAXIMUM_OPERAND_SIZE]; |
325 | | |
326 | 32.9k | MI->flat_insn->detail->x86 |
327 | 32.9k | .operands[MI->flat_insn->detail->x86.op_count] |
328 | 32.9k | .type = X86_OP_MEM; |
329 | 32.9k | MI->flat_insn->detail->x86 |
330 | 32.9k | .operands[MI->flat_insn->detail->x86.op_count] |
331 | 32.9k | .size = MI->x86opsize; |
332 | 32.9k | MI->flat_insn->detail->x86 |
333 | 32.9k | .operands[MI->flat_insn->detail->x86.op_count] |
334 | 32.9k | .mem.segment = X86_REG_INVALID; |
335 | 32.9k | MI->flat_insn->detail->x86 |
336 | 32.9k | .operands[MI->flat_insn->detail->x86.op_count] |
337 | 32.9k | .mem.base = X86_REG_INVALID; |
338 | 32.9k | MI->flat_insn->detail->x86 |
339 | 32.9k | .operands[MI->flat_insn->detail->x86.op_count] |
340 | 32.9k | .mem.index = X86_REG_INVALID; |
341 | 32.9k | MI->flat_insn->detail->x86 |
342 | 32.9k | .operands[MI->flat_insn->detail->x86.op_count] |
343 | 32.9k | .mem.scale = 1; |
344 | 32.9k | MI->flat_insn->detail->x86 |
345 | 32.9k | .operands[MI->flat_insn->detail->x86.op_count] |
346 | 32.9k | .mem.disp = 0; |
347 | | |
348 | 32.9k | get_op_access(MI->csh, MCInst_getOpcode(MI), access, |
349 | 32.9k | &MI->flat_insn->detail->x86.eflags); |
350 | 32.9k | MI->flat_insn->detail->x86 |
351 | 32.9k | .operands[MI->flat_insn->detail->x86.op_count] |
352 | 32.9k | .access = access[MI->flat_insn->detail->x86.op_count]; |
353 | 32.9k | } |
354 | | |
355 | 32.9k | SegReg = MCInst_getOperand(MI, Op + 1); |
356 | 32.9k | reg = MCOperand_getReg(SegReg); |
357 | | // If this has a segment register, print it. |
358 | 32.9k | if (reg) { |
359 | 861 | _printOperand(MI, Op + 1, O); |
360 | 861 | SStream_concat0(O, ":"); |
361 | | |
362 | 861 | if (MI->csh->detail_opt) { |
363 | 861 | MI->flat_insn->detail->x86 |
364 | 861 | .operands[MI->flat_insn->detail->x86.op_count] |
365 | 861 | .mem.segment = X86_register_map(reg); |
366 | 861 | } |
367 | 861 | } |
368 | | |
369 | 32.9k | SStream_concat0(O, "("); |
370 | 32.9k | set_mem_access(MI, true); |
371 | | |
372 | 32.9k | printOperand(MI, Op, O); |
373 | | |
374 | 32.9k | SStream_concat0(O, ")"); |
375 | 32.9k | set_mem_access(MI, false); |
376 | 32.9k | } |
377 | | |
378 | | static void printDstIdx(MCInst *MI, unsigned Op, SStream *O) |
379 | 41.8k | { |
380 | 41.8k | if (MI->csh->detail_opt) { |
381 | 41.8k | uint8_t access[CS_X86_MAXIMUM_OPERAND_SIZE]; |
382 | | |
383 | 41.8k | MI->flat_insn->detail->x86 |
384 | 41.8k | .operands[MI->flat_insn->detail->x86.op_count] |
385 | 41.8k | .type = X86_OP_MEM; |
386 | 41.8k | MI->flat_insn->detail->x86 |
387 | 41.8k | .operands[MI->flat_insn->detail->x86.op_count] |
388 | 41.8k | .size = MI->x86opsize; |
389 | 41.8k | MI->flat_insn->detail->x86 |
390 | 41.8k | .operands[MI->flat_insn->detail->x86.op_count] |
391 | 41.8k | .mem.segment = X86_REG_INVALID; |
392 | 41.8k | MI->flat_insn->detail->x86 |
393 | 41.8k | .operands[MI->flat_insn->detail->x86.op_count] |
394 | 41.8k | .mem.base = X86_REG_INVALID; |
395 | 41.8k | MI->flat_insn->detail->x86 |
396 | 41.8k | .operands[MI->flat_insn->detail->x86.op_count] |
397 | 41.8k | .mem.index = X86_REG_INVALID; |
398 | 41.8k | MI->flat_insn->detail->x86 |
399 | 41.8k | .operands[MI->flat_insn->detail->x86.op_count] |
400 | 41.8k | .mem.scale = 1; |
401 | 41.8k | MI->flat_insn->detail->x86 |
402 | 41.8k | .operands[MI->flat_insn->detail->x86.op_count] |
403 | 41.8k | .mem.disp = 0; |
404 | | |
405 | 41.8k | get_op_access(MI->csh, MCInst_getOpcode(MI), access, |
406 | 41.8k | &MI->flat_insn->detail->x86.eflags); |
407 | 41.8k | MI->flat_insn->detail->x86 |
408 | 41.8k | .operands[MI->flat_insn->detail->x86.op_count] |
409 | 41.8k | .access = access[MI->flat_insn->detail->x86.op_count]; |
410 | 41.8k | } |
411 | | |
412 | | // DI accesses are always ES-based on non-64bit mode |
413 | 41.8k | if (MI->csh->mode != CS_MODE_64) { |
414 | 24.2k | SStream_concat0(O, "%es:("); |
415 | 24.2k | if (MI->csh->detail_opt) { |
416 | 24.2k | MI->flat_insn->detail->x86 |
417 | 24.2k | .operands[MI->flat_insn->detail->x86.op_count] |
418 | 24.2k | .mem.segment = X86_REG_ES; |
419 | 24.2k | } |
420 | 24.2k | } else |
421 | 17.6k | SStream_concat0(O, "("); |
422 | | |
423 | 41.8k | set_mem_access(MI, true); |
424 | | |
425 | 41.8k | printOperand(MI, Op, O); |
426 | | |
427 | 41.8k | SStream_concat0(O, ")"); |
428 | 41.8k | set_mem_access(MI, false); |
429 | 41.8k | } |
430 | | |
431 | | static void printSrcIdx8(MCInst *MI, unsigned OpNo, SStream *O) |
432 | 9.88k | { |
433 | 9.88k | MI->x86opsize = 1; |
434 | 9.88k | printSrcIdx(MI, OpNo, O); |
435 | 9.88k | } |
436 | | |
437 | | static void printSrcIdx16(MCInst *MI, unsigned OpNo, SStream *O) |
438 | 8.18k | { |
439 | 8.18k | MI->x86opsize = 2; |
440 | 8.18k | printSrcIdx(MI, OpNo, O); |
441 | 8.18k | } |
442 | | |
443 | | static void printSrcIdx32(MCInst *MI, unsigned OpNo, SStream *O) |
444 | 10.1k | { |
445 | 10.1k | MI->x86opsize = 4; |
446 | 10.1k | printSrcIdx(MI, OpNo, O); |
447 | 10.1k | } |
448 | | |
449 | | static void printSrcIdx64(MCInst *MI, unsigned OpNo, SStream *O) |
450 | 4.74k | { |
451 | 4.74k | MI->x86opsize = 8; |
452 | 4.74k | printSrcIdx(MI, OpNo, O); |
453 | 4.74k | } |
454 | | |
455 | | static void printDstIdx8(MCInst *MI, unsigned OpNo, SStream *O) |
456 | 15.3k | { |
457 | 15.3k | MI->x86opsize = 1; |
458 | 15.3k | printDstIdx(MI, OpNo, O); |
459 | 15.3k | } |
460 | | |
461 | | static void printDstIdx16(MCInst *MI, unsigned OpNo, SStream *O) |
462 | 10.6k | { |
463 | 10.6k | MI->x86opsize = 2; |
464 | 10.6k | printDstIdx(MI, OpNo, O); |
465 | 10.6k | } |
466 | | |
467 | | static void printDstIdx32(MCInst *MI, unsigned OpNo, SStream *O) |
468 | 10.7k | { |
469 | 10.7k | MI->x86opsize = 4; |
470 | 10.7k | printDstIdx(MI, OpNo, O); |
471 | 10.7k | } |
472 | | |
473 | | static void printDstIdx64(MCInst *MI, unsigned OpNo, SStream *O) |
474 | 5.18k | { |
475 | 5.18k | MI->x86opsize = 8; |
476 | 5.18k | printDstIdx(MI, OpNo, O); |
477 | 5.18k | } |
478 | | |
479 | | static void printMemOffset(MCInst *MI, unsigned Op, SStream *O) |
480 | 8.59k | { |
481 | 8.59k | MCOperand *DispSpec = MCInst_getOperand(MI, Op); |
482 | 8.59k | MCOperand *SegReg = MCInst_getOperand(MI, Op + 1); |
483 | 8.59k | int reg; |
484 | | |
485 | 8.59k | if (MI->csh->detail_opt) { |
486 | 8.59k | uint8_t access[CS_X86_MAXIMUM_OPERAND_SIZE]; |
487 | | |
488 | 8.59k | MI->flat_insn->detail->x86 |
489 | 8.59k | .operands[MI->flat_insn->detail->x86.op_count] |
490 | 8.59k | .type = X86_OP_MEM; |
491 | 8.59k | MI->flat_insn->detail->x86 |
492 | 8.59k | .operands[MI->flat_insn->detail->x86.op_count] |
493 | 8.59k | .size = MI->x86opsize; |
494 | 8.59k | MI->flat_insn->detail->x86 |
495 | 8.59k | .operands[MI->flat_insn->detail->x86.op_count] |
496 | 8.59k | .mem.segment = X86_REG_INVALID; |
497 | 8.59k | MI->flat_insn->detail->x86 |
498 | 8.59k | .operands[MI->flat_insn->detail->x86.op_count] |
499 | 8.59k | .mem.base = X86_REG_INVALID; |
500 | 8.59k | MI->flat_insn->detail->x86 |
501 | 8.59k | .operands[MI->flat_insn->detail->x86.op_count] |
502 | 8.59k | .mem.index = X86_REG_INVALID; |
503 | 8.59k | MI->flat_insn->detail->x86 |
504 | 8.59k | .operands[MI->flat_insn->detail->x86.op_count] |
505 | 8.59k | .mem.scale = 1; |
506 | 8.59k | MI->flat_insn->detail->x86 |
507 | 8.59k | .operands[MI->flat_insn->detail->x86.op_count] |
508 | 8.59k | .mem.disp = 0; |
509 | | |
510 | 8.59k | get_op_access(MI->csh, MCInst_getOpcode(MI), access, |
511 | 8.59k | &MI->flat_insn->detail->x86.eflags); |
512 | 8.59k | MI->flat_insn->detail->x86 |
513 | 8.59k | .operands[MI->flat_insn->detail->x86.op_count] |
514 | 8.59k | .access = access[MI->flat_insn->detail->x86.op_count]; |
515 | 8.59k | } |
516 | | |
517 | | // If this has a segment register, print it. |
518 | 8.59k | reg = MCOperand_getReg(SegReg); |
519 | 8.59k | if (reg) { |
520 | 666 | _printOperand(MI, Op + 1, O); |
521 | 666 | SStream_concat0(O, ":"); |
522 | | |
523 | 666 | if (MI->csh->detail_opt) { |
524 | 666 | MI->flat_insn->detail->x86 |
525 | 666 | .operands[MI->flat_insn->detail->x86.op_count] |
526 | 666 | .mem.segment = X86_register_map(reg); |
527 | 666 | } |
528 | 666 | } |
529 | | |
530 | 8.59k | if (MCOperand_isImm(DispSpec)) { |
531 | 8.59k | int64_t imm = MCOperand_getImm(DispSpec); |
532 | 8.59k | if (MI->csh->detail_opt) |
533 | 8.59k | MI->flat_insn->detail->x86 |
534 | 8.59k | .operands[MI->flat_insn->detail->x86.op_count] |
535 | 8.59k | .mem.disp = imm; |
536 | 8.59k | if (imm < 0) { |
537 | 1.81k | SStream_concat(O, "0x%" PRIx64, |
538 | 1.81k | arch_masks[MI->csh->mode] & imm); |
539 | 6.78k | } else { |
540 | 6.78k | if (imm > HEX_THRESHOLD) |
541 | 6.36k | SStream_concat(O, "0x%" PRIx64, imm); |
542 | 419 | else |
543 | 419 | SStream_concat(O, "%" PRIu64, imm); |
544 | 6.78k | } |
545 | 8.59k | } |
546 | | |
547 | 8.59k | if (MI->csh->detail_opt) |
548 | 8.59k | MI->flat_insn->detail->x86.op_count++; |
549 | 8.59k | } |
550 | | |
551 | | static void printU8Imm(MCInst *MI, unsigned Op, SStream *O) |
552 | 50.6k | { |
553 | 50.6k | uint8_t val = MCOperand_getImm(MCInst_getOperand(MI, Op)) & 0xff; |
554 | | |
555 | 50.6k | if (val > HEX_THRESHOLD) |
556 | 45.9k | SStream_concat(O, "$0x%x", val); |
557 | 4.66k | else |
558 | 4.66k | SStream_concat(O, "$%u", val); |
559 | | |
560 | 50.6k | if (MI->csh->detail_opt) { |
561 | 50.6k | MI->flat_insn->detail->x86 |
562 | 50.6k | .operands[MI->flat_insn->detail->x86.op_count] |
563 | 50.6k | .type = X86_OP_IMM; |
564 | 50.6k | MI->flat_insn->detail->x86 |
565 | 50.6k | .operands[MI->flat_insn->detail->x86.op_count] |
566 | 50.6k | .imm = val; |
567 | 50.6k | MI->flat_insn->detail->x86 |
568 | 50.6k | .operands[MI->flat_insn->detail->x86.op_count] |
569 | 50.6k | .size = 1; |
570 | 50.6k | MI->flat_insn->detail->x86.op_count++; |
571 | 50.6k | } |
572 | 50.6k | } |
573 | | |
574 | | static void printMemOffs8(MCInst *MI, unsigned OpNo, SStream *O) |
575 | 4.77k | { |
576 | 4.77k | MI->x86opsize = 1; |
577 | 4.77k | printMemOffset(MI, OpNo, O); |
578 | 4.77k | } |
579 | | |
580 | | static void printMemOffs16(MCInst *MI, unsigned OpNo, SStream *O) |
581 | 1.06k | { |
582 | 1.06k | MI->x86opsize = 2; |
583 | 1.06k | printMemOffset(MI, OpNo, O); |
584 | 1.06k | } |
585 | | |
586 | | static void printMemOffs32(MCInst *MI, unsigned OpNo, SStream *O) |
587 | 2.27k | { |
588 | 2.27k | MI->x86opsize = 4; |
589 | 2.27k | printMemOffset(MI, OpNo, O); |
590 | 2.27k | } |
591 | | |
592 | | static void printMemOffs64(MCInst *MI, unsigned OpNo, SStream *O) |
593 | 479 | { |
594 | 479 | MI->x86opsize = 8; |
595 | 479 | printMemOffset(MI, OpNo, O); |
596 | 479 | } |
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 | 38.3k | { |
604 | 38.3k | MCOperand *Op = MCInst_getOperand(MI, OpNo); |
605 | 38.3k | if (MCOperand_isImm(Op)) { |
606 | 38.3k | int64_t imm = MCOperand_getImm(Op) + MI->flat_insn->size + |
607 | 38.3k | MI->address; |
608 | | |
609 | | // truncate imm for non-64bit |
610 | 38.3k | if (MI->csh->mode != CS_MODE_64) { |
611 | 24.4k | imm = imm & 0xffffffff; |
612 | 24.4k | } |
613 | | |
614 | 38.3k | if (imm < 0) { |
615 | 1.49k | SStream_concat(O, "0x%" PRIx64, imm); |
616 | 36.8k | } else { |
617 | 36.8k | if (imm > HEX_THRESHOLD) |
618 | 36.8k | SStream_concat(O, "0x%" PRIx64, imm); |
619 | 20 | else |
620 | 20 | SStream_concat(O, "%" PRIu64, imm); |
621 | 36.8k | } |
622 | 38.3k | if (MI->csh->detail_opt) { |
623 | 38.3k | MI->flat_insn->detail->x86 |
624 | 38.3k | .operands[MI->flat_insn->detail->x86.op_count] |
625 | 38.3k | .type = X86_OP_IMM; |
626 | 38.3k | MI->has_imm = true; |
627 | 38.3k | MI->flat_insn->detail->x86 |
628 | 38.3k | .operands[MI->flat_insn->detail->x86.op_count] |
629 | 38.3k | .imm = imm; |
630 | 38.3k | MI->flat_insn->detail->x86.op_count++; |
631 | 38.3k | } |
632 | 38.3k | } |
633 | 38.3k | } |
634 | | |
635 | | static void printOperand(MCInst *MI, unsigned OpNo, SStream *O) |
636 | 365k | { |
637 | 365k | MCOperand *Op = MCInst_getOperand(MI, OpNo); |
638 | 365k | if (MCOperand_isReg(Op)) { |
639 | 326k | unsigned int reg = MCOperand_getReg(Op); |
640 | 326k | printRegName(O, reg); |
641 | 326k | if (MI->csh->detail_opt) { |
642 | 326k | if (MI->csh->doing_mem) { |
643 | 37.3k | MI->flat_insn->detail->x86 |
644 | 37.3k | .operands[MI->flat_insn->detail->x86 |
645 | 37.3k | .op_count] |
646 | 37.3k | .mem.base = X86_register_map(reg); |
647 | 288k | } else { |
648 | 288k | uint8_t access[CS_X86_MAXIMUM_OPERAND_SIZE]; |
649 | | |
650 | 288k | MI->flat_insn->detail->x86 |
651 | 288k | .operands[MI->flat_insn->detail->x86 |
652 | 288k | .op_count] |
653 | 288k | .type = X86_OP_REG; |
654 | 288k | MI->flat_insn->detail->x86 |
655 | 288k | .operands[MI->flat_insn->detail->x86 |
656 | 288k | .op_count] |
657 | 288k | .reg = X86_register_map(reg); |
658 | 288k | MI->flat_insn->detail->x86 |
659 | 288k | .operands[MI->flat_insn->detail->x86 |
660 | 288k | .op_count] |
661 | 288k | .size = |
662 | 288k | MI->csh->regsize_map[X86_register_map( |
663 | 288k | reg)]; |
664 | | |
665 | 288k | get_op_access( |
666 | 288k | MI->csh, MCInst_getOpcode(MI), access, |
667 | 288k | &MI->flat_insn->detail->x86.eflags); |
668 | 288k | MI->flat_insn->detail->x86 |
669 | 288k | .operands[MI->flat_insn->detail->x86 |
670 | 288k | .op_count] |
671 | 288k | .access = |
672 | 288k | access[MI->flat_insn->detail->x86 |
673 | 288k | .op_count]; |
674 | | |
675 | 288k | MI->flat_insn->detail->x86.op_count++; |
676 | 288k | } |
677 | 326k | } |
678 | 326k | } else if (MCOperand_isImm(Op)) { |
679 | | // Print X86 immediates as signed values. |
680 | 39.0k | uint8_t encsize; |
681 | 39.0k | int64_t imm = MCOperand_getImm(Op); |
682 | 39.0k | uint8_t opsize = |
683 | 39.0k | X86_immediate_size(MCInst_getOpcode(MI), &encsize); |
684 | | |
685 | 39.0k | if (opsize == 1) { // print 1 byte immediate in positive form |
686 | 19.2k | imm = imm & 0xff; |
687 | 19.2k | } |
688 | | |
689 | 39.0k | switch (MI->flat_insn->id) { |
690 | 16.5k | default: |
691 | 16.5k | if (imm >= 0) { |
692 | 14.8k | if (imm > HEX_THRESHOLD) |
693 | 13.2k | SStream_concat(O, "$0x%" PRIx64, imm); |
694 | 1.67k | else |
695 | 1.67k | SStream_concat(O, "$%" PRIu64, imm); |
696 | 14.8k | } else { |
697 | 1.67k | 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 | 1.67k | } else { |
716 | 1.67k | if (imm == |
717 | 1.67k | 0x8000000000000000LL) // imm == -imm |
718 | 0 | SStream_concat0( |
719 | 0 | O, |
720 | 0 | "$0x8000000000000000"); |
721 | 1.67k | else if (imm < -HEX_THRESHOLD) |
722 | 1.46k | SStream_concat(O, |
723 | 1.46k | "$-0x%" PRIx64, |
724 | 1.46k | -imm); |
725 | 216 | else |
726 | 216 | SStream_concat(O, "$-%" PRIu64, |
727 | 216 | -imm); |
728 | 1.67k | } |
729 | 1.67k | } |
730 | 16.5k | break; |
731 | | |
732 | 16.5k | case X86_INS_MOVABS: |
733 | 8.20k | case X86_INS_MOV: |
734 | | // do not print number in negative form |
735 | 8.20k | if (imm > HEX_THRESHOLD) |
736 | 7.53k | SStream_concat(O, "$0x%" PRIx64, imm); |
737 | 669 | else |
738 | 669 | SStream_concat(O, "$%" PRIu64, imm); |
739 | 8.20k | 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 | 740 | case X86_INS_LCALL: |
754 | 1.52k | case X86_INS_LJMP: |
755 | 1.52k | case X86_INS_JMP: |
756 | | // always print address in positive form |
757 | 1.52k | if (OpNo == 1) { // selector is ptr16 |
758 | 760 | imm = imm & 0xffff; |
759 | 760 | opsize = 2; |
760 | 760 | } else |
761 | 760 | opsize = 4; |
762 | 1.52k | SStream_concat(O, "$0x%" PRIx64, imm); |
763 | 1.52k | break; |
764 | | |
765 | 3.08k | case X86_INS_AND: |
766 | 5.94k | case X86_INS_OR: |
767 | 8.90k | case X86_INS_XOR: |
768 | | // do not print number in negative form |
769 | 8.90k | if (imm >= 0 && imm <= HEX_THRESHOLD) |
770 | 1.05k | SStream_concat(O, "$%u", imm); |
771 | 7.85k | else { |
772 | 7.85k | imm = arch_masks[opsize ? opsize : MI->imm_size] & |
773 | 7.85k | imm; |
774 | 7.85k | SStream_concat(O, "$0x%" PRIx64, imm); |
775 | 7.85k | } |
776 | 8.90k | break; |
777 | | |
778 | 3.03k | case X86_INS_RET: |
779 | 3.84k | case X86_INS_RETF: |
780 | | // RET imm16 |
781 | 3.84k | if (imm >= 0 && imm <= HEX_THRESHOLD) |
782 | 304 | SStream_concat(O, "$%u", imm); |
783 | 3.53k | else { |
784 | 3.53k | imm = 0xffff & imm; |
785 | 3.53k | SStream_concat(O, "$0x%x", imm); |
786 | 3.53k | } |
787 | 3.84k | break; |
788 | 39.0k | } |
789 | | |
790 | 39.0k | if (MI->csh->detail_opt) { |
791 | 39.0k | 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 | 39.0k | } else { |
801 | 39.0k | MI->flat_insn->detail->x86 |
802 | 39.0k | .operands[MI->flat_insn->detail->x86 |
803 | 39.0k | .op_count] |
804 | 39.0k | .type = X86_OP_IMM; |
805 | 39.0k | MI->has_imm = true; |
806 | 39.0k | MI->flat_insn->detail->x86 |
807 | 39.0k | .operands[MI->flat_insn->detail->x86 |
808 | 39.0k | .op_count] |
809 | 39.0k | .imm = imm; |
810 | | |
811 | 39.0k | if (opsize > 0) { |
812 | 33.7k | MI->flat_insn->detail->x86 |
813 | 33.7k | .operands[MI->flat_insn->detail |
814 | 33.7k | ->x86.op_count] |
815 | 33.7k | .size = opsize; |
816 | 33.7k | MI->flat_insn->detail->x86.encoding |
817 | 33.7k | .imm_size = encsize; |
818 | 33.7k | } 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 | 5.33k | else |
824 | 5.33k | MI->flat_insn->detail->x86 |
825 | 5.33k | .operands[MI->flat_insn->detail |
826 | 5.33k | ->x86.op_count] |
827 | 5.33k | .size = MI->imm_size; |
828 | | |
829 | 39.0k | MI->flat_insn->detail->x86.op_count++; |
830 | 39.0k | } |
831 | 39.0k | } |
832 | 39.0k | } |
833 | 365k | } |
834 | | |
835 | | static void printMemReference(MCInst *MI, unsigned Op, SStream *O) |
836 | 282k | { |
837 | 282k | MCOperand *BaseReg = MCInst_getOperand(MI, Op + X86_AddrBaseReg); |
838 | 282k | MCOperand *IndexReg = MCInst_getOperand(MI, Op + X86_AddrIndexReg); |
839 | 282k | MCOperand *DispSpec = MCInst_getOperand(MI, Op + X86_AddrDisp); |
840 | 282k | MCOperand *SegReg = MCInst_getOperand(MI, Op + X86_AddrSegmentReg); |
841 | 282k | uint64_t ScaleVal; |
842 | 282k | int segreg; |
843 | 282k | int64_t DispVal = 1; |
844 | | |
845 | 282k | if (MI->csh->detail_opt) { |
846 | 282k | uint8_t access[CS_X86_MAXIMUM_OPERAND_SIZE]; |
847 | | |
848 | 282k | MI->flat_insn->detail->x86 |
849 | 282k | .operands[MI->flat_insn->detail->x86.op_count] |
850 | 282k | .type = X86_OP_MEM; |
851 | 282k | MI->flat_insn->detail->x86 |
852 | 282k | .operands[MI->flat_insn->detail->x86.op_count] |
853 | 282k | .size = MI->x86opsize; |
854 | 282k | MI->flat_insn->detail->x86 |
855 | 282k | .operands[MI->flat_insn->detail->x86.op_count] |
856 | 282k | .mem.segment = X86_REG_INVALID; |
857 | 282k | MI->flat_insn->detail->x86 |
858 | 282k | .operands[MI->flat_insn->detail->x86.op_count] |
859 | 282k | .mem.base = X86_register_map(MCOperand_getReg(BaseReg)); |
860 | 282k | if (MCOperand_getReg(IndexReg) != X86_EIZ) { |
861 | 281k | MI->flat_insn->detail->x86 |
862 | 281k | .operands[MI->flat_insn->detail->x86.op_count] |
863 | 281k | .mem.index = |
864 | 281k | X86_register_map(MCOperand_getReg(IndexReg)); |
865 | 281k | } |
866 | 282k | MI->flat_insn->detail->x86 |
867 | 282k | .operands[MI->flat_insn->detail->x86.op_count] |
868 | 282k | .mem.scale = 1; |
869 | 282k | MI->flat_insn->detail->x86 |
870 | 282k | .operands[MI->flat_insn->detail->x86.op_count] |
871 | 282k | .mem.disp = 0; |
872 | | |
873 | 282k | get_op_access(MI->csh, MCInst_getOpcode(MI), access, |
874 | 282k | &MI->flat_insn->detail->x86.eflags); |
875 | 282k | MI->flat_insn->detail->x86 |
876 | 282k | .operands[MI->flat_insn->detail->x86.op_count] |
877 | 282k | .access = access[MI->flat_insn->detail->x86.op_count]; |
878 | 282k | } |
879 | | |
880 | | // If this has a segment register, print it. |
881 | 282k | segreg = MCOperand_getReg(SegReg); |
882 | 282k | if (segreg) { |
883 | 8.10k | _printOperand(MI, Op + X86_AddrSegmentReg, O); |
884 | 8.10k | SStream_concat0(O, ":"); |
885 | | |
886 | 8.10k | if (MI->csh->detail_opt) { |
887 | 8.10k | MI->flat_insn->detail->x86 |
888 | 8.10k | .operands[MI->flat_insn->detail->x86.op_count] |
889 | 8.10k | .mem.segment = X86_register_map(segreg); |
890 | 8.10k | } |
891 | 8.10k | } |
892 | | |
893 | 282k | if (MCOperand_isImm(DispSpec)) { |
894 | 282k | DispVal = MCOperand_getImm(DispSpec); |
895 | 282k | if (MI->csh->detail_opt) |
896 | 282k | MI->flat_insn->detail->x86 |
897 | 282k | .operands[MI->flat_insn->detail->x86.op_count] |
898 | 282k | .mem.disp = DispVal; |
899 | 282k | if (DispVal) { |
900 | 86.3k | if (MCOperand_getReg(IndexReg) || |
901 | 86.3k | MCOperand_getReg(BaseReg)) { |
902 | 82.3k | printInt64(O, DispVal); |
903 | 82.3k | } else { |
904 | | // only immediate as address of memory |
905 | 3.93k | if (DispVal < 0) { |
906 | 1.50k | SStream_concat( |
907 | 1.50k | O, "0x%" PRIx64, |
908 | 1.50k | arch_masks[MI->csh->mode] & |
909 | 1.50k | DispVal); |
910 | 2.43k | } else { |
911 | 2.43k | if (DispVal > HEX_THRESHOLD) |
912 | 1.97k | SStream_concat(O, "0x%" PRIx64, |
913 | 1.97k | DispVal); |
914 | 452 | else |
915 | 452 | SStream_concat(O, "%" PRIu64, |
916 | 452 | DispVal); |
917 | 2.43k | } |
918 | 3.93k | } |
919 | 86.3k | } |
920 | 282k | } |
921 | | |
922 | 282k | if (MCOperand_getReg(IndexReg) || MCOperand_getReg(BaseReg)) { |
923 | 278k | SStream_concat0(O, "("); |
924 | | |
925 | 278k | if (MCOperand_getReg(BaseReg)) |
926 | 277k | _printOperand(MI, Op + X86_AddrBaseReg, O); |
927 | | |
928 | 278k | if (MCOperand_getReg(IndexReg) && |
929 | 278k | MCOperand_getReg(IndexReg) != X86_EIZ) { |
930 | 93.6k | SStream_concat0(O, ", "); |
931 | 93.6k | _printOperand(MI, Op + X86_AddrIndexReg, O); |
932 | 93.6k | ScaleVal = MCOperand_getImm( |
933 | 93.6k | MCInst_getOperand(MI, Op + X86_AddrScaleAmt)); |
934 | 93.6k | if (MI->csh->detail_opt) |
935 | 93.6k | MI->flat_insn->detail->x86 |
936 | 93.6k | .operands[MI->flat_insn->detail->x86 |
937 | 93.6k | .op_count] |
938 | 93.6k | .mem.scale = (int)ScaleVal; |
939 | 93.6k | if (ScaleVal != 1) { |
940 | 9.27k | SStream_concat(O, ", %u", ScaleVal); |
941 | 9.27k | } |
942 | 93.6k | } |
943 | | |
944 | 278k | SStream_concat0(O, ")"); |
945 | 278k | } else { |
946 | 4.35k | if (!DispVal) |
947 | 428 | SStream_concat0(O, "0"); |
948 | 4.35k | } |
949 | | |
950 | 282k | if (MI->csh->detail_opt) |
951 | 282k | MI->flat_insn->detail->x86.op_count++; |
952 | 282k | } |
953 | | |
954 | | static void printanymem(MCInst *MI, unsigned OpNo, SStream *O) |
955 | 7.64k | { |
956 | 7.64k | switch (MI->Opcode) { |
957 | 296 | default: |
958 | 296 | break; |
959 | 739 | case X86_LEA16r: |
960 | 739 | MI->x86opsize = 2; |
961 | 739 | break; |
962 | 625 | case X86_LEA32r: |
963 | 1.79k | case X86_LEA64_32r: |
964 | 1.79k | MI->x86opsize = 4; |
965 | 1.79k | break; |
966 | 462 | case X86_LEA64r: |
967 | 462 | MI->x86opsize = 8; |
968 | 462 | break; |
969 | 0 | #ifndef CAPSTONE_X86_REDUCE |
970 | 406 | case X86_BNDCL32rm: |
971 | 1.07k | case X86_BNDCN32rm: |
972 | 1.58k | case X86_BNDCU32rm: |
973 | 2.31k | case X86_BNDSTXmr: |
974 | 3.14k | case X86_BNDLDXrm: |
975 | 3.54k | case X86_BNDCL64rm: |
976 | 3.96k | case X86_BNDCN64rm: |
977 | 4.35k | case X86_BNDCU64rm: |
978 | 4.35k | MI->x86opsize = 16; |
979 | 4.35k | break; |
980 | 7.64k | #endif |
981 | 7.64k | } |
982 | | |
983 | 7.64k | printMemReference(MI, OpNo, O); |
984 | 7.64k | } |
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 | 1.00M | { |
999 | 1.00M | SStream_concat(OS, "%%%s", getRegisterName(RegNo)); |
1000 | 1.00M | } |
1001 | | |
1002 | | void X86_ATT_printInst(MCInst *MI, SStream *OS, void *info) |
1003 | 700k | { |
1004 | 700k | x86_reg reg, reg2; |
1005 | 700k | enum cs_ac_type access1, access2; |
1006 | 700k | int i; |
1007 | | |
1008 | | // perhaps this instruction does not need printer |
1009 | 700k | 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 | 700k | if (MI->csh->mode == CS_MODE_64 && |
1021 | 700k | 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 | 700k | X86_lockrep(MI, OS); |
1029 | 700k | printInstruction(MI, OS); |
1030 | | |
1031 | 700k | if (MI->has_imm) { |
1032 | | // if op_count > 1, then this operand's size is taken from the destination op |
1033 | 111k | if (MI->flat_insn->detail->x86.op_count > 1) { |
1034 | 62.5k | if (MI->flat_insn->id != X86_INS_LCALL && |
1035 | 62.5k | MI->flat_insn->id != X86_INS_LJMP && |
1036 | 62.5k | MI->flat_insn->id != X86_INS_JMP) { |
1037 | 60.9k | for (i = 0; |
1038 | 184k | i < MI->flat_insn->detail->x86.op_count; |
1039 | 123k | i++) { |
1040 | 123k | if (MI->flat_insn->detail->x86 |
1041 | 123k | .operands[i] |
1042 | 123k | .type == X86_OP_IMM) |
1043 | 62.2k | MI->flat_insn->detail->x86 |
1044 | 62.2k | .operands[i] |
1045 | 62.2k | .size = |
1046 | 62.2k | MI->flat_insn->detail |
1047 | 62.2k | ->x86 |
1048 | 62.2k | .operands |
1049 | 62.2k | [MI->flat_insn |
1050 | 62.2k | ->detail |
1051 | 62.2k | ->x86 |
1052 | 62.2k | .op_count - |
1053 | 62.2k | 1] |
1054 | 62.2k | .size; |
1055 | 123k | } |
1056 | 60.9k | } |
1057 | 62.5k | } else |
1058 | 49.2k | MI->flat_insn->detail->x86.operands[0].size = |
1059 | 49.2k | MI->imm_size; |
1060 | 111k | } |
1061 | | |
1062 | 700k | if (MI->csh->detail_opt) { |
1063 | 700k | uint8_t access[CS_X86_MAXIMUM_OPERAND_SIZE] = { 0 }; |
1064 | | |
1065 | | // some instructions need to supply immediate 1 in the first op |
1066 | 700k | switch (MCInst_getOpcode(MI)) { |
1067 | 655k | default: |
1068 | 655k | break; |
1069 | 655k | case X86_SHL8r1: |
1070 | 936 | case X86_SHL16r1: |
1071 | 1.59k | case X86_SHL32r1: |
1072 | 2.11k | case X86_SHL64r1: |
1073 | 2.59k | case X86_SAL8r1: |
1074 | 3.21k | case X86_SAL16r1: |
1075 | 3.98k | case X86_SAL32r1: |
1076 | 4.65k | case X86_SAL64r1: |
1077 | 5.06k | case X86_SHR8r1: |
1078 | 5.77k | case X86_SHR16r1: |
1079 | 7.05k | case X86_SHR32r1: |
1080 | 7.88k | case X86_SHR64r1: |
1081 | 8.55k | case X86_SAR8r1: |
1082 | 9.01k | case X86_SAR16r1: |
1083 | 9.60k | case X86_SAR32r1: |
1084 | 10.8k | case X86_SAR64r1: |
1085 | 12.4k | case X86_RCL8r1: |
1086 | 13.4k | case X86_RCL16r1: |
1087 | 15.0k | case X86_RCL32r1: |
1088 | 15.9k | case X86_RCL64r1: |
1089 | 16.3k | case X86_RCR8r1: |
1090 | 17.5k | case X86_RCR16r1: |
1091 | 18.3k | case X86_RCR32r1: |
1092 | 18.8k | case X86_RCR64r1: |
1093 | 20.0k | case X86_ROL8r1: |
1094 | 20.6k | case X86_ROL16r1: |
1095 | 21.3k | case X86_ROL32r1: |
1096 | 22.1k | case X86_ROL64r1: |
1097 | 22.7k | case X86_ROR8r1: |
1098 | 23.3k | case X86_ROR16r1: |
1099 | 24.2k | case X86_ROR32r1: |
1100 | 25.0k | case X86_ROR64r1: |
1101 | 25.7k | case X86_SHL8m1: |
1102 | 26.2k | case X86_SHL16m1: |
1103 | 27.0k | case X86_SHL32m1: |
1104 | 27.6k | case X86_SHL64m1: |
1105 | 28.0k | case X86_SAL8m1: |
1106 | 28.4k | case X86_SAL16m1: |
1107 | 29.0k | case X86_SAL32m1: |
1108 | 29.5k | case X86_SAL64m1: |
1109 | 30.1k | case X86_SHR8m1: |
1110 | 30.7k | case X86_SHR16m1: |
1111 | 31.5k | case X86_SHR32m1: |
1112 | 31.8k | case X86_SHR64m1: |
1113 | 32.3k | case X86_SAR8m1: |
1114 | 32.9k | case X86_SAR16m1: |
1115 | 33.7k | case X86_SAR32m1: |
1116 | 34.5k | case X86_SAR64m1: |
1117 | 35.0k | case X86_RCL8m1: |
1118 | 35.6k | case X86_RCL16m1: |
1119 | 36.6k | case X86_RCL32m1: |
1120 | 37.5k | case X86_RCL64m1: |
1121 | 38.0k | case X86_RCR8m1: |
1122 | 38.5k | case X86_RCR16m1: |
1123 | 38.9k | case X86_RCR32m1: |
1124 | 39.3k | case X86_RCR64m1: |
1125 | 40.2k | case X86_ROL8m1: |
1126 | 40.9k | case X86_ROL16m1: |
1127 | 42.2k | case X86_ROL32m1: |
1128 | 42.7k | case X86_ROL64m1: |
1129 | 43.3k | case X86_ROR8m1: |
1130 | 43.9k | case X86_ROR16m1: |
1131 | 44.8k | case X86_ROR32m1: |
1132 | 45.5k | case X86_ROR64m1: |
1133 | | // shift all the ops right to leave 1st slot for this new register op |
1134 | 45.5k | memmove(&(MI->flat_insn->detail->x86.operands[1]), |
1135 | 45.5k | &(MI->flat_insn->detail->x86.operands[0]), |
1136 | 45.5k | sizeof(MI->flat_insn->detail->x86.operands[0]) * |
1137 | 45.5k | (ARR_SIZE(MI->flat_insn->detail->x86 |
1138 | 45.5k | .operands) - |
1139 | 45.5k | 1)); |
1140 | 45.5k | MI->flat_insn->detail->x86.operands[0].type = |
1141 | 45.5k | X86_OP_IMM; |
1142 | 45.5k | MI->flat_insn->detail->x86.operands[0].imm = 1; |
1143 | 45.5k | MI->flat_insn->detail->x86.operands[0].size = 1; |
1144 | 45.5k | MI->flat_insn->detail->x86.op_count++; |
1145 | 700k | } |
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 | 700k | reg = X86_insn_reg_att(MCInst_getOpcode(MI), &access1); |
1154 | 700k | if (reg) { |
1155 | | // shift all the ops right to leave 1st slot for this new register op |
1156 | 39.1k | memmove(&(MI->flat_insn->detail->x86.operands[1]), |
1157 | 39.1k | &(MI->flat_insn->detail->x86.operands[0]), |
1158 | 39.1k | sizeof(MI->flat_insn->detail->x86.operands[0]) * |
1159 | 39.1k | (ARR_SIZE(MI->flat_insn->detail->x86 |
1160 | 39.1k | .operands) - |
1161 | 39.1k | 1)); |
1162 | 39.1k | MI->flat_insn->detail->x86.operands[0].type = |
1163 | 39.1k | X86_OP_REG; |
1164 | 39.1k | MI->flat_insn->detail->x86.operands[0].reg = reg; |
1165 | 39.1k | MI->flat_insn->detail->x86.operands[0].size = |
1166 | 39.1k | MI->csh->regsize_map[reg]; |
1167 | 39.1k | MI->flat_insn->detail->x86.operands[0].access = access1; |
1168 | | |
1169 | 39.1k | MI->flat_insn->detail->x86.op_count++; |
1170 | 661k | } else { |
1171 | 661k | if (X86_insn_reg_att2(MCInst_getOpcode(MI), ®, |
1172 | 661k | &access1, ®2, &access2)) { |
1173 | 16.3k | MI->flat_insn->detail->x86.operands[0].type = |
1174 | 16.3k | X86_OP_REG; |
1175 | 16.3k | MI->flat_insn->detail->x86.operands[0].reg = |
1176 | 16.3k | reg; |
1177 | 16.3k | MI->flat_insn->detail->x86.operands[0].size = |
1178 | 16.3k | MI->csh->regsize_map[reg]; |
1179 | 16.3k | MI->flat_insn->detail->x86.operands[0].access = |
1180 | 16.3k | access1; |
1181 | 16.3k | MI->flat_insn->detail->x86.operands[1].type = |
1182 | 16.3k | X86_OP_REG; |
1183 | 16.3k | MI->flat_insn->detail->x86.operands[1].reg = |
1184 | 16.3k | reg2; |
1185 | 16.3k | MI->flat_insn->detail->x86.operands[1].size = |
1186 | 16.3k | MI->csh->regsize_map[reg2]; |
1187 | 16.3k | MI->flat_insn->detail->x86.operands[1].access = |
1188 | 16.3k | access2; |
1189 | 16.3k | MI->flat_insn->detail->x86.op_count = 2; |
1190 | 16.3k | } |
1191 | 661k | } |
1192 | | |
1193 | 700k | #ifndef CAPSTONE_DIET |
1194 | 700k | get_op_access(MI->csh, MCInst_getOpcode(MI), access, |
1195 | 700k | &MI->flat_insn->detail->x86.eflags); |
1196 | 700k | MI->flat_insn->detail->x86.operands[0].access = access[0]; |
1197 | 700k | MI->flat_insn->detail->x86.operands[1].access = access[1]; |
1198 | 700k | #endif |
1199 | 700k | } |
1200 | 700k | } |
1201 | | |
1202 | | #endif |