• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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), &reg, &reg2)) {
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