Home | History | Annotate | Download | only in X86
      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 (at) 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 
     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 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 
     83 static void printi8mem(MCInst *MI, unsigned OpNo, SStream *O)
     84 {
     85 	MI->x86opsize = 1;
     86 	printMemReference(MI, OpNo, O);
     87 }
     88 
     89 static void printi16mem(MCInst *MI, unsigned OpNo, SStream *O)
     90 {
     91 	MI->x86opsize = 2;
     92 
     93 	printMemReference(MI, OpNo, O);
     94 }
     95 
     96 static void printi32mem(MCInst *MI, unsigned OpNo, SStream *O)
     97 {
     98 	MI->x86opsize = 4;
     99 
    100 	printMemReference(MI, OpNo, O);
    101 }
    102 
    103 static void printi64mem(MCInst *MI, unsigned OpNo, SStream *O)
    104 {
    105 	MI->x86opsize = 8;
    106 	printMemReference(MI, OpNo, O);
    107 }
    108 
    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
    116 static void printi256mem(MCInst *MI, unsigned OpNo, SStream *O)
    117 {
    118 	MI->x86opsize = 32;
    119 	printMemReference(MI, OpNo, O);
    120 }
    121 
    122 static void printi512mem(MCInst *MI, unsigned OpNo, SStream *O)
    123 {
    124 	MI->x86opsize = 64;
    125 	printMemReference(MI, OpNo, O);
    126 }
    127 
    128 static void printf32mem(MCInst *MI, unsigned OpNo, SStream *O)
    129 {
    130 	MI->x86opsize = 4;
    131 	printMemReference(MI, OpNo, O);
    132 }
    133 
    134 static void printf64mem(MCInst *MI, unsigned OpNo, SStream *O)
    135 {
    136 	MI->x86opsize = 8;
    137 	printMemReference(MI, OpNo, O);
    138 }
    139 
    140 static void printf80mem(MCInst *MI, unsigned OpNo, SStream *O)
    141 {
    142 	MI->x86opsize = 10;
    143 	printMemReference(MI, OpNo, O);
    144 }
    145 
    146 static void printf128mem(MCInst *MI, unsigned OpNo, SStream *O)
    147 {
    148 	MI->x86opsize = 16;
    149 	printMemReference(MI, OpNo, O);
    150 }
    151 
    152 static void printf256mem(MCInst *MI, unsigned OpNo, SStream *O)
    153 {
    154 	MI->x86opsize = 32;
    155 	printMemReference(MI, OpNo, O);
    156 }
    157 
    158 static void printf512mem(MCInst *MI, unsigned OpNo, SStream *O)
    159 {
    160 	MI->x86opsize = 64;
    161 	printMemReference(MI, OpNo, O);
    162 }
    163 
    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 
    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 
    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
    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 
    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 
    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 
    333 static void printSrcIdx8(MCInst *MI, unsigned OpNo, SStream *O)
    334 {
    335 	MI->x86opsize = 1;
    336 	printSrcIdx(MI, OpNo, O);
    337 }
    338 
    339 static void printSrcIdx16(MCInst *MI, unsigned OpNo, SStream *O)
    340 {
    341 	MI->x86opsize = 2;
    342 	printSrcIdx(MI, OpNo, O);
    343 }
    344 
    345 static void printSrcIdx32(MCInst *MI, unsigned OpNo, SStream *O)
    346 {
    347 	MI->x86opsize = 4;
    348 	printSrcIdx(MI, OpNo, O);
    349 }
    350 
    351 static void printSrcIdx64(MCInst *MI, unsigned OpNo, SStream *O)
    352 {
    353 	MI->x86opsize = 8;
    354 	printSrcIdx(MI, OpNo, O);
    355 }
    356 
    357 static void printDstIdx8(MCInst *MI, unsigned OpNo, SStream *O)
    358 {
    359 	MI->x86opsize = 1;
    360 	printDstIdx(MI, OpNo, O);
    361 }
    362 
    363 static void printDstIdx16(MCInst *MI, unsigned OpNo, SStream *O)
    364 {
    365 	MI->x86opsize = 2;
    366 	printDstIdx(MI, OpNo, O);
    367 }
    368 
    369 static void printDstIdx32(MCInst *MI, unsigned OpNo, SStream *O)
    370 {
    371 	MI->x86opsize = 4;
    372 	printDstIdx(MI, OpNo, O);
    373 }
    374 
    375 static void printDstIdx64(MCInst *MI, unsigned OpNo, SStream *O)
    376 {
    377 	MI->x86opsize = 8;
    378 	printDstIdx(MI, OpNo, O);
    379 }
    380 
    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 
    425 static void printMemOffs8(MCInst *MI, unsigned OpNo, SStream *O)
    426 {
    427 	MI->x86opsize = 1;
    428 	printMemOffset(MI, OpNo, O);
    429 }
    430 
    431 static void printMemOffs16(MCInst *MI, unsigned OpNo, SStream *O)
    432 {
    433 	MI->x86opsize = 2;
    434 	printMemOffset(MI, OpNo, O);
    435 }
    436 
    437 static void printMemOffs32(MCInst *MI, unsigned OpNo, SStream *O)
    438 {
    439 	MI->x86opsize = 4;
    440 	printMemOffset(MI, OpNo, O);
    441 }
    442 
    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.
    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 
    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 
    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 
    772 static void printRegName(SStream *OS, unsigned RegNo)
    773 {
    774 	SStream_concat(OS, "%%%s", getRegisterName(RegNo));
    775 }
    776 
    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), &reg, &reg2)) {
    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