blob: e1a86037731e874b6ed85756f160e93449758ef1 [file] [log] [blame]
sewardjc9a65702004-07-07 16:32:57 +00001
2/*--------------------------------------------------------------------*/
3/*--- ---*/
4/*--- This file (x86toIR.c) is ---*/
5/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/
6/*--- ---*/
7/*--------------------------------------------------------------------*/
8
sewardj77b86be2004-07-11 13:28:24 +00009/* TODO:
sewardje87b4842004-07-10 12:23:30 +000010 XOR reg with itself
sewardj940e8c92004-07-11 16:53:24 +000011 is Iop_Neg* used?
sewardj77b86be2004-07-11 13:28:24 +000012
sewardje05c42c2004-07-08 20:25:10 +000013*/
14
sewardjc9a65702004-07-07 16:32:57 +000015/* Translates x86 code to IR. */
16
17#include "libvex_basictypes.h"
18#include "libvex_ir.h"
sewardje87b4842004-07-10 12:23:30 +000019#include "libvex.h"
sewardjc9a65702004-07-07 16:32:57 +000020#include "vex_util.h"
21#include "vex_globals.h"
22#include "x86guest_defs.h"
23
24
25/*------------------------------------------------------------*/
26/*--- Globals ---*/
27/*------------------------------------------------------------*/
28
29/* These are set at the start of the translation of a BB, so
30 that we don't have to pass them around endlessly. */
31
32/* We need to know this to do sub-register accesses correctly. */
33/* CONST */
34static Bool host_is_bigendian;
35
36/* Are we being verbose? */
37/* CONST */
38static Bool print_codegen;
39
40/* Pointer to the guest code area. */
41/* CONST */
42static UChar* guest_code;
43
44/* The guest address corresponding to guest_code[0]. */
45/* CONST */
46static Addr32 guest_eip;
47
48/* The BBIR* into which we're generating code. */
49/* What it points to changes as we work through the bb. */
50static IRBB* irbb;
51
52/* Points to the last stmt added to the statement list of irbb, so
53 that when a new stmt is added, the .link field can be correctly
54 updated. */
55static IRStmt* last_stmt;
56
57/* Used to generate new IRTemps. */
58static IRTemp next_irtemp;
59
60
61/* Add a statement to the list held by "irbb". */
sewardjd1061ab2004-07-08 01:45:30 +000062static void stmt ( IRStmt* stmt )
sewardjc9a65702004-07-07 16:32:57 +000063{
64 stmt->link = NULL;
65 if (irbb->stmts == NULL) {
66 irbb->stmts = stmt;
67 } else {
68 last_stmt->link = stmt;
69 }
70 last_stmt = stmt;
71}
72
73/* Generate a new temporary of the given type. */
74static IRTemp newTemp ( IRType ty )
75{
76 addToIRTypeEnv ( irbb->tyenv, next_irtemp, ty );
77 return next_irtemp++;
78}
79
sewardjc9a65702004-07-07 16:32:57 +000080/* Bomb out if we can't handle something. */
sewardjd1061ab2004-07-08 01:45:30 +000081__attribute__ ((noreturn))
sewardjc9a65702004-07-07 16:32:57 +000082static void unimplemented ( Char* str )
83{
84 vex_printf("x86toIR: unimplemented feature\n");
85 vpanic(str);
86}
87
88
89/*------------------------------------------------------------*/
90/*--- Debugging output ---*/
91/*------------------------------------------------------------*/
92
93#define DIP(format, args...) \
94 if (print_codegen) \
95 vex_printf(format, ## args)
96
97#define DIS(buf, format, args...) \
98 if (print_codegen) \
99 vex_sprintf(buf, format, ## args)
100
101
102/*------------------------------------------------------------*/
103/*--- Helper bits and pieces for deconstructing the ---*/
104/*--- x86 insn stream. ---*/
105/*------------------------------------------------------------*/
106
sewardjd1061ab2004-07-08 01:45:30 +0000107/* This is the Intel register encoding -- integer regs. */
108#define R_EAX 0
109#define R_ECX 1
110#define R_EDX 2
111#define R_EBX 3
112#define R_ESP 4
113#define R_EBP 5
114#define R_ESI 6
115#define R_EDI 7
116
117
sewardje05c42c2004-07-08 20:25:10 +0000118static UInt extend_s_8to32( UInt x )
sewardjd1061ab2004-07-08 01:45:30 +0000119{
120 return (UInt)((((Int)x) << 24) >> 24);
121}
122
sewardj0611d802004-07-11 02:37:54 +0000123static UInt extend_s_16to32 ( UInt x )
124{
125 return (UInt)((((Int)x) << 16) >> 16);
126}
127
sewardjd1061ab2004-07-08 01:45:30 +0000128/* Fetch a byte from the guest insn stream. */
sewardje05c42c2004-07-08 20:25:10 +0000129static UChar getIByte ( UInt delta )
sewardjd1061ab2004-07-08 01:45:30 +0000130{
131 return guest_code[delta];
132}
133
sewardjc9a65702004-07-07 16:32:57 +0000134/* Extract the reg field from a modRM byte. */
sewardje05c42c2004-07-08 20:25:10 +0000135static Int gregOfRM ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000136{
137 return (Int)( (mod_reg_rm >> 3) & 7 );
138}
139
140/* Figure out whether the mod and rm parts of a modRM byte refer to a
141 register or memory. If so, the byte will have the form 11XXXYYY,
142 where YYY is the register number. */
sewardje05c42c2004-07-08 20:25:10 +0000143static Bool epartIsReg ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000144{
145 return (0xC0 == (mod_reg_rm & 0xC0));
146}
147
148/* ... and extract the register number ... */
sewardje05c42c2004-07-08 20:25:10 +0000149static Int eregOfRM ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000150{
151 return (Int)(mod_reg_rm & 0x7);
152}
153
sewardje05c42c2004-07-08 20:25:10 +0000154/* Get a 8/16/32-bit unsigned value out of the insn stream. */
155
156static UInt getUChar ( UInt delta )
157{
158 UInt v = guest_code[delta+0];
159 return v & 0xFF;
160}
161
162static UInt getUDisp16 ( UInt delta )
163{
164 UInt v = guest_code[delta+1]; v <<= 8;
165 v |= guest_code[delta+0];
166 return v & 0xFFFF;
167}
168
169static UInt getUDisp32 ( UInt delta )
sewardjd1061ab2004-07-08 01:45:30 +0000170{
171 UInt v = guest_code[delta+3]; v <<= 8;
172 v |= guest_code[delta+2]; v <<= 8;
173 v |= guest_code[delta+1]; v <<= 8;
174 v |= guest_code[delta+0];
175 return v;
176}
177
sewardje05c42c2004-07-08 20:25:10 +0000178static UInt getUDisp ( Int size, UInt delta )
179{
180 switch (size) {
181 case 4: return getUDisp32(delta);
182 case 2: return getUDisp16(delta);
183 case 1: return getUChar(delta);
184 default: vpanic("getUDisp(x86)");
185 }
186 return 0; /*notreached*/
187}
188
189
sewardjd1061ab2004-07-08 01:45:30 +0000190/* Get a byte value out of the insn stream and sign-extend to 32
191 bits. */
sewardje05c42c2004-07-08 20:25:10 +0000192static UInt getSDisp8 ( UInt delta )
sewardjd1061ab2004-07-08 01:45:30 +0000193{
194 return extend_s_8to32( (UInt) (guest_code[delta]) );
195}
196
sewardj0611d802004-07-11 02:37:54 +0000197static UInt getSDisp16 ( UInt delta0 )
198{
199 UChar* eip = (UChar*)(&guest_code[delta0]);
200 UInt d = *eip++;
201 d |= ((*eip++) << 8);
202 return extend_s_16to32(d);
203}
204
205static UInt getSDisp ( Int size, UInt delta )
206{
207 switch (size) {
208 case 4: return getUDisp32(delta);
209 case 2: return getSDisp16(delta);
210 case 1: return getSDisp8(delta);
211 default: vpanic("getSDisp(x86)");
212 }
213 return 0; /*notreached*/
214}
sewardjd1061ab2004-07-08 01:45:30 +0000215
sewardjc9a65702004-07-07 16:32:57 +0000216
217/*------------------------------------------------------------*/
218/*--- Helpers for constructing IR. ---*/
219/*------------------------------------------------------------*/
220
221/* Create a 1/2/4 byte read of an x86 integer registers. For 16/8 bit
222 register references, we need to take the host endianness into
223 account. Supplied value is 0 .. 7 and in the Intel instruction
224 encoding. */
sewardje05c42c2004-07-08 20:25:10 +0000225
sewardj9334b0f2004-07-10 22:43:54 +0000226static IRType szToITy ( Int n )
227{
228 switch (n) {
229 case 1: return Ity_I8;
230 case 2: return Ity_I16;
231 case 4: return Ity_I32;
232 default: vpanic("szToITy(x86)");
233 }
234}
235
236static Int integerGuestRegOffset ( Int sz, UInt archreg )
237{
238 vassert(archreg < 8);
239
240 vassert(!host_is_bigendian);
241
242 /* Correct for little-endian host only. */
243 switch (sz) {
244 case 2:
245 case 4: return OFFB_EAX + 4*archreg;
246 case 1: if (archreg < 4)
247 return OFFB_EAX + 4*archreg + 0;
248 else
249 return OFFB_EAX + 4*(archreg-4) + 1;
250 default: vpanic("integerGuestRegOffset(x86,le)");
251 }
252}
253
sewardjd1061ab2004-07-08 01:45:30 +0000254static IRExpr* getIReg ( Int sz, UInt archreg )
sewardjc9a65702004-07-07 16:32:57 +0000255{
256 vassert(sz == 1 || sz == 2 || sz == 4);
257 vassert(archreg < 8);
sewardj9334b0f2004-07-10 22:43:54 +0000258 return IRExpr_Get( integerGuestRegOffset(sz,archreg),
259 szToITy(sz) );
sewardjc9a65702004-07-07 16:32:57 +0000260}
261
262/* Ditto, but write to a reg instead. */
sewardj41f43bc2004-07-08 14:23:22 +0000263static void putIReg ( Int sz, UInt archreg, IRExpr* e )
sewardjc9a65702004-07-07 16:32:57 +0000264{
265 vassert(sz == 1 || sz == 2 || sz == 4);
266 vassert(archreg < 8);
sewardj9334b0f2004-07-10 22:43:54 +0000267 stmt( IRStmt_Put(NULL, integerGuestRegOffset(sz,archreg), e) );
sewardjd1061ab2004-07-08 01:45:30 +0000268}
269
sewardj41f43bc2004-07-08 14:23:22 +0000270static void assign ( IRTemp dst, IRExpr* e )
sewardjd1061ab2004-07-08 01:45:30 +0000271{
sewardj41f43bc2004-07-08 14:23:22 +0000272 stmt( IRStmt_Tmp(dst, e) );
sewardjd1061ab2004-07-08 01:45:30 +0000273}
274
sewardj41f43bc2004-07-08 14:23:22 +0000275static void storeLE ( IRExpr* addr, IRExpr* data )
sewardjd1061ab2004-07-08 01:45:30 +0000276{
sewardj41f43bc2004-07-08 14:23:22 +0000277 stmt( IRStmt_STle(addr,data) );
sewardjd1061ab2004-07-08 01:45:30 +0000278}
279
sewardje87b4842004-07-10 12:23:30 +0000280static IRExpr* unop ( IROp op, IRExpr* a )
281{
282 return IRExpr_Unop(op, a);
283}
284
sewardjd1061ab2004-07-08 01:45:30 +0000285static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
286{
287 return IRExpr_Binop(op, a1, a2);
288}
289
290static IRExpr* mkexpr ( IRTemp tmp )
291{
292 return IRExpr_Tmp(tmp);
293}
294
sewardjc2ac51e2004-07-12 01:03:26 +0000295static IRExpr* mkU8 ( UInt i )
296{
297 vassert(i < 256);
298 return IRExpr_Const(IRConst_U8(i));
299}
300
301static IRExpr* mkU16 ( UInt i )
302{
303 vassert(i < 65536);
304 return IRExpr_Const(IRConst_U16(i));
305}
306
sewardjd1061ab2004-07-08 01:45:30 +0000307static IRExpr* mkU32 ( UInt i )
308{
309 return IRExpr_Const(IRConst_U32(i));
sewardjc9a65702004-07-07 16:32:57 +0000310}
311
sewardj41f43bc2004-07-08 14:23:22 +0000312static IRExpr* mkU ( IRType ty, UInt i )
313{
sewardjc2ac51e2004-07-12 01:03:26 +0000314 if (ty == Ity_I8) return mkU8(i);
315 if (ty == Ity_I16) return mkU16(i);
316 if (ty == Ity_I32) return mkU32(i);
sewardje90ad6a2004-07-10 19:02:10 +0000317 /* If this panics, it usually means you passed a size (1,2,4)
318 value as the IRType, rather than a real IRType. */
sewardj41f43bc2004-07-08 14:23:22 +0000319 vpanic("mkU(x86)");
320}
321
322static IRExpr* loadLE ( IRType ty, IRExpr* data )
323{
324 return IRExpr_LDle(ty,data);
325}
326
327static IROp mkSizedOp ( IRType ty, IROp op8 )
328{
sewardje05c42c2004-07-08 20:25:10 +0000329 Int adj;
sewardj41f43bc2004-07-08 14:23:22 +0000330 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
331 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8
332 || op8 == Iop_Adc8 || op8 == Iop_Sbb8
333 || op8 == Iop_Mul8
334 || op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
335 || op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8
sewardje90ad6a2004-07-10 19:02:10 +0000336 || op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8
sewardj41f43bc2004-07-08 14:23:22 +0000337 || op8 == Iop_Not8 || op8 == Iop_Neg8 );
sewardje05c42c2004-07-08 20:25:10 +0000338 adj = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
339 return adj + op8;
sewardj41f43bc2004-07-08 14:23:22 +0000340}
341
sewardj9334b0f2004-07-10 22:43:54 +0000342static IROp mkWidenOp ( Int szSmall, Int szBig, Bool signd )
sewardj41f43bc2004-07-08 14:23:22 +0000343{
sewardj9334b0f2004-07-10 22:43:54 +0000344 if (szSmall == 1 && szBig == 4) {
345 return signd ? Iop_8Sto32 : Iop_8Uto32;
sewardj41f43bc2004-07-08 14:23:22 +0000346 }
sewardj9334b0f2004-07-10 22:43:54 +0000347 if (szSmall == 1 && szBig == 2) {
348 return signd ? Iop_8Sto16 : Iop_8Uto16;
349 }
350 if (szSmall == 2 && szBig == 4) {
351 return signd ? Iop_16Sto32 : Iop_16Uto32;
352 }
353 vpanic("mkWidenOp(x86)");
sewardj41f43bc2004-07-08 14:23:22 +0000354}
355
356
357/*------------------------------------------------------------*/
358/*--- Helpers for %eflags. ---*/
359/*------------------------------------------------------------*/
360
sewardje87b4842004-07-10 12:23:30 +0000361
sewardj0611d802004-07-11 02:37:54 +0000362/* -------------- Evaluating the flags-thunk. -------------- */
sewardjc9a65702004-07-07 16:32:57 +0000363
sewardje87b4842004-07-10 12:23:30 +0000364/* Build IR to calculate all the eflags from stored
sewardj77b86be2004-07-11 13:28:24 +0000365 CC_OP/CC_SRC/CC_DST. Returns an expression :: Ity_I32. */
sewardje87b4842004-07-10 12:23:30 +0000366static IRExpr* mk_calculate_eflags_all ( void )
367{
368 IRExpr** args = LibVEX_Alloc(4 * sizeof(IRExpr*));
369 args[0] = IRExpr_Get(OFFB_CC_OP, Ity_I32);
370 args[1] = IRExpr_Get(OFFB_CC_SRC, Ity_I32);
371 args[2] = IRExpr_Get(OFFB_CC_DST, Ity_I32);
372 args[3] = NULL;
373 return IRExpr_CCall("calculate_eflags_all", Ity_I32, args);
374}
375
376/* Build IR to calculate just the carry flags from stored
sewardj77b86be2004-07-11 13:28:24 +0000377 CC_OP/CC_SRC/CC_DST. Returns an expression :: Ity_I32. */
sewardje87b4842004-07-10 12:23:30 +0000378static IRExpr* mk_calculate_eflags_c ( void )
379{
380 IRExpr** args = LibVEX_Alloc(4 * sizeof(IRExpr*));
381 args[0] = IRExpr_Get(OFFB_CC_OP, Ity_I32);
382 args[1] = IRExpr_Get(OFFB_CC_SRC, Ity_I32);
383 args[2] = IRExpr_Get(OFFB_CC_DST, Ity_I32);
384 args[3] = NULL;
385 return IRExpr_CCall("calculate_eflags_c", Ity_I32, args);
386}
387
388
sewardj0611d802004-07-11 02:37:54 +0000389/* -------------- Building the flags-thunk. -------------- */
390
391/* Build the flag-thunk following a flag-setting operation. If guard
392 is non-NULL, it is regarded as a controlling expression of type
393 Ity_Bit, and the thunk is only updated iff guard evaluates to 1 at
394 run-time. If guard is NULL, the update is always done. */
395
396/* This is for add/sub/adc/sbb/and/or/xor, where we need to
397 store the result value and the non-lvalue operand. */
398
399static void setFlags_SRC_DST1 ( IROp op8,
400 IRTemp src,
401 IRTemp dst1,
402 IRType ty )
403{
sewardjc2ac51e2004-07-12 01:03:26 +0000404 Bool logic = False;
sewardj0611d802004-07-11 02:37:54 +0000405 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
406 IRExpr* guard = NULL;
407
408 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
409
410 switch (op8) {
411 case Iop_Or8:
412 case Iop_And8:
sewardjc2ac51e2004-07-12 01:03:26 +0000413 case Iop_Xor8: ccOp += CC_OP_LOGICB; logic = True; break;
sewardj0611d802004-07-11 02:37:54 +0000414 case Iop_Add8: ccOp += CC_OP_ADDB; break;
415 case Iop_Sub8: ccOp += CC_OP_SUBB; break;
416 default: ppIROp(op8);
417 vpanic("setFlags_SRC_DST1(x86)");
418 }
419 stmt( IRStmt_Put(guard, OFFB_CC_OP, mkU32(ccOp)) );
sewardjc2ac51e2004-07-12 01:03:26 +0000420 stmt( IRStmt_Put(guard, OFFB_CC_SRC, logic ? mkU32(0)
421 : mkexpr(src)) );
sewardj0611d802004-07-11 02:37:54 +0000422 stmt( IRStmt_Put(guard, OFFB_CC_DST, mkexpr(dst1)) );
423}
424
425
426/* This is for shl/shr/sar, where we store the result value and the
427 result except shifted one bit less. And then only when the guard
428 says we can. */
429
430static void setFlags_DSTus_DST1 ( IROp op8,
431 IRTemp dstUS,
432 IRTemp dst1,
433 IRType ty,
434 IRExpr* guard )
435{
436 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
437
438 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
439 vassert(guard);
440
441 switch (op8) {
sewardjc2ac51e2004-07-12 01:03:26 +0000442 case Iop_Shr8:
443 case Iop_Sar8: ccOp += CC_OP_SARB; break;
sewardj0611d802004-07-11 02:37:54 +0000444 case Iop_Shl8: ccOp += CC_OP_SHLB; break;
445 default: ppIROp(op8);
446 vpanic("setFlags_DSTus_DST1(x86)");
447 }
448
449 /* CC_SRC = undershifted %d after, CC_DST = %d afterwards */
450 stmt( IRStmt_Put(guard, OFFB_CC_OP, mkU32(ccOp)) );
451 stmt( IRStmt_Put(guard, OFFB_CC_SRC, mkexpr(dstUS)) );
452 stmt( IRStmt_Put(guard, OFFB_CC_DST, mkexpr(dst1)) );
453}
454
455
456/* For the inc/dec case, we store the result value and the former
457 value of the carry flag, which unfortunately we have to compute. */
458
459static void setFlags_INC_DEC ( Bool inc, IRTemp dst, IRType ty )
460{
461 IRExpr* guard = NULL;
462 Int ccOp = inc ? CC_OP_INCB : CC_OP_DECB;
463
464 ccOp += ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
465 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
466
467 /* This has to come first, because calculating the C flag
468 may require reading all three OFFB_CC fields. */
469 stmt( IRStmt_Put(guard, OFFB_CC_SRC, mk_calculate_eflags_c()) );
470 stmt( IRStmt_Put(guard, OFFB_CC_OP, mkU32(ccOp)) );
471 stmt( IRStmt_Put(guard, OFFB_CC_DST, mkexpr(dst)) );
472}
473
474
sewardjcf780b42004-07-13 18:42:17 +0000475/* For multiplies, just remember the two operands and a
476 description of what kind of multiply. */
477
478static
479void setFlags_MUL ( IRType ty, IRTemp src1, IRTemp src2, UInt base_op )
480{
481 switch (ty) {
482 case Ity_I8:
483 stmt( IRStmt_Put( NULL, OFFB_CC_OP, mkU32(base_op+0) ) );
484 stmt( IRStmt_Put( NULL, OFFB_CC_SRC, unop(Iop_8Uto32,mkexpr(src1)) ) );
485 stmt( IRStmt_Put( NULL, OFFB_CC_DST, unop(Iop_8Uto32,mkexpr(src2)) ) );
486 break;
487 case Ity_I16:
488 stmt( IRStmt_Put( NULL, OFFB_CC_OP, mkU32(base_op+1) ) );
489 stmt( IRStmt_Put( NULL, OFFB_CC_SRC, unop(Iop_16Uto32,mkexpr(src1)) ) );
490 stmt( IRStmt_Put( NULL, OFFB_CC_DST, unop(Iop_16Uto32,mkexpr(src2)) ) );
491 break;
492 case Ity_I32:
493 stmt( IRStmt_Put( NULL, OFFB_CC_OP, mkU32(base_op+2) ) );
494 stmt( IRStmt_Put( NULL, OFFB_CC_SRC, mkexpr(src1) ) );
495 stmt( IRStmt_Put( NULL, OFFB_CC_DST, mkexpr(src2) ) );
496 break;
497 default:
498 vpanic("setFlags_MUL(x86)");
499 }
500}
501
502
sewardje87b4842004-07-10 12:23:30 +0000503/* Condition codes, using the Intel encoding. */
sewardj0611d802004-07-11 02:37:54 +0000504
sewardje87b4842004-07-10 12:23:30 +0000505typedef
506 enum {
507 CondO = 0, /* overflow */
508 CondNO = 1, /* no overflow */
sewardj77b86be2004-07-11 13:28:24 +0000509
sewardje87b4842004-07-10 12:23:30 +0000510 CondB = 2, /* below */
511 CondNB = 3, /* not below */
sewardj77b86be2004-07-11 13:28:24 +0000512
sewardje87b4842004-07-10 12:23:30 +0000513 CondZ = 4, /* zero */
514 CondNZ = 5, /* not zero */
sewardj77b86be2004-07-11 13:28:24 +0000515
sewardje87b4842004-07-10 12:23:30 +0000516 CondBE = 6, /* below or equal */
517 CondNBE = 7, /* not below or equal */
sewardj77b86be2004-07-11 13:28:24 +0000518
sewardje87b4842004-07-10 12:23:30 +0000519 CondS = 8, /* negative */
520 CondNS = 9, /* not negative */
sewardj77b86be2004-07-11 13:28:24 +0000521
sewardje87b4842004-07-10 12:23:30 +0000522 CondP = 10, /* parity even */
523 CondNP = 11, /* not parity even */
sewardj77b86be2004-07-11 13:28:24 +0000524
sewardje87b4842004-07-10 12:23:30 +0000525 CondL = 12, /* jump less */
526 CondNL = 13, /* not less */
sewardj77b86be2004-07-11 13:28:24 +0000527
sewardje87b4842004-07-10 12:23:30 +0000528 CondLE = 14, /* less or equal */
sewardj64e1d652004-07-12 14:00:46 +0000529 CondNLE = 15, /* not less or equal */
530
531 CondAlways = 16 /* HACK */
sewardje87b4842004-07-10 12:23:30 +0000532 }
533 Condcode;
534
535static Char* name_Condcode ( Condcode cond )
536{
537 switch (cond) {
538 case CondO: return "o";
539 case CondNO: return "no";
540 case CondB: return "b";
541 case CondNB: return "nb";
542 case CondZ: return "z";
543 case CondNZ: return "nz";
544 case CondBE: return "be";
545 case CondNBE: return "nbe";
546 case CondS: return "s";
547 case CondNS: return "ns";
548 case CondP: return "p";
549 case CondNP: return "np";
550 case CondL: return "l";
551 case CondNL: return "nl";
552 case CondLE: return "le";
553 case CondNLE: return "nle";
sewardj64e1d652004-07-12 14:00:46 +0000554 case CondAlways: return "ALWAYS";
sewardje87b4842004-07-10 12:23:30 +0000555 default: vpanic("name_Condcode");
556 }
557}
558
559static Condcode positiveIse_Condcode ( Condcode cond,
560 Bool* needInvert )
561{
562 vassert(cond >= CondO && cond <= CondNLE);
563 if (cond & 1) {
564 *needInvert = True;
565 return cond-1;
566 } else {
567 *needInvert = False;
568 return cond;
569 }
570}
571
572
573/* Get some particular flag to the lowest bit in a word. It's not
574 masked, tho. */
575static IRExpr* flag_to_bit0 ( UInt ccmask, IRTemp eflags )
576{
577 Int shifts = 0;
578 vassert(ccmask == CC_MASK_C || ccmask == CC_MASK_P
579 || ccmask == CC_MASK_A || ccmask == CC_MASK_Z
580 || ccmask == CC_MASK_S || ccmask == CC_MASK_O);
581 while ((ccmask & 1) == 0) {
582 ccmask >>= 1;
583 shifts++;
584 vassert(ccmask != 0);
585 }
586 if (shifts == 0)
587 return mkexpr(eflags);
588 else
589 return binop(Iop_Shr32, mkexpr(eflags), mkU32(shifts));
590}
591
592
593/* Calculate the eflags, and hence return a 1-bit expression
594 which is 1 iff the given condition-code test would succeed.
sewardj77b86be2004-07-11 13:28:24 +0000595 Returns a value :: Ity_Bit.
sewardje87b4842004-07-10 12:23:30 +0000596*/
597static IRExpr* calculate_condition ( Condcode cond )
598{
599 IRExpr *e;
sewardj77b86be2004-07-11 13:28:24 +0000600 IRTemp eflags = newTemp(Ity_I32);
601 Bool invert = (cond & 1) == 1;
sewardje90ad6a2004-07-10 19:02:10 +0000602
603 assign( eflags, cond == CondB ? mk_calculate_eflags_c()
604 : mk_calculate_eflags_all() );
sewardje87b4842004-07-10 12:23:30 +0000605
606 switch (cond) {
sewardj77b86be2004-07-11 13:28:24 +0000607 case CondNZ:
sewardje87b4842004-07-10 12:23:30 +0000608 case CondZ: /* ZF == 1 */
609 e = flag_to_bit0( CC_MASK_Z, eflags );
610 break;
sewardje90ad6a2004-07-10 19:02:10 +0000611 case CondB: /* CF == 1 */
612 e = flag_to_bit0( CC_MASK_C, eflags );
613 break;
sewardj77b86be2004-07-11 13:28:24 +0000614 case CondNBE:
sewardje87b4842004-07-10 12:23:30 +0000615 case CondBE: /* (CF or ZF) == 1 */
616 e = binop(Iop_Or32,
617 flag_to_bit0(CC_MASK_C,eflags),
618 flag_to_bit0(CC_MASK_Z,eflags) );
619 break;
sewardj940e8c92004-07-11 16:53:24 +0000620 case CondNS:
621 case CondS: /* SF == 1 */
622 e = flag_to_bit0( CC_MASK_S, eflags );
623 break;
sewardj0611d802004-07-11 02:37:54 +0000624 case CondP: /* PF == 1 */
625 e = flag_to_bit0( CC_MASK_P, eflags );
626 break;
sewardjc2ac51e2004-07-12 01:03:26 +0000627 case CondNL:
628 case CondL: /* (SF xor OF) == 1 */
629 e = binop(Iop_Xor32,
630 flag_to_bit0(CC_MASK_S,eflags),
631 flag_to_bit0(CC_MASK_O,eflags)
632 );
633 break;
sewardje87b4842004-07-10 12:23:30 +0000634 case CondLE: /* ((SF xor OF) or ZF) == 1 */
635 e = binop(Iop_Or32,
636 binop(Iop_Xor32,
637 flag_to_bit0(CC_MASK_S,eflags),
638 flag_to_bit0(CC_MASK_O,eflags)
639 ),
640 flag_to_bit0(CC_MASK_Z,eflags));
641 break;
642 default:
643 vex_printf("calculate_condition(%d)\n", (Int)cond);
644 vpanic("calculate_condition(x86)");
645 }
sewardj77b86be2004-07-11 13:28:24 +0000646 return
647 invert ? unop(Iop_32to1, unop(Iop_Not32, e))
648 : unop(Iop_32to1, e);
sewardje87b4842004-07-10 12:23:30 +0000649}
650
651
sewardjc9a65702004-07-07 16:32:57 +0000652//-- /*------------------------------------------------------------*/
653//-- /*--- CPU feature set stuff ---*/
654//-- /*--- This is a little out of place here, but it will do ---*/
655//-- /*--- for now. ---*/
656//-- /*------------------------------------------------------------*/
657//--
sewardje87b4842004-07-10 12:23:30 +0000658//-- #define VG_CPU_VENDOR_GENERIC 0
659//-- #define VG_CPU_VENDOR_INTEL 1
sewardjc9a65702004-07-07 16:32:57 +0000660//-- #define VG_CPU_VENDOR_AMD 2
661//--
662//-- static Int cpu_vendor = VG_CPU_VENDOR_GENERIC;
663//--
664//-- static const struct cpu_vendor {
665//-- const Char *vendorstr;
666//-- Int vendorid;
667//-- } cpu_vendors[] = {
668//-- { "GenuineIntel", VG_CPU_VENDOR_INTEL },
669//-- { "AuthenticAMD", VG_CPU_VENDOR_AMD },
670//-- };
671//--
672//-- static Int cpuid_level = -2; /* -2 -> not initialized */
673//-- static UInt cpu_features[VG_N_FEATURE_WORDS];
674//--
675//-- /* Standard macro to see if a specific flag is changeable */
676//-- static inline Bool flag_is_changeable(UInt flag)
677//-- {
678//-- UInt f1, f2;
679//--
680//-- asm("pushfl\n\t"
681//-- "pushfl\n\t"
682//-- "popl %0\n\t"
683//-- "movl %0,%1\n\t"
684//-- "xorl %2,%0\n\t"
685//-- "pushl %0\n\t"
686//-- "popfl\n\t"
687//-- "pushfl\n\t"
688//-- "popl %0\n\t"
689//-- "popfl\n\t"
690//-- : "=&r" (f1), "=&r" (f2)
691//-- : "ir" (flag));
692//--
693//-- return ((f1^f2) & flag) != 0;
694//-- }
695//--
696//--
697//-- /* Probe for the CPUID instruction */
698//-- static Bool has_cpuid(void)
699//-- {
700//-- return flag_is_changeable(EFlagID);
701//-- }
702//--
703//-- static void get_cpu_features(void)
704//-- {
705//-- Char vendorstr[13];
706//-- Int i;
707//--
708//-- if (!has_cpuid()) {
709//-- cpuid_level = -1;
710//-- return;
711//-- }
712//--
713//-- cpu_features[VG_INT_FEAT] |= (1 << (VG_X86_FEAT_CPUID%32));
714//--
715//-- VG_(cpuid)(0, &cpuid_level, (UInt *)&vendorstr[0], (UInt *)&vendorstr[8], (UInt *)&vendorstr[4]);
716//-- vendorstr[12] = '\0';
717//--
718//-- for(i = 0; i < sizeof(cpu_vendors)/sizeof(*cpu_vendors); i++)
719//-- if (VG_(memcmp)(vendorstr, cpu_vendors[i].vendorstr, 12) == 0) {
720//-- cpu_vendor = cpu_vendors[i].vendorid;
721//-- break;
722//-- }
723//--
724//-- if (cpuid_level >= 1)
725//-- VG_(cpuid)(1, NULL, NULL, &cpu_features[VG_EXT_FEAT], &cpu_features[VG_X86_FEAT]);
726//--
727//-- switch(cpu_vendor) {
728//-- case VG_CPU_VENDOR_AMD:
729//-- /* get AMD-specific flags */
730//-- VG_(cpuid)(0x80000001, NULL, NULL, NULL, &cpu_features[VG_AMD_FEAT]);
731//-- break;
732//--
733//-- default:
734//-- break;
735//-- }
736//-- }
737//--
738//-- Bool VG_(cpu_has_feature)(UInt feature)
739//-- {
740//-- UInt word = feature / 32;
741//-- UInt bit = feature % 32;
742//--
743//-- if (cpuid_level == -2)
744//-- get_cpu_features();
745//--
746//-- vg_assert(word >= 0 && word < VG_N_FEATURE_WORDS);
747//--
748//-- return !!(cpu_features[word] & (1 << bit));
749//-- }
750//--
751//-- /* The set of features we're willing to support for the client
752//--
753//-- This includes supported instruction set extensions, plus any
754//-- extensions which don't have any user-mode visible effect (but the
755//-- client may find interesting).
756//-- */
sewardjd1061ab2004-07-08 01:45:30 +0000757#define VG_X86_SUPPORTED_FEATURES \
758 ((1 << VG_X86_FEAT_FPU) | \
759 (1 << VG_X86_FEAT_VME) | \
760 (1 << VG_X86_FEAT_DE) | \
761 (1 << VG_X86_FEAT_PSE) | \
762 (1 << VG_X86_FEAT_TSC) | \
763 (0 << VG_X86_FEAT_MSR) | \
764 (1 << VG_X86_FEAT_PAE) | \
765 (1 << VG_X86_FEAT_MCE) | \
766 (1 << VG_X86_FEAT_CX8) | \
767 (1 << VG_X86_FEAT_APIC) | \
768 (0 << VG_X86_FEAT_SEP) | \
769 (1 << VG_X86_FEAT_MTRR) | \
770 (1 << VG_X86_FEAT_PGE) | \
771 (1 << VG_X86_FEAT_MCA) | \
772 (1 << VG_X86_FEAT_CMOV) | \
773 (1 << VG_X86_FEAT_PAT) | \
774 (1 << VG_X86_FEAT_PSE36) | \
775 (0 << VG_X86_FEAT_CLFSH) | \
776 (1 << VG_X86_FEAT_DS) | \
777 (1 << VG_X86_FEAT_ACPI) | \
778 (1 << VG_X86_FEAT_MMX) | \
779 (1 << VG_X86_FEAT_FXSR) | \
780 (1 << VG_X86_FEAT_SSE) | \
781 (1 << VG_X86_FEAT_SSE2) | \
782 (1 << VG_X86_FEAT_SS) | \
783 (1 << VG_X86_FEAT_HT) | \
784 (1 << VG_X86_FEAT_TM) | \
785 (0 << VG_X86_FEAT_IA64) | \
786 (1 << VG_X86_FEAT_PBE))
787
788#define VG_AMD_SUPPORTED_FEATURES \
789 ((0 << (VG_AMD_FEAT_SYSCALL % 32)) | \
790 (0 << (VG_AMD_FEAT_NXP % 32)) | \
791 (1 << (VG_AMD_FEAT_MMXEXT % 32)) | \
792 (0 << (VG_AMD_FEAT_FFXSR % 32)) | \
793 (0 << (VG_AMD_FEAT_LONGMODE % 32)) | \
794 (0 << (VG_AMD_FEAT_3DNOWEXT % 32)) | \
795 (0 << (VG_AMD_FEAT_3DNOW % 32)) | \
796 /* Common bits between standard features and AMD features */ \
797 (1 << VG_X86_FEAT_FPU) | \
798 (1 << VG_X86_FEAT_VME) | \
799 (1 << VG_X86_FEAT_DE) | \
800 (1 << VG_X86_FEAT_PSE) | \
801 (1 << VG_X86_FEAT_TSC) | \
802 (0 << VG_X86_FEAT_MSR) | \
803 (1 << VG_X86_FEAT_PAE) | \
804 (1 << VG_X86_FEAT_MCE) | \
805 (1 << VG_X86_FEAT_CX8) | \
806 (1 << VG_X86_FEAT_APIC) | \
807 (1 << VG_X86_FEAT_MTRR) | \
808 (1 << VG_X86_FEAT_PGE) | \
809 (1 << VG_X86_FEAT_MCA) | \
810 (1 << VG_X86_FEAT_CMOV) | \
811 (1 << VG_X86_FEAT_PAT) | \
812 (1 << VG_X86_FEAT_PSE36) | \
813 (1 << VG_X86_FEAT_MMX) | \
814 (1 << VG_X86_FEAT_FXSR))
815
816
sewardjc9a65702004-07-07 16:32:57 +0000817//-- /*
818//-- For simulating the cpuid instruction, we will
819//-- issue a "real" cpuid instruction and then mask out
820//-- the bits of the features we do not support currently (3dnow mostly).
821//-- We also claim to not support most CPUID operations.
822//--
823//-- Dirk Mueller <mueller@kde.org>
824//--
825//-- http://www.sandpile.org/ia32/cpuid.htm
826//--
827//-- references:
828//--
829//-- pre-MMX pentium:
830//--
831//-- <werner> cpuid words (0): 0x1 0x756e6547 0x6c65746e 0x49656e69
832//-- <werner> cpuid words (1): 0x52b 0x0 0x0 0x1bf
833//--
834//-- Updated to be more extensible about future vendor extensions and
835//-- vendor-specific parts of CPUID.
836//-- */
837//-- void VG_(helperc_CPUID)(UInt op, UInt *eax_ret, UInt *ebx_ret, UInt *ecx_ret, UInt *edx_ret)
838//-- {
839//-- UInt eax, ebx, ecx, edx;
840//--
841//-- if (cpuid_level == -2)
842//-- get_cpu_features(); /* for cpu_vendor */
843//--
844//-- VG_(cpuid)(op, &eax, &ebx, &ecx, &edx);
845//--
846//-- /* Common mangling */
847//-- switch(op) {
848//-- case 1:
849//-- edx &= VG_X86_SUPPORTED_FEATURES;
850//-- break;
851//--
852//-- case 0xd8000000: {
853//-- /* Implement some private information at 0xd8000000 */
854//-- static const Char valgrind_vendor[] = "ValgrindVCPU";
855//--
856//-- eax = 0xd8000000; /* max request */
857//-- ebx = *(UInt *)&valgrind_vendor[0];
858//-- ecx = *(UInt *)&valgrind_vendor[8];
859//-- edx = *(UInt *)&valgrind_vendor[4];
860//-- }
861//-- break;
862//-- }
863//--
864//-- /* Vendor-specific mangling of the results */
865//-- switch(cpu_vendor) {
866//-- case VG_CPU_VENDOR_INTEL:
867//-- switch(op) {
868//-- case 1:
869//-- ecx = 0; /* mask out all extended features for now */
870//-- break;
871//--
872//-- case 0x80000001:
873//-- ebx = ecx = edx = 0;
874//-- break;
875//-- }
876//-- break;
877//--
878//-- case VG_CPU_VENDOR_AMD:
879//-- switch(op) {
880//-- case 0x80000001:
881//-- edx &= VG_AMD_SUPPORTED_FEATURES;
882//-- break;
883//-- }
884//-- break;
885//-- }
886//--
887//-- *eax_ret = eax;
888//-- *ebx_ret = ebx;
889//-- *ecx_ret = ecx;
890//-- *edx_ret = edx;
891//-- }
892//--
893//--
894//-- /*------------------------------------------------------------*/
895//-- /*--- Here so it can be inlined everywhere. ---*/
896//-- /*------------------------------------------------------------*/
897//--
898//-- /* Allocate a new temp reg number. */
899//-- __inline__ Int VG_(get_new_temp) ( UCodeBlock* cb )
900//-- {
901//-- Int t = cb->nextTemp;
902//-- cb->nextTemp += 2;
903//-- return t;
904//-- }
905//--
906//-- Int VG_(get_new_shadow) ( UCodeBlock* cb )
907//-- {
908//-- Int t = cb->nextTemp;
909//-- cb->nextTemp += 2;
910//-- return SHADOW(t);
911//-- }
912
913
sewardj41f43bc2004-07-08 14:23:22 +0000914
915static Char* nameGrp1 ( Int opc_aux )
916{
917 static Char* grp1_names[8]
918 = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
919 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp1(x86)");
920 return grp1_names[opc_aux];
921}
922
sewardje90ad6a2004-07-10 19:02:10 +0000923static Char* nameGrp2 ( Int opc_aux )
924{
925 static Char* grp2_names[8]
926 = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
sewardjc2ac51e2004-07-12 01:03:26 +0000927 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp2(x86)");
sewardje90ad6a2004-07-10 19:02:10 +0000928 return grp2_names[opc_aux];
929}
930
sewardjc2ac51e2004-07-12 01:03:26 +0000931static Char* nameGrp4 ( Int opc_aux )
932{
933 static Char* grp4_names[8]
934 = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
935 if (opc_aux < 0 || opc_aux > 1) vpanic("nameGrp4(x86)");
936 return grp4_names[opc_aux];
937}
sewardj0611d802004-07-11 02:37:54 +0000938
939static Char* nameGrp5 ( Int opc_aux )
940{
941 static Char* grp5_names[8]
942 = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
943 if (opc_aux < 0 || opc_aux > 6) vpanic("nameGrp5(x86)");
944 return grp5_names[opc_aux];
945}
946
sewardjc9a65702004-07-07 16:32:57 +0000947//-- static Char* nameGrp8 ( Int opc_aux )
948//-- {
949//-- static Char* grp8_names[8]
950//-- = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
951//-- if (opc_aux < 4 || opc_aux > 7) VG_(core_panic)("nameGrp8");
952//-- return grp8_names[opc_aux];
953//-- }
954
955static
956const Char* nameIReg ( Int size, Int reg )
957{
958 static Char* ireg32_names[8]
959 = { "%eax", "%ecx", "%edx", "%ebx",
960 "%esp", "%ebp", "%esi", "%edi" };
961 static Char* ireg16_names[8]
962 = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di" };
963 static Char* ireg8_names[8]
964 = { "%al", "%cl", "%dl", "%bl",
965 "%ah{sp}", "%ch{bp}", "%dh{si}", "%bh{di}" };
966 if (reg < 0 || reg > 7) goto bad;
967 switch (size) {
968 case 4: return ireg32_names[reg];
969 case 2: return ireg16_names[reg];
970 case 1: return ireg8_names[reg];
971 }
972 bad:
973 vpanic("nameIReg(X86)");
974 return NULL; /*notreached*/
975}
976
977//-- const Char* VG_(name_of_seg_reg) ( Int sreg )
978//-- {
979//-- switch (sreg) {
980//-- case R_ES: return "%es";
981//-- case R_CS: return "%cs";
982//-- case R_SS: return "%ss";
983//-- case R_DS: return "%ds";
984//-- case R_FS: return "%fs";
985//-- case R_GS: return "%gs";
986//-- default: VG_(core_panic)("nameOfSegReg");
987//-- }
988//-- }
989//--
990//-- const Char* VG_(name_of_mmx_reg) ( Int mmxreg )
991//-- {
992//-- static const Char* mmx_names[8]
993//-- = { "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" };
994//-- if (mmxreg < 0 || mmxreg > 7) VG_(core_panic)("name_of_mmx_reg");
995//-- return mmx_names[mmxreg];
996//-- }
997//--
998//-- const Char* VG_(name_of_xmm_reg) ( Int xmmreg )
999//-- {
1000//-- static const Char* xmm_names[8]
1001//-- = { "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7" };
1002//-- if (xmmreg < 0 || xmmreg > 7) VG_(core_panic)("name_of_xmm_reg");
1003//-- return xmm_names[xmmreg];
1004//-- }
1005//--
1006//-- const Char* VG_(name_of_mmx_gran) ( UChar gran )
1007//-- {
1008//-- switch (gran) {
1009//-- case 0: return "b";
1010//-- case 1: return "w";
1011//-- case 2: return "d";
1012//-- case 3: return "q";
1013//-- default: VG_(core_panic)("name_of_mmx_gran");
1014//-- }
1015//-- }
1016
sewardj41f43bc2004-07-08 14:23:22 +00001017static Char nameISize ( Int size )
sewardjc9a65702004-07-07 16:32:57 +00001018{
1019 switch (size) {
1020 case 4: return 'l';
1021 case 2: return 'w';
1022 case 1: return 'b';
1023 default: vpanic("nameISize(x86)");
1024 }
1025}
1026
sewardjc9a65702004-07-07 16:32:57 +00001027//-- __inline__ static UInt LOW24 ( UInt x )
1028//-- {
1029//-- return x & 0x00FFFFFF;
1030//-- }
1031//--
1032//-- __inline__ static UInt HI8 ( UInt x )
1033//-- {
1034//-- return x >> 24;
1035//-- }
1036//--
sewardjc9a65702004-07-07 16:32:57 +00001037//-- /*------------------------------------------------------------*/
1038//-- /*--- Flag-related helpers. ---*/
1039//-- /*------------------------------------------------------------*/
1040//--
1041//-- static void setFlagsFromUOpcode ( UCodeBlock* cb, Int uopc )
1042//-- {
1043//-- switch (uopc) {
1044//-- case XOR: case OR: case AND:
1045//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZCP, FlagA); break;
1046//-- case ADC: case SBB:
1047//-- uFlagsRWU(cb, FlagC, FlagsOSZACP, FlagsEmpty); break;
1048//-- case MUL: case UMUL:
1049//-- uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP); break;
1050//-- case ADD: case SUB: case NEG:
1051//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty); break;
1052//-- case INC: case DEC:
1053//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZAP, FlagsEmpty); break;
1054//-- case SHR: case SAR: case SHL:
1055//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZCP, FlagA); break;
1056//-- case ROL: case ROR:
1057//-- uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsEmpty); break;
1058//-- case RCR: case RCL:
1059//-- uFlagsRWU(cb, FlagC, FlagsOC, FlagsEmpty); break;
1060//-- case NOT:
1061//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty); break;
1062//-- default:
1063//-- VG_(printf)("unhandled case is %s\n",
1064//-- VG_(name_UOpcode)(True, uopc));
1065//-- VG_(core_panic)("setFlagsFromUOpcode: unhandled case");
1066//-- }
1067//-- }
sewardjd1061ab2004-07-08 01:45:30 +00001068
1069/*------------------------------------------------------------*/
1070/*--- JMP helpers ---*/
1071/*------------------------------------------------------------*/
1072
sewardj78c19df2004-07-12 22:49:27 +00001073static void jmp_lit( IRJumpKind kind, Addr32 d32 )
sewardjd1061ab2004-07-08 01:45:30 +00001074{
sewardj78c19df2004-07-12 22:49:27 +00001075 irbb->next = IRNext_DJump( kind, IRConst_U32(d32) );
sewardjd1061ab2004-07-08 01:45:30 +00001076}
1077
sewardj78c19df2004-07-12 22:49:27 +00001078static void jmp_treg( IRJumpKind kind, IRTemp t )
sewardje05c42c2004-07-08 20:25:10 +00001079{
sewardj78c19df2004-07-12 22:49:27 +00001080 irbb->next = IRNext_IJump( kind, mkexpr(t) );
sewardje05c42c2004-07-08 20:25:10 +00001081}
sewardje87b4842004-07-10 12:23:30 +00001082
sewardj9334b0f2004-07-10 22:43:54 +00001083static void jcc_01( Condcode cond, Addr32 d32_false, Addr32 d32_true )
sewardje87b4842004-07-10 12:23:30 +00001084{
1085 Bool invert;
1086 Condcode condPos;
1087 condPos = positiveIse_Condcode ( cond, &invert );
1088 if (invert) {
sewardj78c19df2004-07-12 22:49:27 +00001089 stmt( IRStmt_Exit( calculate_condition(condPos),
1090 IRConst_U32(d32_false) ) );
1091 irbb->next = IRNext_DJump( Ijk_Boring, IRConst_U32(d32_true) );
sewardje87b4842004-07-10 12:23:30 +00001092 } else {
sewardj78c19df2004-07-12 22:49:27 +00001093 stmt( IRStmt_Exit( calculate_condition(condPos),
1094 IRConst_U32(d32_true) ) );
1095 irbb->next = IRNext_DJump( Ijk_Boring, IRConst_U32(d32_false) );
sewardje87b4842004-07-10 12:23:30 +00001096 }
1097}
sewardjc9a65702004-07-07 16:32:57 +00001098
1099
sewardjd1061ab2004-07-08 01:45:30 +00001100/*------------------------------------------------------------*/
1101/*--- Disassembling addressing modes ---*/
1102/*------------------------------------------------------------*/
sewardjc9a65702004-07-07 16:32:57 +00001103
sewardjd1061ab2004-07-08 01:45:30 +00001104static
1105UChar* sorbTxt ( UChar sorb )
1106{
1107 switch (sorb) {
1108 case 0: return ""; /* no override */
1109 case 0x3E: return "%ds";
1110 case 0x26: return "%es:";
1111 case 0x64: return "%fs:";
1112 case 0x65: return "%gs:";
1113 default: vpanic("sorbTxt(x86)");
1114 }
1115}
1116
1117
1118/* Tmp is a TempReg holding a virtual address. Convert it to a linear
1119 address by adding any required segment override as indicated by
1120 sorb. */
1121static
1122IRExpr* handleSegOverride ( UChar sorb, IRExpr* virtual )
1123{
1124 //Int sreg, tsreg;
1125
1126 if (sorb == 0)
1127 /* the common case - no override */
1128 return virtual;
1129
1130 unimplemented("segment overrides in new x86->IR phase");
1131#if 0
1132 switch (sorb) {
1133 case 0x3E: sreg = R_DS; break;
1134 case 0x26: sreg = R_ES; break;
1135 case 0x64: sreg = R_FS; break;
1136 case 0x65: sreg = R_GS; break;
1137 default: VG_(core_panic)("handleSegOverride");
1138 }
1139
1140 tsreg = newTemp(cb);
1141
1142 /* sreg -> tsreg */
1143 uInstr2(cb, GETSEG, 2, ArchRegS, sreg, TempReg, tsreg );
1144
1145 /* tmp += segment_base(ldt[tsreg]); also do limit check */
1146 uInstr2(cb, USESEG, 0, TempReg, tsreg, TempReg, tmp );
1147#endif
1148}
1149
1150
1151/* Generate IR to calculate an address indicated by a ModRM and
1152 following SIB bytes. The expression, and the number of bytes in
1153 the address mode, are returned. Note that this fn should not be
1154 called if the R/M part of the address denotes a register instead of
1155 memory. If print_codegen is true, text of the addressing mode is
sewardj940e8c92004-07-11 16:53:24 +00001156 placed in buf.
1157
1158 The computed address is stored in a new tempreg, and the
1159 identity of the tempreg is returned. */
1160
1161static IRTemp disAMode_copy2tmp ( IRExpr* addr32 )
1162{
1163 IRTemp tmp = newTemp(Ity_I32);
1164 assign( tmp, addr32 );
1165 return tmp;
1166}
sewardjd1061ab2004-07-08 01:45:30 +00001167
1168static
sewardj940e8c92004-07-11 16:53:24 +00001169IRTemp disAMode ( Int* len, UChar sorb, UInt delta, UChar* buf )
sewardjd1061ab2004-07-08 01:45:30 +00001170{
1171 UChar mod_reg_rm = getIByte(delta);
1172 delta++;
1173
1174 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1175 jump table seems a bit excessive.
1176 */
1177 mod_reg_rm &= 0xC7; /* is now XX000YYY */
1178 mod_reg_rm |= (mod_reg_rm >> 3); /* is now XX0XXYYY */
1179 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
1180 switch (mod_reg_rm) {
1181
1182 /* (%eax) .. (%edi), not including (%esp) or (%ebp).
1183 --> GET %reg, t
1184 */
1185 case 0x00: case 0x01: case 0x02: case 0x03:
1186 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1187 { UChar rm = mod_reg_rm;
1188 DIS(buf, "%s(%s)", sorbTxt(sorb), nameIReg(4,rm));
1189 *len = 1;
sewardj940e8c92004-07-11 16:53:24 +00001190 return disAMode_copy2tmp(
1191 handleSegOverride(sorb, getIReg(4,rm)));
sewardjd1061ab2004-07-08 01:45:30 +00001192 }
1193
1194 /* d8(%eax) ... d8(%edi), not including d8(%esp)
1195 --> GET %reg, t ; ADDL d8, t
1196 */
1197 case 0x08: case 0x09: case 0x0A: case 0x0B:
1198 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1199 { UChar rm = mod_reg_rm & 7;
1200 UInt d = getSDisp8(delta);
1201 DIS(buf, "%s%d(%s)", sorbTxt(sorb), d, nameIReg(4,rm));
1202 *len = 2;
sewardj940e8c92004-07-11 16:53:24 +00001203 return disAMode_copy2tmp(
1204 handleSegOverride(sorb,
1205 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001206 }
1207
1208 /* d32(%eax) ... d32(%edi), not including d32(%esp)
1209 --> GET %reg, t ; ADDL d8, t
1210 */
1211 case 0x10: case 0x11: case 0x12: case 0x13:
1212 /* ! 14 */ case 0x15: case 0x16: case 0x17:
1213 { UChar rm = mod_reg_rm & 7;
1214 UInt d = getUDisp32(delta);
1215 DIS(buf, "%s0x%x(%s)", sorbTxt(sorb), d, nameIReg(4,rm));
1216 *len = 5;
sewardj940e8c92004-07-11 16:53:24 +00001217 return disAMode_copy2tmp(
1218 handleSegOverride(sorb,
1219 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001220 }
1221
1222 /* a register, %eax .. %edi. This shouldn't happen. */
1223 case 0x18: case 0x19: case 0x1A: case 0x1B:
1224 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1225 vpanic("disAMode(x86): not an addr!");
1226
1227 /* a 32-bit literal address
1228 --> MOV d32, tmp
1229 */
1230 case 0x05:
1231 { UInt d = getUDisp32(delta);
1232 *len = 5;
1233 DIS(buf, "%s(0x%x)", sorbTxt(sorb), d);
sewardj940e8c92004-07-11 16:53:24 +00001234 return disAMode_copy2tmp(
1235 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001236 }
1237
1238 case 0x04: {
1239 /* SIB, with no displacement. Special cases:
1240 -- %esp cannot act as an index value.
1241 If index_r indicates %esp, zero is used for the index.
1242 -- when mod is zero and base indicates EBP, base is instead
1243 a 32-bit literal.
1244 It's all madness, I tell you. Extract %index, %base and
1245 scale from the SIB byte. The value denoted is then:
1246 | %index == %ESP && %base == %EBP
1247 = d32 following SIB byte
1248 | %index == %ESP && %base != %EBP
1249 = %base
1250 | %index != %ESP && %base == %EBP
1251 = d32 following SIB byte + (%index << scale)
1252 | %index != %ESP && %base != %ESP
1253 = %base + (%index << scale)
1254
1255 What happens to the souls of CPU architects who dream up such
1256 horrendous schemes, do you suppose?
1257 */
1258 UChar sib = getIByte(delta);
1259 UChar scale = (sib >> 6) & 3;
1260 UChar index_r = (sib >> 3) & 7;
1261 UChar base_r = sib & 7;
1262 delta++;
1263
1264 if (index_r != R_ESP && base_r != R_EBP) {
1265 DIS(buf, "%s(%s,%s,%d)", sorbTxt(sorb),
1266 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
1267 *len = 2;
sewardj940e8c92004-07-11 16:53:24 +00001268 return
1269 disAMode_copy2tmp(
sewardjd1061ab2004-07-08 01:45:30 +00001270 handleSegOverride(sorb,
1271 binop(Iop_Add32,
1272 getIReg(4,base_r),
1273 binop(Iop_Shl32, getIReg(4,index_r),
sewardj940e8c92004-07-11 16:53:24 +00001274 mkU32(scale)))));
sewardjd1061ab2004-07-08 01:45:30 +00001275 }
1276
1277 if (index_r != R_ESP && base_r == R_EBP) {
1278 UInt d = getUDisp32(delta);
1279 DIS(buf, "%s0x%x(,%s,%d)", sorbTxt(sorb), d,
1280 nameIReg(4,index_r), 1<<scale);
1281 *len = 6;
1282 return
sewardj940e8c92004-07-11 16:53:24 +00001283 disAMode_copy2tmp(
sewardjd1061ab2004-07-08 01:45:30 +00001284 handleSegOverride(sorb,
1285 binop(Iop_Add32,
1286 binop(Iop_Shl32, getIReg(4,index_r), mkU32(scale)),
sewardj940e8c92004-07-11 16:53:24 +00001287 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001288 }
1289
1290 if (index_r == R_ESP && base_r != R_EBP) {
1291 DIS(buf, "%s(%s,,)", sorbTxt(sorb), nameIReg(4,base_r));
1292 *len = 2;
sewardj940e8c92004-07-11 16:53:24 +00001293 return disAMode_copy2tmp(
1294 handleSegOverride(sorb, getIReg(4,base_r)));
sewardjd1061ab2004-07-08 01:45:30 +00001295 }
1296
1297 if (index_r == R_ESP && base_r == R_EBP) {
1298 UInt d = getUDisp32(delta);
1299 DIS(buf, "%s0x%x()", sorbTxt(sorb), d);
1300 *len = 6;
sewardj41f43bc2004-07-08 14:23:22 +00001301 vpanic("amode 8");
sewardj940e8c92004-07-11 16:53:24 +00001302 return disAMode_copy2tmp(
1303 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001304 }
1305
1306 vassert(0);
1307 }
1308
1309 /* SIB, with 8-bit displacement. Special cases:
1310 -- %esp cannot act as an index value.
1311 If index_r indicates %esp, zero is used for the index.
1312 Denoted value is:
1313 | %index == %ESP
1314 = d8 + %base
1315 | %index != %ESP
1316 = d8 + %base + (%index << scale)
1317 */
1318 case 0x0C: {
1319 UChar sib = getIByte(delta);
1320 UChar scale = (sib >> 6) & 3;
1321 UChar index_r = (sib >> 3) & 7;
1322 UChar base_r = sib & 7;
1323 UInt d = getSDisp8(delta+1);
1324
1325 if (index_r == R_ESP) {
1326 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb), d, nameIReg(4,base_r));
1327 *len = 3;
sewardj940e8c92004-07-11 16:53:24 +00001328 return disAMode_copy2tmp(
1329 handleSegOverride(sorb,
1330 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001331 } else {
1332 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), d,
1333 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
1334 *len = 3;
sewardj77b86be2004-07-11 13:28:24 +00001335 return
sewardj940e8c92004-07-11 16:53:24 +00001336 disAMode_copy2tmp(
1337 handleSegOverride(sorb,
sewardj77b86be2004-07-11 13:28:24 +00001338 binop(Iop_Add32,
1339 binop(Iop_Add32,
1340 getIReg(4,base_r),
1341 binop(Iop_Shl32,
1342 getIReg(4,index_r), mkU32(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001343 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001344 }
1345 vassert(0);
1346 }
1347
1348 /* SIB, with 32-bit displacement. Special cases:
1349 -- %esp cannot act as an index value.
1350 If index_r indicates %esp, zero is used for the index.
1351 Denoted value is:
1352 | %index == %ESP
1353 = d32 + %base
1354 | %index != %ESP
1355 = d32 + %base + (%index << scale)
1356 */
1357 case 0x14: {
1358 UChar sib = getIByte(delta);
1359 UChar scale = (sib >> 6) & 3;
1360 UChar index_r = (sib >> 3) & 7;
1361 UChar base_r = sib & 7;
1362 UInt d = getUDisp32(delta+1);
1363
1364 if (index_r == R_ESP) {
1365 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb), d, nameIReg(4,base_r));
1366 *len = 6;
sewardj940e8c92004-07-11 16:53:24 +00001367 return disAMode_copy2tmp(
1368 handleSegOverride(sorb,
1369 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001370 } else {
1371 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), d,
1372 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
1373 *len = 6;
sewardj9334b0f2004-07-10 22:43:54 +00001374 return
sewardj940e8c92004-07-11 16:53:24 +00001375 disAMode_copy2tmp(
1376 handleSegOverride(sorb,
sewardj9334b0f2004-07-10 22:43:54 +00001377 binop(Iop_Add32,
1378 binop(Iop_Add32,
1379 getIReg(4,base_r),
1380 binop(Iop_Shl32,
1381 getIReg(4,index_r), mkU32(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001382 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001383 }
1384 vassert(0);
1385 }
1386
1387 default:
1388 vpanic("disAMode(x86)");
1389 return 0; /*notreached*/
1390 }
1391}
1392
1393
1394/* Figure out the number of (insn-stream) bytes constituting the amode
1395 beginning at delta. Is useful for getting hold of literals beyond
1396 the end of the amode before it has been disassembled. */
1397
1398static UInt lengthAMode ( UInt delta )
1399{
1400 UChar mod_reg_rm = getIByte(delta); delta++;
1401
1402 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1403 jump table seems a bit excessive.
1404 */
1405 mod_reg_rm &= 0xC7; /* is now XX000YYY */
1406 mod_reg_rm |= (mod_reg_rm >> 3); /* is now XX0XXYYY */
1407 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
1408 switch (mod_reg_rm) {
1409
1410 /* (%eax) .. (%edi), not including (%esp) or (%ebp). */
1411 case 0x00: case 0x01: case 0x02: case 0x03:
1412 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1413 return 1;
1414
1415 /* d8(%eax) ... d8(%edi), not including d8(%esp). */
1416 case 0x08: case 0x09: case 0x0A: case 0x0B:
1417 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1418 return 2;
1419
1420 /* d32(%eax) ... d32(%edi), not including d32(%esp). */
1421 case 0x10: case 0x11: case 0x12: case 0x13:
1422 /* ! 14 */ case 0x15: case 0x16: case 0x17:
1423 return 5;
1424
1425 /* a register, %eax .. %edi. (Not an addr, but still handled.) */
1426 case 0x18: case 0x19: case 0x1A: case 0x1B:
1427 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1428 return 1;
1429
1430 /* a 32-bit literal address. */
1431 case 0x05: return 5;
1432
1433 /* SIB, no displacement. */
1434 case 0x04: {
1435 UChar sib = getIByte(delta);
1436 UChar base_r = sib & 7;
1437 if (base_r == R_EBP) return 6; else return 2;
1438 }
1439 /* SIB, with 8-bit displacement. */
1440 case 0x0C: return 3;
1441
1442 /* SIB, with 32-bit displacement. */
1443 case 0x14: return 6;
1444
1445 default:
1446 vpanic("lengthAMode");
1447 return 0; /*notreached*/
1448 }
1449}
1450
1451/*------------------------------------------------------------*/
1452/*--- Disassembling common idioms ---*/
1453/*------------------------------------------------------------*/
1454
sewardjc9a65702004-07-07 16:32:57 +00001455//-- static
1456//-- void codegen_XOR_reg_with_itself ( UCodeBlock* cb, Int size,
1457//-- Int ge_reg, Int tmp )
1458//-- {
1459//-- DIP("xor%c %s, %s\n", nameISize(size),
1460//-- nameIReg(size,ge_reg), nameIReg(size,ge_reg) );
1461//-- uInstr2(cb, MOV, size, Literal, 0, TempReg, tmp);
1462//-- uLiteral(cb, 0);
1463//-- uInstr2(cb, XOR, size, TempReg, tmp, TempReg, tmp);
1464//-- setFlagsFromUOpcode(cb, XOR);
1465//-- uInstr2(cb, PUT, size, TempReg, tmp, ArchReg, ge_reg);
1466//-- }
1467//--
sewardje87b4842004-07-10 12:23:30 +00001468/* Handle binary integer instructions of the form
1469 op E, G meaning
1470 op reg-or-mem, reg
1471 Is passed the a ptr to the modRM byte, the actual operation, and the
1472 data size. Returns the address advanced completely over this
1473 instruction.
1474
1475 E(src) is reg-or-mem
1476 G(dst) is reg.
1477
1478 If E is reg, --> GET %G, tmp
1479 OP %E, tmp
1480 PUT tmp, %G
1481
1482 If E is mem and OP is not reversible,
1483 --> (getAddr E) -> tmpa
1484 LD (tmpa), tmpa
1485 GET %G, tmp2
1486 OP tmpa, tmp2
1487 PUT tmp2, %G
1488
1489 If E is mem and OP is reversible
1490 --> (getAddr E) -> tmpa
1491 LD (tmpa), tmpa
1492 OP %G, tmpa
1493 PUT tmpa, %G
1494*/
1495static
1496UInt dis_op2_E_G ( UChar sorb,
1497 IROp op8,
1498 Bool keep,
1499 Int size,
1500 UInt delta0,
1501 Char* t_x86opc )
1502{
sewardj9334b0f2004-07-10 22:43:54 +00001503 UChar dis_buf[50];
1504 Int len;
sewardje87b4842004-07-10 12:23:30 +00001505 IRType ty = szToITy(size);
1506 IRTemp dst1 = newTemp(ty);
1507 IRTemp src = newTemp(ty);
1508 IRTemp dst0 = newTemp(ty);
1509 UChar rm = getUChar(delta0);
sewardj940e8c92004-07-11 16:53:24 +00001510 IRTemp addr = INVALID_IRTEMP;
sewardje87b4842004-07-10 12:23:30 +00001511
1512 if (epartIsReg(rm)) {
1513#if 0
1514 /* Specially handle XOR reg,reg, because that doesn't really
1515 depend on reg, and doing the obvious thing potentially
1516 generates a spurious value check failure due to the bogus
1517 dependency. */
1518 if (opc == XOR && gregOfRM(rm) == eregOfRM(rm)) {
1519 codegen_XOR_reg_with_itself ( cb, size, gregOfRM(rm), tmp );
1520 return 1+eip0;
1521 }
1522#endif
1523 assign( dst0, getIReg(size,gregOfRM(rm)) );
1524 assign( src, getIReg(size,eregOfRM(rm)) );
1525 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj0611d802004-07-11 02:37:54 +00001526 setFlags_SRC_DST1(op8, src, dst1, ty);
sewardje87b4842004-07-10 12:23:30 +00001527
1528 if (keep)
1529 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1530
1531 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1532 nameIReg(size,eregOfRM(rm)),
1533 nameIReg(size,gregOfRM(rm)));
1534 return 1+delta0;
sewardje87b4842004-07-10 12:23:30 +00001535 } else {
sewardj9334b0f2004-07-10 22:43:54 +00001536 /* E refers to memory */
1537 addr = disAMode ( &len, sorb, delta0, dis_buf);
1538 assign( dst0, getIReg(size,gregOfRM(rm)) );
sewardj940e8c92004-07-11 16:53:24 +00001539 assign( src, loadLE(szToITy(size), mkexpr(addr)) );
sewardj9334b0f2004-07-10 22:43:54 +00001540 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj0611d802004-07-11 02:37:54 +00001541 setFlags_SRC_DST1(op8, src, dst1, ty);
sewardj9334b0f2004-07-10 22:43:54 +00001542
sewardje87b4842004-07-10 12:23:30 +00001543 if (keep)
sewardj9334b0f2004-07-10 22:43:54 +00001544 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1545
sewardje87b4842004-07-10 12:23:30 +00001546 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1547 dis_buf,nameIReg(size,gregOfRM(rm)));
sewardj9334b0f2004-07-10 22:43:54 +00001548 return len+delta0;
sewardje87b4842004-07-10 12:23:30 +00001549 }
sewardje87b4842004-07-10 12:23:30 +00001550}
sewardje05c42c2004-07-08 20:25:10 +00001551
1552
1553
1554/* Handle binary integer instructions of the form
1555 op G, E meaning
1556 op reg, reg-or-mem
1557 Is passed the a ptr to the modRM byte, the actual operation, and the
1558 data size. Returns the address advanced completely over this
1559 instruction.
1560
1561 G(src) is reg.
1562 E(dst) is reg-or-mem
1563
1564 If E is reg, --> GET %E, tmp
1565 OP %G, tmp
1566 PUT tmp, %E
1567
1568 If E is mem, --> (getAddr E) -> tmpa
1569 LD (tmpa), tmpv
1570 OP %G, tmpv
1571 ST tmpv, (tmpa)
1572*/
1573static
1574UInt dis_op2_G_E ( UChar sorb,
1575 IROp op8,
1576 Bool keep,
1577 Int size,
1578 UInt delta0,
1579 Char* t_x86opc )
1580{
sewardje87b4842004-07-10 12:23:30 +00001581 UChar dis_buf[50];
1582 Int len;
sewardje05c42c2004-07-08 20:25:10 +00001583 IRType ty = szToITy(size);
1584 IRTemp dst1 = newTemp(ty);
1585 IRTemp src = newTemp(ty);
1586 IRTemp dst0 = newTemp(ty);
1587 UChar rm = getIByte(delta0);
sewardj940e8c92004-07-11 16:53:24 +00001588 IRTemp addr = INVALID_IRTEMP;
sewardje05c42c2004-07-08 20:25:10 +00001589
1590 if (epartIsReg(rm)) {
1591#if 0
1592 /* Specially handle XOR reg,reg, because that doesn't really
1593 depend on reg, and doing the obvious thing potentially
1594 generates a spurious value check failure due to the bogus
1595 dependency. */
1596 if (opc == XOR && gregOfRM(rm) == eregOfRM(rm)) {
1597 codegen_XOR_reg_with_itself ( cb, size, gregOfRM(rm), tmp );
1598 return 1+eip0;
1599 }
1600#endif
1601
1602 assign(dst0, getIReg(size,eregOfRM(rm)));
1603 assign(src, getIReg(size,gregOfRM(rm)));
1604 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj0611d802004-07-11 02:37:54 +00001605 setFlags_SRC_DST1(op8, src, dst1, ty);
sewardje05c42c2004-07-08 20:25:10 +00001606
1607 if (keep)
1608 putIReg(size, eregOfRM(rm), mkexpr(dst1));
1609
1610 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1611 nameIReg(size,gregOfRM(rm)),
1612 nameIReg(size,eregOfRM(rm)));
1613 return 1+delta0;
1614 }
1615
1616 /* E refers to memory */
1617 {
sewardje87b4842004-07-10 12:23:30 +00001618 addr = disAMode ( &len, sorb, delta0, dis_buf);
sewardj940e8c92004-07-11 16:53:24 +00001619 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardje87b4842004-07-10 12:23:30 +00001620 assign(src, getIReg(size,gregOfRM(rm)));
1621 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj0611d802004-07-11 02:37:54 +00001622 setFlags_SRC_DST1(op8, src, dst1, ty);
sewardje05c42c2004-07-08 20:25:10 +00001623
sewardje87b4842004-07-10 12:23:30 +00001624 if (keep)
sewardj940e8c92004-07-11 16:53:24 +00001625 storeLE(mkexpr(addr), mkexpr(dst1));
sewardje87b4842004-07-10 12:23:30 +00001626
sewardje05c42c2004-07-08 20:25:10 +00001627 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1628 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje87b4842004-07-10 12:23:30 +00001629 return len+delta0;
sewardje05c42c2004-07-08 20:25:10 +00001630 }
1631}
1632
1633
1634/* Handle move instructions of the form
1635 mov E, G meaning
1636 mov reg-or-mem, reg
1637 Is passed the a ptr to the modRM byte, and the data size. Returns
1638 the address advanced completely over this instruction.
1639
1640 E(src) is reg-or-mem
1641 G(dst) is reg.
1642
1643 If E is reg, --> GET %E, tmpv
1644 PUT tmpv, %G
1645
1646 If E is mem --> (getAddr E) -> tmpa
1647 LD (tmpa), tmpb
1648 PUT tmpb, %G
1649*/
1650static
1651UInt dis_mov_E_G ( UChar sorb,
1652 Int size,
1653 UInt delta0 )
1654{
1655 Int len;
1656 UChar rm = getIByte(delta0);
1657 UChar dis_buf[50];
1658
1659 if (epartIsReg(rm)) {
1660#if 0
1661 Int tmpv = newTemp(cb);
1662 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, tmpv);
1663 uInstr2(cb, PUT, size, TempReg, tmpv, ArchReg, gregOfRM(rm));
1664 DIP("mov%c %s,%s\n", nameISize(size),
1665 nameIReg(size,eregOfRM(rm)),
1666 nameIReg(size,gregOfRM(rm)));
1667 return 1+eip0;
1668#endif
1669 vassert(121221==0);
1670 }
1671
1672 /* E refers to memory */
1673 {
sewardj940e8c92004-07-11 16:53:24 +00001674 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
1675 putIReg(size, gregOfRM(rm), loadLE(szToITy(size), mkexpr(addr)));
sewardje05c42c2004-07-08 20:25:10 +00001676 DIP("mov%c %s,%s\n", nameISize(size),
1677 dis_buf,nameIReg(size,gregOfRM(rm)));
1678 return delta0+len;
1679 }
1680}
1681
1682
1683/* Handle move instructions of the form
1684 mov G, E meaning
1685 mov reg, reg-or-mem
1686 Is passed the a ptr to the modRM byte, and the data size. Returns
1687 the address advanced completely over this instruction.
1688
1689 G(src) is reg.
1690 E(dst) is reg-or-mem
1691
1692 If E is reg, --> GET %G, tmp
1693 PUT tmp, %E
1694
1695 If E is mem, --> (getAddr E) -> tmpa
1696 GET %G, tmpv
1697 ST tmpv, (tmpa)
1698*/
sewardjc9a65702004-07-07 16:32:57 +00001699static
1700UInt dis_mov_G_E ( UChar sorb,
1701 Int size,
1702 UInt delta0 )
1703{
sewardje05c42c2004-07-08 20:25:10 +00001704 Int len;
sewardjc9a65702004-07-07 16:32:57 +00001705 UChar rm = getIByte(delta0);
sewardje05c42c2004-07-08 20:25:10 +00001706 UChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00001707
1708 if (epartIsReg(rm)) {
sewardj41f43bc2004-07-08 14:23:22 +00001709 putIReg(size, eregOfRM(rm), getIReg(size, gregOfRM(rm)));
sewardjc9a65702004-07-07 16:32:57 +00001710 DIP("mov%c %s,%s\n", nameISize(size),
1711 nameIReg(size,gregOfRM(rm)),
1712 nameIReg(size,eregOfRM(rm)));
1713 return 1+delta0;
1714 }
1715
sewardjc9a65702004-07-07 16:32:57 +00001716 /* E refers to memory */
1717 {
sewardj940e8c92004-07-11 16:53:24 +00001718 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf);
1719 storeLE( mkexpr(addr), getIReg(size, gregOfRM(rm)) );
sewardjc9a65702004-07-07 16:32:57 +00001720 DIP("mov%c %s,%s\n", nameISize(size),
1721 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje05c42c2004-07-08 20:25:10 +00001722 return len+delta0;
sewardjc9a65702004-07-07 16:32:57 +00001723 }
sewardjc9a65702004-07-07 16:32:57 +00001724}
1725
1726
sewardj0611d802004-07-11 02:37:54 +00001727/* op $immediate, AL/AX/EAX. */
1728static
1729UInt dis_op_imm_A ( Int size,
1730 IROp op8,
1731 Bool keep,
1732 UInt delta,
1733 Char* t_x86opc )
1734{
1735 IRType ty = szToITy(size);
1736 IRTemp dst0 = newTemp(ty);
1737 IRTemp src = newTemp(ty);
1738 IRTemp dst1 = newTemp(ty);
1739 UInt lit = getUDisp(size,delta);
1740 assign(dst0, getIReg(size,R_EAX));
1741 assign(src, mkU(ty,lit));
1742 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
1743 setFlags_SRC_DST1(op8, src, dst1, ty);
1744
1745 if (keep)
1746 putIReg(size, R_EAX, mkexpr(dst1));
1747
1748 DIP("%s%c $0x%x, %s\n", t_x86opc, nameISize(size),
1749 lit, nameIReg(size,R_EAX));
1750 return delta+size;
1751}
sewardj9334b0f2004-07-10 22:43:54 +00001752
1753
1754/* Sign- and Zero-extending moves. */
1755static
1756UInt dis_movx_E_G ( UChar sorb,
1757 UInt delta, Int szs, Int szd, Bool sign_extend )
1758{
sewardj9334b0f2004-07-10 22:43:54 +00001759 UChar rm = getIByte(delta);
1760 if (epartIsReg(rm)) {
1761 putIReg(szd, gregOfRM(rm),
1762 unop(mkWidenOp(szs,szd,False),
1763 getIReg(szs,eregOfRM(rm))));
1764 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
1765 nameISize(szs), nameISize(szd),
1766 nameIReg(szs,eregOfRM(rm)),
1767 nameIReg(szd,gregOfRM(rm)));
1768 return 1+delta;
1769 }
1770
1771 /* E refers to memory */
1772 {
sewardj940e8c92004-07-11 16:53:24 +00001773 Int len;
1774 UChar dis_buf[50];
1775 IRTemp addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj0611d802004-07-11 02:37:54 +00001776
1777 putIReg(szd, gregOfRM(rm),
1778 unop(mkWidenOp(szs,szd,False),
sewardj940e8c92004-07-11 16:53:24 +00001779 loadLE(szToITy(szs),mkexpr(addr))));
sewardj9334b0f2004-07-10 22:43:54 +00001780 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
1781 nameISize(szs), nameISize(szd),
1782 dis_buf, nameIReg(szd,gregOfRM(rm)));
sewardj0611d802004-07-11 02:37:54 +00001783 return len+delta;
sewardj9334b0f2004-07-10 22:43:54 +00001784 }
1785}
1786
sewardjc9a65702004-07-07 16:32:57 +00001787//--
1788//-- /* Generate code to divide ArchRegs EDX:EAX / DX:AX / AX by the 32 /
1789//-- 16 / 8 bit quantity in the given TempReg. */
1790//-- static
1791//-- void codegen_div ( UCodeBlock* cb, Int sz, Int t, Bool signed_divide )
1792//-- {
1793//-- Int helper;
1794//-- Int ta = newTemp(cb);
1795//-- Int td = newTemp(cb);
1796//--
1797//-- switch (sz) {
1798//-- case 4: helper = (signed_divide ? VGOFF_(helper_idiv_64_32)
1799//-- : VGOFF_(helper_div_64_32));
1800//-- break;
1801//-- case 2: helper = (signed_divide ? VGOFF_(helper_idiv_32_16)
1802//-- : VGOFF_(helper_div_32_16));
1803//-- break;
1804//-- case 1: helper = (signed_divide ? VGOFF_(helper_idiv_16_8)
1805//-- : VGOFF_(helper_div_16_8));
1806//-- break;
1807//-- default: VG_(core_panic)("codegen_div");
1808//-- }
1809//-- uInstr0(cb, CALLM_S, 0);
1810//-- if (sz == 4 || sz == 2) {
1811//-- uInstr1(cb, PUSH, sz, TempReg, t);
1812//-- uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
1813//-- uInstr1(cb, PUSH, sz, TempReg, ta);
1814//-- uInstr2(cb, GET, sz, ArchReg, R_EDX, TempReg, td);
1815//-- uInstr1(cb, PUSH, sz, TempReg, td);
1816//-- uInstr1(cb, CALLM, 0, Lit16, helper);
1817//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsOSZACP);
1818//-- uInstr1(cb, POP, sz, TempReg, t);
1819//-- uInstr2(cb, PUT, sz, TempReg, t, ArchReg, R_EDX);
1820//-- uInstr1(cb, POP, sz, TempReg, t);
1821//-- uInstr2(cb, PUT, sz, TempReg, t, ArchReg, R_EAX);
1822//-- uInstr1(cb, CLEAR, 0, Lit16, 4);
1823//-- } else {
1824//-- uInstr1(cb, PUSH, 1, TempReg, t);
1825//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, ta);
1826//-- uInstr1(cb, PUSH, 2, TempReg, ta);
1827//-- uInstr2(cb, MOV, 1, Literal, 0, TempReg, td);
1828//-- uLiteral(cb, 0);
1829//-- uInstr1(cb, PUSH, 1, TempReg, td);
1830//-- uInstr1(cb, CALLM, 0, Lit16, helper);
1831//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsOSZACP);
1832//-- uInstr1(cb, POP, 1, TempReg, t);
1833//-- uInstr2(cb, PUT, 1, TempReg, t, ArchReg, R_AL);
1834//-- uInstr1(cb, POP, 1, TempReg, t);
1835//-- uInstr2(cb, PUT, 1, TempReg, t, ArchReg, R_AH);
1836//-- uInstr1(cb, CLEAR, 0, Lit16, 4);
1837//-- }
1838//-- uInstr0(cb, CALLM_E, 0);
1839//-- }
sewardj41f43bc2004-07-08 14:23:22 +00001840
1841
1842static
sewardje90ad6a2004-07-10 19:02:10 +00001843UInt dis_Grp1 ( UChar sorb,
sewardj41f43bc2004-07-08 14:23:22 +00001844 UInt delta, UChar modrm,
1845 Int am_sz, Int d_sz, Int sz, UInt d32 )
1846{
sewardje05c42c2004-07-08 20:25:10 +00001847 IROp op8;
sewardj41f43bc2004-07-08 14:23:22 +00001848 Int len;
1849 UChar dis_buf[50];
sewardje05c42c2004-07-08 20:25:10 +00001850 IRType ty = szToITy(sz);
1851 IRTemp dst1 = newTemp(ty);
1852 IRTemp src = newTemp(ty);
1853 IRTemp dst0 = newTemp(ty);
sewardj940e8c92004-07-11 16:53:24 +00001854 IRTemp addr = INVALID_IRTEMP;
sewardj41f43bc2004-07-08 14:23:22 +00001855
1856 switch (gregOfRM(modrm)) {
sewardje05c42c2004-07-08 20:25:10 +00001857 case 0: op8 = Iop_Add8; break; case 1: op8 = Iop_Or8; break;
sewardj940e8c92004-07-11 16:53:24 +00001858 // case 2: op8 = Iop_Adc8; break; case 3: op8 = Iop_Sbb8; break;
sewardje05c42c2004-07-08 20:25:10 +00001859 case 4: op8 = Iop_And8; break; case 5: op8 = Iop_Sub8; break;
1860 case 6: op8 = Iop_Xor8; break; case 7: op8 = Iop_Sub8; break;
sewardj41f43bc2004-07-08 14:23:22 +00001861 default: vpanic("dis_Grp1: unhandled case");
1862 }
sewardj41f43bc2004-07-08 14:23:22 +00001863
1864 if (epartIsReg(modrm)) {
1865 vassert(am_sz == 1);
1866
1867 assign(dst0, getIReg(sz,eregOfRM(modrm)));
1868 assign(src, mkU(ty,d32));
sewardje05c42c2004-07-08 20:25:10 +00001869 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj41f43bc2004-07-08 14:23:22 +00001870
sewardj0611d802004-07-11 02:37:54 +00001871 setFlags_SRC_DST1(op8, src, dst1, ty);
sewardj41f43bc2004-07-08 14:23:22 +00001872
1873 if (gregOfRM(modrm) < 7)
sewardje05c42c2004-07-08 20:25:10 +00001874 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardj41f43bc2004-07-08 14:23:22 +00001875
1876 delta += (am_sz + d_sz);
1877 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz), d32,
1878 nameIReg(sz,eregOfRM(modrm)));
1879 } else {
sewardje87b4842004-07-10 12:23:30 +00001880 addr = disAMode ( &len, sorb, delta, dis_buf);
sewardj41f43bc2004-07-08 14:23:22 +00001881
sewardj940e8c92004-07-11 16:53:24 +00001882 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj41f43bc2004-07-08 14:23:22 +00001883 assign(src, mkU(ty,d32));
sewardje05c42c2004-07-08 20:25:10 +00001884 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj41f43bc2004-07-08 14:23:22 +00001885
sewardj0611d802004-07-11 02:37:54 +00001886 setFlags_SRC_DST1(op8, src, dst1, ty);
sewardj41f43bc2004-07-08 14:23:22 +00001887
1888 if (gregOfRM(modrm) < 7)
sewardj940e8c92004-07-11 16:53:24 +00001889 storeLE(mkexpr(addr), mkexpr(dst1));
sewardj41f43bc2004-07-08 14:23:22 +00001890
1891 delta += (len+d_sz);
1892 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz),
1893 d32, dis_buf);
1894 }
1895 return delta;
1896}
1897
1898
sewardje90ad6a2004-07-10 19:02:10 +00001899/* Group 2 extended opcodes. */
1900static
1901UInt dis_Grp2 ( UChar sorb,
1902 UInt delta, UChar modrm,
1903 Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr )
1904{
1905 /* delta on entry points at the modrm byte. */
sewardj940e8c92004-07-11 16:53:24 +00001906 UChar dis_buf[50];
1907 Int len;
sewardje90ad6a2004-07-10 19:02:10 +00001908 IROp op8;
1909 IRType ty = szToITy(sz);
1910 IRTemp dst0 = newTemp(ty);
1911 IRTemp dst1 = newTemp(ty);
sewardj940e8c92004-07-11 16:53:24 +00001912 IRTemp addr = INVALID_IRTEMP;
sewardje90ad6a2004-07-10 19:02:10 +00001913 Bool isShift;
1914
1915 // IRTemp dst1 = newTemp(ty);
1916 // IRTemp src = newTemp(ty);
1917 // IRTemp dst0 = newTemp(ty);
1918
1919 vassert(sz == 1 || sz == 2 || sz == 4);
1920
1921#if 0
1922 switch (gregOfRM(modrm)) {
1923 case 0: op8 = Iop_RolROL; break; case 1: op8 = ROR; break;
1924 case 2: op8 = RCL; break; case 3: op8 = RCR; break;
1925 case 4: op8 = Iop_Shl8; break; case 5: op8 = Iop_Shr8; break;
sewardjc2ac51e2004-07-12 01:03:26 +00001926 case 7: op8 = Iop_Sar8; break;
sewardje90ad6a2004-07-10 19:02:10 +00001927 default: vpanic("dis_Grp2(Reg): unhandled case(x86)");
1928 }
1929#endif
1930
1931 /* Put value to shift/rotate in dst0. */
1932 if (epartIsReg(modrm)) {
1933 assign(dst0, getIReg(sz, eregOfRM(modrm)));
sewardj940e8c92004-07-11 16:53:24 +00001934 delta += (am_sz + d_sz);
sewardje90ad6a2004-07-10 19:02:10 +00001935 } else {
sewardj940e8c92004-07-11 16:53:24 +00001936 addr = disAMode ( &len, sorb, delta, dis_buf);
1937 assign(dst0, loadLE(ty,mkexpr(addr)));
1938 delta += len + d_sz;
sewardje90ad6a2004-07-10 19:02:10 +00001939 }
1940
1941 isShift = False;
1942 switch (gregOfRM(modrm)) { case 4: case 5: case 7: isShift = True; }
1943
1944 if (isShift) {
1945
1946 IRTemp subshift = newTemp(ty);
1947 IRTemp shift_amt = newTemp(ty);
1948 IRTemp guard = newTemp(Ity_Bit);
1949
1950 switch (gregOfRM(modrm)) {
1951 case 4: op8 = Iop_Shl8; break;
1952 case 5: op8 = Iop_Shr8; break;
sewardjc2ac51e2004-07-12 01:03:26 +00001953 case 7: op8 = Iop_Sar8; break;
sewardje90ad6a2004-07-10 19:02:10 +00001954 default: vpanic("dis_Grp2:shift"); break;
1955 }
1956
1957 /* shift_amt = shift_expr & mask */
1958 assign(shift_amt, binop(mkSizedOp(ty,Iop_And8),
1959 shift_expr, mkU(ty,8*sz-1)));
1960 /* dst1 = dst0 `shift` shift_amt */
1961 assign(dst1, binop(mkSizedOp(ty,op8),
1962 mkexpr(dst0), mkexpr(shift_amt)));
1963 /* subshift = dst0 `shift` (shift_amt - 1) */
1964 assign(subshift,
1965 binop(mkSizedOp(ty,op8),
1966 mkexpr(dst0),
1967 binop(mkSizedOp(ty,Iop_Sub8),
1968 mkexpr(shift_amt), mkU(ty,1))));
1969 /* guard = (shift_amt != 0) */
1970 assign(guard, binop(mkSizedOp(ty,Iop_CmpNE8),
1971 mkexpr(shift_amt), mkU(ty,0)));
1972
1973 /* Build the flags thunk. */
sewardj0611d802004-07-11 02:37:54 +00001974 setFlags_DSTus_DST1(op8, subshift, dst1, ty, mkexpr(guard));
sewardje90ad6a2004-07-10 19:02:10 +00001975 } else {
1976 /* Rotate */
1977 vpanic("dis_Grp2: rotate");
1978 }
1979
1980 /* Save result, and finish up. */
1981 if (epartIsReg(modrm)) {
1982 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
1983 if (print_codegen) {
1984 vex_printf("%s%c ",
1985 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
1986 ppIRExpr(shift_expr);
1987 vex_printf(", %s\n", nameIReg(sz,eregOfRM(modrm)));
1988 }
sewardje90ad6a2004-07-10 19:02:10 +00001989 } else {
sewardj940e8c92004-07-11 16:53:24 +00001990 storeLE(mkexpr(addr), mkexpr(dst1));
1991 if (print_codegen) {
1992 vex_printf("%s%c ",
1993 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
1994 ppIRExpr(shift_expr);
1995 vex_printf(", %s\n", dis_buf);
1996 }
sewardje90ad6a2004-07-10 19:02:10 +00001997 }
sewardje90ad6a2004-07-10 19:02:10 +00001998 return delta;
1999}
2000
2001
2002
sewardjc9a65702004-07-07 16:32:57 +00002003//-- /* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
2004//-- static
2005//-- Addr dis_Grp8_BT ( UCodeBlock* cb,
2006//-- UChar sorb,
2007//-- Addr eip, UChar modrm,
2008//-- Int am_sz, Int sz, UInt src_val )
2009//-- {
sewardjd1061ab2004-07-08 01:45:30 +00002010# define MODIFY_t2_AND_SET_CARRY_FLAG \
2011 /* t2 is the value to be op'd on. Copy to t_fetched, then \
2012 modify t2, if non-BT. */ \
2013 uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t_fetched); \
2014 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
2015 uLiteral(cb, v_mask); \
2016 switch (gregOfRM(modrm)) { \
2017 case 4: /* BT */ break; \
2018 case 5: /* BTS */ \
2019 uInstr2(cb, OR, sz, TempReg, t_mask, TempReg, t2); break; \
2020 case 6: /* BTR */ \
2021 uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t2); break; \
2022 case 7: /* BTC */ \
2023 uInstr2(cb, XOR, sz, TempReg, t_mask, TempReg, t2); break; \
2024 } \
2025 /* Copy relevant bit from t_fetched into carry flag. */ \
2026 uInstr2(cb, SHR, sz, Literal, 0, TempReg, t_fetched); \
2027 uLiteral(cb, src_val); \
2028 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
2029 uLiteral(cb, 1); \
2030 uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t_fetched); \
2031 uInstr1(cb, NEG, sz, TempReg, t_fetched); \
2032 setFlagsFromUOpcode(cb, NEG);
2033
2034
sewardjc9a65702004-07-07 16:32:57 +00002035//-- /* src_val denotes a d8.
2036//-- And eip on entry points at the modrm byte. */
2037//-- Int t1, t2, t_fetched, t_mask;
2038//-- UInt pair;
2039//-- Char dis_buf[50];
2040//-- UInt v_mask;
2041//--
2042//-- /* There is no 1-byte form of this instruction, AFAICS. */
2043//-- vg_assert(sz == 2 || sz == 4);
2044//--
2045//-- /* Limit src_val -- the bit offset -- to something within a word.
2046//-- The Intel docs say that literal offsets larger than a word are
2047//-- masked in this way. */
2048//-- switch (sz) {
2049//-- case 2: src_val &= 15; break;
2050//-- case 4: src_val &= 31; break;
2051//-- default: VG_(core_panic)("dis_Grp8_BT: invalid size");
2052//-- }
2053//--
2054//-- /* Invent a mask suitable for the operation. */
2055//--
2056//-- switch (gregOfRM(modrm)) {
2057//-- case 4: /* BT */ v_mask = 0; break;
2058//-- case 5: /* BTS */ v_mask = 1 << src_val; break;
2059//-- case 6: /* BTR */ v_mask = ~(1 << src_val); break;
2060//-- case 7: /* BTC */ v_mask = 1 << src_val; break;
2061//-- /* If this needs to be extended, probably simplest to make a
2062//-- new function to handle the other cases (0 .. 3). The
2063//-- Intel docs do however not indicate any use for 0 .. 3, so
2064//-- we don't expect this to happen. */
2065//-- default: VG_(core_panic)("dis_Grp8_BT");
2066//-- }
2067//-- /* Probably excessively paranoid. */
2068//-- if (sz == 2)
2069//-- v_mask &= 0x0000FFFF;
2070//--
2071//-- t1 = INVALID_TEMPREG;
2072//-- t_fetched = newTemp(cb);
2073//-- t_mask = newTemp(cb);
2074//--
2075//-- if (epartIsReg(modrm)) {
2076//-- vg_assert(am_sz == 1);
2077//-- t2 = newTemp(cb);
2078//--
2079//-- /* Fetch the value to be tested and modified. */
2080//-- uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t2);
2081//-- /* Do it! */
2082//-- MODIFY_t2_AND_SET_CARRY_FLAG;
2083//-- /* Dump the result back, if non-BT. */
2084//-- if (gregOfRM(modrm) != 4 /* BT */)
2085//-- uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, eregOfRM(modrm));
2086//--
2087//-- eip += (am_sz + 1);
2088//-- DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2089//-- src_val, nameIReg(sz,eregOfRM(modrm)));
2090//-- } else {
2091//-- pair = disAMode ( cb, sorb, eip, dis_buf);
2092//-- t1 = LOW24(pair);
2093//-- t2 = newTemp(cb);
2094//-- eip += HI8(pair);
2095//-- eip += 1;
2096//--
2097//-- /* Fetch the value to be tested and modified. */
2098//-- uInstr2(cb, LOAD, sz, TempReg, t1, TempReg, t2);
2099//-- /* Do it! */
2100//-- MODIFY_t2_AND_SET_CARRY_FLAG;
2101//-- /* Dump the result back, if non-BT. */
2102//-- if (gregOfRM(modrm) != 4 /* BT */) {
2103//-- uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
2104//-- }
2105//-- DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2106//-- src_val, dis_buf);
2107//-- }
2108//-- return eip;
2109//--
2110//-- # undef MODIFY_t2_AND_SET_CARRY_FLAG
2111//-- }
sewardjcf780b42004-07-13 18:42:17 +00002112
2113
2114
2115/* Generate ucode to multiply the value in EAX/AX/AL by the register
2116 specified by the ereg of modrm, and park the result in
2117 EDX:EAX/DX:AX/AX.
2118
2119 Viz, signed/unsigned widening multiply.
2120*/
2121static void codegen_mul_A_D_Reg ( Int sz,
2122 UChar modrm, Bool signed_multiply )
2123{
sewardjc9a65702004-07-07 16:32:57 +00002124//-- Int helper = signed_multiply
2125//-- ?
2126//-- (sz==1 ? VGOFF_(helper_imul_8_16)
2127//-- : (sz==2 ? VGOFF_(helper_imul_16_32)
2128//-- : VGOFF_(helper_imul_32_64)))
2129//-- :
2130//-- (sz==1 ? VGOFF_(helper_mul_8_16)
2131//-- : (sz==2 ? VGOFF_(helper_mul_16_32)
2132//-- : VGOFF_(helper_mul_32_64)));
sewardjcf780b42004-07-13 18:42:17 +00002133 IRType ty = szToITy(sz);
2134 IRTemp t1 = newTemp(ty);
2135 IRTemp t2 = newTemp(ty);
2136 IRTemp tr = newTemp(ty);
2137
sewardjc9a65702004-07-07 16:32:57 +00002138//-- uInstr0(cb, CALLM_S, 0);
2139//-- uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
sewardjcf780b42004-07-13 18:42:17 +00002140 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2141 assign( t2, getIReg(sz, R_EAX) );
2142
2143 switch (ty) {
2144 case Ity_I32: {
2145 IROp hiOp = signed_multiply ? Iop_MullS32_hi32 : Iop_MullU32_hi32;
2146 IRTemp trHi32 = newTemp(Ity_I32);
2147 setFlags_MUL ( Ity_I32, t1, t2,
2148 signed_multiply ? CC_OP_MULLSB : CC_OP_MULLUB );
2149 assign( tr, binop(Iop_Mul32, mkexpr(t1), mkexpr(t2) ) );
2150 assign( trHi32, binop(hiOp, mkexpr(t1), mkexpr(t2) ) );
2151 putIReg(4, R_EAX, mkexpr(tr));
2152 putIReg(4, R_EDX, mkexpr(trHi32));
2153 break;
2154 }
2155 default:
2156 vpanic("codegen_mul_A_D_Reg(x86)");
2157 }
2158 DIP("%s%c %s\n", signed_multiply ? "imul" : "mul",
2159 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2160}
2161
sewardjc9a65702004-07-07 16:32:57 +00002162//-- uInstr1(cb, PUSH, sz, TempReg, t1);
2163//-- uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
2164//-- uInstr1(cb, PUSH, sz, TempReg, ta);
2165//-- uInstr1(cb, CALLM, 0, Lit16, helper);
2166//-- uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP);
2167//-- if (sz > 1) {
2168//-- uInstr1(cb, POP, sz, TempReg, t1);
2169//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EDX);
2170//-- uInstr1(cb, POP, sz, TempReg, t1);
2171//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EAX);
2172//-- } else {
2173//-- uInstr1(cb, CLEAR, 0, Lit16, 4);
2174//-- uInstr1(cb, POP, 2, TempReg, t1);
2175//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
2176//-- }
2177//-- uInstr0(cb, CALLM_E, 0);
sewardjc9a65702004-07-07 16:32:57 +00002178//--
2179//-- }
2180//--
2181//--
2182//-- /* Generate ucode to multiply the value in EAX/AX/AL by the value in
2183//-- TempReg temp, and park the result in EDX:EAX/DX:AX/AX. */
2184//-- static void codegen_mul_A_D_Temp ( UCodeBlock* cb, Int sz,
2185//-- Int temp, Bool signed_multiply,
2186//-- UChar* dis_buf )
2187//-- {
2188//-- Int helper = signed_multiply
2189//-- ?
2190//-- (sz==1 ? VGOFF_(helper_imul_8_16)
2191//-- : (sz==2 ? VGOFF_(helper_imul_16_32)
2192//-- : VGOFF_(helper_imul_32_64)))
2193//-- :
2194//-- (sz==1 ? VGOFF_(helper_mul_8_16)
2195//-- : (sz==2 ? VGOFF_(helper_mul_16_32)
2196//-- : VGOFF_(helper_mul_32_64)));
2197//-- Int t1 = newTemp(cb);
2198//-- uInstr0(cb, CALLM_S, 0);
2199//-- uInstr1(cb, PUSH, sz, TempReg, temp);
2200//-- uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
2201//-- uInstr1(cb, PUSH, sz, TempReg, t1);
2202//-- uInstr1(cb, CALLM, 0, Lit16, helper);
2203//-- uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP);
2204//-- if (sz > 1) {
2205//-- uInstr1(cb, POP, sz, TempReg, t1);
2206//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EDX);
2207//-- uInstr1(cb, POP, sz, TempReg, t1);
2208//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EAX);
2209//-- } else {
2210//-- uInstr1(cb, CLEAR, 0, Lit16, 4);
2211//-- uInstr1(cb, POP, 2, TempReg, t1);
2212//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
2213//-- }
2214//-- uInstr0(cb, CALLM_E, 0);
2215//-- DIP("%s%c %s\n", signed_multiply ? "imul" : "mul",
2216//-- nameISize(sz), dis_buf);
2217//-- }
2218//--
sewardj940e8c92004-07-11 16:53:24 +00002219
2220/* Group 3 extended opcodes. */
2221static
2222UInt dis_Grp3 ( UChar sorb, Int sz, UInt delta )
2223{
sewardjc2ac51e2004-07-12 01:03:26 +00002224 UInt d32;
sewardj940e8c92004-07-11 16:53:24 +00002225 UChar modrm;
2226 UChar dis_buf[50];
sewardjc2ac51e2004-07-12 01:03:26 +00002227 Int len;
2228 IRTemp addr;
sewardj940e8c92004-07-11 16:53:24 +00002229 IRType ty = szToITy(sz);
2230 IRTemp t1 = newTemp(ty);
sewardjc2ac51e2004-07-12 01:03:26 +00002231 // IRTemp t2 = INVALID_IRTEMP;
sewardj940e8c92004-07-11 16:53:24 +00002232 IRTemp dst1, src, dst0;
2233 modrm = getIByte(delta);
2234 if (epartIsReg(modrm)) {
2235 switch (gregOfRM(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002236 case 0: { /* TEST */
2237 delta++; d32 = getUDisp(sz, delta); delta += sz;
2238 dst1 = newTemp(ty);
2239 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2240 getIReg(sz,eregOfRM(modrm)),
2241 mkU(ty,d32)));
2242 setFlags_SRC_DST1( Iop_And8, INVALID_IRTEMP, dst1, ty );
2243 DIP("test%c $0x%x, %s\n", nameISize(sz), d32,
2244 nameIReg(sz, eregOfRM(modrm)));
2245 break;
2246 }
sewardj940e8c92004-07-11 16:53:24 +00002247 case 2: /* NOT */
2248 delta++;
2249 putIReg(sz, eregOfRM(modrm),
2250 unop(mkSizedOp(ty,Iop_Not8),
2251 getIReg(sz, eregOfRM(modrm))));
2252 DIP("not%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2253 break;
2254 case 3: /* NEG */
2255 delta++;
2256 dst0 = newTemp(ty);
2257 src = newTemp(ty);
2258 dst1 = newTemp(ty);
2259 assign(dst0, getIReg(sz,eregOfRM(modrm)));
2260 assign(src, mkU(ty,0));
2261 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8),mkexpr(src), mkexpr(dst0)));
2262 setFlags_SRC_DST1(Iop_Sub8, src, dst1, ty);
2263 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
2264 DIP("neg%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2265 break;
sewardjcf780b42004-07-13 18:42:17 +00002266 case 4: /* MUL (unsigned widening) */
2267 delta++;
2268 codegen_mul_A_D_Reg ( sz, modrm, False );
2269 break;
sewardjc9a65702004-07-07 16:32:57 +00002270//-- case 5: /* IMUL */
2271//-- eip++;
2272//-- codegen_mul_A_D_Reg ( cb, sz, modrm, True );
2273//-- break;
2274//-- case 6: /* DIV */
2275//-- eip++;
2276//-- uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
2277//-- codegen_div ( cb, sz, t1, False );
2278//-- DIP("div%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2279//-- break;
2280//-- case 7: /* IDIV */
2281//-- eip++;
2282//-- uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
2283//-- codegen_div ( cb, sz, t1, True );
2284//-- DIP("idiv%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2285//-- break;
sewardj940e8c92004-07-11 16:53:24 +00002286 default:
2287 vex_printf(
2288 "unhandled Grp3(R) case %d\n", (UInt)gregOfRM(modrm));
2289 vpanic("Grp3(x86)");
2290 }
2291 } else {
sewardjc2ac51e2004-07-12 01:03:26 +00002292 addr = disAMode ( &len, sorb, delta, dis_buf );
2293 t1 = newTemp(ty);
2294 delta += len;
2295 assign(t1, loadLE(ty,mkexpr(addr)));
2296 switch (gregOfRM(modrm)) {
2297 case 0: { /* TEST */
2298 d32 = getUDisp(sz, delta); delta += sz;
2299 dst1 = newTemp(ty);
2300 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2301 mkexpr(t1), mkU(ty,d32)));
2302 setFlags_SRC_DST1( Iop_And8, INVALID_IRTEMP, dst1, ty );
2303 DIP("test%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
2304 break;
2305 }
sewardjc9a65702004-07-07 16:32:57 +00002306//-- case 2: /* NOT */
2307//-- uInstr1(cb, NOT, sz, TempReg, t1);
2308//-- setFlagsFromUOpcode(cb, NOT);
2309//-- uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
2310//-- DIP("not%c %s\n", nameISize(sz), dis_buf);
2311//-- break;
sewardj0c12ea82004-07-12 08:18:16 +00002312 case 3: /* NEG */
2313 dst0 = newTemp(ty);
2314 src = newTemp(ty);
2315 dst1 = newTemp(ty);
2316 assign(dst0, mkexpr(t1));
2317 assign(src, mkU(ty,0));
2318 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8),mkexpr(src), mkexpr(dst0)));
2319 setFlags_SRC_DST1(Iop_Sub8, src, dst1, ty);
2320 storeLE( mkexpr(addr), mkexpr(dst1) );
2321 DIP("neg%c %s\n", nameISize(sz), dis_buf);
2322 break;
sewardjc9a65702004-07-07 16:32:57 +00002323//-- case 4: /* MUL */
2324//-- codegen_mul_A_D_Temp ( cb, sz, t1, False,
2325//-- dis_buf );
2326//-- break;
2327//-- case 5: /* IMUL */
2328//-- codegen_mul_A_D_Temp ( cb, sz, t1, True, dis_buf );
2329//-- break;
2330//-- case 6: /* DIV */
2331//-- codegen_div ( cb, sz, t1, False );
2332//-- DIP("div%c %s\n", nameISize(sz), dis_buf);
2333//-- break;
2334//-- case 7: /* IDIV */
2335//-- codegen_div ( cb, sz, t1, True );
2336//-- DIP("idiv%c %s\n", nameISize(sz), dis_buf);
2337//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +00002338 default:
2339 vex_printf(
2340 "unhandled Grp3(M) case %d\n", (UInt)gregOfRM(modrm));
2341 vpanic("Grp3(x86)");
2342 }
sewardj940e8c92004-07-11 16:53:24 +00002343 }
2344 return delta;
2345}
2346
2347
sewardjc2ac51e2004-07-12 01:03:26 +00002348/* Group 4 extended opcodes. */
2349static
2350UInt dis_Grp4 ( UChar sorb, UInt delta )
2351{
2352 Int t1, t2;
2353 // UInt pair;
2354 UChar modrm;
2355 //UChar dis_buf[50];
2356 t1 = t2 = INVALID_IRTEMP;
2357 IRType ty = Ity_I8;
2358
2359 modrm = getIByte(delta);
2360 if (epartIsReg(modrm)) {
2361 t1 = newTemp(ty);
sewardjc9a65702004-07-07 16:32:57 +00002362//-- uInstr2(cb, GET, 1, ArchReg, eregOfRM(modrm), TempReg, t1);
sewardjc2ac51e2004-07-12 01:03:26 +00002363 assign(t1, getIReg(1, eregOfRM(modrm)));
2364 switch (gregOfRM(modrm)) {
sewardjc9a65702004-07-07 16:32:57 +00002365//-- case 0: /* INC */
2366//-- uInstr1(cb, INC, 1, TempReg, t1);
2367//-- setFlagsFromUOpcode(cb, INC);
2368//-- uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, eregOfRM(modrm));
2369//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +00002370 case 1: /* DEC */
2371 t2 = newTemp(ty);
2372 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
2373 putIReg(1, eregOfRM(modrm), mkexpr(t2));
2374 setFlags_INC_DEC( False, t2, ty );
2375 break;
2376 default:
2377 vex_printf(
2378 "unhandled Grp4(R) case %d\n", (UInt)gregOfRM(modrm));
2379 vpanic("Grp4(x86)");
2380 }
2381 delta++;
2382 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)),
2383 nameIReg(1, eregOfRM(modrm)));
2384 } else {
2385 vassert(0);
sewardjc9a65702004-07-07 16:32:57 +00002386//-- pair = disAMode ( cb, sorb, eip, dis_buf );
2387//-- t2 = LOW24(pair);
2388//-- t1 = newTemp(cb);
2389//-- uInstr2(cb, LOAD, 1, TempReg, t2, TempReg, t1);
2390//-- switch (gregOfRM(modrm)) {
2391//-- case 0: /* INC */
2392//-- uInstr1(cb, INC, 1, TempReg, t1);
2393//-- setFlagsFromUOpcode(cb, INC);
2394//-- uInstr2(cb, STORE, 1, TempReg, t1, TempReg, t2);
2395//-- break;
2396//-- case 1: /* DEC */
2397//-- uInstr1(cb, DEC, 1, TempReg, t1);
2398//-- setFlagsFromUOpcode(cb, DEC);
2399//-- uInstr2(cb, STORE, 1, TempReg, t1, TempReg, t2);
2400//-- break;
2401//-- default:
2402//-- VG_(printf)(
2403//-- "unhandled Grp4(M) case %d\n", (UInt)gregOfRM(modrm));
2404//-- VG_(core_panic)("Grp4");
2405//-- }
2406//-- eip += HI8(pair);
2407//-- DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)), dis_buf);
sewardjc2ac51e2004-07-12 01:03:26 +00002408 }
2409 return delta;
2410}
sewardj0611d802004-07-11 02:37:54 +00002411
2412
2413/* Group 5 extended opcodes. */
2414static
2415UInt dis_Grp5 ( UChar sorb, Int sz, UInt delta, Bool* isEnd )
2416{
2417 Int len;
2418 UChar modrm;
2419 UChar dis_buf[50];
sewardj940e8c92004-07-11 16:53:24 +00002420 IRTemp addr = INVALID_IRTEMP;
sewardj0611d802004-07-11 02:37:54 +00002421 IRType ty = szToITy(sz);
2422 IRTemp t1 = newTemp(ty);
2423 IRTemp t2 = INVALID_IRTEMP;
2424
2425 modrm = getIByte(delta);
2426 if (epartIsReg(modrm)) {
sewardj940e8c92004-07-11 16:53:24 +00002427 assign(t1, getIReg(sz,eregOfRM(modrm)));
sewardj0611d802004-07-11 02:37:54 +00002428 switch (gregOfRM(modrm)) {
sewardjc9a65702004-07-07 16:32:57 +00002429//-- case 0: /* INC */
2430//-- uInstr1(cb, INC, sz, TempReg, t1);
2431//-- setFlagsFromUOpcode(cb, INC);
2432//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
2433//-- break;
2434//-- case 1: /* DEC */
2435//-- uInstr1(cb, DEC, sz, TempReg, t1);
2436//-- setFlagsFromUOpcode(cb, DEC);
2437//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
2438//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +00002439 case 2: /* call Ev */
2440 vassert(sz == 4);
2441 t2 = newTemp(Ity_I32);
2442 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
2443 putIReg(4, R_ESP, mkexpr(t2));
2444 storeLE( mkexpr(t2), mkU32(guest_eip+delta+1));
sewardj78c19df2004-07-12 22:49:27 +00002445 jmp_treg(Ijk_Call,t1);
sewardjc2ac51e2004-07-12 01:03:26 +00002446 *isEnd = True;
2447 break;
sewardj0611d802004-07-11 02:37:54 +00002448 case 4: /* jmp Ev */
2449 vassert(sz == 4);
sewardj78c19df2004-07-12 22:49:27 +00002450 jmp_treg(Ijk_Boring,t1);
sewardj0611d802004-07-11 02:37:54 +00002451 *isEnd = True;
2452 break;
2453 default:
2454 vex_printf(
2455 "unhandled Grp5(R) case %d\n", (UInt)gregOfRM(modrm));
2456 vpanic("Grp5(x86)");
2457 }
2458 delta++;
2459 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
2460 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2461 } else {
2462 addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj940e8c92004-07-11 16:53:24 +00002463 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj0611d802004-07-11 02:37:54 +00002464 switch (gregOfRM(modrm)) {
2465 case 0: /* INC */
2466 t2 = newTemp(ty);
2467 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
2468 mkexpr(t1), mkU(ty,1)));
2469 setFlags_INC_DEC( True, t2, ty );
sewardj940e8c92004-07-11 16:53:24 +00002470 storeLE(mkexpr(addr),mkexpr(t2));
sewardj0611d802004-07-11 02:37:54 +00002471 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002472 case 1: /* DEC */
2473 t2 = newTemp(ty);
2474 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
2475 mkexpr(t1), mkU(ty,1)));
2476 setFlags_INC_DEC( False, t2, ty );
2477 storeLE(mkexpr(addr),mkexpr(t2));
2478 break;
sewardj77b86be2004-07-11 13:28:24 +00002479 case 2: /* call Ev */
2480 vassert(sz == 4);
2481 t2 = newTemp(Ity_I32);
2482 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
2483 putIReg(4, R_ESP, mkexpr(t2));
2484 storeLE( mkexpr(t2), mkU32(guest_eip+delta+len));
sewardj78c19df2004-07-12 22:49:27 +00002485 jmp_treg(Ijk_Call,t1);
sewardj77b86be2004-07-11 13:28:24 +00002486 *isEnd = True;
2487 break;
2488 case 4: /* JMP Ev */
2489 vassert(sz == 4);
sewardj78c19df2004-07-12 22:49:27 +00002490 jmp_treg(Ijk_Boring,t1);
sewardj77b86be2004-07-11 13:28:24 +00002491 *isEnd = True;
2492 break;
sewardj0c12ea82004-07-12 08:18:16 +00002493 case 6: /* PUSH Ev */
2494 vassert(sz == 4 || sz == 2);
2495 t2 = newTemp(Ity_I32);
2496 assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
2497 putIReg(4, R_ESP, mkexpr(t2) );
2498 storeLE( mkexpr(t2), mkexpr(t1) );
2499 break;
sewardj0611d802004-07-11 02:37:54 +00002500 default:
2501 vex_printf(
2502 "unhandled Grp5(M) case %d\n", (UInt)gregOfRM(modrm));
2503 vpanic("Grp5(x86)");
2504 }
2505 delta += len;
2506 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
2507 nameISize(sz), dis_buf);
2508 }
2509 return delta;
2510}
2511
sewardj64e1d652004-07-12 14:00:46 +00002512/*------------------------------------------------------------*/
2513/*--- Disassembling string ops (including REP prefixes) ---*/
2514/*------------------------------------------------------------*/
2515
2516/* Code shared by all the string ops */
2517static
2518void dis_string_op_increment(Int sz, Int t_inc)
2519{
2520 if (sz == 4 || sz == 2) {
2521 assign( t_inc,
2522 binop(Iop_Shl32, IRExpr_Get( OFFB_DFLAG, Ity_I32 ),
2523 mkU32(sz/2) ) );
2524 } else {
2525 assign( t_inc,
2526 IRExpr_Get( OFFB_DFLAG, Ity_I32 ) );
2527 }
2528}
2529
2530#if 0
2531static
2532void dis_string_op( void (*dis_OP)( Int, IRTemp ),
2533 Int sz, Char* name, UChar sorb )
2534{
2535 IRTemp t_inc = newTemp(Ity_I32);
2536 vassert(sorb == 0);
2537 dis_string_op_increment(sz, t_inc);
2538 dis_OP( sz, t_inc );
2539 DIP("%s%c\n", name, nameISize(sz));
2540}
2541#endif
2542
2543static
2544void dis_MOVS ( Int sz, IRTemp t_inc )
2545{
2546 IRType ty = szToITy(sz);
2547 //IRTemp tv = newTemp(ty); /* value being copied */
2548 IRTemp td = newTemp(Ity_I32); /* EDI */
2549 IRTemp ts = newTemp(Ity_I32); /* ESI */
2550
2551 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
2552 //uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
2553 assign( td, getIReg(4, R_EDI) );
2554 assign( ts, getIReg(4, R_ESI) );
2555
2556 //uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tv);
2557 //uInstr2(cb, STORE,sz, TempReg, tv, TempReg, td);
2558 storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
2559
2560 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
2561 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
2562
2563 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2564 //uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
2565 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
2566 putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
2567}
2568
sewardjc9a65702004-07-07 16:32:57 +00002569//-- static
2570//-- void dis_LODS ( UCodeBlock* cb, Int sz, Int t_inc )
2571//-- {
2572//-- Int ta = newTemp(cb); /* EAX */
2573//-- Int ts = newTemp(cb); /* ESI */
2574//--
2575//-- uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
2576//-- uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, ta);
2577//-- uInstr2(cb, PUT, sz, TempReg, ta, ArchReg, R_EAX);
2578//--
2579//-- uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
2580//-- uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
2581//-- }
sewardj64e1d652004-07-12 14:00:46 +00002582
2583static
2584void dis_STOS ( Int sz, IRTemp t_inc )
2585{
2586 IRType ty = szToITy(sz);
2587 IRTemp ta = newTemp(ty); /* EAX */
2588 IRTemp td = newTemp(Ity_I32); /* EDI */
2589
2590 //uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
2591 assign( ta, getIReg(sz, R_EAX) );
2592
2593 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
2594 assign( td, getIReg(4, R_EDI) );
2595
2596 //uInstr2(cb, STORE, sz, TempReg, ta, TempReg, td);
2597 storeLE( mkexpr(ta), mkexpr(td) );
2598
2599 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
2600 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2601 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
2602}
2603
2604static
2605void dis_CMPS ( Int sz, IRTemp t_inc )
2606{
2607 IRType ty = szToITy(sz);
2608 IRTemp tdv = newTemp(sz); /* (EDI) */
2609 IRTemp tsv = newTemp(sz); /* (ESI) */
2610 IRTemp td = newTemp(Ity_I32); /* EDI */
2611 IRTemp ts = newTemp(Ity_I32); /* ESI */
2612
2613 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
2614 assign( td, getIReg(4, R_EDI) );
2615
2616 //uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
2617 assign( ts, getIReg(4, R_ESI) );
2618
2619 //uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tdv);
2620 assign( tdv, loadLE(ty,mkexpr(td)) );
2621
2622 //uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tsv);
2623 //assign( tsv, loadLE(ty,mkexpr(ts)) );
2624
2625 //uInstr2(cb, SUB, sz, TempReg, tdv, TempReg, tsv);
2626 //setFlagsFromUOpcode(cb, SUB);
2627
2628 assign( tsv, binop(mkSizedOp(ty,Iop_Sub8), loadLE(ty,mkexpr(ts)), mkexpr(tdv)) );
2629 setFlags_SRC_DST1 ( Iop_Sub8, tdv, tsv, ty );
2630
2631 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
2632 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
2633
2634 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2635 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
2636
2637 //uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
2638 putIReg(4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
2639}
2640
2641#if 0
2642static
2643void dis_SCAS ( Int sz, IRTemp t_inc )
2644{
2645 IRType ty = szToITy(sz);
2646 IRTemp ta = newTemp(Ity_I32); /* EAX */
2647 IRTemp td = newTemp(Ity_I32); /* EDI */
2648 IRTemp tdv = newTemp(ty); /* (EDI) */
2649
2650 //uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
2651 assign( ta, getIReg(sz, R_EAX) );
2652
2653 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
2654 assign( td, getIReg(4, R_EDI) );
2655
2656 //uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tdv);
2657 assign( tdv, loadLE(ty,mkexpr(td)) );
2658
2659 /* next uinstr kills ta, but that's ok -- don't need it again */
2660 //uInstr2(cb, SUB, sz, TempReg, tdv, TempReg, ta);
2661 //setFlagsFromUOpcode(cb, SUB);
2662
2663 assign( ta, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(ta), mkexpr(tdv)) );
2664 setFlags_SRC_DST1( Iop_Sub8, tdv, ta, ty );
2665
2666 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
2667 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2668 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
2669}
2670#endif
2671
2672/* Wrap the appropriate string op inside a REP/REPE/REPNE.
2673 We assume the insn is the last one in the basic block, and so emit a jump
2674 to the next insn, rather than just falling through. */
2675static
2676void dis_REP_op ( Condcode cond,
2677 void (*dis_OP)(Int, IRTemp),
2678 Int sz, Addr32 eip, Addr32 eip_next, Char* name )
2679{
2680 IRTemp t_inc = newTemp(Ity_I32);
2681 IRTemp tc = newTemp(Ity_I32); /* ECX */
2682
2683 //uInstr2 (cb, GET, 4, ArchReg, R_ECX, TempReg, tc);
2684 assign( tc, getIReg(4,R_ECX) );
2685
2686 //uInstr2 (cb, JIFZ, 4, TempReg, tc, Literal, 0);
2687 //uLiteral(cb, eip_next);
2688 stmt( IRStmt_Exit( binop(Iop_CmpEQ32,mkexpr(tc),mkU32(0)),
2689 IRConst_U32(eip_next) ) );
2690
2691 //uInstr1 (cb, DEC, 4, TempReg, tc);
2692 //uInstr2 (cb, PUT, 4, TempReg, tc, ArchReg, R_ECX);
2693 putIReg(4, R_ECX, binop(Iop_Sub32, mkexpr(tc), mkU32(1)) );
2694
2695 dis_string_op_increment(sz, t_inc);
2696 dis_OP (sz, t_inc);
2697
2698 if (cond == CondAlways) {
sewardj78c19df2004-07-12 22:49:27 +00002699 jmp_lit(Ijk_Boring,eip);
sewardj64e1d652004-07-12 14:00:46 +00002700 } else {
2701 stmt( IRStmt_Exit( calculate_condition(cond),
2702 IRConst_U32(eip) ) );
sewardj78c19df2004-07-12 22:49:27 +00002703 jmp_lit(Ijk_Boring,eip_next);
sewardj64e1d652004-07-12 14:00:46 +00002704 }
2705 DIP("%s%c\n", name, nameISize(sz));
2706}
2707
2708/*------------------------------------------------------------*/
2709/*--- Arithmetic, etc. ---*/
2710/*------------------------------------------------------------*/
2711
sewardjcf780b42004-07-13 18:42:17 +00002712#if 0
2713static
2714void do_mul_and_setFlags ( IRType ty,
2715 IRTemp dst, IRTemp src1, IRTemp src2 )
2716{
2717 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
2718 setFlags_MUL( ty, src1, src2, CC_OP_MULB );
2719 assign( dst, binop( mkSizedOp(ty,Iop_Mul8),
2720 mkexpr(src1),
2721 mkexpr(src2)) );
2722}
2723
2724static
2725void do_mull_and_setFlags ( IRType ty,
2726 Bool sign,
2727 IRTemp dst, IRTemp src1, IRTemp src2 )
2728{
2729 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
2730 setFlags_MUL( ty, src1, src2,
2731 sign ? CC_OP_MULLSB : CC_OP_MULLUB );
2732 assign( dst,
2733 binop( mkSizedOp(ty, sign ? Iop_MullS8 : Iop_MullU8),
2734 mkexpr(src1),
2735 mkexpr(src2)) );
2736}
2737#endif
2738
2739/* (I)MUL E, G. Supplied eip points to the modR/M byte. */
2740static
2741UInt dis_mul_E_G ( UChar sorb,
2742 Int size,
2743 UInt delta0,
2744 Bool signed_multiply )
2745{
2746
2747 // UChar dis_buf[50];
2748 UChar rm = getIByte(delta0);
2749 IRType ty = szToITy(size);
2750 //IRTemp ta = INVALID_IRTEMP;
2751 IRTemp te = newTemp(size);
2752 IRTemp tg = newTemp(size);
2753
2754 if (epartIsReg(rm)) {
2755 vassert(signed_multiply);
2756 assign( tg, getIReg(size, gregOfRM(rm)) );
2757 assign( te, getIReg(size, eregOfRM(rm)) );
2758 setFlags_MUL ( ty, te, tg, CC_OP_MULB );
2759 putIReg(size, gregOfRM(rm),
2760 binop(mkSizedOp(ty,Iop_Mul8),
2761 mkexpr(te), mkexpr(tg)));
2762
2763 DIP("%smul%c %s, %s\n", signed_multiply ? "i" : "",
2764 nameISize(size),
2765 nameIReg(size,eregOfRM(rm)),
2766 nameIReg(size,gregOfRM(rm)));
2767 return 1+delta0;
2768 } else {
2769 vassert(0+0==0);
2770#if 0
2771 UInt pair;
2772 vg_assert(signed_multiply);
2773 pair = disAMode ( cb, sorb, eip0, dis_buf );
2774 ta = LOW24(pair);
2775 uInstr2(cb, LOAD, size, TempReg, ta, TempReg, te);
2776 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tg);
2777 uInstr2(cb, MUL, size, TempReg, te, TempReg, tg);
2778 setFlagsFromUOpcode(cb, MUL);
2779 uInstr2(cb, PUT, size, TempReg, tg, ArchReg, gregOfRM(rm));
2780
2781 DIP("%smul%c %s, %s\n", signed_multiply ? "i" : "",
2782 nameISize(size),
2783 dis_buf, nameIReg(size,gregOfRM(rm)));
2784 return HI8(pair)+eip0;
2785#endif
2786 }
2787}
2788
2789
sewardjc9a65702004-07-07 16:32:57 +00002790//-- /* IMUL I * E -> G. Supplied eip points to the modR/M byte. */
2791//-- static
2792//-- Addr dis_imul_I_E_G ( UCodeBlock* cb,
2793//-- UChar sorb,
2794//-- Int size,
2795//-- Addr eip,
2796//-- Int litsize )
2797//-- {
2798//-- Int ta, te, tl, d32;
2799//-- Char dis_buf[50];
2800//-- UChar rm = getIByte(delta);
2801//-- ta = INVALID_TEMPREG;
2802//-- te = newTemp(cb);
2803//-- tl = newTemp(cb);
2804//--
2805//-- if (epartIsReg(rm)) {
2806//-- uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, te);
2807//-- eip++;
2808//-- } else {
2809//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
2810//-- ta = LOW24(pair);
2811//-- uInstr2(cb, LOAD, size, TempReg, ta, TempReg, te);
2812//-- eip += HI8(pair);
2813//-- }
2814//--
2815//-- d32 = getSDisp(litsize,eip);
2816//-- eip += litsize;
2817//--
2818//-- uInstr2(cb, MOV, size, Literal, 0, TempReg, tl);
2819//-- uLiteral(cb, d32);
2820//-- uInstr2(cb, MUL, size, TempReg, tl, TempReg, te);
2821//-- setFlagsFromUOpcode(cb, MUL);
2822//-- uInstr2(cb, PUT, size, TempReg, te, ArchReg, gregOfRM(rm));
2823//--
2824//-- DIP("imul %d, %s, %s\n", d32,
2825//-- ( epartIsReg(rm) ? nameIReg(size,eregOfRM(rm)) : dis_buf ),
2826//-- nameIReg(size,gregOfRM(rm)) );
2827//--
2828//-- return eip;
2829//-- }
2830//--
2831//--
2832//-- /* Handle FPU insns which read/write memory. On entry, eip points to
2833//-- the second byte of the insn (the one following D8 .. DF). */
2834//-- static
2835//-- Addr dis_fpu_mem ( UCodeBlock* cb,
2836//-- UChar sorb,
2837//-- Int size, Bool is_write,
2838//-- Addr eip, UChar first_byte )
2839//-- {
2840//-- Int ta;
2841//-- UInt pair;
2842//-- UChar dis_buf[50];
2843//-- UChar second_byte = getIByte(delta);
2844//-- vg_assert(second_byte < 0xC0);
2845//-- second_byte &= 0x38;
2846//-- pair = disAMode ( cb, sorb, eip, dis_buf );
2847//-- ta = LOW24(pair);
2848//-- eip += HI8(pair);
2849//-- uInstr2(cb, is_write ? FPU_W : FPU_R, size,
2850//-- Lit16,
2851//-- (((UShort)first_byte) << 8) | ((UShort)second_byte),
2852//-- TempReg, ta);
2853//-- if (is_write) {
2854//-- DIP("fpu_w_%d 0x%x:0x%x, %s\n",
2855//-- size, (UInt)first_byte, (UInt)second_byte, dis_buf );
2856//-- } else {
2857//-- DIP("fpu_r_%d %s, 0x%x:0x%x\n",
2858//-- size, dis_buf, (UInt)first_byte, (UInt)second_byte );
2859//-- }
2860//-- return eip;
2861//-- }
2862//--
2863//--
2864//-- /* Handle FPU insns which don't reference memory. On entry, eip points to
2865//-- the second byte of the insn (the one following D8 .. DF). */
2866//-- static
2867//-- Addr dis_fpu_no_mem ( UCodeBlock* cb, Addr eip, UChar first_byte )
2868//-- {
2869//-- Bool sets_ZCP = False;
2870//-- Bool uses_ZCP = False;
2871//-- UChar second_byte = getUChar(eip); eip++;
2872//-- vg_assert(second_byte >= 0xC0);
2873//--
2874//-- /* Does the insn write any integer condition codes (%EIP) ? */
2875//--
2876//-- if (first_byte == 0xDB && second_byte >= 0xF0 && second_byte <= 0xF7) {
2877//-- /* FCOMI */
2878//-- sets_ZCP = True;
2879//-- } else
2880//-- if (first_byte == 0xDF && second_byte >= 0xF0 && second_byte <= 0xF7) {
2881//-- /* FCOMIP */
2882//-- sets_ZCP = True;
2883//-- } else
2884//-- if (first_byte == 0xDB && second_byte >= 0xE8 && second_byte <= 0xEF) {
2885//-- /* FUCOMI */
2886//-- sets_ZCP = True;
2887//-- } else
2888//-- if (first_byte == 0xDF && second_byte >= 0xE8 && second_byte <= 0xEF) {
2889//-- /* FUCOMIP */
2890//-- sets_ZCP = True;
2891//-- }
2892//--
2893//-- /* Dually, does the insn read any integer condition codes (%EIP) ? */
2894//--
2895//-- if (first_byte == 0xDA && second_byte >= 0xC0 && second_byte <= 0xDF) {
2896//-- /* FCMOVB %st(n), %st(0)
2897//-- FCMOVE %st(n), %st(0)
2898//-- FCMOVBE %st(n), %st(0)
2899//-- FCMOVU %st(n), %st(0)
2900//-- */
2901//-- uses_ZCP = True;
2902//-- } else
2903//-- if (first_byte == 0xDB && second_byte >= 0xC0 && second_byte <= 0xDF) {
2904//-- /* FCMOVNB %st(n), %st(0)
2905//-- FCMOVNE %st(n), %st(0)
2906//-- FCMOVNBE %st(n), %st(0)
2907//-- FCMOVNU %st(n), %st(0)
2908//-- */
2909//-- uses_ZCP = True;
2910//-- }
2911//--
2912//-- uInstr1(cb, FPU, 0,
2913//-- Lit16,
2914//-- (((UShort)first_byte) << 8) | ((UShort)second_byte)
2915//-- );
2916//-- if (uses_ZCP) {
2917//-- /* VG_(printf)("!!! --- FPU insn which reads %EFLAGS\n"); */
2918//-- uFlagsRWU(cb, FlagsZCP, FlagsEmpty, FlagsEmpty);
2919//-- vg_assert(!sets_ZCP);
2920//-- }
2921//-- if (sets_ZCP) {
2922//-- /* VG_(printf)("!!! --- FPU insn which writes %EFLAGS\n"); */
2923//-- uFlagsRWU(cb, FlagsEmpty, FlagsZCP, FlagsEmpty);
2924//-- vg_assert(!uses_ZCP);
2925//-- }
2926//--
2927//-- DIP("fpu 0x%x:0x%x%s%s\n", (UInt)first_byte, (UInt)second_byte,
2928//-- uses_ZCP ? " -rZCP" : "",
2929//-- sets_ZCP ? " -wZCP" : "" );
2930//-- return eip;
2931//-- }
2932//--
2933//--
2934//-- /* Top-level handler for all FPU insns. On entry, eip points to the
2935//-- second byte of the insn. */
2936//-- static
2937//-- Addr dis_fpu ( UCodeBlock* cb,
2938//-- UChar sorb,
2939//-- UChar first_byte, Addr eip )
2940//-- {
2941//-- const Bool rd = False;
2942//-- const Bool wr = True;
2943//-- UChar second_byte = getUChar(eip);
2944//--
2945//-- /* Handle FSTSW %ax specially. */
2946//-- if (first_byte == 0xDF && second_byte == 0xE0) {
2947//-- Int t1 = newTemp(cb);
2948//-- uInstr0(cb, CALLM_S, 0);
2949//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
2950//-- uLiteral(cb, 0);
2951//-- uInstr1(cb, PUSH, 4, TempReg, t1);
2952//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_fstsw_AX) );
2953//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
2954//-- uInstr1(cb, POP, 2, TempReg, t1);
2955//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
2956//-- uInstr0(cb, CALLM_E, 0);
2957//-- DIP("fstsw %%ax\n");
2958//-- eip++;
2959//-- return eip;
2960//-- }
2961//--
2962//-- /* Handle all non-memory FPU ops simply. */
2963//-- if (second_byte >= 0xC0)
2964//-- return dis_fpu_no_mem ( cb, eip, first_byte );
2965//--
2966//-- /* The insn references memory; need to determine
2967//-- whether it reads or writes, and at what size. */
2968//-- switch (first_byte) {
2969//--
2970//-- case 0xD8:
2971//-- switch ((second_byte >> 3) & 7) {
2972//-- case 0: /* FADDs */
2973//-- case 1: /* FMULs */
2974//-- case 2: /* FCOMs */
2975//-- case 3: /* FCOMPs */
2976//-- case 4: /* FSUBs */
2977//-- case 5: /* FSUBRs */
2978//-- case 6: /* FDIVs */
2979//-- case 7: /* FDIVRs */
2980//-- return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
2981//-- default:
2982//-- goto unhandled;
2983//-- }
2984//-- break;
2985//--
2986//-- case 0xD9:
2987//-- switch ((second_byte >> 3) & 7) {
2988//-- case 0: /* FLDs */
2989//-- return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
2990//-- case 2: /* FSTs */
2991//-- case 3: /* FSTPs */
2992//-- return dis_fpu_mem(cb, sorb, 4, wr, eip, first_byte);
2993//-- case 4: /* FLDENV */
2994//-- return dis_fpu_mem(cb, sorb, 28, rd, eip, first_byte);
2995//-- case 5: /* FLDCW */
2996//-- return dis_fpu_mem(cb, sorb, 2, rd, eip, first_byte);
2997//-- case 6: /* FNSTENV */
2998//-- return dis_fpu_mem(cb, sorb, 28, wr, eip, first_byte);
2999//-- case 7: /* FSTCW */
3000//-- /* HACK! FSTCW actually writes 2 bytes, not 4. glibc
3001//-- gets lots of moaning in __floor() if we do the right
3002//-- thing here. */
3003//-- /* Later ... hack disabled .. we do do the Right Thing. */
3004//-- return dis_fpu_mem(cb, sorb, /*4*/ 2, wr, eip, first_byte);
3005//-- default:
3006//-- goto unhandled;
3007//-- }
3008//-- break;
3009//--
3010//-- case 0xDA:
3011//-- switch ((second_byte >> 3) & 7) {
3012//-- case 0: /* FIADD dword-integer */
3013//-- case 1: /* FIMUL dword-integer */
3014//-- case 2: /* FICOM dword-integer */
3015//-- case 3: /* FICOMP dword-integer */
3016//-- case 4: /* FISUB dword-integer */
3017//-- case 5: /* FISUBR dword-integer */
3018//-- case 6: /* FIDIV dword-integer */
3019//-- case 7: /* FIDIVR dword-integer */
3020//-- return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
3021//-- default:
3022//-- goto unhandled;
3023//-- }
3024//-- break;
3025//--
3026//-- case 0xDB:
3027//-- switch ((second_byte >> 3) & 7) {
3028//-- case 0: /* FILD dword-integer */
3029//-- return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
3030//-- case 2: /* FIST dword-integer */
3031//-- return dis_fpu_mem(cb, sorb, 4, wr, eip, first_byte);
3032//-- case 3: /* FISTPl */
3033//-- return dis_fpu_mem(cb, sorb, 4, wr, eip, first_byte);
3034//-- case 5: /* FLD extended-real */
3035//-- return dis_fpu_mem(cb, sorb, 10, rd, eip, first_byte);
3036//-- case 7: /* FSTP extended-real */
3037//-- return dis_fpu_mem(cb, sorb, 10, wr, eip, first_byte);
3038//-- default:
3039//-- goto unhandled;
3040//-- }
3041//-- break;
3042//--
3043//-- case 0xDC:
3044//-- switch ((second_byte >> 3) & 7) {
3045//-- case 0: /* FADD double-real */
3046//-- case 1: /* FMUL double-real */
3047//-- case 2: /* FCOM double-real */
3048//-- case 3: /* FCOMP double-real */
3049//-- case 4: /* FSUB double-real */
3050//-- case 5: /* FSUBR double-real */
3051//-- case 6: /* FDIV double-real */
3052//-- case 7: /* FDIVR double-real */
3053//-- return dis_fpu_mem(cb, sorb, 8, rd, eip, first_byte);
3054//-- default:
3055//-- goto unhandled;
3056//-- }
3057//-- break;
3058//--
3059//-- case 0xDD:
3060//-- switch ((second_byte >> 3) & 7) {
3061//-- case 0: /* FLD double-real */
3062//-- return dis_fpu_mem(cb, sorb, 8, rd, eip, first_byte);
3063//-- case 2: /* FST double-real */
3064//-- case 3: /* FSTP double-real */
3065//-- return dis_fpu_mem(cb, sorb, 8, wr, eip, first_byte);
3066//-- case 4: /* FRSTOR */
3067//-- return dis_fpu_mem(cb, sorb, 108, rd, eip, first_byte);
3068//-- case 6: /* FSAVE */
3069//-- return dis_fpu_mem(cb, sorb, 108, wr, eip, first_byte);
3070//-- case 7: /* FSTSW */
3071//-- return dis_fpu_mem(cb, sorb, 2, wr, eip, first_byte);
3072//-- default:
3073//-- goto unhandled;
3074//-- }
3075//-- break;
3076//--
3077//-- case 0xDE:
3078//-- switch ((second_byte >> 3) & 7) {
3079//-- case 0: /* FIADD word-integer */
3080//-- case 1: /* FIMUL word-integer */
3081//-- case 2: /* FICOM word-integer */
3082//-- case 3: /* FICOMP word-integer */
3083//-- case 4: /* FISUB word-integer */
3084//-- case 5: /* FISUBR word-integer */
3085//-- case 6: /* FIDIV word-integer */
3086//-- case 7: /* FIDIVR word-integer */
3087//-- return dis_fpu_mem(cb, sorb, 2, rd, eip, first_byte);
3088//-- default:
3089//-- goto unhandled;
3090//-- }
3091//-- break;
3092//--
3093//-- case 0xDF:
3094//-- switch ((second_byte >> 3) & 7) {
3095//-- case 0: /* FILD word-integer */
3096//-- return dis_fpu_mem(cb, sorb, 2, rd, eip, first_byte);
3097//-- case 2: /* FIST word-integer */
3098//-- return dis_fpu_mem(cb, sorb, 2, wr, eip, first_byte);
3099//-- case 3: /* FISTP word-integer */
3100//-- return dis_fpu_mem(cb, sorb, 2, wr, eip, first_byte);
3101//-- case 5: /* FILD qword-integer */
3102//-- return dis_fpu_mem(cb, sorb, 8, rd, eip, first_byte);
3103//-- case 7: /* FISTP qword-integer */
3104//-- return dis_fpu_mem(cb, sorb, 8, wr, eip, first_byte);
3105//-- default:
3106//-- goto unhandled;
3107//-- }
3108//-- break;
3109//--
3110//-- default: goto unhandled;
3111//-- }
3112//--
3113//-- unhandled:
3114//-- VG_(printf)("dis_fpu: unhandled memory case 0x%2x:0x%2x(%d)\n",
3115//-- (UInt)first_byte, (UInt)second_byte,
3116//-- (UInt)((second_byte >> 3) & 7) );
3117//-- VG_(core_panic)("dis_fpu: unhandled opcodes");
3118//-- }
3119//--
3120//--
3121//-- /* Double length left shifts. Apparently only required in v-size (no
3122//-- b- variant). */
3123//-- static
3124//-- Addr dis_SHLRD_Gv_Ev ( UCodeBlock* cb,
3125//-- UChar sorb,
3126//-- Addr eip, UChar modrm,
3127//-- Int sz,
3128//-- Tag amt_tag, UInt amt_val,
3129//-- Bool left_shift )
3130//-- {
3131//-- /* amt_tag and amt_val denote either ArchReg(%CL) or a Literal.
3132//-- And eip on entry points at the modrm byte. */
3133//-- Int t, t1, t2, ta, helper;
3134//-- UInt pair;
3135//-- UChar dis_buf[50];
3136//--
3137//-- vg_assert(sz == 2 || sz == 4);
3138//--
3139//-- helper = left_shift
3140//-- ? (sz==4 ? VGOFF_(helper_shldl)
3141//-- : VGOFF_(helper_shldw))
3142//-- : (sz==4 ? VGOFF_(helper_shrdl)
3143//-- : VGOFF_(helper_shrdw));
3144//--
3145//-- /* Get the amount to be shifted by onto the stack. */
3146//-- t = newTemp(cb);
3147//-- t1 = newTemp(cb);
3148//-- t2 = newTemp(cb);
3149//-- if (amt_tag == ArchReg) {
3150//-- vg_assert(amt_val == R_CL);
3151//-- uInstr2(cb, GET, 1, ArchReg, amt_val, TempReg, t);
3152//-- } else {
3153//-- uInstr2(cb, MOV, 1, Literal, 0, TempReg, t);
3154//-- uLiteral(cb, amt_val);
3155//-- }
3156//--
3157//-- uInstr0(cb, CALLM_S, 0);
3158//-- uInstr1(cb, PUSH, 1, TempReg, t);
3159//--
3160//-- /* The E-part is the destination; this is shifted. The G-part
3161//-- supplies bits to be shifted into the E-part, but is not
3162//-- changed. */
3163//--
3164//-- uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t1);
3165//-- uInstr1(cb, PUSH, sz, TempReg, t1);
3166//--
3167//-- if (epartIsReg(modrm)) {
3168//-- eip++;
3169//-- uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t2);
3170//-- uInstr1(cb, PUSH, sz, TempReg, t2);
3171//-- uInstr1(cb, CALLM, 0, Lit16, helper);
3172//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
3173//-- uInstr1(cb, POP, sz, TempReg, t);
3174//-- uInstr2(cb, PUT, sz, TempReg, t, ArchReg, eregOfRM(modrm));
3175//-- DIP("sh%cd%c %%cl, %s, %s\n",
3176//-- ( left_shift ? 'l' : 'r' ), nameISize(sz),
3177//-- nameIReg(sz, gregOfRM(modrm)), nameIReg(sz, eregOfRM(modrm)));
3178//-- } else {
3179//-- pair = disAMode ( cb, sorb, eip, dis_buf );
3180//-- ta = LOW24(pair);
3181//-- eip += HI8(pair);
3182//-- uInstr2(cb, LOAD, sz, TempReg, ta, TempReg, t2);
3183//-- uInstr1(cb, PUSH, sz, TempReg, t2);
3184//-- uInstr1(cb, CALLM, 0, Lit16, helper);
3185//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
3186//-- uInstr1(cb, POP, sz, TempReg, t);
3187//-- uInstr2(cb, STORE, sz, TempReg, t, TempReg, ta);
3188//-- DIP("sh%cd%c %%cl, %s, %s\n", ( left_shift ? 'l' : 'r' ),
3189//-- nameISize(sz), nameIReg(sz, gregOfRM(modrm)), dis_buf);
3190//-- }
3191//--
3192//-- if (amt_tag == Literal) eip++;
3193//-- uInstr1(cb, CLEAR, 0, Lit16, 8);
3194//--
3195//-- uInstr0(cb, CALLM_E, 0);
3196//-- return eip;
3197//-- }
3198//--
3199//--
3200//-- /* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
3201//-- required. */
3202//--
3203//-- typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
3204//--
3205//-- static Char* nameBtOp ( BtOp op )
3206//-- {
3207//-- switch (op) {
3208//-- case BtOpNone: return "";
3209//-- case BtOpSet: return "s";
3210//-- case BtOpReset: return "r";
3211//-- case BtOpComp: return "c";
3212//-- default: VG_(core_panic)("nameBtOp");
3213//-- }
3214//-- }
3215//--
3216//--
3217//-- static
3218//-- Addr dis_bt_G_E ( UCodeBlock* cb,
3219//-- UChar sorb,
3220//-- Int sz, Addr eip, BtOp op )
3221//-- {
3222//-- UInt pair;
3223//-- Char dis_buf[50];
3224//-- UChar modrm;
3225//--
3226//-- Int t_addr, t_bitno, t_mask, t_fetched, t_esp, temp, lit;
3227//--
3228//-- vg_assert(sz == 2 || sz == 4);
3229//--
3230//-- t_addr = t_bitno = t_mask
3231//-- = t_fetched = t_esp = temp = INVALID_TEMPREG;
3232//--
3233//-- t_fetched = newTemp(cb);
3234//-- t_bitno = newTemp(cb);
3235//-- temp = newTemp(cb);
3236//-- lit = newTemp(cb);
3237//--
3238//-- modrm = getUChar(eip);
3239//--
3240//-- uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t_bitno);
3241//--
3242//-- if (sz == 2) {
3243//-- uInstr1(cb, WIDEN, 4, TempReg, t_bitno);
3244//-- uWiden(cb, 2, False);
3245//-- }
3246//--
3247//-- if (epartIsReg(modrm)) {
3248//-- eip++;
3249//-- /* Get it onto the client's stack. */
3250//-- t_esp = newTemp(cb);
3251//-- t_addr = newTemp(cb);
3252//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t_esp);
3253//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t_esp);
3254//-- uLiteral(cb, sz);
3255//-- uInstr2(cb, PUT, 4, TempReg, t_esp, ArchReg, R_ESP);
3256//-- uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, temp);
3257//-- uInstr2(cb, STORE, sz, TempReg, temp, TempReg, t_esp);
3258//-- /* Make t_addr point at it. */
3259//-- uInstr2(cb, MOV, 4, TempReg, t_esp, TempReg, t_addr);
3260//-- /* Mask out upper bits of the shift amount, since we're doing a
3261//-- reg. */
3262//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, lit);
3263//-- uLiteral(cb, sz == 4 ? 31 : 15);
3264//-- uInstr2(cb, AND, 4, TempReg, lit, TempReg, t_bitno);
3265//-- } else {
3266//-- pair = disAMode ( cb, sorb, eip, dis_buf );
3267//-- t_addr = LOW24(pair);
3268//-- eip += HI8(pair);
3269//-- }
3270//--
3271//-- /* At this point: t_addr points to the address being operated on. If
3272//-- it was a reg, we will have pushed it onto the client's stack.
3273//-- t_bitno is the bit number, suitable masked in the case of a reg. */
3274//--
3275//-- /* Now the main sequence. */
3276//--
3277//-- uInstr2(cb, MOV, 4, TempReg, t_bitno, TempReg, temp);
3278//-- uInstr2(cb, SAR, 4, Literal, 0, TempReg, temp);
3279//-- uLiteral(cb, 3);
3280//-- uInstr2(cb, ADD, 4, TempReg, temp, TempReg, t_addr);
3281//-- /* t_addr now holds effective address */
3282//--
3283//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, lit);
3284//-- uLiteral(cb, 7);
3285//-- uInstr2(cb, AND, 4, TempReg, lit, TempReg, t_bitno);
3286//-- /* t_bitno contains offset of bit within byte */
3287//--
3288//-- if (op != BtOpNone) {
3289//-- t_mask = newTemp(cb);
3290//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_mask);
3291//-- uLiteral(cb, 1);
3292//-- uInstr2(cb, SHL, 4, TempReg, t_bitno, TempReg, t_mask);
3293//-- }
3294//-- /* t_mask is now a suitable byte mask */
3295//--
3296//-- uInstr2(cb, LOAD, 1, TempReg, t_addr, TempReg, t_fetched);
3297//-- if (op != BtOpNone) {
3298//-- uInstr2(cb, MOV, 4, TempReg, t_fetched, TempReg, temp);
3299//-- switch (op) {
3300//-- case BtOpSet:
3301//-- uInstr2(cb, OR, 4, TempReg, t_mask, TempReg, temp);
3302//-- break;
3303//-- case BtOpComp:
3304//-- uInstr2(cb, XOR, 4, TempReg, t_mask, TempReg, temp);
3305//-- break;
3306//-- case BtOpReset:
3307//-- uInstr1(cb, NOT, 4, TempReg, t_mask);
3308//-- uInstr2(cb, AND, 4, TempReg, t_mask, TempReg, temp);
3309//-- break;
3310//-- default:
3311//-- VG_(core_panic)("dis_bt_G_E");
3312//-- }
3313//-- uInstr2(cb, STORE, 1, TempReg, temp, TempReg, t_addr);
3314//-- }
3315//--
3316//-- /* Side effect done; now get selected bit into Carry flag */
3317//--
3318//-- uInstr2(cb, SHR, 4, TempReg, t_bitno, TempReg, t_fetched);
3319//-- /* at bit 0 of fetched */
3320//--
3321//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, lit);
3322//-- uLiteral(cb, 1);
3323//-- uInstr2(cb, AND, 4, TempReg, lit, TempReg, t_fetched);
3324//-- /* t_fetched is now 1 or 0 */
3325//--
3326//-- /* NEG is a handy way to convert zero/nonzero into the carry
3327//-- flag. */
3328//-- uInstr1(cb, NEG, 4, TempReg, t_fetched);
3329//-- setFlagsFromUOpcode(cb, NEG);
3330//-- /* t_fetched is now in carry flag */
3331//--
3332//-- /* Move reg operand from stack back to reg */
3333//-- if (epartIsReg(modrm)) {
3334//-- /* t_esp still points at it. */
3335//-- uInstr2(cb, LOAD, sz, TempReg, t_esp, TempReg, temp);
3336//-- uInstr2(cb, PUT, sz, TempReg, temp, ArchReg, eregOfRM(modrm));
3337//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t_esp);
3338//-- uLiteral(cb, sz);
3339//-- uInstr2(cb, PUT, 4, TempReg, t_esp, ArchReg, R_ESP);
3340//-- }
3341//--
3342//-- DIP("bt%s%c %s, %s\n",
3343//-- nameBtOp(op), nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
3344//-- ( epartIsReg(modrm) ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ) );
3345//--
3346//-- return eip;
3347//-- }
3348//--
3349//--
3350//--
3351//-- /* Handle BSF/BSR. Only v-size seems necessary. */
3352//-- static
3353//-- Addr dis_bs_E_G ( UCodeBlock* cb,
3354//-- UChar sorb,
3355//-- Int sz, Addr eip, Bool fwds )
3356//-- {
3357//-- Int t, t1, ta, helper;
3358//-- UInt pair;
3359//-- Char dis_buf[50];
3360//-- UChar modrm;
3361//-- Bool isReg;
3362//--
3363//-- vg_assert(sz == 2 || sz == 4);
3364//--
3365//-- if (fwds)
3366//-- helper = sz == 2 ? VGOFF_(helper_bsfw) : VGOFF_(helper_bsfl);
3367//-- else
3368//-- helper = sz == 2 ? VGOFF_(helper_bsrw) : VGOFF_(helper_bsrl);
3369//--
3370//-- modrm = getUChar(eip);
3371//-- t1 = newTemp(cb);
3372//-- t = newTemp(cb);
3373//--
3374//-- uInstr0(cb, CALLM_S, 0);
3375//-- uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t1);
3376//-- uInstr1(cb, PUSH, sz, TempReg, t1);
3377//--
3378//-- isReg = epartIsReg(modrm);
3379//-- if (isReg) {
3380//-- eip++;
3381//-- uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t);
3382//-- } else {
3383//-- pair = disAMode ( cb, sorb, eip, dis_buf );
3384//-- ta = LOW24(pair);
3385//-- eip += HI8(pair);
3386//-- uInstr2(cb, LOAD, sz, TempReg, ta, TempReg, t);
3387//-- }
3388//-- DIP("bs%c%c %s, %s\n",
3389//-- fwds ? 'f' : 'r', nameISize(sz),
3390//-- ( isReg ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ),
3391//-- nameIReg(sz, gregOfRM(modrm)));
3392//--
3393//-- uInstr1(cb, PUSH, sz, TempReg, t);
3394//-- uInstr1(cb, CALLM, 0, Lit16, helper);
3395//-- uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsOSACP);
3396//-- uInstr1(cb, POP, sz, TempReg, t);
3397//-- uInstr1(cb, POP, sz, TempReg, t);
3398//-- uInstr2(cb, PUT, sz, TempReg, t, ArchReg, gregOfRM(modrm));
3399//-- uInstr0(cb, CALLM_E, 0);
3400//--
3401//-- return eip;
3402//-- }
sewardj64e1d652004-07-12 14:00:46 +00003403
3404
3405static
3406void codegen_xchg_eAX_Reg ( Int sz, Int reg )
3407{
3408 IRType ty = szToITy(sz);
3409 IRTemp t1 = newTemp(ty);
3410 IRTemp t2 = newTemp(ty);
3411 vassert(sz == 2 || sz == 4);
3412 assign( t1, getIReg(sz, R_EAX) );
3413 assign( t2, getIReg(sz, reg) );
3414 putIReg( sz, R_EAX, mkexpr(t2) );
3415 putIReg( sz, reg, mkexpr(t1) );
3416 DIP("xchg%c %s, %s\n",
3417 nameISize(sz), nameIReg(sz, R_EAX), nameIReg(sz, reg));
3418}
3419
3420
sewardjc9a65702004-07-07 16:32:57 +00003421//-- static
3422//-- void codegen_SAHF ( UCodeBlock* cb )
3423//-- {
3424//-- Int t = newTemp(cb);
3425//-- Int t2 = newTemp(cb);
3426//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t);
3427//--
3428//-- /* Mask out parts of t not corresponding to %AH. This stops the
3429//-- instrumenter complaining if they are undefined. Otherwise, the
3430//-- instrumenter would check all 32 bits of t at the PUSH, which
3431//-- could be the cause of incorrect warnings. Discovered by Daniel
3432//-- Veillard <veillard@redhat.com>.
3433//-- */
3434//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
3435//-- uLiteral(cb, 0x0000FF00);
3436//-- uInstr2(cb, AND, 4, TempReg, t2, TempReg, t);
3437//-- /* We deliberately don't set the condition codes here, since this
3438//-- AND is purely internal to Valgrind and nothing to do with the
3439//-- client's state. */
3440//--
3441//-- uInstr0(cb, CALLM_S, 0);
3442//-- uInstr1(cb, PUSH, 4, TempReg, t);
3443//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_SAHF));
3444//-- uFlagsRWU(cb, FlagsEmpty, FlagsSZACP, FlagsEmpty);
3445//-- uInstr1(cb, CLEAR, 0, Lit16, 4);
3446//-- uInstr0(cb, CALLM_E, 0);
3447//-- }
3448//--
3449//-- static
3450//-- void codegen_LAHF ( UCodeBlock* cb )
3451//-- {
3452//-- Int t = newTemp(cb);
3453//--
3454//-- /* Pushed arg is ignored, it just provides somewhere to put the
3455//-- return value. */
3456//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t);
3457//-- uInstr0(cb, CALLM_S, 0);
3458//-- uInstr1(cb, PUSH, 4, TempReg, t);
3459//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_LAHF));
3460//-- uFlagsRWU(cb, FlagsSZACP, FlagsEmpty, FlagsEmpty);
3461//-- uInstr1(cb, POP, 4, TempReg, t);
3462//-- uInstr0(cb, CALLM_E, 0);
3463//--
3464//-- /* At this point, the %ah sub-register in %eax has been updated,
3465//-- the rest is the same, so do a PUT of the whole thing. */
3466//-- uInstr2(cb, PUT, 4, TempReg, t, ArchReg, R_EAX);
3467//-- }
3468//--
3469//--
3470//-- static
3471//-- Addr dis_cmpxchg_G_E ( UCodeBlock* cb,
3472//-- UChar sorb,
3473//-- Int size,
3474//-- Addr eip0 )
3475//-- {
3476//-- Int ta, junk, dest, src, acc;
3477//-- UChar dis_buf[50];
3478//-- UChar rm;
3479//--
3480//-- rm = getUChar(eip0);
3481//-- acc = newTemp(cb);
3482//-- src = newTemp(cb);
3483//-- dest = newTemp(cb);
3484//-- junk = newTemp(cb);
3485//-- /* Only needed to get gcc's dataflow analyser off my back. */
3486//-- ta = INVALID_TEMPREG;
3487//--
3488//-- if (epartIsReg(rm)) {
3489//-- uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, dest);
3490//-- eip0++;
3491//-- DIP("cmpxchg%c %s,%s\n", nameISize(size),
3492//-- nameIReg(size,gregOfRM(rm)),
3493//-- nameIReg(size,eregOfRM(rm)) );
3494//-- } else {
3495//-- UInt pair = disAMode ( cb, sorb, eip0, dis_buf );
3496//-- ta = LOW24(pair);
3497//-- uInstr2(cb, LOAD, size, TempReg, ta, TempReg, dest);
3498//-- eip0 += HI8(pair);
3499//-- DIP("cmpxchg%c %s,%s\n", nameISize(size),
3500//-- nameIReg(size,gregOfRM(rm)), dis_buf);
3501//-- }
3502//--
3503//-- uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, src);
3504//-- uInstr2(cb, GET, size, ArchReg, R_EAX, TempReg, acc);
3505//-- uInstr2(cb, MOV, 4, TempReg, acc, TempReg, junk);
3506//-- uInstr2(cb, SUB, size, TempReg, dest, TempReg, junk);
3507//-- setFlagsFromUOpcode(cb, SUB);
3508//--
3509//-- uInstr2(cb, CMOV, 4, TempReg, src, TempReg, dest);
3510//-- uCond(cb, CondZ);
3511//-- uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
3512//-- uInstr2(cb, CMOV, 4, TempReg, dest, TempReg, acc);
3513//-- uCond(cb, CondNZ);
3514//-- uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
3515//--
3516//-- uInstr2(cb, PUT, size, TempReg, acc, ArchReg, R_EAX);
3517//-- if (epartIsReg(rm)) {
3518//-- uInstr2(cb, PUT, size, TempReg, dest, ArchReg, eregOfRM(rm));
3519//-- } else {
3520//-- uInstr2(cb, STORE, size, TempReg, dest, TempReg, ta);
3521//-- }
3522//--
3523//-- return eip0;
3524//-- }
3525//--
3526//--
3527//-- static
3528//-- Addr dis_cmpxchg8b ( UCodeBlock* cb,
3529//-- UChar sorb,
3530//-- Addr eip0 )
3531//-- {
3532//-- Int tal, tah, junkl, junkh, destl, desth, srcl, srch, accl, acch;
3533//-- UChar dis_buf[50];
3534//-- UChar rm;
3535//-- UInt pair;
3536//--
3537//-- rm = getUChar(eip0);
3538//-- accl = newTemp(cb);
3539//-- acch = newTemp(cb);
3540//-- srcl = newTemp(cb);
3541//-- srch = newTemp(cb);
3542//-- destl = newTemp(cb);
3543//-- desth = newTemp(cb);
3544//-- junkl = newTemp(cb);
3545//-- junkh = newTemp(cb);
3546//--
3547//-- vg_assert(!epartIsReg(rm));
3548//--
3549//-- pair = disAMode ( cb, sorb, eip0, dis_buf );
3550//-- tal = LOW24(pair);
3551//-- tah = newTemp(cb);
3552//-- uInstr2(cb, MOV, 4, TempReg, tal, TempReg, tah);
3553//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, tah);
3554//-- uLiteral(cb, 4);
3555//-- eip0 += HI8(pair);
3556//-- DIP("cmpxchg8b %s\n", dis_buf);
3557//--
3558//-- uInstr0(cb, CALLM_S, 0);
3559//--
3560//-- uInstr2(cb, LOAD, 4, TempReg, tah, TempReg, desth);
3561//-- uInstr1(cb, PUSH, 4, TempReg, desth);
3562//-- uInstr2(cb, LOAD, 4, TempReg, tal, TempReg, destl);
3563//-- uInstr1(cb, PUSH, 4, TempReg, destl);
3564//-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, srch);
3565//-- uInstr1(cb, PUSH, 4, TempReg, srch);
3566//-- uInstr2(cb, GET, 4, ArchReg, R_EBX, TempReg, srcl);
3567//-- uInstr1(cb, PUSH, 4, TempReg, srcl);
3568//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, acch);
3569//-- uInstr1(cb, PUSH, 4, TempReg, acch);
3570//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, accl);
3571//-- uInstr1(cb, PUSH, 4, TempReg, accl);
3572//--
3573//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_cmpxchg8b));
3574//-- uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsEmpty);
3575//--
3576//-- uInstr1(cb, POP, 4, TempReg, accl);
3577//-- uInstr2(cb, PUT, 4, TempReg, accl, ArchReg, R_EAX);
3578//-- uInstr1(cb, POP, 4, TempReg, acch);
3579//-- uInstr2(cb, PUT, 4, TempReg, acch, ArchReg, R_EDX);
3580//-- uInstr1(cb, POP, 4, TempReg, srcl);
3581//-- uInstr2(cb, PUT, 4, TempReg, srcl, ArchReg, R_EBX);
3582//-- uInstr1(cb, POP, 4, TempReg, srch);
3583//-- uInstr2(cb, PUT, 4, TempReg, srch, ArchReg, R_ECX);
3584//-- uInstr1(cb, POP, 4, TempReg, destl);
3585//-- uInstr2(cb, STORE, 4, TempReg, destl, TempReg, tal);
3586//-- uInstr1(cb, POP, 4, TempReg, desth);
3587//-- uInstr2(cb, STORE, 4, TempReg, desth, TempReg, tah);
3588//--
3589//-- uInstr0(cb, CALLM_E, 0);
3590//--
3591//-- return eip0;
3592//-- }
3593//--
3594//--
3595//-- /* Handle conditional move instructions of the form
3596//-- cmovcc E(reg-or-mem), G(reg)
3597//--
3598//-- E(src) is reg-or-mem
3599//-- G(dst) is reg.
3600//--
3601//-- If E is reg, --> GET %E, tmps
3602//-- GET %G, tmpd
3603//-- CMOVcc tmps, tmpd
3604//-- PUT tmpd, %G
3605//--
3606//-- If E is mem --> (getAddr E) -> tmpa
3607//-- LD (tmpa), tmps
3608//-- GET %G, tmpd
3609//-- CMOVcc tmps, tmpd
3610//-- PUT tmpd, %G
3611//-- */
3612//-- static
3613//-- Addr dis_cmov_E_G ( UCodeBlock* cb,
3614//-- UChar sorb,
3615//-- Int size,
3616//-- Condcode cond,
3617//-- Addr eip0 )
3618//-- {
3619//-- UChar rm = getUChar(eip0);
3620//-- UChar dis_buf[50];
3621//--
3622//-- Int tmps = newTemp(cb);
3623//-- Int tmpd = newTemp(cb);
3624//--
3625//-- if (epartIsReg(rm)) {
3626//-- uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, tmps);
3627//-- uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmpd);
3628//-- uInstr2(cb, CMOV, 4, TempReg, tmps, TempReg, tmpd);
3629//-- uCond(cb, cond);
3630//-- uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
3631//-- uInstr2(cb, PUT, size, TempReg, tmpd, ArchReg, gregOfRM(rm));
3632//-- DIP("cmov%c%s %s,%s\n", nameISize(size),
3633//-- VG_(name_UCondcode)(cond),
3634//-- nameIReg(size,eregOfRM(rm)),
3635//-- nameIReg(size,gregOfRM(rm)));
3636//-- return 1+eip0;
3637//-- }
3638//--
3639//-- /* E refers to memory */
3640//-- {
3641//-- UInt pair = disAMode ( cb, sorb, eip0, dis_buf );
3642//-- Int tmpa = LOW24(pair);
3643//-- uInstr2(cb, LOAD, size, TempReg, tmpa, TempReg, tmps);
3644//-- uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmpd);
3645//-- uInstr2(cb, CMOV, 4, TempReg, tmps, TempReg, tmpd);
3646//-- uCond(cb, cond);
3647//-- uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
3648//-- uInstr2(cb, PUT, size, TempReg, tmpd, ArchReg, gregOfRM(rm));
3649//-- DIP("cmov%c%s %s,%s\n", nameISize(size),
3650//-- VG_(name_UCondcode)(cond),
3651//-- dis_buf,
3652//-- nameIReg(size,gregOfRM(rm)));
3653//-- return HI8(pair)+eip0;
3654//-- }
3655//-- }
3656//--
3657//--
3658//-- static
3659//-- Addr dis_xadd_G_E ( UCodeBlock* cb,
3660//-- UChar sorb,
3661//-- Int sz,
3662//-- Addr eip0 )
3663//-- {
3664//-- UChar rm = getUChar(eip0);
3665//-- UChar dis_buf[50];
3666//--
3667//-- Int tmpd = newTemp(cb);
3668//-- Int tmpt = newTemp(cb);
3669//--
3670//-- if (epartIsReg(rm)) {
3671//-- uInstr2(cb, GET, sz, ArchReg, eregOfRM(rm), TempReg, tmpd);
3672//-- uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
3673//-- uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
3674//-- setFlagsFromUOpcode(cb, ADD);
3675//-- uInstr2(cb, PUT, sz, TempReg, tmpt, ArchReg, eregOfRM(rm));
3676//-- uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
3677//-- DIP("xadd%c %s, %s\n",
3678//-- nameISize(sz), nameIReg(sz,gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
3679//-- return 1+eip0;
3680//-- } else {
3681//-- UInt pair = disAMode ( cb, sorb, eip0, dis_buf );
3682//-- Int tmpa = LOW24(pair);
3683//-- uInstr2(cb, LOAD, sz, TempReg, tmpa, TempReg, tmpd);
3684//-- uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
3685//-- uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
3686//-- setFlagsFromUOpcode(cb, ADD);
3687//-- uInstr2(cb, STORE, sz, TempReg, tmpt, TempReg, tmpa);
3688//-- uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
3689//-- DIP("xadd%c %s, %s\n",
3690//-- nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
3691//-- return HI8(pair)+eip0;
3692//-- }
3693//-- }
3694//--
3695//--
3696//-- /* Moves of Ew into a segment register.
3697//-- mov Ew, Sw meaning
3698//-- mov reg-or-mem, reg
3699//-- Is passed the a ptr to the modRM byte, and the data size. Returns
3700//-- the address advanced completely over this instruction.
3701//--
3702//-- Ew(src) is reg-or-mem
3703//-- Sw(dst) is seg reg.
3704//--
3705//-- If E is reg, --> GETw %Ew, tmpv
3706//-- PUTSEG tmpv, %Sw
3707//--
3708//-- If E is mem --> (getAddr E) -> tmpa
3709//-- LDw (tmpa), tmpb
3710//-- PUTSEG tmpb, %Sw
3711//-- */
3712//-- static
3713//-- Addr dis_mov_Ew_Sw ( UCodeBlock* cb,
3714//-- UChar sorb,
3715//-- Addr eip0 )
3716//-- {
3717//-- UChar rm = getUChar(eip0);
3718//-- UChar dis_buf[50];
3719//--
3720//-- if (epartIsReg(rm)) {
3721//-- Int tmpv = newTemp(cb);
3722//-- uInstr2(cb, GET, 2, ArchReg, eregOfRM(rm), TempReg, tmpv);
3723//-- uInstr2(cb, PUTSEG, 2, TempReg, tmpv, ArchRegS, gregOfRM(rm));
3724//-- DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
3725//-- return 1+eip0;
3726//-- }
3727//--
3728//-- /* E refers to memory */
3729//-- {
3730//-- UInt pair = disAMode ( cb, sorb, eip0, dis_buf );
3731//-- Int tmpa = LOW24(pair);
3732//-- Int tmpb = newTemp(cb);
3733//-- uInstr2(cb, LOAD, 2, TempReg, tmpa, TempReg, tmpb);
3734//-- uInstr2(cb, PUTSEG, 2, TempReg, tmpb, ArchRegS, gregOfRM(rm));
3735//-- DIP("movw %s,%s\n", dis_buf,nameSReg(gregOfRM(rm)));
3736//-- return HI8(pair)+eip0;
3737//-- }
3738//-- }
3739//--
3740//--
3741//-- /* Moves of a segment register to Ew.
3742//-- mov Sw, Ew meaning
3743//-- mov reg, reg-or-mem
3744//-- Is passed the a ptr to the modRM byte, and the data size. Returns
3745//-- the address advanced completely over this instruction.
3746//--
3747//-- Sw(src) is seg reg.
3748//-- Ew(dst) is reg-or-mem
3749//--
3750//-- If E is reg, --> GETSEG %Sw, tmp
3751//-- PUTW tmp, %Ew
3752//--
3753//-- If E is mem, --> (getAddr E) -> tmpa
3754//-- GETSEG %Sw, tmpv
3755//-- STW tmpv, (tmpa)
3756//-- */
3757//-- static
3758//-- Addr dis_mov_Sw_Ew ( UCodeBlock* cb,
3759//-- UChar sorb,
3760//-- Addr eip0 )
3761//-- {
3762//-- UChar rm = getUChar(eip0);
3763//-- UChar dis_buf[50];
3764//--
3765//-- if (epartIsReg(rm)) {
3766//-- Int tmpv = newTemp(cb);
3767//-- uInstr2(cb, GETSEG, 2, ArchRegS, gregOfRM(rm), TempReg, tmpv);
3768//-- uInstr2(cb, PUT, 2, TempReg, tmpv, ArchReg, eregOfRM(rm));
3769//-- DIP("movw %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(2,eregOfRM(rm)));
3770//-- return 1+eip0;
3771//-- }
3772//--
3773//-- /* E refers to memory */
3774//-- {
3775//-- UInt pair = disAMode ( cb, sorb, eip0, dis_buf );
3776//-- Int tmpa = LOW24(pair);
3777//-- Int tmpv = newTemp(cb);
3778//-- uInstr2(cb, GETSEG, 2, ArchRegS, gregOfRM(rm), TempReg, tmpv);
3779//-- uInstr2(cb, STORE, 2, TempReg, tmpv, TempReg, tmpa);
3780//-- DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
3781//-- return HI8(pair)+eip0;
3782//-- }
3783//-- }
3784//--
3785//--
3786//--
3787//-- /* Simple MMX operations, either
3788//-- op (src)mmxreg, (dst)mmxreg
3789//-- or
3790//-- op (src)address, (dst)mmxreg
3791//-- opc is the byte following the 0x0F prefix.
3792//-- */
3793//-- static
3794//-- Addr dis_MMXop_regmem_to_reg ( UCodeBlock* cb,
3795//-- UChar sorb,
3796//-- Addr eip,
3797//-- UChar opc,
3798//-- Char* name,
3799//-- Bool show_granularity )
3800//-- {
3801//-- Char dis_buf[50];
3802//-- UChar modrm = getUChar(eip);
3803//-- Bool isReg = epartIsReg(modrm);
3804//--
3805//-- if (isReg) {
3806//-- eip++;
3807//-- uInstr1(cb, MMX2, 0,
3808//-- Lit16,
3809//-- (((UShort)(opc)) << 8) | ((UShort)modrm) );
3810//-- } else {
3811//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
3812//-- Int tmpa = LOW24(pair);
3813//-- eip += HI8(pair);
3814//-- uInstr2(cb, MMX2_MemRd, 8,
3815//-- Lit16,
3816//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
3817//-- TempReg, tmpa);
3818//-- }
3819//--
3820//-- DIP("%s%s %s, %s\n",
3821//-- name, show_granularity ? nameMMXGran(opc & 3) : (Char*)"",
3822//-- ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
3823//-- nameMMXReg(gregOfRM(modrm)) );
3824//--
3825//-- return eip;
3826//-- }
3827//--
3828//--
3829//-- /* Simple MMX operations, either
3830//-- op (src)mmxreg, (dst)mmxreg
3831//-- or
3832//-- op (src)address, (dst)mmxreg
3833//-- opc is the byte following the 0x0F prefix.
3834//-- */
3835//-- static
3836//-- Addr dis_MMXop_regmem_to_reg_Imm8 ( UCodeBlock* cb,
3837//-- UChar sorb,
3838//-- Addr eip,
3839//-- UChar opc,
3840//-- Char* name,
3841//-- Bool show_granularity )
3842//-- {
3843//-- Char dis_buf[50];
3844//-- UChar modrm = getUChar(eip);
3845//-- UChar imm8;
3846//-- Bool isReg = epartIsReg(modrm);
3847//--
3848//-- if (isReg) {
3849//-- eip++;
3850//-- imm8 = getUChar(eip);
3851//-- eip++;
3852//-- uInstr2(cb, MMX3, 0,
3853//-- Lit16,
3854//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
3855//-- Lit16,
3856//-- ((UShort)imm8));
3857//-- } else {
3858//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
3859//-- Int tmpa = LOW24(pair);
3860//-- eip += HI8(pair);
3861//-- imm8 = getUChar(eip);
3862//-- eip++;
3863//-- uInstr3(cb, MMX2a1_MemRd, 8,
3864//-- Lit16,
3865//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
3866//-- Lit16,
3867//-- ((UShort)imm8),
3868//-- TempReg, tmpa);
3869//-- }
3870//--
3871//-- DIP("%s%s %s, %s, $%d\n",
3872//-- name, show_granularity ? nameMMXGran(opc & 3) : (Char*)"",
3873//-- ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
3874//-- nameMMXReg(gregOfRM(modrm)), (Int)imm8 );
3875//--
3876//-- return eip;
3877//-- }
3878//--
3879//--
3880//--
3881//-- /* Simple SSE operations, either
3882//-- op (src)xmmreg, (dst)xmmreg
3883//-- or
3884//-- op (src)address, (dst)xmmreg
3885//-- 3 opcode bytes.
3886//-- Supplied eip points to the first address mode byte.
3887//-- */
3888//-- static
3889//-- Addr dis_SSE3_reg_or_mem ( UCodeBlock* cb,
3890//-- UChar sorb,
3891//-- Addr eip,
3892//-- Int sz,
3893//-- Char* name,
3894//-- UChar opc1,
3895//-- UChar opc2,
3896//-- UChar opc3 )
3897//-- {
3898//-- Char dis_buf[50];
3899//-- UChar modrm = getUChar(eip);
3900//-- Bool isReg = epartIsReg(modrm);
3901//--
3902//-- if (isReg) {
3903//-- /* Completely internal SSE insn. */
3904//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
3905//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
3906//-- Lit16, (((UShort)opc3) << 8) | (UShort)modrm );
3907//-- eip++;
3908//-- } else {
3909//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
3910//-- Int tmpa = LOW24(pair);
3911//-- eip += HI8(pair);
3912//-- uInstr3(cb, SSE3a_MemRd, sz,
3913//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
3914//-- Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
3915//-- TempReg, tmpa);
3916//-- }
3917//--
3918//-- DIP("%s %s, %s\n",
3919//-- name,
3920//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
3921//-- nameXMMReg(gregOfRM(modrm)) );
3922//--
3923//-- return eip;
3924//-- }
3925//--
3926//--
3927//-- /* Simple SSE operations, either
3928//-- op (src)xmmreg, (dst)xmmreg
3929//-- or
3930//-- op (src)address, (dst)xmmreg
3931//-- 2 opcode bytes.
3932//-- Supplied eip points to the first address mode byte.
3933//-- */
3934//-- static
3935//-- Addr dis_SSE2_reg_or_mem ( UCodeBlock* cb,
3936//-- UChar sorb,
3937//-- Addr eip,
3938//-- Int sz,
3939//-- Char* name,
3940//-- UChar opc1,
3941//-- UChar opc2 )
3942//-- {
3943//-- Char dis_buf[50];
3944//-- UChar modrm = getUChar(eip);
3945//-- Bool isReg = epartIsReg(modrm);
3946//--
3947//-- if (isReg) {
3948//-- /* Completely internal SSE insn. */
3949//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
3950//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
3951//-- Lit16, (UShort)modrm );
3952//-- eip++;
3953//-- } else {
3954//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
3955//-- Int tmpa = LOW24(pair);
3956//-- eip += HI8(pair);
3957//-- uInstr3(cb, SSE2a_MemRd, sz,
3958//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
3959//-- Lit16, (UShort)modrm,
3960//-- TempReg, tmpa);
3961//-- }
3962//-- DIP("%s %s, %s\n",
3963//-- name,
3964//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
3965//-- nameXMMReg(gregOfRM(modrm)) );
3966//--
3967//-- return eip;
3968//-- }
3969//--
3970//--
3971//-- /* Simple SSE operations, either
3972//-- op (src)xmmreg, (dst)xmmreg
3973//-- or
3974//-- op (src)address, (dst)xmmreg
3975//-- 2 opcode bytes and an 8-bit immediate after the amode.
3976//-- Supplied eip points to the first address mode byte.
3977//-- */
3978//-- static
3979//-- Addr dis_SSE2_reg_or_mem_Imm8 ( UCodeBlock* cb,
3980//-- UChar sorb,
3981//-- Addr eip,
3982//-- Int sz,
3983//-- Char* name,
3984//-- UChar opc1,
3985//-- UChar opc2 )
3986//-- {
3987//-- Char dis_buf[50];
3988//-- UChar modrm = getUChar(eip);
3989//-- UChar imm8;
3990//-- Bool isReg = epartIsReg(modrm);
3991//--
3992//-- if (isReg) {
3993//-- /* Completely internal SSE insn. */
3994//-- eip++;
3995//-- imm8 = getUChar(eip);
3996//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
3997//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
3998//-- Lit16, (((UShort)modrm) << 8) | (UShort)imm8 );
3999//-- eip++;
4000//-- } else {
4001//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
4002//-- Int tmpa = LOW24(pair);
4003//-- eip += HI8(pair);
4004//-- imm8 = getUChar(eip);
4005//-- eip++;
4006//-- uInstr3(cb, SSE2a1_MemRd, sz,
4007//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
4008//-- Lit16, (((UShort)(modrm)) << 8) | ((UShort)imm8),
4009//-- TempReg, tmpa);
4010//-- }
4011//-- DIP("%s %s, %s, $%d\n",
4012//-- name, ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
4013//-- nameXMMReg(gregOfRM(modrm)), (Int)imm8 );
4014//-- return eip;
4015//-- }
4016//--
4017//--
4018//-- /* Simple SSE operations, either
4019//-- op (src)xmmreg, (dst)xmmreg
4020//-- or
4021//-- op (src)address, (dst)xmmreg
4022//-- 3 opcode bytes and an 8-bit immediate after the amode.
4023//-- Supplied eip points to the first address mode byte.
4024//-- */
4025//-- static
4026//-- Addr dis_SSE3_reg_or_mem_Imm8 ( UCodeBlock* cb,
4027//-- UChar sorb,
4028//-- Addr eip,
4029//-- Int sz,
4030//-- Char* name,
4031//-- UChar opc1,
4032//-- UChar opc2,
4033//-- UChar opc3 )
4034//-- {
4035//-- Char dis_buf[50];
4036//-- UChar modrm = getUChar(eip);
4037//-- UChar imm8;
4038//-- Bool isReg = epartIsReg(modrm);
4039//--
4040//-- if (isReg) {
4041//-- /* Completely internal SSE insn. */
4042//-- eip++;
4043//-- imm8 = getUChar(eip);
4044//-- uInstr3(cb, SSE5, 0, /* ignore sz for internal ops */
4045//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
4046//-- Lit16, (((UShort)opc3) << 8) | (UShort)modrm,
4047//-- Lit16, (UShort)imm8 );
4048//-- eip++;
4049//-- } else {
4050//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
4051//-- Int tmpa = LOW24(pair);
4052//-- eip += HI8(pair);
4053//-- imm8 = getUChar(eip);
4054//-- eip++;
4055//-- uInstr3(cb, SSE3a1_MemRd, sz,
4056//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
4057//-- Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
4058//-- TempReg, tmpa);
4059//-- uLiteral(cb, imm8);
4060//-- }
4061//-- DIP("%s %s, %s, $%d\n",
4062//-- name, ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
4063//-- nameXMMReg(gregOfRM(modrm)), (Int)imm8 );
4064//-- return eip;
4065//-- }
4066//--
4067//--
4068//-- /* Disassemble an SSE insn which is either a simple reg-reg move or a
4069//-- move between registers and memory. Supplied eip points to the
4070//-- first address mode byte.
4071//-- */
4072//-- static
4073//-- Addr dis_SSE3_load_store_or_mov ( UCodeBlock* cb,
4074//-- UChar sorb,
4075//-- Addr eip,
4076//-- Int sz,
4077//-- Bool is_store,
4078//-- Char* name,
4079//-- UChar insn0,
4080//-- UChar insn1,
4081//-- UChar insn2 )
4082//-- {
4083//-- Char dis_buf[50];
4084//-- UChar modrm = getUChar(eip);
4085//-- Bool isReg = epartIsReg(modrm);
4086//-- UInt pair;
4087//-- Int t1;
4088//--
4089//-- if (isReg) {
4090//-- /* Completely internal; we can issue SSE4. */
4091//-- eip++;
4092//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
4093//-- Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
4094//-- Lit16, (((UShort)insn2) << 8) | (UShort)modrm );
4095//-- } else {
4096//-- pair = disAMode ( cb, sorb, eip, dis_buf );
4097//-- t1 = LOW24(pair);
4098//-- eip += HI8(pair);
4099//-- uInstr3(cb, is_store ? SSE3a_MemWr : SSE3a_MemRd, sz,
4100//-- Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
4101//-- Lit16, (((UShort)insn2) << 8) | (UShort)modrm,
4102//-- TempReg, t1 );
4103//-- }
4104//--
4105//-- if (is_store) {
4106//-- DIP("%s %s, %s\n",
4107//-- name,
4108//-- nameXMMReg(gregOfRM(modrm)),
4109//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ) );
4110//-- } else {
4111//-- DIP("%s %s, %s\n",
4112//-- name,
4113//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
4114//-- nameXMMReg(gregOfRM(modrm)) );
4115//-- }
4116//-- return eip;
4117//-- }
4118//--
4119//--
4120//-- /* Disassemble an SSE insn which is either a simple reg-reg move or a
4121//-- move between registers and memory. Supplied eip points to the
4122//-- first address mode byte. */
4123//-- static
4124//-- Addr dis_SSE2_load_store_or_mov ( UCodeBlock* cb,
4125//-- UChar sorb,
4126//-- Addr eip,
4127//-- Int sz,
4128//-- Bool is_store,
4129//-- Char* name,
4130//-- UChar insn0,
4131//-- UChar insn1 )
4132//-- {
4133//-- Char dis_buf[50];
4134//-- UChar modrm = getUChar(eip);
4135//-- Bool isReg = epartIsReg(modrm);
4136//-- UInt pair;
4137//-- Int t1;
4138//--
4139//-- if (isReg) {
4140//-- /* Completely internal; we can issue SSE3. */
4141//-- eip++;
4142//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
4143//-- Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
4144//-- Lit16, (UShort)modrm );
4145//-- } else {
4146//-- pair = disAMode ( cb, sorb, eip, dis_buf );
4147//-- t1 = LOW24(pair);
4148//-- eip += HI8(pair);
4149//-- uInstr3(cb, is_store ? SSE2a_MemWr : SSE2a_MemRd, sz,
4150//-- Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
4151//-- Lit16, (UShort)modrm,
4152//-- TempReg, t1 );
4153//-- }
4154//--
4155//-- if (is_store) {
4156//-- DIP("%s %s, %s\n",
4157//-- name,
4158//-- nameXMMReg(gregOfRM(modrm)),
4159//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ) );
4160//-- } else {
4161//-- DIP("%s %s, %s\n",
4162//-- name,
4163//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
4164//-- nameXMMReg(gregOfRM(modrm)) );
4165//-- }
4166//-- return eip;
4167//-- }
4168//--
4169//--
4170//-- /* Simple SSE operations, either
4171//-- op (src)xmmreg, (dst)mmxreg
4172//-- or
4173//-- op (src)address, (dst)mmxreg
4174//-- 2 opcode bytes.
4175//-- Supplied eip points to the first address mode byte.
4176//-- */
4177//-- static
4178//-- Addr dis_SSE2_to_MMX ( UCodeBlock *cb,
4179//-- UChar sorb,
4180//-- Addr eip,
4181//-- Int sz,
4182//-- Char* name,
4183//-- UChar opc1,
4184//-- UChar opc2 )
4185//-- {
4186//-- UChar dis_buf[50];
4187//-- UChar modrm = getUChar(eip);
4188//-- if (epartIsReg(modrm)) {
4189//-- /* Completely internal SSE insn. */
4190//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
4191//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
4192//-- Lit16, (UShort)modrm );
4193//-- DIP("%s %s, %s\n",
4194//-- name, nameXMMReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)) );
4195//-- eip++;
4196//-- } else {
4197//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
4198//-- Int tmpa = LOW24(pair);
4199//-- eip += HI8(pair);
4200//-- uInstr3(cb, SSE2a_MemRd, sz,
4201//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
4202//-- Lit16, ((UShort)modrm),
4203//-- TempReg, tmpa);
4204//-- DIP("%s %s, %s\n", name, dis_buf, nameMMXReg(gregOfRM(modrm)));
4205//-- }
4206//-- return eip;
4207//-- }
4208//--
4209//--
4210//-- /* Simple SSE operations, either
4211//-- op (src)mmxreg, (dst)xmmreg
4212//-- or
4213//-- op (src)address, (dst)xmmreg
4214//-- 2 opcode bytes.
4215//-- Supplied eip points to the first address mode byte.
4216//-- */
4217//-- static
4218//-- Addr dis_SSE2_from_MMX ( UCodeBlock *cb,
4219//-- UChar sorb,
4220//-- Addr eip,
4221//-- Int sz,
4222//-- Char* name,
4223//-- UChar opc1,
4224//-- UChar opc2 )
4225//-- {
4226//-- UChar dis_buf[50];
4227//-- UChar modrm = getUChar(eip);
4228//-- if (epartIsReg(modrm)) {
4229//-- /* Completely internal SSE insn. */
4230//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
4231//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
4232//-- Lit16, (UShort)modrm );
4233//-- DIP("%s %s, %s\n",
4234//-- name, nameMMXReg(eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)) );
4235//-- eip++;
4236//-- } else {
4237//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
4238//-- Int tmpa = LOW24(pair);
4239//-- eip += HI8(pair);
4240//-- uInstr3(cb, SSE2a_MemRd, sz,
4241//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
4242//-- Lit16, ((UShort)modrm),
4243//-- TempReg, tmpa);
4244//-- DIP("%s %s, %s\n", name, dis_buf, nameXMMReg(gregOfRM(modrm)));
4245//-- }
4246//-- return eip;
4247//-- }
4248//--
4249//--
4250//-- /* Simple SSE operations, either
4251//-- op (src)xmmreg, (dst)mmxreg
4252//-- or
4253//-- op (src)address, (dst)mmxreg
4254//-- 3 opcode bytes.
4255//-- Supplied eip points to the first address mode byte.
4256//-- */
4257//-- static
4258//-- Addr dis_SSE3_to_MMX ( UCodeBlock *cb,
4259//-- UChar sorb,
4260//-- Addr eip,
4261//-- Int sz,
4262//-- Char* name,
4263//-- UChar opc1,
4264//-- UChar opc2,
4265//-- UChar opc3 )
4266//-- {
4267//-- UChar dis_buf[50];
4268//-- UChar modrm = getUChar(eip);
4269//-- if (epartIsReg(modrm)) {
4270//-- /* Completely internal SSE insn. */
4271//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
4272//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
4273//-- Lit16, (((UShort)opc3) << 8) | (UShort)modrm );
4274//-- DIP("%s %s, %s\n",
4275//-- name, nameXMMReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)) );
4276//-- eip++;
4277//-- } else {
4278//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
4279//-- Int tmpa = LOW24(pair);
4280//-- eip += HI8(pair);
4281//-- uInstr3(cb, SSE3a_MemRd, sz,
4282//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
4283//-- Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
4284//-- TempReg, tmpa);
4285//-- DIP("%s %s, %s\n", name, dis_buf, nameMMXReg(gregOfRM(modrm)));
4286//-- }
4287//-- return eip;
4288//-- }
4289//--
4290//--
4291//-- /* Simple SSE operations, either
4292//-- op (src)mmxreg, (dst)xmmreg
4293//-- or
4294//-- op (src)address, (dst)xmmreg
4295//-- 3 opcode bytes.
4296//-- Supplied eip points to the first address mode byte.
4297//-- */
4298//-- static
4299//-- Addr dis_SSE3_from_MMX ( UCodeBlock *cb,
4300//-- UChar sorb,
4301//-- Addr eip,
4302//-- Int sz,
4303//-- Char* name,
4304//-- UChar opc1,
4305//-- UChar opc2,
4306//-- UChar opc3 )
4307//-- {
4308//-- UChar dis_buf[50];
4309//-- UChar modrm = getUChar(eip);
4310//-- if (epartIsReg(modrm)) {
4311//-- /* Completely internal SSE insn. */
4312//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
4313//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
4314//-- Lit16, (((UShort)opc3) << 8) | (UShort)modrm );
4315//-- DIP("%s %s, %s\n",
4316//-- name, nameMMXReg(eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)) );
4317//-- eip++;
4318//-- } else {
4319//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
4320//-- Int tmpa = LOW24(pair);
4321//-- eip += HI8(pair);
4322//-- uInstr3(cb, SSE3a_MemRd, sz,
4323//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
4324//-- Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
4325//-- TempReg, tmpa);
4326//-- DIP("%s %s, %s\n", name, dis_buf, nameXMMReg(gregOfRM(modrm)));
4327//-- }
4328//-- return eip;
4329//-- }
4330//--
4331//--
4332//-- static
4333//-- void dis_push_segreg ( UCodeBlock* cb, UInt sreg, Int sz )
4334//-- {
4335//-- Int t1 = newTemp(cb), t2 = newTemp(cb);
4336//-- vg_assert(sz == 2 || sz == 4);
4337//-- uInstr2(cb, GETSEG, 2, ArchRegS, sreg, TempReg, t1);
4338//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
4339//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
4340//-- uLiteral(cb, sz);
4341//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
4342//-- uInstr2(cb, STORE, 2, TempReg, t1, TempReg, t2);
4343//-- DIP("push %s\n", VG_(name_of_seg_reg)(sreg));
4344//-- }
4345//--
4346//-- static
4347//-- void dis_pop_segreg ( UCodeBlock* cb, UInt sreg, Int sz )
4348//-- {
4349//-- Int t1 = newTemp(cb), t2 = newTemp(cb);
4350//-- vg_assert(sz == 2 || sz == 4);
4351//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
4352//-- uInstr2(cb, LOAD, 2, TempReg, t2, TempReg, t1);
4353//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
4354//-- uLiteral(cb, sz);
4355//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
4356//-- uInstr2(cb, PUTSEG, 2, TempReg, t1, ArchRegS, sreg);
4357//-- DIP("pop %s\n", VG_(name_of_seg_reg)(sreg));
4358//-- }
sewardje05c42c2004-07-08 20:25:10 +00004359
4360static
4361void dis_ret ( UInt d32 )
4362{
4363 IRTemp t1 = newTemp(Ity_I32), t2 = newTemp(Ity_I32);
4364 assign(t1, getIReg(4,R_ESP));
4365 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
4366 putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(4+d32)));
sewardj78c19df2004-07-12 22:49:27 +00004367 jmp_treg(Ijk_Ret,t2);
sewardje05c42c2004-07-08 20:25:10 +00004368}
4369
sewardjc9a65702004-07-07 16:32:57 +00004370
4371/*------------------------------------------------------------*/
4372/*--- Disassembling entire basic blocks ---*/
4373/*------------------------------------------------------------*/
4374
4375/* Disassemble a single instruction into IR, returning the updated
4376 delta, and setting *isEnd to True if this is the last insn in a
4377 basic block. Also do debug printing if necessary. */
4378
4379static UInt disInstr ( UInt delta, Bool* isEnd )
4380{
sewardj0c12ea82004-07-12 08:18:16 +00004381 IRType ty;
4382 IRTemp addr, t1, t2;
sewardje87b4842004-07-10 12:23:30 +00004383 Int alen;
sewardj64e1d652004-07-12 14:00:46 +00004384 UChar opc, modrm, abyte;
4385 UInt d32;
sewardje87b4842004-07-10 12:23:30 +00004386 UChar dis_buf[50];
4387 Int am_sz, d_sz;
sewardjc9a65702004-07-07 16:32:57 +00004388 //Char loc_buf[M_VG_ERRTXT];
4389
4390 /* Holds eip at the start of the insn, so that we can print
4391 consistent error messages for unimplemented insns. */
4392 UInt delta_start = delta;
4393
4394 /* sz denotes the nominal data-op size of the insn; we change it to
4395 2 if an 0x66 prefix is seen */
4396 Int sz = 4;
4397
4398 /* sorb holds the segment-override-prefix byte, if any. Zero if no
4399 prefix has been seen, else one of {0x26, 0x3E, 0x64, 0x65}
4400 indicating the prefix. */
4401 UChar sorb = 0;
4402
4403 /* For printing the stmts after each insn. */
4404 IRStmt* first_stmt = last_stmt;
4405
4406 *isEnd = False;
sewardj940e8c92004-07-11 16:53:24 +00004407 addr = t1 = t2 = INVALID_IRTEMP;
sewardj41f43bc2004-07-08 14:23:22 +00004408 //t3 = t4 = INVALID_IRTEMP;
sewardjc9a65702004-07-07 16:32:57 +00004409
4410 DIP("\t0x%x: ", guest_eip+delta);
4411
4412//-- /* Spot the client-request magic sequence. */
4413//-- {
4414//-- UChar* myeip = (UChar*)eip;
4415//-- /* Spot this:
4416//-- C1C01D roll $29, %eax
4417//-- C1C003 roll $3, %eax
4418//-- C1C81B rorl $27, %eax
4419//-- C1C805 rorl $5, %eax
4420//-- C1C00D roll $13, %eax
4421//-- C1C013 roll $19, %eax
4422//-- */
4423//-- if (myeip[ 0] == 0xC1 && myeip[ 1] == 0xC0 && myeip[ 2] == 0x1D &&
4424//-- myeip[ 3] == 0xC1 && myeip[ 4] == 0xC0 && myeip[ 5] == 0x03 &&
4425//-- myeip[ 6] == 0xC1 && myeip[ 7] == 0xC8 && myeip[ 8] == 0x1B &&
4426//-- myeip[ 9] == 0xC1 && myeip[10] == 0xC8 && myeip[11] == 0x05 &&
4427//-- myeip[12] == 0xC1 && myeip[13] == 0xC0 && myeip[14] == 0x0D &&
4428//-- myeip[15] == 0xC1 && myeip[16] == 0xC0 && myeip[17] == 0x13
4429//-- ) {
4430//-- eip += 18;
4431//-- jmp_lit(cb, eip);
4432//-- LAST_UINSTR(cb).jmpkind = JmpClientReq;
4433//-- *isEnd = True;
4434//-- DIP("%%edx = client_request ( %%eax )\n");
4435//-- return eip;
4436//-- }
4437//-- }
4438
4439 /* Skip a LOCK prefix. */
4440 if (getIByte(delta) == 0xF0) {
4441 /* VG_(printf)("LOCK LOCK LOCK LOCK LOCK \n"); */
4442 vpanic("x86 LOCK. what to do?");
4443 delta++;
4444 }
4445
4446 /* Detect operand-size overrides. */
4447 if (getIByte(delta) == 0x66) { sz = 2; delta++; };
4448
4449 /* segment override prefixes come after the operand-size override,
4450 it seems */
4451 switch (getIByte(delta)) {
4452 case 0x3E: /* %DS: */
4453 case 0x26: /* %ES: */
4454 case 0x64: /* %FS: */
4455 case 0x65: /* %GS: */
4456 sorb = getIByte(delta); delta++;
4457 break;
4458 case 0x2E: /* %CS: */
4459 /* 2E prefix on a conditional branch instruction is a
4460 branch-prediction hint, which can safely be ignored. */
4461 {
4462 UChar op1 = getIByte(delta+1);
4463 UChar op2 = getIByte(delta+2);
4464 if ((op1 >= 0x70 && op1 <= 0x7F)
4465 || (op1 == 0xE3)
4466 || (op1 == 0x0F && op2 >= 0x80 && op2 <= 0x8F)) {
4467 sorb = getIByte(delta); delta++;
4468 break;
4469 }
4470 }
4471 unimplemented("x86 segment override (SEG=CS) prefix");
4472 /*NOTREACHED*/
4473 break;
4474 case 0x36: /* %SS: */
4475 unimplemented("x86 segment override (SEG=SS) prefix");
4476 /*NOTREACHED*/
4477 break;
4478 default:
4479 break;
4480 }
4481
4482//-- /* ---------------------------------------------------- */
4483//-- /* --- The SSE/SSE2 decoder. --- */
4484//-- /* ---------------------------------------------------- */
4485//--
4486//-- /* If it looks like this CPU might support SSE, try decoding SSE
4487//-- insns. */
4488//-- if (VG_(have_ssestate)) {
4489//-- UChar* insn = (UChar*)eip;
4490//--
4491//-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
4492//-- if (insn[0] == 0x0F && insn[1] == 0xAE
4493//-- && (!epartIsReg(insn[2]))
4494//-- && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
4495//-- Bool store = gregOfRM(insn[2]) == 0;
4496//-- vg_assert(sz == 4);
4497//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
4498//-- t1 = LOW24(pair);
4499//-- eip += 2+HI8(pair);
4500//-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
4501//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
4502//-- Lit16, (UShort)insn[2],
4503//-- TempReg, t1 );
4504//-- DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
4505//-- goto decode_success;
4506//-- }
4507//--
4508//-- /* STMXCSR/LDMXCSR m32 -- load/store the MXCSR register. */
4509//-- if (insn[0] == 0x0F && insn[1] == 0xAE
4510//-- && (!epartIsReg(insn[2]))
4511//-- && (gregOfRM(insn[2]) == 3 || gregOfRM(insn[2]) == 2) ) {
4512//-- Bool store = gregOfRM(insn[2]) == 3;
4513//-- vg_assert(sz == 4);
4514//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
4515//-- t1 = LOW24(pair);
4516//-- eip += 2+HI8(pair);
4517//-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 4,
4518//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
4519//-- Lit16, (UShort)insn[2],
4520//-- TempReg, t1 );
4521//-- DIP("%smxcsr %s\n", store ? "st" : "ld", dis_buf );
4522//-- goto decode_success;
4523//-- }
4524//--
4525//-- /* LFENCE/MFENCE/SFENCE -- flush pending operations to memory */
4526//-- if (insn[0] == 0x0F && insn[1] == 0xAE
4527//-- && (epartIsReg(insn[2]))
4528//-- && (gregOfRM(insn[2]) >= 5 && gregOfRM(insn[2]) <= 7))
4529//-- {
4530//-- vg_assert(sz == 4);
4531//-- eip += 3;
4532//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
4533//-- Lit16, (((UShort)0x0F) << 8) | (UShort)0xAE,
4534//-- Lit16, (UShort)insn[2] );
4535//-- DIP("sfence\n");
4536//-- goto decode_success;
4537//-- }
4538//--
4539//-- /* CLFLUSH -- flush cache line */
4540//-- if (insn[0] == 0x0F && insn[1] == 0xAE
4541//-- && (!epartIsReg(insn[2]))
4542//-- && (gregOfRM(insn[2]) == 7))
4543//-- {
4544//-- vg_assert(sz == 4);
4545//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
4546//-- t1 = LOW24(pair);
4547//-- eip += 2+HI8(pair);
4548//-- uInstr3(cb, SSE2a_MemRd, 0, /* ignore sz for internal ops */
4549//-- Lit16, (((UShort)0x0F) << 8) | (UShort)0xAE,
4550//-- Lit16, (UShort)insn[2],
4551//-- TempReg, t1 );
4552//-- DIP("clflush %s\n", dis_buf);
4553//-- goto decode_success;
4554//-- }
4555//--
4556//-- /* CVTPI2PS (0x0F,0x2A) -- mm/m64, xmm */
4557//-- /* CVTPI2PD (0x66,0x0F,0x2A) -- mm/m64, xmm */
4558//-- if (insn[0] == 0x0F && insn[1] == 0x2A) {
4559//-- if (sz == 4) {
4560//-- eip = dis_SSE2_from_MMX
4561//-- ( cb, sorb, eip+2, 8, "cvtpi2ps",
4562//-- insn[0], insn[1] );
4563//-- } else {
4564//-- eip = dis_SSE3_from_MMX
4565//-- ( cb, sorb, eip+2, 8, "cvtpi2pd",
4566//-- 0x66, insn[0], insn[1] );
4567//-- }
4568//-- goto decode_success;
4569//-- }
4570//--
4571//-- /* CVTTPS2PI (0x0F,0x2C) -- xmm/m64, mm */
4572//-- /* CVTPS2PI (0x0F,0x2D) -- xmm/m64, mm */
4573//-- /* CVTTPD2PI (0x66,0x0F,0x2C) -- xmm/m128, mm */
4574//-- /* CVTPD2PI (0x66,0x0F,0x2D) -- xmm/m128, mm */
4575//-- if (insn[0] == 0x0F
4576//-- && (insn[1] == 0x2C || insn[1] == 0x2D)) {
4577//-- if (sz == 4) {
4578//-- eip = dis_SSE2_to_MMX
4579//-- ( cb, sorb, eip+2, 8, "cvt{t}ps2pi",
4580//-- insn[0], insn[1] );
4581//-- } else {
4582//-- eip = dis_SSE3_to_MMX
4583//-- ( cb, sorb, eip+2, 16, "cvt{t}pd2pi",
4584//-- 0x66, insn[0], insn[1] );
4585//-- }
4586//-- goto decode_success;
4587//-- }
4588//--
4589//-- /* CVTTSD2SI (0xF2,0x0F,0x2C) -- convert a double-precision float
4590//-- value in memory or xmm reg to int and put it in an ireg.
4591//-- Truncate. */
4592//-- /* CVTTSS2SI (0xF3,0x0F,0x2C) -- convert a single-precision float
4593//-- value in memory or xmm reg to int and put it in an ireg.
4594//-- Truncate. */
4595//-- /* CVTSD2SI (0xF2,0x0F,0x2D) -- convert a double-precision float
4596//-- value in memory or xmm reg to int and put it in an ireg. Round
4597//-- as per MXCSR. */
4598//-- /* CVTSS2SI (0xF3,0x0F,0x2D) -- convert a single-precision float
4599//-- value in memory or xmm reg to int and put it in an ireg. Round
4600//-- as per MXCSR. */
4601//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
4602//-- && insn[1] == 0x0F
4603//-- && (insn[2] == 0x2C || insn[2] == 0x2D)) {
4604//-- vg_assert(sz == 4);
4605//-- modrm = insn[3];
4606//-- if (epartIsReg(modrm)) {
4607//-- /* We're moving a value in an xmm reg to an ireg. */
4608//-- eip += 4;
4609//-- t1 = newTemp(cb);
4610//-- /* sz is 4 for all 4 insns. */
4611//-- vg_assert(epartIsReg(modrm));
4612//-- uInstr3(cb, SSE3g_RegWr, 4,
4613//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
4614//-- Lit16, (((UShort)insn[2]) << 8) | (UShort)modrm,
4615//-- TempReg, t1 );
4616//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
4617//-- DIP("cvt{t}s{s,d}2si %s, %s\n",
4618//-- nameXMMReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)) );
4619//-- } else {
4620//-- /* So, we're reading memory and writing an ireg. This calls
4621//-- for the ultra-horrible SSE3ag_MemRd_RegWr uinstr. We
4622//-- can't do it in a roundabout route because it does some
4623//-- kind of conversion on the way, which we need to have
4624//-- happen too. So our only choice is to re-emit a suitably
4625//-- rehashed version of the instruction. */
4626//-- /* Destination ireg is GREG. Address goes as EREG as
4627//-- usual. */
4628//-- t1 = newTemp(cb); /* t1 holds value on its way to ireg */
4629//-- pair = disAMode ( cb, sorb, eip+3, dis_buf );
4630//-- t2 = LOW24(pair); /* t2 holds addr */
4631//-- eip += 3+HI8(pair);
4632//-- uInstr2(cb, SSE3ag_MemRd_RegWr, insn[0]==0xF2 ? 8 : 4,
4633//-- TempReg, t2, /* address */
4634//-- TempReg, t1 /* dest */);
4635//-- uLiteral(cb , (((UInt)insn[0]) << 24)
4636//-- | (((UInt)insn[1]) << 16)
4637//-- | (((UInt)insn[2]) << 8)
4638//-- | ((UInt)modrm) );
4639//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
4640//-- DIP("cvt{t}s{s,d}2si %s, %s\n",
4641//-- dis_buf, nameIReg(4,gregOfRM(modrm)) );
4642//-- }
4643//-- goto decode_success;
4644//-- }
4645//--
4646//-- /* CVTSI2SS -- convert int reg, or int value in memory, to low 4
4647//-- bytes of XMM reg. */
4648//-- /* CVTSI2SD -- convert int reg, or int value in memory, to low 8
4649//-- bytes of XMM reg. */
4650//-- if ((insn[0] == 0xF3 /*CVTSI2SS*/ || insn[0] == 0xF2 /* CVTSI2SD*/)
4651//-- && insn[1] == 0x0F && insn[2] == 0x2A) {
4652//-- Char* s_or_d = insn[0]==0xF3 ? "s" : "d";
4653//-- vg_assert(sz == 4);
4654//-- modrm = insn[3];
4655//-- t1 = newTemp(cb);
4656//-- if (epartIsReg(modrm)) {
4657//-- uInstr2(cb, GET, 4, ArchReg, eregOfRM(modrm), TempReg, t1);
4658//-- vg_assert(epartIsReg(modrm));
4659//-- uInstr3(cb, SSE3e_RegRd, 4,
4660//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
4661//-- Lit16, (((UShort)insn[2]) << 8) | (UShort)modrm,
4662//-- TempReg, t1 );
4663//-- eip += 4;
4664//-- DIP("cvtsi2s%s %s, %s\n", s_or_d,
4665//-- nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
4666//-- } else {
4667//-- pair = disAMode ( cb, sorb, eip+3, dis_buf );
4668//-- t2 = LOW24(pair);
4669//-- eip += 3+HI8(pair);
4670//-- uInstr3(cb, SSE3a_MemRd, 4,
4671//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
4672//-- Lit16, (((UShort)insn[2]) << 8) | (UShort)modrm,
4673//-- TempReg, t2 );
4674//-- DIP("cvtsi2s%s %s, %s\n",
4675//-- s_or_d, dis_buf, nameXMMReg(gregOfRM(modrm)));
4676//-- }
4677//-- goto decode_success;
4678//-- }
4679//--
4680//-- /* CVTPS2PD -- convert two packed floats to two packed doubles. */
4681//-- /* 0x66: CVTPD2PS -- convert two packed doubles to two packed floats. */
4682//-- if (insn[0] == 0x0F && insn[1] == 0x5A) {
4683//-- vg_assert(sz == 2 || sz == 4);
4684//-- if (sz == 4) {
4685//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 8, "cvtps2pd",
4686//-- insn[0], insn[1] );
4687//-- } else {
4688//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "cvtpd2ps",
4689//-- 0x66, insn[0], insn[1] );
4690//-- }
4691//-- goto decode_success;
4692//-- }
4693//--
4694//-- /* CVTSS2SD -- convert one single float to double. */
4695//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5A) {
4696//-- vg_assert(sz == 4);
4697//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4, "cvtss2sd",
4698//-- insn[0], insn[1], insn[2] );
4699//-- goto decode_success;
4700//-- }
4701//--
4702//-- /* CVTSD2SS -- convert one single double. to float. */
4703//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5A) {
4704//-- vg_assert(sz == 4);
4705//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8, "cvtsd2ss",
4706//-- insn[0], insn[1], insn[2] );
4707//-- goto decode_success;
4708//-- }
4709//--
4710//-- /* CVTDQ2PS -- convert four ints to four packed floats. */
4711//-- /* 0x66: CVTPS2DQ -- convert four packed floats to four ints. */
4712//-- if (insn[0] == 0x0F && insn[1] == 0x5B) {
4713//-- vg_assert(sz == 2 || sz == 4);
4714//-- if (sz == 4) {
4715//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "cvtdq2ps",
4716//-- insn[0], insn[1] );
4717//-- } else {
4718//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "cvtps2dq",
4719//-- 0x66, insn[0], insn[1] );
4720//-- }
4721//-- goto decode_success;
4722//-- }
4723//--
4724//-- /* CVTPD2DQ -- convert two packed doubles to two ints. */
4725//-- if (sz == 2
4726//-- && insn[0] == 0x0F && insn[1] == 0xE6) {
4727//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 8, "cvtpd2dq",
4728//-- 0x66, insn[0], insn[1] );
4729//-- goto decode_success;
4730//-- }
4731//--
4732//-- /* CVTTPD2DQ -- convert two packed doubles to two ints with truncation. */
4733//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xE6) {
4734//-- vg_assert(sz == 4);
4735//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8, "cvttpd2dq",
4736//-- insn[0], insn[1], insn[2] );
4737//-- goto decode_success;
4738//-- }
4739//--
4740//-- /* CVTDQ2PD -- convert two ints to two packed doubles. */
4741//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xE6) {
4742//-- vg_assert(sz == 4);
4743//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8, "cvtdq2pd",
4744//-- insn[0], insn[1], insn[2] );
4745//-- goto decode_success;
4746//-- }
4747//--
4748//-- /* CVTTPS2DQ -- convert four packed floats to four ints with truncation. */
4749//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5B) {
4750//-- vg_assert(sz == 4);
4751//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 16, "cvttps2dq",
4752//-- insn[0], insn[1], insn[2] );
4753//-- goto decode_success;
4754//-- }
4755//--
4756//-- /* CMPSS -- compare scalar floats. */
4757//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xC2) {
4758//-- vg_assert(sz == 4);
4759//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 8, "cmpss",
4760//-- insn[0], insn[1], insn[2] );
4761//-- goto decode_success;
4762//-- }
4763//--
4764//-- /* CMPSD -- compare scalar doubles. */
4765//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xC2) {
4766//-- vg_assert(sz == 4);
4767//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 8, "cmpsd",
4768//-- insn[0], insn[1], insn[2] );
4769//-- goto decode_success;
4770//-- }
4771//--
4772//-- /* sz==4: CMPPS -- compare packed floats */
4773//-- /* sz==2: CMPPD -- compare packed doubles */
4774//-- if (insn[0] == 0x0F && insn[1] == 0xC2) {
4775//-- vg_assert(sz == 4 || sz == 2);
4776//-- if (sz == 4) {
4777//-- eip = dis_SSE2_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "cmpps",
4778//-- insn[0], insn[1] );
4779//-- } else {
4780//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "cmppd",
4781//-- 0x66, insn[0], insn[1] );
4782//-- }
4783//-- goto decode_success;
4784//-- }
4785//--
4786//-- /* PSHUFD */
4787//-- if (sz == 2
4788//-- && insn[0] == 0x0F && insn[1] == 0x70) {
4789//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16,
4790//-- "pshufd",
4791//-- 0x66, insn[0], insn[1] );
4792//-- goto decode_success;
4793//-- }
4794//--
4795//-- /* PSHUFLW */
4796//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x70) {
4797//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 16,
4798//-- "pshuflw",
4799//-- insn[0], insn[1], insn[2] );
4800//-- goto decode_success;
4801//-- }
4802//--
4803//-- /* PSHUFHW */
4804//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x70) {
4805//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 16,
4806//-- "pshufhw",
4807//-- insn[0], insn[1], insn[2] );
4808//-- goto decode_success;
4809//-- }
4810//--
4811//-- /* SHUFPD */
4812//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC6) {
4813//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "shufpd",
4814//-- 0x66, insn[0], insn[1] );
4815//-- goto decode_success;
4816//-- }
4817//--
4818//-- /* SHUFPS */
4819//-- if (insn[0] == 0x0F && insn[1] == 0xC6) {
4820//-- vg_assert(sz == 4);
4821//-- eip = dis_SSE2_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "shufps",
4822//-- insn[0], insn[1] );
4823//-- goto decode_success;
4824//-- }
4825//--
4826//-- /* 0xF2: MULSD */
4827//-- /* 0xF3: MULSS -- multiply low 4 bytes of XMM reg. */
4828//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
4829//-- && insn[1] == 0x0F && insn[2] == 0x59) {
4830//-- Bool sz8 = insn[0] == 0xF2;
4831//-- vg_assert(sz == 4);
4832//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
4833//-- sz8 ? "mulss" : "mulsd",
4834//-- insn[0], insn[1], insn[2] );
4835//-- goto decode_success;
4836//-- }
4837//--
4838//-- /* MULPS */
4839//-- /* 0x66: MULPD */
4840//-- if (insn[0] == 0x0F && insn[1] == 0x59) {
4841//-- vg_assert(sz == 4 || sz == 2);
4842//-- if (sz == 4) {
4843//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "mulps",
4844//-- insn[0], insn[1] );
4845//-- } else {
4846//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "mulpd",
4847//-- 0x66, insn[0], insn[1] );
4848//-- }
4849//-- goto decode_success;
4850//-- }
4851//--
4852//-- /* 0xF2: DIVSD */
4853//-- /* 0xF3: DIVSS -- divide low 4 bytes of XMM reg. */
4854//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
4855//-- && insn[1] == 0x0F && insn[2] == 0x5E) {
4856//-- Bool sz8 = insn[0] == 0xF2;
4857//-- vg_assert(sz == 4);
4858//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
4859//-- sz8 ? "divsd" : "divss",
4860//-- insn[0], insn[1], insn[2] );
4861//-- goto decode_success;
4862//-- }
4863//--
4864//-- /* DIVPS */
4865//-- /* 0x66: DIVPD */
4866//-- if (insn[0] == 0x0F && insn[1] == 0x5E) {
4867//-- vg_assert(sz == 4 || sz == 2);
4868//-- if (sz == 4) {
4869//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "divps",
4870//-- insn[0], insn[1] );
4871//-- } else {
4872//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "divpd",
4873//-- 0x66, insn[0], insn[1] );
4874//-- }
4875//-- goto decode_success;
4876//-- }
4877//--
4878//-- /* 0xF2: SUBSD */
4879//-- /* 0xF3: SUBSS */
4880//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
4881//-- && insn[1] == 0x0F && insn[2] == 0x5C) {
4882//-- Bool sz8 = insn[0] == 0xF2;
4883//-- vg_assert(sz == 4);
4884//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
4885//-- sz8 ? "subsd" : "subss",
4886//-- insn[0], insn[1], insn[2] );
4887//-- goto decode_success;
4888//-- }
4889//--
4890//-- /* SUBPS */
4891//-- /* 0x66: SUBPD */
4892//-- if (insn[0] == 0x0F && insn[1] == 0x5C) {
4893//-- vg_assert(sz == 4 || sz == 2);
4894//-- if (sz == 4) {
4895//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "subps",
4896//-- insn[0], insn[1] );
4897//-- } else {
4898//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "subpd",
4899//-- 0x66, insn[0], insn[1] );
4900//-- }
4901//-- goto decode_success;
4902//-- }
4903//--
4904//-- /* 0xF2: ADDSD */
4905//-- /* 0xF3: ADDSS */
4906//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
4907//-- && insn[1] == 0x0F && insn[2] == 0x58) {
4908//-- Bool sz8 = insn[0] == 0xF2;
4909//-- vg_assert(sz == 4);
4910//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
4911//-- sz8 ? "addsd" : "addss",
4912//-- insn[0], insn[1], insn[2] );
4913//-- goto decode_success;
4914//-- }
4915//--
4916//-- /* ADDPS */
4917//-- /* 0x66: ADDPD */
4918//-- if (insn[0] == 0x0F && insn[1] == 0x58) {
4919//-- vg_assert(sz == 4 || sz == 2);
4920//-- if (sz == 4) {
4921//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "addps",
4922//-- insn[0], insn[1] );
4923//-- } else {
4924//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "addpd",
4925//-- 0x66, insn[0], insn[1] );
4926//-- }
4927//-- goto decode_success;
4928//-- }
4929//--
4930//-- /* 0xF2: MINSD */
4931//-- /* 0xF3: MINSS */
4932//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
4933//-- && insn[1] == 0x0F && insn[2] == 0x5D) {
4934//-- Bool sz8 = insn[0] == 0xF2;
4935//-- vg_assert(sz == 4);
4936//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
4937//-- sz8 ? "minsd" : "minss",
4938//-- insn[0], insn[1], insn[2] );
4939//-- goto decode_success;
4940//-- }
4941//--
4942//-- /* MINPS */
4943//-- /* 0x66: MINPD */
4944//-- if (insn[0] == 0x0F && insn[1] == 0x5D) {
4945//-- vg_assert(sz == 4 || sz == 2);
4946//-- if (sz == 4) {
4947//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "minps",
4948//-- insn[0], insn[1] );
4949//-- } else {
4950//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "minpd",
4951//-- 0x66, insn[0], insn[1] );
4952//-- }
4953//-- goto decode_success;
4954//-- }
4955//--
4956//-- /* 0xF3: MAXSD */
4957//-- /* 0xF3: MAXSS */
4958//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
4959//-- && insn[1] == 0x0F && insn[2] == 0x5F) {
4960//-- Bool sz8 = insn[0] == 0xF2;
4961//-- vg_assert(sz == 4);
4962//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
4963//-- sz8 ? "maxsd" : "maxss",
4964//-- insn[0], insn[1], insn[2] );
4965//-- goto decode_success;
4966//-- }
4967//--
4968//-- /* MAXPS */
4969//-- /* 0x66: MAXPD */
4970//-- if (insn[0] == 0x0F && insn[1] == 0x5F) {
4971//-- vg_assert(sz == 4 || sz == 2);
4972//-- if (sz == 4) {
4973//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "maxps",
4974//-- insn[0], insn[1] );
4975//-- } else {
4976//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "maxpd",
4977//-- 0x66, insn[0], insn[1] );
4978//-- }
4979//-- goto decode_success;
4980//-- }
4981//--
4982//-- /* RCPPS -- reciprocal of packed floats */
4983//-- if (insn[0] == 0x0F && insn[1] == 0x53) {
4984//-- vg_assert(sz == 4);
4985//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "rcpps",
4986//-- insn[0], insn[1] );
4987//-- goto decode_success;
4988//-- }
4989//--
4990//-- /* XORPS */
4991//-- /* 0x66: XORPD (src)xmmreg-or-mem, (dst)xmmreg */
4992//-- if (insn[0] == 0x0F && insn[1] == 0x57) {
4993//-- vg_assert(sz == 4 || sz == 2);
4994//-- if (sz == 4) {
4995//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "xorps",
4996//-- insn[0], insn[1] );
4997//-- } else {
4998//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "xorpd",
4999//-- 0x66, insn[0], insn[1] );
5000//-- }
5001//-- goto decode_success;
5002//-- }
5003//--
5004//-- /* ANDPS */
5005//-- /* 0x66: ANDPD (src)xmmreg-or-mem, (dst)xmmreg */
5006//-- if (insn[0] == 0x0F && insn[1] == 0x54) {
5007//-- vg_assert(sz == 4 || sz == 2);
5008//-- if (sz == 4) {
5009//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "andps",
5010//-- insn[0], insn[1] );
5011//-- } else {
5012//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "andpd",
5013//-- 0x66, insn[0], insn[1] );
5014//-- }
5015//-- goto decode_success;
5016//-- }
5017//--
5018//-- /* ORPS */
5019//-- /* 0x66: ORPD (src)xmmreg-or-mem, (dst)xmmreg */
5020//-- if (insn[0] == 0x0F && insn[1] == 0x56) {
5021//-- vg_assert(sz == 4 || sz == 2);
5022//-- if (sz == 4) {
5023//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "orps",
5024//-- insn[0], insn[1] );
5025//-- } else {
5026//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "orpd",
5027//-- 0x66, insn[0], insn[1] );
5028//-- }
5029//-- goto decode_success;
5030//-- }
5031//--
5032//-- /* PXOR (src)xmmreg-or-mem, (dst)xmmreg */
5033//-- if (sz == 2
5034//-- && insn[0] == 0x0F && insn[1] == 0xEF) {
5035//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pxor",
5036//-- 0x66, insn[0], insn[1] );
5037//-- goto decode_success;
5038//-- }
5039//--
5040//-- /* PAND (src)xmmreg-or-mem, (dst)xmmreg */
5041//-- if (sz == 2
5042//-- && insn[0] == 0x0F && insn[1] == 0xDB) {
5043//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pand",
5044//-- 0x66, insn[0], insn[1] );
5045//-- goto decode_success;
5046//-- }
5047//--
5048//-- /* PANDN (src)xmmreg-or-mem, (dst)xmmreg */
5049//-- if (sz == 2
5050//-- && insn[0] == 0x0F && insn[1] == 0xDF) {
5051//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pandn",
5052//-- 0x66, insn[0], insn[1] );
5053//-- goto decode_success;
5054//-- }
5055//--
5056//-- /* POR (src)xmmreg-or-mem, (dst)xmmreg */
5057//-- if (sz == 2
5058//-- && insn[0] == 0x0F && insn[1] == 0xEB) {
5059//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "por",
5060//-- 0x66, insn[0], insn[1] );
5061//-- goto decode_success;
5062//-- }
5063//--
5064//-- /* 0xDA: PMINUB(src)xmmreg-or-mem, (dst)xmmreg */
5065//-- /* 0xEA: PMINSW(src)xmmreg-or-mem, (dst)xmmreg */
5066//-- if (sz == 2
5067//-- && insn[0] == 0x0F
5068//-- && (insn[1] == 0xDA || insn[1] == 0xEA)) {
5069//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmin{ub,sw}",
5070//-- 0x66, insn[0], insn[1] );
5071//-- goto decode_success;
5072//-- }
5073//--
5074//-- /* 0xDE: PMAXUB(src)xmmreg-or-mem, (dst)xmmreg */
5075//-- /* 0xEE: PMAXSW(src)xmmreg-or-mem, (dst)xmmreg */
5076//-- if (sz == 2
5077//-- && insn[0] == 0x0F
5078//-- && (insn[1] == 0xDE || insn[1] == 0xEE)) {
5079//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmax{ub,sw}",
5080//-- 0x66, insn[0], insn[1] );
5081//-- goto decode_success;
5082//-- }
5083//--
5084//-- /* 0xE0: PAVGB(src)xmmreg-or-mem, (dst)xmmreg */
5085//-- /* 0xE3: PAVGW(src)xmmreg-or-mem, (dst)xmmreg */
5086//-- if (sz == 2
5087//-- && insn[0] == 0x0F
5088//-- && (insn[1] == 0xE0 || insn[1] == 0xE3)) {
5089//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pavg{b,w}",
5090//-- 0x66, insn[0], insn[1] );
5091//-- goto decode_success;
5092//-- }
5093//--
5094//-- /* 0xF6: PSADBW(src)xmmreg-or-mem, (dst)xmmreg */
5095//-- if (sz == 2
5096//-- && insn[0] == 0x0F && insn[1] == 0xF6) {
5097//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psadbw",
5098//-- 0x66, insn[0], insn[1] );
5099//-- goto decode_success;
5100//-- }
5101//--
5102//-- /* 0x60: PUNPCKLBW (src)xmmreg-or-mem, (dst)xmmreg */
5103//-- /* 0x61: PUNPCKLWD (src)xmmreg-or-mem, (dst)xmmreg */
5104//-- /* 0x62: PUNPCKLDQ (src)xmmreg-or-mem, (dst)xmmreg */
5105//-- /* 0x6C: PUNPCKQLQDQ (src)xmmreg-or-mem, (dst)xmmreg */
5106//-- if (sz == 2
5107//-- && insn[0] == 0x0F
5108//-- && (insn[1] == 0x60 || insn[1] == 0x61
5109//-- || insn[1] == 0x62 || insn[1] == 0x6C)) {
5110//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16,
5111//-- "punpckl{bw,wd,dq,qdq}",
5112//-- 0x66, insn[0], insn[1] );
5113//-- goto decode_success;
5114//-- }
5115//--
5116//-- /* 0x68: PUNPCKHBW (src)xmmreg-or-mem, (dst)xmmreg */
5117//-- /* 0x69: PUNPCKHWD (src)xmmreg-or-mem, (dst)xmmreg */
5118//-- /* 0x6A: PUNPCKHDQ (src)xmmreg-or-mem, (dst)xmmreg */
5119//-- /* 0x6D: PUNPCKHQDQ (src)xmmreg-or-mem, (dst)xmmreg */
5120//-- if (sz == 2
5121//-- && insn[0] == 0x0F
5122//-- && (insn[1] == 0x68 || insn[1] == 0x69
5123//-- || insn[1] == 0x6A || insn[1] == 0x6D)) {
5124//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16,
5125//-- "punpckh{bw,wd,dq,qdq}",
5126//-- 0x66, insn[0], insn[1] );
5127//-- goto decode_success;
5128//-- }
5129//--
5130//-- /* 0x14: UNPCKLPD (src)xmmreg-or-mem, (dst)xmmreg. Reads a+0
5131//-- .. a+7, so we can say size 8 */
5132//-- /* 0x15: UNPCKHPD (src)xmmreg-or-mem, (dst)xmmreg. Reads a+8
5133//-- .. a+15, but we have no way to express this, so better say size
5134//-- 16. Sigh. */
5135//-- if (sz == 2
5136//-- && insn[0] == 0x0F
5137//-- && (insn[1] == 0x14 || insn[1] == 0x15)) {
5138//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2,
5139//-- insn[1]==0x14 ? 8 : 16,
5140//-- "unpck{l,h}pd",
5141//-- 0x66, insn[0], insn[1] );
5142//-- goto decode_success;
5143//-- }
5144//--
5145//-- /* 0x14: UNPCKLPS (src)xmmreg-or-mem, (dst)xmmreg Reads a+0
5146//-- .. a+7, so we can say size 8 */
5147//-- /* 0x15: UNPCKHPS (src)xmmreg-or-mem, (dst)xmmreg Reads a+8
5148//-- .. a+15, but we have no way to express this, so better say size
5149//-- 16. Sigh. */
5150//-- if (sz == 4
5151//-- && insn[0] == 0x0F
5152//-- && (insn[1] == 0x14 || insn[1] == 0x15)) {
5153//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2,
5154//-- insn[1]==0x14 ? 8 : 16,
5155//-- "unpck{l,h}ps",
5156//-- insn[0], insn[1] );
5157//-- goto decode_success;
5158//-- }
5159//--
5160//-- /* 0xFC: PADDB (src)xmmreg-or-mem, (dst)xmmreg */
5161//-- /* 0xFD: PADDW (src)xmmreg-or-mem, (dst)xmmreg */
5162//-- /* 0xFE: PADDD (src)xmmreg-or-mem, (dst)xmmreg */
5163//-- /* 0xD4: PADDQ (src)xmmreg-or-mem, (dst)xmmreg */
5164//-- if (sz == 2
5165//-- && insn[0] == 0x0F
5166//-- && (insn[1] == 0xFC || insn[1] == 0xFD
5167//-- || insn[1] == 0xFE || insn[1] == 0xD4)) {
5168//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "padd{b,w,d,q}",
5169//-- 0x66, insn[0], insn[1] );
5170//-- goto decode_success;
5171//-- }
5172//--
5173//-- /* 0xEC: PADDSB (src)xmmreg-or-mem, (dst)xmmreg */
5174//-- /* 0xED: PADDSW (src)xmmreg-or-mem, (dst)xmmreg */
5175//-- if (sz == 2
5176//-- && insn[0] == 0x0F
5177//-- && (insn[1] == 0xEC || insn[1] == 0xED)) {
5178//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "padds{b,w}",
5179//-- 0x66, insn[0], insn[1] );
5180//-- goto decode_success;
5181//-- }
5182//--
5183//-- /* 0xDC: PADDUSB (src)xmmreg-or-mem, (dst)xmmreg */
5184//-- /* 0xDD: PADDUSW (src)xmmreg-or-mem, (dst)xmmreg */
5185//-- if (sz == 2
5186//-- && insn[0] == 0x0F
5187//-- && (insn[1] == 0xDC || insn[1] == 0xDD)) {
5188//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "paddus{b,w}",
5189//-- 0x66, insn[0], insn[1] );
5190//-- goto decode_success;
5191//-- }
5192//--
5193//-- /* 0xF8: PSUBB (src)xmmreg-or-mem, (dst)xmmreg */
5194//-- /* 0xF9: PSUBW (src)xmmreg-or-mem, (dst)xmmreg */
5195//-- /* 0xFA: PSUBD (src)xmmreg-or-mem, (dst)xmmreg */
5196//-- /* 0xFB: PSUBQ (src)xmmreg-or-mem, (dst)xmmreg */
5197//-- if (sz == 2
5198//-- && insn[0] == 0x0F
5199//-- && (insn[1] == 0xF8 || insn[1] == 0xF9
5200//-- || insn[1] == 0xFA || insn[1] == 0xFB)) {
5201//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psub{b,w,d,q}",
5202//-- 0x66, insn[0], insn[1] );
5203//-- goto decode_success;
5204//-- }
5205//--
5206//-- /* 0xE8: PSUBSB (src)xmmreg-or-mem, (dst)xmmreg */
5207//-- /* 0xE9: PSUBSW (src)xmmreg-or-mem, (dst)xmmreg */
5208//-- if (sz == 2
5209//-- && insn[0] == 0x0F
5210//-- && (insn[1] == 0xE8 || insn[1] == 0xE9)) {
5211//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psubs{b,w}",
5212//-- 0x66, insn[0], insn[1] );
5213//-- goto decode_success;
5214//-- }
5215//--
5216//-- /* 0xD8: PSUBUSB (src)xmmreg-or-mem, (dst)xmmreg */
5217//-- /* 0xD9: PSUBUSW (src)xmmreg-or-mem, (dst)xmmreg */
5218//-- if (sz == 2
5219//-- && insn[0] == 0x0F
5220//-- && (insn[1] == 0xD8 || insn[1] == 0xD9)) {
5221//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psubus{b,w}",
5222//-- 0x66, insn[0], insn[1] );
5223//-- goto decode_success;
5224//-- }
5225//--
5226//-- /* 0xE4: PMULHUW(src)xmmreg-or-mem, (dst)xmmreg */
5227//-- /* 0xE5: PMULHW(src)xmmreg-or-mem, (dst)xmmreg */
5228//-- /* 0xD5: PMULLW(src)xmmreg-or-mem, (dst)xmmreg */
5229//-- if (sz == 2
5230//-- && insn[0] == 0x0F
5231//-- && (insn[1] == 0xE4 || insn[1] == 0xE5 || insn[1] == 0xD5)) {
5232//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmul{hu,h,l}w",
5233//-- 0x66, insn[0], insn[1] );
5234//-- goto decode_success;
5235//-- }
5236//--
5237//-- /* 0xD5: PMULUDQ(src)xmmreg-or-mem, (dst)xmmreg */
5238//-- if (sz == 2
5239//-- && insn[0] == 0x0F && insn[1] == 0xF4) {
5240//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmuludq",
5241//-- 0x66, insn[0], insn[1] );
5242//-- goto decode_success;
5243//-- }
5244//--
5245//-- /* 0xF5: PMADDWD(src)xmmreg-or-mem, (dst)xmmreg */
5246//-- if (sz == 2
5247//-- && insn[0] == 0x0F
5248//-- && insn[1] == 0xF5) {
5249//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmaddwd",
5250//-- 0x66, insn[0], insn[1] );
5251//-- goto decode_success;
5252//-- }
5253//--
5254//-- /* 0x74: PCMPEQB (src)xmmreg-or-mem, (dst)xmmreg */
5255//-- /* 0x75: PCMPEQW (src)xmmreg-or-mem, (dst)xmmreg */
5256//-- /* 0x76: PCMPEQD (src)xmmreg-or-mem, (dst)xmmreg */
5257//-- if (sz == 2
5258//-- && insn[0] == 0x0F
5259//-- && (insn[1] == 0x74 || insn[1] == 0x75 || insn[1] == 0x76)) {
5260//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pcmpeq{b,w,d}",
5261//-- 0x66, insn[0], insn[1] );
5262//-- goto decode_success;
5263//-- }
5264//--
5265//-- /* 0x64: PCMPGTB (src)xmmreg-or-mem, (dst)xmmreg */
5266//-- /* 0x65: PCMPGTW (src)xmmreg-or-mem, (dst)xmmreg */
5267//-- /* 0x66: PCMPGTD (src)xmmreg-or-mem, (dst)xmmreg */
5268//-- if (sz == 2
5269//-- && insn[0] == 0x0F
5270//-- && (insn[1] == 0x64 || insn[1] == 0x65 || insn[1] == 0x66)) {
5271//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pcmpgt{b,w,d}",
5272//-- 0x66, insn[0], insn[1] );
5273//-- goto decode_success;
5274//-- }
5275//--
5276//-- /* 0x63: PACKSSWB (src)xmmreg-or-mem, (dst)xmmreg */
5277//-- /* 0x6B: PACKSSDW (src)xmmreg-or-mem, (dst)xmmreg */
5278//-- if (sz == 2
5279//-- && insn[0] == 0x0F
5280//-- && (insn[1] == 0x63 || insn[1] == 0x6B)) {
5281//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "packss{wb,dw}",
5282//-- 0x66, insn[0], insn[1] );
5283//-- goto decode_success;
5284//-- }
5285//--
5286//-- /* 0x67: PACKUSWB (src)xmmreg-or-mem, (dst)xmmreg */
5287//-- if (sz == 2
5288//-- && insn[0] == 0x0F
5289//-- && insn[1] == 0x67) {
5290//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "packuswb",
5291//-- 0x66, insn[0], insn[1] );
5292//-- goto decode_success;
5293//-- }
5294//--
5295//-- /* 0xF1: PSLLW (src)xmmreg-or-mem, (dst)xmmreg */
5296//-- /* 0xF2: PSLLD (src)xmmreg-or-mem, (dst)xmmreg */
5297//-- /* 0xF3: PSLLQ (src)xmmreg-or-mem, (dst)xmmreg */
5298//-- if (sz == 2
5299//-- && insn[0] == 0x0F
5300//-- && (insn[1] == 0xF1 || insn[1] == 0xF2 || insn[1] == 0xF3)) {
5301//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psll{b,w,d}",
5302//-- 0x66, insn[0], insn[1] );
5303//-- goto decode_success;
5304//-- }
5305//--
5306//-- /* 0xD1: PSRLW (src)xmmreg-or-mem, (dst)xmmreg */
5307//-- /* 0xD2: PSRLD (src)xmmreg-or-mem, (dst)xmmreg */
5308//-- /* 0xD3: PSRLQ (src)xmmreg-or-mem, (dst)xmmreg */
5309//-- if (sz == 2
5310//-- && insn[0] == 0x0F
5311//-- && (insn[1] == 0xD1 || insn[1] == 0xD2 || insn[1] == 0xD3)) {
5312//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psrl{b,w,d}",
5313//-- 0x66, insn[0], insn[1] );
5314//-- goto decode_success;
5315//-- }
5316//--
5317//-- /* 0xE1: PSRAW (src)xmmreg-or-mem, (dst)xmmreg */
5318//-- /* 0xE2: PSRAD (src)xmmreg-or-mem, (dst)xmmreg */
5319//-- if (sz == 2
5320//-- && insn[0] == 0x0F
5321//-- && (insn[1] == 0xE1 || insn[1] == 0xE2)) {
5322//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psra{w,d}",
5323//-- 0x66, insn[0], insn[1] );
5324//-- goto decode_success;
5325//-- }
5326//--
5327//-- /* (U)COMISD (src)xmmreg-or-mem, (dst)xmmreg */
5328//-- if (sz == 2
5329//-- && insn[0] == 0x0F
5330//-- && ( insn[1] == 0x2E || insn[1] == 0x2F ) ) {
5331//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 8, "{u}comisd",
5332//-- 0x66, insn[0], insn[1] );
5333//-- vg_assert(LAST_UINSTR(cb).opcode == SSE3a_MemRd
5334//-- || LAST_UINSTR(cb).opcode == SSE4);
5335//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
5336//-- goto decode_success;
5337//-- }
5338//--
5339//-- /* (U)COMISS (src)xmmreg-or-mem, (dst)xmmreg */
5340//-- if (sz == 4
5341//-- && insn[0] == 0x0F
5342//-- && ( insn[1] == 0x2E || insn[ 1 ] == 0x2F )) {
5343//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 4, "{u}comiss",
5344//-- insn[0], insn[1] );
5345//-- vg_assert(LAST_UINSTR(cb).opcode == SSE2a_MemRd
5346//-- || LAST_UINSTR(cb).opcode == SSE3);
5347//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
5348//-- goto decode_success;
5349//-- }
5350//--
5351//-- /* MOVSD -- move 8 bytes of XMM reg to/from XMM reg or mem. */
5352//-- if (insn[0] == 0xF2
5353//-- && insn[1] == 0x0F
5354//-- && (insn[2] == 0x11 || insn[2] == 0x10)) {
5355//-- vg_assert(sz == 4);
5356//-- eip = dis_SSE3_load_store_or_mov
5357//-- ( cb, sorb, eip+3, 8, insn[2]==0x11, "movsd",
5358//-- insn[0], insn[1], insn[2] );
5359//-- goto decode_success;
5360//-- }
5361//--
5362//-- /* MOVQ -- move 8 bytes of XMM reg to XMM reg or mem. How
5363//-- does this differ from MOVSD ?? */
5364//-- if (sz == 2
5365//-- && insn[0] == 0x0F
5366//-- && insn[1] == 0xD6) {
5367//-- eip = dis_SSE3_load_store_or_mov
5368//-- ( cb, sorb, eip+2, 8, True /*store*/, "movq",
5369//-- 0x66, insn[0], insn[1] );
5370//-- goto decode_success;
5371//-- }
5372//--
5373//-- /* MOVQ -- move 8 bytes of XMM reg or mem to XMM reg. How
5374//-- does this differ from MOVSD ?? */
5375//-- if (insn[0] == 0xF3
5376//-- && insn[1] == 0x0F
5377//-- && insn[2] == 0x7E) {
5378//-- eip = dis_SSE3_load_store_or_mov
5379//-- ( cb, sorb, eip+3, 8, False /*load*/, "movq",
5380//-- insn[0], insn[1], insn[2] );
5381//-- goto decode_success;
5382//-- }
5383//--
5384//-- /* MOVDQ2Q -- move low 4 bytes of XMM reg to MMX reg. */
5385//-- if (insn[0] == 0xF2
5386//-- && insn[1] == 0x0F
5387//-- && insn[2] == 0xD6) {
5388//-- eip = dis_SSE3_to_MMX
5389//-- ( cb, sorb, eip+3, 8, "movdq2q",
5390//-- insn[0], insn[1], insn[2] );
5391//-- goto decode_success;
5392//-- }
5393//--
5394//-- /* MOVQ2DQ -- move MMX reg to low 4 bytes of XMM reg. */
5395//-- if (insn[0] == 0xF3
5396//-- && insn[1] == 0x0F
5397//-- && insn[2] == 0xD6) {
5398//-- eip = dis_SSE3_from_MMX
5399//-- ( cb, sorb, eip+3, 8, "movq2dq",
5400//-- insn[0], insn[1], insn[2] );
5401//-- goto decode_success;
5402//-- }
5403//--
5404//-- /* MOVSS -- move 4 bytes of XMM reg to/from XMM reg or mem. */
5405//-- if (insn[0] == 0xF3
5406//-- && insn[1] == 0x0F
5407//-- && (insn[2] == 0x11 || insn[2] == 0x10)) {
5408//-- vg_assert(sz == 4);
5409//-- eip = dis_SSE3_load_store_or_mov
5410//-- ( cb, sorb, eip+3, 4, insn[2]==0x11, "movss",
5411//-- insn[0], insn[1], insn[2] );
5412//-- goto decode_success;
5413//-- }
5414//--
5415//-- /* I don't understand how MOVAPD differs from MOVAPS. */
5416//-- /* MOVAPD (28,29) -- aligned load/store of xmm reg, or xmm-xmm reg
5417//-- move */
5418//-- if (sz == 2
5419//-- && insn[0] == 0x0F && insn[1] == 0x28) {
5420//-- UChar* name = "movapd";
5421//-- //(insn[1] == 0x10 || insn[1] == 0x11)
5422//-- // ? "movups" : "movaps";
5423//-- Bool store = False; //insn[1] == 0x29 || insn[1] == 11;
5424//-- eip = dis_SSE3_load_store_or_mov
5425//-- ( cb, sorb, eip+2, 16, store, name,
5426//-- 0x66, insn[0], insn[1] );
5427//-- goto decode_success;
5428//-- }
5429//--
5430//-- /* sz==4: MOVAPS (28,29) -- aligned load/store of xmm reg, or
5431//-- xmm-xmm reg move */
5432//-- /* sz==4: MOVUPS (10,11) -- unaligned load/store of xmm reg, or
5433//-- xmm-xmm reg move */
5434//-- /* sz==2: MOVAPD (28,29) -- aligned load/store of xmm reg, or
5435//-- xmm-xmm reg move */
5436//-- /* sz==2: MOVUPD (10,11) -- unaligned load/store of xmm reg, or
5437//-- xmm-xmm reg move */
5438//-- if (insn[0] == 0x0F && (insn[1] == 0x28
5439//-- || insn[1] == 0x29
5440//-- || insn[1] == 0x10
5441//-- || insn[1] == 0x11)) {
5442//-- UChar* name = (insn[1] == 0x10 || insn[1] == 0x11)
5443//-- ? "movups" : "movaps";
5444//-- Bool store = insn[1] == 0x29 || insn[1] == 11;
5445//-- vg_assert(sz == 2 || sz == 4);
5446//-- if (sz == 4) {
5447//-- eip = dis_SSE2_load_store_or_mov
5448//-- ( cb, sorb, eip+2, 16, store, name,
5449//-- insn[0], insn[1] );
5450//-- } else {
5451//-- eip = dis_SSE3_load_store_or_mov
5452//-- ( cb, sorb, eip+2, 16, store, name,
5453//-- 0x66, insn[0], insn[1] );
5454//-- }
5455//-- goto decode_success;
5456//-- }
5457//--
5458//-- /* MOVDQA -- aligned 16-byte load/store. */
5459//-- if (sz == 2
5460//-- && insn[0] == 0x0F
5461//-- && (insn[1] == 0x6F || insn[1] == 0x7F)) {
5462//-- Bool is_store = insn[1]==0x7F;
5463//-- eip = dis_SSE3_load_store_or_mov
5464//-- (cb, sorb, eip+2, 16, is_store, "movdqa",
5465//-- 0x66, insn[0], insn[1] );
5466//-- goto decode_success;
5467//-- }
5468//--
5469//-- /* MOVDQU -- unaligned 16-byte load/store. */
5470//-- if (insn[0] == 0xF3
5471//-- && insn[1] == 0x0F
5472//-- && (insn[2] == 0x6F || insn[2] == 0x7F)) {
5473//-- Bool is_store = insn[2]==0x7F;
5474//-- eip = dis_SSE3_load_store_or_mov
5475//-- (cb, sorb, eip+3, 16, is_store, "movdqu",
5476//-- insn[0], insn[1], insn[2] );
5477//-- goto decode_success;
5478//-- }
5479//--
5480//-- /* MOVNTDQ -- 16-byte store with temporal hint (which we
5481//-- ignore). */
5482//-- if (sz == 2
5483//-- && insn[0] == 0x0F
5484//-- && insn[1] == 0xE7) {
5485//-- eip = dis_SSE3_load_store_or_mov
5486//-- (cb, sorb, eip+2, 16, True /* is_store */, "movntdq",
5487//-- 0x66, insn[0], insn[1] );
5488//-- goto decode_success;
5489//-- }
5490//--
5491//-- /* MOVNTPS -- 16-byte store with temporal hint (which we
5492//-- ignore). */
5493//-- if (insn[0] == 0x0F
5494//-- && insn[1] == 0x2B) {
5495//-- eip = dis_SSE2_load_store_or_mov
5496//-- (cb, sorb, eip+2, 16, True /* is_store */, "movntps",
5497//-- insn[0], insn[1] );
5498//-- goto decode_success;
5499//-- }
5500//--
5501//-- /* MOVNTPD -- 16-byte store with temporal hint (which we
5502//-- ignore). */
5503//-- if (sz == 2
5504//-- && insn[0] == 0x0F
5505//-- && insn[1] == 0x2B) {
5506//-- eip = dis_SSE3_load_store_or_mov
5507//-- (cb, sorb, eip+2, 16, True /* is_store */, "movntpd",
5508//-- 0x66, insn[0], insn[1] );
5509//-- goto decode_success;
5510//-- }
5511//--
5512//-- /* MOVD -- 4-byte move between xmmregs and (ireg or memory). */
5513//-- if (sz == 2
5514//-- && insn[0] == 0x0F
5515//-- && (insn[1] == 0x6E || insn[1] == 0x7E)) {
5516//-- Bool is_store = insn[1]==0x7E;
5517//-- modrm = insn[2];
5518//-- if (epartIsReg(modrm) && is_store) {
5519//-- t1 = newTemp(cb);
5520//-- uInstr3(cb, SSE3e_RegWr, 4,
5521//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
5522//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
5523//-- TempReg, t1 );
5524//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, eregOfRM(modrm));
5525//-- DIP("movd %s, %s\n",
5526//-- nameXMMReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
5527//-- eip += 3;
5528//-- } else
5529//-- if (epartIsReg(modrm) && !is_store) {
5530//-- t1 = newTemp(cb);
5531//-- uInstr2(cb, GET, 4, ArchReg, eregOfRM(modrm), TempReg, t1);
5532//-- uInstr3(cb, SSE3e_RegRd, 4,
5533//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
5534//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
5535//-- TempReg, t1 );
5536//-- DIP("movd %s, %s\n",
5537//-- nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
5538//-- eip += 3;
5539//-- } else {
5540//-- eip = dis_SSE3_load_store_or_mov
5541//-- (cb, sorb, eip+2, 4, is_store, "movd",
5542//-- 0x66, insn[0], insn[1] );
5543//-- }
5544//-- goto decode_success;
5545//-- }
5546//--
5547//-- /* PEXTRW from SSE register; writes ireg */
5548//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC5) {
5549//-- t1 = newTemp(cb);
5550//-- modrm = insn[2];
5551//-- vg_assert(epartIsReg(modrm));
5552//-- vg_assert((modrm & 0xC0) == 0xC0);
5553//-- uInstr3(cb, SSE3g1_RegWr, 4,
5554//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
5555//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
5556//-- TempReg, t1 );
5557//-- uLiteral(cb, insn[3]);
5558//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
5559//-- DIP("pextrw %s, %d, %s\n",
5560//-- nameXMMReg(eregOfRM(modrm)), (Int)insn[3],
5561//-- nameIReg(4, gregOfRM(modrm)));
5562//-- eip += 4;
5563//-- goto decode_success;
5564//-- }
5565//--
5566//-- /* PINSRW to SSE register; reads mem or ireg */
5567//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC4) {
5568//-- t1 = newTemp(cb);
5569//-- modrm = insn[2];
5570//-- if (epartIsReg(modrm)) {
5571//-- uInstr2(cb, GET, 2, ArchReg, eregOfRM(modrm), TempReg, t1);
5572//-- vg_assert(epartIsReg(modrm));
5573//-- uInstr3(cb, SSE3e1_RegRd, 2,
5574//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
5575//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
5576//-- TempReg, t1 );
5577//-- uLiteral(cb, insn[3]);
5578//-- DIP("pinsrw %s, %d, %s\n",
5579//-- nameIReg(2, eregOfRM(modrm)), (Int)insn[3],
5580//-- nameXMMReg(gregOfRM(modrm)));
5581//-- eip += 4;
5582//-- } else {
5583//-- VG_(core_panic)("PINSRW mem");
5584//-- }
5585//-- goto decode_success;
5586//-- }
5587//--
5588//-- /* SQRTSD: square root of scalar double. */
5589//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x51) {
5590//-- vg_assert(sz == 4);
5591//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8,
5592//-- "sqrtsd",
5593//-- insn[0], insn[1], insn[2] );
5594//-- goto decode_success;
5595//-- }
5596//--
5597//-- /* SQRTSS: square root of scalar float. */
5598//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x51) {
5599//-- vg_assert(sz == 4);
5600//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4,
5601//-- "sqrtss",
5602//-- insn[0], insn[1], insn[2] );
5603//-- goto decode_success;
5604//-- }
5605//--
5606//-- /* RSQRTSS: square root reciprocal of scalar float. */
5607//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x52) {
5608//-- vg_assert(sz == 4);
5609//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4,
5610//-- "sqrtss",
5611//-- insn[0], insn[1], insn[2] );
5612//-- goto decode_success;
5613//-- }
5614//--
5615//-- /* 0xF3: RCPSS -- reciprocal of scalar float */
5616//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x53) {
5617//-- vg_assert(sz == 4);
5618//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4,
5619//-- "rcpss",
5620//-- insn[0], insn[1], insn[2] );
5621//-- goto decode_success;
5622//-- }
5623//--
5624//-- /* MOVMSKPD -- extract 2 sign bits from a xmm reg and copy them to
5625//-- an ireg. Top 30 bits of ireg are set to zero. */
5626//-- /* MOVMSKPS -- extract 4 sign bits from a xmm reg and copy them to
5627//-- an ireg. Top 28 bits of ireg are set to zero. */
5628//-- if (insn[0] == 0x0F && insn[1] == 0x50) {
5629//-- vg_assert(sz == 4 || sz == 2);
5630//-- modrm = insn[2];
5631//-- /* Intel docs don't say anything about a memory source being
5632//-- allowed here. */
5633//-- vg_assert(epartIsReg(modrm));
5634//-- t1 = newTemp(cb);
5635//-- if (sz == 4) {
5636//-- uInstr3(cb, SSE2g_RegWr, 4,
5637//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
5638//-- Lit16, (UShort)modrm,
5639//-- TempReg, t1 );
5640//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
5641//-- } else {
5642//-- uInstr3(cb, SSE3g_RegWr, 4,
5643//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
5644//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
5645//-- TempReg, t1 );
5646//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
5647//-- }
5648//-- DIP("movmskp%c %s, %s\n", sz == 4 ? 's' : 'd',
5649//-- nameXMMReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)));
5650//-- eip += 3;
5651//-- goto decode_success;
5652//-- }
5653//--
5654//-- /* ANDNPS */
5655//-- /* 0x66: ANDNPD (src)xmmreg-or-mem, (dst)xmmreg */
5656//-- if (insn[0] == 0x0F && insn[1] == 0x55) {
5657//-- vg_assert(sz == 4 || sz == 2);
5658//-- if (sz == 4) {
5659//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "andnps",
5660//-- insn[0], insn[1] );
5661//-- } else {
5662//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "andnpd",
5663//-- 0x66, insn[0], insn[1] );
5664//-- }
5665//-- goto decode_success;
5666//-- }
5667//--
5668//-- /* MOVHLPS -- move two packed floats from high quadword to low quadword */
5669//-- /* MOVLPS -- load/store two packed floats to/from low quadword. */
5670//-- /* MOVLPD -- load/store packed double to/from low quadword. */
5671//-- if (insn[0] == 0x0F
5672//-- && (insn[1] == 0x12 || insn[1] == 0x13)) {
5673//-- Bool is_store = insn[1]==0x13;
5674//-- vg_assert(sz == 4 || sz == 2);
5675//-- if (sz == 4) {
5676//-- if (epartIsReg(insn[2])) {
5677//-- vg_assert(insn[1]==0x12);
5678//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "movhlps",
5679//-- insn[0], insn[1] );
5680//-- } else {
5681//-- eip = dis_SSE2_load_store_or_mov
5682//-- (cb, sorb, eip+2, 8, is_store, "movlps",
5683//-- insn[0], insn[1] );
5684//-- }
5685//-- } else {
5686//-- vg_assert(!epartIsReg(insn[2]));
5687//-- eip = dis_SSE3_load_store_or_mov
5688//-- (cb, sorb, eip+2, 8, is_store, "movlpd",
5689//-- 0x66, insn[0], insn[1] );
5690//-- }
5691//-- goto decode_success;
5692//-- }
5693//--
5694//-- /* MOVLHPS -- move two packed floats from low quadword to high quadword */
5695//-- /* MOVHPS -- load/store two packed floats to/from high quadword. */
5696//-- /* MOVHPD -- load/store packed double to/from high quadword. */
5697//-- if (insn[0] == 0x0F
5698//-- && (insn[1] == 0x16 || insn[1] == 0x17)) {
5699//-- Bool is_store = insn[1]==0x17;
5700//-- vg_assert(sz == 4 || sz == 2);
5701//-- if (sz == 4) {
5702//-- if (epartIsReg(insn[2])) {
5703//-- vg_assert(insn[1]==0x16);
5704//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "movlhps",
5705//-- insn[0], insn[1] );
5706//-- } else {
5707//-- eip = dis_SSE2_load_store_or_mov
5708//-- (cb, sorb, eip+2, 8, is_store, "movhps",
5709//-- insn[0], insn[1] );
5710//-- }
5711//-- } else {
5712//-- vg_assert(!epartIsReg(insn[2]));
5713//-- eip = dis_SSE3_load_store_or_mov
5714//-- (cb, sorb, eip+2, 8, is_store, "movhpd",
5715//-- 0x66, insn[0], insn[1] );
5716//-- }
5717//-- goto decode_success;
5718//-- }
5719//--
5720//-- /* PMOVMSKB -- extract 16 sign bits from a xmm reg and copy them to
5721//-- an ireg. Top 16 bits of ireg are set to zero. */
5722//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD7) {
5723//-- modrm = insn[2];
5724//-- /* Intel docs don't say anything about a memory source being
5725//-- allowed here. */
5726//-- vg_assert(epartIsReg(modrm));
5727//-- t1 = newTemp(cb);
5728//-- uInstr3(cb, SSE3g_RegWr, 4,
5729//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
5730//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
5731//-- TempReg, t1 );
5732//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
5733//-- DIP("pmovmskb %s, %s\n",
5734//-- nameXMMReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)));
5735//-- eip += 3;
5736//-- goto decode_success;
5737//-- }
5738//--
5739//-- /* sz==4: SQRTPS: square root of packed float. */
5740//-- /* sz==2: SQRTPD: square root of packed double. */
5741//-- if (insn[0] == 0x0F && insn[1] == 0x51) {
5742//-- vg_assert(sz == 2 || sz == 4);
5743//-- if (sz == 4) {
5744//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16,
5745//-- "sqrtps",
5746//-- insn[0], insn[1] );
5747//-- } else {
5748//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16,
5749//-- "sqrtpd",
5750//-- 0x66, insn[0], insn[1] );
5751//-- }
5752//-- goto decode_success;
5753//-- }
5754//--
5755//-- /* RSQRTPS: square root reciprocal of packed float. */
5756//-- if (insn[0] == 0x0F && insn[1] == 0x52) {
5757//-- vg_assert(sz == 4);
5758//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16,
5759//-- "rsqrtps",
5760//-- insn[0], insn[1] );
5761//-- goto decode_success;
5762//-- }
5763//--
5764//-- /* Fall through into the non-SSE decoder. */
5765//--
5766//-- } /* if (VG_(have_ssestate)) */
5767
5768
5769 /* ---------------------------------------------------- */
5770 /* --- end of the SSE/SSE2 decoder. --- */
5771 /* ---------------------------------------------------- */
5772
5773 /* Get the primary opcode. */
5774 opc = getIByte(delta); delta++;
5775
5776 /* We get here if the current insn isn't SSE, or this CPU doesn't
5777 support SSE. */
5778
5779 switch (opc) {
5780
5781 /* ------------------------ Control flow --------------- */
sewardj940e8c92004-07-11 16:53:24 +00005782
5783 case 0xC2: /* RET imm16 */
5784 d32 = getUDisp16(delta);
5785 delta += 2;
5786 dis_ret(d32);
5787 *isEnd = True;
5788 DIP("ret %d\n", d32);
5789 break;
sewardje05c42c2004-07-08 20:25:10 +00005790 case 0xC3: /* RET */
5791 dis_ret(0);
5792 *isEnd = True;
5793 DIP("ret\n");
5794 break;
sewardjd1061ab2004-07-08 01:45:30 +00005795
5796 case 0xE8: /* CALL J4 */
5797 d32 = getUDisp32(delta); delta += 4;
5798 d32 += (guest_eip+delta);
5799 /* (guest_eip+delta) == return-to addr, d32 == call-to addr */
sewardjc2ac51e2004-07-12 01:03:26 +00005800 if (d32 == guest_eip+delta && getIByte(delta) >= 0x58
5801 && getIByte(delta) <= 0x5F) {
sewardjd1061ab2004-07-08 01:45:30 +00005802 /* Specially treat the position-independent-code idiom
5803 call X
5804 X: popl %reg
5805 as
5806 movl %eip, %reg.
5807 since this generates better code, but for no other reason. */
5808 Int archReg = getIByte(delta) - 0x58;
sewardjc2ac51e2004-07-12 01:03:26 +00005809 /* vex_printf("-- fPIC thingy\n"); */
5810 putIReg(4, archReg, mkU32(guest_eip+delta));
sewardjd1061ab2004-07-08 01:45:30 +00005811 delta++; /* Step over the POP */
5812 DIP("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
sewardjc2ac51e2004-07-12 01:03:26 +00005813 } else {
sewardjd1061ab2004-07-08 01:45:30 +00005814 /* The normal sequence for a call. */
5815 t1 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +00005816 assign(t1, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
5817 putIReg(4, R_ESP, mkexpr(t1));
5818 storeLE( mkexpr(t1), mkU32(guest_eip+delta));
sewardj78c19df2004-07-12 22:49:27 +00005819 jmp_lit(Ijk_Call,d32);
sewardjd1061ab2004-07-08 01:45:30 +00005820 *isEnd = True;
5821 DIP("call 0x%x\n",d32);
5822 }
5823 break;
5824
sewardjc9a65702004-07-07 16:32:57 +00005825//-- case 0xC8: /* ENTER */
5826//-- d32 = getUDisp16(eip); eip += 2;
5827//-- abyte = getIByte(delta); delta++;
5828//--
5829//-- vg_assert(sz == 4);
5830//-- vg_assert(abyte == 0);
5831//--
5832//-- t1 = newTemp(cb); t2 = newTemp(cb);
5833//-- uInstr2(cb, GET, sz, ArchReg, R_EBP, TempReg, t1);
5834//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
5835//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
5836//-- uLiteral(cb, sz);
5837//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
5838//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
5839//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
5840//-- if (d32) {
5841//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
5842//-- uLiteral(cb, d32);
5843//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
5844//-- }
5845//-- DIP("enter 0x%x, 0x%x", d32, abyte);
5846//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +00005847
5848 case 0xC9: /* LEAVE */
5849 vassert(sz == 4);
5850 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
5851 assign(t1, getIReg(4,R_EBP));
5852 /* First PUT ESP looks redundant, but need it because ESP must
5853 always be up-to-date for Memcheck to work... */
5854 putIReg(4, R_ESP, mkexpr(t1));
5855 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
5856 putIReg(4, R_EBP, mkexpr(t2));
5857 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(4)) );
5858 DIP("leave\n");
5859 break;
5860
sewardjc9a65702004-07-07 16:32:57 +00005861//-- /* ---------------- Misc weird-ass insns --------------- */
5862//--
5863//-- case 0x27: /* DAA */
5864//-- case 0x2F: /* DAS */
5865//-- t1 = newTemp(cb);
5866//-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
5867//-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
5868//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
5869//-- uWiden(cb, 1, False);
5870//-- uInstr0(cb, CALLM_S, 0);
5871//-- uInstr1(cb, PUSH, 4, TempReg, t1);
5872//-- uInstr1(cb, CALLM, 0, Lit16,
5873//-- opc == 0x27 ? VGOFF_(helper_DAA) : VGOFF_(helper_DAS) );
5874//-- uFlagsRWU(cb, FlagsAC, FlagsSZACP, FlagO);
5875//-- uInstr1(cb, POP, 4, TempReg, t1);
5876//-- uInstr0(cb, CALLM_E, 0);
5877//-- uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
5878//-- DIP(opc == 0x27 ? "daa\n" : "das\n");
5879//-- break;
5880//--
5881//-- case 0x37: /* AAA */
5882//-- case 0x3F: /* AAS */
5883//-- t1 = newTemp(cb);
5884//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
5885//-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
5886//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
5887//-- uWiden(cb, 2, False);
5888//-- uInstr0(cb, CALLM_S, 0);
5889//-- uInstr1(cb, PUSH, 4, TempReg, t1);
5890//-- uInstr1(cb, CALLM, 0, Lit16,
5891//-- opc == 0x37 ? VGOFF_(helper_AAA) : VGOFF_(helper_AAS) );
5892//-- uFlagsRWU(cb, FlagA, FlagsAC, FlagsEmpty);
5893//-- uInstr1(cb, POP, 4, TempReg, t1);
5894//-- uInstr0(cb, CALLM_E, 0);
5895//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
5896//-- DIP(opc == 0x37 ? "aaa\n" : "aas\n");
5897//-- break;
5898//--
5899//-- case 0xD4: /* AAM */
5900//-- case 0xD5: /* AAD */
5901//-- d32 = getIByte(delta); delta++;
5902//-- if (d32 != 10) VG_(core_panic)("disInstr: AAM/AAD but base not 10 !");
5903//-- t1 = newTemp(cb);
5904//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
5905//-- /* Widen %AX to 32 bits, so it's all defined when we push it. */
5906//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
5907//-- uWiden(cb, 2, False);
5908//-- uInstr0(cb, CALLM_S, 0);
5909//-- uInstr1(cb, PUSH, 4, TempReg, t1);
5910//-- uInstr1(cb, CALLM, 0, Lit16,
5911//-- opc == 0xD4 ? VGOFF_(helper_AAM) : VGOFF_(helper_AAD) );
5912//-- uFlagsRWU(cb, FlagsEmpty, FlagsSZP, FlagsEmpty);
5913//-- uInstr1(cb, POP, 4, TempReg, t1);
5914//-- uInstr0(cb, CALLM_E, 0);
5915//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
5916//-- DIP(opc == 0xD4 ? "aam\n" : "aad\n");
5917//-- break;
5918//--
5919//-- /* ------------------------ CWD/CDQ -------------------- */
5920//--
5921//-- case 0x98: /* CBW */
5922//-- t1 = newTemp(cb);
5923//-- if (sz == 4) {
5924//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
5925//-- uInstr1(cb, WIDEN, 4, TempReg, t1); /* 4 == dst size */
5926//-- uWiden(cb, 2, True);
5927//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
5928//-- DIP("cwd\n");
5929//-- } else {
5930//-- vg_assert(sz == 2);
5931//-- uInstr2(cb, GET, 1, ArchReg, R_EAX, TempReg, t1);
5932//-- uInstr1(cb, WIDEN, 2, TempReg, t1); /* 2 == dst size */
5933//-- uWiden(cb, 1, True);
5934//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
5935//-- DIP("cbw\n");
5936//-- }
5937//-- break;
sewardj64e1d652004-07-12 14:00:46 +00005938
5939 case 0x99: /* CWD/CDQ */
5940 ty = szToITy(sz);
5941 putIReg(sz, R_EDX,
5942 binop(mkSizedOp(ty,Iop_Sar8),
5943 getIReg(sz, R_EAX),
5944 mkU(ty,sz == 2 ? 15 : 31)) );
5945 DIP(sz == 2 ? "cwdq\n" : "cdqq\n");
5946 break;
5947
sewardjc9a65702004-07-07 16:32:57 +00005948//-- /* ------------------------ FPU ops -------------------- */
5949//--
5950//-- case 0x9E: /* SAHF */
5951//-- codegen_SAHF ( cb );
5952//-- DIP("sahf\n");
5953//-- break;
5954//--
5955//-- case 0x9F: /* LAHF */
5956//-- codegen_LAHF ( cb );
5957//-- DIP("lahf\n");
5958//-- break;
5959//--
5960//-- case 0x9B: /* FWAIT */
5961//-- /* ignore? */
5962//-- DIP("fwait\n");
5963//-- break;
5964//--
5965//-- case 0xD8:
5966//-- case 0xD9:
5967//-- case 0xDA:
5968//-- case 0xDB:
5969//-- case 0xDC:
5970//-- case 0xDD:
5971//-- case 0xDE:
5972//-- case 0xDF:
5973//-- eip = dis_fpu ( cb, sorb, opc, eip );
5974//-- break;
sewardj0611d802004-07-11 02:37:54 +00005975
5976 /* ------------------------ INC & DEC ------------------ */
5977
5978 case 0x40: /* INC eAX */
5979 case 0x41: /* INC eCX */
5980 case 0x42: /* INC eDX */
5981 case 0x43: /* INC eBX */
5982 case 0x44: /* INC eSP */
5983 case 0x45: /* INC eBP */
5984 case 0x46: /* INC eSI */
5985 case 0x47: /* INC eDI */
5986 vassert(sz == 2 || sz == 4);
5987 ty = szToITy(sz);
5988 t1 = newTemp(ty);
5989 assign( t1, binop(mkSizedOp(ty,Iop_Add8),
5990 getIReg(sz, (UInt)(opc - 0x40)),
5991 mkU(ty,1)) );
5992 setFlags_INC_DEC( True, t1, ty );
5993 putIReg(sz, (UInt)(opc - 0x40), mkexpr(t1));
5994 DIP("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
5995 break;
5996
5997 case 0x48: /* DEC eAX */
5998 case 0x49: /* DEC eCX */
5999 case 0x4A: /* DEC eDX */
6000 case 0x4B: /* DEC eBX */
6001 case 0x4C: /* DEC eSP */
6002 case 0x4D: /* DEC eBP */
6003 case 0x4E: /* DEC eSI */
6004 case 0x4F: /* DEC eDI */
6005 vassert(sz == 2 || sz == 4);
6006 ty = szToITy(sz);
6007 t1 = newTemp(ty);
6008 assign( t1, binop(mkSizedOp(ty,Iop_Sub8),
6009 getIReg(sz, (UInt)(opc - 0x48)),
6010 mkU(ty,1)) );
6011 setFlags_INC_DEC( False, t1, ty );
6012 putIReg(sz, (UInt)(opc - 0x48), mkexpr(t1));
6013 DIP("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
6014 break;
6015
6016 /* ------------------------ INT ------------------------ */
6017
6018 case 0xCD: /* INT imm8 */
6019 d32 = getIByte(delta); delta++;
6020 if (d32 != 0x80) goto decode_failure;
6021 /* It's important that all ArchRegs carry their up-to-date value
6022 at this point. So we declare an end-of-block here, which
6023 forces any TempRegs caching ArchRegs to be flushed. */
sewardj78c19df2004-07-12 22:49:27 +00006024 jmp_lit(Ijk_Syscall,((Addr32)guest_code)+delta);
sewardj0611d802004-07-11 02:37:54 +00006025 *isEnd = True;
6026 DIP("int $0x80\n");
6027 break;
6028
sewardj77b86be2004-07-11 13:28:24 +00006029 /* ------------------------ Jcond, byte offset --------- */
6030
6031 case 0xEB: /* Jb (jump, byte offset) */
6032 d32 = (((Addr32)guest_code)+delta+1) + getSDisp8(delta);
6033 delta++;
sewardj78c19df2004-07-12 22:49:27 +00006034 jmp_lit(Ijk_Boring,d32);
sewardj77b86be2004-07-11 13:28:24 +00006035 *isEnd = True;
6036 DIP("jmp-8 0x%x\n", d32);
6037 break;
sewardj0611d802004-07-11 02:37:54 +00006038
6039 case 0xE9: /* Jv (jump, 16/32 offset) */
6040 vassert(sz == 4); /* JRS added 2004 July 11 */
6041 d32 = (((Addr32)guest_code)+delta+sz) + getSDisp(sz,delta);
6042 delta += sz;
sewardj78c19df2004-07-12 22:49:27 +00006043 jmp_lit(Ijk_Boring,d32);
sewardj0611d802004-07-11 02:37:54 +00006044 *isEnd = True;
6045 DIP("jmp 0x%x\n", d32);
6046 break;
sewardje87b4842004-07-10 12:23:30 +00006047
6048 case 0x70:
6049 case 0x71:
6050 case 0x72: /* JBb/JNAEb (jump below) */
6051 case 0x73: /* JNBb/JAEb (jump not below) */
6052 case 0x74: /* JZb/JEb (jump zero) */
6053 case 0x75: /* JNZb/JNEb (jump not zero) */
6054 case 0x76: /* JBEb/JNAb (jump below or equal) */
6055 case 0x77: /* JNBEb/JAb (jump not below or equal) */
6056 case 0x78: /* JSb (jump negative) */
6057 case 0x79: /* JSb (jump not negative) */
6058 case 0x7A: /* JP (jump parity even) */
6059 case 0x7B: /* JNP/JPO (jump parity odd) */
6060 case 0x7C: /* JLb/JNGEb (jump less) */
6061 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
6062 case 0x7E: /* JLEb/JNGb (jump less or equal) */
6063 case 0x7F: /* JGb/JNLEb (jump greater) */
6064 d32 = (((Addr32)guest_code)+delta+1) + getSDisp8(delta);
6065 delta++;
6066 jcc_01((Condcode)(opc - 0x70), (Addr32)(guest_code+delta), d32);
6067 *isEnd = True;
6068 DIP("j%s-8 0x%x\n", name_Condcode(opc - 0x70), d32);
6069 break;
6070
sewardjc9a65702004-07-07 16:32:57 +00006071//-- case 0xE3: /* JECXZ or perhaps JCXZ, depending on OSO ? Intel
6072//-- manual says it depends on address size override,
6073//-- which doesn't sound right to me. */
6074//-- d32 = (eip+1) + getSDisp8(eip); eip++;
6075//-- t1 = newTemp(cb);
6076//-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
6077//-- uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
6078//-- uLiteral(cb, d32);
6079//-- DIP("j%sz 0x%x\n", nameIReg(sz, R_ECX), d32);
6080//-- break;
6081//--
6082//-- case 0xE0: /* LOOPNE disp8 */
6083//-- case 0xE1: /* LOOPE disp8 */
6084//-- case 0xE2: /* LOOP disp8 */
6085//-- /* Again, the docs say this uses ECX/CX as a count depending on
6086//-- the address size override, not the operand one. Since we
6087//-- don't handle address size overrides, I guess that means
6088//-- ECX. */
6089//-- d32 = (eip+1) + getSDisp8(eip); eip++;
6090//-- t1 = newTemp(cb);
6091//-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
6092//-- uInstr1(cb, DEC, 4, TempReg, t1);
6093//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ECX);
6094//-- uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
6095//-- uLiteral(cb, eip);
6096//-- if (opc == 0xE0 || opc == 0xE1) { /* LOOPE/LOOPNE */
6097//-- jcc_lit(cb, eip, (opc == 0xE1 ? CondNZ : CondZ));
6098//-- }
6099//-- jmp_lit(cb, d32);
6100//-- *isEnd = True;
6101//-- DIP("loop 0x%x\n", d32);
6102//-- break;
6103//--
6104//-- /* ------------------------ IMUL ----------------------- */
6105//--
6106//-- case 0x69: /* IMUL Iv, Ev, Gv */
6107//-- eip = dis_imul_I_E_G ( cb, sorb, sz, eip, sz );
6108//-- break;
6109//-- case 0x6B: /* IMUL Ib, Ev, Gv */
6110//-- eip = dis_imul_I_E_G ( cb, sorb, sz, eip, 1 );
6111//-- break;
sewardj0611d802004-07-11 02:37:54 +00006112
6113 /* ------------------------ MOV ------------------------ */
6114
6115 case 0x88: /* MOV Gb,Eb */
6116 delta = dis_mov_G_E(sorb, 1, delta);
6117 break;
sewardjc9a65702004-07-07 16:32:57 +00006118
6119 case 0x89: /* MOV Gv,Ev */
6120 delta = dis_mov_G_E(sorb, sz, delta);
6121 break;
6122
sewardjc2ac51e2004-07-12 01:03:26 +00006123 case 0x8A: /* MOV Eb,Gb */
6124 delta = dis_mov_E_G(sorb, 1, delta);
6125 break;
sewardje05c42c2004-07-08 20:25:10 +00006126
6127 case 0x8B: /* MOV Ev,Gv */
6128 delta = dis_mov_E_G(sorb, sz, delta);
6129 break;
6130
sewardje87b4842004-07-10 12:23:30 +00006131 case 0x8D: /* LEA M,Gv */
sewardje05c42c2004-07-08 20:25:10 +00006132 vassert(sz == 4);
6133 modrm = getIByte(delta);
6134 if (epartIsReg(modrm))
6135 vpanic("LEA M,Gv: modRM refers to register (x86)");
6136 /* NOTE! this is the one place where a segment override prefix
6137 has no effect on the address calculation. Therefore we pass
6138 zero instead of sorb here. */
sewardje87b4842004-07-10 12:23:30 +00006139 addr = disAMode ( &alen, /*sorb*/ 0, delta, dis_buf );
6140 delta += alen;
sewardj940e8c92004-07-11 16:53:24 +00006141 putIReg(sz, gregOfRM(modrm), mkexpr(addr));
sewardje05c42c2004-07-08 20:25:10 +00006142 DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
6143 nameIReg(sz,gregOfRM(modrm)));
6144 break;
sewardje05c42c2004-07-08 20:25:10 +00006145
sewardjc9a65702004-07-07 16:32:57 +00006146//-- case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
6147//-- eip = dis_mov_Sw_Ew(cb, sorb, eip);
6148//-- break;
6149//--
6150//-- case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
6151//-- eip = dis_mov_Ew_Sw(cb, sorb, eip);
6152//-- break;
6153//--
6154//-- case 0xA0: /* MOV Ob,AL */
6155//-- sz = 1;
6156//-- /* Fall through ... */
sewardj0c12ea82004-07-12 08:18:16 +00006157 case 0xA1: /* MOV Ov,eAX */
6158 d32 = getUDisp32(delta); delta += 4;
6159 ty = szToITy(sz);
6160 addr = newTemp(Ity_I32);
6161 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
6162 putIReg(sz, R_EAX, loadLE(ty, mkexpr(addr)));
6163 DIP("mov%c %s0x%x, %s\n", nameISize(sz), sorbTxt(sorb),
6164 d32, nameIReg(sz,R_EAX));
6165 break;
6166
sewardjc9a65702004-07-07 16:32:57 +00006167//-- case 0xA2: /* MOV AL,Ob */
6168//-- sz = 1;
6169//-- /* Fall through ... */
6170//-- case 0xA3: /* MOV eAX,Ov */
6171//-- d32 = getUDisp32(eip); eip += 4;
6172//-- t1 = newTemp(cb); t2 = newTemp(cb);
6173//-- uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
6174//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
6175//-- uLiteral(cb, d32);
6176//-- handleSegOverride(cb, sorb, t2);
6177//-- uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
6178//-- DIP("mov%c %s, %s0x%x\n", nameISize(sz), nameIReg(sz,R_EAX),
6179//-- sorbTxt(sorb), d32);
6180//-- break;
sewardje87b4842004-07-10 12:23:30 +00006181
sewardjc2ac51e2004-07-12 01:03:26 +00006182#if 0
6183 case 0xB0: /* MOV imm,AL */
6184 case 0xB1: /* MOV imm,CL */
6185 case 0xB2: /* MOV imm,DL */
6186 case 0xB3: /* MOV imm,BL */
6187 case 0xB4: /* MOV imm,AH */
6188 case 0xB5: /* MOV imm,CH */
6189 case 0xB6: /* MOV imm,DH */
6190 case 0xB7: /* MOV imm,BH */
6191 d32 = getIByte(delta); delta += 1;
6192 putIReg(1, opc-0xB0, mkU8(d32));
6193 DIP("movb $0x%x,%s\n", d32, nameIReg(1,opc-0xB0));
6194 break;
6195#endif
sewardje87b4842004-07-10 12:23:30 +00006196 case 0xB8: /* MOV imm,eAX */
6197 case 0xB9: /* MOV imm,eCX */
6198 case 0xBA: /* MOV imm,eDX */
6199 case 0xBB: /* MOV imm,eBX */
6200 case 0xBC: /* MOV imm,eSP */
6201 case 0xBD: /* MOV imm,eBP */
6202 case 0xBE: /* MOV imm,eSI */
6203 case 0xBF: /* MOV imm,eDI */
6204 d32 = getUDisp(sz,delta); delta += sz;
6205 putIReg(sz, opc-0xB8, mkU(szToITy(sz), d32));
6206 DIP("mov%c $0x%x,%s\n", nameISize(sz), d32, nameIReg(sz,opc-0xB8));
6207 break;
6208
sewardj77b86be2004-07-11 13:28:24 +00006209 case 0xC6: /* MOV Ib,Eb */
6210 sz = 1;
6211 goto do_Mov_I_E;
sewardje87b4842004-07-10 12:23:30 +00006212 case 0xC7: /* MOV Iv,Ev */
6213 goto do_Mov_I_E;
6214
6215 do_Mov_I_E:
6216 modrm = getIByte(delta);
6217 if (epartIsReg(modrm)) {
6218 delta++; /* mod/rm byte */
6219 d32 = getUDisp(sz,delta); delta += sz;
6220 putIReg(sz, eregOfRM(modrm), mkU(szToITy(sz), d32));
6221 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32,
6222 nameIReg(sz,eregOfRM(modrm)));
6223 vassert(0);
6224 } else {
6225 addr = disAMode ( &alen, sorb, delta, dis_buf );
6226 delta += alen;
6227 d32 = getUDisp(sz,delta); delta += sz;
sewardj940e8c92004-07-11 16:53:24 +00006228 storeLE(mkexpr(addr), mkU(szToITy(sz), d32));
sewardje87b4842004-07-10 12:23:30 +00006229 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
6230 }
6231 break;
6232
sewardjc9a65702004-07-07 16:32:57 +00006233//-- /* ------------------------ opl imm, A ----------------- */
6234//--
6235//-- case 0x04: /* ADD Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +00006236//-- delta = dis_op_imm_A( 1, ADD, True, delta, "add" );
sewardjc9a65702004-07-07 16:32:57 +00006237//-- break;
sewardj77b86be2004-07-11 13:28:24 +00006238 case 0x05: /* ADD Iv, eAX */
6239 delta = dis_op_imm_A(sz, Iop_Add8, True, delta, "add" );
6240 break;
6241
sewardj940e8c92004-07-11 16:53:24 +00006242 case 0x0C: /* OR Ib, AL */
6243 delta = dis_op_imm_A( 1, Iop_Or8, True, delta, "or" );
6244 break;
sewardjc9a65702004-07-07 16:32:57 +00006245//-- case 0x0D: /* OR Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +00006246//-- delta = dis_op_imm_A( sz, OR, True, delta, "or" );
sewardjc9a65702004-07-07 16:32:57 +00006247//-- break;
6248//--
6249//-- case 0x14: /* ADC Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +00006250//-- delta = dis_op_imm_A( 1, ADC, True, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +00006251//-- break;
6252//-- case 0x15: /* ADC Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +00006253//-- delta = dis_op_imm_A( sz, ADC, True, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +00006254//-- break;
6255//--
6256//-- case 0x1C: /* SBB Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +00006257//-- delta = dis_op_imm_A( 1, SBB, True, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +00006258//-- break;
6259//-- case 0x1D: /* SBB Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +00006260//-- delta = dis_op_imm_A( sz, SBB, True, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +00006261//-- break;
6262//--
sewardj940e8c92004-07-11 16:53:24 +00006263 case 0x24: /* AND Ib, AL */
6264 delta = dis_op_imm_A( 1, Iop_And8, True, delta, "and" );
6265 break;
sewardjc2ac51e2004-07-12 01:03:26 +00006266 case 0x25: /* AND Iv, eAX */
6267 delta = dis_op_imm_A( sz, Iop_And8, True, delta, "and" );
6268 break;
sewardj0611d802004-07-11 02:37:54 +00006269
6270 case 0x2C: /* SUB Ib, AL */
6271 delta = dis_op_imm_A(1, Iop_Sub8, True, delta, "sub" );
6272 break;
sewardjc9a65702004-07-07 16:32:57 +00006273//-- case 0x2D: /* SUB Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +00006274//-- delta = dis_op_imm_A( sz, SUB, True, delta, "sub" );
sewardjc9a65702004-07-07 16:32:57 +00006275//-- break;
6276//--
6277//-- case 0x34: /* XOR Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +00006278//-- delta = dis_op_imm_A( 1, XOR, True, delta, "xor" );
sewardjc9a65702004-07-07 16:32:57 +00006279//-- break;
6280//-- case 0x35: /* XOR Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +00006281//-- delta = dis_op_imm_A( sz, XOR, True, delta, "xor" );
sewardjc9a65702004-07-07 16:32:57 +00006282//-- break;
6283//--
sewardj0611d802004-07-11 02:37:54 +00006284 case 0x3C: /* CMP Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +00006285 delta = dis_op_imm_A( 1, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +00006286 break;
6287 case 0x3D: /* CMP Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +00006288 delta = dis_op_imm_A( sz, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +00006289 break;
6290
sewardj77b86be2004-07-11 13:28:24 +00006291 case 0xA8: /* TEST Ib, AL */
6292 delta = dis_op_imm_A( 1, Iop_And8, False, delta, "test" );
6293 break;
sewardjc2ac51e2004-07-12 01:03:26 +00006294 case 0xA9: /* TEST Iv, eAX */
6295 delta = dis_op_imm_A( sz, Iop_And8, False, delta, "test" );
6296 break;
6297
sewardjc9a65702004-07-07 16:32:57 +00006298//-- /* ------------------------ opl Ev, Gv ----------------- */
6299//--
6300//-- case 0x02: /* ADD Eb,Gb */
sewardj9334b0f2004-07-10 22:43:54 +00006301//-- delta = dis_op2_E_G ( cb, sorb, ADD, True, 1, delta, "add" );
sewardjc9a65702004-07-07 16:32:57 +00006302//-- break;
sewardj9334b0f2004-07-10 22:43:54 +00006303 case 0x03: /* ADD Ev,Gv */
6304 delta = dis_op2_E_G ( sorb, Iop_Add8, True, sz, delta, "add" );
6305 break;
6306
sewardjc9a65702004-07-07 16:32:57 +00006307//-- case 0x0A: /* OR Eb,Gb */
sewardj9334b0f2004-07-10 22:43:54 +00006308//-- delta = dis_op2_E_G ( sorb, OR, True, 1, delta, "or" );
sewardjc9a65702004-07-07 16:32:57 +00006309//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +00006310 case 0x0B: /* OR Ev,Gv */
6311 delta = dis_op2_E_G ( sorb, Iop_Or8, True, sz, delta, "or" );
6312 break;
sewardjc9a65702004-07-07 16:32:57 +00006313//--
6314//-- case 0x12: /* ADC Eb,Gb */
sewardj9334b0f2004-07-10 22:43:54 +00006315//-- delta = dis_op2_E_G ( sorb, ADC, True, 1, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +00006316//-- break;
6317//-- case 0x13: /* ADC Ev,Gv */
sewardj9334b0f2004-07-10 22:43:54 +00006318//-- delta = dis_op2_E_G ( sorb, ADC, True, sz, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +00006319//-- break;
6320//--
6321//-- case 0x1A: /* SBB Eb,Gb */
sewardj9334b0f2004-07-10 22:43:54 +00006322//-- delta = dis_op2_E_G ( sorb, SBB, True, 1, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +00006323//-- break;
6324//-- case 0x1B: /* SBB Ev,Gv */
sewardj9334b0f2004-07-10 22:43:54 +00006325//-- delta = dis_op2_E_G ( sorb, SBB, True, sz, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +00006326//-- break;
6327//--
6328//-- case 0x22: /* AND Eb,Gb */
sewardj9334b0f2004-07-10 22:43:54 +00006329//-- delta = dis_op2_E_G ( sorb, AND, True, 1, delta, "and" );
sewardjc9a65702004-07-07 16:32:57 +00006330//-- break;
sewardj940e8c92004-07-11 16:53:24 +00006331 case 0x23: /* AND Ev,Gv */
6332 delta = dis_op2_E_G ( sorb, Iop_And8, True, sz, delta, "and" );
6333 break;
6334
sewardjc9a65702004-07-07 16:32:57 +00006335//-- case 0x2A: /* SUB Eb,Gb */
sewardj9334b0f2004-07-10 22:43:54 +00006336//-- delta = dis_op2_E_G ( sorb, SUB, True, 1, delta, "sub" );
sewardjc9a65702004-07-07 16:32:57 +00006337//-- break;
sewardj0611d802004-07-11 02:37:54 +00006338 case 0x2B: /* SUB Ev,Gv */
6339 delta = dis_op2_E_G ( sorb, Iop_Sub8, True, sz, delta, "sub" );
6340 break;
sewardjc2ac51e2004-07-12 01:03:26 +00006341
6342 case 0x32: /* XOR Eb,Gb */
6343 delta = dis_op2_E_G ( sorb, Iop_Xor8, True, 1, delta, "xor" );
6344 break;
sewardjc9a65702004-07-07 16:32:57 +00006345//-- case 0x33: /* XOR Ev,Gv */
sewardj9334b0f2004-07-10 22:43:54 +00006346//-- delta = dis_op2_E_G ( sorb, XOR, True, sz, delta, "xor" );
sewardjc9a65702004-07-07 16:32:57 +00006347//-- break;
6348//--
sewardjc2ac51e2004-07-12 01:03:26 +00006349 case 0x3A: /* CMP Eb,Gb */
6350 delta = dis_op2_E_G ( sorb, Iop_Sub8, False, 1, delta, "cmp" );
6351 break;
sewardje90ad6a2004-07-10 19:02:10 +00006352 case 0x3B: /* CMP Ev,Gv */
6353 delta = dis_op2_E_G ( sorb, Iop_Sub8, False, sz, delta, "cmp" );
6354 break;
6355
sewardj0611d802004-07-11 02:37:54 +00006356 case 0x84: /* TEST Eb,Gb */
6357 delta = dis_op2_E_G ( sorb, Iop_And8, False, 1, delta, "test" );
6358 break;
sewardje05c42c2004-07-08 20:25:10 +00006359 case 0x85: /* TEST Ev,Gv */
sewardje87b4842004-07-10 12:23:30 +00006360 delta = dis_op2_E_G ( sorb, Iop_And8, False, sz, delta, "test" );
sewardje05c42c2004-07-08 20:25:10 +00006361 break;
6362
sewardjc9a65702004-07-07 16:32:57 +00006363//-- /* ------------------------ opl Gv, Ev ----------------- */
6364//--
6365//-- case 0x00: /* ADD Gb,Eb */
sewardj9334b0f2004-07-10 22:43:54 +00006366//-- delta = dis_op2_G_E ( sorb, ADD, True, 1, delta, "add" );
sewardjc9a65702004-07-07 16:32:57 +00006367//-- break;
sewardje05c42c2004-07-08 20:25:10 +00006368 case 0x01: /* ADD Gv,Ev */
6369 delta = dis_op2_G_E ( sorb, Iop_Add8, True, sz, delta, "add" );
6370 break;
6371
sewardj940e8c92004-07-11 16:53:24 +00006372 case 0x08: /* OR Gb,Eb */
6373 delta = dis_op2_G_E ( sorb, Iop_Or8, True, 1, delta, "or" );
6374 break;
sewardj9334b0f2004-07-10 22:43:54 +00006375 case 0x09: /* OR Gv,Ev */
6376 delta = dis_op2_G_E ( sorb, Iop_Or8, True, sz, delta, "or" );
6377 break;
6378
sewardjc9a65702004-07-07 16:32:57 +00006379//-- case 0x10: /* ADC Gb,Eb */
sewardj9334b0f2004-07-10 22:43:54 +00006380//-- delta = dis_op2_G_E ( sorb, ADC, True, 1, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +00006381//-- break;
6382//-- case 0x11: /* ADC Gv,Ev */
sewardj9334b0f2004-07-10 22:43:54 +00006383//-- delta = dis_op2_G_E ( sorb, ADC, True, sz, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +00006384//-- break;
6385//--
6386//-- case 0x18: /* SBB Gb,Eb */
sewardj9334b0f2004-07-10 22:43:54 +00006387//-- delta = dis_op2_G_E ( sorb, SBB, True, 1, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +00006388//-- break;
6389//-- case 0x19: /* SBB Gv,Ev */
sewardj9334b0f2004-07-10 22:43:54 +00006390//-- delta = dis_op2_G_E ( sorb, SBB, True, sz, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +00006391//-- break;
6392//--
6393//-- case 0x20: /* AND Gb,Eb */
sewardj9334b0f2004-07-10 22:43:54 +00006394//-- delta = dis_op2_G_E ( sorb, AND, True, 1, delta, "and" );
sewardjc9a65702004-07-07 16:32:57 +00006395//-- break;
sewardj0611d802004-07-11 02:37:54 +00006396 case 0x21: /* AND Gv,Ev */
6397 delta = dis_op2_G_E ( sorb, Iop_And8, True, sz, delta, "and" );
6398 break;
6399
sewardjc9a65702004-07-07 16:32:57 +00006400//-- case 0x28: /* SUB Gb,Eb */
sewardj9334b0f2004-07-10 22:43:54 +00006401//-- delta = dis_op2_G_E ( sorb, SUB, True, 1, delta, "sub" );
sewardjc9a65702004-07-07 16:32:57 +00006402//-- break;
sewardje05c42c2004-07-08 20:25:10 +00006403 case 0x29: /* SUB Gv,Ev */
6404 delta = dis_op2_G_E ( sorb, Iop_Sub8, True, sz, delta, "sub" );
6405 break;
6406
sewardjc2ac51e2004-07-12 01:03:26 +00006407 case 0x30: /* XOR Gb,Eb */
6408 delta = dis_op2_G_E ( sorb, Iop_Xor8, True, 1, delta, "xor" );
6409 break;
sewardje87b4842004-07-10 12:23:30 +00006410 case 0x31: /* XOR Gv,Ev */
6411 delta = dis_op2_G_E ( sorb, Iop_Xor8, True, sz, delta, "xor" );
6412 break;
6413
sewardj0611d802004-07-11 02:37:54 +00006414 case 0x38: /* CMP Gb,Eb */
6415 delta = dis_op2_G_E ( sorb, Iop_Sub8, False, 1, delta, "cmp" );
6416 break;
sewardje90ad6a2004-07-10 19:02:10 +00006417 case 0x39: /* CMP Gv,Ev */
6418 delta = dis_op2_G_E ( sorb, Iop_Sub8, False, sz, delta, "cmp" );
6419 break;
6420
sewardj9334b0f2004-07-10 22:43:54 +00006421 /* ------------------------ POP ------------------------ */
6422
6423 case 0x58: /* POP eAX */
6424 case 0x59: /* POP eCX */
6425 case 0x5A: /* POP eDX */
6426 case 0x5B: /* POP eBX */
6427 case 0x5D: /* POP eBP */
6428 case 0x5E: /* POP eSI */
6429 case 0x5F: /* POP eDI */
6430 case 0x5C: /* POP eSP */
6431 vassert(sz == 2 || sz == 4);
6432 t1 = newTemp(szToITy(sz)); t2 = newTemp(Ity_I32);
6433 assign(t2, getIReg(4, R_ESP));
6434 assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
6435 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
6436 putIReg(sz, opc-0x58, mkexpr(t1));
6437 DIP("pop%c %s\n", nameISize(sz), nameIReg(sz,opc-0x58));
6438 break;
6439
sewardjc9a65702004-07-07 16:32:57 +00006440//-- case 0x9D: /* POPF */
6441//-- vg_assert(sz == 2 || sz == 4);
6442//-- t1 = newTemp(cb); t2 = newTemp(cb);
6443//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
6444//-- uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
6445//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
6446//-- uLiteral(cb, sz);
6447//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
6448//-- uInstr1(cb, PUTF, sz, TempReg, t1);
6449//-- /* PUTF writes all the flags we are interested in */
6450//-- uFlagsRWU(cb, FlagsEmpty, FlagsALL, FlagsEmpty);
6451//-- DIP("popf%c\n", nameISize(sz));
6452//-- break;
6453//--
6454//-- case 0x61: /* POPA */
6455//-- { Int reg;
6456//-- /* Just to keep things sane, we assert for a size 4. It's
6457//-- probably OK for size 2 as well, but I'd like to find a test
6458//-- case; ie, have the assertion fail, before committing to it.
6459//-- If it fails for you, uncomment the sz == 2 bit, try again,
6460//-- and let me know whether or not it works. (jseward@acm.org). */
6461//-- vg_assert(sz == 4 /* || sz == 2 */);
6462//--
6463//-- /* Eight values are popped, one per register, but the value of
6464//-- %esp on the stack is ignored and instead incremented (in one
6465//-- hit at the end) for each of the values. */
6466//-- t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
6467//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
6468//-- uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t3);
6469//--
6470//-- /* Do %edi, %esi, %ebp */
6471//-- for (reg = 7; reg >= 5; reg--) {
6472//-- uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
6473//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
6474//-- uLiteral(cb, sz);
6475//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
6476//-- }
6477//-- /* Ignore (skip) value of %esp on stack. */
6478//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
6479//-- uLiteral(cb, sz);
6480//-- /* Do %ebx, %edx, %ecx, %eax */
6481//-- for (reg = 3; reg >= 0; reg--) {
6482//-- uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
6483//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
6484//-- uLiteral(cb, sz);
6485//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
6486//-- }
6487//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t3);
6488//-- uLiteral(cb, sz * 8); /* One 'sz' per register */
6489//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
6490//-- DIP("popa%c\n", nameISize(sz));
6491//-- break;
6492//-- }
6493//--
6494//-- case 0x8F: /* POPL/POPW m32 */
6495//-- { UInt pair1;
6496//-- Int tmpa;
6497//-- UChar rm = getIByte(delta);
6498//--
6499//-- /* make sure this instruction is correct POP */
6500//-- vg_assert(!epartIsReg(rm) && (gregOfRM(rm) == 0));
6501//-- /* and has correct size */
6502//-- vg_assert(sz == 4);
6503//--
6504//-- t1 = newTemp(cb); t3 = newTemp(cb);
6505//-- /* set t1 to ESP: t1 = ESP */
6506//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
6507//-- /* load M[ESP] to virtual register t3: t3 = M[t1] */
6508//-- uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t3);
6509//--
6510//-- /* increase ESP; must be done before the STORE. Intel manual says:
6511//-- If the ESP register is used as a base register for addressing
6512//-- a destination operand in memory, the POP instruction computes
6513//-- the effective address of the operand after it increments the
6514//-- ESP register.
6515//-- */
6516//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1);
6517//-- uLiteral(cb, sz);
6518//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
6519//--
6520//-- /* resolve MODR/M */
6521//-- pair1 = disAMode ( cb, sorb, eip, dis_buf );
6522//--
6523//-- tmpa = LOW24(pair1);
6524//-- /* uInstr2(cb, LOAD, sz, TempReg, tmpa, TempReg, tmpa); */
6525//-- /* store value from stack in memory, M[m32] = t3 */
6526//-- uInstr2(cb, STORE, 4, TempReg, t3, TempReg, tmpa);
6527//--
6528//-- DIP("popl %s\n", dis_buf);
6529//--
6530//-- eip += HI8(pair1);
6531//-- break;
6532//-- }
6533//--
6534//-- case 0x1F: /* POP %DS */
6535//-- dis_pop_segreg( cb, R_DS, sz ); break;
6536//-- case 0x07: /* POP %ES */
6537//-- dis_pop_segreg( cb, R_ES, sz ); break;
6538//-- case 0x17: /* POP %SS */
6539//-- dis_pop_segreg( cb, R_SS, sz ); break;
sewardjd1061ab2004-07-08 01:45:30 +00006540
6541 /* ------------------------ PUSH ----------------------- */
6542
6543 case 0x50: /* PUSH eAX */
6544 case 0x51: /* PUSH eCX */
6545 case 0x52: /* PUSH eDX */
6546 case 0x53: /* PUSH eBX */
6547 case 0x55: /* PUSH eBP */
6548 case 0x56: /* PUSH eSI */
6549 case 0x57: /* PUSH eDI */
6550 case 0x54: /* PUSH eSP */
6551 /* This is the Right Way, in that the value to be pushed is
6552 established before %esp is changed, so that pushl %esp
6553 correctly pushes the old value. */
6554 vassert(sz == 2 || sz == 4);
6555 ty = sz==2 ? Ity_I16 : Ity_I32;
6556 t1 = newTemp(ty); t2 = newTemp(ty);
sewardj41f43bc2004-07-08 14:23:22 +00006557 assign(t1, getIReg(sz, opc-0x50));
6558 assign(t2, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)));
6559 putIReg(4, R_ESP, mkexpr(t2) );
6560 storeLE(mkexpr(t2),mkexpr(t1));
sewardjd1061ab2004-07-08 01:45:30 +00006561 DIP("push%c %s\n", nameISize(sz), nameIReg(sz,opc-0x50));
6562 break;
6563
6564
sewardj0c12ea82004-07-12 08:18:16 +00006565 case 0x68: /* PUSH Iv */
6566 d32 = getUDisp(sz,delta); delta += sz;
6567 goto do_push_I;
sewardjc9a65702004-07-07 16:32:57 +00006568//-- case 0x6A: /* PUSH Ib, sign-extended to sz */
6569//-- d32 = getSDisp8(eip); eip += 1;
6570//-- goto do_push_I;
sewardj0c12ea82004-07-12 08:18:16 +00006571 do_push_I:
6572 ty = szToITy(sz);
6573 t1 = newTemp(Ity_I32); t2 = newTemp(ty);
6574 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
6575 putIReg(4, R_ESP, mkexpr(t1) );
6576 storeLE( mkexpr(t1), mkU(ty,d32) );
6577 DIP("push%c $0x%x\n", nameISize(sz), d32);
6578 break;
6579
sewardjc9a65702004-07-07 16:32:57 +00006580//-- case 0x9C: /* PUSHF */
6581//-- vg_assert(sz == 2 || sz == 4);
6582//-- t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
6583//-- uInstr1(cb, GETF, sz, TempReg, t1);
6584//-- /* GETF reads all the flags we are interested in */
6585//-- uFlagsRWU(cb, FlagsALL, FlagsEmpty, FlagsEmpty);
6586//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
6587//-- uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
6588//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
6589//-- uLiteral(cb, sz);
6590//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
6591//-- uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
6592//-- DIP("pushf%c\n", nameISize(sz));
6593//-- break;
6594//--
6595//-- case 0x60: /* PUSHA */
6596//-- { Int reg;
6597//-- /* Just to keep things sane, we assert for a size 4. It's
6598//-- probably OK for size 2 as well, but I'd like to find a test
6599//-- case; ie, have the assertion fail, before committing to it.
6600//-- If it fails for you, uncomment the sz == 2 bit, try again,
6601//-- and let me know whether or not it works. (jseward@acm.org). */
6602//-- vg_assert(sz == 4 /* || sz == 2 */);
6603//--
6604//-- /* This is the Right Way, in that the value to be pushed is
6605//-- established before %esp is changed, so that pusha
6606//-- correctly pushes the old %esp value. New value of %esp is
6607//-- pushed at start. */
6608//-- t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
6609//-- t4 = newTemp(cb);
6610//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
6611//-- uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
6612//-- uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t4);
6613//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t4);
6614//-- uLiteral(cb, sz * 8); /* One 'sz' per register. */
6615//-- uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_ESP);
6616//-- /* Do %eax, %ecx, %edx, %ebx */
6617//-- for (reg = 0; reg <= 3; reg++) {
6618//-- uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
6619//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
6620//-- uLiteral(cb, sz);
6621//-- uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
6622//-- }
6623//-- /* Push old value of %esp */
6624//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
6625//-- uLiteral(cb, sz);
6626//-- uInstr2(cb, STORE, sz, TempReg, t3, TempReg, t2);
6627//-- /* Do %ebp, %esi, %edi */
6628//-- for (reg = 5; reg <= 7; reg++) {
6629//-- uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
6630//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
6631//-- uLiteral(cb, sz);
6632//-- uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
6633//-- }
6634//-- DIP("pusha%c\n", nameISize(sz));
6635//-- break;
6636//-- }
6637//--
6638//-- case 0x0E: /* PUSH %CS */
6639//-- dis_push_segreg( cb, R_CS, sz ); break;
6640//-- case 0x1E: /* PUSH %DS */
6641//-- dis_push_segreg( cb, R_DS, sz ); break;
6642//-- case 0x06: /* PUSH %ES */
6643//-- dis_push_segreg( cb, R_ES, sz ); break;
6644//-- case 0x16: /* PUSH %SS */
6645//-- dis_push_segreg( cb, R_SS, sz ); break;
6646//--
6647//-- /* ------------------------ SCAS et al ----------------- */
6648//--
6649//-- case 0xA4: /* MOVS, no REP prefix */
6650//-- case 0xA5:
6651//-- dis_string_op( cb, dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
6652//-- break;
6653//--
6654//-- case 0xA6: /* CMPSb, no REP prefix */
6655//-- case 0xA7:
6656//-- dis_string_op( cb, dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
6657//-- break;
6658//--
6659//-- case 0xAA: /* STOS, no REP prefix */
6660//-- case 0xAB:
6661//-- dis_string_op( cb, dis_STOS, ( opc == 0xAA ? 1 : sz ), "stos", sorb );
6662//-- break;
6663//--
6664//-- case 0xAC: /* LODS, no REP prefix */
6665//-- case 0xAD:
6666//-- dis_string_op( cb, dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
6667//-- break;
6668//--
6669//-- case 0xAE: /* SCAS, no REP prefix */
6670//-- case 0xAF:
sewardj64e1d652004-07-12 14:00:46 +00006671//-- dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
sewardjc9a65702004-07-07 16:32:57 +00006672//-- break;
sewardj64e1d652004-07-12 14:00:46 +00006673
6674
6675 case 0xFC: /* CLD */
6676 stmt( IRStmt_Put( NULL, OFFB_DFLAG, mkU32(1)) );
6677 DIP("cld\n");
6678 break;
6679
sewardjc9a65702004-07-07 16:32:57 +00006680//-- case 0xFD: /* STD */
6681//-- uInstr0(cb, CALLM_S, 0);
6682//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_STD));
6683//-- uFlagsRWU(cb, FlagsEmpty, FlagD, FlagsEmpty);
6684//-- uInstr0(cb, CALLM_E, 0);
6685//-- DIP("std\n");
6686//-- break;
6687//--
6688//-- case 0xF8: /* CLC */
6689//-- uInstr0(cb, CALLM_S, 0);
6690//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CLC));
6691//-- uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
6692//-- uInstr0(cb, CALLM_E, 0);
6693//-- DIP("clc\n");
6694//-- break;
6695//--
6696//-- case 0xF9: /* STC */
6697//-- uInstr0(cb, CALLM_S, 0);
6698//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_STC));
6699//-- uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
6700//-- uInstr0(cb, CALLM_E, 0);
6701//-- DIP("stc\n");
6702//-- break;
6703//--
6704//-- case 0xF5: /* CMC */
6705//-- uInstr0(cb, CALLM_S, 0);
6706//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CMC));
6707//-- uFlagsRWU(cb, FlagC, FlagC, FlagsOSZAP);
6708//-- uInstr0(cb, CALLM_E, 0);
6709//-- DIP("cmc\n");
6710//-- break;
6711//--
6712//-- /* REPNE prefix insn */
6713//-- case 0xF2: {
6714//-- Addr eip_orig = eip - 1;
6715//-- vg_assert(sorb == 0);
6716//-- abyte = getIByte(delta); eip++;
6717//--
6718//-- if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); eip++; }
6719//-- *isEnd = True;
6720//--
6721//-- switch (abyte) {
6722//-- /* According to the Intel manual, "repne movs" should never occur, but
6723//-- * in practice it has happened, so allow for it here... */
6724//-- case 0xA4: sz = 1; /* REPNE MOVS<sz> */
6725//-- case 0xA5:
6726//-- dis_REP_op ( cb, CondNZ, dis_MOVS, sz, eip_orig, eip, "repne movs" );
6727//-- break;
6728//--
6729//-- case 0xA6: sz = 1; /* REPNE CMPS<sz> */
6730//-- case 0xA7:
6731//-- dis_REP_op ( cb, CondNZ, dis_CMPS, sz, eip_orig, eip, "repne cmps" );
6732//-- break;
6733//--
6734//-- case 0xAE: sz = 1; /* REPNE SCAS<sz> */
6735//-- case 0xAF:
6736//-- dis_REP_op ( cb, CondNZ, dis_SCAS, sz, eip_orig, eip, "repne scas" );
6737//-- break;
6738//--
6739//-- default:
6740//-- goto decode_failure;
6741//-- }
6742//-- break;
6743//-- }
sewardj64e1d652004-07-12 14:00:46 +00006744
6745 /* REP/REPE prefix insn (for SCAS and CMPS, 0xF3 means REPE,
6746 for the rest, it means REP) */
6747 case 0xF3: {
6748 Addr32 eip_orig = guest_eip + delta - 1;
6749 vassert(sorb == 0);
6750 abyte = getIByte(delta); delta++;
6751
6752 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
6753 *isEnd = True;
6754
6755 switch (abyte) {
6756 case 0xA4: sz = 1; /* REP MOVS<sz> */
6757 case 0xA5:
6758 dis_REP_op ( CondAlways, dis_MOVS, sz, eip_orig,
6759 guest_eip+delta, "rep movs" );
6760 break;
6761
6762 case 0xA6: sz = 1; /* REPE CMP<sz> */
sewardjc9a65702004-07-07 16:32:57 +00006763//-- case 0xA7:
sewardj64e1d652004-07-12 14:00:46 +00006764 dis_REP_op ( CondZ, dis_CMPS, sz, eip_orig,
6765 guest_eip+delta, "repe cmps" );
6766 break;
6767
6768 case 0xAA: sz = 1; /* REP STOS<sz> */
6769 case 0xAB:
6770 dis_REP_op ( CondAlways, dis_STOS, sz, eip_orig,
6771 guest_eip+delta, "rep stos" );
6772 break;
sewardjc9a65702004-07-07 16:32:57 +00006773//--
6774//-- case 0xAE: sz = 1; /* REPE SCAS<sz> */
6775//-- case 0xAF:
6776//-- dis_REP_op ( cb, CondZ, dis_SCAS, sz, eip_orig, eip, "repe scas" );
6777//-- break;
6778//--
6779//-- case 0x90: /* REP NOP (PAUSE) */
6780//-- /* a hint to the P4 re spin-wait loop */
6781//-- DIP("rep nop (P4 pause)\n");
6782//-- jmp_lit(cb, eip);
6783//-- LAST_UINSTR(cb).jmpkind = JmpYield;
6784//-- break;
6785//--
6786//-- case 0xC3: /* REP RET */
6787//-- /* AMD K7/K8-specific optimisation; faster than vanilla RET */
6788//-- dis_ret(cb, 0);
6789//-- DIP("rep ret\n");
6790//-- break;
sewardj64e1d652004-07-12 14:00:46 +00006791
6792 default:
6793 goto decode_failure;
6794 }
6795 break;
6796 }
sewardj0611d802004-07-11 02:37:54 +00006797
6798 /* ------------------------ XCHG ----------------------- */
6799
6800 case 0x86: /* XCHG Gb,Eb */
6801 sz = 1;
6802 /* Fall through ... */
6803 case 0x87: /* XCHG Gv,Ev */
6804 modrm = getIByte(delta);
6805 ty = szToITy(sz);
6806 t1 = newTemp(ty); t2 = newTemp(ty);
6807 if (epartIsReg(modrm)) {
6808 assign(t1, getIReg(sz, eregOfRM(modrm)));
6809 assign(t2, getIReg(sz, gregOfRM(modrm)));
6810 putIReg(sz, gregOfRM(modrm), mkexpr(t1));
6811 putIReg(sz, eregOfRM(modrm), mkexpr(t2));
6812 delta++;
6813 DIP("xchg%c %s, %s\n",
6814 nameISize(sz), nameIReg(sz,gregOfRM(modrm)),
6815 nameIReg(sz,eregOfRM(modrm)));
6816 } else {
sewardj0c12ea82004-07-12 08:18:16 +00006817 addr = disAMode ( &alen, sorb, delta, dis_buf );
6818 assign( t1, loadLE(ty,mkexpr(addr)) );
6819 assign( t2, getIReg(sz,gregOfRM(modrm)) );
6820 storeLE( mkexpr(addr), mkexpr(t2) );
6821 putIReg( sz, gregOfRM(modrm), mkexpr(t1) );
6822 delta += alen;
sewardj0611d802004-07-11 02:37:54 +00006823 DIP("xchg%c %s, %s\n", nameISize(sz),
6824 nameIReg(sz,gregOfRM(modrm)), dis_buf);
sewardj0611d802004-07-11 02:37:54 +00006825 }
6826 break;
sewardje87b4842004-07-10 12:23:30 +00006827
6828 case 0x90: /* XCHG eAX,eAX */
6829 DIP("nop\n");
6830 break;
sewardj64e1d652004-07-12 14:00:46 +00006831 case 0x91: /* XCHG eAX,eCX */
6832 case 0x92: /* XCHG eAX,eDX */
6833 case 0x93: /* XCHG eAX,eBX */
6834 case 0x94: /* XCHG eAX,eSP */
6835 case 0x95: /* XCHG eAX,eBP */
6836 case 0x96: /* XCHG eAX,eSI */
6837 case 0x97: /* XCHG eAX,eDI */
6838 codegen_xchg_eAX_Reg ( sz, opc - 0x90 );
6839 break;
6840
sewardjc9a65702004-07-07 16:32:57 +00006841//-- /* ------------------------ XLAT ----------------------- */
6842//--
6843//-- case 0xD7: /* XLAT */
6844//-- t1 = newTemp(cb); t2 = newTemp(cb);
6845//-- uInstr2(cb, GET, sz, ArchReg, R_EBX, TempReg, t1); /* get eBX */
6846//-- handleSegOverride( cb, sorb, t1 ); /* make t1 DS:eBX */
6847//-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t2); /* get AL */
6848//-- /* Widen %AL to 32 bits, so it's all defined when we add it. */
6849//-- uInstr1(cb, WIDEN, 4, TempReg, t2);
6850//-- uWiden(cb, 1, False);
6851//-- uInstr2(cb, ADD, sz, TempReg, t2, TempReg, t1); /* add AL to eBX */
6852//-- uInstr2(cb, LOAD, 1, TempReg, t1, TempReg, t2); /* get byte at t1 into t2 */
6853//-- uInstr2(cb, PUT, 1, TempReg, t2, ArchReg, R_AL); /* put byte into AL */
6854//--
6855//-- DIP("xlat%c [ebx]\n", nameISize(sz));
6856//-- break;
6857//--
6858//-- /* ------------------------ IN / OUT ----------------------- */
6859//--
6860//-- case 0xE4: /* IN ib, %al */
6861//-- case 0xE5: /* IN ib, %{e}ax */
6862//-- case 0xEC: /* IN (%dx),%al */
6863//-- case 0xED: /* IN (%dx),%{e}ax */
6864//-- t1 = newTemp(cb);
6865//-- t2 = newTemp(cb);
6866//-- t3 = newTemp(cb);
6867//--
6868//-- uInstr0(cb, CALLM_S, 0);
6869//-- /* operand size? */
6870//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
6871//-- uLiteral(cb, ( opc == 0xE4 || opc == 0xEC ) ? 1 : sz);
6872//-- uInstr1(cb, PUSH, 4, TempReg, t1);
6873//-- /* port number ? */
6874//-- if ( opc == 0xE4 || opc == 0xE5 ) {
6875//-- abyte = getUChar(eip); eip++;
6876//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
6877//-- uLiteral(cb, abyte);
6878//-- }
6879//-- else
6880//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
6881//--
6882//-- uInstr1(cb, PUSH, 4, TempReg, t2);
6883//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_IN));
6884//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
6885//-- uInstr1(cb, POP, 4, TempReg, t2);
6886//-- uInstr1(cb, CLEAR, 0, Lit16, 4);
6887//-- uInstr0(cb, CALLM_E, 0);
6888//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EAX);
6889//-- if ( opc == 0xE4 || opc == 0xE5 ) {
6890//-- DIP("in 0x%x, %%eax/%%ax/%%al\n", getUChar(eip-1) );
6891//-- } else {
6892//-- DIP("in (%%dx), %%eax/%%ax/%%al\n");
6893//-- }
6894//-- break;
6895//-- case 0xE6: /* OUT %al,ib */
6896//-- case 0xE7: /* OUT %{e}ax,ib */
6897//-- case 0xEE: /* OUT %al,(%dx) */
6898//-- case 0xEF: /* OUT %{e}ax,(%dx) */
6899//-- t1 = newTemp(cb);
6900//-- t2 = newTemp(cb);
6901//-- t3 = newTemp(cb);
6902//--
6903//-- uInstr0(cb, CALLM_S, 0);
6904//-- /* operand size? */
6905//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
6906//-- uLiteral(cb, ( opc == 0xE6 || opc == 0xEE ) ? 1 : sz);
6907//-- uInstr1(cb, PUSH, 4, TempReg, t1);
6908//-- /* port number ? */
6909//-- if ( opc == 0xE6 || opc == 0xE7 ) {
6910//-- abyte = getUChar(eip); eip++;
6911//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
6912//-- uLiteral(cb, abyte);
6913//-- }
6914//-- else
6915//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
6916//-- uInstr1(cb, PUSH, 4, TempReg, t2);
6917//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t3);
6918//-- uInstr1(cb, PUSH, 4, TempReg, t3);
6919//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_OUT));
6920//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
6921//-- uInstr1(cb, CLEAR, 0, Lit16, 12);
6922//-- uInstr0(cb, CALLM_E, 0);
6923//-- if ( opc == 0xE4 || opc == 0xE5 ) {
6924//-- DIP("out %%eax/%%ax/%%al, 0x%x\n", getUChar(eip-1) );
6925//-- } else {
6926//-- DIP("out %%eax/%%ax/%%al, (%%dx)\n");
6927//-- }
6928//-- break;
sewardj0611d802004-07-11 02:37:54 +00006929
6930 /* ------------------------ (Grp1 extensions) ---------- */
6931
6932 case 0x80: /* Grp1 Ib,Eb */
6933 modrm = getIByte(delta);
6934 am_sz = lengthAMode(delta);
6935 sz = 1;
6936 d_sz = 1;
sewardjc2ac51e2004-07-12 01:03:26 +00006937 d32 = getUChar(delta + am_sz);
sewardj0611d802004-07-11 02:37:54 +00006938 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
6939 break;
sewardje05c42c2004-07-08 20:25:10 +00006940
6941 case 0x81: /* Grp1 Iv,Ev */
6942 modrm = getIByte(delta);
6943 am_sz = lengthAMode(delta);
6944 d_sz = sz;
6945 d32 = getUDisp(d_sz, delta + am_sz);
6946 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
6947 break;
sewardjd1061ab2004-07-08 01:45:30 +00006948
6949 case 0x83: /* Grp1 Ib,Ev */
6950 modrm = getIByte(delta);
6951 am_sz = lengthAMode(delta);
6952 d_sz = 1;
6953 d32 = getSDisp8(delta + am_sz);
6954 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
6955 break;
6956
sewardjc2ac51e2004-07-12 01:03:26 +00006957 /* ------------------------ (Grp2 extensions) ---------- */
6958
6959 case 0xC0: /* Grp2 Ib,Eb */
6960 modrm = getIByte(delta);
6961 am_sz = lengthAMode(delta);
6962 d_sz = 1;
6963 d32 = getSDisp8(delta + am_sz);
6964 sz = 1;
6965 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz, mkU32(d32) );
6966 break;
sewardje90ad6a2004-07-10 19:02:10 +00006967
6968 case 0xC1: /* Grp2 Ib,Ev */
sewardjc2ac51e2004-07-12 01:03:26 +00006969 modrm = getIByte(delta);
sewardje90ad6a2004-07-10 19:02:10 +00006970 am_sz = lengthAMode(delta);
6971 d_sz = 1;
6972 d32 = getSDisp8(delta + am_sz);
6973 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz, mkU32(d32) );
6974 break;
6975
sewardjc9a65702004-07-07 16:32:57 +00006976//-- case 0xD0: /* Grp2 1,Eb */
6977//-- modrm = getUChar(eip);
6978//-- am_sz = lengthAMode(eip);
6979//-- d_sz = 0;
6980//-- d32 = 1;
6981//-- sz = 1;
6982//-- eip = dis_Grp2 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
6983//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +00006984
6985 case 0xD1: /* Grp2 1,Ev */
6986 modrm = getUChar(delta);
6987 am_sz = lengthAMode(delta);
6988 d_sz = 0;
6989 d32 = 1;
6990 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz, mkU32(d32) );
6991 break;
6992
sewardjc9a65702004-07-07 16:32:57 +00006993//-- case 0xD2: /* Grp2 CL,Eb */
6994//-- modrm = getUChar(eip);
6995//-- am_sz = lengthAMode(eip);
6996//-- d_sz = 0;
6997//-- sz = 1;
6998//-- eip = dis_Grp2 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, ArchReg, R_ECX );
6999//-- break;
sewardj9334b0f2004-07-10 22:43:54 +00007000
7001 case 0xD3: /* Grp2 CL,Ev */
7002 modrm = getIByte(delta);
7003 am_sz = lengthAMode(delta);
7004 d_sz = 0;
7005 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
7006 getIReg(sz,R_ECX) );
7007 break;
7008
sewardj940e8c92004-07-11 16:53:24 +00007009 /* ------------------------ (Grp3 extensions) ---------- */
7010
7011 case 0xF6: /* Grp3 Eb */
7012 delta = dis_Grp3 ( sorb, 1, delta );
7013 break;
7014 case 0xF7: /* Grp3 Ev */
7015 delta = dis_Grp3 ( sorb, sz, delta );
7016 break;
7017
sewardjc2ac51e2004-07-12 01:03:26 +00007018 /* ------------------------ (Grp4 extensions) ---------- */
7019
7020 case 0xFE: /* Grp4 Eb */
7021 delta = dis_Grp4 ( sorb, delta );
7022 break;
sewardj0611d802004-07-11 02:37:54 +00007023
7024 /* ------------------------ (Grp5 extensions) ---------- */
7025
7026 case 0xFF: /* Grp5 Ev */
7027 delta = dis_Grp5 ( sorb, sz, delta, isEnd );
7028 break;
sewardje87b4842004-07-10 12:23:30 +00007029
7030 /* ------------------------ Escapes to 2-byte opcodes -- */
7031
7032 case 0x0F: {
7033 opc = getIByte(delta); delta++;
7034 switch (opc) {
7035
sewardjc9a65702004-07-07 16:32:57 +00007036//-- /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
7037//--
7038//-- case 0xBA: /* Grp8 Ib,Ev */
7039//-- modrm = getUChar(eip);
7040//-- am_sz = lengthAMode(eip);
7041//-- d32 = getSDisp8(eip + am_sz);
7042//-- eip = dis_Grp8_BT ( cb, sorb, eip, modrm, am_sz, sz, d32 );
7043//-- break;
7044//--
7045//-- /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
7046//--
7047//-- case 0xBC: /* BSF Gv,Ev */
7048//-- eip = dis_bs_E_G ( cb, sorb, sz, eip, True );
7049//-- break;
7050//-- case 0xBD: /* BSR Gv,Ev */
7051//-- eip = dis_bs_E_G ( cb, sorb, sz, eip, False );
7052//-- break;
7053//--
7054//-- /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
7055//--
7056//-- case 0xC8: /* BSWAP %eax */
7057//-- case 0xC9:
7058//-- case 0xCA:
7059//-- case 0xCB:
7060//-- case 0xCC:
7061//-- case 0xCD:
7062//-- case 0xCE:
7063//-- case 0xCF: /* BSWAP %edi */
7064//-- /* AFAICS from the Intel docs, this only exists at size 4. */
7065//-- vg_assert(sz == 4);
7066//-- t1 = newTemp(cb);
7067//-- uInstr2(cb, GET, 4, ArchReg, opc-0xC8, TempReg, t1);
7068//-- uInstr1(cb, BSWAP, 4, TempReg, t1);
7069//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, opc-0xC8);
7070//-- DIP("bswapl %s\n", nameIReg(4, opc-0xC8));
7071//-- break;
7072//--
7073//-- /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
7074//--
7075//-- case 0xA3: /* BT Gv,Ev */
7076//-- eip = dis_bt_G_E ( cb, sorb, sz, eip, BtOpNone );
7077//-- break;
7078//-- case 0xB3: /* BTR Gv,Ev */
7079//-- eip = dis_bt_G_E ( cb, sorb, sz, eip, BtOpReset );
7080//-- break;
7081//-- case 0xAB: /* BTS Gv,Ev */
7082//-- eip = dis_bt_G_E ( cb, sorb, sz, eip, BtOpSet );
7083//-- break;
7084//-- case 0xBB: /* BTC Gv,Ev */
7085//-- eip = dis_bt_G_E ( cb, sorb, sz, eip, BtOpComp );
7086//-- break;
7087//--
7088//-- /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
7089//--
7090//-- case 0x40:
7091//-- case 0x41:
7092//-- case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
7093//-- case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
7094//-- case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
7095//-- case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
7096//-- case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
7097//-- case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
7098//-- case 0x48: /* CMOVSb (cmov negative) */
7099//-- case 0x49: /* CMOVSb (cmov not negative) */
7100//-- case 0x4A: /* CMOVP (cmov parity even) */
7101//-- case 0x4B: /* CMOVNP (cmov parity odd) */
7102//-- case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
7103//-- case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
7104//-- case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
7105//-- case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
7106//-- eip = dis_cmov_E_G(cb, sorb, sz, (Condcode)(opc - 0x40), eip);
7107//-- break;
7108//--
7109//-- /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
7110//--
7111//-- case 0xB0: /* CMPXCHG Gv,Ev */
7112//-- eip = dis_cmpxchg_G_E ( cb, sorb, 1, eip );
7113//-- break;
7114//-- case 0xB1: /* CMPXCHG Gv,Ev */
7115//-- eip = dis_cmpxchg_G_E ( cb, sorb, sz, eip );
7116//-- break;
7117//-- case 0xC7: /* CMPXCHG8B Gv */
7118//-- eip = dis_cmpxchg8b ( cb, sorb, eip );
7119//-- break;
7120//--
7121//-- /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
7122//--
7123//-- case 0xA2: /* CPUID */
7124//-- if (!VG_(cpu_has_feature)(VG_X86_FEAT_CPUID))
7125//-- goto decode_failure;
7126//--
7127//-- t1 = newTemp(cb);
7128//-- t2 = newTemp(cb);
7129//-- t3 = newTemp(cb);
7130//-- t4 = newTemp(cb);
7131//-- uInstr0(cb, CALLM_S, 0);
7132//--
7133//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t1);
7134//-- uInstr1(cb, PUSH, 4, TempReg, t1);
7135//--
7136//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
7137//-- uLiteral(cb, 0);
7138//-- uInstr1(cb, PUSH, 4, TempReg, t2);
7139//--
7140//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t3);
7141//-- uLiteral(cb, 0);
7142//-- uInstr1(cb, PUSH, 4, TempReg, t3);
7143//--
7144//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
7145//-- uLiteral(cb, 0);
7146//-- uInstr1(cb, PUSH, 4, TempReg, t4);
7147//--
7148//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CPUID));
7149//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
7150//--
7151//-- uInstr1(cb, POP, 4, TempReg, t4);
7152//-- uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_EDX);
7153//--
7154//-- uInstr1(cb, POP, 4, TempReg, t3);
7155//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ECX);
7156//--
7157//-- uInstr1(cb, POP, 4, TempReg, t2);
7158//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBX);
7159//--
7160//-- uInstr1(cb, POP, 4, TempReg, t1);
7161//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
7162//--
7163//-- uInstr0(cb, CALLM_E, 0);
7164//-- DIP("cpuid\n");
7165//-- break;
7166//--
sewardj9334b0f2004-07-10 22:43:54 +00007167 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
7168
7169 case 0xB6: /* MOVZXb Eb,Gv */
7170 delta = dis_movx_E_G ( sorb, delta, 1, 4, False );
7171 break;
sewardj940e8c92004-07-11 16:53:24 +00007172 case 0xB7: /* MOVZXw Ew,Gv */
7173 delta = dis_movx_E_G ( sorb, delta, 2, 4, False );
7174 break;
7175
sewardj0611d802004-07-11 02:37:54 +00007176 case 0xBE: /* MOVSXb Eb,Gv */
7177 delta = dis_movx_E_G ( sorb, delta, 1, 4, True );
7178 break;
sewardjc9a65702004-07-07 16:32:57 +00007179//-- case 0xBF: /* MOVSXw Ew,Gv */
7180//-- eip = dis_movx_E_G ( cb, sorb, eip, 2, 4, True );
7181//-- break;
7182//--
7183//-- /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
7184//--
7185//-- case 0xC3: /* MOVNTI Gv,Ev */
7186//-- vg_assert(sz == 4);
7187//-- modrm = getUChar(eip);
7188//-- vg_assert(!epartIsReg(modrm));
7189//-- t1 = newTemp(cb);
7190//-- uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
7191//-- pair = disAMode ( cb, sorb, eip, dis_buf );
7192//-- t2 = LOW24(pair);
7193//-- eip += HI8(pair);
7194//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
7195//-- DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
7196//-- break;
sewardjcf780b42004-07-13 18:42:17 +00007197
7198 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
7199
7200 case 0xAF: /* IMUL Ev, Gv */
7201 delta = dis_mul_E_G ( sorb, sz, delta, True );
7202 break;
sewardje87b4842004-07-10 12:23:30 +00007203
7204 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
7205 case 0x80:
7206 case 0x81:
7207 case 0x82: /* JBb/JNAEb (jump below) */
7208 case 0x83: /* JNBb/JAEb (jump not below) */
7209 case 0x84: /* JZb/JEb (jump zero) */
7210 case 0x85: /* JNZb/JNEb (jump not zero) */
7211 case 0x86: /* JBEb/JNAb (jump below or equal) */
7212 case 0x87: /* JNBEb/JAb (jump not below or equal) */
7213 case 0x88: /* JSb (jump negative) */
7214 case 0x89: /* JSb (jump not negative) */
7215 case 0x8A: /* JP (jump parity even) */
7216 case 0x8B: /* JNP/JPO (jump parity odd) */
7217 case 0x8C: /* JLb/JNGEb (jump less) */
7218 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
7219 case 0x8E: /* JLEb/JNGb (jump less or equal) */
7220 case 0x8F: /* JGb/JNLEb (jump greater) */
7221 d32 = (((Addr32)guest_code)+delta+4) + getUDisp32(delta);
7222 delta += 4;
7223 jcc_01((Condcode)(opc - 0x80), (Addr32)(guest_code+delta), d32);
7224 *isEnd = True;
7225 DIP("j%s-32 0x%x\n", name_Condcode(opc - 0x80), d32);
7226 break;
7227
sewardjc9a65702004-07-07 16:32:57 +00007228//--
7229//-- /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
7230//--
7231//-- case 0x31: /* RDTSC */
7232//-- t1 = newTemp(cb);
7233//-- t2 = newTemp(cb);
7234//-- t3 = newTemp(cb);
7235//-- uInstr0(cb, CALLM_S, 0);
7236//-- // Nb: even though these args aren't used by RDTSC_helper, need
7237//-- // them to be defined (for Memcheck). The TempRegs pushed must
7238//-- // also be distinct.
7239//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
7240//-- uLiteral(cb, 0);
7241//-- uInstr1(cb, PUSH, 4, TempReg, t1);
7242//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
7243//-- uLiteral(cb, 0);
7244//-- uInstr1(cb, PUSH, 4, TempReg, t2);
7245//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_RDTSC));
7246//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
7247//-- uInstr1(cb, POP, 4, TempReg, t3);
7248//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EDX);
7249//-- uInstr1(cb, POP, 4, TempReg, t3);
7250//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EAX);
7251//-- uInstr0(cb, CALLM_E, 0);
7252//-- DIP("rdtsc\n");
7253//-- break;
sewardj77b86be2004-07-11 13:28:24 +00007254
7255 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
7256 case 0x90:
7257 case 0x91:
7258 case 0x92: /* set-Bb/set-NAEb (jump below) */
7259 case 0x93: /* set-NBb/set-AEb (jump not below) */
7260 case 0x94: /* set-Zb/set-Eb (jump zero) */
7261 case 0x95: /* set-NZb/set-NEb (jump not zero) */
7262 case 0x96: /* set-BEb/set-NAb (jump below or equal) */
7263 case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
7264 case 0x98: /* set-Sb (jump negative) */
7265 case 0x99: /* set-Sb (jump not negative) */
7266 case 0x9A: /* set-P (jump parity even) */
7267 case 0x9B: /* set-NP (jump parity odd) */
7268 case 0x9C: /* set-Lb/set-NGEb (jump less) */
7269 case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
7270 case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
7271 case 0x9F: /* set-Gb/set-NLEb (jump greater) */
7272 t1 = newTemp(Ity_I8);
7273 assign( t1, unop(Iop_1Uto8,calculate_condition(opc-0x90)) );
7274 modrm = getIByte(delta);
7275 if (epartIsReg(modrm)) {
7276 delta++;
7277 putIReg(1, eregOfRM(modrm), mkexpr(t1));
7278 DIP("set%s %s\n", name_Condcode(opc-0x90),
7279 nameIReg(1,eregOfRM(modrm)));
7280 } else {
7281 vassert(0);
sewardjc9a65702004-07-07 16:32:57 +00007282//-- pair = disAMode ( cb, sorb, eip, dis_buf );
7283//-- t2 = LOW24(pair);
7284//-- eip += HI8(pair);
7285//-- uInstr1(cb, CC2VAL, 1, TempReg, t1);
7286//-- uCond(cb, (Condcode)(opc-0x90));
7287//-- uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
7288//-- uInstr2(cb, STORE, 1, TempReg, t1, TempReg, t2);
7289//-- DIP("set%s %s\n", VG_(name_UCondcode)(opc-0x90), dis_buf);
sewardj77b86be2004-07-11 13:28:24 +00007290 }
7291 break;
7292
sewardjc9a65702004-07-07 16:32:57 +00007293//-- /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
7294//--
7295//-- case 0xA4: /* SHLDv imm8,Gv,Ev */
7296//-- modrm = getUChar(eip);
7297//-- eip = dis_SHLRD_Gv_Ev (
7298//-- cb, sorb, eip, modrm, sz,
7299//-- Literal, getUChar(eip + lengthAMode(eip)),
7300//-- True );
7301//-- break;
7302//-- case 0xA5: /* SHLDv %cl,Gv,Ev */
7303//-- modrm = getUChar(eip);
7304//-- eip = dis_SHLRD_Gv_Ev (
7305//-- cb, sorb, eip, modrm, sz, ArchReg, R_CL, True );
7306//-- break;
7307//--
7308//-- case 0xAC: /* SHRDv imm8,Gv,Ev */
7309//-- modrm = getUChar(eip);
7310//-- eip = dis_SHLRD_Gv_Ev (
7311//-- cb, sorb, eip, modrm, sz,
7312//-- Literal, getUChar(eip + lengthAMode(eip)),
7313//-- False );
7314//-- break;
7315//-- case 0xAD: /* SHRDv %cl,Gv,Ev */
7316//-- modrm = getUChar(eip);
7317//-- eip = dis_SHLRD_Gv_Ev (
7318//-- cb, sorb, eip, modrm, sz, ArchReg, R_CL, False );
7319//-- break;
7320//--
7321//-- /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
7322//--
7323//-- case 0xC0: /* XADD Gb,Eb */
7324//-- eip = dis_xadd_G_E ( cb, sorb, 1, eip );
7325//-- break;
7326//-- case 0xC1: /* XADD Gv,Ev */
7327//-- eip = dis_xadd_G_E ( cb, sorb, sz, eip );
7328//-- break;
7329//--
7330//-- /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
7331//--
7332//-- case 0x0D: /* PREFETCH / PREFETCHW - 3Dnow!ery*/
7333//-- case 0x18: /* PREFETCHT0/PREFETCHT1/PREFETCHT2/PREFETCHNTA */
7334//--
7335//-- vg_assert(sz == 4);
7336//-- modrm = getUChar(eip);
7337//-- if (epartIsReg(modrm)) {
7338//-- goto decode_failure;
7339//-- }
7340//-- if (gregOfRM(modrm) > 3) {
7341//-- goto decode_failure;
7342//-- }
7343//-- eip += lengthAMode(eip);
7344//-- if (VG_(print_codegen)) {
7345//-- UChar* hintstr;
7346//-- if (opc == 0x0D) {
7347//-- switch (gregOfRM(modrm)) {
7348//-- case 0: hintstr = ""; break;
7349//-- case 1: hintstr = "w"; break;
7350//-- default: goto decode_failure;
7351//-- }
7352//-- }
7353//-- else {
7354//-- switch (gregOfRM(modrm)) {
7355//-- case 0: hintstr = "nta"; break;
7356//-- case 1: hintstr = "t0"; break;
7357//-- case 2: hintstr = "t1"; break;
7358//-- case 3: hintstr = "t2"; break;
7359//-- default: goto decode_failure;
7360//-- }
7361//-- }
7362//-- VG_(printf)("prefetch%s ...\n", hintstr);
7363//-- }
7364//-- break;
7365//--
7366//-- case 0x71: case 0x72: case 0x73: {
7367//-- /* (sz==4): PSLL/PSRA/PSRL mmxreg by imm8 */
7368//-- /* (sz==2): PSLL/PSRA/PSRL xmmreg by imm8 */
7369//-- UChar byte1, byte2, byte3, subopc, mmreg;
7370//-- vg_assert(sz == 4 || sz == 2);
7371//-- byte1 = opc; /* 0x71/72/73 */
7372//-- byte2 = getUChar(eip); eip++; /* amode / sub-opcode */
7373//-- byte3 = getUChar(eip); eip++; /* imm8 */
7374//-- mmreg = byte2 & 7;
7375//-- subopc = (byte2 >> 3) & 7;
7376//-- if (subopc == 2 || subopc == 6 || subopc == 4) {
7377//-- /* 2 == 010 == SRL, 6 == 110 == SLL, 4 == 100 == SRA */
7378//-- /* ok */
7379//-- } else
7380//-- if (sz == 2 && opc == 0x73 && (subopc == 7 || subopc == 3)) {
7381//-- /* 3 == PSRLDQ, 7 == PSLLDQ */
7382//-- /* This is allowable in SSE. Because sz==2 we fall thru to
7383//-- SSE5 below. */
7384//-- } else {
7385//-- eip -= (sz==2 ? 3 : 2);
7386//-- goto decode_failure;
7387//-- }
7388//-- if (sz == 4) {
7389//-- /* The leading 0x0F is implied for MMX*, so we don't
7390//-- include it. */
7391//-- uInstr2(cb, MMX3, 0,
7392//-- Lit16, (((UShort)byte1) << 8) | ((UShort)byte2),
7393//-- Lit16, ((UShort)byte3) );
7394//-- DIP("ps%s%s $%d, %s\n",
7395//-- ( subopc == 2 ? "rl"
7396//-- : subopc == 6 ? "ll"
7397//-- : subopc == 4 ? "ra"
7398//-- : "??"),
7399//-- nameMMXGran(opc & 3), (Int)byte3, nameMMXReg(mmreg) );
7400//-- } else {
7401//-- /* Whereas we have to include it for SSE. */
7402//-- uInstr3(cb, SSE5, 0,
7403//-- Lit16, (((UShort)0x66) << 8) | ((UShort)0x0F),
7404//-- Lit16, (((UShort)byte1) << 8) | ((UShort)byte2),
7405//-- Lit16, ((UShort)byte3) );
7406//-- DIP("ps%s%s $%d, %s\n",
7407//-- ( subopc == 2 ? "rl"
7408//-- : subopc == 6 ? "ll"
7409//-- : subopc == 4 ? "ra"
7410//-- : subopc == 3 ? "(PSRLDQ)"
7411//-- : subopc == 7 ? "(PSLLDQ)"
7412//-- : "??"),
7413//-- nameMMXGran(opc & 3), (Int)byte3, nameXMMReg(mmreg) );
7414//-- }
7415//-- break;
7416//-- }
7417//--
7418//-- case 0x77: /* EMMS */
7419//-- vg_assert(sz == 4);
7420//-- uInstr1(cb, MMX1, 0, Lit16, ((UShort)(opc)) );
7421//-- DIP("emms\n");
7422//-- break;
7423//--
7424//-- case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
7425//-- vg_assert(sz == 4);
7426//-- modrm = getUChar(eip);
7427//-- if (epartIsReg(modrm)) {
7428//-- eip++;
7429//-- t1 = newTemp(cb);
7430//-- uInstr2(cb, MMX2_ERegWr, 4,
7431//-- Lit16,
7432//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
7433//-- TempReg, t1 );
7434//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, eregOfRM(modrm));
7435//-- DIP("movd %s, %s\n",
7436//-- nameMMXReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
7437//-- } else {
7438//-- Int tmpa;
7439//-- pair = disAMode ( cb, sorb, eip, dis_buf );
7440//-- tmpa = LOW24(pair);
7441//-- eip += HI8(pair);
7442//-- uInstr2(cb, MMX2_MemWr, 4,
7443//-- Lit16,
7444//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
7445//-- TempReg, tmpa);
7446//-- DIP("movd %s, %s\n", nameMMXReg(gregOfRM(modrm)), dis_buf);
7447//-- }
7448//-- break;
7449//--
7450//-- case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
7451//-- vg_assert(sz == 4);
7452//-- modrm = getUChar(eip);
7453//-- if (epartIsReg(modrm)) {
7454//-- eip++;
7455//-- t1 = newTemp(cb);
7456//-- uInstr2(cb, GET, 4, ArchReg, eregOfRM(modrm), TempReg, t1);
7457//-- uInstr2(cb, MMX2_ERegRd, 4,
7458//-- Lit16,
7459//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
7460//-- TempReg, t1 );
7461//-- DIP("movd %s, %s\n",
7462//-- nameIReg(4,eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
7463//-- } else {
7464//-- Int tmpa;
7465//-- pair = disAMode ( cb, sorb, eip, dis_buf );
7466//-- tmpa = LOW24(pair);
7467//-- eip += HI8(pair);
7468//-- uInstr2(cb, MMX2_MemRd, 4,
7469//-- Lit16,
7470//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
7471//-- TempReg, tmpa);
7472//-- DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregOfRM(modrm)));
7473//-- }
7474//-- break;
7475//--
7476//-- case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
7477//-- vg_assert(sz == 4);
7478//-- modrm = getUChar(eip);
7479//-- if (epartIsReg(modrm)) {
7480//-- eip++;
7481//-- uInstr1(cb, MMX2, 0,
7482//-- Lit16,
7483//-- (((UShort)(opc)) << 8) | ((UShort)modrm) );
7484//-- DIP("movq %s, %s\n",
7485//-- nameMMXReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
7486//-- } else {
7487//-- Int tmpa;
7488//-- pair = disAMode ( cb, sorb, eip, dis_buf );
7489//-- tmpa = LOW24(pair);
7490//-- eip += HI8(pair);
7491//-- uInstr2(cb, MMX2_MemRd, 8,
7492//-- Lit16,
7493//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
7494//-- TempReg, tmpa);
7495//-- DIP("movq %s, %s\n",
7496//-- dis_buf, nameMMXReg(gregOfRM(modrm)));
7497//-- }
7498//-- break;
7499//--
7500//-- case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
7501//-- case 0xE7: /* MOVNTQ (src)mmxreg, (dst)mmxreg-or-mem */
7502//-- vg_assert(sz == 4);
7503//-- modrm = getUChar(eip);
7504//-- if (epartIsReg(modrm)) {
7505//-- eip++;
7506//-- uInstr1(cb, MMX2, 0,
7507//-- Lit16,
7508//-- (((UShort)(opc)) << 8) | ((UShort)modrm) );
7509//-- DIP("movq %s, %s\n",
7510//-- nameMMXReg(gregOfRM(modrm)), nameMMXReg(eregOfRM(modrm)));
7511//-- } else {
7512//-- Int tmpa;
7513//-- pair = disAMode ( cb, sorb, eip, dis_buf );
7514//-- tmpa = LOW24(pair);
7515//-- eip += HI8(pair);
7516//-- uInstr2(cb, MMX2_MemWr, 8,
7517//-- Lit16,
7518//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
7519//-- TempReg, tmpa);
7520//-- DIP("mov(nt)q %s, %s\n",
7521//-- nameMMXReg(gregOfRM(modrm)), dis_buf);
7522//-- }
7523//-- break;
7524//--
7525//-- case 0xFC: case 0xFD: case 0xFE:
7526//-- /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
7527//-- vg_assert(sz == 4);
7528//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "padd", True );
7529//-- break;
7530//--
7531//-- case 0xD4:
7532//-- /* PADDQ (src)mmxreg-or-mem, (dst)mmxreg */
7533//-- vg_assert(sz == 4);
7534//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "paddq", False );
7535//-- break;
7536//--
7537//-- case 0xEC: case 0xED:
7538//-- /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
7539//-- vg_assert(sz == 4);
7540//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "padds", True );
7541//-- break;
7542//--
7543//-- case 0xDC: case 0xDD:
7544//-- /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
7545//-- vg_assert(sz == 4);
7546//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "paddus", True );
7547//-- break;
7548//--
7549//-- case 0xF8: case 0xF9: case 0xFA: case 0xFB:
7550//-- /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
7551//-- vg_assert(sz == 4);
7552//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psub", True );
7553//-- break;
7554//--
7555//-- case 0xE8: case 0xE9:
7556//-- /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
7557//-- vg_assert(sz == 4);
7558//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psubs", True );
7559//-- break;
7560//--
7561//-- case 0xD8: case 0xD9:
7562//-- /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
7563//-- vg_assert(sz == 4);
7564//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psubus", True );
7565//-- break;
7566//--
7567//-- case 0xE4: /* PMULHUW (src)mmxreg-or-mem, (dst)mmxreg */
7568//-- vg_assert(sz == 4);
7569//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmulhuw", False );
7570//-- break;
7571//--
7572//-- case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
7573//-- vg_assert(sz == 4);
7574//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmulhw", False );
7575//-- break;
7576//--
7577//-- case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
7578//-- vg_assert(sz == 4);
7579//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmullw", False );
7580//-- break;
7581//--
7582//-- case 0xF4: /* PMULUDQ (src)mmxreg-or-mem, (dst)mmxreg */
7583//-- vg_assert(sz == 4);
7584//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmuludq", False );
7585//-- break;
7586//--
7587//-- case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
7588//-- vg_assert(sz == 4);
7589//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmaddwd", False );
7590//-- break;
7591//--
7592//-- case 0x74: case 0x75: case 0x76:
7593//-- /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
7594//-- vg_assert(sz == 4);
7595//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pcmpeq", True );
7596//-- break;
7597//--
7598//-- case 0x64: case 0x65: case 0x66:
7599//-- /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
7600//-- vg_assert(sz == 4);
7601//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pcmpgt", True );
7602//-- break;
7603//--
7604//-- case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
7605//-- vg_assert(sz == 4);
7606//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "packssdw", False );
7607//-- break;
7608//--
7609//-- case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
7610//-- vg_assert(sz == 4);
7611//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "packsswb", False );
7612//-- break;
7613//--
7614//-- case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
7615//-- vg_assert(sz == 4);
7616//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "packuswb", False );
7617//-- break;
7618//--
7619//-- case 0x68: case 0x69: case 0x6A:
7620//-- /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
7621//-- vg_assert(sz == 4);
7622//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "punpckh", True );
7623//-- break;
7624//--
7625//-- case 0x60: case 0x61: case 0x62:
7626//-- /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
7627//-- vg_assert(sz == 4);
7628//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "punpckl", True );
7629//-- break;
7630//--
7631//-- case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
7632//-- vg_assert(sz == 4);
7633//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pand", False );
7634//-- break;
7635//--
7636//-- case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
7637//-- vg_assert(sz == 4);
7638//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pandn", False );
7639//-- break;
7640//--
7641//-- case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
7642//-- vg_assert(sz == 4);
7643//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "por", False );
7644//-- break;
7645//--
7646//-- case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
7647//-- vg_assert(sz == 4);
7648//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pxor", False );
7649//-- break;
7650//--
7651//-- case 0xF1: case 0xF2: case 0xF3:
7652//-- /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
7653//-- vg_assert(sz == 4);
7654//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psll", True );
7655//-- break;
7656//--
7657//-- case 0xD1: case 0xD2: case 0xD3:
7658//-- /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
7659//-- vg_assert(sz == 4);
7660//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psrl", True );
7661//-- break;
7662//--
7663//-- case 0xE1: case 0xE2:
7664//-- /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
7665//-- vg_assert(sz == 4);
7666//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psra", True );
7667//-- break;
7668//--
7669//-- case 0xDA:
7670//-- /* PMINUB (src)mmxreg-or-mem, (dst)mmxreg */
7671//-- vg_assert(sz == 4);
7672//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pminub", False );
7673//-- break;
7674//--
7675//-- case 0xDE:
7676//-- /* PMAXUB (src)mmxreg-or-mem, (dst)mmxreg */
7677//-- vg_assert(sz == 4);
7678//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmaxub", False );
7679//-- break;
7680//--
7681//-- case 0xEA:
7682//-- /* PMINSW (src)mmxreg-or-mem, (dst)mmxreg */
7683//-- vg_assert(sz == 4);
7684//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pminsw", False );
7685//-- break;
7686//--
7687//-- case 0xEE:
7688//-- /* PMAXSW (src)mmxreg-or-mem, (dst)mmxreg */
7689//-- vg_assert(sz == 4);
7690//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmaxsw", False );
7691//-- break;
7692//--
7693//-- case 0xE0:
7694//-- /* PAVGB (src)mmxreg-or-mem, (dst)mmxreg */
7695//-- vg_assert(sz == 4);
7696//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pavgb", False );
7697//-- break;
7698//--
7699//-- case 0xE3:
7700//-- /* PAVGW (src)mmxreg-or-mem, (dst)mmxreg */
7701//-- vg_assert(sz == 4);
7702//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pavgw", False );
7703//-- break;
7704//--
7705//-- case 0xF6:
7706//-- /* PSADBW (src)mmxreg-or-mem, (dst)mmxreg */
7707//-- vg_assert(sz == 4);
7708//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psadbw", False );
7709//-- break;
7710//--
7711//-- case 0x70:
7712//-- /* PSHUFW imm8, (src)mmxreg-or-mem, (dst)mmxreg */
7713//-- vg_assert(sz == 4);
7714//-- eip = dis_MMXop_regmem_to_reg_Imm8 ( cb, sorb, eip, opc, "pshufw", False );
7715//-- break;
7716//--
7717//-- case 0xD7:
7718//-- /* PMOVMSKB (src)mmxreg, (dst)ireg */
7719//-- vg_assert(sz == 4);
7720//-- modrm = getUChar(eip);
7721//-- vg_assert(epartIsReg(modrm));
7722//-- t1 = newTemp(cb);
7723//-- uInstr3(cb, SSE2g_RegWr, 4,
7724//-- Lit16, (((UShort)(0x0F)) << 8) | (UShort)(opc),
7725//-- Lit16, (UShort)modrm,
7726//-- TempReg, t1 );
7727//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
7728//-- DIP("pmovmskb %s, %s\n",
7729//-- nameMMXReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)));
7730//-- eip++;
7731//-- break;
7732//--
7733//-- case 0xC5:
7734//-- /* PEXTRW (src)mmxreg, (dst)ireg */
7735//-- vg_assert(sz == 4);
7736//-- t1 = newTemp(cb);
7737//-- modrm = getUChar(eip); eip++;
7738//-- abyte = getUChar(eip); eip++;
7739//-- vg_assert(epartIsReg(modrm));
7740//-- uInstr3(cb, SSE2g1_RegWr, 4,
7741//-- Lit16, (((UShort)(0x0F)) << 8) | (UShort)(opc),
7742//-- Lit16, (UShort)modrm,
7743//-- TempReg, t1 );
7744//-- uLiteral(cb, abyte);
7745//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
7746//-- DIP("pextrw %s, %d, %s\n",
7747//-- nameMMXReg(eregOfRM(modrm)), (Int)abyte,
7748//-- nameIReg(4, gregOfRM(modrm)));
7749//-- break;
7750//--
7751//-- case 0xC4:
7752//-- /* PINSRW (src)ireg, (dst)mmxreg */
7753//-- vg_assert(sz == 4);
7754//-- t1 = newTemp(cb);
7755//-- modrm = getUChar(eip); eip++;
7756//-- abyte = getUChar(eip); eip++;
7757//-- vg_assert(epartIsReg(modrm));
7758//-- uInstr2(cb, GET, 2, ArchReg, eregOfRM(modrm), TempReg, t1);
7759//-- uInstr3(cb, SSE2e1_RegRd, 2,
7760//-- Lit16, (((UShort)(0x0F)) << 8) | (UShort)(opc),
7761//-- Lit16, (UShort)modrm,
7762//-- TempReg, t1 );
7763//-- uLiteral(cb, abyte);
7764//-- DIP("pinsrw %s, %d, %s\n", nameIReg(2, eregOfRM(modrm)),
7765//-- (Int)abyte, nameMMXReg(gregOfRM(modrm)));
7766//-- break;
7767//--
7768//-- case 0xA1: /* POP %FS */
7769//-- dis_pop_segreg( cb, R_FS, sz ); break;
7770//-- case 0xA9: /* POP %GS */
7771//-- dis_pop_segreg( cb, R_GS, sz ); break;
7772//--
7773//-- case 0xA0: /* PUSH %FS */
7774//-- dis_push_segreg( cb, R_FS, sz ); break;
7775//-- case 0xA8: /* PUSH %GS */
7776//-- dis_push_segreg( cb, R_GS, sz ); break;
sewardje87b4842004-07-10 12:23:30 +00007777
7778 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
7779
7780 default:
7781 goto decode_failure;
7782 } /* switch (opc) for the 2-byte opcodes */
7783 goto decode_success;
7784 } /* case 0x0F: of primary opcode */
sewardjc9a65702004-07-07 16:32:57 +00007785
7786 /* ------------------------ ??? ------------------------ */
7787
7788 default:
sewardje87b4842004-07-10 12:23:30 +00007789 decode_failure:
sewardjc9a65702004-07-07 16:32:57 +00007790 /* All decode failures end up here. */
7791 vex_printf("disInstr(x86): unhandled instruction bytes: "
7792 "0x%x 0x%x 0x%x 0x%x\n",
7793 (Int)getIByte(delta_start+0),
7794 (Int)getIByte(delta_start+1),
7795 (Int)getIByte(delta_start+2),
7796 (Int)getIByte(delta_start+3) );
7797 vpanic("x86toIR: unimplemented insn");
7798 /* Print address of failing instruction. */
7799 //VG_(describe_eip)((Addr)eip_start, loc_buf, M_VG_ERRTXT);
7800 //VG_(printf)(" at %s\n", loc_buf);
7801
7802 //uInstr0(cb, CALLM_S, 0);
7803 //uInstr1(cb, CALLM, 0, Lit16,
7804 // VGOFF_(helper_undefined_instruction));
7805 //uInstr0(cb, CALLM_E, 0);
7806
7807 /* just because everything else insists the last instruction of
7808 a BB is a jmp */
7809 //jmp_lit(cb, eip);
7810 //*isEnd = True;
7811 //break;
7812 //return eip;
7813
7814 } /* switch (opc) for the main (primary) opcode switch. */
7815
sewardje87b4842004-07-10 12:23:30 +00007816 decode_success:
sewardjc9a65702004-07-07 16:32:57 +00007817 /* All decode successes end up here. */
7818 DIP("\n");
7819 if (first_stmt == NULL)
7820 first_stmt = irbb->stmts;
7821 else
7822 first_stmt = first_stmt->link;
7823 while (True) {
7824 if (!first_stmt)
7825 break;
7826 vex_printf(" ");
7827 ppIRStmt(first_stmt);
sewardjd1061ab2004-07-08 01:45:30 +00007828 DIP("\n");
sewardjc9a65702004-07-07 16:32:57 +00007829 if (first_stmt == last_stmt)
7830 break;
7831 first_stmt = first_stmt->link;
7832 }
sewardjd1061ab2004-07-08 01:45:30 +00007833 if (*isEnd) {
7834 vassert(irbb->next != NULL);
7835 vex_printf(" ");
7836 ppIRNext(irbb->next);
7837 DIP("\n");
7838 }
sewardjc9a65702004-07-07 16:32:57 +00007839 //for (; first_uinstr < cb->used; first_uinstr++) {
7840 // Bool sane = VG_(saneUInstr)(True, True, &cb->instrs[first_uinstr]);
7841 // if (!sane)
7842 // VG_(up_UInstr)(first_uinstr, &cb->instrs[first_uinstr]);
7843 // else if (VG_(print_codegen))
7844 // VG_(pp_UInstr)(first_uinstr, &cb->instrs[first_uinstr]);
7845 // vg_assert(sane);
7846 // }
7847 return delta;
7848}
7849
7850
7851/* Disassemble a complete basic block, starting at eip, and dumping
7852 the ucode into cb. Returns the size, in bytes, of the basic
7853 block. */
sewardj41f43bc2004-07-08 14:23:22 +00007854IRBB* bbToIR_X86Instr ( UChar* x86code,
sewardjc9a65702004-07-07 16:32:57 +00007855 Addr64 eip,
7856 Int* guest_bytes_read,
7857 Bool (*byte_accessible)(Addr64),
7858 Bool host_bigendian )
7859{
7860 UInt delta;
7861 Int n_instrs;
7862 Bool isEnd;
7863
7864 /* Set up globals. */
7865 host_is_bigendian = host_bigendian;
7866 print_codegen = (vex_verbosity >= 1);
7867 guest_code = x86code;
7868 guest_eip = (Addr32)eip;
7869 irbb = mkIRBB( newIRTypeEnv(), NULL, NULL );
7870 last_stmt = NULL;
7871 next_irtemp = (IRTemp)0;
7872
7873 vassert((eip >> 32) == 0);
7874
7875 DIP("Original x86 code to IR:\n\n");
7876
7877 /* Delta keeps track of how far along the x86code array we
7878 have so far gone. */
7879 isEnd = False;
7880 delta = 0;
7881 n_instrs = 0;
7882 while (True) {
7883 if (isEnd) break;
7884 vassert(n_instrs < vex_guest_insns_per_bb);
7885 delta = disInstr ( delta, &isEnd );
7886 n_instrs++;
7887 DIP("\n");
7888 }
7889
sewardjd1061ab2004-07-08 01:45:30 +00007890 *guest_bytes_read = delta;
sewardjc9a65702004-07-07 16:32:57 +00007891 return irbb;
7892}
7893
7894#undef DIP
7895#undef DIS
7896
7897/*--------------------------------------------------------------------*/
7898/*--- end vg_to_ucode.c ---*/
7899/*--------------------------------------------------------------------*/