VirtualBox

source: vbox/trunk/src/VBox/Disassembler/DisasmFormatYasm.cpp@ 60418

Last change on this file since 60418 was 60418, checked in by vboxsync, 9 years ago

DISFormatYasmEx: Add operand size prefix (ignored) to outsb, movsb, etc.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 69.2 KB
Line 
1/* $Id: DisasmFormatYasm.cpp 60418 2016-04-11 10:40:01Z vboxsync $ */
2/** @file
3 * VBox Disassembler - Yasm(/Nasm) Style Formatter.
4 */
5
6/*
7 * Copyright (C) 2008-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#include <VBox/dis.h>
23#include "DisasmInternal.h"
24#include <iprt/string.h>
25#include <iprt/assert.h>
26#include <iprt/ctype.h>
27
28
29/*********************************************************************************************************************************
30* Global Variables *
31*********************************************************************************************************************************/
32static const char g_szSpaces[] =
33" ";
34static const char g_aszYasmRegGen8[20][5] =
35{
36 "al\0\0", "cl\0\0", "dl\0\0", "bl\0\0", "ah\0\0", "ch\0\0", "dh\0\0", "bh\0\0", "r8b\0", "r9b\0", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b", "spl\0", "bpl\0", "sil\0", "dil\0"
37};
38static const char g_aszYasmRegGen16[16][5] =
39{
40 "ax\0\0", "cx\0\0", "dx\0\0", "bx\0\0", "sp\0\0", "bp\0\0", "si\0\0", "di\0\0", "r8w\0", "r9w\0", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w"
41};
42static const char g_aszYasmRegGen1616[8][6] =
43{
44 "bx+si", "bx+di", "bp+si", "bp+di", "si\0\0\0", "di\0\0\0", "bp\0\0\0", "bx\0\0\0"
45};
46static const char g_aszYasmRegGen32[16][5] =
47{
48 "eax\0", "ecx\0", "edx\0", "ebx\0", "esp\0", "ebp\0", "esi\0", "edi\0", "r8d\0", "r9d\0", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d"
49};
50static const char g_aszYasmRegGen64[16][4] =
51{
52 "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8\0", "r9\0", "r10", "r11", "r12", "r13", "r14", "r15"
53};
54static const char g_aszYasmRegSeg[6][3] =
55{
56 "es", "cs", "ss", "ds", "fs", "gs"
57};
58static const char g_aszYasmRegFP[8][4] =
59{
60 "st0", "st1", "st2", "st3", "st4", "st5", "st6", "st7"
61};
62static const char g_aszYasmRegMMX[8][4] =
63{
64 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7"
65};
66static const char g_aszYasmRegXMM[16][6] =
67{
68 "xmm0\0", "xmm1\0", "xmm2\0", "xmm3\0", "xmm4\0", "xmm5\0", "xmm6\0", "xmm7\0", "xmm8\0", "xmm9\0", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
69};
70static const char g_aszYasmRegYMM[16][6] =
71{
72 "ymm0\0", "ymm1\0", "ymm2\0", "ymm3\0", "ymm4\0", "ymm5\0", "ymm6\0", "ymm7\0", "ymm8\0", "ymm9\0", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15"
73};
74static const char g_aszYasmRegCRx[16][5] =
75{
76 "cr0\0", "cr1\0", "cr2\0", "cr3\0", "cr4\0", "cr5\0", "cr6\0", "cr7\0", "cr8\0", "cr9\0", "cr10", "cr11", "cr12", "cr13", "cr14", "cr15"
77};
78static const char g_aszYasmRegDRx[16][5] =
79{
80 "dr0\0", "dr1\0", "dr2\0", "dr3\0", "dr4\0", "dr5\0", "dr6\0", "dr7\0", "dr8\0", "dr9\0", "dr10", "dr11", "dr12", "dr13", "dr14", "dr15"
81};
82static const char g_aszYasmRegTRx[16][5] =
83{
84 "tr0\0", "tr1\0", "tr2\0", "tr3\0", "tr4\0", "tr5\0", "tr6\0", "tr7\0", "tr8\0", "tr9\0", "tr10", "tr11", "tr12", "tr13", "tr14", "tr15"
85};
86
87
88
89/**
90 * Gets the base register name for the given parameter.
91 *
92 * @returns Pointer to the register name.
93 * @param pDis The disassembler state.
94 * @param pParam The parameter.
95 * @param pcchReg Where to store the length of the name.
96 */
97static const char *disasmFormatYasmBaseReg(PCDISSTATE pDis, PCDISOPPARAM pParam, size_t *pcchReg)
98{
99 switch (pParam->fUse & ( DISUSE_REG_GEN8 | DISUSE_REG_GEN16 | DISUSE_REG_GEN32 | DISUSE_REG_GEN64
100 | DISUSE_REG_FP | DISUSE_REG_MMX | DISUSE_REG_XMM | DISUSE_REG_YMM
101 | DISUSE_REG_CR | DISUSE_REG_DBG | DISUSE_REG_SEG | DISUSE_REG_TEST))
102
103 {
104 case DISUSE_REG_GEN8:
105 {
106 Assert(pParam->Base.idxGenReg < RT_ELEMENTS(g_aszYasmRegGen8));
107 const char *psz = g_aszYasmRegGen8[pParam->Base.idxGenReg];
108 *pcchReg = 2 + !!psz[2] + !!psz[3];
109 return psz;
110 }
111
112 case DISUSE_REG_GEN16:
113 {
114 Assert(pParam->Base.idxGenReg < RT_ELEMENTS(g_aszYasmRegGen16));
115 const char *psz = g_aszYasmRegGen16[pParam->Base.idxGenReg];
116 *pcchReg = 2 + !!psz[2] + !!psz[3];
117 return psz;
118 }
119
120 // VSIB
121 case DISUSE_REG_XMM | DISUSE_REG_GEN32:
122 case DISUSE_REG_YMM | DISUSE_REG_GEN32:
123 case DISUSE_REG_GEN32:
124 {
125 Assert(pParam->Base.idxGenReg < RT_ELEMENTS(g_aszYasmRegGen32));
126 const char *psz = g_aszYasmRegGen32[pParam->Base.idxGenReg];
127 *pcchReg = 2 + !!psz[2] + !!psz[3];
128 return psz;
129 }
130
131 // VSIB
132 case DISUSE_REG_XMM | DISUSE_REG_GEN64:
133 case DISUSE_REG_YMM | DISUSE_REG_GEN64:
134 case DISUSE_REG_GEN64:
135 {
136 Assert(pParam->Base.idxGenReg < RT_ELEMENTS(g_aszYasmRegGen64));
137 const char *psz = g_aszYasmRegGen64[pParam->Base.idxGenReg];
138 *pcchReg = 2 + !!psz[2] + !!psz[3];
139 return psz;
140 }
141
142 case DISUSE_REG_FP:
143 {
144 Assert(pParam->Base.idxFpuReg < RT_ELEMENTS(g_aszYasmRegFP));
145 const char *psz = g_aszYasmRegFP[pParam->Base.idxFpuReg];
146 *pcchReg = 3;
147 return psz;
148 }
149
150 case DISUSE_REG_MMX:
151 {
152 Assert(pParam->Base.idxMmxReg < RT_ELEMENTS(g_aszYasmRegMMX));
153 const char *psz = g_aszYasmRegMMX[pParam->Base.idxMmxReg];
154 *pcchReg = 3;
155 return psz;
156 }
157
158 case DISUSE_REG_XMM:
159 {
160 Assert(pParam->Base.idxXmmReg < RT_ELEMENTS(g_aszYasmRegXMM));
161 const char *psz = g_aszYasmRegXMM[pParam->Base.idxXmmReg];
162 *pcchReg = 4 + !!psz[4];
163 return psz;
164 }
165
166 case DISUSE_REG_YMM:
167 {
168 Assert(pParam->Base.idxYmmReg < RT_ELEMENTS(g_aszYasmRegYMM));
169 const char *psz = g_aszYasmRegYMM[pParam->Base.idxYmmReg];
170 *pcchReg = 4 + !!psz[4];
171 return psz;
172 }
173
174 case DISUSE_REG_CR:
175 {
176 Assert(pParam->Base.idxCtrlReg < RT_ELEMENTS(g_aszYasmRegCRx));
177 const char *psz = g_aszYasmRegCRx[pParam->Base.idxCtrlReg];
178 *pcchReg = 3;
179 return psz;
180 }
181
182 case DISUSE_REG_DBG:
183 {
184 Assert(pParam->Base.idxDbgReg < RT_ELEMENTS(g_aszYasmRegDRx));
185 const char *psz = g_aszYasmRegDRx[pParam->Base.idxDbgReg];
186 *pcchReg = 3;
187 return psz;
188 }
189
190 case DISUSE_REG_SEG:
191 {
192 Assert(pParam->Base.idxSegReg < RT_ELEMENTS(g_aszYasmRegCRx));
193 const char *psz = g_aszYasmRegSeg[pParam->Base.idxSegReg];
194 *pcchReg = 2;
195 return psz;
196 }
197
198 case DISUSE_REG_TEST:
199 {
200 Assert(pParam->Base.idxTestReg < RT_ELEMENTS(g_aszYasmRegTRx));
201 const char *psz = g_aszYasmRegTRx[pParam->Base.idxTestReg];
202 *pcchReg = 3;
203 return psz;
204 }
205
206 default:
207 AssertMsgFailed(("%#x\n", pParam->fUse));
208 *pcchReg = 3;
209 return "r??";
210 }
211}
212
213
214/**
215 * Gets the index register name for the given parameter.
216 *
217 * @returns The index register name.
218 * @param pDis The disassembler state.
219 * @param pParam The parameter.
220 * @param pcchReg Where to store the length of the name.
221 */
222static const char *disasmFormatYasmIndexReg(PCDISSTATE pDis, PCDISOPPARAM pParam, size_t *pcchReg)
223{
224 if (pParam->fUse & DISUSE_REG_XMM)
225 {
226 Assert(pParam->Index.idxXmmReg < RT_ELEMENTS(g_aszYasmRegXMM));
227 const char *psz = g_aszYasmRegXMM[pParam->Index.idxXmmReg];
228 *pcchReg = 4 + !!psz[4];
229 return psz;
230 }
231 else if (pParam->fUse & DISUSE_REG_YMM)
232 {
233 Assert(pParam->Index.idxYmmReg < RT_ELEMENTS(g_aszYasmRegYMM));
234 const char *psz = g_aszYasmRegYMM[pParam->Index.idxYmmReg];
235 *pcchReg = 4 + !!psz[4];
236 return psz;
237
238 }
239 else
240 switch (pDis->uAddrMode)
241 {
242 case DISCPUMODE_16BIT:
243 {
244 Assert(pParam->Index.idxGenReg < RT_ELEMENTS(g_aszYasmRegGen16));
245 const char *psz = g_aszYasmRegGen16[pParam->Index.idxGenReg];
246 *pcchReg = 2 + !!psz[2] + !!psz[3];
247 return psz;
248 }
249
250 case DISCPUMODE_32BIT:
251 {
252 Assert(pParam->Index.idxGenReg < RT_ELEMENTS(g_aszYasmRegGen32));
253 const char *psz = g_aszYasmRegGen32[pParam->Index.idxGenReg];
254 *pcchReg = 2 + !!psz[2] + !!psz[3];
255 return psz;
256 }
257
258 case DISCPUMODE_64BIT:
259 {
260 Assert(pParam->Index.idxGenReg < RT_ELEMENTS(g_aszYasmRegGen64));
261 const char *psz = g_aszYasmRegGen64[pParam->Index.idxGenReg];
262 *pcchReg = 2 + !!psz[2] + !!psz[3];
263 return psz;
264 }
265
266 default:
267 AssertMsgFailed(("%#x %#x\n", pParam->fUse, pDis->uAddrMode));
268 *pcchReg = 3;
269 return "r??";
270 }
271}
272
273
274/**
275 * Formats the current instruction in Yasm (/ Nasm) style.
276 *
277 *
278 * @returns The number of output characters. If this is >= cchBuf, then the content
279 * of pszBuf will be truncated.
280 * @param pDis Pointer to the disassembler state.
281 * @param pszBuf The output buffer.
282 * @param cchBuf The size of the output buffer.
283 * @param fFlags Format flags, see DIS_FORMAT_FLAGS_*.
284 * @param pfnGetSymbol Get symbol name for a jmp or call target address. Optional.
285 * @param pvUser User argument for pfnGetSymbol.
286 */
287DISDECL(size_t) DISFormatYasmEx(PCDISSTATE pDis, char *pszBuf, size_t cchBuf, uint32_t fFlags,
288 PFNDISGETSYMBOL pfnGetSymbol, void *pvUser)
289{
290/** @todo monitor and mwait aren't formatted correctly in 64-bit mode. */
291 /*
292 * Input validation and massaging.
293 */
294 AssertPtr(pDis);
295 AssertPtrNull(pszBuf);
296 Assert(pszBuf || !cchBuf);
297 AssertPtrNull(pfnGetSymbol);
298 AssertMsg(DIS_FMT_FLAGS_IS_VALID(fFlags), ("%#x\n", fFlags));
299 if (fFlags & DIS_FMT_FLAGS_ADDR_COMMENT)
300 fFlags = (fFlags & ~DIS_FMT_FLAGS_ADDR_LEFT) | DIS_FMT_FLAGS_ADDR_RIGHT;
301 if (fFlags & DIS_FMT_FLAGS_BYTES_COMMENT)
302 fFlags = (fFlags & ~DIS_FMT_FLAGS_BYTES_LEFT) | DIS_FMT_FLAGS_BYTES_RIGHT;
303
304 PCDISOPCODE const pOp = pDis->pCurInstr;
305
306 /*
307 * Output macros
308 */
309 char *pszDst = pszBuf;
310 size_t cchDst = cchBuf;
311 size_t cchOutput = 0;
312#define PUT_C(ch) \
313 do { \
314 cchOutput++; \
315 if (cchDst > 1) \
316 { \
317 cchDst--; \
318 *pszDst++ = (ch); \
319 } \
320 } while (0)
321#define PUT_STR(pszSrc, cchSrc) \
322 do { \
323 cchOutput += (cchSrc); \
324 if (cchDst > (cchSrc)) \
325 { \
326 memcpy(pszDst, (pszSrc), (cchSrc)); \
327 pszDst += (cchSrc); \
328 cchDst -= (cchSrc); \
329 } \
330 else if (cchDst > 1) \
331 { \
332 memcpy(pszDst, (pszSrc), cchDst - 1); \
333 pszDst += cchDst - 1; \
334 cchDst = 1; \
335 } \
336 } while (0)
337#define PUT_SZ(sz) \
338 PUT_STR((sz), sizeof(sz) - 1)
339#define PUT_SZ_STRICT(szStrict, szRelaxed) \
340 do { if (fFlags & DIS_FMT_FLAGS_STRICT) PUT_SZ(szStrict); else PUT_SZ(szRelaxed); } while (0)
341#define PUT_PSZ(psz) \
342 do { const size_t cchTmp = strlen(psz); PUT_STR((psz), cchTmp); } while (0)
343#define PUT_NUM(cch, fmt, num) \
344 do { \
345 cchOutput += (cch); \
346 if (cchDst > 1) \
347 { \
348 const size_t cchTmp = RTStrPrintf(pszDst, cchDst, fmt, (num)); \
349 pszDst += cchTmp; \
350 cchDst -= cchTmp; \
351 Assert(cchTmp == (cch) || cchDst == 1); \
352 } \
353 } while (0)
354/** @todo add two flags for choosing between %X / %x and h / 0x. */
355#define PUT_NUM_8(num) PUT_NUM(4, "0%02xh", (uint8_t)(num))
356#define PUT_NUM_16(num) PUT_NUM(6, "0%04xh", (uint16_t)(num))
357#define PUT_NUM_32(num) PUT_NUM(10, "0%08xh", (uint32_t)(num))
358#define PUT_NUM_64(num) PUT_NUM(18, "0%016RX64h", (uint64_t)(num))
359
360#define PUT_NUM_SIGN(cch, fmt, num, stype, utype) \
361 do { \
362 if ((stype)(num) >= 0) \
363 { \
364 PUT_C('+'); \
365 PUT_NUM(cch, fmt, (utype)(num)); \
366 } \
367 else \
368 { \
369 PUT_C('-'); \
370 PUT_NUM(cch, fmt, (utype)-(stype)(num)); \
371 } \
372 } while (0)
373#define PUT_NUM_S8(num) PUT_NUM_SIGN(4, "0%02xh", num, int8_t, uint8_t)
374#define PUT_NUM_S16(num) PUT_NUM_SIGN(6, "0%04xh", num, int16_t, uint16_t)
375#define PUT_NUM_S32(num) PUT_NUM_SIGN(10, "0%08xh", num, int32_t, uint32_t)
376#define PUT_NUM_S64(num) PUT_NUM_SIGN(18, "0%016RX64h", num, int64_t, uint64_t)
377
378#define PUT_SYMBOL_TWO(a_rcSym, a_szStart, a_chEnd) \
379 do { \
380 if (RT_SUCCESS(a_rcSym)) \
381 { \
382 PUT_SZ(a_szStart); \
383 PUT_PSZ(szSymbol); \
384 if (off != 0) \
385 { \
386 if ((int8_t)off == off) \
387 PUT_NUM_S8(off); \
388 else if ((int16_t)off == off) \
389 PUT_NUM_S16(off); \
390 else if ((int32_t)off == off) \
391 PUT_NUM_S32(off); \
392 else \
393 PUT_NUM_S64(off); \
394 } \
395 PUT_C(a_chEnd); \
396 } \
397 } while (0)
398
399#define PUT_SYMBOL(a_uSeg, a_uAddr, a_szStart, a_chEnd) \
400 do { \
401 if (pfnGetSymbol) \
402 { \
403 int rcSym = pfnGetSymbol(pDis, a_uSeg, a_uAddr, szSymbol, sizeof(szSymbol), &off, pvUser); \
404 PUT_SYMBOL_TWO(rcSym, a_szStart, a_chEnd); \
405 } \
406 } while (0)
407
408
409 /*
410 * The address?
411 */
412 if (fFlags & DIS_FMT_FLAGS_ADDR_LEFT)
413 {
414#if HC_ARCH_BITS == 64 || GC_ARCH_BITS == 64
415 if (pDis->uInstrAddr >= _4G)
416 PUT_NUM(9, "%08x`", (uint32_t)(pDis->uInstrAddr >> 32));
417#endif
418 PUT_NUM(8, "%08x", (uint32_t)pDis->uInstrAddr);
419 PUT_C(' ');
420 }
421
422 /*
423 * The opcode bytes?
424 */
425 if (fFlags & DIS_FMT_FLAGS_BYTES_LEFT)
426 {
427 size_t cchTmp = disFormatBytes(pDis, pszDst, cchDst, fFlags);
428 cchOutput += cchTmp;
429 if (cchDst > 1)
430 {
431 if (cchTmp <= cchDst)
432 {
433 cchDst -= cchTmp;
434 pszDst += cchTmp;
435 }
436 else
437 {
438 pszDst += cchDst - 1;
439 cchDst = 1;
440 }
441 }
442
443 /* Some padding to align the instruction. */
444 size_t cchPadding = (7 * (2 + !!(fFlags & DIS_FMT_FLAGS_BYTES_SPACED)))
445 + !!(fFlags & DIS_FMT_FLAGS_BYTES_BRACKETS) * 2
446 + 2;
447 cchPadding = cchTmp + 1 >= cchPadding ? 1 : cchPadding - cchTmp;
448 PUT_STR(g_szSpaces, cchPadding);
449 }
450
451
452 /*
453 * Filter out invalid opcodes first as they need special
454 * treatment. UD2 is an exception and should be handled normally.
455 */
456 size_t const offInstruction = cchOutput;
457 if ( pOp->uOpcode == OP_INVALID
458 || ( pOp->uOpcode == OP_ILLUD2
459 && (pDis->fPrefix & DISPREFIX_LOCK)))
460 PUT_SZ("Illegal opcode");
461 else
462 {
463 /*
464 * Prefixes
465 */
466 if (pDis->fPrefix & DISPREFIX_LOCK)
467 PUT_SZ("lock ");
468 if (pDis->fPrefix & DISPREFIX_REP)
469 PUT_SZ("rep ");
470 else if(pDis->fPrefix & DISPREFIX_REPNE)
471 PUT_SZ("repne ");
472
473 /*
474 * Adjust the format string to the correct mnemonic
475 * or to avoid things the assembler cannot handle correctly.
476 */
477 char szTmpFmt[48];
478 const char *pszFmt = pOp->pszOpcode;
479 bool fIgnoresOpSize = false;
480 switch (pOp->uOpcode)
481 {
482 case OP_JECXZ:
483 pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "jcxz %Jb" : pDis->uOpMode == DISCPUMODE_32BIT ? "jecxz %Jb" : "jrcxz %Jb";
484 break;
485 case OP_PUSHF:
486 pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "pushfw" : pDis->uOpMode == DISCPUMODE_32BIT ? "pushfd" : "pushfq";
487 break;
488 case OP_POPF:
489 pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "popfw" : pDis->uOpMode == DISCPUMODE_32BIT ? "popfd" : "popfq";
490 break;
491 case OP_PUSHA:
492 pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "pushaw" : "pushad";
493 break;
494 case OP_POPA:
495 pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "popaw" : "popad";
496 break;
497 case OP_INSB:
498 pszFmt = "insb";
499 fIgnoresOpSize = true;
500 break;
501 case OP_INSWD:
502 pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "insw" : pDis->uOpMode == DISCPUMODE_32BIT ? "insd" : "insq";
503 break;
504 case OP_OUTSB:
505 pszFmt = "outsb";
506 fIgnoresOpSize = true;
507 break;
508 case OP_OUTSWD:
509 pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "outsw" : pDis->uOpMode == DISCPUMODE_32BIT ? "outsd" : "outsq";
510 break;
511 case OP_MOVSB:
512 pszFmt = "movsb";
513 fIgnoresOpSize = true;
514 break;
515 case OP_MOVSWD:
516 pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "movsw" : pDis->uOpMode == DISCPUMODE_32BIT ? "movsd" : "movsq";
517 break;
518 case OP_CMPSB:
519 pszFmt = "cmpsb";
520 fIgnoresOpSize = true;
521 break;
522 case OP_CMPWD:
523 pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "cmpsw" : pDis->uOpMode == DISCPUMODE_32BIT ? "cmpsd" : "cmpsq";
524 break;
525 case OP_SCASB:
526 pszFmt = "scasb";
527 fIgnoresOpSize = true;
528 break;
529 case OP_SCASWD:
530 pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "scasw" : pDis->uOpMode == DISCPUMODE_32BIT ? "scasd" : "scasq";
531 break;
532 case OP_LODSB:
533 pszFmt = "lodsb";
534 fIgnoresOpSize = true;
535 break;
536 case OP_LODSWD:
537 pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "lodsw" : pDis->uOpMode == DISCPUMODE_32BIT ? "lodsd" : "lodsq";
538 break;
539 case OP_STOSB:
540 pszFmt = "stosb";
541 fIgnoresOpSize = true;
542 break;
543 case OP_STOSWD:
544 pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "stosw" : pDis->uOpMode == DISCPUMODE_32BIT ? "stosd" : "stosq";
545 break;
546 case OP_CBW:
547 pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "cbw" : pDis->uOpMode == DISCPUMODE_32BIT ? "cwde" : "cdqe";
548 break;
549 case OP_CWD:
550 pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "cwd" : pDis->uOpMode == DISCPUMODE_32BIT ? "cdq" : "cqo";
551 break;
552 case OP_SHL:
553 Assert(pszFmt[3] == '/');
554 pszFmt += 4;
555 break;
556 case OP_XLAT:
557 pszFmt = "xlatb";
558 break;
559 case OP_INT3:
560 pszFmt = "int3";
561 break;
562
563 /*
564 * Don't know how to tell yasm to generate complicated nop stuff, so 'db' it.
565 */
566 case OP_NOP:
567 if (pDis->bOpCode == 0x90)
568 /* fine, fine */;
569 else if (pszFmt[sizeof("nop %Ev") - 1] == '/' && pszFmt[sizeof("nop %Ev")] == 'p')
570 pszFmt = "prefetch %Eb";
571 else if (pDis->bOpCode == 0x1f)
572 {
573 Assert(pDis->cbInstr >= 3);
574 PUT_SZ("db 00fh, 01fh,");
575 PUT_NUM_8(MAKE_MODRM(pDis->ModRM.Bits.Mod, pDis->ModRM.Bits.Reg, pDis->ModRM.Bits.Rm));
576 for (unsigned i = 3; i < pDis->cbInstr; i++)
577 {
578 PUT_C(',');
579 PUT_NUM_8(0x90); ///@todo fixme.
580 }
581 pszFmt = "";
582 }
583 break;
584
585 default:
586 /* ST(X) -> stX (floating point) */
587 if (*pszFmt == 'f' && strchr(pszFmt, '('))
588 {
589 char *pszFmtDst = szTmpFmt;
590 char ch;
591 do
592 {
593 ch = *pszFmt++;
594 if (ch == 'S' && pszFmt[0] == 'T' && pszFmt[1] == '(')
595 {
596 *pszFmtDst++ = 's';
597 *pszFmtDst++ = 't';
598 pszFmt += 2;
599 ch = *pszFmt;
600 Assert(pszFmt[1] == ')');
601 pszFmt += 2;
602 *pszFmtDst++ = ch;
603 }
604 else
605 *pszFmtDst++ = ch;
606 } while (ch != '\0');
607 pszFmt = szTmpFmt;
608 }
609 if (strchr ("#@&", *pszFmt))
610 {
611 const char *pszDelim = strchr(pszFmt, '/');
612 const char *pszSpace = (pszDelim ? strchr(pszDelim, ' ') : NULL);
613 if (pszDelim != NULL)
614 {
615 char *pszFmtDst = szTmpFmt;
616 if (pszSpace == NULL) pszSpace = strchr(pszDelim, 0);
617 if ( (*pszFmt == '#' && pDis->bVexWFlag)
618 || (*pszFmt == '@' && !VEXREG_IS256B(pDis->bVexDestReg))
619 || (*pszFmt == '&' && ( DISUSE_IS_EFFECTIVE_ADDR(pDis->Param1.fUse)
620 || DISUSE_IS_EFFECTIVE_ADDR(pDis->Param2.fUse)
621 || DISUSE_IS_EFFECTIVE_ADDR(pDis->Param3.fUse)
622 || DISUSE_IS_EFFECTIVE_ADDR(pDis->Param4.fUse))))
623 {
624 strncpy(pszFmtDst, pszFmt + 1, pszDelim - pszFmt - 1);
625 pszFmtDst += pszDelim - pszFmt - 1;
626 }
627 else
628 {
629 strncpy(pszFmtDst, pszDelim + 1, pszSpace - pszDelim - 1);
630 pszFmtDst += pszSpace - pszDelim - 1;
631 }
632 strcpy (pszFmtDst, pszSpace);
633 pszFmt = szTmpFmt;
634 }
635 }
636 break;
637
638 /*
639 * Horrible hacks.
640 */
641 case OP_FLD:
642 if (pDis->bOpCode == 0xdb) /* m80fp workaround. */
643 *(int *)&pDis->Param1.fParam &= ~0x1f; /* make it pure OP_PARM_M */
644 break;
645 case OP_LAR: /* hack w -> v, probably not correct. */
646 *(int *)&pDis->Param2.fParam &= ~0x1f;
647 *(int *)&pDis->Param2.fParam |= OP_PARM_v;
648 break;
649 }
650
651 /*
652 * Add operand size prefix for outsb, movsb, etc.
653 */
654 if (fIgnoresOpSize && (pDis->fPrefix & DISPREFIX_OPSIZE) )
655 {
656 if (pDis->uCpuMode == DISCPUMODE_16BIT)
657 PUT_SZ("o32 ");
658 else
659 PUT_SZ("o16 ");
660 }
661
662 /*
663 * Formatting context and associated macros.
664 */
665 PCDISOPPARAM pParam = &pDis->Param1;
666 int iParam = 1;
667
668#define PUT_FAR() \
669 do { \
670 if ( OP_PARM_VSUBTYPE(pParam->fParam) == OP_PARM_p \
671 && pOp->uOpcode != OP_LDS /* table bugs? */ \
672 && pOp->uOpcode != OP_LES \
673 && pOp->uOpcode != OP_LFS \
674 && pOp->uOpcode != OP_LGS \
675 && pOp->uOpcode != OP_LSS ) \
676 PUT_SZ("far "); \
677 } while (0)
678 /** @todo mov ah,ch ends up with a byte 'override'... - check if this wasn't fixed. */
679 /** @todo drop the work/dword/qword override when the src/dst is a register (except for movsx/movzx). */
680#define PUT_SIZE_OVERRIDE() \
681 do { \
682 switch (OP_PARM_VSUBTYPE(pParam->fParam)) \
683 { \
684 case OP_PARM_v: \
685 case OP_PARM_y: \
686 switch (pDis->uOpMode) \
687 { \
688 case DISCPUMODE_16BIT: if (OP_PARM_VSUBTYPE(pParam->fParam) != OP_PARM_y) PUT_SZ("word "); break; \
689 case DISCPUMODE_32BIT: \
690 if (pDis->pCurInstr->uOpcode != OP_GATHER || pDis->bVexWFlag) { PUT_SZ("dword "); break; } \
691 case DISCPUMODE_64BIT: PUT_SZ("qword "); break; \
692 default: break; \
693 } \
694 break; \
695 case OP_PARM_b: PUT_SZ("byte "); break; \
696 case OP_PARM_w: \
697 if (OP_PARM_VTYPE(pParam->fParam) == OP_PARM_W || \
698 OP_PARM_VTYPE(pParam->fParam) == OP_PARM_M) \
699 { \
700 if (VEXREG_IS256B(pDis->bVexDestReg)) PUT_SZ("dword "); \
701 else PUT_SZ("word "); \
702 } \
703 break; \
704 case OP_PARM_d: \
705 if (OP_PARM_VTYPE(pParam->fParam) == OP_PARM_W || \
706 OP_PARM_VTYPE(pParam->fParam) == OP_PARM_M) \
707 { \
708 if (VEXREG_IS256B(pDis->bVexDestReg)) PUT_SZ("qword "); \
709 else PUT_SZ("dword "); \
710 } \
711 break; \
712 case OP_PARM_q: \
713 if (OP_PARM_VTYPE(pParam->fParam) == OP_PARM_W || \
714 OP_PARM_VTYPE(pParam->fParam) == OP_PARM_M) \
715 { \
716 if (VEXREG_IS256B(pDis->bVexDestReg)) PUT_SZ("oword "); \
717 else PUT_SZ("qword "); \
718 } \
719 break; \
720 case OP_PARM_ps: \
721 case OP_PARM_pd: \
722 case OP_PARM_x: if (VEXREG_IS256B(pDis->bVexDestReg)) { PUT_SZ("yword "); break; } \
723 case OP_PARM_ss: \
724 case OP_PARM_sd: \
725 case OP_PARM_dq: PUT_SZ("oword "); break; \
726 case OP_PARM_qq: PUT_SZ("yword "); break; \
727 case OP_PARM_p: break; /* see PUT_FAR */ \
728 case OP_PARM_s: if (pParam->fUse & DISUSE_REG_FP) PUT_SZ("tword "); break; /* ?? */ \
729 case OP_PARM_z: break; \
730 case OP_PARM_NONE: \
731 if ( OP_PARM_VTYPE(pParam->fParam) == OP_PARM_M \
732 && ((pParam->fUse & DISUSE_REG_FP) || pOp->uOpcode == OP_FLD)) \
733 PUT_SZ("tword "); \
734 break; \
735 default: break; /*no pointer type specified/necessary*/ \
736 } \
737 } while (0)
738 static const char s_szSegPrefix[6][4] = { "es:", "cs:", "ss:", "ds:", "fs:", "gs:" };
739#define PUT_SEGMENT_OVERRIDE() \
740 do { \
741 if (pDis->fPrefix & DISPREFIX_SEG) \
742 PUT_STR(s_szSegPrefix[pDis->idxSegPrefix], 3); \
743 } while (0)
744
745
746 /*
747 * Segment prefixing for instructions that doesn't do memory access.
748 */
749 if ( (pDis->fPrefix & DISPREFIX_SEG)
750 && !DISUSE_IS_EFFECTIVE_ADDR(pDis->Param1.fUse)
751 && !DISUSE_IS_EFFECTIVE_ADDR(pDis->Param2.fUse)
752 && !DISUSE_IS_EFFECTIVE_ADDR(pDis->Param3.fUse))
753 {
754 PUT_STR(s_szSegPrefix[pDis->idxSegPrefix], 2);
755 PUT_C(' ');
756 }
757
758
759 /*
760 * The formatting loop.
761 */
762 RTINTPTR off;
763 char szSymbol[128];
764 char ch;
765 while ((ch = *pszFmt++) != '\0')
766 {
767 if (ch == '%')
768 {
769 ch = *pszFmt++;
770 switch (ch)
771 {
772 /*
773 * ModRM - Register only.
774 */
775 case 'C': /* Control register (ParseModRM / UseModRM). */
776 case 'D': /* Debug register (ParseModRM / UseModRM). */
777 case 'G': /* ModRM selects general register (ParseModRM / UseModRM). */
778 case 'S': /* ModRM byte selects a segment register (ParseModRM / UseModRM). */
779 case 'T': /* ModRM byte selects a test register (ParseModRM / UseModRM). */
780 case 'V': /* ModRM byte selects an XMM/SSE register (ParseModRM / UseModRM). */
781 case 'P': /* ModRM byte selects MMX register (ParseModRM / UseModRM). */
782 case 'H': /* The VEX.vvvv field of the VEX prefix selects a XMM/YMM register. */
783 case 'L': /* The upper 4 bits of the 8-bit immediate selects a XMM/YMM register. */
784 {
785 pszFmt += RT_C_IS_ALPHA(pszFmt[0]) ? RT_C_IS_ALPHA(pszFmt[1]) ? 2 : 1 : 0;
786 Assert(!(pParam->fUse & (DISUSE_INDEX | DISUSE_SCALE) /* No SIB here... */));
787 Assert(!(pParam->fUse & (DISUSE_DISPLACEMENT8 | DISUSE_DISPLACEMENT16 | DISUSE_DISPLACEMENT32 | DISUSE_DISPLACEMENT64 | DISUSE_RIPDISPLACEMENT32)));
788
789 size_t cchReg;
790 const char *pszReg = disasmFormatYasmBaseReg(pDis, pParam, &cchReg);
791 PUT_STR(pszReg, cchReg);
792 break;
793 }
794
795 /*
796 * ModRM - Register or memory.
797 */
798 case 'E': /* ModRM specifies parameter (ParseModRM / UseModRM / UseSIB). */
799 case 'Q': /* ModRM byte selects MMX register or memory address (ParseModRM / UseModRM). */
800 case 'R': /* ModRM byte may only refer to a general register (ParseModRM / UseModRM). */
801 case 'W': /* ModRM byte selects an XMM/SSE register or a memory address (ParseModRM / UseModRM). */
802 case 'M': /* ModRM may only refer to memory (ParseModRM / UseModRM). */
803 {
804 pszFmt += RT_C_IS_ALPHA(pszFmt[0]) ? RT_C_IS_ALPHA(pszFmt[1]) ? 2 : 1 : 0;
805
806 PUT_FAR();
807 uint32_t const fUse = pParam->fUse;
808 if (DISUSE_IS_EFFECTIVE_ADDR(fUse))
809 {
810 /* Work around mov seg,[mem16] and mov [mem16],seg as these always make a 16-bit mem
811 while the register variants deals with 16, 32 & 64 in the normal fashion. */
812 if ( pParam->fParam != OP_PARM_Ev
813 || pOp->uOpcode != OP_MOV
814 || ( pOp->fParam1 != OP_PARM_Sw
815 && pOp->fParam2 != OP_PARM_Sw))
816 PUT_SIZE_OVERRIDE();
817 PUT_C('[');
818 }
819 if ( (fFlags & DIS_FMT_FLAGS_STRICT)
820 && (fUse & (DISUSE_DISPLACEMENT8 | DISUSE_DISPLACEMENT16 | DISUSE_DISPLACEMENT32 | DISUSE_DISPLACEMENT64 | DISUSE_RIPDISPLACEMENT32)))
821 {
822 if ( (fUse & DISUSE_DISPLACEMENT8)
823 && !pParam->uDisp.i8)
824 PUT_SZ("byte ");
825 else if ( (fUse & DISUSE_DISPLACEMENT16)
826 && (int8_t)pParam->uDisp.i16 == (int16_t)pParam->uDisp.i16)
827 PUT_SZ("word ");
828 else if ( (fUse & DISUSE_DISPLACEMENT32)
829 && (int16_t)pParam->uDisp.i32 == (int32_t)pParam->uDisp.i32) //??
830 PUT_SZ("dword ");
831 else if ( (fUse & DISUSE_DISPLACEMENT64)
832 && (pDis->SIB.Bits.Base != 5 || pDis->ModRM.Bits.Mod != 0)
833 && (int32_t)pParam->uDisp.i64 == (int64_t)pParam->uDisp.i64) //??
834 PUT_SZ("qword ");
835 }
836 if (DISUSE_IS_EFFECTIVE_ADDR(fUse))
837 PUT_SEGMENT_OVERRIDE();
838
839 bool fBase = (fUse & DISUSE_BASE) /* When exactly is DISUSE_BASE supposed to be set? disasmModRMReg doesn't set it. */
840 || ( (fUse & ( DISUSE_REG_GEN8
841 | DISUSE_REG_GEN16
842 | DISUSE_REG_GEN32
843 | DISUSE_REG_GEN64
844 | DISUSE_REG_FP
845 | DISUSE_REG_MMX
846 | DISUSE_REG_XMM
847 | DISUSE_REG_YMM
848 | DISUSE_REG_CR
849 | DISUSE_REG_DBG
850 | DISUSE_REG_SEG
851 | DISUSE_REG_TEST ))
852 && !DISUSE_IS_EFFECTIVE_ADDR(fUse));
853 if (fBase)
854 {
855 size_t cchReg;
856 const char *pszReg = disasmFormatYasmBaseReg(pDis, pParam, &cchReg);
857 PUT_STR(pszReg, cchReg);
858 }
859
860 if (fUse & DISUSE_INDEX)
861 {
862 if (fBase)
863 PUT_C('+');
864
865 size_t cchReg;
866 const char *pszReg = disasmFormatYasmIndexReg(pDis, pParam, &cchReg);
867 PUT_STR(pszReg, cchReg);
868
869 if (fUse & DISUSE_SCALE)
870 {
871 PUT_C('*');
872 PUT_C('0' + pParam->uScale);
873 }
874 }
875 else
876 Assert(!(fUse & DISUSE_SCALE));
877
878 int64_t off2 = 0;
879 if (fUse & (DISUSE_DISPLACEMENT8 | DISUSE_DISPLACEMENT16 | DISUSE_DISPLACEMENT32 | DISUSE_DISPLACEMENT64 | DISUSE_RIPDISPLACEMENT32))
880 {
881 if (fUse & DISUSE_DISPLACEMENT8)
882 off2 = pParam->uDisp.i8;
883 else if (fUse & DISUSE_DISPLACEMENT16)
884 off2 = pParam->uDisp.i16;
885 else if (fUse & (DISUSE_DISPLACEMENT32 | DISUSE_RIPDISPLACEMENT32))
886 off2 = pParam->uDisp.i32;
887 else if (fUse & DISUSE_DISPLACEMENT64)
888 off2 = pParam->uDisp.i64;
889 else
890 {
891 AssertFailed();
892 off2 = 0;
893 }
894
895 int64_t off3 = off2;
896 if (fBase || (fUse & (DISUSE_INDEX | DISUSE_RIPDISPLACEMENT32)))
897 {
898 PUT_C(off3 >= 0 ? '+' : '-');
899 if (off3 < 0)
900 off3 = -off3;
901 }
902 if (fUse & DISUSE_DISPLACEMENT8)
903 PUT_NUM_8( off3);
904 else if (fUse & DISUSE_DISPLACEMENT16)
905 PUT_NUM_16(off3);
906 else if (fUse & DISUSE_DISPLACEMENT32)
907 PUT_NUM_32(off3);
908 else if (fUse & DISUSE_DISPLACEMENT64)
909 PUT_NUM_64(off3);
910 else
911 {
912 PUT_NUM_32(off3);
913 PUT_SZ(" wrt rip (");
914 off2 += pDis->uInstrAddr + pDis->cbInstr;
915 PUT_NUM_64(off2);
916 if (pfnGetSymbol)
917 PUT_SYMBOL((pDis->fPrefix & DISPREFIX_SEG)
918 ? DIS_FMT_SEL_FROM_REG(pDis->idxSegPrefix)
919 : DIS_FMT_SEL_FROM_REG(DISSELREG_DS),
920 pDis->uAddrMode == DISCPUMODE_64BIT
921 ? (uint64_t)off2
922 : pDis->uAddrMode == DISCPUMODE_32BIT
923 ? (uint32_t)off2
924 : (uint16_t)off2,
925 " = ",
926 ')');
927 else
928 PUT_C(')');
929 }
930 }
931
932 if (DISUSE_IS_EFFECTIVE_ADDR(fUse))
933 {
934 if (pfnGetSymbol && !fBase && !(fUse & (DISUSE_INDEX | DISUSE_RIPDISPLACEMENT32)) && off2 != 0)
935 PUT_SYMBOL((pDis->fPrefix & DISPREFIX_SEG)
936 ? DIS_FMT_SEL_FROM_REG(pDis->idxSegPrefix)
937 : DIS_FMT_SEL_FROM_REG(DISSELREG_DS),
938 pDis->uAddrMode == DISCPUMODE_64BIT
939 ? (uint64_t)off2
940 : pDis->uAddrMode == DISCPUMODE_32BIT
941 ? (uint32_t)off2
942 : (uint16_t)off2,
943 " (=",
944 ')');
945 PUT_C(']');
946 }
947 break;
948 }
949
950 case 'F': /* Eflags register (0 - popf/pushf only, avoided in adjustments above). */
951 AssertFailed();
952 break;
953
954 case 'I': /* Immediate data (ParseImmByte, ParseImmByteSX, ParseImmV, ParseImmUshort, ParseImmZ). */
955 Assert(*pszFmt == 'b' || *pszFmt == 'v' || *pszFmt == 'w' || *pszFmt == 'z'); pszFmt++;
956 switch (pParam->fUse & ( DISUSE_IMMEDIATE8 | DISUSE_IMMEDIATE16 | DISUSE_IMMEDIATE32 | DISUSE_IMMEDIATE64
957 | DISUSE_IMMEDIATE16_SX8 | DISUSE_IMMEDIATE32_SX8 | DISUSE_IMMEDIATE64_SX8))
958 {
959 case DISUSE_IMMEDIATE8:
960 if ( (fFlags & DIS_FMT_FLAGS_STRICT)
961 && ( (pOp->fParam1 >= OP_PARM_REG_GEN8_START && pOp->fParam1 <= OP_PARM_REG_GEN8_END)
962 || (pOp->fParam2 >= OP_PARM_REG_GEN8_START && pOp->fParam2 <= OP_PARM_REG_GEN8_END))
963 )
964 PUT_SZ("strict byte ");
965 PUT_NUM_8(pParam->uValue);
966 break;
967
968 case DISUSE_IMMEDIATE16:
969 if ( pDis->uCpuMode != pDis->uOpMode
970 || ( (fFlags & DIS_FMT_FLAGS_STRICT)
971 && ( (int8_t)pParam->uValue == (int16_t)pParam->uValue
972 || (pOp->fParam1 >= OP_PARM_REG_GEN16_START && pOp->fParam1 <= OP_PARM_REG_GEN16_END)
973 || (pOp->fParam2 >= OP_PARM_REG_GEN16_START && pOp->fParam2 <= OP_PARM_REG_GEN16_END))
974 )
975 )
976 {
977 if (OP_PARM_VSUBTYPE(pParam->fParam) == OP_PARM_b)
978 PUT_SZ_STRICT("strict byte ", "byte ");
979 else if ( OP_PARM_VSUBTYPE(pParam->fParam) == OP_PARM_v
980 || OP_PARM_VSUBTYPE(pParam->fParam) == OP_PARM_z)
981 PUT_SZ_STRICT("strict word ", "word ");
982 }
983 PUT_NUM_16(pParam->uValue);
984 break;
985
986 case DISUSE_IMMEDIATE16_SX8:
987 if ( !(pDis->fPrefix & DISPREFIX_OPSIZE)
988 || pDis->pCurInstr->uOpcode != OP_PUSH)
989 PUT_SZ_STRICT("strict byte ", "byte ");
990 else
991 PUT_SZ("word ");
992 PUT_NUM_16(pParam->uValue);
993 break;
994
995 case DISUSE_IMMEDIATE32:
996 if ( pDis->uOpMode != (pDis->uCpuMode == DISCPUMODE_16BIT ? DISCPUMODE_16BIT : DISCPUMODE_32BIT) /* not perfect */
997 || ( (fFlags & DIS_FMT_FLAGS_STRICT)
998 && ( (int8_t)pParam->uValue == (int32_t)pParam->uValue
999 || (pOp->fParam1 >= OP_PARM_REG_GEN32_START && pOp->fParam1 <= OP_PARM_REG_GEN32_END)
1000 || (pOp->fParam2 >= OP_PARM_REG_GEN32_START && pOp->fParam2 <= OP_PARM_REG_GEN32_END))
1001 )
1002 )
1003 {
1004 if (OP_PARM_VSUBTYPE(pParam->fParam) == OP_PARM_b)
1005 PUT_SZ_STRICT("strict byte ", "byte ");
1006 else if ( OP_PARM_VSUBTYPE(pParam->fParam) == OP_PARM_v
1007 || OP_PARM_VSUBTYPE(pParam->fParam) == OP_PARM_z)
1008 PUT_SZ_STRICT("strict dword ", "dword ");
1009 }
1010 PUT_NUM_32(pParam->uValue);
1011 if (pDis->uCpuMode == DISCPUMODE_32BIT)
1012 PUT_SYMBOL(DIS_FMT_SEL_FROM_REG(DISSELREG_CS), pParam->uValue, " (=", ')');
1013 break;
1014
1015 case DISUSE_IMMEDIATE32_SX8:
1016 if ( !(pDis->fPrefix & DISPREFIX_OPSIZE)
1017 || pDis->pCurInstr->uOpcode != OP_PUSH)
1018 PUT_SZ_STRICT("strict byte ", "byte ");
1019 else
1020 PUT_SZ("dword ");
1021 PUT_NUM_32(pParam->uValue);
1022 break;
1023
1024 case DISUSE_IMMEDIATE64_SX8:
1025 if ( !(pDis->fPrefix & DISPREFIX_OPSIZE)
1026 || pDis->pCurInstr->uOpcode != OP_PUSH)
1027 PUT_SZ_STRICT("strict byte ", "byte ");
1028 else
1029 PUT_SZ("qword ");
1030 PUT_NUM_64(pParam->uValue);
1031 break;
1032
1033 case DISUSE_IMMEDIATE64:
1034 PUT_NUM_64(pParam->uValue);
1035 break;
1036
1037 default:
1038 AssertFailed();
1039 break;
1040 }
1041 break;
1042
1043 case 'J': /* Relative jump offset (ParseImmBRel + ParseImmVRel). */
1044 {
1045 int32_t offDisplacement;
1046 Assert(iParam == 1);
1047 bool fPrefix = (fFlags & DIS_FMT_FLAGS_STRICT)
1048 && pOp->uOpcode != OP_CALL
1049 && pOp->uOpcode != OP_LOOP
1050 && pOp->uOpcode != OP_LOOPE
1051 && pOp->uOpcode != OP_LOOPNE
1052 && pOp->uOpcode != OP_JECXZ;
1053 if (pOp->uOpcode == OP_CALL)
1054 fFlags &= ~DIS_FMT_FLAGS_RELATIVE_BRANCH;
1055
1056 if (pParam->fUse & DISUSE_IMMEDIATE8_REL)
1057 {
1058 if (fPrefix)
1059 PUT_SZ("short ");
1060 offDisplacement = (int8_t)pParam->uValue;
1061 Assert(*pszFmt == 'b'); pszFmt++;
1062
1063 if (fFlags & DIS_FMT_FLAGS_RELATIVE_BRANCH)
1064 PUT_NUM_S8(offDisplacement);
1065 }
1066 else if (pParam->fUse & DISUSE_IMMEDIATE16_REL)
1067 {
1068 if (fPrefix)
1069 PUT_SZ("near ");
1070 offDisplacement = (int16_t)pParam->uValue;
1071 Assert(*pszFmt == 'v'); pszFmt++;
1072
1073 if (fFlags & DIS_FMT_FLAGS_RELATIVE_BRANCH)
1074 PUT_NUM_S16(offDisplacement);
1075 }
1076 else
1077 {
1078 if (fPrefix)
1079 PUT_SZ("near ");
1080 offDisplacement = (int32_t)pParam->uValue;
1081 Assert(pParam->fUse & (DISUSE_IMMEDIATE32_REL | DISUSE_IMMEDIATE64_REL));
1082 Assert(*pszFmt == 'v'); pszFmt++;
1083
1084 if (fFlags & DIS_FMT_FLAGS_RELATIVE_BRANCH)
1085 PUT_NUM_S32(offDisplacement);
1086 }
1087 if (fFlags & DIS_FMT_FLAGS_RELATIVE_BRANCH)
1088 PUT_SZ(" (");
1089
1090 RTUINTPTR uTrgAddr = pDis->uInstrAddr + pDis->cbInstr + offDisplacement;
1091 if (pDis->uCpuMode == DISCPUMODE_16BIT)
1092 PUT_NUM_16(uTrgAddr);
1093 else if (pDis->uCpuMode == DISCPUMODE_32BIT)
1094 PUT_NUM_32(uTrgAddr);
1095 else
1096 PUT_NUM_64(uTrgAddr);
1097
1098 if (fFlags & DIS_FMT_FLAGS_RELATIVE_BRANCH)
1099 {
1100 PUT_SYMBOL(DIS_FMT_SEL_FROM_REG(DISSELREG_CS), uTrgAddr, " = ", ' ');
1101 PUT_C(')');
1102 }
1103 else
1104 PUT_SYMBOL(DIS_FMT_SEL_FROM_REG(DISSELREG_CS), uTrgAddr, " (", ')');
1105 break;
1106 }
1107
1108 case 'A': /* Direct (jump/call) address (ParseImmAddr). */
1109 {
1110 Assert(*pszFmt == 'p'); pszFmt++;
1111 PUT_FAR();
1112 PUT_SIZE_OVERRIDE();
1113 PUT_SEGMENT_OVERRIDE();
1114 int rc = VERR_SYMBOL_NOT_FOUND;
1115 switch (pParam->fUse & (DISUSE_IMMEDIATE_ADDR_16_16 | DISUSE_IMMEDIATE_ADDR_16_32 | DISUSE_DISPLACEMENT64 | DISUSE_DISPLACEMENT32 | DISUSE_DISPLACEMENT16))
1116 {
1117 case DISUSE_IMMEDIATE_ADDR_16_16:
1118 PUT_NUM_16(pParam->uValue >> 16);
1119 PUT_C(':');
1120 PUT_NUM_16(pParam->uValue);
1121 if (pfnGetSymbol)
1122 rc = pfnGetSymbol(pDis, DIS_FMT_SEL_FROM_VALUE(pParam->uValue >> 16), (uint16_t)pParam->uValue, szSymbol, sizeof(szSymbol), &off, pvUser);
1123 break;
1124 case DISUSE_IMMEDIATE_ADDR_16_32:
1125 PUT_NUM_16(pParam->uValue >> 32);
1126 PUT_C(':');
1127 PUT_NUM_32(pParam->uValue);
1128 if (pfnGetSymbol)
1129 rc = pfnGetSymbol(pDis, DIS_FMT_SEL_FROM_VALUE(pParam->uValue >> 16), (uint32_t)pParam->uValue, szSymbol, sizeof(szSymbol), &off, pvUser);
1130 break;
1131 case DISUSE_DISPLACEMENT16:
1132 PUT_NUM_16(pParam->uValue);
1133 if (pfnGetSymbol)
1134 rc = pfnGetSymbol(pDis, DIS_FMT_SEL_FROM_REG(DISSELREG_CS), (uint16_t)pParam->uValue, szSymbol, sizeof(szSymbol), &off, pvUser);
1135 break;
1136 case DISUSE_DISPLACEMENT32:
1137 PUT_NUM_32(pParam->uValue);
1138 if (pfnGetSymbol)
1139 rc = pfnGetSymbol(pDis, DIS_FMT_SEL_FROM_REG(DISSELREG_CS), (uint32_t)pParam->uValue, szSymbol, sizeof(szSymbol), &off, pvUser);
1140 break;
1141 case DISUSE_DISPLACEMENT64:
1142 PUT_NUM_64(pParam->uValue);
1143 if (pfnGetSymbol)
1144 rc = pfnGetSymbol(pDis, DIS_FMT_SEL_FROM_REG(DISSELREG_CS), (uint64_t)pParam->uValue, szSymbol, sizeof(szSymbol), &off, pvUser);
1145 break;
1146 default:
1147 AssertFailed();
1148 break;
1149 }
1150
1151 PUT_SYMBOL_TWO(rc, " [", ']');
1152 break;
1153 }
1154
1155 case 'O': /* No ModRM byte (ParseImmAddr). */
1156 {
1157 Assert(*pszFmt == 'b' || *pszFmt == 'v'); pszFmt++;
1158 PUT_FAR();
1159 PUT_SIZE_OVERRIDE();
1160 PUT_C('[');
1161 PUT_SEGMENT_OVERRIDE();
1162 int rc = VERR_SYMBOL_NOT_FOUND;
1163 switch (pParam->fUse & (DISUSE_IMMEDIATE_ADDR_16_16 | DISUSE_IMMEDIATE_ADDR_16_32 | DISUSE_DISPLACEMENT64 | DISUSE_DISPLACEMENT32 | DISUSE_DISPLACEMENT16))
1164 {
1165 case DISUSE_IMMEDIATE_ADDR_16_16:
1166 PUT_NUM_16(pParam->uValue >> 16);
1167 PUT_C(':');
1168 PUT_NUM_16(pParam->uValue);
1169 if (pfnGetSymbol)
1170 rc = pfnGetSymbol(pDis, DIS_FMT_SEL_FROM_VALUE(pParam->uValue >> 16), (uint16_t)pParam->uValue, szSymbol, sizeof(szSymbol), &off, pvUser);
1171 break;
1172 case DISUSE_IMMEDIATE_ADDR_16_32:
1173 PUT_NUM_16(pParam->uValue >> 32);
1174 PUT_C(':');
1175 PUT_NUM_32(pParam->uValue);
1176 if (pfnGetSymbol)
1177 rc = pfnGetSymbol(pDis, DIS_FMT_SEL_FROM_VALUE(pParam->uValue >> 16), (uint32_t)pParam->uValue, szSymbol, sizeof(szSymbol), &off, pvUser);
1178 break;
1179 case DISUSE_DISPLACEMENT16:
1180 PUT_NUM_16(pParam->uDisp.i16);
1181 if (pfnGetSymbol)
1182 rc = pfnGetSymbol(pDis, DIS_FMT_SEL_FROM_REG(DISSELREG_CS), pParam->uDisp.u16, szSymbol, sizeof(szSymbol), &off, pvUser);
1183 break;
1184 case DISUSE_DISPLACEMENT32:
1185 PUT_NUM_32(pParam->uDisp.i32);
1186 if (pfnGetSymbol)
1187 rc = pfnGetSymbol(pDis, DIS_FMT_SEL_FROM_REG(DISSELREG_CS), pParam->uDisp.u32, szSymbol, sizeof(szSymbol), &off, pvUser);
1188 break;
1189 case DISUSE_DISPLACEMENT64:
1190 PUT_NUM_64(pParam->uDisp.i64);
1191 if (pfnGetSymbol)
1192 rc = pfnGetSymbol(pDis, DIS_FMT_SEL_FROM_REG(DISSELREG_CS), pParam->uDisp.u64, szSymbol, sizeof(szSymbol), &off, pvUser);
1193 break;
1194 default:
1195 AssertFailed();
1196 break;
1197 }
1198 PUT_C(']');
1199
1200 PUT_SYMBOL_TWO(rc, " (", ')');
1201 break;
1202 }
1203
1204 case 'X': /* DS:SI (ParseXb, ParseXv). */
1205 case 'Y': /* ES:DI (ParseYb, ParseYv). */
1206 {
1207 Assert(*pszFmt == 'b' || *pszFmt == 'v'); pszFmt++;
1208 PUT_FAR();
1209 PUT_SIZE_OVERRIDE();
1210 PUT_C('[');
1211 if (pParam->fUse & DISUSE_POINTER_DS_BASED)
1212 PUT_SZ("ds:");
1213 else
1214 PUT_SZ("es:");
1215
1216 size_t cchReg;
1217 const char *pszReg = disasmFormatYasmBaseReg(pDis, pParam, &cchReg);
1218 PUT_STR(pszReg, cchReg);
1219 PUT_C(']');
1220 break;
1221 }
1222
1223 case 'e': /* Register based on operand size (e.g. %eAX, %eAH) (ParseFixedReg). */
1224 {
1225 Assert(RT_C_IS_ALPHA(pszFmt[0]) && RT_C_IS_ALPHA(pszFmt[1]) && !RT_C_IS_ALPHA(pszFmt[2]));
1226 pszFmt += 2;
1227 size_t cchReg;
1228 const char *pszReg = disasmFormatYasmBaseReg(pDis, pParam, &cchReg);
1229 PUT_STR(pszReg, cchReg);
1230 break;
1231 }
1232
1233 default:
1234 AssertMsgFailed(("%c%s!\n", ch, pszFmt));
1235 break;
1236 }
1237 AssertMsg(*pszFmt == ',' || *pszFmt == '\0', ("%c%s\n", ch, pszFmt));
1238 }
1239 else
1240 {
1241 PUT_C(ch);
1242 if (ch == ',')
1243 {
1244 Assert(*pszFmt != ' ');
1245 PUT_C(' ');
1246 switch (++iParam)
1247 {
1248 case 2: pParam = &pDis->Param2; break;
1249 case 3: pParam = &pDis->Param3; break;
1250 case 4: pParam = &pDis->Param4; break;
1251 default: pParam = NULL; break;
1252 }
1253 }
1254 }
1255 } /* while more to format */
1256 }
1257
1258 /*
1259 * Any additional output to the right of the instruction?
1260 */
1261 if (fFlags & (DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_ADDR_RIGHT))
1262 {
1263 /* some up front padding. */
1264 size_t cchPadding = cchOutput - offInstruction;
1265 cchPadding = cchPadding + 1 >= 42 ? 1 : 42 - cchPadding;
1266 PUT_STR(g_szSpaces, cchPadding);
1267
1268 /* comment? */
1269 if (fFlags & (DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_ADDR_RIGHT))
1270 PUT_SZ(";");
1271
1272 /*
1273 * The address?
1274 */
1275 if (fFlags & DIS_FMT_FLAGS_ADDR_RIGHT)
1276 {
1277 PUT_C(' ');
1278#if HC_ARCH_BITS == 64 || GC_ARCH_BITS == 64
1279 if (pDis->uInstrAddr >= _4G)
1280 PUT_NUM(9, "%08x`", (uint32_t)(pDis->uInstrAddr >> 32));
1281#endif
1282 PUT_NUM(8, "%08x", (uint32_t)pDis->uInstrAddr);
1283 }
1284
1285 /*
1286 * Opcode bytes?
1287 */
1288 if (fFlags & DIS_FMT_FLAGS_BYTES_RIGHT)
1289 {
1290 PUT_C(' ');
1291 size_t cchTmp = disFormatBytes(pDis, pszDst, cchDst, fFlags);
1292 cchOutput += cchTmp;
1293 if (cchTmp >= cchDst)
1294 cchTmp = cchDst - (cchDst != 0);
1295 cchDst -= cchTmp;
1296 pszDst += cchTmp;
1297 }
1298 }
1299
1300 /*
1301 * Terminate it - on overflow we'll have reserved one byte for this.
1302 */
1303 if (cchDst > 0)
1304 *pszDst = '\0';
1305 else
1306 Assert(!cchBuf);
1307
1308 /* clean up macros */
1309#undef PUT_PSZ
1310#undef PUT_SZ
1311#undef PUT_STR
1312#undef PUT_C
1313 return cchOutput;
1314}
1315
1316
1317/**
1318 * Formats the current instruction in Yasm (/ Nasm) style.
1319 *
1320 * This is a simplified version of DISFormatYasmEx() provided for your convenience.
1321 *
1322 *
1323 * @returns The number of output characters. If this is >= cchBuf, then the content
1324 * of pszBuf will be truncated.
1325 * @param pDis Pointer to the disassembler state.
1326 * @param pszBuf The output buffer.
1327 * @param cchBuf The size of the output buffer.
1328 */
1329DISDECL(size_t) DISFormatYasm(PCDISSTATE pDis, char *pszBuf, size_t cchBuf)
1330{
1331 return DISFormatYasmEx(pDis, pszBuf, cchBuf, 0 /* fFlags */, NULL /* pfnGetSymbol */, NULL /* pvUser */);
1332}
1333
1334
1335/**
1336 * Checks if the encoding of the given disassembled instruction is something we
1337 * can never get YASM to produce.
1338 *
1339 * @returns true if it's odd, false if it isn't.
1340 * @param pDis The disassembler output. The byte fetcher callback will
1341 * be used if present as we might need to fetch opcode
1342 * bytes.
1343 */
1344DISDECL(bool) DISFormatYasmIsOddEncoding(PDISSTATE pDis)
1345{
1346 /*
1347 * Mod rm + SIB: Check for duplicate EBP encodings that yasm won't use for very good reasons.
1348 */
1349 if ( pDis->uAddrMode != DISCPUMODE_16BIT ///@todo correct?
1350 && pDis->ModRM.Bits.Rm == 4
1351 && pDis->ModRM.Bits.Mod != 3)
1352 {
1353 /* No scaled index SIB (index=4), except for ESP. */
1354 if ( pDis->SIB.Bits.Index == 4
1355 && pDis->SIB.Bits.Base != 4)
1356 return true;
1357
1358 /* EBP + displacement */
1359 if ( pDis->ModRM.Bits.Mod != 0
1360 && pDis->SIB.Bits.Base == 5
1361 && pDis->SIB.Bits.Scale == 0)
1362 return true;
1363 }
1364
1365 /*
1366 * Seems to be an instruction alias here, but I cannot find any docs on it... hrmpf!
1367 */
1368 if ( pDis->pCurInstr->uOpcode == OP_SHL
1369 && pDis->ModRM.Bits.Reg == 6)
1370 return true;
1371
1372 /*
1373 * Check for multiple prefixes of the same kind.
1374 */
1375 uint8_t off1stSeg = UINT8_MAX;
1376 uint8_t offOpSize = UINT8_MAX;
1377 uint8_t offAddrSize = UINT8_MAX;
1378 uint32_t fPrefixes = 0;
1379 for (uint32_t offOpcode = 0; offOpcode < RT_ELEMENTS(pDis->abInstr); offOpcode++)
1380 {
1381 uint32_t f;
1382 switch (pDis->abInstr[offOpcode])
1383 {
1384 case 0xf0:
1385 f = DISPREFIX_LOCK;
1386 break;
1387
1388 case 0xf2:
1389 case 0xf3:
1390 f = DISPREFIX_REP; /* yes, both */
1391 break;
1392
1393 case 0x2e:
1394 case 0x3e:
1395 case 0x26:
1396 case 0x36:
1397 case 0x64:
1398 case 0x65:
1399 if (off1stSeg == UINT8_MAX)
1400 off1stSeg = offOpcode;
1401 f = DISPREFIX_SEG;
1402 break;
1403
1404 case 0x66:
1405 if (offOpSize == UINT8_MAX)
1406 offOpSize = offOpcode;
1407 f = DISPREFIX_OPSIZE;
1408 break;
1409
1410 case 0x67:
1411 if (offAddrSize == UINT8_MAX)
1412 offAddrSize = offOpcode;
1413 f = DISPREFIX_ADDRSIZE;
1414 break;
1415
1416 case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
1417 case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
1418 f = pDis->uCpuMode == DISCPUMODE_64BIT ? DISPREFIX_REX : 0;
1419 break;
1420
1421 default:
1422 f = 0;
1423 break;
1424 }
1425 if (!f)
1426 break; /* done */
1427 if (fPrefixes & f)
1428 return true;
1429 fPrefixes |= f;
1430 }
1431
1432 /* segment overrides are fun */
1433 if (fPrefixes & DISPREFIX_SEG)
1434 {
1435 /* no effective address which it may apply to. */
1436 Assert((pDis->fPrefix & DISPREFIX_SEG) || pDis->uCpuMode == DISCPUMODE_64BIT);
1437 if ( !DISUSE_IS_EFFECTIVE_ADDR(pDis->Param1.fUse)
1438 && !DISUSE_IS_EFFECTIVE_ADDR(pDis->Param2.fUse)
1439 && !DISUSE_IS_EFFECTIVE_ADDR(pDis->Param3.fUse))
1440 return true;
1441
1442 /* Yasm puts the segment prefixes before the operand prefix with no
1443 way of overriding it. */
1444 if (offOpSize < off1stSeg)
1445 return true;
1446 }
1447
1448 /* fixed register + addr override doesn't go down all that well. */
1449 if (fPrefixes & DISPREFIX_ADDRSIZE)
1450 {
1451 Assert(pDis->fPrefix & DISPREFIX_ADDRSIZE);
1452 if ( pDis->pCurInstr->fParam3 == OP_PARM_NONE
1453 && pDis->pCurInstr->fParam2 == OP_PARM_NONE
1454 && ( pDis->pCurInstr->fParam1 >= OP_PARM_REG_GEN32_START
1455 && pDis->pCurInstr->fParam1 <= OP_PARM_REG_GEN32_END))
1456 return true;
1457 }
1458
1459 /* Almost all prefixes are bad for jumps. */
1460 if (fPrefixes)
1461 {
1462 switch (pDis->pCurInstr->uOpcode)
1463 {
1464 /* nop w/ prefix(es). */
1465 case OP_NOP:
1466 return true;
1467
1468 case OP_JMP:
1469 if ( pDis->pCurInstr->fParam1 != OP_PARM_Jb
1470 && pDis->pCurInstr->fParam1 != OP_PARM_Jv)
1471 break;
1472 /* fall thru */
1473 case OP_JO:
1474 case OP_JNO:
1475 case OP_JC:
1476 case OP_JNC:
1477 case OP_JE:
1478 case OP_JNE:
1479 case OP_JBE:
1480 case OP_JNBE:
1481 case OP_JS:
1482 case OP_JNS:
1483 case OP_JP:
1484 case OP_JNP:
1485 case OP_JL:
1486 case OP_JNL:
1487 case OP_JLE:
1488 case OP_JNLE:
1489 /** @todo branch hinting 0x2e/0x3e... */
1490 return true;
1491 }
1492
1493 }
1494
1495 /* All but the segment prefix is bad news for push/pop. */
1496 if (fPrefixes & ~DISPREFIX_SEG)
1497 {
1498 switch (pDis->pCurInstr->uOpcode)
1499 {
1500 case OP_POP:
1501 case OP_PUSH:
1502 if ( pDis->pCurInstr->fParam1 >= OP_PARM_REG_SEG_START
1503 && pDis->pCurInstr->fParam1 <= OP_PARM_REG_SEG_END)
1504 return true;
1505 if ( (fPrefixes & ~DISPREFIX_OPSIZE)
1506 && pDis->pCurInstr->fParam1 >= OP_PARM_REG_GEN32_START
1507 && pDis->pCurInstr->fParam1 <= OP_PARM_REG_GEN32_END)
1508 return true;
1509 break;
1510
1511 case OP_POPA:
1512 case OP_POPF:
1513 case OP_PUSHA:
1514 case OP_PUSHF:
1515 if (fPrefixes & ~DISPREFIX_OPSIZE)
1516 return true;
1517 break;
1518 }
1519 }
1520
1521 /* Implicit 8-bit register instructions doesn't mix with operand size. */
1522 if ( (fPrefixes & DISPREFIX_OPSIZE)
1523 && ( ( pDis->pCurInstr->fParam1 == OP_PARM_Gb /* r8 */
1524 && pDis->pCurInstr->fParam2 == OP_PARM_Eb /* r8/mem8 */)
1525 || ( pDis->pCurInstr->fParam2 == OP_PARM_Gb /* r8 */
1526 && pDis->pCurInstr->fParam1 == OP_PARM_Eb /* r8/mem8 */))
1527 )
1528 {
1529 switch (pDis->pCurInstr->uOpcode)
1530 {
1531 case OP_ADD:
1532 case OP_OR:
1533 case OP_ADC:
1534 case OP_SBB:
1535 case OP_AND:
1536 case OP_SUB:
1537 case OP_XOR:
1538 case OP_CMP:
1539 return true;
1540 default:
1541 break;
1542 }
1543 }
1544
1545 /* Instructions taking no address or operand which thus may be annoyingly
1546 difficult to format for yasm. */
1547 if (fPrefixes)
1548 {
1549 switch (pDis->pCurInstr->uOpcode)
1550 {
1551 case OP_STI:
1552 case OP_STC:
1553 case OP_CLI:
1554 case OP_CLD:
1555 case OP_CLC:
1556 case OP_INT:
1557 case OP_INT3:
1558 case OP_INTO:
1559 case OP_HLT:
1560 /** @todo Many more to can be added here. */
1561 return true;
1562 default:
1563 break;
1564 }
1565 }
1566
1567 /* FPU and other instructions that ignores operand size override. */
1568 if (fPrefixes & DISPREFIX_OPSIZE)
1569 {
1570 switch (pDis->pCurInstr->uOpcode)
1571 {
1572 /* FPU: */
1573 case OP_FIADD:
1574 case OP_FIMUL:
1575 case OP_FISUB:
1576 case OP_FISUBR:
1577 case OP_FIDIV:
1578 case OP_FIDIVR:
1579 /** @todo there are many more. */
1580 return true;
1581
1582 case OP_MOV:
1583 /** @todo could be that we're not disassembling these correctly. */
1584 if (pDis->pCurInstr->fParam1 == OP_PARM_Sw)
1585 return true;
1586 /** @todo what about the other way? */
1587 break;
1588
1589 default:
1590 break;
1591 }
1592 }
1593
1594
1595 /*
1596 * Check for the version of xyz reg,reg instruction that the assembler doesn't use.
1597 *
1598 * For example:
1599 * expected: 1aee sbb ch, dh ; SBB r8, r/m8
1600 * yasm: 18F5 sbb ch, dh ; SBB r/m8, r8
1601 */
1602 if (pDis->ModRM.Bits.Mod == 3 /* reg,reg */)
1603 {
1604 switch (pDis->pCurInstr->uOpcode)
1605 {
1606 case OP_ADD:
1607 case OP_OR:
1608 case OP_ADC:
1609 case OP_SBB:
1610 case OP_AND:
1611 case OP_SUB:
1612 case OP_XOR:
1613 case OP_CMP:
1614 if ( ( pDis->pCurInstr->fParam1 == OP_PARM_Gb /* r8 */
1615 && pDis->pCurInstr->fParam2 == OP_PARM_Eb /* r8/mem8 */)
1616 || ( pDis->pCurInstr->fParam1 == OP_PARM_Gv /* rX */
1617 && pDis->pCurInstr->fParam2 == OP_PARM_Ev /* rX/memX */))
1618 return true;
1619
1620 /* 82 (see table A-6). */
1621 if (pDis->bOpCode == 0x82)
1622 return true;
1623 break;
1624
1625 /* ff /0, fe /0, ff /1, fe /0 */
1626 case OP_DEC:
1627 case OP_INC:
1628 return true;
1629
1630 case OP_POP:
1631 case OP_PUSH:
1632 Assert(pDis->bOpCode == 0x8f);
1633 return true;
1634
1635 case OP_MOV:
1636 if ( pDis->bOpCode == 0x8a
1637 || pDis->bOpCode == 0x8b)
1638 return true;
1639 break;
1640
1641 default:
1642 break;
1643 }
1644 }
1645
1646 /* shl eax,1 will be assembled to the form without the immediate byte. */
1647 if ( pDis->pCurInstr->fParam2 == OP_PARM_Ib
1648 && (uint8_t)pDis->Param2.uValue == 1)
1649 {
1650 switch (pDis->pCurInstr->uOpcode)
1651 {
1652 case OP_SHL:
1653 case OP_SHR:
1654 case OP_SAR:
1655 case OP_RCL:
1656 case OP_RCR:
1657 case OP_ROL:
1658 case OP_ROR:
1659 return true;
1660 }
1661 }
1662
1663 /* And some more - see table A-6. */
1664 if (pDis->bOpCode == 0x82)
1665 {
1666 switch (pDis->pCurInstr->uOpcode)
1667 {
1668 case OP_ADD:
1669 case OP_OR:
1670 case OP_ADC:
1671 case OP_SBB:
1672 case OP_AND:
1673 case OP_SUB:
1674 case OP_XOR:
1675 case OP_CMP:
1676 return true;
1677 break;
1678 }
1679 }
1680
1681
1682 /* check for REX.X = 1 without SIB. */
1683
1684 /* Yasm encodes setnbe al with /2 instead of /0 like the AMD manual
1685 says (intel doesn't appear to care). */
1686 switch (pDis->pCurInstr->uOpcode)
1687 {
1688 case OP_SETO:
1689 case OP_SETNO:
1690 case OP_SETC:
1691 case OP_SETNC:
1692 case OP_SETE:
1693 case OP_SETNE:
1694 case OP_SETBE:
1695 case OP_SETNBE:
1696 case OP_SETS:
1697 case OP_SETNS:
1698 case OP_SETP:
1699 case OP_SETNP:
1700 case OP_SETL:
1701 case OP_SETNL:
1702 case OP_SETLE:
1703 case OP_SETNLE:
1704 AssertMsg(pDis->bOpCode >= 0x90 && pDis->bOpCode <= 0x9f, ("%#x\n", pDis->bOpCode));
1705 if (pDis->ModRM.Bits.Reg != 2)
1706 return true;
1707 break;
1708 }
1709
1710 /*
1711 * The MOVZX reg32,mem16 instruction without an operand size prefix
1712 * doesn't quite make sense...
1713 */
1714 if ( pDis->pCurInstr->uOpcode == OP_MOVZX
1715 && pDis->bOpCode == 0xB7
1716 && (pDis->uCpuMode == DISCPUMODE_16BIT) != !!(fPrefixes & DISPREFIX_OPSIZE))
1717 return true;
1718
1719 return false;
1720}
1721
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette