blob: 51de9d44b7989094d2215130e6d7192476b613fb [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
sewardj883b00b2004-09-11 09:30:24 +000014 FUCOMI(P): what happens to A and S flags? Currently are forced
15 to zero.
sewardje166ed02004-10-25 02:27:01 +000016 Fix CPUID, or more precisely, eflags bit 21 so it is changeable.
sewardj3f61ddb2004-10-16 20:51:05 +000017
sewardjce70a5c2004-10-18 14:09:54 +000018 x87 FP Limitations:
sewardj3f61ddb2004-10-16 20:51:05 +000019 * 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.
sewardje166ed02004-10-25 02:27:01 +000024 * some of the FCOM cases could do with testing -- not convinced
25 that the args are the right way round.
sewardje05c42c2004-07-08 20:25:10 +000026*/
27
sewardjc9a65702004-07-07 16:32:57 +000028/* Translates x86 code to IR. */
29
30#include "libvex_basictypes.h"
31#include "libvex_ir.h"
sewardje87b4842004-07-10 12:23:30 +000032#include "libvex.h"
sewardjf6dc3ce2004-10-19 01:03:46 +000033#include "libvex_guest_x86.h"
sewardjc0ee2ed2004-07-27 10:29:41 +000034
35#include "main/vex_util.h"
36#include "main/vex_globals.h"
37#include "guest-x86/gdefs.h"
sewardjc9a65702004-07-07 16:32:57 +000038
39
sewardje166ed02004-10-25 02:27:01 +000040#define RESTEER_THRESH 10
sewardjb4666cf2004-10-23 00:21:50 +000041
42
sewardjc9a65702004-07-07 16:32:57 +000043/*------------------------------------------------------------*/
44/*--- Globals ---*/
45/*------------------------------------------------------------*/
46
47/* These are set at the start of the translation of a BB, so
48 that we don't have to pass them around endlessly. */
49
50/* We need to know this to do sub-register accesses correctly. */
51/* CONST */
52static Bool host_is_bigendian;
53
54/* Are we being verbose? */
55/* CONST */
56static Bool print_codegen;
57
58/* Pointer to the guest code area. */
59/* CONST */
60static UChar* guest_code;
61
62/* The guest address corresponding to guest_code[0]. */
63/* CONST */
sewardjce70a5c2004-10-18 14:09:54 +000064static Addr32 guest_eip_bbstart;
sewardjc9a65702004-07-07 16:32:57 +000065
sewardjd7cb8532004-08-17 23:59:23 +000066/* The IRBB* into which we're generating code. */
sewardjc9a65702004-07-07 16:32:57 +000067static IRBB* irbb;
68
sewardjc9a65702004-07-07 16:32:57 +000069
sewardjce70a5c2004-10-18 14:09:54 +000070/*------------------------------------------------------------*/
71/*--- Debugging output ---*/
72/*------------------------------------------------------------*/
73
74#define DIP(format, args...) \
75 if (print_codegen) \
76 vex_printf(format, ## args)
77
78#define DIS(buf, format, args...) \
79 if (print_codegen) \
80 vex_sprintf(buf, format, ## args)
81
82
83/*------------------------------------------------------------*/
84/*--- Disassemble an entire basic block ---*/
85/*------------------------------------------------------------*/
86
87/* The results of disassembling an instruction. There are three
88 possible outcomes. For Dis_Resteer, the disassembler _must_
89 continue at the specified address. For Dis_StopHere, the
90 disassembler _must_ terminate the BB. For Dis_Continue, we may at
91 our option either disassemble the next insn, or terminate the BB;
92 but in the latter case we must set the bb's ->next field to point
93 to the next instruction. */
94
95typedef
96 enum {
97 Dis_StopHere, /* this insn terminates the BB; we must stop. */
98 Dis_Continue, /* we can optionally continue into the next insn */
99 Dis_Resteer /* followed a branch; continue at the spec'd addr */
100 }
101 DisResult;
102
103
104/* forward decls .. */
105static IRExpr* mkU32 ( UInt i );
106
107/* disInstr disassembles an instruction located at &guest_code[delta],
108 and sets *size to its size. If the returned value is Dis_Resteer,
109 the next guest address is assigned to *whereNext. If chaseJumps
110 is False, disInstr may not return Dis_Resteer. */
111
112static DisResult disInstr ( /*IN*/ Bool resteerOK,
113 /*IN*/ UInt delta,
114 /*OUT*/ UInt* size,
115 /*OUT*/ Addr64* whereNext );
116
117
118/* This is the main (only, in fact) entry point for this module. */
119
120/* Disassemble a complete basic block, starting at eip, and dumping
121 the ucode into cb. Returns the size, in bytes, of the basic
122 block. */
123IRBB* bbToIR_X86Instr ( UChar* x86code,
124 Addr64 guest_eip_start,
125 Int* guest_bytes_read,
126 Bool (*byte_accessible)(Addr64),
127 Bool host_bigendian )
128{
129 UInt delta;
130 Int n_instrs, size;
131 Addr64 guest_next;
132 Bool resteerOK;
133 DisResult dres;
134 static Int n_resteers = 0;
135 Int d_resteers = 0;
sewardjb4666cf2004-10-23 00:21:50 +0000136 Int resteerBelow = RESTEER_THRESH; /* the threshold value */
sewardjce70a5c2004-10-18 14:09:54 +0000137
138 /* Set up globals. */
139 host_is_bigendian = host_bigendian;
140 print_codegen = vex_verbosity >= 1;
141 guest_code = x86code;
142 guest_eip_bbstart = (Addr32)guest_eip_start;
143 irbb = emptyIRBB();
144
145 if (vex_guest_insns_per_bb <= resteerBelow)
146 resteerBelow = vex_guest_insns_per_bb-1;
147
148 vassert((guest_eip_start >> 32) == 0);
149 vassert(vex_guest_insns_per_bb >= 1);
150 vassert(resteerBelow < vex_guest_insns_per_bb);
151 vassert(resteerBelow >= 0);
152 vassert(vex_guest_insns_per_bb);
153
154 DIP("Original x86 code to IR:\n\n");
155
156 /* Delta keeps track of how far along the x86code array we
157 have so far gone. */
158 delta = 0;
159 n_instrs = 0;
160 *guest_bytes_read = 0;
161
162 while (True) {
163 vassert(n_instrs < vex_guest_insns_per_bb);
164
165 guest_next = 0;
166 resteerOK = n_instrs < resteerBelow;
167 dres = disInstr( resteerOK, delta, &size, &guest_next );
168 delta += size;
169 *guest_bytes_read += size;
170 n_instrs++;
171 DIP("\n");
172
173 vassert(size > 0 && size <= 18);
174 if (!resteerOK)
175 vassert(dres != Dis_Resteer);
176 if (dres != Dis_Resteer)
177 vassert(guest_next == 0);
178
179 switch (dres) {
180 case Dis_Continue:
181 vassert(irbb->next == NULL);
182 if (n_instrs < vex_guest_insns_per_bb) {
183 /* keep going */
184 } else {
185 irbb->next = mkU32(((Addr32)guest_eip_start)+delta);
186 return irbb;
187 }
188 break;
189 case Dis_StopHere:
190 vassert(irbb->next != NULL);
191 return irbb;
192 case Dis_Resteer:
193 vassert(irbb->next == NULL);
194 /* figure out a new delta to continue at. */
195 delta = (UInt)(guest_next - guest_eip_start);
196 n_resteers++;
197 d_resteers++;
198 if (0 && (n_resteers & 0xFF) == 0)
199 vex_printf("resteer[%d,%d] to %p (delta = %d)\n",
200 n_resteers, d_resteers,
201 (void*)(UInt)(guest_next), delta);
202 break;
203 }
204 }
205}
206
207
208/*------------------------------------------------------------*/
sewardjf6dc3ce2004-10-19 01:03:46 +0000209/*--- Offsets of various parts of the x86 guest state. ---*/
210/*------------------------------------------------------------*/
211
212#define offsetof(type,memb) ((Int)&((type*)0)->memb)
213
214#define OFFB_FPREGS offsetof(VexGuestX86State,guest_FPREG[0])
215#define OFFB_FPTAGS offsetof(VexGuestX86State,guest_FPTAG[0])
216#define OFFB_EAX offsetof(VexGuestX86State,guest_EAX)
sewardj7cb49d72004-10-24 22:31:25 +0000217#define OFFB_EBX offsetof(VexGuestX86State,guest_EBX)
218#define OFFB_ECX offsetof(VexGuestX86State,guest_ECX)
219#define OFFB_EDX offsetof(VexGuestX86State,guest_EDX)
sewardjf6dc3ce2004-10-19 01:03:46 +0000220#define OFFB_CC_OP offsetof(VexGuestX86State,guest_CC_OP)
221#define OFFB_CC_SRC offsetof(VexGuestX86State,guest_CC_SRC)
222#define OFFB_CC_DST offsetof(VexGuestX86State,guest_CC_DST)
223#define OFFB_DFLAG offsetof(VexGuestX86State,guest_DFLAG)
224#define OFFB_FTOP offsetof(VexGuestX86State,guest_FTOP)
225#define OFFB_FC3210 offsetof(VexGuestX86State,guest_FC3210)
226#define OFFB_FPUCW offsetof(VexGuestX86State,guest_FPUCW)
227
228
229/*------------------------------------------------------------*/
sewardjce70a5c2004-10-18 14:09:54 +0000230/*--- Helper bits and pieces for deconstructing the ---*/
231/*--- x86 insn stream. ---*/
232/*------------------------------------------------------------*/
233
234/* This is the Intel register encoding -- integer regs. */
235#define R_EAX 0
236#define R_ECX 1
237#define R_EDX 2
238#define R_EBX 3
239#define R_ESP 4
240#define R_EBP 5
241#define R_ESI 6
242#define R_EDI 7
243
244#define R_AL (0+R_EAX)
245#define R_AH (4+R_EAX)
246
sewardj063f02f2004-10-20 12:36:12 +0000247/* This is the Intel register encoding -- segment regs. */
248#define R_ES 0
249#define R_CS 1
250#define R_SS 2
251#define R_DS 3
252#define R_FS 4
253#define R_GS 5
254
sewardjce70a5c2004-10-18 14:09:54 +0000255
sewardjc9a65702004-07-07 16:32:57 +0000256/* Add a statement to the list held by "irbb". */
sewardjd7cb8532004-08-17 23:59:23 +0000257static void stmt ( IRStmt* st )
sewardjc9a65702004-07-07 16:32:57 +0000258{
sewardjd7cb8532004-08-17 23:59:23 +0000259 addStmtToIRBB( irbb, st );
sewardjc9a65702004-07-07 16:32:57 +0000260}
261
262/* Generate a new temporary of the given type. */
263static IRTemp newTemp ( IRType ty )
264{
sewardj6d2638e2004-07-15 09:38:27 +0000265 vassert(isPlausibleType(ty));
sewardje539a402004-07-14 18:24:17 +0000266 return newIRTemp( irbb->tyenv, ty );
sewardjc9a65702004-07-07 16:32:57 +0000267}
268
sewardjc9a65702004-07-07 16:32:57 +0000269/* Bomb out if we can't handle something. */
sewardjd1061ab2004-07-08 01:45:30 +0000270__attribute__ ((noreturn))
sewardjc9a65702004-07-07 16:32:57 +0000271static void unimplemented ( Char* str )
272{
273 vex_printf("x86toIR: unimplemented feature\n");
274 vpanic(str);
275}
276
sewardjce70a5c2004-10-18 14:09:54 +0000277/* Various simple conversions */
sewardjd1061ab2004-07-08 01:45:30 +0000278
sewardje05c42c2004-07-08 20:25:10 +0000279static UInt extend_s_8to32( UInt x )
sewardjd1061ab2004-07-08 01:45:30 +0000280{
281 return (UInt)((((Int)x) << 24) >> 24);
282}
283
sewardj0611d802004-07-11 02:37:54 +0000284static UInt extend_s_16to32 ( UInt x )
285{
286 return (UInt)((((Int)x) << 16) >> 16);
287}
288
sewardjd1061ab2004-07-08 01:45:30 +0000289/* Fetch a byte from the guest insn stream. */
sewardje05c42c2004-07-08 20:25:10 +0000290static UChar getIByte ( UInt delta )
sewardjd1061ab2004-07-08 01:45:30 +0000291{
292 return guest_code[delta];
293}
294
sewardjc9a65702004-07-07 16:32:57 +0000295/* Extract the reg field from a modRM byte. */
sewardje05c42c2004-07-08 20:25:10 +0000296static Int gregOfRM ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000297{
298 return (Int)( (mod_reg_rm >> 3) & 7 );
299}
300
301/* Figure out whether the mod and rm parts of a modRM byte refer to a
302 register or memory. If so, the byte will have the form 11XXXYYY,
303 where YYY is the register number. */
sewardje05c42c2004-07-08 20:25:10 +0000304static Bool epartIsReg ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000305{
306 return (0xC0 == (mod_reg_rm & 0xC0));
307}
308
309/* ... and extract the register number ... */
sewardje05c42c2004-07-08 20:25:10 +0000310static Int eregOfRM ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000311{
312 return (Int)(mod_reg_rm & 0x7);
313}
314
sewardje05c42c2004-07-08 20:25:10 +0000315/* Get a 8/16/32-bit unsigned value out of the insn stream. */
316
317static UInt getUChar ( UInt delta )
318{
319 UInt v = guest_code[delta+0];
320 return v & 0xFF;
321}
322
323static UInt getUDisp16 ( UInt delta )
324{
325 UInt v = guest_code[delta+1]; v <<= 8;
326 v |= guest_code[delta+0];
327 return v & 0xFFFF;
328}
329
330static UInt getUDisp32 ( UInt delta )
sewardjd1061ab2004-07-08 01:45:30 +0000331{
332 UInt v = guest_code[delta+3]; v <<= 8;
333 v |= guest_code[delta+2]; v <<= 8;
334 v |= guest_code[delta+1]; v <<= 8;
335 v |= guest_code[delta+0];
336 return v;
337}
338
sewardje05c42c2004-07-08 20:25:10 +0000339static UInt getUDisp ( Int size, UInt delta )
340{
341 switch (size) {
342 case 4: return getUDisp32(delta);
343 case 2: return getUDisp16(delta);
344 case 1: return getUChar(delta);
345 default: vpanic("getUDisp(x86)");
346 }
347 return 0; /*notreached*/
348}
349
350
sewardjd1061ab2004-07-08 01:45:30 +0000351/* Get a byte value out of the insn stream and sign-extend to 32
352 bits. */
sewardje05c42c2004-07-08 20:25:10 +0000353static UInt getSDisp8 ( UInt delta )
sewardjd1061ab2004-07-08 01:45:30 +0000354{
355 return extend_s_8to32( (UInt) (guest_code[delta]) );
356}
357
sewardj0611d802004-07-11 02:37:54 +0000358static UInt getSDisp16 ( UInt delta0 )
359{
360 UChar* eip = (UChar*)(&guest_code[delta0]);
361 UInt d = *eip++;
362 d |= ((*eip++) << 8);
363 return extend_s_16to32(d);
364}
365
366static UInt getSDisp ( Int size, UInt delta )
367{
368 switch (size) {
369 case 4: return getUDisp32(delta);
370 case 2: return getSDisp16(delta);
371 case 1: return getSDisp8(delta);
372 default: vpanic("getSDisp(x86)");
373 }
374 return 0; /*notreached*/
375}
sewardjd1061ab2004-07-08 01:45:30 +0000376
sewardjc9a65702004-07-07 16:32:57 +0000377
378/*------------------------------------------------------------*/
379/*--- Helpers for constructing IR. ---*/
380/*------------------------------------------------------------*/
381
382/* Create a 1/2/4 byte read of an x86 integer registers. For 16/8 bit
383 register references, we need to take the host endianness into
384 account. Supplied value is 0 .. 7 and in the Intel instruction
385 encoding. */
sewardje05c42c2004-07-08 20:25:10 +0000386
sewardj9334b0f2004-07-10 22:43:54 +0000387static IRType szToITy ( Int n )
388{
389 switch (n) {
390 case 1: return Ity_I8;
391 case 2: return Ity_I16;
392 case 4: return Ity_I32;
393 default: vpanic("szToITy(x86)");
394 }
395}
396
397static Int integerGuestRegOffset ( Int sz, UInt archreg )
398{
399 vassert(archreg < 8);
400
401 vassert(!host_is_bigendian);
402
403 /* Correct for little-endian host only. */
sewardj063f02f2004-10-20 12:36:12 +0000404
405 if (sz == 4 || sz == 2 || (sz == 1 && archreg < 4)) {
406 switch (archreg) {
407 case R_EAX: return offsetof(VexGuestX86State,guest_EAX);
408 case R_EBX: return offsetof(VexGuestX86State,guest_EBX);
409 case R_ECX: return offsetof(VexGuestX86State,guest_ECX);
410 case R_EDX: return offsetof(VexGuestX86State,guest_EDX);
411 case R_ESI: return offsetof(VexGuestX86State,guest_ESI);
412 case R_EDI: return offsetof(VexGuestX86State,guest_EDI);
413 case R_ESP: return offsetof(VexGuestX86State,guest_ESP);
414 case R_EBP: return offsetof(VexGuestX86State,guest_EBP);
415 default: vpanic("integerGuestRegOffset(x86,le)(4,2)");
416 }
417 }
418
419 vassert(archreg >= 4 && archreg < 8 && sz == 1);
420 switch (archreg-4) {
421 case R_EAX: return 1+ offsetof(VexGuestX86State,guest_EAX);
422 case R_EBX: return 1+ offsetof(VexGuestX86State,guest_EBX);
423 case R_ECX: return 1+ offsetof(VexGuestX86State,guest_ECX);
424 case R_EDX: return 1+ offsetof(VexGuestX86State,guest_EDX);
425 default: vpanic("integerGuestRegOffset(x86,le)(1h)");
426 }
427
428 /* NOTREACHED */
429 vpanic("integerGuestRegOffset(x86,le)");
430}
431
432static Int segmentGuestRegOffset ( UInt sreg )
433{
434 switch (sreg) {
435 case R_ES: return offsetof(VexGuestX86State,guest_ES);
436 case R_CS: return offsetof(VexGuestX86State,guest_CS);
437 case R_SS: return offsetof(VexGuestX86State,guest_SS);
438 case R_DS: return offsetof(VexGuestX86State,guest_DS);
439 case R_FS: return offsetof(VexGuestX86State,guest_FS);
440 case R_GS: return offsetof(VexGuestX86State,guest_GS);
441 default: vpanic("segmentGuestRegOffset(x86)");
sewardj9334b0f2004-07-10 22:43:54 +0000442 }
443}
444
sewardjd1061ab2004-07-08 01:45:30 +0000445static IRExpr* getIReg ( Int sz, UInt archreg )
sewardjc9a65702004-07-07 16:32:57 +0000446{
447 vassert(sz == 1 || sz == 2 || sz == 4);
448 vassert(archreg < 8);
sewardj9334b0f2004-07-10 22:43:54 +0000449 return IRExpr_Get( integerGuestRegOffset(sz,archreg),
450 szToITy(sz) );
sewardjc9a65702004-07-07 16:32:57 +0000451}
452
453/* Ditto, but write to a reg instead. */
sewardj41f43bc2004-07-08 14:23:22 +0000454static void putIReg ( Int sz, UInt archreg, IRExpr* e )
sewardjc9a65702004-07-07 16:32:57 +0000455{
456 vassert(sz == 1 || sz == 2 || sz == 4);
457 vassert(archreg < 8);
sewardjeeb9ef82004-07-15 12:39:03 +0000458 stmt( IRStmt_Put(integerGuestRegOffset(sz,archreg), e) );
sewardjd1061ab2004-07-08 01:45:30 +0000459}
460
sewardj063f02f2004-10-20 12:36:12 +0000461static IRExpr* getSReg ( UInt sreg )
462{
463 return IRExpr_Get( segmentGuestRegOffset(sreg), Ity_I16 );
464}
465
466static void putSReg ( UInt sreg, IRExpr* e )
467{
468 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I16);
469 stmt( IRStmt_Put( segmentGuestRegOffset(sreg), e ) );
470}
471
sewardj41f43bc2004-07-08 14:23:22 +0000472static void assign ( IRTemp dst, IRExpr* e )
sewardjd1061ab2004-07-08 01:45:30 +0000473{
sewardj41f43bc2004-07-08 14:23:22 +0000474 stmt( IRStmt_Tmp(dst, e) );
sewardjd1061ab2004-07-08 01:45:30 +0000475}
476
sewardj41f43bc2004-07-08 14:23:22 +0000477static void storeLE ( IRExpr* addr, IRExpr* data )
sewardjd1061ab2004-07-08 01:45:30 +0000478{
sewardj41f43bc2004-07-08 14:23:22 +0000479 stmt( IRStmt_STle(addr,data) );
sewardjd1061ab2004-07-08 01:45:30 +0000480}
481
sewardje87b4842004-07-10 12:23:30 +0000482static IRExpr* unop ( IROp op, IRExpr* a )
483{
484 return IRExpr_Unop(op, a);
485}
486
sewardjd1061ab2004-07-08 01:45:30 +0000487static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
488{
489 return IRExpr_Binop(op, a1, a2);
490}
491
492static IRExpr* mkexpr ( IRTemp tmp )
493{
494 return IRExpr_Tmp(tmp);
495}
496
sewardjc2ac51e2004-07-12 01:03:26 +0000497static IRExpr* mkU8 ( UInt i )
498{
499 vassert(i < 256);
500 return IRExpr_Const(IRConst_U8(i));
501}
502
503static IRExpr* mkU16 ( UInt i )
504{
505 vassert(i < 65536);
506 return IRExpr_Const(IRConst_U16(i));
507}
508
sewardjd1061ab2004-07-08 01:45:30 +0000509static IRExpr* mkU32 ( UInt i )
510{
511 return IRExpr_Const(IRConst_U32(i));
sewardjc9a65702004-07-07 16:32:57 +0000512}
513
sewardj41f43bc2004-07-08 14:23:22 +0000514static IRExpr* mkU ( IRType ty, UInt i )
515{
sewardjc2ac51e2004-07-12 01:03:26 +0000516 if (ty == Ity_I8) return mkU8(i);
517 if (ty == Ity_I16) return mkU16(i);
518 if (ty == Ity_I32) return mkU32(i);
sewardje90ad6a2004-07-10 19:02:10 +0000519 /* If this panics, it usually means you passed a size (1,2,4)
520 value as the IRType, rather than a real IRType. */
sewardj41f43bc2004-07-08 14:23:22 +0000521 vpanic("mkU(x86)");
522}
523
524static IRExpr* loadLE ( IRType ty, IRExpr* data )
525{
526 return IRExpr_LDle(ty,data);
527}
528
529static IROp mkSizedOp ( IRType ty, IROp op8 )
530{
sewardje05c42c2004-07-08 20:25:10 +0000531 Int adj;
sewardj41f43bc2004-07-08 14:23:22 +0000532 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
533 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8
sewardj41f43bc2004-07-08 14:23:22 +0000534 || op8 == Iop_Mul8
535 || op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
sewardjc22a6fd2004-07-29 23:41:47 +0000536 || op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8
sewardje90ad6a2004-07-10 19:02:10 +0000537 || op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8
sewardj41f43bc2004-07-08 14:23:22 +0000538 || op8 == Iop_Not8 || op8 == Iop_Neg8 );
sewardje05c42c2004-07-08 20:25:10 +0000539 adj = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
540 return adj + op8;
sewardj41f43bc2004-07-08 14:23:22 +0000541}
542
sewardj9334b0f2004-07-10 22:43:54 +0000543static IROp mkWidenOp ( Int szSmall, Int szBig, Bool signd )
sewardj41f43bc2004-07-08 14:23:22 +0000544{
sewardj9334b0f2004-07-10 22:43:54 +0000545 if (szSmall == 1 && szBig == 4) {
546 return signd ? Iop_8Sto32 : Iop_8Uto32;
sewardj41f43bc2004-07-08 14:23:22 +0000547 }
sewardj9334b0f2004-07-10 22:43:54 +0000548 if (szSmall == 1 && szBig == 2) {
549 return signd ? Iop_8Sto16 : Iop_8Uto16;
550 }
551 if (szSmall == 2 && szBig == 4) {
552 return signd ? Iop_16Sto32 : Iop_16Uto32;
553 }
554 vpanic("mkWidenOp(x86)");
sewardj41f43bc2004-07-08 14:23:22 +0000555}
556
557
558/*------------------------------------------------------------*/
559/*--- Helpers for %eflags. ---*/
560/*------------------------------------------------------------*/
561
sewardj0611d802004-07-11 02:37:54 +0000562/* -------------- Evaluating the flags-thunk. -------------- */
sewardjc9a65702004-07-07 16:32:57 +0000563
sewardje87b4842004-07-10 12:23:30 +0000564/* Build IR to calculate all the eflags from stored
sewardj77b86be2004-07-11 13:28:24 +0000565 CC_OP/CC_SRC/CC_DST. Returns an expression :: Ity_I32. */
sewardje87b4842004-07-10 12:23:30 +0000566static IRExpr* mk_calculate_eflags_all ( void )
567{
568 IRExpr** args = LibVEX_Alloc(4 * sizeof(IRExpr*));
569 args[0] = IRExpr_Get(OFFB_CC_OP, Ity_I32);
570 args[1] = IRExpr_Get(OFFB_CC_SRC, Ity_I32);
571 args[2] = IRExpr_Get(OFFB_CC_DST, Ity_I32);
572 args[3] = NULL;
573 return IRExpr_CCall("calculate_eflags_all", Ity_I32, args);
574}
575
sewardj84ff0652004-08-23 16:16:08 +0000576/* Build IR to calculate just the carry flag from stored
sewardj77b86be2004-07-11 13:28:24 +0000577 CC_OP/CC_SRC/CC_DST. Returns an expression :: Ity_I32. */
sewardje87b4842004-07-10 12:23:30 +0000578static IRExpr* mk_calculate_eflags_c ( void )
579{
580 IRExpr** args = LibVEX_Alloc(4 * sizeof(IRExpr*));
581 args[0] = IRExpr_Get(OFFB_CC_OP, Ity_I32);
582 args[1] = IRExpr_Get(OFFB_CC_SRC, Ity_I32);
583 args[2] = IRExpr_Get(OFFB_CC_DST, Ity_I32);
584 args[3] = NULL;
585 return IRExpr_CCall("calculate_eflags_c", Ity_I32, args);
586}
587
sewardj84ff0652004-08-23 16:16:08 +0000588/* Build IR to calculate some particular condition from stored
589 CC_OP/CC_SRC/CC_DST. Returns an expression :: Ity_Bit. */
590static IRExpr* calculate_condition ( Condcode cond )
591{
592 IRExpr** args = LibVEX_Alloc(5 * sizeof(IRExpr*));
593 args[0] = mkU32(cond);
594 args[1] = IRExpr_Get(OFFB_CC_OP, Ity_I32);
595 args[2] = IRExpr_Get(OFFB_CC_SRC, Ity_I32);
596 args[3] = IRExpr_Get(OFFB_CC_DST, Ity_I32);
597 args[4] = NULL;
598 return unop(Iop_32to1,
599 IRExpr_CCall("calculate_condition", Ity_I32, args));
600}
601
sewardje87b4842004-07-10 12:23:30 +0000602
sewardj0611d802004-07-11 02:37:54 +0000603/* -------------- Building the flags-thunk. -------------- */
604
sewardjb9c5cf62004-08-24 15:10:38 +0000605/* The machinery in this section builds the flag-thunk following a
606 flag-setting operation. Hence the various setFlags_* functions.
607 Note, in reality setFlags_ADD_SUB and setFlags_MUL are pretty much
608 the same -- they just store the two operands.
609*/
610
611static Bool isAddSub ( IROp op8 )
612{
613 return op8 == Iop_Add8 || op8 == Iop_Sub8;
614}
sewardj0611d802004-07-11 02:37:54 +0000615
sewardja2384712004-07-29 14:36:40 +0000616/* U-widen 8/16/32 bit int expr to 32. */
sewardjc22a6fd2004-07-29 23:41:47 +0000617static IRExpr* widenUto32 ( IRExpr* e )
sewardj443cd9d2004-07-18 23:06:45 +0000618{
619 switch (typeOfIRExpr(irbb->tyenv,e)) {
620 case Ity_I32: return e;
621 case Ity_I16: return unop(Iop_16Uto32,e);
622 case Ity_I8: return unop(Iop_8Uto32,e);
623 default: vpanic("widenUto32");
624 }
625}
626
sewardjc22a6fd2004-07-29 23:41:47 +0000627/* S-widen 8/16/32 bit int expr to 32. */
628static IRExpr* widenSto32 ( IRExpr* e )
629{
630 switch (typeOfIRExpr(irbb->tyenv,e)) {
631 case Ity_I32: return e;
632 case Ity_I16: return unop(Iop_16Sto32,e);
633 case Ity_I8: return unop(Iop_8Sto32,e);
634 default: vpanic("widenSto32");
635 }
636}
637
sewardja2384712004-07-29 14:36:40 +0000638/* Narrow 8/16/32 bit int expr to 8/16/32. Clearly only some
639 of these combinations make sense. */
640static IRExpr* narrowTo ( IRType dst_ty, IRExpr* e )
641{
642 IRType src_ty = typeOfIRExpr(irbb->tyenv,e);
643 if (src_ty == dst_ty)
644 return e;
645 if (src_ty == Ity_I32 && dst_ty == Ity_I16)
646 return unop(Iop_32to16, e);
647 if (src_ty == Ity_I32 && dst_ty == Ity_I8)
648 return unop(Iop_32to8, e);
649
650 vex_printf("\nsrc, dst tys are: ");
651 ppIRType(src_ty);
652 vex_printf(", ");
653 ppIRType(dst_ty);
654 vex_printf("\n");
655 vpanic("narrowTo(x86)");
656}
657
sewardj443cd9d2004-07-18 23:06:45 +0000658
sewardjb9c5cf62004-08-24 15:10:38 +0000659/* This is for add/sub/adc/sbb, where (like multiply) we simply store
660 the two arguments. Note, the args are reversed, so if op8
661 indicates subtract, then the value the program is trying to compute
662 is src1 - src2. */
sewardj0611d802004-07-11 02:37:54 +0000663
sewardjb9c5cf62004-08-24 15:10:38 +0000664static void setFlags_ADD_SUB ( IROp op8,
665 IRTemp src2,
666 IRTemp src1,
667 IRType ty )
sewardj0611d802004-07-11 02:37:54 +0000668{
sewardjb9c5cf62004-08-24 15:10:38 +0000669 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
670
671 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
672
673 switch (op8) {
674 case Iop_Add8: ccOp += CC_OP_ADDB; break;
675 case Iop_Sub8: ccOp += CC_OP_SUBB; break;
676 default: ppIROp(op8);
677 vpanic("setFlags_ADD_SUB(x86)");
678 }
679 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
680 stmt( IRStmt_Put( OFFB_CC_SRC, widenUto32(mkexpr(src2))) );
681 stmt( IRStmt_Put( OFFB_CC_DST, widenUto32(mkexpr(src1))) );
682}
683
684
685/* For and/or/xor, only the result is important. However, put zero in
686 CC_SRC to keep memcheck happy. */
687
688static void setFlags_LOGIC ( IROp op8,
689 IRTemp dst1,
690 IRType ty )
691{
692 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
sewardj0611d802004-07-11 02:37:54 +0000693
694 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
695
696 switch (op8) {
697 case Iop_Or8:
698 case Iop_And8:
sewardjb9c5cf62004-08-24 15:10:38 +0000699 case Iop_Xor8: ccOp += CC_OP_LOGICB; break;
sewardj0611d802004-07-11 02:37:54 +0000700 default: ppIROp(op8);
sewardjb9c5cf62004-08-24 15:10:38 +0000701 vpanic("setFlags_LOGIC(x86)");
sewardj0611d802004-07-11 02:37:54 +0000702 }
sewardjeeb9ef82004-07-15 12:39:03 +0000703 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
sewardjb9c5cf62004-08-24 15:10:38 +0000704 stmt( IRStmt_Put( OFFB_CC_SRC, mkU32(0)) );
sewardjc22a6fd2004-07-29 23:41:47 +0000705 stmt( IRStmt_Put( OFFB_CC_DST, widenUto32(mkexpr(dst1))) );
sewardj0611d802004-07-11 02:37:54 +0000706}
707
708
sewardjb9c5cf62004-08-24 15:10:38 +0000709/* For all shift and rotate cases, store the result value and the
710 result except shifted or rotated one bit less ("undershifted",
711 hence US). And then only when the guard is non-zero. */
sewardj0611d802004-07-11 02:37:54 +0000712
sewardjc22a6fd2004-07-29 23:41:47 +0000713static void setFlags_DSTus_DST1 ( IROp op32,
sewardj0611d802004-07-11 02:37:54 +0000714 IRTemp dstUS,
715 IRTemp dst1,
716 IRType ty,
sewardja06e5562004-07-14 13:18:05 +0000717 IRTemp guard )
sewardj0611d802004-07-11 02:37:54 +0000718{
sewardjc22a6fd2004-07-29 23:41:47 +0000719 Int ccOp = ty==Ity_I8 ? 2 : (ty==Ity_I16 ? 1 : 0);
sewardj0611d802004-07-11 02:37:54 +0000720
721 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
722 vassert(guard);
723
sewardjc22a6fd2004-07-29 23:41:47 +0000724 switch (op32) {
725 case Iop_Shr32:
726 case Iop_Sar32: ccOp = CC_OP_SARL - ccOp; break;
727 case Iop_Shl32: ccOp = CC_OP_SHLL - ccOp; break;
728 default: ppIROp(op32);
729 vpanic("setFlags_DSTus_DST1(x86)");
sewardj0611d802004-07-11 02:37:54 +0000730 }
731
732 /* CC_SRC = undershifted %d after, CC_DST = %d afterwards */
sewardjeeb9ef82004-07-15 12:39:03 +0000733 stmt( IRStmt_Put( OFFB_CC_OP,
sewardj4042c7e2004-07-18 01:28:30 +0000734 IRExpr_Mux0X( mkexpr(guard),
735 IRExpr_Get(OFFB_CC_OP,Ity_I32),
736 mkU32(ccOp))) );
sewardjeeb9ef82004-07-15 12:39:03 +0000737 stmt( IRStmt_Put( OFFB_CC_SRC,
sewardj4042c7e2004-07-18 01:28:30 +0000738 IRExpr_Mux0X( mkexpr(guard),
739 IRExpr_Get(OFFB_CC_SRC,Ity_I32),
sewardjc22a6fd2004-07-29 23:41:47 +0000740 widenUto32(mkexpr(dstUS)))) );
sewardjeeb9ef82004-07-15 12:39:03 +0000741 stmt( IRStmt_Put( OFFB_CC_DST,
sewardj4042c7e2004-07-18 01:28:30 +0000742 IRExpr_Mux0X( mkexpr(guard),
743 IRExpr_Get(OFFB_CC_DST,Ity_I32),
sewardjc22a6fd2004-07-29 23:41:47 +0000744 widenUto32(mkexpr(dst1)))) );
sewardj0611d802004-07-11 02:37:54 +0000745}
746
747
748/* For the inc/dec case, we store the result value and the former
749 value of the carry flag, which unfortunately we have to compute. */
750
751static void setFlags_INC_DEC ( Bool inc, IRTemp dst, IRType ty )
752{
sewardjeeb9ef82004-07-15 12:39:03 +0000753 Int ccOp = inc ? CC_OP_INCB : CC_OP_DECB;
sewardj0611d802004-07-11 02:37:54 +0000754
755 ccOp += ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
756 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
757
758 /* This has to come first, because calculating the C flag
759 may require reading all three OFFB_CC fields. */
sewardjeeb9ef82004-07-15 12:39:03 +0000760 stmt( IRStmt_Put( OFFB_CC_SRC, mk_calculate_eflags_c()) );
761 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
762 stmt( IRStmt_Put( OFFB_CC_DST, mkexpr(dst)) );
sewardj0611d802004-07-11 02:37:54 +0000763}
764
765
sewardjcf780b42004-07-13 18:42:17 +0000766/* For multiplies, just remember the two operands and a
767 description of what kind of multiply. */
768
769static
770void setFlags_MUL ( IRType ty, IRTemp src1, IRTemp src2, UInt base_op )
771{
772 switch (ty) {
773 case Ity_I8:
sewardjeeb9ef82004-07-15 12:39:03 +0000774 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+0) ) );
775 stmt( IRStmt_Put( OFFB_CC_SRC, unop(Iop_8Uto32,mkexpr(src1)) ) );
776 stmt( IRStmt_Put( OFFB_CC_DST, unop(Iop_8Uto32,mkexpr(src2)) ) );
sewardjcf780b42004-07-13 18:42:17 +0000777 break;
778 case Ity_I16:
sewardjeeb9ef82004-07-15 12:39:03 +0000779 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+1) ) );
780 stmt( IRStmt_Put( OFFB_CC_SRC, unop(Iop_16Uto32,mkexpr(src1)) ) );
781 stmt( IRStmt_Put( OFFB_CC_DST, unop(Iop_16Uto32,mkexpr(src2)) ) );
sewardjcf780b42004-07-13 18:42:17 +0000782 break;
783 case Ity_I32:
sewardjeeb9ef82004-07-15 12:39:03 +0000784 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+2) ) );
785 stmt( IRStmt_Put( OFFB_CC_SRC, mkexpr(src1) ) );
786 stmt( IRStmt_Put( OFFB_CC_DST, mkexpr(src2) ) );
sewardjcf780b42004-07-13 18:42:17 +0000787 break;
788 default:
789 vpanic("setFlags_MUL(x86)");
790 }
791}
792
793
sewardj3af115f2004-07-14 02:46:52 +0000794/* -------------- Condition codes. -------------- */
795
sewardje87b4842004-07-10 12:23:30 +0000796/* Condition codes, using the Intel encoding. */
sewardj0611d802004-07-11 02:37:54 +0000797
sewardje87b4842004-07-10 12:23:30 +0000798static Char* name_Condcode ( Condcode cond )
799{
800 switch (cond) {
801 case CondO: return "o";
802 case CondNO: return "no";
803 case CondB: return "b";
804 case CondNB: return "nb";
805 case CondZ: return "z";
806 case CondNZ: return "nz";
807 case CondBE: return "be";
808 case CondNBE: return "nbe";
809 case CondS: return "s";
810 case CondNS: return "ns";
811 case CondP: return "p";
812 case CondNP: return "np";
813 case CondL: return "l";
814 case CondNL: return "nl";
815 case CondLE: return "le";
816 case CondNLE: return "nle";
sewardj64e1d652004-07-12 14:00:46 +0000817 case CondAlways: return "ALWAYS";
sewardje87b4842004-07-10 12:23:30 +0000818 default: vpanic("name_Condcode");
819 }
820}
821
822static Condcode positiveIse_Condcode ( Condcode cond,
823 Bool* needInvert )
824{
825 vassert(cond >= CondO && cond <= CondNLE);
826 if (cond & 1) {
827 *needInvert = True;
828 return cond-1;
829 } else {
830 *needInvert = False;
831 return cond;
832 }
833}
834
835
sewardj3af115f2004-07-14 02:46:52 +0000836/* -------------- Helpers for ADD/SUB with carry. -------------- */
837
838/* Given ta1, ta2 and tdst, compute tdst = ADC(ta1,ta2) and set flags
839 appropriately. Depends critically on the relative ordering of
840 CC_OP_ADD{B,W,L} vs CC_OP_ADC{B,W,L}.
841*/
842static void helper_ADC ( Int sz,
843 IRTemp tdst, IRTemp ta1, IRTemp ta2 )
844{
845 UInt thunkOp;
846 IRExpr* thunkExpr;
847 IRType ty = szToITy(sz);
848 IRTemp oldc = newTemp(Ity_I32);
849 IROp plus = mkSizedOp(ty,Iop_Add8);
850
851 /* oldc = old carry flag, 0 or 1 */
sewardja2384712004-07-29 14:36:40 +0000852 assign( oldc, binop(Iop_And32,
sewardj3af115f2004-07-14 02:46:52 +0000853 mk_calculate_eflags_c(),
sewardja2384712004-07-29 14:36:40 +0000854 mkU32(1)) );
sewardj3af115f2004-07-14 02:46:52 +0000855
sewardja2384712004-07-29 14:36:40 +0000856 assign(tdst, binop(plus,
857 binop(plus,mkexpr(ta1),mkexpr(ta2)),
858 narrowTo(ty,mkexpr(oldc))));
859
860 vassert(sz == 1 || sz == 2 || sz == 4);
861 thunkOp = sz==4 ? CC_OP_ADDL : (sz==2 ? CC_OP_ADDW : CC_OP_ADDB);
sewardj3af115f2004-07-14 02:46:52 +0000862
863 /* This dynamically calculates the thunk op number.
864 3 * the old carry flag is added, so (eg) it gives
865 CC_OP_ADDL if old carry was zero, and CC_OP_ADCL if
866 old carry was one. */
867 thunkExpr = binop(Iop_Add32,
868 mkU32(thunkOp),
869 binop(Iop_Mul32, mkexpr(oldc), mkU32(3)));
870
sewardjeeb9ef82004-07-15 12:39:03 +0000871 stmt( IRStmt_Put( OFFB_CC_OP, thunkExpr ) );
872 stmt( IRStmt_Put( OFFB_CC_SRC, mkexpr(ta2) ) );
sewardjb9c5cf62004-08-24 15:10:38 +0000873 stmt( IRStmt_Put( OFFB_CC_DST, mkexpr(ta1) ) );
sewardj3af115f2004-07-14 02:46:52 +0000874}
875
876
sewardjcaca9d02004-07-28 07:11:32 +0000877/* Given ta1, ta2 and tdst, compute tdst = SBB(ta1,ta2) and set flags
878 appropriately. Depends critically on the relative ordering of
879 CC_OP_SUB{B,W,L} vs CC_OP_SBB{B,W,L}.
880*/
881static void helper_SBB ( Int sz,
882 IRTemp tdst, IRTemp ta1, IRTemp ta2 )
883{
884 UInt thunkOp;
885 IRExpr* thunkExpr;
886 IRType ty = szToITy(sz);
887 IRTemp oldc = newTemp(Ity_I32);
888 IROp minus = mkSizedOp(ty,Iop_Sub8);
889
890 /* oldc = old carry flag, 0 or 1 */
sewardja2384712004-07-29 14:36:40 +0000891 assign( oldc, binop(Iop_And32,
sewardjcaca9d02004-07-28 07:11:32 +0000892 mk_calculate_eflags_c(),
sewardja2384712004-07-29 14:36:40 +0000893 mkU32(1)) );
sewardjcaca9d02004-07-28 07:11:32 +0000894
sewardja2384712004-07-29 14:36:40 +0000895 assign(tdst, binop(minus,
896 binop(minus,mkexpr(ta1),mkexpr(ta2)),
897 narrowTo(ty,mkexpr(oldc))));
898
899 vassert(sz == 1 || sz == 2 || sz == 4);
900 thunkOp = sz==4 ? CC_OP_SUBL : (sz==2 ? CC_OP_SUBW : CC_OP_SUBB);
sewardjcaca9d02004-07-28 07:11:32 +0000901
902 /* This dynamically calculates the thunk op number.
903 3 * the old carry flag is added, so (eg) it gives
904 CC_OP_SUBL if old carry was zero, and CC_OP_SBBL if
905 old carry was one. */
906 thunkExpr = binop(Iop_Add32,
907 mkU32(thunkOp),
908 binop(Iop_Mul32, mkexpr(oldc), mkU32(3)));
909
910 stmt( IRStmt_Put( OFFB_CC_OP, thunkExpr ) );
911 stmt( IRStmt_Put( OFFB_CC_SRC, mkexpr(ta2) ) );
sewardjb9c5cf62004-08-24 15:10:38 +0000912 stmt( IRStmt_Put( OFFB_CC_DST, mkexpr(ta1) ) );
sewardjcaca9d02004-07-28 07:11:32 +0000913}
914
915
sewardjc9a65702004-07-07 16:32:57 +0000916//-- /*------------------------------------------------------------*/
917//-- /*--- CPU feature set stuff ---*/
918//-- /*--- This is a little out of place here, but it will do ---*/
919//-- /*--- for now. ---*/
920//-- /*------------------------------------------------------------*/
921//--
sewardje87b4842004-07-10 12:23:30 +0000922//-- #define VG_CPU_VENDOR_GENERIC 0
923//-- #define VG_CPU_VENDOR_INTEL 1
sewardjc9a65702004-07-07 16:32:57 +0000924//-- #define VG_CPU_VENDOR_AMD 2
925//--
926//-- static Int cpu_vendor = VG_CPU_VENDOR_GENERIC;
927//--
928//-- static const struct cpu_vendor {
929//-- const Char *vendorstr;
930//-- Int vendorid;
931//-- } cpu_vendors[] = {
932//-- { "GenuineIntel", VG_CPU_VENDOR_INTEL },
933//-- { "AuthenticAMD", VG_CPU_VENDOR_AMD },
934//-- };
935//--
936//-- static Int cpuid_level = -2; /* -2 -> not initialized */
937//-- static UInt cpu_features[VG_N_FEATURE_WORDS];
938//--
939//-- /* Standard macro to see if a specific flag is changeable */
940//-- static inline Bool flag_is_changeable(UInt flag)
941//-- {
942//-- UInt f1, f2;
943//--
944//-- asm("pushfl\n\t"
945//-- "pushfl\n\t"
946//-- "popl %0\n\t"
947//-- "movl %0,%1\n\t"
948//-- "xorl %2,%0\n\t"
949//-- "pushl %0\n\t"
950//-- "popfl\n\t"
951//-- "pushfl\n\t"
952//-- "popl %0\n\t"
953//-- "popfl\n\t"
954//-- : "=&r" (f1), "=&r" (f2)
955//-- : "ir" (flag));
956//--
957//-- return ((f1^f2) & flag) != 0;
958//-- }
959//--
960//--
961//-- /* Probe for the CPUID instruction */
962//-- static Bool has_cpuid(void)
963//-- {
964//-- return flag_is_changeable(EFlagID);
965//-- }
966//--
967//-- static void get_cpu_features(void)
968//-- {
969//-- Char vendorstr[13];
970//-- Int i;
971//--
972//-- if (!has_cpuid()) {
973//-- cpuid_level = -1;
974//-- return;
975//-- }
976//--
977//-- cpu_features[VG_INT_FEAT] |= (1 << (VG_X86_FEAT_CPUID%32));
978//--
979//-- VG_(cpuid)(0, &cpuid_level, (UInt *)&vendorstr[0], (UInt *)&vendorstr[8], (UInt *)&vendorstr[4]);
980//-- vendorstr[12] = '\0';
981//--
982//-- for(i = 0; i < sizeof(cpu_vendors)/sizeof(*cpu_vendors); i++)
983//-- if (VG_(memcmp)(vendorstr, cpu_vendors[i].vendorstr, 12) == 0) {
984//-- cpu_vendor = cpu_vendors[i].vendorid;
985//-- break;
986//-- }
987//--
988//-- if (cpuid_level >= 1)
989//-- VG_(cpuid)(1, NULL, NULL, &cpu_features[VG_EXT_FEAT], &cpu_features[VG_X86_FEAT]);
990//--
991//-- switch(cpu_vendor) {
992//-- case VG_CPU_VENDOR_AMD:
993//-- /* get AMD-specific flags */
994//-- VG_(cpuid)(0x80000001, NULL, NULL, NULL, &cpu_features[VG_AMD_FEAT]);
995//-- break;
996//--
997//-- default:
998//-- break;
999//-- }
1000//-- }
1001//--
1002//-- Bool VG_(cpu_has_feature)(UInt feature)
1003//-- {
1004//-- UInt word = feature / 32;
1005//-- UInt bit = feature % 32;
1006//--
1007//-- if (cpuid_level == -2)
1008//-- get_cpu_features();
1009//--
1010//-- vg_assert(word >= 0 && word < VG_N_FEATURE_WORDS);
1011//--
1012//-- return !!(cpu_features[word] & (1 << bit));
1013//-- }
1014//--
1015//-- /* The set of features we're willing to support for the client
1016//--
1017//-- This includes supported instruction set extensions, plus any
1018//-- extensions which don't have any user-mode visible effect (but the
1019//-- client may find interesting).
1020//-- */
sewardjd1061ab2004-07-08 01:45:30 +00001021#define VG_X86_SUPPORTED_FEATURES \
1022 ((1 << VG_X86_FEAT_FPU) | \
1023 (1 << VG_X86_FEAT_VME) | \
1024 (1 << VG_X86_FEAT_DE) | \
1025 (1 << VG_X86_FEAT_PSE) | \
1026 (1 << VG_X86_FEAT_TSC) | \
1027 (0 << VG_X86_FEAT_MSR) | \
1028 (1 << VG_X86_FEAT_PAE) | \
1029 (1 << VG_X86_FEAT_MCE) | \
1030 (1 << VG_X86_FEAT_CX8) | \
1031 (1 << VG_X86_FEAT_APIC) | \
1032 (0 << VG_X86_FEAT_SEP) | \
1033 (1 << VG_X86_FEAT_MTRR) | \
1034 (1 << VG_X86_FEAT_PGE) | \
1035 (1 << VG_X86_FEAT_MCA) | \
1036 (1 << VG_X86_FEAT_CMOV) | \
1037 (1 << VG_X86_FEAT_PAT) | \
1038 (1 << VG_X86_FEAT_PSE36) | \
1039 (0 << VG_X86_FEAT_CLFSH) | \
1040 (1 << VG_X86_FEAT_DS) | \
1041 (1 << VG_X86_FEAT_ACPI) | \
1042 (1 << VG_X86_FEAT_MMX) | \
1043 (1 << VG_X86_FEAT_FXSR) | \
1044 (1 << VG_X86_FEAT_SSE) | \
1045 (1 << VG_X86_FEAT_SSE2) | \
1046 (1 << VG_X86_FEAT_SS) | \
1047 (1 << VG_X86_FEAT_HT) | \
1048 (1 << VG_X86_FEAT_TM) | \
1049 (0 << VG_X86_FEAT_IA64) | \
1050 (1 << VG_X86_FEAT_PBE))
1051
1052#define VG_AMD_SUPPORTED_FEATURES \
1053 ((0 << (VG_AMD_FEAT_SYSCALL % 32)) | \
1054 (0 << (VG_AMD_FEAT_NXP % 32)) | \
1055 (1 << (VG_AMD_FEAT_MMXEXT % 32)) | \
1056 (0 << (VG_AMD_FEAT_FFXSR % 32)) | \
1057 (0 << (VG_AMD_FEAT_LONGMODE % 32)) | \
1058 (0 << (VG_AMD_FEAT_3DNOWEXT % 32)) | \
1059 (0 << (VG_AMD_FEAT_3DNOW % 32)) | \
1060 /* Common bits between standard features and AMD features */ \
1061 (1 << VG_X86_FEAT_FPU) | \
1062 (1 << VG_X86_FEAT_VME) | \
1063 (1 << VG_X86_FEAT_DE) | \
1064 (1 << VG_X86_FEAT_PSE) | \
1065 (1 << VG_X86_FEAT_TSC) | \
1066 (0 << VG_X86_FEAT_MSR) | \
1067 (1 << VG_X86_FEAT_PAE) | \
1068 (1 << VG_X86_FEAT_MCE) | \
1069 (1 << VG_X86_FEAT_CX8) | \
1070 (1 << VG_X86_FEAT_APIC) | \
1071 (1 << VG_X86_FEAT_MTRR) | \
1072 (1 << VG_X86_FEAT_PGE) | \
1073 (1 << VG_X86_FEAT_MCA) | \
1074 (1 << VG_X86_FEAT_CMOV) | \
1075 (1 << VG_X86_FEAT_PAT) | \
1076 (1 << VG_X86_FEAT_PSE36) | \
1077 (1 << VG_X86_FEAT_MMX) | \
1078 (1 << VG_X86_FEAT_FXSR))
1079
1080
sewardjc9a65702004-07-07 16:32:57 +00001081//-- /*
1082//-- For simulating the cpuid instruction, we will
1083//-- issue a "real" cpuid instruction and then mask out
1084//-- the bits of the features we do not support currently (3dnow mostly).
1085//-- We also claim to not support most CPUID operations.
1086//--
1087//-- Dirk Mueller <mueller@kde.org>
1088//--
1089//-- http://www.sandpile.org/ia32/cpuid.htm
1090//--
1091//-- references:
1092//--
1093//-- pre-MMX pentium:
1094//--
1095//-- <werner> cpuid words (0): 0x1 0x756e6547 0x6c65746e 0x49656e69
1096//-- <werner> cpuid words (1): 0x52b 0x0 0x0 0x1bf
1097//--
1098//-- Updated to be more extensible about future vendor extensions and
1099//-- vendor-specific parts of CPUID.
1100//-- */
1101//-- void VG_(helperc_CPUID)(UInt op, UInt *eax_ret, UInt *ebx_ret, UInt *ecx_ret, UInt *edx_ret)
1102//-- {
1103//-- UInt eax, ebx, ecx, edx;
1104//--
1105//-- if (cpuid_level == -2)
1106//-- get_cpu_features(); /* for cpu_vendor */
1107//--
1108//-- VG_(cpuid)(op, &eax, &ebx, &ecx, &edx);
1109//--
1110//-- /* Common mangling */
1111//-- switch(op) {
1112//-- case 1:
1113//-- edx &= VG_X86_SUPPORTED_FEATURES;
1114//-- break;
1115//--
1116//-- case 0xd8000000: {
1117//-- /* Implement some private information at 0xd8000000 */
1118//-- static const Char valgrind_vendor[] = "ValgrindVCPU";
1119//--
1120//-- eax = 0xd8000000; /* max request */
1121//-- ebx = *(UInt *)&valgrind_vendor[0];
1122//-- ecx = *(UInt *)&valgrind_vendor[8];
1123//-- edx = *(UInt *)&valgrind_vendor[4];
1124//-- }
1125//-- break;
1126//-- }
1127//--
1128//-- /* Vendor-specific mangling of the results */
1129//-- switch(cpu_vendor) {
1130//-- case VG_CPU_VENDOR_INTEL:
1131//-- switch(op) {
1132//-- case 1:
1133//-- ecx = 0; /* mask out all extended features for now */
1134//-- break;
1135//--
1136//-- case 0x80000001:
1137//-- ebx = ecx = edx = 0;
1138//-- break;
1139//-- }
1140//-- break;
1141//--
1142//-- case VG_CPU_VENDOR_AMD:
1143//-- switch(op) {
1144//-- case 0x80000001:
1145//-- edx &= VG_AMD_SUPPORTED_FEATURES;
1146//-- break;
1147//-- }
1148//-- break;
1149//-- }
1150//--
1151//-- *eax_ret = eax;
1152//-- *ebx_ret = ebx;
1153//-- *ecx_ret = ecx;
1154//-- *edx_ret = edx;
1155//-- }
1156//--
1157//--
1158//-- /*------------------------------------------------------------*/
1159//-- /*--- Here so it can be inlined everywhere. ---*/
1160//-- /*------------------------------------------------------------*/
1161//--
1162//-- /* Allocate a new temp reg number. */
1163//-- __inline__ Int VG_(get_new_temp) ( UCodeBlock* cb )
1164//-- {
1165//-- Int t = cb->nextTemp;
1166//-- cb->nextTemp += 2;
1167//-- return t;
1168//-- }
1169//--
1170//-- Int VG_(get_new_shadow) ( UCodeBlock* cb )
1171//-- {
1172//-- Int t = cb->nextTemp;
1173//-- cb->nextTemp += 2;
1174//-- return SHADOW(t);
1175//-- }
1176
1177
sewardj41f43bc2004-07-08 14:23:22 +00001178
1179static Char* nameGrp1 ( Int opc_aux )
1180{
1181 static Char* grp1_names[8]
1182 = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
1183 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp1(x86)");
1184 return grp1_names[opc_aux];
1185}
1186
sewardje90ad6a2004-07-10 19:02:10 +00001187static Char* nameGrp2 ( Int opc_aux )
1188{
1189 static Char* grp2_names[8]
1190 = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
sewardjc2ac51e2004-07-12 01:03:26 +00001191 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp2(x86)");
sewardje90ad6a2004-07-10 19:02:10 +00001192 return grp2_names[opc_aux];
1193}
1194
sewardjc2ac51e2004-07-12 01:03:26 +00001195static Char* nameGrp4 ( Int opc_aux )
1196{
1197 static Char* grp4_names[8]
1198 = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
1199 if (opc_aux < 0 || opc_aux > 1) vpanic("nameGrp4(x86)");
1200 return grp4_names[opc_aux];
1201}
sewardj0611d802004-07-11 02:37:54 +00001202
1203static Char* nameGrp5 ( Int opc_aux )
1204{
1205 static Char* grp5_names[8]
1206 = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
1207 if (opc_aux < 0 || opc_aux > 6) vpanic("nameGrp5(x86)");
1208 return grp5_names[opc_aux];
1209}
1210
sewardjc9a65702004-07-07 16:32:57 +00001211//-- static Char* nameGrp8 ( Int opc_aux )
1212//-- {
1213//-- static Char* grp8_names[8]
1214//-- = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
1215//-- if (opc_aux < 4 || opc_aux > 7) VG_(core_panic)("nameGrp8");
1216//-- return grp8_names[opc_aux];
1217//-- }
1218
sewardj1813dbe2004-07-28 17:09:04 +00001219static Char* nameIReg ( Int size, Int reg )
sewardjc9a65702004-07-07 16:32:57 +00001220{
1221 static Char* ireg32_names[8]
1222 = { "%eax", "%ecx", "%edx", "%ebx",
1223 "%esp", "%ebp", "%esi", "%edi" };
1224 static Char* ireg16_names[8]
1225 = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di" };
1226 static Char* ireg8_names[8]
1227 = { "%al", "%cl", "%dl", "%bl",
1228 "%ah{sp}", "%ch{bp}", "%dh{si}", "%bh{di}" };
1229 if (reg < 0 || reg > 7) goto bad;
1230 switch (size) {
1231 case 4: return ireg32_names[reg];
1232 case 2: return ireg16_names[reg];
1233 case 1: return ireg8_names[reg];
1234 }
1235 bad:
1236 vpanic("nameIReg(X86)");
1237 return NULL; /*notreached*/
1238}
1239
sewardj063f02f2004-10-20 12:36:12 +00001240static Char* nameSReg ( UInt sreg )
1241{
1242 switch (sreg) {
1243 case R_ES: return "%es";
1244 case R_CS: return "%cs";
1245 case R_SS: return "%ss";
1246 case R_DS: return "%ds";
1247 case R_FS: return "%fs";
1248 case R_GS: return "%gs";
1249 default: vpanic("nameSReg(x86)");
1250 }
1251}
1252
sewardjc9a65702004-07-07 16:32:57 +00001253//-- const Char* VG_(name_of_mmx_reg) ( Int mmxreg )
1254//-- {
1255//-- static const Char* mmx_names[8]
1256//-- = { "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" };
1257//-- if (mmxreg < 0 || mmxreg > 7) VG_(core_panic)("name_of_mmx_reg");
1258//-- return mmx_names[mmxreg];
1259//-- }
1260//--
1261//-- const Char* VG_(name_of_xmm_reg) ( Int xmmreg )
1262//-- {
1263//-- static const Char* xmm_names[8]
1264//-- = { "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7" };
1265//-- if (xmmreg < 0 || xmmreg > 7) VG_(core_panic)("name_of_xmm_reg");
1266//-- return xmm_names[xmmreg];
1267//-- }
1268//--
1269//-- const Char* VG_(name_of_mmx_gran) ( UChar gran )
1270//-- {
1271//-- switch (gran) {
1272//-- case 0: return "b";
1273//-- case 1: return "w";
1274//-- case 2: return "d";
1275//-- case 3: return "q";
1276//-- default: VG_(core_panic)("name_of_mmx_gran");
1277//-- }
1278//-- }
1279
sewardj41f43bc2004-07-08 14:23:22 +00001280static Char nameISize ( Int size )
sewardjc9a65702004-07-07 16:32:57 +00001281{
1282 switch (size) {
1283 case 4: return 'l';
1284 case 2: return 'w';
1285 case 1: return 'b';
1286 default: vpanic("nameISize(x86)");
1287 }
1288}
1289
sewardjc9a65702004-07-07 16:32:57 +00001290//-- __inline__ static UInt LOW24 ( UInt x )
1291//-- {
1292//-- return x & 0x00FFFFFF;
1293//-- }
1294//--
1295//-- __inline__ static UInt HI8 ( UInt x )
1296//-- {
1297//-- return x >> 24;
1298//-- }
1299//--
sewardjc9a65702004-07-07 16:32:57 +00001300//-- /*------------------------------------------------------------*/
1301//-- /*--- Flag-related helpers. ---*/
1302//-- /*------------------------------------------------------------*/
1303//--
1304//-- static void setFlagsFromUOpcode ( UCodeBlock* cb, Int uopc )
1305//-- {
1306//-- switch (uopc) {
1307//-- case XOR: case OR: case AND:
1308//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZCP, FlagA); break;
1309//-- case ADC: case SBB:
1310//-- uFlagsRWU(cb, FlagC, FlagsOSZACP, FlagsEmpty); break;
1311//-- case MUL: case UMUL:
1312//-- uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP); break;
1313//-- case ADD: case SUB: case NEG:
1314//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty); break;
1315//-- case INC: case DEC:
1316//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZAP, FlagsEmpty); break;
1317//-- case SHR: case SAR: case SHL:
1318//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZCP, FlagA); break;
1319//-- case ROL: case ROR:
1320//-- uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsEmpty); break;
1321//-- case RCR: case RCL:
1322//-- uFlagsRWU(cb, FlagC, FlagsOC, FlagsEmpty); break;
1323//-- case NOT:
1324//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty); break;
1325//-- default:
1326//-- VG_(printf)("unhandled case is %s\n",
1327//-- VG_(name_UOpcode)(True, uopc));
1328//-- VG_(core_panic)("setFlagsFromUOpcode: unhandled case");
1329//-- }
1330//-- }
sewardjd1061ab2004-07-08 01:45:30 +00001331
1332/*------------------------------------------------------------*/
1333/*--- JMP helpers ---*/
1334/*------------------------------------------------------------*/
1335
sewardj78c19df2004-07-12 22:49:27 +00001336static void jmp_lit( IRJumpKind kind, Addr32 d32 )
sewardjd1061ab2004-07-08 01:45:30 +00001337{
sewardje539a402004-07-14 18:24:17 +00001338 irbb->next = mkU32(d32);
1339 irbb->jumpkind = kind;
sewardjd1061ab2004-07-08 01:45:30 +00001340}
1341
sewardj78c19df2004-07-12 22:49:27 +00001342static void jmp_treg( IRJumpKind kind, IRTemp t )
sewardje05c42c2004-07-08 20:25:10 +00001343{
sewardje539a402004-07-14 18:24:17 +00001344 irbb->next = mkexpr(t);
1345 irbb->jumpkind = kind;
sewardje05c42c2004-07-08 20:25:10 +00001346}
sewardje87b4842004-07-10 12:23:30 +00001347
sewardj9334b0f2004-07-10 22:43:54 +00001348static void jcc_01( Condcode cond, Addr32 d32_false, Addr32 d32_true )
sewardje87b4842004-07-10 12:23:30 +00001349{
1350 Bool invert;
1351 Condcode condPos;
1352 condPos = positiveIse_Condcode ( cond, &invert );
1353 if (invert) {
sewardj78c19df2004-07-12 22:49:27 +00001354 stmt( IRStmt_Exit( calculate_condition(condPos),
1355 IRConst_U32(d32_false) ) );
sewardje539a402004-07-14 18:24:17 +00001356 irbb->next = mkU32(d32_true);
1357 irbb->jumpkind = Ijk_Boring;
sewardje87b4842004-07-10 12:23:30 +00001358 } else {
sewardj78c19df2004-07-12 22:49:27 +00001359 stmt( IRStmt_Exit( calculate_condition(condPos),
1360 IRConst_U32(d32_true) ) );
sewardje539a402004-07-14 18:24:17 +00001361 irbb->next = mkU32(d32_false);
1362 irbb->jumpkind = Ijk_Boring;
sewardje87b4842004-07-10 12:23:30 +00001363 }
1364}
sewardjc9a65702004-07-07 16:32:57 +00001365
1366
sewardjd1061ab2004-07-08 01:45:30 +00001367/*------------------------------------------------------------*/
1368/*--- Disassembling addressing modes ---*/
1369/*------------------------------------------------------------*/
sewardjc9a65702004-07-07 16:32:57 +00001370
sewardjd1061ab2004-07-08 01:45:30 +00001371static
1372UChar* sorbTxt ( UChar sorb )
1373{
1374 switch (sorb) {
1375 case 0: return ""; /* no override */
1376 case 0x3E: return "%ds";
1377 case 0x26: return "%es:";
1378 case 0x64: return "%fs:";
1379 case 0x65: return "%gs:";
1380 default: vpanic("sorbTxt(x86)");
1381 }
1382}
1383
1384
1385/* Tmp is a TempReg holding a virtual address. Convert it to a linear
1386 address by adding any required segment override as indicated by
1387 sorb. */
1388static
1389IRExpr* handleSegOverride ( UChar sorb, IRExpr* virtual )
1390{
1391 //Int sreg, tsreg;
1392
1393 if (sorb == 0)
1394 /* the common case - no override */
1395 return virtual;
1396
1397 unimplemented("segment overrides in new x86->IR phase");
1398#if 0
1399 switch (sorb) {
1400 case 0x3E: sreg = R_DS; break;
1401 case 0x26: sreg = R_ES; break;
1402 case 0x64: sreg = R_FS; break;
1403 case 0x65: sreg = R_GS; break;
1404 default: VG_(core_panic)("handleSegOverride");
1405 }
1406
1407 tsreg = newTemp(cb);
1408
1409 /* sreg -> tsreg */
1410 uInstr2(cb, GETSEG, 2, ArchRegS, sreg, TempReg, tsreg );
1411
1412 /* tmp += segment_base(ldt[tsreg]); also do limit check */
1413 uInstr2(cb, USESEG, 0, TempReg, tsreg, TempReg, tmp );
1414#endif
1415}
1416
1417
1418/* Generate IR to calculate an address indicated by a ModRM and
1419 following SIB bytes. The expression, and the number of bytes in
1420 the address mode, are returned. Note that this fn should not be
1421 called if the R/M part of the address denotes a register instead of
1422 memory. If print_codegen is true, text of the addressing mode is
sewardj940e8c92004-07-11 16:53:24 +00001423 placed in buf.
1424
1425 The computed address is stored in a new tempreg, and the
1426 identity of the tempreg is returned. */
1427
1428static IRTemp disAMode_copy2tmp ( IRExpr* addr32 )
1429{
1430 IRTemp tmp = newTemp(Ity_I32);
1431 assign( tmp, addr32 );
1432 return tmp;
1433}
sewardjd1061ab2004-07-08 01:45:30 +00001434
1435static
sewardj940e8c92004-07-11 16:53:24 +00001436IRTemp disAMode ( Int* len, UChar sorb, UInt delta, UChar* buf )
sewardjd1061ab2004-07-08 01:45:30 +00001437{
1438 UChar mod_reg_rm = getIByte(delta);
1439 delta++;
1440
1441 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1442 jump table seems a bit excessive.
1443 */
1444 mod_reg_rm &= 0xC7; /* is now XX000YYY */
1445 mod_reg_rm |= (mod_reg_rm >> 3); /* is now XX0XXYYY */
1446 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
1447 switch (mod_reg_rm) {
1448
1449 /* (%eax) .. (%edi), not including (%esp) or (%ebp).
1450 --> GET %reg, t
1451 */
1452 case 0x00: case 0x01: case 0x02: case 0x03:
1453 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1454 { UChar rm = mod_reg_rm;
1455 DIS(buf, "%s(%s)", sorbTxt(sorb), nameIReg(4,rm));
1456 *len = 1;
sewardj940e8c92004-07-11 16:53:24 +00001457 return disAMode_copy2tmp(
1458 handleSegOverride(sorb, getIReg(4,rm)));
sewardjd1061ab2004-07-08 01:45:30 +00001459 }
1460
1461 /* d8(%eax) ... d8(%edi), not including d8(%esp)
1462 --> GET %reg, t ; ADDL d8, t
1463 */
1464 case 0x08: case 0x09: case 0x0A: case 0x0B:
1465 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1466 { UChar rm = mod_reg_rm & 7;
1467 UInt d = getSDisp8(delta);
1468 DIS(buf, "%s%d(%s)", sorbTxt(sorb), d, nameIReg(4,rm));
1469 *len = 2;
sewardj940e8c92004-07-11 16:53:24 +00001470 return disAMode_copy2tmp(
1471 handleSegOverride(sorb,
1472 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001473 }
1474
1475 /* d32(%eax) ... d32(%edi), not including d32(%esp)
1476 --> GET %reg, t ; ADDL d8, t
1477 */
1478 case 0x10: case 0x11: case 0x12: case 0x13:
1479 /* ! 14 */ case 0x15: case 0x16: case 0x17:
1480 { UChar rm = mod_reg_rm & 7;
1481 UInt d = getUDisp32(delta);
1482 DIS(buf, "%s0x%x(%s)", sorbTxt(sorb), d, nameIReg(4,rm));
1483 *len = 5;
sewardj940e8c92004-07-11 16:53:24 +00001484 return disAMode_copy2tmp(
1485 handleSegOverride(sorb,
1486 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001487 }
1488
1489 /* a register, %eax .. %edi. This shouldn't happen. */
1490 case 0x18: case 0x19: case 0x1A: case 0x1B:
1491 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1492 vpanic("disAMode(x86): not an addr!");
1493
1494 /* a 32-bit literal address
1495 --> MOV d32, tmp
1496 */
1497 case 0x05:
1498 { UInt d = getUDisp32(delta);
1499 *len = 5;
1500 DIS(buf, "%s(0x%x)", sorbTxt(sorb), d);
sewardj940e8c92004-07-11 16:53:24 +00001501 return disAMode_copy2tmp(
1502 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001503 }
1504
1505 case 0x04: {
1506 /* SIB, with no displacement. Special cases:
1507 -- %esp cannot act as an index value.
1508 If index_r indicates %esp, zero is used for the index.
1509 -- when mod is zero and base indicates EBP, base is instead
1510 a 32-bit literal.
1511 It's all madness, I tell you. Extract %index, %base and
1512 scale from the SIB byte. The value denoted is then:
1513 | %index == %ESP && %base == %EBP
1514 = d32 following SIB byte
1515 | %index == %ESP && %base != %EBP
1516 = %base
1517 | %index != %ESP && %base == %EBP
1518 = d32 following SIB byte + (%index << scale)
1519 | %index != %ESP && %base != %ESP
1520 = %base + (%index << scale)
1521
1522 What happens to the souls of CPU architects who dream up such
1523 horrendous schemes, do you suppose?
1524 */
1525 UChar sib = getIByte(delta);
1526 UChar scale = (sib >> 6) & 3;
1527 UChar index_r = (sib >> 3) & 7;
1528 UChar base_r = sib & 7;
1529 delta++;
1530
1531 if (index_r != R_ESP && base_r != R_EBP) {
1532 DIS(buf, "%s(%s,%s,%d)", sorbTxt(sorb),
1533 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
1534 *len = 2;
sewardj940e8c92004-07-11 16:53:24 +00001535 return
1536 disAMode_copy2tmp(
sewardjd1061ab2004-07-08 01:45:30 +00001537 handleSegOverride(sorb,
1538 binop(Iop_Add32,
1539 getIReg(4,base_r),
1540 binop(Iop_Shl32, getIReg(4,index_r),
sewardj6d2638e2004-07-15 09:38:27 +00001541 mkU8(scale)))));
sewardjd1061ab2004-07-08 01:45:30 +00001542 }
1543
1544 if (index_r != R_ESP && base_r == R_EBP) {
1545 UInt d = getUDisp32(delta);
1546 DIS(buf, "%s0x%x(,%s,%d)", sorbTxt(sorb), d,
1547 nameIReg(4,index_r), 1<<scale);
1548 *len = 6;
1549 return
sewardj940e8c92004-07-11 16:53:24 +00001550 disAMode_copy2tmp(
sewardjd1061ab2004-07-08 01:45:30 +00001551 handleSegOverride(sorb,
1552 binop(Iop_Add32,
sewardj6d2638e2004-07-15 09:38:27 +00001553 binop(Iop_Shl32, getIReg(4,index_r), mkU8(scale)),
sewardj940e8c92004-07-11 16:53:24 +00001554 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001555 }
1556
1557 if (index_r == R_ESP && base_r != R_EBP) {
1558 DIS(buf, "%s(%s,,)", sorbTxt(sorb), nameIReg(4,base_r));
1559 *len = 2;
sewardj940e8c92004-07-11 16:53:24 +00001560 return disAMode_copy2tmp(
1561 handleSegOverride(sorb, getIReg(4,base_r)));
sewardjd1061ab2004-07-08 01:45:30 +00001562 }
1563
1564 if (index_r == R_ESP && base_r == R_EBP) {
1565 UInt d = getUDisp32(delta);
1566 DIS(buf, "%s0x%x()", sorbTxt(sorb), d);
1567 *len = 6;
sewardj41f43bc2004-07-08 14:23:22 +00001568 vpanic("amode 8");
sewardj940e8c92004-07-11 16:53:24 +00001569 return disAMode_copy2tmp(
1570 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001571 }
1572
1573 vassert(0);
1574 }
1575
1576 /* SIB, with 8-bit displacement. Special cases:
1577 -- %esp cannot act as an index value.
1578 If index_r indicates %esp, zero is used for the index.
1579 Denoted value is:
1580 | %index == %ESP
1581 = d8 + %base
1582 | %index != %ESP
1583 = d8 + %base + (%index << scale)
1584 */
1585 case 0x0C: {
1586 UChar sib = getIByte(delta);
1587 UChar scale = (sib >> 6) & 3;
1588 UChar index_r = (sib >> 3) & 7;
1589 UChar base_r = sib & 7;
1590 UInt d = getSDisp8(delta+1);
1591
1592 if (index_r == R_ESP) {
1593 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb), d, nameIReg(4,base_r));
1594 *len = 3;
sewardj940e8c92004-07-11 16:53:24 +00001595 return disAMode_copy2tmp(
1596 handleSegOverride(sorb,
1597 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001598 } else {
1599 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), d,
1600 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
1601 *len = 3;
sewardj77b86be2004-07-11 13:28:24 +00001602 return
sewardj940e8c92004-07-11 16:53:24 +00001603 disAMode_copy2tmp(
1604 handleSegOverride(sorb,
sewardj77b86be2004-07-11 13:28:24 +00001605 binop(Iop_Add32,
1606 binop(Iop_Add32,
1607 getIReg(4,base_r),
1608 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001609 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001610 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001611 }
1612 vassert(0);
1613 }
1614
1615 /* SIB, with 32-bit displacement. Special cases:
1616 -- %esp cannot act as an index value.
1617 If index_r indicates %esp, zero is used for the index.
1618 Denoted value is:
1619 | %index == %ESP
1620 = d32 + %base
1621 | %index != %ESP
1622 = d32 + %base + (%index << scale)
1623 */
1624 case 0x14: {
1625 UChar sib = getIByte(delta);
1626 UChar scale = (sib >> 6) & 3;
1627 UChar index_r = (sib >> 3) & 7;
1628 UChar base_r = sib & 7;
1629 UInt d = getUDisp32(delta+1);
1630
1631 if (index_r == R_ESP) {
1632 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb), d, nameIReg(4,base_r));
1633 *len = 6;
sewardj940e8c92004-07-11 16:53:24 +00001634 return disAMode_copy2tmp(
1635 handleSegOverride(sorb,
1636 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001637 } else {
1638 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), d,
1639 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
1640 *len = 6;
sewardj9334b0f2004-07-10 22:43:54 +00001641 return
sewardj940e8c92004-07-11 16:53:24 +00001642 disAMode_copy2tmp(
1643 handleSegOverride(sorb,
sewardj9334b0f2004-07-10 22:43:54 +00001644 binop(Iop_Add32,
1645 binop(Iop_Add32,
1646 getIReg(4,base_r),
1647 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001648 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001649 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001650 }
1651 vassert(0);
1652 }
1653
1654 default:
1655 vpanic("disAMode(x86)");
1656 return 0; /*notreached*/
1657 }
1658}
1659
1660
1661/* Figure out the number of (insn-stream) bytes constituting the amode
1662 beginning at delta. Is useful for getting hold of literals beyond
1663 the end of the amode before it has been disassembled. */
1664
1665static UInt lengthAMode ( UInt delta )
1666{
1667 UChar mod_reg_rm = getIByte(delta); delta++;
1668
1669 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1670 jump table seems a bit excessive.
1671 */
1672 mod_reg_rm &= 0xC7; /* is now XX000YYY */
1673 mod_reg_rm |= (mod_reg_rm >> 3); /* is now XX0XXYYY */
1674 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
1675 switch (mod_reg_rm) {
1676
1677 /* (%eax) .. (%edi), not including (%esp) or (%ebp). */
1678 case 0x00: case 0x01: case 0x02: case 0x03:
1679 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1680 return 1;
1681
1682 /* d8(%eax) ... d8(%edi), not including d8(%esp). */
1683 case 0x08: case 0x09: case 0x0A: case 0x0B:
1684 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1685 return 2;
1686
1687 /* d32(%eax) ... d32(%edi), not including d32(%esp). */
1688 case 0x10: case 0x11: case 0x12: case 0x13:
1689 /* ! 14 */ case 0x15: case 0x16: case 0x17:
1690 return 5;
1691
1692 /* a register, %eax .. %edi. (Not an addr, but still handled.) */
1693 case 0x18: case 0x19: case 0x1A: case 0x1B:
1694 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1695 return 1;
1696
1697 /* a 32-bit literal address. */
1698 case 0x05: return 5;
1699
1700 /* SIB, no displacement. */
1701 case 0x04: {
1702 UChar sib = getIByte(delta);
1703 UChar base_r = sib & 7;
1704 if (base_r == R_EBP) return 6; else return 2;
1705 }
1706 /* SIB, with 8-bit displacement. */
1707 case 0x0C: return 3;
1708
1709 /* SIB, with 32-bit displacement. */
1710 case 0x14: return 6;
1711
1712 default:
1713 vpanic("lengthAMode");
1714 return 0; /*notreached*/
1715 }
1716}
1717
1718/*------------------------------------------------------------*/
1719/*--- Disassembling common idioms ---*/
1720/*------------------------------------------------------------*/
1721
sewardj5df3bfe2004-07-27 09:30:31 +00001722static
1723void codegen_XOR_reg_with_itself ( Int size, Int ge_reg )
1724{
1725 IRType ty = szToITy(size);
1726 /* reg := 0 */
1727 putIReg(size, ge_reg, mkU(ty,0));
1728 /* Flags: C,A,O=0, Z=1, S=0, P=1 */
1729 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
1730 stmt( IRStmt_Put( OFFB_CC_SRC, mkU32(CC_MASK_Z|CC_MASK_P) ));
1731 stmt( IRStmt_Put( OFFB_CC_DST, mkU32(0) ));
1732 DIP("xor%c %s, %s\n", nameISize(size),
1733 nameIReg(size,ge_reg), nameIReg(size,ge_reg) );
1734}
1735
1736
sewardje87b4842004-07-10 12:23:30 +00001737/* Handle binary integer instructions of the form
1738 op E, G meaning
1739 op reg-or-mem, reg
1740 Is passed the a ptr to the modRM byte, the actual operation, and the
1741 data size. Returns the address advanced completely over this
1742 instruction.
1743
1744 E(src) is reg-or-mem
1745 G(dst) is reg.
1746
1747 If E is reg, --> GET %G, tmp
1748 OP %E, tmp
1749 PUT tmp, %G
1750
1751 If E is mem and OP is not reversible,
1752 --> (getAddr E) -> tmpa
1753 LD (tmpa), tmpa
1754 GET %G, tmp2
1755 OP tmpa, tmp2
1756 PUT tmp2, %G
1757
1758 If E is mem and OP is reversible
1759 --> (getAddr E) -> tmpa
1760 LD (tmpa), tmpa
1761 OP %G, tmpa
1762 PUT tmpa, %G
1763*/
1764static
1765UInt dis_op2_E_G ( UChar sorb,
sewardj180e8b32004-07-29 01:40:11 +00001766 Bool addSubCarry,
sewardje87b4842004-07-10 12:23:30 +00001767 IROp op8,
1768 Bool keep,
1769 Int size,
1770 UInt delta0,
1771 Char* t_x86opc )
1772{
sewardj9334b0f2004-07-10 22:43:54 +00001773 UChar dis_buf[50];
1774 Int len;
sewardje87b4842004-07-10 12:23:30 +00001775 IRType ty = szToITy(size);
1776 IRTemp dst1 = newTemp(ty);
1777 IRTemp src = newTemp(ty);
1778 IRTemp dst0 = newTemp(ty);
1779 UChar rm = getUChar(delta0);
sewardj940e8c92004-07-11 16:53:24 +00001780 IRTemp addr = INVALID_IRTEMP;
sewardje87b4842004-07-10 12:23:30 +00001781
sewardj180e8b32004-07-29 01:40:11 +00001782 /* addSubCarry == True indicates the intended operation is
1783 add-with-carry or subtract-with-borrow. */
1784 if (addSubCarry) {
1785 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1786 vassert(keep);
1787 }
1788
sewardje87b4842004-07-10 12:23:30 +00001789 if (epartIsReg(rm)) {
sewardje87b4842004-07-10 12:23:30 +00001790 /* Specially handle XOR reg,reg, because that doesn't really
1791 depend on reg, and doing the obvious thing potentially
1792 generates a spurious value check failure due to the bogus
1793 dependency. */
sewardj5df3bfe2004-07-27 09:30:31 +00001794 if (op8 == Iop_Xor8 && gregOfRM(rm) == eregOfRM(rm)) {
1795 codegen_XOR_reg_with_itself ( size, gregOfRM(rm) );
1796 return 1+delta0;
sewardje87b4842004-07-10 12:23:30 +00001797 }
sewardje87b4842004-07-10 12:23:30 +00001798 assign( dst0, getIReg(size,gregOfRM(rm)) );
1799 assign( src, getIReg(size,eregOfRM(rm)) );
sewardje87b4842004-07-10 12:23:30 +00001800
sewardj180e8b32004-07-29 01:40:11 +00001801 if (addSubCarry && op8 == Iop_Add8) {
1802 vassert(0);
1803 helper_ADC( size, dst1, dst0, src );
sewardje87b4842004-07-10 12:23:30 +00001804 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00001805 } else
1806 if (addSubCarry && op8 == Iop_Sub8) {
1807 vassert(0);
1808 helper_SBB( size, dst1, dst0, src );
1809 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1810 } else {
1811 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardjb9c5cf62004-08-24 15:10:38 +00001812 if (isAddSub(op8))
1813 setFlags_ADD_SUB(op8, src, dst0, ty);
1814 else
1815 setFlags_LOGIC(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00001816 if (keep)
1817 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1818 }
sewardje87b4842004-07-10 12:23:30 +00001819
1820 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1821 nameIReg(size,eregOfRM(rm)),
1822 nameIReg(size,gregOfRM(rm)));
1823 return 1+delta0;
sewardje87b4842004-07-10 12:23:30 +00001824 } else {
sewardj9334b0f2004-07-10 22:43:54 +00001825 /* E refers to memory */
1826 addr = disAMode ( &len, sorb, delta0, dis_buf);
1827 assign( dst0, getIReg(size,gregOfRM(rm)) );
sewardj940e8c92004-07-11 16:53:24 +00001828 assign( src, loadLE(szToITy(size), mkexpr(addr)) );
sewardj9334b0f2004-07-10 22:43:54 +00001829
sewardj180e8b32004-07-29 01:40:11 +00001830 if (addSubCarry && op8 == Iop_Add8) {
sewardj180e8b32004-07-29 01:40:11 +00001831 helper_ADC( size, dst1, dst0, src );
sewardj9334b0f2004-07-10 22:43:54 +00001832 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00001833 } else
1834 if (addSubCarry && op8 == Iop_Sub8) {
1835 helper_SBB( size, dst1, dst0, src );
1836 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1837 } else {
1838 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardjb9c5cf62004-08-24 15:10:38 +00001839 if (isAddSub(op8))
1840 setFlags_ADD_SUB(op8, src, dst0, ty);
1841 else
1842 setFlags_LOGIC(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00001843 if (keep)
1844 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1845 }
sewardj9334b0f2004-07-10 22:43:54 +00001846
sewardje87b4842004-07-10 12:23:30 +00001847 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1848 dis_buf,nameIReg(size,gregOfRM(rm)));
sewardj9334b0f2004-07-10 22:43:54 +00001849 return len+delta0;
sewardje87b4842004-07-10 12:23:30 +00001850 }
sewardje87b4842004-07-10 12:23:30 +00001851}
sewardje05c42c2004-07-08 20:25:10 +00001852
1853
1854
1855/* Handle binary integer instructions of the form
1856 op G, E meaning
1857 op reg, reg-or-mem
1858 Is passed the a ptr to the modRM byte, the actual operation, and the
1859 data size. Returns the address advanced completely over this
1860 instruction.
1861
1862 G(src) is reg.
1863 E(dst) is reg-or-mem
1864
1865 If E is reg, --> GET %E, tmp
1866 OP %G, tmp
1867 PUT tmp, %E
1868
1869 If E is mem, --> (getAddr E) -> tmpa
1870 LD (tmpa), tmpv
1871 OP %G, tmpv
1872 ST tmpv, (tmpa)
1873*/
1874static
1875UInt dis_op2_G_E ( UChar sorb,
sewardjcaca9d02004-07-28 07:11:32 +00001876 Bool addSubCarry,
sewardje05c42c2004-07-08 20:25:10 +00001877 IROp op8,
1878 Bool keep,
1879 Int size,
1880 UInt delta0,
1881 Char* t_x86opc )
1882{
sewardje87b4842004-07-10 12:23:30 +00001883 UChar dis_buf[50];
1884 Int len;
sewardje05c42c2004-07-08 20:25:10 +00001885 IRType ty = szToITy(size);
1886 IRTemp dst1 = newTemp(ty);
1887 IRTemp src = newTemp(ty);
1888 IRTemp dst0 = newTemp(ty);
1889 UChar rm = getIByte(delta0);
sewardj940e8c92004-07-11 16:53:24 +00001890 IRTemp addr = INVALID_IRTEMP;
sewardje05c42c2004-07-08 20:25:10 +00001891
sewardjcaca9d02004-07-28 07:11:32 +00001892 /* addSubCarry == True indicates the intended operation is
1893 add-with-carry or subtract-with-borrow. */
1894 if (addSubCarry) {
1895 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1896 vassert(keep);
1897 }
1898
sewardje05c42c2004-07-08 20:25:10 +00001899 if (epartIsReg(rm)) {
sewardje05c42c2004-07-08 20:25:10 +00001900 /* Specially handle XOR reg,reg, because that doesn't really
1901 depend on reg, and doing the obvious thing potentially
1902 generates a spurious value check failure due to the bogus
1903 dependency. */
sewardj5df3bfe2004-07-27 09:30:31 +00001904 if (op8 == Iop_Xor8 && gregOfRM(rm) == eregOfRM(rm)) {
1905 codegen_XOR_reg_with_itself ( size, gregOfRM(rm) );
1906 return 1+delta0;
sewardje05c42c2004-07-08 20:25:10 +00001907 }
sewardje05c42c2004-07-08 20:25:10 +00001908 assign(dst0, getIReg(size,eregOfRM(rm)));
1909 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00001910
sewardjcaca9d02004-07-28 07:11:32 +00001911 if (addSubCarry && op8 == Iop_Add8) {
sewardj1813dbe2004-07-28 17:09:04 +00001912 helper_ADC( size, dst1, dst0, src );
1913 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00001914 } else
1915 if (addSubCarry && op8 == Iop_Sub8) {
1916 helper_SBB( size, dst1, dst0, src );
sewardje05c42c2004-07-08 20:25:10 +00001917 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00001918 } else {
1919 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardjb9c5cf62004-08-24 15:10:38 +00001920 if (isAddSub(op8))
1921 setFlags_ADD_SUB(op8, src, dst0, ty);
1922 else
1923 setFlags_LOGIC(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00001924 if (keep)
1925 putIReg(size, eregOfRM(rm), mkexpr(dst1));
1926 }
sewardje05c42c2004-07-08 20:25:10 +00001927
1928 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1929 nameIReg(size,gregOfRM(rm)),
1930 nameIReg(size,eregOfRM(rm)));
1931 return 1+delta0;
1932 }
1933
1934 /* E refers to memory */
1935 {
sewardje87b4842004-07-10 12:23:30 +00001936 addr = disAMode ( &len, sorb, delta0, dis_buf);
sewardj940e8c92004-07-11 16:53:24 +00001937 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardje87b4842004-07-10 12:23:30 +00001938 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00001939
sewardjcaca9d02004-07-28 07:11:32 +00001940 if (addSubCarry && op8 == Iop_Add8) {
1941 helper_ADC( size, dst1, dst0, src );
1942 storeLE(mkexpr(addr), mkexpr(dst1));
1943 } else
1944 if (addSubCarry && op8 == Iop_Sub8) {
1945 helper_SBB( size, dst1, dst0, src );
1946 storeLE(mkexpr(addr), mkexpr(dst1));
1947 } else {
1948 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardjb9c5cf62004-08-24 15:10:38 +00001949 if (isAddSub(op8))
1950 setFlags_ADD_SUB(op8, src, dst0, ty);
1951 else
1952 setFlags_LOGIC(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00001953 if (keep)
1954 storeLE(mkexpr(addr), mkexpr(dst1));
1955 }
sewardje87b4842004-07-10 12:23:30 +00001956
sewardje05c42c2004-07-08 20:25:10 +00001957 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1958 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje87b4842004-07-10 12:23:30 +00001959 return len+delta0;
sewardje05c42c2004-07-08 20:25:10 +00001960 }
1961}
1962
1963
1964/* Handle move instructions of the form
1965 mov E, G meaning
1966 mov reg-or-mem, reg
1967 Is passed the a ptr to the modRM byte, and the data size. Returns
1968 the address advanced completely over this instruction.
1969
1970 E(src) is reg-or-mem
1971 G(dst) is reg.
1972
1973 If E is reg, --> GET %E, tmpv
1974 PUT tmpv, %G
1975
1976 If E is mem --> (getAddr E) -> tmpa
1977 LD (tmpa), tmpb
1978 PUT tmpb, %G
1979*/
1980static
1981UInt dis_mov_E_G ( UChar sorb,
1982 Int size,
1983 UInt delta0 )
1984{
1985 Int len;
1986 UChar rm = getIByte(delta0);
1987 UChar dis_buf[50];
1988
1989 if (epartIsReg(rm)) {
1990#if 0
1991 Int tmpv = newTemp(cb);
1992 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, tmpv);
1993 uInstr2(cb, PUT, size, TempReg, tmpv, ArchReg, gregOfRM(rm));
1994 DIP("mov%c %s,%s\n", nameISize(size),
1995 nameIReg(size,eregOfRM(rm)),
1996 nameIReg(size,gregOfRM(rm)));
1997 return 1+eip0;
1998#endif
1999 vassert(121221==0);
2000 }
2001
2002 /* E refers to memory */
2003 {
sewardj940e8c92004-07-11 16:53:24 +00002004 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
2005 putIReg(size, gregOfRM(rm), loadLE(szToITy(size), mkexpr(addr)));
sewardje05c42c2004-07-08 20:25:10 +00002006 DIP("mov%c %s,%s\n", nameISize(size),
2007 dis_buf,nameIReg(size,gregOfRM(rm)));
2008 return delta0+len;
2009 }
2010}
2011
2012
2013/* Handle move instructions of the form
2014 mov G, E meaning
2015 mov reg, reg-or-mem
2016 Is passed the a ptr to the modRM byte, and the data size. Returns
2017 the address advanced completely over this instruction.
2018
2019 G(src) is reg.
2020 E(dst) is reg-or-mem
2021
2022 If E is reg, --> GET %G, tmp
2023 PUT tmp, %E
2024
2025 If E is mem, --> (getAddr E) -> tmpa
2026 GET %G, tmpv
2027 ST tmpv, (tmpa)
2028*/
sewardjc9a65702004-07-07 16:32:57 +00002029static
2030UInt dis_mov_G_E ( UChar sorb,
2031 Int size,
2032 UInt delta0 )
2033{
sewardje05c42c2004-07-08 20:25:10 +00002034 Int len;
sewardjc9a65702004-07-07 16:32:57 +00002035 UChar rm = getIByte(delta0);
sewardje05c42c2004-07-08 20:25:10 +00002036 UChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00002037
2038 if (epartIsReg(rm)) {
sewardj41f43bc2004-07-08 14:23:22 +00002039 putIReg(size, eregOfRM(rm), getIReg(size, gregOfRM(rm)));
sewardjc9a65702004-07-07 16:32:57 +00002040 DIP("mov%c %s,%s\n", nameISize(size),
2041 nameIReg(size,gregOfRM(rm)),
2042 nameIReg(size,eregOfRM(rm)));
2043 return 1+delta0;
2044 }
2045
sewardjc9a65702004-07-07 16:32:57 +00002046 /* E refers to memory */
2047 {
sewardj940e8c92004-07-11 16:53:24 +00002048 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf);
2049 storeLE( mkexpr(addr), getIReg(size, gregOfRM(rm)) );
sewardjc9a65702004-07-07 16:32:57 +00002050 DIP("mov%c %s,%s\n", nameISize(size),
2051 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje05c42c2004-07-08 20:25:10 +00002052 return len+delta0;
sewardjc9a65702004-07-07 16:32:57 +00002053 }
sewardjc9a65702004-07-07 16:32:57 +00002054}
2055
2056
sewardj0611d802004-07-11 02:37:54 +00002057/* op $immediate, AL/AX/EAX. */
2058static
2059UInt dis_op_imm_A ( Int size,
2060 IROp op8,
2061 Bool keep,
2062 UInt delta,
2063 Char* t_x86opc )
2064{
2065 IRType ty = szToITy(size);
2066 IRTemp dst0 = newTemp(ty);
2067 IRTemp src = newTemp(ty);
2068 IRTemp dst1 = newTemp(ty);
2069 UInt lit = getUDisp(size,delta);
2070 assign(dst0, getIReg(size,R_EAX));
2071 assign(src, mkU(ty,lit));
2072 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardjb9c5cf62004-08-24 15:10:38 +00002073 if (isAddSub(op8))
2074 setFlags_ADD_SUB(op8, src, dst0, ty);
2075 else
2076 setFlags_LOGIC(op8, dst1, ty);
sewardj0611d802004-07-11 02:37:54 +00002077
2078 if (keep)
2079 putIReg(size, R_EAX, mkexpr(dst1));
2080
2081 DIP("%s%c $0x%x, %s\n", t_x86opc, nameISize(size),
2082 lit, nameIReg(size,R_EAX));
2083 return delta+size;
2084}
sewardj9334b0f2004-07-10 22:43:54 +00002085
2086
2087/* Sign- and Zero-extending moves. */
2088static
2089UInt dis_movx_E_G ( UChar sorb,
2090 UInt delta, Int szs, Int szd, Bool sign_extend )
2091{
sewardj9334b0f2004-07-10 22:43:54 +00002092 UChar rm = getIByte(delta);
2093 if (epartIsReg(rm)) {
2094 putIReg(szd, gregOfRM(rm),
sewardjc4eaff32004-09-10 20:25:11 +00002095 unop(mkWidenOp(szs,szd,sign_extend),
sewardj9334b0f2004-07-10 22:43:54 +00002096 getIReg(szs,eregOfRM(rm))));
2097 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2098 nameISize(szs), nameISize(szd),
2099 nameIReg(szs,eregOfRM(rm)),
2100 nameIReg(szd,gregOfRM(rm)));
2101 return 1+delta;
2102 }
2103
2104 /* E refers to memory */
2105 {
sewardj940e8c92004-07-11 16:53:24 +00002106 Int len;
2107 UChar dis_buf[50];
2108 IRTemp addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj0611d802004-07-11 02:37:54 +00002109
2110 putIReg(szd, gregOfRM(rm),
sewardjc4eaff32004-09-10 20:25:11 +00002111 unop(mkWidenOp(szs,szd,sign_extend),
sewardj940e8c92004-07-11 16:53:24 +00002112 loadLE(szToITy(szs),mkexpr(addr))));
sewardj9334b0f2004-07-10 22:43:54 +00002113 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2114 nameISize(szs), nameISize(szd),
2115 dis_buf, nameIReg(szd,gregOfRM(rm)));
sewardj0611d802004-07-11 02:37:54 +00002116 return len+delta;
sewardj9334b0f2004-07-10 22:43:54 +00002117 }
2118}
2119
sewardj9690d922004-07-14 01:39:17 +00002120
2121/* Generate code to divide ArchRegs EDX:EAX / DX:AX / AX by the 32 /
2122 16 / 8 bit quantity in the given IRTemp. */
2123static
2124void codegen_div ( Int sz, IRTemp t, Bool signed_divide )
2125{
sewardje5427e82004-09-11 19:43:51 +00002126 IROp op = signed_divide ? Iop_DivModS64to32 : Iop_DivModU64to32;
2127 IRTemp src64 = newTemp(Ity_I64);
2128 IRTemp dst64 = newTemp(Ity_I64);
sewardj9690d922004-07-14 01:39:17 +00002129 switch (sz) {
sewardje5427e82004-09-11 19:43:51 +00002130 case 4:
sewardj9690d922004-07-14 01:39:17 +00002131 assign( src64, binop(Iop_32HLto64,
sewardje5427e82004-09-11 19:43:51 +00002132 getIReg(4,R_EDX), getIReg(4,R_EAX)) );
sewardj9690d922004-07-14 01:39:17 +00002133 assign( dst64, binop(op, mkexpr(src64), mkexpr(t)) );
sewardj8c7f1ab2004-07-29 20:31:09 +00002134 putIReg( 4, R_EAX, unop(Iop_64to32,mkexpr(dst64)) );
sewardj9690d922004-07-14 01:39:17 +00002135 putIReg( 4, R_EDX, unop(Iop_64HIto32,mkexpr(dst64)) );
2136 break;
sewardje5427e82004-09-11 19:43:51 +00002137 case 2: {
2138 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2139 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2140 assign( src64, unop(widen3264,
2141 binop(Iop_16HLto32,
2142 getIReg(2,R_EDX), getIReg(2,R_EAX))) );
2143 assign( dst64, binop(op, mkexpr(src64), unop(widen1632,mkexpr(t))) );
2144 putIReg( 2, R_EAX, unop(Iop_32to16,unop(Iop_64to32,mkexpr(dst64))) );
2145 putIReg( 2, R_EDX, unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(dst64))) );
2146 break;
sewardj9690d922004-07-14 01:39:17 +00002147 }
sewardj4e82db72004-10-16 11:32:15 +00002148 case 1: {
2149 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2150 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2151 IROp widen816 = signed_divide ? Iop_8Sto16 : Iop_8Uto16;
2152 assign( src64, unop(widen3264, unop(widen1632, getIReg(2,R_EAX))) );
2153 assign( dst64,
2154 binop(op, mkexpr(src64),
2155 unop(widen1632, unop(widen816, mkexpr(t)))) );
2156 putIReg( 1, R_AL, unop(Iop_16to8, unop(Iop_32to16,
2157 unop(Iop_64to32,mkexpr(dst64)))) );
2158 putIReg( 1, R_AH, unop(Iop_16to8, unop(Iop_32to16,
2159 unop(Iop_64HIto32,mkexpr(dst64)))) );
2160 break;
2161 }
sewardj9690d922004-07-14 01:39:17 +00002162 default: vpanic("codegen_div(x86)");
2163 }
2164}
sewardjc9a65702004-07-07 16:32:57 +00002165//-- Int helper;
2166//-- Int ta = newTemp(cb);
2167//-- Int td = newTemp(cb);
2168//--
2169//-- switch (sz) {
2170//-- case 4: helper = (signed_divide ? VGOFF_(helper_idiv_64_32)
2171//-- : VGOFF_(helper_div_64_32));
2172//-- break;
2173//-- case 2: helper = (signed_divide ? VGOFF_(helper_idiv_32_16)
2174//-- : VGOFF_(helper_div_32_16));
2175//-- break;
2176//-- case 1: helper = (signed_divide ? VGOFF_(helper_idiv_16_8)
2177//-- : VGOFF_(helper_div_16_8));
2178//-- break;
2179//-- default: VG_(core_panic)("codegen_div");
2180//-- }
2181//-- uInstr0(cb, CALLM_S, 0);
2182//-- if (sz == 4 || sz == 2) {
2183//-- uInstr1(cb, PUSH, sz, TempReg, t);
2184//-- uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
2185//-- uInstr1(cb, PUSH, sz, TempReg, ta);
2186//-- uInstr2(cb, GET, sz, ArchReg, R_EDX, TempReg, td);
2187//-- uInstr1(cb, PUSH, sz, TempReg, td);
2188//-- uInstr1(cb, CALLM, 0, Lit16, helper);
2189//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsOSZACP);
2190//-- uInstr1(cb, POP, sz, TempReg, t);
2191//-- uInstr2(cb, PUT, sz, TempReg, t, ArchReg, R_EDX);
2192//-- uInstr1(cb, POP, sz, TempReg, t);
2193//-- uInstr2(cb, PUT, sz, TempReg, t, ArchReg, R_EAX);
2194//-- uInstr1(cb, CLEAR, 0, Lit16, 4);
2195//-- } else {
2196//-- uInstr1(cb, PUSH, 1, TempReg, t);
2197//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, ta);
2198//-- uInstr1(cb, PUSH, 2, TempReg, ta);
2199//-- uInstr2(cb, MOV, 1, Literal, 0, TempReg, td);
2200//-- uLiteral(cb, 0);
2201//-- uInstr1(cb, PUSH, 1, TempReg, td);
2202//-- uInstr1(cb, CALLM, 0, Lit16, helper);
2203//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsOSZACP);
2204//-- uInstr1(cb, POP, 1, TempReg, t);
2205//-- uInstr2(cb, PUT, 1, TempReg, t, ArchReg, R_AL);
2206//-- uInstr1(cb, POP, 1, TempReg, t);
2207//-- uInstr2(cb, PUT, 1, TempReg, t, ArchReg, R_AH);
2208//-- uInstr1(cb, CLEAR, 0, Lit16, 4);
2209//-- }
2210//-- uInstr0(cb, CALLM_E, 0);
2211//-- }
sewardj41f43bc2004-07-08 14:23:22 +00002212
2213
2214static
sewardje90ad6a2004-07-10 19:02:10 +00002215UInt dis_Grp1 ( UChar sorb,
sewardj41f43bc2004-07-08 14:23:22 +00002216 UInt delta, UChar modrm,
2217 Int am_sz, Int d_sz, Int sz, UInt d32 )
2218{
sewardj41f43bc2004-07-08 14:23:22 +00002219 Int len;
2220 UChar dis_buf[50];
sewardje05c42c2004-07-08 20:25:10 +00002221 IRType ty = szToITy(sz);
2222 IRTemp dst1 = newTemp(ty);
2223 IRTemp src = newTemp(ty);
2224 IRTemp dst0 = newTemp(ty);
sewardj940e8c92004-07-11 16:53:24 +00002225 IRTemp addr = INVALID_IRTEMP;
sewardj66de2272004-07-16 21:19:05 +00002226 IROp op8 = Iop_INVALID;
sewardj180e8b32004-07-29 01:40:11 +00002227 UInt mask = sz==1 ? 0xFF : (sz==2 ? 0xFFFF : 0xFFFFFFFF);
sewardj41f43bc2004-07-08 14:23:22 +00002228
2229 switch (gregOfRM(modrm)) {
sewardje05c42c2004-07-08 20:25:10 +00002230 case 0: op8 = Iop_Add8; break; case 1: op8 = Iop_Or8; break;
sewardj66de2272004-07-16 21:19:05 +00002231 case 2: break; // ADC
2232 case 3: break; // SBB
sewardje05c42c2004-07-08 20:25:10 +00002233 case 4: op8 = Iop_And8; break; case 5: op8 = Iop_Sub8; break;
2234 case 6: op8 = Iop_Xor8; break; case 7: op8 = Iop_Sub8; break;
sewardj41f43bc2004-07-08 14:23:22 +00002235 default: vpanic("dis_Grp1: unhandled case");
2236 }
sewardj41f43bc2004-07-08 14:23:22 +00002237
2238 if (epartIsReg(modrm)) {
2239 vassert(am_sz == 1);
2240
2241 assign(dst0, getIReg(sz,eregOfRM(modrm)));
sewardj180e8b32004-07-29 01:40:11 +00002242 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002243
sewardj180e8b32004-07-29 01:40:11 +00002244 if (gregOfRM(modrm) == 2 /* ADC */) {
2245 helper_ADC( sz, dst1, dst0, src );
2246 } else
2247 if (gregOfRM(modrm) == 3 /* SBB */) {
2248 helper_SBB( sz, dst1, dst0, src );
2249 } else {
2250 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardjb9c5cf62004-08-24 15:10:38 +00002251 if (isAddSub(op8))
2252 setFlags_ADD_SUB(op8, src, dst0, ty);
2253 else
2254 setFlags_LOGIC(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00002255 }
sewardj41f43bc2004-07-08 14:23:22 +00002256
2257 if (gregOfRM(modrm) < 7)
sewardje05c42c2004-07-08 20:25:10 +00002258 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardj41f43bc2004-07-08 14:23:22 +00002259
2260 delta += (am_sz + d_sz);
2261 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz), d32,
2262 nameIReg(sz,eregOfRM(modrm)));
2263 } else {
sewardje87b4842004-07-10 12:23:30 +00002264 addr = disAMode ( &len, sorb, delta, dis_buf);
sewardj41f43bc2004-07-08 14:23:22 +00002265
sewardj940e8c92004-07-11 16:53:24 +00002266 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj180e8b32004-07-29 01:40:11 +00002267 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002268
sewardj66de2272004-07-16 21:19:05 +00002269 if (gregOfRM(modrm) == 2 /* ADC */) {
sewardj3af115f2004-07-14 02:46:52 +00002270 helper_ADC( sz, dst1, dst0, src );
2271 } else
sewardj66de2272004-07-16 21:19:05 +00002272 if (gregOfRM(modrm) == 3 /* SBB */) {
sewardje166ed02004-10-25 02:27:01 +00002273 helper_SBB( sz, dst1, dst0, src );
sewardj3af115f2004-07-14 02:46:52 +00002274 } else {
2275 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardjb9c5cf62004-08-24 15:10:38 +00002276 if (isAddSub(op8))
2277 setFlags_ADD_SUB(op8, src, dst0, ty);
2278 else
2279 setFlags_LOGIC(op8, dst1, ty);
sewardj3af115f2004-07-14 02:46:52 +00002280 }
sewardj41f43bc2004-07-08 14:23:22 +00002281
2282 if (gregOfRM(modrm) < 7)
sewardj940e8c92004-07-11 16:53:24 +00002283 storeLE(mkexpr(addr), mkexpr(dst1));
sewardj41f43bc2004-07-08 14:23:22 +00002284
2285 delta += (len+d_sz);
2286 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz),
2287 d32, dis_buf);
2288 }
2289 return delta;
2290}
2291
2292
sewardj6d2638e2004-07-15 09:38:27 +00002293/* Group 2 extended opcodes. shift_expr must be an 8-bit typed
2294 expression. */
2295
sewardje90ad6a2004-07-10 19:02:10 +00002296static
2297UInt dis_Grp2 ( UChar sorb,
2298 UInt delta, UChar modrm,
sewardj6d2638e2004-07-15 09:38:27 +00002299 Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
2300 Char* shift_expr_txt )
sewardje90ad6a2004-07-10 19:02:10 +00002301{
2302 /* delta on entry points at the modrm byte. */
sewardj6d2638e2004-07-15 09:38:27 +00002303 UChar dis_buf[50];
2304 Int len;
sewardj9aebb0c2004-10-24 19:20:43 +00002305 Bool isShift, isRotate, isRotateRC;
sewardj6d2638e2004-07-15 09:38:27 +00002306 IRType ty = szToITy(sz);
2307 IRTemp dst0 = newTemp(ty);
2308 IRTemp dst1 = newTemp(ty);
2309 IRTemp addr = INVALID_IRTEMP;
sewardje90ad6a2004-07-10 19:02:10 +00002310
2311 vassert(sz == 1 || sz == 2 || sz == 4);
2312
sewardje90ad6a2004-07-10 19:02:10 +00002313 /* Put value to shift/rotate in dst0. */
2314 if (epartIsReg(modrm)) {
2315 assign(dst0, getIReg(sz, eregOfRM(modrm)));
sewardj940e8c92004-07-11 16:53:24 +00002316 delta += (am_sz + d_sz);
sewardje90ad6a2004-07-10 19:02:10 +00002317 } else {
sewardj940e8c92004-07-11 16:53:24 +00002318 addr = disAMode ( &len, sorb, delta, dis_buf);
2319 assign(dst0, loadLE(ty,mkexpr(addr)));
2320 delta += len + d_sz;
sewardje90ad6a2004-07-10 19:02:10 +00002321 }
2322
2323 isShift = False;
2324 switch (gregOfRM(modrm)) { case 4: case 5: case 7: isShift = True; }
2325
sewardj750f4072004-07-26 22:39:11 +00002326 isRotate = False;
2327 switch (gregOfRM(modrm)) { case 0: case 1: isRotate = True; }
2328
sewardj9aebb0c2004-10-24 19:20:43 +00002329 isRotateRC = gregOfRM(modrm) == 3;
2330
2331 if (!isShift && !isRotate && !isRotateRC) {
sewardj8c7f1ab2004-07-29 20:31:09 +00002332 vex_printf("\ncase %d\n", gregOfRM(modrm));
2333 vpanic("dis_Grp2(Reg): unhandled case(x86)");
2334 }
2335
sewardj9aebb0c2004-10-24 19:20:43 +00002336 if (isRotateRC) {
2337 /* call a helper; this insn is so ridiculous it does not deserve
2338 better */
2339 IRTemp r64 = newTemp(Ity_I64);
2340 IRExpr** args = LibVEX_Alloc(5 * sizeof(IRExpr*));
2341 args[0] = widenUto32(mkexpr(dst0)); /* thing to rotate */
2342 args[1] = widenUto32(shift_expr); /* rotate amount */
2343 args[2] = widenUto32(mk_calculate_eflags_all());
2344 args[3] = mkU32(sz);
2345 args[4] = NULL;
2346 assign( r64, IRExpr_CCall("calculate_RCR", Ity_I64, args) );
2347 /* new eflags in hi half r64; new value in lo half r64 */
2348 assign( dst1, narrowTo(ty, unop(Iop_64to32, mkexpr(r64))) );
2349 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
2350 stmt( IRStmt_Put( OFFB_CC_SRC, unop(Iop_64HIto32, mkexpr(r64)) ));
2351 stmt( IRStmt_Put( OFFB_CC_DST, mkU32(0) ));
2352 }
2353
sewardje90ad6a2004-07-10 19:02:10 +00002354 if (isShift) {
2355
sewardjc22a6fd2004-07-29 23:41:47 +00002356 IRTemp pre32 = newTemp(Ity_I32);
2357 IRTemp res32 = newTemp(Ity_I32);
2358 IRTemp res32ss = newTemp(Ity_I32);
sewardj6d2638e2004-07-15 09:38:27 +00002359 IRTemp shift_amt = newTemp(Ity_I8);
sewardjc22a6fd2004-07-29 23:41:47 +00002360 IROp op32;
sewardje90ad6a2004-07-10 19:02:10 +00002361
2362 switch (gregOfRM(modrm)) {
sewardjc22a6fd2004-07-29 23:41:47 +00002363 case 4: op32 = Iop_Shl32; break;
2364 case 5: op32 = Iop_Shr32; break;
2365 case 7: op32 = Iop_Sar32; break;
sewardje90ad6a2004-07-10 19:02:10 +00002366 default: vpanic("dis_Grp2:shift"); break;
2367 }
2368
sewardjc22a6fd2004-07-29 23:41:47 +00002369 /* Widen the value to be shifted to 32 bits, do the shift, and
2370 narrow back down. This seems surprisingly long-winded, but
2371 unfortunately the Intel semantics requires that 8/16-bit
2372 shifts give defined results for shift values all the way up
2373 to 31, and this seems the simplest way to do it. It has the
2374 advantage that the only IR level shifts generated are of 32
2375 bit values, and the shift amount is guaranteed to be in the
2376 range 0 .. 31, thereby observing the IR semantics requiring
2377 all shift values to be in the range 0 .. 2^word_size-1. */
2378
2379 /* shift_amt = shift_expr & 31, regardless of operation size */
2380 assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(31)) );
2381
2382 /* suitably widen the value to be shifted to 32 bits. */
2383 assign( pre32, op32==Iop_Sar32 ? widenSto32(mkexpr(dst0))
2384 : widenUto32(mkexpr(dst0)) );
2385
2386 /* res32 = pre32 `shift` shift_amt */
2387 assign( res32, binop(op32, mkexpr(pre32), mkexpr(shift_amt)) );
2388
2389 /* res32ss = pre32 `shift` ((shift_amt - 1) & 31) */
2390 assign( res32ss,
2391 binop(op32,
2392 mkexpr(pre32),
2393 binop(Iop_And8,
2394 binop(Iop_Sub8,
2395 mkexpr(shift_amt), mkU8(1)),
2396 mkU8(31))) );
sewardje90ad6a2004-07-10 19:02:10 +00002397
2398 /* Build the flags thunk. */
sewardjc22a6fd2004-07-29 23:41:47 +00002399 setFlags_DSTus_DST1(op32, res32ss, res32, ty, shift_amt);
2400
2401 /* Narrow the result back down. */
2402 assign( dst1, narrowTo(ty, mkexpr(res32)) );
sewardj750f4072004-07-26 22:39:11 +00002403
sewardj1813dbe2004-07-28 17:09:04 +00002404 } /* if (isShift) */
2405
2406 else
sewardj750f4072004-07-26 22:39:11 +00002407 if (isRotate) {
sewardj7ebbdae2004-08-26 12:30:48 +00002408 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
2409 Bool left = gregOfRM(modrm) == 0;
2410 IRTemp rot_amt = newTemp(Ity_I8);
2411 IRTemp rot_amt32 = newTemp(Ity_I8);
2412 IRTemp oldFlags = newTemp(Ity_I32);
sewardj750f4072004-07-26 22:39:11 +00002413
2414 /* rot_amt = shift_expr & mask */
sewardjc22a6fd2004-07-29 23:41:47 +00002415 /* By masking the rotate amount thusly, the IR-level Shl/Shr
2416 expressions never shift beyond the word size and thus remain
2417 well defined. */
sewardj7ebbdae2004-08-26 12:30:48 +00002418 assign(rot_amt32, binop(Iop_And8, shift_expr, mkU8(31)));
2419
2420 if (ty == Ity_I32)
2421 assign(rot_amt, mkexpr(rot_amt32));
2422 else
2423 assign(rot_amt, binop(Iop_And8, mkexpr(rot_amt32), mkU8(8*sz-1)));
sewardj750f4072004-07-26 22:39:11 +00002424
2425 if (left) {
sewardj1813dbe2004-07-28 17:09:04 +00002426
sewardj750f4072004-07-26 22:39:11 +00002427 /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
2428 assign(dst1,
2429 binop( mkSizedOp(ty,Iop_Or8),
2430 binop( mkSizedOp(ty,Iop_Shl8),
2431 mkexpr(dst0),
2432 mkexpr(rot_amt)
2433 ),
2434 binop( mkSizedOp(ty,Iop_Shr8),
2435 mkexpr(dst0),
2436 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
2437 )
2438 )
2439 );
sewardj1813dbe2004-07-28 17:09:04 +00002440 ccOp += CC_OP_ROLB;
sewardj750f4072004-07-26 22:39:11 +00002441
sewardj1813dbe2004-07-28 17:09:04 +00002442 } else { /* right */
sewardj750f4072004-07-26 22:39:11 +00002443
sewardj1813dbe2004-07-28 17:09:04 +00002444 /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
2445 assign(dst1,
2446 binop( mkSizedOp(ty,Iop_Or8),
2447 binop( mkSizedOp(ty,Iop_Shr8),
2448 mkexpr(dst0),
2449 mkexpr(rot_amt)
2450 ),
2451 binop( mkSizedOp(ty,Iop_Shl8),
2452 mkexpr(dst0),
2453 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
sewardj750f4072004-07-26 22:39:11 +00002454 )
2455 )
2456 );
sewardj1813dbe2004-07-28 17:09:04 +00002457 ccOp += CC_OP_RORB;
sewardjc22a6fd2004-07-29 23:41:47 +00002458
sewardj750f4072004-07-26 22:39:11 +00002459 }
sewardjc22a6fd2004-07-29 23:41:47 +00002460
sewardj1813dbe2004-07-28 17:09:04 +00002461 /* dst1 now holds the rotated value. Build flag thunk. We
2462 need the resulting value for this, and the previous flags.
2463 Except don't set it if the rotate count is zero. */
2464
2465 assign(oldFlags, mk_calculate_eflags_all());
2466
2467 /* CC_DST is the rotated value. CC_SRC is flags before. */
2468 stmt( IRStmt_Put( OFFB_CC_OP,
sewardj7ebbdae2004-08-26 12:30:48 +00002469 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj1813dbe2004-07-28 17:09:04 +00002470 IRExpr_Get(OFFB_CC_OP,Ity_I32),
2471 mkU32(ccOp))) );
2472 stmt( IRStmt_Put( OFFB_CC_DST,
sewardj7ebbdae2004-08-26 12:30:48 +00002473 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj1813dbe2004-07-28 17:09:04 +00002474 IRExpr_Get(OFFB_CC_DST,Ity_I32),
sewardjc22a6fd2004-07-29 23:41:47 +00002475 widenUto32(mkexpr(dst1)))) );
sewardj1813dbe2004-07-28 17:09:04 +00002476 stmt( IRStmt_Put( OFFB_CC_SRC,
sewardj7ebbdae2004-08-26 12:30:48 +00002477 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj1813dbe2004-07-28 17:09:04 +00002478 IRExpr_Get(OFFB_CC_SRC,Ity_I32),
2479 mkexpr(oldFlags))) );
2480 } /* if (isRotate) */
sewardje90ad6a2004-07-10 19:02:10 +00002481
2482 /* Save result, and finish up. */
2483 if (epartIsReg(modrm)) {
2484 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
2485 if (print_codegen) {
2486 vex_printf("%s%c ",
2487 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002488 if (shift_expr_txt)
2489 vex_printf("%s", shift_expr_txt);
2490 else
2491 ppIRExpr(shift_expr);
sewardje90ad6a2004-07-10 19:02:10 +00002492 vex_printf(", %s\n", nameIReg(sz,eregOfRM(modrm)));
2493 }
sewardje90ad6a2004-07-10 19:02:10 +00002494 } else {
sewardj940e8c92004-07-11 16:53:24 +00002495 storeLE(mkexpr(addr), mkexpr(dst1));
2496 if (print_codegen) {
2497 vex_printf("%s%c ",
2498 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002499 if (shift_expr_txt)
2500 vex_printf("%s", shift_expr_txt);
2501 else
2502 ppIRExpr(shift_expr);
sewardj940e8c92004-07-11 16:53:24 +00002503 vex_printf(", %s\n", dis_buf);
2504 }
sewardje90ad6a2004-07-10 19:02:10 +00002505 }
sewardje90ad6a2004-07-10 19:02:10 +00002506 return delta;
2507}
2508
2509
2510
sewardjc9a65702004-07-07 16:32:57 +00002511//-- /* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
2512//-- static
2513//-- Addr dis_Grp8_BT ( UCodeBlock* cb,
2514//-- UChar sorb,
2515//-- Addr eip, UChar modrm,
2516//-- Int am_sz, Int sz, UInt src_val )
2517//-- {
sewardjd1061ab2004-07-08 01:45:30 +00002518# define MODIFY_t2_AND_SET_CARRY_FLAG \
2519 /* t2 is the value to be op'd on. Copy to t_fetched, then \
2520 modify t2, if non-BT. */ \
2521 uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t_fetched); \
2522 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
2523 uLiteral(cb, v_mask); \
2524 switch (gregOfRM(modrm)) { \
2525 case 4: /* BT */ break; \
2526 case 5: /* BTS */ \
2527 uInstr2(cb, OR, sz, TempReg, t_mask, TempReg, t2); break; \
2528 case 6: /* BTR */ \
2529 uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t2); break; \
2530 case 7: /* BTC */ \
2531 uInstr2(cb, XOR, sz, TempReg, t_mask, TempReg, t2); break; \
2532 } \
2533 /* Copy relevant bit from t_fetched into carry flag. */ \
2534 uInstr2(cb, SHR, sz, Literal, 0, TempReg, t_fetched); \
2535 uLiteral(cb, src_val); \
2536 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
2537 uLiteral(cb, 1); \
2538 uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t_fetched); \
2539 uInstr1(cb, NEG, sz, TempReg, t_fetched); \
2540 setFlagsFromUOpcode(cb, NEG);
2541
2542
sewardjc9a65702004-07-07 16:32:57 +00002543//-- /* src_val denotes a d8.
2544//-- And eip on entry points at the modrm byte. */
2545//-- Int t1, t2, t_fetched, t_mask;
2546//-- UInt pair;
2547//-- Char dis_buf[50];
2548//-- UInt v_mask;
2549//--
2550//-- /* There is no 1-byte form of this instruction, AFAICS. */
2551//-- vg_assert(sz == 2 || sz == 4);
2552//--
2553//-- /* Limit src_val -- the bit offset -- to something within a word.
2554//-- The Intel docs say that literal offsets larger than a word are
2555//-- masked in this way. */
2556//-- switch (sz) {
2557//-- case 2: src_val &= 15; break;
2558//-- case 4: src_val &= 31; break;
2559//-- default: VG_(core_panic)("dis_Grp8_BT: invalid size");
2560//-- }
2561//--
2562//-- /* Invent a mask suitable for the operation. */
2563//--
2564//-- switch (gregOfRM(modrm)) {
2565//-- case 4: /* BT */ v_mask = 0; break;
2566//-- case 5: /* BTS */ v_mask = 1 << src_val; break;
2567//-- case 6: /* BTR */ v_mask = ~(1 << src_val); break;
2568//-- case 7: /* BTC */ v_mask = 1 << src_val; break;
2569//-- /* If this needs to be extended, probably simplest to make a
2570//-- new function to handle the other cases (0 .. 3). The
2571//-- Intel docs do however not indicate any use for 0 .. 3, so
2572//-- we don't expect this to happen. */
2573//-- default: VG_(core_panic)("dis_Grp8_BT");
2574//-- }
2575//-- /* Probably excessively paranoid. */
2576//-- if (sz == 2)
2577//-- v_mask &= 0x0000FFFF;
2578//--
2579//-- t1 = INVALID_TEMPREG;
2580//-- t_fetched = newTemp(cb);
2581//-- t_mask = newTemp(cb);
2582//--
2583//-- if (epartIsReg(modrm)) {
2584//-- vg_assert(am_sz == 1);
2585//-- t2 = newTemp(cb);
2586//--
2587//-- /* Fetch the value to be tested and modified. */
2588//-- uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t2);
2589//-- /* Do it! */
2590//-- MODIFY_t2_AND_SET_CARRY_FLAG;
2591//-- /* Dump the result back, if non-BT. */
2592//-- if (gregOfRM(modrm) != 4 /* BT */)
2593//-- uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, eregOfRM(modrm));
2594//--
2595//-- eip += (am_sz + 1);
2596//-- DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2597//-- src_val, nameIReg(sz,eregOfRM(modrm)));
2598//-- } else {
2599//-- pair = disAMode ( cb, sorb, eip, dis_buf);
2600//-- t1 = LOW24(pair);
2601//-- t2 = newTemp(cb);
2602//-- eip += HI8(pair);
2603//-- eip += 1;
2604//--
2605//-- /* Fetch the value to be tested and modified. */
2606//-- uInstr2(cb, LOAD, sz, TempReg, t1, TempReg, t2);
2607//-- /* Do it! */
2608//-- MODIFY_t2_AND_SET_CARRY_FLAG;
2609//-- /* Dump the result back, if non-BT. */
2610//-- if (gregOfRM(modrm) != 4 /* BT */) {
2611//-- uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
2612//-- }
2613//-- DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2614//-- src_val, dis_buf);
2615//-- }
2616//-- return eip;
2617//--
2618//-- # undef MODIFY_t2_AND_SET_CARRY_FLAG
2619//-- }
sewardjcf780b42004-07-13 18:42:17 +00002620
2621
2622
sewardj1813dbe2004-07-28 17:09:04 +00002623/* Signed/unsigned widening multiply. Generate IR to multiply the
2624 value in EAX/AX/AL by the given IRTemp, and park the result in
2625 EDX:EAX/DX:AX/AX.
sewardjcf780b42004-07-13 18:42:17 +00002626*/
sewardj1813dbe2004-07-28 17:09:04 +00002627static void codegen_mulL_A_D ( Int sz, Bool syned,
2628 IRTemp tmp, Char* tmp_txt )
sewardjcf780b42004-07-13 18:42:17 +00002629{
sewardjcf780b42004-07-13 18:42:17 +00002630 IRType ty = szToITy(sz);
2631 IRTemp t1 = newTemp(ty);
sewardjcf780b42004-07-13 18:42:17 +00002632
sewardj1813dbe2004-07-28 17:09:04 +00002633 assign( t1, getIReg(sz, R_EAX) );
sewardjcf780b42004-07-13 18:42:17 +00002634
2635 switch (ty) {
sewardjb81f8b32004-07-30 10:17:50 +00002636 case Ity_I32: {
2637 IRTemp res64 = newTemp(Ity_I64);
2638 IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32;
2639 UInt tBaseOp = syned ? CC_OP_SMULB : CC_OP_UMULB;
2640 setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
2641 assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
2642 putIReg(4, R_EDX, unop(Iop_64HIto32,mkexpr(res64)));
2643 putIReg(4, R_EAX, unop(Iop_64to32,mkexpr(res64)));
2644 break;
2645 }
2646 case Ity_I16: {
2647 IRTemp res32 = newTemp(Ity_I32);
2648 IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16;
2649 UInt tBaseOp = syned ? CC_OP_SMULB : CC_OP_UMULB;
2650 setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
2651 assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
2652 putIReg(2, R_EDX, unop(Iop_32HIto16,mkexpr(res32)));
2653 putIReg(2, R_EAX, unop(Iop_32to16,mkexpr(res32)));
2654 break;
2655 }
2656 case Ity_I8: {
2657 IRTemp res16 = newTemp(Ity_I16);
2658 IROp mulOp = syned ? Iop_MullS8 : Iop_MullU8;
2659 UInt tBaseOp = syned ? CC_OP_SMULB : CC_OP_UMULB;
2660 setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
2661 assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
2662 putIReg(2, R_EAX, mkexpr(res16));
2663 break;
2664 }
2665 default:
2666 vpanic("codegen_mulL_A_D(x86)");
sewardjcf780b42004-07-13 18:42:17 +00002667 }
sewardj1813dbe2004-07-28 17:09:04 +00002668 DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
sewardjcf780b42004-07-13 18:42:17 +00002669}
2670
sewardj940e8c92004-07-11 16:53:24 +00002671
2672/* Group 3 extended opcodes. */
2673static
2674UInt dis_Grp3 ( UChar sorb, Int sz, UInt delta )
2675{
sewardjc2ac51e2004-07-12 01:03:26 +00002676 UInt d32;
sewardj940e8c92004-07-11 16:53:24 +00002677 UChar modrm;
2678 UChar dis_buf[50];
sewardjc2ac51e2004-07-12 01:03:26 +00002679 Int len;
2680 IRTemp addr;
sewardj940e8c92004-07-11 16:53:24 +00002681 IRType ty = szToITy(sz);
2682 IRTemp t1 = newTemp(ty);
sewardjc2ac51e2004-07-12 01:03:26 +00002683 // IRTemp t2 = INVALID_IRTEMP;
sewardj940e8c92004-07-11 16:53:24 +00002684 IRTemp dst1, src, dst0;
2685 modrm = getIByte(delta);
2686 if (epartIsReg(modrm)) {
2687 switch (gregOfRM(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002688 case 0: { /* TEST */
2689 delta++; d32 = getUDisp(sz, delta); delta += sz;
2690 dst1 = newTemp(ty);
2691 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2692 getIReg(sz,eregOfRM(modrm)),
2693 mkU(ty,d32)));
sewardjb9c5cf62004-08-24 15:10:38 +00002694 setFlags_LOGIC( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002695 DIP("test%c $0x%x, %s\n", nameISize(sz), d32,
2696 nameIReg(sz, eregOfRM(modrm)));
2697 break;
2698 }
sewardj940e8c92004-07-11 16:53:24 +00002699 case 2: /* NOT */
2700 delta++;
2701 putIReg(sz, eregOfRM(modrm),
2702 unop(mkSizedOp(ty,Iop_Not8),
2703 getIReg(sz, eregOfRM(modrm))));
2704 DIP("not%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2705 break;
2706 case 3: /* NEG */
2707 delta++;
2708 dst0 = newTemp(ty);
2709 src = newTemp(ty);
2710 dst1 = newTemp(ty);
sewardja511afc2004-07-29 22:26:03 +00002711 assign(dst0, mkU(ty,0));
2712 assign(src, getIReg(sz,eregOfRM(modrm)));
2713 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
sewardjb9c5cf62004-08-24 15:10:38 +00002714 setFlags_ADD_SUB(Iop_Sub8, src, dst0, ty);
sewardj940e8c92004-07-11 16:53:24 +00002715 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
2716 DIP("neg%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2717 break;
sewardjcf780b42004-07-13 18:42:17 +00002718 case 4: /* MUL (unsigned widening) */
2719 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002720 src = newTemp(ty);
2721 assign(src, getIReg(sz,eregOfRM(modrm)));
2722 codegen_mulL_A_D ( sz, False, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcf780b42004-07-13 18:42:17 +00002723 break;
sewardjcaca9d02004-07-28 07:11:32 +00002724 case 5: /* IMUL (signed widening) */
2725 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002726 src = newTemp(ty);
2727 assign(src, getIReg(sz,eregOfRM(modrm)));
2728 codegen_mulL_A_D ( sz, True, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcaca9d02004-07-28 07:11:32 +00002729 break;
sewardj68511542004-07-28 00:15:44 +00002730 case 6: /* DIV */
2731 delta++;
2732 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2733 codegen_div ( sz, t1, False );
2734 DIP("div%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2735 break;
sewardjcaca9d02004-07-28 07:11:32 +00002736 case 7: /* IDIV */
2737 delta++;
2738 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2739 codegen_div ( sz, t1, True );
2740 DIP("idiv%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2741 break;
sewardj940e8c92004-07-11 16:53:24 +00002742 default:
2743 vex_printf(
2744 "unhandled Grp3(R) case %d\n", (UInt)gregOfRM(modrm));
2745 vpanic("Grp3(x86)");
2746 }
2747 } else {
sewardjc2ac51e2004-07-12 01:03:26 +00002748 addr = disAMode ( &len, sorb, delta, dis_buf );
2749 t1 = newTemp(ty);
2750 delta += len;
2751 assign(t1, loadLE(ty,mkexpr(addr)));
2752 switch (gregOfRM(modrm)) {
2753 case 0: { /* TEST */
2754 d32 = getUDisp(sz, delta); delta += sz;
2755 dst1 = newTemp(ty);
2756 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2757 mkexpr(t1), mkU(ty,d32)));
sewardjb9c5cf62004-08-24 15:10:38 +00002758 setFlags_LOGIC( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002759 DIP("test%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
2760 break;
2761 }
sewardj78fe7912004-08-20 23:38:07 +00002762 /* probably OK, but awaiting test case */
2763 case 2: /* NOT */
2764 storeLE( mkexpr(addr), unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
2765 DIP("not%c %s\n", nameISize(sz), dis_buf);
2766 break;
sewardj0c12ea82004-07-12 08:18:16 +00002767 case 3: /* NEG */
2768 dst0 = newTemp(ty);
2769 src = newTemp(ty);
2770 dst1 = newTemp(ty);
sewardja511afc2004-07-29 22:26:03 +00002771 assign(dst0, mkU(ty,0));
2772 assign(src, mkexpr(t1));
2773 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
sewardjb9c5cf62004-08-24 15:10:38 +00002774 setFlags_ADD_SUB(Iop_Sub8, src, dst0, ty);
sewardj0c12ea82004-07-12 08:18:16 +00002775 storeLE( mkexpr(addr), mkexpr(dst1) );
2776 DIP("neg%c %s\n", nameISize(sz), dis_buf);
2777 break;
sewardj1813dbe2004-07-28 17:09:04 +00002778 case 4: /* MUL */
2779 codegen_mulL_A_D ( sz, False, t1, dis_buf );
2780 break;
2781 case 5: /* IMUL */
2782 codegen_mulL_A_D ( sz, True, t1, dis_buf );
2783 break;
sewardj9690d922004-07-14 01:39:17 +00002784 case 6: /* DIV */
2785 codegen_div ( sz, t1, False );
2786 DIP("div%c %s\n", nameISize(sz), dis_buf);
2787 break;
sewardj1813dbe2004-07-28 17:09:04 +00002788 case 7: /* IDIV */
2789 codegen_div ( sz, t1, True );
2790 DIP("idiv%c %s\n", nameISize(sz), dis_buf);
2791 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002792 default:
2793 vex_printf(
2794 "unhandled Grp3(M) case %d\n", (UInt)gregOfRM(modrm));
2795 vpanic("Grp3(x86)");
2796 }
sewardj940e8c92004-07-11 16:53:24 +00002797 }
2798 return delta;
2799}
2800
2801
sewardjc2ac51e2004-07-12 01:03:26 +00002802/* Group 4 extended opcodes. */
2803static
2804UInt dis_Grp4 ( UChar sorb, UInt delta )
2805{
sewardj7ed22952004-07-29 00:09:58 +00002806 Int alen;
sewardjc2ac51e2004-07-12 01:03:26 +00002807 UChar modrm;
sewardj7ed22952004-07-29 00:09:58 +00002808 UChar dis_buf[50];
sewardjc2ac51e2004-07-12 01:03:26 +00002809 IRType ty = Ity_I8;
sewardj7ed22952004-07-29 00:09:58 +00002810 IRTemp t1 = newTemp(ty);
2811 IRTemp t2 = newTemp(ty);
sewardjc2ac51e2004-07-12 01:03:26 +00002812
2813 modrm = getIByte(delta);
2814 if (epartIsReg(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002815 assign(t1, getIReg(1, eregOfRM(modrm)));
2816 switch (gregOfRM(modrm)) {
sewardj7ed22952004-07-29 00:09:58 +00002817 case 0: /* INC */
2818 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
2819 putIReg(1, eregOfRM(modrm), mkexpr(t2));
2820 setFlags_INC_DEC( True, t2, ty );
2821 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002822 case 1: /* DEC */
sewardjc2ac51e2004-07-12 01:03:26 +00002823 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
2824 putIReg(1, eregOfRM(modrm), mkexpr(t2));
2825 setFlags_INC_DEC( False, t2, ty );
2826 break;
2827 default:
2828 vex_printf(
2829 "unhandled Grp4(R) case %d\n", (UInt)gregOfRM(modrm));
sewardj7ed22952004-07-29 00:09:58 +00002830 vpanic("Grp4(x86,R)");
sewardjc2ac51e2004-07-12 01:03:26 +00002831 }
2832 delta++;
2833 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)),
2834 nameIReg(1, eregOfRM(modrm)));
2835 } else {
sewardj7ed22952004-07-29 00:09:58 +00002836 IRTemp addr = disAMode ( &alen, sorb, delta, dis_buf );
2837 assign( t1, loadLE(ty, mkexpr(addr)) );
2838 switch (gregOfRM(modrm)) {
sewardj588ea762004-09-10 18:56:32 +00002839 case 0: /* INC */
2840 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
2841 storeLE( mkexpr(addr), mkexpr(t2) );
2842 setFlags_INC_DEC( True, t2, ty );
2843 break;
sewardj7ed22952004-07-29 00:09:58 +00002844 case 1: /* DEC */
2845 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
2846 storeLE( mkexpr(addr), mkexpr(t2) );
2847 setFlags_INC_DEC( False, t2, ty );
2848 break;
2849 default:
2850 vex_printf(
2851 "unhandled Grp4(M) case %d\n", (UInt)gregOfRM(modrm));
2852 vpanic("Grp4(x86,M)");
2853 }
2854 delta += alen;
2855 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)), dis_buf);
sewardjc2ac51e2004-07-12 01:03:26 +00002856 }
2857 return delta;
2858}
sewardj0611d802004-07-11 02:37:54 +00002859
2860
2861/* Group 5 extended opcodes. */
2862static
sewardjce70a5c2004-10-18 14:09:54 +00002863UInt dis_Grp5 ( UChar sorb, Int sz, UInt delta, DisResult* whatNext )
sewardj0611d802004-07-11 02:37:54 +00002864{
2865 Int len;
2866 UChar modrm;
2867 UChar dis_buf[50];
sewardj940e8c92004-07-11 16:53:24 +00002868 IRTemp addr = INVALID_IRTEMP;
sewardj0611d802004-07-11 02:37:54 +00002869 IRType ty = szToITy(sz);
2870 IRTemp t1 = newTemp(ty);
2871 IRTemp t2 = INVALID_IRTEMP;
2872
2873 modrm = getIByte(delta);
2874 if (epartIsReg(modrm)) {
sewardj940e8c92004-07-11 16:53:24 +00002875 assign(t1, getIReg(sz,eregOfRM(modrm)));
sewardj0611d802004-07-11 02:37:54 +00002876 switch (gregOfRM(modrm)) {
sewardjc9a65702004-07-07 16:32:57 +00002877//-- case 0: /* INC */
2878//-- uInstr1(cb, INC, sz, TempReg, t1);
2879//-- setFlagsFromUOpcode(cb, INC);
2880//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
2881//-- break;
2882//-- case 1: /* DEC */
2883//-- uInstr1(cb, DEC, sz, TempReg, t1);
2884//-- setFlagsFromUOpcode(cb, DEC);
2885//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
2886//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +00002887 case 2: /* call Ev */
2888 vassert(sz == 4);
2889 t2 = newTemp(Ity_I32);
2890 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
2891 putIReg(4, R_ESP, mkexpr(t2));
sewardjce70a5c2004-10-18 14:09:54 +00002892 storeLE( mkexpr(t2), mkU32(guest_eip_bbstart+delta+1));
sewardj78c19df2004-07-12 22:49:27 +00002893 jmp_treg(Ijk_Call,t1);
sewardjce70a5c2004-10-18 14:09:54 +00002894 *whatNext = Dis_StopHere;
sewardjc2ac51e2004-07-12 01:03:26 +00002895 break;
sewardj0611d802004-07-11 02:37:54 +00002896 case 4: /* jmp Ev */
2897 vassert(sz == 4);
sewardj78c19df2004-07-12 22:49:27 +00002898 jmp_treg(Ijk_Boring,t1);
sewardjce70a5c2004-10-18 14:09:54 +00002899 *whatNext = Dis_StopHere;
sewardj0611d802004-07-11 02:37:54 +00002900 break;
2901 default:
2902 vex_printf(
2903 "unhandled Grp5(R) case %d\n", (UInt)gregOfRM(modrm));
2904 vpanic("Grp5(x86)");
2905 }
2906 delta++;
2907 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
2908 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2909 } else {
2910 addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj940e8c92004-07-11 16:53:24 +00002911 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj0611d802004-07-11 02:37:54 +00002912 switch (gregOfRM(modrm)) {
2913 case 0: /* INC */
2914 t2 = newTemp(ty);
2915 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
2916 mkexpr(t1), mkU(ty,1)));
2917 setFlags_INC_DEC( True, t2, ty );
sewardj940e8c92004-07-11 16:53:24 +00002918 storeLE(mkexpr(addr),mkexpr(t2));
sewardj0611d802004-07-11 02:37:54 +00002919 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002920 case 1: /* DEC */
2921 t2 = newTemp(ty);
2922 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
2923 mkexpr(t1), mkU(ty,1)));
2924 setFlags_INC_DEC( False, t2, ty );
2925 storeLE(mkexpr(addr),mkexpr(t2));
2926 break;
sewardj77b86be2004-07-11 13:28:24 +00002927 case 2: /* call Ev */
2928 vassert(sz == 4);
2929 t2 = newTemp(Ity_I32);
2930 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
2931 putIReg(4, R_ESP, mkexpr(t2));
sewardjce70a5c2004-10-18 14:09:54 +00002932 storeLE( mkexpr(t2), mkU32(guest_eip_bbstart+delta+len));
sewardj78c19df2004-07-12 22:49:27 +00002933 jmp_treg(Ijk_Call,t1);
sewardjce70a5c2004-10-18 14:09:54 +00002934 *whatNext = Dis_StopHere;
sewardj77b86be2004-07-11 13:28:24 +00002935 break;
2936 case 4: /* JMP Ev */
2937 vassert(sz == 4);
sewardj78c19df2004-07-12 22:49:27 +00002938 jmp_treg(Ijk_Boring,t1);
sewardjce70a5c2004-10-18 14:09:54 +00002939 *whatNext = Dis_StopHere;
sewardj77b86be2004-07-11 13:28:24 +00002940 break;
sewardj0c12ea82004-07-12 08:18:16 +00002941 case 6: /* PUSH Ev */
2942 vassert(sz == 4 || sz == 2);
2943 t2 = newTemp(Ity_I32);
2944 assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
2945 putIReg(4, R_ESP, mkexpr(t2) );
2946 storeLE( mkexpr(t2), mkexpr(t1) );
2947 break;
sewardj0611d802004-07-11 02:37:54 +00002948 default:
2949 vex_printf(
2950 "unhandled Grp5(M) case %d\n", (UInt)gregOfRM(modrm));
2951 vpanic("Grp5(x86)");
2952 }
2953 delta += len;
2954 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
2955 nameISize(sz), dis_buf);
2956 }
2957 return delta;
2958}
2959
sewardj64e1d652004-07-12 14:00:46 +00002960/*------------------------------------------------------------*/
2961/*--- Disassembling string ops (including REP prefixes) ---*/
2962/*------------------------------------------------------------*/
2963
2964/* Code shared by all the string ops */
2965static
2966void dis_string_op_increment(Int sz, Int t_inc)
2967{
2968 if (sz == 4 || sz == 2) {
2969 assign( t_inc,
2970 binop(Iop_Shl32, IRExpr_Get( OFFB_DFLAG, Ity_I32 ),
sewardj6d2638e2004-07-15 09:38:27 +00002971 mkU8(sz/2) ) );
sewardj64e1d652004-07-12 14:00:46 +00002972 } else {
2973 assign( t_inc,
2974 IRExpr_Get( OFFB_DFLAG, Ity_I32 ) );
2975 }
2976}
2977
sewardj64e1d652004-07-12 14:00:46 +00002978static
2979void dis_string_op( void (*dis_OP)( Int, IRTemp ),
2980 Int sz, Char* name, UChar sorb )
2981{
2982 IRTemp t_inc = newTemp(Ity_I32);
2983 vassert(sorb == 0);
2984 dis_string_op_increment(sz, t_inc);
2985 dis_OP( sz, t_inc );
2986 DIP("%s%c\n", name, nameISize(sz));
2987}
sewardj64e1d652004-07-12 14:00:46 +00002988
2989static
2990void dis_MOVS ( Int sz, IRTemp t_inc )
2991{
2992 IRType ty = szToITy(sz);
2993 //IRTemp tv = newTemp(ty); /* value being copied */
2994 IRTemp td = newTemp(Ity_I32); /* EDI */
2995 IRTemp ts = newTemp(Ity_I32); /* ESI */
2996
2997 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
2998 //uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
2999 assign( td, getIReg(4, R_EDI) );
3000 assign( ts, getIReg(4, R_ESI) );
3001
3002 //uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tv);
3003 //uInstr2(cb, STORE,sz, TempReg, tv, TempReg, td);
3004 storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
3005
3006 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
3007 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
3008
3009 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
3010 //uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
3011 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3012 putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3013}
3014
sewardjc9a65702004-07-07 16:32:57 +00003015//-- static
3016//-- void dis_LODS ( UCodeBlock* cb, Int sz, Int t_inc )
3017//-- {
3018//-- Int ta = newTemp(cb); /* EAX */
3019//-- Int ts = newTemp(cb); /* ESI */
3020//--
3021//-- uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
3022//-- uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, ta);
3023//-- uInstr2(cb, PUT, sz, TempReg, ta, ArchReg, R_EAX);
3024//--
3025//-- uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
3026//-- uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
3027//-- }
sewardj64e1d652004-07-12 14:00:46 +00003028
3029static
3030void dis_STOS ( Int sz, IRTemp t_inc )
3031{
3032 IRType ty = szToITy(sz);
3033 IRTemp ta = newTemp(ty); /* EAX */
3034 IRTemp td = newTemp(Ity_I32); /* EDI */
3035
3036 //uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
3037 assign( ta, getIReg(sz, R_EAX) );
3038
3039 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
3040 assign( td, getIReg(4, R_EDI) );
3041
3042 //uInstr2(cb, STORE, sz, TempReg, ta, TempReg, td);
sewardj6d2638e2004-07-15 09:38:27 +00003043 storeLE( mkexpr(td), mkexpr(ta) );
sewardj64e1d652004-07-12 14:00:46 +00003044
3045 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
3046 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
3047 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3048}
3049
3050static
3051void dis_CMPS ( Int sz, IRTemp t_inc )
3052{
3053 IRType ty = szToITy(sz);
sewardj6d2638e2004-07-15 09:38:27 +00003054 IRTemp tdv = newTemp(ty); /* (EDI) */
3055 IRTemp tsv = newTemp(ty); /* (ESI) */
sewardj64e1d652004-07-12 14:00:46 +00003056 IRTemp td = newTemp(Ity_I32); /* EDI */
3057 IRTemp ts = newTemp(Ity_I32); /* ESI */
3058
3059 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
3060 assign( td, getIReg(4, R_EDI) );
3061
3062 //uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
3063 assign( ts, getIReg(4, R_ESI) );
3064
3065 //uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tdv);
3066 assign( tdv, loadLE(ty,mkexpr(td)) );
3067
3068 //uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tsv);
sewardjb9c5cf62004-08-24 15:10:38 +00003069 assign( tsv, loadLE(ty,mkexpr(ts)) );
sewardj64e1d652004-07-12 14:00:46 +00003070
3071 //uInstr2(cb, SUB, sz, TempReg, tdv, TempReg, tsv);
3072 //setFlagsFromUOpcode(cb, SUB);
sewardjb9c5cf62004-08-24 15:10:38 +00003073 setFlags_ADD_SUB ( Iop_Sub8, tdv, tsv, ty );
sewardj64e1d652004-07-12 14:00:46 +00003074
3075 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
3076 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
3077
3078 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
3079 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3080
3081 //uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
3082 putIReg(4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3083}
3084
sewardj64e1d652004-07-12 14:00:46 +00003085static
3086void dis_SCAS ( Int sz, IRTemp t_inc )
3087{
3088 IRType ty = szToITy(sz);
sewardj82292882004-07-27 00:15:59 +00003089 IRTemp ta = newTemp(ty); /* EAX */
sewardj64e1d652004-07-12 14:00:46 +00003090 IRTemp td = newTemp(Ity_I32); /* EDI */
3091 IRTemp tdv = newTemp(ty); /* (EDI) */
3092
3093 //uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
sewardjb9c5cf62004-08-24 15:10:38 +00003094 assign( ta, getIReg(sz, R_EAX) );
sewardj64e1d652004-07-12 14:00:46 +00003095
3096 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
3097 assign( td, getIReg(4, R_EDI) );
3098
3099 //uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tdv);
3100 assign( tdv, loadLE(ty,mkexpr(td)) );
3101
sewardj64e1d652004-07-12 14:00:46 +00003102 //uInstr2(cb, SUB, sz, TempReg, tdv, TempReg, ta);
3103 //setFlagsFromUOpcode(cb, SUB);
sewardjb9c5cf62004-08-24 15:10:38 +00003104 setFlags_ADD_SUB( Iop_Sub8, tdv, ta, ty );
sewardj64e1d652004-07-12 14:00:46 +00003105
3106 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
3107 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
3108 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3109}
sewardj82292882004-07-27 00:15:59 +00003110
sewardj64e1d652004-07-12 14:00:46 +00003111
3112/* Wrap the appropriate string op inside a REP/REPE/REPNE.
3113 We assume the insn is the last one in the basic block, and so emit a jump
3114 to the next insn, rather than just falling through. */
3115static
3116void dis_REP_op ( Condcode cond,
3117 void (*dis_OP)(Int, IRTemp),
3118 Int sz, Addr32 eip, Addr32 eip_next, Char* name )
3119{
3120 IRTemp t_inc = newTemp(Ity_I32);
3121 IRTemp tc = newTemp(Ity_I32); /* ECX */
3122
3123 //uInstr2 (cb, GET, 4, ArchReg, R_ECX, TempReg, tc);
3124 assign( tc, getIReg(4,R_ECX) );
3125
3126 //uInstr2 (cb, JIFZ, 4, TempReg, tc, Literal, 0);
3127 //uLiteral(cb, eip_next);
3128 stmt( IRStmt_Exit( binop(Iop_CmpEQ32,mkexpr(tc),mkU32(0)),
3129 IRConst_U32(eip_next) ) );
3130
3131 //uInstr1 (cb, DEC, 4, TempReg, tc);
3132 //uInstr2 (cb, PUT, 4, TempReg, tc, ArchReg, R_ECX);
3133 putIReg(4, R_ECX, binop(Iop_Sub32, mkexpr(tc), mkU32(1)) );
3134
3135 dis_string_op_increment(sz, t_inc);
3136 dis_OP (sz, t_inc);
3137
3138 if (cond == CondAlways) {
sewardj78c19df2004-07-12 22:49:27 +00003139 jmp_lit(Ijk_Boring,eip);
sewardj64e1d652004-07-12 14:00:46 +00003140 } else {
3141 stmt( IRStmt_Exit( calculate_condition(cond),
3142 IRConst_U32(eip) ) );
sewardj78c19df2004-07-12 22:49:27 +00003143 jmp_lit(Ijk_Boring,eip_next);
sewardj64e1d652004-07-12 14:00:46 +00003144 }
3145 DIP("%s%c\n", name, nameISize(sz));
3146}
3147
3148/*------------------------------------------------------------*/
3149/*--- Arithmetic, etc. ---*/
3150/*------------------------------------------------------------*/
3151
sewardjcf780b42004-07-13 18:42:17 +00003152/* (I)MUL E, G. Supplied eip points to the modR/M byte. */
3153static
3154UInt dis_mul_E_G ( UChar sorb,
3155 Int size,
3156 UInt delta0,
sewardj56296d82004-07-30 01:52:45 +00003157 Bool syned )
sewardjcf780b42004-07-13 18:42:17 +00003158{
sewardj71a65362004-07-28 01:48:34 +00003159 Int alen;
3160 UChar dis_buf[50];
sewardjcf780b42004-07-13 18:42:17 +00003161 UChar rm = getIByte(delta0);
3162 IRType ty = szToITy(size);
sewardj6d2638e2004-07-15 09:38:27 +00003163 IRTemp te = newTemp(ty);
3164 IRTemp tg = newTemp(ty);
sewardjcf780b42004-07-13 18:42:17 +00003165
sewardj56296d82004-07-30 01:52:45 +00003166 vassert(syned);
sewardj71a65362004-07-28 01:48:34 +00003167
sewardjcf780b42004-07-13 18:42:17 +00003168 if (epartIsReg(rm)) {
sewardjcf780b42004-07-13 18:42:17 +00003169 assign( tg, getIReg(size, gregOfRM(rm)) );
3170 assign( te, getIReg(size, eregOfRM(rm)) );
sewardj56296d82004-07-30 01:52:45 +00003171 setFlags_MUL ( ty, te, tg, syned ? CC_OP_SMULB : CC_OP_UMULB );
sewardjcf780b42004-07-13 18:42:17 +00003172 putIReg(size, gregOfRM(rm),
3173 binop(mkSizedOp(ty,Iop_Mul8),
3174 mkexpr(te), mkexpr(tg)));
3175
sewardj56296d82004-07-30 01:52:45 +00003176 DIP("%smul%c %s, %s\n", syned ? "i" : "",
sewardjcf780b42004-07-13 18:42:17 +00003177 nameISize(size),
3178 nameIReg(size,eregOfRM(rm)),
3179 nameIReg(size,gregOfRM(rm)));
3180 return 1+delta0;
3181 } else {
sewardj71a65362004-07-28 01:48:34 +00003182 IRTemp addr = disAMode( &alen, sorb, delta0, dis_buf );
3183 assign( tg, getIReg(size, gregOfRM(rm)) );
3184 assign( te, loadLE(ty,mkexpr(addr)) );
sewardj56296d82004-07-30 01:52:45 +00003185 setFlags_MUL ( ty, te, tg, syned ? CC_OP_SMULB : CC_OP_UMULB );
sewardj71a65362004-07-28 01:48:34 +00003186 putIReg(size, gregOfRM(rm),
3187 binop(mkSizedOp(ty,Iop_Mul8),
3188 mkexpr(te), mkexpr(tg)));
sewardjcf780b42004-07-13 18:42:17 +00003189
sewardj56296d82004-07-30 01:52:45 +00003190 DIP("%smul%c %s, %s\n", syned ? "i" : "",
sewardjcf780b42004-07-13 18:42:17 +00003191 nameISize(size),
3192 dis_buf, nameIReg(size,gregOfRM(rm)));
sewardj71a65362004-07-28 01:48:34 +00003193 return alen+delta0;
sewardjcf780b42004-07-13 18:42:17 +00003194 }
3195}
3196
3197
sewardj1813dbe2004-07-28 17:09:04 +00003198/* IMUL I * E -> G. Supplied eip points to the modR/M byte. */
3199static
3200UInt dis_imul_I_E_G ( UChar sorb,
3201 Int size,
3202 UInt delta,
3203 Int litsize )
3204{
sewardj883b00b2004-09-11 09:30:24 +00003205 Int d32, alen;
sewardjb81f8b32004-07-30 10:17:50 +00003206 Char dis_buf[50];
3207 UChar rm = getIByte(delta);
sewardj1813dbe2004-07-28 17:09:04 +00003208 IRType ty = szToITy(size);
3209 IRTemp te = newTemp(ty);
3210 IRTemp tl = newTemp(ty);
3211
sewardjb81f8b32004-07-30 10:17:50 +00003212 vassert(size == 1 || size == 2 || size == 4);
3213
sewardj1813dbe2004-07-28 17:09:04 +00003214 if (epartIsReg(rm)) {
3215 assign(te, getIReg(size, eregOfRM(rm)));
3216 delta++;
3217 } else {
sewardj883b00b2004-09-11 09:30:24 +00003218 IRTemp addr = disAMode( &alen, sorb, delta, dis_buf );
3219 assign(te, loadLE(ty, mkexpr(addr)));
3220 delta += alen;
sewardj1813dbe2004-07-28 17:09:04 +00003221 }
3222 d32 = getSDisp(litsize,delta);
3223 delta += litsize;
3224
sewardjb81f8b32004-07-30 10:17:50 +00003225 if (size == 1) d32 &= 0xFF;
3226 if (size == 2) d32 &= 0xFFFF;
3227
sewardj1813dbe2004-07-28 17:09:04 +00003228 assign(tl, mkU(ty,d32));
sewardj56296d82004-07-30 01:52:45 +00003229 setFlags_MUL ( ty, te, tl, CC_OP_SMULB );
sewardj1813dbe2004-07-28 17:09:04 +00003230 putIReg(size, gregOfRM(rm),
3231 binop(mkSizedOp(ty,Iop_Mul8),
3232 mkexpr(te), mkexpr(tl)));
3233
3234 DIP("imul %d, %s, %s\n", d32,
3235 ( epartIsReg(rm) ? nameIReg(size,eregOfRM(rm)) : dis_buf ),
3236 nameIReg(size,gregOfRM(rm)) );
3237 return delta;
3238}
3239
3240
sewardjd1725d12004-08-12 20:46:53 +00003241/*------------------------------------------------------------*/
3242/*--- x87 floating point insns. ---*/
3243/*------------------------------------------------------------*/
3244
sewardj207557a2004-08-27 12:00:18 +00003245/* --- Helper functions for dealing with the register stack. --- */
3246
sewardj17442fe2004-09-20 14:54:28 +00003247/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */
sewardj207557a2004-08-27 12:00:18 +00003248
sewardj17442fe2004-09-20 14:54:28 +00003249static IRExpr* mkQNaN64 ( void )
sewardj207557a2004-08-27 12:00:18 +00003250{
sewardj17442fe2004-09-20 14:54:28 +00003251 /* QNaN is 0 2047 1 0(51times)
3252 == 0b 11111111111b 1 0(51times)
3253 == 0x7FF8 0000 0000 0000
3254 */
3255 return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL));
sewardj207557a2004-08-27 12:00:18 +00003256}
3257
3258/* --------- Get/set the top-of-stack pointer. --------- */
sewardjd1725d12004-08-12 20:46:53 +00003259
3260static IRExpr* get_ftop ( void )
3261{
3262 return IRExpr_Get( OFFB_FTOP, Ity_I32 );
3263}
3264
sewardj207557a2004-08-27 12:00:18 +00003265static void put_ftop ( IRExpr* e )
sewardjd1725d12004-08-12 20:46:53 +00003266{
sewardj207557a2004-08-27 12:00:18 +00003267 stmt( IRStmt_Put( OFFB_FTOP, e ) );
sewardjd1725d12004-08-12 20:46:53 +00003268}
3269
sewardjc4be80c2004-09-10 16:17:45 +00003270/* --------- Get/set the C3210 bits of the control word. --------- */
sewardjbdc7d212004-09-09 02:46:40 +00003271
sewardjc4be80c2004-09-10 16:17:45 +00003272static IRExpr* get_C3210 ( void )
sewardjbdc7d212004-09-09 02:46:40 +00003273{
sewardjc4be80c2004-09-10 16:17:45 +00003274 return IRExpr_Get( OFFB_FC3210, Ity_I32 );
sewardjbdc7d212004-09-09 02:46:40 +00003275}
3276
sewardjc4be80c2004-09-10 16:17:45 +00003277static void put_C3210 ( IRExpr* e )
sewardjbdc7d212004-09-09 02:46:40 +00003278{
sewardjc4be80c2004-09-10 16:17:45 +00003279 stmt( IRStmt_Put( OFFB_FC3210, e ) );
sewardjbdc7d212004-09-09 02:46:40 +00003280}
sewardjd1725d12004-08-12 20:46:53 +00003281
sewardj8f3debf2004-09-08 23:42:23 +00003282/* --------- Get/set the FPU control word. --------- */
3283/* Note, IA32 has this as a 16-bit value, so fstcw/fldcw need to cast
3284 to/from 16 bits. Here we represent it in 32 bits. */
3285static IRExpr* /* :: Ity_I32 */ get_fpucw ( void )
3286{
3287 return IRExpr_Get( OFFB_FPUCW, Ity_I32 );
3288}
3289
3290static void put_fpucw ( IRExpr* /* :: Ity_I32 */ e )
3291{
3292 stmt( IRStmt_Put( OFFB_FPUCW, e ) );
3293}
3294
3295
3296/* --------- Get the FPU rounding mode from the CW. --------- */
3297/* Produces a value in 0 .. 3, which is encoded as per the type
3298 IRRoundingMode. On IA32 the relevant value is precisely bits 11
3299 and 10 of the control word.
3300*/
3301static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
3302{
3303 return binop( Iop_And32,
3304 binop(Iop_Shr32, get_fpucw(), mkU8(10)),
3305 mkU32(3) );
3306}
3307
3308
sewardj207557a2004-08-27 12:00:18 +00003309/* --------- Get/set FP register tag bytes. --------- */
3310
sewardj207557a2004-08-27 12:00:18 +00003311/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */
3312
3313static void put_ST_TAG ( Int i, IRExpr* value )
3314{
sewardj2d3f77c2004-09-22 23:49:09 +00003315 IRArray* descr;
sewardj207557a2004-08-27 12:00:18 +00003316 vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_I8);
sewardjf6dc3ce2004-10-19 01:03:46 +00003317 descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003318 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
sewardj207557a2004-08-27 12:00:18 +00003319}
3320
3321/* Given i, generate an expression yielding 'ST_TAG(i)'. This will be
sewardjdb199622004-09-06 23:19:03 +00003322 zero to indicate "Empty" and nonzero to indicate "NonEmpty". */
sewardj207557a2004-08-27 12:00:18 +00003323
3324static IRExpr* get_ST_TAG ( Int i )
3325{
sewardjf6dc3ce2004-10-19 01:03:46 +00003326 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003327 return IRExpr_GetI( descr, get_ftop(), i );
sewardj207557a2004-08-27 12:00:18 +00003328}
3329
3330
3331/* --------- Get/set FP registers. --------- */
3332
sewardj2d3f77c2004-09-22 23:49:09 +00003333/* Given i, and some expression e, emit 'ST(i) = e' and set the
3334 register's tag to indicate the register is full. The previous
3335 state of the register is not checked. */
sewardj207557a2004-08-27 12:00:18 +00003336
3337static void put_ST_UNCHECKED ( Int i, IRExpr* value )
sewardjd1725d12004-08-12 20:46:53 +00003338{
sewardj2d3f77c2004-09-22 23:49:09 +00003339 IRArray* descr;
sewardjdb199622004-09-06 23:19:03 +00003340 vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_F64);
sewardjf6dc3ce2004-10-19 01:03:46 +00003341 descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003342 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
sewardj207557a2004-08-27 12:00:18 +00003343 /* Mark the register as in-use. */
3344 put_ST_TAG(i, mkU8(1));
sewardjd1725d12004-08-12 20:46:53 +00003345}
3346
sewardj207557a2004-08-27 12:00:18 +00003347/* Given i, and some expression e, emit
3348 ST(i) = is_full(i) ? NaN : e
3349 and set the tag accordingly.
3350*/
3351
3352static void put_ST ( Int i, IRExpr* value )
3353{
3354 put_ST_UNCHECKED( i,
sewardjdb199622004-09-06 23:19:03 +00003355 IRExpr_Mux0X( get_ST_TAG(i),
3356 /* 0 means empty */
3357 value,
3358 /* non-0 means full */
sewardj17442fe2004-09-20 14:54:28 +00003359 mkQNaN64()
sewardj207557a2004-08-27 12:00:18 +00003360 )
3361 );
3362}
3363
3364
sewardjd1725d12004-08-12 20:46:53 +00003365/* Given i, generate an expression yielding 'ST(i)'. */
3366
sewardj207557a2004-08-27 12:00:18 +00003367static IRExpr* get_ST_UNCHECKED ( Int i )
sewardjd1725d12004-08-12 20:46:53 +00003368{
sewardjf6dc3ce2004-10-19 01:03:46 +00003369 IRArray* descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003370 return IRExpr_GetI( descr, get_ftop(), i );
sewardjd1725d12004-08-12 20:46:53 +00003371}
3372
sewardjc4be80c2004-09-10 16:17:45 +00003373
sewardj207557a2004-08-27 12:00:18 +00003374/* Given i, generate an expression yielding
3375 is_full(i) ? ST(i) : NaN
3376*/
3377
3378static IRExpr* get_ST ( Int i )
3379{
3380 return
3381 IRExpr_Mux0X( get_ST_TAG(i),
3382 /* 0 means empty */
sewardj17442fe2004-09-20 14:54:28 +00003383 mkQNaN64(),
sewardj207557a2004-08-27 12:00:18 +00003384 /* non-0 means full */
3385 get_ST_UNCHECKED(i));
3386}
3387
3388
sewardjd1725d12004-08-12 20:46:53 +00003389/* Adjust FTOP downwards by one register. */
3390
sewardj207557a2004-08-27 12:00:18 +00003391static void fp_push ( void )
sewardjd1725d12004-08-12 20:46:53 +00003392{
sewardj2d3f77c2004-09-22 23:49:09 +00003393 put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) );
sewardjd1725d12004-08-12 20:46:53 +00003394}
3395
sewardj207557a2004-08-27 12:00:18 +00003396/* Adjust FTOP upwards by one register, and mark the vacated register
3397 as empty. */
sewardja58ea662004-08-15 03:12:41 +00003398
sewardj207557a2004-08-27 12:00:18 +00003399static void fp_pop ( void )
sewardja58ea662004-08-15 03:12:41 +00003400{
sewardjdb199622004-09-06 23:19:03 +00003401 put_ST_TAG(0, mkU8(0));
sewardj2d3f77c2004-09-22 23:49:09 +00003402 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
sewardja58ea662004-08-15 03:12:41 +00003403}
3404
sewardj3f61ddb2004-10-16 20:51:05 +00003405/* Clear the C2 bit of the FPU status register, for
3406 sin/cos/tan/sincos. */
3407
3408static void clear_C2 ( void )
3409{
3410 put_C3210( binop(Iop_And32, get_C3210(), mkU32(~FC_MASK_C2)) );
3411}
3412
3413
sewardj207557a2004-08-27 12:00:18 +00003414/* ------------------------------------------------------- */
3415/* Given all that stack-mangling junk, we can now go ahead
3416 and describe FP instructions.
3417*/
3418
sewardj3fd5e572004-09-09 22:43:51 +00003419/* ST(0) = ST(0) `op` mem64/32(addr)
sewardj207557a2004-08-27 12:00:18 +00003420 Need to check ST(0)'s tag on read, but not on write.
3421*/
sewardja58ea662004-08-15 03:12:41 +00003422static
3423void fp_do_op_mem_ST_0 ( IRTemp addr, UChar* op_txt, UChar* dis_buf,
3424 IROp op, Bool dbl )
3425{
3426 DIP("f%s%c %s", op_txt, dbl?'l':'s', dis_buf);
3427 if (dbl) {
sewardj3fd5e572004-09-09 22:43:51 +00003428 put_ST_UNCHECKED(0,
3429 binop( op,
3430 get_ST(0),
3431 loadLE(Ity_F64,mkexpr(addr))
3432 ));
sewardja58ea662004-08-15 03:12:41 +00003433 } else {
sewardj3fd5e572004-09-09 22:43:51 +00003434 put_ST_UNCHECKED(0,
3435 binop( op,
3436 get_ST(0),
3437 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr)))
3438 ));
3439 }
3440}
3441
3442
3443/* ST(0) = mem64/32(addr) `op` ST(0)
3444 Need to check ST(0)'s tag on read, but not on write.
3445*/
3446static
3447void fp_do_oprev_mem_ST_0 ( IRTemp addr, UChar* op_txt, UChar* dis_buf,
sewardj883b00b2004-09-11 09:30:24 +00003448 IROp op, Bool dbl )
sewardj3fd5e572004-09-09 22:43:51 +00003449{
3450 DIP("f%s%c %s", op_txt, dbl?'l':'s', dis_buf);
3451 if (dbl) {
3452 put_ST_UNCHECKED(0,
3453 binop( op,
3454 loadLE(Ity_F64,mkexpr(addr)),
3455 get_ST(0)
3456 ));
3457 } else {
3458 put_ST_UNCHECKED(0,
3459 binop( op,
3460 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))),
3461 get_ST(0)
3462 ));
sewardja58ea662004-08-15 03:12:41 +00003463 }
3464}
3465
sewardjd1725d12004-08-12 20:46:53 +00003466
sewardjdb199622004-09-06 23:19:03 +00003467/* ST(dst) = ST(dst) `op` ST(src).
3468 Check dst and src tags when reading but not on write.
3469*/
3470static
sewardjbdc7d212004-09-09 02:46:40 +00003471void fp_do_op_ST_ST ( UChar* op_txt, IROp op, UInt st_src, UInt st_dst,
3472 Bool pop_after )
sewardjdb199622004-09-06 23:19:03 +00003473{
sewardjbdc7d212004-09-09 02:46:40 +00003474 DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"", st_src, st_dst );
sewardjdb199622004-09-06 23:19:03 +00003475 put_ST_UNCHECKED(
3476 st_dst,
3477 binop(op, get_ST(st_dst), get_ST(st_src) )
3478 );
sewardjbdc7d212004-09-09 02:46:40 +00003479 if (pop_after)
3480 fp_pop();
3481}
3482
3483/* ST(dst) = ST(src) `op` ST(dst).
3484 Check dst and src tags when reading but not on write.
3485*/
3486static
3487void fp_do_oprev_ST_ST ( UChar* op_txt, IROp op, UInt st_src, UInt st_dst,
sewardj883b00b2004-09-11 09:30:24 +00003488 Bool pop_after )
sewardjbdc7d212004-09-09 02:46:40 +00003489{
3490 DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"", st_src, st_dst );
3491 put_ST_UNCHECKED(
3492 st_dst,
3493 binop(op, get_ST(st_src), get_ST(st_dst) )
3494 );
3495 if (pop_after)
3496 fp_pop();
sewardjdb199622004-09-06 23:19:03 +00003497}
3498
sewardj8308aad2004-09-12 11:09:54 +00003499/* %eflags(Z,P,C) = UCOMI( st(0), st(i) ) */
3500static void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
3501{
3502 DIP("fucomi%s %%st(0),%%st(%d)\n", pop_after ? "p" : "", i);
3503 /* This is a bit of a hack (and isn't really right). It sets
3504 Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
3505 documentation implies A and S are unchanged.
3506 */
3507 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
3508 stmt( IRStmt_Put( OFFB_CC_DST, mkU32(0) ));
3509 stmt( IRStmt_Put( OFFB_CC_SRC,
3510 binop( Iop_And32,
3511 binop(Iop_CmpF64, get_ST(0), get_ST(i)),
3512 mkU32(0x45)
3513 )));
3514 if (pop_after)
3515 fp_pop();
3516}
3517
sewardjdb199622004-09-06 23:19:03 +00003518
sewardjd1725d12004-08-12 20:46:53 +00003519static
3520UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta )
3521{
sewardja58ea662004-08-15 03:12:41 +00003522 Int len;
3523 UInt r_src, r_dst;
3524 Char dis_buf[32];
sewardj89cd0932004-09-08 18:23:25 +00003525 IRTemp t1, t2;
sewardjd1725d12004-08-12 20:46:53 +00003526
3527 /* On entry, delta points at the second byte of the insn (the modrm
3528 byte).*/
3529 UChar first_opcode = getIByte(delta-1);
3530 UChar modrm = getIByte(delta+0);
3531
3532 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
3533
3534 if (first_opcode == 0xD8) {
sewardjdb199622004-09-06 23:19:03 +00003535 if (modrm < 0xC0) {
sewardj89cd0932004-09-08 18:23:25 +00003536
3537 /* bits 5,4,3 are an opcode extension, and the modRM also
3538 specifies an address. */
3539 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3540 delta += len;
3541
3542 switch (gregOfRM(modrm)) {
3543
sewardj3fd5e572004-09-09 22:43:51 +00003544 case 0: /* FADD single-real */
3545 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, False );
3546 break;
3547
sewardj89cd0932004-09-08 18:23:25 +00003548 case 1: /* FMUL single-real */
3549 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, False );
3550 break;
3551
sewardje166ed02004-10-25 02:27:01 +00003552 case 3: /* FCOM single-real */
3553 DIP("fcomps %s\n", dis_buf);
3554 /* This forces C1 to zero, which isn't right. */
3555 put_C3210(
3556 binop( Iop_And32,
3557 binop(Iop_Shl32,
3558 binop(Iop_CmpF64,
3559 get_ST(0),
3560 unop(Iop_F32toF64,
3561 loadLE(Ity_F32,mkexpr(addr)))),
3562 mkU8(8)),
3563 mkU32(0x4500)
3564 ));
3565 fp_pop();
3566 break;
3567
sewardj588ea762004-09-10 18:56:32 +00003568 case 4: /* FSUB single-real */
3569 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, False );
3570 break;
3571
3572 case 5: /* FSUBR single-real */
3573 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, False );
3574 break;
3575
sewardjbdc7d212004-09-09 02:46:40 +00003576 case 6: /* FDIV single-real */
3577 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, False );
3578 break;
3579
sewardj8308aad2004-09-12 11:09:54 +00003580 case 7: /* FDIVR single-real */
3581 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, False );
3582 break;
3583
sewardj89cd0932004-09-08 18:23:25 +00003584 default:
3585 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3586 vex_printf("first_opcode == 0xD8\n");
3587 goto decode_fail;
3588 }
sewardjdb199622004-09-06 23:19:03 +00003589 } else {
3590 delta++;
3591 switch (modrm) {
sewardj89cd0932004-09-08 18:23:25 +00003592
sewardjdb199622004-09-06 23:19:03 +00003593 case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
sewardjbdc7d212004-09-09 02:46:40 +00003594 fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
sewardjdb199622004-09-06 23:19:03 +00003595 break;
sewardj89cd0932004-09-08 18:23:25 +00003596
sewardj3fd5e572004-09-09 22:43:51 +00003597 case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
3598 fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
3599 break;
3600
sewardje166ed02004-10-25 02:27:01 +00003601#if 1
3602 /* Dunno if this is right */
3603 case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
3604 r_dst = (UInt)modrm - 0xD0;
3605 DIP("fcom %%st(0),%%st(%d)\n", r_dst);
3606 /* This forces C1 to zero, which isn't right. */
3607 put_C3210(
3608 binop( Iop_And32,
3609 binop(Iop_Shl32,
3610 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3611 mkU8(8)),
3612 mkU32(0x4500)
3613 ));
3614 break;
3615#endif
3616#if 1
sewardj98169c52004-10-24 13:11:39 +00003617 /* Dunno if this is right */
3618 case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
3619 r_dst = (UInt)modrm - 0xD8;
3620 DIP("fcomp %%st(0),%%st(%d)\n", r_dst);
3621 /* This forces C1 to zero, which isn't right. */
3622 put_C3210(
3623 binop( Iop_And32,
3624 binop(Iop_Shl32,
3625 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3626 mkU8(8)),
3627 mkU32(0x4500)
3628 ));
3629 fp_pop();
3630 break;
3631#endif
sewardj89cd0932004-09-08 18:23:25 +00003632 case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
sewardjbdc7d212004-09-09 02:46:40 +00003633 fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
sewardj89cd0932004-09-08 18:23:25 +00003634 break;
3635
sewardj8308aad2004-09-12 11:09:54 +00003636 case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
3637 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
3638 break;
3639
sewardj3fd5e572004-09-09 22:43:51 +00003640 case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
3641 fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
3642 break;
3643
3644 case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
3645 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
3646 break;
3647
sewardjdb199622004-09-06 23:19:03 +00003648 default:
3649 goto decode_fail;
3650 }
3651 }
sewardjd1725d12004-08-12 20:46:53 +00003652 }
3653
3654 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
3655 else
3656 if (first_opcode == 0xD9) {
sewardjbb53f8c2004-08-14 11:50:01 +00003657 if (modrm < 0xC0) {
sewardj89cd0932004-09-08 18:23:25 +00003658
3659 /* bits 5,4,3 are an opcode extension, and the modRM also
3660 specifies an address. */
3661 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3662 delta += len;
3663
3664 switch (gregOfRM(modrm)) {
3665
3666 case 0: /* FLD single-real */
3667 DIP("fldF %s\n", dis_buf);
3668 fp_push();
3669 put_ST(0, unop(Iop_F32toF64,
sewardj8f3debf2004-09-08 23:42:23 +00003670 loadLE(Ity_F32, mkexpr(addr))));
sewardj89cd0932004-09-08 18:23:25 +00003671 break;
3672
sewardj588ea762004-09-10 18:56:32 +00003673 case 2: /* FST single-real */
3674 DIP("fstS %s", dis_buf);
3675 storeLE(mkexpr(addr), unop(Iop_F64toF32, get_ST(0)));
3676 break;
3677
sewardj89cd0932004-09-08 18:23:25 +00003678 case 3: /* FSTP single-real */
3679 DIP("fstpS %s", dis_buf);
3680 storeLE(mkexpr(addr), unop(Iop_F64toF32, get_ST(0)));
3681 fp_pop();
3682 break;
3683
sewardj588ea762004-09-10 18:56:32 +00003684 case 5: /* FLDCW */
sewardj8f3debf2004-09-08 23:42:23 +00003685 DIP("fldcw %s", dis_buf);
3686 put_fpucw( unop(Iop_16Uto32, loadLE(Ity_I16, mkexpr(addr))) );
sewardj89cd0932004-09-08 18:23:25 +00003687 break;
3688
sewardj588ea762004-09-10 18:56:32 +00003689 case 7: /* FNSTCW */
3690 DIP("fnstcw %s", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00003691 storeLE(mkexpr(addr), unop(Iop_32to16, get_fpucw()));
sewardj89cd0932004-09-08 18:23:25 +00003692 break;
3693
3694 default:
3695 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3696 vex_printf("first_opcode == 0xD9\n");
3697 goto decode_fail;
3698 }
3699
sewardjbb53f8c2004-08-14 11:50:01 +00003700 } else {
3701 delta++;
3702 switch (modrm) {
sewardj89cd0932004-09-08 18:23:25 +00003703
sewardjbb53f8c2004-08-14 11:50:01 +00003704 case 0xC0 ... 0xC7: /* FLD %st(?) */
sewardja58ea662004-08-15 03:12:41 +00003705 r_src = (UInt)modrm - 0xC0;
3706 DIP("fld %%st(%d)\n", r_src);
sewardjbb53f8c2004-08-14 11:50:01 +00003707 t1 = newTemp(Ity_F64);
sewardja58ea662004-08-15 03:12:41 +00003708 assign(t1, get_ST(r_src));
sewardj207557a2004-08-27 12:00:18 +00003709 fp_push();
3710 put_ST(0, mkexpr(t1));
sewardjbb53f8c2004-08-14 11:50:01 +00003711 break;
3712
sewardj89cd0932004-09-08 18:23:25 +00003713 case 0xC8 ... 0xCF: /* FXCH %st(?) */
3714 r_src = (UInt)modrm - 0xC8;
3715 DIP("fxch %%st(%d)\n", r_src);
3716 t1 = newTemp(Ity_F64);
3717 t2 = newTemp(Ity_F64);
3718 assign(t1, get_ST(0));
3719 assign(t2, get_ST(r_src));
3720 put_ST_UNCHECKED(0, mkexpr(t2));
3721 put_ST_UNCHECKED(r_src, mkexpr(t1));
3722 break;
3723
sewardjcfded9a2004-09-09 11:44:16 +00003724 case 0xE0: /* FCHS */
3725 DIP("fchs\n");
3726 put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
3727 break;
3728
sewardj883b00b2004-09-11 09:30:24 +00003729 case 0xE1: /* FABS */
3730 DIP("fabs\n");
3731 put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
3732 break;
sewardjc4be80c2004-09-10 16:17:45 +00003733
sewardj883b00b2004-09-11 09:30:24 +00003734 case 0xE5: { /* FXAM */
3735 /* This is an interesting one. It examines %st(0),
3736 regardless of whether the tag says it's empty or not.
3737 Here, just pass both the tag (in our format) and the
3738 value (as a double, actually a ULong) to a helper
3739 function. */
3740 IRExpr** args;
3741 DIP("fxam");
3742 args = LibVEX_Alloc(3 * sizeof(IRExpr*));
3743 args[0] = unop(Iop_8Uto32, get_ST_TAG(0));
sewardj17442fe2004-09-20 14:54:28 +00003744 args[1] = unop(Iop_ReinterpF64asI64, get_ST_UNCHECKED(0));
sewardj883b00b2004-09-11 09:30:24 +00003745 args[2] = NULL;
3746 put_C3210(IRExpr_CCall("calculate_FXAM", Ity_I32, args));
3747 break;
3748 }
3749
3750 case 0xE8: /* FLD1 */
sewardjdb199622004-09-06 23:19:03 +00003751 DIP("fld1");
sewardjce646f22004-08-31 23:55:54 +00003752 fp_push();
3753 put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
3754 break;
3755
sewardj37158712004-10-15 21:23:12 +00003756 case 0xE9: /* FLDL2T */
3757 DIP("fldl2t");
3758 fp_push();
3759 put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781)));
3760 break;
3761
sewardj8308aad2004-09-12 11:09:54 +00003762 case 0xEA: /* FLDL2E */
3763 DIP("fldl2e");
3764 fp_push();
3765 put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739)));
3766 break;
3767
sewardja0d48d62004-09-20 21:19:03 +00003768 case 0xEB: /* FLDPI */
3769 DIP("fldpi");
3770 fp_push();
3771 put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851)));
3772 break;
3773
sewardjdb199622004-09-06 23:19:03 +00003774 case 0xEC: /* FLDLG2 */
3775 DIP("fldlg2");
3776 fp_push();
3777 put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143)));
3778 break;
3779
3780 case 0xED: /* FLDLN2 */
3781 DIP("fldln2");
3782 fp_push();
3783 put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942)));
3784 break;
3785
sewardja58ea662004-08-15 03:12:41 +00003786 case 0xEE: /* FLDZ */
3787 DIP("fldz");
sewardj207557a2004-08-27 12:00:18 +00003788 fp_push();
3789 put_ST(0, IRExpr_Const(IRConst_F64(0.0)));
sewardja58ea662004-08-15 03:12:41 +00003790 break;
3791
sewardj06c32a02004-09-12 12:07:34 +00003792 case 0xF0: /* F2XM1 */
3793 DIP("f2xm1\n");
3794 put_ST_UNCHECKED(0, unop(Iop_2xm1F64, get_ST(0)));
3795 break;
3796
sewardj52ace3e2004-09-11 17:10:08 +00003797 case 0xF1: /* FYL2X */
3798 DIP("fyl2x\n");
3799 put_ST_UNCHECKED(1, binop(Iop_Yl2xF64,
3800 get_ST(1), get_ST(0)));
3801 fp_pop();
3802 break;
3803
sewardj99016a72004-10-15 22:09:17 +00003804 case 0xF2: /* FPTAN */
3805 DIP("ftan\n");
3806 put_ST_UNCHECKED(0, unop(Iop_TanF64, get_ST(0)));
3807 fp_push();
3808 put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
sewardj3f61ddb2004-10-16 20:51:05 +00003809 clear_C2(); /* HACK */
sewardj99016a72004-10-15 22:09:17 +00003810 break;
3811
sewardjcfded9a2004-09-09 11:44:16 +00003812 case 0xF3: /* FPATAN */
3813 DIP("fpatan\n");
sewardj52ace3e2004-09-11 17:10:08 +00003814 put_ST_UNCHECKED(1, binop(Iop_AtanF64,
sewardjcfded9a2004-09-09 11:44:16 +00003815 get_ST(1), get_ST(0)));
3816 fp_pop();
3817 break;
3818
sewardj442d0be2004-10-15 22:57:13 +00003819 case 0xF5: { /* FPREM1 -- IEEE compliant */
3820 IRTemp a1 = newTemp(Ity_F64);
3821 IRTemp a2 = newTemp(Ity_F64);
3822 DIP("fprem1\n");
3823 /* Do FPREM1 twice, once to get the remainder, and once
3824 to get the C3210 flag values. */
3825 assign( a1, get_ST(0) );
3826 assign( a2, get_ST(1) );
3827 put_ST_UNCHECKED(0, binop(Iop_PRem1F64,
3828 mkexpr(a1), mkexpr(a2)));
3829 put_C3210( binop(Iop_PRem1C3210F64, mkexpr(a1), mkexpr(a2)) );
3830 break;
3831 }
3832
sewardj46de4072004-09-11 19:23:24 +00003833 case 0xF8: { /* FPREM -- not IEEE compliant */
3834 IRTemp a1 = newTemp(Ity_F64);
3835 IRTemp a2 = newTemp(Ity_F64);
3836 DIP("fprem\n");
3837 /* Do FPREM twice, once to get the remainder, and once
3838 to get the C3210 flag values. */
3839 assign( a1, get_ST(0) );
3840 assign( a2, get_ST(1) );
3841 put_ST_UNCHECKED(0, binop(Iop_PRemF64,
3842 mkexpr(a1), mkexpr(a2)));
3843 put_C3210( binop(Iop_PRemC3210F64, mkexpr(a1), mkexpr(a2)) );
3844 break;
3845 }
3846
sewardj8308aad2004-09-12 11:09:54 +00003847 case 0xF9: /* FYL2XP1 */
3848 DIP("fyl2xp1\n");
3849 put_ST_UNCHECKED(1, binop(Iop_Yl2xp1F64,
3850 get_ST(1), get_ST(0)));
3851 fp_pop();
3852 break;
3853
sewardjc4be80c2004-09-10 16:17:45 +00003854 case 0xFA: /* FSQRT */
3855 DIP("fsqrt\n");
3856 put_ST_UNCHECKED(0, unop(Iop_SqrtF64, get_ST(0)));
3857 break;
3858
sewardje6709112004-09-10 18:37:18 +00003859 case 0xFC: /* FRNDINT */
3860 DIP("frndint\n");
3861 put_ST_UNCHECKED(0,
3862 binop(Iop_RoundF64, get_roundingmode(), get_ST(0)) );
3863 break;
3864
sewardj06c32a02004-09-12 12:07:34 +00003865 case 0xFD: /* FSCALE */
3866 DIP("fscale\n");
3867 put_ST_UNCHECKED(0, binop(Iop_ScaleF64,
3868 get_ST(0), get_ST(1)));
3869 break;
3870
sewardjcfded9a2004-09-09 11:44:16 +00003871 case 0xFE: /* FSIN */
3872 DIP("fsin\n");
3873 put_ST_UNCHECKED(0, unop(Iop_SinF64, get_ST(0)));
sewardj3f61ddb2004-10-16 20:51:05 +00003874 clear_C2(); /* HACK */
sewardjcfded9a2004-09-09 11:44:16 +00003875 break;
3876
3877 case 0xFF: /* FCOS */
3878 DIP("fcos\n");
3879 put_ST_UNCHECKED(0, unop(Iop_CosF64, get_ST(0)));
sewardj3f61ddb2004-10-16 20:51:05 +00003880 clear_C2(); /* HACK */
sewardjcfded9a2004-09-09 11:44:16 +00003881 break;
3882
sewardjbb53f8c2004-08-14 11:50:01 +00003883 default:
3884 goto decode_fail;
3885 }
3886 }
sewardjd1725d12004-08-12 20:46:53 +00003887 }
3888
3889 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
3890 else
3891 if (first_opcode == 0xDA) {
sewardjbb53f8c2004-08-14 11:50:01 +00003892
3893 if (modrm < 0xC0) {
3894
3895 /* bits 5,4,3 are an opcode extension, and the modRM also
3896 specifies an address. */
sewardjce646f22004-08-31 23:55:54 +00003897 IROp fop;
sewardjbb53f8c2004-08-14 11:50:01 +00003898 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3899 delta += len;
sewardjbb53f8c2004-08-14 11:50:01 +00003900 switch (gregOfRM(modrm)) {
sewardjce646f22004-08-31 23:55:54 +00003901
sewardjdb199622004-09-06 23:19:03 +00003902 case 0: /* FIADD m32int */ /* ST(0) += m32int */
3903 DIP("fiaddl %s", dis_buf);
3904 fop = Iop_AddF64;
3905 goto do_fop_m32;
3906
sewardj207557a2004-08-27 12:00:18 +00003907 case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
sewardjbb53f8c2004-08-14 11:50:01 +00003908 DIP("fimull %s", dis_buf);
sewardjce646f22004-08-31 23:55:54 +00003909 fop = Iop_MulF64;
3910 goto do_fop_m32;
3911
3912 case 4: /* FISUB m32int */ /* ST(0) -= m32int */
3913 DIP("fisubl %s", dis_buf);
3914 fop = Iop_SubF64;
3915 goto do_fop_m32;
3916
sewardj8308aad2004-09-12 11:09:54 +00003917 case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
3918 DIP("fisubrl %s", dis_buf);
3919 fop = Iop_SubF64;
3920 goto do_foprev_m32;
3921
sewardjce646f22004-08-31 23:55:54 +00003922 case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
3923 DIP("fisubl %s", dis_buf);
3924 fop = Iop_DivF64;
3925 goto do_fop_m32;
3926
sewardjc4eaff32004-09-10 20:25:11 +00003927 case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
sewardj8308aad2004-09-12 11:09:54 +00003928 DIP("fidivrl %s", dis_buf);
sewardjc4eaff32004-09-10 20:25:11 +00003929 fop = Iop_DivF64;
3930 goto do_foprev_m32;
3931
sewardjce646f22004-08-31 23:55:54 +00003932 do_fop_m32:
sewardj207557a2004-08-27 12:00:18 +00003933 put_ST_UNCHECKED(0,
sewardjce646f22004-08-31 23:55:54 +00003934 binop(fop,
sewardj207557a2004-08-27 12:00:18 +00003935 get_ST(0),
sewardj89cd0932004-09-08 18:23:25 +00003936 unop(Iop_I32toF64,
3937 loadLE(Ity_I32, mkexpr(addr)))));
sewardjbb53f8c2004-08-14 11:50:01 +00003938 break;
3939
sewardjc4eaff32004-09-10 20:25:11 +00003940 do_foprev_m32:
3941 put_ST_UNCHECKED(0,
3942 binop(fop,
3943 unop(Iop_I32toF64,
3944 loadLE(Ity_I32, mkexpr(addr))),
3945 get_ST(0)));
3946 break;
3947
sewardjbb53f8c2004-08-14 11:50:01 +00003948 default:
3949 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3950 vex_printf("first_opcode == 0xDA\n");
3951 goto decode_fail;
3952 }
3953 } else {
sewardjbdc7d212004-09-09 02:46:40 +00003954
3955 delta++;
3956 switch (modrm) {
3957
sewardj3fd5e572004-09-09 22:43:51 +00003958 case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
3959 r_src = (UInt)modrm - 0xC8;
3960 DIP("fcmovz %%st(%d), %%st(0)", r_src);
3961 put_ST_UNCHECKED(0,
3962 IRExpr_Mux0X(
3963 unop(Iop_1Uto8,calculate_condition(CondZ)),
3964 get_ST(0), get_ST(r_src)) );
3965 break;
3966
sewardjbdc7d212004-09-09 02:46:40 +00003967 case 0xE9: /* FUCOMPP %st(0),%st(1) */
3968 DIP("fucompp %%st(0),%%st(1)\n");
sewardjc4be80c2004-09-10 16:17:45 +00003969 /* This forces C1 to zero, which isn't right. */
3970 put_C3210(
3971 binop( Iop_And32,
3972 binop(Iop_Shl32,
3973 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
3974 mkU8(8)),
3975 mkU32(0x4500)
3976 ));
sewardjbdc7d212004-09-09 02:46:40 +00003977 fp_pop();
3978 fp_pop();
3979 break;
3980
3981 default:
3982 goto decode_fail;
3983 }
3984
sewardjbb53f8c2004-08-14 11:50:01 +00003985 }
sewardjd1725d12004-08-12 20:46:53 +00003986 }
3987
3988 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
3989 else
3990 if (first_opcode == 0xDB) {
sewardj89cd0932004-09-08 18:23:25 +00003991 if (modrm < 0xC0) {
3992
3993 /* bits 5,4,3 are an opcode extension, and the modRM also
3994 specifies an address. */
3995 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3996 delta += len;
3997
3998 switch (gregOfRM(modrm)) {
3999
4000 case 0: /* FILD m32int */
4001 DIP("fildl %s\n", dis_buf);
4002 fp_push();
4003 put_ST(0, unop(Iop_I32toF64,
4004 loadLE(Ity_I32, mkexpr(addr))));
4005 break;
4006
sewardj8f3debf2004-09-08 23:42:23 +00004007 case 2: /* FIST m32 */
4008 DIP("fistl %s", dis_buf);
4009 storeLE( mkexpr(addr),
4010 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
4011 break;
4012
sewardj89cd0932004-09-08 18:23:25 +00004013 case 3: /* FISTP m32 */
4014 DIP("fistpl %s", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004015 storeLE( mkexpr(addr),
4016 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
sewardj89cd0932004-09-08 18:23:25 +00004017 fp_pop();
4018 break;
sewardj17442fe2004-09-20 14:54:28 +00004019
sewardjb3bce0e2004-09-14 23:20:10 +00004020 case 5: { /* FLD extended-real */
sewardj7cb49d72004-10-24 22:31:25 +00004021 /* Uses dirty helper:
4022 ULong loadF80le ( VexGuestX86State*, UInt )
4023 addr holds the address. First, do a dirty call to
sewardjb3bce0e2004-09-14 23:20:10 +00004024 get hold of the data. */
4025 /* give details of args, and where to call */
sewardj17442fe2004-09-20 14:54:28 +00004026 IRDirty* d;
4027 DIP("fldt %s", dis_buf);
4028 d = emptyIRDirty();
sewardjb3bce0e2004-09-14 23:20:10 +00004029 d->name = "loadF80le";
4030 d->args = LibVEX_Alloc(2 * sizeof(IRTemp));
sewardj17442fe2004-09-20 14:54:28 +00004031 d->args[0] = mkexpr(addr);
4032 d->args[1] = NULL;
4033 d->tmp = newTemp(Ity_I64);
sewardjb3bce0e2004-09-14 23:20:10 +00004034 /* declare that we're reading memory */
4035 d->mFx = Ifx_Read;
sewardj17442fe2004-09-20 14:54:28 +00004036 d->mAddr = mkexpr(addr);
sewardjb3bce0e2004-09-14 23:20:10 +00004037 d->mSize = 10;
4038 /* declare that we don't mess with guest state */
4039 d->nFxState = 0;
4040 /* execute the dirty call, dumping the result in d->tmp. */
4041 stmt( IRStmt_Dirty(d) );
4042 fp_push();
sewardj17442fe2004-09-20 14:54:28 +00004043 put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(d->tmp)));
sewardjb3bce0e2004-09-14 23:20:10 +00004044 break;
4045 }
sewardj17442fe2004-09-20 14:54:28 +00004046
4047 case 7: { /* FSTP extended-real */
4048 /* Uses dirty helper: void storeF80le ( UInt, ULong ) */
4049 IRDirty* d;
4050 DIP("fldt %s", dis_buf);
4051 d = emptyIRDirty();
4052 d->name = "storeF80le";
4053 /* takes 2 args */
4054 d->args = LibVEX_Alloc(3 * sizeof(IRTemp));
4055 d->args[0] = mkexpr(addr);
4056 d->args[1] = unop(Iop_ReinterpF64asI64, get_ST(0));
4057 d->args[2] = NULL;
4058 /* returns nothing */
4059 d->tmp = INVALID_IRTEMP;
4060 /* declare we're writing memory */
4061 d->mFx = Ifx_Write;
4062 d->mAddr = mkexpr(addr);
4063 d->mSize = 10;
4064 /* declare that we don't mess with guest state */
4065 d->nFxState = 0;
4066 /* execute the dirty call. */
4067 stmt( IRStmt_Dirty(d) );
4068 fp_pop();
4069 break;
4070 }
4071
sewardjb3bce0e2004-09-14 23:20:10 +00004072 default:
sewardj89cd0932004-09-08 18:23:25 +00004073 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4074 vex_printf("first_opcode == 0xDB\n");
4075 goto decode_fail;
4076 }
4077
4078 } else {
sewardj8308aad2004-09-12 11:09:54 +00004079
4080 delta++;
4081 switch (modrm) {
4082
sewardj4e82db72004-10-16 11:32:15 +00004083 case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
4084 r_src = (UInt)modrm - 0xC8;
4085 DIP("fcmovnz %%st(%d), %%st(0)", r_src);
4086 put_ST_UNCHECKED(0,
4087 IRExpr_Mux0X(
4088 unop(Iop_1Uto8,calculate_condition(CondNZ)),
4089 get_ST(0), get_ST(r_src)) );
4090 break;
4091
sewardj8308aad2004-09-12 11:09:54 +00004092 case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
4093 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
4094 break;
4095
sewardj37158712004-10-15 21:23:12 +00004096 case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
4097 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
4098 break;
4099
sewardj8308aad2004-09-12 11:09:54 +00004100 default:
4101 goto decode_fail;
sewardj17442fe2004-09-20 14:54:28 +00004102 }
sewardj89cd0932004-09-08 18:23:25 +00004103 }
sewardjd1725d12004-08-12 20:46:53 +00004104 }
4105
4106 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
4107 else
4108 if (first_opcode == 0xDC) {
sewardja58ea662004-08-15 03:12:41 +00004109 if (modrm < 0xC0) {
4110
sewardj89cd0932004-09-08 18:23:25 +00004111 /* bits 5,4,3 are an opcode extension, and the modRM also
4112 specifies an address. */
sewardja58ea662004-08-15 03:12:41 +00004113 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4114 delta += len;
4115
4116 switch (gregOfRM(modrm)) {
4117
4118 case 0: /* FADD double-real */
4119 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
4120 break;
4121
sewardjcfded9a2004-09-09 11:44:16 +00004122 case 1: /* FMUL double-real */
4123 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
4124 break;
4125
sewardje166ed02004-10-25 02:27:01 +00004126 case 2: /* FCOM double-real */
4127 DIP("fcoml %s\n", dis_buf);
4128 /* This forces C1 to zero, which isn't right. */
4129 put_C3210(
4130 binop( Iop_And32,
4131 binop(Iop_Shl32,
4132 binop(Iop_CmpF64,
4133 get_ST(0),
4134 loadLE(Ity_F64,mkexpr(addr))),
4135 mkU8(8)),
4136 mkU32(0x4500)
4137 ));
4138 break;
4139
sewardj883b00b2004-09-11 09:30:24 +00004140 case 3: /* FCOMP double-real */
sewardje166ed02004-10-25 02:27:01 +00004141 DIP("fcompl %s\n", dis_buf);
sewardj883b00b2004-09-11 09:30:24 +00004142 /* This forces C1 to zero, which isn't right. */
4143 put_C3210(
4144 binop( Iop_And32,
4145 binop(Iop_Shl32,
4146 binop(Iop_CmpF64,
4147 get_ST(0),
4148 loadLE(Ity_F64,mkexpr(addr))),
4149 mkU8(8)),
4150 mkU32(0x4500)
4151 ));
4152 fp_pop();
4153 break;
4154
sewardjcfded9a2004-09-09 11:44:16 +00004155 case 4: /* FSUB double-real */
4156 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
4157 break;
4158
sewardj3fd5e572004-09-09 22:43:51 +00004159 case 5: /* FSUBR double-real */
4160 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
4161 break;
4162
sewardjcfded9a2004-09-09 11:44:16 +00004163 case 6: /* FDIV double-real */
4164 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
4165 break;
4166
sewardj883b00b2004-09-11 09:30:24 +00004167 case 7: /* FDIVR double-real */
4168 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
4169 break;
4170
sewardja58ea662004-08-15 03:12:41 +00004171 default:
4172 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4173 vex_printf("first_opcode == 0xDC\n");
4174 goto decode_fail;
4175 }
4176
4177 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004178
4179 delta++;
4180 switch (modrm) {
4181
sewardj3fd5e572004-09-09 22:43:51 +00004182 case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
4183 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
4184 break;
4185
sewardjcfded9a2004-09-09 11:44:16 +00004186 case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
4187 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
4188 break;
4189
sewardj47341042004-09-19 11:55:46 +00004190 case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
4191 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
4192 break;
4193
sewardjcfded9a2004-09-09 11:44:16 +00004194 case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
4195 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
4196 break;
4197
sewardja0d48d62004-09-20 21:19:03 +00004198 case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
4199 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
4200 break;
4201
sewardjbdc7d212004-09-09 02:46:40 +00004202 case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
4203 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
4204 break;
4205
4206 default:
4207 goto decode_fail;
4208 }
4209
sewardja58ea662004-08-15 03:12:41 +00004210 }
sewardjd1725d12004-08-12 20:46:53 +00004211 }
4212
4213 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
4214 else
4215 if (first_opcode == 0xDD) {
4216
4217 if (modrm < 0xC0) {
4218
sewardjbb53f8c2004-08-14 11:50:01 +00004219 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjd1725d12004-08-12 20:46:53 +00004220 specifies an address. */
sewardjbb53f8c2004-08-14 11:50:01 +00004221 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4222 delta += len;
sewardjd1725d12004-08-12 20:46:53 +00004223
4224 switch (gregOfRM(modrm)) {
4225
4226 case 0: /* FLD double-real */
4227 DIP("fldD %s\n", dis_buf);
sewardj207557a2004-08-27 12:00:18 +00004228 fp_push();
4229 put_ST(0, IRExpr_LDle(Ity_F64, mkexpr(addr)));
sewardjbb53f8c2004-08-14 11:50:01 +00004230 break;
sewardjd1725d12004-08-12 20:46:53 +00004231
sewardjd1725d12004-08-12 20:46:53 +00004232 case 2: /* FST double-real */
sewardj89cd0932004-09-08 18:23:25 +00004233 DIP("fstD %s", dis_buf);
4234 storeLE(mkexpr(addr), get_ST(0));
sewardjd1725d12004-08-12 20:46:53 +00004235 break;
sewardj89cd0932004-09-08 18:23:25 +00004236
sewardja58ea662004-08-15 03:12:41 +00004237 case 3: /* FSTP double-real */
4238 DIP("fstpD %s", dis_buf);
4239 storeLE(mkexpr(addr), get_ST(0));
sewardj207557a2004-08-27 12:00:18 +00004240 fp_pop();
sewardja58ea662004-08-15 03:12:41 +00004241 break;
sewardjd1725d12004-08-12 20:46:53 +00004242
4243 default:
sewardjbb53f8c2004-08-14 11:50:01 +00004244 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4245 vex_printf("first_opcode == 0xDD\n");
sewardjd1725d12004-08-12 20:46:53 +00004246 goto decode_fail;
sewardjbb53f8c2004-08-14 11:50:01 +00004247 }
sewardjd1725d12004-08-12 20:46:53 +00004248 } else {
sewardja58ea662004-08-15 03:12:41 +00004249 delta++;
4250 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00004251
sewardj06c32a02004-09-12 12:07:34 +00004252 case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
4253 r_dst = (UInt)modrm - 0xD0;
4254 DIP("fst %%st(0),%%st(%d)\n", r_dst);
4255 /* P4 manual says: "If the destination operand is a
4256 non-empty register, the invalid-operation exception
4257 is not generated. Hence put_ST_UNCHECKED. */
4258 put_ST_UNCHECKED(r_dst, get_ST(0));
4259 break;
4260
sewardja58ea662004-08-15 03:12:41 +00004261 case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
4262 r_dst = (UInt)modrm - 0xD8;
4263 DIP("fstp %%st(0),%%st(%d)\n", r_dst);
sewardj207557a2004-08-27 12:00:18 +00004264 /* P4 manual says: "If the destination operand is a
4265 non-empty register, the invalid-operation exception
4266 is not generated. Hence put_ST_UNCHECKED. */
4267 put_ST_UNCHECKED(r_dst, get_ST(0));
4268 fp_pop();
sewardja58ea662004-08-15 03:12:41 +00004269 break;
sewardjbdc7d212004-09-09 02:46:40 +00004270
4271 case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
4272 r_dst = (UInt)modrm - 0xE0;
4273 DIP("fucom %%st(0),%%st(%d)\n", r_dst);
sewardjc4be80c2004-09-10 16:17:45 +00004274 /* This forces C1 to zero, which isn't right. */
4275 put_C3210(
4276 binop( Iop_And32,
4277 binop(Iop_Shl32,
4278 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4279 mkU8(8)),
4280 mkU32(0x4500)
4281 ));
sewardjbdc7d212004-09-09 02:46:40 +00004282 break;
4283
4284 case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
4285 r_dst = (UInt)modrm - 0xE8;
4286 DIP("fucomp %%st(0),%%st(%d)\n", r_dst);
sewardjc4be80c2004-09-10 16:17:45 +00004287 /* This forces C1 to zero, which isn't right. */
4288 put_C3210(
4289 binop( Iop_And32,
4290 binop(Iop_Shl32,
4291 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4292 mkU8(8)),
4293 mkU32(0x4500)
4294 ));
sewardjbdc7d212004-09-09 02:46:40 +00004295 fp_pop();
4296 break;
4297
sewardja58ea662004-08-15 03:12:41 +00004298 default:
4299 goto decode_fail;
4300 }
sewardjd1725d12004-08-12 20:46:53 +00004301 }
4302 }
4303
4304 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
4305 else
4306 if (first_opcode == 0xDE) {
sewardjbdc7d212004-09-09 02:46:40 +00004307
4308 if (modrm < 0xC0) {
4309 goto decode_fail;
4310
4311 } else {
4312
4313 delta++;
4314 switch (modrm) {
4315
sewardjcfded9a2004-09-09 11:44:16 +00004316 case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
4317 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
4318 break;
4319
sewardjbdc7d212004-09-09 02:46:40 +00004320 case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
4321 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
4322 break;
4323
sewardje166ed02004-10-25 02:27:01 +00004324 case 0xD9: /* FCOMPP %st(0),%st(1) */
4325 DIP("fuompp %%st(0),%%st(1)\n");
4326 /* This forces C1 to zero, which isn't right. */
4327 put_C3210(
4328 binop( Iop_And32,
4329 binop(Iop_Shl32,
4330 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
4331 mkU8(8)),
4332 mkU32(0x4500)
4333 ));
4334 fp_pop();
4335 fp_pop();
4336 break;
4337
sewardjcfded9a2004-09-09 11:44:16 +00004338 case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
4339 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, True );
4340 break;
4341
sewardj3fd5e572004-09-09 22:43:51 +00004342 case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
4343 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, True );
4344 break;
4345
sewardjbdc7d212004-09-09 02:46:40 +00004346 case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
4347 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
4348 break;
4349
4350 case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
4351 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
4352 break;
4353
4354 default:
4355 goto decode_fail;
4356 }
4357
4358 }
sewardjd1725d12004-08-12 20:46:53 +00004359 }
4360
4361 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
4362 else
4363 if (first_opcode == 0xDF) {
sewardj89cd0932004-09-08 18:23:25 +00004364
4365 if (modrm < 0xC0) {
4366
4367 /* bits 5,4,3 are an opcode extension, and the modRM also
4368 specifies an address. */
4369 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4370 delta += len;
4371
4372 switch (gregOfRM(modrm)) {
4373
sewardj883b00b2004-09-11 09:30:24 +00004374 case 0: /* FILD m16int */
4375 DIP("fildw %s\n", dis_buf);
4376 fp_push();
4377 put_ST(0, unop(Iop_I32toF64,
4378 unop(Iop_16Sto32,
4379 loadLE(Ity_I16, mkexpr(addr)))));
4380 break;
4381
sewardj37158712004-10-15 21:23:12 +00004382 case 2: /* FIST m16 */
4383 DIP("fistp %s", dis_buf);
4384 storeLE( mkexpr(addr),
4385 binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
4386 break;
4387
sewardj89cd0932004-09-08 18:23:25 +00004388 case 3: /* FISTP m16 */
4389 DIP("fistps %s", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004390 storeLE( mkexpr(addr),
4391 binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
4392 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00004393 break;
4394
sewardj89cd0932004-09-08 18:23:25 +00004395 case 5: /* FILD m64 */
4396 DIP("fildll %s\n", dis_buf);
4397 fp_push();
4398 put_ST(0, unop(Iop_I64toF64,
4399 loadLE(Ity_I64, mkexpr(addr))));
4400 break;
sewardj89cd0932004-09-08 18:23:25 +00004401
sewardjcfded9a2004-09-09 11:44:16 +00004402 case 7: /* FISTP m64 */
4403 DIP("fistpll %s", dis_buf);
4404 storeLE( mkexpr(addr),
4405 binop(Iop_F64toI64, get_roundingmode(), get_ST(0)) );
4406 fp_pop();
4407 break;
4408
sewardj89cd0932004-09-08 18:23:25 +00004409 default:
4410 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4411 vex_printf("first_opcode == 0xDF\n");
4412 goto decode_fail;
4413 }
4414
4415 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004416
4417 delta++;
4418 switch (modrm) {
4419
4420 case 0xE0: /* FNSTSW %ax */
4421 DIP("fnstsw %%ax\n");
4422 /* Invent a plausible-looking FPU status word value and
4423 dump it in %AX:
sewardjc4be80c2004-09-10 16:17:45 +00004424 ((ftop & 7) << 11) | (c3210 & 0x4700)
sewardjbdc7d212004-09-09 02:46:40 +00004425 */
4426 putIReg(2, R_EAX,
4427 unop(Iop_32to16,
4428 binop(Iop_Or32,
4429 binop(Iop_Shl32,
4430 binop(Iop_And32, get_ftop(), mkU32(7)),
4431 mkU8(11)),
sewardjc4be80c2004-09-10 16:17:45 +00004432 binop(Iop_And32, get_C3210(), mkU32(0x4700))
sewardjbdc7d212004-09-09 02:46:40 +00004433 )));
4434 break;
4435
sewardj883b00b2004-09-11 09:30:24 +00004436 case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
sewardj8308aad2004-09-12 11:09:54 +00004437 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
sewardj883b00b2004-09-11 09:30:24 +00004438 break;
4439
sewardjbdc7d212004-09-09 02:46:40 +00004440 default:
4441 goto decode_fail;
4442 }
sewardj89cd0932004-09-08 18:23:25 +00004443 }
4444
sewardjd1725d12004-08-12 20:46:53 +00004445 }
4446
4447 else
4448 vpanic("dis_FPU(x86): invalid primary opcode");
4449
sewardj69d9d662004-10-14 21:58:52 +00004450 *decode_ok = True;
4451 return delta;
4452
sewardjd1725d12004-08-12 20:46:53 +00004453 decode_fail:
4454 *decode_ok = False;
4455 return delta;
4456}
4457
4458
sewardjc9a65702004-07-07 16:32:57 +00004459//-- /* Handle FPU insns which read/write memory. On entry, eip points to
4460//-- the second byte of the insn (the one following D8 .. DF). */
4461//-- static
4462//-- Addr dis_fpu_mem ( UCodeBlock* cb,
4463//-- UChar sorb,
4464//-- Int size, Bool is_write,
4465//-- Addr eip, UChar first_byte )
4466//-- {
4467//-- Int ta;
4468//-- UInt pair;
4469//-- UChar dis_buf[50];
4470//-- UChar second_byte = getIByte(delta);
4471//-- vg_assert(second_byte < 0xC0);
4472//-- second_byte &= 0x38;
4473//-- pair = disAMode ( cb, sorb, eip, dis_buf );
4474//-- ta = LOW24(pair);
4475//-- eip += HI8(pair);
4476//-- uInstr2(cb, is_write ? FPU_W : FPU_R, size,
4477//-- Lit16,
4478//-- (((UShort)first_byte) << 8) | ((UShort)second_byte),
4479//-- TempReg, ta);
4480//-- if (is_write) {
4481//-- DIP("fpu_w_%d 0x%x:0x%x, %s\n",
4482//-- size, (UInt)first_byte, (UInt)second_byte, dis_buf );
4483//-- } else {
4484//-- DIP("fpu_r_%d %s, 0x%x:0x%x\n",
4485//-- size, dis_buf, (UInt)first_byte, (UInt)second_byte );
4486//-- }
4487//-- return eip;
4488//-- }
4489//--
4490//--
4491//-- /* Handle FPU insns which don't reference memory. On entry, eip points to
4492//-- the second byte of the insn (the one following D8 .. DF). */
4493//-- static
4494//-- Addr dis_fpu_no_mem ( UCodeBlock* cb, Addr eip, UChar first_byte )
4495//-- {
4496//-- Bool sets_ZCP = False;
4497//-- Bool uses_ZCP = False;
4498//-- UChar second_byte = getUChar(eip); eip++;
4499//-- vg_assert(second_byte >= 0xC0);
4500//--
4501//-- /* Does the insn write any integer condition codes (%EIP) ? */
4502//--
4503//-- if (first_byte == 0xDB && second_byte >= 0xF0 && second_byte <= 0xF7) {
4504//-- /* FCOMI */
4505//-- sets_ZCP = True;
4506//-- } else
4507//-- if (first_byte == 0xDF && second_byte >= 0xF0 && second_byte <= 0xF7) {
4508//-- /* FCOMIP */
4509//-- sets_ZCP = True;
4510//-- } else
4511//-- if (first_byte == 0xDB && second_byte >= 0xE8 && second_byte <= 0xEF) {
4512//-- /* FUCOMI */
4513//-- sets_ZCP = True;
4514//-- } else
4515//-- if (first_byte == 0xDF && second_byte >= 0xE8 && second_byte <= 0xEF) {
4516//-- /* FUCOMIP */
4517//-- sets_ZCP = True;
4518//-- }
4519//--
4520//-- /* Dually, does the insn read any integer condition codes (%EIP) ? */
4521//--
4522//-- if (first_byte == 0xDA && second_byte >= 0xC0 && second_byte <= 0xDF) {
4523//-- /* FCMOVB %st(n), %st(0)
4524//-- FCMOVE %st(n), %st(0)
4525//-- FCMOVBE %st(n), %st(0)
4526//-- FCMOVU %st(n), %st(0)
4527//-- */
4528//-- uses_ZCP = True;
4529//-- } else
4530//-- if (first_byte == 0xDB && second_byte >= 0xC0 && second_byte <= 0xDF) {
4531//-- /* FCMOVNB %st(n), %st(0)
4532//-- FCMOVNE %st(n), %st(0)
4533//-- FCMOVNBE %st(n), %st(0)
4534//-- FCMOVNU %st(n), %st(0)
4535//-- */
4536//-- uses_ZCP = True;
4537//-- }
4538//--
4539//-- uInstr1(cb, FPU, 0,
4540//-- Lit16,
4541//-- (((UShort)first_byte) << 8) | ((UShort)second_byte)
4542//-- );
4543//-- if (uses_ZCP) {
4544//-- /* VG_(printf)("!!! --- FPU insn which reads %EFLAGS\n"); */
4545//-- uFlagsRWU(cb, FlagsZCP, FlagsEmpty, FlagsEmpty);
4546//-- vg_assert(!sets_ZCP);
4547//-- }
4548//-- if (sets_ZCP) {
4549//-- /* VG_(printf)("!!! --- FPU insn which writes %EFLAGS\n"); */
4550//-- uFlagsRWU(cb, FlagsEmpty, FlagsZCP, FlagsEmpty);
4551//-- vg_assert(!uses_ZCP);
4552//-- }
4553//--
4554//-- DIP("fpu 0x%x:0x%x%s%s\n", (UInt)first_byte, (UInt)second_byte,
4555//-- uses_ZCP ? " -rZCP" : "",
4556//-- sets_ZCP ? " -wZCP" : "" );
4557//-- return eip;
4558//-- }
4559//--
4560//--
4561//-- /* Top-level handler for all FPU insns. On entry, eip points to the
4562//-- second byte of the insn. */
4563//-- static
4564//-- Addr dis_fpu ( UCodeBlock* cb,
4565//-- UChar sorb,
4566//-- UChar first_byte, Addr eip )
4567//-- {
4568//-- const Bool rd = False;
4569//-- const Bool wr = True;
4570//-- UChar second_byte = getUChar(eip);
4571//--
4572//-- /* Handle FSTSW %ax specially. */
4573//-- if (first_byte == 0xDF && second_byte == 0xE0) {
4574//-- Int t1 = newTemp(cb);
4575//-- uInstr0(cb, CALLM_S, 0);
4576//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
4577//-- uLiteral(cb, 0);
4578//-- uInstr1(cb, PUSH, 4, TempReg, t1);
4579//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_fstsw_AX) );
4580//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
4581//-- uInstr1(cb, POP, 2, TempReg, t1);
4582//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
4583//-- uInstr0(cb, CALLM_E, 0);
4584//-- DIP("fstsw %%ax\n");
4585//-- eip++;
4586//-- return eip;
4587//-- }
4588//--
4589//-- /* Handle all non-memory FPU ops simply. */
4590//-- if (second_byte >= 0xC0)
4591//-- return dis_fpu_no_mem ( cb, eip, first_byte );
4592//--
4593//-- /* The insn references memory; need to determine
4594//-- whether it reads or writes, and at what size. */
4595//-- switch (first_byte) {
4596//--
4597//-- case 0xD8:
4598//-- switch ((second_byte >> 3) & 7) {
4599//-- case 0: /* FADDs */
4600//-- case 1: /* FMULs */
4601//-- case 2: /* FCOMs */
4602//-- case 3: /* FCOMPs */
4603//-- case 4: /* FSUBs */
4604//-- case 5: /* FSUBRs */
4605//-- case 6: /* FDIVs */
4606//-- case 7: /* FDIVRs */
4607//-- return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
4608//-- default:
4609//-- goto unhandled;
4610//-- }
4611//-- break;
4612//--
4613//-- case 0xD9:
4614//-- switch ((second_byte >> 3) & 7) {
4615//-- case 0: /* FLDs */
4616//-- return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
4617//-- case 2: /* FSTs */
4618//-- case 3: /* FSTPs */
4619//-- return dis_fpu_mem(cb, sorb, 4, wr, eip, first_byte);
4620//-- case 4: /* FLDENV */
4621//-- return dis_fpu_mem(cb, sorb, 28, rd, eip, first_byte);
4622//-- case 5: /* FLDCW */
4623//-- return dis_fpu_mem(cb, sorb, 2, rd, eip, first_byte);
4624//-- case 6: /* FNSTENV */
4625//-- return dis_fpu_mem(cb, sorb, 28, wr, eip, first_byte);
4626//-- case 7: /* FSTCW */
4627//-- /* HACK! FSTCW actually writes 2 bytes, not 4. glibc
4628//-- gets lots of moaning in __floor() if we do the right
4629//-- thing here. */
4630//-- /* Later ... hack disabled .. we do do the Right Thing. */
4631//-- return dis_fpu_mem(cb, sorb, /*4*/ 2, wr, eip, first_byte);
4632//-- default:
4633//-- goto unhandled;
4634//-- }
4635//-- break;
4636//--
4637//-- case 0xDA:
4638//-- switch ((second_byte >> 3) & 7) {
4639//-- case 0: /* FIADD dword-integer */
4640//-- case 1: /* FIMUL dword-integer */
4641//-- case 2: /* FICOM dword-integer */
4642//-- case 3: /* FICOMP dword-integer */
4643//-- case 4: /* FISUB dword-integer */
4644//-- case 5: /* FISUBR dword-integer */
4645//-- case 6: /* FIDIV dword-integer */
4646//-- case 7: /* FIDIVR dword-integer */
4647//-- return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
4648//-- default:
4649//-- goto unhandled;
4650//-- }
4651//-- break;
4652//--
4653//-- case 0xDB:
4654//-- switch ((second_byte >> 3) & 7) {
4655//-- case 0: /* FILD dword-integer */
4656//-- return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
4657//-- case 2: /* FIST dword-integer */
4658//-- return dis_fpu_mem(cb, sorb, 4, wr, eip, first_byte);
4659//-- case 3: /* FISTPl */
4660//-- return dis_fpu_mem(cb, sorb, 4, wr, eip, first_byte);
4661//-- case 5: /* FLD extended-real */
4662//-- return dis_fpu_mem(cb, sorb, 10, rd, eip, first_byte);
4663//-- case 7: /* FSTP extended-real */
4664//-- return dis_fpu_mem(cb, sorb, 10, wr, eip, first_byte);
4665//-- default:
4666//-- goto unhandled;
4667//-- }
4668//-- break;
4669//--
4670//-- case 0xDC:
4671//-- switch ((second_byte >> 3) & 7) {
4672//-- case 0: /* FADD double-real */
4673//-- case 1: /* FMUL double-real */
4674//-- case 2: /* FCOM double-real */
4675//-- case 3: /* FCOMP double-real */
4676//-- case 4: /* FSUB double-real */
4677//-- case 5: /* FSUBR double-real */
4678//-- case 6: /* FDIV double-real */
4679//-- case 7: /* FDIVR double-real */
4680//-- return dis_fpu_mem(cb, sorb, 8, rd, eip, first_byte);
4681//-- default:
4682//-- goto unhandled;
4683//-- }
4684//-- break;
4685//--
4686//-- case 0xDD:
4687//-- switch ((second_byte >> 3) & 7) {
4688//-- case 0: /* FLD double-real */
4689//-- return dis_fpu_mem(cb, sorb, 8, rd, eip, first_byte);
4690//-- case 2: /* FST double-real */
4691//-- case 3: /* FSTP double-real */
4692//-- return dis_fpu_mem(cb, sorb, 8, wr, eip, first_byte);
4693//-- case 4: /* FRSTOR */
4694//-- return dis_fpu_mem(cb, sorb, 108, rd, eip, first_byte);
4695//-- case 6: /* FSAVE */
4696//-- return dis_fpu_mem(cb, sorb, 108, wr, eip, first_byte);
4697//-- case 7: /* FSTSW */
4698//-- return dis_fpu_mem(cb, sorb, 2, wr, eip, first_byte);
4699//-- default:
4700//-- goto unhandled;
4701//-- }
4702//-- break;
4703//--
4704//-- case 0xDE:
4705//-- switch ((second_byte >> 3) & 7) {
4706//-- case 0: /* FIADD word-integer */
4707//-- case 1: /* FIMUL word-integer */
4708//-- case 2: /* FICOM word-integer */
4709//-- case 3: /* FICOMP word-integer */
4710//-- case 4: /* FISUB word-integer */
4711//-- case 5: /* FISUBR word-integer */
4712//-- case 6: /* FIDIV word-integer */
4713//-- case 7: /* FIDIVR word-integer */
4714//-- return dis_fpu_mem(cb, sorb, 2, rd, eip, first_byte);
4715//-- default:
4716//-- goto unhandled;
4717//-- }
4718//-- break;
4719//--
4720//-- case 0xDF:
4721//-- switch ((second_byte >> 3) & 7) {
4722//-- case 0: /* FILD word-integer */
4723//-- return dis_fpu_mem(cb, sorb, 2, rd, eip, first_byte);
4724//-- case 2: /* FIST word-integer */
4725//-- return dis_fpu_mem(cb, sorb, 2, wr, eip, first_byte);
4726//-- case 3: /* FISTP word-integer */
4727//-- return dis_fpu_mem(cb, sorb, 2, wr, eip, first_byte);
4728//-- case 5: /* FILD qword-integer */
4729//-- return dis_fpu_mem(cb, sorb, 8, rd, eip, first_byte);
4730//-- case 7: /* FISTP qword-integer */
4731//-- return dis_fpu_mem(cb, sorb, 8, wr, eip, first_byte);
4732//-- default:
4733//-- goto unhandled;
4734//-- }
4735//-- break;
4736//--
4737//-- default: goto unhandled;
4738//-- }
4739//--
4740//-- unhandled:
4741//-- VG_(printf)("dis_fpu: unhandled memory case 0x%2x:0x%2x(%d)\n",
4742//-- (UInt)first_byte, (UInt)second_byte,
4743//-- (UInt)((second_byte >> 3) & 7) );
4744//-- VG_(core_panic)("dis_fpu: unhandled opcodes");
4745//-- }
sewardja06e5562004-07-14 13:18:05 +00004746
4747
4748/* Double length left and right shifts. Apparently only required in
4749 v-size (no b- variant). */
4750static
4751UInt dis_SHLRD_Gv_Ev ( UChar sorb,
4752 UInt delta, UChar modrm,
4753 Int sz,
4754 IRExpr* shift_amt,
4755 Bool amt_is_literal,
4756 Char* shift_amt_txt,
4757 Bool left_shift )
4758{
4759 /* shift_amt :: Ity_I8 is the amount to shift. shift_amt_txt is used
4760 for printing it. And eip on entry points at the modrm byte. */
4761 Int len;
4762 UChar dis_buf[50];
4763
sewardj6d2638e2004-07-15 09:38:27 +00004764 IRType ty = szToITy(sz);
4765 IRTemp gsrc = newTemp(ty);
4766 IRTemp esrc = newTemp(ty);
4767 IRTemp addr = INVALID_IRTEMP;
4768 IRTemp tmpSH = newTemp(Ity_I8);
sewardj6d2638e2004-07-15 09:38:27 +00004769 IRTemp tmpL = INVALID_IRTEMP;
4770 IRTemp tmpRes = INVALID_IRTEMP;
sewardja06e5562004-07-14 13:18:05 +00004771 IRTemp tmpSubSh = INVALID_IRTEMP;
4772 IROp mkpair;
4773 IROp getres;
4774 IROp shift;
sewardja06e5562004-07-14 13:18:05 +00004775 IRExpr* mask = NULL;
4776
4777 vassert(sz == 2 || sz == 4);
4778
4779 /* The E-part is the destination; this is shifted. The G-part
4780 supplies bits to be shifted into the E-part, but is not
4781 changed.
4782
4783 If shifting left, form a double-length word with E at the top
4784 and G at the bottom, and shift this left. The result is then in
4785 the high part.
4786
4787 If shifting right, form a double-length word with G at the top
4788 and E at the bottom, and shift this right. The result is then
4789 at the bottom. */
4790
4791 /* Fetch the operands. */
4792
4793 assign( gsrc, getIReg(sz, gregOfRM(modrm)) );
4794
4795 if (epartIsReg(modrm)) {
4796 delta++;
4797 assign( esrc, getIReg(sz, eregOfRM(modrm)) );
sewardj68511542004-07-28 00:15:44 +00004798 DIP("sh%cd%c %s, %s, %s\n",
sewardja06e5562004-07-14 13:18:05 +00004799 ( left_shift ? 'l' : 'r' ), nameISize(sz),
sewardj68511542004-07-28 00:15:44 +00004800 shift_amt_txt,
sewardja06e5562004-07-14 13:18:05 +00004801 nameIReg(sz, gregOfRM(modrm)), nameIReg(sz, eregOfRM(modrm)));
4802 } else {
4803 addr = disAMode ( &len, sorb, delta, dis_buf );
4804 delta += len;
4805 assign( esrc, loadLE(ty, mkexpr(addr)) );
sewardj68511542004-07-28 00:15:44 +00004806 DIP("sh%cd%c %s, %s, %s\n",
4807 ( left_shift ? 'l' : 'r' ), nameISize(sz),
4808 shift_amt_txt,
4809 nameIReg(sz, gregOfRM(modrm)), dis_buf);
sewardja06e5562004-07-14 13:18:05 +00004810 }
4811
4812 /* Round up the relevant primops. */
4813
4814 if (sz == 4) {
4815 tmpL = newTemp(Ity_I64);
4816 tmpRes = newTemp(Ity_I32);
4817 tmpSubSh = newTemp(Ity_I32);
sewardje539a402004-07-14 18:24:17 +00004818 mkpair = Iop_32HLto64;
sewardj8c7f1ab2004-07-29 20:31:09 +00004819 getres = left_shift ? Iop_64HIto32 : Iop_64to32;
sewardje539a402004-07-14 18:24:17 +00004820 shift = left_shift ? Iop_Shl64 : Iop_Shr64;
4821 mask = mkU8(31);
sewardja06e5562004-07-14 13:18:05 +00004822 } else {
4823 /* sz == 2 */
sewardj8c7f1ab2004-07-29 20:31:09 +00004824 tmpL = newTemp(Ity_I32);
4825 tmpRes = newTemp(Ity_I16);
4826 tmpSubSh = newTemp(Ity_I16);
4827 mkpair = Iop_16HLto32;
4828 getres = left_shift ? Iop_32HIto16 : Iop_32to16;
4829 shift = left_shift ? Iop_Shl32 : Iop_Shr32;
4830 mask = mkU8(15);
sewardja06e5562004-07-14 13:18:05 +00004831 }
4832
4833 /* Do the shift, calculate the subshift value, and set
4834 the flag thunk. */
4835
sewardj8c7f1ab2004-07-29 20:31:09 +00004836 assign( tmpSH, binop(Iop_And8, shift_amt, mask) );
4837
sewardja06e5562004-07-14 13:18:05 +00004838 if (left_shift)
4839 assign( tmpL, binop(mkpair, mkexpr(esrc), mkexpr(gsrc)) );
4840 else
4841 assign( tmpL, binop(mkpair, mkexpr(gsrc), mkexpr(esrc)) );
4842
4843 assign( tmpRes, unop(getres, binop(shift, mkexpr(tmpL), mkexpr(tmpSH)) ) );
4844 assign( tmpSubSh,
4845 unop(getres,
4846 binop(shift,
4847 mkexpr(tmpL),
4848 binop(Iop_And8,
4849 binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
4850 mask))) );
sewardja06e5562004-07-14 13:18:05 +00004851
sewardjc22a6fd2004-07-29 23:41:47 +00004852 setFlags_DSTus_DST1 ( left_shift ? Iop_Shl32 : Iop_Sar32,
sewardjbb53f8c2004-08-14 11:50:01 +00004853 tmpSubSh, tmpRes, ty, tmpSH );
sewardja06e5562004-07-14 13:18:05 +00004854
4855 /* Put result back. */
4856
4857 if (epartIsReg(modrm)) {
4858 putIReg(sz, eregOfRM(modrm), mkexpr(tmpRes));
4859 } else {
4860 storeLE( mkexpr(addr), mkexpr(tmpRes) );
4861 }
4862
4863 if (amt_is_literal) delta++;
4864 return delta;
4865}
4866
4867
sewardj1c6f9912004-09-07 10:15:24 +00004868/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
4869 required. */
4870
4871typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
4872
4873static Char* nameBtOp ( BtOp op )
4874{
4875 switch (op) {
4876 case BtOpNone: return "";
4877 case BtOpSet: return "s";
4878 case BtOpReset: return "r";
4879 case BtOpComp: return "c";
4880 default: vpanic("nameBtOp(x86)");
4881 }
4882}
4883
4884
4885static
4886UInt dis_bt_G_E ( UChar sorb, Int sz, UInt delta, BtOp op )
4887{
4888 Char dis_buf[50];
4889 UChar modrm;
4890 Int len;
4891 IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
4892 t_addr1, t_esp, t_mask;
4893
4894 vassert(sz == 2 || sz == 4);
4895
4896 t_fetched = t_bitno0 = t_bitno1 = t_bitno2
4897 = t_addr0 = t_addr1 = t_esp = t_mask = INVALID_IRTEMP;
4898
4899 t_fetched = newTemp(Ity_I8);
4900 t_bitno0 = newTemp(Ity_I32);
4901 t_bitno1 = newTemp(Ity_I32);
4902 t_bitno2 = newTemp(Ity_I8);
4903 t_addr1 = newTemp(Ity_I32);
4904 modrm = getIByte(delta);
4905
4906 assign( t_bitno0, widenUto32(getIReg(sz, gregOfRM(modrm))) );
4907
4908 if (epartIsReg(modrm)) {
sewardj1c6f9912004-09-07 10:15:24 +00004909 delta++;
4910 /* Get it onto the client's stack. */
4911 t_esp = newTemp(Ity_I32);
4912 t_addr0 = newTemp(Ity_I32);
4913
4914 assign( t_esp, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
4915 putIReg(4, R_ESP, mkexpr(t_esp));
4916
4917 storeLE( mkexpr(t_esp), getIReg(sz, eregOfRM(modrm)) );
4918
4919 /* Make t_addr0 point at it. */
4920 assign( t_addr0, mkexpr(t_esp) );
4921
4922 /* Mask out upper bits of the shift amount, since we're doing a
4923 reg. */
4924 assign( t_bitno1, binop(Iop_And32,
4925 mkexpr(t_bitno0),
4926 mkU32(sz == 4 ? 31 : 15)) );
4927
4928 } else {
4929 t_addr0 = disAMode ( &len, sorb, delta, dis_buf );
4930 delta += len;
4931 assign( t_bitno1, mkexpr(t_bitno0) );
4932 }
4933
4934 /* At this point: t_addr0 is the address being operated on. If it
4935 was a reg, we will have pushed it onto the client's stack.
4936 t_bitno1 is the bit number, suitably masked in the case of a
4937 reg. */
4938
4939 /* Now the main sequence. */
4940 assign( t_addr1,
4941 binop(Iop_Add32,
4942 mkexpr(t_addr0),
4943 binop(Iop_Sar32, mkexpr(t_bitno1), mkU8(3))) );
4944
4945 /* t_addr1 now holds effective address */
4946
4947 assign( t_bitno2,
4948 unop(Iop_32to8,
4949 binop(Iop_And32, mkexpr(t_bitno1), mkU32(7))) );
4950
4951 /* t_bitno2 contains offset of bit within byte */
4952
4953 if (op != BtOpNone) {
4954 t_mask = newTemp(Ity_I8);
4955 assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
4956 }
sewardj4963a422004-10-14 23:34:03 +00004957
sewardj1c6f9912004-09-07 10:15:24 +00004958 /* t_mask is now a suitable byte mask */
4959
4960 assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
4961
4962 if (op != BtOpNone) {
4963 switch (op) {
4964 case BtOpSet:
4965 storeLE( mkexpr(t_addr1),
4966 binop(Iop_Or8, mkexpr(t_fetched),
4967 mkexpr(t_mask)) );
4968 break;
4969 case BtOpComp:
4970 storeLE( mkexpr(t_addr1),
4971 binop(Iop_Xor8, mkexpr(t_fetched),
4972 mkexpr(t_mask)) );
4973 break;
4974 case BtOpReset:
4975 storeLE( mkexpr(t_addr1),
4976 binop(Iop_And8, mkexpr(t_fetched),
4977 unop(Iop_Not8, mkexpr(t_mask))) );
4978 break;
4979 default:
4980 vpanic("dis_bt_G_E(x86)");
4981 }
4982 }
4983
4984 /* Side effect done; now get selected bit into Carry flag */
4985 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
4986 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
4987 stmt( IRStmt_Put( OFFB_CC_DST, mkU32(0) ));
4988 stmt( IRStmt_Put(
4989 OFFB_CC_SRC,
4990 binop(Iop_And32,
4991 binop(Iop_Shr32,
4992 unop(Iop_8Uto32, mkexpr(t_fetched)),
4993 mkexpr(t_bitno2)),
4994 mkU32(1)))
4995 );
4996
4997 /* Move reg operand from stack back to reg */
4998 if (epartIsReg(modrm)) {
4999 /* t_esp still points at it. */
sewardj4963a422004-10-14 23:34:03 +00005000 putIReg(sz, eregOfRM(modrm), loadLE(szToITy(sz), mkexpr(t_esp)) );
sewardj1c6f9912004-09-07 10:15:24 +00005001 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t_esp), mkU32(sz)) );
5002 }
5003
5004 DIP("bt%s%c %s, %s\n",
5005 nameBtOp(op), nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
5006 ( epartIsReg(modrm) ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ) );
5007
5008 return delta;
5009}
sewardjce646f22004-08-31 23:55:54 +00005010
5011
5012
5013/* Handle BSF/BSR. Only v-size seems necessary. */
5014static
5015UInt dis_bs_E_G ( UChar sorb, Int sz, UInt delta, Bool fwds )
5016{
5017 Bool isReg;
5018 UChar modrm;
5019 Char dis_buf[50];
5020
5021 IRType ty = szToITy(sz);
5022 IRTemp src = newTemp(ty);
5023 IRTemp dst = newTemp(ty);
5024
5025 IRTemp src32 = newTemp(Ity_I32);
5026 IRTemp dst32 = newTemp(Ity_I32);
5027 IRTemp src8 = newTemp(Ity_I8);
5028
5029 vassert(sz == 4 || sz == 2);
sewardjce646f22004-08-31 23:55:54 +00005030
5031 modrm = getIByte(delta);
5032
5033 isReg = epartIsReg(modrm);
5034 if (isReg) {
5035 delta++;
5036 assign( src, getIReg(sz, eregOfRM(modrm)) );
5037 } else {
5038 Int len;
5039 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5040 delta += len;
5041 assign( src, loadLE(ty, mkexpr(addr)) );
5042 }
5043
5044 DIP("bs%c%c %s, %s\n",
5045 fwds ? 'f' : 'r', nameISize(sz),
5046 ( isReg ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ),
5047 nameIReg(sz, gregOfRM(modrm)));
5048
5049 /* Generate an 8-bit expression which is zero iff the
5050 original is zero, and nonzero otherwise */
5051 assign( src8,
5052 unop(Iop_1Uto8, binop(mkSizedOp(ty,Iop_CmpNE8),
5053 mkexpr(src), mkU(ty,0))) );
5054
5055 /* Flags: Z is 1 iff source value is zero. All others
5056 are undefined -- we force them to zero. */
5057 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
5058 stmt( IRStmt_Put( OFFB_CC_DST, mkU32(0) ));
5059 stmt( IRStmt_Put(
5060 OFFB_CC_SRC,
5061 IRExpr_Mux0X( mkexpr(src8),
5062 /* src==0 */
5063 mkU32(CC_MASK_Z),
5064 /* src!=0 */
5065 mkU32(0)
5066 )
5067 ));
5068
5069 /* Result: iff source value is zero, we can't use
5070 Iop_Clz32/Iop_Ctz32 as they have no defined result in that case.
5071 But anyway, Intel x86 semantics say the result is undefined in
5072 such situations. Hence handle the zero case specially. */
5073
5074 /* Bleh. What we compute:
5075
5076 bsf32: if src == 0 then 0 else Ctz32(src)
5077 bsr32: if src == 0 then 0 else 31 - Clz32(src)
5078
5079 bsf16: if src == 0 then 0 else Ctz32(16Uto32(src))
5080 bsr16: if src == 0 then 0 else 31 - Clz32(16Uto32(src))
5081
5082 First, widen src to 32 bits if it is not already.
sewardj37158712004-10-15 21:23:12 +00005083
5084 Postscript 15 Oct 04: it seems that at least VIA Nehemiah leaves the
5085 dst register unchanged when src == 0. Hence change accordingly.
sewardjce646f22004-08-31 23:55:54 +00005086 */
5087 if (sz == 2)
5088 assign( src32, unop(Iop_16Uto32, mkexpr(src)) );
5089 else
5090 assign( src32, mkexpr(src) );
5091
5092 /* The main computation, guarding against zero. */
5093 assign( dst32,
5094 IRExpr_Mux0X(
5095 mkexpr(src8),
sewardj37158712004-10-15 21:23:12 +00005096 /* src == 0 -- leave dst unchanged */
5097 widenUto32( getIReg( sz, gregOfRM(modrm) ) ),
sewardjce646f22004-08-31 23:55:54 +00005098 /* src != 0 */
5099 fwds ? unop(Iop_Ctz32, mkexpr(src32))
5100 : binop(Iop_Sub32,
5101 mkU32(31),
5102 unop(Iop_Clz32, mkexpr(src32)))
5103 )
5104 );
5105
5106 if (sz == 2)
5107 assign( dst, unop(Iop_32to16, mkexpr(dst32)) );
5108 else
5109 assign( dst, mkexpr(dst32) );
5110
5111 /* dump result back */
5112 putIReg( sz, gregOfRM(modrm), mkexpr(dst) );
5113
5114 return delta;
5115}
sewardj64e1d652004-07-12 14:00:46 +00005116
5117
5118static
5119void codegen_xchg_eAX_Reg ( Int sz, Int reg )
5120{
5121 IRType ty = szToITy(sz);
5122 IRTemp t1 = newTemp(ty);
5123 IRTemp t2 = newTemp(ty);
5124 vassert(sz == 2 || sz == 4);
5125 assign( t1, getIReg(sz, R_EAX) );
5126 assign( t2, getIReg(sz, reg) );
5127 putIReg( sz, R_EAX, mkexpr(t2) );
5128 putIReg( sz, reg, mkexpr(t1) );
5129 DIP("xchg%c %s, %s\n",
5130 nameISize(sz), nameIReg(sz, R_EAX), nameIReg(sz, reg));
5131}
5132
5133
sewardjbdc7d212004-09-09 02:46:40 +00005134static
5135void codegen_SAHF ( void )
5136{
5137 /* Set the flags to:
5138 (calculate_flags_all() & CC_MASK_O) -- retain the old O flag
5139 | (%AH & (CC_MASK_S|CC_MASK_Z|CC_MASK_A|CC_MASK_P|CC_MASK_C)
5140 */
5141 UInt mask_SZACP = CC_MASK_S|CC_MASK_Z|CC_MASK_A|CC_MASK_P|CC_MASK_C;
5142 IRTemp oldflags = newTemp(Ity_I32);
5143 assign( oldflags, mk_calculate_eflags_all() );
5144 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
5145 stmt( IRStmt_Put( OFFB_CC_DST, mkU32(0) ));
5146 stmt( IRStmt_Put( OFFB_CC_SRC,
5147 binop(Iop_Or32,
5148 binop(Iop_And32, mkexpr(oldflags), mkU32(CC_MASK_O)),
5149 binop(Iop_And32,
5150 binop(Iop_Shr32, getIReg(4, R_EAX), mkU8(8)),
5151 mkU32(mask_SZACP))
5152 )
5153 ));
5154}
5155
5156
sewardjc9a65702004-07-07 16:32:57 +00005157//-- static
5158//-- void codegen_LAHF ( UCodeBlock* cb )
5159//-- {
5160//-- Int t = newTemp(cb);
5161//--
5162//-- /* Pushed arg is ignored, it just provides somewhere to put the
5163//-- return value. */
5164//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t);
5165//-- uInstr0(cb, CALLM_S, 0);
5166//-- uInstr1(cb, PUSH, 4, TempReg, t);
5167//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_LAHF));
5168//-- uFlagsRWU(cb, FlagsSZACP, FlagsEmpty, FlagsEmpty);
5169//-- uInstr1(cb, POP, 4, TempReg, t);
5170//-- uInstr0(cb, CALLM_E, 0);
5171//--
5172//-- /* At this point, the %ah sub-register in %eax has been updated,
5173//-- the rest is the same, so do a PUT of the whole thing. */
5174//-- uInstr2(cb, PUT, 4, TempReg, t, ArchReg, R_EAX);
5175//-- }
5176//--
sewardj458a6f82004-08-25 12:46:02 +00005177
5178static
5179UInt dis_cmpxchg_G_E ( UChar sorb,
5180 Int size,
5181 UInt delta0 )
5182{
5183 UChar dis_buf[50];
5184 Int len;
5185
5186 IRType ty = szToITy(size);
5187 IRTemp acc = newTemp(ty);
5188 IRTemp src = newTemp(ty);
5189 IRTemp dest = newTemp(ty);
5190 IRTemp dest2 = newTemp(ty);
5191 IRTemp acc2 = newTemp(ty);
5192 IRTemp cond8 = newTemp(Ity_I8);
5193 IRTemp addr = INVALID_IRTEMP;
5194 UChar rm = getUChar(delta0);
5195
5196 if (epartIsReg(rm)) {
5197 assign( dest, getIReg(size, eregOfRM(rm)) );
5198 delta0++;
5199 DIP("cmpxchg%c %s,%s\n", nameISize(size),
5200 nameIReg(size,gregOfRM(rm)),
5201 nameIReg(size,eregOfRM(rm)) );
sewardj458a6f82004-08-25 12:46:02 +00005202 } else {
5203 addr = disAMode ( &len, sorb, delta0, dis_buf );
5204 assign( dest, loadLE(ty, mkexpr(addr)) );
5205 delta0 += len;
5206 DIP("cmpxchg%c %s,%s\n", nameISize(size),
5207 nameIReg(size,gregOfRM(rm)), dis_buf);
5208 }
5209
5210 assign( src, getIReg(size, gregOfRM(rm)) );
5211 assign( acc, getIReg(size, R_EAX) );
5212 setFlags_ADD_SUB(Iop_Sub8, dest, acc, ty);
5213 assign( cond8, unop(Iop_1Uto8, calculate_condition(CondZ)) );
5214 assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
5215 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
5216 putIReg(size, R_EAX, mkexpr(acc2));
5217
5218 if (epartIsReg(rm)) {
5219 putIReg(size, eregOfRM(rm), mkexpr(dest2));
5220 } else {
5221 storeLE( mkexpr(addr), mkexpr(dest2) );
5222 }
5223
5224 return delta0;
5225}
5226
5227
sewardjc9a65702004-07-07 16:32:57 +00005228//-- static
5229//-- Addr dis_cmpxchg8b ( UCodeBlock* cb,
5230//-- UChar sorb,
5231//-- Addr eip0 )
5232//-- {
5233//-- Int tal, tah, junkl, junkh, destl, desth, srcl, srch, accl, acch;
5234//-- UChar dis_buf[50];
5235//-- UChar rm;
5236//-- UInt pair;
5237//--
5238//-- rm = getUChar(eip0);
5239//-- accl = newTemp(cb);
5240//-- acch = newTemp(cb);
5241//-- srcl = newTemp(cb);
5242//-- srch = newTemp(cb);
5243//-- destl = newTemp(cb);
5244//-- desth = newTemp(cb);
5245//-- junkl = newTemp(cb);
5246//-- junkh = newTemp(cb);
5247//--
5248//-- vg_assert(!epartIsReg(rm));
5249//--
5250//-- pair = disAMode ( cb, sorb, eip0, dis_buf );
5251//-- tal = LOW24(pair);
5252//-- tah = newTemp(cb);
5253//-- uInstr2(cb, MOV, 4, TempReg, tal, TempReg, tah);
5254//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, tah);
5255//-- uLiteral(cb, 4);
5256//-- eip0 += HI8(pair);
5257//-- DIP("cmpxchg8b %s\n", dis_buf);
5258//--
5259//-- uInstr0(cb, CALLM_S, 0);
5260//--
5261//-- uInstr2(cb, LOAD, 4, TempReg, tah, TempReg, desth);
5262//-- uInstr1(cb, PUSH, 4, TempReg, desth);
5263//-- uInstr2(cb, LOAD, 4, TempReg, tal, TempReg, destl);
5264//-- uInstr1(cb, PUSH, 4, TempReg, destl);
5265//-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, srch);
5266//-- uInstr1(cb, PUSH, 4, TempReg, srch);
5267//-- uInstr2(cb, GET, 4, ArchReg, R_EBX, TempReg, srcl);
5268//-- uInstr1(cb, PUSH, 4, TempReg, srcl);
5269//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, acch);
5270//-- uInstr1(cb, PUSH, 4, TempReg, acch);
5271//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, accl);
5272//-- uInstr1(cb, PUSH, 4, TempReg, accl);
5273//--
5274//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_cmpxchg8b));
5275//-- uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsEmpty);
5276//--
5277//-- uInstr1(cb, POP, 4, TempReg, accl);
5278//-- uInstr2(cb, PUT, 4, TempReg, accl, ArchReg, R_EAX);
5279//-- uInstr1(cb, POP, 4, TempReg, acch);
5280//-- uInstr2(cb, PUT, 4, TempReg, acch, ArchReg, R_EDX);
5281//-- uInstr1(cb, POP, 4, TempReg, srcl);
5282//-- uInstr2(cb, PUT, 4, TempReg, srcl, ArchReg, R_EBX);
5283//-- uInstr1(cb, POP, 4, TempReg, srch);
5284//-- uInstr2(cb, PUT, 4, TempReg, srch, ArchReg, R_ECX);
5285//-- uInstr1(cb, POP, 4, TempReg, destl);
5286//-- uInstr2(cb, STORE, 4, TempReg, destl, TempReg, tal);
5287//-- uInstr1(cb, POP, 4, TempReg, desth);
5288//-- uInstr2(cb, STORE, 4, TempReg, desth, TempReg, tah);
5289//--
5290//-- uInstr0(cb, CALLM_E, 0);
5291//--
5292//-- return eip0;
5293//-- }
sewardj458a6f82004-08-25 12:46:02 +00005294
5295
5296/* Handle conditional move instructions of the form
5297 cmovcc E(reg-or-mem), G(reg)
5298
5299 E(src) is reg-or-mem
5300 G(dst) is reg.
5301
5302 If E is reg, --> GET %E, tmps
5303 GET %G, tmpd
5304 CMOVcc tmps, tmpd
5305 PUT tmpd, %G
5306
5307 If E is mem --> (getAddr E) -> tmpa
5308 LD (tmpa), tmps
5309 GET %G, tmpd
5310 CMOVcc tmps, tmpd
5311 PUT tmpd, %G
5312*/
5313static
5314UInt dis_cmov_E_G ( UChar sorb,
5315 Int sz,
5316 Condcode cond,
5317 UInt delta0 )
5318{
5319 UChar rm = getIByte(delta0);
5320 UChar dis_buf[50];
5321 Int len;
5322
sewardj883b00b2004-09-11 09:30:24 +00005323 IRType ty = szToITy(sz);
sewardj458a6f82004-08-25 12:46:02 +00005324 IRTemp tmps = newTemp(ty);
5325 IRTemp tmpd = newTemp(ty);
5326
5327 if (epartIsReg(rm)) {
5328 assign( tmps, getIReg(sz, eregOfRM(rm)) );
5329 assign( tmpd, getIReg(sz, gregOfRM(rm)) );
5330
5331 putIReg(sz, gregOfRM(rm),
5332 IRExpr_Mux0X( unop(Iop_1Uto8,calculate_condition(cond)),
5333 mkexpr(tmpd),
5334 mkexpr(tmps) )
5335 );
5336 DIP("cmov%c%s %s,%s\n", nameISize(sz),
5337 name_Condcode(cond),
5338 nameIReg(sz,eregOfRM(rm)),
5339 nameIReg(sz,gregOfRM(rm)));
5340 return 1+delta0;
5341 }
5342
5343 /* E refers to memory */
5344 {
5345 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
5346 assign( tmps, loadLE(ty, mkexpr(addr)) );
5347 assign( tmpd, getIReg(sz, gregOfRM(rm)) );
5348
5349 putIReg(sz, gregOfRM(rm),
5350 IRExpr_Mux0X( unop(Iop_1Uto8,calculate_condition(cond)),
5351 mkexpr(tmpd),
5352 mkexpr(tmps) )
5353 );
5354
5355 DIP("cmov%c%s %s,%s\n", nameISize(sz),
5356 name_Condcode(cond),
5357 dis_buf,
5358 nameIReg(sz,gregOfRM(rm)));
5359 return len+delta0;
5360 }
5361}
5362
5363
sewardj883b00b2004-09-11 09:30:24 +00005364static
5365UInt dis_xadd_G_E ( UChar sorb, Int sz, UInt delta0 )
5366{
5367 Int len;
5368 UChar rm = getIByte(delta0);
5369 UChar dis_buf[50];
5370
5371 // Int tmpd = newTemp(cb);
5372 //Int tmpt = newTemp(cb);
5373
5374 IRType ty = szToITy(sz);
5375 IRTemp tmpd = newTemp(ty);
5376 IRTemp tmpt0 = newTemp(ty);
5377 IRTemp tmpt1 = newTemp(ty);
5378
5379 if (epartIsReg(rm)) {
5380 vassert(0);
5381#if 0
5382 uInstr2(cb, GET, sz, ArchReg, eregOfRM(rm), TempReg, tmpd);
5383 uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
5384 uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
5385 setFlagsFromUOpcode(cb, ADD);
5386 uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
5387 uInstr2(cb, PUT, sz, TempReg, tmpt, ArchReg, eregOfRM(rm));
5388 DIP("xadd%c %s, %s\n",
5389 nameISize(sz), nameIReg(sz,gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
5390 return 1+eip0;
5391#endif
5392 } else {
5393 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
5394 assign( tmpd, loadLE(ty, mkexpr(addr)) );
5395 assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
5396 setFlags_ADD_SUB( Iop_Add8, tmpt0, tmpd, ty );
5397 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8), mkexpr(tmpd), mkexpr(tmpt0)) );
5398 storeLE( mkexpr(addr), mkexpr(tmpt1) );
5399 putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
5400 DIP("xadd%c %s, %s\n",
5401 nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
5402 return len+delta0;
5403 }
5404}
5405
sewardjc9a65702004-07-07 16:32:57 +00005406//-- /* Moves of Ew into a segment register.
5407//-- mov Ew, Sw meaning
5408//-- mov reg-or-mem, reg
5409//-- Is passed the a ptr to the modRM byte, and the data size. Returns
5410//-- the address advanced completely over this instruction.
5411//--
5412//-- Ew(src) is reg-or-mem
5413//-- Sw(dst) is seg reg.
5414//--
5415//-- If E is reg, --> GETw %Ew, tmpv
5416//-- PUTSEG tmpv, %Sw
5417//--
5418//-- If E is mem --> (getAddr E) -> tmpa
5419//-- LDw (tmpa), tmpb
5420//-- PUTSEG tmpb, %Sw
5421//-- */
5422//-- static
5423//-- Addr dis_mov_Ew_Sw ( UCodeBlock* cb,
5424//-- UChar sorb,
5425//-- Addr eip0 )
5426//-- {
5427//-- UChar rm = getUChar(eip0);
5428//-- UChar dis_buf[50];
5429//--
5430//-- if (epartIsReg(rm)) {
5431//-- Int tmpv = newTemp(cb);
5432//-- uInstr2(cb, GET, 2, ArchReg, eregOfRM(rm), TempReg, tmpv);
5433//-- uInstr2(cb, PUTSEG, 2, TempReg, tmpv, ArchRegS, gregOfRM(rm));
5434//-- DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
5435//-- return 1+eip0;
5436//-- }
5437//--
5438//-- /* E refers to memory */
5439//-- {
5440//-- UInt pair = disAMode ( cb, sorb, eip0, dis_buf );
5441//-- Int tmpa = LOW24(pair);
5442//-- Int tmpb = newTemp(cb);
5443//-- uInstr2(cb, LOAD, 2, TempReg, tmpa, TempReg, tmpb);
5444//-- uInstr2(cb, PUTSEG, 2, TempReg, tmpb, ArchRegS, gregOfRM(rm));
5445//-- DIP("movw %s,%s\n", dis_buf,nameSReg(gregOfRM(rm)));
5446//-- return HI8(pair)+eip0;
5447//-- }
5448//-- }
5449//--
5450//--
5451//-- /* Moves of a segment register to Ew.
5452//-- mov Sw, Ew meaning
5453//-- mov reg, reg-or-mem
5454//-- Is passed the a ptr to the modRM byte, and the data size. Returns
5455//-- the address advanced completely over this instruction.
5456//--
5457//-- Sw(src) is seg reg.
5458//-- Ew(dst) is reg-or-mem
5459//--
5460//-- If E is reg, --> GETSEG %Sw, tmp
5461//-- PUTW tmp, %Ew
5462//--
5463//-- If E is mem, --> (getAddr E) -> tmpa
5464//-- GETSEG %Sw, tmpv
5465//-- STW tmpv, (tmpa)
5466//-- */
sewardj063f02f2004-10-20 12:36:12 +00005467static
5468UInt dis_mov_Sw_Ew ( UChar sorb,
5469 Int sz,
5470 UInt delta0 )
5471{
5472 UChar rm = getIByte(delta0);
5473 //UChar dis_buf[50];
5474
5475 vassert(sz == 2 || sz == 4);
5476
5477 if (epartIsReg(rm)) {
5478 if (sz == 4)
5479 putIReg(4, eregOfRM(rm), unop(Iop_16Uto32, getSReg(gregOfRM(rm))));
5480 else
5481 putIReg(2, eregOfRM(rm), getSReg(gregOfRM(rm)));
5482
5483 DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
5484 return 1+delta0;
5485 }
5486
5487 vassert(0);
5488#if 0
5489 /* E refers to memory */
5490 {
5491 UInt pair = disAMode ( cb, sorb, eip0, dis_buf );
5492 Int tmpa = LOW24(pair);
5493 Int tmpv = newTemp(cb);
5494 uInstr2(cb, GETSEG, 2, ArchRegS, gregOfRM(rm), TempReg, tmpv);
5495 uInstr2(cb, STORE, 2, TempReg, tmpv, TempReg, tmpa);
5496 DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
5497 return HI8(pair)+eip0;
5498 }
5499#endif
5500}
5501
5502
5503
sewardjc9a65702004-07-07 16:32:57 +00005504//-- /* Simple MMX operations, either
5505//-- op (src)mmxreg, (dst)mmxreg
5506//-- or
5507//-- op (src)address, (dst)mmxreg
5508//-- opc is the byte following the 0x0F prefix.
5509//-- */
5510//-- static
5511//-- Addr dis_MMXop_regmem_to_reg ( UCodeBlock* cb,
5512//-- UChar sorb,
5513//-- Addr eip,
5514//-- UChar opc,
5515//-- Char* name,
5516//-- Bool show_granularity )
5517//-- {
5518//-- Char dis_buf[50];
5519//-- UChar modrm = getUChar(eip);
5520//-- Bool isReg = epartIsReg(modrm);
5521//--
5522//-- if (isReg) {
5523//-- eip++;
5524//-- uInstr1(cb, MMX2, 0,
5525//-- Lit16,
5526//-- (((UShort)(opc)) << 8) | ((UShort)modrm) );
5527//-- } else {
5528//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
5529//-- Int tmpa = LOW24(pair);
5530//-- eip += HI8(pair);
5531//-- uInstr2(cb, MMX2_MemRd, 8,
5532//-- Lit16,
5533//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
5534//-- TempReg, tmpa);
5535//-- }
5536//--
5537//-- DIP("%s%s %s, %s\n",
5538//-- name, show_granularity ? nameMMXGran(opc & 3) : (Char*)"",
5539//-- ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
5540//-- nameMMXReg(gregOfRM(modrm)) );
5541//--
5542//-- return eip;
5543//-- }
5544//--
5545//--
5546//-- /* Simple MMX operations, either
5547//-- op (src)mmxreg, (dst)mmxreg
5548//-- or
5549//-- op (src)address, (dst)mmxreg
5550//-- opc is the byte following the 0x0F prefix.
5551//-- */
5552//-- static
5553//-- Addr dis_MMXop_regmem_to_reg_Imm8 ( UCodeBlock* cb,
5554//-- UChar sorb,
5555//-- Addr eip,
5556//-- UChar opc,
5557//-- Char* name,
5558//-- Bool show_granularity )
5559//-- {
5560//-- Char dis_buf[50];
5561//-- UChar modrm = getUChar(eip);
5562//-- UChar imm8;
5563//-- Bool isReg = epartIsReg(modrm);
5564//--
5565//-- if (isReg) {
5566//-- eip++;
5567//-- imm8 = getUChar(eip);
5568//-- eip++;
5569//-- uInstr2(cb, MMX3, 0,
5570//-- Lit16,
5571//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
5572//-- Lit16,
5573//-- ((UShort)imm8));
5574//-- } else {
5575//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
5576//-- Int tmpa = LOW24(pair);
5577//-- eip += HI8(pair);
5578//-- imm8 = getUChar(eip);
5579//-- eip++;
5580//-- uInstr3(cb, MMX2a1_MemRd, 8,
5581//-- Lit16,
5582//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
5583//-- Lit16,
5584//-- ((UShort)imm8),
5585//-- TempReg, tmpa);
5586//-- }
5587//--
5588//-- DIP("%s%s %s, %s, $%d\n",
5589//-- name, show_granularity ? nameMMXGran(opc & 3) : (Char*)"",
5590//-- ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
5591//-- nameMMXReg(gregOfRM(modrm)), (Int)imm8 );
5592//--
5593//-- return eip;
5594//-- }
5595//--
5596//--
5597//--
5598//-- /* Simple SSE operations, either
5599//-- op (src)xmmreg, (dst)xmmreg
5600//-- or
5601//-- op (src)address, (dst)xmmreg
5602//-- 3 opcode bytes.
5603//-- Supplied eip points to the first address mode byte.
5604//-- */
5605//-- static
5606//-- Addr dis_SSE3_reg_or_mem ( UCodeBlock* cb,
5607//-- UChar sorb,
sewardjbb53f8c2004-08-14 11:50:01 +00005608//-- Addr eip,
sewardjc9a65702004-07-07 16:32:57 +00005609//-- Int sz,
5610//-- Char* name,
5611//-- UChar opc1,
5612//-- UChar opc2,
5613//-- UChar opc3 )
5614//-- {
5615//-- Char dis_buf[50];
5616//-- UChar modrm = getUChar(eip);
5617//-- Bool isReg = epartIsReg(modrm);
5618//--
5619//-- if (isReg) {
5620//-- /* Completely internal SSE insn. */
5621//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
5622//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
5623//-- Lit16, (((UShort)opc3) << 8) | (UShort)modrm );
5624//-- eip++;
5625//-- } else {
5626//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
5627//-- Int tmpa = LOW24(pair);
5628//-- eip += HI8(pair);
5629//-- uInstr3(cb, SSE3a_MemRd, sz,
5630//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
5631//-- Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
5632//-- TempReg, tmpa);
5633//-- }
5634//--
5635//-- DIP("%s %s, %s\n",
5636//-- name,
5637//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
5638//-- nameXMMReg(gregOfRM(modrm)) );
5639//--
5640//-- return eip;
5641//-- }
5642//--
5643//--
5644//-- /* Simple SSE operations, either
5645//-- op (src)xmmreg, (dst)xmmreg
5646//-- or
5647//-- op (src)address, (dst)xmmreg
5648//-- 2 opcode bytes.
5649//-- Supplied eip points to the first address mode byte.
5650//-- */
5651//-- static
5652//-- Addr dis_SSE2_reg_or_mem ( UCodeBlock* cb,
5653//-- UChar sorb,
5654//-- Addr eip,
5655//-- Int sz,
5656//-- Char* name,
5657//-- UChar opc1,
5658//-- UChar opc2 )
5659//-- {
5660//-- Char dis_buf[50];
5661//-- UChar modrm = getUChar(eip);
5662//-- Bool isReg = epartIsReg(modrm);
5663//--
5664//-- if (isReg) {
5665//-- /* Completely internal SSE insn. */
5666//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
5667//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
5668//-- Lit16, (UShort)modrm );
5669//-- eip++;
5670//-- } else {
5671//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
5672//-- Int tmpa = LOW24(pair);
5673//-- eip += HI8(pair);
5674//-- uInstr3(cb, SSE2a_MemRd, sz,
5675//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
5676//-- Lit16, (UShort)modrm,
5677//-- TempReg, tmpa);
5678//-- }
5679//-- DIP("%s %s, %s\n",
5680//-- name,
5681//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
5682//-- nameXMMReg(gregOfRM(modrm)) );
5683//--
5684//-- return eip;
5685//-- }
5686//--
5687//--
5688//-- /* Simple SSE operations, either
5689//-- op (src)xmmreg, (dst)xmmreg
5690//-- or
5691//-- op (src)address, (dst)xmmreg
5692//-- 2 opcode bytes and an 8-bit immediate after the amode.
5693//-- Supplied eip points to the first address mode byte.
5694//-- */
5695//-- static
5696//-- Addr dis_SSE2_reg_or_mem_Imm8 ( UCodeBlock* cb,
5697//-- UChar sorb,
5698//-- Addr eip,
5699//-- Int sz,
5700//-- Char* name,
5701//-- UChar opc1,
5702//-- UChar opc2 )
5703//-- {
5704//-- Char dis_buf[50];
5705//-- UChar modrm = getUChar(eip);
5706//-- UChar imm8;
5707//-- Bool isReg = epartIsReg(modrm);
5708//--
5709//-- if (isReg) {
5710//-- /* Completely internal SSE insn. */
5711//-- eip++;
5712//-- imm8 = getUChar(eip);
5713//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
5714//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
5715//-- Lit16, (((UShort)modrm) << 8) | (UShort)imm8 );
5716//-- eip++;
5717//-- } else {
5718//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
5719//-- Int tmpa = LOW24(pair);
5720//-- eip += HI8(pair);
5721//-- imm8 = getUChar(eip);
5722//-- eip++;
5723//-- uInstr3(cb, SSE2a1_MemRd, sz,
5724//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
5725//-- Lit16, (((UShort)(modrm)) << 8) | ((UShort)imm8),
5726//-- TempReg, tmpa);
5727//-- }
5728//-- DIP("%s %s, %s, $%d\n",
5729//-- name, ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
5730//-- nameXMMReg(gregOfRM(modrm)), (Int)imm8 );
5731//-- return eip;
5732//-- }
5733//--
5734//--
5735//-- /* Simple SSE operations, either
5736//-- op (src)xmmreg, (dst)xmmreg
5737//-- or
5738//-- op (src)address, (dst)xmmreg
5739//-- 3 opcode bytes and an 8-bit immediate after the amode.
5740//-- Supplied eip points to the first address mode byte.
5741//-- */
5742//-- static
5743//-- Addr dis_SSE3_reg_or_mem_Imm8 ( UCodeBlock* cb,
5744//-- UChar sorb,
5745//-- Addr eip,
5746//-- Int sz,
5747//-- Char* name,
5748//-- UChar opc1,
5749//-- UChar opc2,
5750//-- UChar opc3 )
5751//-- {
5752//-- Char dis_buf[50];
5753//-- UChar modrm = getUChar(eip);
5754//-- UChar imm8;
5755//-- Bool isReg = epartIsReg(modrm);
5756//--
5757//-- if (isReg) {
5758//-- /* Completely internal SSE insn. */
5759//-- eip++;
5760//-- imm8 = getUChar(eip);
5761//-- uInstr3(cb, SSE5, 0, /* ignore sz for internal ops */
5762//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
5763//-- Lit16, (((UShort)opc3) << 8) | (UShort)modrm,
5764//-- Lit16, (UShort)imm8 );
5765//-- eip++;
5766//-- } else {
5767//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
5768//-- Int tmpa = LOW24(pair);
5769//-- eip += HI8(pair);
5770//-- imm8 = getUChar(eip);
5771//-- eip++;
5772//-- uInstr3(cb, SSE3a1_MemRd, sz,
5773//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
5774//-- Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
5775//-- TempReg, tmpa);
5776//-- uLiteral(cb, imm8);
5777//-- }
5778//-- DIP("%s %s, %s, $%d\n",
5779//-- name, ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
5780//-- nameXMMReg(gregOfRM(modrm)), (Int)imm8 );
5781//-- return eip;
5782//-- }
5783//--
5784//--
5785//-- /* Disassemble an SSE insn which is either a simple reg-reg move or a
5786//-- move between registers and memory. Supplied eip points to the
5787//-- first address mode byte.
5788//-- */
5789//-- static
5790//-- Addr dis_SSE3_load_store_or_mov ( UCodeBlock* cb,
5791//-- UChar sorb,
5792//-- Addr eip,
5793//-- Int sz,
5794//-- Bool is_store,
5795//-- Char* name,
5796//-- UChar insn0,
5797//-- UChar insn1,
5798//-- UChar insn2 )
5799//-- {
5800//-- Char dis_buf[50];
5801//-- UChar modrm = getUChar(eip);
5802//-- Bool isReg = epartIsReg(modrm);
5803//-- UInt pair;
5804//-- Int t1;
5805//--
5806//-- if (isReg) {
5807//-- /* Completely internal; we can issue SSE4. */
5808//-- eip++;
5809//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
5810//-- Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
5811//-- Lit16, (((UShort)insn2) << 8) | (UShort)modrm );
5812//-- } else {
5813//-- pair = disAMode ( cb, sorb, eip, dis_buf );
5814//-- t1 = LOW24(pair);
5815//-- eip += HI8(pair);
5816//-- uInstr3(cb, is_store ? SSE3a_MemWr : SSE3a_MemRd, sz,
5817//-- Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
5818//-- Lit16, (((UShort)insn2) << 8) | (UShort)modrm,
5819//-- TempReg, t1 );
5820//-- }
5821//--
5822//-- if (is_store) {
5823//-- DIP("%s %s, %s\n",
5824//-- name,
5825//-- nameXMMReg(gregOfRM(modrm)),
5826//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ) );
5827//-- } else {
5828//-- DIP("%s %s, %s\n",
5829//-- name,
5830//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
5831//-- nameXMMReg(gregOfRM(modrm)) );
5832//-- }
5833//-- return eip;
5834//-- }
5835//--
5836//--
5837//-- /* Disassemble an SSE insn which is either a simple reg-reg move or a
5838//-- move between registers and memory. Supplied eip points to the
5839//-- first address mode byte. */
5840//-- static
5841//-- Addr dis_SSE2_load_store_or_mov ( UCodeBlock* cb,
5842//-- UChar sorb,
5843//-- Addr eip,
5844//-- Int sz,
5845//-- Bool is_store,
5846//-- Char* name,
5847//-- UChar insn0,
5848//-- UChar insn1 )
5849//-- {
5850//-- Char dis_buf[50];
5851//-- UChar modrm = getUChar(eip);
5852//-- Bool isReg = epartIsReg(modrm);
5853//-- UInt pair;
5854//-- Int t1;
5855//--
5856//-- if (isReg) {
5857//-- /* Completely internal; we can issue SSE3. */
5858//-- eip++;
5859//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
5860//-- Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
5861//-- Lit16, (UShort)modrm );
5862//-- } else {
5863//-- pair = disAMode ( cb, sorb, eip, dis_buf );
5864//-- t1 = LOW24(pair);
5865//-- eip += HI8(pair);
5866//-- uInstr3(cb, is_store ? SSE2a_MemWr : SSE2a_MemRd, sz,
5867//-- Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
5868//-- Lit16, (UShort)modrm,
5869//-- TempReg, t1 );
5870//-- }
5871//--
5872//-- if (is_store) {
5873//-- DIP("%s %s, %s\n",
5874//-- name,
5875//-- nameXMMReg(gregOfRM(modrm)),
5876//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ) );
5877//-- } else {
5878//-- DIP("%s %s, %s\n",
5879//-- name,
5880//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
5881//-- nameXMMReg(gregOfRM(modrm)) );
5882//-- }
5883//-- return eip;
5884//-- }
5885//--
5886//--
5887//-- /* Simple SSE operations, either
5888//-- op (src)xmmreg, (dst)mmxreg
5889//-- or
5890//-- op (src)address, (dst)mmxreg
5891//-- 2 opcode bytes.
5892//-- Supplied eip points to the first address mode byte.
5893//-- */
5894//-- static
5895//-- Addr dis_SSE2_to_MMX ( UCodeBlock *cb,
5896//-- UChar sorb,
5897//-- Addr eip,
5898//-- Int sz,
5899//-- Char* name,
5900//-- UChar opc1,
5901//-- UChar opc2 )
5902//-- {
5903//-- UChar dis_buf[50];
5904//-- UChar modrm = getUChar(eip);
5905//-- if (epartIsReg(modrm)) {
5906//-- /* Completely internal SSE insn. */
5907//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
5908//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
5909//-- Lit16, (UShort)modrm );
5910//-- DIP("%s %s, %s\n",
5911//-- name, nameXMMReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)) );
5912//-- eip++;
5913//-- } else {
5914//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
5915//-- Int tmpa = LOW24(pair);
5916//-- eip += HI8(pair);
5917//-- uInstr3(cb, SSE2a_MemRd, sz,
5918//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
5919//-- Lit16, ((UShort)modrm),
5920//-- TempReg, tmpa);
5921//-- DIP("%s %s, %s\n", name, dis_buf, nameMMXReg(gregOfRM(modrm)));
5922//-- }
5923//-- return eip;
5924//-- }
5925//--
5926//--
5927//-- /* Simple SSE operations, either
5928//-- op (src)mmxreg, (dst)xmmreg
5929//-- or
5930//-- op (src)address, (dst)xmmreg
5931//-- 2 opcode bytes.
5932//-- Supplied eip points to the first address mode byte.
5933//-- */
5934//-- static
5935//-- Addr dis_SSE2_from_MMX ( UCodeBlock *cb,
5936//-- UChar sorb,
5937//-- Addr eip,
5938//-- Int sz,
5939//-- Char* name,
5940//-- UChar opc1,
5941//-- UChar opc2 )
5942//-- {
5943//-- UChar dis_buf[50];
5944//-- UChar modrm = getUChar(eip);
5945//-- if (epartIsReg(modrm)) {
5946//-- /* Completely internal SSE insn. */
5947//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
5948//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
5949//-- Lit16, (UShort)modrm );
5950//-- DIP("%s %s, %s\n",
5951//-- name, nameMMXReg(eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)) );
5952//-- eip++;
5953//-- } else {
5954//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
5955//-- Int tmpa = LOW24(pair);
5956//-- eip += HI8(pair);
5957//-- uInstr3(cb, SSE2a_MemRd, sz,
5958//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
5959//-- Lit16, ((UShort)modrm),
5960//-- TempReg, tmpa);
5961//-- DIP("%s %s, %s\n", name, dis_buf, nameXMMReg(gregOfRM(modrm)));
5962//-- }
5963//-- return eip;
5964//-- }
5965//--
5966//--
5967//-- /* Simple SSE operations, either
5968//-- op (src)xmmreg, (dst)mmxreg
5969//-- or
5970//-- op (src)address, (dst)mmxreg
5971//-- 3 opcode bytes.
5972//-- Supplied eip points to the first address mode byte.
5973//-- */
5974//-- static
5975//-- Addr dis_SSE3_to_MMX ( UCodeBlock *cb,
5976//-- UChar sorb,
5977//-- Addr eip,
5978//-- Int sz,
5979//-- Char* name,
5980//-- UChar opc1,
5981//-- UChar opc2,
5982//-- UChar opc3 )
5983//-- {
5984//-- UChar dis_buf[50];
5985//-- UChar modrm = getUChar(eip);
5986//-- if (epartIsReg(modrm)) {
5987//-- /* Completely internal SSE insn. */
5988//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
5989//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
5990//-- Lit16, (((UShort)opc3) << 8) | (UShort)modrm );
5991//-- DIP("%s %s, %s\n",
5992//-- name, nameXMMReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)) );
5993//-- eip++;
5994//-- } else {
5995//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
5996//-- Int tmpa = LOW24(pair);
5997//-- eip += HI8(pair);
5998//-- uInstr3(cb, SSE3a_MemRd, sz,
5999//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
6000//-- Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
6001//-- TempReg, tmpa);
6002//-- DIP("%s %s, %s\n", name, dis_buf, nameMMXReg(gregOfRM(modrm)));
6003//-- }
6004//-- return eip;
6005//-- }
6006//--
6007//--
6008//-- /* Simple SSE operations, either
6009//-- op (src)mmxreg, (dst)xmmreg
6010//-- or
6011//-- op (src)address, (dst)xmmreg
6012//-- 3 opcode bytes.
6013//-- Supplied eip points to the first address mode byte.
6014//-- */
6015//-- static
6016//-- Addr dis_SSE3_from_MMX ( UCodeBlock *cb,
6017//-- UChar sorb,
6018//-- Addr eip,
6019//-- Int sz,
6020//-- Char* name,
6021//-- UChar opc1,
6022//-- UChar opc2,
6023//-- UChar opc3 )
6024//-- {
6025//-- UChar dis_buf[50];
6026//-- UChar modrm = getUChar(eip);
6027//-- if (epartIsReg(modrm)) {
6028//-- /* Completely internal SSE insn. */
6029//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
6030//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
6031//-- Lit16, (((UShort)opc3) << 8) | (UShort)modrm );
6032//-- DIP("%s %s, %s\n",
6033//-- name, nameMMXReg(eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)) );
6034//-- eip++;
6035//-- } else {
6036//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
6037//-- Int tmpa = LOW24(pair);
6038//-- eip += HI8(pair);
6039//-- uInstr3(cb, SSE3a_MemRd, sz,
6040//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
6041//-- Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
6042//-- TempReg, tmpa);
6043//-- DIP("%s %s, %s\n", name, dis_buf, nameXMMReg(gregOfRM(modrm)));
6044//-- }
6045//-- return eip;
6046//-- }
6047//--
6048//--
6049//-- static
6050//-- void dis_push_segreg ( UCodeBlock* cb, UInt sreg, Int sz )
6051//-- {
6052//-- Int t1 = newTemp(cb), t2 = newTemp(cb);
6053//-- vg_assert(sz == 2 || sz == 4);
6054//-- uInstr2(cb, GETSEG, 2, ArchRegS, sreg, TempReg, t1);
6055//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
6056//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
6057//-- uLiteral(cb, sz);
6058//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
6059//-- uInstr2(cb, STORE, 2, TempReg, t1, TempReg, t2);
6060//-- DIP("push %s\n", VG_(name_of_seg_reg)(sreg));
6061//-- }
6062//--
6063//-- static
6064//-- void dis_pop_segreg ( UCodeBlock* cb, UInt sreg, Int sz )
6065//-- {
6066//-- Int t1 = newTemp(cb), t2 = newTemp(cb);
6067//-- vg_assert(sz == 2 || sz == 4);
6068//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
6069//-- uInstr2(cb, LOAD, 2, TempReg, t2, TempReg, t1);
6070//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
6071//-- uLiteral(cb, sz);
6072//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
6073//-- uInstr2(cb, PUTSEG, 2, TempReg, t1, ArchRegS, sreg);
6074//-- DIP("pop %s\n", VG_(name_of_seg_reg)(sreg));
6075//-- }
sewardje05c42c2004-07-08 20:25:10 +00006076
6077static
6078void dis_ret ( UInt d32 )
6079{
6080 IRTemp t1 = newTemp(Ity_I32), t2 = newTemp(Ity_I32);
6081 assign(t1, getIReg(4,R_ESP));
6082 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
6083 putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(4+d32)));
sewardj78c19df2004-07-12 22:49:27 +00006084 jmp_treg(Ijk_Ret,t2);
sewardje05c42c2004-07-08 20:25:10 +00006085}
6086
sewardjc9a65702004-07-07 16:32:57 +00006087
6088/*------------------------------------------------------------*/
sewardjce70a5c2004-10-18 14:09:54 +00006089/*--- Disassemble a single instruction ---*/
sewardjc9a65702004-07-07 16:32:57 +00006090/*------------------------------------------------------------*/
6091
sewardjce70a5c2004-10-18 14:09:54 +00006092/* Disassemble a single instruction into IR. The instruction
6093 is located in host memory at &guest_code[delta].
6094 Set *size to be the size of the instruction.
6095 If the returned value is Dis_Resteer,
6096 the next guest address is assigned to *whereNext. If resteerOK
6097 is False, disInstr may not return Dis_Resteer. */
6098
6099static DisResult disInstr ( /*IN*/ Bool resteerOK,
6100 /*IN*/ UInt delta,
6101 /*OUT*/ UInt* size,
6102 /*OUT*/ Addr64* whereNext )
sewardjc9a65702004-07-07 16:32:57 +00006103{
sewardjce70a5c2004-10-18 14:09:54 +00006104 IRType ty;
6105 IRTemp addr, t1, t2;
6106 Int alen;
6107 UChar opc, modrm, abyte;
6108 UInt d32;
6109 UChar dis_buf[50];
6110 Int am_sz, d_sz;
6111 DisResult whatNext = Dis_Continue;
6112
sewardjc9a65702004-07-07 16:32:57 +00006113 //Char loc_buf[M_VG_ERRTXT];
6114
6115 /* Holds eip at the start of the insn, so that we can print
6116 consistent error messages for unimplemented insns. */
6117 UInt delta_start = delta;
6118
6119 /* sz denotes the nominal data-op size of the insn; we change it to
6120 2 if an 0x66 prefix is seen */
6121 Int sz = 4;
6122
6123 /* sorb holds the segment-override-prefix byte, if any. Zero if no
6124 prefix has been seen, else one of {0x26, 0x3E, 0x64, 0x65}
6125 indicating the prefix. */
6126 UChar sorb = 0;
6127
6128 /* For printing the stmts after each insn. */
sewardjd7cb8532004-08-17 23:59:23 +00006129 Int first_stmt_idx = irbb->stmts_used;
sewardjc9a65702004-07-07 16:32:57 +00006130
sewardjce70a5c2004-10-18 14:09:54 +00006131 /* If we don't set *size properly, this causes bbToIR_X86Instr to
6132 assert. */
6133 *size = 0;
6134
sewardj940e8c92004-07-11 16:53:24 +00006135 addr = t1 = t2 = INVALID_IRTEMP;
sewardj41f43bc2004-07-08 14:23:22 +00006136 //t3 = t4 = INVALID_IRTEMP;
sewardjc9a65702004-07-07 16:32:57 +00006137
sewardjce70a5c2004-10-18 14:09:54 +00006138 DIP("\t0x%x: ", guest_eip_bbstart+delta);
sewardjc9a65702004-07-07 16:32:57 +00006139
sewardj750f4072004-07-26 22:39:11 +00006140 /* Spot the client-request magic sequence. */
6141 {
6142 UChar* code = (UChar*)(guest_code + delta);
6143 /* Spot this:
6144 C1C01D roll $29, %eax
6145 C1C003 roll $3, %eax
6146 C1C81B rorl $27, %eax
6147 C1C805 rorl $5, %eax
6148 C1C00D roll $13, %eax
6149 C1C013 roll $19, %eax
6150 */
6151 if (code[ 0] == 0xC1 && code[ 1] == 0xC0 && code[ 2] == 0x1D &&
6152 code[ 3] == 0xC1 && code[ 4] == 0xC0 && code[ 5] == 0x03 &&
6153 code[ 6] == 0xC1 && code[ 7] == 0xC8 && code[ 8] == 0x1B &&
6154 code[ 9] == 0xC1 && code[10] == 0xC8 && code[11] == 0x05 &&
6155 code[12] == 0xC1 && code[13] == 0xC0 && code[14] == 0x0D &&
6156 code[15] == 0xC1 && code[16] == 0xC0 && code[17] == 0x13
6157 ) {
sewardjce70a5c2004-10-18 14:09:54 +00006158 DIP("%%edx = client_request ( %%eax )\n");
sewardj750f4072004-07-26 22:39:11 +00006159 delta += 18;
sewardjce70a5c2004-10-18 14:09:54 +00006160 jmp_lit(Ijk_ClientReq, guest_eip_bbstart+delta);
6161 whatNext = Dis_StopHere;
6162 goto decode_success;
sewardj750f4072004-07-26 22:39:11 +00006163 }
6164 }
sewardjc9a65702004-07-07 16:32:57 +00006165
6166 /* Skip a LOCK prefix. */
6167 if (getIByte(delta) == 0xF0) {
sewardj458a6f82004-08-25 12:46:02 +00006168 vex_printf("vex x86->IR: ignoring LOCK prefix\n");
sewardjc9a65702004-07-07 16:32:57 +00006169 delta++;
6170 }
6171
6172 /* Detect operand-size overrides. */
6173 if (getIByte(delta) == 0x66) { sz = 2; delta++; };
6174
6175 /* segment override prefixes come after the operand-size override,
6176 it seems */
6177 switch (getIByte(delta)) {
6178 case 0x3E: /* %DS: */
6179 case 0x26: /* %ES: */
6180 case 0x64: /* %FS: */
6181 case 0x65: /* %GS: */
6182 sorb = getIByte(delta); delta++;
6183 break;
6184 case 0x2E: /* %CS: */
6185 /* 2E prefix on a conditional branch instruction is a
6186 branch-prediction hint, which can safely be ignored. */
6187 {
6188 UChar op1 = getIByte(delta+1);
6189 UChar op2 = getIByte(delta+2);
6190 if ((op1 >= 0x70 && op1 <= 0x7F)
6191 || (op1 == 0xE3)
6192 || (op1 == 0x0F && op2 >= 0x80 && op2 <= 0x8F)) {
sewardjce70a5c2004-10-18 14:09:54 +00006193 vex_printf("vex x86->IR: ignoring branch hint\n");
sewardjc9a65702004-07-07 16:32:57 +00006194 sorb = getIByte(delta); delta++;
6195 break;
6196 }
6197 }
6198 unimplemented("x86 segment override (SEG=CS) prefix");
6199 /*NOTREACHED*/
6200 break;
6201 case 0x36: /* %SS: */
6202 unimplemented("x86 segment override (SEG=SS) prefix");
6203 /*NOTREACHED*/
6204 break;
6205 default:
6206 break;
6207 }
6208
6209//-- /* ---------------------------------------------------- */
6210//-- /* --- The SSE/SSE2 decoder. --- */
6211//-- /* ---------------------------------------------------- */
6212//--
6213//-- /* If it looks like this CPU might support SSE, try decoding SSE
6214//-- insns. */
6215//-- if (VG_(have_ssestate)) {
6216//-- UChar* insn = (UChar*)eip;
6217//--
6218//-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
6219//-- if (insn[0] == 0x0F && insn[1] == 0xAE
6220//-- && (!epartIsReg(insn[2]))
6221//-- && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
6222//-- Bool store = gregOfRM(insn[2]) == 0;
6223//-- vg_assert(sz == 4);
6224//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
6225//-- t1 = LOW24(pair);
6226//-- eip += 2+HI8(pair);
6227//-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
6228//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
6229//-- Lit16, (UShort)insn[2],
6230//-- TempReg, t1 );
6231//-- DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
6232//-- goto decode_success;
6233//-- }
6234//--
6235//-- /* STMXCSR/LDMXCSR m32 -- load/store the MXCSR register. */
6236//-- if (insn[0] == 0x0F && insn[1] == 0xAE
6237//-- && (!epartIsReg(insn[2]))
6238//-- && (gregOfRM(insn[2]) == 3 || gregOfRM(insn[2]) == 2) ) {
6239//-- Bool store = gregOfRM(insn[2]) == 3;
6240//-- vg_assert(sz == 4);
6241//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
6242//-- t1 = LOW24(pair);
6243//-- eip += 2+HI8(pair);
6244//-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 4,
6245//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
6246//-- Lit16, (UShort)insn[2],
6247//-- TempReg, t1 );
6248//-- DIP("%smxcsr %s\n", store ? "st" : "ld", dis_buf );
6249//-- goto decode_success;
6250//-- }
6251//--
6252//-- /* LFENCE/MFENCE/SFENCE -- flush pending operations to memory */
6253//-- if (insn[0] == 0x0F && insn[1] == 0xAE
6254//-- && (epartIsReg(insn[2]))
6255//-- && (gregOfRM(insn[2]) >= 5 && gregOfRM(insn[2]) <= 7))
6256//-- {
6257//-- vg_assert(sz == 4);
6258//-- eip += 3;
6259//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
6260//-- Lit16, (((UShort)0x0F) << 8) | (UShort)0xAE,
6261//-- Lit16, (UShort)insn[2] );
6262//-- DIP("sfence\n");
6263//-- goto decode_success;
6264//-- }
6265//--
6266//-- /* CLFLUSH -- flush cache line */
6267//-- if (insn[0] == 0x0F && insn[1] == 0xAE
6268//-- && (!epartIsReg(insn[2]))
6269//-- && (gregOfRM(insn[2]) == 7))
6270//-- {
6271//-- vg_assert(sz == 4);
6272//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
6273//-- t1 = LOW24(pair);
6274//-- eip += 2+HI8(pair);
6275//-- uInstr3(cb, SSE2a_MemRd, 0, /* ignore sz for internal ops */
6276//-- Lit16, (((UShort)0x0F) << 8) | (UShort)0xAE,
6277//-- Lit16, (UShort)insn[2],
6278//-- TempReg, t1 );
6279//-- DIP("clflush %s\n", dis_buf);
6280//-- goto decode_success;
6281//-- }
6282//--
6283//-- /* CVTPI2PS (0x0F,0x2A) -- mm/m64, xmm */
6284//-- /* CVTPI2PD (0x66,0x0F,0x2A) -- mm/m64, xmm */
6285//-- if (insn[0] == 0x0F && insn[1] == 0x2A) {
6286//-- if (sz == 4) {
6287//-- eip = dis_SSE2_from_MMX
6288//-- ( cb, sorb, eip+2, 8, "cvtpi2ps",
6289//-- insn[0], insn[1] );
6290//-- } else {
6291//-- eip = dis_SSE3_from_MMX
6292//-- ( cb, sorb, eip+2, 8, "cvtpi2pd",
6293//-- 0x66, insn[0], insn[1] );
6294//-- }
6295//-- goto decode_success;
6296//-- }
6297//--
6298//-- /* CVTTPS2PI (0x0F,0x2C) -- xmm/m64, mm */
6299//-- /* CVTPS2PI (0x0F,0x2D) -- xmm/m64, mm */
6300//-- /* CVTTPD2PI (0x66,0x0F,0x2C) -- xmm/m128, mm */
6301//-- /* CVTPD2PI (0x66,0x0F,0x2D) -- xmm/m128, mm */
6302//-- if (insn[0] == 0x0F
6303//-- && (insn[1] == 0x2C || insn[1] == 0x2D)) {
6304//-- if (sz == 4) {
6305//-- eip = dis_SSE2_to_MMX
6306//-- ( cb, sorb, eip+2, 8, "cvt{t}ps2pi",
6307//-- insn[0], insn[1] );
6308//-- } else {
6309//-- eip = dis_SSE3_to_MMX
6310//-- ( cb, sorb, eip+2, 16, "cvt{t}pd2pi",
6311//-- 0x66, insn[0], insn[1] );
6312//-- }
6313//-- goto decode_success;
6314//-- }
6315//--
6316//-- /* CVTTSD2SI (0xF2,0x0F,0x2C) -- convert a double-precision float
6317//-- value in memory or xmm reg to int and put it in an ireg.
6318//-- Truncate. */
6319//-- /* CVTTSS2SI (0xF3,0x0F,0x2C) -- convert a single-precision float
6320//-- value in memory or xmm reg to int and put it in an ireg.
6321//-- Truncate. */
6322//-- /* CVTSD2SI (0xF2,0x0F,0x2D) -- convert a double-precision float
6323//-- value in memory or xmm reg to int and put it in an ireg. Round
6324//-- as per MXCSR. */
6325//-- /* CVTSS2SI (0xF3,0x0F,0x2D) -- convert a single-precision float
6326//-- value in memory or xmm reg to int and put it in an ireg. Round
6327//-- as per MXCSR. */
6328//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
6329//-- && insn[1] == 0x0F
6330//-- && (insn[2] == 0x2C || insn[2] == 0x2D)) {
6331//-- vg_assert(sz == 4);
6332//-- modrm = insn[3];
6333//-- if (epartIsReg(modrm)) {
6334//-- /* We're moving a value in an xmm reg to an ireg. */
6335//-- eip += 4;
6336//-- t1 = newTemp(cb);
6337//-- /* sz is 4 for all 4 insns. */
6338//-- vg_assert(epartIsReg(modrm));
6339//-- uInstr3(cb, SSE3g_RegWr, 4,
6340//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
6341//-- Lit16, (((UShort)insn[2]) << 8) | (UShort)modrm,
6342//-- TempReg, t1 );
6343//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
6344//-- DIP("cvt{t}s{s,d}2si %s, %s\n",
6345//-- nameXMMReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)) );
6346//-- } else {
6347//-- /* So, we're reading memory and writing an ireg. This calls
6348//-- for the ultra-horrible SSE3ag_MemRd_RegWr uinstr. We
6349//-- can't do it in a roundabout route because it does some
6350//-- kind of conversion on the way, which we need to have
6351//-- happen too. So our only choice is to re-emit a suitably
6352//-- rehashed version of the instruction. */
6353//-- /* Destination ireg is GREG. Address goes as EREG as
6354//-- usual. */
6355//-- t1 = newTemp(cb); /* t1 holds value on its way to ireg */
6356//-- pair = disAMode ( cb, sorb, eip+3, dis_buf );
6357//-- t2 = LOW24(pair); /* t2 holds addr */
6358//-- eip += 3+HI8(pair);
6359//-- uInstr2(cb, SSE3ag_MemRd_RegWr, insn[0]==0xF2 ? 8 : 4,
6360//-- TempReg, t2, /* address */
6361//-- TempReg, t1 /* dest */);
6362//-- uLiteral(cb , (((UInt)insn[0]) << 24)
6363//-- | (((UInt)insn[1]) << 16)
6364//-- | (((UInt)insn[2]) << 8)
6365//-- | ((UInt)modrm) );
6366//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
6367//-- DIP("cvt{t}s{s,d}2si %s, %s\n",
6368//-- dis_buf, nameIReg(4,gregOfRM(modrm)) );
6369//-- }
6370//-- goto decode_success;
6371//-- }
6372//--
6373//-- /* CVTSI2SS -- convert int reg, or int value in memory, to low 4
6374//-- bytes of XMM reg. */
6375//-- /* CVTSI2SD -- convert int reg, or int value in memory, to low 8
6376//-- bytes of XMM reg. */
6377//-- if ((insn[0] == 0xF3 /*CVTSI2SS*/ || insn[0] == 0xF2 /* CVTSI2SD*/)
6378//-- && insn[1] == 0x0F && insn[2] == 0x2A) {
6379//-- Char* s_or_d = insn[0]==0xF3 ? "s" : "d";
6380//-- vg_assert(sz == 4);
6381//-- modrm = insn[3];
6382//-- t1 = newTemp(cb);
6383//-- if (epartIsReg(modrm)) {
6384//-- uInstr2(cb, GET, 4, ArchReg, eregOfRM(modrm), TempReg, t1);
6385//-- vg_assert(epartIsReg(modrm));
6386//-- uInstr3(cb, SSE3e_RegRd, 4,
6387//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
6388//-- Lit16, (((UShort)insn[2]) << 8) | (UShort)modrm,
6389//-- TempReg, t1 );
6390//-- eip += 4;
6391//-- DIP("cvtsi2s%s %s, %s\n", s_or_d,
6392//-- nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
6393//-- } else {
6394//-- pair = disAMode ( cb, sorb, eip+3, dis_buf );
6395//-- t2 = LOW24(pair);
6396//-- eip += 3+HI8(pair);
6397//-- uInstr3(cb, SSE3a_MemRd, 4,
6398//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
6399//-- Lit16, (((UShort)insn[2]) << 8) | (UShort)modrm,
6400//-- TempReg, t2 );
6401//-- DIP("cvtsi2s%s %s, %s\n",
6402//-- s_or_d, dis_buf, nameXMMReg(gregOfRM(modrm)));
6403//-- }
6404//-- goto decode_success;
6405//-- }
6406//--
6407//-- /* CVTPS2PD -- convert two packed floats to two packed doubles. */
6408//-- /* 0x66: CVTPD2PS -- convert two packed doubles to two packed floats. */
6409//-- if (insn[0] == 0x0F && insn[1] == 0x5A) {
6410//-- vg_assert(sz == 2 || sz == 4);
6411//-- if (sz == 4) {
6412//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 8, "cvtps2pd",
6413//-- insn[0], insn[1] );
6414//-- } else {
6415//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "cvtpd2ps",
6416//-- 0x66, insn[0], insn[1] );
6417//-- }
6418//-- goto decode_success;
6419//-- }
6420//--
6421//-- /* CVTSS2SD -- convert one single float to double. */
6422//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5A) {
6423//-- vg_assert(sz == 4);
6424//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4, "cvtss2sd",
6425//-- insn[0], insn[1], insn[2] );
6426//-- goto decode_success;
6427//-- }
6428//--
6429//-- /* CVTSD2SS -- convert one single double. to float. */
6430//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5A) {
6431//-- vg_assert(sz == 4);
6432//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8, "cvtsd2ss",
6433//-- insn[0], insn[1], insn[2] );
6434//-- goto decode_success;
6435//-- }
6436//--
6437//-- /* CVTDQ2PS -- convert four ints to four packed floats. */
6438//-- /* 0x66: CVTPS2DQ -- convert four packed floats to four ints. */
6439//-- if (insn[0] == 0x0F && insn[1] == 0x5B) {
6440//-- vg_assert(sz == 2 || sz == 4);
6441//-- if (sz == 4) {
6442//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "cvtdq2ps",
6443//-- insn[0], insn[1] );
6444//-- } else {
6445//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "cvtps2dq",
6446//-- 0x66, insn[0], insn[1] );
6447//-- }
6448//-- goto decode_success;
6449//-- }
6450//--
6451//-- /* CVTPD2DQ -- convert two packed doubles to two ints. */
6452//-- if (sz == 2
6453//-- && insn[0] == 0x0F && insn[1] == 0xE6) {
6454//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 8, "cvtpd2dq",
6455//-- 0x66, insn[0], insn[1] );
6456//-- goto decode_success;
6457//-- }
6458//--
6459//-- /* CVTTPD2DQ -- convert two packed doubles to two ints with truncation. */
6460//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xE6) {
6461//-- vg_assert(sz == 4);
6462//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8, "cvttpd2dq",
6463//-- insn[0], insn[1], insn[2] );
6464//-- goto decode_success;
6465//-- }
6466//--
6467//-- /* CVTDQ2PD -- convert two ints to two packed doubles. */
6468//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xE6) {
6469//-- vg_assert(sz == 4);
6470//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8, "cvtdq2pd",
6471//-- insn[0], insn[1], insn[2] );
6472//-- goto decode_success;
6473//-- }
6474//--
6475//-- /* CVTTPS2DQ -- convert four packed floats to four ints with truncation. */
6476//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5B) {
6477//-- vg_assert(sz == 4);
6478//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 16, "cvttps2dq",
6479//-- insn[0], insn[1], insn[2] );
6480//-- goto decode_success;
6481//-- }
6482//--
6483//-- /* CMPSS -- compare scalar floats. */
6484//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xC2) {
6485//-- vg_assert(sz == 4);
6486//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 8, "cmpss",
6487//-- insn[0], insn[1], insn[2] );
6488//-- goto decode_success;
6489//-- }
6490//--
6491//-- /* CMPSD -- compare scalar doubles. */
6492//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xC2) {
6493//-- vg_assert(sz == 4);
6494//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 8, "cmpsd",
6495//-- insn[0], insn[1], insn[2] );
6496//-- goto decode_success;
6497//-- }
6498//--
6499//-- /* sz==4: CMPPS -- compare packed floats */
6500//-- /* sz==2: CMPPD -- compare packed doubles */
6501//-- if (insn[0] == 0x0F && insn[1] == 0xC2) {
6502//-- vg_assert(sz == 4 || sz == 2);
6503//-- if (sz == 4) {
6504//-- eip = dis_SSE2_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "cmpps",
6505//-- insn[0], insn[1] );
6506//-- } else {
6507//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "cmppd",
6508//-- 0x66, insn[0], insn[1] );
6509//-- }
6510//-- goto decode_success;
6511//-- }
6512//--
6513//-- /* PSHUFD */
6514//-- if (sz == 2
6515//-- && insn[0] == 0x0F && insn[1] == 0x70) {
6516//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16,
6517//-- "pshufd",
6518//-- 0x66, insn[0], insn[1] );
6519//-- goto decode_success;
6520//-- }
6521//--
6522//-- /* PSHUFLW */
6523//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x70) {
6524//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 16,
6525//-- "pshuflw",
6526//-- insn[0], insn[1], insn[2] );
6527//-- goto decode_success;
6528//-- }
6529//--
6530//-- /* PSHUFHW */
6531//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x70) {
6532//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 16,
6533//-- "pshufhw",
6534//-- insn[0], insn[1], insn[2] );
6535//-- goto decode_success;
6536//-- }
6537//--
6538//-- /* SHUFPD */
6539//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC6) {
6540//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "shufpd",
6541//-- 0x66, insn[0], insn[1] );
6542//-- goto decode_success;
6543//-- }
6544//--
6545//-- /* SHUFPS */
6546//-- if (insn[0] == 0x0F && insn[1] == 0xC6) {
6547//-- vg_assert(sz == 4);
6548//-- eip = dis_SSE2_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "shufps",
6549//-- insn[0], insn[1] );
6550//-- goto decode_success;
6551//-- }
6552//--
6553//-- /* 0xF2: MULSD */
6554//-- /* 0xF3: MULSS -- multiply low 4 bytes of XMM reg. */
6555//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
6556//-- && insn[1] == 0x0F && insn[2] == 0x59) {
6557//-- Bool sz8 = insn[0] == 0xF2;
6558//-- vg_assert(sz == 4);
6559//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
6560//-- sz8 ? "mulss" : "mulsd",
6561//-- insn[0], insn[1], insn[2] );
6562//-- goto decode_success;
6563//-- }
6564//--
6565//-- /* MULPS */
6566//-- /* 0x66: MULPD */
6567//-- if (insn[0] == 0x0F && insn[1] == 0x59) {
6568//-- vg_assert(sz == 4 || sz == 2);
6569//-- if (sz == 4) {
6570//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "mulps",
6571//-- insn[0], insn[1] );
6572//-- } else {
6573//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "mulpd",
6574//-- 0x66, insn[0], insn[1] );
6575//-- }
6576//-- goto decode_success;
6577//-- }
6578//--
6579//-- /* 0xF2: DIVSD */
6580//-- /* 0xF3: DIVSS -- divide low 4 bytes of XMM reg. */
6581//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
6582//-- && insn[1] == 0x0F && insn[2] == 0x5E) {
6583//-- Bool sz8 = insn[0] == 0xF2;
6584//-- vg_assert(sz == 4);
6585//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
6586//-- sz8 ? "divsd" : "divss",
6587//-- insn[0], insn[1], insn[2] );
6588//-- goto decode_success;
6589//-- }
6590//--
6591//-- /* DIVPS */
6592//-- /* 0x66: DIVPD */
6593//-- if (insn[0] == 0x0F && insn[1] == 0x5E) {
6594//-- vg_assert(sz == 4 || sz == 2);
6595//-- if (sz == 4) {
6596//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "divps",
6597//-- insn[0], insn[1] );
6598//-- } else {
6599//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "divpd",
6600//-- 0x66, insn[0], insn[1] );
6601//-- }
6602//-- goto decode_success;
6603//-- }
6604//--
6605//-- /* 0xF2: SUBSD */
6606//-- /* 0xF3: SUBSS */
6607//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
6608//-- && insn[1] == 0x0F && insn[2] == 0x5C) {
6609//-- Bool sz8 = insn[0] == 0xF2;
6610//-- vg_assert(sz == 4);
6611//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
6612//-- sz8 ? "subsd" : "subss",
6613//-- insn[0], insn[1], insn[2] );
6614//-- goto decode_success;
6615//-- }
6616//--
6617//-- /* SUBPS */
6618//-- /* 0x66: SUBPD */
6619//-- if (insn[0] == 0x0F && insn[1] == 0x5C) {
6620//-- vg_assert(sz == 4 || sz == 2);
6621//-- if (sz == 4) {
6622//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "subps",
6623//-- insn[0], insn[1] );
6624//-- } else {
6625//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "subpd",
6626//-- 0x66, insn[0], insn[1] );
6627//-- }
6628//-- goto decode_success;
6629//-- }
6630//--
6631//-- /* 0xF2: ADDSD */
6632//-- /* 0xF3: ADDSS */
6633//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
6634//-- && insn[1] == 0x0F && insn[2] == 0x58) {
6635//-- Bool sz8 = insn[0] == 0xF2;
6636//-- vg_assert(sz == 4);
6637//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
6638//-- sz8 ? "addsd" : "addss",
6639//-- insn[0], insn[1], insn[2] );
6640//-- goto decode_success;
6641//-- }
6642//--
6643//-- /* ADDPS */
6644//-- /* 0x66: ADDPD */
6645//-- if (insn[0] == 0x0F && insn[1] == 0x58) {
6646//-- vg_assert(sz == 4 || sz == 2);
6647//-- if (sz == 4) {
6648//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "addps",
6649//-- insn[0], insn[1] );
6650//-- } else {
6651//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "addpd",
6652//-- 0x66, insn[0], insn[1] );
6653//-- }
6654//-- goto decode_success;
6655//-- }
6656//--
6657//-- /* 0xF2: MINSD */
6658//-- /* 0xF3: MINSS */
6659//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
6660//-- && insn[1] == 0x0F && insn[2] == 0x5D) {
6661//-- Bool sz8 = insn[0] == 0xF2;
6662//-- vg_assert(sz == 4);
6663//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
6664//-- sz8 ? "minsd" : "minss",
6665//-- insn[0], insn[1], insn[2] );
6666//-- goto decode_success;
6667//-- }
6668//--
6669//-- /* MINPS */
6670//-- /* 0x66: MINPD */
6671//-- if (insn[0] == 0x0F && insn[1] == 0x5D) {
6672//-- vg_assert(sz == 4 || sz == 2);
6673//-- if (sz == 4) {
6674//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "minps",
6675//-- insn[0], insn[1] );
6676//-- } else {
6677//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "minpd",
6678//-- 0x66, insn[0], insn[1] );
6679//-- }
6680//-- goto decode_success;
6681//-- }
6682//--
6683//-- /* 0xF3: MAXSD */
6684//-- /* 0xF3: MAXSS */
6685//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
6686//-- && insn[1] == 0x0F && insn[2] == 0x5F) {
6687//-- Bool sz8 = insn[0] == 0xF2;
6688//-- vg_assert(sz == 4);
6689//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
6690//-- sz8 ? "maxsd" : "maxss",
6691//-- insn[0], insn[1], insn[2] );
6692//-- goto decode_success;
6693//-- }
6694//--
6695//-- /* MAXPS */
6696//-- /* 0x66: MAXPD */
6697//-- if (insn[0] == 0x0F && insn[1] == 0x5F) {
6698//-- vg_assert(sz == 4 || sz == 2);
6699//-- if (sz == 4) {
6700//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "maxps",
6701//-- insn[0], insn[1] );
6702//-- } else {
6703//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "maxpd",
6704//-- 0x66, insn[0], insn[1] );
6705//-- }
6706//-- goto decode_success;
6707//-- }
6708//--
6709//-- /* RCPPS -- reciprocal of packed floats */
6710//-- if (insn[0] == 0x0F && insn[1] == 0x53) {
6711//-- vg_assert(sz == 4);
6712//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "rcpps",
6713//-- insn[0], insn[1] );
6714//-- goto decode_success;
6715//-- }
6716//--
6717//-- /* XORPS */
6718//-- /* 0x66: XORPD (src)xmmreg-or-mem, (dst)xmmreg */
6719//-- if (insn[0] == 0x0F && insn[1] == 0x57) {
6720//-- vg_assert(sz == 4 || sz == 2);
6721//-- if (sz == 4) {
6722//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "xorps",
6723//-- insn[0], insn[1] );
6724//-- } else {
6725//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "xorpd",
6726//-- 0x66, insn[0], insn[1] );
6727//-- }
6728//-- goto decode_success;
6729//-- }
6730//--
6731//-- /* ANDPS */
6732//-- /* 0x66: ANDPD (src)xmmreg-or-mem, (dst)xmmreg */
6733//-- if (insn[0] == 0x0F && insn[1] == 0x54) {
6734//-- vg_assert(sz == 4 || sz == 2);
6735//-- if (sz == 4) {
6736//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "andps",
6737//-- insn[0], insn[1] );
6738//-- } else {
6739//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "andpd",
6740//-- 0x66, insn[0], insn[1] );
6741//-- }
6742//-- goto decode_success;
6743//-- }
6744//--
6745//-- /* ORPS */
6746//-- /* 0x66: ORPD (src)xmmreg-or-mem, (dst)xmmreg */
6747//-- if (insn[0] == 0x0F && insn[1] == 0x56) {
6748//-- vg_assert(sz == 4 || sz == 2);
6749//-- if (sz == 4) {
6750//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "orps",
6751//-- insn[0], insn[1] );
6752//-- } else {
6753//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "orpd",
6754//-- 0x66, insn[0], insn[1] );
6755//-- }
6756//-- goto decode_success;
6757//-- }
6758//--
6759//-- /* PXOR (src)xmmreg-or-mem, (dst)xmmreg */
6760//-- if (sz == 2
6761//-- && insn[0] == 0x0F && insn[1] == 0xEF) {
6762//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pxor",
6763//-- 0x66, insn[0], insn[1] );
6764//-- goto decode_success;
6765//-- }
6766//--
6767//-- /* PAND (src)xmmreg-or-mem, (dst)xmmreg */
6768//-- if (sz == 2
6769//-- && insn[0] == 0x0F && insn[1] == 0xDB) {
6770//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pand",
6771//-- 0x66, insn[0], insn[1] );
6772//-- goto decode_success;
6773//-- }
6774//--
6775//-- /* PANDN (src)xmmreg-or-mem, (dst)xmmreg */
6776//-- if (sz == 2
6777//-- && insn[0] == 0x0F && insn[1] == 0xDF) {
6778//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pandn",
6779//-- 0x66, insn[0], insn[1] );
6780//-- goto decode_success;
6781//-- }
6782//--
6783//-- /* POR (src)xmmreg-or-mem, (dst)xmmreg */
6784//-- if (sz == 2
6785//-- && insn[0] == 0x0F && insn[1] == 0xEB) {
6786//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "por",
6787//-- 0x66, insn[0], insn[1] );
6788//-- goto decode_success;
6789//-- }
6790//--
6791//-- /* 0xDA: PMINUB(src)xmmreg-or-mem, (dst)xmmreg */
6792//-- /* 0xEA: PMINSW(src)xmmreg-or-mem, (dst)xmmreg */
6793//-- if (sz == 2
6794//-- && insn[0] == 0x0F
6795//-- && (insn[1] == 0xDA || insn[1] == 0xEA)) {
6796//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmin{ub,sw}",
6797//-- 0x66, insn[0], insn[1] );
6798//-- goto decode_success;
6799//-- }
6800//--
6801//-- /* 0xDE: PMAXUB(src)xmmreg-or-mem, (dst)xmmreg */
6802//-- /* 0xEE: PMAXSW(src)xmmreg-or-mem, (dst)xmmreg */
6803//-- if (sz == 2
6804//-- && insn[0] == 0x0F
6805//-- && (insn[1] == 0xDE || insn[1] == 0xEE)) {
6806//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmax{ub,sw}",
6807//-- 0x66, insn[0], insn[1] );
6808//-- goto decode_success;
6809//-- }
6810//--
6811//-- /* 0xE0: PAVGB(src)xmmreg-or-mem, (dst)xmmreg */
6812//-- /* 0xE3: PAVGW(src)xmmreg-or-mem, (dst)xmmreg */
6813//-- if (sz == 2
6814//-- && insn[0] == 0x0F
6815//-- && (insn[1] == 0xE0 || insn[1] == 0xE3)) {
6816//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pavg{b,w}",
6817//-- 0x66, insn[0], insn[1] );
6818//-- goto decode_success;
6819//-- }
6820//--
6821//-- /* 0xF6: PSADBW(src)xmmreg-or-mem, (dst)xmmreg */
6822//-- if (sz == 2
6823//-- && insn[0] == 0x0F && insn[1] == 0xF6) {
6824//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psadbw",
6825//-- 0x66, insn[0], insn[1] );
6826//-- goto decode_success;
6827//-- }
6828//--
6829//-- /* 0x60: PUNPCKLBW (src)xmmreg-or-mem, (dst)xmmreg */
6830//-- /* 0x61: PUNPCKLWD (src)xmmreg-or-mem, (dst)xmmreg */
6831//-- /* 0x62: PUNPCKLDQ (src)xmmreg-or-mem, (dst)xmmreg */
6832//-- /* 0x6C: PUNPCKQLQDQ (src)xmmreg-or-mem, (dst)xmmreg */
6833//-- if (sz == 2
6834//-- && insn[0] == 0x0F
6835//-- && (insn[1] == 0x60 || insn[1] == 0x61
6836//-- || insn[1] == 0x62 || insn[1] == 0x6C)) {
6837//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16,
6838//-- "punpckl{bw,wd,dq,qdq}",
6839//-- 0x66, insn[0], insn[1] );
6840//-- goto decode_success;
6841//-- }
6842//--
6843//-- /* 0x68: PUNPCKHBW (src)xmmreg-or-mem, (dst)xmmreg */
6844//-- /* 0x69: PUNPCKHWD (src)xmmreg-or-mem, (dst)xmmreg */
6845//-- /* 0x6A: PUNPCKHDQ (src)xmmreg-or-mem, (dst)xmmreg */
6846//-- /* 0x6D: PUNPCKHQDQ (src)xmmreg-or-mem, (dst)xmmreg */
6847//-- if (sz == 2
6848//-- && insn[0] == 0x0F
6849//-- && (insn[1] == 0x68 || insn[1] == 0x69
6850//-- || insn[1] == 0x6A || insn[1] == 0x6D)) {
6851//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16,
6852//-- "punpckh{bw,wd,dq,qdq}",
6853//-- 0x66, insn[0], insn[1] );
6854//-- goto decode_success;
6855//-- }
6856//--
6857//-- /* 0x14: UNPCKLPD (src)xmmreg-or-mem, (dst)xmmreg. Reads a+0
6858//-- .. a+7, so we can say size 8 */
6859//-- /* 0x15: UNPCKHPD (src)xmmreg-or-mem, (dst)xmmreg. Reads a+8
6860//-- .. a+15, but we have no way to express this, so better say size
6861//-- 16. Sigh. */
6862//-- if (sz == 2
6863//-- && insn[0] == 0x0F
6864//-- && (insn[1] == 0x14 || insn[1] == 0x15)) {
6865//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2,
6866//-- insn[1]==0x14 ? 8 : 16,
6867//-- "unpck{l,h}pd",
6868//-- 0x66, insn[0], insn[1] );
6869//-- goto decode_success;
6870//-- }
6871//--
6872//-- /* 0x14: UNPCKLPS (src)xmmreg-or-mem, (dst)xmmreg Reads a+0
6873//-- .. a+7, so we can say size 8 */
6874//-- /* 0x15: UNPCKHPS (src)xmmreg-or-mem, (dst)xmmreg Reads a+8
6875//-- .. a+15, but we have no way to express this, so better say size
6876//-- 16. Sigh. */
6877//-- if (sz == 4
6878//-- && insn[0] == 0x0F
6879//-- && (insn[1] == 0x14 || insn[1] == 0x15)) {
6880//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2,
6881//-- insn[1]==0x14 ? 8 : 16,
6882//-- "unpck{l,h}ps",
6883//-- insn[0], insn[1] );
6884//-- goto decode_success;
6885//-- }
6886//--
6887//-- /* 0xFC: PADDB (src)xmmreg-or-mem, (dst)xmmreg */
6888//-- /* 0xFD: PADDW (src)xmmreg-or-mem, (dst)xmmreg */
6889//-- /* 0xFE: PADDD (src)xmmreg-or-mem, (dst)xmmreg */
6890//-- /* 0xD4: PADDQ (src)xmmreg-or-mem, (dst)xmmreg */
6891//-- if (sz == 2
6892//-- && insn[0] == 0x0F
6893//-- && (insn[1] == 0xFC || insn[1] == 0xFD
6894//-- || insn[1] == 0xFE || insn[1] == 0xD4)) {
6895//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "padd{b,w,d,q}",
6896//-- 0x66, insn[0], insn[1] );
6897//-- goto decode_success;
6898//-- }
6899//--
6900//-- /* 0xEC: PADDSB (src)xmmreg-or-mem, (dst)xmmreg */
6901//-- /* 0xED: PADDSW (src)xmmreg-or-mem, (dst)xmmreg */
6902//-- if (sz == 2
6903//-- && insn[0] == 0x0F
6904//-- && (insn[1] == 0xEC || insn[1] == 0xED)) {
6905//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "padds{b,w}",
6906//-- 0x66, insn[0], insn[1] );
6907//-- goto decode_success;
6908//-- }
6909//--
6910//-- /* 0xDC: PADDUSB (src)xmmreg-or-mem, (dst)xmmreg */
6911//-- /* 0xDD: PADDUSW (src)xmmreg-or-mem, (dst)xmmreg */
6912//-- if (sz == 2
6913//-- && insn[0] == 0x0F
6914//-- && (insn[1] == 0xDC || insn[1] == 0xDD)) {
6915//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "paddus{b,w}",
6916//-- 0x66, insn[0], insn[1] );
6917//-- goto decode_success;
6918//-- }
6919//--
6920//-- /* 0xF8: PSUBB (src)xmmreg-or-mem, (dst)xmmreg */
6921//-- /* 0xF9: PSUBW (src)xmmreg-or-mem, (dst)xmmreg */
6922//-- /* 0xFA: PSUBD (src)xmmreg-or-mem, (dst)xmmreg */
6923//-- /* 0xFB: PSUBQ (src)xmmreg-or-mem, (dst)xmmreg */
6924//-- if (sz == 2
6925//-- && insn[0] == 0x0F
6926//-- && (insn[1] == 0xF8 || insn[1] == 0xF9
6927//-- || insn[1] == 0xFA || insn[1] == 0xFB)) {
6928//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psub{b,w,d,q}",
6929//-- 0x66, insn[0], insn[1] );
6930//-- goto decode_success;
6931//-- }
6932//--
6933//-- /* 0xE8: PSUBSB (src)xmmreg-or-mem, (dst)xmmreg */
6934//-- /* 0xE9: PSUBSW (src)xmmreg-or-mem, (dst)xmmreg */
6935//-- if (sz == 2
6936//-- && insn[0] == 0x0F
6937//-- && (insn[1] == 0xE8 || insn[1] == 0xE9)) {
6938//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psubs{b,w}",
6939//-- 0x66, insn[0], insn[1] );
6940//-- goto decode_success;
6941//-- }
6942//--
6943//-- /* 0xD8: PSUBUSB (src)xmmreg-or-mem, (dst)xmmreg */
6944//-- /* 0xD9: PSUBUSW (src)xmmreg-or-mem, (dst)xmmreg */
6945//-- if (sz == 2
6946//-- && insn[0] == 0x0F
6947//-- && (insn[1] == 0xD8 || insn[1] == 0xD9)) {
6948//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psubus{b,w}",
6949//-- 0x66, insn[0], insn[1] );
6950//-- goto decode_success;
6951//-- }
6952//--
6953//-- /* 0xE4: PMULHUW(src)xmmreg-or-mem, (dst)xmmreg */
6954//-- /* 0xE5: PMULHW(src)xmmreg-or-mem, (dst)xmmreg */
6955//-- /* 0xD5: PMULLW(src)xmmreg-or-mem, (dst)xmmreg */
6956//-- if (sz == 2
6957//-- && insn[0] == 0x0F
6958//-- && (insn[1] == 0xE4 || insn[1] == 0xE5 || insn[1] == 0xD5)) {
6959//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmul{hu,h,l}w",
6960//-- 0x66, insn[0], insn[1] );
6961//-- goto decode_success;
6962//-- }
6963//--
6964//-- /* 0xD5: PMULUDQ(src)xmmreg-or-mem, (dst)xmmreg */
6965//-- if (sz == 2
6966//-- && insn[0] == 0x0F && insn[1] == 0xF4) {
6967//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmuludq",
6968//-- 0x66, insn[0], insn[1] );
6969//-- goto decode_success;
6970//-- }
6971//--
6972//-- /* 0xF5: PMADDWD(src)xmmreg-or-mem, (dst)xmmreg */
6973//-- if (sz == 2
6974//-- && insn[0] == 0x0F
6975//-- && insn[1] == 0xF5) {
6976//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmaddwd",
6977//-- 0x66, insn[0], insn[1] );
6978//-- goto decode_success;
6979//-- }
6980//--
6981//-- /* 0x74: PCMPEQB (src)xmmreg-or-mem, (dst)xmmreg */
6982//-- /* 0x75: PCMPEQW (src)xmmreg-or-mem, (dst)xmmreg */
6983//-- /* 0x76: PCMPEQD (src)xmmreg-or-mem, (dst)xmmreg */
6984//-- if (sz == 2
6985//-- && insn[0] == 0x0F
6986//-- && (insn[1] == 0x74 || insn[1] == 0x75 || insn[1] == 0x76)) {
6987//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pcmpeq{b,w,d}",
6988//-- 0x66, insn[0], insn[1] );
6989//-- goto decode_success;
6990//-- }
6991//--
6992//-- /* 0x64: PCMPGTB (src)xmmreg-or-mem, (dst)xmmreg */
6993//-- /* 0x65: PCMPGTW (src)xmmreg-or-mem, (dst)xmmreg */
6994//-- /* 0x66: PCMPGTD (src)xmmreg-or-mem, (dst)xmmreg */
6995//-- if (sz == 2
6996//-- && insn[0] == 0x0F
6997//-- && (insn[1] == 0x64 || insn[1] == 0x65 || insn[1] == 0x66)) {
6998//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pcmpgt{b,w,d}",
6999//-- 0x66, insn[0], insn[1] );
7000//-- goto decode_success;
7001//-- }
7002//--
7003//-- /* 0x63: PACKSSWB (src)xmmreg-or-mem, (dst)xmmreg */
7004//-- /* 0x6B: PACKSSDW (src)xmmreg-or-mem, (dst)xmmreg */
7005//-- if (sz == 2
7006//-- && insn[0] == 0x0F
7007//-- && (insn[1] == 0x63 || insn[1] == 0x6B)) {
7008//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "packss{wb,dw}",
7009//-- 0x66, insn[0], insn[1] );
7010//-- goto decode_success;
7011//-- }
7012//--
7013//-- /* 0x67: PACKUSWB (src)xmmreg-or-mem, (dst)xmmreg */
7014//-- if (sz == 2
7015//-- && insn[0] == 0x0F
7016//-- && insn[1] == 0x67) {
7017//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "packuswb",
7018//-- 0x66, insn[0], insn[1] );
7019//-- goto decode_success;
7020//-- }
7021//--
7022//-- /* 0xF1: PSLLW (src)xmmreg-or-mem, (dst)xmmreg */
7023//-- /* 0xF2: PSLLD (src)xmmreg-or-mem, (dst)xmmreg */
7024//-- /* 0xF3: PSLLQ (src)xmmreg-or-mem, (dst)xmmreg */
7025//-- if (sz == 2
7026//-- && insn[0] == 0x0F
7027//-- && (insn[1] == 0xF1 || insn[1] == 0xF2 || insn[1] == 0xF3)) {
7028//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psll{b,w,d}",
7029//-- 0x66, insn[0], insn[1] );
7030//-- goto decode_success;
7031//-- }
7032//--
7033//-- /* 0xD1: PSRLW (src)xmmreg-or-mem, (dst)xmmreg */
7034//-- /* 0xD2: PSRLD (src)xmmreg-or-mem, (dst)xmmreg */
7035//-- /* 0xD3: PSRLQ (src)xmmreg-or-mem, (dst)xmmreg */
7036//-- if (sz == 2
7037//-- && insn[0] == 0x0F
7038//-- && (insn[1] == 0xD1 || insn[1] == 0xD2 || insn[1] == 0xD3)) {
7039//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psrl{b,w,d}",
7040//-- 0x66, insn[0], insn[1] );
7041//-- goto decode_success;
7042//-- }
7043//--
7044//-- /* 0xE1: PSRAW (src)xmmreg-or-mem, (dst)xmmreg */
7045//-- /* 0xE2: PSRAD (src)xmmreg-or-mem, (dst)xmmreg */
7046//-- if (sz == 2
7047//-- && insn[0] == 0x0F
7048//-- && (insn[1] == 0xE1 || insn[1] == 0xE2)) {
7049//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psra{w,d}",
7050//-- 0x66, insn[0], insn[1] );
7051//-- goto decode_success;
7052//-- }
7053//--
7054//-- /* (U)COMISD (src)xmmreg-or-mem, (dst)xmmreg */
7055//-- if (sz == 2
7056//-- && insn[0] == 0x0F
7057//-- && ( insn[1] == 0x2E || insn[1] == 0x2F ) ) {
7058//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 8, "{u}comisd",
7059//-- 0x66, insn[0], insn[1] );
7060//-- vg_assert(LAST_UINSTR(cb).opcode == SSE3a_MemRd
7061//-- || LAST_UINSTR(cb).opcode == SSE4);
7062//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
7063//-- goto decode_success;
7064//-- }
7065//--
7066//-- /* (U)COMISS (src)xmmreg-or-mem, (dst)xmmreg */
7067//-- if (sz == 4
7068//-- && insn[0] == 0x0F
7069//-- && ( insn[1] == 0x2E || insn[ 1 ] == 0x2F )) {
7070//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 4, "{u}comiss",
7071//-- insn[0], insn[1] );
7072//-- vg_assert(LAST_UINSTR(cb).opcode == SSE2a_MemRd
7073//-- || LAST_UINSTR(cb).opcode == SSE3);
7074//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
7075//-- goto decode_success;
7076//-- }
7077//--
7078//-- /* MOVSD -- move 8 bytes of XMM reg to/from XMM reg or mem. */
7079//-- if (insn[0] == 0xF2
7080//-- && insn[1] == 0x0F
7081//-- && (insn[2] == 0x11 || insn[2] == 0x10)) {
7082//-- vg_assert(sz == 4);
7083//-- eip = dis_SSE3_load_store_or_mov
7084//-- ( cb, sorb, eip+3, 8, insn[2]==0x11, "movsd",
7085//-- insn[0], insn[1], insn[2] );
7086//-- goto decode_success;
7087//-- }
7088//--
7089//-- /* MOVQ -- move 8 bytes of XMM reg to XMM reg or mem. How
7090//-- does this differ from MOVSD ?? */
7091//-- if (sz == 2
7092//-- && insn[0] == 0x0F
7093//-- && insn[1] == 0xD6) {
7094//-- eip = dis_SSE3_load_store_or_mov
7095//-- ( cb, sorb, eip+2, 8, True /*store*/, "movq",
7096//-- 0x66, insn[0], insn[1] );
7097//-- goto decode_success;
7098//-- }
7099//--
7100//-- /* MOVQ -- move 8 bytes of XMM reg or mem to XMM reg. How
7101//-- does this differ from MOVSD ?? */
7102//-- if (insn[0] == 0xF3
7103//-- && insn[1] == 0x0F
7104//-- && insn[2] == 0x7E) {
7105//-- eip = dis_SSE3_load_store_or_mov
7106//-- ( cb, sorb, eip+3, 8, False /*load*/, "movq",
7107//-- insn[0], insn[1], insn[2] );
7108//-- goto decode_success;
7109//-- }
7110//--
7111//-- /* MOVDQ2Q -- move low 4 bytes of XMM reg to MMX reg. */
7112//-- if (insn[0] == 0xF2
7113//-- && insn[1] == 0x0F
7114//-- && insn[2] == 0xD6) {
7115//-- eip = dis_SSE3_to_MMX
7116//-- ( cb, sorb, eip+3, 8, "movdq2q",
7117//-- insn[0], insn[1], insn[2] );
7118//-- goto decode_success;
7119//-- }
7120//--
7121//-- /* MOVQ2DQ -- move MMX reg to low 4 bytes of XMM reg. */
7122//-- if (insn[0] == 0xF3
7123//-- && insn[1] == 0x0F
7124//-- && insn[2] == 0xD6) {
7125//-- eip = dis_SSE3_from_MMX
7126//-- ( cb, sorb, eip+3, 8, "movq2dq",
7127//-- insn[0], insn[1], insn[2] );
7128//-- goto decode_success;
7129//-- }
7130//--
7131//-- /* MOVSS -- move 4 bytes of XMM reg to/from XMM reg or mem. */
7132//-- if (insn[0] == 0xF3
7133//-- && insn[1] == 0x0F
7134//-- && (insn[2] == 0x11 || insn[2] == 0x10)) {
7135//-- vg_assert(sz == 4);
7136//-- eip = dis_SSE3_load_store_or_mov
7137//-- ( cb, sorb, eip+3, 4, insn[2]==0x11, "movss",
7138//-- insn[0], insn[1], insn[2] );
7139//-- goto decode_success;
7140//-- }
7141//--
7142//-- /* I don't understand how MOVAPD differs from MOVAPS. */
7143//-- /* MOVAPD (28,29) -- aligned load/store of xmm reg, or xmm-xmm reg
7144//-- move */
7145//-- if (sz == 2
7146//-- && insn[0] == 0x0F && insn[1] == 0x28) {
7147//-- UChar* name = "movapd";
7148//-- //(insn[1] == 0x10 || insn[1] == 0x11)
7149//-- // ? "movups" : "movaps";
7150//-- Bool store = False; //insn[1] == 0x29 || insn[1] == 11;
7151//-- eip = dis_SSE3_load_store_or_mov
7152//-- ( cb, sorb, eip+2, 16, store, name,
7153//-- 0x66, insn[0], insn[1] );
7154//-- goto decode_success;
7155//-- }
7156//--
7157//-- /* sz==4: MOVAPS (28,29) -- aligned load/store of xmm reg, or
7158//-- xmm-xmm reg move */
7159//-- /* sz==4: MOVUPS (10,11) -- unaligned load/store of xmm reg, or
7160//-- xmm-xmm reg move */
7161//-- /* sz==2: MOVAPD (28,29) -- aligned load/store of xmm reg, or
7162//-- xmm-xmm reg move */
7163//-- /* sz==2: MOVUPD (10,11) -- unaligned load/store of xmm reg, or
7164//-- xmm-xmm reg move */
7165//-- if (insn[0] == 0x0F && (insn[1] == 0x28
7166//-- || insn[1] == 0x29
7167//-- || insn[1] == 0x10
7168//-- || insn[1] == 0x11)) {
7169//-- UChar* name = (insn[1] == 0x10 || insn[1] == 0x11)
7170//-- ? "movups" : "movaps";
7171//-- Bool store = insn[1] == 0x29 || insn[1] == 11;
7172//-- vg_assert(sz == 2 || sz == 4);
7173//-- if (sz == 4) {
7174//-- eip = dis_SSE2_load_store_or_mov
7175//-- ( cb, sorb, eip+2, 16, store, name,
7176//-- insn[0], insn[1] );
7177//-- } else {
7178//-- eip = dis_SSE3_load_store_or_mov
7179//-- ( cb, sorb, eip+2, 16, store, name,
7180//-- 0x66, insn[0], insn[1] );
7181//-- }
7182//-- goto decode_success;
7183//-- }
7184//--
7185//-- /* MOVDQA -- aligned 16-byte load/store. */
7186//-- if (sz == 2
7187//-- && insn[0] == 0x0F
7188//-- && (insn[1] == 0x6F || insn[1] == 0x7F)) {
7189//-- Bool is_store = insn[1]==0x7F;
7190//-- eip = dis_SSE3_load_store_or_mov
7191//-- (cb, sorb, eip+2, 16, is_store, "movdqa",
7192//-- 0x66, insn[0], insn[1] );
7193//-- goto decode_success;
7194//-- }
7195//--
7196//-- /* MOVDQU -- unaligned 16-byte load/store. */
7197//-- if (insn[0] == 0xF3
7198//-- && insn[1] == 0x0F
7199//-- && (insn[2] == 0x6F || insn[2] == 0x7F)) {
7200//-- Bool is_store = insn[2]==0x7F;
7201//-- eip = dis_SSE3_load_store_or_mov
7202//-- (cb, sorb, eip+3, 16, is_store, "movdqu",
7203//-- insn[0], insn[1], insn[2] );
7204//-- goto decode_success;
7205//-- }
7206//--
7207//-- /* MOVNTDQ -- 16-byte store with temporal hint (which we
7208//-- ignore). */
7209//-- if (sz == 2
7210//-- && insn[0] == 0x0F
7211//-- && insn[1] == 0xE7) {
7212//-- eip = dis_SSE3_load_store_or_mov
7213//-- (cb, sorb, eip+2, 16, True /* is_store */, "movntdq",
7214//-- 0x66, insn[0], insn[1] );
7215//-- goto decode_success;
7216//-- }
7217//--
7218//-- /* MOVNTPS -- 16-byte store with temporal hint (which we
7219//-- ignore). */
7220//-- if (insn[0] == 0x0F
7221//-- && insn[1] == 0x2B) {
7222//-- eip = dis_SSE2_load_store_or_mov
7223//-- (cb, sorb, eip+2, 16, True /* is_store */, "movntps",
7224//-- insn[0], insn[1] );
7225//-- goto decode_success;
7226//-- }
7227//--
7228//-- /* MOVNTPD -- 16-byte store with temporal hint (which we
7229//-- ignore). */
7230//-- if (sz == 2
7231//-- && insn[0] == 0x0F
7232//-- && insn[1] == 0x2B) {
7233//-- eip = dis_SSE3_load_store_or_mov
7234//-- (cb, sorb, eip+2, 16, True /* is_store */, "movntpd",
7235//-- 0x66, insn[0], insn[1] );
7236//-- goto decode_success;
7237//-- }
7238//--
7239//-- /* MOVD -- 4-byte move between xmmregs and (ireg or memory). */
7240//-- if (sz == 2
7241//-- && insn[0] == 0x0F
7242//-- && (insn[1] == 0x6E || insn[1] == 0x7E)) {
7243//-- Bool is_store = insn[1]==0x7E;
7244//-- modrm = insn[2];
7245//-- if (epartIsReg(modrm) && is_store) {
7246//-- t1 = newTemp(cb);
7247//-- uInstr3(cb, SSE3e_RegWr, 4,
7248//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
7249//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
7250//-- TempReg, t1 );
7251//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, eregOfRM(modrm));
7252//-- DIP("movd %s, %s\n",
7253//-- nameXMMReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
7254//-- eip += 3;
7255//-- } else
7256//-- if (epartIsReg(modrm) && !is_store) {
7257//-- t1 = newTemp(cb);
7258//-- uInstr2(cb, GET, 4, ArchReg, eregOfRM(modrm), TempReg, t1);
7259//-- uInstr3(cb, SSE3e_RegRd, 4,
7260//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
7261//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
7262//-- TempReg, t1 );
7263//-- DIP("movd %s, %s\n",
7264//-- nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
7265//-- eip += 3;
7266//-- } else {
7267//-- eip = dis_SSE3_load_store_or_mov
7268//-- (cb, sorb, eip+2, 4, is_store, "movd",
7269//-- 0x66, insn[0], insn[1] );
7270//-- }
7271//-- goto decode_success;
7272//-- }
7273//--
7274//-- /* PEXTRW from SSE register; writes ireg */
7275//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC5) {
7276//-- t1 = newTemp(cb);
7277//-- modrm = insn[2];
7278//-- vg_assert(epartIsReg(modrm));
7279//-- vg_assert((modrm & 0xC0) == 0xC0);
7280//-- uInstr3(cb, SSE3g1_RegWr, 4,
7281//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
7282//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
7283//-- TempReg, t1 );
7284//-- uLiteral(cb, insn[3]);
7285//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
7286//-- DIP("pextrw %s, %d, %s\n",
7287//-- nameXMMReg(eregOfRM(modrm)), (Int)insn[3],
7288//-- nameIReg(4, gregOfRM(modrm)));
7289//-- eip += 4;
7290//-- goto decode_success;
7291//-- }
7292//--
7293//-- /* PINSRW to SSE register; reads mem or ireg */
7294//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC4) {
7295//-- t1 = newTemp(cb);
7296//-- modrm = insn[2];
7297//-- if (epartIsReg(modrm)) {
7298//-- uInstr2(cb, GET, 2, ArchReg, eregOfRM(modrm), TempReg, t1);
7299//-- vg_assert(epartIsReg(modrm));
7300//-- uInstr3(cb, SSE3e1_RegRd, 2,
7301//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
7302//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
7303//-- TempReg, t1 );
7304//-- uLiteral(cb, insn[3]);
7305//-- DIP("pinsrw %s, %d, %s\n",
7306//-- nameIReg(2, eregOfRM(modrm)), (Int)insn[3],
7307//-- nameXMMReg(gregOfRM(modrm)));
7308//-- eip += 4;
7309//-- } else {
7310//-- VG_(core_panic)("PINSRW mem");
7311//-- }
7312//-- goto decode_success;
7313//-- }
7314//--
7315//-- /* SQRTSD: square root of scalar double. */
7316//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x51) {
7317//-- vg_assert(sz == 4);
7318//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8,
7319//-- "sqrtsd",
7320//-- insn[0], insn[1], insn[2] );
7321//-- goto decode_success;
7322//-- }
7323//--
7324//-- /* SQRTSS: square root of scalar float. */
7325//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x51) {
7326//-- vg_assert(sz == 4);
7327//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4,
7328//-- "sqrtss",
7329//-- insn[0], insn[1], insn[2] );
7330//-- goto decode_success;
7331//-- }
7332//--
7333//-- /* RSQRTSS: square root reciprocal of scalar float. */
7334//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x52) {
7335//-- vg_assert(sz == 4);
7336//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4,
7337//-- "sqrtss",
7338//-- insn[0], insn[1], insn[2] );
7339//-- goto decode_success;
7340//-- }
7341//--
7342//-- /* 0xF3: RCPSS -- reciprocal of scalar float */
7343//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x53) {
7344//-- vg_assert(sz == 4);
7345//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4,
7346//-- "rcpss",
7347//-- insn[0], insn[1], insn[2] );
7348//-- goto decode_success;
7349//-- }
7350//--
7351//-- /* MOVMSKPD -- extract 2 sign bits from a xmm reg and copy them to
7352//-- an ireg. Top 30 bits of ireg are set to zero. */
7353//-- /* MOVMSKPS -- extract 4 sign bits from a xmm reg and copy them to
7354//-- an ireg. Top 28 bits of ireg are set to zero. */
7355//-- if (insn[0] == 0x0F && insn[1] == 0x50) {
7356//-- vg_assert(sz == 4 || sz == 2);
7357//-- modrm = insn[2];
7358//-- /* Intel docs don't say anything about a memory source being
7359//-- allowed here. */
7360//-- vg_assert(epartIsReg(modrm));
7361//-- t1 = newTemp(cb);
7362//-- if (sz == 4) {
7363//-- uInstr3(cb, SSE2g_RegWr, 4,
7364//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
7365//-- Lit16, (UShort)modrm,
7366//-- TempReg, t1 );
7367//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
7368//-- } else {
7369//-- uInstr3(cb, SSE3g_RegWr, 4,
7370//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
7371//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
7372//-- TempReg, t1 );
7373//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
7374//-- }
7375//-- DIP("movmskp%c %s, %s\n", sz == 4 ? 's' : 'd',
7376//-- nameXMMReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)));
7377//-- eip += 3;
7378//-- goto decode_success;
7379//-- }
7380//--
7381//-- /* ANDNPS */
7382//-- /* 0x66: ANDNPD (src)xmmreg-or-mem, (dst)xmmreg */
7383//-- if (insn[0] == 0x0F && insn[1] == 0x55) {
7384//-- vg_assert(sz == 4 || sz == 2);
7385//-- if (sz == 4) {
7386//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "andnps",
7387//-- insn[0], insn[1] );
7388//-- } else {
7389//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "andnpd",
7390//-- 0x66, insn[0], insn[1] );
7391//-- }
7392//-- goto decode_success;
7393//-- }
7394//--
7395//-- /* MOVHLPS -- move two packed floats from high quadword to low quadword */
7396//-- /* MOVLPS -- load/store two packed floats to/from low quadword. */
7397//-- /* MOVLPD -- load/store packed double to/from low quadword. */
7398//-- if (insn[0] == 0x0F
7399//-- && (insn[1] == 0x12 || insn[1] == 0x13)) {
7400//-- Bool is_store = insn[1]==0x13;
7401//-- vg_assert(sz == 4 || sz == 2);
7402//-- if (sz == 4) {
7403//-- if (epartIsReg(insn[2])) {
7404//-- vg_assert(insn[1]==0x12);
7405//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "movhlps",
7406//-- insn[0], insn[1] );
7407//-- } else {
7408//-- eip = dis_SSE2_load_store_or_mov
7409//-- (cb, sorb, eip+2, 8, is_store, "movlps",
7410//-- insn[0], insn[1] );
7411//-- }
7412//-- } else {
7413//-- vg_assert(!epartIsReg(insn[2]));
7414//-- eip = dis_SSE3_load_store_or_mov
7415//-- (cb, sorb, eip+2, 8, is_store, "movlpd",
7416//-- 0x66, insn[0], insn[1] );
7417//-- }
7418//-- goto decode_success;
7419//-- }
7420//--
7421//-- /* MOVLHPS -- move two packed floats from low quadword to high quadword */
7422//-- /* MOVHPS -- load/store two packed floats to/from high quadword. */
7423//-- /* MOVHPD -- load/store packed double to/from high quadword. */
7424//-- if (insn[0] == 0x0F
7425//-- && (insn[1] == 0x16 || insn[1] == 0x17)) {
7426//-- Bool is_store = insn[1]==0x17;
7427//-- vg_assert(sz == 4 || sz == 2);
7428//-- if (sz == 4) {
7429//-- if (epartIsReg(insn[2])) {
7430//-- vg_assert(insn[1]==0x16);
7431//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "movlhps",
7432//-- insn[0], insn[1] );
7433//-- } else {
7434//-- eip = dis_SSE2_load_store_or_mov
7435//-- (cb, sorb, eip+2, 8, is_store, "movhps",
7436//-- insn[0], insn[1] );
7437//-- }
7438//-- } else {
7439//-- vg_assert(!epartIsReg(insn[2]));
7440//-- eip = dis_SSE3_load_store_or_mov
7441//-- (cb, sorb, eip+2, 8, is_store, "movhpd",
7442//-- 0x66, insn[0], insn[1] );
7443//-- }
7444//-- goto decode_success;
7445//-- }
7446//--
7447//-- /* PMOVMSKB -- extract 16 sign bits from a xmm reg and copy them to
7448//-- an ireg. Top 16 bits of ireg are set to zero. */
7449//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD7) {
7450//-- modrm = insn[2];
7451//-- /* Intel docs don't say anything about a memory source being
7452//-- allowed here. */
7453//-- vg_assert(epartIsReg(modrm));
7454//-- t1 = newTemp(cb);
7455//-- uInstr3(cb, SSE3g_RegWr, 4,
7456//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
7457//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
7458//-- TempReg, t1 );
7459//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
7460//-- DIP("pmovmskb %s, %s\n",
7461//-- nameXMMReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)));
7462//-- eip += 3;
7463//-- goto decode_success;
7464//-- }
7465//--
7466//-- /* sz==4: SQRTPS: square root of packed float. */
7467//-- /* sz==2: SQRTPD: square root of packed double. */
7468//-- if (insn[0] == 0x0F && insn[1] == 0x51) {
7469//-- vg_assert(sz == 2 || sz == 4);
7470//-- if (sz == 4) {
7471//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16,
7472//-- "sqrtps",
7473//-- insn[0], insn[1] );
7474//-- } else {
7475//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16,
7476//-- "sqrtpd",
7477//-- 0x66, insn[0], insn[1] );
7478//-- }
7479//-- goto decode_success;
7480//-- }
7481//--
7482//-- /* RSQRTPS: square root reciprocal of packed float. */
7483//-- if (insn[0] == 0x0F && insn[1] == 0x52) {
7484//-- vg_assert(sz == 4);
7485//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16,
7486//-- "rsqrtps",
7487//-- insn[0], insn[1] );
7488//-- goto decode_success;
7489//-- }
7490//--
7491//-- /* Fall through into the non-SSE decoder. */
7492//--
7493//-- } /* if (VG_(have_ssestate)) */
7494
7495
7496 /* ---------------------------------------------------- */
7497 /* --- end of the SSE/SSE2 decoder. --- */
7498 /* ---------------------------------------------------- */
7499
7500 /* Get the primary opcode. */
7501 opc = getIByte(delta); delta++;
7502
7503 /* We get here if the current insn isn't SSE, or this CPU doesn't
7504 support SSE. */
7505
7506 switch (opc) {
7507
7508 /* ------------------------ Control flow --------------- */
sewardj940e8c92004-07-11 16:53:24 +00007509
7510 case 0xC2: /* RET imm16 */
7511 d32 = getUDisp16(delta);
7512 delta += 2;
7513 dis_ret(d32);
sewardjce70a5c2004-10-18 14:09:54 +00007514 whatNext = Dis_StopHere;
sewardj940e8c92004-07-11 16:53:24 +00007515 DIP("ret %d\n", d32);
7516 break;
sewardje05c42c2004-07-08 20:25:10 +00007517 case 0xC3: /* RET */
7518 dis_ret(0);
sewardjce70a5c2004-10-18 14:09:54 +00007519 whatNext = Dis_StopHere;
sewardje05c42c2004-07-08 20:25:10 +00007520 DIP("ret\n");
7521 break;
sewardjd1061ab2004-07-08 01:45:30 +00007522
7523 case 0xE8: /* CALL J4 */
7524 d32 = getUDisp32(delta); delta += 4;
sewardjce70a5c2004-10-18 14:09:54 +00007525 d32 += (guest_eip_bbstart+delta);
7526 /* (guest_eip_bbstart+delta) == return-to addr, d32 == call-to addr */
7527 if (d32 == guest_eip_bbstart+delta && getIByte(delta) >= 0x58
7528 && getIByte(delta) <= 0x5F) {
sewardjd1061ab2004-07-08 01:45:30 +00007529 /* Specially treat the position-independent-code idiom
7530 call X
7531 X: popl %reg
7532 as
7533 movl %eip, %reg.
7534 since this generates better code, but for no other reason. */
7535 Int archReg = getIByte(delta) - 0x58;
sewardjc2ac51e2004-07-12 01:03:26 +00007536 /* vex_printf("-- fPIC thingy\n"); */
sewardjce70a5c2004-10-18 14:09:54 +00007537 putIReg(4, archReg, mkU32(guest_eip_bbstart+delta));
sewardjd1061ab2004-07-08 01:45:30 +00007538 delta++; /* Step over the POP */
7539 DIP("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
sewardjc2ac51e2004-07-12 01:03:26 +00007540 } else {
sewardjd1061ab2004-07-08 01:45:30 +00007541 /* The normal sequence for a call. */
7542 t1 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +00007543 assign(t1, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
7544 putIReg(4, R_ESP, mkexpr(t1));
sewardjce70a5c2004-10-18 14:09:54 +00007545 storeLE( mkexpr(t1), mkU32(guest_eip_bbstart+delta));
7546 if (resteerOK) {
7547 /* follow into the call target. */
7548 whatNext = Dis_Resteer;
7549 *whereNext = d32;
7550 } else {
7551 jmp_lit(Ijk_Call,d32);
7552 whatNext = Dis_StopHere;
7553 }
sewardjd1061ab2004-07-08 01:45:30 +00007554 DIP("call 0x%x\n",d32);
7555 }
7556 break;
7557
sewardjc9a65702004-07-07 16:32:57 +00007558//-- case 0xC8: /* ENTER */
7559//-- d32 = getUDisp16(eip); eip += 2;
7560//-- abyte = getIByte(delta); delta++;
7561//--
7562//-- vg_assert(sz == 4);
7563//-- vg_assert(abyte == 0);
7564//--
7565//-- t1 = newTemp(cb); t2 = newTemp(cb);
7566//-- uInstr2(cb, GET, sz, ArchReg, R_EBP, TempReg, t1);
7567//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
7568//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
7569//-- uLiteral(cb, sz);
7570//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
7571//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
7572//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
7573//-- if (d32) {
7574//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
7575//-- uLiteral(cb, d32);
7576//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
7577//-- }
7578//-- DIP("enter 0x%x, 0x%x", d32, abyte);
7579//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +00007580
7581 case 0xC9: /* LEAVE */
7582 vassert(sz == 4);
7583 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
7584 assign(t1, getIReg(4,R_EBP));
7585 /* First PUT ESP looks redundant, but need it because ESP must
7586 always be up-to-date for Memcheck to work... */
7587 putIReg(4, R_ESP, mkexpr(t1));
7588 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
7589 putIReg(4, R_EBP, mkexpr(t2));
7590 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(4)) );
7591 DIP("leave\n");
7592 break;
7593
sewardjc9a65702004-07-07 16:32:57 +00007594//-- /* ---------------- Misc weird-ass insns --------------- */
7595//--
7596//-- case 0x27: /* DAA */
7597//-- case 0x2F: /* DAS */
7598//-- t1 = newTemp(cb);
7599//-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
7600//-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
7601//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
7602//-- uWiden(cb, 1, False);
7603//-- uInstr0(cb, CALLM_S, 0);
7604//-- uInstr1(cb, PUSH, 4, TempReg, t1);
7605//-- uInstr1(cb, CALLM, 0, Lit16,
7606//-- opc == 0x27 ? VGOFF_(helper_DAA) : VGOFF_(helper_DAS) );
7607//-- uFlagsRWU(cb, FlagsAC, FlagsSZACP, FlagO);
7608//-- uInstr1(cb, POP, 4, TempReg, t1);
7609//-- uInstr0(cb, CALLM_E, 0);
7610//-- uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
7611//-- DIP(opc == 0x27 ? "daa\n" : "das\n");
7612//-- break;
7613//--
7614//-- case 0x37: /* AAA */
7615//-- case 0x3F: /* AAS */
7616//-- t1 = newTemp(cb);
7617//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
7618//-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
7619//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
7620//-- uWiden(cb, 2, False);
7621//-- uInstr0(cb, CALLM_S, 0);
7622//-- uInstr1(cb, PUSH, 4, TempReg, t1);
7623//-- uInstr1(cb, CALLM, 0, Lit16,
7624//-- opc == 0x37 ? VGOFF_(helper_AAA) : VGOFF_(helper_AAS) );
7625//-- uFlagsRWU(cb, FlagA, FlagsAC, FlagsEmpty);
7626//-- uInstr1(cb, POP, 4, TempReg, t1);
7627//-- uInstr0(cb, CALLM_E, 0);
7628//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
7629//-- DIP(opc == 0x37 ? "aaa\n" : "aas\n");
7630//-- break;
7631//--
7632//-- case 0xD4: /* AAM */
7633//-- case 0xD5: /* AAD */
7634//-- d32 = getIByte(delta); delta++;
7635//-- if (d32 != 10) VG_(core_panic)("disInstr: AAM/AAD but base not 10 !");
7636//-- t1 = newTemp(cb);
7637//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
7638//-- /* Widen %AX to 32 bits, so it's all defined when we push it. */
7639//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
7640//-- uWiden(cb, 2, False);
7641//-- uInstr0(cb, CALLM_S, 0);
7642//-- uInstr1(cb, PUSH, 4, TempReg, t1);
7643//-- uInstr1(cb, CALLM, 0, Lit16,
7644//-- opc == 0xD4 ? VGOFF_(helper_AAM) : VGOFF_(helper_AAD) );
7645//-- uFlagsRWU(cb, FlagsEmpty, FlagsSZP, FlagsEmpty);
7646//-- uInstr1(cb, POP, 4, TempReg, t1);
7647//-- uInstr0(cb, CALLM_E, 0);
7648//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
7649//-- DIP(opc == 0xD4 ? "aam\n" : "aad\n");
7650//-- break;
sewardj1c6f9912004-09-07 10:15:24 +00007651
7652 /* ------------------------ CWD/CDQ -------------------- */
7653
7654 case 0x98: /* CBW */
7655 if (sz == 4) {
7656 putIReg(4, R_EAX, unop(Iop_16Sto32, getIReg(2, R_EAX)));
7657 DIP("cwde\n");
7658 } else {
sewardj47341042004-09-19 11:55:46 +00007659 vassert(sz == 2);
7660 putIReg(2, R_EAX, unop(Iop_8Sto16, getIReg(1, R_EAX)));
7661 DIP("cbw\n");
sewardj1c6f9912004-09-07 10:15:24 +00007662 }
7663 break;
sewardj64e1d652004-07-12 14:00:46 +00007664
7665 case 0x99: /* CWD/CDQ */
7666 ty = szToITy(sz);
7667 putIReg(sz, R_EDX,
7668 binop(mkSizedOp(ty,Iop_Sar8),
7669 getIReg(sz, R_EAX),
sewardj6d2638e2004-07-15 09:38:27 +00007670 mkU8(sz == 2 ? 15 : 31)) );
sewardj64e1d652004-07-12 14:00:46 +00007671 DIP(sz == 2 ? "cwdq\n" : "cdqq\n");
7672 break;
7673
sewardjbdc7d212004-09-09 02:46:40 +00007674 /* ------------------------ FPU ops -------------------- */
7675
7676 case 0x9E: /* SAHF */
7677 codegen_SAHF();
7678 DIP("sahf\n");
7679 break;
7680
sewardjc9a65702004-07-07 16:32:57 +00007681//-- case 0x9F: /* LAHF */
7682//-- codegen_LAHF ( cb );
7683//-- DIP("lahf\n");
7684//-- break;
7685//--
sewardjbdc7d212004-09-09 02:46:40 +00007686 case 0x9B: /* FWAIT */
7687 /* ignore? */
7688 DIP("fwait\n");
7689 break;
7690
sewardjd1725d12004-08-12 20:46:53 +00007691 case 0xD8:
7692 case 0xD9:
7693 case 0xDA:
7694 case 0xDB:
7695 case 0xDC:
7696 case 0xDD:
7697 case 0xDE:
7698 case 0xDF: {
7699 UInt delta0 = delta;
7700 Bool decode_OK = False;
7701 delta = dis_FPU ( &decode_OK, sorb, delta );
7702 if (!decode_OK) {
7703 delta = delta0;
7704 goto decode_failure;
7705 }
7706 break;
7707 }
sewardj0611d802004-07-11 02:37:54 +00007708
7709 /* ------------------------ INC & DEC ------------------ */
7710
7711 case 0x40: /* INC eAX */
7712 case 0x41: /* INC eCX */
7713 case 0x42: /* INC eDX */
7714 case 0x43: /* INC eBX */
7715 case 0x44: /* INC eSP */
7716 case 0x45: /* INC eBP */
7717 case 0x46: /* INC eSI */
7718 case 0x47: /* INC eDI */
7719 vassert(sz == 2 || sz == 4);
7720 ty = szToITy(sz);
7721 t1 = newTemp(ty);
7722 assign( t1, binop(mkSizedOp(ty,Iop_Add8),
7723 getIReg(sz, (UInt)(opc - 0x40)),
7724 mkU(ty,1)) );
7725 setFlags_INC_DEC( True, t1, ty );
7726 putIReg(sz, (UInt)(opc - 0x40), mkexpr(t1));
7727 DIP("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
7728 break;
7729
7730 case 0x48: /* DEC eAX */
7731 case 0x49: /* DEC eCX */
7732 case 0x4A: /* DEC eDX */
7733 case 0x4B: /* DEC eBX */
7734 case 0x4C: /* DEC eSP */
7735 case 0x4D: /* DEC eBP */
7736 case 0x4E: /* DEC eSI */
7737 case 0x4F: /* DEC eDI */
7738 vassert(sz == 2 || sz == 4);
7739 ty = szToITy(sz);
7740 t1 = newTemp(ty);
7741 assign( t1, binop(mkSizedOp(ty,Iop_Sub8),
7742 getIReg(sz, (UInt)(opc - 0x48)),
7743 mkU(ty,1)) );
7744 setFlags_INC_DEC( False, t1, ty );
7745 putIReg(sz, (UInt)(opc - 0x48), mkexpr(t1));
7746 DIP("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
7747 break;
7748
7749 /* ------------------------ INT ------------------------ */
7750
7751 case 0xCD: /* INT imm8 */
7752 d32 = getIByte(delta); delta++;
7753 if (d32 != 0x80) goto decode_failure;
7754 /* It's important that all ArchRegs carry their up-to-date value
7755 at this point. So we declare an end-of-block here, which
7756 forces any TempRegs caching ArchRegs to be flushed. */
sewardj4fd30f22004-10-25 00:42:16 +00007757 jmp_lit(Ijk_Syscall,((Addr32)guest_eip_bbstart)+delta);
sewardjce70a5c2004-10-18 14:09:54 +00007758 whatNext = Dis_StopHere;
sewardj0611d802004-07-11 02:37:54 +00007759 DIP("int $0x80\n");
7760 break;
7761
sewardj77b86be2004-07-11 13:28:24 +00007762 /* ------------------------ Jcond, byte offset --------- */
7763
7764 case 0xEB: /* Jb (jump, byte offset) */
sewardj4fd30f22004-10-25 00:42:16 +00007765 d32 = (((Addr32)guest_eip_bbstart)+delta+1) + getSDisp8(delta);
sewardj77b86be2004-07-11 13:28:24 +00007766 delta++;
sewardjce70a5c2004-10-18 14:09:54 +00007767 if (resteerOK) {
7768 whatNext = Dis_Resteer;
7769 *whereNext = d32;
7770 } else {
7771 jmp_lit(Ijk_Boring,d32);
7772 whatNext = Dis_StopHere;
7773 }
sewardj77b86be2004-07-11 13:28:24 +00007774 DIP("jmp-8 0x%x\n", d32);
7775 break;
sewardj0611d802004-07-11 02:37:54 +00007776
7777 case 0xE9: /* Jv (jump, 16/32 offset) */
7778 vassert(sz == 4); /* JRS added 2004 July 11 */
sewardj4fd30f22004-10-25 00:42:16 +00007779 d32 = (((Addr32)guest_eip_bbstart)+delta+sz) + getSDisp(sz,delta);
sewardj0611d802004-07-11 02:37:54 +00007780 delta += sz;
sewardjce70a5c2004-10-18 14:09:54 +00007781 if (resteerOK) {
7782 whatNext = Dis_Resteer;
7783 *whereNext = d32;
7784 } else {
7785 jmp_lit(Ijk_Boring,d32);
7786 whatNext = Dis_StopHere;
7787 }
sewardj0611d802004-07-11 02:37:54 +00007788 DIP("jmp 0x%x\n", d32);
7789 break;
sewardje87b4842004-07-10 12:23:30 +00007790
7791 case 0x70:
7792 case 0x71:
7793 case 0x72: /* JBb/JNAEb (jump below) */
7794 case 0x73: /* JNBb/JAEb (jump not below) */
7795 case 0x74: /* JZb/JEb (jump zero) */
7796 case 0x75: /* JNZb/JNEb (jump not zero) */
7797 case 0x76: /* JBEb/JNAb (jump below or equal) */
7798 case 0x77: /* JNBEb/JAb (jump not below or equal) */
7799 case 0x78: /* JSb (jump negative) */
7800 case 0x79: /* JSb (jump not negative) */
7801 case 0x7A: /* JP (jump parity even) */
7802 case 0x7B: /* JNP/JPO (jump parity odd) */
7803 case 0x7C: /* JLb/JNGEb (jump less) */
7804 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
7805 case 0x7E: /* JLEb/JNGb (jump less or equal) */
7806 case 0x7F: /* JGb/JNLEb (jump greater) */
sewardj4fd30f22004-10-25 00:42:16 +00007807 d32 = (((Addr32)guest_eip_bbstart)+delta+1) + getSDisp8(delta);
sewardje87b4842004-07-10 12:23:30 +00007808 delta++;
sewardj4fd30f22004-10-25 00:42:16 +00007809 jcc_01((Condcode)(opc - 0x70), (Addr32)(guest_eip_bbstart+delta), d32);
sewardjce70a5c2004-10-18 14:09:54 +00007810 whatNext = Dis_StopHere;
sewardje87b4842004-07-10 12:23:30 +00007811 DIP("j%s-8 0x%x\n", name_Condcode(opc - 0x70), d32);
7812 break;
7813
sewardj458a6f82004-08-25 12:46:02 +00007814 case 0xE3: /* JECXZ or perhaps JCXZ, depending on OSO ? Intel
7815 manual says it depends on address size override,
7816 which doesn't sound right to me. */
7817 vassert(sz==4); /* possibly also OK for sz==2 */
sewardj4fd30f22004-10-25 00:42:16 +00007818 d32 = (((Addr32)guest_eip_bbstart)+delta+1) + getSDisp8(delta);
sewardj458a6f82004-08-25 12:46:02 +00007819 delta++;
7820 ty = szToITy(sz);
7821 stmt( IRStmt_Exit(
7822 binop(mkSizedOp(ty,Iop_CmpEQ8),
7823 getIReg(sz,R_ECX),
7824 mkU(ty,0)),
7825 IRConst_U32(d32))
7826 );
7827
7828 DIP("j%sz 0x%x\n", nameIReg(sz, R_ECX), d32);
7829 break;
7830
sewardjc9a65702004-07-07 16:32:57 +00007831//-- case 0xE0: /* LOOPNE disp8 */
7832//-- case 0xE1: /* LOOPE disp8 */
7833//-- case 0xE2: /* LOOP disp8 */
7834//-- /* Again, the docs say this uses ECX/CX as a count depending on
7835//-- the address size override, not the operand one. Since we
7836//-- don't handle address size overrides, I guess that means
7837//-- ECX. */
7838//-- d32 = (eip+1) + getSDisp8(eip); eip++;
7839//-- t1 = newTemp(cb);
7840//-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
7841//-- uInstr1(cb, DEC, 4, TempReg, t1);
7842//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ECX);
7843//-- uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
7844//-- uLiteral(cb, eip);
7845//-- if (opc == 0xE0 || opc == 0xE1) { /* LOOPE/LOOPNE */
7846//-- jcc_lit(cb, eip, (opc == 0xE1 ? CondNZ : CondZ));
7847//-- }
7848//-- jmp_lit(cb, d32);
sewardjce70a5c2004-10-18 14:09:54 +00007849//-- whatNext = Dis_StopHere;
sewardjc9a65702004-07-07 16:32:57 +00007850//-- DIP("loop 0x%x\n", d32);
7851//-- break;
sewardj1813dbe2004-07-28 17:09:04 +00007852
7853 /* ------------------------ IMUL ----------------------- */
7854
7855 case 0x69: /* IMUL Iv, Ev, Gv */
7856 delta = dis_imul_I_E_G ( sorb, sz, delta, sz );
7857 break;
7858 case 0x6B: /* IMUL Ib, Ev, Gv */
7859 delta = dis_imul_I_E_G ( sorb, sz, delta, 1 );
7860 break;
sewardj0611d802004-07-11 02:37:54 +00007861
7862 /* ------------------------ MOV ------------------------ */
7863
7864 case 0x88: /* MOV Gb,Eb */
7865 delta = dis_mov_G_E(sorb, 1, delta);
7866 break;
sewardjc9a65702004-07-07 16:32:57 +00007867
7868 case 0x89: /* MOV Gv,Ev */
7869 delta = dis_mov_G_E(sorb, sz, delta);
7870 break;
7871
sewardjc2ac51e2004-07-12 01:03:26 +00007872 case 0x8A: /* MOV Eb,Gb */
7873 delta = dis_mov_E_G(sorb, 1, delta);
7874 break;
sewardje05c42c2004-07-08 20:25:10 +00007875
7876 case 0x8B: /* MOV Ev,Gv */
7877 delta = dis_mov_E_G(sorb, sz, delta);
7878 break;
7879
sewardje87b4842004-07-10 12:23:30 +00007880 case 0x8D: /* LEA M,Gv */
sewardje05c42c2004-07-08 20:25:10 +00007881 vassert(sz == 4);
7882 modrm = getIByte(delta);
7883 if (epartIsReg(modrm))
7884 vpanic("LEA M,Gv: modRM refers to register (x86)");
7885 /* NOTE! this is the one place where a segment override prefix
7886 has no effect on the address calculation. Therefore we pass
7887 zero instead of sorb here. */
sewardje87b4842004-07-10 12:23:30 +00007888 addr = disAMode ( &alen, /*sorb*/ 0, delta, dis_buf );
7889 delta += alen;
sewardj940e8c92004-07-11 16:53:24 +00007890 putIReg(sz, gregOfRM(modrm), mkexpr(addr));
sewardje05c42c2004-07-08 20:25:10 +00007891 DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
7892 nameIReg(sz,gregOfRM(modrm)));
7893 break;
sewardje05c42c2004-07-08 20:25:10 +00007894
sewardj063f02f2004-10-20 12:36:12 +00007895 case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
7896 delta = dis_mov_Sw_Ew(sorb, sz, delta);
7897 break;
7898
sewardjc9a65702004-07-07 16:32:57 +00007899//-- case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
7900//-- eip = dis_mov_Ew_Sw(cb, sorb, eip);
7901//-- break;
7902//--
sewardj43852812004-10-16 23:10:08 +00007903 case 0xA0: /* MOV Ob,AL */
7904 sz = 1;
7905 /* Fall through ... */
sewardj0c12ea82004-07-12 08:18:16 +00007906 case 0xA1: /* MOV Ov,eAX */
7907 d32 = getUDisp32(delta); delta += 4;
7908 ty = szToITy(sz);
7909 addr = newTemp(Ity_I32);
7910 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
7911 putIReg(sz, R_EAX, loadLE(ty, mkexpr(addr)));
7912 DIP("mov%c %s0x%x, %s\n", nameISize(sz), sorbTxt(sorb),
7913 d32, nameIReg(sz,R_EAX));
7914 break;
7915
sewardj180e8b32004-07-29 01:40:11 +00007916 case 0xA2: /* MOV Ob,AL */
7917 sz = 1;
7918 /* Fall through ... */
sewardj750f4072004-07-26 22:39:11 +00007919 case 0xA3: /* MOV eAX,Ov */
7920 d32 = getUDisp32(delta); delta += 4;
7921 ty = szToITy(sz);
7922 addr = newTemp(Ity_I32);
7923 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
7924 storeLE( mkexpr(addr), getIReg(sz,R_EAX) );
7925 DIP("mov%c %s, %s0x%x\n", nameISize(sz), nameIReg(sz,R_EAX),
7926 sorbTxt(sorb), d32);
7927 break;
sewardje87b4842004-07-10 12:23:30 +00007928
sewardjc2ac51e2004-07-12 01:03:26 +00007929 case 0xB0: /* MOV imm,AL */
7930 case 0xB1: /* MOV imm,CL */
7931 case 0xB2: /* MOV imm,DL */
7932 case 0xB3: /* MOV imm,BL */
7933 case 0xB4: /* MOV imm,AH */
7934 case 0xB5: /* MOV imm,CH */
7935 case 0xB6: /* MOV imm,DH */
7936 case 0xB7: /* MOV imm,BH */
7937 d32 = getIByte(delta); delta += 1;
7938 putIReg(1, opc-0xB0, mkU8(d32));
7939 DIP("movb $0x%x,%s\n", d32, nameIReg(1,opc-0xB0));
7940 break;
sewardj7ed22952004-07-29 00:09:58 +00007941
sewardje87b4842004-07-10 12:23:30 +00007942 case 0xB8: /* MOV imm,eAX */
7943 case 0xB9: /* MOV imm,eCX */
7944 case 0xBA: /* MOV imm,eDX */
7945 case 0xBB: /* MOV imm,eBX */
7946 case 0xBC: /* MOV imm,eSP */
7947 case 0xBD: /* MOV imm,eBP */
7948 case 0xBE: /* MOV imm,eSI */
7949 case 0xBF: /* MOV imm,eDI */
7950 d32 = getUDisp(sz,delta); delta += sz;
7951 putIReg(sz, opc-0xB8, mkU(szToITy(sz), d32));
7952 DIP("mov%c $0x%x,%s\n", nameISize(sz), d32, nameIReg(sz,opc-0xB8));
7953 break;
7954
sewardj77b86be2004-07-11 13:28:24 +00007955 case 0xC6: /* MOV Ib,Eb */
7956 sz = 1;
7957 goto do_Mov_I_E;
sewardje87b4842004-07-10 12:23:30 +00007958 case 0xC7: /* MOV Iv,Ev */
7959 goto do_Mov_I_E;
7960
7961 do_Mov_I_E:
7962 modrm = getIByte(delta);
7963 if (epartIsReg(modrm)) {
7964 delta++; /* mod/rm byte */
7965 d32 = getUDisp(sz,delta); delta += sz;
7966 putIReg(sz, eregOfRM(modrm), mkU(szToITy(sz), d32));
7967 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32,
7968 nameIReg(sz,eregOfRM(modrm)));
7969 vassert(0);
7970 } else {
7971 addr = disAMode ( &alen, sorb, delta, dis_buf );
7972 delta += alen;
7973 d32 = getUDisp(sz,delta); delta += sz;
sewardj940e8c92004-07-11 16:53:24 +00007974 storeLE(mkexpr(addr), mkU(szToITy(sz), d32));
sewardje87b4842004-07-10 12:23:30 +00007975 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
7976 }
7977 break;
7978
sewardj1813dbe2004-07-28 17:09:04 +00007979 /* ------------------------ opl imm, A ----------------- */
7980
7981 case 0x04: /* ADD Ib, AL */
7982 delta = dis_op_imm_A( 1, Iop_Add8, True, delta, "add" );
7983 break;
sewardj77b86be2004-07-11 13:28:24 +00007984 case 0x05: /* ADD Iv, eAX */
7985 delta = dis_op_imm_A(sz, Iop_Add8, True, delta, "add" );
7986 break;
7987
sewardj940e8c92004-07-11 16:53:24 +00007988 case 0x0C: /* OR Ib, AL */
7989 delta = dis_op_imm_A( 1, Iop_Or8, True, delta, "or" );
7990 break;
sewardj82292882004-07-27 00:15:59 +00007991 case 0x0D: /* OR Iv, eAX */
7992 delta = dis_op_imm_A( sz, Iop_Or8, True, delta, "or" );
7993 break;
7994
sewardjc9a65702004-07-07 16:32:57 +00007995//-- case 0x14: /* ADC Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +00007996//-- delta = dis_op_imm_A( 1, ADC, True, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +00007997//-- break;
7998//-- case 0x15: /* ADC Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +00007999//-- delta = dis_op_imm_A( sz, ADC, True, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +00008000//-- break;
8001//--
8002//-- case 0x1C: /* SBB Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +00008003//-- delta = dis_op_imm_A( 1, SBB, True, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +00008004//-- break;
8005//-- case 0x1D: /* SBB Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +00008006//-- delta = dis_op_imm_A( sz, SBB, True, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +00008007//-- break;
8008//--
sewardj940e8c92004-07-11 16:53:24 +00008009 case 0x24: /* AND Ib, AL */
8010 delta = dis_op_imm_A( 1, Iop_And8, True, delta, "and" );
8011 break;
sewardjc2ac51e2004-07-12 01:03:26 +00008012 case 0x25: /* AND Iv, eAX */
8013 delta = dis_op_imm_A( sz, Iop_And8, True, delta, "and" );
8014 break;
sewardj0611d802004-07-11 02:37:54 +00008015
8016 case 0x2C: /* SUB Ib, AL */
8017 delta = dis_op_imm_A(1, Iop_Sub8, True, delta, "sub" );
8018 break;
sewardj68511542004-07-28 00:15:44 +00008019 case 0x2D: /* SUB Iv, eAX */
8020 delta = dis_op_imm_A( sz, Iop_Sub8, True, delta, "sub" );
8021 break;
8022
sewardj1c6f9912004-09-07 10:15:24 +00008023 case 0x34: /* XOR Ib, AL */
8024 delta = dis_op_imm_A( 1, Iop_Xor8, True, delta, "xor" );
8025 break;
sewardjcaca9d02004-07-28 07:11:32 +00008026 case 0x35: /* XOR Iv, eAX */
8027 delta = dis_op_imm_A( sz, Iop_Xor8, True, delta, "xor" );
8028 break;
8029
sewardj0611d802004-07-11 02:37:54 +00008030 case 0x3C: /* CMP Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +00008031 delta = dis_op_imm_A( 1, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +00008032 break;
8033 case 0x3D: /* CMP Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +00008034 delta = dis_op_imm_A( sz, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +00008035 break;
8036
sewardj77b86be2004-07-11 13:28:24 +00008037 case 0xA8: /* TEST Ib, AL */
8038 delta = dis_op_imm_A( 1, Iop_And8, False, delta, "test" );
8039 break;
sewardjc2ac51e2004-07-12 01:03:26 +00008040 case 0xA9: /* TEST Iv, eAX */
8041 delta = dis_op_imm_A( sz, Iop_And8, False, delta, "test" );
8042 break;
8043
sewardj1c6f9912004-09-07 10:15:24 +00008044 /* ------------------------ opl Ev, Gv ----------------- */
8045
sewardj89cd0932004-09-08 18:23:25 +00008046 case 0x02: /* ADD Eb,Gb */
8047 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, 1, delta, "add" );
8048 break;
sewardj9334b0f2004-07-10 22:43:54 +00008049 case 0x03: /* ADD Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00008050 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, sz, delta, "add" );
sewardj9334b0f2004-07-10 22:43:54 +00008051 break;
8052
sewardj7ed22952004-07-29 00:09:58 +00008053 case 0x0A: /* OR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00008054 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, 1, delta, "or" );
sewardj7ed22952004-07-29 00:09:58 +00008055 break;
sewardjc2ac51e2004-07-12 01:03:26 +00008056 case 0x0B: /* OR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00008057 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, sz, delta, "or" );
sewardjc2ac51e2004-07-12 01:03:26 +00008058 break;
sewardjc9a65702004-07-07 16:32:57 +00008059//--
8060//-- case 0x12: /* ADC Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00008061//-- delta = dis_op2_E_G ( sorb, True, ADC, True, 1, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +00008062//-- break;
sewardjc4eaff32004-09-10 20:25:11 +00008063 case 0x13: /* ADC Ev,Gv */
8064 delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
8065 break;
8066
sewardjc9a65702004-07-07 16:32:57 +00008067//-- case 0x1A: /* SBB Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00008068//-- delta = dis_op2_E_G ( sorb, True, SBB, True, 1, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +00008069//-- break;
sewardj180e8b32004-07-29 01:40:11 +00008070 case 0x1B: /* SBB Ev,Gv */
8071 delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
sewardj940e8c92004-07-11 16:53:24 +00008072 break;
8073
sewardj1c6f9912004-09-07 10:15:24 +00008074 case 0x22: /* AND Eb,Gb */
8075 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, 1, delta, "and" );
8076 break;
sewardj180e8b32004-07-29 01:40:11 +00008077 case 0x23: /* AND Ev,Gv */
8078 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, sz, delta, "and" );
8079 break;
8080
8081 case 0x2A: /* SUB Eb,Gb */
8082 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
8083 break;
sewardj0611d802004-07-11 02:37:54 +00008084 case 0x2B: /* SUB Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00008085 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
sewardj0611d802004-07-11 02:37:54 +00008086 break;
sewardjc2ac51e2004-07-12 01:03:26 +00008087
8088 case 0x32: /* XOR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00008089 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +00008090 break;
sewardj1813dbe2004-07-28 17:09:04 +00008091 case 0x33: /* XOR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00008092 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
sewardj1813dbe2004-07-28 17:09:04 +00008093 break;
8094
sewardjc2ac51e2004-07-12 01:03:26 +00008095 case 0x3A: /* CMP Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00008096 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardjc2ac51e2004-07-12 01:03:26 +00008097 break;
sewardje90ad6a2004-07-10 19:02:10 +00008098 case 0x3B: /* CMP Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00008099 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +00008100 break;
8101
sewardj0611d802004-07-11 02:37:54 +00008102 case 0x84: /* TEST Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00008103 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, 1, delta, "test" );
sewardj0611d802004-07-11 02:37:54 +00008104 break;
sewardje05c42c2004-07-08 20:25:10 +00008105 case 0x85: /* TEST Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00008106 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, sz, delta, "test" );
sewardje05c42c2004-07-08 20:25:10 +00008107 break;
8108
sewardj180e8b32004-07-29 01:40:11 +00008109 /* ------------------------ opl Gv, Ev ----------------- */
8110
8111 case 0x00: /* ADD Gb,Eb */
8112 delta = dis_op2_G_E ( sorb, False, Iop_Add8, True, 1, delta, "add" );
8113 break;
sewardje05c42c2004-07-08 20:25:10 +00008114 case 0x01: /* ADD Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00008115 delta = dis_op2_G_E ( sorb, False, Iop_Add8, True, sz, delta, "add" );
sewardje05c42c2004-07-08 20:25:10 +00008116 break;
8117
sewardj940e8c92004-07-11 16:53:24 +00008118 case 0x08: /* OR Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +00008119 delta = dis_op2_G_E ( sorb, False, Iop_Or8, True, 1, delta, "or" );
sewardj940e8c92004-07-11 16:53:24 +00008120 break;
sewardj9334b0f2004-07-10 22:43:54 +00008121 case 0x09: /* OR Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00008122 delta = dis_op2_G_E ( sorb, False, Iop_Or8, True, sz, delta, "or" );
sewardj9334b0f2004-07-10 22:43:54 +00008123 break;
8124
sewardja2384712004-07-29 14:36:40 +00008125 case 0x10: /* ADC Gb,Eb */
8126 delta = dis_op2_G_E ( sorb, True, Iop_Add8, True, 1, delta, "adc" );
8127 break;
sewardjcaca9d02004-07-28 07:11:32 +00008128 case 0x11: /* ADC Gv,Ev */
8129 delta = dis_op2_G_E ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
8130 break;
8131
sewardja2384712004-07-29 14:36:40 +00008132 case 0x18: /* SBB Gb,Eb */
8133 delta = dis_op2_G_E ( sorb, True, Iop_Sub8, True, 1, delta, "sbb" );
8134 break;
sewardjcaca9d02004-07-28 07:11:32 +00008135 case 0x19: /* SBB Gv,Ev */
8136 delta = dis_op2_G_E ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
8137 break;
8138
sewardja2384712004-07-29 14:36:40 +00008139 case 0x20: /* AND Gb,Eb */
8140 delta = dis_op2_G_E ( sorb, False, Iop_And8, True, 1, delta, "and" );
8141 break;
sewardj0611d802004-07-11 02:37:54 +00008142 case 0x21: /* AND Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00008143 delta = dis_op2_G_E ( sorb, False, Iop_And8, True, sz, delta, "and" );
sewardj0611d802004-07-11 02:37:54 +00008144 break;
8145
sewardj180e8b32004-07-29 01:40:11 +00008146 case 0x28: /* SUB Gb,Eb */
8147 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
8148 break;
sewardje05c42c2004-07-08 20:25:10 +00008149 case 0x29: /* SUB Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00008150 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
sewardje05c42c2004-07-08 20:25:10 +00008151 break;
8152
sewardjc2ac51e2004-07-12 01:03:26 +00008153 case 0x30: /* XOR Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +00008154 delta = dis_op2_G_E ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +00008155 break;
sewardje87b4842004-07-10 12:23:30 +00008156 case 0x31: /* XOR Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00008157 delta = dis_op2_G_E ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
sewardje87b4842004-07-10 12:23:30 +00008158 break;
8159
sewardj0611d802004-07-11 02:37:54 +00008160 case 0x38: /* CMP Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +00008161 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +00008162 break;
sewardje90ad6a2004-07-10 19:02:10 +00008163 case 0x39: /* CMP Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00008164 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +00008165 break;
8166
sewardj9334b0f2004-07-10 22:43:54 +00008167 /* ------------------------ POP ------------------------ */
8168
8169 case 0x58: /* POP eAX */
8170 case 0x59: /* POP eCX */
8171 case 0x5A: /* POP eDX */
8172 case 0x5B: /* POP eBX */
8173 case 0x5D: /* POP eBP */
8174 case 0x5E: /* POP eSI */
8175 case 0x5F: /* POP eDI */
8176 case 0x5C: /* POP eSP */
8177 vassert(sz == 2 || sz == 4);
8178 t1 = newTemp(szToITy(sz)); t2 = newTemp(Ity_I32);
8179 assign(t2, getIReg(4, R_ESP));
8180 assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
8181 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
8182 putIReg(sz, opc-0x58, mkexpr(t1));
8183 DIP("pop%c %s\n", nameISize(sz), nameIReg(sz,opc-0x58));
8184 break;
8185
sewardja2384712004-07-29 14:36:40 +00008186 case 0x9D: /* POPF */
8187 vassert(sz == 2 || sz == 4);
8188 vassert(sz == 4); // until we know a sz==2 test case exists
8189 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
8190 assign(t2, getIReg(4, R_ESP));
sewardjc22a6fd2004-07-29 23:41:47 +00008191 assign(t1, widenUto32(loadLE(szToITy(sz),mkexpr(t2))));
sewardja2384712004-07-29 14:36:40 +00008192 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
sewardj98169c52004-10-24 13:11:39 +00008193 /* t1 is the flag word. Mask out everything except OSZACP and
sewardja2384712004-07-29 14:36:40 +00008194 set the flags thunk to CC_OP_COPY. */
8195 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
8196 stmt( IRStmt_Put( OFFB_CC_DST, mkU32(0) ));
8197 stmt( IRStmt_Put( OFFB_CC_SRC,
8198 binop(Iop_And32,
8199 mkexpr(t1),
8200 mkU32( CC_MASK_C | CC_MASK_P | CC_MASK_A
8201 | CC_MASK_Z | CC_MASK_S| CC_MASK_O )
8202 )
8203 )
8204 );
8205
8206 /* Also need to set the D flag, which is held in bit 10 of t1.
8207 If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
8208 stmt( IRStmt_Put(
8209 OFFB_DFLAG,
8210 IRExpr_Mux0X(
8211 unop(Iop_32to8,
8212 binop(Iop_And32,
8213 binop(Iop_Shr32, mkexpr(t1), mkU8(10)),
8214 mkU32(1))),
8215 mkU32(1),
8216 mkU32(0xFFFFFFFF)))
8217 );
8218
8219 DIP("popf%c\n", nameISize(sz));
8220 break;
8221
sewardjc9a65702004-07-07 16:32:57 +00008222//-- case 0x61: /* POPA */
8223//-- { Int reg;
8224//-- /* Just to keep things sane, we assert for a size 4. It's
8225//-- probably OK for size 2 as well, but I'd like to find a test
8226//-- case; ie, have the assertion fail, before committing to it.
8227//-- If it fails for you, uncomment the sz == 2 bit, try again,
8228//-- and let me know whether or not it works. (jseward@acm.org). */
8229//-- vg_assert(sz == 4 /* || sz == 2 */);
8230//--
8231//-- /* Eight values are popped, one per register, but the value of
8232//-- %esp on the stack is ignored and instead incremented (in one
8233//-- hit at the end) for each of the values. */
8234//-- t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
8235//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
8236//-- uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t3);
8237//--
8238//-- /* Do %edi, %esi, %ebp */
8239//-- for (reg = 7; reg >= 5; reg--) {
8240//-- uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
8241//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
8242//-- uLiteral(cb, sz);
8243//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
8244//-- }
8245//-- /* Ignore (skip) value of %esp on stack. */
8246//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
8247//-- uLiteral(cb, sz);
8248//-- /* Do %ebx, %edx, %ecx, %eax */
8249//-- for (reg = 3; reg >= 0; reg--) {
8250//-- uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
8251//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
8252//-- uLiteral(cb, sz);
8253//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
8254//-- }
8255//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t3);
8256//-- uLiteral(cb, sz * 8); /* One 'sz' per register */
8257//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
8258//-- DIP("popa%c\n", nameISize(sz));
8259//-- break;
8260//-- }
8261//--
8262//-- case 0x8F: /* POPL/POPW m32 */
8263//-- { UInt pair1;
8264//-- Int tmpa;
8265//-- UChar rm = getIByte(delta);
8266//--
8267//-- /* make sure this instruction is correct POP */
8268//-- vg_assert(!epartIsReg(rm) && (gregOfRM(rm) == 0));
8269//-- /* and has correct size */
8270//-- vg_assert(sz == 4);
8271//--
8272//-- t1 = newTemp(cb); t3 = newTemp(cb);
8273//-- /* set t1 to ESP: t1 = ESP */
8274//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
8275//-- /* load M[ESP] to virtual register t3: t3 = M[t1] */
8276//-- uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t3);
8277//--
8278//-- /* increase ESP; must be done before the STORE. Intel manual says:
8279//-- If the ESP register is used as a base register for addressing
8280//-- a destination operand in memory, the POP instruction computes
8281//-- the effective address of the operand after it increments the
8282//-- ESP register.
8283//-- */
8284//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1);
8285//-- uLiteral(cb, sz);
8286//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
8287//--
8288//-- /* resolve MODR/M */
8289//-- pair1 = disAMode ( cb, sorb, eip, dis_buf );
8290//--
8291//-- tmpa = LOW24(pair1);
8292//-- /* uInstr2(cb, LOAD, sz, TempReg, tmpa, TempReg, tmpa); */
8293//-- /* store value from stack in memory, M[m32] = t3 */
8294//-- uInstr2(cb, STORE, 4, TempReg, t3, TempReg, tmpa);
8295//--
8296//-- DIP("popl %s\n", dis_buf);
8297//--
8298//-- eip += HI8(pair1);
8299//-- break;
8300//-- }
8301//--
8302//-- case 0x1F: /* POP %DS */
8303//-- dis_pop_segreg( cb, R_DS, sz ); break;
8304//-- case 0x07: /* POP %ES */
8305//-- dis_pop_segreg( cb, R_ES, sz ); break;
8306//-- case 0x17: /* POP %SS */
8307//-- dis_pop_segreg( cb, R_SS, sz ); break;
sewardjd1061ab2004-07-08 01:45:30 +00008308
8309 /* ------------------------ PUSH ----------------------- */
8310
8311 case 0x50: /* PUSH eAX */
8312 case 0x51: /* PUSH eCX */
8313 case 0x52: /* PUSH eDX */
8314 case 0x53: /* PUSH eBX */
8315 case 0x55: /* PUSH eBP */
8316 case 0x56: /* PUSH eSI */
8317 case 0x57: /* PUSH eDI */
8318 case 0x54: /* PUSH eSP */
8319 /* This is the Right Way, in that the value to be pushed is
8320 established before %esp is changed, so that pushl %esp
8321 correctly pushes the old value. */
8322 vassert(sz == 2 || sz == 4);
8323 ty = sz==2 ? Ity_I16 : Ity_I32;
sewardj883b00b2004-09-11 09:30:24 +00008324 t1 = newTemp(ty); t2 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +00008325 assign(t1, getIReg(sz, opc-0x50));
8326 assign(t2, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)));
8327 putIReg(4, R_ESP, mkexpr(t2) );
8328 storeLE(mkexpr(t2),mkexpr(t1));
sewardjd1061ab2004-07-08 01:45:30 +00008329 DIP("push%c %s\n", nameISize(sz), nameIReg(sz,opc-0x50));
8330 break;
8331
8332
sewardj0c12ea82004-07-12 08:18:16 +00008333 case 0x68: /* PUSH Iv */
8334 d32 = getUDisp(sz,delta); delta += sz;
8335 goto do_push_I;
sewardj741153c2004-07-25 23:39:13 +00008336 case 0x6A: /* PUSH Ib, sign-extended to sz */
8337 d32 = getSDisp8(delta); delta += 1;
8338 goto do_push_I;
sewardj0c12ea82004-07-12 08:18:16 +00008339 do_push_I:
8340 ty = szToITy(sz);
8341 t1 = newTemp(Ity_I32); t2 = newTemp(ty);
8342 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
8343 putIReg(4, R_ESP, mkexpr(t1) );
8344 storeLE( mkexpr(t1), mkU(ty,d32) );
8345 DIP("push%c $0x%x\n", nameISize(sz), d32);
8346 break;
8347
sewardja2384712004-07-29 14:36:40 +00008348 case 0x9C: /* PUSHF */ {
8349 IRTemp t3;
8350 vassert(sz == 2 || sz == 4);
8351 vassert(sz == 4); // wait for sz==2 test case
8352
8353 t1 = newTemp(Ity_I32);
8354 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
8355 putIReg(4, R_ESP, mkexpr(t1) );
8356
8357 t2 = newTemp(Ity_I32);
8358 assign( t2, mk_calculate_eflags_all() );
8359
8360 /* Patch in the D flag. This can simply be the inversion
8361 of bit 10 of baseBlock[OFFB_DFLAG]. */
8362 t3 = newTemp(Ity_I32);
8363 assign( t3, binop(Iop_Or32,
8364 mkexpr(t2),
8365 binop(Iop_And32,
8366 unop(Iop_Not32, IRExpr_Get(OFFB_DFLAG,Ity_I32)),
8367 mkU32(1<<10)))
8368 );
8369 /* if sz==2, the stored value needs to be narrowed. */
8370 if (sz == 2)
8371 storeLE( mkexpr(t1), unop(Iop_32to16,mkexpr(t3)) );
8372 else
8373 storeLE( mkexpr(t1), mkexpr(t3) );
8374
8375 DIP("pushf%c\n", nameISize(sz));
8376 break;
8377 }
8378
sewardjc9a65702004-07-07 16:32:57 +00008379//-- case 0x60: /* PUSHA */
8380//-- { Int reg;
8381//-- /* Just to keep things sane, we assert for a size 4. It's
8382//-- probably OK for size 2 as well, but I'd like to find a test
8383//-- case; ie, have the assertion fail, before committing to it.
8384//-- If it fails for you, uncomment the sz == 2 bit, try again,
8385//-- and let me know whether or not it works. (jseward@acm.org). */
8386//-- vg_assert(sz == 4 /* || sz == 2 */);
8387//--
8388//-- /* This is the Right Way, in that the value to be pushed is
8389//-- established before %esp is changed, so that pusha
8390//-- correctly pushes the old %esp value. New value of %esp is
8391//-- pushed at start. */
8392//-- t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
8393//-- t4 = newTemp(cb);
8394//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
8395//-- uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
8396//-- uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t4);
8397//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t4);
8398//-- uLiteral(cb, sz * 8); /* One 'sz' per register. */
8399//-- uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_ESP);
8400//-- /* Do %eax, %ecx, %edx, %ebx */
8401//-- for (reg = 0; reg <= 3; reg++) {
8402//-- uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
8403//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
8404//-- uLiteral(cb, sz);
8405//-- uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
8406//-- }
8407//-- /* Push old value of %esp */
8408//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
8409//-- uLiteral(cb, sz);
8410//-- uInstr2(cb, STORE, sz, TempReg, t3, TempReg, t2);
8411//-- /* Do %ebp, %esi, %edi */
8412//-- for (reg = 5; reg <= 7; reg++) {
8413//-- uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
8414//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
8415//-- uLiteral(cb, sz);
8416//-- uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
8417//-- }
8418//-- DIP("pusha%c\n", nameISize(sz));
8419//-- break;
8420//-- }
8421//--
8422//-- case 0x0E: /* PUSH %CS */
8423//-- dis_push_segreg( cb, R_CS, sz ); break;
8424//-- case 0x1E: /* PUSH %DS */
8425//-- dis_push_segreg( cb, R_DS, sz ); break;
8426//-- case 0x06: /* PUSH %ES */
8427//-- dis_push_segreg( cb, R_ES, sz ); break;
8428//-- case 0x16: /* PUSH %SS */
8429//-- dis_push_segreg( cb, R_SS, sz ); break;
sewardj458a6f82004-08-25 12:46:02 +00008430
8431 /* ------------------------ SCAS et al ----------------- */
8432
8433 case 0xA4: /* MOVS, no REP prefix */
8434 case 0xA5:
8435 dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
8436 break;
8437
sewardjc9a65702004-07-07 16:32:57 +00008438//-- case 0xA6: /* CMPSb, no REP prefix */
8439//-- case 0xA7:
8440//-- dis_string_op( cb, dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
8441//-- break;
8442//--
sewardj883b00b2004-09-11 09:30:24 +00008443 case 0xAA: /* STOS, no REP prefix */
sewardj47341042004-09-19 11:55:46 +00008444 case 0xAB:
sewardj883b00b2004-09-11 09:30:24 +00008445 dis_string_op( dis_STOS, ( opc == 0xAA ? 1 : sz ), "stos", sorb );
8446 break;
sewardjc9a65702004-07-07 16:32:57 +00008447//--
8448//-- case 0xAC: /* LODS, no REP prefix */
8449//-- case 0xAD:
8450//-- dis_string_op( cb, dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
8451//-- break;
sewardj2d4c3a02004-10-15 00:03:23 +00008452
8453 case 0xAE: /* SCAS, no REP prefix */
8454 case 0xAF:
8455 dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
8456 break;
sewardj64e1d652004-07-12 14:00:46 +00008457
8458
8459 case 0xFC: /* CLD */
sewardjeeb9ef82004-07-15 12:39:03 +00008460 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(1)) );
sewardj64e1d652004-07-12 14:00:46 +00008461 DIP("cld\n");
8462 break;
8463
sewardj1813dbe2004-07-28 17:09:04 +00008464 case 0xFD: /* STD */
8465 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(0xFFFFFFFF)) );
8466 DIP("std\n");
8467 break;
8468
sewardjc9a65702004-07-07 16:32:57 +00008469//-- case 0xF8: /* CLC */
8470//-- uInstr0(cb, CALLM_S, 0);
8471//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CLC));
8472//-- uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
8473//-- uInstr0(cb, CALLM_E, 0);
8474//-- DIP("clc\n");
8475//-- break;
8476//--
8477//-- case 0xF9: /* STC */
8478//-- uInstr0(cb, CALLM_S, 0);
8479//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_STC));
8480//-- uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
8481//-- uInstr0(cb, CALLM_E, 0);
8482//-- DIP("stc\n");
8483//-- break;
8484//--
8485//-- case 0xF5: /* CMC */
8486//-- uInstr0(cb, CALLM_S, 0);
8487//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CMC));
8488//-- uFlagsRWU(cb, FlagC, FlagC, FlagsOSZAP);
8489//-- uInstr0(cb, CALLM_E, 0);
8490//-- DIP("cmc\n");
8491//-- break;
sewardj82292882004-07-27 00:15:59 +00008492
8493 /* REPNE prefix insn */
8494 case 0xF2: {
sewardjce70a5c2004-10-18 14:09:54 +00008495 Addr32 eip_orig = guest_eip_bbstart + delta - 1;
sewardj82292882004-07-27 00:15:59 +00008496 vassert(sorb == 0);
8497 abyte = getIByte(delta); delta++;
8498
8499 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
sewardjce70a5c2004-10-18 14:09:54 +00008500 whatNext = Dis_StopHere;
sewardj82292882004-07-27 00:15:59 +00008501
8502 switch (abyte) {
8503 /* According to the Intel manual, "repne movs" should never occur, but
8504 * in practice it has happened, so allow for it here... */
sewardj180e8b32004-07-29 01:40:11 +00008505 case 0xA4: sz = 1; /* REPNE MOVS<sz> */
sewardjc4be80c2004-09-10 16:17:45 +00008506 vassert(0);
sewardjc9a65702004-07-07 16:32:57 +00008507//-- case 0xA5:
sewardj180e8b32004-07-29 01:40:11 +00008508 // dis_REP_op ( CondNZ, dis_MOVS, sz, eip_orig,
sewardjce70a5c2004-10-18 14:09:54 +00008509 // guest_eip_bbstart+delta, "repne movs" );
sewardj180e8b32004-07-29 01:40:11 +00008510 // break;
sewardjc9a65702004-07-07 16:32:57 +00008511//--
8512//-- case 0xA6: sz = 1; /* REPNE CMPS<sz> */
8513//-- case 0xA7:
8514//-- dis_REP_op ( cb, CondNZ, dis_CMPS, sz, eip_orig, eip, "repne cmps" );
8515//-- break;
8516//--
sewardj82292882004-07-27 00:15:59 +00008517 case 0xAE: sz = 1; /* REPNE SCAS<sz> */
sewardj2d4c3a02004-10-15 00:03:23 +00008518 case 0xAF:
sewardj82292882004-07-27 00:15:59 +00008519 dis_REP_op ( CondNZ, dis_SCAS, sz, eip_orig,
sewardjce70a5c2004-10-18 14:09:54 +00008520 guest_eip_bbstart+delta, "repne scas" );
sewardj82292882004-07-27 00:15:59 +00008521 break;
8522
8523 default:
8524 goto decode_failure;
8525 }
8526 break;
8527 }
sewardj64e1d652004-07-12 14:00:46 +00008528
8529 /* REP/REPE prefix insn (for SCAS and CMPS, 0xF3 means REPE,
8530 for the rest, it means REP) */
8531 case 0xF3: {
sewardjce70a5c2004-10-18 14:09:54 +00008532 Addr32 eip_orig = guest_eip_bbstart + delta - 1;
sewardj64e1d652004-07-12 14:00:46 +00008533 vassert(sorb == 0);
8534 abyte = getIByte(delta); delta++;
8535
8536 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
sewardjce70a5c2004-10-18 14:09:54 +00008537 whatNext = Dis_StopHere;
sewardj64e1d652004-07-12 14:00:46 +00008538
8539 switch (abyte) {
8540 case 0xA4: sz = 1; /* REP MOVS<sz> */
8541 case 0xA5:
8542 dis_REP_op ( CondAlways, dis_MOVS, sz, eip_orig,
sewardjce70a5c2004-10-18 14:09:54 +00008543 guest_eip_bbstart+delta, "rep movs" );
sewardj64e1d652004-07-12 14:00:46 +00008544 break;
8545
8546 case 0xA6: sz = 1; /* REPE CMP<sz> */
sewardj2d4c3a02004-10-15 00:03:23 +00008547 case 0xA7:
sewardj64e1d652004-07-12 14:00:46 +00008548 dis_REP_op ( CondZ, dis_CMPS, sz, eip_orig,
sewardjce70a5c2004-10-18 14:09:54 +00008549 guest_eip_bbstart+delta, "repe cmps" );
sewardj64e1d652004-07-12 14:00:46 +00008550 break;
8551
8552 case 0xAA: sz = 1; /* REP STOS<sz> */
8553 case 0xAB:
8554 dis_REP_op ( CondAlways, dis_STOS, sz, eip_orig,
sewardjce70a5c2004-10-18 14:09:54 +00008555 guest_eip_bbstart+delta, "rep stos" );
sewardj64e1d652004-07-12 14:00:46 +00008556 break;
sewardjc9a65702004-07-07 16:32:57 +00008557//--
8558//-- case 0xAE: sz = 1; /* REPE SCAS<sz> */
8559//-- case 0xAF:
8560//-- dis_REP_op ( cb, CondZ, dis_SCAS, sz, eip_orig, eip, "repe scas" );
8561//-- break;
8562//--
8563//-- case 0x90: /* REP NOP (PAUSE) */
8564//-- /* a hint to the P4 re spin-wait loop */
8565//-- DIP("rep nop (P4 pause)\n");
8566//-- jmp_lit(cb, eip);
8567//-- LAST_UINSTR(cb).jmpkind = JmpYield;
8568//-- break;
8569//--
8570//-- case 0xC3: /* REP RET */
8571//-- /* AMD K7/K8-specific optimisation; faster than vanilla RET */
8572//-- dis_ret(cb, 0);
8573//-- DIP("rep ret\n");
8574//-- break;
sewardj64e1d652004-07-12 14:00:46 +00008575
8576 default:
8577 goto decode_failure;
8578 }
8579 break;
8580 }
sewardj0611d802004-07-11 02:37:54 +00008581
8582 /* ------------------------ XCHG ----------------------- */
8583
8584 case 0x86: /* XCHG Gb,Eb */
8585 sz = 1;
8586 /* Fall through ... */
8587 case 0x87: /* XCHG Gv,Ev */
8588 modrm = getIByte(delta);
8589 ty = szToITy(sz);
8590 t1 = newTemp(ty); t2 = newTemp(ty);
8591 if (epartIsReg(modrm)) {
8592 assign(t1, getIReg(sz, eregOfRM(modrm)));
8593 assign(t2, getIReg(sz, gregOfRM(modrm)));
8594 putIReg(sz, gregOfRM(modrm), mkexpr(t1));
8595 putIReg(sz, eregOfRM(modrm), mkexpr(t2));
8596 delta++;
8597 DIP("xchg%c %s, %s\n",
8598 nameISize(sz), nameIReg(sz,gregOfRM(modrm)),
8599 nameIReg(sz,eregOfRM(modrm)));
8600 } else {
sewardj0c12ea82004-07-12 08:18:16 +00008601 addr = disAMode ( &alen, sorb, delta, dis_buf );
8602 assign( t1, loadLE(ty,mkexpr(addr)) );
8603 assign( t2, getIReg(sz,gregOfRM(modrm)) );
8604 storeLE( mkexpr(addr), mkexpr(t2) );
8605 putIReg( sz, gregOfRM(modrm), mkexpr(t1) );
8606 delta += alen;
sewardj0611d802004-07-11 02:37:54 +00008607 DIP("xchg%c %s, %s\n", nameISize(sz),
8608 nameIReg(sz,gregOfRM(modrm)), dis_buf);
sewardj0611d802004-07-11 02:37:54 +00008609 }
8610 break;
sewardje87b4842004-07-10 12:23:30 +00008611
8612 case 0x90: /* XCHG eAX,eAX */
8613 DIP("nop\n");
8614 break;
sewardj64e1d652004-07-12 14:00:46 +00008615 case 0x91: /* XCHG eAX,eCX */
8616 case 0x92: /* XCHG eAX,eDX */
8617 case 0x93: /* XCHG eAX,eBX */
8618 case 0x94: /* XCHG eAX,eSP */
8619 case 0x95: /* XCHG eAX,eBP */
8620 case 0x96: /* XCHG eAX,eSI */
8621 case 0x97: /* XCHG eAX,eDI */
8622 codegen_xchg_eAX_Reg ( sz, opc - 0x90 );
8623 break;
8624
sewardjc9a65702004-07-07 16:32:57 +00008625//-- /* ------------------------ XLAT ----------------------- */
8626//--
8627//-- case 0xD7: /* XLAT */
8628//-- t1 = newTemp(cb); t2 = newTemp(cb);
8629//-- uInstr2(cb, GET, sz, ArchReg, R_EBX, TempReg, t1); /* get eBX */
8630//-- handleSegOverride( cb, sorb, t1 ); /* make t1 DS:eBX */
8631//-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t2); /* get AL */
8632//-- /* Widen %AL to 32 bits, so it's all defined when we add it. */
8633//-- uInstr1(cb, WIDEN, 4, TempReg, t2);
8634//-- uWiden(cb, 1, False);
8635//-- uInstr2(cb, ADD, sz, TempReg, t2, TempReg, t1); /* add AL to eBX */
8636//-- uInstr2(cb, LOAD, 1, TempReg, t1, TempReg, t2); /* get byte at t1 into t2 */
8637//-- uInstr2(cb, PUT, 1, TempReg, t2, ArchReg, R_AL); /* put byte into AL */
8638//--
8639//-- DIP("xlat%c [ebx]\n", nameISize(sz));
8640//-- break;
8641//--
8642//-- /* ------------------------ IN / OUT ----------------------- */
8643//--
8644//-- case 0xE4: /* IN ib, %al */
8645//-- case 0xE5: /* IN ib, %{e}ax */
8646//-- case 0xEC: /* IN (%dx),%al */
8647//-- case 0xED: /* IN (%dx),%{e}ax */
8648//-- t1 = newTemp(cb);
8649//-- t2 = newTemp(cb);
8650//-- t3 = newTemp(cb);
8651//--
8652//-- uInstr0(cb, CALLM_S, 0);
8653//-- /* operand size? */
8654//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
8655//-- uLiteral(cb, ( opc == 0xE4 || opc == 0xEC ) ? 1 : sz);
8656//-- uInstr1(cb, PUSH, 4, TempReg, t1);
8657//-- /* port number ? */
8658//-- if ( opc == 0xE4 || opc == 0xE5 ) {
8659//-- abyte = getUChar(eip); eip++;
8660//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
8661//-- uLiteral(cb, abyte);
8662//-- }
8663//-- else
8664//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
8665//--
8666//-- uInstr1(cb, PUSH, 4, TempReg, t2);
8667//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_IN));
8668//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
8669//-- uInstr1(cb, POP, 4, TempReg, t2);
8670//-- uInstr1(cb, CLEAR, 0, Lit16, 4);
8671//-- uInstr0(cb, CALLM_E, 0);
8672//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EAX);
8673//-- if ( opc == 0xE4 || opc == 0xE5 ) {
8674//-- DIP("in 0x%x, %%eax/%%ax/%%al\n", getUChar(eip-1) );
8675//-- } else {
8676//-- DIP("in (%%dx), %%eax/%%ax/%%al\n");
8677//-- }
8678//-- break;
8679//-- case 0xE6: /* OUT %al,ib */
8680//-- case 0xE7: /* OUT %{e}ax,ib */
8681//-- case 0xEE: /* OUT %al,(%dx) */
8682//-- case 0xEF: /* OUT %{e}ax,(%dx) */
8683//-- t1 = newTemp(cb);
8684//-- t2 = newTemp(cb);
8685//-- t3 = newTemp(cb);
8686//--
8687//-- uInstr0(cb, CALLM_S, 0);
8688//-- /* operand size? */
8689//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
8690//-- uLiteral(cb, ( opc == 0xE6 || opc == 0xEE ) ? 1 : sz);
8691//-- uInstr1(cb, PUSH, 4, TempReg, t1);
8692//-- /* port number ? */
8693//-- if ( opc == 0xE6 || opc == 0xE7 ) {
8694//-- abyte = getUChar(eip); eip++;
8695//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
8696//-- uLiteral(cb, abyte);
8697//-- }
8698//-- else
8699//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
8700//-- uInstr1(cb, PUSH, 4, TempReg, t2);
8701//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t3);
8702//-- uInstr1(cb, PUSH, 4, TempReg, t3);
8703//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_OUT));
8704//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
8705//-- uInstr1(cb, CLEAR, 0, Lit16, 12);
8706//-- uInstr0(cb, CALLM_E, 0);
8707//-- if ( opc == 0xE4 || opc == 0xE5 ) {
8708//-- DIP("out %%eax/%%ax/%%al, 0x%x\n", getUChar(eip-1) );
8709//-- } else {
8710//-- DIP("out %%eax/%%ax/%%al, (%%dx)\n");
8711//-- }
8712//-- break;
sewardj0611d802004-07-11 02:37:54 +00008713
8714 /* ------------------------ (Grp1 extensions) ---------- */
8715
8716 case 0x80: /* Grp1 Ib,Eb */
8717 modrm = getIByte(delta);
8718 am_sz = lengthAMode(delta);
8719 sz = 1;
8720 d_sz = 1;
sewardjc2ac51e2004-07-12 01:03:26 +00008721 d32 = getUChar(delta + am_sz);
sewardj0611d802004-07-11 02:37:54 +00008722 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
8723 break;
sewardje05c42c2004-07-08 20:25:10 +00008724
8725 case 0x81: /* Grp1 Iv,Ev */
8726 modrm = getIByte(delta);
8727 am_sz = lengthAMode(delta);
8728 d_sz = sz;
8729 d32 = getUDisp(d_sz, delta + am_sz);
8730 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
8731 break;
sewardjd1061ab2004-07-08 01:45:30 +00008732
8733 case 0x83: /* Grp1 Ib,Ev */
8734 modrm = getIByte(delta);
8735 am_sz = lengthAMode(delta);
8736 d_sz = 1;
8737 d32 = getSDisp8(delta + am_sz);
8738 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
8739 break;
8740
sewardjc2ac51e2004-07-12 01:03:26 +00008741 /* ------------------------ (Grp2 extensions) ---------- */
8742
8743 case 0xC0: /* Grp2 Ib,Eb */
8744 modrm = getIByte(delta);
8745 am_sz = lengthAMode(delta);
8746 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +00008747 d32 = getUChar(delta + am_sz);
sewardjc2ac51e2004-07-12 01:03:26 +00008748 sz = 1;
sewardj6d2638e2004-07-15 09:38:27 +00008749 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
8750 mkU8(d32 & 0xFF), NULL );
sewardjc2ac51e2004-07-12 01:03:26 +00008751 break;
sewardje90ad6a2004-07-10 19:02:10 +00008752
8753 case 0xC1: /* Grp2 Ib,Ev */
sewardjc2ac51e2004-07-12 01:03:26 +00008754 modrm = getIByte(delta);
sewardje90ad6a2004-07-10 19:02:10 +00008755 am_sz = lengthAMode(delta);
8756 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +00008757 d32 = getUChar(delta + am_sz);
sewardj6d2638e2004-07-15 09:38:27 +00008758 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
8759 mkU8(d32 & 0xFF), NULL );
sewardje90ad6a2004-07-10 19:02:10 +00008760 break;
8761
sewardj180e8b32004-07-29 01:40:11 +00008762 case 0xD0: /* Grp2 1,Eb */
8763 modrm = getIByte(delta);
8764 am_sz = lengthAMode(delta);
8765 d_sz = 0;
8766 d32 = 1;
8767 sz = 1;
8768 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
8769 mkU8(d32), NULL );
8770 break;
sewardjc2ac51e2004-07-12 01:03:26 +00008771
8772 case 0xD1: /* Grp2 1,Ev */
8773 modrm = getUChar(delta);
8774 am_sz = lengthAMode(delta);
8775 d_sz = 0;
8776 d32 = 1;
sewardj6d2638e2004-07-15 09:38:27 +00008777 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
8778 mkU8(d32), NULL );
sewardjc2ac51e2004-07-12 01:03:26 +00008779 break;
8780
sewardj8c7f1ab2004-07-29 20:31:09 +00008781 case 0xD2: /* Grp2 CL,Eb */
8782 modrm = getUChar(delta);
8783 am_sz = lengthAMode(delta);
8784 d_sz = 0;
8785 sz = 1;
8786 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
8787 getIReg(1,R_ECX), "%cl" );
8788 break;
sewardj9334b0f2004-07-10 22:43:54 +00008789
8790 case 0xD3: /* Grp2 CL,Ev */
8791 modrm = getIByte(delta);
8792 am_sz = lengthAMode(delta);
8793 d_sz = 0;
8794 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardj6d2638e2004-07-15 09:38:27 +00008795 getIReg(1,R_ECX), "%cl" );
sewardj9334b0f2004-07-10 22:43:54 +00008796 break;
8797
sewardj940e8c92004-07-11 16:53:24 +00008798 /* ------------------------ (Grp3 extensions) ---------- */
8799
8800 case 0xF6: /* Grp3 Eb */
8801 delta = dis_Grp3 ( sorb, 1, delta );
8802 break;
8803 case 0xF7: /* Grp3 Ev */
8804 delta = dis_Grp3 ( sorb, sz, delta );
8805 break;
8806
sewardjc2ac51e2004-07-12 01:03:26 +00008807 /* ------------------------ (Grp4 extensions) ---------- */
8808
8809 case 0xFE: /* Grp4 Eb */
8810 delta = dis_Grp4 ( sorb, delta );
8811 break;
sewardj0611d802004-07-11 02:37:54 +00008812
8813 /* ------------------------ (Grp5 extensions) ---------- */
8814
8815 case 0xFF: /* Grp5 Ev */
sewardjce70a5c2004-10-18 14:09:54 +00008816 delta = dis_Grp5 ( sorb, sz, delta, &whatNext );
sewardj0611d802004-07-11 02:37:54 +00008817 break;
sewardje87b4842004-07-10 12:23:30 +00008818
8819 /* ------------------------ Escapes to 2-byte opcodes -- */
8820
8821 case 0x0F: {
8822 opc = getIByte(delta); delta++;
8823 switch (opc) {
8824
sewardjc9a65702004-07-07 16:32:57 +00008825//-- /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
8826//--
8827//-- case 0xBA: /* Grp8 Ib,Ev */
8828//-- modrm = getUChar(eip);
8829//-- am_sz = lengthAMode(eip);
8830//-- d32 = getSDisp8(eip + am_sz);
8831//-- eip = dis_Grp8_BT ( cb, sorb, eip, modrm, am_sz, sz, d32 );
8832//-- break;
sewardjce646f22004-08-31 23:55:54 +00008833
8834 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
8835
8836 case 0xBC: /* BSF Gv,Ev */
8837 delta = dis_bs_E_G ( sorb, sz, delta, True );
8838 break;
8839 case 0xBD: /* BSR Gv,Ev */
8840 delta = dis_bs_E_G ( sorb, sz, delta, False );
8841 break;
sewardj1c4208f2004-08-25 13:25:29 +00008842
8843 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
8844
8845 case 0xC8: /* BSWAP %eax */
8846 case 0xC9:
8847 case 0xCA:
sewardjb4666cf2004-10-23 00:21:50 +00008848 case 0xCB:
8849 case 0xCC:
8850 case 0xCD:
sewardj1c4208f2004-08-25 13:25:29 +00008851 case 0xCE:
sewardj1c6f9912004-09-07 10:15:24 +00008852 case 0xCF: /* BSWAP %edi */
sewardj1c4208f2004-08-25 13:25:29 +00008853 /* AFAICS from the Intel docs, this only exists at size 4. */
8854 vassert(sz == 4);
8855 t1 = newTemp(Ity_I32);
8856 t2 = newTemp(Ity_I32);
8857 assign( t1, getIReg(4, opc-0xC8) );
8858
8859 assign( t2,
8860 binop(Iop_Or32,
8861 binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
8862 binop(Iop_Or32,
8863 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
8864 mkU32(0x00FF0000)),
8865 binop(Iop_Or32,
8866 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
8867 mkU32(0x0000FF00)),
8868 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
8869 mkU32(0x000000FF) )
8870 )))
8871 );
8872
8873 putIReg(4, opc-0xC8, mkexpr(t2));
sewardj1c4208f2004-08-25 13:25:29 +00008874 DIP("bswapl %s\n", nameIReg(4, opc-0xC8));
8875 break;
8876
sewardj1c6f9912004-09-07 10:15:24 +00008877 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
8878
8879 case 0xA3: /* BT Gv,Ev */
8880 delta = dis_bt_G_E ( sorb, sz, delta, BtOpNone );
8881 break;
sewardje6709112004-09-10 18:37:18 +00008882 case 0xB3: /* BTR Gv,Ev */
8883 delta = dis_bt_G_E ( sorb, sz, delta, BtOpReset );
8884 break;
sewardj1c6f9912004-09-07 10:15:24 +00008885 case 0xAB: /* BTS Gv,Ev */
8886 delta = dis_bt_G_E ( sorb, sz, delta, BtOpSet );
8887 break;
sewardj4963a422004-10-14 23:34:03 +00008888 case 0xBB: /* BTC Gv,Ev */
8889 delta = dis_bt_G_E ( sorb, sz, delta, BtOpComp );
8890 break;
sewardj458a6f82004-08-25 12:46:02 +00008891
8892 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
8893
sewardj2d4c3a02004-10-15 00:03:23 +00008894 case 0x40:
8895 case 0x41:
sewardj458a6f82004-08-25 12:46:02 +00008896 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
8897 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
8898 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
8899 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
8900 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
8901 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
sewardjce646f22004-08-31 23:55:54 +00008902 case 0x48: /* CMOVSb (cmov negative) */
sewardj458a6f82004-08-25 12:46:02 +00008903 case 0x49: /* CMOVSb (cmov not negative) */
sewardj2d4c3a02004-10-15 00:03:23 +00008904 case 0x4A: /* CMOVP (cmov parity even) */
8905 case 0x4B: /* CMOVNP (cmov parity odd) */
sewardj458a6f82004-08-25 12:46:02 +00008906 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
8907 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
8908 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
8909 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
8910 delta = dis_cmov_E_G(sorb, sz, (Condcode)(opc - 0x40), delta);
8911 break;
8912
8913 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
8914
sewardjc744e872004-08-26 11:24:39 +00008915 case 0xB0: /* CMPXCHG Gb,Eb */
8916 delta = dis_cmpxchg_G_E ( sorb, 1, delta );
8917 break;
sewardj458a6f82004-08-25 12:46:02 +00008918 case 0xB1: /* CMPXCHG Gv,Ev */
8919 delta = dis_cmpxchg_G_E ( sorb, sz, delta );
8920 break;
sewardjc9a65702004-07-07 16:32:57 +00008921//-- case 0xC7: /* CMPXCHG8B Gv */
8922//-- eip = dis_cmpxchg8b ( cb, sorb, eip );
8923//-- break;
8924//--
sewardj588ea762004-09-10 18:56:32 +00008925 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
8926
sewardj7cb49d72004-10-24 22:31:25 +00008927 case 0xA2: { /* CPUID */
8928 /* Uses dirty helper:
8929 void dirtyhelper_CPUID ( VexGuestX86State* )
8930 declared to mod eax, wr ebx, ecx, edx
8931 */
8932 /* give details of args, and where to call */
8933 IRDirty* d;
8934 d = emptyIRDirty();
8935 d->name = "dirtyhelper_CPUID";
8936 d->args = LibVEX_Alloc(1 * sizeof(IRTemp));
8937 d->args[0] = NULL;
8938 d->tmp = INVALID_IRTEMP;
8939 /* declare that we're not accessing memory */
8940 d->mFx = Ifx_None;
8941 d->mAddr = NULL;
8942 d->mSize = 0;
8943 /* declare guest state effects */
8944 d->nFxState = 4;
8945 d->fxState[0].fx = Ifx_Modify;
8946 d->fxState[0].offset = OFFB_EAX;
8947 d->fxState[0].size = 4;
8948 d->fxState[1].fx = Ifx_Write;
8949 d->fxState[1].offset = OFFB_EBX;
8950 d->fxState[1].size = 4;
8951 d->fxState[2].fx = Ifx_Write;
8952 d->fxState[2].offset = OFFB_ECX;
8953 d->fxState[2].size = 4;
8954 d->fxState[3].fx = Ifx_Write;
8955 d->fxState[3].offset = OFFB_EDX;
8956 d->fxState[3].size = 4;
8957 /* execute the dirty call, side-effecting guest state */
8958 stmt( IRStmt_Dirty(d) );
sewardj588ea762004-09-10 18:56:32 +00008959 break;
sewardj7cb49d72004-10-24 22:31:25 +00008960 }
8961
sewardjc9a65702004-07-07 16:32:57 +00008962//-- if (!VG_(cpu_has_feature)(VG_X86_FEAT_CPUID))
8963//-- goto decode_failure;
8964//--
8965//-- t1 = newTemp(cb);
8966//-- t2 = newTemp(cb);
8967//-- t3 = newTemp(cb);
8968//-- t4 = newTemp(cb);
8969//-- uInstr0(cb, CALLM_S, 0);
8970//--
8971//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t1);
8972//-- uInstr1(cb, PUSH, 4, TempReg, t1);
8973//--
8974//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
8975//-- uLiteral(cb, 0);
8976//-- uInstr1(cb, PUSH, 4, TempReg, t2);
8977//--
8978//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t3);
8979//-- uLiteral(cb, 0);
8980//-- uInstr1(cb, PUSH, 4, TempReg, t3);
8981//--
8982//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
8983//-- uLiteral(cb, 0);
8984//-- uInstr1(cb, PUSH, 4, TempReg, t4);
8985//--
8986//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CPUID));
8987//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
8988//--
8989//-- uInstr1(cb, POP, 4, TempReg, t4);
8990//-- uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_EDX);
8991//--
8992//-- uInstr1(cb, POP, 4, TempReg, t3);
8993//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ECX);
8994//--
8995//-- uInstr1(cb, POP, 4, TempReg, t2);
8996//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBX);
8997//--
8998//-- uInstr1(cb, POP, 4, TempReg, t1);
8999//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
9000//--
9001//-- uInstr0(cb, CALLM_E, 0);
9002//-- DIP("cpuid\n");
9003//-- break;
9004//--
sewardj9334b0f2004-07-10 22:43:54 +00009005 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
9006
9007 case 0xB6: /* MOVZXb Eb,Gv */
9008 delta = dis_movx_E_G ( sorb, delta, 1, 4, False );
9009 break;
sewardj940e8c92004-07-11 16:53:24 +00009010 case 0xB7: /* MOVZXw Ew,Gv */
9011 delta = dis_movx_E_G ( sorb, delta, 2, 4, False );
9012 break;
9013
sewardj0611d802004-07-11 02:37:54 +00009014 case 0xBE: /* MOVSXb Eb,Gv */
9015 delta = dis_movx_E_G ( sorb, delta, 1, 4, True );
9016 break;
sewardj7ed22952004-07-29 00:09:58 +00009017 case 0xBF: /* MOVSXw Ew,Gv */
9018 delta = dis_movx_E_G ( sorb, delta, 2, 4, True );
9019 break;
9020
sewardjc9a65702004-07-07 16:32:57 +00009021//-- /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
9022//--
9023//-- case 0xC3: /* MOVNTI Gv,Ev */
9024//-- vg_assert(sz == 4);
9025//-- modrm = getUChar(eip);
9026//-- vg_assert(!epartIsReg(modrm));
9027//-- t1 = newTemp(cb);
9028//-- uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
9029//-- pair = disAMode ( cb, sorb, eip, dis_buf );
9030//-- t2 = LOW24(pair);
9031//-- eip += HI8(pair);
9032//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
9033//-- DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
9034//-- break;
sewardjcf780b42004-07-13 18:42:17 +00009035
9036 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
9037
9038 case 0xAF: /* IMUL Ev, Gv */
9039 delta = dis_mul_E_G ( sorb, sz, delta, True );
9040 break;
sewardje87b4842004-07-10 12:23:30 +00009041
9042 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
9043 case 0x80:
9044 case 0x81:
9045 case 0x82: /* JBb/JNAEb (jump below) */
9046 case 0x83: /* JNBb/JAEb (jump not below) */
9047 case 0x84: /* JZb/JEb (jump zero) */
9048 case 0x85: /* JNZb/JNEb (jump not zero) */
9049 case 0x86: /* JBEb/JNAb (jump below or equal) */
9050 case 0x87: /* JNBEb/JAb (jump not below or equal) */
9051 case 0x88: /* JSb (jump negative) */
9052 case 0x89: /* JSb (jump not negative) */
9053 case 0x8A: /* JP (jump parity even) */
9054 case 0x8B: /* JNP/JPO (jump parity odd) */
9055 case 0x8C: /* JLb/JNGEb (jump less) */
9056 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
9057 case 0x8E: /* JLEb/JNGb (jump less or equal) */
9058 case 0x8F: /* JGb/JNLEb (jump greater) */
sewardj4fd30f22004-10-25 00:42:16 +00009059 d32 = (((Addr32)guest_eip_bbstart)+delta+4) + getUDisp32(delta);
sewardje87b4842004-07-10 12:23:30 +00009060 delta += 4;
sewardj4fd30f22004-10-25 00:42:16 +00009061 jcc_01((Condcode)(opc - 0x80), (Addr32)(guest_eip_bbstart+delta), d32);
sewardjce70a5c2004-10-18 14:09:54 +00009062 whatNext = Dis_StopHere;
sewardje87b4842004-07-10 12:23:30 +00009063 DIP("j%s-32 0x%x\n", name_Condcode(opc - 0x80), d32);
9064 break;
9065
sewardj89cd0932004-09-08 18:23:25 +00009066
9067 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
9068
9069 case 0x31: /* RDTSC */
9070 vex_printf("vex x86->IR: kludged rdtsc\n");
9071 putIReg(4, R_EAX, mkU32(0));
9072 putIReg(4, R_EDX, mkU32(0));
9073
sewardjc9a65702004-07-07 16:32:57 +00009074//-- t1 = newTemp(cb);
9075//-- t2 = newTemp(cb);
9076//-- t3 = newTemp(cb);
9077//-- uInstr0(cb, CALLM_S, 0);
9078//-- // Nb: even though these args aren't used by RDTSC_helper, need
9079//-- // them to be defined (for Memcheck). The TempRegs pushed must
9080//-- // also be distinct.
9081//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
9082//-- uLiteral(cb, 0);
9083//-- uInstr1(cb, PUSH, 4, TempReg, t1);
9084//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
9085//-- uLiteral(cb, 0);
9086//-- uInstr1(cb, PUSH, 4, TempReg, t2);
9087//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_RDTSC));
9088//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
9089//-- uInstr1(cb, POP, 4, TempReg, t3);
9090//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EDX);
9091//-- uInstr1(cb, POP, 4, TempReg, t3);
9092//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EAX);
9093//-- uInstr0(cb, CALLM_E, 0);
sewardj89cd0932004-09-08 18:23:25 +00009094 DIP("rdtsc\n");
9095 break;
sewardj77b86be2004-07-11 13:28:24 +00009096
9097 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
9098 case 0x90:
9099 case 0x91:
9100 case 0x92: /* set-Bb/set-NAEb (jump below) */
9101 case 0x93: /* set-NBb/set-AEb (jump not below) */
9102 case 0x94: /* set-Zb/set-Eb (jump zero) */
9103 case 0x95: /* set-NZb/set-NEb (jump not zero) */
9104 case 0x96: /* set-BEb/set-NAb (jump below or equal) */
9105 case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
9106 case 0x98: /* set-Sb (jump negative) */
9107 case 0x99: /* set-Sb (jump not negative) */
9108 case 0x9A: /* set-P (jump parity even) */
9109 case 0x9B: /* set-NP (jump parity odd) */
9110 case 0x9C: /* set-Lb/set-NGEb (jump less) */
9111 case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
9112 case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
9113 case 0x9F: /* set-Gb/set-NLEb (jump greater) */
9114 t1 = newTemp(Ity_I8);
9115 assign( t1, unop(Iop_1Uto8,calculate_condition(opc-0x90)) );
9116 modrm = getIByte(delta);
9117 if (epartIsReg(modrm)) {
9118 delta++;
9119 putIReg(1, eregOfRM(modrm), mkexpr(t1));
9120 DIP("set%s %s\n", name_Condcode(opc-0x90),
9121 nameIReg(1,eregOfRM(modrm)));
9122 } else {
sewardj750f4072004-07-26 22:39:11 +00009123 addr = disAMode ( &alen, sorb, delta, dis_buf );
9124 delta += alen;
9125 storeLE( mkexpr(addr), mkexpr(t1) );
9126 DIP("set%s %s\n", name_Condcode(opc-0x90), dis_buf);
sewardj77b86be2004-07-11 13:28:24 +00009127 }
9128 break;
9129
sewardj180e8b32004-07-29 01:40:11 +00009130 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
9131
9132 case 0xA4: /* SHLDv imm8,Gv,Ev */
9133 modrm = getIByte(delta);
9134 d32 = delta + lengthAMode(delta);
9135 vex_sprintf(dis_buf, "$%d", delta);
9136 delta = dis_SHLRD_Gv_Ev (
9137 sorb, delta, modrm, sz,
9138 mkU8(getIByte(d32)), True, /* literal */
9139 dis_buf, True );
9140 break;
sewardja06e5562004-07-14 13:18:05 +00009141 case 0xA5: /* SHLDv %cl,Gv,Ev */
9142 modrm = getIByte(delta);
9143 delta = dis_SHLRD_Gv_Ev (
9144 sorb, delta, modrm, sz,
9145 getIReg(1,R_ECX), False, /* not literal */
9146 "%cl", True );
9147 break;
9148
sewardj68511542004-07-28 00:15:44 +00009149 case 0xAC: /* SHRDv imm8,Gv,Ev */
9150 modrm = getIByte(delta);
9151 d32 = delta + lengthAMode(delta);
9152 vex_sprintf(dis_buf, "$%d", delta);
9153 delta = dis_SHLRD_Gv_Ev (
9154 sorb, delta, modrm, sz,
9155 mkU8(getIByte(d32)), True, /* literal */
9156 dis_buf, False );
9157 break;
sewardja511afc2004-07-29 22:26:03 +00009158 case 0xAD: /* SHRDv %cl,Gv,Ev */
9159 modrm = getIByte(delta);
9160 delta = dis_SHLRD_Gv_Ev (
9161 sorb, delta, modrm, sz,
9162 getIReg(1,R_ECX), False, /* not literal */
9163 "%cl", False );
9164 break;
9165
sewardj883b00b2004-09-11 09:30:24 +00009166//-- /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
sewardjc9a65702004-07-07 16:32:57 +00009167//--
9168//-- case 0xC0: /* XADD Gb,Eb */
9169//-- eip = dis_xadd_G_E ( cb, sorb, 1, eip );
9170//-- break;
sewardj883b00b2004-09-11 09:30:24 +00009171 case 0xC1: /* XADD Gv,Ev */
9172 delta = dis_xadd_G_E ( sorb, sz, delta );
9173 break;
9174
sewardjc9a65702004-07-07 16:32:57 +00009175//-- /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
9176//--
9177//-- case 0x0D: /* PREFETCH / PREFETCHW - 3Dnow!ery*/
9178//-- case 0x18: /* PREFETCHT0/PREFETCHT1/PREFETCHT2/PREFETCHNTA */
9179//--
9180//-- vg_assert(sz == 4);
9181//-- modrm = getUChar(eip);
9182//-- if (epartIsReg(modrm)) {
9183//-- goto decode_failure;
9184//-- }
9185//-- if (gregOfRM(modrm) > 3) {
9186//-- goto decode_failure;
9187//-- }
9188//-- eip += lengthAMode(eip);
9189//-- if (VG_(print_codegen)) {
9190//-- UChar* hintstr;
9191//-- if (opc == 0x0D) {
9192//-- switch (gregOfRM(modrm)) {
9193//-- case 0: hintstr = ""; break;
9194//-- case 1: hintstr = "w"; break;
9195//-- default: goto decode_failure;
9196//-- }
9197//-- }
9198//-- else {
9199//-- switch (gregOfRM(modrm)) {
9200//-- case 0: hintstr = "nta"; break;
9201//-- case 1: hintstr = "t0"; break;
9202//-- case 2: hintstr = "t1"; break;
9203//-- case 3: hintstr = "t2"; break;
9204//-- default: goto decode_failure;
9205//-- }
9206//-- }
9207//-- VG_(printf)("prefetch%s ...\n", hintstr);
9208//-- }
9209//-- break;
9210//--
9211//-- case 0x71: case 0x72: case 0x73: {
9212//-- /* (sz==4): PSLL/PSRA/PSRL mmxreg by imm8 */
9213//-- /* (sz==2): PSLL/PSRA/PSRL xmmreg by imm8 */
9214//-- UChar byte1, byte2, byte3, subopc, mmreg;
9215//-- vg_assert(sz == 4 || sz == 2);
9216//-- byte1 = opc; /* 0x71/72/73 */
9217//-- byte2 = getUChar(eip); eip++; /* amode / sub-opcode */
9218//-- byte3 = getUChar(eip); eip++; /* imm8 */
9219//-- mmreg = byte2 & 7;
9220//-- subopc = (byte2 >> 3) & 7;
9221//-- if (subopc == 2 || subopc == 6 || subopc == 4) {
9222//-- /* 2 == 010 == SRL, 6 == 110 == SLL, 4 == 100 == SRA */
9223//-- /* ok */
9224//-- } else
9225//-- if (sz == 2 && opc == 0x73 && (subopc == 7 || subopc == 3)) {
9226//-- /* 3 == PSRLDQ, 7 == PSLLDQ */
9227//-- /* This is allowable in SSE. Because sz==2 we fall thru to
9228//-- SSE5 below. */
9229//-- } else {
9230//-- eip -= (sz==2 ? 3 : 2);
9231//-- goto decode_failure;
9232//-- }
9233//-- if (sz == 4) {
9234//-- /* The leading 0x0F is implied for MMX*, so we don't
9235//-- include it. */
9236//-- uInstr2(cb, MMX3, 0,
9237//-- Lit16, (((UShort)byte1) << 8) | ((UShort)byte2),
9238//-- Lit16, ((UShort)byte3) );
9239//-- DIP("ps%s%s $%d, %s\n",
9240//-- ( subopc == 2 ? "rl"
9241//-- : subopc == 6 ? "ll"
9242//-- : subopc == 4 ? "ra"
9243//-- : "??"),
9244//-- nameMMXGran(opc & 3), (Int)byte3, nameMMXReg(mmreg) );
9245//-- } else {
9246//-- /* Whereas we have to include it for SSE. */
9247//-- uInstr3(cb, SSE5, 0,
9248//-- Lit16, (((UShort)0x66) << 8) | ((UShort)0x0F),
9249//-- Lit16, (((UShort)byte1) << 8) | ((UShort)byte2),
9250//-- Lit16, ((UShort)byte3) );
9251//-- DIP("ps%s%s $%d, %s\n",
9252//-- ( subopc == 2 ? "rl"
9253//-- : subopc == 6 ? "ll"
9254//-- : subopc == 4 ? "ra"
9255//-- : subopc == 3 ? "(PSRLDQ)"
9256//-- : subopc == 7 ? "(PSLLDQ)"
9257//-- : "??"),
9258//-- nameMMXGran(opc & 3), (Int)byte3, nameXMMReg(mmreg) );
9259//-- }
9260//-- break;
9261//-- }
9262//--
9263//-- case 0x77: /* EMMS */
9264//-- vg_assert(sz == 4);
9265//-- uInstr1(cb, MMX1, 0, Lit16, ((UShort)(opc)) );
9266//-- DIP("emms\n");
9267//-- break;
9268//--
9269//-- case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
9270//-- vg_assert(sz == 4);
9271//-- modrm = getUChar(eip);
9272//-- if (epartIsReg(modrm)) {
9273//-- eip++;
9274//-- t1 = newTemp(cb);
9275//-- uInstr2(cb, MMX2_ERegWr, 4,
9276//-- Lit16,
9277//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
9278//-- TempReg, t1 );
9279//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, eregOfRM(modrm));
9280//-- DIP("movd %s, %s\n",
9281//-- nameMMXReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
9282//-- } else {
9283//-- Int tmpa;
9284//-- pair = disAMode ( cb, sorb, eip, dis_buf );
9285//-- tmpa = LOW24(pair);
9286//-- eip += HI8(pair);
9287//-- uInstr2(cb, MMX2_MemWr, 4,
9288//-- Lit16,
9289//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
9290//-- TempReg, tmpa);
9291//-- DIP("movd %s, %s\n", nameMMXReg(gregOfRM(modrm)), dis_buf);
9292//-- }
9293//-- break;
9294//--
9295//-- case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
9296//-- vg_assert(sz == 4);
9297//-- modrm = getUChar(eip);
9298//-- if (epartIsReg(modrm)) {
9299//-- eip++;
9300//-- t1 = newTemp(cb);
9301//-- uInstr2(cb, GET, 4, ArchReg, eregOfRM(modrm), TempReg, t1);
9302//-- uInstr2(cb, MMX2_ERegRd, 4,
9303//-- Lit16,
9304//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
9305//-- TempReg, t1 );
9306//-- DIP("movd %s, %s\n",
9307//-- nameIReg(4,eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
9308//-- } else {
9309//-- Int tmpa;
9310//-- pair = disAMode ( cb, sorb, eip, dis_buf );
9311//-- tmpa = LOW24(pair);
9312//-- eip += HI8(pair);
9313//-- uInstr2(cb, MMX2_MemRd, 4,
9314//-- Lit16,
9315//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
9316//-- TempReg, tmpa);
9317//-- DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregOfRM(modrm)));
9318//-- }
9319//-- break;
9320//--
9321//-- case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
9322//-- vg_assert(sz == 4);
9323//-- modrm = getUChar(eip);
9324//-- if (epartIsReg(modrm)) {
9325//-- eip++;
9326//-- uInstr1(cb, MMX2, 0,
9327//-- Lit16,
9328//-- (((UShort)(opc)) << 8) | ((UShort)modrm) );
9329//-- DIP("movq %s, %s\n",
9330//-- nameMMXReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
9331//-- } else {
9332//-- Int tmpa;
9333//-- pair = disAMode ( cb, sorb, eip, dis_buf );
9334//-- tmpa = LOW24(pair);
9335//-- eip += HI8(pair);
9336//-- uInstr2(cb, MMX2_MemRd, 8,
9337//-- Lit16,
9338//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
9339//-- TempReg, tmpa);
9340//-- DIP("movq %s, %s\n",
9341//-- dis_buf, nameMMXReg(gregOfRM(modrm)));
9342//-- }
9343//-- break;
9344//--
9345//-- case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
9346//-- case 0xE7: /* MOVNTQ (src)mmxreg, (dst)mmxreg-or-mem */
9347//-- vg_assert(sz == 4);
9348//-- modrm = getUChar(eip);
9349//-- if (epartIsReg(modrm)) {
9350//-- eip++;
9351//-- uInstr1(cb, MMX2, 0,
9352//-- Lit16,
9353//-- (((UShort)(opc)) << 8) | ((UShort)modrm) );
9354//-- DIP("movq %s, %s\n",
9355//-- nameMMXReg(gregOfRM(modrm)), nameMMXReg(eregOfRM(modrm)));
9356//-- } else {
9357//-- Int tmpa;
9358//-- pair = disAMode ( cb, sorb, eip, dis_buf );
9359//-- tmpa = LOW24(pair);
9360//-- eip += HI8(pair);
9361//-- uInstr2(cb, MMX2_MemWr, 8,
9362//-- Lit16,
9363//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
9364//-- TempReg, tmpa);
9365//-- DIP("mov(nt)q %s, %s\n",
9366//-- nameMMXReg(gregOfRM(modrm)), dis_buf);
9367//-- }
9368//-- break;
9369//--
9370//-- case 0xFC: case 0xFD: case 0xFE:
9371//-- /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
9372//-- vg_assert(sz == 4);
9373//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "padd", True );
9374//-- break;
9375//--
9376//-- case 0xD4:
9377//-- /* PADDQ (src)mmxreg-or-mem, (dst)mmxreg */
9378//-- vg_assert(sz == 4);
9379//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "paddq", False );
9380//-- break;
9381//--
9382//-- case 0xEC: case 0xED:
9383//-- /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
9384//-- vg_assert(sz == 4);
9385//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "padds", True );
9386//-- break;
9387//--
9388//-- case 0xDC: case 0xDD:
9389//-- /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
9390//-- vg_assert(sz == 4);
9391//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "paddus", True );
9392//-- break;
9393//--
9394//-- case 0xF8: case 0xF9: case 0xFA: case 0xFB:
9395//-- /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
9396//-- vg_assert(sz == 4);
9397//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psub", True );
9398//-- break;
9399//--
9400//-- case 0xE8: case 0xE9:
9401//-- /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
9402//-- vg_assert(sz == 4);
9403//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psubs", True );
9404//-- break;
9405//--
9406//-- case 0xD8: case 0xD9:
9407//-- /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
9408//-- vg_assert(sz == 4);
9409//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psubus", True );
9410//-- break;
9411//--
9412//-- case 0xE4: /* PMULHUW (src)mmxreg-or-mem, (dst)mmxreg */
9413//-- vg_assert(sz == 4);
9414//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmulhuw", False );
9415//-- break;
9416//--
9417//-- case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
9418//-- vg_assert(sz == 4);
9419//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmulhw", False );
9420//-- break;
9421//--
9422//-- case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
9423//-- vg_assert(sz == 4);
9424//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmullw", False );
9425//-- break;
9426//--
9427//-- case 0xF4: /* PMULUDQ (src)mmxreg-or-mem, (dst)mmxreg */
9428//-- vg_assert(sz == 4);
9429//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmuludq", False );
9430//-- break;
9431//--
9432//-- case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
9433//-- vg_assert(sz == 4);
9434//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmaddwd", False );
9435//-- break;
9436//--
9437//-- case 0x74: case 0x75: case 0x76:
9438//-- /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
9439//-- vg_assert(sz == 4);
9440//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pcmpeq", True );
9441//-- break;
9442//--
9443//-- case 0x64: case 0x65: case 0x66:
9444//-- /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
9445//-- vg_assert(sz == 4);
9446//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pcmpgt", True );
9447//-- break;
9448//--
9449//-- case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
9450//-- vg_assert(sz == 4);
9451//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "packssdw", False );
9452//-- break;
9453//--
9454//-- case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
9455//-- vg_assert(sz == 4);
9456//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "packsswb", False );
9457//-- break;
9458//--
9459//-- case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
9460//-- vg_assert(sz == 4);
9461//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "packuswb", False );
9462//-- break;
9463//--
9464//-- case 0x68: case 0x69: case 0x6A:
9465//-- /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
9466//-- vg_assert(sz == 4);
9467//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "punpckh", True );
9468//-- break;
9469//--
9470//-- case 0x60: case 0x61: case 0x62:
9471//-- /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
9472//-- vg_assert(sz == 4);
9473//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "punpckl", True );
9474//-- break;
9475//--
9476//-- case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
9477//-- vg_assert(sz == 4);
9478//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pand", False );
9479//-- break;
9480//--
9481//-- case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
9482//-- vg_assert(sz == 4);
9483//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pandn", False );
9484//-- break;
9485//--
9486//-- case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
9487//-- vg_assert(sz == 4);
9488//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "por", False );
9489//-- break;
9490//--
9491//-- case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
9492//-- vg_assert(sz == 4);
9493//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pxor", False );
9494//-- break;
9495//--
9496//-- case 0xF1: case 0xF2: case 0xF3:
9497//-- /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
9498//-- vg_assert(sz == 4);
9499//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psll", True );
9500//-- break;
9501//--
9502//-- case 0xD1: case 0xD2: case 0xD3:
9503//-- /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
9504//-- vg_assert(sz == 4);
9505//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psrl", True );
9506//-- break;
9507//--
9508//-- case 0xE1: case 0xE2:
9509//-- /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
9510//-- vg_assert(sz == 4);
9511//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psra", True );
9512//-- break;
9513//--
9514//-- case 0xDA:
9515//-- /* PMINUB (src)mmxreg-or-mem, (dst)mmxreg */
9516//-- vg_assert(sz == 4);
9517//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pminub", False );
9518//-- break;
9519//--
9520//-- case 0xDE:
9521//-- /* PMAXUB (src)mmxreg-or-mem, (dst)mmxreg */
9522//-- vg_assert(sz == 4);
9523//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmaxub", False );
9524//-- break;
9525//--
9526//-- case 0xEA:
9527//-- /* PMINSW (src)mmxreg-or-mem, (dst)mmxreg */
9528//-- vg_assert(sz == 4);
9529//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pminsw", False );
9530//-- break;
9531//--
9532//-- case 0xEE:
9533//-- /* PMAXSW (src)mmxreg-or-mem, (dst)mmxreg */
9534//-- vg_assert(sz == 4);
9535//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmaxsw", False );
9536//-- break;
9537//--
9538//-- case 0xE0:
9539//-- /* PAVGB (src)mmxreg-or-mem, (dst)mmxreg */
9540//-- vg_assert(sz == 4);
9541//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pavgb", False );
9542//-- break;
9543//--
9544//-- case 0xE3:
9545//-- /* PAVGW (src)mmxreg-or-mem, (dst)mmxreg */
9546//-- vg_assert(sz == 4);
9547//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pavgw", False );
9548//-- break;
9549//--
9550//-- case 0xF6:
9551//-- /* PSADBW (src)mmxreg-or-mem, (dst)mmxreg */
9552//-- vg_assert(sz == 4);
9553//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psadbw", False );
9554//-- break;
9555//--
9556//-- case 0x70:
9557//-- /* PSHUFW imm8, (src)mmxreg-or-mem, (dst)mmxreg */
9558//-- vg_assert(sz == 4);
9559//-- eip = dis_MMXop_regmem_to_reg_Imm8 ( cb, sorb, eip, opc, "pshufw", False );
9560//-- break;
9561//--
9562//-- case 0xD7:
9563//-- /* PMOVMSKB (src)mmxreg, (dst)ireg */
9564//-- vg_assert(sz == 4);
9565//-- modrm = getUChar(eip);
9566//-- vg_assert(epartIsReg(modrm));
9567//-- t1 = newTemp(cb);
9568//-- uInstr3(cb, SSE2g_RegWr, 4,
9569//-- Lit16, (((UShort)(0x0F)) << 8) | (UShort)(opc),
9570//-- Lit16, (UShort)modrm,
9571//-- TempReg, t1 );
9572//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
9573//-- DIP("pmovmskb %s, %s\n",
9574//-- nameMMXReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)));
9575//-- eip++;
9576//-- break;
9577//--
9578//-- case 0xC5:
9579//-- /* PEXTRW (src)mmxreg, (dst)ireg */
9580//-- vg_assert(sz == 4);
9581//-- t1 = newTemp(cb);
9582//-- modrm = getUChar(eip); eip++;
9583//-- abyte = getUChar(eip); eip++;
9584//-- vg_assert(epartIsReg(modrm));
9585//-- uInstr3(cb, SSE2g1_RegWr, 4,
9586//-- Lit16, (((UShort)(0x0F)) << 8) | (UShort)(opc),
9587//-- Lit16, (UShort)modrm,
9588//-- TempReg, t1 );
9589//-- uLiteral(cb, abyte);
9590//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
9591//-- DIP("pextrw %s, %d, %s\n",
9592//-- nameMMXReg(eregOfRM(modrm)), (Int)abyte,
9593//-- nameIReg(4, gregOfRM(modrm)));
9594//-- break;
9595//--
9596//-- case 0xC4:
9597//-- /* PINSRW (src)ireg, (dst)mmxreg */
9598//-- vg_assert(sz == 4);
9599//-- t1 = newTemp(cb);
9600//-- modrm = getUChar(eip); eip++;
9601//-- abyte = getUChar(eip); eip++;
9602//-- vg_assert(epartIsReg(modrm));
9603//-- uInstr2(cb, GET, 2, ArchReg, eregOfRM(modrm), TempReg, t1);
9604//-- uInstr3(cb, SSE2e1_RegRd, 2,
9605//-- Lit16, (((UShort)(0x0F)) << 8) | (UShort)(opc),
9606//-- Lit16, (UShort)modrm,
9607//-- TempReg, t1 );
9608//-- uLiteral(cb, abyte);
9609//-- DIP("pinsrw %s, %d, %s\n", nameIReg(2, eregOfRM(modrm)),
9610//-- (Int)abyte, nameMMXReg(gregOfRM(modrm)));
9611//-- break;
9612//--
9613//-- case 0xA1: /* POP %FS */
9614//-- dis_pop_segreg( cb, R_FS, sz ); break;
9615//-- case 0xA9: /* POP %GS */
9616//-- dis_pop_segreg( cb, R_GS, sz ); break;
9617//--
9618//-- case 0xA0: /* PUSH %FS */
9619//-- dis_push_segreg( cb, R_FS, sz ); break;
9620//-- case 0xA8: /* PUSH %GS */
9621//-- dis_push_segreg( cb, R_GS, sz ); break;
sewardje87b4842004-07-10 12:23:30 +00009622
9623 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
9624
9625 default:
9626 goto decode_failure;
9627 } /* switch (opc) for the 2-byte opcodes */
9628 goto decode_success;
9629 } /* case 0x0F: of primary opcode */
sewardjc9a65702004-07-07 16:32:57 +00009630
9631 /* ------------------------ ??? ------------------------ */
9632
9633 default:
sewardje87b4842004-07-10 12:23:30 +00009634 decode_failure:
sewardjc9a65702004-07-07 16:32:57 +00009635 /* All decode failures end up here. */
9636 vex_printf("disInstr(x86): unhandled instruction bytes: "
9637 "0x%x 0x%x 0x%x 0x%x\n",
9638 (Int)getIByte(delta_start+0),
9639 (Int)getIByte(delta_start+1),
9640 (Int)getIByte(delta_start+2),
9641 (Int)getIByte(delta_start+3) );
9642 vpanic("x86toIR: unimplemented insn");
9643 /* Print address of failing instruction. */
9644 //VG_(describe_eip)((Addr)eip_start, loc_buf, M_VG_ERRTXT);
9645 //VG_(printf)(" at %s\n", loc_buf);
9646
9647 //uInstr0(cb, CALLM_S, 0);
9648 //uInstr1(cb, CALLM, 0, Lit16,
9649 // VGOFF_(helper_undefined_instruction));
9650 //uInstr0(cb, CALLM_E, 0);
9651
9652 /* just because everything else insists the last instruction of
9653 a BB is a jmp */
9654 //jmp_lit(cb, eip);
sewardjce70a5c2004-10-18 14:09:54 +00009655 //whatNext = Dis_StopHere;
sewardjc9a65702004-07-07 16:32:57 +00009656 //break;
9657 //return eip;
9658
9659 } /* switch (opc) for the main (primary) opcode switch. */
9660
sewardje87b4842004-07-10 12:23:30 +00009661 decode_success:
sewardjc9a65702004-07-07 16:32:57 +00009662 /* All decode successes end up here. */
9663 DIP("\n");
sewardjd7cb8532004-08-17 23:59:23 +00009664 { Int i;
sewardjce70a5c2004-10-18 14:09:54 +00009665 if (print_codegen) {
9666 for (i = first_stmt_idx; i < irbb->stmts_used; i++) {
sewardjd7cb8532004-08-17 23:59:23 +00009667 vex_printf(" ");
9668 ppIRStmt(irbb->stmts[i]);
9669 vex_printf("\n");
9670 }
9671 }
sewardjc9a65702004-07-07 16:32:57 +00009672 }
sewardjce70a5c2004-10-18 14:09:54 +00009673 if (whatNext == Dis_StopHere) {
sewardjd1061ab2004-07-08 01:45:30 +00009674 vassert(irbb->next != NULL);
sewardje539a402004-07-14 18:24:17 +00009675 if (print_codegen) {
9676 vex_printf(" ");
9677 vex_printf( "goto {");
9678 ppIRJumpKind(irbb->jumpkind);
9679 vex_printf( "} ");
9680 ppIRExpr( irbb->next );
9681 vex_printf( "\n");
9682 }
sewardjd1061ab2004-07-08 01:45:30 +00009683 }
sewardjc9a65702004-07-07 16:32:57 +00009684
sewardjce70a5c2004-10-18 14:09:54 +00009685 *size = delta - delta_start;
9686 return whatNext;
sewardjc9a65702004-07-07 16:32:57 +00009687}
9688
9689#undef DIP
9690#undef DIS
9691
9692/*--------------------------------------------------------------------*/
sewardjc0ee2ed2004-07-27 10:29:41 +00009693/*--- end guest-x86/toIR.c ---*/
sewardjc9a65702004-07-07 16:32:57 +00009694/*--------------------------------------------------------------------*/