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