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