1 //===-- X86IntelInstPrinter.cpp - Intel 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 Intel-style
11 // assembly.
12 //
13 //===----------------------------------------------------------------------===//
14
15 /* Capstone Disassembly Engine */
16 /* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2014 */
17
18 #ifdef CAPSTONE_HAS_X86
19
20 #if !defined(CAPSTONE_HAS_OSXKERNEL)
21 #include <ctype.h>
22 #endif
23 #include <platform.h>
24 #if defined(CAPSTONE_HAS_OSXKERNEL)
25 #include <libkern/libkern.h>
26 #else
27 #include <stdio.h>
28 #include <stdlib.h>
29 #endif
30 #include <string.h>
31
32 #include "../../utils.h"
33 #include "../../MCInst.h"
34 #include "../../SStream.h"
35 #include "../../MCRegisterInfo.h"
36
37 #include "X86Mapping.h"
38
39 #define GET_INSTRINFO_ENUM
40 #ifdef CAPSTONE_X86_REDUCE
41 #include "X86GenInstrInfo_reduce.inc"
42 #else
43 #include "X86GenInstrInfo.inc"
44 #endif
45
46 #include "X86BaseInfo.h"
47
48 static void printMemReference(MCInst *MI, unsigned Op, SStream *O);
49 static void printOperand(MCInst *MI, unsigned OpNo, SStream *O);
50
51
set_mem_access(MCInst * MI,bool status)52 static void set_mem_access(MCInst *MI, bool status)
53 {
54 if (MI->csh->detail != CS_OPT_ON)
55 return;
56
57 MI->csh->doing_mem = status;
58 if (!status)
59 // done, create the next operand slot
60 MI->flat_insn->detail->x86.op_count++;
61
62 }
63
printopaquemem(MCInst * MI,unsigned OpNo,SStream * O)64 static void printopaquemem(MCInst *MI, unsigned OpNo, SStream *O)
65 {
66 SStream_concat0(O, "ptr ");
67
68 switch(MI->csh->mode) {
69 case CS_MODE_16:
70 if (MI->flat_insn->id == X86_INS_LJMP || MI->flat_insn->id == X86_INS_LCALL)
71 MI->x86opsize = 4;
72 else
73 MI->x86opsize = 2;
74 break;
75 case CS_MODE_32:
76 if (MI->flat_insn->id == X86_INS_LJMP || MI->flat_insn->id == X86_INS_LCALL)
77 MI->x86opsize = 6;
78 else
79 MI->x86opsize = 4;
80 break;
81 case CS_MODE_64:
82 if (MI->flat_insn->id == X86_INS_LJMP || MI->flat_insn->id == X86_INS_LCALL)
83 MI->x86opsize = 10;
84 else
85 MI->x86opsize = 8;
86 break;
87 default: // never reach
88 break;
89 }
90
91 printMemReference(MI, OpNo, O);
92 }
93
printi8mem(MCInst * MI,unsigned OpNo,SStream * O)94 static void printi8mem(MCInst *MI, unsigned OpNo, SStream *O)
95 {
96 SStream_concat0(O, "byte ptr ");
97 MI->x86opsize = 1;
98 printMemReference(MI, OpNo, O);
99 }
100
printi16mem(MCInst * MI,unsigned OpNo,SStream * O)101 static void printi16mem(MCInst *MI, unsigned OpNo, SStream *O)
102 {
103 MI->x86opsize = 2;
104 SStream_concat0(O, "word ptr ");
105 printMemReference(MI, OpNo, O);
106 }
107
printi32mem(MCInst * MI,unsigned OpNo,SStream * O)108 static void printi32mem(MCInst *MI, unsigned OpNo, SStream *O)
109 {
110 MI->x86opsize = 4;
111 SStream_concat0(O, "dword ptr ");
112 printMemReference(MI, OpNo, O);
113 }
114
printi64mem(MCInst * MI,unsigned OpNo,SStream * O)115 static void printi64mem(MCInst *MI, unsigned OpNo, SStream *O)
116 {
117 SStream_concat0(O, "qword ptr ");
118 MI->x86opsize = 8;
119 printMemReference(MI, OpNo, O);
120 }
121
printi128mem(MCInst * MI,unsigned OpNo,SStream * O)122 static void printi128mem(MCInst *MI, unsigned OpNo, SStream *O)
123 {
124 SStream_concat0(O, "xmmword ptr ");
125 MI->x86opsize = 16;
126 printMemReference(MI, OpNo, O);
127 }
128
129 #ifndef CAPSTONE_X86_REDUCE
printi256mem(MCInst * MI,unsigned OpNo,SStream * O)130 static void printi256mem(MCInst *MI, unsigned OpNo, SStream *O)
131 {
132 SStream_concat0(O, "ymmword ptr ");
133 MI->x86opsize = 32;
134 printMemReference(MI, OpNo, O);
135 }
136
printi512mem(MCInst * MI,unsigned OpNo,SStream * O)137 static void printi512mem(MCInst *MI, unsigned OpNo, SStream *O)
138 {
139 SStream_concat0(O, "zmmword ptr ");
140 MI->x86opsize = 64;
141 printMemReference(MI, OpNo, O);
142 }
143
printf32mem(MCInst * MI,unsigned OpNo,SStream * O)144 static void printf32mem(MCInst *MI, unsigned OpNo, SStream *O)
145 {
146 SStream_concat0(O, "dword ptr ");
147 MI->x86opsize = 4;
148 printMemReference(MI, OpNo, O);
149 }
150
printf64mem(MCInst * MI,unsigned OpNo,SStream * O)151 static void printf64mem(MCInst *MI, unsigned OpNo, SStream *O)
152 {
153 SStream_concat0(O, "qword ptr ");
154 MI->x86opsize = 8;
155 printMemReference(MI, OpNo, O);
156 }
157
printf80mem(MCInst * MI,unsigned OpNo,SStream * O)158 static void printf80mem(MCInst *MI, unsigned OpNo, SStream *O)
159 {
160 SStream_concat0(O, "xword ptr ");
161 MI->x86opsize = 10;
162 printMemReference(MI, OpNo, O);
163 }
164
printf128mem(MCInst * MI,unsigned OpNo,SStream * O)165 static void printf128mem(MCInst *MI, unsigned OpNo, SStream *O)
166 {
167 SStream_concat0(O, "xmmword ptr ");
168 MI->x86opsize = 16;
169 printMemReference(MI, OpNo, O);
170 }
171
printf256mem(MCInst * MI,unsigned OpNo,SStream * O)172 static void printf256mem(MCInst *MI, unsigned OpNo, SStream *O)
173 {
174 SStream_concat0(O, "ymmword ptr ");
175 MI->x86opsize = 32;
176 printMemReference(MI, OpNo, O);
177 }
178
printf512mem(MCInst * MI,unsigned OpNo,SStream * O)179 static void printf512mem(MCInst *MI, unsigned OpNo, SStream *O)
180 {
181 SStream_concat0(O, "zmmword ptr ");
182 MI->x86opsize = 64;
183 printMemReference(MI, OpNo, O);
184 }
185
printSSECC(MCInst * MI,unsigned Op,SStream * OS)186 static void printSSECC(MCInst *MI, unsigned Op, SStream *OS)
187 {
188 int64_t Imm = MCOperand_getImm(MCInst_getOperand(MI, Op)) & 7;
189 switch (Imm) {
190 default: break; // never reach
191 case 0: SStream_concat0(OS, "eq"); op_addSseCC(MI, X86_SSE_CC_EQ); break;
192 case 1: SStream_concat0(OS, "lt"); op_addSseCC(MI, X86_SSE_CC_LT); break;
193 case 2: SStream_concat0(OS, "le"); op_addSseCC(MI, X86_SSE_CC_LE); break;
194 case 3: SStream_concat0(OS, "unord"); op_addSseCC(MI, X86_SSE_CC_UNORD); break;
195 case 4: SStream_concat0(OS, "neq"); op_addSseCC(MI, X86_SSE_CC_NEQ); break;
196 case 5: SStream_concat0(OS, "nlt"); op_addSseCC(MI, X86_SSE_CC_NLT); break;
197 case 6: SStream_concat0(OS, "nle"); op_addSseCC(MI, X86_SSE_CC_NLE); break;
198 case 7: SStream_concat0(OS, "ord"); op_addSseCC(MI, X86_SSE_CC_ORD); break;
199 case 8: SStream_concat0(OS, "eq_uq"); op_addSseCC(MI, X86_SSE_CC_EQ_UQ); break;
200 case 9: SStream_concat0(OS, "nge"); op_addSseCC(MI, X86_SSE_CC_NGE); break;
201 case 0xa: SStream_concat0(OS, "ngt"); op_addSseCC(MI, X86_SSE_CC_NGT); break;
202 case 0xb: SStream_concat0(OS, "false"); op_addSseCC(MI, X86_SSE_CC_FALSE); break;
203 case 0xc: SStream_concat0(OS, "neq_oq"); op_addSseCC(MI, X86_SSE_CC_NEQ_OQ); break;
204 case 0xd: SStream_concat0(OS, "ge"); op_addSseCC(MI, X86_SSE_CC_GE); break;
205 case 0xe: SStream_concat0(OS, "gt"); op_addSseCC(MI, X86_SSE_CC_GT); break;
206 case 0xf: SStream_concat0(OS, "true"); op_addSseCC(MI, X86_SSE_CC_TRUE); break;
207 }
208 }
209
printAVXCC(MCInst * MI,unsigned Op,SStream * O)210 static void printAVXCC(MCInst *MI, unsigned Op, SStream *O)
211 {
212 int64_t Imm = MCOperand_getImm(MCInst_getOperand(MI, Op)) & 0x1f;
213 switch (Imm) {
214 default: break;//printf("Invalid avxcc argument!\n"); break;
215 case 0: SStream_concat0(O, "eq"); op_addAvxCC(MI, X86_AVX_CC_EQ); break;
216 case 1: SStream_concat0(O, "lt"); op_addAvxCC(MI, X86_AVX_CC_LT); break;
217 case 2: SStream_concat0(O, "le"); op_addAvxCC(MI, X86_AVX_CC_LE); break;
218 case 3: SStream_concat0(O, "unord"); op_addAvxCC(MI, X86_AVX_CC_UNORD); break;
219 case 4: SStream_concat0(O, "neq"); op_addAvxCC(MI, X86_AVX_CC_NEQ); break;
220 case 5: SStream_concat0(O, "nlt"); op_addAvxCC(MI, X86_AVX_CC_NLT); break;
221 case 6: SStream_concat0(O, "nle"); op_addAvxCC(MI, X86_AVX_CC_NLE); break;
222 case 7: SStream_concat0(O, "ord"); op_addAvxCC(MI, X86_AVX_CC_ORD); break;
223 case 8: SStream_concat0(O, "eq_uq"); op_addAvxCC(MI, X86_AVX_CC_EQ_UQ); break;
224 case 9: SStream_concat0(O, "nge"); op_addAvxCC(MI, X86_AVX_CC_NGE); break;
225 case 0xa: SStream_concat0(O, "ngt"); op_addAvxCC(MI, X86_AVX_CC_NGT); break;
226 case 0xb: SStream_concat0(O, "false"); op_addAvxCC(MI, X86_AVX_CC_FALSE); break;
227 case 0xc: SStream_concat0(O, "neq_oq"); op_addAvxCC(MI, X86_AVX_CC_NEQ_OQ); break;
228 case 0xd: SStream_concat0(O, "ge"); op_addAvxCC(MI, X86_AVX_CC_GE); break;
229 case 0xe: SStream_concat0(O, "gt"); op_addAvxCC(MI, X86_AVX_CC_GT); break;
230 case 0xf: SStream_concat0(O, "true"); op_addAvxCC(MI, X86_AVX_CC_TRUE); break;
231 case 0x10: SStream_concat0(O, "eq_os"); op_addAvxCC(MI, X86_AVX_CC_EQ_OS); break;
232 case 0x11: SStream_concat0(O, "lt_oq"); op_addAvxCC(MI, X86_AVX_CC_LT_OQ); break;
233 case 0x12: SStream_concat0(O, "le_oq"); op_addAvxCC(MI, X86_AVX_CC_LE_OQ); break;
234 case 0x13: SStream_concat0(O, "unord_s"); op_addAvxCC(MI, X86_AVX_CC_UNORD_S); break;
235 case 0x14: SStream_concat0(O, "neq_us"); op_addAvxCC(MI, X86_AVX_CC_NEQ_US); break;
236 case 0x15: SStream_concat0(O, "nlt_uq"); op_addAvxCC(MI, X86_AVX_CC_NLT_UQ); break;
237 case 0x16: SStream_concat0(O, "nle_uq"); op_addAvxCC(MI, X86_AVX_CC_NLE_UQ); break;
238 case 0x17: SStream_concat0(O, "ord_s"); op_addAvxCC(MI, X86_AVX_CC_ORD_S); break;
239 case 0x18: SStream_concat0(O, "eq_us"); op_addAvxCC(MI, X86_AVX_CC_EQ_US); break;
240 case 0x19: SStream_concat0(O, "nge_uq"); op_addAvxCC(MI, X86_AVX_CC_NGE_UQ); break;
241 case 0x1a: SStream_concat0(O, "ngt_uq"); op_addAvxCC(MI, X86_AVX_CC_NGT_UQ); break;
242 case 0x1b: SStream_concat0(O, "false_os"); op_addAvxCC(MI, X86_AVX_CC_FALSE_OS); break;
243 case 0x1c: SStream_concat0(O, "neq_os"); op_addAvxCC(MI, X86_AVX_CC_NEQ_OS); break;
244 case 0x1d: SStream_concat0(O, "ge_oq"); op_addAvxCC(MI, X86_AVX_CC_GE_OQ); break;
245 case 0x1e: SStream_concat0(O, "gt_oq"); op_addAvxCC(MI, X86_AVX_CC_GT_OQ); break;
246 case 0x1f: SStream_concat0(O, "true_us"); op_addAvxCC(MI, X86_AVX_CC_TRUE_US); break;
247 }
248 }
249
printRoundingControl(MCInst * MI,unsigned Op,SStream * O)250 static void printRoundingControl(MCInst *MI, unsigned Op, SStream *O)
251 {
252 int64_t Imm = MCOperand_getImm(MCInst_getOperand(MI, Op)) & 0x3;
253 switch (Imm) {
254 case 0: SStream_concat0(O, "{rn-sae}"); op_addAvxSae(MI); op_addAvxRoundingMode(MI, X86_AVX_RM_RN); break;
255 case 1: SStream_concat0(O, "{rd-sae}"); op_addAvxSae(MI); op_addAvxRoundingMode(MI, X86_AVX_RM_RD); break;
256 case 2: SStream_concat0(O, "{ru-sae}"); op_addAvxSae(MI); op_addAvxRoundingMode(MI, X86_AVX_RM_RU); break;
257 case 3: SStream_concat0(O, "{rz-sae}"); op_addAvxSae(MI); op_addAvxRoundingMode(MI, X86_AVX_RM_RZ); break;
258 default: break; // never reach
259 }
260 }
261
262 #endif
263
264 static char *getRegisterName(unsigned RegNo);
printRegName(SStream * OS,unsigned RegNo)265 static void printRegName(SStream *OS, unsigned RegNo)
266 {
267 SStream_concat0(OS, getRegisterName(RegNo));
268 }
269
270 // local printOperand, without updating public operands
_printOperand(MCInst * MI,unsigned OpNo,SStream * O)271 static void _printOperand(MCInst *MI, unsigned OpNo, SStream *O)
272 {
273 MCOperand *Op = MCInst_getOperand(MI, OpNo);
274 if (MCOperand_isReg(Op)) {
275 printRegName(O, MCOperand_getReg(Op));
276 } else if (MCOperand_isImm(Op)) {
277 int64_t imm = MCOperand_getImm(Op);
278 if (imm < 0) {
279 if (imm < -HEX_THRESHOLD)
280 SStream_concat(O, "-0x%"PRIx64, -imm);
281 else
282 SStream_concat(O, "-%"PRIu64, -imm);
283
284 } else {
285 if (imm > HEX_THRESHOLD)
286 SStream_concat(O, "0x%"PRIx64, imm);
287 else
288 SStream_concat(O, "%"PRIu64, imm);
289 }
290 }
291 }
292
printSrcIdx(MCInst * MI,unsigned Op,SStream * O)293 static void printSrcIdx(MCInst *MI, unsigned Op, SStream *O)
294 {
295 MCOperand *SegReg;
296 int reg;
297
298 if (MI->csh->detail) {
299 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].type = X86_OP_MEM;
300 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].size = MI->x86opsize;
301 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.segment = X86_REG_INVALID;
302 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.base = X86_REG_INVALID;
303 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.index = X86_REG_INVALID;
304 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.scale = 1;
305 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.disp = 0;
306 }
307
308 SegReg = MCInst_getOperand(MI, Op+1);
309 reg = MCOperand_getReg(SegReg);
310
311 // If this has a segment register, print it.
312 if (reg) {
313 _printOperand(MI, Op+1, O);
314 if (MI->csh->detail) {
315 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.segment = reg;
316 }
317 SStream_concat0(O, ":");
318 }
319
320 SStream_concat0(O, "[");
321 set_mem_access(MI, true);
322 printOperand(MI, Op, O);
323 SStream_concat0(O, "]");
324 set_mem_access(MI, false);
325 }
326
printDstIdx(MCInst * MI,unsigned Op,SStream * O)327 static void printDstIdx(MCInst *MI, unsigned Op, SStream *O)
328 {
329 if (MI->csh->detail) {
330 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].type = X86_OP_MEM;
331 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].size = MI->x86opsize;
332 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.segment = X86_REG_INVALID;
333 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.base = X86_REG_INVALID;
334 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.index = X86_REG_INVALID;
335 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.scale = 1;
336 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.disp = 0;
337 }
338
339 // DI accesses are always ES-based on non-64bit mode
340 if (MI->csh->mode != CS_MODE_64) {
341 SStream_concat(O, "es:[");
342 if (MI->csh->detail) {
343 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.segment = X86_REG_ES;
344 }
345 } else
346 SStream_concat(O, "[");
347
348 set_mem_access(MI, true);
349 printOperand(MI, Op, O);
350 SStream_concat0(O, "]");
351 set_mem_access(MI, false);
352 }
353
printSrcIdx8(MCInst * MI,unsigned OpNo,SStream * O)354 void printSrcIdx8(MCInst *MI, unsigned OpNo, SStream *O)
355 {
356 SStream_concat0(O, "byte ptr ");
357 MI->x86opsize = 1;
358 printSrcIdx(MI, OpNo, O);
359 }
360
printSrcIdx16(MCInst * MI,unsigned OpNo,SStream * O)361 void printSrcIdx16(MCInst *MI, unsigned OpNo, SStream *O)
362 {
363 SStream_concat0(O, "word ptr ");
364 MI->x86opsize = 2;
365 printSrcIdx(MI, OpNo, O);
366 }
367
printSrcIdx32(MCInst * MI,unsigned OpNo,SStream * O)368 void printSrcIdx32(MCInst *MI, unsigned OpNo, SStream *O)
369 {
370 SStream_concat0(O, "dword ptr ");
371 MI->x86opsize = 4;
372 printSrcIdx(MI, OpNo, O);
373 }
374
printSrcIdx64(MCInst * MI,unsigned OpNo,SStream * O)375 void printSrcIdx64(MCInst *MI, unsigned OpNo, SStream *O)
376 {
377 SStream_concat0(O, "qword ptr ");
378 MI->x86opsize = 8;
379 printSrcIdx(MI, OpNo, O);
380 }
381
printDstIdx8(MCInst * MI,unsigned OpNo,SStream * O)382 void printDstIdx8(MCInst *MI, unsigned OpNo, SStream *O)
383 {
384 SStream_concat0(O, "byte ptr ");
385 MI->x86opsize = 1;
386 printDstIdx(MI, OpNo, O);
387 }
388
printDstIdx16(MCInst * MI,unsigned OpNo,SStream * O)389 void printDstIdx16(MCInst *MI, unsigned OpNo, SStream *O)
390 {
391 SStream_concat0(O, "word ptr ");
392 MI->x86opsize = 2;
393 printDstIdx(MI, OpNo, O);
394 }
395
printDstIdx32(MCInst * MI,unsigned OpNo,SStream * O)396 void printDstIdx32(MCInst *MI, unsigned OpNo, SStream *O)
397 {
398 SStream_concat0(O, "dword ptr ");
399 MI->x86opsize = 4;
400 printDstIdx(MI, OpNo, O);
401 }
402
printDstIdx64(MCInst * MI,unsigned OpNo,SStream * O)403 void printDstIdx64(MCInst *MI, unsigned OpNo, SStream *O)
404 {
405 SStream_concat0(O, "qword ptr ");
406 MI->x86opsize = 8;
407 printDstIdx(MI, OpNo, O);
408 }
409
printMemOffset(MCInst * MI,unsigned Op,SStream * O)410 static void printMemOffset(MCInst *MI, unsigned Op, SStream *O)
411 {
412 MCOperand *DispSpec = MCInst_getOperand(MI, Op);
413 MCOperand *SegReg = MCInst_getOperand(MI, Op + 1);
414 int reg;
415
416 if (MI->csh->detail) {
417 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].type = X86_OP_MEM;
418 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].size = MI->x86opsize;
419 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.segment = X86_REG_INVALID;
420 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.base = X86_REG_INVALID;
421 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.index = X86_REG_INVALID;
422 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.scale = 1;
423 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.disp = 0;
424 }
425
426 // If this has a segment register, print it.
427 reg = MCOperand_getReg(SegReg);
428 if (reg) {
429 _printOperand(MI, Op + 1, O);
430 SStream_concat0(O, ":");
431 if (MI->csh->detail) {
432 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.segment = reg;
433 }
434 }
435
436 SStream_concat0(O, "[");
437
438 if (MCOperand_isImm(DispSpec)) {
439 int64_t imm = MCOperand_getImm(DispSpec);
440 if (MI->csh->detail)
441 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.disp = imm;
442 if (imm < 0) {
443 SStream_concat(O, "0x%"PRIx64, arch_masks[MI->csh->mode] & imm);
444 } else {
445 if (imm > HEX_THRESHOLD)
446 SStream_concat(O, "0x%"PRIx64, imm);
447 else
448 SStream_concat(O, "%"PRIu64, imm);
449 }
450 }
451
452 SStream_concat0(O, "]");
453
454 if (MI->csh->detail)
455 MI->flat_insn->detail->x86.op_count++;
456
457 if (MI->op1_size == 0)
458 MI->op1_size = MI->x86opsize;
459 }
460
printMemOffs8(MCInst * MI,unsigned OpNo,SStream * O)461 static void printMemOffs8(MCInst *MI, unsigned OpNo, SStream *O)
462 {
463 SStream_concat0(O, "byte ptr ");
464 MI->x86opsize = 1;
465 printMemOffset(MI, OpNo, O);
466 }
467
printMemOffs16(MCInst * MI,unsigned OpNo,SStream * O)468 static void printMemOffs16(MCInst *MI, unsigned OpNo, SStream *O)
469 {
470 SStream_concat0(O, "word ptr ");
471 MI->x86opsize = 2;
472 printMemOffset(MI, OpNo, O);
473 }
474
printMemOffs32(MCInst * MI,unsigned OpNo,SStream * O)475 static void printMemOffs32(MCInst *MI, unsigned OpNo, SStream *O)
476 {
477 SStream_concat0(O, "dword ptr ");
478 MI->x86opsize = 4;
479 printMemOffset(MI, OpNo, O);
480 }
481
printMemOffs64(MCInst * MI,unsigned OpNo,SStream * O)482 static void printMemOffs64(MCInst *MI, unsigned OpNo, SStream *O)
483 {
484 SStream_concat0(O, "qword ptr ");
485 MI->x86opsize = 8;
486 printMemOffset(MI, OpNo, O);
487 }
488
489 #ifndef CAPSTONE_DIET
490 static char *printAliasInstr(MCInst *MI, SStream *OS, void *info);
491 #endif
492 static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI);
493
X86_Intel_printInst(MCInst * MI,SStream * O,void * Info)494 void X86_Intel_printInst(MCInst *MI, SStream *O, void *Info)
495 {
496 x86_reg reg, reg2;
497 #ifndef CAPSTONE_DIET
498 char *mnem;
499
500 // Try to print any aliases first.
501 mnem = printAliasInstr(MI, O, Info);
502 if (mnem)
503 cs_mem_free(mnem);
504 else
505 #endif
506 printInstruction(MI, O, Info);
507
508 reg = X86_insn_reg_intel(MCInst_getOpcode(MI));
509 if (MI->csh->detail) {
510 // first op can be embedded in the asm by llvm.
511 // so we have to add the missing register as the first operand
512 if (reg) {
513 // shift all the ops right to leave 1st slot for this new register op
514 memmove(&(MI->flat_insn->detail->x86.operands[1]), &(MI->flat_insn->detail->x86.operands[0]),
515 sizeof(MI->flat_insn->detail->x86.operands[0]) * (ARR_SIZE(MI->flat_insn->detail->x86.operands) - 1));
516 MI->flat_insn->detail->x86.operands[0].type = X86_OP_REG;
517 MI->flat_insn->detail->x86.operands[0].reg = reg;
518 MI->flat_insn->detail->x86.operands[0].size = MI->csh->regsize_map[reg];
519 MI->flat_insn->detail->x86.operands[1].size = MI->csh->regsize_map[reg];
520 MI->flat_insn->detail->x86.op_count++;
521 } else {
522 if (X86_insn_reg_intel2(MCInst_getOpcode(MI), ®, ®2)) {
523 MI->flat_insn->detail->x86.operands[0].type = X86_OP_REG;
524 MI->flat_insn->detail->x86.operands[0].reg = reg;
525 MI->flat_insn->detail->x86.operands[0].size = MI->csh->regsize_map[reg];
526 MI->flat_insn->detail->x86.operands[1].type = X86_OP_REG;
527 MI->flat_insn->detail->x86.operands[1].reg = reg2;
528 MI->flat_insn->detail->x86.operands[1].size = MI->csh->regsize_map[reg2];
529 MI->flat_insn->detail->x86.op_count = 2;
530 }
531 }
532 }
533
534 if (MI->op1_size == 0 && reg)
535 MI->op1_size = MI->csh->regsize_map[reg];
536 }
537
538 /// printPCRelImm - This is used to print an immediate value that ends up
539 /// being encoded as a pc-relative value.
printPCRelImm(MCInst * MI,unsigned OpNo,SStream * O)540 static void printPCRelImm(MCInst *MI, unsigned OpNo, SStream *O)
541 {
542 MCOperand *Op = MCInst_getOperand(MI, OpNo);
543 if (MCOperand_isImm(Op)) {
544 int64_t imm = MCOperand_getImm(Op) + MI->flat_insn->size + MI->address;
545
546 // truncat imm for non-64bit
547 if (MI->csh->mode != CS_MODE_64) {
548 imm = imm & 0xffffffff;
549 }
550
551 if (MI->csh->mode == CS_MODE_16 &&
552 (MI->Opcode != X86_JMP_4 && MI->Opcode != X86_CALLpcrel32))
553 imm = imm & 0xffff;
554
555 // Hack: X86 16bit with opcode X86_JMP_4
556 if (MI->csh->mode == CS_MODE_16 &&
557 (MI->Opcode == X86_JMP_4 && MI->x86_prefix[2] != 0x66))
558 imm = imm & 0xffff;
559
560 // CALL/JMP rel16 is special
561 if (MI->Opcode == X86_CALLpcrel16 || MI->Opcode == X86_JMP_2)
562 imm = imm & 0xffff;
563
564 if (imm < 0) {
565 SStream_concat(O, "0x%"PRIx64, imm);
566 } else {
567 if (imm > HEX_THRESHOLD)
568 SStream_concat(O, "0x%"PRIx64, imm);
569 else
570 SStream_concat(O, "%"PRIu64, imm);
571 }
572 if (MI->csh->detail) {
573 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].type = X86_OP_IMM;
574 // if op_count > 0, then this operand's size is taken from the destination op
575 if (MI->flat_insn->detail->x86.op_count > 0)
576 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].size = MI->flat_insn->detail->x86.operands[0].size;
577 else
578 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].size = MI->imm_size;
579 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].imm = imm;
580 MI->flat_insn->detail->x86.op_count++;
581 }
582
583 if (MI->op1_size == 0)
584 MI->op1_size = MI->imm_size;
585 }
586 }
587
printOperand(MCInst * MI,unsigned OpNo,SStream * O)588 static void printOperand(MCInst *MI, unsigned OpNo, SStream *O)
589 {
590 uint8_t opsize = 0;
591 MCOperand *Op = MCInst_getOperand(MI, OpNo);
592
593 if (MCOperand_isReg(Op)) {
594 unsigned int reg = MCOperand_getReg(Op);
595
596 printRegName(O, reg);
597 if (MI->csh->detail) {
598 if (MI->csh->doing_mem) {
599 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.base = reg;
600 } else {
601 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].type = X86_OP_REG;
602 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].reg = reg;
603 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].size = MI->csh->regsize_map[reg];
604 MI->flat_insn->detail->x86.op_count++;
605 }
606 }
607
608 if (MI->op1_size == 0)
609 MI->op1_size = MI->csh->regsize_map[reg];
610 } else if (MCOperand_isImm(Op)) {
611 int64_t imm = MCOperand_getImm(Op);
612
613 switch(MCInst_getOpcode(MI)) {
614 default:
615 break;
616
617 case X86_AAD8i8:
618 case X86_AAM8i8:
619 case X86_ADC8i8:
620 case X86_ADD8i8:
621 case X86_AND8i8:
622 case X86_CMP8i8:
623 case X86_OR8i8:
624 case X86_SBB8i8:
625 case X86_SUB8i8:
626 case X86_TEST8i8:
627 case X86_XOR8i8:
628 case X86_ROL8ri:
629 case X86_ADC8ri:
630 case X86_ADD8ri:
631 case X86_ADD8ri8:
632 case X86_AND8ri:
633 case X86_AND8ri8:
634 case X86_CMP8ri:
635 case X86_MOV8ri:
636 case X86_MOV8ri_alt:
637 case X86_OR8ri:
638 case X86_OR8ri8:
639 case X86_RCL8ri:
640 case X86_RCR8ri:
641 case X86_ROR8ri:
642 case X86_SAL8ri:
643 case X86_SAR8ri:
644 case X86_SBB8ri:
645 case X86_SHL8ri:
646 case X86_SHR8ri:
647 case X86_SUB8ri:
648 case X86_SUB8ri8:
649 case X86_TEST8ri:
650 case X86_TEST8ri_NOREX:
651 case X86_TEST8ri_alt:
652 case X86_XOR8ri:
653 case X86_XOR8ri8:
654 case X86_OUT8ir:
655
656 case X86_ADC8mi:
657 case X86_ADD8mi:
658 case X86_AND8mi:
659 case X86_CMP8mi:
660 case X86_LOCK_ADD8mi:
661 case X86_LOCK_AND8mi:
662 case X86_LOCK_OR8mi:
663 case X86_LOCK_SUB8mi:
664 case X86_LOCK_XOR8mi:
665 case X86_MOV8mi:
666 case X86_OR8mi:
667 case X86_RCL8mi:
668 case X86_RCR8mi:
669 case X86_ROL8mi:
670 case X86_ROR8mi:
671 case X86_SAL8mi:
672 case X86_SAR8mi:
673 case X86_SBB8mi:
674 case X86_SHL8mi:
675 case X86_SHR8mi:
676 case X86_SUB8mi:
677 case X86_TEST8mi:
678 case X86_TEST8mi_alt:
679 case X86_XOR8mi:
680 case X86_PUSH64i8:
681 case X86_CMP32ri8:
682 case X86_CMP64ri8:
683
684 imm = imm & 0xff;
685 opsize = 1; // immediate of 1 byte
686 break;
687 }
688
689 switch(MI->flat_insn->id) {
690 default:
691 if (imm >= 0) {
692 if (imm > HEX_THRESHOLD)
693 SStream_concat(O, "0x%"PRIx64, imm);
694 else
695 SStream_concat(O, "%"PRIu64, imm);
696 } else {
697 if (imm < -HEX_THRESHOLD)
698 SStream_concat(O, "-0x%"PRIx64, -imm);
699 else
700 SStream_concat(O, "-%"PRIu64, -imm);
701 }
702
703 break;
704
705 case X86_INS_LCALL:
706 case X86_INS_LJMP:
707 // always print address in positive form
708 if (OpNo == 1) { // selector is ptr16
709 imm = imm & 0xffff;
710 opsize = 2;
711 }
712 if (imm > HEX_THRESHOLD)
713 SStream_concat(O, "0x%"PRIx64, imm);
714 else
715 SStream_concat(O, "%"PRIu64, imm);
716 break;
717
718 case X86_INS_AND:
719 case X86_INS_OR:
720 case X86_INS_XOR:
721 // do not print number in negative form
722 if (imm >= 0 && imm <= HEX_THRESHOLD)
723 SStream_concat(O, "%u", imm);
724 else {
725 imm = arch_masks[MI->op1_size? MI->op1_size : MI->imm_size] & imm;
726 SStream_concat(O, "0x%"PRIx64, imm);
727 }
728 break;
729 case X86_INS_RET:
730 // RET imm16
731 if (imm >= 0 && imm <= HEX_THRESHOLD)
732 SStream_concat(O, "%u", imm);
733 else {
734 imm = 0xffff & imm;
735 SStream_concat(O, "0x%x", 0xffff & imm);
736 }
737 break;
738 }
739
740 if (MI->csh->detail) {
741 if (MI->csh->doing_mem) {
742 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.disp = imm;
743 } else {
744 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].type = X86_OP_IMM;
745 if (opsize > 0)
746 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].size = opsize;
747 else if (MI->flat_insn->detail->x86.op_count > 0) {
748 if (MI->flat_insn->id != X86_INS_LCALL && MI->flat_insn->id != X86_INS_LJMP) {
749 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].size =
750 MI->flat_insn->detail->x86.operands[0].size;
751 } else
752 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].size = MI->imm_size;
753 } else
754 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].size = MI->imm_size;
755
756 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].imm = imm;
757 MI->flat_insn->detail->x86.op_count++;
758 }
759 }
760
761 //if (MI->op1_size == 0)
762 // MI->op1_size = MI->imm_size;
763 }
764 }
765
printMemReference(MCInst * MI,unsigned Op,SStream * O)766 static void printMemReference(MCInst *MI, unsigned Op, SStream *O)
767 {
768 bool NeedPlus = false;
769 MCOperand *BaseReg = MCInst_getOperand(MI, Op + X86_AddrBaseReg);
770 uint64_t ScaleVal = MCOperand_getImm(MCInst_getOperand(MI, Op + X86_AddrScaleAmt));
771 MCOperand *IndexReg = MCInst_getOperand(MI, Op + X86_AddrIndexReg);
772 MCOperand *DispSpec = MCInst_getOperand(MI, Op + X86_AddrDisp);
773 MCOperand *SegReg = MCInst_getOperand(MI, Op + X86_AddrSegmentReg);
774 int reg;
775
776 if (MI->csh->detail) {
777 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].type = X86_OP_MEM;
778 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].size = MI->x86opsize;
779 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.segment = X86_REG_INVALID;
780 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.base = MCOperand_getReg(BaseReg);
781 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.index = MCOperand_getReg(IndexReg);
782 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.scale = (int)ScaleVal;
783 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.disp = 0;
784 }
785
786 // If this has a segment register, print it.
787 reg = MCOperand_getReg(SegReg);
788 if (reg) {
789 _printOperand(MI, Op + X86_AddrSegmentReg, O);
790 if (MI->csh->detail) {
791 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.segment = reg;
792 }
793 SStream_concat0(O, ":");
794 }
795
796 SStream_concat0(O, "[");
797
798 if (MCOperand_getReg(BaseReg)) {
799 _printOperand(MI, Op + X86_AddrBaseReg, O);
800 NeedPlus = true;
801 }
802
803 if (MCOperand_getReg(IndexReg)) {
804 if (NeedPlus) SStream_concat0(O, " + ");
805 _printOperand(MI, Op + X86_AddrIndexReg, O);
806 if (ScaleVal != 1)
807 SStream_concat(O, "*%u", ScaleVal);
808 NeedPlus = true;
809 }
810
811 if (MCOperand_isImm(DispSpec)) {
812 int64_t DispVal = MCOperand_getImm(DispSpec);
813 if (MI->csh->detail)
814 MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.disp = DispVal;
815 if (DispVal) {
816 if (NeedPlus) {
817 if (DispVal < 0) {
818 if (DispVal < -HEX_THRESHOLD)
819 SStream_concat(O, " - 0x%"PRIx64, -DispVal);
820 else
821 SStream_concat(O, " - %"PRIu64, -DispVal);
822 } else {
823 if (DispVal > HEX_THRESHOLD)
824 SStream_concat(O, " + 0x%"PRIx64, DispVal);
825 else
826 SStream_concat(O, " + %"PRIu64, DispVal);
827 }
828 } else {
829 // memory reference to an immediate address
830 if (DispVal < 0) {
831 SStream_concat(O, "0x%"PRIx64, arch_masks[MI->csh->mode] & DispVal);
832 } else {
833 if (DispVal > HEX_THRESHOLD)
834 SStream_concat(O, "0x%"PRIx64, DispVal);
835 else
836 SStream_concat(O, "%"PRIu64, DispVal);
837 }
838 }
839
840 } else {
841 // DispVal = 0
842 if (!NeedPlus) // [0]
843 SStream_concat0(O, "0");
844 }
845 }
846
847 SStream_concat0(O, "]");
848
849 if (MI->csh->detail)
850 MI->flat_insn->detail->x86.op_count++;
851
852 if (MI->op1_size == 0)
853 MI->op1_size = MI->x86opsize;
854 }
855
856 #define GET_REGINFO_ENUM
857 #include "X86GenRegisterInfo.inc"
858
859 #define PRINT_ALIAS_INSTR
860 #ifdef CAPSTONE_X86_REDUCE
861 #include "X86GenAsmWriter1_reduce.inc"
862 #else
863 #include "X86GenAsmWriter1.inc"
864 #endif
865
866 #endif
867