blob: a2fb1ee6baf9949f98bc190bbce843c9e8190a47 [file] [log] [blame]
sewardjc9a65702004-07-07 16:32:57 +00001
2/*--------------------------------------------------------------------*/
3/*--- ---*/
sewardjc0ee2ed2004-07-27 10:29:41 +00004/*--- This file (guest-x86/toIR.c) is ---*/
sewardjc9a65702004-07-07 16:32:57 +00005/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/
6/*--- ---*/
7/*--------------------------------------------------------------------*/
8
sewardj77b86be2004-07-11 13:28:24 +00009/* TODO:
sewardj1f40a0a2004-07-21 12:28:07 +000010 SBB reg with itself
sewardj940e8c92004-07-11 16:53:24 +000011 is Iop_Neg* used?
sewardj1f40a0a2004-07-21 12:28:07 +000012 MOVAPS fix (vg_to_ucode rev 1.143)
sewardj458a6f82004-08-25 12:46:02 +000013 check flag settings for cmpxchg
sewardje5427e82004-09-11 19:43:51 +000014 check 16/8 bit div/idiv
sewardj883b00b2004-09-11 09:30:24 +000015 FUCOMI(P): what happens to A and S flags? Currently are forced
16 to zero.
sewardj3f61ddb2004-10-16 20:51:05 +000017
18 Limitations:
19 * no FP exceptions, except for handling stack over/underflow
20 * FP rounding mode observed only for float->int conversions
21 * FP sin/cos/tan/sincos: C2 flag is always cleared. IOW the
22 simulation claims the argument is in-range (-2^63 <= arg <= 2^63)
23 even when it isn't.
sewardje05c42c2004-07-08 20:25:10 +000024*/
25
sewardjc9a65702004-07-07 16:32:57 +000026/* Translates x86 code to IR. */
27
28#include "libvex_basictypes.h"
29#include "libvex_ir.h"
sewardje87b4842004-07-10 12:23:30 +000030#include "libvex.h"
sewardjc0ee2ed2004-07-27 10:29:41 +000031
32#include "main/vex_util.h"
33#include "main/vex_globals.h"
34#include "guest-x86/gdefs.h"
sewardjc9a65702004-07-07 16:32:57 +000035
36
37/*------------------------------------------------------------*/
38/*--- Globals ---*/
39/*------------------------------------------------------------*/
40
41/* These are set at the start of the translation of a BB, so
42 that we don't have to pass them around endlessly. */
43
44/* We need to know this to do sub-register accesses correctly. */
45/* CONST */
46static Bool host_is_bigendian;
47
48/* Are we being verbose? */
49/* CONST */
50static Bool print_codegen;
51
52/* Pointer to the guest code area. */
53/* CONST */
54static UChar* guest_code;
55
56/* The guest address corresponding to guest_code[0]. */
57/* CONST */
58static Addr32 guest_eip;
59
sewardjd7cb8532004-08-17 23:59:23 +000060/* The IRBB* into which we're generating code. */
sewardjc9a65702004-07-07 16:32:57 +000061static IRBB* irbb;
62
sewardjc9a65702004-07-07 16:32:57 +000063
64/* Add a statement to the list held by "irbb". */
sewardjd7cb8532004-08-17 23:59:23 +000065static void stmt ( IRStmt* st )
sewardjc9a65702004-07-07 16:32:57 +000066{
sewardjd7cb8532004-08-17 23:59:23 +000067 addStmtToIRBB( irbb, st );
sewardjc9a65702004-07-07 16:32:57 +000068}
69
70/* Generate a new temporary of the given type. */
71static IRTemp newTemp ( IRType ty )
72{
sewardj6d2638e2004-07-15 09:38:27 +000073 vassert(isPlausibleType(ty));
sewardje539a402004-07-14 18:24:17 +000074 return newIRTemp( irbb->tyenv, ty );
sewardjc9a65702004-07-07 16:32:57 +000075}
76
sewardjc9a65702004-07-07 16:32:57 +000077/* Bomb out if we can't handle something. */
sewardjd1061ab2004-07-08 01:45:30 +000078__attribute__ ((noreturn))
sewardjc9a65702004-07-07 16:32:57 +000079static void unimplemented ( Char* str )
80{
81 vex_printf("x86toIR: unimplemented feature\n");
82 vpanic(str);
83}
84
85
86/*------------------------------------------------------------*/
87/*--- Debugging output ---*/
88/*------------------------------------------------------------*/
89
90#define DIP(format, args...) \
91 if (print_codegen) \
92 vex_printf(format, ## args)
93
94#define DIS(buf, format, args...) \
95 if (print_codegen) \
96 vex_sprintf(buf, format, ## args)
97
98
99/*------------------------------------------------------------*/
100/*--- Helper bits and pieces for deconstructing the ---*/
101/*--- x86 insn stream. ---*/
102/*------------------------------------------------------------*/
103
sewardjd1061ab2004-07-08 01:45:30 +0000104/* This is the Intel register encoding -- integer regs. */
105#define R_EAX 0
106#define R_ECX 1
107#define R_EDX 2
108#define R_EBX 3
109#define R_ESP 4
110#define R_EBP 5
111#define R_ESI 6
112#define R_EDI 7
113
sewardj4e82db72004-10-16 11:32:15 +0000114#define R_AL (0+R_EAX)
115#define R_AH (4+R_EAX)
116
sewardjd1061ab2004-07-08 01:45:30 +0000117
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);
sewardjeeb9ef82004-07-15 12:39:03 +0000267 stmt( IRStmt_Put(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
sewardj41f43bc2004-07-08 14:23:22 +0000332 || op8 == Iop_Mul8
333 || op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
sewardjc22a6fd2004-07-29 23:41:47 +0000334 || op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8
sewardje90ad6a2004-07-10 19:02:10 +0000335 || op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8
sewardj41f43bc2004-07-08 14:23:22 +0000336 || op8 == Iop_Not8 || op8 == Iop_Neg8 );
sewardje05c42c2004-07-08 20:25:10 +0000337 adj = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
338 return adj + op8;
sewardj41f43bc2004-07-08 14:23:22 +0000339}
340
sewardj9334b0f2004-07-10 22:43:54 +0000341static IROp mkWidenOp ( Int szSmall, Int szBig, Bool signd )
sewardj41f43bc2004-07-08 14:23:22 +0000342{
sewardj9334b0f2004-07-10 22:43:54 +0000343 if (szSmall == 1 && szBig == 4) {
344 return signd ? Iop_8Sto32 : Iop_8Uto32;
sewardj41f43bc2004-07-08 14:23:22 +0000345 }
sewardj9334b0f2004-07-10 22:43:54 +0000346 if (szSmall == 1 && szBig == 2) {
347 return signd ? Iop_8Sto16 : Iop_8Uto16;
348 }
349 if (szSmall == 2 && szBig == 4) {
350 return signd ? Iop_16Sto32 : Iop_16Uto32;
351 }
352 vpanic("mkWidenOp(x86)");
sewardj41f43bc2004-07-08 14:23:22 +0000353}
354
355
356/*------------------------------------------------------------*/
357/*--- Helpers for %eflags. ---*/
358/*------------------------------------------------------------*/
359
sewardj0611d802004-07-11 02:37:54 +0000360/* -------------- Evaluating the flags-thunk. -------------- */
sewardjc9a65702004-07-07 16:32:57 +0000361
sewardje87b4842004-07-10 12:23:30 +0000362/* Build IR to calculate all the eflags from stored
sewardj77b86be2004-07-11 13:28:24 +0000363 CC_OP/CC_SRC/CC_DST. Returns an expression :: Ity_I32. */
sewardje87b4842004-07-10 12:23:30 +0000364static IRExpr* mk_calculate_eflags_all ( void )
365{
366 IRExpr** args = LibVEX_Alloc(4 * sizeof(IRExpr*));
367 args[0] = IRExpr_Get(OFFB_CC_OP, Ity_I32);
368 args[1] = IRExpr_Get(OFFB_CC_SRC, Ity_I32);
369 args[2] = IRExpr_Get(OFFB_CC_DST, Ity_I32);
370 args[3] = NULL;
371 return IRExpr_CCall("calculate_eflags_all", Ity_I32, args);
372}
373
sewardj84ff0652004-08-23 16:16:08 +0000374/* Build IR to calculate just the carry flag from stored
sewardj77b86be2004-07-11 13:28:24 +0000375 CC_OP/CC_SRC/CC_DST. Returns an expression :: Ity_I32. */
sewardje87b4842004-07-10 12:23:30 +0000376static IRExpr* mk_calculate_eflags_c ( void )
377{
378 IRExpr** args = LibVEX_Alloc(4 * sizeof(IRExpr*));
379 args[0] = IRExpr_Get(OFFB_CC_OP, Ity_I32);
380 args[1] = IRExpr_Get(OFFB_CC_SRC, Ity_I32);
381 args[2] = IRExpr_Get(OFFB_CC_DST, Ity_I32);
382 args[3] = NULL;
383 return IRExpr_CCall("calculate_eflags_c", Ity_I32, args);
384}
385
sewardj84ff0652004-08-23 16:16:08 +0000386/* Build IR to calculate some particular condition from stored
387 CC_OP/CC_SRC/CC_DST. Returns an expression :: Ity_Bit. */
388static IRExpr* calculate_condition ( Condcode cond )
389{
390 IRExpr** args = LibVEX_Alloc(5 * sizeof(IRExpr*));
391 args[0] = mkU32(cond);
392 args[1] = IRExpr_Get(OFFB_CC_OP, Ity_I32);
393 args[2] = IRExpr_Get(OFFB_CC_SRC, Ity_I32);
394 args[3] = IRExpr_Get(OFFB_CC_DST, Ity_I32);
395 args[4] = NULL;
396 return unop(Iop_32to1,
397 IRExpr_CCall("calculate_condition", Ity_I32, args));
398}
399
sewardje87b4842004-07-10 12:23:30 +0000400
sewardj0611d802004-07-11 02:37:54 +0000401/* -------------- Building the flags-thunk. -------------- */
402
sewardjb9c5cf62004-08-24 15:10:38 +0000403/* The machinery in this section builds the flag-thunk following a
404 flag-setting operation. Hence the various setFlags_* functions.
405 Note, in reality setFlags_ADD_SUB and setFlags_MUL are pretty much
406 the same -- they just store the two operands.
407*/
408
409static Bool isAddSub ( IROp op8 )
410{
411 return op8 == Iop_Add8 || op8 == Iop_Sub8;
412}
sewardj0611d802004-07-11 02:37:54 +0000413
sewardja2384712004-07-29 14:36:40 +0000414/* U-widen 8/16/32 bit int expr to 32. */
sewardjc22a6fd2004-07-29 23:41:47 +0000415static IRExpr* widenUto32 ( IRExpr* e )
sewardj443cd9d2004-07-18 23:06:45 +0000416{
417 switch (typeOfIRExpr(irbb->tyenv,e)) {
418 case Ity_I32: return e;
419 case Ity_I16: return unop(Iop_16Uto32,e);
420 case Ity_I8: return unop(Iop_8Uto32,e);
421 default: vpanic("widenUto32");
422 }
423}
424
sewardjc22a6fd2004-07-29 23:41:47 +0000425/* S-widen 8/16/32 bit int expr to 32. */
426static IRExpr* widenSto32 ( IRExpr* e )
427{
428 switch (typeOfIRExpr(irbb->tyenv,e)) {
429 case Ity_I32: return e;
430 case Ity_I16: return unop(Iop_16Sto32,e);
431 case Ity_I8: return unop(Iop_8Sto32,e);
432 default: vpanic("widenSto32");
433 }
434}
435
sewardja2384712004-07-29 14:36:40 +0000436/* Narrow 8/16/32 bit int expr to 8/16/32. Clearly only some
437 of these combinations make sense. */
438static IRExpr* narrowTo ( IRType dst_ty, IRExpr* e )
439{
440 IRType src_ty = typeOfIRExpr(irbb->tyenv,e);
441 if (src_ty == dst_ty)
442 return e;
443 if (src_ty == Ity_I32 && dst_ty == Ity_I16)
444 return unop(Iop_32to16, e);
445 if (src_ty == Ity_I32 && dst_ty == Ity_I8)
446 return unop(Iop_32to8, e);
447
448 vex_printf("\nsrc, dst tys are: ");
449 ppIRType(src_ty);
450 vex_printf(", ");
451 ppIRType(dst_ty);
452 vex_printf("\n");
453 vpanic("narrowTo(x86)");
454}
455
sewardj443cd9d2004-07-18 23:06:45 +0000456
sewardjb9c5cf62004-08-24 15:10:38 +0000457/* This is for add/sub/adc/sbb, where (like multiply) we simply store
458 the two arguments. Note, the args are reversed, so if op8
459 indicates subtract, then the value the program is trying to compute
460 is src1 - src2. */
sewardj0611d802004-07-11 02:37:54 +0000461
sewardjb9c5cf62004-08-24 15:10:38 +0000462static void setFlags_ADD_SUB ( IROp op8,
463 IRTemp src2,
464 IRTemp src1,
465 IRType ty )
sewardj0611d802004-07-11 02:37:54 +0000466{
sewardjb9c5cf62004-08-24 15:10:38 +0000467 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
468
469 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
470
471 switch (op8) {
472 case Iop_Add8: ccOp += CC_OP_ADDB; break;
473 case Iop_Sub8: ccOp += CC_OP_SUBB; break;
474 default: ppIROp(op8);
475 vpanic("setFlags_ADD_SUB(x86)");
476 }
477 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
478 stmt( IRStmt_Put( OFFB_CC_SRC, widenUto32(mkexpr(src2))) );
479 stmt( IRStmt_Put( OFFB_CC_DST, widenUto32(mkexpr(src1))) );
480}
481
482
483/* For and/or/xor, only the result is important. However, put zero in
484 CC_SRC to keep memcheck happy. */
485
486static void setFlags_LOGIC ( IROp op8,
487 IRTemp dst1,
488 IRType ty )
489{
490 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
sewardj0611d802004-07-11 02:37:54 +0000491
492 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
493
494 switch (op8) {
495 case Iop_Or8:
496 case Iop_And8:
sewardjb9c5cf62004-08-24 15:10:38 +0000497 case Iop_Xor8: ccOp += CC_OP_LOGICB; break;
sewardj0611d802004-07-11 02:37:54 +0000498 default: ppIROp(op8);
sewardjb9c5cf62004-08-24 15:10:38 +0000499 vpanic("setFlags_LOGIC(x86)");
sewardj0611d802004-07-11 02:37:54 +0000500 }
sewardjeeb9ef82004-07-15 12:39:03 +0000501 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
sewardjb9c5cf62004-08-24 15:10:38 +0000502 stmt( IRStmt_Put( OFFB_CC_SRC, mkU32(0)) );
sewardjc22a6fd2004-07-29 23:41:47 +0000503 stmt( IRStmt_Put( OFFB_CC_DST, widenUto32(mkexpr(dst1))) );
sewardj0611d802004-07-11 02:37:54 +0000504}
505
506
sewardjb9c5cf62004-08-24 15:10:38 +0000507/* For all shift and rotate cases, store the result value and the
508 result except shifted or rotated one bit less ("undershifted",
509 hence US). And then only when the guard is non-zero. */
sewardj0611d802004-07-11 02:37:54 +0000510
sewardjc22a6fd2004-07-29 23:41:47 +0000511static void setFlags_DSTus_DST1 ( IROp op32,
sewardj0611d802004-07-11 02:37:54 +0000512 IRTemp dstUS,
513 IRTemp dst1,
514 IRType ty,
sewardja06e5562004-07-14 13:18:05 +0000515 IRTemp guard )
sewardj0611d802004-07-11 02:37:54 +0000516{
sewardjc22a6fd2004-07-29 23:41:47 +0000517 Int ccOp = ty==Ity_I8 ? 2 : (ty==Ity_I16 ? 1 : 0);
sewardj0611d802004-07-11 02:37:54 +0000518
519 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
520 vassert(guard);
521
sewardjc22a6fd2004-07-29 23:41:47 +0000522 switch (op32) {
523 case Iop_Shr32:
524 case Iop_Sar32: ccOp = CC_OP_SARL - ccOp; break;
525 case Iop_Shl32: ccOp = CC_OP_SHLL - ccOp; break;
526 default: ppIROp(op32);
527 vpanic("setFlags_DSTus_DST1(x86)");
sewardj0611d802004-07-11 02:37:54 +0000528 }
529
530 /* CC_SRC = undershifted %d after, CC_DST = %d afterwards */
sewardjeeb9ef82004-07-15 12:39:03 +0000531 stmt( IRStmt_Put( OFFB_CC_OP,
sewardj4042c7e2004-07-18 01:28:30 +0000532 IRExpr_Mux0X( mkexpr(guard),
533 IRExpr_Get(OFFB_CC_OP,Ity_I32),
534 mkU32(ccOp))) );
sewardjeeb9ef82004-07-15 12:39:03 +0000535 stmt( IRStmt_Put( OFFB_CC_SRC,
sewardj4042c7e2004-07-18 01:28:30 +0000536 IRExpr_Mux0X( mkexpr(guard),
537 IRExpr_Get(OFFB_CC_SRC,Ity_I32),
sewardjc22a6fd2004-07-29 23:41:47 +0000538 widenUto32(mkexpr(dstUS)))) );
sewardjeeb9ef82004-07-15 12:39:03 +0000539 stmt( IRStmt_Put( OFFB_CC_DST,
sewardj4042c7e2004-07-18 01:28:30 +0000540 IRExpr_Mux0X( mkexpr(guard),
541 IRExpr_Get(OFFB_CC_DST,Ity_I32),
sewardjc22a6fd2004-07-29 23:41:47 +0000542 widenUto32(mkexpr(dst1)))) );
sewardj0611d802004-07-11 02:37:54 +0000543}
544
545
546/* For the inc/dec case, we store the result value and the former
547 value of the carry flag, which unfortunately we have to compute. */
548
549static void setFlags_INC_DEC ( Bool inc, IRTemp dst, IRType ty )
550{
sewardjeeb9ef82004-07-15 12:39:03 +0000551 Int ccOp = inc ? CC_OP_INCB : CC_OP_DECB;
sewardj0611d802004-07-11 02:37:54 +0000552
553 ccOp += ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
554 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
555
556 /* This has to come first, because calculating the C flag
557 may require reading all three OFFB_CC fields. */
sewardjeeb9ef82004-07-15 12:39:03 +0000558 stmt( IRStmt_Put( OFFB_CC_SRC, mk_calculate_eflags_c()) );
559 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
560 stmt( IRStmt_Put( OFFB_CC_DST, mkexpr(dst)) );
sewardj0611d802004-07-11 02:37:54 +0000561}
562
563
sewardjcf780b42004-07-13 18:42:17 +0000564/* For multiplies, just remember the two operands and a
565 description of what kind of multiply. */
566
567static
568void setFlags_MUL ( IRType ty, IRTemp src1, IRTemp src2, UInt base_op )
569{
570 switch (ty) {
571 case Ity_I8:
sewardjeeb9ef82004-07-15 12:39:03 +0000572 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+0) ) );
573 stmt( IRStmt_Put( OFFB_CC_SRC, unop(Iop_8Uto32,mkexpr(src1)) ) );
574 stmt( IRStmt_Put( OFFB_CC_DST, unop(Iop_8Uto32,mkexpr(src2)) ) );
sewardjcf780b42004-07-13 18:42:17 +0000575 break;
576 case Ity_I16:
sewardjeeb9ef82004-07-15 12:39:03 +0000577 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+1) ) );
578 stmt( IRStmt_Put( OFFB_CC_SRC, unop(Iop_16Uto32,mkexpr(src1)) ) );
579 stmt( IRStmt_Put( OFFB_CC_DST, unop(Iop_16Uto32,mkexpr(src2)) ) );
sewardjcf780b42004-07-13 18:42:17 +0000580 break;
581 case Ity_I32:
sewardjeeb9ef82004-07-15 12:39:03 +0000582 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+2) ) );
583 stmt( IRStmt_Put( OFFB_CC_SRC, mkexpr(src1) ) );
584 stmt( IRStmt_Put( OFFB_CC_DST, mkexpr(src2) ) );
sewardjcf780b42004-07-13 18:42:17 +0000585 break;
586 default:
587 vpanic("setFlags_MUL(x86)");
588 }
589}
590
591
sewardj3af115f2004-07-14 02:46:52 +0000592/* -------------- Condition codes. -------------- */
593
sewardje87b4842004-07-10 12:23:30 +0000594/* Condition codes, using the Intel encoding. */
sewardj0611d802004-07-11 02:37:54 +0000595
sewardje87b4842004-07-10 12:23:30 +0000596static Char* name_Condcode ( Condcode cond )
597{
598 switch (cond) {
599 case CondO: return "o";
600 case CondNO: return "no";
601 case CondB: return "b";
602 case CondNB: return "nb";
603 case CondZ: return "z";
604 case CondNZ: return "nz";
605 case CondBE: return "be";
606 case CondNBE: return "nbe";
607 case CondS: return "s";
608 case CondNS: return "ns";
609 case CondP: return "p";
610 case CondNP: return "np";
611 case CondL: return "l";
612 case CondNL: return "nl";
613 case CondLE: return "le";
614 case CondNLE: return "nle";
sewardj64e1d652004-07-12 14:00:46 +0000615 case CondAlways: return "ALWAYS";
sewardje87b4842004-07-10 12:23:30 +0000616 default: vpanic("name_Condcode");
617 }
618}
619
620static Condcode positiveIse_Condcode ( Condcode cond,
621 Bool* needInvert )
622{
623 vassert(cond >= CondO && cond <= CondNLE);
624 if (cond & 1) {
625 *needInvert = True;
626 return cond-1;
627 } else {
628 *needInvert = False;
629 return cond;
630 }
631}
632
633
sewardj3af115f2004-07-14 02:46:52 +0000634/* -------------- Helpers for ADD/SUB with carry. -------------- */
635
636/* Given ta1, ta2 and tdst, compute tdst = ADC(ta1,ta2) and set flags
637 appropriately. Depends critically on the relative ordering of
638 CC_OP_ADD{B,W,L} vs CC_OP_ADC{B,W,L}.
639*/
640static void helper_ADC ( Int sz,
641 IRTemp tdst, IRTemp ta1, IRTemp ta2 )
642{
643 UInt thunkOp;
644 IRExpr* thunkExpr;
645 IRType ty = szToITy(sz);
646 IRTemp oldc = newTemp(Ity_I32);
647 IROp plus = mkSizedOp(ty,Iop_Add8);
648
649 /* oldc = old carry flag, 0 or 1 */
sewardja2384712004-07-29 14:36:40 +0000650 assign( oldc, binop(Iop_And32,
sewardj3af115f2004-07-14 02:46:52 +0000651 mk_calculate_eflags_c(),
sewardja2384712004-07-29 14:36:40 +0000652 mkU32(1)) );
sewardj3af115f2004-07-14 02:46:52 +0000653
sewardja2384712004-07-29 14:36:40 +0000654 assign(tdst, binop(plus,
655 binop(plus,mkexpr(ta1),mkexpr(ta2)),
656 narrowTo(ty,mkexpr(oldc))));
657
658 vassert(sz == 1 || sz == 2 || sz == 4);
659 thunkOp = sz==4 ? CC_OP_ADDL : (sz==2 ? CC_OP_ADDW : CC_OP_ADDB);
sewardj3af115f2004-07-14 02:46:52 +0000660
661 /* This dynamically calculates the thunk op number.
662 3 * the old carry flag is added, so (eg) it gives
663 CC_OP_ADDL if old carry was zero, and CC_OP_ADCL if
664 old carry was one. */
665 thunkExpr = binop(Iop_Add32,
666 mkU32(thunkOp),
667 binop(Iop_Mul32, mkexpr(oldc), mkU32(3)));
668
sewardjeeb9ef82004-07-15 12:39:03 +0000669 stmt( IRStmt_Put( OFFB_CC_OP, thunkExpr ) );
670 stmt( IRStmt_Put( OFFB_CC_SRC, mkexpr(ta2) ) );
sewardjb9c5cf62004-08-24 15:10:38 +0000671 stmt( IRStmt_Put( OFFB_CC_DST, mkexpr(ta1) ) );
sewardj3af115f2004-07-14 02:46:52 +0000672}
673
674
sewardjcaca9d02004-07-28 07:11:32 +0000675/* Given ta1, ta2 and tdst, compute tdst = SBB(ta1,ta2) and set flags
676 appropriately. Depends critically on the relative ordering of
677 CC_OP_SUB{B,W,L} vs CC_OP_SBB{B,W,L}.
678*/
679static void helper_SBB ( Int sz,
680 IRTemp tdst, IRTemp ta1, IRTemp ta2 )
681{
682 UInt thunkOp;
683 IRExpr* thunkExpr;
684 IRType ty = szToITy(sz);
685 IRTemp oldc = newTemp(Ity_I32);
686 IROp minus = mkSizedOp(ty,Iop_Sub8);
687
688 /* oldc = old carry flag, 0 or 1 */
sewardja2384712004-07-29 14:36:40 +0000689 assign( oldc, binop(Iop_And32,
sewardjcaca9d02004-07-28 07:11:32 +0000690 mk_calculate_eflags_c(),
sewardja2384712004-07-29 14:36:40 +0000691 mkU32(1)) );
sewardjcaca9d02004-07-28 07:11:32 +0000692
sewardja2384712004-07-29 14:36:40 +0000693 assign(tdst, binop(minus,
694 binop(minus,mkexpr(ta1),mkexpr(ta2)),
695 narrowTo(ty,mkexpr(oldc))));
696
697 vassert(sz == 1 || sz == 2 || sz == 4);
698 thunkOp = sz==4 ? CC_OP_SUBL : (sz==2 ? CC_OP_SUBW : CC_OP_SUBB);
sewardjcaca9d02004-07-28 07:11:32 +0000699
700 /* This dynamically calculates the thunk op number.
701 3 * the old carry flag is added, so (eg) it gives
702 CC_OP_SUBL if old carry was zero, and CC_OP_SBBL if
703 old carry was one. */
704 thunkExpr = binop(Iop_Add32,
705 mkU32(thunkOp),
706 binop(Iop_Mul32, mkexpr(oldc), mkU32(3)));
707
708 stmt( IRStmt_Put( OFFB_CC_OP, thunkExpr ) );
709 stmt( IRStmt_Put( OFFB_CC_SRC, mkexpr(ta2) ) );
sewardjb9c5cf62004-08-24 15:10:38 +0000710 stmt( IRStmt_Put( OFFB_CC_DST, mkexpr(ta1) ) );
sewardjcaca9d02004-07-28 07:11:32 +0000711}
712
713
sewardjc9a65702004-07-07 16:32:57 +0000714//-- /*------------------------------------------------------------*/
715//-- /*--- CPU feature set stuff ---*/
716//-- /*--- This is a little out of place here, but it will do ---*/
717//-- /*--- for now. ---*/
718//-- /*------------------------------------------------------------*/
719//--
sewardje87b4842004-07-10 12:23:30 +0000720//-- #define VG_CPU_VENDOR_GENERIC 0
721//-- #define VG_CPU_VENDOR_INTEL 1
sewardjc9a65702004-07-07 16:32:57 +0000722//-- #define VG_CPU_VENDOR_AMD 2
723//--
724//-- static Int cpu_vendor = VG_CPU_VENDOR_GENERIC;
725//--
726//-- static const struct cpu_vendor {
727//-- const Char *vendorstr;
728//-- Int vendorid;
729//-- } cpu_vendors[] = {
730//-- { "GenuineIntel", VG_CPU_VENDOR_INTEL },
731//-- { "AuthenticAMD", VG_CPU_VENDOR_AMD },
732//-- };
733//--
734//-- static Int cpuid_level = -2; /* -2 -> not initialized */
735//-- static UInt cpu_features[VG_N_FEATURE_WORDS];
736//--
737//-- /* Standard macro to see if a specific flag is changeable */
738//-- static inline Bool flag_is_changeable(UInt flag)
739//-- {
740//-- UInt f1, f2;
741//--
742//-- asm("pushfl\n\t"
743//-- "pushfl\n\t"
744//-- "popl %0\n\t"
745//-- "movl %0,%1\n\t"
746//-- "xorl %2,%0\n\t"
747//-- "pushl %0\n\t"
748//-- "popfl\n\t"
749//-- "pushfl\n\t"
750//-- "popl %0\n\t"
751//-- "popfl\n\t"
752//-- : "=&r" (f1), "=&r" (f2)
753//-- : "ir" (flag));
754//--
755//-- return ((f1^f2) & flag) != 0;
756//-- }
757//--
758//--
759//-- /* Probe for the CPUID instruction */
760//-- static Bool has_cpuid(void)
761//-- {
762//-- return flag_is_changeable(EFlagID);
763//-- }
764//--
765//-- static void get_cpu_features(void)
766//-- {
767//-- Char vendorstr[13];
768//-- Int i;
769//--
770//-- if (!has_cpuid()) {
771//-- cpuid_level = -1;
772//-- return;
773//-- }
774//--
775//-- cpu_features[VG_INT_FEAT] |= (1 << (VG_X86_FEAT_CPUID%32));
776//--
777//-- VG_(cpuid)(0, &cpuid_level, (UInt *)&vendorstr[0], (UInt *)&vendorstr[8], (UInt *)&vendorstr[4]);
778//-- vendorstr[12] = '\0';
779//--
780//-- for(i = 0; i < sizeof(cpu_vendors)/sizeof(*cpu_vendors); i++)
781//-- if (VG_(memcmp)(vendorstr, cpu_vendors[i].vendorstr, 12) == 0) {
782//-- cpu_vendor = cpu_vendors[i].vendorid;
783//-- break;
784//-- }
785//--
786//-- if (cpuid_level >= 1)
787//-- VG_(cpuid)(1, NULL, NULL, &cpu_features[VG_EXT_FEAT], &cpu_features[VG_X86_FEAT]);
788//--
789//-- switch(cpu_vendor) {
790//-- case VG_CPU_VENDOR_AMD:
791//-- /* get AMD-specific flags */
792//-- VG_(cpuid)(0x80000001, NULL, NULL, NULL, &cpu_features[VG_AMD_FEAT]);
793//-- break;
794//--
795//-- default:
796//-- break;
797//-- }
798//-- }
799//--
800//-- Bool VG_(cpu_has_feature)(UInt feature)
801//-- {
802//-- UInt word = feature / 32;
803//-- UInt bit = feature % 32;
804//--
805//-- if (cpuid_level == -2)
806//-- get_cpu_features();
807//--
808//-- vg_assert(word >= 0 && word < VG_N_FEATURE_WORDS);
809//--
810//-- return !!(cpu_features[word] & (1 << bit));
811//-- }
812//--
813//-- /* The set of features we're willing to support for the client
814//--
815//-- This includes supported instruction set extensions, plus any
816//-- extensions which don't have any user-mode visible effect (but the
817//-- client may find interesting).
818//-- */
sewardjd1061ab2004-07-08 01:45:30 +0000819#define VG_X86_SUPPORTED_FEATURES \
820 ((1 << VG_X86_FEAT_FPU) | \
821 (1 << VG_X86_FEAT_VME) | \
822 (1 << VG_X86_FEAT_DE) | \
823 (1 << VG_X86_FEAT_PSE) | \
824 (1 << VG_X86_FEAT_TSC) | \
825 (0 << VG_X86_FEAT_MSR) | \
826 (1 << VG_X86_FEAT_PAE) | \
827 (1 << VG_X86_FEAT_MCE) | \
828 (1 << VG_X86_FEAT_CX8) | \
829 (1 << VG_X86_FEAT_APIC) | \
830 (0 << VG_X86_FEAT_SEP) | \
831 (1 << VG_X86_FEAT_MTRR) | \
832 (1 << VG_X86_FEAT_PGE) | \
833 (1 << VG_X86_FEAT_MCA) | \
834 (1 << VG_X86_FEAT_CMOV) | \
835 (1 << VG_X86_FEAT_PAT) | \
836 (1 << VG_X86_FEAT_PSE36) | \
837 (0 << VG_X86_FEAT_CLFSH) | \
838 (1 << VG_X86_FEAT_DS) | \
839 (1 << VG_X86_FEAT_ACPI) | \
840 (1 << VG_X86_FEAT_MMX) | \
841 (1 << VG_X86_FEAT_FXSR) | \
842 (1 << VG_X86_FEAT_SSE) | \
843 (1 << VG_X86_FEAT_SSE2) | \
844 (1 << VG_X86_FEAT_SS) | \
845 (1 << VG_X86_FEAT_HT) | \
846 (1 << VG_X86_FEAT_TM) | \
847 (0 << VG_X86_FEAT_IA64) | \
848 (1 << VG_X86_FEAT_PBE))
849
850#define VG_AMD_SUPPORTED_FEATURES \
851 ((0 << (VG_AMD_FEAT_SYSCALL % 32)) | \
852 (0 << (VG_AMD_FEAT_NXP % 32)) | \
853 (1 << (VG_AMD_FEAT_MMXEXT % 32)) | \
854 (0 << (VG_AMD_FEAT_FFXSR % 32)) | \
855 (0 << (VG_AMD_FEAT_LONGMODE % 32)) | \
856 (0 << (VG_AMD_FEAT_3DNOWEXT % 32)) | \
857 (0 << (VG_AMD_FEAT_3DNOW % 32)) | \
858 /* Common bits between standard features and AMD features */ \
859 (1 << VG_X86_FEAT_FPU) | \
860 (1 << VG_X86_FEAT_VME) | \
861 (1 << VG_X86_FEAT_DE) | \
862 (1 << VG_X86_FEAT_PSE) | \
863 (1 << VG_X86_FEAT_TSC) | \
864 (0 << VG_X86_FEAT_MSR) | \
865 (1 << VG_X86_FEAT_PAE) | \
866 (1 << VG_X86_FEAT_MCE) | \
867 (1 << VG_X86_FEAT_CX8) | \
868 (1 << VG_X86_FEAT_APIC) | \
869 (1 << VG_X86_FEAT_MTRR) | \
870 (1 << VG_X86_FEAT_PGE) | \
871 (1 << VG_X86_FEAT_MCA) | \
872 (1 << VG_X86_FEAT_CMOV) | \
873 (1 << VG_X86_FEAT_PAT) | \
874 (1 << VG_X86_FEAT_PSE36) | \
875 (1 << VG_X86_FEAT_MMX) | \
876 (1 << VG_X86_FEAT_FXSR))
877
878
sewardjc9a65702004-07-07 16:32:57 +0000879//-- /*
880//-- For simulating the cpuid instruction, we will
881//-- issue a "real" cpuid instruction and then mask out
882//-- the bits of the features we do not support currently (3dnow mostly).
883//-- We also claim to not support most CPUID operations.
884//--
885//-- Dirk Mueller <mueller@kde.org>
886//--
887//-- http://www.sandpile.org/ia32/cpuid.htm
888//--
889//-- references:
890//--
891//-- pre-MMX pentium:
892//--
893//-- <werner> cpuid words (0): 0x1 0x756e6547 0x6c65746e 0x49656e69
894//-- <werner> cpuid words (1): 0x52b 0x0 0x0 0x1bf
895//--
896//-- Updated to be more extensible about future vendor extensions and
897//-- vendor-specific parts of CPUID.
898//-- */
899//-- void VG_(helperc_CPUID)(UInt op, UInt *eax_ret, UInt *ebx_ret, UInt *ecx_ret, UInt *edx_ret)
900//-- {
901//-- UInt eax, ebx, ecx, edx;
902//--
903//-- if (cpuid_level == -2)
904//-- get_cpu_features(); /* for cpu_vendor */
905//--
906//-- VG_(cpuid)(op, &eax, &ebx, &ecx, &edx);
907//--
908//-- /* Common mangling */
909//-- switch(op) {
910//-- case 1:
911//-- edx &= VG_X86_SUPPORTED_FEATURES;
912//-- break;
913//--
914//-- case 0xd8000000: {
915//-- /* Implement some private information at 0xd8000000 */
916//-- static const Char valgrind_vendor[] = "ValgrindVCPU";
917//--
918//-- eax = 0xd8000000; /* max request */
919//-- ebx = *(UInt *)&valgrind_vendor[0];
920//-- ecx = *(UInt *)&valgrind_vendor[8];
921//-- edx = *(UInt *)&valgrind_vendor[4];
922//-- }
923//-- break;
924//-- }
925//--
926//-- /* Vendor-specific mangling of the results */
927//-- switch(cpu_vendor) {
928//-- case VG_CPU_VENDOR_INTEL:
929//-- switch(op) {
930//-- case 1:
931//-- ecx = 0; /* mask out all extended features for now */
932//-- break;
933//--
934//-- case 0x80000001:
935//-- ebx = ecx = edx = 0;
936//-- break;
937//-- }
938//-- break;
939//--
940//-- case VG_CPU_VENDOR_AMD:
941//-- switch(op) {
942//-- case 0x80000001:
943//-- edx &= VG_AMD_SUPPORTED_FEATURES;
944//-- break;
945//-- }
946//-- break;
947//-- }
948//--
949//-- *eax_ret = eax;
950//-- *ebx_ret = ebx;
951//-- *ecx_ret = ecx;
952//-- *edx_ret = edx;
953//-- }
954//--
955//--
956//-- /*------------------------------------------------------------*/
957//-- /*--- Here so it can be inlined everywhere. ---*/
958//-- /*------------------------------------------------------------*/
959//--
960//-- /* Allocate a new temp reg number. */
961//-- __inline__ Int VG_(get_new_temp) ( UCodeBlock* cb )
962//-- {
963//-- Int t = cb->nextTemp;
964//-- cb->nextTemp += 2;
965//-- return t;
966//-- }
967//--
968//-- Int VG_(get_new_shadow) ( UCodeBlock* cb )
969//-- {
970//-- Int t = cb->nextTemp;
971//-- cb->nextTemp += 2;
972//-- return SHADOW(t);
973//-- }
974
975
sewardj41f43bc2004-07-08 14:23:22 +0000976
977static Char* nameGrp1 ( Int opc_aux )
978{
979 static Char* grp1_names[8]
980 = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
981 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp1(x86)");
982 return grp1_names[opc_aux];
983}
984
sewardje90ad6a2004-07-10 19:02:10 +0000985static Char* nameGrp2 ( Int opc_aux )
986{
987 static Char* grp2_names[8]
988 = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
sewardjc2ac51e2004-07-12 01:03:26 +0000989 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp2(x86)");
sewardje90ad6a2004-07-10 19:02:10 +0000990 return grp2_names[opc_aux];
991}
992
sewardjc2ac51e2004-07-12 01:03:26 +0000993static Char* nameGrp4 ( Int opc_aux )
994{
995 static Char* grp4_names[8]
996 = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
997 if (opc_aux < 0 || opc_aux > 1) vpanic("nameGrp4(x86)");
998 return grp4_names[opc_aux];
999}
sewardj0611d802004-07-11 02:37:54 +00001000
1001static Char* nameGrp5 ( Int opc_aux )
1002{
1003 static Char* grp5_names[8]
1004 = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
1005 if (opc_aux < 0 || opc_aux > 6) vpanic("nameGrp5(x86)");
1006 return grp5_names[opc_aux];
1007}
1008
sewardjc9a65702004-07-07 16:32:57 +00001009//-- static Char* nameGrp8 ( Int opc_aux )
1010//-- {
1011//-- static Char* grp8_names[8]
1012//-- = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
1013//-- if (opc_aux < 4 || opc_aux > 7) VG_(core_panic)("nameGrp8");
1014//-- return grp8_names[opc_aux];
1015//-- }
1016
sewardj1813dbe2004-07-28 17:09:04 +00001017static Char* nameIReg ( Int size, Int reg )
sewardjc9a65702004-07-07 16:32:57 +00001018{
1019 static Char* ireg32_names[8]
1020 = { "%eax", "%ecx", "%edx", "%ebx",
1021 "%esp", "%ebp", "%esi", "%edi" };
1022 static Char* ireg16_names[8]
1023 = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di" };
1024 static Char* ireg8_names[8]
1025 = { "%al", "%cl", "%dl", "%bl",
1026 "%ah{sp}", "%ch{bp}", "%dh{si}", "%bh{di}" };
1027 if (reg < 0 || reg > 7) goto bad;
1028 switch (size) {
1029 case 4: return ireg32_names[reg];
1030 case 2: return ireg16_names[reg];
1031 case 1: return ireg8_names[reg];
1032 }
1033 bad:
1034 vpanic("nameIReg(X86)");
1035 return NULL; /*notreached*/
1036}
1037
1038//-- const Char* VG_(name_of_seg_reg) ( Int sreg )
1039//-- {
1040//-- switch (sreg) {
1041//-- case R_ES: return "%es";
1042//-- case R_CS: return "%cs";
1043//-- case R_SS: return "%ss";
1044//-- case R_DS: return "%ds";
1045//-- case R_FS: return "%fs";
1046//-- case R_GS: return "%gs";
1047//-- default: VG_(core_panic)("nameOfSegReg");
1048//-- }
1049//-- }
1050//--
1051//-- const Char* VG_(name_of_mmx_reg) ( Int mmxreg )
1052//-- {
1053//-- static const Char* mmx_names[8]
1054//-- = { "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" };
1055//-- if (mmxreg < 0 || mmxreg > 7) VG_(core_panic)("name_of_mmx_reg");
1056//-- return mmx_names[mmxreg];
1057//-- }
1058//--
1059//-- const Char* VG_(name_of_xmm_reg) ( Int xmmreg )
1060//-- {
1061//-- static const Char* xmm_names[8]
1062//-- = { "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7" };
1063//-- if (xmmreg < 0 || xmmreg > 7) VG_(core_panic)("name_of_xmm_reg");
1064//-- return xmm_names[xmmreg];
1065//-- }
1066//--
1067//-- const Char* VG_(name_of_mmx_gran) ( UChar gran )
1068//-- {
1069//-- switch (gran) {
1070//-- case 0: return "b";
1071//-- case 1: return "w";
1072//-- case 2: return "d";
1073//-- case 3: return "q";
1074//-- default: VG_(core_panic)("name_of_mmx_gran");
1075//-- }
1076//-- }
1077
sewardj41f43bc2004-07-08 14:23:22 +00001078static Char nameISize ( Int size )
sewardjc9a65702004-07-07 16:32:57 +00001079{
1080 switch (size) {
1081 case 4: return 'l';
1082 case 2: return 'w';
1083 case 1: return 'b';
1084 default: vpanic("nameISize(x86)");
1085 }
1086}
1087
sewardjc9a65702004-07-07 16:32:57 +00001088//-- __inline__ static UInt LOW24 ( UInt x )
1089//-- {
1090//-- return x & 0x00FFFFFF;
1091//-- }
1092//--
1093//-- __inline__ static UInt HI8 ( UInt x )
1094//-- {
1095//-- return x >> 24;
1096//-- }
1097//--
sewardjc9a65702004-07-07 16:32:57 +00001098//-- /*------------------------------------------------------------*/
1099//-- /*--- Flag-related helpers. ---*/
1100//-- /*------------------------------------------------------------*/
1101//--
1102//-- static void setFlagsFromUOpcode ( UCodeBlock* cb, Int uopc )
1103//-- {
1104//-- switch (uopc) {
1105//-- case XOR: case OR: case AND:
1106//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZCP, FlagA); break;
1107//-- case ADC: case SBB:
1108//-- uFlagsRWU(cb, FlagC, FlagsOSZACP, FlagsEmpty); break;
1109//-- case MUL: case UMUL:
1110//-- uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP); break;
1111//-- case ADD: case SUB: case NEG:
1112//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty); break;
1113//-- case INC: case DEC:
1114//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZAP, FlagsEmpty); break;
1115//-- case SHR: case SAR: case SHL:
1116//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZCP, FlagA); break;
1117//-- case ROL: case ROR:
1118//-- uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsEmpty); break;
1119//-- case RCR: case RCL:
1120//-- uFlagsRWU(cb, FlagC, FlagsOC, FlagsEmpty); break;
1121//-- case NOT:
1122//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty); break;
1123//-- default:
1124//-- VG_(printf)("unhandled case is %s\n",
1125//-- VG_(name_UOpcode)(True, uopc));
1126//-- VG_(core_panic)("setFlagsFromUOpcode: unhandled case");
1127//-- }
1128//-- }
sewardjd1061ab2004-07-08 01:45:30 +00001129
1130/*------------------------------------------------------------*/
1131/*--- JMP helpers ---*/
1132/*------------------------------------------------------------*/
1133
sewardj78c19df2004-07-12 22:49:27 +00001134static void jmp_lit( IRJumpKind kind, Addr32 d32 )
sewardjd1061ab2004-07-08 01:45:30 +00001135{
sewardje539a402004-07-14 18:24:17 +00001136 irbb->next = mkU32(d32);
1137 irbb->jumpkind = kind;
sewardjd1061ab2004-07-08 01:45:30 +00001138}
1139
sewardj78c19df2004-07-12 22:49:27 +00001140static void jmp_treg( IRJumpKind kind, IRTemp t )
sewardje05c42c2004-07-08 20:25:10 +00001141{
sewardje539a402004-07-14 18:24:17 +00001142 irbb->next = mkexpr(t);
1143 irbb->jumpkind = kind;
sewardje05c42c2004-07-08 20:25:10 +00001144}
sewardje87b4842004-07-10 12:23:30 +00001145
sewardj9334b0f2004-07-10 22:43:54 +00001146static void jcc_01( Condcode cond, Addr32 d32_false, Addr32 d32_true )
sewardje87b4842004-07-10 12:23:30 +00001147{
1148 Bool invert;
1149 Condcode condPos;
1150 condPos = positiveIse_Condcode ( cond, &invert );
1151 if (invert) {
sewardj78c19df2004-07-12 22:49:27 +00001152 stmt( IRStmt_Exit( calculate_condition(condPos),
1153 IRConst_U32(d32_false) ) );
sewardje539a402004-07-14 18:24:17 +00001154 irbb->next = mkU32(d32_true);
1155 irbb->jumpkind = Ijk_Boring;
sewardje87b4842004-07-10 12:23:30 +00001156 } else {
sewardj78c19df2004-07-12 22:49:27 +00001157 stmt( IRStmt_Exit( calculate_condition(condPos),
1158 IRConst_U32(d32_true) ) );
sewardje539a402004-07-14 18:24:17 +00001159 irbb->next = mkU32(d32_false);
1160 irbb->jumpkind = Ijk_Boring;
sewardje87b4842004-07-10 12:23:30 +00001161 }
1162}
sewardjc9a65702004-07-07 16:32:57 +00001163
1164
sewardjd1061ab2004-07-08 01:45:30 +00001165/*------------------------------------------------------------*/
1166/*--- Disassembling addressing modes ---*/
1167/*------------------------------------------------------------*/
sewardjc9a65702004-07-07 16:32:57 +00001168
sewardjd1061ab2004-07-08 01:45:30 +00001169static
1170UChar* sorbTxt ( UChar sorb )
1171{
1172 switch (sorb) {
1173 case 0: return ""; /* no override */
1174 case 0x3E: return "%ds";
1175 case 0x26: return "%es:";
1176 case 0x64: return "%fs:";
1177 case 0x65: return "%gs:";
1178 default: vpanic("sorbTxt(x86)");
1179 }
1180}
1181
1182
1183/* Tmp is a TempReg holding a virtual address. Convert it to a linear
1184 address by adding any required segment override as indicated by
1185 sorb. */
1186static
1187IRExpr* handleSegOverride ( UChar sorb, IRExpr* virtual )
1188{
1189 //Int sreg, tsreg;
1190
1191 if (sorb == 0)
1192 /* the common case - no override */
1193 return virtual;
1194
1195 unimplemented("segment overrides in new x86->IR phase");
1196#if 0
1197 switch (sorb) {
1198 case 0x3E: sreg = R_DS; break;
1199 case 0x26: sreg = R_ES; break;
1200 case 0x64: sreg = R_FS; break;
1201 case 0x65: sreg = R_GS; break;
1202 default: VG_(core_panic)("handleSegOverride");
1203 }
1204
1205 tsreg = newTemp(cb);
1206
1207 /* sreg -> tsreg */
1208 uInstr2(cb, GETSEG, 2, ArchRegS, sreg, TempReg, tsreg );
1209
1210 /* tmp += segment_base(ldt[tsreg]); also do limit check */
1211 uInstr2(cb, USESEG, 0, TempReg, tsreg, TempReg, tmp );
1212#endif
1213}
1214
1215
1216/* Generate IR to calculate an address indicated by a ModRM and
1217 following SIB bytes. The expression, and the number of bytes in
1218 the address mode, are returned. Note that this fn should not be
1219 called if the R/M part of the address denotes a register instead of
1220 memory. If print_codegen is true, text of the addressing mode is
sewardj940e8c92004-07-11 16:53:24 +00001221 placed in buf.
1222
1223 The computed address is stored in a new tempreg, and the
1224 identity of the tempreg is returned. */
1225
1226static IRTemp disAMode_copy2tmp ( IRExpr* addr32 )
1227{
1228 IRTemp tmp = newTemp(Ity_I32);
1229 assign( tmp, addr32 );
1230 return tmp;
1231}
sewardjd1061ab2004-07-08 01:45:30 +00001232
1233static
sewardj940e8c92004-07-11 16:53:24 +00001234IRTemp disAMode ( Int* len, UChar sorb, UInt delta, UChar* buf )
sewardjd1061ab2004-07-08 01:45:30 +00001235{
1236 UChar mod_reg_rm = getIByte(delta);
1237 delta++;
1238
1239 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1240 jump table seems a bit excessive.
1241 */
1242 mod_reg_rm &= 0xC7; /* is now XX000YYY */
1243 mod_reg_rm |= (mod_reg_rm >> 3); /* is now XX0XXYYY */
1244 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
1245 switch (mod_reg_rm) {
1246
1247 /* (%eax) .. (%edi), not including (%esp) or (%ebp).
1248 --> GET %reg, t
1249 */
1250 case 0x00: case 0x01: case 0x02: case 0x03:
1251 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1252 { UChar rm = mod_reg_rm;
1253 DIS(buf, "%s(%s)", sorbTxt(sorb), nameIReg(4,rm));
1254 *len = 1;
sewardj940e8c92004-07-11 16:53:24 +00001255 return disAMode_copy2tmp(
1256 handleSegOverride(sorb, getIReg(4,rm)));
sewardjd1061ab2004-07-08 01:45:30 +00001257 }
1258
1259 /* d8(%eax) ... d8(%edi), not including d8(%esp)
1260 --> GET %reg, t ; ADDL d8, t
1261 */
1262 case 0x08: case 0x09: case 0x0A: case 0x0B:
1263 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1264 { UChar rm = mod_reg_rm & 7;
1265 UInt d = getSDisp8(delta);
1266 DIS(buf, "%s%d(%s)", sorbTxt(sorb), d, nameIReg(4,rm));
1267 *len = 2;
sewardj940e8c92004-07-11 16:53:24 +00001268 return disAMode_copy2tmp(
1269 handleSegOverride(sorb,
1270 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001271 }
1272
1273 /* d32(%eax) ... d32(%edi), not including d32(%esp)
1274 --> GET %reg, t ; ADDL d8, t
1275 */
1276 case 0x10: case 0x11: case 0x12: case 0x13:
1277 /* ! 14 */ case 0x15: case 0x16: case 0x17:
1278 { UChar rm = mod_reg_rm & 7;
1279 UInt d = getUDisp32(delta);
1280 DIS(buf, "%s0x%x(%s)", sorbTxt(sorb), d, nameIReg(4,rm));
1281 *len = 5;
sewardj940e8c92004-07-11 16:53:24 +00001282 return disAMode_copy2tmp(
1283 handleSegOverride(sorb,
1284 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001285 }
1286
1287 /* a register, %eax .. %edi. This shouldn't happen. */
1288 case 0x18: case 0x19: case 0x1A: case 0x1B:
1289 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1290 vpanic("disAMode(x86): not an addr!");
1291
1292 /* a 32-bit literal address
1293 --> MOV d32, tmp
1294 */
1295 case 0x05:
1296 { UInt d = getUDisp32(delta);
1297 *len = 5;
1298 DIS(buf, "%s(0x%x)", sorbTxt(sorb), d);
sewardj940e8c92004-07-11 16:53:24 +00001299 return disAMode_copy2tmp(
1300 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001301 }
1302
1303 case 0x04: {
1304 /* SIB, with no displacement. Special cases:
1305 -- %esp cannot act as an index value.
1306 If index_r indicates %esp, zero is used for the index.
1307 -- when mod is zero and base indicates EBP, base is instead
1308 a 32-bit literal.
1309 It's all madness, I tell you. Extract %index, %base and
1310 scale from the SIB byte. The value denoted is then:
1311 | %index == %ESP && %base == %EBP
1312 = d32 following SIB byte
1313 | %index == %ESP && %base != %EBP
1314 = %base
1315 | %index != %ESP && %base == %EBP
1316 = d32 following SIB byte + (%index << scale)
1317 | %index != %ESP && %base != %ESP
1318 = %base + (%index << scale)
1319
1320 What happens to the souls of CPU architects who dream up such
1321 horrendous schemes, do you suppose?
1322 */
1323 UChar sib = getIByte(delta);
1324 UChar scale = (sib >> 6) & 3;
1325 UChar index_r = (sib >> 3) & 7;
1326 UChar base_r = sib & 7;
1327 delta++;
1328
1329 if (index_r != R_ESP && base_r != R_EBP) {
1330 DIS(buf, "%s(%s,%s,%d)", sorbTxt(sorb),
1331 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
1332 *len = 2;
sewardj940e8c92004-07-11 16:53:24 +00001333 return
1334 disAMode_copy2tmp(
sewardjd1061ab2004-07-08 01:45:30 +00001335 handleSegOverride(sorb,
1336 binop(Iop_Add32,
1337 getIReg(4,base_r),
1338 binop(Iop_Shl32, getIReg(4,index_r),
sewardj6d2638e2004-07-15 09:38:27 +00001339 mkU8(scale)))));
sewardjd1061ab2004-07-08 01:45:30 +00001340 }
1341
1342 if (index_r != R_ESP && base_r == R_EBP) {
1343 UInt d = getUDisp32(delta);
1344 DIS(buf, "%s0x%x(,%s,%d)", sorbTxt(sorb), d,
1345 nameIReg(4,index_r), 1<<scale);
1346 *len = 6;
1347 return
sewardj940e8c92004-07-11 16:53:24 +00001348 disAMode_copy2tmp(
sewardjd1061ab2004-07-08 01:45:30 +00001349 handleSegOverride(sorb,
1350 binop(Iop_Add32,
sewardj6d2638e2004-07-15 09:38:27 +00001351 binop(Iop_Shl32, getIReg(4,index_r), mkU8(scale)),
sewardj940e8c92004-07-11 16:53:24 +00001352 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001353 }
1354
1355 if (index_r == R_ESP && base_r != R_EBP) {
1356 DIS(buf, "%s(%s,,)", sorbTxt(sorb), nameIReg(4,base_r));
1357 *len = 2;
sewardj940e8c92004-07-11 16:53:24 +00001358 return disAMode_copy2tmp(
1359 handleSegOverride(sorb, getIReg(4,base_r)));
sewardjd1061ab2004-07-08 01:45:30 +00001360 }
1361
1362 if (index_r == R_ESP && base_r == R_EBP) {
1363 UInt d = getUDisp32(delta);
1364 DIS(buf, "%s0x%x()", sorbTxt(sorb), d);
1365 *len = 6;
sewardj41f43bc2004-07-08 14:23:22 +00001366 vpanic("amode 8");
sewardj940e8c92004-07-11 16:53:24 +00001367 return disAMode_copy2tmp(
1368 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001369 }
1370
1371 vassert(0);
1372 }
1373
1374 /* SIB, with 8-bit displacement. Special cases:
1375 -- %esp cannot act as an index value.
1376 If index_r indicates %esp, zero is used for the index.
1377 Denoted value is:
1378 | %index == %ESP
1379 = d8 + %base
1380 | %index != %ESP
1381 = d8 + %base + (%index << scale)
1382 */
1383 case 0x0C: {
1384 UChar sib = getIByte(delta);
1385 UChar scale = (sib >> 6) & 3;
1386 UChar index_r = (sib >> 3) & 7;
1387 UChar base_r = sib & 7;
1388 UInt d = getSDisp8(delta+1);
1389
1390 if (index_r == R_ESP) {
1391 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb), d, nameIReg(4,base_r));
1392 *len = 3;
sewardj940e8c92004-07-11 16:53:24 +00001393 return disAMode_copy2tmp(
1394 handleSegOverride(sorb,
1395 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001396 } else {
1397 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), d,
1398 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
1399 *len = 3;
sewardj77b86be2004-07-11 13:28:24 +00001400 return
sewardj940e8c92004-07-11 16:53:24 +00001401 disAMode_copy2tmp(
1402 handleSegOverride(sorb,
sewardj77b86be2004-07-11 13:28:24 +00001403 binop(Iop_Add32,
1404 binop(Iop_Add32,
1405 getIReg(4,base_r),
1406 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001407 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001408 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001409 }
1410 vassert(0);
1411 }
1412
1413 /* SIB, with 32-bit displacement. Special cases:
1414 -- %esp cannot act as an index value.
1415 If index_r indicates %esp, zero is used for the index.
1416 Denoted value is:
1417 | %index == %ESP
1418 = d32 + %base
1419 | %index != %ESP
1420 = d32 + %base + (%index << scale)
1421 */
1422 case 0x14: {
1423 UChar sib = getIByte(delta);
1424 UChar scale = (sib >> 6) & 3;
1425 UChar index_r = (sib >> 3) & 7;
1426 UChar base_r = sib & 7;
1427 UInt d = getUDisp32(delta+1);
1428
1429 if (index_r == R_ESP) {
1430 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb), d, nameIReg(4,base_r));
1431 *len = 6;
sewardj940e8c92004-07-11 16:53:24 +00001432 return disAMode_copy2tmp(
1433 handleSegOverride(sorb,
1434 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001435 } else {
1436 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), d,
1437 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
1438 *len = 6;
sewardj9334b0f2004-07-10 22:43:54 +00001439 return
sewardj940e8c92004-07-11 16:53:24 +00001440 disAMode_copy2tmp(
1441 handleSegOverride(sorb,
sewardj9334b0f2004-07-10 22:43:54 +00001442 binop(Iop_Add32,
1443 binop(Iop_Add32,
1444 getIReg(4,base_r),
1445 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001446 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001447 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001448 }
1449 vassert(0);
1450 }
1451
1452 default:
1453 vpanic("disAMode(x86)");
1454 return 0; /*notreached*/
1455 }
1456}
1457
1458
1459/* Figure out the number of (insn-stream) bytes constituting the amode
1460 beginning at delta. Is useful for getting hold of literals beyond
1461 the end of the amode before it has been disassembled. */
1462
1463static UInt lengthAMode ( UInt delta )
1464{
1465 UChar mod_reg_rm = getIByte(delta); delta++;
1466
1467 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1468 jump table seems a bit excessive.
1469 */
1470 mod_reg_rm &= 0xC7; /* is now XX000YYY */
1471 mod_reg_rm |= (mod_reg_rm >> 3); /* is now XX0XXYYY */
1472 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
1473 switch (mod_reg_rm) {
1474
1475 /* (%eax) .. (%edi), not including (%esp) or (%ebp). */
1476 case 0x00: case 0x01: case 0x02: case 0x03:
1477 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1478 return 1;
1479
1480 /* d8(%eax) ... d8(%edi), not including d8(%esp). */
1481 case 0x08: case 0x09: case 0x0A: case 0x0B:
1482 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1483 return 2;
1484
1485 /* d32(%eax) ... d32(%edi), not including d32(%esp). */
1486 case 0x10: case 0x11: case 0x12: case 0x13:
1487 /* ! 14 */ case 0x15: case 0x16: case 0x17:
1488 return 5;
1489
1490 /* a register, %eax .. %edi. (Not an addr, but still handled.) */
1491 case 0x18: case 0x19: case 0x1A: case 0x1B:
1492 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1493 return 1;
1494
1495 /* a 32-bit literal address. */
1496 case 0x05: return 5;
1497
1498 /* SIB, no displacement. */
1499 case 0x04: {
1500 UChar sib = getIByte(delta);
1501 UChar base_r = sib & 7;
1502 if (base_r == R_EBP) return 6; else return 2;
1503 }
1504 /* SIB, with 8-bit displacement. */
1505 case 0x0C: return 3;
1506
1507 /* SIB, with 32-bit displacement. */
1508 case 0x14: return 6;
1509
1510 default:
1511 vpanic("lengthAMode");
1512 return 0; /*notreached*/
1513 }
1514}
1515
1516/*------------------------------------------------------------*/
1517/*--- Disassembling common idioms ---*/
1518/*------------------------------------------------------------*/
1519
sewardj5df3bfe2004-07-27 09:30:31 +00001520static
1521void codegen_XOR_reg_with_itself ( Int size, Int ge_reg )
1522{
1523 IRType ty = szToITy(size);
1524 /* reg := 0 */
1525 putIReg(size, ge_reg, mkU(ty,0));
1526 /* Flags: C,A,O=0, Z=1, S=0, P=1 */
1527 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
1528 stmt( IRStmt_Put( OFFB_CC_SRC, mkU32(CC_MASK_Z|CC_MASK_P) ));
1529 stmt( IRStmt_Put( OFFB_CC_DST, mkU32(0) ));
1530 DIP("xor%c %s, %s\n", nameISize(size),
1531 nameIReg(size,ge_reg), nameIReg(size,ge_reg) );
1532}
1533
1534
sewardje87b4842004-07-10 12:23:30 +00001535/* Handle binary integer instructions of the form
1536 op E, G meaning
1537 op reg-or-mem, reg
1538 Is passed the a ptr to the modRM byte, the actual operation, and the
1539 data size. Returns the address advanced completely over this
1540 instruction.
1541
1542 E(src) is reg-or-mem
1543 G(dst) is reg.
1544
1545 If E is reg, --> GET %G, tmp
1546 OP %E, tmp
1547 PUT tmp, %G
1548
1549 If E is mem and OP is not reversible,
1550 --> (getAddr E) -> tmpa
1551 LD (tmpa), tmpa
1552 GET %G, tmp2
1553 OP tmpa, tmp2
1554 PUT tmp2, %G
1555
1556 If E is mem and OP is reversible
1557 --> (getAddr E) -> tmpa
1558 LD (tmpa), tmpa
1559 OP %G, tmpa
1560 PUT tmpa, %G
1561*/
1562static
1563UInt dis_op2_E_G ( UChar sorb,
sewardj180e8b32004-07-29 01:40:11 +00001564 Bool addSubCarry,
sewardje87b4842004-07-10 12:23:30 +00001565 IROp op8,
1566 Bool keep,
1567 Int size,
1568 UInt delta0,
1569 Char* t_x86opc )
1570{
sewardj9334b0f2004-07-10 22:43:54 +00001571 UChar dis_buf[50];
1572 Int len;
sewardje87b4842004-07-10 12:23:30 +00001573 IRType ty = szToITy(size);
1574 IRTemp dst1 = newTemp(ty);
1575 IRTemp src = newTemp(ty);
1576 IRTemp dst0 = newTemp(ty);
1577 UChar rm = getUChar(delta0);
sewardj940e8c92004-07-11 16:53:24 +00001578 IRTemp addr = INVALID_IRTEMP;
sewardje87b4842004-07-10 12:23:30 +00001579
sewardj180e8b32004-07-29 01:40:11 +00001580 /* addSubCarry == True indicates the intended operation is
1581 add-with-carry or subtract-with-borrow. */
1582 if (addSubCarry) {
1583 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1584 vassert(keep);
1585 }
1586
sewardje87b4842004-07-10 12:23:30 +00001587 if (epartIsReg(rm)) {
sewardje87b4842004-07-10 12:23:30 +00001588 /* Specially handle XOR reg,reg, because that doesn't really
1589 depend on reg, and doing the obvious thing potentially
1590 generates a spurious value check failure due to the bogus
1591 dependency. */
sewardj5df3bfe2004-07-27 09:30:31 +00001592 if (op8 == Iop_Xor8 && gregOfRM(rm) == eregOfRM(rm)) {
1593 codegen_XOR_reg_with_itself ( size, gregOfRM(rm) );
1594 return 1+delta0;
sewardje87b4842004-07-10 12:23:30 +00001595 }
sewardje87b4842004-07-10 12:23:30 +00001596 assign( dst0, getIReg(size,gregOfRM(rm)) );
1597 assign( src, getIReg(size,eregOfRM(rm)) );
sewardje87b4842004-07-10 12:23:30 +00001598
sewardj180e8b32004-07-29 01:40:11 +00001599 if (addSubCarry && op8 == Iop_Add8) {
1600 vassert(0);
1601 helper_ADC( size, dst1, dst0, src );
sewardje87b4842004-07-10 12:23:30 +00001602 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00001603 } else
1604 if (addSubCarry && op8 == Iop_Sub8) {
1605 vassert(0);
1606 helper_SBB( size, dst1, dst0, src );
1607 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1608 } else {
1609 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardjb9c5cf62004-08-24 15:10:38 +00001610 if (isAddSub(op8))
1611 setFlags_ADD_SUB(op8, src, dst0, ty);
1612 else
1613 setFlags_LOGIC(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00001614 if (keep)
1615 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1616 }
sewardje87b4842004-07-10 12:23:30 +00001617
1618 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1619 nameIReg(size,eregOfRM(rm)),
1620 nameIReg(size,gregOfRM(rm)));
1621 return 1+delta0;
sewardje87b4842004-07-10 12:23:30 +00001622 } else {
sewardj9334b0f2004-07-10 22:43:54 +00001623 /* E refers to memory */
1624 addr = disAMode ( &len, sorb, delta0, dis_buf);
1625 assign( dst0, getIReg(size,gregOfRM(rm)) );
sewardj940e8c92004-07-11 16:53:24 +00001626 assign( src, loadLE(szToITy(size), mkexpr(addr)) );
sewardj9334b0f2004-07-10 22:43:54 +00001627
sewardj180e8b32004-07-29 01:40:11 +00001628 if (addSubCarry && op8 == Iop_Add8) {
sewardj180e8b32004-07-29 01:40:11 +00001629 helper_ADC( size, dst1, dst0, src );
sewardj9334b0f2004-07-10 22:43:54 +00001630 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00001631 } else
1632 if (addSubCarry && op8 == Iop_Sub8) {
1633 helper_SBB( size, dst1, dst0, src );
1634 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1635 } else {
1636 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardjb9c5cf62004-08-24 15:10:38 +00001637 if (isAddSub(op8))
1638 setFlags_ADD_SUB(op8, src, dst0, ty);
1639 else
1640 setFlags_LOGIC(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00001641 if (keep)
1642 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1643 }
sewardj9334b0f2004-07-10 22:43:54 +00001644
sewardje87b4842004-07-10 12:23:30 +00001645 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1646 dis_buf,nameIReg(size,gregOfRM(rm)));
sewardj9334b0f2004-07-10 22:43:54 +00001647 return len+delta0;
sewardje87b4842004-07-10 12:23:30 +00001648 }
sewardje87b4842004-07-10 12:23:30 +00001649}
sewardje05c42c2004-07-08 20:25:10 +00001650
1651
1652
1653/* Handle binary integer instructions of the form
1654 op G, E meaning
1655 op reg, reg-or-mem
1656 Is passed the a ptr to the modRM byte, the actual operation, and the
1657 data size. Returns the address advanced completely over this
1658 instruction.
1659
1660 G(src) is reg.
1661 E(dst) is reg-or-mem
1662
1663 If E is reg, --> GET %E, tmp
1664 OP %G, tmp
1665 PUT tmp, %E
1666
1667 If E is mem, --> (getAddr E) -> tmpa
1668 LD (tmpa), tmpv
1669 OP %G, tmpv
1670 ST tmpv, (tmpa)
1671*/
1672static
1673UInt dis_op2_G_E ( UChar sorb,
sewardjcaca9d02004-07-28 07:11:32 +00001674 Bool addSubCarry,
sewardje05c42c2004-07-08 20:25:10 +00001675 IROp op8,
1676 Bool keep,
1677 Int size,
1678 UInt delta0,
1679 Char* t_x86opc )
1680{
sewardje87b4842004-07-10 12:23:30 +00001681 UChar dis_buf[50];
1682 Int len;
sewardje05c42c2004-07-08 20:25:10 +00001683 IRType ty = szToITy(size);
1684 IRTemp dst1 = newTemp(ty);
1685 IRTemp src = newTemp(ty);
1686 IRTemp dst0 = newTemp(ty);
1687 UChar rm = getIByte(delta0);
sewardj940e8c92004-07-11 16:53:24 +00001688 IRTemp addr = INVALID_IRTEMP;
sewardje05c42c2004-07-08 20:25:10 +00001689
sewardjcaca9d02004-07-28 07:11:32 +00001690 /* addSubCarry == True indicates the intended operation is
1691 add-with-carry or subtract-with-borrow. */
1692 if (addSubCarry) {
1693 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1694 vassert(keep);
1695 }
1696
sewardje05c42c2004-07-08 20:25:10 +00001697 if (epartIsReg(rm)) {
sewardje05c42c2004-07-08 20:25:10 +00001698 /* Specially handle XOR reg,reg, because that doesn't really
1699 depend on reg, and doing the obvious thing potentially
1700 generates a spurious value check failure due to the bogus
1701 dependency. */
sewardj5df3bfe2004-07-27 09:30:31 +00001702 if (op8 == Iop_Xor8 && gregOfRM(rm) == eregOfRM(rm)) {
1703 codegen_XOR_reg_with_itself ( size, gregOfRM(rm) );
1704 return 1+delta0;
sewardje05c42c2004-07-08 20:25:10 +00001705 }
sewardje05c42c2004-07-08 20:25:10 +00001706 assign(dst0, getIReg(size,eregOfRM(rm)));
1707 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00001708
sewardjcaca9d02004-07-28 07:11:32 +00001709 if (addSubCarry && op8 == Iop_Add8) {
sewardj1813dbe2004-07-28 17:09:04 +00001710 helper_ADC( size, dst1, dst0, src );
1711 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00001712 } else
1713 if (addSubCarry && op8 == Iop_Sub8) {
1714 helper_SBB( size, dst1, dst0, src );
sewardje05c42c2004-07-08 20:25:10 +00001715 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00001716 } else {
1717 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardjb9c5cf62004-08-24 15:10:38 +00001718 if (isAddSub(op8))
1719 setFlags_ADD_SUB(op8, src, dst0, ty);
1720 else
1721 setFlags_LOGIC(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00001722 if (keep)
1723 putIReg(size, eregOfRM(rm), mkexpr(dst1));
1724 }
sewardje05c42c2004-07-08 20:25:10 +00001725
1726 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1727 nameIReg(size,gregOfRM(rm)),
1728 nameIReg(size,eregOfRM(rm)));
1729 return 1+delta0;
1730 }
1731
1732 /* E refers to memory */
1733 {
sewardje87b4842004-07-10 12:23:30 +00001734 addr = disAMode ( &len, sorb, delta0, dis_buf);
sewardj940e8c92004-07-11 16:53:24 +00001735 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardje87b4842004-07-10 12:23:30 +00001736 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00001737
sewardjcaca9d02004-07-28 07:11:32 +00001738 if (addSubCarry && op8 == Iop_Add8) {
1739 helper_ADC( size, dst1, dst0, src );
1740 storeLE(mkexpr(addr), mkexpr(dst1));
1741 } else
1742 if (addSubCarry && op8 == Iop_Sub8) {
1743 helper_SBB( size, dst1, dst0, src );
1744 storeLE(mkexpr(addr), mkexpr(dst1));
1745 } else {
1746 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardjb9c5cf62004-08-24 15:10:38 +00001747 if (isAddSub(op8))
1748 setFlags_ADD_SUB(op8, src, dst0, ty);
1749 else
1750 setFlags_LOGIC(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00001751 if (keep)
1752 storeLE(mkexpr(addr), mkexpr(dst1));
1753 }
sewardje87b4842004-07-10 12:23:30 +00001754
sewardje05c42c2004-07-08 20:25:10 +00001755 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1756 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje87b4842004-07-10 12:23:30 +00001757 return len+delta0;
sewardje05c42c2004-07-08 20:25:10 +00001758 }
1759}
1760
1761
1762/* Handle move instructions of the form
1763 mov E, G meaning
1764 mov reg-or-mem, reg
1765 Is passed the a ptr to the modRM byte, and the data size. Returns
1766 the address advanced completely over this instruction.
1767
1768 E(src) is reg-or-mem
1769 G(dst) is reg.
1770
1771 If E is reg, --> GET %E, tmpv
1772 PUT tmpv, %G
1773
1774 If E is mem --> (getAddr E) -> tmpa
1775 LD (tmpa), tmpb
1776 PUT tmpb, %G
1777*/
1778static
1779UInt dis_mov_E_G ( UChar sorb,
1780 Int size,
1781 UInt delta0 )
1782{
1783 Int len;
1784 UChar rm = getIByte(delta0);
1785 UChar dis_buf[50];
1786
1787 if (epartIsReg(rm)) {
1788#if 0
1789 Int tmpv = newTemp(cb);
1790 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, tmpv);
1791 uInstr2(cb, PUT, size, TempReg, tmpv, ArchReg, gregOfRM(rm));
1792 DIP("mov%c %s,%s\n", nameISize(size),
1793 nameIReg(size,eregOfRM(rm)),
1794 nameIReg(size,gregOfRM(rm)));
1795 return 1+eip0;
1796#endif
1797 vassert(121221==0);
1798 }
1799
1800 /* E refers to memory */
1801 {
sewardj940e8c92004-07-11 16:53:24 +00001802 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
1803 putIReg(size, gregOfRM(rm), loadLE(szToITy(size), mkexpr(addr)));
sewardje05c42c2004-07-08 20:25:10 +00001804 DIP("mov%c %s,%s\n", nameISize(size),
1805 dis_buf,nameIReg(size,gregOfRM(rm)));
1806 return delta0+len;
1807 }
1808}
1809
1810
1811/* Handle move instructions of the form
1812 mov G, E meaning
1813 mov reg, reg-or-mem
1814 Is passed the a ptr to the modRM byte, and the data size. Returns
1815 the address advanced completely over this instruction.
1816
1817 G(src) is reg.
1818 E(dst) is reg-or-mem
1819
1820 If E is reg, --> GET %G, tmp
1821 PUT tmp, %E
1822
1823 If E is mem, --> (getAddr E) -> tmpa
1824 GET %G, tmpv
1825 ST tmpv, (tmpa)
1826*/
sewardjc9a65702004-07-07 16:32:57 +00001827static
1828UInt dis_mov_G_E ( UChar sorb,
1829 Int size,
1830 UInt delta0 )
1831{
sewardje05c42c2004-07-08 20:25:10 +00001832 Int len;
sewardjc9a65702004-07-07 16:32:57 +00001833 UChar rm = getIByte(delta0);
sewardje05c42c2004-07-08 20:25:10 +00001834 UChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00001835
1836 if (epartIsReg(rm)) {
sewardj41f43bc2004-07-08 14:23:22 +00001837 putIReg(size, eregOfRM(rm), getIReg(size, gregOfRM(rm)));
sewardjc9a65702004-07-07 16:32:57 +00001838 DIP("mov%c %s,%s\n", nameISize(size),
1839 nameIReg(size,gregOfRM(rm)),
1840 nameIReg(size,eregOfRM(rm)));
1841 return 1+delta0;
1842 }
1843
sewardjc9a65702004-07-07 16:32:57 +00001844 /* E refers to memory */
1845 {
sewardj940e8c92004-07-11 16:53:24 +00001846 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf);
1847 storeLE( mkexpr(addr), getIReg(size, gregOfRM(rm)) );
sewardjc9a65702004-07-07 16:32:57 +00001848 DIP("mov%c %s,%s\n", nameISize(size),
1849 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje05c42c2004-07-08 20:25:10 +00001850 return len+delta0;
sewardjc9a65702004-07-07 16:32:57 +00001851 }
sewardjc9a65702004-07-07 16:32:57 +00001852}
1853
1854
sewardj0611d802004-07-11 02:37:54 +00001855/* op $immediate, AL/AX/EAX. */
1856static
1857UInt dis_op_imm_A ( Int size,
1858 IROp op8,
1859 Bool keep,
1860 UInt delta,
1861 Char* t_x86opc )
1862{
1863 IRType ty = szToITy(size);
1864 IRTemp dst0 = newTemp(ty);
1865 IRTemp src = newTemp(ty);
1866 IRTemp dst1 = newTemp(ty);
1867 UInt lit = getUDisp(size,delta);
1868 assign(dst0, getIReg(size,R_EAX));
1869 assign(src, mkU(ty,lit));
1870 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardjb9c5cf62004-08-24 15:10:38 +00001871 if (isAddSub(op8))
1872 setFlags_ADD_SUB(op8, src, dst0, ty);
1873 else
1874 setFlags_LOGIC(op8, dst1, ty);
sewardj0611d802004-07-11 02:37:54 +00001875
1876 if (keep)
1877 putIReg(size, R_EAX, mkexpr(dst1));
1878
1879 DIP("%s%c $0x%x, %s\n", t_x86opc, nameISize(size),
1880 lit, nameIReg(size,R_EAX));
1881 return delta+size;
1882}
sewardj9334b0f2004-07-10 22:43:54 +00001883
1884
1885/* Sign- and Zero-extending moves. */
1886static
1887UInt dis_movx_E_G ( UChar sorb,
1888 UInt delta, Int szs, Int szd, Bool sign_extend )
1889{
sewardj9334b0f2004-07-10 22:43:54 +00001890 UChar rm = getIByte(delta);
1891 if (epartIsReg(rm)) {
1892 putIReg(szd, gregOfRM(rm),
sewardjc4eaff32004-09-10 20:25:11 +00001893 unop(mkWidenOp(szs,szd,sign_extend),
sewardj9334b0f2004-07-10 22:43:54 +00001894 getIReg(szs,eregOfRM(rm))));
1895 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
1896 nameISize(szs), nameISize(szd),
1897 nameIReg(szs,eregOfRM(rm)),
1898 nameIReg(szd,gregOfRM(rm)));
1899 return 1+delta;
1900 }
1901
1902 /* E refers to memory */
1903 {
sewardj940e8c92004-07-11 16:53:24 +00001904 Int len;
1905 UChar dis_buf[50];
1906 IRTemp addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj0611d802004-07-11 02:37:54 +00001907
1908 putIReg(szd, gregOfRM(rm),
sewardjc4eaff32004-09-10 20:25:11 +00001909 unop(mkWidenOp(szs,szd,sign_extend),
sewardj940e8c92004-07-11 16:53:24 +00001910 loadLE(szToITy(szs),mkexpr(addr))));
sewardj9334b0f2004-07-10 22:43:54 +00001911 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
1912 nameISize(szs), nameISize(szd),
1913 dis_buf, nameIReg(szd,gregOfRM(rm)));
sewardj0611d802004-07-11 02:37:54 +00001914 return len+delta;
sewardj9334b0f2004-07-10 22:43:54 +00001915 }
1916}
1917
sewardj9690d922004-07-14 01:39:17 +00001918
1919/* Generate code to divide ArchRegs EDX:EAX / DX:AX / AX by the 32 /
1920 16 / 8 bit quantity in the given IRTemp. */
1921static
1922void codegen_div ( Int sz, IRTemp t, Bool signed_divide )
1923{
sewardje5427e82004-09-11 19:43:51 +00001924 IROp op = signed_divide ? Iop_DivModS64to32 : Iop_DivModU64to32;
1925 IRTemp src64 = newTemp(Ity_I64);
1926 IRTemp dst64 = newTemp(Ity_I64);
sewardj9690d922004-07-14 01:39:17 +00001927 switch (sz) {
sewardje5427e82004-09-11 19:43:51 +00001928 case 4:
sewardj9690d922004-07-14 01:39:17 +00001929 assign( src64, binop(Iop_32HLto64,
sewardje5427e82004-09-11 19:43:51 +00001930 getIReg(4,R_EDX), getIReg(4,R_EAX)) );
sewardj9690d922004-07-14 01:39:17 +00001931 assign( dst64, binop(op, mkexpr(src64), mkexpr(t)) );
sewardj8c7f1ab2004-07-29 20:31:09 +00001932 putIReg( 4, R_EAX, unop(Iop_64to32,mkexpr(dst64)) );
sewardj9690d922004-07-14 01:39:17 +00001933 putIReg( 4, R_EDX, unop(Iop_64HIto32,mkexpr(dst64)) );
1934 break;
sewardje5427e82004-09-11 19:43:51 +00001935 case 2: {
1936 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
1937 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
1938 assign( src64, unop(widen3264,
1939 binop(Iop_16HLto32,
1940 getIReg(2,R_EDX), getIReg(2,R_EAX))) );
1941 assign( dst64, binop(op, mkexpr(src64), unop(widen1632,mkexpr(t))) );
1942 putIReg( 2, R_EAX, unop(Iop_32to16,unop(Iop_64to32,mkexpr(dst64))) );
1943 putIReg( 2, R_EDX, unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(dst64))) );
1944 break;
sewardj9690d922004-07-14 01:39:17 +00001945 }
sewardj4e82db72004-10-16 11:32:15 +00001946 case 1: {
1947 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
1948 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
1949 IROp widen816 = signed_divide ? Iop_8Sto16 : Iop_8Uto16;
1950 assign( src64, unop(widen3264, unop(widen1632, getIReg(2,R_EAX))) );
1951 assign( dst64,
1952 binop(op, mkexpr(src64),
1953 unop(widen1632, unop(widen816, mkexpr(t)))) );
1954 putIReg( 1, R_AL, unop(Iop_16to8, unop(Iop_32to16,
1955 unop(Iop_64to32,mkexpr(dst64)))) );
1956 putIReg( 1, R_AH, unop(Iop_16to8, unop(Iop_32to16,
1957 unop(Iop_64HIto32,mkexpr(dst64)))) );
1958 break;
1959 }
sewardj9690d922004-07-14 01:39:17 +00001960 default: vpanic("codegen_div(x86)");
1961 }
1962}
sewardjc9a65702004-07-07 16:32:57 +00001963//-- Int helper;
1964//-- Int ta = newTemp(cb);
1965//-- Int td = newTemp(cb);
1966//--
1967//-- switch (sz) {
1968//-- case 4: helper = (signed_divide ? VGOFF_(helper_idiv_64_32)
1969//-- : VGOFF_(helper_div_64_32));
1970//-- break;
1971//-- case 2: helper = (signed_divide ? VGOFF_(helper_idiv_32_16)
1972//-- : VGOFF_(helper_div_32_16));
1973//-- break;
1974//-- case 1: helper = (signed_divide ? VGOFF_(helper_idiv_16_8)
1975//-- : VGOFF_(helper_div_16_8));
1976//-- break;
1977//-- default: VG_(core_panic)("codegen_div");
1978//-- }
1979//-- uInstr0(cb, CALLM_S, 0);
1980//-- if (sz == 4 || sz == 2) {
1981//-- uInstr1(cb, PUSH, sz, TempReg, t);
1982//-- uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
1983//-- uInstr1(cb, PUSH, sz, TempReg, ta);
1984//-- uInstr2(cb, GET, sz, ArchReg, R_EDX, TempReg, td);
1985//-- uInstr1(cb, PUSH, sz, TempReg, td);
1986//-- uInstr1(cb, CALLM, 0, Lit16, helper);
1987//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsOSZACP);
1988//-- uInstr1(cb, POP, sz, TempReg, t);
1989//-- uInstr2(cb, PUT, sz, TempReg, t, ArchReg, R_EDX);
1990//-- uInstr1(cb, POP, sz, TempReg, t);
1991//-- uInstr2(cb, PUT, sz, TempReg, t, ArchReg, R_EAX);
1992//-- uInstr1(cb, CLEAR, 0, Lit16, 4);
1993//-- } else {
1994//-- uInstr1(cb, PUSH, 1, TempReg, t);
1995//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, ta);
1996//-- uInstr1(cb, PUSH, 2, TempReg, ta);
1997//-- uInstr2(cb, MOV, 1, Literal, 0, TempReg, td);
1998//-- uLiteral(cb, 0);
1999//-- uInstr1(cb, PUSH, 1, TempReg, td);
2000//-- uInstr1(cb, CALLM, 0, Lit16, helper);
2001//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsOSZACP);
2002//-- uInstr1(cb, POP, 1, TempReg, t);
2003//-- uInstr2(cb, PUT, 1, TempReg, t, ArchReg, R_AL);
2004//-- uInstr1(cb, POP, 1, TempReg, t);
2005//-- uInstr2(cb, PUT, 1, TempReg, t, ArchReg, R_AH);
2006//-- uInstr1(cb, CLEAR, 0, Lit16, 4);
2007//-- }
2008//-- uInstr0(cb, CALLM_E, 0);
2009//-- }
sewardj41f43bc2004-07-08 14:23:22 +00002010
2011
2012static
sewardje90ad6a2004-07-10 19:02:10 +00002013UInt dis_Grp1 ( UChar sorb,
sewardj41f43bc2004-07-08 14:23:22 +00002014 UInt delta, UChar modrm,
2015 Int am_sz, Int d_sz, Int sz, UInt d32 )
2016{
sewardj41f43bc2004-07-08 14:23:22 +00002017 Int len;
2018 UChar dis_buf[50];
sewardje05c42c2004-07-08 20:25:10 +00002019 IRType ty = szToITy(sz);
2020 IRTemp dst1 = newTemp(ty);
2021 IRTemp src = newTemp(ty);
2022 IRTemp dst0 = newTemp(ty);
sewardj940e8c92004-07-11 16:53:24 +00002023 IRTemp addr = INVALID_IRTEMP;
sewardj66de2272004-07-16 21:19:05 +00002024 IROp op8 = Iop_INVALID;
sewardj180e8b32004-07-29 01:40:11 +00002025 UInt mask = sz==1 ? 0xFF : (sz==2 ? 0xFFFF : 0xFFFFFFFF);
sewardj41f43bc2004-07-08 14:23:22 +00002026
2027 switch (gregOfRM(modrm)) {
sewardje05c42c2004-07-08 20:25:10 +00002028 case 0: op8 = Iop_Add8; break; case 1: op8 = Iop_Or8; break;
sewardj66de2272004-07-16 21:19:05 +00002029 case 2: break; // ADC
2030 case 3: break; // SBB
sewardje05c42c2004-07-08 20:25:10 +00002031 case 4: op8 = Iop_And8; break; case 5: op8 = Iop_Sub8; break;
2032 case 6: op8 = Iop_Xor8; break; case 7: op8 = Iop_Sub8; break;
sewardj41f43bc2004-07-08 14:23:22 +00002033 default: vpanic("dis_Grp1: unhandled case");
2034 }
sewardj41f43bc2004-07-08 14:23:22 +00002035
2036 if (epartIsReg(modrm)) {
2037 vassert(am_sz == 1);
2038
2039 assign(dst0, getIReg(sz,eregOfRM(modrm)));
sewardj180e8b32004-07-29 01:40:11 +00002040 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002041
sewardj180e8b32004-07-29 01:40:11 +00002042 if (gregOfRM(modrm) == 2 /* ADC */) {
2043 helper_ADC( sz, dst1, dst0, src );
2044 } else
2045 if (gregOfRM(modrm) == 3 /* SBB */) {
2046 helper_SBB( sz, dst1, dst0, src );
2047 } else {
2048 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardjb9c5cf62004-08-24 15:10:38 +00002049 if (isAddSub(op8))
2050 setFlags_ADD_SUB(op8, src, dst0, ty);
2051 else
2052 setFlags_LOGIC(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00002053 }
sewardj41f43bc2004-07-08 14:23:22 +00002054
2055 if (gregOfRM(modrm) < 7)
sewardje05c42c2004-07-08 20:25:10 +00002056 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardj41f43bc2004-07-08 14:23:22 +00002057
2058 delta += (am_sz + d_sz);
2059 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz), d32,
2060 nameIReg(sz,eregOfRM(modrm)));
2061 } else {
sewardje87b4842004-07-10 12:23:30 +00002062 addr = disAMode ( &len, sorb, delta, dis_buf);
sewardj41f43bc2004-07-08 14:23:22 +00002063
sewardj940e8c92004-07-11 16:53:24 +00002064 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj180e8b32004-07-29 01:40:11 +00002065 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002066
sewardj66de2272004-07-16 21:19:05 +00002067 if (gregOfRM(modrm) == 2 /* ADC */) {
sewardj3af115f2004-07-14 02:46:52 +00002068 helper_ADC( sz, dst1, dst0, src );
2069 } else
sewardj66de2272004-07-16 21:19:05 +00002070 if (gregOfRM(modrm) == 3 /* SBB */) {
sewardj3af115f2004-07-14 02:46:52 +00002071 vassert(0);
2072 } else {
2073 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardjb9c5cf62004-08-24 15:10:38 +00002074 if (isAddSub(op8))
2075 setFlags_ADD_SUB(op8, src, dst0, ty);
2076 else
2077 setFlags_LOGIC(op8, dst1, ty);
sewardj3af115f2004-07-14 02:46:52 +00002078 }
sewardj41f43bc2004-07-08 14:23:22 +00002079
2080 if (gregOfRM(modrm) < 7)
sewardj940e8c92004-07-11 16:53:24 +00002081 storeLE(mkexpr(addr), mkexpr(dst1));
sewardj41f43bc2004-07-08 14:23:22 +00002082
2083 delta += (len+d_sz);
2084 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz),
2085 d32, dis_buf);
2086 }
2087 return delta;
2088}
2089
2090
sewardj6d2638e2004-07-15 09:38:27 +00002091/* Group 2 extended opcodes. shift_expr must be an 8-bit typed
2092 expression. */
2093
sewardje90ad6a2004-07-10 19:02:10 +00002094static
2095UInt dis_Grp2 ( UChar sorb,
2096 UInt delta, UChar modrm,
sewardj6d2638e2004-07-15 09:38:27 +00002097 Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
2098 Char* shift_expr_txt )
sewardje90ad6a2004-07-10 19:02:10 +00002099{
2100 /* delta on entry points at the modrm byte. */
sewardj6d2638e2004-07-15 09:38:27 +00002101 UChar dis_buf[50];
2102 Int len;
sewardj750f4072004-07-26 22:39:11 +00002103 Bool isShift, isRotate;
sewardj6d2638e2004-07-15 09:38:27 +00002104 IRType ty = szToITy(sz);
2105 IRTemp dst0 = newTemp(ty);
2106 IRTemp dst1 = newTemp(ty);
2107 IRTemp addr = INVALID_IRTEMP;
sewardje90ad6a2004-07-10 19:02:10 +00002108
2109 vassert(sz == 1 || sz == 2 || sz == 4);
2110
sewardje90ad6a2004-07-10 19:02:10 +00002111 /* Put value to shift/rotate in dst0. */
2112 if (epartIsReg(modrm)) {
2113 assign(dst0, getIReg(sz, eregOfRM(modrm)));
sewardj940e8c92004-07-11 16:53:24 +00002114 delta += (am_sz + d_sz);
sewardje90ad6a2004-07-10 19:02:10 +00002115 } else {
sewardj940e8c92004-07-11 16:53:24 +00002116 addr = disAMode ( &len, sorb, delta, dis_buf);
2117 assign(dst0, loadLE(ty,mkexpr(addr)));
2118 delta += len + d_sz;
sewardje90ad6a2004-07-10 19:02:10 +00002119 }
2120
2121 isShift = False;
2122 switch (gregOfRM(modrm)) { case 4: case 5: case 7: isShift = True; }
2123
sewardj750f4072004-07-26 22:39:11 +00002124 isRotate = False;
2125 switch (gregOfRM(modrm)) { case 0: case 1: isRotate = True; }
2126
sewardj8c7f1ab2004-07-29 20:31:09 +00002127 if (!isShift && !isRotate) {
2128 vex_printf("\ncase %d\n", gregOfRM(modrm));
2129 vpanic("dis_Grp2(Reg): unhandled case(x86)");
2130 }
2131
sewardje90ad6a2004-07-10 19:02:10 +00002132 if (isShift) {
2133
sewardjc22a6fd2004-07-29 23:41:47 +00002134 IRTemp pre32 = newTemp(Ity_I32);
2135 IRTemp res32 = newTemp(Ity_I32);
2136 IRTemp res32ss = newTemp(Ity_I32);
sewardj6d2638e2004-07-15 09:38:27 +00002137 IRTemp shift_amt = newTemp(Ity_I8);
sewardjc22a6fd2004-07-29 23:41:47 +00002138 IROp op32;
sewardje90ad6a2004-07-10 19:02:10 +00002139
2140 switch (gregOfRM(modrm)) {
sewardjc22a6fd2004-07-29 23:41:47 +00002141 case 4: op32 = Iop_Shl32; break;
2142 case 5: op32 = Iop_Shr32; break;
2143 case 7: op32 = Iop_Sar32; break;
sewardje90ad6a2004-07-10 19:02:10 +00002144 default: vpanic("dis_Grp2:shift"); break;
2145 }
2146
sewardjc22a6fd2004-07-29 23:41:47 +00002147 /* Widen the value to be shifted to 32 bits, do the shift, and
2148 narrow back down. This seems surprisingly long-winded, but
2149 unfortunately the Intel semantics requires that 8/16-bit
2150 shifts give defined results for shift values all the way up
2151 to 31, and this seems the simplest way to do it. It has the
2152 advantage that the only IR level shifts generated are of 32
2153 bit values, and the shift amount is guaranteed to be in the
2154 range 0 .. 31, thereby observing the IR semantics requiring
2155 all shift values to be in the range 0 .. 2^word_size-1. */
2156
2157 /* shift_amt = shift_expr & 31, regardless of operation size */
2158 assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(31)) );
2159
2160 /* suitably widen the value to be shifted to 32 bits. */
2161 assign( pre32, op32==Iop_Sar32 ? widenSto32(mkexpr(dst0))
2162 : widenUto32(mkexpr(dst0)) );
2163
2164 /* res32 = pre32 `shift` shift_amt */
2165 assign( res32, binop(op32, mkexpr(pre32), mkexpr(shift_amt)) );
2166
2167 /* res32ss = pre32 `shift` ((shift_amt - 1) & 31) */
2168 assign( res32ss,
2169 binop(op32,
2170 mkexpr(pre32),
2171 binop(Iop_And8,
2172 binop(Iop_Sub8,
2173 mkexpr(shift_amt), mkU8(1)),
2174 mkU8(31))) );
sewardje90ad6a2004-07-10 19:02:10 +00002175
2176 /* Build the flags thunk. */
sewardjc22a6fd2004-07-29 23:41:47 +00002177 setFlags_DSTus_DST1(op32, res32ss, res32, ty, shift_amt);
2178
2179 /* Narrow the result back down. */
2180 assign( dst1, narrowTo(ty, mkexpr(res32)) );
sewardj750f4072004-07-26 22:39:11 +00002181
sewardj1813dbe2004-07-28 17:09:04 +00002182 } /* if (isShift) */
2183
2184 else
sewardj750f4072004-07-26 22:39:11 +00002185 if (isRotate) {
sewardj7ebbdae2004-08-26 12:30:48 +00002186 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
2187 Bool left = gregOfRM(modrm) == 0;
2188 IRTemp rot_amt = newTemp(Ity_I8);
2189 IRTemp rot_amt32 = newTemp(Ity_I8);
2190 IRTemp oldFlags = newTemp(Ity_I32);
sewardj750f4072004-07-26 22:39:11 +00002191
2192 /* rot_amt = shift_expr & mask */
sewardjc22a6fd2004-07-29 23:41:47 +00002193 /* By masking the rotate amount thusly, the IR-level Shl/Shr
2194 expressions never shift beyond the word size and thus remain
2195 well defined. */
sewardj7ebbdae2004-08-26 12:30:48 +00002196 assign(rot_amt32, binop(Iop_And8, shift_expr, mkU8(31)));
2197
2198 if (ty == Ity_I32)
2199 assign(rot_amt, mkexpr(rot_amt32));
2200 else
2201 assign(rot_amt, binop(Iop_And8, mkexpr(rot_amt32), mkU8(8*sz-1)));
sewardj750f4072004-07-26 22:39:11 +00002202
2203 if (left) {
sewardj1813dbe2004-07-28 17:09:04 +00002204
sewardj750f4072004-07-26 22:39:11 +00002205 /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
2206 assign(dst1,
2207 binop( mkSizedOp(ty,Iop_Or8),
2208 binop( mkSizedOp(ty,Iop_Shl8),
2209 mkexpr(dst0),
2210 mkexpr(rot_amt)
2211 ),
2212 binop( mkSizedOp(ty,Iop_Shr8),
2213 mkexpr(dst0),
2214 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
2215 )
2216 )
2217 );
sewardj1813dbe2004-07-28 17:09:04 +00002218 ccOp += CC_OP_ROLB;
sewardj750f4072004-07-26 22:39:11 +00002219
sewardj1813dbe2004-07-28 17:09:04 +00002220 } else { /* right */
sewardj750f4072004-07-26 22:39:11 +00002221
sewardj1813dbe2004-07-28 17:09:04 +00002222 /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
2223 assign(dst1,
2224 binop( mkSizedOp(ty,Iop_Or8),
2225 binop( mkSizedOp(ty,Iop_Shr8),
2226 mkexpr(dst0),
2227 mkexpr(rot_amt)
2228 ),
2229 binop( mkSizedOp(ty,Iop_Shl8),
2230 mkexpr(dst0),
2231 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
sewardj750f4072004-07-26 22:39:11 +00002232 )
2233 )
2234 );
sewardj1813dbe2004-07-28 17:09:04 +00002235 ccOp += CC_OP_RORB;
sewardjc22a6fd2004-07-29 23:41:47 +00002236
sewardj750f4072004-07-26 22:39:11 +00002237 }
sewardjc22a6fd2004-07-29 23:41:47 +00002238
sewardj1813dbe2004-07-28 17:09:04 +00002239 /* dst1 now holds the rotated value. Build flag thunk. We
2240 need the resulting value for this, and the previous flags.
2241 Except don't set it if the rotate count is zero. */
2242
2243 assign(oldFlags, mk_calculate_eflags_all());
2244
2245 /* CC_DST is the rotated value. CC_SRC is flags before. */
2246 stmt( IRStmt_Put( OFFB_CC_OP,
sewardj7ebbdae2004-08-26 12:30:48 +00002247 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj1813dbe2004-07-28 17:09:04 +00002248 IRExpr_Get(OFFB_CC_OP,Ity_I32),
2249 mkU32(ccOp))) );
2250 stmt( IRStmt_Put( OFFB_CC_DST,
sewardj7ebbdae2004-08-26 12:30:48 +00002251 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj1813dbe2004-07-28 17:09:04 +00002252 IRExpr_Get(OFFB_CC_DST,Ity_I32),
sewardjc22a6fd2004-07-29 23:41:47 +00002253 widenUto32(mkexpr(dst1)))) );
sewardj1813dbe2004-07-28 17:09:04 +00002254 stmt( IRStmt_Put( OFFB_CC_SRC,
sewardj7ebbdae2004-08-26 12:30:48 +00002255 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj1813dbe2004-07-28 17:09:04 +00002256 IRExpr_Get(OFFB_CC_SRC,Ity_I32),
2257 mkexpr(oldFlags))) );
2258 } /* if (isRotate) */
sewardje90ad6a2004-07-10 19:02:10 +00002259
2260 /* Save result, and finish up. */
2261 if (epartIsReg(modrm)) {
2262 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
2263 if (print_codegen) {
2264 vex_printf("%s%c ",
2265 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002266 if (shift_expr_txt)
2267 vex_printf("%s", shift_expr_txt);
2268 else
2269 ppIRExpr(shift_expr);
sewardje90ad6a2004-07-10 19:02:10 +00002270 vex_printf(", %s\n", nameIReg(sz,eregOfRM(modrm)));
2271 }
sewardje90ad6a2004-07-10 19:02:10 +00002272 } else {
sewardj940e8c92004-07-11 16:53:24 +00002273 storeLE(mkexpr(addr), mkexpr(dst1));
2274 if (print_codegen) {
2275 vex_printf("%s%c ",
2276 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002277 if (shift_expr_txt)
2278 vex_printf("%s", shift_expr_txt);
2279 else
2280 ppIRExpr(shift_expr);
sewardj940e8c92004-07-11 16:53:24 +00002281 vex_printf(", %s\n", dis_buf);
2282 }
sewardje90ad6a2004-07-10 19:02:10 +00002283 }
sewardje90ad6a2004-07-10 19:02:10 +00002284 return delta;
2285}
2286
2287
2288
sewardjc9a65702004-07-07 16:32:57 +00002289//-- /* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
2290//-- static
2291//-- Addr dis_Grp8_BT ( UCodeBlock* cb,
2292//-- UChar sorb,
2293//-- Addr eip, UChar modrm,
2294//-- Int am_sz, Int sz, UInt src_val )
2295//-- {
sewardjd1061ab2004-07-08 01:45:30 +00002296# define MODIFY_t2_AND_SET_CARRY_FLAG \
2297 /* t2 is the value to be op'd on. Copy to t_fetched, then \
2298 modify t2, if non-BT. */ \
2299 uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t_fetched); \
2300 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
2301 uLiteral(cb, v_mask); \
2302 switch (gregOfRM(modrm)) { \
2303 case 4: /* BT */ break; \
2304 case 5: /* BTS */ \
2305 uInstr2(cb, OR, sz, TempReg, t_mask, TempReg, t2); break; \
2306 case 6: /* BTR */ \
2307 uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t2); break; \
2308 case 7: /* BTC */ \
2309 uInstr2(cb, XOR, sz, TempReg, t_mask, TempReg, t2); break; \
2310 } \
2311 /* Copy relevant bit from t_fetched into carry flag. */ \
2312 uInstr2(cb, SHR, sz, Literal, 0, TempReg, t_fetched); \
2313 uLiteral(cb, src_val); \
2314 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
2315 uLiteral(cb, 1); \
2316 uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t_fetched); \
2317 uInstr1(cb, NEG, sz, TempReg, t_fetched); \
2318 setFlagsFromUOpcode(cb, NEG);
2319
2320
sewardjc9a65702004-07-07 16:32:57 +00002321//-- /* src_val denotes a d8.
2322//-- And eip on entry points at the modrm byte. */
2323//-- Int t1, t2, t_fetched, t_mask;
2324//-- UInt pair;
2325//-- Char dis_buf[50];
2326//-- UInt v_mask;
2327//--
2328//-- /* There is no 1-byte form of this instruction, AFAICS. */
2329//-- vg_assert(sz == 2 || sz == 4);
2330//--
2331//-- /* Limit src_val -- the bit offset -- to something within a word.
2332//-- The Intel docs say that literal offsets larger than a word are
2333//-- masked in this way. */
2334//-- switch (sz) {
2335//-- case 2: src_val &= 15; break;
2336//-- case 4: src_val &= 31; break;
2337//-- default: VG_(core_panic)("dis_Grp8_BT: invalid size");
2338//-- }
2339//--
2340//-- /* Invent a mask suitable for the operation. */
2341//--
2342//-- switch (gregOfRM(modrm)) {
2343//-- case 4: /* BT */ v_mask = 0; break;
2344//-- case 5: /* BTS */ v_mask = 1 << src_val; break;
2345//-- case 6: /* BTR */ v_mask = ~(1 << src_val); break;
2346//-- case 7: /* BTC */ v_mask = 1 << src_val; break;
2347//-- /* If this needs to be extended, probably simplest to make a
2348//-- new function to handle the other cases (0 .. 3). The
2349//-- Intel docs do however not indicate any use for 0 .. 3, so
2350//-- we don't expect this to happen. */
2351//-- default: VG_(core_panic)("dis_Grp8_BT");
2352//-- }
2353//-- /* Probably excessively paranoid. */
2354//-- if (sz == 2)
2355//-- v_mask &= 0x0000FFFF;
2356//--
2357//-- t1 = INVALID_TEMPREG;
2358//-- t_fetched = newTemp(cb);
2359//-- t_mask = newTemp(cb);
2360//--
2361//-- if (epartIsReg(modrm)) {
2362//-- vg_assert(am_sz == 1);
2363//-- t2 = newTemp(cb);
2364//--
2365//-- /* Fetch the value to be tested and modified. */
2366//-- uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t2);
2367//-- /* Do it! */
2368//-- MODIFY_t2_AND_SET_CARRY_FLAG;
2369//-- /* Dump the result back, if non-BT. */
2370//-- if (gregOfRM(modrm) != 4 /* BT */)
2371//-- uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, eregOfRM(modrm));
2372//--
2373//-- eip += (am_sz + 1);
2374//-- DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2375//-- src_val, nameIReg(sz,eregOfRM(modrm)));
2376//-- } else {
2377//-- pair = disAMode ( cb, sorb, eip, dis_buf);
2378//-- t1 = LOW24(pair);
2379//-- t2 = newTemp(cb);
2380//-- eip += HI8(pair);
2381//-- eip += 1;
2382//--
2383//-- /* Fetch the value to be tested and modified. */
2384//-- uInstr2(cb, LOAD, sz, TempReg, t1, TempReg, t2);
2385//-- /* Do it! */
2386//-- MODIFY_t2_AND_SET_CARRY_FLAG;
2387//-- /* Dump the result back, if non-BT. */
2388//-- if (gregOfRM(modrm) != 4 /* BT */) {
2389//-- uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
2390//-- }
2391//-- DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2392//-- src_val, dis_buf);
2393//-- }
2394//-- return eip;
2395//--
2396//-- # undef MODIFY_t2_AND_SET_CARRY_FLAG
2397//-- }
sewardjcf780b42004-07-13 18:42:17 +00002398
2399
2400
sewardj1813dbe2004-07-28 17:09:04 +00002401/* Signed/unsigned widening multiply. Generate IR to multiply the
2402 value in EAX/AX/AL by the given IRTemp, and park the result in
2403 EDX:EAX/DX:AX/AX.
sewardjcf780b42004-07-13 18:42:17 +00002404*/
sewardj1813dbe2004-07-28 17:09:04 +00002405static void codegen_mulL_A_D ( Int sz, Bool syned,
2406 IRTemp tmp, Char* tmp_txt )
sewardjcf780b42004-07-13 18:42:17 +00002407{
sewardjcf780b42004-07-13 18:42:17 +00002408 IRType ty = szToITy(sz);
2409 IRTemp t1 = newTemp(ty);
sewardjcf780b42004-07-13 18:42:17 +00002410
sewardj1813dbe2004-07-28 17:09:04 +00002411 assign( t1, getIReg(sz, R_EAX) );
sewardjcf780b42004-07-13 18:42:17 +00002412
2413 switch (ty) {
sewardjb81f8b32004-07-30 10:17:50 +00002414 case Ity_I32: {
2415 IRTemp res64 = newTemp(Ity_I64);
2416 IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32;
2417 UInt tBaseOp = syned ? CC_OP_SMULB : CC_OP_UMULB;
2418 setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
2419 assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
2420 putIReg(4, R_EDX, unop(Iop_64HIto32,mkexpr(res64)));
2421 putIReg(4, R_EAX, unop(Iop_64to32,mkexpr(res64)));
2422 break;
2423 }
2424 case Ity_I16: {
2425 IRTemp res32 = newTemp(Ity_I32);
2426 IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16;
2427 UInt tBaseOp = syned ? CC_OP_SMULB : CC_OP_UMULB;
2428 setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
2429 assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
2430 putIReg(2, R_EDX, unop(Iop_32HIto16,mkexpr(res32)));
2431 putIReg(2, R_EAX, unop(Iop_32to16,mkexpr(res32)));
2432 break;
2433 }
2434 case Ity_I8: {
2435 IRTemp res16 = newTemp(Ity_I16);
2436 IROp mulOp = syned ? Iop_MullS8 : Iop_MullU8;
2437 UInt tBaseOp = syned ? CC_OP_SMULB : CC_OP_UMULB;
2438 setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
2439 assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
2440 putIReg(2, R_EAX, mkexpr(res16));
2441 break;
2442 }
2443 default:
2444 vpanic("codegen_mulL_A_D(x86)");
sewardjcf780b42004-07-13 18:42:17 +00002445 }
sewardj1813dbe2004-07-28 17:09:04 +00002446 DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
sewardjcf780b42004-07-13 18:42:17 +00002447}
2448
sewardj940e8c92004-07-11 16:53:24 +00002449
2450/* Group 3 extended opcodes. */
2451static
2452UInt dis_Grp3 ( UChar sorb, Int sz, UInt delta )
2453{
sewardjc2ac51e2004-07-12 01:03:26 +00002454 UInt d32;
sewardj940e8c92004-07-11 16:53:24 +00002455 UChar modrm;
2456 UChar dis_buf[50];
sewardjc2ac51e2004-07-12 01:03:26 +00002457 Int len;
2458 IRTemp addr;
sewardj940e8c92004-07-11 16:53:24 +00002459 IRType ty = szToITy(sz);
2460 IRTemp t1 = newTemp(ty);
sewardjc2ac51e2004-07-12 01:03:26 +00002461 // IRTemp t2 = INVALID_IRTEMP;
sewardj940e8c92004-07-11 16:53:24 +00002462 IRTemp dst1, src, dst0;
2463 modrm = getIByte(delta);
2464 if (epartIsReg(modrm)) {
2465 switch (gregOfRM(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002466 case 0: { /* TEST */
2467 delta++; d32 = getUDisp(sz, delta); delta += sz;
2468 dst1 = newTemp(ty);
2469 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2470 getIReg(sz,eregOfRM(modrm)),
2471 mkU(ty,d32)));
sewardjb9c5cf62004-08-24 15:10:38 +00002472 setFlags_LOGIC( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002473 DIP("test%c $0x%x, %s\n", nameISize(sz), d32,
2474 nameIReg(sz, eregOfRM(modrm)));
2475 break;
2476 }
sewardj940e8c92004-07-11 16:53:24 +00002477 case 2: /* NOT */
2478 delta++;
2479 putIReg(sz, eregOfRM(modrm),
2480 unop(mkSizedOp(ty,Iop_Not8),
2481 getIReg(sz, eregOfRM(modrm))));
2482 DIP("not%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2483 break;
2484 case 3: /* NEG */
2485 delta++;
2486 dst0 = newTemp(ty);
2487 src = newTemp(ty);
2488 dst1 = newTemp(ty);
sewardja511afc2004-07-29 22:26:03 +00002489 assign(dst0, mkU(ty,0));
2490 assign(src, getIReg(sz,eregOfRM(modrm)));
2491 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
sewardjb9c5cf62004-08-24 15:10:38 +00002492 setFlags_ADD_SUB(Iop_Sub8, src, dst0, ty);
sewardj940e8c92004-07-11 16:53:24 +00002493 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
2494 DIP("neg%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2495 break;
sewardjcf780b42004-07-13 18:42:17 +00002496 case 4: /* MUL (unsigned widening) */
2497 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002498 src = newTemp(ty);
2499 assign(src, getIReg(sz,eregOfRM(modrm)));
2500 codegen_mulL_A_D ( sz, False, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcf780b42004-07-13 18:42:17 +00002501 break;
sewardjcaca9d02004-07-28 07:11:32 +00002502 case 5: /* IMUL (signed widening) */
2503 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002504 src = newTemp(ty);
2505 assign(src, getIReg(sz,eregOfRM(modrm)));
2506 codegen_mulL_A_D ( sz, True, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcaca9d02004-07-28 07:11:32 +00002507 break;
sewardj68511542004-07-28 00:15:44 +00002508 case 6: /* DIV */
2509 delta++;
2510 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2511 codegen_div ( sz, t1, False );
2512 DIP("div%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2513 break;
sewardjcaca9d02004-07-28 07:11:32 +00002514 case 7: /* IDIV */
2515 delta++;
2516 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2517 codegen_div ( sz, t1, True );
2518 DIP("idiv%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2519 break;
sewardj940e8c92004-07-11 16:53:24 +00002520 default:
2521 vex_printf(
2522 "unhandled Grp3(R) case %d\n", (UInt)gregOfRM(modrm));
2523 vpanic("Grp3(x86)");
2524 }
2525 } else {
sewardjc2ac51e2004-07-12 01:03:26 +00002526 addr = disAMode ( &len, sorb, delta, dis_buf );
2527 t1 = newTemp(ty);
2528 delta += len;
2529 assign(t1, loadLE(ty,mkexpr(addr)));
2530 switch (gregOfRM(modrm)) {
2531 case 0: { /* TEST */
2532 d32 = getUDisp(sz, delta); delta += sz;
2533 dst1 = newTemp(ty);
2534 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2535 mkexpr(t1), mkU(ty,d32)));
sewardjb9c5cf62004-08-24 15:10:38 +00002536 setFlags_LOGIC( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002537 DIP("test%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
2538 break;
2539 }
sewardj78fe7912004-08-20 23:38:07 +00002540 /* probably OK, but awaiting test case */
2541 case 2: /* NOT */
2542 storeLE( mkexpr(addr), unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
2543 DIP("not%c %s\n", nameISize(sz), dis_buf);
2544 break;
sewardj0c12ea82004-07-12 08:18:16 +00002545 case 3: /* NEG */
2546 dst0 = newTemp(ty);
2547 src = newTemp(ty);
2548 dst1 = newTemp(ty);
sewardja511afc2004-07-29 22:26:03 +00002549 assign(dst0, mkU(ty,0));
2550 assign(src, mkexpr(t1));
2551 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
sewardjb9c5cf62004-08-24 15:10:38 +00002552 setFlags_ADD_SUB(Iop_Sub8, src, dst0, ty);
sewardj0c12ea82004-07-12 08:18:16 +00002553 storeLE( mkexpr(addr), mkexpr(dst1) );
2554 DIP("neg%c %s\n", nameISize(sz), dis_buf);
2555 break;
sewardj1813dbe2004-07-28 17:09:04 +00002556 case 4: /* MUL */
2557 codegen_mulL_A_D ( sz, False, t1, dis_buf );
2558 break;
2559 case 5: /* IMUL */
2560 codegen_mulL_A_D ( sz, True, t1, dis_buf );
2561 break;
sewardj9690d922004-07-14 01:39:17 +00002562 case 6: /* DIV */
2563 codegen_div ( sz, t1, False );
2564 DIP("div%c %s\n", nameISize(sz), dis_buf);
2565 break;
sewardj1813dbe2004-07-28 17:09:04 +00002566 case 7: /* IDIV */
2567 codegen_div ( sz, t1, True );
2568 DIP("idiv%c %s\n", nameISize(sz), dis_buf);
2569 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002570 default:
2571 vex_printf(
2572 "unhandled Grp3(M) case %d\n", (UInt)gregOfRM(modrm));
2573 vpanic("Grp3(x86)");
2574 }
sewardj940e8c92004-07-11 16:53:24 +00002575 }
2576 return delta;
2577}
2578
2579
sewardjc2ac51e2004-07-12 01:03:26 +00002580/* Group 4 extended opcodes. */
2581static
2582UInt dis_Grp4 ( UChar sorb, UInt delta )
2583{
sewardj7ed22952004-07-29 00:09:58 +00002584 Int alen;
sewardjc2ac51e2004-07-12 01:03:26 +00002585 UChar modrm;
sewardj7ed22952004-07-29 00:09:58 +00002586 UChar dis_buf[50];
sewardjc2ac51e2004-07-12 01:03:26 +00002587 IRType ty = Ity_I8;
sewardj7ed22952004-07-29 00:09:58 +00002588 IRTemp t1 = newTemp(ty);
2589 IRTemp t2 = newTemp(ty);
sewardjc2ac51e2004-07-12 01:03:26 +00002590
2591 modrm = getIByte(delta);
2592 if (epartIsReg(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002593 assign(t1, getIReg(1, eregOfRM(modrm)));
2594 switch (gregOfRM(modrm)) {
sewardj7ed22952004-07-29 00:09:58 +00002595 case 0: /* INC */
2596 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
2597 putIReg(1, eregOfRM(modrm), mkexpr(t2));
2598 setFlags_INC_DEC( True, t2, ty );
2599 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002600 case 1: /* DEC */
sewardjc2ac51e2004-07-12 01:03:26 +00002601 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
2602 putIReg(1, eregOfRM(modrm), mkexpr(t2));
2603 setFlags_INC_DEC( False, t2, ty );
2604 break;
2605 default:
2606 vex_printf(
2607 "unhandled Grp4(R) case %d\n", (UInt)gregOfRM(modrm));
sewardj7ed22952004-07-29 00:09:58 +00002608 vpanic("Grp4(x86,R)");
sewardjc2ac51e2004-07-12 01:03:26 +00002609 }
2610 delta++;
2611 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)),
2612 nameIReg(1, eregOfRM(modrm)));
2613 } else {
sewardj7ed22952004-07-29 00:09:58 +00002614 IRTemp addr = disAMode ( &alen, sorb, delta, dis_buf );
2615 assign( t1, loadLE(ty, mkexpr(addr)) );
2616 switch (gregOfRM(modrm)) {
sewardj588ea762004-09-10 18:56:32 +00002617 case 0: /* INC */
2618 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
2619 storeLE( mkexpr(addr), mkexpr(t2) );
2620 setFlags_INC_DEC( True, t2, ty );
2621 break;
sewardj7ed22952004-07-29 00:09:58 +00002622 case 1: /* DEC */
2623 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
2624 storeLE( mkexpr(addr), mkexpr(t2) );
2625 setFlags_INC_DEC( False, t2, ty );
2626 break;
2627 default:
2628 vex_printf(
2629 "unhandled Grp4(M) case %d\n", (UInt)gregOfRM(modrm));
2630 vpanic("Grp4(x86,M)");
2631 }
2632 delta += alen;
2633 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)), dis_buf);
sewardjc2ac51e2004-07-12 01:03:26 +00002634 }
2635 return delta;
2636}
sewardj0611d802004-07-11 02:37:54 +00002637
2638
2639/* Group 5 extended opcodes. */
2640static
2641UInt dis_Grp5 ( UChar sorb, Int sz, UInt delta, Bool* isEnd )
2642{
2643 Int len;
2644 UChar modrm;
2645 UChar dis_buf[50];
sewardj940e8c92004-07-11 16:53:24 +00002646 IRTemp addr = INVALID_IRTEMP;
sewardj0611d802004-07-11 02:37:54 +00002647 IRType ty = szToITy(sz);
2648 IRTemp t1 = newTemp(ty);
2649 IRTemp t2 = INVALID_IRTEMP;
2650
2651 modrm = getIByte(delta);
2652 if (epartIsReg(modrm)) {
sewardj940e8c92004-07-11 16:53:24 +00002653 assign(t1, getIReg(sz,eregOfRM(modrm)));
sewardj0611d802004-07-11 02:37:54 +00002654 switch (gregOfRM(modrm)) {
sewardjc9a65702004-07-07 16:32:57 +00002655//-- case 0: /* INC */
2656//-- uInstr1(cb, INC, sz, TempReg, t1);
2657//-- setFlagsFromUOpcode(cb, INC);
2658//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
2659//-- break;
2660//-- case 1: /* DEC */
2661//-- uInstr1(cb, DEC, sz, TempReg, t1);
2662//-- setFlagsFromUOpcode(cb, DEC);
2663//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
2664//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +00002665 case 2: /* call Ev */
2666 vassert(sz == 4);
2667 t2 = newTemp(Ity_I32);
2668 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
2669 putIReg(4, R_ESP, mkexpr(t2));
2670 storeLE( mkexpr(t2), mkU32(guest_eip+delta+1));
sewardj78c19df2004-07-12 22:49:27 +00002671 jmp_treg(Ijk_Call,t1);
sewardjc2ac51e2004-07-12 01:03:26 +00002672 *isEnd = True;
2673 break;
sewardj0611d802004-07-11 02:37:54 +00002674 case 4: /* jmp Ev */
2675 vassert(sz == 4);
sewardj78c19df2004-07-12 22:49:27 +00002676 jmp_treg(Ijk_Boring,t1);
sewardj0611d802004-07-11 02:37:54 +00002677 *isEnd = True;
2678 break;
2679 default:
2680 vex_printf(
2681 "unhandled Grp5(R) case %d\n", (UInt)gregOfRM(modrm));
2682 vpanic("Grp5(x86)");
2683 }
2684 delta++;
2685 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
2686 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2687 } else {
2688 addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj940e8c92004-07-11 16:53:24 +00002689 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj0611d802004-07-11 02:37:54 +00002690 switch (gregOfRM(modrm)) {
2691 case 0: /* INC */
2692 t2 = newTemp(ty);
2693 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
2694 mkexpr(t1), mkU(ty,1)));
2695 setFlags_INC_DEC( True, t2, ty );
sewardj940e8c92004-07-11 16:53:24 +00002696 storeLE(mkexpr(addr),mkexpr(t2));
sewardj0611d802004-07-11 02:37:54 +00002697 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002698 case 1: /* DEC */
2699 t2 = newTemp(ty);
2700 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
2701 mkexpr(t1), mkU(ty,1)));
2702 setFlags_INC_DEC( False, t2, ty );
2703 storeLE(mkexpr(addr),mkexpr(t2));
2704 break;
sewardj77b86be2004-07-11 13:28:24 +00002705 case 2: /* call Ev */
2706 vassert(sz == 4);
2707 t2 = newTemp(Ity_I32);
2708 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
2709 putIReg(4, R_ESP, mkexpr(t2));
2710 storeLE( mkexpr(t2), mkU32(guest_eip+delta+len));
sewardj78c19df2004-07-12 22:49:27 +00002711 jmp_treg(Ijk_Call,t1);
sewardj77b86be2004-07-11 13:28:24 +00002712 *isEnd = True;
2713 break;
2714 case 4: /* JMP Ev */
2715 vassert(sz == 4);
sewardj78c19df2004-07-12 22:49:27 +00002716 jmp_treg(Ijk_Boring,t1);
sewardj77b86be2004-07-11 13:28:24 +00002717 *isEnd = True;
2718 break;
sewardj0c12ea82004-07-12 08:18:16 +00002719 case 6: /* PUSH Ev */
2720 vassert(sz == 4 || sz == 2);
2721 t2 = newTemp(Ity_I32);
2722 assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
2723 putIReg(4, R_ESP, mkexpr(t2) );
2724 storeLE( mkexpr(t2), mkexpr(t1) );
2725 break;
sewardj0611d802004-07-11 02:37:54 +00002726 default:
2727 vex_printf(
2728 "unhandled Grp5(M) case %d\n", (UInt)gregOfRM(modrm));
2729 vpanic("Grp5(x86)");
2730 }
2731 delta += len;
2732 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
2733 nameISize(sz), dis_buf);
2734 }
2735 return delta;
2736}
2737
sewardj64e1d652004-07-12 14:00:46 +00002738/*------------------------------------------------------------*/
2739/*--- Disassembling string ops (including REP prefixes) ---*/
2740/*------------------------------------------------------------*/
2741
2742/* Code shared by all the string ops */
2743static
2744void dis_string_op_increment(Int sz, Int t_inc)
2745{
2746 if (sz == 4 || sz == 2) {
2747 assign( t_inc,
2748 binop(Iop_Shl32, IRExpr_Get( OFFB_DFLAG, Ity_I32 ),
sewardj6d2638e2004-07-15 09:38:27 +00002749 mkU8(sz/2) ) );
sewardj64e1d652004-07-12 14:00:46 +00002750 } else {
2751 assign( t_inc,
2752 IRExpr_Get( OFFB_DFLAG, Ity_I32 ) );
2753 }
2754}
2755
sewardj64e1d652004-07-12 14:00:46 +00002756static
2757void dis_string_op( void (*dis_OP)( Int, IRTemp ),
2758 Int sz, Char* name, UChar sorb )
2759{
2760 IRTemp t_inc = newTemp(Ity_I32);
2761 vassert(sorb == 0);
2762 dis_string_op_increment(sz, t_inc);
2763 dis_OP( sz, t_inc );
2764 DIP("%s%c\n", name, nameISize(sz));
2765}
sewardj64e1d652004-07-12 14:00:46 +00002766
2767static
2768void dis_MOVS ( Int sz, IRTemp t_inc )
2769{
2770 IRType ty = szToITy(sz);
2771 //IRTemp tv = newTemp(ty); /* value being copied */
2772 IRTemp td = newTemp(Ity_I32); /* EDI */
2773 IRTemp ts = newTemp(Ity_I32); /* ESI */
2774
2775 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
2776 //uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
2777 assign( td, getIReg(4, R_EDI) );
2778 assign( ts, getIReg(4, R_ESI) );
2779
2780 //uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tv);
2781 //uInstr2(cb, STORE,sz, TempReg, tv, TempReg, td);
2782 storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
2783
2784 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
2785 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
2786
2787 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2788 //uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
2789 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
2790 putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
2791}
2792
sewardjc9a65702004-07-07 16:32:57 +00002793//-- static
2794//-- void dis_LODS ( UCodeBlock* cb, Int sz, Int t_inc )
2795//-- {
2796//-- Int ta = newTemp(cb); /* EAX */
2797//-- Int ts = newTemp(cb); /* ESI */
2798//--
2799//-- uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
2800//-- uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, ta);
2801//-- uInstr2(cb, PUT, sz, TempReg, ta, ArchReg, R_EAX);
2802//--
2803//-- uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
2804//-- uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
2805//-- }
sewardj64e1d652004-07-12 14:00:46 +00002806
2807static
2808void dis_STOS ( Int sz, IRTemp t_inc )
2809{
2810 IRType ty = szToITy(sz);
2811 IRTemp ta = newTemp(ty); /* EAX */
2812 IRTemp td = newTemp(Ity_I32); /* EDI */
2813
2814 //uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
2815 assign( ta, getIReg(sz, R_EAX) );
2816
2817 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
2818 assign( td, getIReg(4, R_EDI) );
2819
2820 //uInstr2(cb, STORE, sz, TempReg, ta, TempReg, td);
sewardj6d2638e2004-07-15 09:38:27 +00002821 storeLE( mkexpr(td), mkexpr(ta) );
sewardj64e1d652004-07-12 14:00:46 +00002822
2823 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
2824 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2825 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
2826}
2827
2828static
2829void dis_CMPS ( Int sz, IRTemp t_inc )
2830{
2831 IRType ty = szToITy(sz);
sewardj6d2638e2004-07-15 09:38:27 +00002832 IRTemp tdv = newTemp(ty); /* (EDI) */
2833 IRTemp tsv = newTemp(ty); /* (ESI) */
sewardj64e1d652004-07-12 14:00:46 +00002834 IRTemp td = newTemp(Ity_I32); /* EDI */
2835 IRTemp ts = newTemp(Ity_I32); /* ESI */
2836
2837 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
2838 assign( td, getIReg(4, R_EDI) );
2839
2840 //uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
2841 assign( ts, getIReg(4, R_ESI) );
2842
2843 //uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tdv);
2844 assign( tdv, loadLE(ty,mkexpr(td)) );
2845
2846 //uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tsv);
sewardjb9c5cf62004-08-24 15:10:38 +00002847 assign( tsv, loadLE(ty,mkexpr(ts)) );
sewardj64e1d652004-07-12 14:00:46 +00002848
2849 //uInstr2(cb, SUB, sz, TempReg, tdv, TempReg, tsv);
2850 //setFlagsFromUOpcode(cb, SUB);
sewardjb9c5cf62004-08-24 15:10:38 +00002851 setFlags_ADD_SUB ( Iop_Sub8, tdv, tsv, ty );
sewardj64e1d652004-07-12 14:00:46 +00002852
2853 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
2854 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
2855
2856 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2857 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
2858
2859 //uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
2860 putIReg(4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
2861}
2862
sewardj64e1d652004-07-12 14:00:46 +00002863static
2864void dis_SCAS ( Int sz, IRTemp t_inc )
2865{
2866 IRType ty = szToITy(sz);
sewardj82292882004-07-27 00:15:59 +00002867 IRTemp ta = newTemp(ty); /* EAX */
sewardj64e1d652004-07-12 14:00:46 +00002868 IRTemp td = newTemp(Ity_I32); /* EDI */
2869 IRTemp tdv = newTemp(ty); /* (EDI) */
2870
2871 //uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
sewardjb9c5cf62004-08-24 15:10:38 +00002872 assign( ta, getIReg(sz, R_EAX) );
sewardj64e1d652004-07-12 14:00:46 +00002873
2874 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
2875 assign( td, getIReg(4, R_EDI) );
2876
2877 //uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tdv);
2878 assign( tdv, loadLE(ty,mkexpr(td)) );
2879
sewardj64e1d652004-07-12 14:00:46 +00002880 //uInstr2(cb, SUB, sz, TempReg, tdv, TempReg, ta);
2881 //setFlagsFromUOpcode(cb, SUB);
sewardjb9c5cf62004-08-24 15:10:38 +00002882 setFlags_ADD_SUB( Iop_Sub8, tdv, ta, ty );
sewardj64e1d652004-07-12 14:00:46 +00002883
2884 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
2885 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2886 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
2887}
sewardj82292882004-07-27 00:15:59 +00002888
sewardj64e1d652004-07-12 14:00:46 +00002889
2890/* Wrap the appropriate string op inside a REP/REPE/REPNE.
2891 We assume the insn is the last one in the basic block, and so emit a jump
2892 to the next insn, rather than just falling through. */
2893static
2894void dis_REP_op ( Condcode cond,
2895 void (*dis_OP)(Int, IRTemp),
2896 Int sz, Addr32 eip, Addr32 eip_next, Char* name )
2897{
2898 IRTemp t_inc = newTemp(Ity_I32);
2899 IRTemp tc = newTemp(Ity_I32); /* ECX */
2900
2901 //uInstr2 (cb, GET, 4, ArchReg, R_ECX, TempReg, tc);
2902 assign( tc, getIReg(4,R_ECX) );
2903
2904 //uInstr2 (cb, JIFZ, 4, TempReg, tc, Literal, 0);
2905 //uLiteral(cb, eip_next);
2906 stmt( IRStmt_Exit( binop(Iop_CmpEQ32,mkexpr(tc),mkU32(0)),
2907 IRConst_U32(eip_next) ) );
2908
2909 //uInstr1 (cb, DEC, 4, TempReg, tc);
2910 //uInstr2 (cb, PUT, 4, TempReg, tc, ArchReg, R_ECX);
2911 putIReg(4, R_ECX, binop(Iop_Sub32, mkexpr(tc), mkU32(1)) );
2912
2913 dis_string_op_increment(sz, t_inc);
2914 dis_OP (sz, t_inc);
2915
2916 if (cond == CondAlways) {
sewardj78c19df2004-07-12 22:49:27 +00002917 jmp_lit(Ijk_Boring,eip);
sewardj64e1d652004-07-12 14:00:46 +00002918 } else {
2919 stmt( IRStmt_Exit( calculate_condition(cond),
2920 IRConst_U32(eip) ) );
sewardj78c19df2004-07-12 22:49:27 +00002921 jmp_lit(Ijk_Boring,eip_next);
sewardj64e1d652004-07-12 14:00:46 +00002922 }
2923 DIP("%s%c\n", name, nameISize(sz));
2924}
2925
2926/*------------------------------------------------------------*/
2927/*--- Arithmetic, etc. ---*/
2928/*------------------------------------------------------------*/
2929
sewardjcf780b42004-07-13 18:42:17 +00002930/* (I)MUL E, G. Supplied eip points to the modR/M byte. */
2931static
2932UInt dis_mul_E_G ( UChar sorb,
2933 Int size,
2934 UInt delta0,
sewardj56296d82004-07-30 01:52:45 +00002935 Bool syned )
sewardjcf780b42004-07-13 18:42:17 +00002936{
sewardj71a65362004-07-28 01:48:34 +00002937 Int alen;
2938 UChar dis_buf[50];
sewardjcf780b42004-07-13 18:42:17 +00002939 UChar rm = getIByte(delta0);
2940 IRType ty = szToITy(size);
sewardj6d2638e2004-07-15 09:38:27 +00002941 IRTemp te = newTemp(ty);
2942 IRTemp tg = newTemp(ty);
sewardjcf780b42004-07-13 18:42:17 +00002943
sewardj56296d82004-07-30 01:52:45 +00002944 vassert(syned);
sewardj71a65362004-07-28 01:48:34 +00002945
sewardjcf780b42004-07-13 18:42:17 +00002946 if (epartIsReg(rm)) {
sewardjcf780b42004-07-13 18:42:17 +00002947 assign( tg, getIReg(size, gregOfRM(rm)) );
2948 assign( te, getIReg(size, eregOfRM(rm)) );
sewardj56296d82004-07-30 01:52:45 +00002949 setFlags_MUL ( ty, te, tg, syned ? CC_OP_SMULB : CC_OP_UMULB );
sewardjcf780b42004-07-13 18:42:17 +00002950 putIReg(size, gregOfRM(rm),
2951 binop(mkSizedOp(ty,Iop_Mul8),
2952 mkexpr(te), mkexpr(tg)));
2953
sewardj56296d82004-07-30 01:52:45 +00002954 DIP("%smul%c %s, %s\n", syned ? "i" : "",
sewardjcf780b42004-07-13 18:42:17 +00002955 nameISize(size),
2956 nameIReg(size,eregOfRM(rm)),
2957 nameIReg(size,gregOfRM(rm)));
2958 return 1+delta0;
2959 } else {
sewardj71a65362004-07-28 01:48:34 +00002960 IRTemp addr = disAMode( &alen, sorb, delta0, dis_buf );
2961 assign( tg, getIReg(size, gregOfRM(rm)) );
2962 assign( te, loadLE(ty,mkexpr(addr)) );
sewardj56296d82004-07-30 01:52:45 +00002963 setFlags_MUL ( ty, te, tg, syned ? CC_OP_SMULB : CC_OP_UMULB );
sewardj71a65362004-07-28 01:48:34 +00002964 putIReg(size, gregOfRM(rm),
2965 binop(mkSizedOp(ty,Iop_Mul8),
2966 mkexpr(te), mkexpr(tg)));
sewardjcf780b42004-07-13 18:42:17 +00002967
sewardj56296d82004-07-30 01:52:45 +00002968 DIP("%smul%c %s, %s\n", syned ? "i" : "",
sewardjcf780b42004-07-13 18:42:17 +00002969 nameISize(size),
2970 dis_buf, nameIReg(size,gregOfRM(rm)));
sewardj71a65362004-07-28 01:48:34 +00002971 return alen+delta0;
sewardjcf780b42004-07-13 18:42:17 +00002972 }
2973}
2974
2975
sewardj1813dbe2004-07-28 17:09:04 +00002976/* IMUL I * E -> G. Supplied eip points to the modR/M byte. */
2977static
2978UInt dis_imul_I_E_G ( UChar sorb,
2979 Int size,
2980 UInt delta,
2981 Int litsize )
2982{
sewardj883b00b2004-09-11 09:30:24 +00002983 Int d32, alen;
sewardjb81f8b32004-07-30 10:17:50 +00002984 Char dis_buf[50];
2985 UChar rm = getIByte(delta);
sewardj1813dbe2004-07-28 17:09:04 +00002986 IRType ty = szToITy(size);
2987 IRTemp te = newTemp(ty);
2988 IRTemp tl = newTemp(ty);
2989
sewardjb81f8b32004-07-30 10:17:50 +00002990 vassert(size == 1 || size == 2 || size == 4);
2991
sewardj1813dbe2004-07-28 17:09:04 +00002992 if (epartIsReg(rm)) {
2993 assign(te, getIReg(size, eregOfRM(rm)));
2994 delta++;
2995 } else {
sewardj883b00b2004-09-11 09:30:24 +00002996 IRTemp addr = disAMode( &alen, sorb, delta, dis_buf );
2997 assign(te, loadLE(ty, mkexpr(addr)));
2998 delta += alen;
sewardj1813dbe2004-07-28 17:09:04 +00002999 }
3000 d32 = getSDisp(litsize,delta);
3001 delta += litsize;
3002
sewardjb81f8b32004-07-30 10:17:50 +00003003 if (size == 1) d32 &= 0xFF;
3004 if (size == 2) d32 &= 0xFFFF;
3005
sewardj1813dbe2004-07-28 17:09:04 +00003006 assign(tl, mkU(ty,d32));
sewardj56296d82004-07-30 01:52:45 +00003007 setFlags_MUL ( ty, te, tl, CC_OP_SMULB );
sewardj1813dbe2004-07-28 17:09:04 +00003008 putIReg(size, gregOfRM(rm),
3009 binop(mkSizedOp(ty,Iop_Mul8),
3010 mkexpr(te), mkexpr(tl)));
3011
3012 DIP("imul %d, %s, %s\n", d32,
3013 ( epartIsReg(rm) ? nameIReg(size,eregOfRM(rm)) : dis_buf ),
3014 nameIReg(size,gregOfRM(rm)) );
3015 return delta;
3016}
3017
3018
sewardjd1725d12004-08-12 20:46:53 +00003019/*------------------------------------------------------------*/
3020/*--- x87 floating point insns. ---*/
3021/*------------------------------------------------------------*/
3022
sewardj207557a2004-08-27 12:00:18 +00003023/* --- Helper functions for dealing with the register stack. --- */
3024
sewardj17442fe2004-09-20 14:54:28 +00003025/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */
sewardj207557a2004-08-27 12:00:18 +00003026
sewardj17442fe2004-09-20 14:54:28 +00003027static IRExpr* mkQNaN64 ( void )
sewardj207557a2004-08-27 12:00:18 +00003028{
sewardj17442fe2004-09-20 14:54:28 +00003029 /* QNaN is 0 2047 1 0(51times)
3030 == 0b 11111111111b 1 0(51times)
3031 == 0x7FF8 0000 0000 0000
3032 */
3033 return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL));
sewardj207557a2004-08-27 12:00:18 +00003034}
3035
3036/* --------- Get/set the top-of-stack pointer. --------- */
sewardjd1725d12004-08-12 20:46:53 +00003037
3038static IRExpr* get_ftop ( void )
3039{
3040 return IRExpr_Get( OFFB_FTOP, Ity_I32 );
3041}
3042
sewardj207557a2004-08-27 12:00:18 +00003043static void put_ftop ( IRExpr* e )
sewardjd1725d12004-08-12 20:46:53 +00003044{
sewardj207557a2004-08-27 12:00:18 +00003045 stmt( IRStmt_Put( OFFB_FTOP, e ) );
sewardjd1725d12004-08-12 20:46:53 +00003046}
3047
sewardjc4be80c2004-09-10 16:17:45 +00003048/* --------- Get/set the C3210 bits of the control word. --------- */
sewardjbdc7d212004-09-09 02:46:40 +00003049
sewardjc4be80c2004-09-10 16:17:45 +00003050static IRExpr* get_C3210 ( void )
sewardjbdc7d212004-09-09 02:46:40 +00003051{
sewardjc4be80c2004-09-10 16:17:45 +00003052 return IRExpr_Get( OFFB_FC3210, Ity_I32 );
sewardjbdc7d212004-09-09 02:46:40 +00003053}
3054
sewardjc4be80c2004-09-10 16:17:45 +00003055static void put_C3210 ( IRExpr* e )
sewardjbdc7d212004-09-09 02:46:40 +00003056{
sewardjc4be80c2004-09-10 16:17:45 +00003057 stmt( IRStmt_Put( OFFB_FC3210, e ) );
sewardjbdc7d212004-09-09 02:46:40 +00003058}
sewardjd1725d12004-08-12 20:46:53 +00003059
sewardj8f3debf2004-09-08 23:42:23 +00003060/* --------- Get/set the FPU control word. --------- */
3061/* Note, IA32 has this as a 16-bit value, so fstcw/fldcw need to cast
3062 to/from 16 bits. Here we represent it in 32 bits. */
3063static IRExpr* /* :: Ity_I32 */ get_fpucw ( void )
3064{
3065 return IRExpr_Get( OFFB_FPUCW, Ity_I32 );
3066}
3067
3068static void put_fpucw ( IRExpr* /* :: Ity_I32 */ e )
3069{
3070 stmt( IRStmt_Put( OFFB_FPUCW, e ) );
3071}
3072
3073
3074/* --------- Get the FPU rounding mode from the CW. --------- */
3075/* Produces a value in 0 .. 3, which is encoded as per the type
3076 IRRoundingMode. On IA32 the relevant value is precisely bits 11
3077 and 10 of the control word.
3078*/
3079static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
3080{
3081 return binop( Iop_And32,
3082 binop(Iop_Shr32, get_fpucw(), mkU8(10)),
3083 mkU32(3) );
3084}
3085
3086
sewardj207557a2004-08-27 12:00:18 +00003087/* --------- Get/set FP register tag bytes. --------- */
3088
sewardj207557a2004-08-27 12:00:18 +00003089/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */
3090
3091static void put_ST_TAG ( Int i, IRExpr* value )
3092{
sewardj2d3f77c2004-09-22 23:49:09 +00003093 IRArray* descr;
sewardj207557a2004-08-27 12:00:18 +00003094 vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_I8);
sewardj2d3f77c2004-09-22 23:49:09 +00003095 descr = mkIRArray( OFFB_FTAG0, Ity_I8, 8 );
3096 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
sewardj207557a2004-08-27 12:00:18 +00003097}
3098
3099/* Given i, generate an expression yielding 'ST_TAG(i)'. This will be
sewardjdb199622004-09-06 23:19:03 +00003100 zero to indicate "Empty" and nonzero to indicate "NonEmpty". */
sewardj207557a2004-08-27 12:00:18 +00003101
3102static IRExpr* get_ST_TAG ( Int i )
3103{
sewardj2d3f77c2004-09-22 23:49:09 +00003104 IRArray* descr = mkIRArray( OFFB_FTAG0, Ity_I8, 8 );
3105 return IRExpr_GetI( descr, get_ftop(), i );
sewardj207557a2004-08-27 12:00:18 +00003106}
3107
3108
3109/* --------- Get/set FP registers. --------- */
3110
sewardj2d3f77c2004-09-22 23:49:09 +00003111/* Given i, and some expression e, emit 'ST(i) = e' and set the
3112 register's tag to indicate the register is full. The previous
3113 state of the register is not checked. */
sewardj207557a2004-08-27 12:00:18 +00003114
3115static void put_ST_UNCHECKED ( Int i, IRExpr* value )
sewardjd1725d12004-08-12 20:46:53 +00003116{
sewardj2d3f77c2004-09-22 23:49:09 +00003117 IRArray* descr;
sewardjdb199622004-09-06 23:19:03 +00003118 vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_F64);
sewardj2d3f77c2004-09-22 23:49:09 +00003119 descr = mkIRArray( OFFB_F0, Ity_F64, 8 );
3120 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
sewardj207557a2004-08-27 12:00:18 +00003121 /* Mark the register as in-use. */
3122 put_ST_TAG(i, mkU8(1));
sewardjd1725d12004-08-12 20:46:53 +00003123}
3124
sewardj207557a2004-08-27 12:00:18 +00003125/* Given i, and some expression e, emit
3126 ST(i) = is_full(i) ? NaN : e
3127 and set the tag accordingly.
3128*/
3129
3130static void put_ST ( Int i, IRExpr* value )
3131{
3132 put_ST_UNCHECKED( i,
sewardjdb199622004-09-06 23:19:03 +00003133 IRExpr_Mux0X( get_ST_TAG(i),
3134 /* 0 means empty */
3135 value,
3136 /* non-0 means full */
sewardj17442fe2004-09-20 14:54:28 +00003137 mkQNaN64()
sewardj207557a2004-08-27 12:00:18 +00003138 )
3139 );
3140}
3141
3142
sewardjd1725d12004-08-12 20:46:53 +00003143/* Given i, generate an expression yielding 'ST(i)'. */
3144
sewardj207557a2004-08-27 12:00:18 +00003145static IRExpr* get_ST_UNCHECKED ( Int i )
sewardjd1725d12004-08-12 20:46:53 +00003146{
sewardj2d3f77c2004-09-22 23:49:09 +00003147 IRArray* descr = mkIRArray( OFFB_F0, Ity_F64, 8 );
3148 return IRExpr_GetI( descr, get_ftop(), i );
sewardjd1725d12004-08-12 20:46:53 +00003149}
3150
sewardjc4be80c2004-09-10 16:17:45 +00003151
sewardj207557a2004-08-27 12:00:18 +00003152/* Given i, generate an expression yielding
3153 is_full(i) ? ST(i) : NaN
3154*/
3155
3156static IRExpr* get_ST ( Int i )
3157{
3158 return
3159 IRExpr_Mux0X( get_ST_TAG(i),
3160 /* 0 means empty */
sewardj17442fe2004-09-20 14:54:28 +00003161 mkQNaN64(),
sewardj207557a2004-08-27 12:00:18 +00003162 /* non-0 means full */
3163 get_ST_UNCHECKED(i));
3164}
3165
3166
sewardjd1725d12004-08-12 20:46:53 +00003167/* Adjust FTOP downwards by one register. */
3168
sewardj207557a2004-08-27 12:00:18 +00003169static void fp_push ( void )
sewardjd1725d12004-08-12 20:46:53 +00003170{
sewardj2d3f77c2004-09-22 23:49:09 +00003171 put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) );
sewardjd1725d12004-08-12 20:46:53 +00003172}
3173
sewardj207557a2004-08-27 12:00:18 +00003174/* Adjust FTOP upwards by one register, and mark the vacated register
3175 as empty. */
sewardja58ea662004-08-15 03:12:41 +00003176
sewardj207557a2004-08-27 12:00:18 +00003177static void fp_pop ( void )
sewardja58ea662004-08-15 03:12:41 +00003178{
sewardjdb199622004-09-06 23:19:03 +00003179 put_ST_TAG(0, mkU8(0));
sewardj2d3f77c2004-09-22 23:49:09 +00003180 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
sewardja58ea662004-08-15 03:12:41 +00003181}
3182
sewardj3f61ddb2004-10-16 20:51:05 +00003183/* Clear the C2 bit of the FPU status register, for
3184 sin/cos/tan/sincos. */
3185
3186static void clear_C2 ( void )
3187{
3188 put_C3210( binop(Iop_And32, get_C3210(), mkU32(~FC_MASK_C2)) );
3189}
3190
3191
sewardj207557a2004-08-27 12:00:18 +00003192/* ------------------------------------------------------- */
3193/* Given all that stack-mangling junk, we can now go ahead
3194 and describe FP instructions.
3195*/
3196
sewardj3fd5e572004-09-09 22:43:51 +00003197/* ST(0) = ST(0) `op` mem64/32(addr)
sewardj207557a2004-08-27 12:00:18 +00003198 Need to check ST(0)'s tag on read, but not on write.
3199*/
sewardja58ea662004-08-15 03:12:41 +00003200static
3201void fp_do_op_mem_ST_0 ( IRTemp addr, UChar* op_txt, UChar* dis_buf,
3202 IROp op, Bool dbl )
3203{
3204 DIP("f%s%c %s", op_txt, dbl?'l':'s', dis_buf);
3205 if (dbl) {
sewardj3fd5e572004-09-09 22:43:51 +00003206 put_ST_UNCHECKED(0,
3207 binop( op,
3208 get_ST(0),
3209 loadLE(Ity_F64,mkexpr(addr))
3210 ));
sewardja58ea662004-08-15 03:12:41 +00003211 } else {
sewardj3fd5e572004-09-09 22:43:51 +00003212 put_ST_UNCHECKED(0,
3213 binop( op,
3214 get_ST(0),
3215 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr)))
3216 ));
3217 }
3218}
3219
3220
3221/* ST(0) = mem64/32(addr) `op` ST(0)
3222 Need to check ST(0)'s tag on read, but not on write.
3223*/
3224static
3225void fp_do_oprev_mem_ST_0 ( IRTemp addr, UChar* op_txt, UChar* dis_buf,
sewardj883b00b2004-09-11 09:30:24 +00003226 IROp op, Bool dbl )
sewardj3fd5e572004-09-09 22:43:51 +00003227{
3228 DIP("f%s%c %s", op_txt, dbl?'l':'s', dis_buf);
3229 if (dbl) {
3230 put_ST_UNCHECKED(0,
3231 binop( op,
3232 loadLE(Ity_F64,mkexpr(addr)),
3233 get_ST(0)
3234 ));
3235 } else {
3236 put_ST_UNCHECKED(0,
3237 binop( op,
3238 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))),
3239 get_ST(0)
3240 ));
sewardja58ea662004-08-15 03:12:41 +00003241 }
3242}
3243
sewardjd1725d12004-08-12 20:46:53 +00003244
sewardjdb199622004-09-06 23:19:03 +00003245/* ST(dst) = ST(dst) `op` ST(src).
3246 Check dst and src tags when reading but not on write.
3247*/
3248static
sewardjbdc7d212004-09-09 02:46:40 +00003249void fp_do_op_ST_ST ( UChar* op_txt, IROp op, UInt st_src, UInt st_dst,
3250 Bool pop_after )
sewardjdb199622004-09-06 23:19:03 +00003251{
sewardjbdc7d212004-09-09 02:46:40 +00003252 DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"", st_src, st_dst );
sewardjdb199622004-09-06 23:19:03 +00003253 put_ST_UNCHECKED(
3254 st_dst,
3255 binop(op, get_ST(st_dst), get_ST(st_src) )
3256 );
sewardjbdc7d212004-09-09 02:46:40 +00003257 if (pop_after)
3258 fp_pop();
3259}
3260
3261/* ST(dst) = ST(src) `op` ST(dst).
3262 Check dst and src tags when reading but not on write.
3263*/
3264static
3265void fp_do_oprev_ST_ST ( UChar* op_txt, IROp op, UInt st_src, UInt st_dst,
sewardj883b00b2004-09-11 09:30:24 +00003266 Bool pop_after )
sewardjbdc7d212004-09-09 02:46:40 +00003267{
3268 DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"", st_src, st_dst );
3269 put_ST_UNCHECKED(
3270 st_dst,
3271 binop(op, get_ST(st_src), get_ST(st_dst) )
3272 );
3273 if (pop_after)
3274 fp_pop();
sewardjdb199622004-09-06 23:19:03 +00003275}
3276
sewardj8308aad2004-09-12 11:09:54 +00003277/* %eflags(Z,P,C) = UCOMI( st(0), st(i) ) */
3278static void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
3279{
3280 DIP("fucomi%s %%st(0),%%st(%d)\n", pop_after ? "p" : "", i);
3281 /* This is a bit of a hack (and isn't really right). It sets
3282 Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
3283 documentation implies A and S are unchanged.
3284 */
3285 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
3286 stmt( IRStmt_Put( OFFB_CC_DST, mkU32(0) ));
3287 stmt( IRStmt_Put( OFFB_CC_SRC,
3288 binop( Iop_And32,
3289 binop(Iop_CmpF64, get_ST(0), get_ST(i)),
3290 mkU32(0x45)
3291 )));
3292 if (pop_after)
3293 fp_pop();
3294}
3295
sewardjdb199622004-09-06 23:19:03 +00003296
sewardjd1725d12004-08-12 20:46:53 +00003297static
3298UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta )
3299{
sewardja58ea662004-08-15 03:12:41 +00003300 Int len;
3301 UInt r_src, r_dst;
3302 Char dis_buf[32];
sewardj89cd0932004-09-08 18:23:25 +00003303 IRTemp t1, t2;
sewardjd1725d12004-08-12 20:46:53 +00003304
3305 /* On entry, delta points at the second byte of the insn (the modrm
3306 byte).*/
3307 UChar first_opcode = getIByte(delta-1);
3308 UChar modrm = getIByte(delta+0);
3309
3310 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
3311
3312 if (first_opcode == 0xD8) {
sewardjdb199622004-09-06 23:19:03 +00003313 if (modrm < 0xC0) {
sewardj89cd0932004-09-08 18:23:25 +00003314
3315 /* bits 5,4,3 are an opcode extension, and the modRM also
3316 specifies an address. */
3317 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3318 delta += len;
3319
3320 switch (gregOfRM(modrm)) {
3321
sewardj3fd5e572004-09-09 22:43:51 +00003322 case 0: /* FADD single-real */
3323 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, False );
3324 break;
3325
sewardj89cd0932004-09-08 18:23:25 +00003326 case 1: /* FMUL single-real */
3327 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, False );
3328 break;
3329
sewardj588ea762004-09-10 18:56:32 +00003330 case 4: /* FSUB single-real */
3331 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, False );
3332 break;
3333
3334 case 5: /* FSUBR single-real */
3335 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, False );
3336 break;
3337
sewardjbdc7d212004-09-09 02:46:40 +00003338 case 6: /* FDIV single-real */
3339 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, False );
3340 break;
3341
sewardj8308aad2004-09-12 11:09:54 +00003342 case 7: /* FDIVR single-real */
3343 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, False );
3344 break;
3345
sewardj89cd0932004-09-08 18:23:25 +00003346 default:
3347 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3348 vex_printf("first_opcode == 0xD8\n");
3349 goto decode_fail;
3350 }
sewardjdb199622004-09-06 23:19:03 +00003351 } else {
3352 delta++;
3353 switch (modrm) {
sewardj89cd0932004-09-08 18:23:25 +00003354
sewardjdb199622004-09-06 23:19:03 +00003355 case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
sewardjbdc7d212004-09-09 02:46:40 +00003356 fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
sewardjdb199622004-09-06 23:19:03 +00003357 break;
sewardj89cd0932004-09-08 18:23:25 +00003358
sewardj3fd5e572004-09-09 22:43:51 +00003359 case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
3360 fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
3361 break;
3362
sewardj89cd0932004-09-08 18:23:25 +00003363 case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
sewardjbdc7d212004-09-09 02:46:40 +00003364 fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
sewardj89cd0932004-09-08 18:23:25 +00003365 break;
3366
sewardj8308aad2004-09-12 11:09:54 +00003367 case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
3368 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
3369 break;
3370
sewardj3fd5e572004-09-09 22:43:51 +00003371 case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
3372 fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
3373 break;
3374
3375 case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
3376 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
3377 break;
3378
sewardjdb199622004-09-06 23:19:03 +00003379 default:
3380 goto decode_fail;
3381 }
3382 }
sewardjd1725d12004-08-12 20:46:53 +00003383 }
3384
3385 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
3386 else
3387 if (first_opcode == 0xD9) {
sewardjbb53f8c2004-08-14 11:50:01 +00003388 if (modrm < 0xC0) {
sewardj89cd0932004-09-08 18:23:25 +00003389
3390 /* bits 5,4,3 are an opcode extension, and the modRM also
3391 specifies an address. */
3392 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3393 delta += len;
3394
3395 switch (gregOfRM(modrm)) {
3396
3397 case 0: /* FLD single-real */
3398 DIP("fldF %s\n", dis_buf);
3399 fp_push();
3400 put_ST(0, unop(Iop_F32toF64,
sewardj8f3debf2004-09-08 23:42:23 +00003401 loadLE(Ity_F32, mkexpr(addr))));
sewardj89cd0932004-09-08 18:23:25 +00003402 break;
3403
sewardj588ea762004-09-10 18:56:32 +00003404 case 2: /* FST single-real */
3405 DIP("fstS %s", dis_buf);
3406 storeLE(mkexpr(addr), unop(Iop_F64toF32, get_ST(0)));
3407 break;
3408
sewardj89cd0932004-09-08 18:23:25 +00003409 case 3: /* FSTP single-real */
3410 DIP("fstpS %s", dis_buf);
3411 storeLE(mkexpr(addr), unop(Iop_F64toF32, get_ST(0)));
3412 fp_pop();
3413 break;
3414
sewardj588ea762004-09-10 18:56:32 +00003415 case 5: /* FLDCW */
sewardj8f3debf2004-09-08 23:42:23 +00003416 DIP("fldcw %s", dis_buf);
3417 put_fpucw( unop(Iop_16Uto32, loadLE(Ity_I16, mkexpr(addr))) );
sewardj89cd0932004-09-08 18:23:25 +00003418 break;
3419
sewardj588ea762004-09-10 18:56:32 +00003420 case 7: /* FNSTCW */
3421 DIP("fnstcw %s", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00003422 storeLE(mkexpr(addr), unop(Iop_32to16, get_fpucw()));
sewardj89cd0932004-09-08 18:23:25 +00003423 break;
3424
3425 default:
3426 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3427 vex_printf("first_opcode == 0xD9\n");
3428 goto decode_fail;
3429 }
3430
sewardjbb53f8c2004-08-14 11:50:01 +00003431 } else {
3432 delta++;
3433 switch (modrm) {
sewardj89cd0932004-09-08 18:23:25 +00003434
sewardjbb53f8c2004-08-14 11:50:01 +00003435 case 0xC0 ... 0xC7: /* FLD %st(?) */
sewardja58ea662004-08-15 03:12:41 +00003436 r_src = (UInt)modrm - 0xC0;
3437 DIP("fld %%st(%d)\n", r_src);
sewardjbb53f8c2004-08-14 11:50:01 +00003438 t1 = newTemp(Ity_F64);
sewardja58ea662004-08-15 03:12:41 +00003439 assign(t1, get_ST(r_src));
sewardj207557a2004-08-27 12:00:18 +00003440 fp_push();
3441 put_ST(0, mkexpr(t1));
sewardjbb53f8c2004-08-14 11:50:01 +00003442 break;
3443
sewardj89cd0932004-09-08 18:23:25 +00003444 case 0xC8 ... 0xCF: /* FXCH %st(?) */
3445 r_src = (UInt)modrm - 0xC8;
3446 DIP("fxch %%st(%d)\n", r_src);
3447 t1 = newTemp(Ity_F64);
3448 t2 = newTemp(Ity_F64);
3449 assign(t1, get_ST(0));
3450 assign(t2, get_ST(r_src));
3451 put_ST_UNCHECKED(0, mkexpr(t2));
3452 put_ST_UNCHECKED(r_src, mkexpr(t1));
3453 break;
3454
sewardjcfded9a2004-09-09 11:44:16 +00003455 case 0xE0: /* FCHS */
3456 DIP("fchs\n");
3457 put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
3458 break;
3459
sewardj883b00b2004-09-11 09:30:24 +00003460 case 0xE1: /* FABS */
3461 DIP("fabs\n");
3462 put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
3463 break;
sewardjc4be80c2004-09-10 16:17:45 +00003464
sewardj883b00b2004-09-11 09:30:24 +00003465 case 0xE5: { /* FXAM */
3466 /* This is an interesting one. It examines %st(0),
3467 regardless of whether the tag says it's empty or not.
3468 Here, just pass both the tag (in our format) and the
3469 value (as a double, actually a ULong) to a helper
3470 function. */
3471 IRExpr** args;
3472 DIP("fxam");
3473 args = LibVEX_Alloc(3 * sizeof(IRExpr*));
3474 args[0] = unop(Iop_8Uto32, get_ST_TAG(0));
sewardj17442fe2004-09-20 14:54:28 +00003475 args[1] = unop(Iop_ReinterpF64asI64, get_ST_UNCHECKED(0));
sewardj883b00b2004-09-11 09:30:24 +00003476 args[2] = NULL;
3477 put_C3210(IRExpr_CCall("calculate_FXAM", Ity_I32, args));
3478 break;
3479 }
3480
3481 case 0xE8: /* FLD1 */
sewardjdb199622004-09-06 23:19:03 +00003482 DIP("fld1");
sewardjce646f22004-08-31 23:55:54 +00003483 fp_push();
3484 put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
3485 break;
3486
sewardj37158712004-10-15 21:23:12 +00003487 case 0xE9: /* FLDL2T */
3488 DIP("fldl2t");
3489 fp_push();
3490 put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781)));
3491 break;
3492
sewardj8308aad2004-09-12 11:09:54 +00003493 case 0xEA: /* FLDL2E */
3494 DIP("fldl2e");
3495 fp_push();
3496 put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739)));
3497 break;
3498
sewardja0d48d62004-09-20 21:19:03 +00003499 case 0xEB: /* FLDPI */
3500 DIP("fldpi");
3501 fp_push();
3502 put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851)));
3503 break;
3504
sewardjdb199622004-09-06 23:19:03 +00003505 case 0xEC: /* FLDLG2 */
3506 DIP("fldlg2");
3507 fp_push();
3508 put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143)));
3509 break;
3510
3511 case 0xED: /* FLDLN2 */
3512 DIP("fldln2");
3513 fp_push();
3514 put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942)));
3515 break;
3516
sewardja58ea662004-08-15 03:12:41 +00003517 case 0xEE: /* FLDZ */
3518 DIP("fldz");
sewardj207557a2004-08-27 12:00:18 +00003519 fp_push();
3520 put_ST(0, IRExpr_Const(IRConst_F64(0.0)));
sewardja58ea662004-08-15 03:12:41 +00003521 break;
3522
sewardj06c32a02004-09-12 12:07:34 +00003523 case 0xF0: /* F2XM1 */
3524 DIP("f2xm1\n");
3525 put_ST_UNCHECKED(0, unop(Iop_2xm1F64, get_ST(0)));
3526 break;
3527
sewardj52ace3e2004-09-11 17:10:08 +00003528 case 0xF1: /* FYL2X */
3529 DIP("fyl2x\n");
3530 put_ST_UNCHECKED(1, binop(Iop_Yl2xF64,
3531 get_ST(1), get_ST(0)));
3532 fp_pop();
3533 break;
3534
sewardj99016a72004-10-15 22:09:17 +00003535 case 0xF2: /* FPTAN */
3536 DIP("ftan\n");
3537 put_ST_UNCHECKED(0, unop(Iop_TanF64, get_ST(0)));
3538 fp_push();
3539 put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
sewardj3f61ddb2004-10-16 20:51:05 +00003540 clear_C2(); /* HACK */
sewardj99016a72004-10-15 22:09:17 +00003541 break;
3542
sewardjcfded9a2004-09-09 11:44:16 +00003543 case 0xF3: /* FPATAN */
3544 DIP("fpatan\n");
sewardj52ace3e2004-09-11 17:10:08 +00003545 put_ST_UNCHECKED(1, binop(Iop_AtanF64,
sewardjcfded9a2004-09-09 11:44:16 +00003546 get_ST(1), get_ST(0)));
3547 fp_pop();
3548 break;
3549
sewardj442d0be2004-10-15 22:57:13 +00003550 case 0xF5: { /* FPREM1 -- IEEE compliant */
3551 IRTemp a1 = newTemp(Ity_F64);
3552 IRTemp a2 = newTemp(Ity_F64);
3553 DIP("fprem1\n");
3554 /* Do FPREM1 twice, once to get the remainder, and once
3555 to get the C3210 flag values. */
3556 assign( a1, get_ST(0) );
3557 assign( a2, get_ST(1) );
3558 put_ST_UNCHECKED(0, binop(Iop_PRem1F64,
3559 mkexpr(a1), mkexpr(a2)));
3560 put_C3210( binop(Iop_PRem1C3210F64, mkexpr(a1), mkexpr(a2)) );
3561 break;
3562 }
3563
sewardj46de4072004-09-11 19:23:24 +00003564 case 0xF8: { /* FPREM -- not IEEE compliant */
3565 IRTemp a1 = newTemp(Ity_F64);
3566 IRTemp a2 = newTemp(Ity_F64);
3567 DIP("fprem\n");
3568 /* Do FPREM twice, once to get the remainder, and once
3569 to get the C3210 flag values. */
3570 assign( a1, get_ST(0) );
3571 assign( a2, get_ST(1) );
3572 put_ST_UNCHECKED(0, binop(Iop_PRemF64,
3573 mkexpr(a1), mkexpr(a2)));
3574 put_C3210( binop(Iop_PRemC3210F64, mkexpr(a1), mkexpr(a2)) );
3575 break;
3576 }
3577
sewardj8308aad2004-09-12 11:09:54 +00003578 case 0xF9: /* FYL2XP1 */
3579 DIP("fyl2xp1\n");
3580 put_ST_UNCHECKED(1, binop(Iop_Yl2xp1F64,
3581 get_ST(1), get_ST(0)));
3582 fp_pop();
3583 break;
3584
sewardjc4be80c2004-09-10 16:17:45 +00003585 case 0xFA: /* FSQRT */
3586 DIP("fsqrt\n");
3587 put_ST_UNCHECKED(0, unop(Iop_SqrtF64, get_ST(0)));
3588 break;
3589
sewardje6709112004-09-10 18:37:18 +00003590 case 0xFC: /* FRNDINT */
3591 DIP("frndint\n");
3592 put_ST_UNCHECKED(0,
3593 binop(Iop_RoundF64, get_roundingmode(), get_ST(0)) );
3594 break;
3595
sewardj06c32a02004-09-12 12:07:34 +00003596 case 0xFD: /* FSCALE */
3597 DIP("fscale\n");
3598 put_ST_UNCHECKED(0, binop(Iop_ScaleF64,
3599 get_ST(0), get_ST(1)));
3600 break;
3601
sewardjcfded9a2004-09-09 11:44:16 +00003602 case 0xFE: /* FSIN */
3603 DIP("fsin\n");
3604 put_ST_UNCHECKED(0, unop(Iop_SinF64, get_ST(0)));
sewardj3f61ddb2004-10-16 20:51:05 +00003605 clear_C2(); /* HACK */
sewardjcfded9a2004-09-09 11:44:16 +00003606 break;
3607
3608 case 0xFF: /* FCOS */
3609 DIP("fcos\n");
3610 put_ST_UNCHECKED(0, unop(Iop_CosF64, get_ST(0)));
sewardj3f61ddb2004-10-16 20:51:05 +00003611 clear_C2(); /* HACK */
sewardjcfded9a2004-09-09 11:44:16 +00003612 break;
3613
sewardjbb53f8c2004-08-14 11:50:01 +00003614 default:
3615 goto decode_fail;
3616 }
3617 }
sewardjd1725d12004-08-12 20:46:53 +00003618 }
3619
3620 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
3621 else
3622 if (first_opcode == 0xDA) {
sewardjbb53f8c2004-08-14 11:50:01 +00003623
3624 if (modrm < 0xC0) {
3625
3626 /* bits 5,4,3 are an opcode extension, and the modRM also
3627 specifies an address. */
sewardjce646f22004-08-31 23:55:54 +00003628 IROp fop;
sewardjbb53f8c2004-08-14 11:50:01 +00003629 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3630 delta += len;
sewardjbb53f8c2004-08-14 11:50:01 +00003631 switch (gregOfRM(modrm)) {
sewardjce646f22004-08-31 23:55:54 +00003632
sewardjdb199622004-09-06 23:19:03 +00003633 case 0: /* FIADD m32int */ /* ST(0) += m32int */
3634 DIP("fiaddl %s", dis_buf);
3635 fop = Iop_AddF64;
3636 goto do_fop_m32;
3637
sewardj207557a2004-08-27 12:00:18 +00003638 case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
sewardjbb53f8c2004-08-14 11:50:01 +00003639 DIP("fimull %s", dis_buf);
sewardjce646f22004-08-31 23:55:54 +00003640 fop = Iop_MulF64;
3641 goto do_fop_m32;
3642
3643 case 4: /* FISUB m32int */ /* ST(0) -= m32int */
3644 DIP("fisubl %s", dis_buf);
3645 fop = Iop_SubF64;
3646 goto do_fop_m32;
3647
sewardj8308aad2004-09-12 11:09:54 +00003648 case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
3649 DIP("fisubrl %s", dis_buf);
3650 fop = Iop_SubF64;
3651 goto do_foprev_m32;
3652
sewardjce646f22004-08-31 23:55:54 +00003653 case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
3654 DIP("fisubl %s", dis_buf);
3655 fop = Iop_DivF64;
3656 goto do_fop_m32;
3657
sewardjc4eaff32004-09-10 20:25:11 +00003658 case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
sewardj8308aad2004-09-12 11:09:54 +00003659 DIP("fidivrl %s", dis_buf);
sewardjc4eaff32004-09-10 20:25:11 +00003660 fop = Iop_DivF64;
3661 goto do_foprev_m32;
3662
sewardjce646f22004-08-31 23:55:54 +00003663 do_fop_m32:
sewardj207557a2004-08-27 12:00:18 +00003664 put_ST_UNCHECKED(0,
sewardjce646f22004-08-31 23:55:54 +00003665 binop(fop,
sewardj207557a2004-08-27 12:00:18 +00003666 get_ST(0),
sewardj89cd0932004-09-08 18:23:25 +00003667 unop(Iop_I32toF64,
3668 loadLE(Ity_I32, mkexpr(addr)))));
sewardjbb53f8c2004-08-14 11:50:01 +00003669 break;
3670
sewardjc4eaff32004-09-10 20:25:11 +00003671 do_foprev_m32:
3672 put_ST_UNCHECKED(0,
3673 binop(fop,
3674 unop(Iop_I32toF64,
3675 loadLE(Ity_I32, mkexpr(addr))),
3676 get_ST(0)));
3677 break;
3678
sewardjbb53f8c2004-08-14 11:50:01 +00003679 default:
3680 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3681 vex_printf("first_opcode == 0xDA\n");
3682 goto decode_fail;
3683 }
3684 } else {
sewardjbdc7d212004-09-09 02:46:40 +00003685
3686 delta++;
3687 switch (modrm) {
3688
sewardj3fd5e572004-09-09 22:43:51 +00003689 case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
3690 r_src = (UInt)modrm - 0xC8;
3691 DIP("fcmovz %%st(%d), %%st(0)", r_src);
3692 put_ST_UNCHECKED(0,
3693 IRExpr_Mux0X(
3694 unop(Iop_1Uto8,calculate_condition(CondZ)),
3695 get_ST(0), get_ST(r_src)) );
3696 break;
3697
sewardjbdc7d212004-09-09 02:46:40 +00003698 case 0xE9: /* FUCOMPP %st(0),%st(1) */
3699 DIP("fucompp %%st(0),%%st(1)\n");
sewardjc4be80c2004-09-10 16:17:45 +00003700 /* This forces C1 to zero, which isn't right. */
3701 put_C3210(
3702 binop( Iop_And32,
3703 binop(Iop_Shl32,
3704 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
3705 mkU8(8)),
3706 mkU32(0x4500)
3707 ));
sewardjbdc7d212004-09-09 02:46:40 +00003708 fp_pop();
3709 fp_pop();
3710 break;
3711
3712 default:
3713 goto decode_fail;
3714 }
3715
sewardjbb53f8c2004-08-14 11:50:01 +00003716 }
sewardjd1725d12004-08-12 20:46:53 +00003717 }
3718
3719 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
3720 else
3721 if (first_opcode == 0xDB) {
sewardj89cd0932004-09-08 18:23:25 +00003722 if (modrm < 0xC0) {
3723
3724 /* bits 5,4,3 are an opcode extension, and the modRM also
3725 specifies an address. */
3726 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3727 delta += len;
3728
3729 switch (gregOfRM(modrm)) {
3730
3731 case 0: /* FILD m32int */
3732 DIP("fildl %s\n", dis_buf);
3733 fp_push();
3734 put_ST(0, unop(Iop_I32toF64,
3735 loadLE(Ity_I32, mkexpr(addr))));
3736 break;
3737
sewardj8f3debf2004-09-08 23:42:23 +00003738 case 2: /* FIST m32 */
3739 DIP("fistl %s", dis_buf);
3740 storeLE( mkexpr(addr),
3741 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
3742 break;
3743
sewardj89cd0932004-09-08 18:23:25 +00003744 case 3: /* FISTP m32 */
3745 DIP("fistpl %s", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00003746 storeLE( mkexpr(addr),
3747 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
sewardj89cd0932004-09-08 18:23:25 +00003748 fp_pop();
3749 break;
sewardj17442fe2004-09-20 14:54:28 +00003750
sewardjb3bce0e2004-09-14 23:20:10 +00003751 case 5: { /* FLD extended-real */
sewardj17442fe2004-09-20 14:54:28 +00003752 /* Uses dirty helper: ULong loadF80le ( UInt ) */
sewardjb3bce0e2004-09-14 23:20:10 +00003753 /* addr holds the address. First, do a dirty call to
3754 get hold of the data. */
3755 /* give details of args, and where to call */
sewardj17442fe2004-09-20 14:54:28 +00003756 IRDirty* d;
3757 DIP("fldt %s", dis_buf);
3758 d = emptyIRDirty();
sewardjb3bce0e2004-09-14 23:20:10 +00003759 d->name = "loadF80le";
3760 d->args = LibVEX_Alloc(2 * sizeof(IRTemp));
sewardj17442fe2004-09-20 14:54:28 +00003761 d->args[0] = mkexpr(addr);
3762 d->args[1] = NULL;
3763 d->tmp = newTemp(Ity_I64);
sewardjb3bce0e2004-09-14 23:20:10 +00003764 /* declare that we're reading memory */
3765 d->mFx = Ifx_Read;
sewardj17442fe2004-09-20 14:54:28 +00003766 d->mAddr = mkexpr(addr);
sewardjb3bce0e2004-09-14 23:20:10 +00003767 d->mSize = 10;
3768 /* declare that we don't mess with guest state */
3769 d->nFxState = 0;
3770 /* execute the dirty call, dumping the result in d->tmp. */
3771 stmt( IRStmt_Dirty(d) );
3772 fp_push();
sewardj17442fe2004-09-20 14:54:28 +00003773 put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(d->tmp)));
sewardjb3bce0e2004-09-14 23:20:10 +00003774 break;
3775 }
sewardj17442fe2004-09-20 14:54:28 +00003776
3777 case 7: { /* FSTP extended-real */
3778 /* Uses dirty helper: void storeF80le ( UInt, ULong ) */
3779 IRDirty* d;
3780 DIP("fldt %s", dis_buf);
3781 d = emptyIRDirty();
3782 d->name = "storeF80le";
3783 /* takes 2 args */
3784 d->args = LibVEX_Alloc(3 * sizeof(IRTemp));
3785 d->args[0] = mkexpr(addr);
3786 d->args[1] = unop(Iop_ReinterpF64asI64, get_ST(0));
3787 d->args[2] = NULL;
3788 /* returns nothing */
3789 d->tmp = INVALID_IRTEMP;
3790 /* declare we're writing memory */
3791 d->mFx = Ifx_Write;
3792 d->mAddr = mkexpr(addr);
3793 d->mSize = 10;
3794 /* declare that we don't mess with guest state */
3795 d->nFxState = 0;
3796 /* execute the dirty call. */
3797 stmt( IRStmt_Dirty(d) );
3798 fp_pop();
3799 break;
3800 }
3801
sewardjb3bce0e2004-09-14 23:20:10 +00003802 default:
sewardj89cd0932004-09-08 18:23:25 +00003803 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3804 vex_printf("first_opcode == 0xDB\n");
3805 goto decode_fail;
3806 }
3807
3808 } else {
sewardj8308aad2004-09-12 11:09:54 +00003809
3810 delta++;
3811 switch (modrm) {
3812
sewardj4e82db72004-10-16 11:32:15 +00003813 case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
3814 r_src = (UInt)modrm - 0xC8;
3815 DIP("fcmovnz %%st(%d), %%st(0)", r_src);
3816 put_ST_UNCHECKED(0,
3817 IRExpr_Mux0X(
3818 unop(Iop_1Uto8,calculate_condition(CondNZ)),
3819 get_ST(0), get_ST(r_src)) );
3820 break;
3821
sewardj8308aad2004-09-12 11:09:54 +00003822 case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
3823 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
3824 break;
3825
sewardj37158712004-10-15 21:23:12 +00003826 case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
3827 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
3828 break;
3829
sewardj8308aad2004-09-12 11:09:54 +00003830 default:
3831 goto decode_fail;
sewardj17442fe2004-09-20 14:54:28 +00003832 }
sewardj89cd0932004-09-08 18:23:25 +00003833 }
sewardjd1725d12004-08-12 20:46:53 +00003834 }
3835
3836 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
3837 else
3838 if (first_opcode == 0xDC) {
sewardja58ea662004-08-15 03:12:41 +00003839 if (modrm < 0xC0) {
3840
sewardj89cd0932004-09-08 18:23:25 +00003841 /* bits 5,4,3 are an opcode extension, and the modRM also
3842 specifies an address. */
sewardja58ea662004-08-15 03:12:41 +00003843 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3844 delta += len;
3845
3846 switch (gregOfRM(modrm)) {
3847
3848 case 0: /* FADD double-real */
3849 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
3850 break;
3851
sewardjcfded9a2004-09-09 11:44:16 +00003852 case 1: /* FMUL double-real */
3853 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
3854 break;
3855
sewardj883b00b2004-09-11 09:30:24 +00003856 case 3: /* FCOMP double-real */
3857 DIP("fcomp %s\n", dis_buf);
3858 /* This forces C1 to zero, which isn't right. */
3859 put_C3210(
3860 binop( Iop_And32,
3861 binop(Iop_Shl32,
3862 binop(Iop_CmpF64,
3863 get_ST(0),
3864 loadLE(Ity_F64,mkexpr(addr))),
3865 mkU8(8)),
3866 mkU32(0x4500)
3867 ));
3868 fp_pop();
3869 break;
3870
sewardjcfded9a2004-09-09 11:44:16 +00003871 case 4: /* FSUB double-real */
3872 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
3873 break;
3874
sewardj3fd5e572004-09-09 22:43:51 +00003875 case 5: /* FSUBR double-real */
3876 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
3877 break;
3878
sewardjcfded9a2004-09-09 11:44:16 +00003879 case 6: /* FDIV double-real */
3880 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
3881 break;
3882
sewardj883b00b2004-09-11 09:30:24 +00003883 case 7: /* FDIVR double-real */
3884 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
3885 break;
3886
sewardja58ea662004-08-15 03:12:41 +00003887 default:
3888 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3889 vex_printf("first_opcode == 0xDC\n");
3890 goto decode_fail;
3891 }
3892
3893 } else {
sewardjbdc7d212004-09-09 02:46:40 +00003894
3895 delta++;
3896 switch (modrm) {
3897
sewardj3fd5e572004-09-09 22:43:51 +00003898 case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
3899 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
3900 break;
3901
sewardjcfded9a2004-09-09 11:44:16 +00003902 case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
3903 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
3904 break;
3905
sewardj47341042004-09-19 11:55:46 +00003906 case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
3907 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
3908 break;
3909
sewardjcfded9a2004-09-09 11:44:16 +00003910 case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
3911 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
3912 break;
3913
sewardja0d48d62004-09-20 21:19:03 +00003914 case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
3915 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
3916 break;
3917
sewardjbdc7d212004-09-09 02:46:40 +00003918 case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
3919 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
3920 break;
3921
3922 default:
3923 goto decode_fail;
3924 }
3925
sewardja58ea662004-08-15 03:12:41 +00003926 }
sewardjd1725d12004-08-12 20:46:53 +00003927 }
3928
3929 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
3930 else
3931 if (first_opcode == 0xDD) {
3932
3933 if (modrm < 0xC0) {
3934
sewardjbb53f8c2004-08-14 11:50:01 +00003935 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjd1725d12004-08-12 20:46:53 +00003936 specifies an address. */
sewardjbb53f8c2004-08-14 11:50:01 +00003937 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3938 delta += len;
sewardjd1725d12004-08-12 20:46:53 +00003939
3940 switch (gregOfRM(modrm)) {
3941
3942 case 0: /* FLD double-real */
3943 DIP("fldD %s\n", dis_buf);
sewardj207557a2004-08-27 12:00:18 +00003944 fp_push();
3945 put_ST(0, IRExpr_LDle(Ity_F64, mkexpr(addr)));
sewardjbb53f8c2004-08-14 11:50:01 +00003946 break;
sewardjd1725d12004-08-12 20:46:53 +00003947
sewardjd1725d12004-08-12 20:46:53 +00003948 case 2: /* FST double-real */
sewardj89cd0932004-09-08 18:23:25 +00003949 DIP("fstD %s", dis_buf);
3950 storeLE(mkexpr(addr), get_ST(0));
sewardjd1725d12004-08-12 20:46:53 +00003951 break;
sewardj89cd0932004-09-08 18:23:25 +00003952
sewardja58ea662004-08-15 03:12:41 +00003953 case 3: /* FSTP double-real */
3954 DIP("fstpD %s", dis_buf);
3955 storeLE(mkexpr(addr), get_ST(0));
sewardj207557a2004-08-27 12:00:18 +00003956 fp_pop();
sewardja58ea662004-08-15 03:12:41 +00003957 break;
sewardjd1725d12004-08-12 20:46:53 +00003958
3959 default:
sewardjbb53f8c2004-08-14 11:50:01 +00003960 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3961 vex_printf("first_opcode == 0xDD\n");
sewardjd1725d12004-08-12 20:46:53 +00003962 goto decode_fail;
sewardjbb53f8c2004-08-14 11:50:01 +00003963 }
sewardjd1725d12004-08-12 20:46:53 +00003964 } else {
sewardja58ea662004-08-15 03:12:41 +00003965 delta++;
3966 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00003967
sewardj06c32a02004-09-12 12:07:34 +00003968 case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
3969 r_dst = (UInt)modrm - 0xD0;
3970 DIP("fst %%st(0),%%st(%d)\n", r_dst);
3971 /* P4 manual says: "If the destination operand is a
3972 non-empty register, the invalid-operation exception
3973 is not generated. Hence put_ST_UNCHECKED. */
3974 put_ST_UNCHECKED(r_dst, get_ST(0));
3975 break;
3976
sewardja58ea662004-08-15 03:12:41 +00003977 case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
3978 r_dst = (UInt)modrm - 0xD8;
3979 DIP("fstp %%st(0),%%st(%d)\n", r_dst);
sewardj207557a2004-08-27 12:00:18 +00003980 /* P4 manual says: "If the destination operand is a
3981 non-empty register, the invalid-operation exception
3982 is not generated. Hence put_ST_UNCHECKED. */
3983 put_ST_UNCHECKED(r_dst, get_ST(0));
3984 fp_pop();
sewardja58ea662004-08-15 03:12:41 +00003985 break;
sewardjbdc7d212004-09-09 02:46:40 +00003986
3987 case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
3988 r_dst = (UInt)modrm - 0xE0;
3989 DIP("fucom %%st(0),%%st(%d)\n", r_dst);
sewardjc4be80c2004-09-10 16:17:45 +00003990 /* This forces C1 to zero, which isn't right. */
3991 put_C3210(
3992 binop( Iop_And32,
3993 binop(Iop_Shl32,
3994 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3995 mkU8(8)),
3996 mkU32(0x4500)
3997 ));
sewardjbdc7d212004-09-09 02:46:40 +00003998 break;
3999
4000 case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
4001 r_dst = (UInt)modrm - 0xE8;
4002 DIP("fucomp %%st(0),%%st(%d)\n", r_dst);
sewardjc4be80c2004-09-10 16:17:45 +00004003 /* This forces C1 to zero, which isn't right. */
4004 put_C3210(
4005 binop( Iop_And32,
4006 binop(Iop_Shl32,
4007 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4008 mkU8(8)),
4009 mkU32(0x4500)
4010 ));
sewardjbdc7d212004-09-09 02:46:40 +00004011 fp_pop();
4012 break;
4013
sewardja58ea662004-08-15 03:12:41 +00004014 default:
4015 goto decode_fail;
4016 }
sewardjd1725d12004-08-12 20:46:53 +00004017 }
4018 }
4019
4020 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
4021 else
4022 if (first_opcode == 0xDE) {
sewardjbdc7d212004-09-09 02:46:40 +00004023
4024 if (modrm < 0xC0) {
4025 goto decode_fail;
4026
4027 } else {
4028
4029 delta++;
4030 switch (modrm) {
4031
sewardjcfded9a2004-09-09 11:44:16 +00004032 case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
4033 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
4034 break;
4035
sewardjbdc7d212004-09-09 02:46:40 +00004036 case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
4037 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
4038 break;
4039
sewardjcfded9a2004-09-09 11:44:16 +00004040 case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
4041 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, True );
4042 break;
4043
sewardj3fd5e572004-09-09 22:43:51 +00004044 case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
4045 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, True );
4046 break;
4047
sewardjbdc7d212004-09-09 02:46:40 +00004048 case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
4049 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
4050 break;
4051
4052 case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
4053 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
4054 break;
4055
4056 default:
4057 goto decode_fail;
4058 }
4059
4060 }
sewardjd1725d12004-08-12 20:46:53 +00004061 }
4062
4063 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
4064 else
4065 if (first_opcode == 0xDF) {
sewardj89cd0932004-09-08 18:23:25 +00004066
4067 if (modrm < 0xC0) {
4068
4069 /* bits 5,4,3 are an opcode extension, and the modRM also
4070 specifies an address. */
4071 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4072 delta += len;
4073
4074 switch (gregOfRM(modrm)) {
4075
sewardj883b00b2004-09-11 09:30:24 +00004076 case 0: /* FILD m16int */
4077 DIP("fildw %s\n", dis_buf);
4078 fp_push();
4079 put_ST(0, unop(Iop_I32toF64,
4080 unop(Iop_16Sto32,
4081 loadLE(Ity_I16, mkexpr(addr)))));
4082 break;
4083
sewardj37158712004-10-15 21:23:12 +00004084 case 2: /* FIST m16 */
4085 DIP("fistp %s", dis_buf);
4086 storeLE( mkexpr(addr),
4087 binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
4088 break;
4089
sewardj89cd0932004-09-08 18:23:25 +00004090 case 3: /* FISTP m16 */
4091 DIP("fistps %s", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004092 storeLE( mkexpr(addr),
4093 binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
4094 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00004095 break;
4096
sewardj89cd0932004-09-08 18:23:25 +00004097 case 5: /* FILD m64 */
4098 DIP("fildll %s\n", dis_buf);
4099 fp_push();
4100 put_ST(0, unop(Iop_I64toF64,
4101 loadLE(Ity_I64, mkexpr(addr))));
4102 break;
sewardj89cd0932004-09-08 18:23:25 +00004103
sewardjcfded9a2004-09-09 11:44:16 +00004104 case 7: /* FISTP m64 */
4105 DIP("fistpll %s", dis_buf);
4106 storeLE( mkexpr(addr),
4107 binop(Iop_F64toI64, get_roundingmode(), get_ST(0)) );
4108 fp_pop();
4109 break;
4110
sewardj89cd0932004-09-08 18:23:25 +00004111 default:
4112 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4113 vex_printf("first_opcode == 0xDF\n");
4114 goto decode_fail;
4115 }
4116
4117 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004118
4119 delta++;
4120 switch (modrm) {
4121
4122 case 0xE0: /* FNSTSW %ax */
4123 DIP("fnstsw %%ax\n");
4124 /* Invent a plausible-looking FPU status word value and
4125 dump it in %AX:
sewardjc4be80c2004-09-10 16:17:45 +00004126 ((ftop & 7) << 11) | (c3210 & 0x4700)
sewardjbdc7d212004-09-09 02:46:40 +00004127 */
4128 putIReg(2, R_EAX,
4129 unop(Iop_32to16,
4130 binop(Iop_Or32,
4131 binop(Iop_Shl32,
4132 binop(Iop_And32, get_ftop(), mkU32(7)),
4133 mkU8(11)),
sewardjc4be80c2004-09-10 16:17:45 +00004134 binop(Iop_And32, get_C3210(), mkU32(0x4700))
sewardjbdc7d212004-09-09 02:46:40 +00004135 )));
4136 break;
4137
sewardj883b00b2004-09-11 09:30:24 +00004138 case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
sewardj8308aad2004-09-12 11:09:54 +00004139 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
sewardj883b00b2004-09-11 09:30:24 +00004140 break;
4141
sewardjbdc7d212004-09-09 02:46:40 +00004142 default:
4143 goto decode_fail;
4144 }
sewardj89cd0932004-09-08 18:23:25 +00004145 }
4146
sewardjd1725d12004-08-12 20:46:53 +00004147 }
4148
4149 else
4150 vpanic("dis_FPU(x86): invalid primary opcode");
4151
sewardj69d9d662004-10-14 21:58:52 +00004152 *decode_ok = True;
4153 return delta;
4154
sewardjd1725d12004-08-12 20:46:53 +00004155 decode_fail:
4156 *decode_ok = False;
4157 return delta;
4158}
4159
4160
sewardjc9a65702004-07-07 16:32:57 +00004161//-- /* Handle FPU insns which read/write memory. On entry, eip points to
4162//-- the second byte of the insn (the one following D8 .. DF). */
4163//-- static
4164//-- Addr dis_fpu_mem ( UCodeBlock* cb,
4165//-- UChar sorb,
4166//-- Int size, Bool is_write,
4167//-- Addr eip, UChar first_byte )
4168//-- {
4169//-- Int ta;
4170//-- UInt pair;
4171//-- UChar dis_buf[50];
4172//-- UChar second_byte = getIByte(delta);
4173//-- vg_assert(second_byte < 0xC0);
4174//-- second_byte &= 0x38;
4175//-- pair = disAMode ( cb, sorb, eip, dis_buf );
4176//-- ta = LOW24(pair);
4177//-- eip += HI8(pair);
4178//-- uInstr2(cb, is_write ? FPU_W : FPU_R, size,
4179//-- Lit16,
4180//-- (((UShort)first_byte) << 8) | ((UShort)second_byte),
4181//-- TempReg, ta);
4182//-- if (is_write) {
4183//-- DIP("fpu_w_%d 0x%x:0x%x, %s\n",
4184//-- size, (UInt)first_byte, (UInt)second_byte, dis_buf );
4185//-- } else {
4186//-- DIP("fpu_r_%d %s, 0x%x:0x%x\n",
4187//-- size, dis_buf, (UInt)first_byte, (UInt)second_byte );
4188//-- }
4189//-- return eip;
4190//-- }
4191//--
4192//--
4193//-- /* Handle FPU insns which don't reference memory. On entry, eip points to
4194//-- the second byte of the insn (the one following D8 .. DF). */
4195//-- static
4196//-- Addr dis_fpu_no_mem ( UCodeBlock* cb, Addr eip, UChar first_byte )
4197//-- {
4198//-- Bool sets_ZCP = False;
4199//-- Bool uses_ZCP = False;
4200//-- UChar second_byte = getUChar(eip); eip++;
4201//-- vg_assert(second_byte >= 0xC0);
4202//--
4203//-- /* Does the insn write any integer condition codes (%EIP) ? */
4204//--
4205//-- if (first_byte == 0xDB && second_byte >= 0xF0 && second_byte <= 0xF7) {
4206//-- /* FCOMI */
4207//-- sets_ZCP = True;
4208//-- } else
4209//-- if (first_byte == 0xDF && second_byte >= 0xF0 && second_byte <= 0xF7) {
4210//-- /* FCOMIP */
4211//-- sets_ZCP = True;
4212//-- } else
4213//-- if (first_byte == 0xDB && second_byte >= 0xE8 && second_byte <= 0xEF) {
4214//-- /* FUCOMI */
4215//-- sets_ZCP = True;
4216//-- } else
4217//-- if (first_byte == 0xDF && second_byte >= 0xE8 && second_byte <= 0xEF) {
4218//-- /* FUCOMIP */
4219//-- sets_ZCP = True;
4220//-- }
4221//--
4222//-- /* Dually, does the insn read any integer condition codes (%EIP) ? */
4223//--
4224//-- if (first_byte == 0xDA && second_byte >= 0xC0 && second_byte <= 0xDF) {
4225//-- /* FCMOVB %st(n), %st(0)
4226//-- FCMOVE %st(n), %st(0)
4227//-- FCMOVBE %st(n), %st(0)
4228//-- FCMOVU %st(n), %st(0)
4229//-- */
4230//-- uses_ZCP = True;
4231//-- } else
4232//-- if (first_byte == 0xDB && second_byte >= 0xC0 && second_byte <= 0xDF) {
4233//-- /* FCMOVNB %st(n), %st(0)
4234//-- FCMOVNE %st(n), %st(0)
4235//-- FCMOVNBE %st(n), %st(0)
4236//-- FCMOVNU %st(n), %st(0)
4237//-- */
4238//-- uses_ZCP = True;
4239//-- }
4240//--
4241//-- uInstr1(cb, FPU, 0,
4242//-- Lit16,
4243//-- (((UShort)first_byte) << 8) | ((UShort)second_byte)
4244//-- );
4245//-- if (uses_ZCP) {
4246//-- /* VG_(printf)("!!! --- FPU insn which reads %EFLAGS\n"); */
4247//-- uFlagsRWU(cb, FlagsZCP, FlagsEmpty, FlagsEmpty);
4248//-- vg_assert(!sets_ZCP);
4249//-- }
4250//-- if (sets_ZCP) {
4251//-- /* VG_(printf)("!!! --- FPU insn which writes %EFLAGS\n"); */
4252//-- uFlagsRWU(cb, FlagsEmpty, FlagsZCP, FlagsEmpty);
4253//-- vg_assert(!uses_ZCP);
4254//-- }
4255//--
4256//-- DIP("fpu 0x%x:0x%x%s%s\n", (UInt)first_byte, (UInt)second_byte,
4257//-- uses_ZCP ? " -rZCP" : "",
4258//-- sets_ZCP ? " -wZCP" : "" );
4259//-- return eip;
4260//-- }
4261//--
4262//--
4263//-- /* Top-level handler for all FPU insns. On entry, eip points to the
4264//-- second byte of the insn. */
4265//-- static
4266//-- Addr dis_fpu ( UCodeBlock* cb,
4267//-- UChar sorb,
4268//-- UChar first_byte, Addr eip )
4269//-- {
4270//-- const Bool rd = False;
4271//-- const Bool wr = True;
4272//-- UChar second_byte = getUChar(eip);
4273//--
4274//-- /* Handle FSTSW %ax specially. */
4275//-- if (first_byte == 0xDF && second_byte == 0xE0) {
4276//-- Int t1 = newTemp(cb);
4277//-- uInstr0(cb, CALLM_S, 0);
4278//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
4279//-- uLiteral(cb, 0);
4280//-- uInstr1(cb, PUSH, 4, TempReg, t1);
4281//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_fstsw_AX) );
4282//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
4283//-- uInstr1(cb, POP, 2, TempReg, t1);
4284//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
4285//-- uInstr0(cb, CALLM_E, 0);
4286//-- DIP("fstsw %%ax\n");
4287//-- eip++;
4288//-- return eip;
4289//-- }
4290//--
4291//-- /* Handle all non-memory FPU ops simply. */
4292//-- if (second_byte >= 0xC0)
4293//-- return dis_fpu_no_mem ( cb, eip, first_byte );
4294//--
4295//-- /* The insn references memory; need to determine
4296//-- whether it reads or writes, and at what size. */
4297//-- switch (first_byte) {
4298//--
4299//-- case 0xD8:
4300//-- switch ((second_byte >> 3) & 7) {
4301//-- case 0: /* FADDs */
4302//-- case 1: /* FMULs */
4303//-- case 2: /* FCOMs */
4304//-- case 3: /* FCOMPs */
4305//-- case 4: /* FSUBs */
4306//-- case 5: /* FSUBRs */
4307//-- case 6: /* FDIVs */
4308//-- case 7: /* FDIVRs */
4309//-- return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
4310//-- default:
4311//-- goto unhandled;
4312//-- }
4313//-- break;
4314//--
4315//-- case 0xD9:
4316//-- switch ((second_byte >> 3) & 7) {
4317//-- case 0: /* FLDs */
4318//-- return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
4319//-- case 2: /* FSTs */
4320//-- case 3: /* FSTPs */
4321//-- return dis_fpu_mem(cb, sorb, 4, wr, eip, first_byte);
4322//-- case 4: /* FLDENV */
4323//-- return dis_fpu_mem(cb, sorb, 28, rd, eip, first_byte);
4324//-- case 5: /* FLDCW */
4325//-- return dis_fpu_mem(cb, sorb, 2, rd, eip, first_byte);
4326//-- case 6: /* FNSTENV */
4327//-- return dis_fpu_mem(cb, sorb, 28, wr, eip, first_byte);
4328//-- case 7: /* FSTCW */
4329//-- /* HACK! FSTCW actually writes 2 bytes, not 4. glibc
4330//-- gets lots of moaning in __floor() if we do the right
4331//-- thing here. */
4332//-- /* Later ... hack disabled .. we do do the Right Thing. */
4333//-- return dis_fpu_mem(cb, sorb, /*4*/ 2, wr, eip, first_byte);
4334//-- default:
4335//-- goto unhandled;
4336//-- }
4337//-- break;
4338//--
4339//-- case 0xDA:
4340//-- switch ((second_byte >> 3) & 7) {
4341//-- case 0: /* FIADD dword-integer */
4342//-- case 1: /* FIMUL dword-integer */
4343//-- case 2: /* FICOM dword-integer */
4344//-- case 3: /* FICOMP dword-integer */
4345//-- case 4: /* FISUB dword-integer */
4346//-- case 5: /* FISUBR dword-integer */
4347//-- case 6: /* FIDIV dword-integer */
4348//-- case 7: /* FIDIVR dword-integer */
4349//-- return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
4350//-- default:
4351//-- goto unhandled;
4352//-- }
4353//-- break;
4354//--
4355//-- case 0xDB:
4356//-- switch ((second_byte >> 3) & 7) {
4357//-- case 0: /* FILD dword-integer */
4358//-- return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
4359//-- case 2: /* FIST dword-integer */
4360//-- return dis_fpu_mem(cb, sorb, 4, wr, eip, first_byte);
4361//-- case 3: /* FISTPl */
4362//-- return dis_fpu_mem(cb, sorb, 4, wr, eip, first_byte);
4363//-- case 5: /* FLD extended-real */
4364//-- return dis_fpu_mem(cb, sorb, 10, rd, eip, first_byte);
4365//-- case 7: /* FSTP extended-real */
4366//-- return dis_fpu_mem(cb, sorb, 10, wr, eip, first_byte);
4367//-- default:
4368//-- goto unhandled;
4369//-- }
4370//-- break;
4371//--
4372//-- case 0xDC:
4373//-- switch ((second_byte >> 3) & 7) {
4374//-- case 0: /* FADD double-real */
4375//-- case 1: /* FMUL double-real */
4376//-- case 2: /* FCOM double-real */
4377//-- case 3: /* FCOMP double-real */
4378//-- case 4: /* FSUB double-real */
4379//-- case 5: /* FSUBR double-real */
4380//-- case 6: /* FDIV double-real */
4381//-- case 7: /* FDIVR double-real */
4382//-- return dis_fpu_mem(cb, sorb, 8, rd, eip, first_byte);
4383//-- default:
4384//-- goto unhandled;
4385//-- }
4386//-- break;
4387//--
4388//-- case 0xDD:
4389//-- switch ((second_byte >> 3) & 7) {
4390//-- case 0: /* FLD double-real */
4391//-- return dis_fpu_mem(cb, sorb, 8, rd, eip, first_byte);
4392//-- case 2: /* FST double-real */
4393//-- case 3: /* FSTP double-real */
4394//-- return dis_fpu_mem(cb, sorb, 8, wr, eip, first_byte);
4395//-- case 4: /* FRSTOR */
4396//-- return dis_fpu_mem(cb, sorb, 108, rd, eip, first_byte);
4397//-- case 6: /* FSAVE */
4398//-- return dis_fpu_mem(cb, sorb, 108, wr, eip, first_byte);
4399//-- case 7: /* FSTSW */
4400//-- return dis_fpu_mem(cb, sorb, 2, wr, eip, first_byte);
4401//-- default:
4402//-- goto unhandled;
4403//-- }
4404//-- break;
4405//--
4406//-- case 0xDE:
4407//-- switch ((second_byte >> 3) & 7) {
4408//-- case 0: /* FIADD word-integer */
4409//-- case 1: /* FIMUL word-integer */
4410//-- case 2: /* FICOM word-integer */
4411//-- case 3: /* FICOMP word-integer */
4412//-- case 4: /* FISUB word-integer */
4413//-- case 5: /* FISUBR word-integer */
4414//-- case 6: /* FIDIV word-integer */
4415//-- case 7: /* FIDIVR word-integer */
4416//-- return dis_fpu_mem(cb, sorb, 2, rd, eip, first_byte);
4417//-- default:
4418//-- goto unhandled;
4419//-- }
4420//-- break;
4421//--
4422//-- case 0xDF:
4423//-- switch ((second_byte >> 3) & 7) {
4424//-- case 0: /* FILD word-integer */
4425//-- return dis_fpu_mem(cb, sorb, 2, rd, eip, first_byte);
4426//-- case 2: /* FIST word-integer */
4427//-- return dis_fpu_mem(cb, sorb, 2, wr, eip, first_byte);
4428//-- case 3: /* FISTP word-integer */
4429//-- return dis_fpu_mem(cb, sorb, 2, wr, eip, first_byte);
4430//-- case 5: /* FILD qword-integer */
4431//-- return dis_fpu_mem(cb, sorb, 8, rd, eip, first_byte);
4432//-- case 7: /* FISTP qword-integer */
4433//-- return dis_fpu_mem(cb, sorb, 8, wr, eip, first_byte);
4434//-- default:
4435//-- goto unhandled;
4436//-- }
4437//-- break;
4438//--
4439//-- default: goto unhandled;
4440//-- }
4441//--
4442//-- unhandled:
4443//-- VG_(printf)("dis_fpu: unhandled memory case 0x%2x:0x%2x(%d)\n",
4444//-- (UInt)first_byte, (UInt)second_byte,
4445//-- (UInt)((second_byte >> 3) & 7) );
4446//-- VG_(core_panic)("dis_fpu: unhandled opcodes");
4447//-- }
sewardja06e5562004-07-14 13:18:05 +00004448
4449
4450/* Double length left and right shifts. Apparently only required in
4451 v-size (no b- variant). */
4452static
4453UInt dis_SHLRD_Gv_Ev ( UChar sorb,
4454 UInt delta, UChar modrm,
4455 Int sz,
4456 IRExpr* shift_amt,
4457 Bool amt_is_literal,
4458 Char* shift_amt_txt,
4459 Bool left_shift )
4460{
4461 /* shift_amt :: Ity_I8 is the amount to shift. shift_amt_txt is used
4462 for printing it. And eip on entry points at the modrm byte. */
4463 Int len;
4464 UChar dis_buf[50];
4465
sewardj6d2638e2004-07-15 09:38:27 +00004466 IRType ty = szToITy(sz);
4467 IRTemp gsrc = newTemp(ty);
4468 IRTemp esrc = newTemp(ty);
4469 IRTemp addr = INVALID_IRTEMP;
4470 IRTemp tmpSH = newTemp(Ity_I8);
sewardj6d2638e2004-07-15 09:38:27 +00004471 IRTemp tmpL = INVALID_IRTEMP;
4472 IRTemp tmpRes = INVALID_IRTEMP;
sewardja06e5562004-07-14 13:18:05 +00004473 IRTemp tmpSubSh = INVALID_IRTEMP;
4474 IROp mkpair;
4475 IROp getres;
4476 IROp shift;
sewardja06e5562004-07-14 13:18:05 +00004477 IRExpr* mask = NULL;
4478
4479 vassert(sz == 2 || sz == 4);
4480
4481 /* The E-part is the destination; this is shifted. The G-part
4482 supplies bits to be shifted into the E-part, but is not
4483 changed.
4484
4485 If shifting left, form a double-length word with E at the top
4486 and G at the bottom, and shift this left. The result is then in
4487 the high part.
4488
4489 If shifting right, form a double-length word with G at the top
4490 and E at the bottom, and shift this right. The result is then
4491 at the bottom. */
4492
4493 /* Fetch the operands. */
4494
4495 assign( gsrc, getIReg(sz, gregOfRM(modrm)) );
4496
4497 if (epartIsReg(modrm)) {
4498 delta++;
4499 assign( esrc, getIReg(sz, eregOfRM(modrm)) );
sewardj68511542004-07-28 00:15:44 +00004500 DIP("sh%cd%c %s, %s, %s\n",
sewardja06e5562004-07-14 13:18:05 +00004501 ( left_shift ? 'l' : 'r' ), nameISize(sz),
sewardj68511542004-07-28 00:15:44 +00004502 shift_amt_txt,
sewardja06e5562004-07-14 13:18:05 +00004503 nameIReg(sz, gregOfRM(modrm)), nameIReg(sz, eregOfRM(modrm)));
4504 } else {
4505 addr = disAMode ( &len, sorb, delta, dis_buf );
4506 delta += len;
4507 assign( esrc, loadLE(ty, mkexpr(addr)) );
sewardj68511542004-07-28 00:15:44 +00004508 DIP("sh%cd%c %s, %s, %s\n",
4509 ( left_shift ? 'l' : 'r' ), nameISize(sz),
4510 shift_amt_txt,
4511 nameIReg(sz, gregOfRM(modrm)), dis_buf);
sewardja06e5562004-07-14 13:18:05 +00004512 }
4513
4514 /* Round up the relevant primops. */
4515
4516 if (sz == 4) {
4517 tmpL = newTemp(Ity_I64);
4518 tmpRes = newTemp(Ity_I32);
4519 tmpSubSh = newTemp(Ity_I32);
sewardje539a402004-07-14 18:24:17 +00004520 mkpair = Iop_32HLto64;
sewardj8c7f1ab2004-07-29 20:31:09 +00004521 getres = left_shift ? Iop_64HIto32 : Iop_64to32;
sewardje539a402004-07-14 18:24:17 +00004522 shift = left_shift ? Iop_Shl64 : Iop_Shr64;
4523 mask = mkU8(31);
sewardja06e5562004-07-14 13:18:05 +00004524 } else {
4525 /* sz == 2 */
sewardj8c7f1ab2004-07-29 20:31:09 +00004526 tmpL = newTemp(Ity_I32);
4527 tmpRes = newTemp(Ity_I16);
4528 tmpSubSh = newTemp(Ity_I16);
4529 mkpair = Iop_16HLto32;
4530 getres = left_shift ? Iop_32HIto16 : Iop_32to16;
4531 shift = left_shift ? Iop_Shl32 : Iop_Shr32;
4532 mask = mkU8(15);
sewardja06e5562004-07-14 13:18:05 +00004533 }
4534
4535 /* Do the shift, calculate the subshift value, and set
4536 the flag thunk. */
4537
sewardj8c7f1ab2004-07-29 20:31:09 +00004538 assign( tmpSH, binop(Iop_And8, shift_amt, mask) );
4539
sewardja06e5562004-07-14 13:18:05 +00004540 if (left_shift)
4541 assign( tmpL, binop(mkpair, mkexpr(esrc), mkexpr(gsrc)) );
4542 else
4543 assign( tmpL, binop(mkpair, mkexpr(gsrc), mkexpr(esrc)) );
4544
4545 assign( tmpRes, unop(getres, binop(shift, mkexpr(tmpL), mkexpr(tmpSH)) ) );
4546 assign( tmpSubSh,
4547 unop(getres,
4548 binop(shift,
4549 mkexpr(tmpL),
4550 binop(Iop_And8,
4551 binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
4552 mask))) );
sewardja06e5562004-07-14 13:18:05 +00004553
sewardjc22a6fd2004-07-29 23:41:47 +00004554 setFlags_DSTus_DST1 ( left_shift ? Iop_Shl32 : Iop_Sar32,
sewardjbb53f8c2004-08-14 11:50:01 +00004555 tmpSubSh, tmpRes, ty, tmpSH );
sewardja06e5562004-07-14 13:18:05 +00004556
4557 /* Put result back. */
4558
4559 if (epartIsReg(modrm)) {
4560 putIReg(sz, eregOfRM(modrm), mkexpr(tmpRes));
4561 } else {
4562 storeLE( mkexpr(addr), mkexpr(tmpRes) );
4563 }
4564
4565 if (amt_is_literal) delta++;
4566 return delta;
4567}
4568
4569
sewardj1c6f9912004-09-07 10:15:24 +00004570/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
4571 required. */
4572
4573typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
4574
4575static Char* nameBtOp ( BtOp op )
4576{
4577 switch (op) {
4578 case BtOpNone: return "";
4579 case BtOpSet: return "s";
4580 case BtOpReset: return "r";
4581 case BtOpComp: return "c";
4582 default: vpanic("nameBtOp(x86)");
4583 }
4584}
4585
4586
4587static
4588UInt dis_bt_G_E ( UChar sorb, Int sz, UInt delta, BtOp op )
4589{
4590 Char dis_buf[50];
4591 UChar modrm;
4592 Int len;
4593 IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
4594 t_addr1, t_esp, t_mask;
4595
4596 vassert(sz == 2 || sz == 4);
4597
4598 t_fetched = t_bitno0 = t_bitno1 = t_bitno2
4599 = t_addr0 = t_addr1 = t_esp = t_mask = INVALID_IRTEMP;
4600
4601 t_fetched = newTemp(Ity_I8);
4602 t_bitno0 = newTemp(Ity_I32);
4603 t_bitno1 = newTemp(Ity_I32);
4604 t_bitno2 = newTemp(Ity_I8);
4605 t_addr1 = newTemp(Ity_I32);
4606 modrm = getIByte(delta);
4607
4608 assign( t_bitno0, widenUto32(getIReg(sz, gregOfRM(modrm))) );
4609
4610 if (epartIsReg(modrm)) {
sewardj1c6f9912004-09-07 10:15:24 +00004611 delta++;
4612 /* Get it onto the client's stack. */
4613 t_esp = newTemp(Ity_I32);
4614 t_addr0 = newTemp(Ity_I32);
4615
4616 assign( t_esp, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
4617 putIReg(4, R_ESP, mkexpr(t_esp));
4618
4619 storeLE( mkexpr(t_esp), getIReg(sz, eregOfRM(modrm)) );
4620
4621 /* Make t_addr0 point at it. */
4622 assign( t_addr0, mkexpr(t_esp) );
4623
4624 /* Mask out upper bits of the shift amount, since we're doing a
4625 reg. */
4626 assign( t_bitno1, binop(Iop_And32,
4627 mkexpr(t_bitno0),
4628 mkU32(sz == 4 ? 31 : 15)) );
4629
4630 } else {
4631 t_addr0 = disAMode ( &len, sorb, delta, dis_buf );
4632 delta += len;
4633 assign( t_bitno1, mkexpr(t_bitno0) );
4634 }
4635
4636 /* At this point: t_addr0 is the address being operated on. If it
4637 was a reg, we will have pushed it onto the client's stack.
4638 t_bitno1 is the bit number, suitably masked in the case of a
4639 reg. */
4640
4641 /* Now the main sequence. */
4642 assign( t_addr1,
4643 binop(Iop_Add32,
4644 mkexpr(t_addr0),
4645 binop(Iop_Sar32, mkexpr(t_bitno1), mkU8(3))) );
4646
4647 /* t_addr1 now holds effective address */
4648
4649 assign( t_bitno2,
4650 unop(Iop_32to8,
4651 binop(Iop_And32, mkexpr(t_bitno1), mkU32(7))) );
4652
4653 /* t_bitno2 contains offset of bit within byte */
4654
4655 if (op != BtOpNone) {
4656 t_mask = newTemp(Ity_I8);
4657 assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
4658 }
sewardj4963a422004-10-14 23:34:03 +00004659
sewardj1c6f9912004-09-07 10:15:24 +00004660 /* t_mask is now a suitable byte mask */
4661
4662 assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
4663
4664 if (op != BtOpNone) {
4665 switch (op) {
4666 case BtOpSet:
4667 storeLE( mkexpr(t_addr1),
4668 binop(Iop_Or8, mkexpr(t_fetched),
4669 mkexpr(t_mask)) );
4670 break;
4671 case BtOpComp:
4672 storeLE( mkexpr(t_addr1),
4673 binop(Iop_Xor8, mkexpr(t_fetched),
4674 mkexpr(t_mask)) );
4675 break;
4676 case BtOpReset:
4677 storeLE( mkexpr(t_addr1),
4678 binop(Iop_And8, mkexpr(t_fetched),
4679 unop(Iop_Not8, mkexpr(t_mask))) );
4680 break;
4681 default:
4682 vpanic("dis_bt_G_E(x86)");
4683 }
4684 }
4685
4686 /* Side effect done; now get selected bit into Carry flag */
4687 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
4688 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
4689 stmt( IRStmt_Put( OFFB_CC_DST, mkU32(0) ));
4690 stmt( IRStmt_Put(
4691 OFFB_CC_SRC,
4692 binop(Iop_And32,
4693 binop(Iop_Shr32,
4694 unop(Iop_8Uto32, mkexpr(t_fetched)),
4695 mkexpr(t_bitno2)),
4696 mkU32(1)))
4697 );
4698
4699 /* Move reg operand from stack back to reg */
4700 if (epartIsReg(modrm)) {
4701 /* t_esp still points at it. */
sewardj4963a422004-10-14 23:34:03 +00004702 putIReg(sz, eregOfRM(modrm), loadLE(szToITy(sz), mkexpr(t_esp)) );
sewardj1c6f9912004-09-07 10:15:24 +00004703 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t_esp), mkU32(sz)) );
4704 }
4705
4706 DIP("bt%s%c %s, %s\n",
4707 nameBtOp(op), nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
4708 ( epartIsReg(modrm) ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ) );
4709
4710 return delta;
4711}
sewardjce646f22004-08-31 23:55:54 +00004712
4713
4714
4715/* Handle BSF/BSR. Only v-size seems necessary. */
4716static
4717UInt dis_bs_E_G ( UChar sorb, Int sz, UInt delta, Bool fwds )
4718{
4719 Bool isReg;
4720 UChar modrm;
4721 Char dis_buf[50];
4722
4723 IRType ty = szToITy(sz);
4724 IRTemp src = newTemp(ty);
4725 IRTemp dst = newTemp(ty);
4726
4727 IRTemp src32 = newTemp(Ity_I32);
4728 IRTemp dst32 = newTemp(Ity_I32);
4729 IRTemp src8 = newTemp(Ity_I8);
4730
4731 vassert(sz == 4 || sz == 2);
sewardjce646f22004-08-31 23:55:54 +00004732
4733 modrm = getIByte(delta);
4734
4735 isReg = epartIsReg(modrm);
4736 if (isReg) {
4737 delta++;
4738 assign( src, getIReg(sz, eregOfRM(modrm)) );
4739 } else {
4740 Int len;
4741 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4742 delta += len;
4743 assign( src, loadLE(ty, mkexpr(addr)) );
4744 }
4745
4746 DIP("bs%c%c %s, %s\n",
4747 fwds ? 'f' : 'r', nameISize(sz),
4748 ( isReg ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ),
4749 nameIReg(sz, gregOfRM(modrm)));
4750
4751 /* Generate an 8-bit expression which is zero iff the
4752 original is zero, and nonzero otherwise */
4753 assign( src8,
4754 unop(Iop_1Uto8, binop(mkSizedOp(ty,Iop_CmpNE8),
4755 mkexpr(src), mkU(ty,0))) );
4756
4757 /* Flags: Z is 1 iff source value is zero. All others
4758 are undefined -- we force them to zero. */
4759 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
4760 stmt( IRStmt_Put( OFFB_CC_DST, mkU32(0) ));
4761 stmt( IRStmt_Put(
4762 OFFB_CC_SRC,
4763 IRExpr_Mux0X( mkexpr(src8),
4764 /* src==0 */
4765 mkU32(CC_MASK_Z),
4766 /* src!=0 */
4767 mkU32(0)
4768 )
4769 ));
4770
4771 /* Result: iff source value is zero, we can't use
4772 Iop_Clz32/Iop_Ctz32 as they have no defined result in that case.
4773 But anyway, Intel x86 semantics say the result is undefined in
4774 such situations. Hence handle the zero case specially. */
4775
4776 /* Bleh. What we compute:
4777
4778 bsf32: if src == 0 then 0 else Ctz32(src)
4779 bsr32: if src == 0 then 0 else 31 - Clz32(src)
4780
4781 bsf16: if src == 0 then 0 else Ctz32(16Uto32(src))
4782 bsr16: if src == 0 then 0 else 31 - Clz32(16Uto32(src))
4783
4784 First, widen src to 32 bits if it is not already.
sewardj37158712004-10-15 21:23:12 +00004785
4786 Postscript 15 Oct 04: it seems that at least VIA Nehemiah leaves the
4787 dst register unchanged when src == 0. Hence change accordingly.
sewardjce646f22004-08-31 23:55:54 +00004788 */
4789 if (sz == 2)
4790 assign( src32, unop(Iop_16Uto32, mkexpr(src)) );
4791 else
4792 assign( src32, mkexpr(src) );
4793
4794 /* The main computation, guarding against zero. */
4795 assign( dst32,
4796 IRExpr_Mux0X(
4797 mkexpr(src8),
sewardj37158712004-10-15 21:23:12 +00004798 /* src == 0 -- leave dst unchanged */
4799 widenUto32( getIReg( sz, gregOfRM(modrm) ) ),
sewardjce646f22004-08-31 23:55:54 +00004800 /* src != 0 */
4801 fwds ? unop(Iop_Ctz32, mkexpr(src32))
4802 : binop(Iop_Sub32,
4803 mkU32(31),
4804 unop(Iop_Clz32, mkexpr(src32)))
4805 )
4806 );
4807
4808 if (sz == 2)
4809 assign( dst, unop(Iop_32to16, mkexpr(dst32)) );
4810 else
4811 assign( dst, mkexpr(dst32) );
4812
4813 /* dump result back */
4814 putIReg( sz, gregOfRM(modrm), mkexpr(dst) );
4815
4816 return delta;
4817}
sewardj64e1d652004-07-12 14:00:46 +00004818
4819
4820static
4821void codegen_xchg_eAX_Reg ( Int sz, Int reg )
4822{
4823 IRType ty = szToITy(sz);
4824 IRTemp t1 = newTemp(ty);
4825 IRTemp t2 = newTemp(ty);
4826 vassert(sz == 2 || sz == 4);
4827 assign( t1, getIReg(sz, R_EAX) );
4828 assign( t2, getIReg(sz, reg) );
4829 putIReg( sz, R_EAX, mkexpr(t2) );
4830 putIReg( sz, reg, mkexpr(t1) );
4831 DIP("xchg%c %s, %s\n",
4832 nameISize(sz), nameIReg(sz, R_EAX), nameIReg(sz, reg));
4833}
4834
4835
sewardjbdc7d212004-09-09 02:46:40 +00004836static
4837void codegen_SAHF ( void )
4838{
4839 /* Set the flags to:
4840 (calculate_flags_all() & CC_MASK_O) -- retain the old O flag
4841 | (%AH & (CC_MASK_S|CC_MASK_Z|CC_MASK_A|CC_MASK_P|CC_MASK_C)
4842 */
4843 UInt mask_SZACP = CC_MASK_S|CC_MASK_Z|CC_MASK_A|CC_MASK_P|CC_MASK_C;
4844 IRTemp oldflags = newTemp(Ity_I32);
4845 assign( oldflags, mk_calculate_eflags_all() );
4846 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
4847 stmt( IRStmt_Put( OFFB_CC_DST, mkU32(0) ));
4848 stmt( IRStmt_Put( OFFB_CC_SRC,
4849 binop(Iop_Or32,
4850 binop(Iop_And32, mkexpr(oldflags), mkU32(CC_MASK_O)),
4851 binop(Iop_And32,
4852 binop(Iop_Shr32, getIReg(4, R_EAX), mkU8(8)),
4853 mkU32(mask_SZACP))
4854 )
4855 ));
4856}
4857
4858
sewardjc9a65702004-07-07 16:32:57 +00004859//-- static
4860//-- void codegen_LAHF ( UCodeBlock* cb )
4861//-- {
4862//-- Int t = newTemp(cb);
4863//--
4864//-- /* Pushed arg is ignored, it just provides somewhere to put the
4865//-- return value. */
4866//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t);
4867//-- uInstr0(cb, CALLM_S, 0);
4868//-- uInstr1(cb, PUSH, 4, TempReg, t);
4869//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_LAHF));
4870//-- uFlagsRWU(cb, FlagsSZACP, FlagsEmpty, FlagsEmpty);
4871//-- uInstr1(cb, POP, 4, TempReg, t);
4872//-- uInstr0(cb, CALLM_E, 0);
4873//--
4874//-- /* At this point, the %ah sub-register in %eax has been updated,
4875//-- the rest is the same, so do a PUT of the whole thing. */
4876//-- uInstr2(cb, PUT, 4, TempReg, t, ArchReg, R_EAX);
4877//-- }
4878//--
sewardj458a6f82004-08-25 12:46:02 +00004879
4880static
4881UInt dis_cmpxchg_G_E ( UChar sorb,
4882 Int size,
4883 UInt delta0 )
4884{
4885 UChar dis_buf[50];
4886 Int len;
4887
4888 IRType ty = szToITy(size);
4889 IRTemp acc = newTemp(ty);
4890 IRTemp src = newTemp(ty);
4891 IRTemp dest = newTemp(ty);
4892 IRTemp dest2 = newTemp(ty);
4893 IRTemp acc2 = newTemp(ty);
4894 IRTemp cond8 = newTemp(Ity_I8);
4895 IRTemp addr = INVALID_IRTEMP;
4896 UChar rm = getUChar(delta0);
4897
4898 if (epartIsReg(rm)) {
4899 assign( dest, getIReg(size, eregOfRM(rm)) );
4900 delta0++;
4901 DIP("cmpxchg%c %s,%s\n", nameISize(size),
4902 nameIReg(size,gregOfRM(rm)),
4903 nameIReg(size,eregOfRM(rm)) );
sewardj458a6f82004-08-25 12:46:02 +00004904 } else {
4905 addr = disAMode ( &len, sorb, delta0, dis_buf );
4906 assign( dest, loadLE(ty, mkexpr(addr)) );
4907 delta0 += len;
4908 DIP("cmpxchg%c %s,%s\n", nameISize(size),
4909 nameIReg(size,gregOfRM(rm)), dis_buf);
4910 }
4911
4912 assign( src, getIReg(size, gregOfRM(rm)) );
4913 assign( acc, getIReg(size, R_EAX) );
4914 setFlags_ADD_SUB(Iop_Sub8, dest, acc, ty);
4915 assign( cond8, unop(Iop_1Uto8, calculate_condition(CondZ)) );
4916 assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
4917 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
4918 putIReg(size, R_EAX, mkexpr(acc2));
4919
4920 if (epartIsReg(rm)) {
4921 putIReg(size, eregOfRM(rm), mkexpr(dest2));
4922 } else {
4923 storeLE( mkexpr(addr), mkexpr(dest2) );
4924 }
4925
4926 return delta0;
4927}
4928
4929
sewardjc9a65702004-07-07 16:32:57 +00004930//-- static
4931//-- Addr dis_cmpxchg8b ( UCodeBlock* cb,
4932//-- UChar sorb,
4933//-- Addr eip0 )
4934//-- {
4935//-- Int tal, tah, junkl, junkh, destl, desth, srcl, srch, accl, acch;
4936//-- UChar dis_buf[50];
4937//-- UChar rm;
4938//-- UInt pair;
4939//--
4940//-- rm = getUChar(eip0);
4941//-- accl = newTemp(cb);
4942//-- acch = newTemp(cb);
4943//-- srcl = newTemp(cb);
4944//-- srch = newTemp(cb);
4945//-- destl = newTemp(cb);
4946//-- desth = newTemp(cb);
4947//-- junkl = newTemp(cb);
4948//-- junkh = newTemp(cb);
4949//--
4950//-- vg_assert(!epartIsReg(rm));
4951//--
4952//-- pair = disAMode ( cb, sorb, eip0, dis_buf );
4953//-- tal = LOW24(pair);
4954//-- tah = newTemp(cb);
4955//-- uInstr2(cb, MOV, 4, TempReg, tal, TempReg, tah);
4956//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, tah);
4957//-- uLiteral(cb, 4);
4958//-- eip0 += HI8(pair);
4959//-- DIP("cmpxchg8b %s\n", dis_buf);
4960//--
4961//-- uInstr0(cb, CALLM_S, 0);
4962//--
4963//-- uInstr2(cb, LOAD, 4, TempReg, tah, TempReg, desth);
4964//-- uInstr1(cb, PUSH, 4, TempReg, desth);
4965//-- uInstr2(cb, LOAD, 4, TempReg, tal, TempReg, destl);
4966//-- uInstr1(cb, PUSH, 4, TempReg, destl);
4967//-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, srch);
4968//-- uInstr1(cb, PUSH, 4, TempReg, srch);
4969//-- uInstr2(cb, GET, 4, ArchReg, R_EBX, TempReg, srcl);
4970//-- uInstr1(cb, PUSH, 4, TempReg, srcl);
4971//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, acch);
4972//-- uInstr1(cb, PUSH, 4, TempReg, acch);
4973//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, accl);
4974//-- uInstr1(cb, PUSH, 4, TempReg, accl);
4975//--
4976//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_cmpxchg8b));
4977//-- uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsEmpty);
4978//--
4979//-- uInstr1(cb, POP, 4, TempReg, accl);
4980//-- uInstr2(cb, PUT, 4, TempReg, accl, ArchReg, R_EAX);
4981//-- uInstr1(cb, POP, 4, TempReg, acch);
4982//-- uInstr2(cb, PUT, 4, TempReg, acch, ArchReg, R_EDX);
4983//-- uInstr1(cb, POP, 4, TempReg, srcl);
4984//-- uInstr2(cb, PUT, 4, TempReg, srcl, ArchReg, R_EBX);
4985//-- uInstr1(cb, POP, 4, TempReg, srch);
4986//-- uInstr2(cb, PUT, 4, TempReg, srch, ArchReg, R_ECX);
4987//-- uInstr1(cb, POP, 4, TempReg, destl);
4988//-- uInstr2(cb, STORE, 4, TempReg, destl, TempReg, tal);
4989//-- uInstr1(cb, POP, 4, TempReg, desth);
4990//-- uInstr2(cb, STORE, 4, TempReg, desth, TempReg, tah);
4991//--
4992//-- uInstr0(cb, CALLM_E, 0);
4993//--
4994//-- return eip0;
4995//-- }
sewardj458a6f82004-08-25 12:46:02 +00004996
4997
4998/* Handle conditional move instructions of the form
4999 cmovcc E(reg-or-mem), G(reg)
5000
5001 E(src) is reg-or-mem
5002 G(dst) is reg.
5003
5004 If E is reg, --> GET %E, tmps
5005 GET %G, tmpd
5006 CMOVcc tmps, tmpd
5007 PUT tmpd, %G
5008
5009 If E is mem --> (getAddr E) -> tmpa
5010 LD (tmpa), tmps
5011 GET %G, tmpd
5012 CMOVcc tmps, tmpd
5013 PUT tmpd, %G
5014*/
5015static
5016UInt dis_cmov_E_G ( UChar sorb,
5017 Int sz,
5018 Condcode cond,
5019 UInt delta0 )
5020{
5021 UChar rm = getIByte(delta0);
5022 UChar dis_buf[50];
5023 Int len;
5024
sewardj883b00b2004-09-11 09:30:24 +00005025 IRType ty = szToITy(sz);
sewardj458a6f82004-08-25 12:46:02 +00005026 IRTemp tmps = newTemp(ty);
5027 IRTemp tmpd = newTemp(ty);
5028
5029 if (epartIsReg(rm)) {
5030 assign( tmps, getIReg(sz, eregOfRM(rm)) );
5031 assign( tmpd, getIReg(sz, gregOfRM(rm)) );
5032
5033 putIReg(sz, gregOfRM(rm),
5034 IRExpr_Mux0X( unop(Iop_1Uto8,calculate_condition(cond)),
5035 mkexpr(tmpd),
5036 mkexpr(tmps) )
5037 );
5038 DIP("cmov%c%s %s,%s\n", nameISize(sz),
5039 name_Condcode(cond),
5040 nameIReg(sz,eregOfRM(rm)),
5041 nameIReg(sz,gregOfRM(rm)));
5042 return 1+delta0;
5043 }
5044
5045 /* E refers to memory */
5046 {
5047 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
5048 assign( tmps, loadLE(ty, mkexpr(addr)) );
5049 assign( tmpd, getIReg(sz, gregOfRM(rm)) );
5050
5051 putIReg(sz, gregOfRM(rm),
5052 IRExpr_Mux0X( unop(Iop_1Uto8,calculate_condition(cond)),
5053 mkexpr(tmpd),
5054 mkexpr(tmps) )
5055 );
5056
5057 DIP("cmov%c%s %s,%s\n", nameISize(sz),
5058 name_Condcode(cond),
5059 dis_buf,
5060 nameIReg(sz,gregOfRM(rm)));
5061 return len+delta0;
5062 }
5063}
5064
5065
sewardj883b00b2004-09-11 09:30:24 +00005066static
5067UInt dis_xadd_G_E ( UChar sorb, Int sz, UInt delta0 )
5068{
5069 Int len;
5070 UChar rm = getIByte(delta0);
5071 UChar dis_buf[50];
5072
5073 // Int tmpd = newTemp(cb);
5074 //Int tmpt = newTemp(cb);
5075
5076 IRType ty = szToITy(sz);
5077 IRTemp tmpd = newTemp(ty);
5078 IRTemp tmpt0 = newTemp(ty);
5079 IRTemp tmpt1 = newTemp(ty);
5080
5081 if (epartIsReg(rm)) {
5082 vassert(0);
5083#if 0
5084 uInstr2(cb, GET, sz, ArchReg, eregOfRM(rm), TempReg, tmpd);
5085 uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
5086 uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
5087 setFlagsFromUOpcode(cb, ADD);
5088 uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
5089 uInstr2(cb, PUT, sz, TempReg, tmpt, ArchReg, eregOfRM(rm));
5090 DIP("xadd%c %s, %s\n",
5091 nameISize(sz), nameIReg(sz,gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
5092 return 1+eip0;
5093#endif
5094 } else {
5095 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
5096 assign( tmpd, loadLE(ty, mkexpr(addr)) );
5097 assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
5098 setFlags_ADD_SUB( Iop_Add8, tmpt0, tmpd, ty );
5099 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8), mkexpr(tmpd), mkexpr(tmpt0)) );
5100 storeLE( mkexpr(addr), mkexpr(tmpt1) );
5101 putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
5102 DIP("xadd%c %s, %s\n",
5103 nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
5104 return len+delta0;
5105 }
5106}
5107
sewardjc9a65702004-07-07 16:32:57 +00005108//-- /* Moves of Ew into a segment register.
5109//-- mov Ew, Sw meaning
5110//-- mov reg-or-mem, reg
5111//-- Is passed the a ptr to the modRM byte, and the data size. Returns
5112//-- the address advanced completely over this instruction.
5113//--
5114//-- Ew(src) is reg-or-mem
5115//-- Sw(dst) is seg reg.
5116//--
5117//-- If E is reg, --> GETw %Ew, tmpv
5118//-- PUTSEG tmpv, %Sw
5119//--
5120//-- If E is mem --> (getAddr E) -> tmpa
5121//-- LDw (tmpa), tmpb
5122//-- PUTSEG tmpb, %Sw
5123//-- */
5124//-- static
5125//-- Addr dis_mov_Ew_Sw ( UCodeBlock* cb,
5126//-- UChar sorb,
5127//-- Addr eip0 )
5128//-- {
5129//-- UChar rm = getUChar(eip0);
5130//-- UChar dis_buf[50];
5131//--
5132//-- if (epartIsReg(rm)) {
5133//-- Int tmpv = newTemp(cb);
5134//-- uInstr2(cb, GET, 2, ArchReg, eregOfRM(rm), TempReg, tmpv);
5135//-- uInstr2(cb, PUTSEG, 2, TempReg, tmpv, ArchRegS, gregOfRM(rm));
5136//-- DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
5137//-- return 1+eip0;
5138//-- }
5139//--
5140//-- /* E refers to memory */
5141//-- {
5142//-- UInt pair = disAMode ( cb, sorb, eip0, dis_buf );
5143//-- Int tmpa = LOW24(pair);
5144//-- Int tmpb = newTemp(cb);
5145//-- uInstr2(cb, LOAD, 2, TempReg, tmpa, TempReg, tmpb);
5146//-- uInstr2(cb, PUTSEG, 2, TempReg, tmpb, ArchRegS, gregOfRM(rm));
5147//-- DIP("movw %s,%s\n", dis_buf,nameSReg(gregOfRM(rm)));
5148//-- return HI8(pair)+eip0;
5149//-- }
5150//-- }
5151//--
5152//--
5153//-- /* Moves of a segment register to Ew.
5154//-- mov Sw, Ew meaning
5155//-- mov reg, reg-or-mem
5156//-- Is passed the a ptr to the modRM byte, and the data size. Returns
5157//-- the address advanced completely over this instruction.
5158//--
5159//-- Sw(src) is seg reg.
5160//-- Ew(dst) is reg-or-mem
5161//--
5162//-- If E is reg, --> GETSEG %Sw, tmp
5163//-- PUTW tmp, %Ew
5164//--
5165//-- If E is mem, --> (getAddr E) -> tmpa
5166//-- GETSEG %Sw, tmpv
5167//-- STW tmpv, (tmpa)
5168//-- */
5169//-- static
5170//-- Addr dis_mov_Sw_Ew ( UCodeBlock* cb,
5171//-- UChar sorb,
5172//-- Addr eip0 )
5173//-- {
5174//-- UChar rm = getUChar(eip0);
5175//-- UChar dis_buf[50];
5176//--
5177//-- if (epartIsReg(rm)) {
5178//-- Int tmpv = newTemp(cb);
5179//-- uInstr2(cb, GETSEG, 2, ArchRegS, gregOfRM(rm), TempReg, tmpv);
5180//-- uInstr2(cb, PUT, 2, TempReg, tmpv, ArchReg, eregOfRM(rm));
5181//-- DIP("movw %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(2,eregOfRM(rm)));
5182//-- return 1+eip0;
5183//-- }
5184//--
5185//-- /* E refers to memory */
5186//-- {
5187//-- UInt pair = disAMode ( cb, sorb, eip0, dis_buf );
5188//-- Int tmpa = LOW24(pair);
5189//-- Int tmpv = newTemp(cb);
5190//-- uInstr2(cb, GETSEG, 2, ArchRegS, gregOfRM(rm), TempReg, tmpv);
5191//-- uInstr2(cb, STORE, 2, TempReg, tmpv, TempReg, tmpa);
5192//-- DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
5193//-- return HI8(pair)+eip0;
5194//-- }
5195//-- }
5196//--
5197//--
5198//--
5199//-- /* Simple MMX operations, either
5200//-- op (src)mmxreg, (dst)mmxreg
5201//-- or
5202//-- op (src)address, (dst)mmxreg
5203//-- opc is the byte following the 0x0F prefix.
5204//-- */
5205//-- static
5206//-- Addr dis_MMXop_regmem_to_reg ( UCodeBlock* cb,
5207//-- UChar sorb,
5208//-- Addr eip,
5209//-- UChar opc,
5210//-- Char* name,
5211//-- Bool show_granularity )
5212//-- {
5213//-- Char dis_buf[50];
5214//-- UChar modrm = getUChar(eip);
5215//-- Bool isReg = epartIsReg(modrm);
5216//--
5217//-- if (isReg) {
5218//-- eip++;
5219//-- uInstr1(cb, MMX2, 0,
5220//-- Lit16,
5221//-- (((UShort)(opc)) << 8) | ((UShort)modrm) );
5222//-- } else {
5223//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
5224//-- Int tmpa = LOW24(pair);
5225//-- eip += HI8(pair);
5226//-- uInstr2(cb, MMX2_MemRd, 8,
5227//-- Lit16,
5228//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
5229//-- TempReg, tmpa);
5230//-- }
5231//--
5232//-- DIP("%s%s %s, %s\n",
5233//-- name, show_granularity ? nameMMXGran(opc & 3) : (Char*)"",
5234//-- ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
5235//-- nameMMXReg(gregOfRM(modrm)) );
5236//--
5237//-- return eip;
5238//-- }
5239//--
5240//--
5241//-- /* Simple MMX operations, either
5242//-- op (src)mmxreg, (dst)mmxreg
5243//-- or
5244//-- op (src)address, (dst)mmxreg
5245//-- opc is the byte following the 0x0F prefix.
5246//-- */
5247//-- static
5248//-- Addr dis_MMXop_regmem_to_reg_Imm8 ( UCodeBlock* cb,
5249//-- UChar sorb,
5250//-- Addr eip,
5251//-- UChar opc,
5252//-- Char* name,
5253//-- Bool show_granularity )
5254//-- {
5255//-- Char dis_buf[50];
5256//-- UChar modrm = getUChar(eip);
5257//-- UChar imm8;
5258//-- Bool isReg = epartIsReg(modrm);
5259//--
5260//-- if (isReg) {
5261//-- eip++;
5262//-- imm8 = getUChar(eip);
5263//-- eip++;
5264//-- uInstr2(cb, MMX3, 0,
5265//-- Lit16,
5266//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
5267//-- Lit16,
5268//-- ((UShort)imm8));
5269//-- } else {
5270//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
5271//-- Int tmpa = LOW24(pair);
5272//-- eip += HI8(pair);
5273//-- imm8 = getUChar(eip);
5274//-- eip++;
5275//-- uInstr3(cb, MMX2a1_MemRd, 8,
5276//-- Lit16,
5277//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
5278//-- Lit16,
5279//-- ((UShort)imm8),
5280//-- TempReg, tmpa);
5281//-- }
5282//--
5283//-- DIP("%s%s %s, %s, $%d\n",
5284//-- name, show_granularity ? nameMMXGran(opc & 3) : (Char*)"",
5285//-- ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
5286//-- nameMMXReg(gregOfRM(modrm)), (Int)imm8 );
5287//--
5288//-- return eip;
5289//-- }
5290//--
5291//--
5292//--
5293//-- /* Simple SSE operations, either
5294//-- op (src)xmmreg, (dst)xmmreg
5295//-- or
5296//-- op (src)address, (dst)xmmreg
5297//-- 3 opcode bytes.
5298//-- Supplied eip points to the first address mode byte.
5299//-- */
5300//-- static
5301//-- Addr dis_SSE3_reg_or_mem ( UCodeBlock* cb,
5302//-- UChar sorb,
sewardjbb53f8c2004-08-14 11:50:01 +00005303//-- Addr eip,
sewardjc9a65702004-07-07 16:32:57 +00005304//-- Int sz,
5305//-- Char* name,
5306//-- UChar opc1,
5307//-- UChar opc2,
5308//-- UChar opc3 )
5309//-- {
5310//-- Char dis_buf[50];
5311//-- UChar modrm = getUChar(eip);
5312//-- Bool isReg = epartIsReg(modrm);
5313//--
5314//-- if (isReg) {
5315//-- /* Completely internal SSE insn. */
5316//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
5317//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
5318//-- Lit16, (((UShort)opc3) << 8) | (UShort)modrm );
5319//-- eip++;
5320//-- } else {
5321//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
5322//-- Int tmpa = LOW24(pair);
5323//-- eip += HI8(pair);
5324//-- uInstr3(cb, SSE3a_MemRd, sz,
5325//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
5326//-- Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
5327//-- TempReg, tmpa);
5328//-- }
5329//--
5330//-- DIP("%s %s, %s\n",
5331//-- name,
5332//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
5333//-- nameXMMReg(gregOfRM(modrm)) );
5334//--
5335//-- return eip;
5336//-- }
5337//--
5338//--
5339//-- /* Simple SSE operations, either
5340//-- op (src)xmmreg, (dst)xmmreg
5341//-- or
5342//-- op (src)address, (dst)xmmreg
5343//-- 2 opcode bytes.
5344//-- Supplied eip points to the first address mode byte.
5345//-- */
5346//-- static
5347//-- Addr dis_SSE2_reg_or_mem ( UCodeBlock* cb,
5348//-- UChar sorb,
5349//-- Addr eip,
5350//-- Int sz,
5351//-- Char* name,
5352//-- UChar opc1,
5353//-- UChar opc2 )
5354//-- {
5355//-- Char dis_buf[50];
5356//-- UChar modrm = getUChar(eip);
5357//-- Bool isReg = epartIsReg(modrm);
5358//--
5359//-- if (isReg) {
5360//-- /* Completely internal SSE insn. */
5361//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
5362//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
5363//-- Lit16, (UShort)modrm );
5364//-- eip++;
5365//-- } else {
5366//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
5367//-- Int tmpa = LOW24(pair);
5368//-- eip += HI8(pair);
5369//-- uInstr3(cb, SSE2a_MemRd, sz,
5370//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
5371//-- Lit16, (UShort)modrm,
5372//-- TempReg, tmpa);
5373//-- }
5374//-- DIP("%s %s, %s\n",
5375//-- name,
5376//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
5377//-- nameXMMReg(gregOfRM(modrm)) );
5378//--
5379//-- return eip;
5380//-- }
5381//--
5382//--
5383//-- /* Simple SSE operations, either
5384//-- op (src)xmmreg, (dst)xmmreg
5385//-- or
5386//-- op (src)address, (dst)xmmreg
5387//-- 2 opcode bytes and an 8-bit immediate after the amode.
5388//-- Supplied eip points to the first address mode byte.
5389//-- */
5390//-- static
5391//-- Addr dis_SSE2_reg_or_mem_Imm8 ( UCodeBlock* cb,
5392//-- UChar sorb,
5393//-- Addr eip,
5394//-- Int sz,
5395//-- Char* name,
5396//-- UChar opc1,
5397//-- UChar opc2 )
5398//-- {
5399//-- Char dis_buf[50];
5400//-- UChar modrm = getUChar(eip);
5401//-- UChar imm8;
5402//-- Bool isReg = epartIsReg(modrm);
5403//--
5404//-- if (isReg) {
5405//-- /* Completely internal SSE insn. */
5406//-- eip++;
5407//-- imm8 = getUChar(eip);
5408//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
5409//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
5410//-- Lit16, (((UShort)modrm) << 8) | (UShort)imm8 );
5411//-- eip++;
5412//-- } else {
5413//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
5414//-- Int tmpa = LOW24(pair);
5415//-- eip += HI8(pair);
5416//-- imm8 = getUChar(eip);
5417//-- eip++;
5418//-- uInstr3(cb, SSE2a1_MemRd, sz,
5419//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
5420//-- Lit16, (((UShort)(modrm)) << 8) | ((UShort)imm8),
5421//-- TempReg, tmpa);
5422//-- }
5423//-- DIP("%s %s, %s, $%d\n",
5424//-- name, ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
5425//-- nameXMMReg(gregOfRM(modrm)), (Int)imm8 );
5426//-- return eip;
5427//-- }
5428//--
5429//--
5430//-- /* Simple SSE operations, either
5431//-- op (src)xmmreg, (dst)xmmreg
5432//-- or
5433//-- op (src)address, (dst)xmmreg
5434//-- 3 opcode bytes and an 8-bit immediate after the amode.
5435//-- Supplied eip points to the first address mode byte.
5436//-- */
5437//-- static
5438//-- Addr dis_SSE3_reg_or_mem_Imm8 ( UCodeBlock* cb,
5439//-- UChar sorb,
5440//-- Addr eip,
5441//-- Int sz,
5442//-- Char* name,
5443//-- UChar opc1,
5444//-- UChar opc2,
5445//-- UChar opc3 )
5446//-- {
5447//-- Char dis_buf[50];
5448//-- UChar modrm = getUChar(eip);
5449//-- UChar imm8;
5450//-- Bool isReg = epartIsReg(modrm);
5451//--
5452//-- if (isReg) {
5453//-- /* Completely internal SSE insn. */
5454//-- eip++;
5455//-- imm8 = getUChar(eip);
5456//-- uInstr3(cb, SSE5, 0, /* ignore sz for internal ops */
5457//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
5458//-- Lit16, (((UShort)opc3) << 8) | (UShort)modrm,
5459//-- Lit16, (UShort)imm8 );
5460//-- eip++;
5461//-- } else {
5462//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
5463//-- Int tmpa = LOW24(pair);
5464//-- eip += HI8(pair);
5465//-- imm8 = getUChar(eip);
5466//-- eip++;
5467//-- uInstr3(cb, SSE3a1_MemRd, sz,
5468//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
5469//-- Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
5470//-- TempReg, tmpa);
5471//-- uLiteral(cb, imm8);
5472//-- }
5473//-- DIP("%s %s, %s, $%d\n",
5474//-- name, ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
5475//-- nameXMMReg(gregOfRM(modrm)), (Int)imm8 );
5476//-- return eip;
5477//-- }
5478//--
5479//--
5480//-- /* Disassemble an SSE insn which is either a simple reg-reg move or a
5481//-- move between registers and memory. Supplied eip points to the
5482//-- first address mode byte.
5483//-- */
5484//-- static
5485//-- Addr dis_SSE3_load_store_or_mov ( UCodeBlock* cb,
5486//-- UChar sorb,
5487//-- Addr eip,
5488//-- Int sz,
5489//-- Bool is_store,
5490//-- Char* name,
5491//-- UChar insn0,
5492//-- UChar insn1,
5493//-- UChar insn2 )
5494//-- {
5495//-- Char dis_buf[50];
5496//-- UChar modrm = getUChar(eip);
5497//-- Bool isReg = epartIsReg(modrm);
5498//-- UInt pair;
5499//-- Int t1;
5500//--
5501//-- if (isReg) {
5502//-- /* Completely internal; we can issue SSE4. */
5503//-- eip++;
5504//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
5505//-- Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
5506//-- Lit16, (((UShort)insn2) << 8) | (UShort)modrm );
5507//-- } else {
5508//-- pair = disAMode ( cb, sorb, eip, dis_buf );
5509//-- t1 = LOW24(pair);
5510//-- eip += HI8(pair);
5511//-- uInstr3(cb, is_store ? SSE3a_MemWr : SSE3a_MemRd, sz,
5512//-- Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
5513//-- Lit16, (((UShort)insn2) << 8) | (UShort)modrm,
5514//-- TempReg, t1 );
5515//-- }
5516//--
5517//-- if (is_store) {
5518//-- DIP("%s %s, %s\n",
5519//-- name,
5520//-- nameXMMReg(gregOfRM(modrm)),
5521//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ) );
5522//-- } else {
5523//-- DIP("%s %s, %s\n",
5524//-- name,
5525//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
5526//-- nameXMMReg(gregOfRM(modrm)) );
5527//-- }
5528//-- return eip;
5529//-- }
5530//--
5531//--
5532//-- /* Disassemble an SSE insn which is either a simple reg-reg move or a
5533//-- move between registers and memory. Supplied eip points to the
5534//-- first address mode byte. */
5535//-- static
5536//-- Addr dis_SSE2_load_store_or_mov ( UCodeBlock* cb,
5537//-- UChar sorb,
5538//-- Addr eip,
5539//-- Int sz,
5540//-- Bool is_store,
5541//-- Char* name,
5542//-- UChar insn0,
5543//-- UChar insn1 )
5544//-- {
5545//-- Char dis_buf[50];
5546//-- UChar modrm = getUChar(eip);
5547//-- Bool isReg = epartIsReg(modrm);
5548//-- UInt pair;
5549//-- Int t1;
5550//--
5551//-- if (isReg) {
5552//-- /* Completely internal; we can issue SSE3. */
5553//-- eip++;
5554//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
5555//-- Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
5556//-- Lit16, (UShort)modrm );
5557//-- } else {
5558//-- pair = disAMode ( cb, sorb, eip, dis_buf );
5559//-- t1 = LOW24(pair);
5560//-- eip += HI8(pair);
5561//-- uInstr3(cb, is_store ? SSE2a_MemWr : SSE2a_MemRd, sz,
5562//-- Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
5563//-- Lit16, (UShort)modrm,
5564//-- TempReg, t1 );
5565//-- }
5566//--
5567//-- if (is_store) {
5568//-- DIP("%s %s, %s\n",
5569//-- name,
5570//-- nameXMMReg(gregOfRM(modrm)),
5571//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ) );
5572//-- } else {
5573//-- DIP("%s %s, %s\n",
5574//-- name,
5575//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
5576//-- nameXMMReg(gregOfRM(modrm)) );
5577//-- }
5578//-- return eip;
5579//-- }
5580//--
5581//--
5582//-- /* Simple SSE operations, either
5583//-- op (src)xmmreg, (dst)mmxreg
5584//-- or
5585//-- op (src)address, (dst)mmxreg
5586//-- 2 opcode bytes.
5587//-- Supplied eip points to the first address mode byte.
5588//-- */
5589//-- static
5590//-- Addr dis_SSE2_to_MMX ( UCodeBlock *cb,
5591//-- UChar sorb,
5592//-- Addr eip,
5593//-- Int sz,
5594//-- Char* name,
5595//-- UChar opc1,
5596//-- UChar opc2 )
5597//-- {
5598//-- UChar dis_buf[50];
5599//-- UChar modrm = getUChar(eip);
5600//-- if (epartIsReg(modrm)) {
5601//-- /* Completely internal SSE insn. */
5602//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
5603//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
5604//-- Lit16, (UShort)modrm );
5605//-- DIP("%s %s, %s\n",
5606//-- name, nameXMMReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)) );
5607//-- eip++;
5608//-- } else {
5609//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
5610//-- Int tmpa = LOW24(pair);
5611//-- eip += HI8(pair);
5612//-- uInstr3(cb, SSE2a_MemRd, sz,
5613//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
5614//-- Lit16, ((UShort)modrm),
5615//-- TempReg, tmpa);
5616//-- DIP("%s %s, %s\n", name, dis_buf, nameMMXReg(gregOfRM(modrm)));
5617//-- }
5618//-- return eip;
5619//-- }
5620//--
5621//--
5622//-- /* Simple SSE operations, either
5623//-- op (src)mmxreg, (dst)xmmreg
5624//-- or
5625//-- op (src)address, (dst)xmmreg
5626//-- 2 opcode bytes.
5627//-- Supplied eip points to the first address mode byte.
5628//-- */
5629//-- static
5630//-- Addr dis_SSE2_from_MMX ( UCodeBlock *cb,
5631//-- UChar sorb,
5632//-- Addr eip,
5633//-- Int sz,
5634//-- Char* name,
5635//-- UChar opc1,
5636//-- UChar opc2 )
5637//-- {
5638//-- UChar dis_buf[50];
5639//-- UChar modrm = getUChar(eip);
5640//-- if (epartIsReg(modrm)) {
5641//-- /* Completely internal SSE insn. */
5642//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
5643//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
5644//-- Lit16, (UShort)modrm );
5645//-- DIP("%s %s, %s\n",
5646//-- name, nameMMXReg(eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)) );
5647//-- eip++;
5648//-- } else {
5649//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
5650//-- Int tmpa = LOW24(pair);
5651//-- eip += HI8(pair);
5652//-- uInstr3(cb, SSE2a_MemRd, sz,
5653//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
5654//-- Lit16, ((UShort)modrm),
5655//-- TempReg, tmpa);
5656//-- DIP("%s %s, %s\n", name, dis_buf, nameXMMReg(gregOfRM(modrm)));
5657//-- }
5658//-- return eip;
5659//-- }
5660//--
5661//--
5662//-- /* Simple SSE operations, either
5663//-- op (src)xmmreg, (dst)mmxreg
5664//-- or
5665//-- op (src)address, (dst)mmxreg
5666//-- 3 opcode bytes.
5667//-- Supplied eip points to the first address mode byte.
5668//-- */
5669//-- static
5670//-- Addr dis_SSE3_to_MMX ( UCodeBlock *cb,
5671//-- UChar sorb,
5672//-- Addr eip,
5673//-- Int sz,
5674//-- Char* name,
5675//-- UChar opc1,
5676//-- UChar opc2,
5677//-- UChar opc3 )
5678//-- {
5679//-- UChar dis_buf[50];
5680//-- UChar modrm = getUChar(eip);
5681//-- if (epartIsReg(modrm)) {
5682//-- /* Completely internal SSE insn. */
5683//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
5684//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
5685//-- Lit16, (((UShort)opc3) << 8) | (UShort)modrm );
5686//-- DIP("%s %s, %s\n",
5687//-- name, nameXMMReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)) );
5688//-- eip++;
5689//-- } else {
5690//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
5691//-- Int tmpa = LOW24(pair);
5692//-- eip += HI8(pair);
5693//-- uInstr3(cb, SSE3a_MemRd, sz,
5694//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
5695//-- Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
5696//-- TempReg, tmpa);
5697//-- DIP("%s %s, %s\n", name, dis_buf, nameMMXReg(gregOfRM(modrm)));
5698//-- }
5699//-- return eip;
5700//-- }
5701//--
5702//--
5703//-- /* Simple SSE operations, either
5704//-- op (src)mmxreg, (dst)xmmreg
5705//-- or
5706//-- op (src)address, (dst)xmmreg
5707//-- 3 opcode bytes.
5708//-- Supplied eip points to the first address mode byte.
5709//-- */
5710//-- static
5711//-- Addr dis_SSE3_from_MMX ( UCodeBlock *cb,
5712//-- UChar sorb,
5713//-- Addr eip,
5714//-- Int sz,
5715//-- Char* name,
5716//-- UChar opc1,
5717//-- UChar opc2,
5718//-- UChar opc3 )
5719//-- {
5720//-- UChar dis_buf[50];
5721//-- UChar modrm = getUChar(eip);
5722//-- if (epartIsReg(modrm)) {
5723//-- /* Completely internal SSE insn. */
5724//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
5725//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
5726//-- Lit16, (((UShort)opc3) << 8) | (UShort)modrm );
5727//-- DIP("%s %s, %s\n",
5728//-- name, nameMMXReg(eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)) );
5729//-- eip++;
5730//-- } else {
5731//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
5732//-- Int tmpa = LOW24(pair);
5733//-- eip += HI8(pair);
5734//-- uInstr3(cb, SSE3a_MemRd, sz,
5735//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
5736//-- Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
5737//-- TempReg, tmpa);
5738//-- DIP("%s %s, %s\n", name, dis_buf, nameXMMReg(gregOfRM(modrm)));
5739//-- }
5740//-- return eip;
5741//-- }
5742//--
5743//--
5744//-- static
5745//-- void dis_push_segreg ( UCodeBlock* cb, UInt sreg, Int sz )
5746//-- {
5747//-- Int t1 = newTemp(cb), t2 = newTemp(cb);
5748//-- vg_assert(sz == 2 || sz == 4);
5749//-- uInstr2(cb, GETSEG, 2, ArchRegS, sreg, TempReg, t1);
5750//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
5751//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
5752//-- uLiteral(cb, sz);
5753//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
5754//-- uInstr2(cb, STORE, 2, TempReg, t1, TempReg, t2);
5755//-- DIP("push %s\n", VG_(name_of_seg_reg)(sreg));
5756//-- }
5757//--
5758//-- static
5759//-- void dis_pop_segreg ( UCodeBlock* cb, UInt sreg, Int sz )
5760//-- {
5761//-- Int t1 = newTemp(cb), t2 = newTemp(cb);
5762//-- vg_assert(sz == 2 || sz == 4);
5763//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
5764//-- uInstr2(cb, LOAD, 2, TempReg, t2, TempReg, t1);
5765//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
5766//-- uLiteral(cb, sz);
5767//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
5768//-- uInstr2(cb, PUTSEG, 2, TempReg, t1, ArchRegS, sreg);
5769//-- DIP("pop %s\n", VG_(name_of_seg_reg)(sreg));
5770//-- }
sewardje05c42c2004-07-08 20:25:10 +00005771
5772static
5773void dis_ret ( UInt d32 )
5774{
5775 IRTemp t1 = newTemp(Ity_I32), t2 = newTemp(Ity_I32);
5776 assign(t1, getIReg(4,R_ESP));
5777 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
5778 putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(4+d32)));
sewardj78c19df2004-07-12 22:49:27 +00005779 jmp_treg(Ijk_Ret,t2);
sewardje05c42c2004-07-08 20:25:10 +00005780}
5781
sewardjc9a65702004-07-07 16:32:57 +00005782
5783/*------------------------------------------------------------*/
5784/*--- Disassembling entire basic blocks ---*/
5785/*------------------------------------------------------------*/
5786
5787/* Disassemble a single instruction into IR, returning the updated
5788 delta, and setting *isEnd to True if this is the last insn in a
5789 basic block. Also do debug printing if necessary. */
5790
5791static UInt disInstr ( UInt delta, Bool* isEnd )
5792{
sewardj0c12ea82004-07-12 08:18:16 +00005793 IRType ty;
5794 IRTemp addr, t1, t2;
sewardje87b4842004-07-10 12:23:30 +00005795 Int alen;
sewardj64e1d652004-07-12 14:00:46 +00005796 UChar opc, modrm, abyte;
5797 UInt d32;
sewardje87b4842004-07-10 12:23:30 +00005798 UChar dis_buf[50];
5799 Int am_sz, d_sz;
sewardjc9a65702004-07-07 16:32:57 +00005800 //Char loc_buf[M_VG_ERRTXT];
5801
5802 /* Holds eip at the start of the insn, so that we can print
5803 consistent error messages for unimplemented insns. */
5804 UInt delta_start = delta;
5805
5806 /* sz denotes the nominal data-op size of the insn; we change it to
5807 2 if an 0x66 prefix is seen */
5808 Int sz = 4;
5809
5810 /* sorb holds the segment-override-prefix byte, if any. Zero if no
5811 prefix has been seen, else one of {0x26, 0x3E, 0x64, 0x65}
5812 indicating the prefix. */
5813 UChar sorb = 0;
5814
5815 /* For printing the stmts after each insn. */
sewardjd7cb8532004-08-17 23:59:23 +00005816 Int first_stmt_idx = irbb->stmts_used;
sewardjc9a65702004-07-07 16:32:57 +00005817
5818 *isEnd = False;
sewardj940e8c92004-07-11 16:53:24 +00005819 addr = t1 = t2 = INVALID_IRTEMP;
sewardj41f43bc2004-07-08 14:23:22 +00005820 //t3 = t4 = INVALID_IRTEMP;
sewardjc9a65702004-07-07 16:32:57 +00005821
5822 DIP("\t0x%x: ", guest_eip+delta);
5823
sewardj750f4072004-07-26 22:39:11 +00005824 /* Spot the client-request magic sequence. */
5825 {
5826 UChar* code = (UChar*)(guest_code + delta);
5827 /* Spot this:
5828 C1C01D roll $29, %eax
5829 C1C003 roll $3, %eax
5830 C1C81B rorl $27, %eax
5831 C1C805 rorl $5, %eax
5832 C1C00D roll $13, %eax
5833 C1C013 roll $19, %eax
5834 */
5835 if (code[ 0] == 0xC1 && code[ 1] == 0xC0 && code[ 2] == 0x1D &&
5836 code[ 3] == 0xC1 && code[ 4] == 0xC0 && code[ 5] == 0x03 &&
5837 code[ 6] == 0xC1 && code[ 7] == 0xC8 && code[ 8] == 0x1B &&
5838 code[ 9] == 0xC1 && code[10] == 0xC8 && code[11] == 0x05 &&
5839 code[12] == 0xC1 && code[13] == 0xC0 && code[14] == 0x0D &&
5840 code[15] == 0xC1 && code[16] == 0xC0 && code[17] == 0x13
5841 ) {
5842 delta += 18;
5843 jmp_lit(Ijk_ClientReq, guest_eip+delta);
5844 *isEnd = True;
5845 DIP("%%edx = client_request ( %%eax )\n");
5846 return delta;
5847 }
5848 }
sewardjc9a65702004-07-07 16:32:57 +00005849
5850 /* Skip a LOCK prefix. */
5851 if (getIByte(delta) == 0xF0) {
sewardj458a6f82004-08-25 12:46:02 +00005852 vex_printf("vex x86->IR: ignoring LOCK prefix\n");
sewardjc9a65702004-07-07 16:32:57 +00005853 delta++;
5854 }
5855
5856 /* Detect operand-size overrides. */
5857 if (getIByte(delta) == 0x66) { sz = 2; delta++; };
5858
5859 /* segment override prefixes come after the operand-size override,
5860 it seems */
5861 switch (getIByte(delta)) {
5862 case 0x3E: /* %DS: */
5863 case 0x26: /* %ES: */
5864 case 0x64: /* %FS: */
5865 case 0x65: /* %GS: */
5866 sorb = getIByte(delta); delta++;
5867 break;
5868 case 0x2E: /* %CS: */
5869 /* 2E prefix on a conditional branch instruction is a
5870 branch-prediction hint, which can safely be ignored. */
5871 {
5872 UChar op1 = getIByte(delta+1);
5873 UChar op2 = getIByte(delta+2);
5874 if ((op1 >= 0x70 && op1 <= 0x7F)
5875 || (op1 == 0xE3)
5876 || (op1 == 0x0F && op2 >= 0x80 && op2 <= 0x8F)) {
5877 sorb = getIByte(delta); delta++;
5878 break;
5879 }
5880 }
5881 unimplemented("x86 segment override (SEG=CS) prefix");
5882 /*NOTREACHED*/
5883 break;
5884 case 0x36: /* %SS: */
5885 unimplemented("x86 segment override (SEG=SS) prefix");
5886 /*NOTREACHED*/
5887 break;
5888 default:
5889 break;
5890 }
5891
5892//-- /* ---------------------------------------------------- */
5893//-- /* --- The SSE/SSE2 decoder. --- */
5894//-- /* ---------------------------------------------------- */
5895//--
5896//-- /* If it looks like this CPU might support SSE, try decoding SSE
5897//-- insns. */
5898//-- if (VG_(have_ssestate)) {
5899//-- UChar* insn = (UChar*)eip;
5900//--
5901//-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
5902//-- if (insn[0] == 0x0F && insn[1] == 0xAE
5903//-- && (!epartIsReg(insn[2]))
5904//-- && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
5905//-- Bool store = gregOfRM(insn[2]) == 0;
5906//-- vg_assert(sz == 4);
5907//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
5908//-- t1 = LOW24(pair);
5909//-- eip += 2+HI8(pair);
5910//-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
5911//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
5912//-- Lit16, (UShort)insn[2],
5913//-- TempReg, t1 );
5914//-- DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
5915//-- goto decode_success;
5916//-- }
5917//--
5918//-- /* STMXCSR/LDMXCSR m32 -- load/store the MXCSR register. */
5919//-- if (insn[0] == 0x0F && insn[1] == 0xAE
5920//-- && (!epartIsReg(insn[2]))
5921//-- && (gregOfRM(insn[2]) == 3 || gregOfRM(insn[2]) == 2) ) {
5922//-- Bool store = gregOfRM(insn[2]) == 3;
5923//-- vg_assert(sz == 4);
5924//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
5925//-- t1 = LOW24(pair);
5926//-- eip += 2+HI8(pair);
5927//-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 4,
5928//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
5929//-- Lit16, (UShort)insn[2],
5930//-- TempReg, t1 );
5931//-- DIP("%smxcsr %s\n", store ? "st" : "ld", dis_buf );
5932//-- goto decode_success;
5933//-- }
5934//--
5935//-- /* LFENCE/MFENCE/SFENCE -- flush pending operations to memory */
5936//-- if (insn[0] == 0x0F && insn[1] == 0xAE
5937//-- && (epartIsReg(insn[2]))
5938//-- && (gregOfRM(insn[2]) >= 5 && gregOfRM(insn[2]) <= 7))
5939//-- {
5940//-- vg_assert(sz == 4);
5941//-- eip += 3;
5942//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
5943//-- Lit16, (((UShort)0x0F) << 8) | (UShort)0xAE,
5944//-- Lit16, (UShort)insn[2] );
5945//-- DIP("sfence\n");
5946//-- goto decode_success;
5947//-- }
5948//--
5949//-- /* CLFLUSH -- flush cache line */
5950//-- if (insn[0] == 0x0F && insn[1] == 0xAE
5951//-- && (!epartIsReg(insn[2]))
5952//-- && (gregOfRM(insn[2]) == 7))
5953//-- {
5954//-- vg_assert(sz == 4);
5955//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
5956//-- t1 = LOW24(pair);
5957//-- eip += 2+HI8(pair);
5958//-- uInstr3(cb, SSE2a_MemRd, 0, /* ignore sz for internal ops */
5959//-- Lit16, (((UShort)0x0F) << 8) | (UShort)0xAE,
5960//-- Lit16, (UShort)insn[2],
5961//-- TempReg, t1 );
5962//-- DIP("clflush %s\n", dis_buf);
5963//-- goto decode_success;
5964//-- }
5965//--
5966//-- /* CVTPI2PS (0x0F,0x2A) -- mm/m64, xmm */
5967//-- /* CVTPI2PD (0x66,0x0F,0x2A) -- mm/m64, xmm */
5968//-- if (insn[0] == 0x0F && insn[1] == 0x2A) {
5969//-- if (sz == 4) {
5970//-- eip = dis_SSE2_from_MMX
5971//-- ( cb, sorb, eip+2, 8, "cvtpi2ps",
5972//-- insn[0], insn[1] );
5973//-- } else {
5974//-- eip = dis_SSE3_from_MMX
5975//-- ( cb, sorb, eip+2, 8, "cvtpi2pd",
5976//-- 0x66, insn[0], insn[1] );
5977//-- }
5978//-- goto decode_success;
5979//-- }
5980//--
5981//-- /* CVTTPS2PI (0x0F,0x2C) -- xmm/m64, mm */
5982//-- /* CVTPS2PI (0x0F,0x2D) -- xmm/m64, mm */
5983//-- /* CVTTPD2PI (0x66,0x0F,0x2C) -- xmm/m128, mm */
5984//-- /* CVTPD2PI (0x66,0x0F,0x2D) -- xmm/m128, mm */
5985//-- if (insn[0] == 0x0F
5986//-- && (insn[1] == 0x2C || insn[1] == 0x2D)) {
5987//-- if (sz == 4) {
5988//-- eip = dis_SSE2_to_MMX
5989//-- ( cb, sorb, eip+2, 8, "cvt{t}ps2pi",
5990//-- insn[0], insn[1] );
5991//-- } else {
5992//-- eip = dis_SSE3_to_MMX
5993//-- ( cb, sorb, eip+2, 16, "cvt{t}pd2pi",
5994//-- 0x66, insn[0], insn[1] );
5995//-- }
5996//-- goto decode_success;
5997//-- }
5998//--
5999//-- /* CVTTSD2SI (0xF2,0x0F,0x2C) -- convert a double-precision float
6000//-- value in memory or xmm reg to int and put it in an ireg.
6001//-- Truncate. */
6002//-- /* CVTTSS2SI (0xF3,0x0F,0x2C) -- convert a single-precision float
6003//-- value in memory or xmm reg to int and put it in an ireg.
6004//-- Truncate. */
6005//-- /* CVTSD2SI (0xF2,0x0F,0x2D) -- convert a double-precision float
6006//-- value in memory or xmm reg to int and put it in an ireg. Round
6007//-- as per MXCSR. */
6008//-- /* CVTSS2SI (0xF3,0x0F,0x2D) -- convert a single-precision float
6009//-- value in memory or xmm reg to int and put it in an ireg. Round
6010//-- as per MXCSR. */
6011//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
6012//-- && insn[1] == 0x0F
6013//-- && (insn[2] == 0x2C || insn[2] == 0x2D)) {
6014//-- vg_assert(sz == 4);
6015//-- modrm = insn[3];
6016//-- if (epartIsReg(modrm)) {
6017//-- /* We're moving a value in an xmm reg to an ireg. */
6018//-- eip += 4;
6019//-- t1 = newTemp(cb);
6020//-- /* sz is 4 for all 4 insns. */
6021//-- vg_assert(epartIsReg(modrm));
6022//-- uInstr3(cb, SSE3g_RegWr, 4,
6023//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
6024//-- Lit16, (((UShort)insn[2]) << 8) | (UShort)modrm,
6025//-- TempReg, t1 );
6026//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
6027//-- DIP("cvt{t}s{s,d}2si %s, %s\n",
6028//-- nameXMMReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)) );
6029//-- } else {
6030//-- /* So, we're reading memory and writing an ireg. This calls
6031//-- for the ultra-horrible SSE3ag_MemRd_RegWr uinstr. We
6032//-- can't do it in a roundabout route because it does some
6033//-- kind of conversion on the way, which we need to have
6034//-- happen too. So our only choice is to re-emit a suitably
6035//-- rehashed version of the instruction. */
6036//-- /* Destination ireg is GREG. Address goes as EREG as
6037//-- usual. */
6038//-- t1 = newTemp(cb); /* t1 holds value on its way to ireg */
6039//-- pair = disAMode ( cb, sorb, eip+3, dis_buf );
6040//-- t2 = LOW24(pair); /* t2 holds addr */
6041//-- eip += 3+HI8(pair);
6042//-- uInstr2(cb, SSE3ag_MemRd_RegWr, insn[0]==0xF2 ? 8 : 4,
6043//-- TempReg, t2, /* address */
6044//-- TempReg, t1 /* dest */);
6045//-- uLiteral(cb , (((UInt)insn[0]) << 24)
6046//-- | (((UInt)insn[1]) << 16)
6047//-- | (((UInt)insn[2]) << 8)
6048//-- | ((UInt)modrm) );
6049//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
6050//-- DIP("cvt{t}s{s,d}2si %s, %s\n",
6051//-- dis_buf, nameIReg(4,gregOfRM(modrm)) );
6052//-- }
6053//-- goto decode_success;
6054//-- }
6055//--
6056//-- /* CVTSI2SS -- convert int reg, or int value in memory, to low 4
6057//-- bytes of XMM reg. */
6058//-- /* CVTSI2SD -- convert int reg, or int value in memory, to low 8
6059//-- bytes of XMM reg. */
6060//-- if ((insn[0] == 0xF3 /*CVTSI2SS*/ || insn[0] == 0xF2 /* CVTSI2SD*/)
6061//-- && insn[1] == 0x0F && insn[2] == 0x2A) {
6062//-- Char* s_or_d = insn[0]==0xF3 ? "s" : "d";
6063//-- vg_assert(sz == 4);
6064//-- modrm = insn[3];
6065//-- t1 = newTemp(cb);
6066//-- if (epartIsReg(modrm)) {
6067//-- uInstr2(cb, GET, 4, ArchReg, eregOfRM(modrm), TempReg, t1);
6068//-- vg_assert(epartIsReg(modrm));
6069//-- uInstr3(cb, SSE3e_RegRd, 4,
6070//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
6071//-- Lit16, (((UShort)insn[2]) << 8) | (UShort)modrm,
6072//-- TempReg, t1 );
6073//-- eip += 4;
6074//-- DIP("cvtsi2s%s %s, %s\n", s_or_d,
6075//-- nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
6076//-- } else {
6077//-- pair = disAMode ( cb, sorb, eip+3, dis_buf );
6078//-- t2 = LOW24(pair);
6079//-- eip += 3+HI8(pair);
6080//-- uInstr3(cb, SSE3a_MemRd, 4,
6081//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
6082//-- Lit16, (((UShort)insn[2]) << 8) | (UShort)modrm,
6083//-- TempReg, t2 );
6084//-- DIP("cvtsi2s%s %s, %s\n",
6085//-- s_or_d, dis_buf, nameXMMReg(gregOfRM(modrm)));
6086//-- }
6087//-- goto decode_success;
6088//-- }
6089//--
6090//-- /* CVTPS2PD -- convert two packed floats to two packed doubles. */
6091//-- /* 0x66: CVTPD2PS -- convert two packed doubles to two packed floats. */
6092//-- if (insn[0] == 0x0F && insn[1] == 0x5A) {
6093//-- vg_assert(sz == 2 || sz == 4);
6094//-- if (sz == 4) {
6095//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 8, "cvtps2pd",
6096//-- insn[0], insn[1] );
6097//-- } else {
6098//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "cvtpd2ps",
6099//-- 0x66, insn[0], insn[1] );
6100//-- }
6101//-- goto decode_success;
6102//-- }
6103//--
6104//-- /* CVTSS2SD -- convert one single float to double. */
6105//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5A) {
6106//-- vg_assert(sz == 4);
6107//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4, "cvtss2sd",
6108//-- insn[0], insn[1], insn[2] );
6109//-- goto decode_success;
6110//-- }
6111//--
6112//-- /* CVTSD2SS -- convert one single double. to float. */
6113//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5A) {
6114//-- vg_assert(sz == 4);
6115//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8, "cvtsd2ss",
6116//-- insn[0], insn[1], insn[2] );
6117//-- goto decode_success;
6118//-- }
6119//--
6120//-- /* CVTDQ2PS -- convert four ints to four packed floats. */
6121//-- /* 0x66: CVTPS2DQ -- convert four packed floats to four ints. */
6122//-- if (insn[0] == 0x0F && insn[1] == 0x5B) {
6123//-- vg_assert(sz == 2 || sz == 4);
6124//-- if (sz == 4) {
6125//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "cvtdq2ps",
6126//-- insn[0], insn[1] );
6127//-- } else {
6128//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "cvtps2dq",
6129//-- 0x66, insn[0], insn[1] );
6130//-- }
6131//-- goto decode_success;
6132//-- }
6133//--
6134//-- /* CVTPD2DQ -- convert two packed doubles to two ints. */
6135//-- if (sz == 2
6136//-- && insn[0] == 0x0F && insn[1] == 0xE6) {
6137//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 8, "cvtpd2dq",
6138//-- 0x66, insn[0], insn[1] );
6139//-- goto decode_success;
6140//-- }
6141//--
6142//-- /* CVTTPD2DQ -- convert two packed doubles to two ints with truncation. */
6143//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xE6) {
6144//-- vg_assert(sz == 4);
6145//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8, "cvttpd2dq",
6146//-- insn[0], insn[1], insn[2] );
6147//-- goto decode_success;
6148//-- }
6149//--
6150//-- /* CVTDQ2PD -- convert two ints to two packed doubles. */
6151//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xE6) {
6152//-- vg_assert(sz == 4);
6153//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8, "cvtdq2pd",
6154//-- insn[0], insn[1], insn[2] );
6155//-- goto decode_success;
6156//-- }
6157//--
6158//-- /* CVTTPS2DQ -- convert four packed floats to four ints with truncation. */
6159//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5B) {
6160//-- vg_assert(sz == 4);
6161//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 16, "cvttps2dq",
6162//-- insn[0], insn[1], insn[2] );
6163//-- goto decode_success;
6164//-- }
6165//--
6166//-- /* CMPSS -- compare scalar floats. */
6167//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xC2) {
6168//-- vg_assert(sz == 4);
6169//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 8, "cmpss",
6170//-- insn[0], insn[1], insn[2] );
6171//-- goto decode_success;
6172//-- }
6173//--
6174//-- /* CMPSD -- compare scalar doubles. */
6175//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xC2) {
6176//-- vg_assert(sz == 4);
6177//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 8, "cmpsd",
6178//-- insn[0], insn[1], insn[2] );
6179//-- goto decode_success;
6180//-- }
6181//--
6182//-- /* sz==4: CMPPS -- compare packed floats */
6183//-- /* sz==2: CMPPD -- compare packed doubles */
6184//-- if (insn[0] == 0x0F && insn[1] == 0xC2) {
6185//-- vg_assert(sz == 4 || sz == 2);
6186//-- if (sz == 4) {
6187//-- eip = dis_SSE2_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "cmpps",
6188//-- insn[0], insn[1] );
6189//-- } else {
6190//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "cmppd",
6191//-- 0x66, insn[0], insn[1] );
6192//-- }
6193//-- goto decode_success;
6194//-- }
6195//--
6196//-- /* PSHUFD */
6197//-- if (sz == 2
6198//-- && insn[0] == 0x0F && insn[1] == 0x70) {
6199//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16,
6200//-- "pshufd",
6201//-- 0x66, insn[0], insn[1] );
6202//-- goto decode_success;
6203//-- }
6204//--
6205//-- /* PSHUFLW */
6206//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x70) {
6207//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 16,
6208//-- "pshuflw",
6209//-- insn[0], insn[1], insn[2] );
6210//-- goto decode_success;
6211//-- }
6212//--
6213//-- /* PSHUFHW */
6214//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x70) {
6215//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 16,
6216//-- "pshufhw",
6217//-- insn[0], insn[1], insn[2] );
6218//-- goto decode_success;
6219//-- }
6220//--
6221//-- /* SHUFPD */
6222//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC6) {
6223//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "shufpd",
6224//-- 0x66, insn[0], insn[1] );
6225//-- goto decode_success;
6226//-- }
6227//--
6228//-- /* SHUFPS */
6229//-- if (insn[0] == 0x0F && insn[1] == 0xC6) {
6230//-- vg_assert(sz == 4);
6231//-- eip = dis_SSE2_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "shufps",
6232//-- insn[0], insn[1] );
6233//-- goto decode_success;
6234//-- }
6235//--
6236//-- /* 0xF2: MULSD */
6237//-- /* 0xF3: MULSS -- multiply low 4 bytes of XMM reg. */
6238//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
6239//-- && insn[1] == 0x0F && insn[2] == 0x59) {
6240//-- Bool sz8 = insn[0] == 0xF2;
6241//-- vg_assert(sz == 4);
6242//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
6243//-- sz8 ? "mulss" : "mulsd",
6244//-- insn[0], insn[1], insn[2] );
6245//-- goto decode_success;
6246//-- }
6247//--
6248//-- /* MULPS */
6249//-- /* 0x66: MULPD */
6250//-- if (insn[0] == 0x0F && insn[1] == 0x59) {
6251//-- vg_assert(sz == 4 || sz == 2);
6252//-- if (sz == 4) {
6253//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "mulps",
6254//-- insn[0], insn[1] );
6255//-- } else {
6256//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "mulpd",
6257//-- 0x66, insn[0], insn[1] );
6258//-- }
6259//-- goto decode_success;
6260//-- }
6261//--
6262//-- /* 0xF2: DIVSD */
6263//-- /* 0xF3: DIVSS -- divide low 4 bytes of XMM reg. */
6264//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
6265//-- && insn[1] == 0x0F && insn[2] == 0x5E) {
6266//-- Bool sz8 = insn[0] == 0xF2;
6267//-- vg_assert(sz == 4);
6268//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
6269//-- sz8 ? "divsd" : "divss",
6270//-- insn[0], insn[1], insn[2] );
6271//-- goto decode_success;
6272//-- }
6273//--
6274//-- /* DIVPS */
6275//-- /* 0x66: DIVPD */
6276//-- if (insn[0] == 0x0F && insn[1] == 0x5E) {
6277//-- vg_assert(sz == 4 || sz == 2);
6278//-- if (sz == 4) {
6279//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "divps",
6280//-- insn[0], insn[1] );
6281//-- } else {
6282//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "divpd",
6283//-- 0x66, insn[0], insn[1] );
6284//-- }
6285//-- goto decode_success;
6286//-- }
6287//--
6288//-- /* 0xF2: SUBSD */
6289//-- /* 0xF3: SUBSS */
6290//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
6291//-- && insn[1] == 0x0F && insn[2] == 0x5C) {
6292//-- Bool sz8 = insn[0] == 0xF2;
6293//-- vg_assert(sz == 4);
6294//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
6295//-- sz8 ? "subsd" : "subss",
6296//-- insn[0], insn[1], insn[2] );
6297//-- goto decode_success;
6298//-- }
6299//--
6300//-- /* SUBPS */
6301//-- /* 0x66: SUBPD */
6302//-- if (insn[0] == 0x0F && insn[1] == 0x5C) {
6303//-- vg_assert(sz == 4 || sz == 2);
6304//-- if (sz == 4) {
6305//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "subps",
6306//-- insn[0], insn[1] );
6307//-- } else {
6308//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "subpd",
6309//-- 0x66, insn[0], insn[1] );
6310//-- }
6311//-- goto decode_success;
6312//-- }
6313//--
6314//-- /* 0xF2: ADDSD */
6315//-- /* 0xF3: ADDSS */
6316//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
6317//-- && insn[1] == 0x0F && insn[2] == 0x58) {
6318//-- Bool sz8 = insn[0] == 0xF2;
6319//-- vg_assert(sz == 4);
6320//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
6321//-- sz8 ? "addsd" : "addss",
6322//-- insn[0], insn[1], insn[2] );
6323//-- goto decode_success;
6324//-- }
6325//--
6326//-- /* ADDPS */
6327//-- /* 0x66: ADDPD */
6328//-- if (insn[0] == 0x0F && insn[1] == 0x58) {
6329//-- vg_assert(sz == 4 || sz == 2);
6330//-- if (sz == 4) {
6331//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "addps",
6332//-- insn[0], insn[1] );
6333//-- } else {
6334//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "addpd",
6335//-- 0x66, insn[0], insn[1] );
6336//-- }
6337//-- goto decode_success;
6338//-- }
6339//--
6340//-- /* 0xF2: MINSD */
6341//-- /* 0xF3: MINSS */
6342//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
6343//-- && insn[1] == 0x0F && insn[2] == 0x5D) {
6344//-- Bool sz8 = insn[0] == 0xF2;
6345//-- vg_assert(sz == 4);
6346//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
6347//-- sz8 ? "minsd" : "minss",
6348//-- insn[0], insn[1], insn[2] );
6349//-- goto decode_success;
6350//-- }
6351//--
6352//-- /* MINPS */
6353//-- /* 0x66: MINPD */
6354//-- if (insn[0] == 0x0F && insn[1] == 0x5D) {
6355//-- vg_assert(sz == 4 || sz == 2);
6356//-- if (sz == 4) {
6357//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "minps",
6358//-- insn[0], insn[1] );
6359//-- } else {
6360//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "minpd",
6361//-- 0x66, insn[0], insn[1] );
6362//-- }
6363//-- goto decode_success;
6364//-- }
6365//--
6366//-- /* 0xF3: MAXSD */
6367//-- /* 0xF3: MAXSS */
6368//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
6369//-- && insn[1] == 0x0F && insn[2] == 0x5F) {
6370//-- Bool sz8 = insn[0] == 0xF2;
6371//-- vg_assert(sz == 4);
6372//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
6373//-- sz8 ? "maxsd" : "maxss",
6374//-- insn[0], insn[1], insn[2] );
6375//-- goto decode_success;
6376//-- }
6377//--
6378//-- /* MAXPS */
6379//-- /* 0x66: MAXPD */
6380//-- if (insn[0] == 0x0F && insn[1] == 0x5F) {
6381//-- vg_assert(sz == 4 || sz == 2);
6382//-- if (sz == 4) {
6383//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "maxps",
6384//-- insn[0], insn[1] );
6385//-- } else {
6386//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "maxpd",
6387//-- 0x66, insn[0], insn[1] );
6388//-- }
6389//-- goto decode_success;
6390//-- }
6391//--
6392//-- /* RCPPS -- reciprocal of packed floats */
6393//-- if (insn[0] == 0x0F && insn[1] == 0x53) {
6394//-- vg_assert(sz == 4);
6395//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "rcpps",
6396//-- insn[0], insn[1] );
6397//-- goto decode_success;
6398//-- }
6399//--
6400//-- /* XORPS */
6401//-- /* 0x66: XORPD (src)xmmreg-or-mem, (dst)xmmreg */
6402//-- if (insn[0] == 0x0F && insn[1] == 0x57) {
6403//-- vg_assert(sz == 4 || sz == 2);
6404//-- if (sz == 4) {
6405//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "xorps",
6406//-- insn[0], insn[1] );
6407//-- } else {
6408//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "xorpd",
6409//-- 0x66, insn[0], insn[1] );
6410//-- }
6411//-- goto decode_success;
6412//-- }
6413//--
6414//-- /* ANDPS */
6415//-- /* 0x66: ANDPD (src)xmmreg-or-mem, (dst)xmmreg */
6416//-- if (insn[0] == 0x0F && insn[1] == 0x54) {
6417//-- vg_assert(sz == 4 || sz == 2);
6418//-- if (sz == 4) {
6419//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "andps",
6420//-- insn[0], insn[1] );
6421//-- } else {
6422//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "andpd",
6423//-- 0x66, insn[0], insn[1] );
6424//-- }
6425//-- goto decode_success;
6426//-- }
6427//--
6428//-- /* ORPS */
6429//-- /* 0x66: ORPD (src)xmmreg-or-mem, (dst)xmmreg */
6430//-- if (insn[0] == 0x0F && insn[1] == 0x56) {
6431//-- vg_assert(sz == 4 || sz == 2);
6432//-- if (sz == 4) {
6433//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "orps",
6434//-- insn[0], insn[1] );
6435//-- } else {
6436//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "orpd",
6437//-- 0x66, insn[0], insn[1] );
6438//-- }
6439//-- goto decode_success;
6440//-- }
6441//--
6442//-- /* PXOR (src)xmmreg-or-mem, (dst)xmmreg */
6443//-- if (sz == 2
6444//-- && insn[0] == 0x0F && insn[1] == 0xEF) {
6445//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pxor",
6446//-- 0x66, insn[0], insn[1] );
6447//-- goto decode_success;
6448//-- }
6449//--
6450//-- /* PAND (src)xmmreg-or-mem, (dst)xmmreg */
6451//-- if (sz == 2
6452//-- && insn[0] == 0x0F && insn[1] == 0xDB) {
6453//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pand",
6454//-- 0x66, insn[0], insn[1] );
6455//-- goto decode_success;
6456//-- }
6457//--
6458//-- /* PANDN (src)xmmreg-or-mem, (dst)xmmreg */
6459//-- if (sz == 2
6460//-- && insn[0] == 0x0F && insn[1] == 0xDF) {
6461//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pandn",
6462//-- 0x66, insn[0], insn[1] );
6463//-- goto decode_success;
6464//-- }
6465//--
6466//-- /* POR (src)xmmreg-or-mem, (dst)xmmreg */
6467//-- if (sz == 2
6468//-- && insn[0] == 0x0F && insn[1] == 0xEB) {
6469//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "por",
6470//-- 0x66, insn[0], insn[1] );
6471//-- goto decode_success;
6472//-- }
6473//--
6474//-- /* 0xDA: PMINUB(src)xmmreg-or-mem, (dst)xmmreg */
6475//-- /* 0xEA: PMINSW(src)xmmreg-or-mem, (dst)xmmreg */
6476//-- if (sz == 2
6477//-- && insn[0] == 0x0F
6478//-- && (insn[1] == 0xDA || insn[1] == 0xEA)) {
6479//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmin{ub,sw}",
6480//-- 0x66, insn[0], insn[1] );
6481//-- goto decode_success;
6482//-- }
6483//--
6484//-- /* 0xDE: PMAXUB(src)xmmreg-or-mem, (dst)xmmreg */
6485//-- /* 0xEE: PMAXSW(src)xmmreg-or-mem, (dst)xmmreg */
6486//-- if (sz == 2
6487//-- && insn[0] == 0x0F
6488//-- && (insn[1] == 0xDE || insn[1] == 0xEE)) {
6489//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmax{ub,sw}",
6490//-- 0x66, insn[0], insn[1] );
6491//-- goto decode_success;
6492//-- }
6493//--
6494//-- /* 0xE0: PAVGB(src)xmmreg-or-mem, (dst)xmmreg */
6495//-- /* 0xE3: PAVGW(src)xmmreg-or-mem, (dst)xmmreg */
6496//-- if (sz == 2
6497//-- && insn[0] == 0x0F
6498//-- && (insn[1] == 0xE0 || insn[1] == 0xE3)) {
6499//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pavg{b,w}",
6500//-- 0x66, insn[0], insn[1] );
6501//-- goto decode_success;
6502//-- }
6503//--
6504//-- /* 0xF6: PSADBW(src)xmmreg-or-mem, (dst)xmmreg */
6505//-- if (sz == 2
6506//-- && insn[0] == 0x0F && insn[1] == 0xF6) {
6507//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psadbw",
6508//-- 0x66, insn[0], insn[1] );
6509//-- goto decode_success;
6510//-- }
6511//--
6512//-- /* 0x60: PUNPCKLBW (src)xmmreg-or-mem, (dst)xmmreg */
6513//-- /* 0x61: PUNPCKLWD (src)xmmreg-or-mem, (dst)xmmreg */
6514//-- /* 0x62: PUNPCKLDQ (src)xmmreg-or-mem, (dst)xmmreg */
6515//-- /* 0x6C: PUNPCKQLQDQ (src)xmmreg-or-mem, (dst)xmmreg */
6516//-- if (sz == 2
6517//-- && insn[0] == 0x0F
6518//-- && (insn[1] == 0x60 || insn[1] == 0x61
6519//-- || insn[1] == 0x62 || insn[1] == 0x6C)) {
6520//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16,
6521//-- "punpckl{bw,wd,dq,qdq}",
6522//-- 0x66, insn[0], insn[1] );
6523//-- goto decode_success;
6524//-- }
6525//--
6526//-- /* 0x68: PUNPCKHBW (src)xmmreg-or-mem, (dst)xmmreg */
6527//-- /* 0x69: PUNPCKHWD (src)xmmreg-or-mem, (dst)xmmreg */
6528//-- /* 0x6A: PUNPCKHDQ (src)xmmreg-or-mem, (dst)xmmreg */
6529//-- /* 0x6D: PUNPCKHQDQ (src)xmmreg-or-mem, (dst)xmmreg */
6530//-- if (sz == 2
6531//-- && insn[0] == 0x0F
6532//-- && (insn[1] == 0x68 || insn[1] == 0x69
6533//-- || insn[1] == 0x6A || insn[1] == 0x6D)) {
6534//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16,
6535//-- "punpckh{bw,wd,dq,qdq}",
6536//-- 0x66, insn[0], insn[1] );
6537//-- goto decode_success;
6538//-- }
6539//--
6540//-- /* 0x14: UNPCKLPD (src)xmmreg-or-mem, (dst)xmmreg. Reads a+0
6541//-- .. a+7, so we can say size 8 */
6542//-- /* 0x15: UNPCKHPD (src)xmmreg-or-mem, (dst)xmmreg. Reads a+8
6543//-- .. a+15, but we have no way to express this, so better say size
6544//-- 16. Sigh. */
6545//-- if (sz == 2
6546//-- && insn[0] == 0x0F
6547//-- && (insn[1] == 0x14 || insn[1] == 0x15)) {
6548//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2,
6549//-- insn[1]==0x14 ? 8 : 16,
6550//-- "unpck{l,h}pd",
6551//-- 0x66, insn[0], insn[1] );
6552//-- goto decode_success;
6553//-- }
6554//--
6555//-- /* 0x14: UNPCKLPS (src)xmmreg-or-mem, (dst)xmmreg Reads a+0
6556//-- .. a+7, so we can say size 8 */
6557//-- /* 0x15: UNPCKHPS (src)xmmreg-or-mem, (dst)xmmreg Reads a+8
6558//-- .. a+15, but we have no way to express this, so better say size
6559//-- 16. Sigh. */
6560//-- if (sz == 4
6561//-- && insn[0] == 0x0F
6562//-- && (insn[1] == 0x14 || insn[1] == 0x15)) {
6563//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2,
6564//-- insn[1]==0x14 ? 8 : 16,
6565//-- "unpck{l,h}ps",
6566//-- insn[0], insn[1] );
6567//-- goto decode_success;
6568//-- }
6569//--
6570//-- /* 0xFC: PADDB (src)xmmreg-or-mem, (dst)xmmreg */
6571//-- /* 0xFD: PADDW (src)xmmreg-or-mem, (dst)xmmreg */
6572//-- /* 0xFE: PADDD (src)xmmreg-or-mem, (dst)xmmreg */
6573//-- /* 0xD4: PADDQ (src)xmmreg-or-mem, (dst)xmmreg */
6574//-- if (sz == 2
6575//-- && insn[0] == 0x0F
6576//-- && (insn[1] == 0xFC || insn[1] == 0xFD
6577//-- || insn[1] == 0xFE || insn[1] == 0xD4)) {
6578//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "padd{b,w,d,q}",
6579//-- 0x66, insn[0], insn[1] );
6580//-- goto decode_success;
6581//-- }
6582//--
6583//-- /* 0xEC: PADDSB (src)xmmreg-or-mem, (dst)xmmreg */
6584//-- /* 0xED: PADDSW (src)xmmreg-or-mem, (dst)xmmreg */
6585//-- if (sz == 2
6586//-- && insn[0] == 0x0F
6587//-- && (insn[1] == 0xEC || insn[1] == 0xED)) {
6588//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "padds{b,w}",
6589//-- 0x66, insn[0], insn[1] );
6590//-- goto decode_success;
6591//-- }
6592//--
6593//-- /* 0xDC: PADDUSB (src)xmmreg-or-mem, (dst)xmmreg */
6594//-- /* 0xDD: PADDUSW (src)xmmreg-or-mem, (dst)xmmreg */
6595//-- if (sz == 2
6596//-- && insn[0] == 0x0F
6597//-- && (insn[1] == 0xDC || insn[1] == 0xDD)) {
6598//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "paddus{b,w}",
6599//-- 0x66, insn[0], insn[1] );
6600//-- goto decode_success;
6601//-- }
6602//--
6603//-- /* 0xF8: PSUBB (src)xmmreg-or-mem, (dst)xmmreg */
6604//-- /* 0xF9: PSUBW (src)xmmreg-or-mem, (dst)xmmreg */
6605//-- /* 0xFA: PSUBD (src)xmmreg-or-mem, (dst)xmmreg */
6606//-- /* 0xFB: PSUBQ (src)xmmreg-or-mem, (dst)xmmreg */
6607//-- if (sz == 2
6608//-- && insn[0] == 0x0F
6609//-- && (insn[1] == 0xF8 || insn[1] == 0xF9
6610//-- || insn[1] == 0xFA || insn[1] == 0xFB)) {
6611//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psub{b,w,d,q}",
6612//-- 0x66, insn[0], insn[1] );
6613//-- goto decode_success;
6614//-- }
6615//--
6616//-- /* 0xE8: PSUBSB (src)xmmreg-or-mem, (dst)xmmreg */
6617//-- /* 0xE9: PSUBSW (src)xmmreg-or-mem, (dst)xmmreg */
6618//-- if (sz == 2
6619//-- && insn[0] == 0x0F
6620//-- && (insn[1] == 0xE8 || insn[1] == 0xE9)) {
6621//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psubs{b,w}",
6622//-- 0x66, insn[0], insn[1] );
6623//-- goto decode_success;
6624//-- }
6625//--
6626//-- /* 0xD8: PSUBUSB (src)xmmreg-or-mem, (dst)xmmreg */
6627//-- /* 0xD9: PSUBUSW (src)xmmreg-or-mem, (dst)xmmreg */
6628//-- if (sz == 2
6629//-- && insn[0] == 0x0F
6630//-- && (insn[1] == 0xD8 || insn[1] == 0xD9)) {
6631//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psubus{b,w}",
6632//-- 0x66, insn[0], insn[1] );
6633//-- goto decode_success;
6634//-- }
6635//--
6636//-- /* 0xE4: PMULHUW(src)xmmreg-or-mem, (dst)xmmreg */
6637//-- /* 0xE5: PMULHW(src)xmmreg-or-mem, (dst)xmmreg */
6638//-- /* 0xD5: PMULLW(src)xmmreg-or-mem, (dst)xmmreg */
6639//-- if (sz == 2
6640//-- && insn[0] == 0x0F
6641//-- && (insn[1] == 0xE4 || insn[1] == 0xE5 || insn[1] == 0xD5)) {
6642//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmul{hu,h,l}w",
6643//-- 0x66, insn[0], insn[1] );
6644//-- goto decode_success;
6645//-- }
6646//--
6647//-- /* 0xD5: PMULUDQ(src)xmmreg-or-mem, (dst)xmmreg */
6648//-- if (sz == 2
6649//-- && insn[0] == 0x0F && insn[1] == 0xF4) {
6650//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmuludq",
6651//-- 0x66, insn[0], insn[1] );
6652//-- goto decode_success;
6653//-- }
6654//--
6655//-- /* 0xF5: PMADDWD(src)xmmreg-or-mem, (dst)xmmreg */
6656//-- if (sz == 2
6657//-- && insn[0] == 0x0F
6658//-- && insn[1] == 0xF5) {
6659//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmaddwd",
6660//-- 0x66, insn[0], insn[1] );
6661//-- goto decode_success;
6662//-- }
6663//--
6664//-- /* 0x74: PCMPEQB (src)xmmreg-or-mem, (dst)xmmreg */
6665//-- /* 0x75: PCMPEQW (src)xmmreg-or-mem, (dst)xmmreg */
6666//-- /* 0x76: PCMPEQD (src)xmmreg-or-mem, (dst)xmmreg */
6667//-- if (sz == 2
6668//-- && insn[0] == 0x0F
6669//-- && (insn[1] == 0x74 || insn[1] == 0x75 || insn[1] == 0x76)) {
6670//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pcmpeq{b,w,d}",
6671//-- 0x66, insn[0], insn[1] );
6672//-- goto decode_success;
6673//-- }
6674//--
6675//-- /* 0x64: PCMPGTB (src)xmmreg-or-mem, (dst)xmmreg */
6676//-- /* 0x65: PCMPGTW (src)xmmreg-or-mem, (dst)xmmreg */
6677//-- /* 0x66: PCMPGTD (src)xmmreg-or-mem, (dst)xmmreg */
6678//-- if (sz == 2
6679//-- && insn[0] == 0x0F
6680//-- && (insn[1] == 0x64 || insn[1] == 0x65 || insn[1] == 0x66)) {
6681//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pcmpgt{b,w,d}",
6682//-- 0x66, insn[0], insn[1] );
6683//-- goto decode_success;
6684//-- }
6685//--
6686//-- /* 0x63: PACKSSWB (src)xmmreg-or-mem, (dst)xmmreg */
6687//-- /* 0x6B: PACKSSDW (src)xmmreg-or-mem, (dst)xmmreg */
6688//-- if (sz == 2
6689//-- && insn[0] == 0x0F
6690//-- && (insn[1] == 0x63 || insn[1] == 0x6B)) {
6691//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "packss{wb,dw}",
6692//-- 0x66, insn[0], insn[1] );
6693//-- goto decode_success;
6694//-- }
6695//--
6696//-- /* 0x67: PACKUSWB (src)xmmreg-or-mem, (dst)xmmreg */
6697//-- if (sz == 2
6698//-- && insn[0] == 0x0F
6699//-- && insn[1] == 0x67) {
6700//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "packuswb",
6701//-- 0x66, insn[0], insn[1] );
6702//-- goto decode_success;
6703//-- }
6704//--
6705//-- /* 0xF1: PSLLW (src)xmmreg-or-mem, (dst)xmmreg */
6706//-- /* 0xF2: PSLLD (src)xmmreg-or-mem, (dst)xmmreg */
6707//-- /* 0xF3: PSLLQ (src)xmmreg-or-mem, (dst)xmmreg */
6708//-- if (sz == 2
6709//-- && insn[0] == 0x0F
6710//-- && (insn[1] == 0xF1 || insn[1] == 0xF2 || insn[1] == 0xF3)) {
6711//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psll{b,w,d}",
6712//-- 0x66, insn[0], insn[1] );
6713//-- goto decode_success;
6714//-- }
6715//--
6716//-- /* 0xD1: PSRLW (src)xmmreg-or-mem, (dst)xmmreg */
6717//-- /* 0xD2: PSRLD (src)xmmreg-or-mem, (dst)xmmreg */
6718//-- /* 0xD3: PSRLQ (src)xmmreg-or-mem, (dst)xmmreg */
6719//-- if (sz == 2
6720//-- && insn[0] == 0x0F
6721//-- && (insn[1] == 0xD1 || insn[1] == 0xD2 || insn[1] == 0xD3)) {
6722//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psrl{b,w,d}",
6723//-- 0x66, insn[0], insn[1] );
6724//-- goto decode_success;
6725//-- }
6726//--
6727//-- /* 0xE1: PSRAW (src)xmmreg-or-mem, (dst)xmmreg */
6728//-- /* 0xE2: PSRAD (src)xmmreg-or-mem, (dst)xmmreg */
6729//-- if (sz == 2
6730//-- && insn[0] == 0x0F
6731//-- && (insn[1] == 0xE1 || insn[1] == 0xE2)) {
6732//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psra{w,d}",
6733//-- 0x66, insn[0], insn[1] );
6734//-- goto decode_success;
6735//-- }
6736//--
6737//-- /* (U)COMISD (src)xmmreg-or-mem, (dst)xmmreg */
6738//-- if (sz == 2
6739//-- && insn[0] == 0x0F
6740//-- && ( insn[1] == 0x2E || insn[1] == 0x2F ) ) {
6741//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 8, "{u}comisd",
6742//-- 0x66, insn[0], insn[1] );
6743//-- vg_assert(LAST_UINSTR(cb).opcode == SSE3a_MemRd
6744//-- || LAST_UINSTR(cb).opcode == SSE4);
6745//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
6746//-- goto decode_success;
6747//-- }
6748//--
6749//-- /* (U)COMISS (src)xmmreg-or-mem, (dst)xmmreg */
6750//-- if (sz == 4
6751//-- && insn[0] == 0x0F
6752//-- && ( insn[1] == 0x2E || insn[ 1 ] == 0x2F )) {
6753//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 4, "{u}comiss",
6754//-- insn[0], insn[1] );
6755//-- vg_assert(LAST_UINSTR(cb).opcode == SSE2a_MemRd
6756//-- || LAST_UINSTR(cb).opcode == SSE3);
6757//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
6758//-- goto decode_success;
6759//-- }
6760//--
6761//-- /* MOVSD -- move 8 bytes of XMM reg to/from XMM reg or mem. */
6762//-- if (insn[0] == 0xF2
6763//-- && insn[1] == 0x0F
6764//-- && (insn[2] == 0x11 || insn[2] == 0x10)) {
6765//-- vg_assert(sz == 4);
6766//-- eip = dis_SSE3_load_store_or_mov
6767//-- ( cb, sorb, eip+3, 8, insn[2]==0x11, "movsd",
6768//-- insn[0], insn[1], insn[2] );
6769//-- goto decode_success;
6770//-- }
6771//--
6772//-- /* MOVQ -- move 8 bytes of XMM reg to XMM reg or mem. How
6773//-- does this differ from MOVSD ?? */
6774//-- if (sz == 2
6775//-- && insn[0] == 0x0F
6776//-- && insn[1] == 0xD6) {
6777//-- eip = dis_SSE3_load_store_or_mov
6778//-- ( cb, sorb, eip+2, 8, True /*store*/, "movq",
6779//-- 0x66, insn[0], insn[1] );
6780//-- goto decode_success;
6781//-- }
6782//--
6783//-- /* MOVQ -- move 8 bytes of XMM reg or mem to XMM reg. How
6784//-- does this differ from MOVSD ?? */
6785//-- if (insn[0] == 0xF3
6786//-- && insn[1] == 0x0F
6787//-- && insn[2] == 0x7E) {
6788//-- eip = dis_SSE3_load_store_or_mov
6789//-- ( cb, sorb, eip+3, 8, False /*load*/, "movq",
6790//-- insn[0], insn[1], insn[2] );
6791//-- goto decode_success;
6792//-- }
6793//--
6794//-- /* MOVDQ2Q -- move low 4 bytes of XMM reg to MMX reg. */
6795//-- if (insn[0] == 0xF2
6796//-- && insn[1] == 0x0F
6797//-- && insn[2] == 0xD6) {
6798//-- eip = dis_SSE3_to_MMX
6799//-- ( cb, sorb, eip+3, 8, "movdq2q",
6800//-- insn[0], insn[1], insn[2] );
6801//-- goto decode_success;
6802//-- }
6803//--
6804//-- /* MOVQ2DQ -- move MMX reg to low 4 bytes of XMM reg. */
6805//-- if (insn[0] == 0xF3
6806//-- && insn[1] == 0x0F
6807//-- && insn[2] == 0xD6) {
6808//-- eip = dis_SSE3_from_MMX
6809//-- ( cb, sorb, eip+3, 8, "movq2dq",
6810//-- insn[0], insn[1], insn[2] );
6811//-- goto decode_success;
6812//-- }
6813//--
6814//-- /* MOVSS -- move 4 bytes of XMM reg to/from XMM reg or mem. */
6815//-- if (insn[0] == 0xF3
6816//-- && insn[1] == 0x0F
6817//-- && (insn[2] == 0x11 || insn[2] == 0x10)) {
6818//-- vg_assert(sz == 4);
6819//-- eip = dis_SSE3_load_store_or_mov
6820//-- ( cb, sorb, eip+3, 4, insn[2]==0x11, "movss",
6821//-- insn[0], insn[1], insn[2] );
6822//-- goto decode_success;
6823//-- }
6824//--
6825//-- /* I don't understand how MOVAPD differs from MOVAPS. */
6826//-- /* MOVAPD (28,29) -- aligned load/store of xmm reg, or xmm-xmm reg
6827//-- move */
6828//-- if (sz == 2
6829//-- && insn[0] == 0x0F && insn[1] == 0x28) {
6830//-- UChar* name = "movapd";
6831//-- //(insn[1] == 0x10 || insn[1] == 0x11)
6832//-- // ? "movups" : "movaps";
6833//-- Bool store = False; //insn[1] == 0x29 || insn[1] == 11;
6834//-- eip = dis_SSE3_load_store_or_mov
6835//-- ( cb, sorb, eip+2, 16, store, name,
6836//-- 0x66, insn[0], insn[1] );
6837//-- goto decode_success;
6838//-- }
6839//--
6840//-- /* sz==4: MOVAPS (28,29) -- aligned load/store of xmm reg, or
6841//-- xmm-xmm reg move */
6842//-- /* sz==4: MOVUPS (10,11) -- unaligned load/store of xmm reg, or
6843//-- xmm-xmm reg move */
6844//-- /* sz==2: MOVAPD (28,29) -- aligned load/store of xmm reg, or
6845//-- xmm-xmm reg move */
6846//-- /* sz==2: MOVUPD (10,11) -- unaligned load/store of xmm reg, or
6847//-- xmm-xmm reg move */
6848//-- if (insn[0] == 0x0F && (insn[1] == 0x28
6849//-- || insn[1] == 0x29
6850//-- || insn[1] == 0x10
6851//-- || insn[1] == 0x11)) {
6852//-- UChar* name = (insn[1] == 0x10 || insn[1] == 0x11)
6853//-- ? "movups" : "movaps";
6854//-- Bool store = insn[1] == 0x29 || insn[1] == 11;
6855//-- vg_assert(sz == 2 || sz == 4);
6856//-- if (sz == 4) {
6857//-- eip = dis_SSE2_load_store_or_mov
6858//-- ( cb, sorb, eip+2, 16, store, name,
6859//-- insn[0], insn[1] );
6860//-- } else {
6861//-- eip = dis_SSE3_load_store_or_mov
6862//-- ( cb, sorb, eip+2, 16, store, name,
6863//-- 0x66, insn[0], insn[1] );
6864//-- }
6865//-- goto decode_success;
6866//-- }
6867//--
6868//-- /* MOVDQA -- aligned 16-byte load/store. */
6869//-- if (sz == 2
6870//-- && insn[0] == 0x0F
6871//-- && (insn[1] == 0x6F || insn[1] == 0x7F)) {
6872//-- Bool is_store = insn[1]==0x7F;
6873//-- eip = dis_SSE3_load_store_or_mov
6874//-- (cb, sorb, eip+2, 16, is_store, "movdqa",
6875//-- 0x66, insn[0], insn[1] );
6876//-- goto decode_success;
6877//-- }
6878//--
6879//-- /* MOVDQU -- unaligned 16-byte load/store. */
6880//-- if (insn[0] == 0xF3
6881//-- && insn[1] == 0x0F
6882//-- && (insn[2] == 0x6F || insn[2] == 0x7F)) {
6883//-- Bool is_store = insn[2]==0x7F;
6884//-- eip = dis_SSE3_load_store_or_mov
6885//-- (cb, sorb, eip+3, 16, is_store, "movdqu",
6886//-- insn[0], insn[1], insn[2] );
6887//-- goto decode_success;
6888//-- }
6889//--
6890//-- /* MOVNTDQ -- 16-byte store with temporal hint (which we
6891//-- ignore). */
6892//-- if (sz == 2
6893//-- && insn[0] == 0x0F
6894//-- && insn[1] == 0xE7) {
6895//-- eip = dis_SSE3_load_store_or_mov
6896//-- (cb, sorb, eip+2, 16, True /* is_store */, "movntdq",
6897//-- 0x66, insn[0], insn[1] );
6898//-- goto decode_success;
6899//-- }
6900//--
6901//-- /* MOVNTPS -- 16-byte store with temporal hint (which we
6902//-- ignore). */
6903//-- if (insn[0] == 0x0F
6904//-- && insn[1] == 0x2B) {
6905//-- eip = dis_SSE2_load_store_or_mov
6906//-- (cb, sorb, eip+2, 16, True /* is_store */, "movntps",
6907//-- insn[0], insn[1] );
6908//-- goto decode_success;
6909//-- }
6910//--
6911//-- /* MOVNTPD -- 16-byte store with temporal hint (which we
6912//-- ignore). */
6913//-- if (sz == 2
6914//-- && insn[0] == 0x0F
6915//-- && insn[1] == 0x2B) {
6916//-- eip = dis_SSE3_load_store_or_mov
6917//-- (cb, sorb, eip+2, 16, True /* is_store */, "movntpd",
6918//-- 0x66, insn[0], insn[1] );
6919//-- goto decode_success;
6920//-- }
6921//--
6922//-- /* MOVD -- 4-byte move between xmmregs and (ireg or memory). */
6923//-- if (sz == 2
6924//-- && insn[0] == 0x0F
6925//-- && (insn[1] == 0x6E || insn[1] == 0x7E)) {
6926//-- Bool is_store = insn[1]==0x7E;
6927//-- modrm = insn[2];
6928//-- if (epartIsReg(modrm) && is_store) {
6929//-- t1 = newTemp(cb);
6930//-- uInstr3(cb, SSE3e_RegWr, 4,
6931//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
6932//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
6933//-- TempReg, t1 );
6934//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, eregOfRM(modrm));
6935//-- DIP("movd %s, %s\n",
6936//-- nameXMMReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
6937//-- eip += 3;
6938//-- } else
6939//-- if (epartIsReg(modrm) && !is_store) {
6940//-- t1 = newTemp(cb);
6941//-- uInstr2(cb, GET, 4, ArchReg, eregOfRM(modrm), TempReg, t1);
6942//-- uInstr3(cb, SSE3e_RegRd, 4,
6943//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
6944//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
6945//-- TempReg, t1 );
6946//-- DIP("movd %s, %s\n",
6947//-- nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
6948//-- eip += 3;
6949//-- } else {
6950//-- eip = dis_SSE3_load_store_or_mov
6951//-- (cb, sorb, eip+2, 4, is_store, "movd",
6952//-- 0x66, insn[0], insn[1] );
6953//-- }
6954//-- goto decode_success;
6955//-- }
6956//--
6957//-- /* PEXTRW from SSE register; writes ireg */
6958//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC5) {
6959//-- t1 = newTemp(cb);
6960//-- modrm = insn[2];
6961//-- vg_assert(epartIsReg(modrm));
6962//-- vg_assert((modrm & 0xC0) == 0xC0);
6963//-- uInstr3(cb, SSE3g1_RegWr, 4,
6964//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
6965//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
6966//-- TempReg, t1 );
6967//-- uLiteral(cb, insn[3]);
6968//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
6969//-- DIP("pextrw %s, %d, %s\n",
6970//-- nameXMMReg(eregOfRM(modrm)), (Int)insn[3],
6971//-- nameIReg(4, gregOfRM(modrm)));
6972//-- eip += 4;
6973//-- goto decode_success;
6974//-- }
6975//--
6976//-- /* PINSRW to SSE register; reads mem or ireg */
6977//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC4) {
6978//-- t1 = newTemp(cb);
6979//-- modrm = insn[2];
6980//-- if (epartIsReg(modrm)) {
6981//-- uInstr2(cb, GET, 2, ArchReg, eregOfRM(modrm), TempReg, t1);
6982//-- vg_assert(epartIsReg(modrm));
6983//-- uInstr3(cb, SSE3e1_RegRd, 2,
6984//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
6985//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
6986//-- TempReg, t1 );
6987//-- uLiteral(cb, insn[3]);
6988//-- DIP("pinsrw %s, %d, %s\n",
6989//-- nameIReg(2, eregOfRM(modrm)), (Int)insn[3],
6990//-- nameXMMReg(gregOfRM(modrm)));
6991//-- eip += 4;
6992//-- } else {
6993//-- VG_(core_panic)("PINSRW mem");
6994//-- }
6995//-- goto decode_success;
6996//-- }
6997//--
6998//-- /* SQRTSD: square root of scalar double. */
6999//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x51) {
7000//-- vg_assert(sz == 4);
7001//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8,
7002//-- "sqrtsd",
7003//-- insn[0], insn[1], insn[2] );
7004//-- goto decode_success;
7005//-- }
7006//--
7007//-- /* SQRTSS: square root of scalar float. */
7008//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x51) {
7009//-- vg_assert(sz == 4);
7010//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4,
7011//-- "sqrtss",
7012//-- insn[0], insn[1], insn[2] );
7013//-- goto decode_success;
7014//-- }
7015//--
7016//-- /* RSQRTSS: square root reciprocal of scalar float. */
7017//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x52) {
7018//-- vg_assert(sz == 4);
7019//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4,
7020//-- "sqrtss",
7021//-- insn[0], insn[1], insn[2] );
7022//-- goto decode_success;
7023//-- }
7024//--
7025//-- /* 0xF3: RCPSS -- reciprocal of scalar float */
7026//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x53) {
7027//-- vg_assert(sz == 4);
7028//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4,
7029//-- "rcpss",
7030//-- insn[0], insn[1], insn[2] );
7031//-- goto decode_success;
7032//-- }
7033//--
7034//-- /* MOVMSKPD -- extract 2 sign bits from a xmm reg and copy them to
7035//-- an ireg. Top 30 bits of ireg are set to zero. */
7036//-- /* MOVMSKPS -- extract 4 sign bits from a xmm reg and copy them to
7037//-- an ireg. Top 28 bits of ireg are set to zero. */
7038//-- if (insn[0] == 0x0F && insn[1] == 0x50) {
7039//-- vg_assert(sz == 4 || sz == 2);
7040//-- modrm = insn[2];
7041//-- /* Intel docs don't say anything about a memory source being
7042//-- allowed here. */
7043//-- vg_assert(epartIsReg(modrm));
7044//-- t1 = newTemp(cb);
7045//-- if (sz == 4) {
7046//-- uInstr3(cb, SSE2g_RegWr, 4,
7047//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
7048//-- Lit16, (UShort)modrm,
7049//-- TempReg, t1 );
7050//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
7051//-- } else {
7052//-- uInstr3(cb, SSE3g_RegWr, 4,
7053//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
7054//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
7055//-- TempReg, t1 );
7056//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
7057//-- }
7058//-- DIP("movmskp%c %s, %s\n", sz == 4 ? 's' : 'd',
7059//-- nameXMMReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)));
7060//-- eip += 3;
7061//-- goto decode_success;
7062//-- }
7063//--
7064//-- /* ANDNPS */
7065//-- /* 0x66: ANDNPD (src)xmmreg-or-mem, (dst)xmmreg */
7066//-- if (insn[0] == 0x0F && insn[1] == 0x55) {
7067//-- vg_assert(sz == 4 || sz == 2);
7068//-- if (sz == 4) {
7069//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "andnps",
7070//-- insn[0], insn[1] );
7071//-- } else {
7072//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "andnpd",
7073//-- 0x66, insn[0], insn[1] );
7074//-- }
7075//-- goto decode_success;
7076//-- }
7077//--
7078//-- /* MOVHLPS -- move two packed floats from high quadword to low quadword */
7079//-- /* MOVLPS -- load/store two packed floats to/from low quadword. */
7080//-- /* MOVLPD -- load/store packed double to/from low quadword. */
7081//-- if (insn[0] == 0x0F
7082//-- && (insn[1] == 0x12 || insn[1] == 0x13)) {
7083//-- Bool is_store = insn[1]==0x13;
7084//-- vg_assert(sz == 4 || sz == 2);
7085//-- if (sz == 4) {
7086//-- if (epartIsReg(insn[2])) {
7087//-- vg_assert(insn[1]==0x12);
7088//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "movhlps",
7089//-- insn[0], insn[1] );
7090//-- } else {
7091//-- eip = dis_SSE2_load_store_or_mov
7092//-- (cb, sorb, eip+2, 8, is_store, "movlps",
7093//-- insn[0], insn[1] );
7094//-- }
7095//-- } else {
7096//-- vg_assert(!epartIsReg(insn[2]));
7097//-- eip = dis_SSE3_load_store_or_mov
7098//-- (cb, sorb, eip+2, 8, is_store, "movlpd",
7099//-- 0x66, insn[0], insn[1] );
7100//-- }
7101//-- goto decode_success;
7102//-- }
7103//--
7104//-- /* MOVLHPS -- move two packed floats from low quadword to high quadword */
7105//-- /* MOVHPS -- load/store two packed floats to/from high quadword. */
7106//-- /* MOVHPD -- load/store packed double to/from high quadword. */
7107//-- if (insn[0] == 0x0F
7108//-- && (insn[1] == 0x16 || insn[1] == 0x17)) {
7109//-- Bool is_store = insn[1]==0x17;
7110//-- vg_assert(sz == 4 || sz == 2);
7111//-- if (sz == 4) {
7112//-- if (epartIsReg(insn[2])) {
7113//-- vg_assert(insn[1]==0x16);
7114//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "movlhps",
7115//-- insn[0], insn[1] );
7116//-- } else {
7117//-- eip = dis_SSE2_load_store_or_mov
7118//-- (cb, sorb, eip+2, 8, is_store, "movhps",
7119//-- insn[0], insn[1] );
7120//-- }
7121//-- } else {
7122//-- vg_assert(!epartIsReg(insn[2]));
7123//-- eip = dis_SSE3_load_store_or_mov
7124//-- (cb, sorb, eip+2, 8, is_store, "movhpd",
7125//-- 0x66, insn[0], insn[1] );
7126//-- }
7127//-- goto decode_success;
7128//-- }
7129//--
7130//-- /* PMOVMSKB -- extract 16 sign bits from a xmm reg and copy them to
7131//-- an ireg. Top 16 bits of ireg are set to zero. */
7132//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD7) {
7133//-- modrm = insn[2];
7134//-- /* Intel docs don't say anything about a memory source being
7135//-- allowed here. */
7136//-- vg_assert(epartIsReg(modrm));
7137//-- t1 = newTemp(cb);
7138//-- uInstr3(cb, SSE3g_RegWr, 4,
7139//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
7140//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
7141//-- TempReg, t1 );
7142//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
7143//-- DIP("pmovmskb %s, %s\n",
7144//-- nameXMMReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)));
7145//-- eip += 3;
7146//-- goto decode_success;
7147//-- }
7148//--
7149//-- /* sz==4: SQRTPS: square root of packed float. */
7150//-- /* sz==2: SQRTPD: square root of packed double. */
7151//-- if (insn[0] == 0x0F && insn[1] == 0x51) {
7152//-- vg_assert(sz == 2 || sz == 4);
7153//-- if (sz == 4) {
7154//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16,
7155//-- "sqrtps",
7156//-- insn[0], insn[1] );
7157//-- } else {
7158//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16,
7159//-- "sqrtpd",
7160//-- 0x66, insn[0], insn[1] );
7161//-- }
7162//-- goto decode_success;
7163//-- }
7164//--
7165//-- /* RSQRTPS: square root reciprocal of packed float. */
7166//-- if (insn[0] == 0x0F && insn[1] == 0x52) {
7167//-- vg_assert(sz == 4);
7168//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16,
7169//-- "rsqrtps",
7170//-- insn[0], insn[1] );
7171//-- goto decode_success;
7172//-- }
7173//--
7174//-- /* Fall through into the non-SSE decoder. */
7175//--
7176//-- } /* if (VG_(have_ssestate)) */
7177
7178
7179 /* ---------------------------------------------------- */
7180 /* --- end of the SSE/SSE2 decoder. --- */
7181 /* ---------------------------------------------------- */
7182
7183 /* Get the primary opcode. */
7184 opc = getIByte(delta); delta++;
7185
7186 /* We get here if the current insn isn't SSE, or this CPU doesn't
7187 support SSE. */
7188
7189 switch (opc) {
7190
7191 /* ------------------------ Control flow --------------- */
sewardj940e8c92004-07-11 16:53:24 +00007192
7193 case 0xC2: /* RET imm16 */
7194 d32 = getUDisp16(delta);
7195 delta += 2;
7196 dis_ret(d32);
7197 *isEnd = True;
7198 DIP("ret %d\n", d32);
7199 break;
sewardje05c42c2004-07-08 20:25:10 +00007200 case 0xC3: /* RET */
7201 dis_ret(0);
7202 *isEnd = True;
7203 DIP("ret\n");
7204 break;
sewardjd1061ab2004-07-08 01:45:30 +00007205
7206 case 0xE8: /* CALL J4 */
7207 d32 = getUDisp32(delta); delta += 4;
7208 d32 += (guest_eip+delta);
7209 /* (guest_eip+delta) == return-to addr, d32 == call-to addr */
sewardjc2ac51e2004-07-12 01:03:26 +00007210 if (d32 == guest_eip+delta && getIByte(delta) >= 0x58
7211 && getIByte(delta) <= 0x5F) {
sewardjd1061ab2004-07-08 01:45:30 +00007212 /* Specially treat the position-independent-code idiom
7213 call X
7214 X: popl %reg
7215 as
7216 movl %eip, %reg.
7217 since this generates better code, but for no other reason. */
7218 Int archReg = getIByte(delta) - 0x58;
sewardjc2ac51e2004-07-12 01:03:26 +00007219 /* vex_printf("-- fPIC thingy\n"); */
7220 putIReg(4, archReg, mkU32(guest_eip+delta));
sewardjd1061ab2004-07-08 01:45:30 +00007221 delta++; /* Step over the POP */
7222 DIP("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
sewardjc2ac51e2004-07-12 01:03:26 +00007223 } else {
sewardjd1061ab2004-07-08 01:45:30 +00007224 /* The normal sequence for a call. */
7225 t1 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +00007226 assign(t1, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
7227 putIReg(4, R_ESP, mkexpr(t1));
7228 storeLE( mkexpr(t1), mkU32(guest_eip+delta));
sewardj78c19df2004-07-12 22:49:27 +00007229 jmp_lit(Ijk_Call,d32);
sewardjd1061ab2004-07-08 01:45:30 +00007230 *isEnd = True;
7231 DIP("call 0x%x\n",d32);
7232 }
7233 break;
7234
sewardjc9a65702004-07-07 16:32:57 +00007235//-- case 0xC8: /* ENTER */
7236//-- d32 = getUDisp16(eip); eip += 2;
7237//-- abyte = getIByte(delta); delta++;
7238//--
7239//-- vg_assert(sz == 4);
7240//-- vg_assert(abyte == 0);
7241//--
7242//-- t1 = newTemp(cb); t2 = newTemp(cb);
7243//-- uInstr2(cb, GET, sz, ArchReg, R_EBP, TempReg, t1);
7244//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
7245//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
7246//-- uLiteral(cb, sz);
7247//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
7248//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
7249//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
7250//-- if (d32) {
7251//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
7252//-- uLiteral(cb, d32);
7253//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
7254//-- }
7255//-- DIP("enter 0x%x, 0x%x", d32, abyte);
7256//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +00007257
7258 case 0xC9: /* LEAVE */
7259 vassert(sz == 4);
7260 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
7261 assign(t1, getIReg(4,R_EBP));
7262 /* First PUT ESP looks redundant, but need it because ESP must
7263 always be up-to-date for Memcheck to work... */
7264 putIReg(4, R_ESP, mkexpr(t1));
7265 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
7266 putIReg(4, R_EBP, mkexpr(t2));
7267 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(4)) );
7268 DIP("leave\n");
7269 break;
7270
sewardjc9a65702004-07-07 16:32:57 +00007271//-- /* ---------------- Misc weird-ass insns --------------- */
7272//--
7273//-- case 0x27: /* DAA */
7274//-- case 0x2F: /* DAS */
7275//-- t1 = newTemp(cb);
7276//-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
7277//-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
7278//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
7279//-- uWiden(cb, 1, False);
7280//-- uInstr0(cb, CALLM_S, 0);
7281//-- uInstr1(cb, PUSH, 4, TempReg, t1);
7282//-- uInstr1(cb, CALLM, 0, Lit16,
7283//-- opc == 0x27 ? VGOFF_(helper_DAA) : VGOFF_(helper_DAS) );
7284//-- uFlagsRWU(cb, FlagsAC, FlagsSZACP, FlagO);
7285//-- uInstr1(cb, POP, 4, TempReg, t1);
7286//-- uInstr0(cb, CALLM_E, 0);
7287//-- uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
7288//-- DIP(opc == 0x27 ? "daa\n" : "das\n");
7289//-- break;
7290//--
7291//-- case 0x37: /* AAA */
7292//-- case 0x3F: /* AAS */
7293//-- t1 = newTemp(cb);
7294//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
7295//-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
7296//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
7297//-- uWiden(cb, 2, False);
7298//-- uInstr0(cb, CALLM_S, 0);
7299//-- uInstr1(cb, PUSH, 4, TempReg, t1);
7300//-- uInstr1(cb, CALLM, 0, Lit16,
7301//-- opc == 0x37 ? VGOFF_(helper_AAA) : VGOFF_(helper_AAS) );
7302//-- uFlagsRWU(cb, FlagA, FlagsAC, FlagsEmpty);
7303//-- uInstr1(cb, POP, 4, TempReg, t1);
7304//-- uInstr0(cb, CALLM_E, 0);
7305//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
7306//-- DIP(opc == 0x37 ? "aaa\n" : "aas\n");
7307//-- break;
7308//--
7309//-- case 0xD4: /* AAM */
7310//-- case 0xD5: /* AAD */
7311//-- d32 = getIByte(delta); delta++;
7312//-- if (d32 != 10) VG_(core_panic)("disInstr: AAM/AAD but base not 10 !");
7313//-- t1 = newTemp(cb);
7314//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
7315//-- /* Widen %AX to 32 bits, so it's all defined when we push it. */
7316//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
7317//-- uWiden(cb, 2, False);
7318//-- uInstr0(cb, CALLM_S, 0);
7319//-- uInstr1(cb, PUSH, 4, TempReg, t1);
7320//-- uInstr1(cb, CALLM, 0, Lit16,
7321//-- opc == 0xD4 ? VGOFF_(helper_AAM) : VGOFF_(helper_AAD) );
7322//-- uFlagsRWU(cb, FlagsEmpty, FlagsSZP, FlagsEmpty);
7323//-- uInstr1(cb, POP, 4, TempReg, t1);
7324//-- uInstr0(cb, CALLM_E, 0);
7325//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
7326//-- DIP(opc == 0xD4 ? "aam\n" : "aad\n");
7327//-- break;
sewardj1c6f9912004-09-07 10:15:24 +00007328
7329 /* ------------------------ CWD/CDQ -------------------- */
7330
7331 case 0x98: /* CBW */
7332 if (sz == 4) {
7333 putIReg(4, R_EAX, unop(Iop_16Sto32, getIReg(2, R_EAX)));
7334 DIP("cwde\n");
7335 } else {
sewardj47341042004-09-19 11:55:46 +00007336 vassert(sz == 2);
7337 putIReg(2, R_EAX, unop(Iop_8Sto16, getIReg(1, R_EAX)));
7338 DIP("cbw\n");
sewardj1c6f9912004-09-07 10:15:24 +00007339 }
7340 break;
sewardj64e1d652004-07-12 14:00:46 +00007341
7342 case 0x99: /* CWD/CDQ */
7343 ty = szToITy(sz);
7344 putIReg(sz, R_EDX,
7345 binop(mkSizedOp(ty,Iop_Sar8),
7346 getIReg(sz, R_EAX),
sewardj6d2638e2004-07-15 09:38:27 +00007347 mkU8(sz == 2 ? 15 : 31)) );
sewardj64e1d652004-07-12 14:00:46 +00007348 DIP(sz == 2 ? "cwdq\n" : "cdqq\n");
7349 break;
7350
sewardjbdc7d212004-09-09 02:46:40 +00007351 /* ------------------------ FPU ops -------------------- */
7352
7353 case 0x9E: /* SAHF */
7354 codegen_SAHF();
7355 DIP("sahf\n");
7356 break;
7357
sewardjc9a65702004-07-07 16:32:57 +00007358//-- case 0x9F: /* LAHF */
7359//-- codegen_LAHF ( cb );
7360//-- DIP("lahf\n");
7361//-- break;
7362//--
sewardjbdc7d212004-09-09 02:46:40 +00007363 case 0x9B: /* FWAIT */
7364 /* ignore? */
7365 DIP("fwait\n");
7366 break;
7367
sewardjd1725d12004-08-12 20:46:53 +00007368 case 0xD8:
7369 case 0xD9:
7370 case 0xDA:
7371 case 0xDB:
7372 case 0xDC:
7373 case 0xDD:
7374 case 0xDE:
7375 case 0xDF: {
7376 UInt delta0 = delta;
7377 Bool decode_OK = False;
7378 delta = dis_FPU ( &decode_OK, sorb, delta );
7379 if (!decode_OK) {
7380 delta = delta0;
7381 goto decode_failure;
7382 }
7383 break;
7384 }
sewardj0611d802004-07-11 02:37:54 +00007385
7386 /* ------------------------ INC & DEC ------------------ */
7387
7388 case 0x40: /* INC eAX */
7389 case 0x41: /* INC eCX */
7390 case 0x42: /* INC eDX */
7391 case 0x43: /* INC eBX */
7392 case 0x44: /* INC eSP */
7393 case 0x45: /* INC eBP */
7394 case 0x46: /* INC eSI */
7395 case 0x47: /* INC eDI */
7396 vassert(sz == 2 || sz == 4);
7397 ty = szToITy(sz);
7398 t1 = newTemp(ty);
7399 assign( t1, binop(mkSizedOp(ty,Iop_Add8),
7400 getIReg(sz, (UInt)(opc - 0x40)),
7401 mkU(ty,1)) );
7402 setFlags_INC_DEC( True, t1, ty );
7403 putIReg(sz, (UInt)(opc - 0x40), mkexpr(t1));
7404 DIP("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
7405 break;
7406
7407 case 0x48: /* DEC eAX */
7408 case 0x49: /* DEC eCX */
7409 case 0x4A: /* DEC eDX */
7410 case 0x4B: /* DEC eBX */
7411 case 0x4C: /* DEC eSP */
7412 case 0x4D: /* DEC eBP */
7413 case 0x4E: /* DEC eSI */
7414 case 0x4F: /* DEC eDI */
7415 vassert(sz == 2 || sz == 4);
7416 ty = szToITy(sz);
7417 t1 = newTemp(ty);
7418 assign( t1, binop(mkSizedOp(ty,Iop_Sub8),
7419 getIReg(sz, (UInt)(opc - 0x48)),
7420 mkU(ty,1)) );
7421 setFlags_INC_DEC( False, t1, ty );
7422 putIReg(sz, (UInt)(opc - 0x48), mkexpr(t1));
7423 DIP("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
7424 break;
7425
7426 /* ------------------------ INT ------------------------ */
7427
7428 case 0xCD: /* INT imm8 */
7429 d32 = getIByte(delta); delta++;
7430 if (d32 != 0x80) goto decode_failure;
7431 /* It's important that all ArchRegs carry their up-to-date value
7432 at this point. So we declare an end-of-block here, which
7433 forces any TempRegs caching ArchRegs to be flushed. */
sewardj78c19df2004-07-12 22:49:27 +00007434 jmp_lit(Ijk_Syscall,((Addr32)guest_code)+delta);
sewardj0611d802004-07-11 02:37:54 +00007435 *isEnd = True;
7436 DIP("int $0x80\n");
7437 break;
7438
sewardj77b86be2004-07-11 13:28:24 +00007439 /* ------------------------ Jcond, byte offset --------- */
7440
7441 case 0xEB: /* Jb (jump, byte offset) */
7442 d32 = (((Addr32)guest_code)+delta+1) + getSDisp8(delta);
7443 delta++;
sewardj78c19df2004-07-12 22:49:27 +00007444 jmp_lit(Ijk_Boring,d32);
sewardj77b86be2004-07-11 13:28:24 +00007445 *isEnd = True;
7446 DIP("jmp-8 0x%x\n", d32);
7447 break;
sewardj0611d802004-07-11 02:37:54 +00007448
7449 case 0xE9: /* Jv (jump, 16/32 offset) */
7450 vassert(sz == 4); /* JRS added 2004 July 11 */
7451 d32 = (((Addr32)guest_code)+delta+sz) + getSDisp(sz,delta);
7452 delta += sz;
sewardj78c19df2004-07-12 22:49:27 +00007453 jmp_lit(Ijk_Boring,d32);
sewardj0611d802004-07-11 02:37:54 +00007454 *isEnd = True;
7455 DIP("jmp 0x%x\n", d32);
7456 break;
sewardje87b4842004-07-10 12:23:30 +00007457
7458 case 0x70:
7459 case 0x71:
7460 case 0x72: /* JBb/JNAEb (jump below) */
7461 case 0x73: /* JNBb/JAEb (jump not below) */
7462 case 0x74: /* JZb/JEb (jump zero) */
7463 case 0x75: /* JNZb/JNEb (jump not zero) */
7464 case 0x76: /* JBEb/JNAb (jump below or equal) */
7465 case 0x77: /* JNBEb/JAb (jump not below or equal) */
7466 case 0x78: /* JSb (jump negative) */
7467 case 0x79: /* JSb (jump not negative) */
7468 case 0x7A: /* JP (jump parity even) */
7469 case 0x7B: /* JNP/JPO (jump parity odd) */
7470 case 0x7C: /* JLb/JNGEb (jump less) */
7471 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
7472 case 0x7E: /* JLEb/JNGb (jump less or equal) */
7473 case 0x7F: /* JGb/JNLEb (jump greater) */
7474 d32 = (((Addr32)guest_code)+delta+1) + getSDisp8(delta);
7475 delta++;
7476 jcc_01((Condcode)(opc - 0x70), (Addr32)(guest_code+delta), d32);
7477 *isEnd = True;
7478 DIP("j%s-8 0x%x\n", name_Condcode(opc - 0x70), d32);
7479 break;
7480
sewardj458a6f82004-08-25 12:46:02 +00007481 case 0xE3: /* JECXZ or perhaps JCXZ, depending on OSO ? Intel
7482 manual says it depends on address size override,
7483 which doesn't sound right to me. */
7484 vassert(sz==4); /* possibly also OK for sz==2 */
7485 d32 = (((Addr32)guest_code)+delta+1) + getSDisp8(delta);
7486 delta++;
7487 ty = szToITy(sz);
7488 stmt( IRStmt_Exit(
7489 binop(mkSizedOp(ty,Iop_CmpEQ8),
7490 getIReg(sz,R_ECX),
7491 mkU(ty,0)),
7492 IRConst_U32(d32))
7493 );
7494
7495 DIP("j%sz 0x%x\n", nameIReg(sz, R_ECX), d32);
7496 break;
7497
sewardjc9a65702004-07-07 16:32:57 +00007498//-- case 0xE0: /* LOOPNE disp8 */
7499//-- case 0xE1: /* LOOPE disp8 */
7500//-- case 0xE2: /* LOOP disp8 */
7501//-- /* Again, the docs say this uses ECX/CX as a count depending on
7502//-- the address size override, not the operand one. Since we
7503//-- don't handle address size overrides, I guess that means
7504//-- ECX. */
7505//-- d32 = (eip+1) + getSDisp8(eip); eip++;
7506//-- t1 = newTemp(cb);
7507//-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
7508//-- uInstr1(cb, DEC, 4, TempReg, t1);
7509//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ECX);
7510//-- uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
7511//-- uLiteral(cb, eip);
7512//-- if (opc == 0xE0 || opc == 0xE1) { /* LOOPE/LOOPNE */
7513//-- jcc_lit(cb, eip, (opc == 0xE1 ? CondNZ : CondZ));
7514//-- }
7515//-- jmp_lit(cb, d32);
7516//-- *isEnd = True;
7517//-- DIP("loop 0x%x\n", d32);
7518//-- break;
sewardj1813dbe2004-07-28 17:09:04 +00007519
7520 /* ------------------------ IMUL ----------------------- */
7521
7522 case 0x69: /* IMUL Iv, Ev, Gv */
7523 delta = dis_imul_I_E_G ( sorb, sz, delta, sz );
7524 break;
7525 case 0x6B: /* IMUL Ib, Ev, Gv */
7526 delta = dis_imul_I_E_G ( sorb, sz, delta, 1 );
7527 break;
sewardj0611d802004-07-11 02:37:54 +00007528
7529 /* ------------------------ MOV ------------------------ */
7530
7531 case 0x88: /* MOV Gb,Eb */
7532 delta = dis_mov_G_E(sorb, 1, delta);
7533 break;
sewardjc9a65702004-07-07 16:32:57 +00007534
7535 case 0x89: /* MOV Gv,Ev */
7536 delta = dis_mov_G_E(sorb, sz, delta);
7537 break;
7538
sewardjc2ac51e2004-07-12 01:03:26 +00007539 case 0x8A: /* MOV Eb,Gb */
7540 delta = dis_mov_E_G(sorb, 1, delta);
7541 break;
sewardje05c42c2004-07-08 20:25:10 +00007542
7543 case 0x8B: /* MOV Ev,Gv */
7544 delta = dis_mov_E_G(sorb, sz, delta);
7545 break;
7546
sewardje87b4842004-07-10 12:23:30 +00007547 case 0x8D: /* LEA M,Gv */
sewardje05c42c2004-07-08 20:25:10 +00007548 vassert(sz == 4);
7549 modrm = getIByte(delta);
7550 if (epartIsReg(modrm))
7551 vpanic("LEA M,Gv: modRM refers to register (x86)");
7552 /* NOTE! this is the one place where a segment override prefix
7553 has no effect on the address calculation. Therefore we pass
7554 zero instead of sorb here. */
sewardje87b4842004-07-10 12:23:30 +00007555 addr = disAMode ( &alen, /*sorb*/ 0, delta, dis_buf );
7556 delta += alen;
sewardj940e8c92004-07-11 16:53:24 +00007557 putIReg(sz, gregOfRM(modrm), mkexpr(addr));
sewardje05c42c2004-07-08 20:25:10 +00007558 DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
7559 nameIReg(sz,gregOfRM(modrm)));
7560 break;
sewardje05c42c2004-07-08 20:25:10 +00007561
sewardjc9a65702004-07-07 16:32:57 +00007562//-- case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
7563//-- eip = dis_mov_Sw_Ew(cb, sorb, eip);
7564//-- break;
7565//--
7566//-- case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
7567//-- eip = dis_mov_Ew_Sw(cb, sorb, eip);
7568//-- break;
7569//--
sewardj43852812004-10-16 23:10:08 +00007570 case 0xA0: /* MOV Ob,AL */
7571 sz = 1;
7572 /* Fall through ... */
sewardj0c12ea82004-07-12 08:18:16 +00007573 case 0xA1: /* MOV Ov,eAX */
7574 d32 = getUDisp32(delta); delta += 4;
7575 ty = szToITy(sz);
7576 addr = newTemp(Ity_I32);
7577 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
7578 putIReg(sz, R_EAX, loadLE(ty, mkexpr(addr)));
7579 DIP("mov%c %s0x%x, %s\n", nameISize(sz), sorbTxt(sorb),
7580 d32, nameIReg(sz,R_EAX));
7581 break;
7582
sewardj180e8b32004-07-29 01:40:11 +00007583 case 0xA2: /* MOV Ob,AL */
7584 sz = 1;
7585 /* Fall through ... */
sewardj750f4072004-07-26 22:39:11 +00007586 case 0xA3: /* MOV eAX,Ov */
7587 d32 = getUDisp32(delta); delta += 4;
7588 ty = szToITy(sz);
7589 addr = newTemp(Ity_I32);
7590 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
7591 storeLE( mkexpr(addr), getIReg(sz,R_EAX) );
7592 DIP("mov%c %s, %s0x%x\n", nameISize(sz), nameIReg(sz,R_EAX),
7593 sorbTxt(sorb), d32);
7594 break;
sewardje87b4842004-07-10 12:23:30 +00007595
sewardjc2ac51e2004-07-12 01:03:26 +00007596 case 0xB0: /* MOV imm,AL */
7597 case 0xB1: /* MOV imm,CL */
7598 case 0xB2: /* MOV imm,DL */
7599 case 0xB3: /* MOV imm,BL */
7600 case 0xB4: /* MOV imm,AH */
7601 case 0xB5: /* MOV imm,CH */
7602 case 0xB6: /* MOV imm,DH */
7603 case 0xB7: /* MOV imm,BH */
7604 d32 = getIByte(delta); delta += 1;
7605 putIReg(1, opc-0xB0, mkU8(d32));
7606 DIP("movb $0x%x,%s\n", d32, nameIReg(1,opc-0xB0));
7607 break;
sewardj7ed22952004-07-29 00:09:58 +00007608
sewardje87b4842004-07-10 12:23:30 +00007609 case 0xB8: /* MOV imm,eAX */
7610 case 0xB9: /* MOV imm,eCX */
7611 case 0xBA: /* MOV imm,eDX */
7612 case 0xBB: /* MOV imm,eBX */
7613 case 0xBC: /* MOV imm,eSP */
7614 case 0xBD: /* MOV imm,eBP */
7615 case 0xBE: /* MOV imm,eSI */
7616 case 0xBF: /* MOV imm,eDI */
7617 d32 = getUDisp(sz,delta); delta += sz;
7618 putIReg(sz, opc-0xB8, mkU(szToITy(sz), d32));
7619 DIP("mov%c $0x%x,%s\n", nameISize(sz), d32, nameIReg(sz,opc-0xB8));
7620 break;
7621
sewardj77b86be2004-07-11 13:28:24 +00007622 case 0xC6: /* MOV Ib,Eb */
7623 sz = 1;
7624 goto do_Mov_I_E;
sewardje87b4842004-07-10 12:23:30 +00007625 case 0xC7: /* MOV Iv,Ev */
7626 goto do_Mov_I_E;
7627
7628 do_Mov_I_E:
7629 modrm = getIByte(delta);
7630 if (epartIsReg(modrm)) {
7631 delta++; /* mod/rm byte */
7632 d32 = getUDisp(sz,delta); delta += sz;
7633 putIReg(sz, eregOfRM(modrm), mkU(szToITy(sz), d32));
7634 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32,
7635 nameIReg(sz,eregOfRM(modrm)));
7636 vassert(0);
7637 } else {
7638 addr = disAMode ( &alen, sorb, delta, dis_buf );
7639 delta += alen;
7640 d32 = getUDisp(sz,delta); delta += sz;
sewardj940e8c92004-07-11 16:53:24 +00007641 storeLE(mkexpr(addr), mkU(szToITy(sz), d32));
sewardje87b4842004-07-10 12:23:30 +00007642 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
7643 }
7644 break;
7645
sewardj1813dbe2004-07-28 17:09:04 +00007646 /* ------------------------ opl imm, A ----------------- */
7647
7648 case 0x04: /* ADD Ib, AL */
7649 delta = dis_op_imm_A( 1, Iop_Add8, True, delta, "add" );
7650 break;
sewardj77b86be2004-07-11 13:28:24 +00007651 case 0x05: /* ADD Iv, eAX */
7652 delta = dis_op_imm_A(sz, Iop_Add8, True, delta, "add" );
7653 break;
7654
sewardj940e8c92004-07-11 16:53:24 +00007655 case 0x0C: /* OR Ib, AL */
7656 delta = dis_op_imm_A( 1, Iop_Or8, True, delta, "or" );
7657 break;
sewardj82292882004-07-27 00:15:59 +00007658 case 0x0D: /* OR Iv, eAX */
7659 delta = dis_op_imm_A( sz, Iop_Or8, True, delta, "or" );
7660 break;
7661
sewardjc9a65702004-07-07 16:32:57 +00007662//-- case 0x14: /* ADC Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +00007663//-- delta = dis_op_imm_A( 1, ADC, True, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +00007664//-- break;
7665//-- case 0x15: /* ADC Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +00007666//-- delta = dis_op_imm_A( sz, ADC, True, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +00007667//-- break;
7668//--
7669//-- case 0x1C: /* SBB Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +00007670//-- delta = dis_op_imm_A( 1, SBB, True, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +00007671//-- break;
7672//-- case 0x1D: /* SBB Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +00007673//-- delta = dis_op_imm_A( sz, SBB, True, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +00007674//-- break;
7675//--
sewardj940e8c92004-07-11 16:53:24 +00007676 case 0x24: /* AND Ib, AL */
7677 delta = dis_op_imm_A( 1, Iop_And8, True, delta, "and" );
7678 break;
sewardjc2ac51e2004-07-12 01:03:26 +00007679 case 0x25: /* AND Iv, eAX */
7680 delta = dis_op_imm_A( sz, Iop_And8, True, delta, "and" );
7681 break;
sewardj0611d802004-07-11 02:37:54 +00007682
7683 case 0x2C: /* SUB Ib, AL */
7684 delta = dis_op_imm_A(1, Iop_Sub8, True, delta, "sub" );
7685 break;
sewardj68511542004-07-28 00:15:44 +00007686 case 0x2D: /* SUB Iv, eAX */
7687 delta = dis_op_imm_A( sz, Iop_Sub8, True, delta, "sub" );
7688 break;
7689
sewardj1c6f9912004-09-07 10:15:24 +00007690 case 0x34: /* XOR Ib, AL */
7691 delta = dis_op_imm_A( 1, Iop_Xor8, True, delta, "xor" );
7692 break;
sewardjcaca9d02004-07-28 07:11:32 +00007693 case 0x35: /* XOR Iv, eAX */
7694 delta = dis_op_imm_A( sz, Iop_Xor8, True, delta, "xor" );
7695 break;
7696
sewardj0611d802004-07-11 02:37:54 +00007697 case 0x3C: /* CMP Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +00007698 delta = dis_op_imm_A( 1, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +00007699 break;
7700 case 0x3D: /* CMP Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +00007701 delta = dis_op_imm_A( sz, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +00007702 break;
7703
sewardj77b86be2004-07-11 13:28:24 +00007704 case 0xA8: /* TEST Ib, AL */
7705 delta = dis_op_imm_A( 1, Iop_And8, False, delta, "test" );
7706 break;
sewardjc2ac51e2004-07-12 01:03:26 +00007707 case 0xA9: /* TEST Iv, eAX */
7708 delta = dis_op_imm_A( sz, Iop_And8, False, delta, "test" );
7709 break;
7710
sewardj1c6f9912004-09-07 10:15:24 +00007711 /* ------------------------ opl Ev, Gv ----------------- */
7712
sewardj89cd0932004-09-08 18:23:25 +00007713 case 0x02: /* ADD Eb,Gb */
7714 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, 1, delta, "add" );
7715 break;
sewardj9334b0f2004-07-10 22:43:54 +00007716 case 0x03: /* ADD Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00007717 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, sz, delta, "add" );
sewardj9334b0f2004-07-10 22:43:54 +00007718 break;
7719
sewardj7ed22952004-07-29 00:09:58 +00007720 case 0x0A: /* OR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00007721 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, 1, delta, "or" );
sewardj7ed22952004-07-29 00:09:58 +00007722 break;
sewardjc2ac51e2004-07-12 01:03:26 +00007723 case 0x0B: /* OR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00007724 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, sz, delta, "or" );
sewardjc2ac51e2004-07-12 01:03:26 +00007725 break;
sewardjc9a65702004-07-07 16:32:57 +00007726//--
7727//-- case 0x12: /* ADC Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00007728//-- delta = dis_op2_E_G ( sorb, True, ADC, True, 1, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +00007729//-- break;
sewardjc4eaff32004-09-10 20:25:11 +00007730 case 0x13: /* ADC Ev,Gv */
7731 delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
7732 break;
7733
sewardjc9a65702004-07-07 16:32:57 +00007734//-- case 0x1A: /* SBB Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00007735//-- delta = dis_op2_E_G ( sorb, True, SBB, True, 1, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +00007736//-- break;
sewardj180e8b32004-07-29 01:40:11 +00007737 case 0x1B: /* SBB Ev,Gv */
7738 delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
sewardj940e8c92004-07-11 16:53:24 +00007739 break;
7740
sewardj1c6f9912004-09-07 10:15:24 +00007741 case 0x22: /* AND Eb,Gb */
7742 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, 1, delta, "and" );
7743 break;
sewardj180e8b32004-07-29 01:40:11 +00007744 case 0x23: /* AND Ev,Gv */
7745 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, sz, delta, "and" );
7746 break;
7747
7748 case 0x2A: /* SUB Eb,Gb */
7749 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
7750 break;
sewardj0611d802004-07-11 02:37:54 +00007751 case 0x2B: /* SUB Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00007752 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
sewardj0611d802004-07-11 02:37:54 +00007753 break;
sewardjc2ac51e2004-07-12 01:03:26 +00007754
7755 case 0x32: /* XOR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00007756 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +00007757 break;
sewardj1813dbe2004-07-28 17:09:04 +00007758 case 0x33: /* XOR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00007759 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
sewardj1813dbe2004-07-28 17:09:04 +00007760 break;
7761
sewardjc2ac51e2004-07-12 01:03:26 +00007762 case 0x3A: /* CMP Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00007763 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardjc2ac51e2004-07-12 01:03:26 +00007764 break;
sewardje90ad6a2004-07-10 19:02:10 +00007765 case 0x3B: /* CMP Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00007766 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +00007767 break;
7768
sewardj0611d802004-07-11 02:37:54 +00007769 case 0x84: /* TEST Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00007770 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, 1, delta, "test" );
sewardj0611d802004-07-11 02:37:54 +00007771 break;
sewardje05c42c2004-07-08 20:25:10 +00007772 case 0x85: /* TEST Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00007773 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, sz, delta, "test" );
sewardje05c42c2004-07-08 20:25:10 +00007774 break;
7775
sewardj180e8b32004-07-29 01:40:11 +00007776 /* ------------------------ opl Gv, Ev ----------------- */
7777
7778 case 0x00: /* ADD Gb,Eb */
7779 delta = dis_op2_G_E ( sorb, False, Iop_Add8, True, 1, delta, "add" );
7780 break;
sewardje05c42c2004-07-08 20:25:10 +00007781 case 0x01: /* ADD Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00007782 delta = dis_op2_G_E ( sorb, False, Iop_Add8, True, sz, delta, "add" );
sewardje05c42c2004-07-08 20:25:10 +00007783 break;
7784
sewardj940e8c92004-07-11 16:53:24 +00007785 case 0x08: /* OR Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +00007786 delta = dis_op2_G_E ( sorb, False, Iop_Or8, True, 1, delta, "or" );
sewardj940e8c92004-07-11 16:53:24 +00007787 break;
sewardj9334b0f2004-07-10 22:43:54 +00007788 case 0x09: /* OR Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00007789 delta = dis_op2_G_E ( sorb, False, Iop_Or8, True, sz, delta, "or" );
sewardj9334b0f2004-07-10 22:43:54 +00007790 break;
7791
sewardja2384712004-07-29 14:36:40 +00007792 case 0x10: /* ADC Gb,Eb */
7793 delta = dis_op2_G_E ( sorb, True, Iop_Add8, True, 1, delta, "adc" );
7794 break;
sewardjcaca9d02004-07-28 07:11:32 +00007795 case 0x11: /* ADC Gv,Ev */
7796 delta = dis_op2_G_E ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
7797 break;
7798
sewardja2384712004-07-29 14:36:40 +00007799 case 0x18: /* SBB Gb,Eb */
7800 delta = dis_op2_G_E ( sorb, True, Iop_Sub8, True, 1, delta, "sbb" );
7801 break;
sewardjcaca9d02004-07-28 07:11:32 +00007802 case 0x19: /* SBB Gv,Ev */
7803 delta = dis_op2_G_E ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
7804 break;
7805
sewardja2384712004-07-29 14:36:40 +00007806 case 0x20: /* AND Gb,Eb */
7807 delta = dis_op2_G_E ( sorb, False, Iop_And8, True, 1, delta, "and" );
7808 break;
sewardj0611d802004-07-11 02:37:54 +00007809 case 0x21: /* AND Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00007810 delta = dis_op2_G_E ( sorb, False, Iop_And8, True, sz, delta, "and" );
sewardj0611d802004-07-11 02:37:54 +00007811 break;
7812
sewardj180e8b32004-07-29 01:40:11 +00007813 case 0x28: /* SUB Gb,Eb */
7814 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
7815 break;
sewardje05c42c2004-07-08 20:25:10 +00007816 case 0x29: /* SUB Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00007817 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
sewardje05c42c2004-07-08 20:25:10 +00007818 break;
7819
sewardjc2ac51e2004-07-12 01:03:26 +00007820 case 0x30: /* XOR Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +00007821 delta = dis_op2_G_E ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +00007822 break;
sewardje87b4842004-07-10 12:23:30 +00007823 case 0x31: /* XOR Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00007824 delta = dis_op2_G_E ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
sewardje87b4842004-07-10 12:23:30 +00007825 break;
7826
sewardj0611d802004-07-11 02:37:54 +00007827 case 0x38: /* CMP Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +00007828 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +00007829 break;
sewardje90ad6a2004-07-10 19:02:10 +00007830 case 0x39: /* CMP Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00007831 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +00007832 break;
7833
sewardj9334b0f2004-07-10 22:43:54 +00007834 /* ------------------------ POP ------------------------ */
7835
7836 case 0x58: /* POP eAX */
7837 case 0x59: /* POP eCX */
7838 case 0x5A: /* POP eDX */
7839 case 0x5B: /* POP eBX */
7840 case 0x5D: /* POP eBP */
7841 case 0x5E: /* POP eSI */
7842 case 0x5F: /* POP eDI */
7843 case 0x5C: /* POP eSP */
7844 vassert(sz == 2 || sz == 4);
7845 t1 = newTemp(szToITy(sz)); t2 = newTemp(Ity_I32);
7846 assign(t2, getIReg(4, R_ESP));
7847 assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
7848 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
7849 putIReg(sz, opc-0x58, mkexpr(t1));
7850 DIP("pop%c %s\n", nameISize(sz), nameIReg(sz,opc-0x58));
7851 break;
7852
sewardja2384712004-07-29 14:36:40 +00007853 case 0x9D: /* POPF */
7854 vassert(sz == 2 || sz == 4);
7855 vassert(sz == 4); // until we know a sz==2 test case exists
7856 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
7857 assign(t2, getIReg(4, R_ESP));
sewardjc22a6fd2004-07-29 23:41:47 +00007858 assign(t1, widenUto32(loadLE(szToITy(sz),mkexpr(t2))));
sewardja2384712004-07-29 14:36:40 +00007859 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
7860 /* t1 is the flag word. Mask out everything OSZACP and
7861 set the flags thunk to CC_OP_COPY. */
7862 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
7863 stmt( IRStmt_Put( OFFB_CC_DST, mkU32(0) ));
7864 stmt( IRStmt_Put( OFFB_CC_SRC,
7865 binop(Iop_And32,
7866 mkexpr(t1),
7867 mkU32( CC_MASK_C | CC_MASK_P | CC_MASK_A
7868 | CC_MASK_Z | CC_MASK_S| CC_MASK_O )
7869 )
7870 )
7871 );
7872
7873 /* Also need to set the D flag, which is held in bit 10 of t1.
7874 If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
7875 stmt( IRStmt_Put(
7876 OFFB_DFLAG,
7877 IRExpr_Mux0X(
7878 unop(Iop_32to8,
7879 binop(Iop_And32,
7880 binop(Iop_Shr32, mkexpr(t1), mkU8(10)),
7881 mkU32(1))),
7882 mkU32(1),
7883 mkU32(0xFFFFFFFF)))
7884 );
7885
7886 DIP("popf%c\n", nameISize(sz));
7887 break;
7888
sewardjc9a65702004-07-07 16:32:57 +00007889//-- case 0x61: /* POPA */
7890//-- { Int reg;
7891//-- /* Just to keep things sane, we assert for a size 4. It's
7892//-- probably OK for size 2 as well, but I'd like to find a test
7893//-- case; ie, have the assertion fail, before committing to it.
7894//-- If it fails for you, uncomment the sz == 2 bit, try again,
7895//-- and let me know whether or not it works. (jseward@acm.org). */
7896//-- vg_assert(sz == 4 /* || sz == 2 */);
7897//--
7898//-- /* Eight values are popped, one per register, but the value of
7899//-- %esp on the stack is ignored and instead incremented (in one
7900//-- hit at the end) for each of the values. */
7901//-- t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
7902//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
7903//-- uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t3);
7904//--
7905//-- /* Do %edi, %esi, %ebp */
7906//-- for (reg = 7; reg >= 5; reg--) {
7907//-- uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
7908//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
7909//-- uLiteral(cb, sz);
7910//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
7911//-- }
7912//-- /* Ignore (skip) value of %esp on stack. */
7913//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
7914//-- uLiteral(cb, sz);
7915//-- /* Do %ebx, %edx, %ecx, %eax */
7916//-- for (reg = 3; reg >= 0; reg--) {
7917//-- uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
7918//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
7919//-- uLiteral(cb, sz);
7920//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
7921//-- }
7922//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t3);
7923//-- uLiteral(cb, sz * 8); /* One 'sz' per register */
7924//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
7925//-- DIP("popa%c\n", nameISize(sz));
7926//-- break;
7927//-- }
7928//--
7929//-- case 0x8F: /* POPL/POPW m32 */
7930//-- { UInt pair1;
7931//-- Int tmpa;
7932//-- UChar rm = getIByte(delta);
7933//--
7934//-- /* make sure this instruction is correct POP */
7935//-- vg_assert(!epartIsReg(rm) && (gregOfRM(rm) == 0));
7936//-- /* and has correct size */
7937//-- vg_assert(sz == 4);
7938//--
7939//-- t1 = newTemp(cb); t3 = newTemp(cb);
7940//-- /* set t1 to ESP: t1 = ESP */
7941//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
7942//-- /* load M[ESP] to virtual register t3: t3 = M[t1] */
7943//-- uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t3);
7944//--
7945//-- /* increase ESP; must be done before the STORE. Intel manual says:
7946//-- If the ESP register is used as a base register for addressing
7947//-- a destination operand in memory, the POP instruction computes
7948//-- the effective address of the operand after it increments the
7949//-- ESP register.
7950//-- */
7951//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1);
7952//-- uLiteral(cb, sz);
7953//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
7954//--
7955//-- /* resolve MODR/M */
7956//-- pair1 = disAMode ( cb, sorb, eip, dis_buf );
7957//--
7958//-- tmpa = LOW24(pair1);
7959//-- /* uInstr2(cb, LOAD, sz, TempReg, tmpa, TempReg, tmpa); */
7960//-- /* store value from stack in memory, M[m32] = t3 */
7961//-- uInstr2(cb, STORE, 4, TempReg, t3, TempReg, tmpa);
7962//--
7963//-- DIP("popl %s\n", dis_buf);
7964//--
7965//-- eip += HI8(pair1);
7966//-- break;
7967//-- }
7968//--
7969//-- case 0x1F: /* POP %DS */
7970//-- dis_pop_segreg( cb, R_DS, sz ); break;
7971//-- case 0x07: /* POP %ES */
7972//-- dis_pop_segreg( cb, R_ES, sz ); break;
7973//-- case 0x17: /* POP %SS */
7974//-- dis_pop_segreg( cb, R_SS, sz ); break;
sewardjd1061ab2004-07-08 01:45:30 +00007975
7976 /* ------------------------ PUSH ----------------------- */
7977
7978 case 0x50: /* PUSH eAX */
7979 case 0x51: /* PUSH eCX */
7980 case 0x52: /* PUSH eDX */
7981 case 0x53: /* PUSH eBX */
7982 case 0x55: /* PUSH eBP */
7983 case 0x56: /* PUSH eSI */
7984 case 0x57: /* PUSH eDI */
7985 case 0x54: /* PUSH eSP */
7986 /* This is the Right Way, in that the value to be pushed is
7987 established before %esp is changed, so that pushl %esp
7988 correctly pushes the old value. */
7989 vassert(sz == 2 || sz == 4);
7990 ty = sz==2 ? Ity_I16 : Ity_I32;
sewardj883b00b2004-09-11 09:30:24 +00007991 t1 = newTemp(ty); t2 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +00007992 assign(t1, getIReg(sz, opc-0x50));
7993 assign(t2, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)));
7994 putIReg(4, R_ESP, mkexpr(t2) );
7995 storeLE(mkexpr(t2),mkexpr(t1));
sewardjd1061ab2004-07-08 01:45:30 +00007996 DIP("push%c %s\n", nameISize(sz), nameIReg(sz,opc-0x50));
7997 break;
7998
7999
sewardj0c12ea82004-07-12 08:18:16 +00008000 case 0x68: /* PUSH Iv */
8001 d32 = getUDisp(sz,delta); delta += sz;
8002 goto do_push_I;
sewardj741153c2004-07-25 23:39:13 +00008003 case 0x6A: /* PUSH Ib, sign-extended to sz */
8004 d32 = getSDisp8(delta); delta += 1;
8005 goto do_push_I;
sewardj0c12ea82004-07-12 08:18:16 +00008006 do_push_I:
8007 ty = szToITy(sz);
8008 t1 = newTemp(Ity_I32); t2 = newTemp(ty);
8009 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
8010 putIReg(4, R_ESP, mkexpr(t1) );
8011 storeLE( mkexpr(t1), mkU(ty,d32) );
8012 DIP("push%c $0x%x\n", nameISize(sz), d32);
8013 break;
8014
sewardja2384712004-07-29 14:36:40 +00008015 case 0x9C: /* PUSHF */ {
8016 IRTemp t3;
8017 vassert(sz == 2 || sz == 4);
8018 vassert(sz == 4); // wait for sz==2 test case
8019
8020 t1 = newTemp(Ity_I32);
8021 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
8022 putIReg(4, R_ESP, mkexpr(t1) );
8023
8024 t2 = newTemp(Ity_I32);
8025 assign( t2, mk_calculate_eflags_all() );
8026
8027 /* Patch in the D flag. This can simply be the inversion
8028 of bit 10 of baseBlock[OFFB_DFLAG]. */
8029 t3 = newTemp(Ity_I32);
8030 assign( t3, binop(Iop_Or32,
8031 mkexpr(t2),
8032 binop(Iop_And32,
8033 unop(Iop_Not32, IRExpr_Get(OFFB_DFLAG,Ity_I32)),
8034 mkU32(1<<10)))
8035 );
8036 /* if sz==2, the stored value needs to be narrowed. */
8037 if (sz == 2)
8038 storeLE( mkexpr(t1), unop(Iop_32to16,mkexpr(t3)) );
8039 else
8040 storeLE( mkexpr(t1), mkexpr(t3) );
8041
8042 DIP("pushf%c\n", nameISize(sz));
8043 break;
8044 }
8045
sewardjc9a65702004-07-07 16:32:57 +00008046//-- case 0x60: /* PUSHA */
8047//-- { Int reg;
8048//-- /* Just to keep things sane, we assert for a size 4. It's
8049//-- probably OK for size 2 as well, but I'd like to find a test
8050//-- case; ie, have the assertion fail, before committing to it.
8051//-- If it fails for you, uncomment the sz == 2 bit, try again,
8052//-- and let me know whether or not it works. (jseward@acm.org). */
8053//-- vg_assert(sz == 4 /* || sz == 2 */);
8054//--
8055//-- /* This is the Right Way, in that the value to be pushed is
8056//-- established before %esp is changed, so that pusha
8057//-- correctly pushes the old %esp value. New value of %esp is
8058//-- pushed at start. */
8059//-- t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
8060//-- t4 = newTemp(cb);
8061//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
8062//-- uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
8063//-- uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t4);
8064//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t4);
8065//-- uLiteral(cb, sz * 8); /* One 'sz' per register. */
8066//-- uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_ESP);
8067//-- /* Do %eax, %ecx, %edx, %ebx */
8068//-- for (reg = 0; reg <= 3; reg++) {
8069//-- uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
8070//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
8071//-- uLiteral(cb, sz);
8072//-- uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
8073//-- }
8074//-- /* Push old value of %esp */
8075//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
8076//-- uLiteral(cb, sz);
8077//-- uInstr2(cb, STORE, sz, TempReg, t3, TempReg, t2);
8078//-- /* Do %ebp, %esi, %edi */
8079//-- for (reg = 5; reg <= 7; reg++) {
8080//-- uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
8081//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
8082//-- uLiteral(cb, sz);
8083//-- uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
8084//-- }
8085//-- DIP("pusha%c\n", nameISize(sz));
8086//-- break;
8087//-- }
8088//--
8089//-- case 0x0E: /* PUSH %CS */
8090//-- dis_push_segreg( cb, R_CS, sz ); break;
8091//-- case 0x1E: /* PUSH %DS */
8092//-- dis_push_segreg( cb, R_DS, sz ); break;
8093//-- case 0x06: /* PUSH %ES */
8094//-- dis_push_segreg( cb, R_ES, sz ); break;
8095//-- case 0x16: /* PUSH %SS */
8096//-- dis_push_segreg( cb, R_SS, sz ); break;
sewardj458a6f82004-08-25 12:46:02 +00008097
8098 /* ------------------------ SCAS et al ----------------- */
8099
8100 case 0xA4: /* MOVS, no REP prefix */
8101 case 0xA5:
8102 dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
8103 break;
8104
sewardjc9a65702004-07-07 16:32:57 +00008105//-- case 0xA6: /* CMPSb, no REP prefix */
8106//-- case 0xA7:
8107//-- dis_string_op( cb, dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
8108//-- break;
8109//--
sewardj883b00b2004-09-11 09:30:24 +00008110 case 0xAA: /* STOS, no REP prefix */
sewardj47341042004-09-19 11:55:46 +00008111 case 0xAB:
sewardj883b00b2004-09-11 09:30:24 +00008112 dis_string_op( dis_STOS, ( opc == 0xAA ? 1 : sz ), "stos", sorb );
8113 break;
sewardjc9a65702004-07-07 16:32:57 +00008114//--
8115//-- case 0xAC: /* LODS, no REP prefix */
8116//-- case 0xAD:
8117//-- dis_string_op( cb, dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
8118//-- break;
sewardj2d4c3a02004-10-15 00:03:23 +00008119
8120 case 0xAE: /* SCAS, no REP prefix */
8121 case 0xAF:
8122 dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
8123 break;
sewardj64e1d652004-07-12 14:00:46 +00008124
8125
8126 case 0xFC: /* CLD */
sewardjeeb9ef82004-07-15 12:39:03 +00008127 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(1)) );
sewardj64e1d652004-07-12 14:00:46 +00008128 DIP("cld\n");
8129 break;
8130
sewardj1813dbe2004-07-28 17:09:04 +00008131 case 0xFD: /* STD */
8132 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(0xFFFFFFFF)) );
8133 DIP("std\n");
8134 break;
8135
sewardjc9a65702004-07-07 16:32:57 +00008136//-- case 0xF8: /* CLC */
8137//-- uInstr0(cb, CALLM_S, 0);
8138//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CLC));
8139//-- uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
8140//-- uInstr0(cb, CALLM_E, 0);
8141//-- DIP("clc\n");
8142//-- break;
8143//--
8144//-- case 0xF9: /* STC */
8145//-- uInstr0(cb, CALLM_S, 0);
8146//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_STC));
8147//-- uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
8148//-- uInstr0(cb, CALLM_E, 0);
8149//-- DIP("stc\n");
8150//-- break;
8151//--
8152//-- case 0xF5: /* CMC */
8153//-- uInstr0(cb, CALLM_S, 0);
8154//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CMC));
8155//-- uFlagsRWU(cb, FlagC, FlagC, FlagsOSZAP);
8156//-- uInstr0(cb, CALLM_E, 0);
8157//-- DIP("cmc\n");
8158//-- break;
sewardj82292882004-07-27 00:15:59 +00008159
8160 /* REPNE prefix insn */
8161 case 0xF2: {
8162 Addr32 eip_orig = guest_eip + delta - 1;
8163 vassert(sorb == 0);
8164 abyte = getIByte(delta); delta++;
8165
8166 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
8167 *isEnd = True;
8168
8169 switch (abyte) {
8170 /* According to the Intel manual, "repne movs" should never occur, but
8171 * in practice it has happened, so allow for it here... */
sewardj180e8b32004-07-29 01:40:11 +00008172 case 0xA4: sz = 1; /* REPNE MOVS<sz> */
sewardjc4be80c2004-09-10 16:17:45 +00008173 vassert(0);
sewardjc9a65702004-07-07 16:32:57 +00008174//-- case 0xA5:
sewardj180e8b32004-07-29 01:40:11 +00008175 // dis_REP_op ( CondNZ, dis_MOVS, sz, eip_orig,
8176 // guest_eip+delta, "repne movs" );
8177 // break;
sewardjc9a65702004-07-07 16:32:57 +00008178//--
8179//-- case 0xA6: sz = 1; /* REPNE CMPS<sz> */
8180//-- case 0xA7:
8181//-- dis_REP_op ( cb, CondNZ, dis_CMPS, sz, eip_orig, eip, "repne cmps" );
8182//-- break;
8183//--
sewardj82292882004-07-27 00:15:59 +00008184 case 0xAE: sz = 1; /* REPNE SCAS<sz> */
sewardj2d4c3a02004-10-15 00:03:23 +00008185 case 0xAF:
sewardj82292882004-07-27 00:15:59 +00008186 dis_REP_op ( CondNZ, dis_SCAS, sz, eip_orig,
8187 guest_eip+delta, "repne scas" );
8188 break;
8189
8190 default:
8191 goto decode_failure;
8192 }
8193 break;
8194 }
sewardj64e1d652004-07-12 14:00:46 +00008195
8196 /* REP/REPE prefix insn (for SCAS and CMPS, 0xF3 means REPE,
8197 for the rest, it means REP) */
8198 case 0xF3: {
8199 Addr32 eip_orig = guest_eip + delta - 1;
8200 vassert(sorb == 0);
8201 abyte = getIByte(delta); delta++;
8202
8203 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
8204 *isEnd = True;
8205
8206 switch (abyte) {
8207 case 0xA4: sz = 1; /* REP MOVS<sz> */
8208 case 0xA5:
8209 dis_REP_op ( CondAlways, dis_MOVS, sz, eip_orig,
8210 guest_eip+delta, "rep movs" );
8211 break;
8212
8213 case 0xA6: sz = 1; /* REPE CMP<sz> */
sewardj2d4c3a02004-10-15 00:03:23 +00008214 case 0xA7:
sewardj64e1d652004-07-12 14:00:46 +00008215 dis_REP_op ( CondZ, dis_CMPS, sz, eip_orig,
8216 guest_eip+delta, "repe cmps" );
8217 break;
8218
8219 case 0xAA: sz = 1; /* REP STOS<sz> */
8220 case 0xAB:
8221 dis_REP_op ( CondAlways, dis_STOS, sz, eip_orig,
8222 guest_eip+delta, "rep stos" );
8223 break;
sewardjc9a65702004-07-07 16:32:57 +00008224//--
8225//-- case 0xAE: sz = 1; /* REPE SCAS<sz> */
8226//-- case 0xAF:
8227//-- dis_REP_op ( cb, CondZ, dis_SCAS, sz, eip_orig, eip, "repe scas" );
8228//-- break;
8229//--
8230//-- case 0x90: /* REP NOP (PAUSE) */
8231//-- /* a hint to the P4 re spin-wait loop */
8232//-- DIP("rep nop (P4 pause)\n");
8233//-- jmp_lit(cb, eip);
8234//-- LAST_UINSTR(cb).jmpkind = JmpYield;
8235//-- break;
8236//--
8237//-- case 0xC3: /* REP RET */
8238//-- /* AMD K7/K8-specific optimisation; faster than vanilla RET */
8239//-- dis_ret(cb, 0);
8240//-- DIP("rep ret\n");
8241//-- break;
sewardj64e1d652004-07-12 14:00:46 +00008242
8243 default:
8244 goto decode_failure;
8245 }
8246 break;
8247 }
sewardj0611d802004-07-11 02:37:54 +00008248
8249 /* ------------------------ XCHG ----------------------- */
8250
8251 case 0x86: /* XCHG Gb,Eb */
8252 sz = 1;
8253 /* Fall through ... */
8254 case 0x87: /* XCHG Gv,Ev */
8255 modrm = getIByte(delta);
8256 ty = szToITy(sz);
8257 t1 = newTemp(ty); t2 = newTemp(ty);
8258 if (epartIsReg(modrm)) {
8259 assign(t1, getIReg(sz, eregOfRM(modrm)));
8260 assign(t2, getIReg(sz, gregOfRM(modrm)));
8261 putIReg(sz, gregOfRM(modrm), mkexpr(t1));
8262 putIReg(sz, eregOfRM(modrm), mkexpr(t2));
8263 delta++;
8264 DIP("xchg%c %s, %s\n",
8265 nameISize(sz), nameIReg(sz,gregOfRM(modrm)),
8266 nameIReg(sz,eregOfRM(modrm)));
8267 } else {
sewardj0c12ea82004-07-12 08:18:16 +00008268 addr = disAMode ( &alen, sorb, delta, dis_buf );
8269 assign( t1, loadLE(ty,mkexpr(addr)) );
8270 assign( t2, getIReg(sz,gregOfRM(modrm)) );
8271 storeLE( mkexpr(addr), mkexpr(t2) );
8272 putIReg( sz, gregOfRM(modrm), mkexpr(t1) );
8273 delta += alen;
sewardj0611d802004-07-11 02:37:54 +00008274 DIP("xchg%c %s, %s\n", nameISize(sz),
8275 nameIReg(sz,gregOfRM(modrm)), dis_buf);
sewardj0611d802004-07-11 02:37:54 +00008276 }
8277 break;
sewardje87b4842004-07-10 12:23:30 +00008278
8279 case 0x90: /* XCHG eAX,eAX */
8280 DIP("nop\n");
8281 break;
sewardj64e1d652004-07-12 14:00:46 +00008282 case 0x91: /* XCHG eAX,eCX */
8283 case 0x92: /* XCHG eAX,eDX */
8284 case 0x93: /* XCHG eAX,eBX */
8285 case 0x94: /* XCHG eAX,eSP */
8286 case 0x95: /* XCHG eAX,eBP */
8287 case 0x96: /* XCHG eAX,eSI */
8288 case 0x97: /* XCHG eAX,eDI */
8289 codegen_xchg_eAX_Reg ( sz, opc - 0x90 );
8290 break;
8291
sewardjc9a65702004-07-07 16:32:57 +00008292//-- /* ------------------------ XLAT ----------------------- */
8293//--
8294//-- case 0xD7: /* XLAT */
8295//-- t1 = newTemp(cb); t2 = newTemp(cb);
8296//-- uInstr2(cb, GET, sz, ArchReg, R_EBX, TempReg, t1); /* get eBX */
8297//-- handleSegOverride( cb, sorb, t1 ); /* make t1 DS:eBX */
8298//-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t2); /* get AL */
8299//-- /* Widen %AL to 32 bits, so it's all defined when we add it. */
8300//-- uInstr1(cb, WIDEN, 4, TempReg, t2);
8301//-- uWiden(cb, 1, False);
8302//-- uInstr2(cb, ADD, sz, TempReg, t2, TempReg, t1); /* add AL to eBX */
8303//-- uInstr2(cb, LOAD, 1, TempReg, t1, TempReg, t2); /* get byte at t1 into t2 */
8304//-- uInstr2(cb, PUT, 1, TempReg, t2, ArchReg, R_AL); /* put byte into AL */
8305//--
8306//-- DIP("xlat%c [ebx]\n", nameISize(sz));
8307//-- break;
8308//--
8309//-- /* ------------------------ IN / OUT ----------------------- */
8310//--
8311//-- case 0xE4: /* IN ib, %al */
8312//-- case 0xE5: /* IN ib, %{e}ax */
8313//-- case 0xEC: /* IN (%dx),%al */
8314//-- case 0xED: /* IN (%dx),%{e}ax */
8315//-- t1 = newTemp(cb);
8316//-- t2 = newTemp(cb);
8317//-- t3 = newTemp(cb);
8318//--
8319//-- uInstr0(cb, CALLM_S, 0);
8320//-- /* operand size? */
8321//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
8322//-- uLiteral(cb, ( opc == 0xE4 || opc == 0xEC ) ? 1 : sz);
8323//-- uInstr1(cb, PUSH, 4, TempReg, t1);
8324//-- /* port number ? */
8325//-- if ( opc == 0xE4 || opc == 0xE5 ) {
8326//-- abyte = getUChar(eip); eip++;
8327//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
8328//-- uLiteral(cb, abyte);
8329//-- }
8330//-- else
8331//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
8332//--
8333//-- uInstr1(cb, PUSH, 4, TempReg, t2);
8334//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_IN));
8335//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
8336//-- uInstr1(cb, POP, 4, TempReg, t2);
8337//-- uInstr1(cb, CLEAR, 0, Lit16, 4);
8338//-- uInstr0(cb, CALLM_E, 0);
8339//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EAX);
8340//-- if ( opc == 0xE4 || opc == 0xE5 ) {
8341//-- DIP("in 0x%x, %%eax/%%ax/%%al\n", getUChar(eip-1) );
8342//-- } else {
8343//-- DIP("in (%%dx), %%eax/%%ax/%%al\n");
8344//-- }
8345//-- break;
8346//-- case 0xE6: /* OUT %al,ib */
8347//-- case 0xE7: /* OUT %{e}ax,ib */
8348//-- case 0xEE: /* OUT %al,(%dx) */
8349//-- case 0xEF: /* OUT %{e}ax,(%dx) */
8350//-- t1 = newTemp(cb);
8351//-- t2 = newTemp(cb);
8352//-- t3 = newTemp(cb);
8353//--
8354//-- uInstr0(cb, CALLM_S, 0);
8355//-- /* operand size? */
8356//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
8357//-- uLiteral(cb, ( opc == 0xE6 || opc == 0xEE ) ? 1 : sz);
8358//-- uInstr1(cb, PUSH, 4, TempReg, t1);
8359//-- /* port number ? */
8360//-- if ( opc == 0xE6 || opc == 0xE7 ) {
8361//-- abyte = getUChar(eip); eip++;
8362//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
8363//-- uLiteral(cb, abyte);
8364//-- }
8365//-- else
8366//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
8367//-- uInstr1(cb, PUSH, 4, TempReg, t2);
8368//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t3);
8369//-- uInstr1(cb, PUSH, 4, TempReg, t3);
8370//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_OUT));
8371//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
8372//-- uInstr1(cb, CLEAR, 0, Lit16, 12);
8373//-- uInstr0(cb, CALLM_E, 0);
8374//-- if ( opc == 0xE4 || opc == 0xE5 ) {
8375//-- DIP("out %%eax/%%ax/%%al, 0x%x\n", getUChar(eip-1) );
8376//-- } else {
8377//-- DIP("out %%eax/%%ax/%%al, (%%dx)\n");
8378//-- }
8379//-- break;
sewardj0611d802004-07-11 02:37:54 +00008380
8381 /* ------------------------ (Grp1 extensions) ---------- */
8382
8383 case 0x80: /* Grp1 Ib,Eb */
8384 modrm = getIByte(delta);
8385 am_sz = lengthAMode(delta);
8386 sz = 1;
8387 d_sz = 1;
sewardjc2ac51e2004-07-12 01:03:26 +00008388 d32 = getUChar(delta + am_sz);
sewardj0611d802004-07-11 02:37:54 +00008389 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
8390 break;
sewardje05c42c2004-07-08 20:25:10 +00008391
8392 case 0x81: /* Grp1 Iv,Ev */
8393 modrm = getIByte(delta);
8394 am_sz = lengthAMode(delta);
8395 d_sz = sz;
8396 d32 = getUDisp(d_sz, delta + am_sz);
8397 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
8398 break;
sewardjd1061ab2004-07-08 01:45:30 +00008399
8400 case 0x83: /* Grp1 Ib,Ev */
8401 modrm = getIByte(delta);
8402 am_sz = lengthAMode(delta);
8403 d_sz = 1;
8404 d32 = getSDisp8(delta + am_sz);
8405 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
8406 break;
8407
sewardjc2ac51e2004-07-12 01:03:26 +00008408 /* ------------------------ (Grp2 extensions) ---------- */
8409
8410 case 0xC0: /* Grp2 Ib,Eb */
8411 modrm = getIByte(delta);
8412 am_sz = lengthAMode(delta);
8413 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +00008414 d32 = getUChar(delta + am_sz);
sewardjc2ac51e2004-07-12 01:03:26 +00008415 sz = 1;
sewardj6d2638e2004-07-15 09:38:27 +00008416 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
8417 mkU8(d32 & 0xFF), NULL );
sewardjc2ac51e2004-07-12 01:03:26 +00008418 break;
sewardje90ad6a2004-07-10 19:02:10 +00008419
8420 case 0xC1: /* Grp2 Ib,Ev */
sewardjc2ac51e2004-07-12 01:03:26 +00008421 modrm = getIByte(delta);
sewardje90ad6a2004-07-10 19:02:10 +00008422 am_sz = lengthAMode(delta);
8423 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +00008424 d32 = getUChar(delta + am_sz);
sewardj6d2638e2004-07-15 09:38:27 +00008425 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
8426 mkU8(d32 & 0xFF), NULL );
sewardje90ad6a2004-07-10 19:02:10 +00008427 break;
8428
sewardj180e8b32004-07-29 01:40:11 +00008429 case 0xD0: /* Grp2 1,Eb */
8430 modrm = getIByte(delta);
8431 am_sz = lengthAMode(delta);
8432 d_sz = 0;
8433 d32 = 1;
8434 sz = 1;
8435 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
8436 mkU8(d32), NULL );
8437 break;
sewardjc2ac51e2004-07-12 01:03:26 +00008438
8439 case 0xD1: /* Grp2 1,Ev */
8440 modrm = getUChar(delta);
8441 am_sz = lengthAMode(delta);
8442 d_sz = 0;
8443 d32 = 1;
sewardj6d2638e2004-07-15 09:38:27 +00008444 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
8445 mkU8(d32), NULL );
sewardjc2ac51e2004-07-12 01:03:26 +00008446 break;
8447
sewardj8c7f1ab2004-07-29 20:31:09 +00008448 case 0xD2: /* Grp2 CL,Eb */
8449 modrm = getUChar(delta);
8450 am_sz = lengthAMode(delta);
8451 d_sz = 0;
8452 sz = 1;
8453 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
8454 getIReg(1,R_ECX), "%cl" );
8455 break;
sewardj9334b0f2004-07-10 22:43:54 +00008456
8457 case 0xD3: /* Grp2 CL,Ev */
8458 modrm = getIByte(delta);
8459 am_sz = lengthAMode(delta);
8460 d_sz = 0;
8461 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardj6d2638e2004-07-15 09:38:27 +00008462 getIReg(1,R_ECX), "%cl" );
sewardj9334b0f2004-07-10 22:43:54 +00008463 break;
8464
sewardj940e8c92004-07-11 16:53:24 +00008465 /* ------------------------ (Grp3 extensions) ---------- */
8466
8467 case 0xF6: /* Grp3 Eb */
8468 delta = dis_Grp3 ( sorb, 1, delta );
8469 break;
8470 case 0xF7: /* Grp3 Ev */
8471 delta = dis_Grp3 ( sorb, sz, delta );
8472 break;
8473
sewardjc2ac51e2004-07-12 01:03:26 +00008474 /* ------------------------ (Grp4 extensions) ---------- */
8475
8476 case 0xFE: /* Grp4 Eb */
8477 delta = dis_Grp4 ( sorb, delta );
8478 break;
sewardj0611d802004-07-11 02:37:54 +00008479
8480 /* ------------------------ (Grp5 extensions) ---------- */
8481
8482 case 0xFF: /* Grp5 Ev */
8483 delta = dis_Grp5 ( sorb, sz, delta, isEnd );
8484 break;
sewardje87b4842004-07-10 12:23:30 +00008485
8486 /* ------------------------ Escapes to 2-byte opcodes -- */
8487
8488 case 0x0F: {
8489 opc = getIByte(delta); delta++;
8490 switch (opc) {
8491
sewardjc9a65702004-07-07 16:32:57 +00008492//-- /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
8493//--
8494//-- case 0xBA: /* Grp8 Ib,Ev */
8495//-- modrm = getUChar(eip);
8496//-- am_sz = lengthAMode(eip);
8497//-- d32 = getSDisp8(eip + am_sz);
8498//-- eip = dis_Grp8_BT ( cb, sorb, eip, modrm, am_sz, sz, d32 );
8499//-- break;
sewardjce646f22004-08-31 23:55:54 +00008500
8501 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
8502
8503 case 0xBC: /* BSF Gv,Ev */
8504 delta = dis_bs_E_G ( sorb, sz, delta, True );
8505 break;
8506 case 0xBD: /* BSR Gv,Ev */
8507 delta = dis_bs_E_G ( sorb, sz, delta, False );
8508 break;
sewardj1c4208f2004-08-25 13:25:29 +00008509
8510 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
8511
8512 case 0xC8: /* BSWAP %eax */
8513 case 0xC9:
8514 case 0xCA:
sewardjc9a65702004-07-07 16:32:57 +00008515//-- case 0xCB:
8516//-- case 0xCC:
8517//-- case 0xCD:
sewardj1c4208f2004-08-25 13:25:29 +00008518 case 0xCE:
sewardj1c6f9912004-09-07 10:15:24 +00008519 case 0xCF: /* BSWAP %edi */
sewardj1c4208f2004-08-25 13:25:29 +00008520 /* AFAICS from the Intel docs, this only exists at size 4. */
8521 vassert(sz == 4);
8522 t1 = newTemp(Ity_I32);
8523 t2 = newTemp(Ity_I32);
8524 assign( t1, getIReg(4, opc-0xC8) );
8525
8526 assign( t2,
8527 binop(Iop_Or32,
8528 binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
8529 binop(Iop_Or32,
8530 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
8531 mkU32(0x00FF0000)),
8532 binop(Iop_Or32,
8533 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
8534 mkU32(0x0000FF00)),
8535 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
8536 mkU32(0x000000FF) )
8537 )))
8538 );
8539
8540 putIReg(4, opc-0xC8, mkexpr(t2));
sewardjc9a65702004-07-07 16:32:57 +00008541//-- t1 = newTemp(cb);
8542//-- uInstr2(cb, GET, 4, ArchReg, opc-0xC8, TempReg, t1);
sewardj1c4208f2004-08-25 13:25:29 +00008543//-- uInstr1(cb, BSWAP, 4, TempReg, t1);
sewardjc9a65702004-07-07 16:32:57 +00008544//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, opc-0xC8);
sewardj1c4208f2004-08-25 13:25:29 +00008545 DIP("bswapl %s\n", nameIReg(4, opc-0xC8));
8546 break;
8547
sewardj1c6f9912004-09-07 10:15:24 +00008548 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
8549
8550 case 0xA3: /* BT Gv,Ev */
8551 delta = dis_bt_G_E ( sorb, sz, delta, BtOpNone );
8552 break;
sewardje6709112004-09-10 18:37:18 +00008553 case 0xB3: /* BTR Gv,Ev */
8554 delta = dis_bt_G_E ( sorb, sz, delta, BtOpReset );
8555 break;
sewardj1c6f9912004-09-07 10:15:24 +00008556 case 0xAB: /* BTS Gv,Ev */
8557 delta = dis_bt_G_E ( sorb, sz, delta, BtOpSet );
8558 break;
sewardj4963a422004-10-14 23:34:03 +00008559 case 0xBB: /* BTC Gv,Ev */
8560 delta = dis_bt_G_E ( sorb, sz, delta, BtOpComp );
8561 break;
sewardj458a6f82004-08-25 12:46:02 +00008562
8563 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
8564
sewardj2d4c3a02004-10-15 00:03:23 +00008565 case 0x40:
8566 case 0x41:
sewardj458a6f82004-08-25 12:46:02 +00008567 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
8568 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
8569 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
8570 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
8571 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
8572 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
sewardjce646f22004-08-31 23:55:54 +00008573 case 0x48: /* CMOVSb (cmov negative) */
sewardj458a6f82004-08-25 12:46:02 +00008574 case 0x49: /* CMOVSb (cmov not negative) */
sewardj2d4c3a02004-10-15 00:03:23 +00008575 case 0x4A: /* CMOVP (cmov parity even) */
8576 case 0x4B: /* CMOVNP (cmov parity odd) */
sewardj458a6f82004-08-25 12:46:02 +00008577 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
8578 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
8579 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
8580 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
8581 delta = dis_cmov_E_G(sorb, sz, (Condcode)(opc - 0x40), delta);
8582 break;
8583
8584 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
8585
sewardjc744e872004-08-26 11:24:39 +00008586 case 0xB0: /* CMPXCHG Gb,Eb */
8587 delta = dis_cmpxchg_G_E ( sorb, 1, delta );
8588 break;
sewardj458a6f82004-08-25 12:46:02 +00008589 case 0xB1: /* CMPXCHG Gv,Ev */
8590 delta = dis_cmpxchg_G_E ( sorb, sz, delta );
8591 break;
sewardjc9a65702004-07-07 16:32:57 +00008592//-- case 0xC7: /* CMPXCHG8B Gv */
8593//-- eip = dis_cmpxchg8b ( cb, sorb, eip );
8594//-- break;
8595//--
sewardj588ea762004-09-10 18:56:32 +00008596 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
8597
8598 case 0xA2: /* CPUID */
8599 vex_printf("vex x86->IR: hacked CPUID\n");
8600 putIReg(4, R_EAX, mkU32(0));
8601 putIReg(4, R_EBX, mkU32(0x756e6547));
8602 putIReg(4, R_ECX, mkU32(0x49656e69));
8603 putIReg(4, R_EDX, mkU32(0x6c65746e));
8604 break;
sewardjc9a65702004-07-07 16:32:57 +00008605//-- if (!VG_(cpu_has_feature)(VG_X86_FEAT_CPUID))
8606//-- goto decode_failure;
8607//--
8608//-- t1 = newTemp(cb);
8609//-- t2 = newTemp(cb);
8610//-- t3 = newTemp(cb);
8611//-- t4 = newTemp(cb);
8612//-- uInstr0(cb, CALLM_S, 0);
8613//--
8614//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t1);
8615//-- uInstr1(cb, PUSH, 4, TempReg, t1);
8616//--
8617//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
8618//-- uLiteral(cb, 0);
8619//-- uInstr1(cb, PUSH, 4, TempReg, t2);
8620//--
8621//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t3);
8622//-- uLiteral(cb, 0);
8623//-- uInstr1(cb, PUSH, 4, TempReg, t3);
8624//--
8625//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
8626//-- uLiteral(cb, 0);
8627//-- uInstr1(cb, PUSH, 4, TempReg, t4);
8628//--
8629//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CPUID));
8630//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
8631//--
8632//-- uInstr1(cb, POP, 4, TempReg, t4);
8633//-- uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_EDX);
8634//--
8635//-- uInstr1(cb, POP, 4, TempReg, t3);
8636//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ECX);
8637//--
8638//-- uInstr1(cb, POP, 4, TempReg, t2);
8639//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBX);
8640//--
8641//-- uInstr1(cb, POP, 4, TempReg, t1);
8642//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
8643//--
8644//-- uInstr0(cb, CALLM_E, 0);
8645//-- DIP("cpuid\n");
8646//-- break;
8647//--
sewardj9334b0f2004-07-10 22:43:54 +00008648 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
8649
8650 case 0xB6: /* MOVZXb Eb,Gv */
8651 delta = dis_movx_E_G ( sorb, delta, 1, 4, False );
8652 break;
sewardj940e8c92004-07-11 16:53:24 +00008653 case 0xB7: /* MOVZXw Ew,Gv */
8654 delta = dis_movx_E_G ( sorb, delta, 2, 4, False );
8655 break;
8656
sewardj0611d802004-07-11 02:37:54 +00008657 case 0xBE: /* MOVSXb Eb,Gv */
8658 delta = dis_movx_E_G ( sorb, delta, 1, 4, True );
8659 break;
sewardj7ed22952004-07-29 00:09:58 +00008660 case 0xBF: /* MOVSXw Ew,Gv */
8661 delta = dis_movx_E_G ( sorb, delta, 2, 4, True );
8662 break;
8663
sewardjc9a65702004-07-07 16:32:57 +00008664//-- /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
8665//--
8666//-- case 0xC3: /* MOVNTI Gv,Ev */
8667//-- vg_assert(sz == 4);
8668//-- modrm = getUChar(eip);
8669//-- vg_assert(!epartIsReg(modrm));
8670//-- t1 = newTemp(cb);
8671//-- uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
8672//-- pair = disAMode ( cb, sorb, eip, dis_buf );
8673//-- t2 = LOW24(pair);
8674//-- eip += HI8(pair);
8675//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
8676//-- DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
8677//-- break;
sewardjcf780b42004-07-13 18:42:17 +00008678
8679 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
8680
8681 case 0xAF: /* IMUL Ev, Gv */
8682 delta = dis_mul_E_G ( sorb, sz, delta, True );
8683 break;
sewardje87b4842004-07-10 12:23:30 +00008684
8685 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
8686 case 0x80:
8687 case 0x81:
8688 case 0x82: /* JBb/JNAEb (jump below) */
8689 case 0x83: /* JNBb/JAEb (jump not below) */
8690 case 0x84: /* JZb/JEb (jump zero) */
8691 case 0x85: /* JNZb/JNEb (jump not zero) */
8692 case 0x86: /* JBEb/JNAb (jump below or equal) */
8693 case 0x87: /* JNBEb/JAb (jump not below or equal) */
8694 case 0x88: /* JSb (jump negative) */
8695 case 0x89: /* JSb (jump not negative) */
8696 case 0x8A: /* JP (jump parity even) */
8697 case 0x8B: /* JNP/JPO (jump parity odd) */
8698 case 0x8C: /* JLb/JNGEb (jump less) */
8699 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
8700 case 0x8E: /* JLEb/JNGb (jump less or equal) */
8701 case 0x8F: /* JGb/JNLEb (jump greater) */
8702 d32 = (((Addr32)guest_code)+delta+4) + getUDisp32(delta);
8703 delta += 4;
8704 jcc_01((Condcode)(opc - 0x80), (Addr32)(guest_code+delta), d32);
8705 *isEnd = True;
8706 DIP("j%s-32 0x%x\n", name_Condcode(opc - 0x80), d32);
8707 break;
8708
sewardj89cd0932004-09-08 18:23:25 +00008709
8710 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
8711
8712 case 0x31: /* RDTSC */
8713 vex_printf("vex x86->IR: kludged rdtsc\n");
8714 putIReg(4, R_EAX, mkU32(0));
8715 putIReg(4, R_EDX, mkU32(0));
8716
sewardjc9a65702004-07-07 16:32:57 +00008717//-- t1 = newTemp(cb);
8718//-- t2 = newTemp(cb);
8719//-- t3 = newTemp(cb);
8720//-- uInstr0(cb, CALLM_S, 0);
8721//-- // Nb: even though these args aren't used by RDTSC_helper, need
8722//-- // them to be defined (for Memcheck). The TempRegs pushed must
8723//-- // also be distinct.
8724//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
8725//-- uLiteral(cb, 0);
8726//-- uInstr1(cb, PUSH, 4, TempReg, t1);
8727//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
8728//-- uLiteral(cb, 0);
8729//-- uInstr1(cb, PUSH, 4, TempReg, t2);
8730//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_RDTSC));
8731//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
8732//-- uInstr1(cb, POP, 4, TempReg, t3);
8733//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EDX);
8734//-- uInstr1(cb, POP, 4, TempReg, t3);
8735//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EAX);
8736//-- uInstr0(cb, CALLM_E, 0);
sewardj89cd0932004-09-08 18:23:25 +00008737 DIP("rdtsc\n");
8738 break;
sewardj77b86be2004-07-11 13:28:24 +00008739
8740 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
8741 case 0x90:
8742 case 0x91:
8743 case 0x92: /* set-Bb/set-NAEb (jump below) */
8744 case 0x93: /* set-NBb/set-AEb (jump not below) */
8745 case 0x94: /* set-Zb/set-Eb (jump zero) */
8746 case 0x95: /* set-NZb/set-NEb (jump not zero) */
8747 case 0x96: /* set-BEb/set-NAb (jump below or equal) */
8748 case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
8749 case 0x98: /* set-Sb (jump negative) */
8750 case 0x99: /* set-Sb (jump not negative) */
8751 case 0x9A: /* set-P (jump parity even) */
8752 case 0x9B: /* set-NP (jump parity odd) */
8753 case 0x9C: /* set-Lb/set-NGEb (jump less) */
8754 case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
8755 case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
8756 case 0x9F: /* set-Gb/set-NLEb (jump greater) */
8757 t1 = newTemp(Ity_I8);
8758 assign( t1, unop(Iop_1Uto8,calculate_condition(opc-0x90)) );
8759 modrm = getIByte(delta);
8760 if (epartIsReg(modrm)) {
8761 delta++;
8762 putIReg(1, eregOfRM(modrm), mkexpr(t1));
8763 DIP("set%s %s\n", name_Condcode(opc-0x90),
8764 nameIReg(1,eregOfRM(modrm)));
8765 } else {
sewardj750f4072004-07-26 22:39:11 +00008766 addr = disAMode ( &alen, sorb, delta, dis_buf );
8767 delta += alen;
8768 storeLE( mkexpr(addr), mkexpr(t1) );
8769 DIP("set%s %s\n", name_Condcode(opc-0x90), dis_buf);
sewardj77b86be2004-07-11 13:28:24 +00008770 }
8771 break;
8772
sewardj180e8b32004-07-29 01:40:11 +00008773 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
8774
8775 case 0xA4: /* SHLDv imm8,Gv,Ev */
8776 modrm = getIByte(delta);
8777 d32 = delta + lengthAMode(delta);
8778 vex_sprintf(dis_buf, "$%d", delta);
8779 delta = dis_SHLRD_Gv_Ev (
8780 sorb, delta, modrm, sz,
8781 mkU8(getIByte(d32)), True, /* literal */
8782 dis_buf, True );
8783 break;
sewardja06e5562004-07-14 13:18:05 +00008784 case 0xA5: /* SHLDv %cl,Gv,Ev */
8785 modrm = getIByte(delta);
8786 delta = dis_SHLRD_Gv_Ev (
8787 sorb, delta, modrm, sz,
8788 getIReg(1,R_ECX), False, /* not literal */
8789 "%cl", True );
8790 break;
8791
sewardj68511542004-07-28 00:15:44 +00008792 case 0xAC: /* SHRDv imm8,Gv,Ev */
8793 modrm = getIByte(delta);
8794 d32 = delta + lengthAMode(delta);
8795 vex_sprintf(dis_buf, "$%d", delta);
8796 delta = dis_SHLRD_Gv_Ev (
8797 sorb, delta, modrm, sz,
8798 mkU8(getIByte(d32)), True, /* literal */
8799 dis_buf, False );
8800 break;
sewardja511afc2004-07-29 22:26:03 +00008801 case 0xAD: /* SHRDv %cl,Gv,Ev */
8802 modrm = getIByte(delta);
8803 delta = dis_SHLRD_Gv_Ev (
8804 sorb, delta, modrm, sz,
8805 getIReg(1,R_ECX), False, /* not literal */
8806 "%cl", False );
8807 break;
8808
sewardj883b00b2004-09-11 09:30:24 +00008809//-- /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
sewardjc9a65702004-07-07 16:32:57 +00008810//--
8811//-- case 0xC0: /* XADD Gb,Eb */
8812//-- eip = dis_xadd_G_E ( cb, sorb, 1, eip );
8813//-- break;
sewardj883b00b2004-09-11 09:30:24 +00008814 case 0xC1: /* XADD Gv,Ev */
8815 delta = dis_xadd_G_E ( sorb, sz, delta );
8816 break;
8817
sewardjc9a65702004-07-07 16:32:57 +00008818//-- /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
8819//--
8820//-- case 0x0D: /* PREFETCH / PREFETCHW - 3Dnow!ery*/
8821//-- case 0x18: /* PREFETCHT0/PREFETCHT1/PREFETCHT2/PREFETCHNTA */
8822//--
8823//-- vg_assert(sz == 4);
8824//-- modrm = getUChar(eip);
8825//-- if (epartIsReg(modrm)) {
8826//-- goto decode_failure;
8827//-- }
8828//-- if (gregOfRM(modrm) > 3) {
8829//-- goto decode_failure;
8830//-- }
8831//-- eip += lengthAMode(eip);
8832//-- if (VG_(print_codegen)) {
8833//-- UChar* hintstr;
8834//-- if (opc == 0x0D) {
8835//-- switch (gregOfRM(modrm)) {
8836//-- case 0: hintstr = ""; break;
8837//-- case 1: hintstr = "w"; break;
8838//-- default: goto decode_failure;
8839//-- }
8840//-- }
8841//-- else {
8842//-- switch (gregOfRM(modrm)) {
8843//-- case 0: hintstr = "nta"; break;
8844//-- case 1: hintstr = "t0"; break;
8845//-- case 2: hintstr = "t1"; break;
8846//-- case 3: hintstr = "t2"; break;
8847//-- default: goto decode_failure;
8848//-- }
8849//-- }
8850//-- VG_(printf)("prefetch%s ...\n", hintstr);
8851//-- }
8852//-- break;
8853//--
8854//-- case 0x71: case 0x72: case 0x73: {
8855//-- /* (sz==4): PSLL/PSRA/PSRL mmxreg by imm8 */
8856//-- /* (sz==2): PSLL/PSRA/PSRL xmmreg by imm8 */
8857//-- UChar byte1, byte2, byte3, subopc, mmreg;
8858//-- vg_assert(sz == 4 || sz == 2);
8859//-- byte1 = opc; /* 0x71/72/73 */
8860//-- byte2 = getUChar(eip); eip++; /* amode / sub-opcode */
8861//-- byte3 = getUChar(eip); eip++; /* imm8 */
8862//-- mmreg = byte2 & 7;
8863//-- subopc = (byte2 >> 3) & 7;
8864//-- if (subopc == 2 || subopc == 6 || subopc == 4) {
8865//-- /* 2 == 010 == SRL, 6 == 110 == SLL, 4 == 100 == SRA */
8866//-- /* ok */
8867//-- } else
8868//-- if (sz == 2 && opc == 0x73 && (subopc == 7 || subopc == 3)) {
8869//-- /* 3 == PSRLDQ, 7 == PSLLDQ */
8870//-- /* This is allowable in SSE. Because sz==2 we fall thru to
8871//-- SSE5 below. */
8872//-- } else {
8873//-- eip -= (sz==2 ? 3 : 2);
8874//-- goto decode_failure;
8875//-- }
8876//-- if (sz == 4) {
8877//-- /* The leading 0x0F is implied for MMX*, so we don't
8878//-- include it. */
8879//-- uInstr2(cb, MMX3, 0,
8880//-- Lit16, (((UShort)byte1) << 8) | ((UShort)byte2),
8881//-- Lit16, ((UShort)byte3) );
8882//-- DIP("ps%s%s $%d, %s\n",
8883//-- ( subopc == 2 ? "rl"
8884//-- : subopc == 6 ? "ll"
8885//-- : subopc == 4 ? "ra"
8886//-- : "??"),
8887//-- nameMMXGran(opc & 3), (Int)byte3, nameMMXReg(mmreg) );
8888//-- } else {
8889//-- /* Whereas we have to include it for SSE. */
8890//-- uInstr3(cb, SSE5, 0,
8891//-- Lit16, (((UShort)0x66) << 8) | ((UShort)0x0F),
8892//-- Lit16, (((UShort)byte1) << 8) | ((UShort)byte2),
8893//-- Lit16, ((UShort)byte3) );
8894//-- DIP("ps%s%s $%d, %s\n",
8895//-- ( subopc == 2 ? "rl"
8896//-- : subopc == 6 ? "ll"
8897//-- : subopc == 4 ? "ra"
8898//-- : subopc == 3 ? "(PSRLDQ)"
8899//-- : subopc == 7 ? "(PSLLDQ)"
8900//-- : "??"),
8901//-- nameMMXGran(opc & 3), (Int)byte3, nameXMMReg(mmreg) );
8902//-- }
8903//-- break;
8904//-- }
8905//--
8906//-- case 0x77: /* EMMS */
8907//-- vg_assert(sz == 4);
8908//-- uInstr1(cb, MMX1, 0, Lit16, ((UShort)(opc)) );
8909//-- DIP("emms\n");
8910//-- break;
8911//--
8912//-- case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
8913//-- vg_assert(sz == 4);
8914//-- modrm = getUChar(eip);
8915//-- if (epartIsReg(modrm)) {
8916//-- eip++;
8917//-- t1 = newTemp(cb);
8918//-- uInstr2(cb, MMX2_ERegWr, 4,
8919//-- Lit16,
8920//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
8921//-- TempReg, t1 );
8922//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, eregOfRM(modrm));
8923//-- DIP("movd %s, %s\n",
8924//-- nameMMXReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
8925//-- } else {
8926//-- Int tmpa;
8927//-- pair = disAMode ( cb, sorb, eip, dis_buf );
8928//-- tmpa = LOW24(pair);
8929//-- eip += HI8(pair);
8930//-- uInstr2(cb, MMX2_MemWr, 4,
8931//-- Lit16,
8932//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
8933//-- TempReg, tmpa);
8934//-- DIP("movd %s, %s\n", nameMMXReg(gregOfRM(modrm)), dis_buf);
8935//-- }
8936//-- break;
8937//--
8938//-- case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
8939//-- vg_assert(sz == 4);
8940//-- modrm = getUChar(eip);
8941//-- if (epartIsReg(modrm)) {
8942//-- eip++;
8943//-- t1 = newTemp(cb);
8944//-- uInstr2(cb, GET, 4, ArchReg, eregOfRM(modrm), TempReg, t1);
8945//-- uInstr2(cb, MMX2_ERegRd, 4,
8946//-- Lit16,
8947//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
8948//-- TempReg, t1 );
8949//-- DIP("movd %s, %s\n",
8950//-- nameIReg(4,eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
8951//-- } else {
8952//-- Int tmpa;
8953//-- pair = disAMode ( cb, sorb, eip, dis_buf );
8954//-- tmpa = LOW24(pair);
8955//-- eip += HI8(pair);
8956//-- uInstr2(cb, MMX2_MemRd, 4,
8957//-- Lit16,
8958//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
8959//-- TempReg, tmpa);
8960//-- DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregOfRM(modrm)));
8961//-- }
8962//-- break;
8963//--
8964//-- case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
8965//-- vg_assert(sz == 4);
8966//-- modrm = getUChar(eip);
8967//-- if (epartIsReg(modrm)) {
8968//-- eip++;
8969//-- uInstr1(cb, MMX2, 0,
8970//-- Lit16,
8971//-- (((UShort)(opc)) << 8) | ((UShort)modrm) );
8972//-- DIP("movq %s, %s\n",
8973//-- nameMMXReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
8974//-- } else {
8975//-- Int tmpa;
8976//-- pair = disAMode ( cb, sorb, eip, dis_buf );
8977//-- tmpa = LOW24(pair);
8978//-- eip += HI8(pair);
8979//-- uInstr2(cb, MMX2_MemRd, 8,
8980//-- Lit16,
8981//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
8982//-- TempReg, tmpa);
8983//-- DIP("movq %s, %s\n",
8984//-- dis_buf, nameMMXReg(gregOfRM(modrm)));
8985//-- }
8986//-- break;
8987//--
8988//-- case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
8989//-- case 0xE7: /* MOVNTQ (src)mmxreg, (dst)mmxreg-or-mem */
8990//-- vg_assert(sz == 4);
8991//-- modrm = getUChar(eip);
8992//-- if (epartIsReg(modrm)) {
8993//-- eip++;
8994//-- uInstr1(cb, MMX2, 0,
8995//-- Lit16,
8996//-- (((UShort)(opc)) << 8) | ((UShort)modrm) );
8997//-- DIP("movq %s, %s\n",
8998//-- nameMMXReg(gregOfRM(modrm)), nameMMXReg(eregOfRM(modrm)));
8999//-- } else {
9000//-- Int tmpa;
9001//-- pair = disAMode ( cb, sorb, eip, dis_buf );
9002//-- tmpa = LOW24(pair);
9003//-- eip += HI8(pair);
9004//-- uInstr2(cb, MMX2_MemWr, 8,
9005//-- Lit16,
9006//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
9007//-- TempReg, tmpa);
9008//-- DIP("mov(nt)q %s, %s\n",
9009//-- nameMMXReg(gregOfRM(modrm)), dis_buf);
9010//-- }
9011//-- break;
9012//--
9013//-- case 0xFC: case 0xFD: case 0xFE:
9014//-- /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
9015//-- vg_assert(sz == 4);
9016//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "padd", True );
9017//-- break;
9018//--
9019//-- case 0xD4:
9020//-- /* PADDQ (src)mmxreg-or-mem, (dst)mmxreg */
9021//-- vg_assert(sz == 4);
9022//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "paddq", False );
9023//-- break;
9024//--
9025//-- case 0xEC: case 0xED:
9026//-- /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
9027//-- vg_assert(sz == 4);
9028//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "padds", True );
9029//-- break;
9030//--
9031//-- case 0xDC: case 0xDD:
9032//-- /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
9033//-- vg_assert(sz == 4);
9034//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "paddus", True );
9035//-- break;
9036//--
9037//-- case 0xF8: case 0xF9: case 0xFA: case 0xFB:
9038//-- /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
9039//-- vg_assert(sz == 4);
9040//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psub", True );
9041//-- break;
9042//--
9043//-- case 0xE8: case 0xE9:
9044//-- /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
9045//-- vg_assert(sz == 4);
9046//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psubs", True );
9047//-- break;
9048//--
9049//-- case 0xD8: case 0xD9:
9050//-- /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
9051//-- vg_assert(sz == 4);
9052//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psubus", True );
9053//-- break;
9054//--
9055//-- case 0xE4: /* PMULHUW (src)mmxreg-or-mem, (dst)mmxreg */
9056//-- vg_assert(sz == 4);
9057//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmulhuw", False );
9058//-- break;
9059//--
9060//-- case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
9061//-- vg_assert(sz == 4);
9062//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmulhw", False );
9063//-- break;
9064//--
9065//-- case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
9066//-- vg_assert(sz == 4);
9067//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmullw", False );
9068//-- break;
9069//--
9070//-- case 0xF4: /* PMULUDQ (src)mmxreg-or-mem, (dst)mmxreg */
9071//-- vg_assert(sz == 4);
9072//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmuludq", False );
9073//-- break;
9074//--
9075//-- case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
9076//-- vg_assert(sz == 4);
9077//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmaddwd", False );
9078//-- break;
9079//--
9080//-- case 0x74: case 0x75: case 0x76:
9081//-- /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
9082//-- vg_assert(sz == 4);
9083//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pcmpeq", True );
9084//-- break;
9085//--
9086//-- case 0x64: case 0x65: case 0x66:
9087//-- /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
9088//-- vg_assert(sz == 4);
9089//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pcmpgt", True );
9090//-- break;
9091//--
9092//-- case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
9093//-- vg_assert(sz == 4);
9094//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "packssdw", False );
9095//-- break;
9096//--
9097//-- case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
9098//-- vg_assert(sz == 4);
9099//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "packsswb", False );
9100//-- break;
9101//--
9102//-- case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
9103//-- vg_assert(sz == 4);
9104//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "packuswb", False );
9105//-- break;
9106//--
9107//-- case 0x68: case 0x69: case 0x6A:
9108//-- /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
9109//-- vg_assert(sz == 4);
9110//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "punpckh", True );
9111//-- break;
9112//--
9113//-- case 0x60: case 0x61: case 0x62:
9114//-- /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
9115//-- vg_assert(sz == 4);
9116//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "punpckl", True );
9117//-- break;
9118//--
9119//-- case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
9120//-- vg_assert(sz == 4);
9121//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pand", False );
9122//-- break;
9123//--
9124//-- case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
9125//-- vg_assert(sz == 4);
9126//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pandn", False );
9127//-- break;
9128//--
9129//-- case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
9130//-- vg_assert(sz == 4);
9131//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "por", False );
9132//-- break;
9133//--
9134//-- case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
9135//-- vg_assert(sz == 4);
9136//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pxor", False );
9137//-- break;
9138//--
9139//-- case 0xF1: case 0xF2: case 0xF3:
9140//-- /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
9141//-- vg_assert(sz == 4);
9142//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psll", True );
9143//-- break;
9144//--
9145//-- case 0xD1: case 0xD2: case 0xD3:
9146//-- /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
9147//-- vg_assert(sz == 4);
9148//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psrl", True );
9149//-- break;
9150//--
9151//-- case 0xE1: case 0xE2:
9152//-- /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
9153//-- vg_assert(sz == 4);
9154//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psra", True );
9155//-- break;
9156//--
9157//-- case 0xDA:
9158//-- /* PMINUB (src)mmxreg-or-mem, (dst)mmxreg */
9159//-- vg_assert(sz == 4);
9160//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pminub", False );
9161//-- break;
9162//--
9163//-- case 0xDE:
9164//-- /* PMAXUB (src)mmxreg-or-mem, (dst)mmxreg */
9165//-- vg_assert(sz == 4);
9166//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmaxub", False );
9167//-- break;
9168//--
9169//-- case 0xEA:
9170//-- /* PMINSW (src)mmxreg-or-mem, (dst)mmxreg */
9171//-- vg_assert(sz == 4);
9172//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pminsw", False );
9173//-- break;
9174//--
9175//-- case 0xEE:
9176//-- /* PMAXSW (src)mmxreg-or-mem, (dst)mmxreg */
9177//-- vg_assert(sz == 4);
9178//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmaxsw", False );
9179//-- break;
9180//--
9181//-- case 0xE0:
9182//-- /* PAVGB (src)mmxreg-or-mem, (dst)mmxreg */
9183//-- vg_assert(sz == 4);
9184//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pavgb", False );
9185//-- break;
9186//--
9187//-- case 0xE3:
9188//-- /* PAVGW (src)mmxreg-or-mem, (dst)mmxreg */
9189//-- vg_assert(sz == 4);
9190//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pavgw", False );
9191//-- break;
9192//--
9193//-- case 0xF6:
9194//-- /* PSADBW (src)mmxreg-or-mem, (dst)mmxreg */
9195//-- vg_assert(sz == 4);
9196//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psadbw", False );
9197//-- break;
9198//--
9199//-- case 0x70:
9200//-- /* PSHUFW imm8, (src)mmxreg-or-mem, (dst)mmxreg */
9201//-- vg_assert(sz == 4);
9202//-- eip = dis_MMXop_regmem_to_reg_Imm8 ( cb, sorb, eip, opc, "pshufw", False );
9203//-- break;
9204//--
9205//-- case 0xD7:
9206//-- /* PMOVMSKB (src)mmxreg, (dst)ireg */
9207//-- vg_assert(sz == 4);
9208//-- modrm = getUChar(eip);
9209//-- vg_assert(epartIsReg(modrm));
9210//-- t1 = newTemp(cb);
9211//-- uInstr3(cb, SSE2g_RegWr, 4,
9212//-- Lit16, (((UShort)(0x0F)) << 8) | (UShort)(opc),
9213//-- Lit16, (UShort)modrm,
9214//-- TempReg, t1 );
9215//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
9216//-- DIP("pmovmskb %s, %s\n",
9217//-- nameMMXReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)));
9218//-- eip++;
9219//-- break;
9220//--
9221//-- case 0xC5:
9222//-- /* PEXTRW (src)mmxreg, (dst)ireg */
9223//-- vg_assert(sz == 4);
9224//-- t1 = newTemp(cb);
9225//-- modrm = getUChar(eip); eip++;
9226//-- abyte = getUChar(eip); eip++;
9227//-- vg_assert(epartIsReg(modrm));
9228//-- uInstr3(cb, SSE2g1_RegWr, 4,
9229//-- Lit16, (((UShort)(0x0F)) << 8) | (UShort)(opc),
9230//-- Lit16, (UShort)modrm,
9231//-- TempReg, t1 );
9232//-- uLiteral(cb, abyte);
9233//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
9234//-- DIP("pextrw %s, %d, %s\n",
9235//-- nameMMXReg(eregOfRM(modrm)), (Int)abyte,
9236//-- nameIReg(4, gregOfRM(modrm)));
9237//-- break;
9238//--
9239//-- case 0xC4:
9240//-- /* PINSRW (src)ireg, (dst)mmxreg */
9241//-- vg_assert(sz == 4);
9242//-- t1 = newTemp(cb);
9243//-- modrm = getUChar(eip); eip++;
9244//-- abyte = getUChar(eip); eip++;
9245//-- vg_assert(epartIsReg(modrm));
9246//-- uInstr2(cb, GET, 2, ArchReg, eregOfRM(modrm), TempReg, t1);
9247//-- uInstr3(cb, SSE2e1_RegRd, 2,
9248//-- Lit16, (((UShort)(0x0F)) << 8) | (UShort)(opc),
9249//-- Lit16, (UShort)modrm,
9250//-- TempReg, t1 );
9251//-- uLiteral(cb, abyte);
9252//-- DIP("pinsrw %s, %d, %s\n", nameIReg(2, eregOfRM(modrm)),
9253//-- (Int)abyte, nameMMXReg(gregOfRM(modrm)));
9254//-- break;
9255//--
9256//-- case 0xA1: /* POP %FS */
9257//-- dis_pop_segreg( cb, R_FS, sz ); break;
9258//-- case 0xA9: /* POP %GS */
9259//-- dis_pop_segreg( cb, R_GS, sz ); break;
9260//--
9261//-- case 0xA0: /* PUSH %FS */
9262//-- dis_push_segreg( cb, R_FS, sz ); break;
9263//-- case 0xA8: /* PUSH %GS */
9264//-- dis_push_segreg( cb, R_GS, sz ); break;
sewardje87b4842004-07-10 12:23:30 +00009265
9266 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
9267
9268 default:
9269 goto decode_failure;
9270 } /* switch (opc) for the 2-byte opcodes */
9271 goto decode_success;
9272 } /* case 0x0F: of primary opcode */
sewardjc9a65702004-07-07 16:32:57 +00009273
9274 /* ------------------------ ??? ------------------------ */
9275
9276 default:
sewardje87b4842004-07-10 12:23:30 +00009277 decode_failure:
sewardjc9a65702004-07-07 16:32:57 +00009278 /* All decode failures end up here. */
9279 vex_printf("disInstr(x86): unhandled instruction bytes: "
9280 "0x%x 0x%x 0x%x 0x%x\n",
9281 (Int)getIByte(delta_start+0),
9282 (Int)getIByte(delta_start+1),
9283 (Int)getIByte(delta_start+2),
9284 (Int)getIByte(delta_start+3) );
9285 vpanic("x86toIR: unimplemented insn");
9286 /* Print address of failing instruction. */
9287 //VG_(describe_eip)((Addr)eip_start, loc_buf, M_VG_ERRTXT);
9288 //VG_(printf)(" at %s\n", loc_buf);
9289
9290 //uInstr0(cb, CALLM_S, 0);
9291 //uInstr1(cb, CALLM, 0, Lit16,
9292 // VGOFF_(helper_undefined_instruction));
9293 //uInstr0(cb, CALLM_E, 0);
9294
9295 /* just because everything else insists the last instruction of
9296 a BB is a jmp */
9297 //jmp_lit(cb, eip);
9298 //*isEnd = True;
9299 //break;
9300 //return eip;
9301
9302 } /* switch (opc) for the main (primary) opcode switch. */
9303
sewardje87b4842004-07-10 12:23:30 +00009304 decode_success:
sewardjc9a65702004-07-07 16:32:57 +00009305 /* All decode successes end up here. */
9306 DIP("\n");
sewardjd7cb8532004-08-17 23:59:23 +00009307 { Int i;
9308 for (i = first_stmt_idx; i < irbb->stmts_used; i++) {
9309 if (print_codegen) {
9310 vex_printf(" ");
9311 ppIRStmt(irbb->stmts[i]);
9312 vex_printf("\n");
9313 }
9314 }
sewardjc9a65702004-07-07 16:32:57 +00009315 }
sewardjd1061ab2004-07-08 01:45:30 +00009316 if (*isEnd) {
9317 vassert(irbb->next != NULL);
sewardje539a402004-07-14 18:24:17 +00009318 if (print_codegen) {
9319 vex_printf(" ");
9320 vex_printf( "goto {");
9321 ppIRJumpKind(irbb->jumpkind);
9322 vex_printf( "} ");
9323 ppIRExpr( irbb->next );
9324 vex_printf( "\n");
9325 }
sewardjd1061ab2004-07-08 01:45:30 +00009326 }
sewardjc9a65702004-07-07 16:32:57 +00009327 //for (; first_uinstr < cb->used; first_uinstr++) {
9328 // Bool sane = VG_(saneUInstr)(True, True, &cb->instrs[first_uinstr]);
9329 // if (!sane)
9330 // VG_(up_UInstr)(first_uinstr, &cb->instrs[first_uinstr]);
9331 // else if (VG_(print_codegen))
9332 // VG_(pp_UInstr)(first_uinstr, &cb->instrs[first_uinstr]);
9333 // vg_assert(sane);
9334 // }
9335 return delta;
9336}
9337
9338
9339/* Disassemble a complete basic block, starting at eip, and dumping
9340 the ucode into cb. Returns the size, in bytes, of the basic
9341 block. */
sewardj41f43bc2004-07-08 14:23:22 +00009342IRBB* bbToIR_X86Instr ( UChar* x86code,
sewardjc9a65702004-07-07 16:32:57 +00009343 Addr64 eip,
9344 Int* guest_bytes_read,
9345 Bool (*byte_accessible)(Addr64),
9346 Bool host_bigendian )
9347{
9348 UInt delta;
9349 Int n_instrs;
9350 Bool isEnd;
9351
9352 /* Set up globals. */
9353 host_is_bigendian = host_bigendian;
9354 print_codegen = (vex_verbosity >= 1);
9355 guest_code = x86code;
9356 guest_eip = (Addr32)eip;
sewardjd7cb8532004-08-17 23:59:23 +00009357 irbb = emptyIRBB();
sewardjc9a65702004-07-07 16:32:57 +00009358
9359 vassert((eip >> 32) == 0);
sewardjb2dc8092004-07-25 17:25:06 +00009360 vassert(vex_guest_insns_per_bb >= 1);
sewardjc9a65702004-07-07 16:32:57 +00009361
9362 DIP("Original x86 code to IR:\n\n");
9363
9364 /* Delta keeps track of how far along the x86code array we
9365 have so far gone. */
9366 isEnd = False;
9367 delta = 0;
9368 n_instrs = 0;
9369 while (True) {
9370 if (isEnd) break;
sewardjb2dc8092004-07-25 17:25:06 +00009371 if (n_instrs == vex_guest_insns_per_bb) {
9372 vassert(irbb->next == NULL);
9373 irbb->next = mkU32(((Addr32)eip)+delta);
9374 break;
9375 }
sewardjc9a65702004-07-07 16:32:57 +00009376 vassert(n_instrs < vex_guest_insns_per_bb);
9377 delta = disInstr ( delta, &isEnd );
9378 n_instrs++;
9379 DIP("\n");
9380 }
9381
sewardjd1061ab2004-07-08 01:45:30 +00009382 *guest_bytes_read = delta;
sewardjc9a65702004-07-07 16:32:57 +00009383 return irbb;
9384}
9385
9386#undef DIP
9387#undef DIS
9388
9389/*--------------------------------------------------------------------*/
sewardjc0ee2ed2004-07-27 10:29:41 +00009390/*--- end guest-x86/toIR.c ---*/
sewardjc9a65702004-07-07 16:32:57 +00009391/*--------------------------------------------------------------------*/