blob: da621c3ddc72fa22d7dce3c471248d28936c5461 [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
sewardjf8ed9d82004-11-12 17:40:23 +00009/*
10 This file is part of LibVEX, a library for dynamic binary
11 instrumentation and translation.
12
13 Copyright (C) 2004 OpenWorks, LLP.
14
15 This program is free software; you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation; Version 2 dated June 1991 of the
18 license.
19
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or liability
23 for damages. See the GNU General Public License for more details.
24
25 Neither the names of the U.S. Department of Energy nor the
26 University of California nor the names of its contributors may be
27 used to endorse or promote products derived from this software
28 without prior written permission.
29
30 You should have received a copy of the GNU General Public License
31 along with this program; if not, write to the Free Software
32 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
33 USA.
34*/
35
sewardj77b86be2004-07-11 13:28:24 +000036/* TODO:
sewardj1f40a0a2004-07-21 12:28:07 +000037 SBB reg with itself
sewardj1f40a0a2004-07-21 12:28:07 +000038 MOVAPS fix (vg_to_ucode rev 1.143)
sewardj458a6f82004-08-25 12:46:02 +000039 check flag settings for cmpxchg
sewardj883b00b2004-09-11 09:30:24 +000040 FUCOMI(P): what happens to A and S flags? Currently are forced
41 to zero.
sewardje166ed02004-10-25 02:27:01 +000042 Fix CPUID, or more precisely, eflags bit 21 so it is changeable.
sewardj3f61ddb2004-10-16 20:51:05 +000043
sewardjce70a5c2004-10-18 14:09:54 +000044 x87 FP Limitations:
sewardj3f61ddb2004-10-16 20:51:05 +000045 * no FP exceptions, except for handling stack over/underflow
46 * FP rounding mode observed only for float->int conversions
47 * FP sin/cos/tan/sincos: C2 flag is always cleared. IOW the
48 simulation claims the argument is in-range (-2^63 <= arg <= 2^63)
49 even when it isn't.
sewardje166ed02004-10-25 02:27:01 +000050 * some of the FCOM cases could do with testing -- not convinced
51 that the args are the right way round.
sewardje05c42c2004-07-08 20:25:10 +000052*/
53
sewardjc9a65702004-07-07 16:32:57 +000054/* Translates x86 code to IR. */
55
56#include "libvex_basictypes.h"
57#include "libvex_ir.h"
sewardje87b4842004-07-10 12:23:30 +000058#include "libvex.h"
sewardjf6dc3ce2004-10-19 01:03:46 +000059#include "libvex_guest_x86.h"
sewardjc0ee2ed2004-07-27 10:29:41 +000060
61#include "main/vex_util.h"
62#include "main/vex_globals.h"
63#include "guest-x86/gdefs.h"
sewardjc9a65702004-07-07 16:32:57 +000064
65
66/*------------------------------------------------------------*/
67/*--- Globals ---*/
68/*------------------------------------------------------------*/
69
70/* These are set at the start of the translation of a BB, so
71 that we don't have to pass them around endlessly. */
72
73/* We need to know this to do sub-register accesses correctly. */
74/* CONST */
75static Bool host_is_bigendian;
76
sewardjc9a65702004-07-07 16:32:57 +000077/* Pointer to the guest code area. */
78/* CONST */
79static UChar* guest_code;
80
81/* The guest address corresponding to guest_code[0]. */
82/* CONST */
sewardjce70a5c2004-10-18 14:09:54 +000083static Addr32 guest_eip_bbstart;
sewardjc9a65702004-07-07 16:32:57 +000084
sewardjd7cb8532004-08-17 23:59:23 +000085/* The IRBB* into which we're generating code. */
sewardjc9a65702004-07-07 16:32:57 +000086static IRBB* irbb;
87
sewardjc9a65702004-07-07 16:32:57 +000088
sewardjce70a5c2004-10-18 14:09:54 +000089/*------------------------------------------------------------*/
90/*--- Debugging output ---*/
91/*------------------------------------------------------------*/
92
sewardjf48ac192004-10-29 00:41:29 +000093#define DIP(format, args...) \
94 if (vex_traceflags & VEX_TRACE_FE) \
sewardjce70a5c2004-10-18 14:09:54 +000095 vex_printf(format, ## args)
96
sewardjf48ac192004-10-29 00:41:29 +000097#define DIS(buf, format, args...) \
98 if (vex_traceflags & VEX_TRACE_FE) \
sewardjce70a5c2004-10-18 14:09:54 +000099 vex_sprintf(buf, format, ## args)
100
101
102/*------------------------------------------------------------*/
sewardjdcc85fc2004-10-26 13:26:20 +0000103/*--- Offsets of various parts of the x86 guest state. ---*/
104/*------------------------------------------------------------*/
105
sewardj2a2ba8b2004-11-08 13:14:06 +0000106#define OFFB_FPREGS offsetof(VexGuestX86State,guest_FPREG[0])
107#define OFFB_FPTAGS offsetof(VexGuestX86State,guest_FPTAG[0])
108#define OFFB_EAX offsetof(VexGuestX86State,guest_EAX)
109#define OFFB_EBX offsetof(VexGuestX86State,guest_EBX)
110#define OFFB_ECX offsetof(VexGuestX86State,guest_ECX)
111#define OFFB_EDX offsetof(VexGuestX86State,guest_EDX)
112#define OFFB_EIP offsetof(VexGuestX86State,guest_EIP)
113
114#define OFFB_CC_OP offsetof(VexGuestX86State,guest_CC_OP)
115#define OFFB_CC_DEP1 offsetof(VexGuestX86State,guest_CC_DEP1)
116#define OFFB_CC_DEP2 offsetof(VexGuestX86State,guest_CC_DEP2)
117#define OFFB_CC_NDEP offsetof(VexGuestX86State,guest_CC_NDEP)
118
119#define OFFB_DFLAG offsetof(VexGuestX86State,guest_DFLAG)
120#define OFFB_IDFLAG offsetof(VexGuestX86State,guest_IDFLAG)
121#define OFFB_FTOP offsetof(VexGuestX86State,guest_FTOP)
122#define OFFB_FC3210 offsetof(VexGuestX86State,guest_FC3210)
123#define OFFB_FPUCW offsetof(VexGuestX86State,guest_FPUCW)
sewardjdcc85fc2004-10-26 13:26:20 +0000124
125
126/*------------------------------------------------------------*/
sewardjce70a5c2004-10-18 14:09:54 +0000127/*--- Disassemble an entire basic block ---*/
128/*------------------------------------------------------------*/
129
130/* The results of disassembling an instruction. There are three
131 possible outcomes. For Dis_Resteer, the disassembler _must_
132 continue at the specified address. For Dis_StopHere, the
133 disassembler _must_ terminate the BB. For Dis_Continue, we may at
134 our option either disassemble the next insn, or terminate the BB;
135 but in the latter case we must set the bb's ->next field to point
136 to the next instruction. */
137
138typedef
139 enum {
140 Dis_StopHere, /* this insn terminates the BB; we must stop. */
141 Dis_Continue, /* we can optionally continue into the next insn */
142 Dis_Resteer /* followed a branch; continue at the spec'd addr */
143 }
144 DisResult;
145
146
147/* forward decls .. */
148static IRExpr* mkU32 ( UInt i );
sewardjdcc85fc2004-10-26 13:26:20 +0000149static void stmt ( IRStmt* st );
150
sewardjce70a5c2004-10-18 14:09:54 +0000151
152/* disInstr disassembles an instruction located at &guest_code[delta],
153 and sets *size to its size. If the returned value is Dis_Resteer,
sewardj5bd4d162004-11-10 13:02:48 +0000154 the next guest address is assigned to *whereNext. disInstr is not
155 permitted to return Dis_Resteer if either (1) resteerOK is False,
156 or (2) resteerOkFn, when applied to the address which it wishes to
157 resteer into, returns False. */
sewardjce70a5c2004-10-18 14:09:54 +0000158
159static DisResult disInstr ( /*IN*/ Bool resteerOK,
sewardj5bd4d162004-11-10 13:02:48 +0000160 /*IN*/ Bool (*resteerOkFn) ( Addr64 ),
sewardjce70a5c2004-10-18 14:09:54 +0000161 /*IN*/ UInt delta,
162 /*OUT*/ UInt* size,
163 /*OUT*/ Addr64* whereNext );
164
165
166/* This is the main (only, in fact) entry point for this module. */
167
168/* Disassemble a complete basic block, starting at eip, and dumping
169 the ucode into cb. Returns the size, in bytes, of the basic
170 block. */
171IRBB* bbToIR_X86Instr ( UChar* x86code,
172 Addr64 guest_eip_start,
173 Int* guest_bytes_read,
174 Bool (*byte_accessible)(Addr64),
sewardj5bd4d162004-11-10 13:02:48 +0000175 Bool (*chase_into_ok)(Addr64),
sewardjce70a5c2004-10-18 14:09:54 +0000176 Bool host_bigendian )
177{
178 UInt delta;
sewardjdcc85fc2004-10-26 13:26:20 +0000179 Int i, n_instrs, size, first_stmt_idx;
sewardjce70a5c2004-10-18 14:09:54 +0000180 Addr64 guest_next;
181 Bool resteerOK;
182 DisResult dres;
183 static Int n_resteers = 0;
184 Int d_resteers = 0;
sewardj08613742004-10-25 13:01:45 +0000185
186 /* check sanity .. */
187 vassert(vex_control.guest_max_insns >= 1);
188 vassert(vex_control.guest_max_insns < 1000);
189 vassert(vex_control.guest_chase_thresh >= 0);
190 vassert(vex_control.guest_chase_thresh < vex_control.guest_max_insns);
sewardjce70a5c2004-10-18 14:09:54 +0000191
192 /* Set up globals. */
193 host_is_bigendian = host_bigendian;
sewardjce70a5c2004-10-18 14:09:54 +0000194 guest_code = x86code;
195 guest_eip_bbstart = (Addr32)guest_eip_start;
196 irbb = emptyIRBB();
197
sewardjce70a5c2004-10-18 14:09:54 +0000198 vassert((guest_eip_start >> 32) == 0);
sewardjce70a5c2004-10-18 14:09:54 +0000199
sewardjce70a5c2004-10-18 14:09:54 +0000200 /* Delta keeps track of how far along the x86code array we
201 have so far gone. */
202 delta = 0;
203 n_instrs = 0;
204 *guest_bytes_read = 0;
205
206 while (True) {
sewardj08613742004-10-25 13:01:45 +0000207 vassert(n_instrs < vex_control.guest_max_insns);
sewardjce70a5c2004-10-18 14:09:54 +0000208
209 guest_next = 0;
sewardj08613742004-10-25 13:01:45 +0000210 resteerOK = n_instrs < vex_control.guest_chase_thresh;
sewardjdcc85fc2004-10-26 13:26:20 +0000211 first_stmt_idx = irbb->stmts_used;
212
213 if (n_instrs > 0) {
214 /* for the first insn, the dispatch loop will have set
sewardj5bd4d162004-11-10 13:02:48 +0000215 %EIP, but for all the others we have to do it ourselves. */
sewardjdcc85fc2004-10-26 13:26:20 +0000216 stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_eip_bbstart + delta)) );
217 }
218
sewardj5bd4d162004-11-10 13:02:48 +0000219 dres = disInstr( resteerOK, chase_into_ok,
220 delta, &size, &guest_next );
sewardjdcc85fc2004-10-26 13:26:20 +0000221
222 /* Print the resulting IR, if needed. */
sewardjf48ac192004-10-29 00:41:29 +0000223 if (vex_traceflags & VEX_TRACE_FE) {
sewardjdcc85fc2004-10-26 13:26:20 +0000224 for (i = first_stmt_idx; i < irbb->stmts_used; i++) {
225 vex_printf(" ");
226 ppIRStmt(irbb->stmts[i]);
227 vex_printf("\n");
228 }
229 }
230
231 if (dres == Dis_StopHere) {
232 vassert(irbb->next != NULL);
sewardjf48ac192004-10-29 00:41:29 +0000233 if (vex_traceflags & VEX_TRACE_FE) {
sewardjdcc85fc2004-10-26 13:26:20 +0000234 vex_printf(" ");
235 vex_printf( "goto {");
236 ppIRJumpKind(irbb->jumpkind);
237 vex_printf( "} ");
238 ppIRExpr( irbb->next );
239 vex_printf( "\n");
240 }
241 }
242
sewardjce70a5c2004-10-18 14:09:54 +0000243 delta += size;
244 *guest_bytes_read += size;
245 n_instrs++;
246 DIP("\n");
247
248 vassert(size > 0 && size <= 18);
249 if (!resteerOK)
250 vassert(dres != Dis_Resteer);
251 if (dres != Dis_Resteer)
252 vassert(guest_next == 0);
253
254 switch (dres) {
255 case Dis_Continue:
256 vassert(irbb->next == NULL);
sewardj08613742004-10-25 13:01:45 +0000257 if (n_instrs < vex_control.guest_max_insns) {
sewardjce70a5c2004-10-18 14:09:54 +0000258 /* keep going */
259 } else {
260 irbb->next = mkU32(((Addr32)guest_eip_start)+delta);
261 return irbb;
262 }
263 break;
264 case Dis_StopHere:
265 vassert(irbb->next != NULL);
266 return irbb;
267 case Dis_Resteer:
268 vassert(irbb->next == NULL);
269 /* figure out a new delta to continue at. */
sewardj5bd4d162004-11-10 13:02:48 +0000270 vassert(chase_into_ok(guest_next));
sewardjce70a5c2004-10-18 14:09:54 +0000271 delta = (UInt)(guest_next - guest_eip_start);
272 n_resteers++;
273 d_resteers++;
274 if (0 && (n_resteers & 0xFF) == 0)
sewardj5bd4d162004-11-10 13:02:48 +0000275 vex_printf("resteer[%d,%d] to %p (delta = %d)\n",
276 n_resteers, d_resteers,
sewardjce70a5c2004-10-18 14:09:54 +0000277 (void*)(UInt)(guest_next), delta);
278 break;
279 }
280 }
281}
282
283
284/*------------------------------------------------------------*/
285/*--- Helper bits and pieces for deconstructing the ---*/
286/*--- x86 insn stream. ---*/
287/*------------------------------------------------------------*/
288
289/* This is the Intel register encoding -- integer regs. */
290#define R_EAX 0
291#define R_ECX 1
292#define R_EDX 2
293#define R_EBX 3
294#define R_ESP 4
295#define R_EBP 5
296#define R_ESI 6
297#define R_EDI 7
298
299#define R_AL (0+R_EAX)
300#define R_AH (4+R_EAX)
301
sewardj063f02f2004-10-20 12:36:12 +0000302/* This is the Intel register encoding -- segment regs. */
303#define R_ES 0
304#define R_CS 1
305#define R_SS 2
306#define R_DS 3
307#define R_FS 4
308#define R_GS 5
309
sewardjce70a5c2004-10-18 14:09:54 +0000310
sewardjc9a65702004-07-07 16:32:57 +0000311/* Add a statement to the list held by "irbb". */
sewardjd7cb8532004-08-17 23:59:23 +0000312static void stmt ( IRStmt* st )
sewardjc9a65702004-07-07 16:32:57 +0000313{
sewardjd7cb8532004-08-17 23:59:23 +0000314 addStmtToIRBB( irbb, st );
sewardjc9a65702004-07-07 16:32:57 +0000315}
316
317/* Generate a new temporary of the given type. */
318static IRTemp newTemp ( IRType ty )
319{
sewardj6d2638e2004-07-15 09:38:27 +0000320 vassert(isPlausibleType(ty));
sewardje539a402004-07-14 18:24:17 +0000321 return newIRTemp( irbb->tyenv, ty );
sewardjc9a65702004-07-07 16:32:57 +0000322}
323
sewardjc9a65702004-07-07 16:32:57 +0000324/* Bomb out if we can't handle something. */
sewardjd1061ab2004-07-08 01:45:30 +0000325__attribute__ ((noreturn))
sewardjc9a65702004-07-07 16:32:57 +0000326static void unimplemented ( Char* str )
327{
328 vex_printf("x86toIR: unimplemented feature\n");
329 vpanic(str);
330}
331
sewardjce70a5c2004-10-18 14:09:54 +0000332/* Various simple conversions */
sewardjd1061ab2004-07-08 01:45:30 +0000333
sewardje05c42c2004-07-08 20:25:10 +0000334static UInt extend_s_8to32( UInt x )
sewardjd1061ab2004-07-08 01:45:30 +0000335{
336 return (UInt)((((Int)x) << 24) >> 24);
337}
338
sewardj0611d802004-07-11 02:37:54 +0000339static UInt extend_s_16to32 ( UInt x )
340{
341 return (UInt)((((Int)x) << 16) >> 16);
342}
343
sewardjd1061ab2004-07-08 01:45:30 +0000344/* Fetch a byte from the guest insn stream. */
sewardje05c42c2004-07-08 20:25:10 +0000345static UChar getIByte ( UInt delta )
sewardjd1061ab2004-07-08 01:45:30 +0000346{
347 return guest_code[delta];
348}
349
sewardjc9a65702004-07-07 16:32:57 +0000350/* Extract the reg field from a modRM byte. */
sewardje05c42c2004-07-08 20:25:10 +0000351static Int gregOfRM ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000352{
353 return (Int)( (mod_reg_rm >> 3) & 7 );
354}
355
356/* Figure out whether the mod and rm parts of a modRM byte refer to a
357 register or memory. If so, the byte will have the form 11XXXYYY,
358 where YYY is the register number. */
sewardje05c42c2004-07-08 20:25:10 +0000359static Bool epartIsReg ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000360{
361 return (0xC0 == (mod_reg_rm & 0xC0));
362}
363
364/* ... and extract the register number ... */
sewardje05c42c2004-07-08 20:25:10 +0000365static Int eregOfRM ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000366{
367 return (Int)(mod_reg_rm & 0x7);
368}
369
sewardje05c42c2004-07-08 20:25:10 +0000370/* Get a 8/16/32-bit unsigned value out of the insn stream. */
371
372static UInt getUChar ( UInt delta )
373{
374 UInt v = guest_code[delta+0];
375 return v & 0xFF;
376}
377
378static UInt getUDisp16 ( UInt delta )
379{
380 UInt v = guest_code[delta+1]; v <<= 8;
381 v |= guest_code[delta+0];
382 return v & 0xFFFF;
383}
384
385static UInt getUDisp32 ( UInt delta )
sewardjd1061ab2004-07-08 01:45:30 +0000386{
387 UInt v = guest_code[delta+3]; v <<= 8;
388 v |= guest_code[delta+2]; v <<= 8;
389 v |= guest_code[delta+1]; v <<= 8;
390 v |= guest_code[delta+0];
391 return v;
392}
393
sewardje05c42c2004-07-08 20:25:10 +0000394static UInt getUDisp ( Int size, UInt delta )
395{
396 switch (size) {
397 case 4: return getUDisp32(delta);
398 case 2: return getUDisp16(delta);
399 case 1: return getUChar(delta);
400 default: vpanic("getUDisp(x86)");
401 }
402 return 0; /*notreached*/
403}
404
405
sewardjd1061ab2004-07-08 01:45:30 +0000406/* Get a byte value out of the insn stream and sign-extend to 32
407 bits. */
sewardje05c42c2004-07-08 20:25:10 +0000408static UInt getSDisp8 ( UInt delta )
sewardjd1061ab2004-07-08 01:45:30 +0000409{
410 return extend_s_8to32( (UInt) (guest_code[delta]) );
411}
412
sewardj0611d802004-07-11 02:37:54 +0000413static UInt getSDisp16 ( UInt delta0 )
414{
415 UChar* eip = (UChar*)(&guest_code[delta0]);
416 UInt d = *eip++;
417 d |= ((*eip++) << 8);
418 return extend_s_16to32(d);
419}
420
421static UInt getSDisp ( Int size, UInt delta )
422{
423 switch (size) {
424 case 4: return getUDisp32(delta);
425 case 2: return getSDisp16(delta);
426 case 1: return getSDisp8(delta);
427 default: vpanic("getSDisp(x86)");
428 }
429 return 0; /*notreached*/
430}
sewardjd1061ab2004-07-08 01:45:30 +0000431
sewardjc9a65702004-07-07 16:32:57 +0000432
433/*------------------------------------------------------------*/
434/*--- Helpers for constructing IR. ---*/
435/*------------------------------------------------------------*/
436
437/* Create a 1/2/4 byte read of an x86 integer registers. For 16/8 bit
438 register references, we need to take the host endianness into
439 account. Supplied value is 0 .. 7 and in the Intel instruction
440 encoding. */
sewardje05c42c2004-07-08 20:25:10 +0000441
sewardj9334b0f2004-07-10 22:43:54 +0000442static IRType szToITy ( Int n )
443{
444 switch (n) {
445 case 1: return Ity_I8;
446 case 2: return Ity_I16;
447 case 4: return Ity_I32;
448 default: vpanic("szToITy(x86)");
449 }
450}
451
452static Int integerGuestRegOffset ( Int sz, UInt archreg )
453{
454 vassert(archreg < 8);
455
456 vassert(!host_is_bigendian);
457
458 /* Correct for little-endian host only. */
sewardj063f02f2004-10-20 12:36:12 +0000459
460 if (sz == 4 || sz == 2 || (sz == 1 && archreg < 4)) {
461 switch (archreg) {
462 case R_EAX: return offsetof(VexGuestX86State,guest_EAX);
463 case R_EBX: return offsetof(VexGuestX86State,guest_EBX);
464 case R_ECX: return offsetof(VexGuestX86State,guest_ECX);
465 case R_EDX: return offsetof(VexGuestX86State,guest_EDX);
466 case R_ESI: return offsetof(VexGuestX86State,guest_ESI);
467 case R_EDI: return offsetof(VexGuestX86State,guest_EDI);
468 case R_ESP: return offsetof(VexGuestX86State,guest_ESP);
469 case R_EBP: return offsetof(VexGuestX86State,guest_EBP);
470 default: vpanic("integerGuestRegOffset(x86,le)(4,2)");
471 }
472 }
473
474 vassert(archreg >= 4 && archreg < 8 && sz == 1);
475 switch (archreg-4) {
476 case R_EAX: return 1+ offsetof(VexGuestX86State,guest_EAX);
477 case R_EBX: return 1+ offsetof(VexGuestX86State,guest_EBX);
478 case R_ECX: return 1+ offsetof(VexGuestX86State,guest_ECX);
479 case R_EDX: return 1+ offsetof(VexGuestX86State,guest_EDX);
480 default: vpanic("integerGuestRegOffset(x86,le)(1h)");
481 }
482
483 /* NOTREACHED */
484 vpanic("integerGuestRegOffset(x86,le)");
485}
486
487static Int segmentGuestRegOffset ( UInt sreg )
488{
489 switch (sreg) {
490 case R_ES: return offsetof(VexGuestX86State,guest_ES);
491 case R_CS: return offsetof(VexGuestX86State,guest_CS);
492 case R_SS: return offsetof(VexGuestX86State,guest_SS);
493 case R_DS: return offsetof(VexGuestX86State,guest_DS);
494 case R_FS: return offsetof(VexGuestX86State,guest_FS);
495 case R_GS: return offsetof(VexGuestX86State,guest_GS);
496 default: vpanic("segmentGuestRegOffset(x86)");
sewardj9334b0f2004-07-10 22:43:54 +0000497 }
498}
499
sewardjd1061ab2004-07-08 01:45:30 +0000500static IRExpr* getIReg ( Int sz, UInt archreg )
sewardjc9a65702004-07-07 16:32:57 +0000501{
502 vassert(sz == 1 || sz == 2 || sz == 4);
503 vassert(archreg < 8);
sewardj9334b0f2004-07-10 22:43:54 +0000504 return IRExpr_Get( integerGuestRegOffset(sz,archreg),
sewardj5bd4d162004-11-10 13:02:48 +0000505 szToITy(sz) );
sewardjc9a65702004-07-07 16:32:57 +0000506}
507
508/* Ditto, but write to a reg instead. */
sewardj41f43bc2004-07-08 14:23:22 +0000509static void putIReg ( Int sz, UInt archreg, IRExpr* e )
sewardjc9a65702004-07-07 16:32:57 +0000510{
511 vassert(sz == 1 || sz == 2 || sz == 4);
512 vassert(archreg < 8);
sewardjeeb9ef82004-07-15 12:39:03 +0000513 stmt( IRStmt_Put(integerGuestRegOffset(sz,archreg), e) );
sewardjd1061ab2004-07-08 01:45:30 +0000514}
515
sewardj063f02f2004-10-20 12:36:12 +0000516static IRExpr* getSReg ( UInt sreg )
517{
518 return IRExpr_Get( segmentGuestRegOffset(sreg), Ity_I16 );
519}
520
sewardjf9655262004-10-31 20:02:16 +0000521#if 0
sewardj063f02f2004-10-20 12:36:12 +0000522static void putSReg ( UInt sreg, IRExpr* e )
523{
524 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I16);
525 stmt( IRStmt_Put( segmentGuestRegOffset(sreg), e ) );
526}
sewardjf9655262004-10-31 20:02:16 +0000527#endif
sewardj063f02f2004-10-20 12:36:12 +0000528
sewardj41f43bc2004-07-08 14:23:22 +0000529static void assign ( IRTemp dst, IRExpr* e )
sewardjd1061ab2004-07-08 01:45:30 +0000530{
sewardj41f43bc2004-07-08 14:23:22 +0000531 stmt( IRStmt_Tmp(dst, e) );
sewardjd1061ab2004-07-08 01:45:30 +0000532}
533
sewardj41f43bc2004-07-08 14:23:22 +0000534static void storeLE ( IRExpr* addr, IRExpr* data )
sewardjd1061ab2004-07-08 01:45:30 +0000535{
sewardj41f43bc2004-07-08 14:23:22 +0000536 stmt( IRStmt_STle(addr,data) );
sewardjd1061ab2004-07-08 01:45:30 +0000537}
538
sewardje87b4842004-07-10 12:23:30 +0000539static IRExpr* unop ( IROp op, IRExpr* a )
540{
541 return IRExpr_Unop(op, a);
542}
543
sewardjd1061ab2004-07-08 01:45:30 +0000544static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
545{
546 return IRExpr_Binop(op, a1, a2);
547}
548
549static IRExpr* mkexpr ( IRTemp tmp )
550{
551 return IRExpr_Tmp(tmp);
552}
553
sewardjc2ac51e2004-07-12 01:03:26 +0000554static IRExpr* mkU8 ( UInt i )
555{
556 vassert(i < 256);
557 return IRExpr_Const(IRConst_U8(i));
558}
559
560static IRExpr* mkU16 ( UInt i )
561{
562 vassert(i < 65536);
563 return IRExpr_Const(IRConst_U16(i));
564}
565
sewardjd1061ab2004-07-08 01:45:30 +0000566static IRExpr* mkU32 ( UInt i )
567{
568 return IRExpr_Const(IRConst_U32(i));
sewardjc9a65702004-07-07 16:32:57 +0000569}
570
sewardj41f43bc2004-07-08 14:23:22 +0000571static IRExpr* mkU ( IRType ty, UInt i )
572{
sewardjc2ac51e2004-07-12 01:03:26 +0000573 if (ty == Ity_I8) return mkU8(i);
574 if (ty == Ity_I16) return mkU16(i);
575 if (ty == Ity_I32) return mkU32(i);
sewardje90ad6a2004-07-10 19:02:10 +0000576 /* If this panics, it usually means you passed a size (1,2,4)
577 value as the IRType, rather than a real IRType. */
sewardj41f43bc2004-07-08 14:23:22 +0000578 vpanic("mkU(x86)");
579}
580
581static IRExpr* loadLE ( IRType ty, IRExpr* data )
582{
583 return IRExpr_LDle(ty,data);
584}
585
586static IROp mkSizedOp ( IRType ty, IROp op8 )
587{
sewardje05c42c2004-07-08 20:25:10 +0000588 Int adj;
sewardj41f43bc2004-07-08 14:23:22 +0000589 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
590 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8
sewardj41f43bc2004-07-08 14:23:22 +0000591 || op8 == Iop_Mul8
592 || op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
sewardj5bd4d162004-11-10 13:02:48 +0000593 || op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8
sewardje90ad6a2004-07-10 19:02:10 +0000594 || op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8
sewardj86b133b2004-11-15 13:54:26 +0000595 || op8 == Iop_Not8 );
sewardje05c42c2004-07-08 20:25:10 +0000596 adj = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
597 return adj + op8;
sewardj41f43bc2004-07-08 14:23:22 +0000598}
599
sewardj9334b0f2004-07-10 22:43:54 +0000600static IROp mkWidenOp ( Int szSmall, Int szBig, Bool signd )
sewardj41f43bc2004-07-08 14:23:22 +0000601{
sewardj9334b0f2004-07-10 22:43:54 +0000602 if (szSmall == 1 && szBig == 4) {
603 return signd ? Iop_8Sto32 : Iop_8Uto32;
sewardj41f43bc2004-07-08 14:23:22 +0000604 }
sewardj9334b0f2004-07-10 22:43:54 +0000605 if (szSmall == 1 && szBig == 2) {
606 return signd ? Iop_8Sto16 : Iop_8Uto16;
607 }
608 if (szSmall == 2 && szBig == 4) {
609 return signd ? Iop_16Sto32 : Iop_16Uto32;
610 }
sewardj948d48b2004-11-05 19:49:09 +0000611 vpanic("mkWidenOp(x86,guest)");
sewardj41f43bc2004-07-08 14:23:22 +0000612}
613
614
615/*------------------------------------------------------------*/
616/*--- Helpers for %eflags. ---*/
617/*------------------------------------------------------------*/
618
sewardj0611d802004-07-11 02:37:54 +0000619/* -------------- Evaluating the flags-thunk. -------------- */
sewardjc9a65702004-07-07 16:32:57 +0000620
sewardje87b4842004-07-10 12:23:30 +0000621/* Build IR to calculate all the eflags from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000622 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
623 Ity_I32. */
sewardje87b4842004-07-10 12:23:30 +0000624static IRExpr* mk_calculate_eflags_all ( void )
625{
sewardjf9655262004-10-31 20:02:16 +0000626 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000627 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
628 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
629 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
630 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000631 IRExpr* call
632 = mkIRExprCCall(
633 Ity_I32,
634 0/*regparm*/,
635 "calculate_eflags_all", &calculate_eflags_all,
636 args
637 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000638 /* Exclude OP and NDEP from definedness checking. We're only
639 interested in DEP1 and DEP2. */
640 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
sewardj43c56462004-11-06 12:17:57 +0000641 return call;
sewardje87b4842004-07-10 12:23:30 +0000642}
643
sewardj84ff0652004-08-23 16:16:08 +0000644/* Build IR to calculate some particular condition from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000645 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
646 Ity_Bit. */
sewardj8ea867b2004-10-30 19:03:02 +0000647static IRExpr* mk_calculate_condition ( Condcode cond )
sewardj84ff0652004-08-23 16:16:08 +0000648{
sewardjf9655262004-10-31 20:02:16 +0000649 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000650 = mkIRExprVec_5( mkU32(cond),
sewardjf9655262004-10-31 20:02:16 +0000651 IRExpr_Get(OFFB_CC_OP, Ity_I32),
sewardj2a2ba8b2004-11-08 13:14:06 +0000652 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
653 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
654 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000655 IRExpr* call
656 = mkIRExprCCall(
657 Ity_I32,
658 0/*regparm*/,
659 "calculate_condition", &calculate_condition,
660 args
661 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000662 /* Exclude the requested condition, OP and NDEP from definedness
663 checking. We're only interested in DEP1 and DEP2. */
664 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<1) | (1<<4);
sewardj43c56462004-11-06 12:17:57 +0000665 return unop(Iop_32to1, call);
666}
667
668/* Build IR to calculate just the carry flag from stored
sewardj2a2ba8b2004-11-08 13:14:06 +0000669 CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression :: Ity_I32. */
sewardj43c56462004-11-06 12:17:57 +0000670static IRExpr* mk_calculate_eflags_c ( void )
671{
672 IRExpr** args
sewardj2a2ba8b2004-11-08 13:14:06 +0000673 = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
674 IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
675 IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
676 IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
sewardj43c56462004-11-06 12:17:57 +0000677 IRExpr* call
678 = mkIRExprCCall(
679 Ity_I32,
680 0/*regparm*/,
681 "calculate_eflags_c", &calculate_eflags_c,
682 args
683 );
sewardj2a2ba8b2004-11-08 13:14:06 +0000684 /* Exclude OP and NDEP from definedness checking. We're only
685 interested in DEP1 and DEP2. */
686 call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
sewardj43c56462004-11-06 12:17:57 +0000687 return call;
sewardj84ff0652004-08-23 16:16:08 +0000688}
689
sewardje87b4842004-07-10 12:23:30 +0000690
sewardj0611d802004-07-11 02:37:54 +0000691/* -------------- Building the flags-thunk. -------------- */
692
sewardjb9c5cf62004-08-24 15:10:38 +0000693/* The machinery in this section builds the flag-thunk following a
694 flag-setting operation. Hence the various setFlags_* functions.
sewardjb9c5cf62004-08-24 15:10:38 +0000695*/
696
697static Bool isAddSub ( IROp op8 )
698{
699 return op8 == Iop_Add8 || op8 == Iop_Sub8;
700}
sewardj0611d802004-07-11 02:37:54 +0000701
sewardj2a2ba8b2004-11-08 13:14:06 +0000702static Bool isLogic ( IROp op8 )
703{
704 return op8 == Iop_And8 || op8 == Iop_Or8 || op8 == Iop_Xor8;
705}
706
sewardja2384712004-07-29 14:36:40 +0000707/* U-widen 8/16/32 bit int expr to 32. */
sewardjc22a6fd2004-07-29 23:41:47 +0000708static IRExpr* widenUto32 ( IRExpr* e )
sewardj443cd9d2004-07-18 23:06:45 +0000709{
710 switch (typeOfIRExpr(irbb->tyenv,e)) {
711 case Ity_I32: return e;
712 case Ity_I16: return unop(Iop_16Uto32,e);
713 case Ity_I8: return unop(Iop_8Uto32,e);
714 default: vpanic("widenUto32");
715 }
716}
717
sewardjc22a6fd2004-07-29 23:41:47 +0000718/* S-widen 8/16/32 bit int expr to 32. */
719static IRExpr* widenSto32 ( IRExpr* e )
720{
721 switch (typeOfIRExpr(irbb->tyenv,e)) {
722 case Ity_I32: return e;
723 case Ity_I16: return unop(Iop_16Sto32,e);
724 case Ity_I8: return unop(Iop_8Sto32,e);
725 default: vpanic("widenSto32");
726 }
727}
728
sewardja2384712004-07-29 14:36:40 +0000729/* Narrow 8/16/32 bit int expr to 8/16/32. Clearly only some
730 of these combinations make sense. */
731static IRExpr* narrowTo ( IRType dst_ty, IRExpr* e )
732{
733 IRType src_ty = typeOfIRExpr(irbb->tyenv,e);
734 if (src_ty == dst_ty)
735 return e;
736 if (src_ty == Ity_I32 && dst_ty == Ity_I16)
737 return unop(Iop_32to16, e);
738 if (src_ty == Ity_I32 && dst_ty == Ity_I8)
739 return unop(Iop_32to8, e);
740
741 vex_printf("\nsrc, dst tys are: ");
742 ppIRType(src_ty);
743 vex_printf(", ");
744 ppIRType(dst_ty);
745 vex_printf("\n");
746 vpanic("narrowTo(x86)");
747}
748
sewardj443cd9d2004-07-18 23:06:45 +0000749
sewardj2a2ba8b2004-11-08 13:14:06 +0000750/* Set the flags thunk OP, DEP1 and DEP2 fields. The supplied op is
sewardj948d48b2004-11-05 19:49:09 +0000751 auto-sized up to the real op. */
sewardj0611d802004-07-11 02:37:54 +0000752
sewardj2a2ba8b2004-11-08 13:14:06 +0000753static
754void setFlags_DEP1_DEP2 ( IROp op8, IRTemp dep1, IRTemp dep2, IRType ty )
sewardj0611d802004-07-11 02:37:54 +0000755{
sewardjb9c5cf62004-08-24 15:10:38 +0000756 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
757
758 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
759
760 switch (op8) {
761 case Iop_Add8: ccOp += CC_OP_ADDB; break;
762 case Iop_Sub8: ccOp += CC_OP_SUBB; break;
763 default: ppIROp(op8);
sewardj2a2ba8b2004-11-08 13:14:06 +0000764 vpanic("setFlags_DEP1_DEP2(x86)");
sewardjb9c5cf62004-08-24 15:10:38 +0000765 }
sewardj2a2ba8b2004-11-08 13:14:06 +0000766 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
767 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
768 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(dep2))) );
sewardjb9c5cf62004-08-24 15:10:38 +0000769}
770
771
sewardj2a2ba8b2004-11-08 13:14:06 +0000772/* Set the OP and DEP1 fields only, and write zero to DEP2. */
sewardjb9c5cf62004-08-24 15:10:38 +0000773
sewardj2a2ba8b2004-11-08 13:14:06 +0000774static
775void setFlags_DEP1 ( IROp op8, IRTemp dep1, IRType ty )
sewardjb9c5cf62004-08-24 15:10:38 +0000776{
777 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
sewardj0611d802004-07-11 02:37:54 +0000778
779 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
780
781 switch (op8) {
782 case Iop_Or8:
783 case Iop_And8:
sewardjb9c5cf62004-08-24 15:10:38 +0000784 case Iop_Xor8: ccOp += CC_OP_LOGICB; break;
sewardj0611d802004-07-11 02:37:54 +0000785 default: ppIROp(op8);
sewardj2a2ba8b2004-11-08 13:14:06 +0000786 vpanic("setFlags_DEP1(x86)");
sewardj0611d802004-07-11 02:37:54 +0000787 }
sewardj2a2ba8b2004-11-08 13:14:06 +0000788 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
789 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
790 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
sewardj0611d802004-07-11 02:37:54 +0000791}
792
793
sewardj948d48b2004-11-05 19:49:09 +0000794/* For shift operations, we put in the result and the undershifted
795 result. Except if the shift amount is zero, the thunk is left
796 unchanged. */
sewardj0611d802004-07-11 02:37:54 +0000797
sewardj2a2ba8b2004-11-08 13:14:06 +0000798static void setFlags_DEP1_DEP2_shift ( IROp op32,
799 IRTemp res,
800 IRTemp resUS,
801 IRType ty,
802 IRTemp guard )
sewardj0611d802004-07-11 02:37:54 +0000803{
sewardjc22a6fd2004-07-29 23:41:47 +0000804 Int ccOp = ty==Ity_I8 ? 2 : (ty==Ity_I16 ? 1 : 0);
sewardj0611d802004-07-11 02:37:54 +0000805
806 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
807 vassert(guard);
808
sewardj2a2ba8b2004-11-08 13:14:06 +0000809 /* Both kinds of right shifts are handled by the same thunk
810 operation. */
sewardjc22a6fd2004-07-29 23:41:47 +0000811 switch (op32) {
812 case Iop_Shr32:
sewardj2a2ba8b2004-11-08 13:14:06 +0000813 case Iop_Sar32: ccOp = CC_OP_SHRL - ccOp; break;
sewardjc22a6fd2004-07-29 23:41:47 +0000814 case Iop_Shl32: ccOp = CC_OP_SHLL - ccOp; break;
815 default: ppIROp(op32);
sewardj2a2ba8b2004-11-08 13:14:06 +0000816 vpanic("setFlags_DEP1_DEP2_shift(x86)");
sewardj0611d802004-07-11 02:37:54 +0000817 }
818
sewardj2a2ba8b2004-11-08 13:14:06 +0000819 /* DEP1 contains the result, DEP2 contains the undershifted value. */
sewardjeeb9ef82004-07-15 12:39:03 +0000820 stmt( IRStmt_Put( OFFB_CC_OP,
sewardj4042c7e2004-07-18 01:28:30 +0000821 IRExpr_Mux0X( mkexpr(guard),
822 IRExpr_Get(OFFB_CC_OP,Ity_I32),
823 mkU32(ccOp))) );
sewardj2a2ba8b2004-11-08 13:14:06 +0000824 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj4042c7e2004-07-18 01:28:30 +0000825 IRExpr_Mux0X( mkexpr(guard),
sewardj2a2ba8b2004-11-08 13:14:06 +0000826 IRExpr_Get(OFFB_CC_DEP1,Ity_I32),
sewardj948d48b2004-11-05 19:49:09 +0000827 widenUto32(mkexpr(res)))) );
sewardj2a2ba8b2004-11-08 13:14:06 +0000828 stmt( IRStmt_Put( OFFB_CC_DEP2,
sewardj4042c7e2004-07-18 01:28:30 +0000829 IRExpr_Mux0X( mkexpr(guard),
sewardj2a2ba8b2004-11-08 13:14:06 +0000830 IRExpr_Get(OFFB_CC_DEP2,Ity_I32),
sewardj948d48b2004-11-05 19:49:09 +0000831 widenUto32(mkexpr(resUS)))) );
sewardj0611d802004-07-11 02:37:54 +0000832}
833
834
sewardj2a2ba8b2004-11-08 13:14:06 +0000835/* For the inc/dec case, we store in DEP1 the result value and in NDEP
sewardj948d48b2004-11-05 19:49:09 +0000836 the former value of the carry flag, which unfortunately we have to
837 compute. */
sewardj0611d802004-07-11 02:37:54 +0000838
sewardj948d48b2004-11-05 19:49:09 +0000839static void setFlags_INC_DEC ( Bool inc, IRTemp res, IRType ty )
sewardj0611d802004-07-11 02:37:54 +0000840{
sewardj948d48b2004-11-05 19:49:09 +0000841 Int ccOp = inc ? CC_OP_INCB : CC_OP_DECB;
sewardj0611d802004-07-11 02:37:54 +0000842
843 ccOp += ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
844 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
845
846 /* This has to come first, because calculating the C flag
sewardj2a2ba8b2004-11-08 13:14:06 +0000847 may require reading all four thunk fields. */
848 stmt( IRStmt_Put( OFFB_CC_NDEP, mk_calculate_eflags_c()) );
849 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
850 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(res)) );
851 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
sewardj0611d802004-07-11 02:37:54 +0000852}
853
854
sewardj2a2ba8b2004-11-08 13:14:06 +0000855/* Multiplies are pretty much like add and sub: DEP1 and DEP2 hold the
856 two arguments. */
sewardjcf780b42004-07-13 18:42:17 +0000857
858static
sewardj2a2ba8b2004-11-08 13:14:06 +0000859void setFlags_MUL ( IRType ty, IRTemp arg1, IRTemp arg2, UInt base_op )
sewardjcf780b42004-07-13 18:42:17 +0000860{
861 switch (ty) {
sewardj2a2ba8b2004-11-08 13:14:06 +0000862 case Ity_I8:
863 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+0) ) );
864 break;
865 case Ity_I16:
866 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+1) ) );
867 break;
868 case Ity_I32:
869 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+2) ) );
870 break;
871 default:
872 vpanic("setFlags_MUL(x86)");
sewardjcf780b42004-07-13 18:42:17 +0000873 }
sewardj2a2ba8b2004-11-08 13:14:06 +0000874 stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(arg1)) ));
875 stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(arg2)) ));
sewardjcf780b42004-07-13 18:42:17 +0000876}
877
878
sewardj3af115f2004-07-14 02:46:52 +0000879/* -------------- Condition codes. -------------- */
880
sewardje87b4842004-07-10 12:23:30 +0000881/* Condition codes, using the Intel encoding. */
sewardj0611d802004-07-11 02:37:54 +0000882
sewardje87b4842004-07-10 12:23:30 +0000883static Char* name_Condcode ( Condcode cond )
884{
885 switch (cond) {
886 case CondO: return "o";
887 case CondNO: return "no";
888 case CondB: return "b";
889 case CondNB: return "nb";
890 case CondZ: return "z";
891 case CondNZ: return "nz";
892 case CondBE: return "be";
893 case CondNBE: return "nbe";
894 case CondS: return "s";
895 case CondNS: return "ns";
896 case CondP: return "p";
897 case CondNP: return "np";
898 case CondL: return "l";
899 case CondNL: return "nl";
900 case CondLE: return "le";
901 case CondNLE: return "nle";
sewardj64e1d652004-07-12 14:00:46 +0000902 case CondAlways: return "ALWAYS";
sewardje87b4842004-07-10 12:23:30 +0000903 default: vpanic("name_Condcode");
904 }
905}
906
907static Condcode positiveIse_Condcode ( Condcode cond,
908 Bool* needInvert )
909{
910 vassert(cond >= CondO && cond <= CondNLE);
911 if (cond & 1) {
912 *needInvert = True;
913 return cond-1;
914 } else {
915 *needInvert = False;
916 return cond;
917 }
918}
919
920
sewardj3af115f2004-07-14 02:46:52 +0000921/* -------------- Helpers for ADD/SUB with carry. -------------- */
922
sewardj948d48b2004-11-05 19:49:09 +0000923/* Given ta1, ta2 and tres, compute tres = ADC(ta1,ta2) and set flags
sewardj2a2ba8b2004-11-08 13:14:06 +0000924 appropriately.
sewardj3af115f2004-07-14 02:46:52 +0000925*/
926static void helper_ADC ( Int sz,
sewardj5bd4d162004-11-10 13:02:48 +0000927 IRTemp tres, IRTemp ta1, IRTemp ta2 )
sewardj3af115f2004-07-14 02:46:52 +0000928{
929 UInt thunkOp;
sewardj2a2ba8b2004-11-08 13:14:06 +0000930 IRType ty = szToITy(sz);
931 IRTemp oldc = newTemp(Ity_I32);
932 IRTemp oldcn = newTemp(ty);
933 IROp plus = mkSizedOp(ty, Iop_Add8);
934 IROp xor = mkSizedOp(ty, Iop_Xor8);
sewardja2384712004-07-29 14:36:40 +0000935
936 vassert(sz == 1 || sz == 2 || sz == 4);
sewardj2a2ba8b2004-11-08 13:14:06 +0000937 thunkOp = sz==4 ? CC_OP_ADCL : (sz==2 ? CC_OP_ADCW : CC_OP_ADCB);
sewardj3af115f2004-07-14 02:46:52 +0000938
sewardj2a2ba8b2004-11-08 13:14:06 +0000939 /* oldc = old carry flag, 0 or 1 */
940 assign( oldc, binop(Iop_And32,
941 mk_calculate_eflags_c(),
sewardj5bd4d162004-11-10 13:02:48 +0000942 mkU32(1)) );
sewardj3af115f2004-07-14 02:46:52 +0000943
sewardj2a2ba8b2004-11-08 13:14:06 +0000944 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
945
946 assign( tres, binop(plus,
947 binop(plus,mkexpr(ta1),mkexpr(ta2)),
948 mkexpr(oldcn)) );
949
950 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(thunkOp) ) );
951 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(ta1) ) );
952 stmt( IRStmt_Put( OFFB_CC_DEP2, binop(xor, mkexpr(ta2), mkexpr(oldcn)) ) );
953 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
sewardj3af115f2004-07-14 02:46:52 +0000954}
955
956
sewardj948d48b2004-11-05 19:49:09 +0000957/* Given ta1, ta2 and tres, compute tres = SBB(ta1,ta2) and set flags
sewardj2a2ba8b2004-11-08 13:14:06 +0000958 appropriately.
sewardjcaca9d02004-07-28 07:11:32 +0000959*/
960static void helper_SBB ( Int sz,
sewardj5bd4d162004-11-10 13:02:48 +0000961 IRTemp tres, IRTemp ta1, IRTemp ta2 )
sewardjcaca9d02004-07-28 07:11:32 +0000962{
963 UInt thunkOp;
sewardj2a2ba8b2004-11-08 13:14:06 +0000964 IRType ty = szToITy(sz);
965 IRTemp oldc = newTemp(Ity_I32);
966 IRTemp oldcn = newTemp(ty);
967 IROp minus = mkSizedOp(ty, Iop_Sub8);
968 IROp xor = mkSizedOp(ty, Iop_Xor8);
969
970 vassert(sz == 1 || sz == 2 || sz == 4);
971 thunkOp = sz==4 ? CC_OP_SBBL : (sz==2 ? CC_OP_SBBW : CC_OP_SBBB);
sewardjcaca9d02004-07-28 07:11:32 +0000972
973 /* oldc = old carry flag, 0 or 1 */
sewardja2384712004-07-29 14:36:40 +0000974 assign( oldc, binop(Iop_And32,
sewardjcaca9d02004-07-28 07:11:32 +0000975 mk_calculate_eflags_c(),
sewardj5bd4d162004-11-10 13:02:48 +0000976 mkU32(1)) );
sewardjcaca9d02004-07-28 07:11:32 +0000977
sewardj2a2ba8b2004-11-08 13:14:06 +0000978 assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
sewardja2384712004-07-29 14:36:40 +0000979
sewardj2a2ba8b2004-11-08 13:14:06 +0000980 assign( tres, binop(minus,
981 binop(minus,mkexpr(ta1),mkexpr(ta2)),
982 mkexpr(oldcn)) );
sewardjcaca9d02004-07-28 07:11:32 +0000983
sewardj2a2ba8b2004-11-08 13:14:06 +0000984 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(thunkOp) ) );
985 stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(ta1) ) );
986 stmt( IRStmt_Put( OFFB_CC_DEP2, binop(xor, mkexpr(ta2), mkexpr(oldcn)) ) );
987 stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
sewardjcaca9d02004-07-28 07:11:32 +0000988}
989
990
sewardjc9a65702004-07-07 16:32:57 +0000991//-- /*------------------------------------------------------------*/
992//-- /*--- CPU feature set stuff ---*/
993//-- /*--- This is a little out of place here, but it will do ---*/
994//-- /*--- for now. ---*/
995//-- /*------------------------------------------------------------*/
996//--
sewardje87b4842004-07-10 12:23:30 +0000997//-- #define VG_CPU_VENDOR_GENERIC 0
998//-- #define VG_CPU_VENDOR_INTEL 1
sewardj5bd4d162004-11-10 13:02:48 +0000999//-- #define VG_CPU_VENDOR_AMD 2
sewardjc9a65702004-07-07 16:32:57 +00001000//--
1001//-- static Int cpu_vendor = VG_CPU_VENDOR_GENERIC;
1002//--
1003//-- static const struct cpu_vendor {
sewardj5bd4d162004-11-10 13:02:48 +00001004//-- const Char *vendorstr;
1005//-- Int vendorid;
sewardjc9a65702004-07-07 16:32:57 +00001006//-- } cpu_vendors[] = {
sewardj5bd4d162004-11-10 13:02:48 +00001007//-- { "GenuineIntel", VG_CPU_VENDOR_INTEL },
1008//-- { "AuthenticAMD", VG_CPU_VENDOR_AMD },
sewardjc9a65702004-07-07 16:32:57 +00001009//-- };
1010//--
sewardj5bd4d162004-11-10 13:02:48 +00001011//-- static Int cpuid_level = -2; /* -2 -> not initialized */
sewardjc9a65702004-07-07 16:32:57 +00001012//-- static UInt cpu_features[VG_N_FEATURE_WORDS];
1013//--
1014//-- /* Standard macro to see if a specific flag is changeable */
1015//-- static inline Bool flag_is_changeable(UInt flag)
1016//-- {
1017//-- UInt f1, f2;
1018//--
1019//-- asm("pushfl\n\t"
1020//-- "pushfl\n\t"
1021//-- "popl %0\n\t"
1022//-- "movl %0,%1\n\t"
1023//-- "xorl %2,%0\n\t"
1024//-- "pushl %0\n\t"
1025//-- "popfl\n\t"
1026//-- "pushfl\n\t"
1027//-- "popl %0\n\t"
1028//-- "popfl\n\t"
1029//-- : "=&r" (f1), "=&r" (f2)
1030//-- : "ir" (flag));
1031//--
1032//-- return ((f1^f2) & flag) != 0;
1033//-- }
1034//--
1035//--
1036//-- /* Probe for the CPUID instruction */
1037//-- static Bool has_cpuid(void)
1038//-- {
1039//-- return flag_is_changeable(EFlagID);
1040//-- }
1041//--
1042//-- static void get_cpu_features(void)
1043//-- {
1044//-- Char vendorstr[13];
1045//-- Int i;
1046//--
1047//-- if (!has_cpuid()) {
1048//-- cpuid_level = -1;
1049//-- return;
1050//-- }
1051//--
1052//-- cpu_features[VG_INT_FEAT] |= (1 << (VG_X86_FEAT_CPUID%32));
1053//--
1054//-- VG_(cpuid)(0, &cpuid_level, (UInt *)&vendorstr[0], (UInt *)&vendorstr[8], (UInt *)&vendorstr[4]);
1055//-- vendorstr[12] = '\0';
1056//--
1057//-- for(i = 0; i < sizeof(cpu_vendors)/sizeof(*cpu_vendors); i++)
1058//-- if (VG_(memcmp)(vendorstr, cpu_vendors[i].vendorstr, 12) == 0) {
sewardj5bd4d162004-11-10 13:02:48 +00001059//-- cpu_vendor = cpu_vendors[i].vendorid;
1060//-- break;
sewardjc9a65702004-07-07 16:32:57 +00001061//-- }
1062//--
1063//-- if (cpuid_level >= 1)
1064//-- VG_(cpuid)(1, NULL, NULL, &cpu_features[VG_EXT_FEAT], &cpu_features[VG_X86_FEAT]);
1065//--
1066//-- switch(cpu_vendor) {
1067//-- case VG_CPU_VENDOR_AMD:
1068//-- /* get AMD-specific flags */
1069//-- VG_(cpuid)(0x80000001, NULL, NULL, NULL, &cpu_features[VG_AMD_FEAT]);
1070//-- break;
1071//--
1072//-- default:
1073//-- break;
1074//-- }
1075//-- }
1076//--
1077//-- Bool VG_(cpu_has_feature)(UInt feature)
1078//-- {
1079//-- UInt word = feature / 32;
1080//-- UInt bit = feature % 32;
1081//--
1082//-- if (cpuid_level == -2)
1083//-- get_cpu_features();
1084//--
1085//-- vg_assert(word >= 0 && word < VG_N_FEATURE_WORDS);
1086//--
1087//-- return !!(cpu_features[word] & (1 << bit));
1088//-- }
1089//--
1090//-- /* The set of features we're willing to support for the client
1091//--
1092//-- This includes supported instruction set extensions, plus any
1093//-- extensions which don't have any user-mode visible effect (but the
1094//-- client may find interesting).
1095//-- */
sewardj5bd4d162004-11-10 13:02:48 +00001096#define VG_X86_SUPPORTED_FEATURES \
1097 ((1 << VG_X86_FEAT_FPU) | \
1098 (1 << VG_X86_FEAT_VME) | \
1099 (1 << VG_X86_FEAT_DE) | \
1100 (1 << VG_X86_FEAT_PSE) | \
1101 (1 << VG_X86_FEAT_TSC) | \
1102 (0 << VG_X86_FEAT_MSR) | \
1103 (1 << VG_X86_FEAT_PAE) | \
1104 (1 << VG_X86_FEAT_MCE) | \
1105 (1 << VG_X86_FEAT_CX8) | \
1106 (1 << VG_X86_FEAT_APIC) | \
1107 (0 << VG_X86_FEAT_SEP) | \
1108 (1 << VG_X86_FEAT_MTRR) | \
1109 (1 << VG_X86_FEAT_PGE) | \
1110 (1 << VG_X86_FEAT_MCA) | \
1111 (1 << VG_X86_FEAT_CMOV) | \
1112 (1 << VG_X86_FEAT_PAT) | \
1113 (1 << VG_X86_FEAT_PSE36) | \
1114 (0 << VG_X86_FEAT_CLFSH) | \
1115 (1 << VG_X86_FEAT_DS) | \
1116 (1 << VG_X86_FEAT_ACPI) | \
1117 (1 << VG_X86_FEAT_MMX) | \
1118 (1 << VG_X86_FEAT_FXSR) | \
1119 (1 << VG_X86_FEAT_SSE) | \
1120 (1 << VG_X86_FEAT_SSE2) | \
1121 (1 << VG_X86_FEAT_SS) | \
1122 (1 << VG_X86_FEAT_HT) | \
1123 (1 << VG_X86_FEAT_TM) | \
1124 (0 << VG_X86_FEAT_IA64) | \
1125 (1 << VG_X86_FEAT_PBE))
sewardjd1061ab2004-07-08 01:45:30 +00001126
sewardj5bd4d162004-11-10 13:02:48 +00001127#define VG_AMD_SUPPORTED_FEATURES \
1128 ((0 << (VG_AMD_FEAT_SYSCALL % 32)) | \
1129 (0 << (VG_AMD_FEAT_NXP % 32)) | \
1130 (1 << (VG_AMD_FEAT_MMXEXT % 32)) | \
1131 (0 << (VG_AMD_FEAT_FFXSR % 32)) | \
1132 (0 << (VG_AMD_FEAT_LONGMODE % 32)) | \
1133 (0 << (VG_AMD_FEAT_3DNOWEXT % 32)) | \
1134 (0 << (VG_AMD_FEAT_3DNOW % 32)) | \
1135 /* Common bits between standard features and AMD features */ \
1136 (1 << VG_X86_FEAT_FPU) | \
1137 (1 << VG_X86_FEAT_VME) | \
1138 (1 << VG_X86_FEAT_DE) | \
1139 (1 << VG_X86_FEAT_PSE) | \
1140 (1 << VG_X86_FEAT_TSC) | \
1141 (0 << VG_X86_FEAT_MSR) | \
1142 (1 << VG_X86_FEAT_PAE) | \
1143 (1 << VG_X86_FEAT_MCE) | \
1144 (1 << VG_X86_FEAT_CX8) | \
1145 (1 << VG_X86_FEAT_APIC) | \
1146 (1 << VG_X86_FEAT_MTRR) | \
1147 (1 << VG_X86_FEAT_PGE) | \
1148 (1 << VG_X86_FEAT_MCA) | \
1149 (1 << VG_X86_FEAT_CMOV) | \
1150 (1 << VG_X86_FEAT_PAT) | \
1151 (1 << VG_X86_FEAT_PSE36) | \
1152 (1 << VG_X86_FEAT_MMX) | \
1153 (1 << VG_X86_FEAT_FXSR))
sewardjd1061ab2004-07-08 01:45:30 +00001154
1155
sewardj5bd4d162004-11-10 13:02:48 +00001156//-- /*
sewardjc9a65702004-07-07 16:32:57 +00001157//-- For simulating the cpuid instruction, we will
1158//-- issue a "real" cpuid instruction and then mask out
1159//-- the bits of the features we do not support currently (3dnow mostly).
1160//-- We also claim to not support most CPUID operations.
sewardj5bd4d162004-11-10 13:02:48 +00001161//--
sewardjc9a65702004-07-07 16:32:57 +00001162//-- Dirk Mueller <mueller@kde.org>
1163//--
1164//-- http://www.sandpile.org/ia32/cpuid.htm
1165//--
1166//-- references:
1167//--
1168//-- pre-MMX pentium:
1169//--
1170//-- <werner> cpuid words (0): 0x1 0x756e6547 0x6c65746e 0x49656e69
1171//-- <werner> cpuid words (1): 0x52b 0x0 0x0 0x1bf
1172//--
1173//-- Updated to be more extensible about future vendor extensions and
1174//-- vendor-specific parts of CPUID.
1175//-- */
1176//-- void VG_(helperc_CPUID)(UInt op, UInt *eax_ret, UInt *ebx_ret, UInt *ecx_ret, UInt *edx_ret)
1177//-- {
1178//-- UInt eax, ebx, ecx, edx;
1179//--
1180//-- if (cpuid_level == -2)
sewardj5bd4d162004-11-10 13:02:48 +00001181//-- get_cpu_features(); /* for cpu_vendor */
sewardjc9a65702004-07-07 16:32:57 +00001182//--
1183//-- VG_(cpuid)(op, &eax, &ebx, &ecx, &edx);
1184//--
1185//-- /* Common mangling */
1186//-- switch(op) {
1187//-- case 1:
1188//-- edx &= VG_X86_SUPPORTED_FEATURES;
1189//-- break;
1190//--
1191//-- case 0xd8000000: {
1192//-- /* Implement some private information at 0xd8000000 */
1193//-- static const Char valgrind_vendor[] = "ValgrindVCPU";
1194//--
sewardj5bd4d162004-11-10 13:02:48 +00001195//-- eax = 0xd8000000; /* max request */
sewardjc9a65702004-07-07 16:32:57 +00001196//-- ebx = *(UInt *)&valgrind_vendor[0];
1197//-- ecx = *(UInt *)&valgrind_vendor[8];
1198//-- edx = *(UInt *)&valgrind_vendor[4];
1199//-- }
1200//-- break;
1201//-- }
1202//--
1203//-- /* Vendor-specific mangling of the results */
1204//-- switch(cpu_vendor) {
1205//-- case VG_CPU_VENDOR_INTEL:
1206//-- switch(op) {
1207//-- case 1:
sewardj5bd4d162004-11-10 13:02:48 +00001208//-- ecx = 0; /* mask out all extended features for now */
1209//-- break;
sewardjc9a65702004-07-07 16:32:57 +00001210//--
1211//-- case 0x80000001:
sewardj5bd4d162004-11-10 13:02:48 +00001212//-- ebx = ecx = edx = 0;
1213//-- break;
sewardjc9a65702004-07-07 16:32:57 +00001214//-- }
1215//-- break;
1216//--
1217//-- case VG_CPU_VENDOR_AMD:
1218//-- switch(op) {
1219//-- case 0x80000001:
sewardj5bd4d162004-11-10 13:02:48 +00001220//-- edx &= VG_AMD_SUPPORTED_FEATURES;
1221//-- break;
sewardjc9a65702004-07-07 16:32:57 +00001222//-- }
1223//-- break;
1224//-- }
1225//--
1226//-- *eax_ret = eax;
1227//-- *ebx_ret = ebx;
1228//-- *ecx_ret = ecx;
1229//-- *edx_ret = edx;
1230//-- }
1231//--
1232//--
1233//-- /*------------------------------------------------------------*/
1234//-- /*--- Here so it can be inlined everywhere. ---*/
1235//-- /*------------------------------------------------------------*/
1236//--
1237//-- /* Allocate a new temp reg number. */
1238//-- __inline__ Int VG_(get_new_temp) ( UCodeBlock* cb )
1239//-- {
1240//-- Int t = cb->nextTemp;
1241//-- cb->nextTemp += 2;
1242//-- return t;
1243//-- }
1244//--
1245//-- Int VG_(get_new_shadow) ( UCodeBlock* cb )
1246//-- {
1247//-- Int t = cb->nextTemp;
1248//-- cb->nextTemp += 2;
1249//-- return SHADOW(t);
1250//-- }
1251
1252
sewardj41f43bc2004-07-08 14:23:22 +00001253
1254static Char* nameGrp1 ( Int opc_aux )
1255{
1256 static Char* grp1_names[8]
1257 = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
1258 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp1(x86)");
1259 return grp1_names[opc_aux];
1260}
1261
sewardje90ad6a2004-07-10 19:02:10 +00001262static Char* nameGrp2 ( Int opc_aux )
1263{
1264 static Char* grp2_names[8]
1265 = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
sewardjc2ac51e2004-07-12 01:03:26 +00001266 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp2(x86)");
sewardje90ad6a2004-07-10 19:02:10 +00001267 return grp2_names[opc_aux];
1268}
1269
sewardjc2ac51e2004-07-12 01:03:26 +00001270static Char* nameGrp4 ( Int opc_aux )
1271{
1272 static Char* grp4_names[8]
1273 = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
1274 if (opc_aux < 0 || opc_aux > 1) vpanic("nameGrp4(x86)");
1275 return grp4_names[opc_aux];
1276}
sewardj0611d802004-07-11 02:37:54 +00001277
1278static Char* nameGrp5 ( Int opc_aux )
1279{
1280 static Char* grp5_names[8]
1281 = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
1282 if (opc_aux < 0 || opc_aux > 6) vpanic("nameGrp5(x86)");
1283 return grp5_names[opc_aux];
1284}
1285
sewardjc9a65702004-07-07 16:32:57 +00001286//-- static Char* nameGrp8 ( Int opc_aux )
1287//-- {
1288//-- static Char* grp8_names[8]
1289//-- = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
1290//-- if (opc_aux < 4 || opc_aux > 7) VG_(core_panic)("nameGrp8");
1291//-- return grp8_names[opc_aux];
1292//-- }
1293
sewardj1813dbe2004-07-28 17:09:04 +00001294static Char* nameIReg ( Int size, Int reg )
sewardjc9a65702004-07-07 16:32:57 +00001295{
1296 static Char* ireg32_names[8]
1297 = { "%eax", "%ecx", "%edx", "%ebx",
1298 "%esp", "%ebp", "%esi", "%edi" };
1299 static Char* ireg16_names[8]
1300 = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di" };
1301 static Char* ireg8_names[8]
1302 = { "%al", "%cl", "%dl", "%bl",
1303 "%ah{sp}", "%ch{bp}", "%dh{si}", "%bh{di}" };
1304 if (reg < 0 || reg > 7) goto bad;
1305 switch (size) {
1306 case 4: return ireg32_names[reg];
1307 case 2: return ireg16_names[reg];
1308 case 1: return ireg8_names[reg];
1309 }
1310 bad:
1311 vpanic("nameIReg(X86)");
1312 return NULL; /*notreached*/
1313}
1314
sewardj063f02f2004-10-20 12:36:12 +00001315static Char* nameSReg ( UInt sreg )
1316{
1317 switch (sreg) {
1318 case R_ES: return "%es";
1319 case R_CS: return "%cs";
1320 case R_SS: return "%ss";
1321 case R_DS: return "%ds";
1322 case R_FS: return "%fs";
1323 case R_GS: return "%gs";
1324 default: vpanic("nameSReg(x86)");
1325 }
1326}
1327
sewardj464efa42004-11-19 22:17:29 +00001328static Char* nameMMXReg ( Int mmxreg )
1329{
1330 static Char* mmx_names[8]
1331 = { "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" };
1332 if (mmxreg < 0 || mmxreg > 7) vpanic("nameMMXReg(x86,guest)");
1333 return mmx_names[mmxreg];
1334}
1335
sewardjc9a65702004-07-07 16:32:57 +00001336//-- const Char* VG_(name_of_xmm_reg) ( Int xmmreg )
1337//-- {
1338//-- static const Char* xmm_names[8]
1339//-- = { "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7" };
1340//-- if (xmmreg < 0 || xmmreg > 7) VG_(core_panic)("name_of_xmm_reg");
1341//-- return xmm_names[xmmreg];
1342//-- }
sewardj464efa42004-11-19 22:17:29 +00001343
1344static Char* nameMMXGran ( UChar gran )
1345{
1346 switch (gran) {
1347 case 0: return "b";
1348 case 1: return "w";
1349 case 2: return "d";
1350 case 3: return "q";
1351 default: vpanic("nameMMXGran(x86,guest)");
1352 }
1353}
sewardjc9a65702004-07-07 16:32:57 +00001354
sewardj41f43bc2004-07-08 14:23:22 +00001355static Char nameISize ( Int size )
sewardjc9a65702004-07-07 16:32:57 +00001356{
1357 switch (size) {
1358 case 4: return 'l';
1359 case 2: return 'w';
1360 case 1: return 'b';
1361 default: vpanic("nameISize(x86)");
1362 }
1363}
1364
sewardjc9a65702004-07-07 16:32:57 +00001365//-- __inline__ static UInt LOW24 ( UInt x )
1366//-- {
1367//-- return x & 0x00FFFFFF;
1368//-- }
1369//--
1370//-- __inline__ static UInt HI8 ( UInt x )
1371//-- {
1372//-- return x >> 24;
1373//-- }
1374//--
sewardjc9a65702004-07-07 16:32:57 +00001375//-- /*------------------------------------------------------------*/
1376//-- /*--- Flag-related helpers. ---*/
1377//-- /*------------------------------------------------------------*/
1378//--
1379//-- static void setFlagsFromUOpcode ( UCodeBlock* cb, Int uopc )
1380//-- {
1381//-- switch (uopc) {
1382//-- case XOR: case OR: case AND:
1383//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZCP, FlagA); break;
1384//-- case ADC: case SBB:
1385//-- uFlagsRWU(cb, FlagC, FlagsOSZACP, FlagsEmpty); break;
1386//-- case MUL: case UMUL:
sewardj5bd4d162004-11-10 13:02:48 +00001387//-- uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP); break;
sewardjc9a65702004-07-07 16:32:57 +00001388//-- case ADD: case SUB: case NEG:
1389//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty); break;
1390//-- case INC: case DEC:
1391//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZAP, FlagsEmpty); break;
1392//-- case SHR: case SAR: case SHL:
1393//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZCP, FlagA); break;
1394//-- case ROL: case ROR:
1395//-- uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsEmpty); break;
1396//-- case RCR: case RCL:
1397//-- uFlagsRWU(cb, FlagC, FlagsOC, FlagsEmpty); break;
1398//-- case NOT:
1399//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty); break;
1400//-- default:
1401//-- VG_(printf)("unhandled case is %s\n",
1402//-- VG_(name_UOpcode)(True, uopc));
1403//-- VG_(core_panic)("setFlagsFromUOpcode: unhandled case");
1404//-- }
1405//-- }
sewardjd1061ab2004-07-08 01:45:30 +00001406
1407/*------------------------------------------------------------*/
1408/*--- JMP helpers ---*/
1409/*------------------------------------------------------------*/
1410
sewardj78c19df2004-07-12 22:49:27 +00001411static void jmp_lit( IRJumpKind kind, Addr32 d32 )
sewardjd1061ab2004-07-08 01:45:30 +00001412{
sewardje539a402004-07-14 18:24:17 +00001413 irbb->next = mkU32(d32);
1414 irbb->jumpkind = kind;
sewardjd1061ab2004-07-08 01:45:30 +00001415}
1416
sewardj78c19df2004-07-12 22:49:27 +00001417static void jmp_treg( IRJumpKind kind, IRTemp t )
sewardje05c42c2004-07-08 20:25:10 +00001418{
sewardje539a402004-07-14 18:24:17 +00001419 irbb->next = mkexpr(t);
1420 irbb->jumpkind = kind;
sewardje05c42c2004-07-08 20:25:10 +00001421}
sewardje87b4842004-07-10 12:23:30 +00001422
sewardj9334b0f2004-07-10 22:43:54 +00001423static void jcc_01( Condcode cond, Addr32 d32_false, Addr32 d32_true )
sewardje87b4842004-07-10 12:23:30 +00001424{
1425 Bool invert;
1426 Condcode condPos;
1427 condPos = positiveIse_Condcode ( cond, &invert );
1428 if (invert) {
sewardj8ea867b2004-10-30 19:03:02 +00001429 stmt( IRStmt_Exit( mk_calculate_condition(condPos),
sewardj78c19df2004-07-12 22:49:27 +00001430 IRConst_U32(d32_false) ) );
sewardje539a402004-07-14 18:24:17 +00001431 irbb->next = mkU32(d32_true);
1432 irbb->jumpkind = Ijk_Boring;
sewardje87b4842004-07-10 12:23:30 +00001433 } else {
sewardj8ea867b2004-10-30 19:03:02 +00001434 stmt( IRStmt_Exit( mk_calculate_condition(condPos),
sewardj78c19df2004-07-12 22:49:27 +00001435 IRConst_U32(d32_true) ) );
sewardje539a402004-07-14 18:24:17 +00001436 irbb->next = mkU32(d32_false);
1437 irbb->jumpkind = Ijk_Boring;
sewardje87b4842004-07-10 12:23:30 +00001438 }
1439}
sewardjc9a65702004-07-07 16:32:57 +00001440
1441
sewardjd1061ab2004-07-08 01:45:30 +00001442/*------------------------------------------------------------*/
1443/*--- Disassembling addressing modes ---*/
1444/*------------------------------------------------------------*/
sewardjc9a65702004-07-07 16:32:57 +00001445
sewardjd1061ab2004-07-08 01:45:30 +00001446static
1447UChar* sorbTxt ( UChar sorb )
1448{
1449 switch (sorb) {
1450 case 0: return ""; /* no override */
1451 case 0x3E: return "%ds";
1452 case 0x26: return "%es:";
1453 case 0x64: return "%fs:";
1454 case 0x65: return "%gs:";
1455 default: vpanic("sorbTxt(x86)");
1456 }
1457}
1458
1459
1460/* Tmp is a TempReg holding a virtual address. Convert it to a linear
1461 address by adding any required segment override as indicated by
1462 sorb. */
1463static
1464IRExpr* handleSegOverride ( UChar sorb, IRExpr* virtual )
1465{
1466 //Int sreg, tsreg;
1467
1468 if (sorb == 0)
1469 /* the common case - no override */
1470 return virtual;
1471
1472 unimplemented("segment overrides in new x86->IR phase");
1473#if 0
1474 switch (sorb) {
1475 case 0x3E: sreg = R_DS; break;
1476 case 0x26: sreg = R_ES; break;
1477 case 0x64: sreg = R_FS; break;
1478 case 0x65: sreg = R_GS; break;
1479 default: VG_(core_panic)("handleSegOverride");
1480 }
1481
1482 tsreg = newTemp(cb);
1483
1484 /* sreg -> tsreg */
1485 uInstr2(cb, GETSEG, 2, ArchRegS, sreg, TempReg, tsreg );
1486
1487 /* tmp += segment_base(ldt[tsreg]); also do limit check */
1488 uInstr2(cb, USESEG, 0, TempReg, tsreg, TempReg, tmp );
1489#endif
1490}
1491
1492
1493/* Generate IR to calculate an address indicated by a ModRM and
1494 following SIB bytes. The expression, and the number of bytes in
1495 the address mode, are returned. Note that this fn should not be
1496 called if the R/M part of the address denotes a register instead of
1497 memory. If print_codegen is true, text of the addressing mode is
sewardj940e8c92004-07-11 16:53:24 +00001498 placed in buf.
1499
1500 The computed address is stored in a new tempreg, and the
1501 identity of the tempreg is returned. */
1502
1503static IRTemp disAMode_copy2tmp ( IRExpr* addr32 )
1504{
1505 IRTemp tmp = newTemp(Ity_I32);
1506 assign( tmp, addr32 );
1507 return tmp;
1508}
sewardjd1061ab2004-07-08 01:45:30 +00001509
1510static
sewardj940e8c92004-07-11 16:53:24 +00001511IRTemp disAMode ( Int* len, UChar sorb, UInt delta, UChar* buf )
sewardjd1061ab2004-07-08 01:45:30 +00001512{
1513 UChar mod_reg_rm = getIByte(delta);
1514 delta++;
1515
1516 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1517 jump table seems a bit excessive.
1518 */
1519 mod_reg_rm &= 0xC7; /* is now XX000YYY */
1520 mod_reg_rm |= (mod_reg_rm >> 3); /* is now XX0XXYYY */
1521 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
1522 switch (mod_reg_rm) {
1523
1524 /* (%eax) .. (%edi), not including (%esp) or (%ebp).
1525 --> GET %reg, t
1526 */
1527 case 0x00: case 0x01: case 0x02: case 0x03:
1528 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1529 { UChar rm = mod_reg_rm;
1530 DIS(buf, "%s(%s)", sorbTxt(sorb), nameIReg(4,rm));
1531 *len = 1;
sewardj5bd4d162004-11-10 13:02:48 +00001532 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001533 handleSegOverride(sorb, getIReg(4,rm)));
sewardjd1061ab2004-07-08 01:45:30 +00001534 }
1535
1536 /* d8(%eax) ... d8(%edi), not including d8(%esp)
1537 --> GET %reg, t ; ADDL d8, t
1538 */
1539 case 0x08: case 0x09: case 0x0A: case 0x0B:
1540 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1541 { UChar rm = mod_reg_rm & 7;
1542 UInt d = getSDisp8(delta);
1543 DIS(buf, "%s%d(%s)", sorbTxt(sorb), d, nameIReg(4,rm));
sewardj5bd4d162004-11-10 13:02:48 +00001544 *len = 2;
1545 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001546 handleSegOverride(sorb,
1547 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001548 }
1549
1550 /* d32(%eax) ... d32(%edi), not including d32(%esp)
1551 --> GET %reg, t ; ADDL d8, t
1552 */
1553 case 0x10: case 0x11: case 0x12: case 0x13:
1554 /* ! 14 */ case 0x15: case 0x16: case 0x17:
1555 { UChar rm = mod_reg_rm & 7;
1556 UInt d = getUDisp32(delta);
1557 DIS(buf, "%s0x%x(%s)", sorbTxt(sorb), d, nameIReg(4,rm));
sewardj5bd4d162004-11-10 13:02:48 +00001558 *len = 5;
1559 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001560 handleSegOverride(sorb,
1561 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001562 }
1563
1564 /* a register, %eax .. %edi. This shouldn't happen. */
1565 case 0x18: case 0x19: case 0x1A: case 0x1B:
1566 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1567 vpanic("disAMode(x86): not an addr!");
1568
1569 /* a 32-bit literal address
1570 --> MOV d32, tmp
1571 */
1572 case 0x05:
1573 { UInt d = getUDisp32(delta);
1574 *len = 5;
1575 DIS(buf, "%s(0x%x)", sorbTxt(sorb), d);
sewardj940e8c92004-07-11 16:53:24 +00001576 return disAMode_copy2tmp(
1577 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001578 }
1579
1580 case 0x04: {
1581 /* SIB, with no displacement. Special cases:
1582 -- %esp cannot act as an index value.
1583 If index_r indicates %esp, zero is used for the index.
1584 -- when mod is zero and base indicates EBP, base is instead
1585 a 32-bit literal.
1586 It's all madness, I tell you. Extract %index, %base and
1587 scale from the SIB byte. The value denoted is then:
1588 | %index == %ESP && %base == %EBP
1589 = d32 following SIB byte
1590 | %index == %ESP && %base != %EBP
1591 = %base
1592 | %index != %ESP && %base == %EBP
1593 = d32 following SIB byte + (%index << scale)
1594 | %index != %ESP && %base != %ESP
1595 = %base + (%index << scale)
1596
1597 What happens to the souls of CPU architects who dream up such
1598 horrendous schemes, do you suppose?
1599 */
1600 UChar sib = getIByte(delta);
1601 UChar scale = (sib >> 6) & 3;
1602 UChar index_r = (sib >> 3) & 7;
1603 UChar base_r = sib & 7;
sewardj5bd4d162004-11-10 13:02:48 +00001604 delta++;
sewardjd1061ab2004-07-08 01:45:30 +00001605
1606 if (index_r != R_ESP && base_r != R_EBP) {
1607 DIS(buf, "%s(%s,%s,%d)", sorbTxt(sorb),
1608 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001609 *len = 2;
sewardj940e8c92004-07-11 16:53:24 +00001610 return
1611 disAMode_copy2tmp(
sewardj5bd4d162004-11-10 13:02:48 +00001612 handleSegOverride(sorb,
1613 binop(Iop_Add32,
sewardjd1061ab2004-07-08 01:45:30 +00001614 getIReg(4,base_r),
1615 binop(Iop_Shl32, getIReg(4,index_r),
sewardj6d2638e2004-07-15 09:38:27 +00001616 mkU8(scale)))));
sewardjd1061ab2004-07-08 01:45:30 +00001617 }
1618
1619 if (index_r != R_ESP && base_r == R_EBP) {
1620 UInt d = getUDisp32(delta);
1621 DIS(buf, "%s0x%x(,%s,%d)", sorbTxt(sorb), d,
1622 nameIReg(4,index_r), 1<<scale);
1623 *len = 6;
1624 return
sewardj940e8c92004-07-11 16:53:24 +00001625 disAMode_copy2tmp(
sewardjd1061ab2004-07-08 01:45:30 +00001626 handleSegOverride(sorb,
sewardj5bd4d162004-11-10 13:02:48 +00001627 binop(Iop_Add32,
1628 binop(Iop_Shl32, getIReg(4,index_r), mkU8(scale)),
sewardj940e8c92004-07-11 16:53:24 +00001629 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001630 }
1631
1632 if (index_r == R_ESP && base_r != R_EBP) {
1633 DIS(buf, "%s(%s,,)", sorbTxt(sorb), nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001634 *len = 2;
1635 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001636 handleSegOverride(sorb, getIReg(4,base_r)));
sewardjd1061ab2004-07-08 01:45:30 +00001637 }
1638
1639 if (index_r == R_ESP && base_r == R_EBP) {
1640 UInt d = getUDisp32(delta);
1641 DIS(buf, "%s0x%x()", sorbTxt(sorb), d);
sewardj5bd4d162004-11-10 13:02:48 +00001642 *len = 6;
1643 vpanic("amode 8");
1644 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001645 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001646 }
1647
1648 vassert(0);
1649 }
1650
1651 /* SIB, with 8-bit displacement. Special cases:
1652 -- %esp cannot act as an index value.
1653 If index_r indicates %esp, zero is used for the index.
1654 Denoted value is:
1655 | %index == %ESP
1656 = d8 + %base
1657 | %index != %ESP
1658 = d8 + %base + (%index << scale)
1659 */
1660 case 0x0C: {
1661 UChar sib = getIByte(delta);
1662 UChar scale = (sib >> 6) & 3;
1663 UChar index_r = (sib >> 3) & 7;
1664 UChar base_r = sib & 7;
1665 UInt d = getSDisp8(delta+1);
1666
1667 if (index_r == R_ESP) {
1668 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb), d, nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001669 *len = 3;
1670 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001671 handleSegOverride(sorb,
1672 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001673 } else {
1674 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), d,
1675 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001676 *len = 3;
1677 return
sewardj940e8c92004-07-11 16:53:24 +00001678 disAMode_copy2tmp(
1679 handleSegOverride(sorb,
sewardj77b86be2004-07-11 13:28:24 +00001680 binop(Iop_Add32,
1681 binop(Iop_Add32,
1682 getIReg(4,base_r),
1683 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001684 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001685 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001686 }
1687 vassert(0);
1688 }
1689
1690 /* SIB, with 32-bit displacement. Special cases:
1691 -- %esp cannot act as an index value.
1692 If index_r indicates %esp, zero is used for the index.
1693 Denoted value is:
1694 | %index == %ESP
1695 = d32 + %base
1696 | %index != %ESP
1697 = d32 + %base + (%index << scale)
1698 */
1699 case 0x14: {
1700 UChar sib = getIByte(delta);
1701 UChar scale = (sib >> 6) & 3;
1702 UChar index_r = (sib >> 3) & 7;
1703 UChar base_r = sib & 7;
1704 UInt d = getUDisp32(delta+1);
1705
1706 if (index_r == R_ESP) {
1707 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb), d, nameIReg(4,base_r));
sewardj5bd4d162004-11-10 13:02:48 +00001708 *len = 6;
1709 return disAMode_copy2tmp(
sewardj940e8c92004-07-11 16:53:24 +00001710 handleSegOverride(sorb,
1711 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001712 } else {
1713 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), d,
1714 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardj5bd4d162004-11-10 13:02:48 +00001715 *len = 6;
1716 return
sewardj940e8c92004-07-11 16:53:24 +00001717 disAMode_copy2tmp(
1718 handleSegOverride(sorb,
sewardj9334b0f2004-07-10 22:43:54 +00001719 binop(Iop_Add32,
1720 binop(Iop_Add32,
1721 getIReg(4,base_r),
1722 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001723 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001724 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001725 }
1726 vassert(0);
1727 }
1728
1729 default:
1730 vpanic("disAMode(x86)");
1731 return 0; /*notreached*/
1732 }
1733}
1734
1735
1736/* Figure out the number of (insn-stream) bytes constituting the amode
1737 beginning at delta. Is useful for getting hold of literals beyond
1738 the end of the amode before it has been disassembled. */
1739
1740static UInt lengthAMode ( UInt delta )
1741{
1742 UChar mod_reg_rm = getIByte(delta); delta++;
1743
1744 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1745 jump table seems a bit excessive.
1746 */
1747 mod_reg_rm &= 0xC7; /* is now XX000YYY */
1748 mod_reg_rm |= (mod_reg_rm >> 3); /* is now XX0XXYYY */
1749 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
1750 switch (mod_reg_rm) {
1751
1752 /* (%eax) .. (%edi), not including (%esp) or (%ebp). */
1753 case 0x00: case 0x01: case 0x02: case 0x03:
1754 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1755 return 1;
1756
1757 /* d8(%eax) ... d8(%edi), not including d8(%esp). */
1758 case 0x08: case 0x09: case 0x0A: case 0x0B:
1759 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1760 return 2;
1761
1762 /* d32(%eax) ... d32(%edi), not including d32(%esp). */
1763 case 0x10: case 0x11: case 0x12: case 0x13:
1764 /* ! 14 */ case 0x15: case 0x16: case 0x17:
1765 return 5;
1766
1767 /* a register, %eax .. %edi. (Not an addr, but still handled.) */
1768 case 0x18: case 0x19: case 0x1A: case 0x1B:
1769 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1770 return 1;
1771
1772 /* a 32-bit literal address. */
1773 case 0x05: return 5;
1774
1775 /* SIB, no displacement. */
1776 case 0x04: {
1777 UChar sib = getIByte(delta);
1778 UChar base_r = sib & 7;
1779 if (base_r == R_EBP) return 6; else return 2;
1780 }
1781 /* SIB, with 8-bit displacement. */
1782 case 0x0C: return 3;
1783
1784 /* SIB, with 32-bit displacement. */
1785 case 0x14: return 6;
1786
1787 default:
1788 vpanic("lengthAMode");
1789 return 0; /*notreached*/
1790 }
1791}
1792
1793/*------------------------------------------------------------*/
1794/*--- Disassembling common idioms ---*/
1795/*------------------------------------------------------------*/
1796
sewardj5df3bfe2004-07-27 09:30:31 +00001797static
1798void codegen_XOR_reg_with_itself ( Int size, Int ge_reg )
1799{
1800 IRType ty = szToITy(size);
1801 /* reg := 0 */
1802 putIReg(size, ge_reg, mkU(ty,0));
1803 /* Flags: C,A,O=0, Z=1, S=0, P=1 */
sewardj2a2ba8b2004-11-08 13:14:06 +00001804 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
1805 stmt( IRStmt_Put( OFFB_CC_DEP1, mkU32(CC_MASK_Z|CC_MASK_P) ));
1806 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardj5df3bfe2004-07-27 09:30:31 +00001807 DIP("xor%c %s, %s\n", nameISize(size),
1808 nameIReg(size,ge_reg), nameIReg(size,ge_reg) );
1809}
1810
1811
sewardje87b4842004-07-10 12:23:30 +00001812/* Handle binary integer instructions of the form
1813 op E, G meaning
1814 op reg-or-mem, reg
1815 Is passed the a ptr to the modRM byte, the actual operation, and the
1816 data size. Returns the address advanced completely over this
1817 instruction.
1818
1819 E(src) is reg-or-mem
1820 G(dst) is reg.
1821
1822 If E is reg, --> GET %G, tmp
1823 OP %E, tmp
1824 PUT tmp, %G
1825
1826 If E is mem and OP is not reversible,
1827 --> (getAddr E) -> tmpa
1828 LD (tmpa), tmpa
1829 GET %G, tmp2
1830 OP tmpa, tmp2
1831 PUT tmp2, %G
1832
1833 If E is mem and OP is reversible
1834 --> (getAddr E) -> tmpa
1835 LD (tmpa), tmpa
1836 OP %G, tmpa
1837 PUT tmpa, %G
1838*/
1839static
1840UInt dis_op2_E_G ( UChar sorb,
sewardj180e8b32004-07-29 01:40:11 +00001841 Bool addSubCarry,
sewardje87b4842004-07-10 12:23:30 +00001842 IROp op8,
1843 Bool keep,
1844 Int size,
1845 UInt delta0,
1846 Char* t_x86opc )
1847{
sewardj9334b0f2004-07-10 22:43:54 +00001848 UChar dis_buf[50];
1849 Int len;
sewardje87b4842004-07-10 12:23:30 +00001850 IRType ty = szToITy(size);
1851 IRTemp dst1 = newTemp(ty);
1852 IRTemp src = newTemp(ty);
1853 IRTemp dst0 = newTemp(ty);
1854 UChar rm = getUChar(delta0);
sewardj92d168d2004-11-15 14:22:12 +00001855 IRTemp addr = IRTemp_INVALID;
sewardje87b4842004-07-10 12:23:30 +00001856
sewardj180e8b32004-07-29 01:40:11 +00001857 /* addSubCarry == True indicates the intended operation is
1858 add-with-carry or subtract-with-borrow. */
1859 if (addSubCarry) {
1860 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1861 vassert(keep);
1862 }
1863
sewardje87b4842004-07-10 12:23:30 +00001864 if (epartIsReg(rm)) {
sewardje87b4842004-07-10 12:23:30 +00001865 /* Specially handle XOR reg,reg, because that doesn't really
1866 depend on reg, and doing the obvious thing potentially
1867 generates a spurious value check failure due to the bogus
1868 dependency. */
sewardj5df3bfe2004-07-27 09:30:31 +00001869 if (op8 == Iop_Xor8 && gregOfRM(rm) == eregOfRM(rm)) {
1870 codegen_XOR_reg_with_itself ( size, gregOfRM(rm) );
1871 return 1+delta0;
sewardje87b4842004-07-10 12:23:30 +00001872 }
sewardje87b4842004-07-10 12:23:30 +00001873 assign( dst0, getIReg(size,gregOfRM(rm)) );
1874 assign( src, getIReg(size,eregOfRM(rm)) );
sewardje87b4842004-07-10 12:23:30 +00001875
sewardj180e8b32004-07-29 01:40:11 +00001876 if (addSubCarry && op8 == Iop_Add8) {
1877 vassert(0);
1878 helper_ADC( size, dst1, dst0, src );
sewardje87b4842004-07-10 12:23:30 +00001879 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00001880 } else
1881 if (addSubCarry && op8 == Iop_Sub8) {
sewardj180e8b32004-07-29 01:40:11 +00001882 helper_SBB( size, dst1, dst0, src );
1883 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1884 } else {
1885 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj5bd4d162004-11-10 13:02:48 +00001886 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001887 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001888 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001889 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00001890 if (keep)
1891 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1892 }
sewardje87b4842004-07-10 12:23:30 +00001893
1894 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1895 nameIReg(size,eregOfRM(rm)),
1896 nameIReg(size,gregOfRM(rm)));
1897 return 1+delta0;
sewardje87b4842004-07-10 12:23:30 +00001898 } else {
sewardj9334b0f2004-07-10 22:43:54 +00001899 /* E refers to memory */
1900 addr = disAMode ( &len, sorb, delta0, dis_buf);
1901 assign( dst0, getIReg(size,gregOfRM(rm)) );
sewardj940e8c92004-07-11 16:53:24 +00001902 assign( src, loadLE(szToITy(size), mkexpr(addr)) );
sewardj9334b0f2004-07-10 22:43:54 +00001903
sewardj180e8b32004-07-29 01:40:11 +00001904 if (addSubCarry && op8 == Iop_Add8) {
sewardj180e8b32004-07-29 01:40:11 +00001905 helper_ADC( size, dst1, dst0, src );
sewardj9334b0f2004-07-10 22:43:54 +00001906 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00001907 } else
1908 if (addSubCarry && op8 == Iop_Sub8) {
1909 helper_SBB( size, dst1, dst0, src );
1910 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1911 } else {
1912 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardj5bd4d162004-11-10 13:02:48 +00001913 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001914 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001915 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001916 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00001917 if (keep)
1918 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1919 }
sewardj9334b0f2004-07-10 22:43:54 +00001920
sewardje87b4842004-07-10 12:23:30 +00001921 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1922 dis_buf,nameIReg(size,gregOfRM(rm)));
sewardj9334b0f2004-07-10 22:43:54 +00001923 return len+delta0;
sewardje87b4842004-07-10 12:23:30 +00001924 }
sewardje87b4842004-07-10 12:23:30 +00001925}
sewardje05c42c2004-07-08 20:25:10 +00001926
1927
1928
1929/* Handle binary integer instructions of the form
1930 op G, E meaning
1931 op reg, reg-or-mem
1932 Is passed the a ptr to the modRM byte, the actual operation, and the
1933 data size. Returns the address advanced completely over this
1934 instruction.
1935
1936 G(src) is reg.
1937 E(dst) is reg-or-mem
1938
1939 If E is reg, --> GET %E, tmp
1940 OP %G, tmp
1941 PUT tmp, %E
1942
1943 If E is mem, --> (getAddr E) -> tmpa
1944 LD (tmpa), tmpv
1945 OP %G, tmpv
1946 ST tmpv, (tmpa)
1947*/
1948static
1949UInt dis_op2_G_E ( UChar sorb,
sewardjcaca9d02004-07-28 07:11:32 +00001950 Bool addSubCarry,
sewardje05c42c2004-07-08 20:25:10 +00001951 IROp op8,
1952 Bool keep,
1953 Int size,
1954 UInt delta0,
1955 Char* t_x86opc )
1956{
sewardje87b4842004-07-10 12:23:30 +00001957 UChar dis_buf[50];
1958 Int len;
sewardje05c42c2004-07-08 20:25:10 +00001959 IRType ty = szToITy(size);
1960 IRTemp dst1 = newTemp(ty);
1961 IRTemp src = newTemp(ty);
1962 IRTemp dst0 = newTemp(ty);
1963 UChar rm = getIByte(delta0);
sewardj92d168d2004-11-15 14:22:12 +00001964 IRTemp addr = IRTemp_INVALID;
sewardje05c42c2004-07-08 20:25:10 +00001965
sewardjcaca9d02004-07-28 07:11:32 +00001966 /* addSubCarry == True indicates the intended operation is
1967 add-with-carry or subtract-with-borrow. */
1968 if (addSubCarry) {
1969 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1970 vassert(keep);
1971 }
1972
sewardje05c42c2004-07-08 20:25:10 +00001973 if (epartIsReg(rm)) {
sewardje05c42c2004-07-08 20:25:10 +00001974 /* Specially handle XOR reg,reg, because that doesn't really
1975 depend on reg, and doing the obvious thing potentially
1976 generates a spurious value check failure due to the bogus
1977 dependency. */
sewardj5df3bfe2004-07-27 09:30:31 +00001978 if (op8 == Iop_Xor8 && gregOfRM(rm) == eregOfRM(rm)) {
1979 codegen_XOR_reg_with_itself ( size, gregOfRM(rm) );
1980 return 1+delta0;
sewardje05c42c2004-07-08 20:25:10 +00001981 }
sewardje05c42c2004-07-08 20:25:10 +00001982 assign(dst0, getIReg(size,eregOfRM(rm)));
1983 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00001984
sewardjcaca9d02004-07-28 07:11:32 +00001985 if (addSubCarry && op8 == Iop_Add8) {
sewardj1813dbe2004-07-28 17:09:04 +00001986 helper_ADC( size, dst1, dst0, src );
1987 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00001988 } else
1989 if (addSubCarry && op8 == Iop_Sub8) {
1990 helper_SBB( size, dst1, dst0, src );
sewardje05c42c2004-07-08 20:25:10 +00001991 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00001992 } else {
1993 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00001994 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00001995 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00001996 else
sewardj2a2ba8b2004-11-08 13:14:06 +00001997 setFlags_DEP1(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00001998 if (keep)
1999 putIReg(size, eregOfRM(rm), mkexpr(dst1));
2000 }
sewardje05c42c2004-07-08 20:25:10 +00002001
2002 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
2003 nameIReg(size,gregOfRM(rm)),
2004 nameIReg(size,eregOfRM(rm)));
2005 return 1+delta0;
2006 }
2007
2008 /* E refers to memory */
2009 {
sewardje87b4842004-07-10 12:23:30 +00002010 addr = disAMode ( &len, sorb, delta0, dis_buf);
sewardj940e8c92004-07-11 16:53:24 +00002011 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardje87b4842004-07-10 12:23:30 +00002012 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00002013
sewardjcaca9d02004-07-28 07:11:32 +00002014 if (addSubCarry && op8 == Iop_Add8) {
2015 helper_ADC( size, dst1, dst0, src );
2016 storeLE(mkexpr(addr), mkexpr(dst1));
2017 } else
2018 if (addSubCarry && op8 == Iop_Sub8) {
2019 helper_SBB( size, dst1, dst0, src );
2020 storeLE(mkexpr(addr), mkexpr(dst1));
2021 } else {
2022 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00002023 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002024 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002025 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002026 setFlags_DEP1(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00002027 if (keep)
2028 storeLE(mkexpr(addr), mkexpr(dst1));
2029 }
sewardje87b4842004-07-10 12:23:30 +00002030
sewardje05c42c2004-07-08 20:25:10 +00002031 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
2032 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje87b4842004-07-10 12:23:30 +00002033 return len+delta0;
sewardje05c42c2004-07-08 20:25:10 +00002034 }
2035}
2036
2037
2038/* Handle move instructions of the form
2039 mov E, G meaning
2040 mov reg-or-mem, reg
2041 Is passed the a ptr to the modRM byte, and the data size. Returns
2042 the address advanced completely over this instruction.
2043
2044 E(src) is reg-or-mem
2045 G(dst) is reg.
2046
2047 If E is reg, --> GET %E, tmpv
2048 PUT tmpv, %G
2049
2050 If E is mem --> (getAddr E) -> tmpa
2051 LD (tmpa), tmpb
2052 PUT tmpb, %G
2053*/
2054static
2055UInt dis_mov_E_G ( UChar sorb,
2056 Int size,
2057 UInt delta0 )
2058{
2059 Int len;
2060 UChar rm = getIByte(delta0);
2061 UChar dis_buf[50];
2062
2063 if (epartIsReg(rm)) {
sewardj7ca37d92004-10-25 02:58:30 +00002064 putIReg(size, gregOfRM(rm), getIReg(size, eregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00002065 DIP("mov%c %s,%s\n", nameISize(size),
2066 nameIReg(size,eregOfRM(rm)),
2067 nameIReg(size,gregOfRM(rm)));
sewardj7ca37d92004-10-25 02:58:30 +00002068 return 1+delta0;
sewardje05c42c2004-07-08 20:25:10 +00002069 }
2070
2071 /* E refers to memory */
2072 {
sewardj940e8c92004-07-11 16:53:24 +00002073 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
2074 putIReg(size, gregOfRM(rm), loadLE(szToITy(size), mkexpr(addr)));
sewardje05c42c2004-07-08 20:25:10 +00002075 DIP("mov%c %s,%s\n", nameISize(size),
2076 dis_buf,nameIReg(size,gregOfRM(rm)));
2077 return delta0+len;
2078 }
2079}
2080
2081
2082/* Handle move instructions of the form
2083 mov G, E meaning
2084 mov reg, reg-or-mem
2085 Is passed the a ptr to the modRM byte, and the data size. Returns
2086 the address advanced completely over this instruction.
2087
2088 G(src) is reg.
2089 E(dst) is reg-or-mem
2090
2091 If E is reg, --> GET %G, tmp
2092 PUT tmp, %E
2093
2094 If E is mem, --> (getAddr E) -> tmpa
2095 GET %G, tmpv
2096 ST tmpv, (tmpa)
2097*/
sewardjc9a65702004-07-07 16:32:57 +00002098static
2099UInt dis_mov_G_E ( UChar sorb,
2100 Int size,
2101 UInt delta0 )
2102{
sewardje05c42c2004-07-08 20:25:10 +00002103 Int len;
sewardjc9a65702004-07-07 16:32:57 +00002104 UChar rm = getIByte(delta0);
sewardje05c42c2004-07-08 20:25:10 +00002105 UChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00002106
2107 if (epartIsReg(rm)) {
sewardj41f43bc2004-07-08 14:23:22 +00002108 putIReg(size, eregOfRM(rm), getIReg(size, gregOfRM(rm)));
sewardjc9a65702004-07-07 16:32:57 +00002109 DIP("mov%c %s,%s\n", nameISize(size),
2110 nameIReg(size,gregOfRM(rm)),
2111 nameIReg(size,eregOfRM(rm)));
2112 return 1+delta0;
2113 }
2114
sewardjc9a65702004-07-07 16:32:57 +00002115 /* E refers to memory */
2116 {
sewardj940e8c92004-07-11 16:53:24 +00002117 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf);
2118 storeLE( mkexpr(addr), getIReg(size, gregOfRM(rm)) );
sewardjc9a65702004-07-07 16:32:57 +00002119 DIP("mov%c %s,%s\n", nameISize(size),
2120 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje05c42c2004-07-08 20:25:10 +00002121 return len+delta0;
sewardjc9a65702004-07-07 16:32:57 +00002122 }
sewardjc9a65702004-07-07 16:32:57 +00002123}
2124
2125
sewardj0611d802004-07-11 02:37:54 +00002126/* op $immediate, AL/AX/EAX. */
2127static
2128UInt dis_op_imm_A ( Int size,
2129 IROp op8,
2130 Bool keep,
2131 UInt delta,
2132 Char* t_x86opc )
2133{
2134 IRType ty = szToITy(size);
2135 IRTemp dst0 = newTemp(ty);
2136 IRTemp src = newTemp(ty);
2137 IRTemp dst1 = newTemp(ty);
2138 UInt lit = getUDisp(size,delta);
2139 assign(dst0, getIReg(size,R_EAX));
2140 assign(src, mkU(ty,lit));
2141 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardjb9c5cf62004-08-24 15:10:38 +00002142 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002143 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002144 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002145 if (isLogic(op8))
2146 setFlags_DEP1(op8, dst1, ty);
2147 else
2148 vpanic("dis_op_imm_A(x86,guest)");
sewardj0611d802004-07-11 02:37:54 +00002149
2150 if (keep)
2151 putIReg(size, R_EAX, mkexpr(dst1));
2152
2153 DIP("%s%c $0x%x, %s\n", t_x86opc, nameISize(size),
2154 lit, nameIReg(size,R_EAX));
2155 return delta+size;
2156}
sewardj9334b0f2004-07-10 22:43:54 +00002157
2158
2159/* Sign- and Zero-extending moves. */
2160static
2161UInt dis_movx_E_G ( UChar sorb,
2162 UInt delta, Int szs, Int szd, Bool sign_extend )
2163{
sewardj9334b0f2004-07-10 22:43:54 +00002164 UChar rm = getIByte(delta);
2165 if (epartIsReg(rm)) {
2166 putIReg(szd, gregOfRM(rm),
sewardj5bd4d162004-11-10 13:02:48 +00002167 unop(mkWidenOp(szs,szd,sign_extend),
2168 getIReg(szs,eregOfRM(rm))));
sewardj9334b0f2004-07-10 22:43:54 +00002169 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2170 nameISize(szs), nameISize(szd),
2171 nameIReg(szs,eregOfRM(rm)),
2172 nameIReg(szd,gregOfRM(rm)));
2173 return 1+delta;
2174 }
2175
2176 /* E refers to memory */
2177 {
sewardj940e8c92004-07-11 16:53:24 +00002178 Int len;
2179 UChar dis_buf[50];
2180 IRTemp addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj0611d802004-07-11 02:37:54 +00002181
2182 putIReg(szd, gregOfRM(rm),
sewardj5bd4d162004-11-10 13:02:48 +00002183 unop(mkWidenOp(szs,szd,sign_extend),
sewardj940e8c92004-07-11 16:53:24 +00002184 loadLE(szToITy(szs),mkexpr(addr))));
sewardj9334b0f2004-07-10 22:43:54 +00002185 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
2186 nameISize(szs), nameISize(szd),
2187 dis_buf, nameIReg(szd,gregOfRM(rm)));
sewardj0611d802004-07-11 02:37:54 +00002188 return len+delta;
sewardj9334b0f2004-07-10 22:43:54 +00002189 }
2190}
2191
sewardj9690d922004-07-14 01:39:17 +00002192
2193/* Generate code to divide ArchRegs EDX:EAX / DX:AX / AX by the 32 /
2194 16 / 8 bit quantity in the given IRTemp. */
2195static
2196void codegen_div ( Int sz, IRTemp t, Bool signed_divide )
2197{
sewardje5427e82004-09-11 19:43:51 +00002198 IROp op = signed_divide ? Iop_DivModS64to32 : Iop_DivModU64to32;
2199 IRTemp src64 = newTemp(Ity_I64);
2200 IRTemp dst64 = newTemp(Ity_I64);
sewardj9690d922004-07-14 01:39:17 +00002201 switch (sz) {
sewardje5427e82004-09-11 19:43:51 +00002202 case 4:
sewardj9690d922004-07-14 01:39:17 +00002203 assign( src64, binop(Iop_32HLto64,
sewardje5427e82004-09-11 19:43:51 +00002204 getIReg(4,R_EDX), getIReg(4,R_EAX)) );
sewardj9690d922004-07-14 01:39:17 +00002205 assign( dst64, binop(op, mkexpr(src64), mkexpr(t)) );
sewardj8c7f1ab2004-07-29 20:31:09 +00002206 putIReg( 4, R_EAX, unop(Iop_64to32,mkexpr(dst64)) );
sewardj9690d922004-07-14 01:39:17 +00002207 putIReg( 4, R_EDX, unop(Iop_64HIto32,mkexpr(dst64)) );
2208 break;
sewardje5427e82004-09-11 19:43:51 +00002209 case 2: {
2210 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2211 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2212 assign( src64, unop(widen3264,
2213 binop(Iop_16HLto32,
2214 getIReg(2,R_EDX), getIReg(2,R_EAX))) );
2215 assign( dst64, binop(op, mkexpr(src64), unop(widen1632,mkexpr(t))) );
2216 putIReg( 2, R_EAX, unop(Iop_32to16,unop(Iop_64to32,mkexpr(dst64))) );
2217 putIReg( 2, R_EDX, unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(dst64))) );
2218 break;
sewardj9690d922004-07-14 01:39:17 +00002219 }
sewardj4e82db72004-10-16 11:32:15 +00002220 case 1: {
2221 IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
2222 IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
2223 IROp widen816 = signed_divide ? Iop_8Sto16 : Iop_8Uto16;
2224 assign( src64, unop(widen3264, unop(widen1632, getIReg(2,R_EAX))) );
2225 assign( dst64,
2226 binop(op, mkexpr(src64),
2227 unop(widen1632, unop(widen816, mkexpr(t)))) );
2228 putIReg( 1, R_AL, unop(Iop_16to8, unop(Iop_32to16,
2229 unop(Iop_64to32,mkexpr(dst64)))) );
2230 putIReg( 1, R_AH, unop(Iop_16to8, unop(Iop_32to16,
2231 unop(Iop_64HIto32,mkexpr(dst64)))) );
2232 break;
2233 }
sewardj9690d922004-07-14 01:39:17 +00002234 default: vpanic("codegen_div(x86)");
2235 }
2236}
sewardjc9a65702004-07-07 16:32:57 +00002237//-- Int helper;
2238//-- Int ta = newTemp(cb);
2239//-- Int td = newTemp(cb);
2240//--
2241//-- switch (sz) {
2242//-- case 4: helper = (signed_divide ? VGOFF_(helper_idiv_64_32)
2243//-- : VGOFF_(helper_div_64_32));
2244//-- break;
2245//-- case 2: helper = (signed_divide ? VGOFF_(helper_idiv_32_16)
2246//-- : VGOFF_(helper_div_32_16));
2247//-- break;
2248//-- case 1: helper = (signed_divide ? VGOFF_(helper_idiv_16_8)
2249//-- : VGOFF_(helper_div_16_8));
2250//-- break;
2251//-- default: VG_(core_panic)("codegen_div");
2252//-- }
2253//-- uInstr0(cb, CALLM_S, 0);
2254//-- if (sz == 4 || sz == 2) {
2255//-- uInstr1(cb, PUSH, sz, TempReg, t);
2256//-- uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
2257//-- uInstr1(cb, PUSH, sz, TempReg, ta);
2258//-- uInstr2(cb, GET, sz, ArchReg, R_EDX, TempReg, td);
2259//-- uInstr1(cb, PUSH, sz, TempReg, td);
2260//-- uInstr1(cb, CALLM, 0, Lit16, helper);
2261//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsOSZACP);
2262//-- uInstr1(cb, POP, sz, TempReg, t);
2263//-- uInstr2(cb, PUT, sz, TempReg, t, ArchReg, R_EDX);
2264//-- uInstr1(cb, POP, sz, TempReg, t);
2265//-- uInstr2(cb, PUT, sz, TempReg, t, ArchReg, R_EAX);
2266//-- uInstr1(cb, CLEAR, 0, Lit16, 4);
2267//-- } else {
2268//-- uInstr1(cb, PUSH, 1, TempReg, t);
2269//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, ta);
2270//-- uInstr1(cb, PUSH, 2, TempReg, ta);
2271//-- uInstr2(cb, MOV, 1, Literal, 0, TempReg, td);
2272//-- uLiteral(cb, 0);
2273//-- uInstr1(cb, PUSH, 1, TempReg, td);
2274//-- uInstr1(cb, CALLM, 0, Lit16, helper);
2275//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsOSZACP);
2276//-- uInstr1(cb, POP, 1, TempReg, t);
2277//-- uInstr2(cb, PUT, 1, TempReg, t, ArchReg, R_AL);
2278//-- uInstr1(cb, POP, 1, TempReg, t);
2279//-- uInstr2(cb, PUT, 1, TempReg, t, ArchReg, R_AH);
2280//-- uInstr1(cb, CLEAR, 0, Lit16, 4);
2281//-- }
2282//-- uInstr0(cb, CALLM_E, 0);
2283//-- }
sewardj41f43bc2004-07-08 14:23:22 +00002284
2285
2286static
sewardje90ad6a2004-07-10 19:02:10 +00002287UInt dis_Grp1 ( UChar sorb,
sewardj41f43bc2004-07-08 14:23:22 +00002288 UInt delta, UChar modrm,
2289 Int am_sz, Int d_sz, Int sz, UInt d32 )
2290{
sewardj41f43bc2004-07-08 14:23:22 +00002291 Int len;
2292 UChar dis_buf[50];
sewardje05c42c2004-07-08 20:25:10 +00002293 IRType ty = szToITy(sz);
2294 IRTemp dst1 = newTemp(ty);
2295 IRTemp src = newTemp(ty);
2296 IRTemp dst0 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002297 IRTemp addr = IRTemp_INVALID;
sewardj66de2272004-07-16 21:19:05 +00002298 IROp op8 = Iop_INVALID;
sewardj180e8b32004-07-29 01:40:11 +00002299 UInt mask = sz==1 ? 0xFF : (sz==2 ? 0xFFFF : 0xFFFFFFFF);
sewardj41f43bc2004-07-08 14:23:22 +00002300
2301 switch (gregOfRM(modrm)) {
sewardje05c42c2004-07-08 20:25:10 +00002302 case 0: op8 = Iop_Add8; break; case 1: op8 = Iop_Or8; break;
sewardj66de2272004-07-16 21:19:05 +00002303 case 2: break; // ADC
2304 case 3: break; // SBB
sewardje05c42c2004-07-08 20:25:10 +00002305 case 4: op8 = Iop_And8; break; case 5: op8 = Iop_Sub8; break;
2306 case 6: op8 = Iop_Xor8; break; case 7: op8 = Iop_Sub8; break;
sewardj41f43bc2004-07-08 14:23:22 +00002307 default: vpanic("dis_Grp1: unhandled case");
2308 }
sewardj41f43bc2004-07-08 14:23:22 +00002309
2310 if (epartIsReg(modrm)) {
2311 vassert(am_sz == 1);
2312
2313 assign(dst0, getIReg(sz,eregOfRM(modrm)));
sewardj180e8b32004-07-29 01:40:11 +00002314 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002315
sewardj180e8b32004-07-29 01:40:11 +00002316 if (gregOfRM(modrm) == 2 /* ADC */) {
2317 helper_ADC( sz, dst1, dst0, src );
2318 } else
2319 if (gregOfRM(modrm) == 3 /* SBB */) {
2320 helper_SBB( sz, dst1, dst0, src );
2321 } else {
2322 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00002323 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002324 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002325 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002326 setFlags_DEP1(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00002327 }
sewardj41f43bc2004-07-08 14:23:22 +00002328
2329 if (gregOfRM(modrm) < 7)
sewardje05c42c2004-07-08 20:25:10 +00002330 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardj41f43bc2004-07-08 14:23:22 +00002331
2332 delta += (am_sz + d_sz);
2333 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz), d32,
2334 nameIReg(sz,eregOfRM(modrm)));
2335 } else {
sewardje87b4842004-07-10 12:23:30 +00002336 addr = disAMode ( &len, sorb, delta, dis_buf);
sewardj41f43bc2004-07-08 14:23:22 +00002337
sewardj940e8c92004-07-11 16:53:24 +00002338 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj180e8b32004-07-29 01:40:11 +00002339 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002340
sewardj66de2272004-07-16 21:19:05 +00002341 if (gregOfRM(modrm) == 2 /* ADC */) {
sewardj3af115f2004-07-14 02:46:52 +00002342 helper_ADC( sz, dst1, dst0, src );
2343 } else
sewardj66de2272004-07-16 21:19:05 +00002344 if (gregOfRM(modrm) == 3 /* SBB */) {
sewardje166ed02004-10-25 02:27:01 +00002345 helper_SBB( sz, dst1, dst0, src );
sewardj3af115f2004-07-14 02:46:52 +00002346 } else {
2347 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardj5bd4d162004-11-10 13:02:48 +00002348 if (isAddSub(op8))
sewardj2a2ba8b2004-11-08 13:14:06 +00002349 setFlags_DEP1_DEP2(op8, dst0, src, ty);
sewardjb9c5cf62004-08-24 15:10:38 +00002350 else
sewardj2a2ba8b2004-11-08 13:14:06 +00002351 setFlags_DEP1(op8, dst1, ty);
sewardj3af115f2004-07-14 02:46:52 +00002352 }
sewardj41f43bc2004-07-08 14:23:22 +00002353
2354 if (gregOfRM(modrm) < 7)
sewardj940e8c92004-07-11 16:53:24 +00002355 storeLE(mkexpr(addr), mkexpr(dst1));
sewardj41f43bc2004-07-08 14:23:22 +00002356
2357 delta += (len+d_sz);
2358 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz),
2359 d32, dis_buf);
2360 }
2361 return delta;
2362}
2363
2364
sewardj6d2638e2004-07-15 09:38:27 +00002365/* Group 2 extended opcodes. shift_expr must be an 8-bit typed
2366 expression. */
2367
sewardje90ad6a2004-07-10 19:02:10 +00002368static
2369UInt dis_Grp2 ( UChar sorb,
2370 UInt delta, UChar modrm,
sewardj6d2638e2004-07-15 09:38:27 +00002371 Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
2372 Char* shift_expr_txt )
sewardje90ad6a2004-07-10 19:02:10 +00002373{
2374 /* delta on entry points at the modrm byte. */
sewardj6d2638e2004-07-15 09:38:27 +00002375 UChar dis_buf[50];
2376 Int len;
sewardj9aebb0c2004-10-24 19:20:43 +00002377 Bool isShift, isRotate, isRotateRC;
sewardj6d2638e2004-07-15 09:38:27 +00002378 IRType ty = szToITy(sz);
2379 IRTemp dst0 = newTemp(ty);
2380 IRTemp dst1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002381 IRTemp addr = IRTemp_INVALID;
sewardje90ad6a2004-07-10 19:02:10 +00002382
2383 vassert(sz == 1 || sz == 2 || sz == 4);
2384
sewardje90ad6a2004-07-10 19:02:10 +00002385 /* Put value to shift/rotate in dst0. */
2386 if (epartIsReg(modrm)) {
2387 assign(dst0, getIReg(sz, eregOfRM(modrm)));
sewardj940e8c92004-07-11 16:53:24 +00002388 delta += (am_sz + d_sz);
sewardje90ad6a2004-07-10 19:02:10 +00002389 } else {
sewardj940e8c92004-07-11 16:53:24 +00002390 addr = disAMode ( &len, sorb, delta, dis_buf);
2391 assign(dst0, loadLE(ty,mkexpr(addr)));
2392 delta += len + d_sz;
sewardje90ad6a2004-07-10 19:02:10 +00002393 }
2394
2395 isShift = False;
2396 switch (gregOfRM(modrm)) { case 4: case 5: case 7: isShift = True; }
2397
sewardj750f4072004-07-26 22:39:11 +00002398 isRotate = False;
2399 switch (gregOfRM(modrm)) { case 0: case 1: isRotate = True; }
2400
sewardj9aebb0c2004-10-24 19:20:43 +00002401 isRotateRC = gregOfRM(modrm) == 3;
2402
2403 if (!isShift && !isRotate && !isRotateRC) {
sewardj8c7f1ab2004-07-29 20:31:09 +00002404 vex_printf("\ncase %d\n", gregOfRM(modrm));
2405 vpanic("dis_Grp2(Reg): unhandled case(x86)");
2406 }
2407
sewardj9aebb0c2004-10-24 19:20:43 +00002408 if (isRotateRC) {
2409 /* call a helper; this insn is so ridiculous it does not deserve
2410 better */
2411 IRTemp r64 = newTemp(Ity_I64);
sewardjf9655262004-10-31 20:02:16 +00002412 IRExpr** args
2413 = mkIRExprVec_4( widenUto32(mkexpr(dst0)), /* thing to rotate */
2414 widenUto32(shift_expr), /* rotate amount */
2415 widenUto32(mk_calculate_eflags_all()),
2416 mkU32(sz) );
2417 assign( r64, mkIRExprCCall(
sewardj8ea867b2004-10-30 19:03:02 +00002418 Ity_I64,
sewardjf9655262004-10-31 20:02:16 +00002419 0/*regparm*/,
2420 "calculate_RCR", &calculate_RCR,
sewardj8ea867b2004-10-30 19:03:02 +00002421 args
sewardjf9655262004-10-31 20:02:16 +00002422 )
2423 );
sewardj9aebb0c2004-10-24 19:20:43 +00002424 /* new eflags in hi half r64; new value in lo half r64 */
2425 assign( dst1, narrowTo(ty, unop(Iop_64to32, mkexpr(r64))) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002426 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
2427 stmt( IRStmt_Put( OFFB_CC_DEP1, unop(Iop_64HIto32, mkexpr(r64)) ));
2428 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardj9aebb0c2004-10-24 19:20:43 +00002429 }
2430
sewardje90ad6a2004-07-10 19:02:10 +00002431 if (isShift) {
2432
sewardjc22a6fd2004-07-29 23:41:47 +00002433 IRTemp pre32 = newTemp(Ity_I32);
2434 IRTemp res32 = newTemp(Ity_I32);
2435 IRTemp res32ss = newTemp(Ity_I32);
sewardj6d2638e2004-07-15 09:38:27 +00002436 IRTemp shift_amt = newTemp(Ity_I8);
sewardjc22a6fd2004-07-29 23:41:47 +00002437 IROp op32;
sewardje90ad6a2004-07-10 19:02:10 +00002438
2439 switch (gregOfRM(modrm)) {
sewardjc22a6fd2004-07-29 23:41:47 +00002440 case 4: op32 = Iop_Shl32; break;
2441 case 5: op32 = Iop_Shr32; break;
2442 case 7: op32 = Iop_Sar32; break;
sewardje90ad6a2004-07-10 19:02:10 +00002443 default: vpanic("dis_Grp2:shift"); break;
2444 }
2445
sewardjc22a6fd2004-07-29 23:41:47 +00002446 /* Widen the value to be shifted to 32 bits, do the shift, and
2447 narrow back down. This seems surprisingly long-winded, but
2448 unfortunately the Intel semantics requires that 8/16-bit
2449 shifts give defined results for shift values all the way up
2450 to 31, and this seems the simplest way to do it. It has the
2451 advantage that the only IR level shifts generated are of 32
2452 bit values, and the shift amount is guaranteed to be in the
2453 range 0 .. 31, thereby observing the IR semantics requiring
2454 all shift values to be in the range 0 .. 2^word_size-1. */
2455
2456 /* shift_amt = shift_expr & 31, regardless of operation size */
2457 assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(31)) );
2458
2459 /* suitably widen the value to be shifted to 32 bits. */
2460 assign( pre32, op32==Iop_Sar32 ? widenSto32(mkexpr(dst0))
2461 : widenUto32(mkexpr(dst0)) );
2462
2463 /* res32 = pre32 `shift` shift_amt */
2464 assign( res32, binop(op32, mkexpr(pre32), mkexpr(shift_amt)) );
2465
2466 /* res32ss = pre32 `shift` ((shift_amt - 1) & 31) */
2467 assign( res32ss,
2468 binop(op32,
2469 mkexpr(pre32),
2470 binop(Iop_And8,
2471 binop(Iop_Sub8,
2472 mkexpr(shift_amt), mkU8(1)),
2473 mkU8(31))) );
sewardje90ad6a2004-07-10 19:02:10 +00002474
2475 /* Build the flags thunk. */
sewardj2a2ba8b2004-11-08 13:14:06 +00002476 setFlags_DEP1_DEP2_shift(op32, res32, res32ss, ty, shift_amt);
sewardjc22a6fd2004-07-29 23:41:47 +00002477
2478 /* Narrow the result back down. */
2479 assign( dst1, narrowTo(ty, mkexpr(res32)) );
sewardj750f4072004-07-26 22:39:11 +00002480
sewardj1813dbe2004-07-28 17:09:04 +00002481 } /* if (isShift) */
2482
2483 else
sewardj750f4072004-07-26 22:39:11 +00002484 if (isRotate) {
sewardj7ebbdae2004-08-26 12:30:48 +00002485 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
2486 Bool left = gregOfRM(modrm) == 0;
2487 IRTemp rot_amt = newTemp(Ity_I8);
2488 IRTemp rot_amt32 = newTemp(Ity_I8);
2489 IRTemp oldFlags = newTemp(Ity_I32);
sewardj750f4072004-07-26 22:39:11 +00002490
2491 /* rot_amt = shift_expr & mask */
sewardjc22a6fd2004-07-29 23:41:47 +00002492 /* By masking the rotate amount thusly, the IR-level Shl/Shr
2493 expressions never shift beyond the word size and thus remain
2494 well defined. */
sewardj7ebbdae2004-08-26 12:30:48 +00002495 assign(rot_amt32, binop(Iop_And8, shift_expr, mkU8(31)));
2496
2497 if (ty == Ity_I32)
2498 assign(rot_amt, mkexpr(rot_amt32));
2499 else
2500 assign(rot_amt, binop(Iop_And8, mkexpr(rot_amt32), mkU8(8*sz-1)));
sewardj750f4072004-07-26 22:39:11 +00002501
2502 if (left) {
sewardj1813dbe2004-07-28 17:09:04 +00002503
sewardj750f4072004-07-26 22:39:11 +00002504 /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
2505 assign(dst1,
2506 binop( mkSizedOp(ty,Iop_Or8),
2507 binop( mkSizedOp(ty,Iop_Shl8),
2508 mkexpr(dst0),
2509 mkexpr(rot_amt)
2510 ),
2511 binop( mkSizedOp(ty,Iop_Shr8),
2512 mkexpr(dst0),
2513 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
2514 )
2515 )
2516 );
sewardj1813dbe2004-07-28 17:09:04 +00002517 ccOp += CC_OP_ROLB;
sewardj750f4072004-07-26 22:39:11 +00002518
sewardj1813dbe2004-07-28 17:09:04 +00002519 } else { /* right */
sewardj750f4072004-07-26 22:39:11 +00002520
sewardj1813dbe2004-07-28 17:09:04 +00002521 /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
2522 assign(dst1,
2523 binop( mkSizedOp(ty,Iop_Or8),
2524 binop( mkSizedOp(ty,Iop_Shr8),
2525 mkexpr(dst0),
2526 mkexpr(rot_amt)
2527 ),
2528 binop( mkSizedOp(ty,Iop_Shl8),
2529 mkexpr(dst0),
2530 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
sewardj750f4072004-07-26 22:39:11 +00002531 )
2532 )
2533 );
sewardj1813dbe2004-07-28 17:09:04 +00002534 ccOp += CC_OP_RORB;
sewardjc22a6fd2004-07-29 23:41:47 +00002535
sewardj750f4072004-07-26 22:39:11 +00002536 }
sewardjc22a6fd2004-07-29 23:41:47 +00002537
sewardj1813dbe2004-07-28 17:09:04 +00002538 /* dst1 now holds the rotated value. Build flag thunk. We
2539 need the resulting value for this, and the previous flags.
2540 Except don't set it if the rotate count is zero. */
2541
2542 assign(oldFlags, mk_calculate_eflags_all());
2543
sewardj2a2ba8b2004-11-08 13:14:06 +00002544 /* CC_DEP1 is the rotated value. CC_NDEP is flags before. */
sewardj1813dbe2004-07-28 17:09:04 +00002545 stmt( IRStmt_Put( OFFB_CC_OP,
sewardj7ebbdae2004-08-26 12:30:48 +00002546 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj1813dbe2004-07-28 17:09:04 +00002547 IRExpr_Get(OFFB_CC_OP,Ity_I32),
2548 mkU32(ccOp))) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002549 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj7ebbdae2004-08-26 12:30:48 +00002550 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj2a2ba8b2004-11-08 13:14:06 +00002551 IRExpr_Get(OFFB_CC_DEP1,Ity_I32),
sewardjc22a6fd2004-07-29 23:41:47 +00002552 widenUto32(mkexpr(dst1)))) );
sewardj2a2ba8b2004-11-08 13:14:06 +00002553 stmt( IRStmt_Put( OFFB_CC_DEP2,
sewardj7ebbdae2004-08-26 12:30:48 +00002554 IRExpr_Mux0X( mkexpr(rot_amt32),
sewardj2a2ba8b2004-11-08 13:14:06 +00002555 IRExpr_Get(OFFB_CC_DEP2,Ity_I32),
2556 mkU32(0))) );
2557 stmt( IRStmt_Put( OFFB_CC_NDEP,
2558 IRExpr_Mux0X( mkexpr(rot_amt32),
2559 IRExpr_Get(OFFB_CC_NDEP,Ity_I32),
sewardj1813dbe2004-07-28 17:09:04 +00002560 mkexpr(oldFlags))) );
2561 } /* if (isRotate) */
sewardje90ad6a2004-07-10 19:02:10 +00002562
2563 /* Save result, and finish up. */
2564 if (epartIsReg(modrm)) {
2565 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardjf48ac192004-10-29 00:41:29 +00002566 if (vex_traceflags & VEX_TRACE_FE) {
sewardje90ad6a2004-07-10 19:02:10 +00002567 vex_printf("%s%c ",
2568 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002569 if (shift_expr_txt)
2570 vex_printf("%s", shift_expr_txt);
2571 else
2572 ppIRExpr(shift_expr);
sewardje90ad6a2004-07-10 19:02:10 +00002573 vex_printf(", %s\n", nameIReg(sz,eregOfRM(modrm)));
2574 }
sewardje90ad6a2004-07-10 19:02:10 +00002575 } else {
sewardj940e8c92004-07-11 16:53:24 +00002576 storeLE(mkexpr(addr), mkexpr(dst1));
sewardjf48ac192004-10-29 00:41:29 +00002577 if (vex_traceflags & VEX_TRACE_FE) {
sewardj940e8c92004-07-11 16:53:24 +00002578 vex_printf("%s%c ",
2579 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002580 if (shift_expr_txt)
2581 vex_printf("%s", shift_expr_txt);
2582 else
2583 ppIRExpr(shift_expr);
sewardj940e8c92004-07-11 16:53:24 +00002584 vex_printf(", %s\n", dis_buf);
2585 }
sewardje90ad6a2004-07-10 19:02:10 +00002586 }
sewardje90ad6a2004-07-10 19:02:10 +00002587 return delta;
2588}
2589
2590
2591
sewardjc9a65702004-07-07 16:32:57 +00002592//-- /* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
2593//-- static
2594//-- Addr dis_Grp8_BT ( UCodeBlock* cb,
2595//-- UChar sorb,
2596//-- Addr eip, UChar modrm,
2597//-- Int am_sz, Int sz, UInt src_val )
2598//-- {
sewardj5bd4d162004-11-10 13:02:48 +00002599# define MODIFY_t2_AND_SET_CARRY_FLAG \
2600 /* t2 is the value to be op'd on. Copy to t_fetched, then \
2601 modify t2, if non-BT. */ \
2602 uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t_fetched); \
2603 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
2604 uLiteral(cb, v_mask); \
2605 switch (gregOfRM(modrm)) { \
2606 case 4: /* BT */ break; \
2607 case 5: /* BTS */ \
2608 uInstr2(cb, OR, sz, TempReg, t_mask, TempReg, t2); break; \
2609 case 6: /* BTR */ \
2610 uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t2); break; \
2611 case 7: /* BTC */ \
2612 uInstr2(cb, XOR, sz, TempReg, t_mask, TempReg, t2); break; \
2613 } \
2614 /* Copy relevant bit from t_fetched into carry flag. */ \
2615 uInstr2(cb, SHR, sz, Literal, 0, TempReg, t_fetched); \
2616 uLiteral(cb, src_val); \
2617 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
2618 uLiteral(cb, 1); \
2619 uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t_fetched); \
2620 uInstr1(cb, NEG, sz, TempReg, t_fetched); \
sewardjd1061ab2004-07-08 01:45:30 +00002621 setFlagsFromUOpcode(cb, NEG);
2622
2623
sewardjc9a65702004-07-07 16:32:57 +00002624//-- /* src_val denotes a d8.
2625//-- And eip on entry points at the modrm byte. */
2626//-- Int t1, t2, t_fetched, t_mask;
2627//-- UInt pair;
2628//-- Char dis_buf[50];
2629//-- UInt v_mask;
2630//--
2631//-- /* There is no 1-byte form of this instruction, AFAICS. */
2632//-- vg_assert(sz == 2 || sz == 4);
2633//--
2634//-- /* Limit src_val -- the bit offset -- to something within a word.
2635//-- The Intel docs say that literal offsets larger than a word are
2636//-- masked in this way. */
2637//-- switch (sz) {
2638//-- case 2: src_val &= 15; break;
2639//-- case 4: src_val &= 31; break;
2640//-- default: VG_(core_panic)("dis_Grp8_BT: invalid size");
2641//-- }
2642//--
2643//-- /* Invent a mask suitable for the operation. */
2644//--
2645//-- switch (gregOfRM(modrm)) {
2646//-- case 4: /* BT */ v_mask = 0; break;
2647//-- case 5: /* BTS */ v_mask = 1 << src_val; break;
2648//-- case 6: /* BTR */ v_mask = ~(1 << src_val); break;
2649//-- case 7: /* BTC */ v_mask = 1 << src_val; break;
2650//-- /* If this needs to be extended, probably simplest to make a
2651//-- new function to handle the other cases (0 .. 3). The
2652//-- Intel docs do however not indicate any use for 0 .. 3, so
2653//-- we don't expect this to happen. */
2654//-- default: VG_(core_panic)("dis_Grp8_BT");
2655//-- }
2656//-- /* Probably excessively paranoid. */
2657//-- if (sz == 2)
2658//-- v_mask &= 0x0000FFFF;
2659//--
2660//-- t1 = INVALID_TEMPREG;
2661//-- t_fetched = newTemp(cb);
2662//-- t_mask = newTemp(cb);
2663//--
2664//-- if (epartIsReg(modrm)) {
2665//-- vg_assert(am_sz == 1);
2666//-- t2 = newTemp(cb);
2667//--
2668//-- /* Fetch the value to be tested and modified. */
2669//-- uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t2);
2670//-- /* Do it! */
2671//-- MODIFY_t2_AND_SET_CARRY_FLAG;
2672//-- /* Dump the result back, if non-BT. */
2673//-- if (gregOfRM(modrm) != 4 /* BT */)
2674//-- uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, eregOfRM(modrm));
2675//--
2676//-- eip += (am_sz + 1);
2677//-- DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2678//-- src_val, nameIReg(sz,eregOfRM(modrm)));
2679//-- } else {
2680//-- pair = disAMode ( cb, sorb, eip, dis_buf);
2681//-- t1 = LOW24(pair);
2682//-- t2 = newTemp(cb);
2683//-- eip += HI8(pair);
2684//-- eip += 1;
2685//--
2686//-- /* Fetch the value to be tested and modified. */
2687//-- uInstr2(cb, LOAD, sz, TempReg, t1, TempReg, t2);
2688//-- /* Do it! */
2689//-- MODIFY_t2_AND_SET_CARRY_FLAG;
2690//-- /* Dump the result back, if non-BT. */
2691//-- if (gregOfRM(modrm) != 4 /* BT */) {
2692//-- uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
2693//-- }
2694//-- DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2695//-- src_val, dis_buf);
2696//-- }
2697//-- return eip;
2698//--
2699//-- # undef MODIFY_t2_AND_SET_CARRY_FLAG
2700//-- }
sewardjcf780b42004-07-13 18:42:17 +00002701
2702
2703
sewardj1813dbe2004-07-28 17:09:04 +00002704/* Signed/unsigned widening multiply. Generate IR to multiply the
2705 value in EAX/AX/AL by the given IRTemp, and park the result in
2706 EDX:EAX/DX:AX/AX.
sewardjcf780b42004-07-13 18:42:17 +00002707*/
sewardj1813dbe2004-07-28 17:09:04 +00002708static void codegen_mulL_A_D ( Int sz, Bool syned,
2709 IRTemp tmp, Char* tmp_txt )
sewardjcf780b42004-07-13 18:42:17 +00002710{
sewardjcf780b42004-07-13 18:42:17 +00002711 IRType ty = szToITy(sz);
2712 IRTemp t1 = newTemp(ty);
sewardjcf780b42004-07-13 18:42:17 +00002713
sewardj1813dbe2004-07-28 17:09:04 +00002714 assign( t1, getIReg(sz, R_EAX) );
sewardjcf780b42004-07-13 18:42:17 +00002715
2716 switch (ty) {
sewardjb81f8b32004-07-30 10:17:50 +00002717 case Ity_I32: {
2718 IRTemp res64 = newTemp(Ity_I64);
sewardj948d48b2004-11-05 19:49:09 +00002719 IRTemp resHi = newTemp(Ity_I32);
2720 IRTemp resLo = newTemp(Ity_I32);
sewardjb81f8b32004-07-30 10:17:50 +00002721 IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32;
2722 UInt tBaseOp = syned ? CC_OP_SMULB : CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002723 setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002724 assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002725 assign( resHi, unop(Iop_64HIto32,mkexpr(res64)));
2726 assign( resLo, unop(Iop_64to32,mkexpr(res64)));
sewardj948d48b2004-11-05 19:49:09 +00002727 putIReg(4, R_EDX, mkexpr(resHi));
2728 putIReg(4, R_EAX, mkexpr(resLo));
sewardjb81f8b32004-07-30 10:17:50 +00002729 break;
2730 }
2731 case Ity_I16: {
2732 IRTemp res32 = newTemp(Ity_I32);
sewardj948d48b2004-11-05 19:49:09 +00002733 IRTemp resHi = newTemp(Ity_I16);
2734 IRTemp resLo = newTemp(Ity_I16);
sewardjb81f8b32004-07-30 10:17:50 +00002735 IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16;
2736 UInt tBaseOp = syned ? CC_OP_SMULB : CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002737 setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002738 assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002739 assign( resHi, unop(Iop_32HIto16,mkexpr(res32)));
2740 assign( resLo, unop(Iop_32to16,mkexpr(res32)));
sewardj948d48b2004-11-05 19:49:09 +00002741 putIReg(2, R_EDX, mkexpr(resHi));
2742 putIReg(2, R_EAX, mkexpr(resLo));
sewardjb81f8b32004-07-30 10:17:50 +00002743 break;
2744 }
2745 case Ity_I8: {
2746 IRTemp res16 = newTemp(Ity_I16);
sewardj948d48b2004-11-05 19:49:09 +00002747 IRTemp resHi = newTemp(Ity_I8);
2748 IRTemp resLo = newTemp(Ity_I8);
sewardjb81f8b32004-07-30 10:17:50 +00002749 IROp mulOp = syned ? Iop_MullS8 : Iop_MullU8;
2750 UInt tBaseOp = syned ? CC_OP_SMULB : CC_OP_UMULB;
sewardj2a2ba8b2004-11-08 13:14:06 +00002751 setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
sewardjb81f8b32004-07-30 10:17:50 +00002752 assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
sewardj948d48b2004-11-05 19:49:09 +00002753 assign( resHi, unop(Iop_16HIto8,mkexpr(res16)));
2754 assign( resLo, unop(Iop_16to8,mkexpr(res16)));
sewardjb81f8b32004-07-30 10:17:50 +00002755 putIReg(2, R_EAX, mkexpr(res16));
2756 break;
2757 }
2758 default:
2759 vpanic("codegen_mulL_A_D(x86)");
sewardjcf780b42004-07-13 18:42:17 +00002760 }
sewardj1813dbe2004-07-28 17:09:04 +00002761 DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
sewardjcf780b42004-07-13 18:42:17 +00002762}
2763
sewardj940e8c92004-07-11 16:53:24 +00002764
2765/* Group 3 extended opcodes. */
2766static
2767UInt dis_Grp3 ( UChar sorb, Int sz, UInt delta )
2768{
sewardjc2ac51e2004-07-12 01:03:26 +00002769 UInt d32;
sewardj940e8c92004-07-11 16:53:24 +00002770 UChar modrm;
2771 UChar dis_buf[50];
sewardjc2ac51e2004-07-12 01:03:26 +00002772 Int len;
2773 IRTemp addr;
sewardj940e8c92004-07-11 16:53:24 +00002774 IRType ty = szToITy(sz);
2775 IRTemp t1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002776 // IRTemp t2 = IRTemp_INVALID;
sewardj940e8c92004-07-11 16:53:24 +00002777 IRTemp dst1, src, dst0;
2778 modrm = getIByte(delta);
2779 if (epartIsReg(modrm)) {
2780 switch (gregOfRM(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002781 case 0: { /* TEST */
2782 delta++; d32 = getUDisp(sz, delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00002783 dst1 = newTemp(ty);
2784 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2785 getIReg(sz,eregOfRM(modrm)),
sewardjc2ac51e2004-07-12 01:03:26 +00002786 mkU(ty,d32)));
sewardj5bd4d162004-11-10 13:02:48 +00002787 setFlags_DEP1( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002788 DIP("test%c $0x%x, %s\n", nameISize(sz), d32,
2789 nameIReg(sz, eregOfRM(modrm)));
2790 break;
2791 }
sewardj940e8c92004-07-11 16:53:24 +00002792 case 2: /* NOT */
2793 delta++;
2794 putIReg(sz, eregOfRM(modrm),
2795 unop(mkSizedOp(ty,Iop_Not8),
2796 getIReg(sz, eregOfRM(modrm))));
2797 DIP("not%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2798 break;
2799 case 3: /* NEG */
2800 delta++;
2801 dst0 = newTemp(ty);
2802 src = newTemp(ty);
2803 dst1 = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002804 assign(dst0, mkU(ty,0));
sewardja511afc2004-07-29 22:26:03 +00002805 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj5bd4d162004-11-10 13:02:48 +00002806 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
sewardj2a2ba8b2004-11-08 13:14:06 +00002807 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj5bd4d162004-11-10 13:02:48 +00002808 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardj940e8c92004-07-11 16:53:24 +00002809 DIP("neg%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2810 break;
sewardjcf780b42004-07-13 18:42:17 +00002811 case 4: /* MUL (unsigned widening) */
2812 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002813 src = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002814 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj1813dbe2004-07-28 17:09:04 +00002815 codegen_mulL_A_D ( sz, False, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcf780b42004-07-13 18:42:17 +00002816 break;
sewardjcaca9d02004-07-28 07:11:32 +00002817 case 5: /* IMUL (signed widening) */
2818 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002819 src = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002820 assign(src, getIReg(sz,eregOfRM(modrm)));
sewardj1813dbe2004-07-28 17:09:04 +00002821 codegen_mulL_A_D ( sz, True, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcaca9d02004-07-28 07:11:32 +00002822 break;
sewardj68511542004-07-28 00:15:44 +00002823 case 6: /* DIV */
2824 delta++;
2825 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2826 codegen_div ( sz, t1, False );
2827 DIP("div%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2828 break;
sewardjcaca9d02004-07-28 07:11:32 +00002829 case 7: /* IDIV */
2830 delta++;
2831 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2832 codegen_div ( sz, t1, True );
2833 DIP("idiv%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2834 break;
sewardj940e8c92004-07-11 16:53:24 +00002835 default:
2836 vex_printf(
2837 "unhandled Grp3(R) case %d\n", (UInt)gregOfRM(modrm));
2838 vpanic("Grp3(x86)");
2839 }
2840 } else {
sewardjc2ac51e2004-07-12 01:03:26 +00002841 addr = disAMode ( &len, sorb, delta, dis_buf );
2842 t1 = newTemp(ty);
2843 delta += len;
2844 assign(t1, loadLE(ty,mkexpr(addr)));
2845 switch (gregOfRM(modrm)) {
2846 case 0: { /* TEST */
2847 d32 = getUDisp(sz, delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00002848 dst1 = newTemp(ty);
2849 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2850 mkexpr(t1), mkU(ty,d32)));
2851 setFlags_DEP1( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002852 DIP("test%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
2853 break;
2854 }
sewardj78fe7912004-08-20 23:38:07 +00002855 /* probably OK, but awaiting test case */
2856 case 2: /* NOT */
2857 storeLE( mkexpr(addr), unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
2858 DIP("not%c %s\n", nameISize(sz), dis_buf);
2859 break;
sewardj0c12ea82004-07-12 08:18:16 +00002860 case 3: /* NEG */
2861 dst0 = newTemp(ty);
2862 src = newTemp(ty);
2863 dst1 = newTemp(ty);
sewardj5bd4d162004-11-10 13:02:48 +00002864 assign(dst0, mkU(ty,0));
sewardja511afc2004-07-29 22:26:03 +00002865 assign(src, mkexpr(t1));
sewardj5bd4d162004-11-10 13:02:48 +00002866 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
sewardj2a2ba8b2004-11-08 13:14:06 +00002867 setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
sewardj5bd4d162004-11-10 13:02:48 +00002868 storeLE( mkexpr(addr), mkexpr(dst1) );
sewardj0c12ea82004-07-12 08:18:16 +00002869 DIP("neg%c %s\n", nameISize(sz), dis_buf);
2870 break;
sewardj1813dbe2004-07-28 17:09:04 +00002871 case 4: /* MUL */
2872 codegen_mulL_A_D ( sz, False, t1, dis_buf );
2873 break;
2874 case 5: /* IMUL */
2875 codegen_mulL_A_D ( sz, True, t1, dis_buf );
2876 break;
sewardj9690d922004-07-14 01:39:17 +00002877 case 6: /* DIV */
2878 codegen_div ( sz, t1, False );
2879 DIP("div%c %s\n", nameISize(sz), dis_buf);
2880 break;
sewardj1813dbe2004-07-28 17:09:04 +00002881 case 7: /* IDIV */
2882 codegen_div ( sz, t1, True );
2883 DIP("idiv%c %s\n", nameISize(sz), dis_buf);
2884 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002885 default:
2886 vex_printf(
2887 "unhandled Grp3(M) case %d\n", (UInt)gregOfRM(modrm));
2888 vpanic("Grp3(x86)");
2889 }
sewardj940e8c92004-07-11 16:53:24 +00002890 }
2891 return delta;
2892}
2893
2894
sewardjc2ac51e2004-07-12 01:03:26 +00002895/* Group 4 extended opcodes. */
2896static
2897UInt dis_Grp4 ( UChar sorb, UInt delta )
2898{
sewardj7ed22952004-07-29 00:09:58 +00002899 Int alen;
sewardjc2ac51e2004-07-12 01:03:26 +00002900 UChar modrm;
sewardj7ed22952004-07-29 00:09:58 +00002901 UChar dis_buf[50];
sewardjc2ac51e2004-07-12 01:03:26 +00002902 IRType ty = Ity_I8;
sewardj7ed22952004-07-29 00:09:58 +00002903 IRTemp t1 = newTemp(ty);
2904 IRTemp t2 = newTemp(ty);
sewardjc2ac51e2004-07-12 01:03:26 +00002905
2906 modrm = getIByte(delta);
2907 if (epartIsReg(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002908 assign(t1, getIReg(1, eregOfRM(modrm)));
2909 switch (gregOfRM(modrm)) {
sewardj7ed22952004-07-29 00:09:58 +00002910 case 0: /* INC */
2911 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
2912 putIReg(1, eregOfRM(modrm), mkexpr(t2));
2913 setFlags_INC_DEC( True, t2, ty );
2914 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002915 case 1: /* DEC */
sewardjc2ac51e2004-07-12 01:03:26 +00002916 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
2917 putIReg(1, eregOfRM(modrm), mkexpr(t2));
2918 setFlags_INC_DEC( False, t2, ty );
2919 break;
2920 default:
2921 vex_printf(
2922 "unhandled Grp4(R) case %d\n", (UInt)gregOfRM(modrm));
sewardj7ed22952004-07-29 00:09:58 +00002923 vpanic("Grp4(x86,R)");
sewardjc2ac51e2004-07-12 01:03:26 +00002924 }
2925 delta++;
2926 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)),
2927 nameIReg(1, eregOfRM(modrm)));
2928 } else {
sewardj7ed22952004-07-29 00:09:58 +00002929 IRTemp addr = disAMode ( &alen, sorb, delta, dis_buf );
2930 assign( t1, loadLE(ty, mkexpr(addr)) );
2931 switch (gregOfRM(modrm)) {
sewardj588ea762004-09-10 18:56:32 +00002932 case 0: /* INC */
2933 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
2934 storeLE( mkexpr(addr), mkexpr(t2) );
2935 setFlags_INC_DEC( True, t2, ty );
2936 break;
sewardj7ed22952004-07-29 00:09:58 +00002937 case 1: /* DEC */
2938 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
2939 storeLE( mkexpr(addr), mkexpr(t2) );
2940 setFlags_INC_DEC( False, t2, ty );
2941 break;
2942 default:
2943 vex_printf(
2944 "unhandled Grp4(M) case %d\n", (UInt)gregOfRM(modrm));
2945 vpanic("Grp4(x86,M)");
2946 }
2947 delta += alen;
2948 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)), dis_buf);
sewardjc2ac51e2004-07-12 01:03:26 +00002949 }
2950 return delta;
2951}
sewardj0611d802004-07-11 02:37:54 +00002952
2953
2954/* Group 5 extended opcodes. */
2955static
sewardjce70a5c2004-10-18 14:09:54 +00002956UInt dis_Grp5 ( UChar sorb, Int sz, UInt delta, DisResult* whatNext )
sewardj0611d802004-07-11 02:37:54 +00002957{
2958 Int len;
2959 UChar modrm;
2960 UChar dis_buf[50];
sewardj92d168d2004-11-15 14:22:12 +00002961 IRTemp addr = IRTemp_INVALID;
sewardj0611d802004-07-11 02:37:54 +00002962 IRType ty = szToITy(sz);
2963 IRTemp t1 = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00002964 IRTemp t2 = IRTemp_INVALID;
sewardj0611d802004-07-11 02:37:54 +00002965
2966 modrm = getIByte(delta);
2967 if (epartIsReg(modrm)) {
sewardj940e8c92004-07-11 16:53:24 +00002968 assign(t1, getIReg(sz,eregOfRM(modrm)));
sewardj0611d802004-07-11 02:37:54 +00002969 switch (gregOfRM(modrm)) {
sewardjc9a65702004-07-07 16:32:57 +00002970//-- case 0: /* INC */
2971//-- uInstr1(cb, INC, sz, TempReg, t1);
2972//-- setFlagsFromUOpcode(cb, INC);
2973//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
2974//-- break;
2975//-- case 1: /* DEC */
2976//-- uInstr1(cb, DEC, sz, TempReg, t1);
2977//-- setFlagsFromUOpcode(cb, DEC);
2978//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
2979//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +00002980 case 2: /* call Ev */
2981 vassert(sz == 4);
2982 t2 = newTemp(Ity_I32);
2983 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
2984 putIReg(4, R_ESP, mkexpr(t2));
sewardj5bd4d162004-11-10 13:02:48 +00002985 storeLE( mkexpr(t2), mkU32(guest_eip_bbstart+delta+1));
2986 jmp_treg(Ijk_Call,t1);
sewardjce70a5c2004-10-18 14:09:54 +00002987 *whatNext = Dis_StopHere;
sewardjc2ac51e2004-07-12 01:03:26 +00002988 break;
sewardj0611d802004-07-11 02:37:54 +00002989 case 4: /* jmp Ev */
2990 vassert(sz == 4);
sewardj78c19df2004-07-12 22:49:27 +00002991 jmp_treg(Ijk_Boring,t1);
sewardjce70a5c2004-10-18 14:09:54 +00002992 *whatNext = Dis_StopHere;
sewardj0611d802004-07-11 02:37:54 +00002993 break;
2994 default:
2995 vex_printf(
2996 "unhandled Grp5(R) case %d\n", (UInt)gregOfRM(modrm));
2997 vpanic("Grp5(x86)");
2998 }
2999 delta++;
3000 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
3001 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
3002 } else {
3003 addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj940e8c92004-07-11 16:53:24 +00003004 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj0611d802004-07-11 02:37:54 +00003005 switch (gregOfRM(modrm)) {
3006 case 0: /* INC */
3007 t2 = newTemp(ty);
3008 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3009 mkexpr(t1), mkU(ty,1)));
3010 setFlags_INC_DEC( True, t2, ty );
sewardj940e8c92004-07-11 16:53:24 +00003011 storeLE(mkexpr(addr),mkexpr(t2));
sewardj0611d802004-07-11 02:37:54 +00003012 break;
sewardjc2ac51e2004-07-12 01:03:26 +00003013 case 1: /* DEC */
3014 t2 = newTemp(ty);
3015 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3016 mkexpr(t1), mkU(ty,1)));
3017 setFlags_INC_DEC( False, t2, ty );
3018 storeLE(mkexpr(addr),mkexpr(t2));
3019 break;
sewardj77b86be2004-07-11 13:28:24 +00003020 case 2: /* call Ev */
3021 vassert(sz == 4);
3022 t2 = newTemp(Ity_I32);
3023 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
3024 putIReg(4, R_ESP, mkexpr(t2));
sewardj5bd4d162004-11-10 13:02:48 +00003025 storeLE( mkexpr(t2), mkU32(guest_eip_bbstart+delta+len));
3026 jmp_treg(Ijk_Call,t1);
sewardjce70a5c2004-10-18 14:09:54 +00003027 *whatNext = Dis_StopHere;
sewardj77b86be2004-07-11 13:28:24 +00003028 break;
3029 case 4: /* JMP Ev */
3030 vassert(sz == 4);
sewardj78c19df2004-07-12 22:49:27 +00003031 jmp_treg(Ijk_Boring,t1);
sewardjce70a5c2004-10-18 14:09:54 +00003032 *whatNext = Dis_StopHere;
sewardj77b86be2004-07-11 13:28:24 +00003033 break;
sewardj0c12ea82004-07-12 08:18:16 +00003034 case 6: /* PUSH Ev */
3035 vassert(sz == 4 || sz == 2);
3036 t2 = newTemp(Ity_I32);
3037 assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
3038 putIReg(4, R_ESP, mkexpr(t2) );
sewardj5bd4d162004-11-10 13:02:48 +00003039 storeLE( mkexpr(t2), mkexpr(t1) );
sewardj0c12ea82004-07-12 08:18:16 +00003040 break;
sewardj0611d802004-07-11 02:37:54 +00003041 default:
3042 vex_printf(
3043 "unhandled Grp5(M) case %d\n", (UInt)gregOfRM(modrm));
3044 vpanic("Grp5(x86)");
3045 }
3046 delta += len;
3047 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
3048 nameISize(sz), dis_buf);
3049 }
3050 return delta;
3051}
3052
sewardj464efa42004-11-19 22:17:29 +00003053
sewardj64e1d652004-07-12 14:00:46 +00003054/*------------------------------------------------------------*/
3055/*--- Disassembling string ops (including REP prefixes) ---*/
3056/*------------------------------------------------------------*/
3057
3058/* Code shared by all the string ops */
3059static
3060void dis_string_op_increment(Int sz, Int t_inc)
3061{
3062 if (sz == 4 || sz == 2) {
3063 assign( t_inc,
3064 binop(Iop_Shl32, IRExpr_Get( OFFB_DFLAG, Ity_I32 ),
sewardj6d2638e2004-07-15 09:38:27 +00003065 mkU8(sz/2) ) );
sewardj64e1d652004-07-12 14:00:46 +00003066 } else {
3067 assign( t_inc,
3068 IRExpr_Get( OFFB_DFLAG, Ity_I32 ) );
3069 }
3070}
3071
sewardj64e1d652004-07-12 14:00:46 +00003072static
3073void dis_string_op( void (*dis_OP)( Int, IRTemp ),
3074 Int sz, Char* name, UChar sorb )
3075{
3076 IRTemp t_inc = newTemp(Ity_I32);
3077 vassert(sorb == 0);
3078 dis_string_op_increment(sz, t_inc);
3079 dis_OP( sz, t_inc );
3080 DIP("%s%c\n", name, nameISize(sz));
3081}
sewardj64e1d652004-07-12 14:00:46 +00003082
3083static
3084void dis_MOVS ( Int sz, IRTemp t_inc )
3085{
3086 IRType ty = szToITy(sz);
3087 //IRTemp tv = newTemp(ty); /* value being copied */
3088 IRTemp td = newTemp(Ity_I32); /* EDI */
3089 IRTemp ts = newTemp(Ity_I32); /* ESI */
3090
3091 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
3092 //uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
3093 assign( td, getIReg(4, R_EDI) );
3094 assign( ts, getIReg(4, R_ESI) );
3095
3096 //uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tv);
3097 //uInstr2(cb, STORE,sz, TempReg, tv, TempReg, td);
3098 storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
3099
3100 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
3101 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
3102
3103 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
3104 //uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
3105 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3106 putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3107}
3108
sewardjc9a65702004-07-07 16:32:57 +00003109//-- static
3110//-- void dis_LODS ( UCodeBlock* cb, Int sz, Int t_inc )
3111//-- {
3112//-- Int ta = newTemp(cb); /* EAX */
3113//-- Int ts = newTemp(cb); /* ESI */
3114//--
3115//-- uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
3116//-- uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, ta);
3117//-- uInstr2(cb, PUT, sz, TempReg, ta, ArchReg, R_EAX);
3118//--
3119//-- uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
3120//-- uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
3121//-- }
sewardj64e1d652004-07-12 14:00:46 +00003122
3123static
3124void dis_STOS ( Int sz, IRTemp t_inc )
3125{
3126 IRType ty = szToITy(sz);
3127 IRTemp ta = newTemp(ty); /* EAX */
3128 IRTemp td = newTemp(Ity_I32); /* EDI */
3129
3130 //uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
3131 assign( ta, getIReg(sz, R_EAX) );
3132
3133 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
3134 assign( td, getIReg(4, R_EDI) );
3135
3136 //uInstr2(cb, STORE, sz, TempReg, ta, TempReg, td);
sewardj6d2638e2004-07-15 09:38:27 +00003137 storeLE( mkexpr(td), mkexpr(ta) );
sewardj64e1d652004-07-12 14:00:46 +00003138
3139 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
3140 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
3141 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3142}
3143
3144static
3145void dis_CMPS ( Int sz, IRTemp t_inc )
3146{
3147 IRType ty = szToITy(sz);
sewardj6d2638e2004-07-15 09:38:27 +00003148 IRTemp tdv = newTemp(ty); /* (EDI) */
3149 IRTemp tsv = newTemp(ty); /* (ESI) */
sewardj2a2ba8b2004-11-08 13:14:06 +00003150 //IRTemp res = newTemp(ty);
sewardj64e1d652004-07-12 14:00:46 +00003151 IRTemp td = newTemp(Ity_I32); /* EDI */
3152 IRTemp ts = newTemp(Ity_I32); /* ESI */
3153
3154 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
3155 assign( td, getIReg(4, R_EDI) );
3156
3157 //uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
3158 assign( ts, getIReg(4, R_ESI) );
3159
3160 //uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tdv);
3161 assign( tdv, loadLE(ty,mkexpr(td)) );
3162
3163 //uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tsv);
sewardjb9c5cf62004-08-24 15:10:38 +00003164 assign( tsv, loadLE(ty,mkexpr(ts)) );
sewardj64e1d652004-07-12 14:00:46 +00003165
3166 //uInstr2(cb, SUB, sz, TempReg, tdv, TempReg, tsv);
3167 //setFlagsFromUOpcode(cb, SUB);
sewardj2a2ba8b2004-11-08 13:14:06 +00003168 //assign( res, binop(mkSizedOp(ty, Iop_Sub8), mkexpr(tsv), mkexpr(tdv)) );
3169 setFlags_DEP1_DEP2 ( Iop_Sub8, tsv, tdv, ty );
sewardj64e1d652004-07-12 14:00:46 +00003170
3171 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
3172 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
3173
3174 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
3175 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3176
3177 //uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
3178 putIReg(4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
3179}
3180
sewardj64e1d652004-07-12 14:00:46 +00003181static
3182void dis_SCAS ( Int sz, IRTemp t_inc )
3183{
3184 IRType ty = szToITy(sz);
sewardj82292882004-07-27 00:15:59 +00003185 IRTemp ta = newTemp(ty); /* EAX */
sewardj64e1d652004-07-12 14:00:46 +00003186 IRTemp td = newTemp(Ity_I32); /* EDI */
3187 IRTemp tdv = newTemp(ty); /* (EDI) */
sewardj2a2ba8b2004-11-08 13:14:06 +00003188 //IRTemp res = newTemp(ty);
sewardj64e1d652004-07-12 14:00:46 +00003189
3190 //uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
sewardjb9c5cf62004-08-24 15:10:38 +00003191 assign( ta, getIReg(sz, R_EAX) );
sewardj64e1d652004-07-12 14:00:46 +00003192
3193 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
3194 assign( td, getIReg(4, R_EDI) );
3195
3196 //uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tdv);
3197 assign( tdv, loadLE(ty,mkexpr(td)) );
3198
sewardj64e1d652004-07-12 14:00:46 +00003199 //uInstr2(cb, SUB, sz, TempReg, tdv, TempReg, ta);
3200 //setFlagsFromUOpcode(cb, SUB);
sewardj2a2ba8b2004-11-08 13:14:06 +00003201 //assign( res, binop(mkSizedOp(ty, Iop_Sub8), mkexpr(ta), mkexpr(tdv)) );
3202 setFlags_DEP1_DEP2 ( Iop_Sub8, ta, tdv, ty );
sewardj64e1d652004-07-12 14:00:46 +00003203
3204 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
3205 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
3206 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
3207}
sewardj82292882004-07-27 00:15:59 +00003208
sewardj64e1d652004-07-12 14:00:46 +00003209
3210/* Wrap the appropriate string op inside a REP/REPE/REPNE.
3211 We assume the insn is the last one in the basic block, and so emit a jump
3212 to the next insn, rather than just falling through. */
3213static
3214void dis_REP_op ( Condcode cond,
3215 void (*dis_OP)(Int, IRTemp),
3216 Int sz, Addr32 eip, Addr32 eip_next, Char* name )
3217{
3218 IRTemp t_inc = newTemp(Ity_I32);
3219 IRTemp tc = newTemp(Ity_I32); /* ECX */
3220
3221 //uInstr2 (cb, GET, 4, ArchReg, R_ECX, TempReg, tc);
3222 assign( tc, getIReg(4,R_ECX) );
3223
3224 //uInstr2 (cb, JIFZ, 4, TempReg, tc, Literal, 0);
3225 //uLiteral(cb, eip_next);
3226 stmt( IRStmt_Exit( binop(Iop_CmpEQ32,mkexpr(tc),mkU32(0)),
3227 IRConst_U32(eip_next) ) );
3228
3229 //uInstr1 (cb, DEC, 4, TempReg, tc);
3230 //uInstr2 (cb, PUT, 4, TempReg, tc, ArchReg, R_ECX);
3231 putIReg(4, R_ECX, binop(Iop_Sub32, mkexpr(tc), mkU32(1)) );
3232
3233 dis_string_op_increment(sz, t_inc);
3234 dis_OP (sz, t_inc);
3235
3236 if (cond == CondAlways) {
sewardj78c19df2004-07-12 22:49:27 +00003237 jmp_lit(Ijk_Boring,eip);
sewardj64e1d652004-07-12 14:00:46 +00003238 } else {
sewardj8ea867b2004-10-30 19:03:02 +00003239 stmt( IRStmt_Exit( mk_calculate_condition(cond),
sewardj5bd4d162004-11-10 13:02:48 +00003240 IRConst_U32(eip) ) );
sewardj78c19df2004-07-12 22:49:27 +00003241 jmp_lit(Ijk_Boring,eip_next);
sewardj64e1d652004-07-12 14:00:46 +00003242 }
3243 DIP("%s%c\n", name, nameISize(sz));
3244}
3245
sewardj464efa42004-11-19 22:17:29 +00003246
sewardj64e1d652004-07-12 14:00:46 +00003247/*------------------------------------------------------------*/
3248/*--- Arithmetic, etc. ---*/
3249/*------------------------------------------------------------*/
3250
sewardj2a2ba8b2004-11-08 13:14:06 +00003251/* IMUL E, G. Supplied eip points to the modR/M byte. */
sewardjcf780b42004-07-13 18:42:17 +00003252static
3253UInt dis_mul_E_G ( UChar sorb,
3254 Int size,
sewardj2a2ba8b2004-11-08 13:14:06 +00003255 UInt delta0 )
sewardjcf780b42004-07-13 18:42:17 +00003256{
sewardj71a65362004-07-28 01:48:34 +00003257 Int alen;
3258 UChar dis_buf[50];
sewardjcf780b42004-07-13 18:42:17 +00003259 UChar rm = getIByte(delta0);
3260 IRType ty = szToITy(size);
sewardj6d2638e2004-07-15 09:38:27 +00003261 IRTemp te = newTemp(ty);
3262 IRTemp tg = newTemp(ty);
sewardj948d48b2004-11-05 19:49:09 +00003263 IRTemp resLo = newTemp(ty);
sewardj71a65362004-07-28 01:48:34 +00003264
sewardj948d48b2004-11-05 19:49:09 +00003265 assign( tg, getIReg(size, gregOfRM(rm)) );
sewardjcf780b42004-07-13 18:42:17 +00003266 if (epartIsReg(rm)) {
sewardjcf780b42004-07-13 18:42:17 +00003267 assign( te, getIReg(size, eregOfRM(rm)) );
sewardj948d48b2004-11-05 19:49:09 +00003268 } else {
3269 IRTemp addr = disAMode( &alen, sorb, delta0, dis_buf );
3270 assign( te, loadLE(ty,mkexpr(addr)) );
3271 }
sewardjcf780b42004-07-13 18:42:17 +00003272
sewardj2a2ba8b2004-11-08 13:14:06 +00003273 setFlags_MUL ( ty, te, tg, CC_OP_SMULB );
sewardj948d48b2004-11-05 19:49:09 +00003274
sewardj2a2ba8b2004-11-08 13:14:06 +00003275 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tg) ) );
sewardj948d48b2004-11-05 19:49:09 +00003276
3277 putIReg(size, gregOfRM(rm), mkexpr(resLo) );
3278
3279 if (epartIsReg(rm)) {
sewardj2a2ba8b2004-11-08 13:14:06 +00003280 DIP("imul%c %s, %s\n", nameISize(size),
3281 nameIReg(size,eregOfRM(rm)),
3282 nameIReg(size,gregOfRM(rm)));
sewardjcf780b42004-07-13 18:42:17 +00003283 return 1+delta0;
3284 } else {
sewardj2a2ba8b2004-11-08 13:14:06 +00003285 DIP("imul%c %s, %s\n", nameISize(size),
3286 dis_buf, nameIReg(size,gregOfRM(rm)));
sewardj71a65362004-07-28 01:48:34 +00003287 return alen+delta0;
sewardjcf780b42004-07-13 18:42:17 +00003288 }
3289}
3290
3291
sewardj1813dbe2004-07-28 17:09:04 +00003292/* IMUL I * E -> G. Supplied eip points to the modR/M byte. */
3293static
3294UInt dis_imul_I_E_G ( UChar sorb,
3295 Int size,
3296 UInt delta,
3297 Int litsize )
3298{
sewardj883b00b2004-09-11 09:30:24 +00003299 Int d32, alen;
sewardjb81f8b32004-07-30 10:17:50 +00003300 Char dis_buf[50];
3301 UChar rm = getIByte(delta);
sewardj1813dbe2004-07-28 17:09:04 +00003302 IRType ty = szToITy(size);
3303 IRTemp te = newTemp(ty);
3304 IRTemp tl = newTemp(ty);
sewardj948d48b2004-11-05 19:49:09 +00003305 IRTemp resLo = newTemp(ty);
sewardj1813dbe2004-07-28 17:09:04 +00003306
sewardjb81f8b32004-07-30 10:17:50 +00003307 vassert(size == 1 || size == 2 || size == 4);
3308
sewardj1813dbe2004-07-28 17:09:04 +00003309 if (epartIsReg(rm)) {
3310 assign(te, getIReg(size, eregOfRM(rm)));
3311 delta++;
3312 } else {
sewardj883b00b2004-09-11 09:30:24 +00003313 IRTemp addr = disAMode( &alen, sorb, delta, dis_buf );
3314 assign(te, loadLE(ty, mkexpr(addr)));
3315 delta += alen;
sewardj1813dbe2004-07-28 17:09:04 +00003316 }
3317 d32 = getSDisp(litsize,delta);
3318 delta += litsize;
3319
sewardjb81f8b32004-07-30 10:17:50 +00003320 if (size == 1) d32 &= 0xFF;
3321 if (size == 2) d32 &= 0xFFFF;
3322
sewardj1813dbe2004-07-28 17:09:04 +00003323 assign(tl, mkU(ty,d32));
sewardj948d48b2004-11-05 19:49:09 +00003324
sewardj2a2ba8b2004-11-08 13:14:06 +00003325 assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tl) ));
sewardj948d48b2004-11-05 19:49:09 +00003326
sewardj2a2ba8b2004-11-08 13:14:06 +00003327 setFlags_MUL ( ty, te, tl, CC_OP_SMULB );
sewardj948d48b2004-11-05 19:49:09 +00003328
3329 putIReg(size, gregOfRM(rm), mkexpr(resLo));
sewardj1813dbe2004-07-28 17:09:04 +00003330
3331 DIP("imul %d, %s, %s\n", d32,
3332 ( epartIsReg(rm) ? nameIReg(size,eregOfRM(rm)) : dis_buf ),
3333 nameIReg(size,gregOfRM(rm)) );
3334 return delta;
sewardj948d48b2004-11-05 19:49:09 +00003335}
sewardj1813dbe2004-07-28 17:09:04 +00003336
3337
sewardjd1725d12004-08-12 20:46:53 +00003338/*------------------------------------------------------------*/
sewardj464efa42004-11-19 22:17:29 +00003339/*--- ---*/
3340/*--- x87 FLOATING POINT INSTRUCTIONS ---*/
3341/*--- ---*/
sewardjd1725d12004-08-12 20:46:53 +00003342/*------------------------------------------------------------*/
3343
sewardj207557a2004-08-27 12:00:18 +00003344/* --- Helper functions for dealing with the register stack. --- */
3345
sewardj17442fe2004-09-20 14:54:28 +00003346/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */
sewardj207557a2004-08-27 12:00:18 +00003347
sewardj17442fe2004-09-20 14:54:28 +00003348static IRExpr* mkQNaN64 ( void )
sewardj207557a2004-08-27 12:00:18 +00003349{
sewardj17442fe2004-09-20 14:54:28 +00003350 /* QNaN is 0 2047 1 0(51times)
3351 == 0b 11111111111b 1 0(51times)
3352 == 0x7FF8 0000 0000 0000
3353 */
3354 return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL));
sewardj207557a2004-08-27 12:00:18 +00003355}
3356
3357/* --------- Get/set the top-of-stack pointer. --------- */
sewardjd1725d12004-08-12 20:46:53 +00003358
3359static IRExpr* get_ftop ( void )
3360{
3361 return IRExpr_Get( OFFB_FTOP, Ity_I32 );
3362}
3363
sewardj207557a2004-08-27 12:00:18 +00003364static void put_ftop ( IRExpr* e )
sewardjd1725d12004-08-12 20:46:53 +00003365{
sewardj207557a2004-08-27 12:00:18 +00003366 stmt( IRStmt_Put( OFFB_FTOP, e ) );
sewardjd1725d12004-08-12 20:46:53 +00003367}
3368
sewardjc4be80c2004-09-10 16:17:45 +00003369/* --------- Get/set the C3210 bits of the control word. --------- */
sewardjbdc7d212004-09-09 02:46:40 +00003370
sewardjc4be80c2004-09-10 16:17:45 +00003371static IRExpr* get_C3210 ( void )
sewardjbdc7d212004-09-09 02:46:40 +00003372{
sewardjc4be80c2004-09-10 16:17:45 +00003373 return IRExpr_Get( OFFB_FC3210, Ity_I32 );
sewardjbdc7d212004-09-09 02:46:40 +00003374}
3375
sewardjc4be80c2004-09-10 16:17:45 +00003376static void put_C3210 ( IRExpr* e )
sewardjbdc7d212004-09-09 02:46:40 +00003377{
sewardjc4be80c2004-09-10 16:17:45 +00003378 stmt( IRStmt_Put( OFFB_FC3210, e ) );
sewardjbdc7d212004-09-09 02:46:40 +00003379}
sewardjd1725d12004-08-12 20:46:53 +00003380
sewardj8f3debf2004-09-08 23:42:23 +00003381/* --------- Get/set the FPU control word. --------- */
3382/* Note, IA32 has this as a 16-bit value, so fstcw/fldcw need to cast
3383 to/from 16 bits. Here we represent it in 32 bits. */
3384static IRExpr* /* :: Ity_I32 */ get_fpucw ( void )
3385{
3386 return IRExpr_Get( OFFB_FPUCW, Ity_I32 );
3387}
3388
3389static void put_fpucw ( IRExpr* /* :: Ity_I32 */ e )
3390{
3391 stmt( IRStmt_Put( OFFB_FPUCW, e ) );
3392}
3393
3394
3395/* --------- Get the FPU rounding mode from the CW. --------- */
3396/* Produces a value in 0 .. 3, which is encoded as per the type
3397 IRRoundingMode. On IA32 the relevant value is precisely bits 11
3398 and 10 of the control word.
3399*/
3400static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
3401{
3402 return binop( Iop_And32,
3403 binop(Iop_Shr32, get_fpucw(), mkU8(10)),
3404 mkU32(3) );
3405}
3406
3407
sewardj207557a2004-08-27 12:00:18 +00003408/* --------- Get/set FP register tag bytes. --------- */
3409
sewardj207557a2004-08-27 12:00:18 +00003410/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */
3411
3412static void put_ST_TAG ( Int i, IRExpr* value )
3413{
sewardj2d3f77c2004-09-22 23:49:09 +00003414 IRArray* descr;
sewardj207557a2004-08-27 12:00:18 +00003415 vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_I8);
sewardjf6dc3ce2004-10-19 01:03:46 +00003416 descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003417 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
sewardj207557a2004-08-27 12:00:18 +00003418}
3419
3420/* Given i, generate an expression yielding 'ST_TAG(i)'. This will be
sewardjdb199622004-09-06 23:19:03 +00003421 zero to indicate "Empty" and nonzero to indicate "NonEmpty". */
sewardj207557a2004-08-27 12:00:18 +00003422
3423static IRExpr* get_ST_TAG ( Int i )
3424{
sewardjf6dc3ce2004-10-19 01:03:46 +00003425 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003426 return IRExpr_GetI( descr, get_ftop(), i );
sewardj207557a2004-08-27 12:00:18 +00003427}
3428
3429
3430/* --------- Get/set FP registers. --------- */
3431
sewardj2d3f77c2004-09-22 23:49:09 +00003432/* Given i, and some expression e, emit 'ST(i) = e' and set the
3433 register's tag to indicate the register is full. The previous
3434 state of the register is not checked. */
sewardj207557a2004-08-27 12:00:18 +00003435
3436static void put_ST_UNCHECKED ( Int i, IRExpr* value )
sewardjd1725d12004-08-12 20:46:53 +00003437{
sewardj2d3f77c2004-09-22 23:49:09 +00003438 IRArray* descr;
sewardjdb199622004-09-06 23:19:03 +00003439 vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_F64);
sewardjf6dc3ce2004-10-19 01:03:46 +00003440 descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003441 stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
sewardj207557a2004-08-27 12:00:18 +00003442 /* Mark the register as in-use. */
3443 put_ST_TAG(i, mkU8(1));
sewardjd1725d12004-08-12 20:46:53 +00003444}
3445
sewardj207557a2004-08-27 12:00:18 +00003446/* Given i, and some expression e, emit
3447 ST(i) = is_full(i) ? NaN : e
3448 and set the tag accordingly.
3449*/
3450
3451static void put_ST ( Int i, IRExpr* value )
3452{
3453 put_ST_UNCHECKED( i,
sewardjdb199622004-09-06 23:19:03 +00003454 IRExpr_Mux0X( get_ST_TAG(i),
3455 /* 0 means empty */
3456 value,
3457 /* non-0 means full */
sewardj17442fe2004-09-20 14:54:28 +00003458 mkQNaN64()
sewardj207557a2004-08-27 12:00:18 +00003459 )
3460 );
3461}
3462
3463
sewardjd1725d12004-08-12 20:46:53 +00003464/* Given i, generate an expression yielding 'ST(i)'. */
3465
sewardj207557a2004-08-27 12:00:18 +00003466static IRExpr* get_ST_UNCHECKED ( Int i )
sewardjd1725d12004-08-12 20:46:53 +00003467{
sewardjf6dc3ce2004-10-19 01:03:46 +00003468 IRArray* descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
sewardj2d3f77c2004-09-22 23:49:09 +00003469 return IRExpr_GetI( descr, get_ftop(), i );
sewardjd1725d12004-08-12 20:46:53 +00003470}
3471
sewardjc4be80c2004-09-10 16:17:45 +00003472
sewardj207557a2004-08-27 12:00:18 +00003473/* Given i, generate an expression yielding
3474 is_full(i) ? ST(i) : NaN
3475*/
3476
3477static IRExpr* get_ST ( Int i )
3478{
3479 return
3480 IRExpr_Mux0X( get_ST_TAG(i),
3481 /* 0 means empty */
sewardj17442fe2004-09-20 14:54:28 +00003482 mkQNaN64(),
sewardj207557a2004-08-27 12:00:18 +00003483 /* non-0 means full */
3484 get_ST_UNCHECKED(i));
3485}
3486
3487
sewardjd1725d12004-08-12 20:46:53 +00003488/* Adjust FTOP downwards by one register. */
3489
sewardj207557a2004-08-27 12:00:18 +00003490static void fp_push ( void )
sewardjd1725d12004-08-12 20:46:53 +00003491{
sewardj2d3f77c2004-09-22 23:49:09 +00003492 put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) );
sewardjd1725d12004-08-12 20:46:53 +00003493}
3494
sewardj207557a2004-08-27 12:00:18 +00003495/* Adjust FTOP upwards by one register, and mark the vacated register
3496 as empty. */
sewardja58ea662004-08-15 03:12:41 +00003497
sewardj207557a2004-08-27 12:00:18 +00003498static void fp_pop ( void )
sewardja58ea662004-08-15 03:12:41 +00003499{
sewardjdb199622004-09-06 23:19:03 +00003500 put_ST_TAG(0, mkU8(0));
sewardj2d3f77c2004-09-22 23:49:09 +00003501 put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
sewardja58ea662004-08-15 03:12:41 +00003502}
3503
sewardj3f61ddb2004-10-16 20:51:05 +00003504/* Clear the C2 bit of the FPU status register, for
3505 sin/cos/tan/sincos. */
3506
3507static void clear_C2 ( void )
3508{
3509 put_C3210( binop(Iop_And32, get_C3210(), mkU32(~FC_MASK_C2)) );
3510}
3511
3512
sewardj207557a2004-08-27 12:00:18 +00003513/* ------------------------------------------------------- */
3514/* Given all that stack-mangling junk, we can now go ahead
3515 and describe FP instructions.
3516*/
3517
sewardj3fd5e572004-09-09 22:43:51 +00003518/* ST(0) = ST(0) `op` mem64/32(addr)
sewardj207557a2004-08-27 12:00:18 +00003519 Need to check ST(0)'s tag on read, but not on write.
3520*/
sewardja58ea662004-08-15 03:12:41 +00003521static
3522void fp_do_op_mem_ST_0 ( IRTemp addr, UChar* op_txt, UChar* dis_buf,
3523 IROp op, Bool dbl )
3524{
3525 DIP("f%s%c %s", op_txt, dbl?'l':'s', dis_buf);
3526 if (dbl) {
sewardj3fd5e572004-09-09 22:43:51 +00003527 put_ST_UNCHECKED(0,
3528 binop( op,
3529 get_ST(0),
3530 loadLE(Ity_F64,mkexpr(addr))
3531 ));
sewardja58ea662004-08-15 03:12:41 +00003532 } else {
sewardj3fd5e572004-09-09 22:43:51 +00003533 put_ST_UNCHECKED(0,
3534 binop( op,
3535 get_ST(0),
3536 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr)))
3537 ));
3538 }
3539}
3540
3541
3542/* ST(0) = mem64/32(addr) `op` ST(0)
3543 Need to check ST(0)'s tag on read, but not on write.
3544*/
3545static
3546void fp_do_oprev_mem_ST_0 ( IRTemp addr, UChar* op_txt, UChar* dis_buf,
sewardj883b00b2004-09-11 09:30:24 +00003547 IROp op, Bool dbl )
sewardj3fd5e572004-09-09 22:43:51 +00003548{
3549 DIP("f%s%c %s", op_txt, dbl?'l':'s', dis_buf);
3550 if (dbl) {
3551 put_ST_UNCHECKED(0,
3552 binop( op,
3553 loadLE(Ity_F64,mkexpr(addr)),
3554 get_ST(0)
3555 ));
3556 } else {
3557 put_ST_UNCHECKED(0,
3558 binop( op,
3559 unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))),
3560 get_ST(0)
3561 ));
sewardja58ea662004-08-15 03:12:41 +00003562 }
3563}
3564
sewardjd1725d12004-08-12 20:46:53 +00003565
sewardjdb199622004-09-06 23:19:03 +00003566/* ST(dst) = ST(dst) `op` ST(src).
3567 Check dst and src tags when reading but not on write.
3568*/
3569static
sewardjbdc7d212004-09-09 02:46:40 +00003570void fp_do_op_ST_ST ( UChar* op_txt, IROp op, UInt st_src, UInt st_dst,
3571 Bool pop_after )
sewardjdb199622004-09-06 23:19:03 +00003572{
sewardjbdc7d212004-09-09 02:46:40 +00003573 DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"", st_src, st_dst );
sewardjdb199622004-09-06 23:19:03 +00003574 put_ST_UNCHECKED(
3575 st_dst,
3576 binop(op, get_ST(st_dst), get_ST(st_src) )
3577 );
sewardjbdc7d212004-09-09 02:46:40 +00003578 if (pop_after)
3579 fp_pop();
3580}
3581
3582/* ST(dst) = ST(src) `op` ST(dst).
3583 Check dst and src tags when reading but not on write.
3584*/
3585static
3586void fp_do_oprev_ST_ST ( UChar* op_txt, IROp op, UInt st_src, UInt st_dst,
sewardj883b00b2004-09-11 09:30:24 +00003587 Bool pop_after )
sewardjbdc7d212004-09-09 02:46:40 +00003588{
3589 DIP("f%s%s st(%d), st(%d)\n", op_txt, pop_after?"p":"", st_src, st_dst );
3590 put_ST_UNCHECKED(
3591 st_dst,
3592 binop(op, get_ST(st_src), get_ST(st_dst) )
3593 );
3594 if (pop_after)
3595 fp_pop();
sewardjdb199622004-09-06 23:19:03 +00003596}
3597
sewardj8308aad2004-09-12 11:09:54 +00003598/* %eflags(Z,P,C) = UCOMI( st(0), st(i) ) */
3599static void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
3600{
3601 DIP("fucomi%s %%st(0),%%st(%d)\n", pop_after ? "p" : "", i);
3602 /* This is a bit of a hack (and isn't really right). It sets
3603 Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
3604 documentation implies A and S are unchanged.
3605 */
sewardj2a2ba8b2004-11-08 13:14:06 +00003606 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
3607 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
3608 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj8308aad2004-09-12 11:09:54 +00003609 binop( Iop_And32,
3610 binop(Iop_CmpF64, get_ST(0), get_ST(i)),
3611 mkU32(0x45)
3612 )));
3613 if (pop_after)
3614 fp_pop();
3615}
3616
sewardjdb199622004-09-06 23:19:03 +00003617
sewardjd1725d12004-08-12 20:46:53 +00003618static
3619UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta )
3620{
sewardja58ea662004-08-15 03:12:41 +00003621 Int len;
3622 UInt r_src, r_dst;
sewardj464efa42004-11-19 22:17:29 +00003623 UChar dis_buf[50];
sewardj89cd0932004-09-08 18:23:25 +00003624 IRTemp t1, t2;
sewardjd1725d12004-08-12 20:46:53 +00003625
3626 /* On entry, delta points at the second byte of the insn (the modrm
3627 byte).*/
3628 UChar first_opcode = getIByte(delta-1);
3629 UChar modrm = getIByte(delta+0);
3630
3631 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
3632
3633 if (first_opcode == 0xD8) {
sewardjdb199622004-09-06 23:19:03 +00003634 if (modrm < 0xC0) {
sewardj89cd0932004-09-08 18:23:25 +00003635
3636 /* bits 5,4,3 are an opcode extension, and the modRM also
3637 specifies an address. */
3638 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3639 delta += len;
3640
3641 switch (gregOfRM(modrm)) {
3642
sewardj3fd5e572004-09-09 22:43:51 +00003643 case 0: /* FADD single-real */
3644 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, False );
3645 break;
3646
sewardj89cd0932004-09-08 18:23:25 +00003647 case 1: /* FMUL single-real */
3648 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, False );
3649 break;
3650
sewardj7ca37d92004-10-25 02:58:30 +00003651 case 2: /* FCOM single-real */
3652 DIP("fcoms %s\n", dis_buf);
3653 /* This forces C1 to zero, which isn't right. */
3654 put_C3210(
3655 binop( Iop_And32,
3656 binop(Iop_Shl32,
3657 binop(Iop_CmpF64,
3658 get_ST(0),
3659 unop(Iop_F32toF64,
3660 loadLE(Ity_F32,mkexpr(addr)))),
3661 mkU8(8)),
3662 mkU32(0x4500)
3663 ));
3664 break;
3665
3666 case 3: /* FCOMP single-real */
sewardje166ed02004-10-25 02:27:01 +00003667 DIP("fcomps %s\n", dis_buf);
3668 /* This forces C1 to zero, which isn't right. */
3669 put_C3210(
3670 binop( Iop_And32,
3671 binop(Iop_Shl32,
3672 binop(Iop_CmpF64,
3673 get_ST(0),
3674 unop(Iop_F32toF64,
3675 loadLE(Ity_F32,mkexpr(addr)))),
3676 mkU8(8)),
3677 mkU32(0x4500)
3678 ));
3679 fp_pop();
3680 break;
3681
sewardj588ea762004-09-10 18:56:32 +00003682 case 4: /* FSUB single-real */
3683 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, False );
3684 break;
3685
3686 case 5: /* FSUBR single-real */
3687 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, False );
3688 break;
3689
sewardjbdc7d212004-09-09 02:46:40 +00003690 case 6: /* FDIV single-real */
3691 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, False );
3692 break;
3693
sewardj8308aad2004-09-12 11:09:54 +00003694 case 7: /* FDIVR single-real */
3695 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, False );
3696 break;
3697
sewardj89cd0932004-09-08 18:23:25 +00003698 default:
3699 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3700 vex_printf("first_opcode == 0xD8\n");
3701 goto decode_fail;
3702 }
sewardjdb199622004-09-06 23:19:03 +00003703 } else {
3704 delta++;
3705 switch (modrm) {
sewardj89cd0932004-09-08 18:23:25 +00003706
sewardjdb199622004-09-06 23:19:03 +00003707 case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
sewardjbdc7d212004-09-09 02:46:40 +00003708 fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
sewardjdb199622004-09-06 23:19:03 +00003709 break;
sewardj89cd0932004-09-08 18:23:25 +00003710
sewardj3fd5e572004-09-09 22:43:51 +00003711 case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
3712 fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
3713 break;
3714
sewardje166ed02004-10-25 02:27:01 +00003715#if 1
3716 /* Dunno if this is right */
3717 case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
3718 r_dst = (UInt)modrm - 0xD0;
3719 DIP("fcom %%st(0),%%st(%d)\n", r_dst);
3720 /* This forces C1 to zero, which isn't right. */
3721 put_C3210(
3722 binop( Iop_And32,
3723 binop(Iop_Shl32,
3724 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3725 mkU8(8)),
3726 mkU32(0x4500)
3727 ));
3728 break;
3729#endif
3730#if 1
sewardj98169c52004-10-24 13:11:39 +00003731 /* Dunno if this is right */
3732 case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
3733 r_dst = (UInt)modrm - 0xD8;
3734 DIP("fcomp %%st(0),%%st(%d)\n", r_dst);
3735 /* This forces C1 to zero, which isn't right. */
3736 put_C3210(
3737 binop( Iop_And32,
3738 binop(Iop_Shl32,
3739 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
3740 mkU8(8)),
3741 mkU32(0x4500)
3742 ));
3743 fp_pop();
3744 break;
3745#endif
sewardj89cd0932004-09-08 18:23:25 +00003746 case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
sewardjbdc7d212004-09-09 02:46:40 +00003747 fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
sewardj89cd0932004-09-08 18:23:25 +00003748 break;
3749
sewardj8308aad2004-09-12 11:09:54 +00003750 case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
3751 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
3752 break;
3753
sewardj3fd5e572004-09-09 22:43:51 +00003754 case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
3755 fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
3756 break;
3757
3758 case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
3759 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
3760 break;
3761
sewardjdb199622004-09-06 23:19:03 +00003762 default:
3763 goto decode_fail;
3764 }
3765 }
sewardjd1725d12004-08-12 20:46:53 +00003766 }
3767
3768 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
3769 else
3770 if (first_opcode == 0xD9) {
sewardjbb53f8c2004-08-14 11:50:01 +00003771 if (modrm < 0xC0) {
sewardj89cd0932004-09-08 18:23:25 +00003772
3773 /* bits 5,4,3 are an opcode extension, and the modRM also
3774 specifies an address. */
3775 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3776 delta += len;
3777
3778 switch (gregOfRM(modrm)) {
3779
3780 case 0: /* FLD single-real */
3781 DIP("fldF %s\n", dis_buf);
3782 fp_push();
3783 put_ST(0, unop(Iop_F32toF64,
sewardj8f3debf2004-09-08 23:42:23 +00003784 loadLE(Ity_F32, mkexpr(addr))));
sewardj89cd0932004-09-08 18:23:25 +00003785 break;
3786
sewardj588ea762004-09-10 18:56:32 +00003787 case 2: /* FST single-real */
3788 DIP("fstS %s", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00003789 storeLE(mkexpr(addr), unop(Iop_F64toF32, get_ST(0)));
sewardj588ea762004-09-10 18:56:32 +00003790 break;
3791
sewardj89cd0932004-09-08 18:23:25 +00003792 case 3: /* FSTP single-real */
3793 DIP("fstpS %s", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00003794 storeLE(mkexpr(addr), unop(Iop_F64toF32, get_ST(0)));
3795 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00003796 break;
3797
sewardj588ea762004-09-10 18:56:32 +00003798 case 5: /* FLDCW */
sewardj8f3debf2004-09-08 23:42:23 +00003799 DIP("fldcw %s", dis_buf);
3800 put_fpucw( unop(Iop_16Uto32, loadLE(Ity_I16, mkexpr(addr))) );
sewardj89cd0932004-09-08 18:23:25 +00003801 break;
3802
sewardj588ea762004-09-10 18:56:32 +00003803 case 7: /* FNSTCW */
3804 DIP("fnstcw %s", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00003805 storeLE(mkexpr(addr), unop(Iop_32to16, get_fpucw()));
sewardj89cd0932004-09-08 18:23:25 +00003806 break;
3807
3808 default:
3809 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3810 vex_printf("first_opcode == 0xD9\n");
3811 goto decode_fail;
3812 }
3813
sewardjbb53f8c2004-08-14 11:50:01 +00003814 } else {
3815 delta++;
3816 switch (modrm) {
sewardj89cd0932004-09-08 18:23:25 +00003817
sewardjbb53f8c2004-08-14 11:50:01 +00003818 case 0xC0 ... 0xC7: /* FLD %st(?) */
sewardja58ea662004-08-15 03:12:41 +00003819 r_src = (UInt)modrm - 0xC0;
3820 DIP("fld %%st(%d)\n", r_src);
sewardj5bd4d162004-11-10 13:02:48 +00003821 t1 = newTemp(Ity_F64);
3822 assign(t1, get_ST(r_src));
3823 fp_push();
3824 put_ST(0, mkexpr(t1));
sewardjbb53f8c2004-08-14 11:50:01 +00003825 break;
3826
sewardj89cd0932004-09-08 18:23:25 +00003827 case 0xC8 ... 0xCF: /* FXCH %st(?) */
3828 r_src = (UInt)modrm - 0xC8;
3829 DIP("fxch %%st(%d)\n", r_src);
3830 t1 = newTemp(Ity_F64);
3831 t2 = newTemp(Ity_F64);
3832 assign(t1, get_ST(0));
3833 assign(t2, get_ST(r_src));
3834 put_ST_UNCHECKED(0, mkexpr(t2));
3835 put_ST_UNCHECKED(r_src, mkexpr(t1));
3836 break;
3837
sewardjcfded9a2004-09-09 11:44:16 +00003838 case 0xE0: /* FCHS */
3839 DIP("fchs\n");
3840 put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
3841 break;
3842
sewardj883b00b2004-09-11 09:30:24 +00003843 case 0xE1: /* FABS */
3844 DIP("fabs\n");
3845 put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
3846 break;
sewardjc4be80c2004-09-10 16:17:45 +00003847
sewardj883b00b2004-09-11 09:30:24 +00003848 case 0xE5: { /* FXAM */
3849 /* This is an interesting one. It examines %st(0),
3850 regardless of whether the tag says it's empty or not.
3851 Here, just pass both the tag (in our format) and the
3852 value (as a double, actually a ULong) to a helper
3853 function. */
sewardjf9655262004-10-31 20:02:16 +00003854 IRExpr** args
3855 = mkIRExprVec_2( unop(Iop_8Uto32, get_ST_TAG(0)),
3856 unop(Iop_ReinterpF64asI64,
3857 get_ST_UNCHECKED(0)) );
3858 put_C3210(mkIRExprCCall(
sewardj8ea867b2004-10-30 19:03:02 +00003859 Ity_I32,
sewardjf9655262004-10-31 20:02:16 +00003860 0/*regparm*/,
3861 "calculate_FXAM", &calculate_FXAM,
sewardj8ea867b2004-10-30 19:03:02 +00003862 args
3863 ));
sewardjf9655262004-10-31 20:02:16 +00003864 DIP("fxam");
sewardj883b00b2004-09-11 09:30:24 +00003865 break;
3866 }
3867
3868 case 0xE8: /* FLD1 */
sewardjdb199622004-09-06 23:19:03 +00003869 DIP("fld1");
sewardjce646f22004-08-31 23:55:54 +00003870 fp_push();
3871 put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
3872 break;
3873
sewardj37158712004-10-15 21:23:12 +00003874 case 0xE9: /* FLDL2T */
3875 DIP("fldl2t");
3876 fp_push();
3877 put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781)));
3878 break;
3879
sewardj8308aad2004-09-12 11:09:54 +00003880 case 0xEA: /* FLDL2E */
3881 DIP("fldl2e");
3882 fp_push();
3883 put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739)));
3884 break;
3885
sewardja0d48d62004-09-20 21:19:03 +00003886 case 0xEB: /* FLDPI */
3887 DIP("fldpi");
3888 fp_push();
3889 put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851)));
3890 break;
3891
sewardjdb199622004-09-06 23:19:03 +00003892 case 0xEC: /* FLDLG2 */
3893 DIP("fldlg2");
3894 fp_push();
3895 put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143)));
3896 break;
3897
3898 case 0xED: /* FLDLN2 */
3899 DIP("fldln2");
3900 fp_push();
3901 put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942)));
3902 break;
3903
sewardja58ea662004-08-15 03:12:41 +00003904 case 0xEE: /* FLDZ */
3905 DIP("fldz");
sewardj207557a2004-08-27 12:00:18 +00003906 fp_push();
3907 put_ST(0, IRExpr_Const(IRConst_F64(0.0)));
sewardja58ea662004-08-15 03:12:41 +00003908 break;
3909
sewardj06c32a02004-09-12 12:07:34 +00003910 case 0xF0: /* F2XM1 */
3911 DIP("f2xm1\n");
3912 put_ST_UNCHECKED(0, unop(Iop_2xm1F64, get_ST(0)));
3913 break;
3914
sewardj52ace3e2004-09-11 17:10:08 +00003915 case 0xF1: /* FYL2X */
3916 DIP("fyl2x\n");
3917 put_ST_UNCHECKED(1, binop(Iop_Yl2xF64,
3918 get_ST(1), get_ST(0)));
3919 fp_pop();
3920 break;
3921
sewardj99016a72004-10-15 22:09:17 +00003922 case 0xF2: /* FPTAN */
3923 DIP("ftan\n");
3924 put_ST_UNCHECKED(0, unop(Iop_TanF64, get_ST(0)));
3925 fp_push();
3926 put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
sewardj3f61ddb2004-10-16 20:51:05 +00003927 clear_C2(); /* HACK */
sewardj99016a72004-10-15 22:09:17 +00003928 break;
3929
sewardjcfded9a2004-09-09 11:44:16 +00003930 case 0xF3: /* FPATAN */
3931 DIP("fpatan\n");
sewardj52ace3e2004-09-11 17:10:08 +00003932 put_ST_UNCHECKED(1, binop(Iop_AtanF64,
sewardjcfded9a2004-09-09 11:44:16 +00003933 get_ST(1), get_ST(0)));
3934 fp_pop();
3935 break;
3936
sewardj442d0be2004-10-15 22:57:13 +00003937 case 0xF5: { /* FPREM1 -- IEEE compliant */
3938 IRTemp a1 = newTemp(Ity_F64);
3939 IRTemp a2 = newTemp(Ity_F64);
3940 DIP("fprem1\n");
3941 /* Do FPREM1 twice, once to get the remainder, and once
3942 to get the C3210 flag values. */
3943 assign( a1, get_ST(0) );
3944 assign( a2, get_ST(1) );
3945 put_ST_UNCHECKED(0, binop(Iop_PRem1F64,
3946 mkexpr(a1), mkexpr(a2)));
3947 put_C3210( binop(Iop_PRem1C3210F64, mkexpr(a1), mkexpr(a2)) );
3948 break;
3949 }
3950
sewardj46de4072004-09-11 19:23:24 +00003951 case 0xF8: { /* FPREM -- not IEEE compliant */
3952 IRTemp a1 = newTemp(Ity_F64);
3953 IRTemp a2 = newTemp(Ity_F64);
3954 DIP("fprem\n");
3955 /* Do FPREM twice, once to get the remainder, and once
3956 to get the C3210 flag values. */
3957 assign( a1, get_ST(0) );
3958 assign( a2, get_ST(1) );
3959 put_ST_UNCHECKED(0, binop(Iop_PRemF64,
3960 mkexpr(a1), mkexpr(a2)));
3961 put_C3210( binop(Iop_PRemC3210F64, mkexpr(a1), mkexpr(a2)) );
3962 break;
3963 }
3964
sewardj8308aad2004-09-12 11:09:54 +00003965 case 0xF9: /* FYL2XP1 */
3966 DIP("fyl2xp1\n");
3967 put_ST_UNCHECKED(1, binop(Iop_Yl2xp1F64,
3968 get_ST(1), get_ST(0)));
3969 fp_pop();
3970 break;
3971
sewardjc4be80c2004-09-10 16:17:45 +00003972 case 0xFA: /* FSQRT */
3973 DIP("fsqrt\n");
3974 put_ST_UNCHECKED(0, unop(Iop_SqrtF64, get_ST(0)));
3975 break;
3976
sewardje6709112004-09-10 18:37:18 +00003977 case 0xFC: /* FRNDINT */
3978 DIP("frndint\n");
3979 put_ST_UNCHECKED(0,
3980 binop(Iop_RoundF64, get_roundingmode(), get_ST(0)) );
3981 break;
3982
sewardj06c32a02004-09-12 12:07:34 +00003983 case 0xFD: /* FSCALE */
3984 DIP("fscale\n");
3985 put_ST_UNCHECKED(0, binop(Iop_ScaleF64,
3986 get_ST(0), get_ST(1)));
3987 break;
3988
sewardjcfded9a2004-09-09 11:44:16 +00003989 case 0xFE: /* FSIN */
3990 DIP("fsin\n");
3991 put_ST_UNCHECKED(0, unop(Iop_SinF64, get_ST(0)));
sewardj3f61ddb2004-10-16 20:51:05 +00003992 clear_C2(); /* HACK */
sewardjcfded9a2004-09-09 11:44:16 +00003993 break;
3994
3995 case 0xFF: /* FCOS */
3996 DIP("fcos\n");
3997 put_ST_UNCHECKED(0, unop(Iop_CosF64, get_ST(0)));
sewardj3f61ddb2004-10-16 20:51:05 +00003998 clear_C2(); /* HACK */
sewardjcfded9a2004-09-09 11:44:16 +00003999 break;
4000
sewardjbb53f8c2004-08-14 11:50:01 +00004001 default:
4002 goto decode_fail;
4003 }
4004 }
sewardjd1725d12004-08-12 20:46:53 +00004005 }
4006
4007 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
4008 else
4009 if (first_opcode == 0xDA) {
sewardjbb53f8c2004-08-14 11:50:01 +00004010
4011 if (modrm < 0xC0) {
4012
4013 /* bits 5,4,3 are an opcode extension, and the modRM also
4014 specifies an address. */
sewardjce646f22004-08-31 23:55:54 +00004015 IROp fop;
sewardjbb53f8c2004-08-14 11:50:01 +00004016 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4017 delta += len;
sewardjbb53f8c2004-08-14 11:50:01 +00004018 switch (gregOfRM(modrm)) {
sewardjce646f22004-08-31 23:55:54 +00004019
sewardjdb199622004-09-06 23:19:03 +00004020 case 0: /* FIADD m32int */ /* ST(0) += m32int */
4021 DIP("fiaddl %s", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004022 fop = Iop_AddF64;
4023 goto do_fop_m32;
sewardjdb199622004-09-06 23:19:03 +00004024
sewardj207557a2004-08-27 12:00:18 +00004025 case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
sewardjbb53f8c2004-08-14 11:50:01 +00004026 DIP("fimull %s", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004027 fop = Iop_MulF64;
4028 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004029
4030 case 4: /* FISUB m32int */ /* ST(0) -= m32int */
4031 DIP("fisubl %s", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004032 fop = Iop_SubF64;
4033 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004034
sewardj8308aad2004-09-12 11:09:54 +00004035 case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
4036 DIP("fisubrl %s", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004037 fop = Iop_SubF64;
4038 goto do_foprev_m32;
sewardj8308aad2004-09-12 11:09:54 +00004039
sewardjce646f22004-08-31 23:55:54 +00004040 case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
4041 DIP("fisubl %s", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004042 fop = Iop_DivF64;
4043 goto do_fop_m32;
sewardjce646f22004-08-31 23:55:54 +00004044
sewardjc4eaff32004-09-10 20:25:11 +00004045 case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
sewardj8308aad2004-09-12 11:09:54 +00004046 DIP("fidivrl %s", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004047 fop = Iop_DivF64;
4048 goto do_foprev_m32;
sewardjc4eaff32004-09-10 20:25:11 +00004049
sewardjce646f22004-08-31 23:55:54 +00004050 do_fop_m32:
sewardj207557a2004-08-27 12:00:18 +00004051 put_ST_UNCHECKED(0,
sewardjce646f22004-08-31 23:55:54 +00004052 binop(fop,
sewardj207557a2004-08-27 12:00:18 +00004053 get_ST(0),
sewardj89cd0932004-09-08 18:23:25 +00004054 unop(Iop_I32toF64,
4055 loadLE(Ity_I32, mkexpr(addr)))));
sewardjbb53f8c2004-08-14 11:50:01 +00004056 break;
4057
sewardjc4eaff32004-09-10 20:25:11 +00004058 do_foprev_m32:
4059 put_ST_UNCHECKED(0,
4060 binop(fop,
4061 unop(Iop_I32toF64,
4062 loadLE(Ity_I32, mkexpr(addr))),
4063 get_ST(0)));
4064 break;
4065
sewardjbb53f8c2004-08-14 11:50:01 +00004066 default:
4067 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4068 vex_printf("first_opcode == 0xDA\n");
4069 goto decode_fail;
4070 }
4071 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004072
4073 delta++;
4074 switch (modrm) {
4075
sewardj3fd5e572004-09-09 22:43:51 +00004076 case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
4077 r_src = (UInt)modrm - 0xC8;
sewardj5bd4d162004-11-10 13:02:48 +00004078 DIP("fcmovz %%st(%d), %%st(0)", r_src);
4079 put_ST_UNCHECKED(0,
sewardj3fd5e572004-09-09 22:43:51 +00004080 IRExpr_Mux0X(
sewardj8ea867b2004-10-30 19:03:02 +00004081 unop(Iop_1Uto8,mk_calculate_condition(CondZ)),
sewardj3fd5e572004-09-09 22:43:51 +00004082 get_ST(0), get_ST(r_src)) );
4083 break;
4084
sewardjbdc7d212004-09-09 02:46:40 +00004085 case 0xE9: /* FUCOMPP %st(0),%st(1) */
4086 DIP("fucompp %%st(0),%%st(1)\n");
sewardjc4be80c2004-09-10 16:17:45 +00004087 /* This forces C1 to zero, which isn't right. */
4088 put_C3210(
4089 binop( Iop_And32,
4090 binop(Iop_Shl32,
4091 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
4092 mkU8(8)),
4093 mkU32(0x4500)
4094 ));
sewardjbdc7d212004-09-09 02:46:40 +00004095 fp_pop();
4096 fp_pop();
4097 break;
4098
sewardj5bd4d162004-11-10 13:02:48 +00004099 default:
sewardjbdc7d212004-09-09 02:46:40 +00004100 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004101 }
sewardjbdc7d212004-09-09 02:46:40 +00004102
sewardjbb53f8c2004-08-14 11:50:01 +00004103 }
sewardjd1725d12004-08-12 20:46:53 +00004104 }
4105
4106 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
4107 else
4108 if (first_opcode == 0xDB) {
sewardj89cd0932004-09-08 18:23:25 +00004109 if (modrm < 0xC0) {
4110
4111 /* bits 5,4,3 are an opcode extension, and the modRM also
4112 specifies an address. */
4113 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4114 delta += len;
4115
4116 switch (gregOfRM(modrm)) {
4117
4118 case 0: /* FILD m32int */
4119 DIP("fildl %s\n", dis_buf);
4120 fp_push();
4121 put_ST(0, unop(Iop_I32toF64,
4122 loadLE(Ity_I32, mkexpr(addr))));
4123 break;
4124
sewardj8f3debf2004-09-08 23:42:23 +00004125 case 2: /* FIST m32 */
4126 DIP("fistl %s", dis_buf);
4127 storeLE( mkexpr(addr),
4128 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
4129 break;
4130
sewardj89cd0932004-09-08 18:23:25 +00004131 case 3: /* FISTP m32 */
4132 DIP("fistpl %s", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004133 storeLE( mkexpr(addr),
4134 binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
sewardj5bd4d162004-11-10 13:02:48 +00004135 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00004136 break;
sewardj17442fe2004-09-20 14:54:28 +00004137
sewardjb3bce0e2004-09-14 23:20:10 +00004138 case 5: { /* FLD extended-real */
sewardj7cb49d72004-10-24 22:31:25 +00004139 /* Uses dirty helper:
4140 ULong loadF80le ( VexGuestX86State*, UInt )
4141 addr holds the address. First, do a dirty call to
sewardjb3bce0e2004-09-14 23:20:10 +00004142 get hold of the data. */
sewardjc5fc7aa2004-10-27 23:00:55 +00004143 IRTemp val = newTemp(Ity_I64);
4144 IRExpr** args = mkIRExprVec_1 ( mkexpr(addr) );
4145
sewardj8ea867b2004-10-30 19:03:02 +00004146 IRDirty* d = unsafeIRDirty_1_N (
4147 val,
sewardjf9655262004-10-31 20:02:16 +00004148 0/*regparms*/, "loadF80le", &loadF80le,
sewardj8ea867b2004-10-30 19:03:02 +00004149 args
4150 );
sewardjb3bce0e2004-09-14 23:20:10 +00004151 /* declare that we're reading memory */
4152 d->mFx = Ifx_Read;
sewardj17442fe2004-09-20 14:54:28 +00004153 d->mAddr = mkexpr(addr);
sewardjb3bce0e2004-09-14 23:20:10 +00004154 d->mSize = 10;
sewardjc5fc7aa2004-10-27 23:00:55 +00004155
4156 /* execute the dirty call, dumping the result in val. */
sewardjb3bce0e2004-09-14 23:20:10 +00004157 stmt( IRStmt_Dirty(d) );
4158 fp_push();
sewardjc5fc7aa2004-10-27 23:00:55 +00004159 put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(val)));
4160
4161 DIP("fldt %s", dis_buf);
sewardjb3bce0e2004-09-14 23:20:10 +00004162 break;
4163 }
sewardj17442fe2004-09-20 14:54:28 +00004164
4165 case 7: { /* FSTP extended-real */
4166 /* Uses dirty helper: void storeF80le ( UInt, ULong ) */
sewardjc5fc7aa2004-10-27 23:00:55 +00004167 IRExpr** args
4168 = mkIRExprVec_2( mkexpr(addr),
4169 unop(Iop_ReinterpF64asI64, get_ST(0)) );
4170
sewardj8ea867b2004-10-30 19:03:02 +00004171 IRDirty* d = unsafeIRDirty_0_N (
sewardjf9655262004-10-31 20:02:16 +00004172 0/*regparms*/,
4173 "storeF80le", &storeF80le,
sewardj8ea867b2004-10-30 19:03:02 +00004174 args
4175 );
sewardj17442fe2004-09-20 14:54:28 +00004176 /* declare we're writing memory */
4177 d->mFx = Ifx_Write;
4178 d->mAddr = mkexpr(addr);
4179 d->mSize = 10;
sewardjc5fc7aa2004-10-27 23:00:55 +00004180
sewardj17442fe2004-09-20 14:54:28 +00004181 /* execute the dirty call. */
4182 stmt( IRStmt_Dirty(d) );
4183 fp_pop();
sewardjc5fc7aa2004-10-27 23:00:55 +00004184
4185 DIP("fstpt %s", dis_buf);
sewardj17442fe2004-09-20 14:54:28 +00004186 break;
4187 }
4188
sewardjb3bce0e2004-09-14 23:20:10 +00004189 default:
sewardj89cd0932004-09-08 18:23:25 +00004190 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4191 vex_printf("first_opcode == 0xDB\n");
4192 goto decode_fail;
4193 }
4194
4195 } else {
sewardj8308aad2004-09-12 11:09:54 +00004196
4197 delta++;
4198 switch (modrm) {
4199
sewardj4e82db72004-10-16 11:32:15 +00004200 case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
4201 r_src = (UInt)modrm - 0xC8;
sewardj5bd4d162004-11-10 13:02:48 +00004202 DIP("fcmovnz %%st(%d), %%st(0)", r_src);
4203 put_ST_UNCHECKED(0,
sewardj4e82db72004-10-16 11:32:15 +00004204 IRExpr_Mux0X(
sewardj8ea867b2004-10-30 19:03:02 +00004205 unop(Iop_1Uto8,mk_calculate_condition(CondNZ)),
sewardj4e82db72004-10-16 11:32:15 +00004206 get_ST(0), get_ST(r_src)) );
4207 break;
4208
sewardj8308aad2004-09-12 11:09:54 +00004209 case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
4210 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
4211 break;
4212
sewardj37158712004-10-15 21:23:12 +00004213 case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
4214 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
4215 break;
4216
sewardj8308aad2004-09-12 11:09:54 +00004217 default:
4218 goto decode_fail;
sewardj17442fe2004-09-20 14:54:28 +00004219 }
sewardj89cd0932004-09-08 18:23:25 +00004220 }
sewardjd1725d12004-08-12 20:46:53 +00004221 }
4222
4223 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
4224 else
4225 if (first_opcode == 0xDC) {
sewardja58ea662004-08-15 03:12:41 +00004226 if (modrm < 0xC0) {
4227
sewardj89cd0932004-09-08 18:23:25 +00004228 /* bits 5,4,3 are an opcode extension, and the modRM also
4229 specifies an address. */
sewardja58ea662004-08-15 03:12:41 +00004230 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4231 delta += len;
4232
4233 switch (gregOfRM(modrm)) {
4234
4235 case 0: /* FADD double-real */
4236 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
4237 break;
4238
sewardjcfded9a2004-09-09 11:44:16 +00004239 case 1: /* FMUL double-real */
4240 fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
4241 break;
4242
sewardje166ed02004-10-25 02:27:01 +00004243 case 2: /* FCOM double-real */
4244 DIP("fcoml %s\n", dis_buf);
4245 /* This forces C1 to zero, which isn't right. */
4246 put_C3210(
4247 binop( Iop_And32,
4248 binop(Iop_Shl32,
4249 binop(Iop_CmpF64,
4250 get_ST(0),
4251 loadLE(Ity_F64,mkexpr(addr))),
4252 mkU8(8)),
4253 mkU32(0x4500)
4254 ));
4255 break;
4256
sewardj883b00b2004-09-11 09:30:24 +00004257 case 3: /* FCOMP double-real */
sewardje166ed02004-10-25 02:27:01 +00004258 DIP("fcompl %s\n", dis_buf);
sewardj883b00b2004-09-11 09:30:24 +00004259 /* This forces C1 to zero, which isn't right. */
4260 put_C3210(
4261 binop( Iop_And32,
4262 binop(Iop_Shl32,
4263 binop(Iop_CmpF64,
4264 get_ST(0),
4265 loadLE(Ity_F64,mkexpr(addr))),
4266 mkU8(8)),
4267 mkU32(0x4500)
4268 ));
4269 fp_pop();
4270 break;
4271
sewardjcfded9a2004-09-09 11:44:16 +00004272 case 4: /* FSUB double-real */
4273 fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
4274 break;
4275
sewardj3fd5e572004-09-09 22:43:51 +00004276 case 5: /* FSUBR double-real */
4277 fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
4278 break;
4279
sewardjcfded9a2004-09-09 11:44:16 +00004280 case 6: /* FDIV double-real */
4281 fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
4282 break;
4283
sewardj883b00b2004-09-11 09:30:24 +00004284 case 7: /* FDIVR double-real */
4285 fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
4286 break;
4287
sewardja58ea662004-08-15 03:12:41 +00004288 default:
4289 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4290 vex_printf("first_opcode == 0xDC\n");
4291 goto decode_fail;
4292 }
4293
4294 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004295
4296 delta++;
4297 switch (modrm) {
4298
sewardj3fd5e572004-09-09 22:43:51 +00004299 case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
4300 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
4301 break;
4302
sewardjcfded9a2004-09-09 11:44:16 +00004303 case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
4304 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
4305 break;
4306
sewardj47341042004-09-19 11:55:46 +00004307 case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
4308 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
4309 break;
4310
sewardjcfded9a2004-09-09 11:44:16 +00004311 case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
4312 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
4313 break;
4314
sewardja0d48d62004-09-20 21:19:03 +00004315 case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
4316 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
4317 break;
4318
sewardjbdc7d212004-09-09 02:46:40 +00004319 case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
4320 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
4321 break;
4322
4323 default:
4324 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004325 }
sewardjbdc7d212004-09-09 02:46:40 +00004326
sewardja58ea662004-08-15 03:12:41 +00004327 }
sewardjd1725d12004-08-12 20:46:53 +00004328 }
4329
4330 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
4331 else
4332 if (first_opcode == 0xDD) {
4333
4334 if (modrm < 0xC0) {
4335
sewardjbb53f8c2004-08-14 11:50:01 +00004336 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjd1725d12004-08-12 20:46:53 +00004337 specifies an address. */
sewardjbb53f8c2004-08-14 11:50:01 +00004338 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4339 delta += len;
sewardjd1725d12004-08-12 20:46:53 +00004340
4341 switch (gregOfRM(modrm)) {
4342
4343 case 0: /* FLD double-real */
4344 DIP("fldD %s\n", dis_buf);
sewardj207557a2004-08-27 12:00:18 +00004345 fp_push();
4346 put_ST(0, IRExpr_LDle(Ity_F64, mkexpr(addr)));
sewardjbb53f8c2004-08-14 11:50:01 +00004347 break;
sewardjd1725d12004-08-12 20:46:53 +00004348
sewardjd1725d12004-08-12 20:46:53 +00004349 case 2: /* FST double-real */
sewardj89cd0932004-09-08 18:23:25 +00004350 DIP("fstD %s", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004351 storeLE(mkexpr(addr), get_ST(0));
sewardjd1725d12004-08-12 20:46:53 +00004352 break;
sewardj89cd0932004-09-08 18:23:25 +00004353
sewardja58ea662004-08-15 03:12:41 +00004354 case 3: /* FSTP double-real */
4355 DIP("fstpD %s", dis_buf);
sewardj5bd4d162004-11-10 13:02:48 +00004356 storeLE(mkexpr(addr), get_ST(0));
4357 fp_pop();
sewardja58ea662004-08-15 03:12:41 +00004358 break;
sewardjd1725d12004-08-12 20:46:53 +00004359
4360 default:
sewardjbb53f8c2004-08-14 11:50:01 +00004361 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4362 vex_printf("first_opcode == 0xDD\n");
sewardjd1725d12004-08-12 20:46:53 +00004363 goto decode_fail;
sewardjbb53f8c2004-08-14 11:50:01 +00004364 }
sewardjd1725d12004-08-12 20:46:53 +00004365 } else {
sewardja58ea662004-08-15 03:12:41 +00004366 delta++;
4367 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00004368
sewardj06c32a02004-09-12 12:07:34 +00004369 case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
4370 r_dst = (UInt)modrm - 0xD0;
4371 DIP("fst %%st(0),%%st(%d)\n", r_dst);
sewardj5bd4d162004-11-10 13:02:48 +00004372 /* P4 manual says: "If the destination operand is a
sewardj06c32a02004-09-12 12:07:34 +00004373 non-empty register, the invalid-operation exception
4374 is not generated. Hence put_ST_UNCHECKED. */
4375 put_ST_UNCHECKED(r_dst, get_ST(0));
4376 break;
4377
sewardja58ea662004-08-15 03:12:41 +00004378 case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
4379 r_dst = (UInt)modrm - 0xD8;
4380 DIP("fstp %%st(0),%%st(%d)\n", r_dst);
sewardj5bd4d162004-11-10 13:02:48 +00004381 /* P4 manual says: "If the destination operand is a
sewardj207557a2004-08-27 12:00:18 +00004382 non-empty register, the invalid-operation exception
4383 is not generated. Hence put_ST_UNCHECKED. */
4384 put_ST_UNCHECKED(r_dst, get_ST(0));
4385 fp_pop();
sewardja58ea662004-08-15 03:12:41 +00004386 break;
sewardjbdc7d212004-09-09 02:46:40 +00004387
4388 case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
4389 r_dst = (UInt)modrm - 0xE0;
4390 DIP("fucom %%st(0),%%st(%d)\n", r_dst);
sewardjc4be80c2004-09-10 16:17:45 +00004391 /* This forces C1 to zero, which isn't right. */
4392 put_C3210(
4393 binop( Iop_And32,
4394 binop(Iop_Shl32,
4395 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4396 mkU8(8)),
4397 mkU32(0x4500)
4398 ));
sewardjbdc7d212004-09-09 02:46:40 +00004399 break;
4400
4401 case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
4402 r_dst = (UInt)modrm - 0xE8;
4403 DIP("fucomp %%st(0),%%st(%d)\n", r_dst);
sewardjc4be80c2004-09-10 16:17:45 +00004404 /* This forces C1 to zero, which isn't right. */
4405 put_C3210(
4406 binop( Iop_And32,
4407 binop(Iop_Shl32,
4408 binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4409 mkU8(8)),
4410 mkU32(0x4500)
4411 ));
sewardjbdc7d212004-09-09 02:46:40 +00004412 fp_pop();
4413 break;
4414
sewardj5bd4d162004-11-10 13:02:48 +00004415 default:
sewardja58ea662004-08-15 03:12:41 +00004416 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004417 }
sewardjd1725d12004-08-12 20:46:53 +00004418 }
4419 }
4420
4421 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
4422 else
4423 if (first_opcode == 0xDE) {
sewardjbdc7d212004-09-09 02:46:40 +00004424
4425 if (modrm < 0xC0) {
4426 goto decode_fail;
4427
4428 } else {
4429
4430 delta++;
sewardj5bd4d162004-11-10 13:02:48 +00004431 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00004432
sewardjcfded9a2004-09-09 11:44:16 +00004433 case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
4434 fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
4435 break;
4436
sewardjbdc7d212004-09-09 02:46:40 +00004437 case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
4438 fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
4439 break;
4440
sewardje166ed02004-10-25 02:27:01 +00004441 case 0xD9: /* FCOMPP %st(0),%st(1) */
4442 DIP("fuompp %%st(0),%%st(1)\n");
4443 /* This forces C1 to zero, which isn't right. */
4444 put_C3210(
4445 binop( Iop_And32,
4446 binop(Iop_Shl32,
4447 binop(Iop_CmpF64, get_ST(0), get_ST(1)),
4448 mkU8(8)),
4449 mkU32(0x4500)
4450 ));
4451 fp_pop();
4452 fp_pop();
4453 break;
4454
sewardjcfded9a2004-09-09 11:44:16 +00004455 case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
4456 fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, True );
4457 break;
4458
sewardj3fd5e572004-09-09 22:43:51 +00004459 case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
4460 fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, True );
4461 break;
4462
sewardjbdc7d212004-09-09 02:46:40 +00004463 case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
4464 fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
4465 break;
4466
4467 case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
4468 fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
4469 break;
4470
4471 default:
4472 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004473 }
sewardjbdc7d212004-09-09 02:46:40 +00004474
4475 }
sewardjd1725d12004-08-12 20:46:53 +00004476 }
4477
4478 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
4479 else
4480 if (first_opcode == 0xDF) {
sewardj89cd0932004-09-08 18:23:25 +00004481
4482 if (modrm < 0xC0) {
4483
4484 /* bits 5,4,3 are an opcode extension, and the modRM also
4485 specifies an address. */
4486 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4487 delta += len;
4488
4489 switch (gregOfRM(modrm)) {
4490
sewardj883b00b2004-09-11 09:30:24 +00004491 case 0: /* FILD m16int */
4492 DIP("fildw %s\n", dis_buf);
4493 fp_push();
4494 put_ST(0, unop(Iop_I32toF64,
4495 unop(Iop_16Sto32,
4496 loadLE(Ity_I16, mkexpr(addr)))));
4497 break;
4498
sewardj37158712004-10-15 21:23:12 +00004499 case 2: /* FIST m16 */
4500 DIP("fistp %s", dis_buf);
4501 storeLE( mkexpr(addr),
4502 binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
4503 break;
4504
sewardj89cd0932004-09-08 18:23:25 +00004505 case 3: /* FISTP m16 */
4506 DIP("fistps %s", dis_buf);
sewardj8f3debf2004-09-08 23:42:23 +00004507 storeLE( mkexpr(addr),
4508 binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
4509 fp_pop();
sewardj89cd0932004-09-08 18:23:25 +00004510 break;
4511
sewardj89cd0932004-09-08 18:23:25 +00004512 case 5: /* FILD m64 */
4513 DIP("fildll %s\n", dis_buf);
4514 fp_push();
4515 put_ST(0, unop(Iop_I64toF64,
4516 loadLE(Ity_I64, mkexpr(addr))));
4517 break;
sewardj89cd0932004-09-08 18:23:25 +00004518
sewardjcfded9a2004-09-09 11:44:16 +00004519 case 7: /* FISTP m64 */
4520 DIP("fistpll %s", dis_buf);
4521 storeLE( mkexpr(addr),
4522 binop(Iop_F64toI64, get_roundingmode(), get_ST(0)) );
4523 fp_pop();
4524 break;
4525
sewardj89cd0932004-09-08 18:23:25 +00004526 default:
4527 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
4528 vex_printf("first_opcode == 0xDF\n");
4529 goto decode_fail;
4530 }
4531
4532 } else {
sewardjbdc7d212004-09-09 02:46:40 +00004533
4534 delta++;
sewardj5bd4d162004-11-10 13:02:48 +00004535 switch (modrm) {
sewardjbdc7d212004-09-09 02:46:40 +00004536
4537 case 0xE0: /* FNSTSW %ax */
4538 DIP("fnstsw %%ax\n");
4539 /* Invent a plausible-looking FPU status word value and
4540 dump it in %AX:
sewardjc4be80c2004-09-10 16:17:45 +00004541 ((ftop & 7) << 11) | (c3210 & 0x4700)
sewardjbdc7d212004-09-09 02:46:40 +00004542 */
4543 putIReg(2, R_EAX,
4544 unop(Iop_32to16,
4545 binop(Iop_Or32,
4546 binop(Iop_Shl32,
4547 binop(Iop_And32, get_ftop(), mkU32(7)),
4548 mkU8(11)),
sewardjc4be80c2004-09-10 16:17:45 +00004549 binop(Iop_And32, get_C3210(), mkU32(0x4700))
sewardjbdc7d212004-09-09 02:46:40 +00004550 )));
4551 break;
4552
sewardj883b00b2004-09-11 09:30:24 +00004553 case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
sewardj8308aad2004-09-12 11:09:54 +00004554 fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
sewardj883b00b2004-09-11 09:30:24 +00004555 break;
4556
sewardjbdc7d212004-09-09 02:46:40 +00004557 default:
4558 goto decode_fail;
sewardj5bd4d162004-11-10 13:02:48 +00004559 }
sewardj89cd0932004-09-08 18:23:25 +00004560 }
4561
sewardjd1725d12004-08-12 20:46:53 +00004562 }
4563
4564 else
4565 vpanic("dis_FPU(x86): invalid primary opcode");
4566
sewardj69d9d662004-10-14 21:58:52 +00004567 *decode_ok = True;
4568 return delta;
4569
sewardjd1725d12004-08-12 20:46:53 +00004570 decode_fail:
4571 *decode_ok = False;
4572 return delta;
4573}
4574
4575
sewardj464efa42004-11-19 22:17:29 +00004576/*------------------------------------------------------------*/
4577/*--- ---*/
4578/*--- MMX INSTRUCTIONS ---*/
4579/*--- ---*/
4580/*------------------------------------------------------------*/
sewardja06e5562004-07-14 13:18:05 +00004581
sewardj464efa42004-11-19 22:17:29 +00004582/* Effect of MMX insns on x87 FPU state (table 11-2 of
4583 IA32 arch manual, volume 3):
4584
4585 Read from, or write to MMX register (viz, any insn except EMMS):
4586 * All tags set to Valid (non-empty) -- FPTAGS[i] := nonzero
4587 * FP stack pointer set to zero
4588
4589 EMMS:
4590 * All tags set to Invalid (empty) -- FPTAGS[i] := zero
4591 * FP stack pointer set to zero
4592*/
4593
4594static void do_MMX_boilerplate ( void )
4595{
4596 Int i;
4597 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
4598 IRExpr* zero = mkU32(0);
4599 IRExpr* tag1 = mkU8(1);
4600 put_ftop(zero);
4601 for (i = 0; i < 8; i++)
4602 stmt( IRStmt_PutI( descr, zero, i, tag1 ) );
4603}
4604
4605static void do_EMMS_boilerplate ( void )
4606{
4607 Int i;
4608 IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
4609 IRExpr* zero = mkU32(0);
4610 IRExpr* tag0 = mkU8(0);
4611 put_ftop(zero);
4612 for (i = 0; i < 8; i++)
4613 stmt( IRStmt_PutI( descr, zero, i, tag0 ) );
4614}
4615
4616
4617static IRExpr* getMMXReg ( UInt archreg )
4618{
4619 vassert(archreg < 8);
4620 return IRExpr_Get( OFFB_FPREGS + 8 * archreg, Ity_I64 );
4621}
4622
4623
4624static void putMMXReg ( UInt archreg, IRExpr* e )
4625{
4626 vassert(archreg < 8);
4627 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I64);
4628 stmt( IRStmt_Put( OFFB_FPREGS + 8 * archreg, e ) );
4629}
4630
4631
4632static
4633UInt dis_MMXop_regmem_to_reg ( UChar sorb,
4634 UInt delta,
4635 UChar opc,
4636 Char* name,
4637 Bool show_granularity )
4638{
sewardj63ba4092004-11-21 12:30:18 +00004639 Char dis_buf[50];
4640 UChar modrm = getIByte(delta);
4641 Bool isReg = epartIsReg(modrm);
4642 IRExpr* argL = NULL;
4643 IRExpr* argR = NULL;
4644 IRTemp res = newTemp(Ity_I64);
sewardj464efa42004-11-19 22:17:29 +00004645
4646# define XXX(_name) hAddr = &_name; hName = #_name;
4647
4648 void* hAddr = NULL;
4649 Char* hName = NULL;
4650 switch (opc) {
sewardj63ba4092004-11-21 12:30:18 +00004651 case 0xFC: XXX(calculate_add8x8); break;
4652 case 0xFD: XXX(calculate_add16x4); break;
4653 case 0xFE: XXX(calculate_add32x2); break;
sewardj464efa42004-11-19 22:17:29 +00004654
sewardj63ba4092004-11-21 12:30:18 +00004655 case 0xEC: XXX(calculate_qadd8Sx8); break;
4656 case 0xED: XXX(calculate_qadd16Sx4); break;
sewardj464efa42004-11-19 22:17:29 +00004657
sewardj63ba4092004-11-21 12:30:18 +00004658 case 0xDC: XXX(calculate_qadd8Ux8); break;
4659 case 0xDD: XXX(calculate_qadd16Ux4); break;
sewardj464efa42004-11-19 22:17:29 +00004660
sewardj63ba4092004-11-21 12:30:18 +00004661 case 0xF8: XXX(calculate_sub8x8); break;
4662 case 0xF9: XXX(calculate_sub16x4); break;
4663 case 0xFA: XXX(calculate_sub32x2); break;
sewardj464efa42004-11-19 22:17:29 +00004664
sewardj63ba4092004-11-21 12:30:18 +00004665 case 0xE8: XXX(calculate_qsub8Sx8); break;
4666 case 0xE9: XXX(calculate_qsub16Sx4); break;
sewardj464efa42004-11-19 22:17:29 +00004667
sewardj63ba4092004-11-21 12:30:18 +00004668 case 0xD8: XXX(calculate_qsub8Ux8); break;
4669 case 0xD9: XXX(calculate_qsub16Ux4); break;
sewardj464efa42004-11-19 22:17:29 +00004670
sewardj63ba4092004-11-21 12:30:18 +00004671 case 0xE5: XXX(calculate_mulhi16x4); break;
4672 case 0xD5: XXX(calculate_mullo16x4); break;
sewardj4340dac2004-11-20 13:17:04 +00004673 case 0xF5: XXX(calculate_pmaddwd); break;
4674
sewardj63ba4092004-11-21 12:30:18 +00004675 case 0x74: XXX(calculate_cmpeq8x8); break;
4676 case 0x75: XXX(calculate_cmpeq16x4); break;
4677 case 0x76: XXX(calculate_cmpeq32x2); break;
sewardj4340dac2004-11-20 13:17:04 +00004678
sewardj63ba4092004-11-21 12:30:18 +00004679 case 0x64: XXX(calculate_cmpge8Sx8); break;
4680 case 0x65: XXX(calculate_cmpge16Sx4); break;
4681 case 0x66: XXX(calculate_cmpge32Sx2); break;
4682
4683 case 0x6B: XXX(calculate_packssdw); break;
4684 case 0x63: XXX(calculate_packsswb); break;
4685 case 0x67: XXX(calculate_packuswb); break;
4686
4687 case 0x68: XXX(calculate_punpckhbw); break;
4688 case 0x69: XXX(calculate_punpckhwd); break;
4689 case 0x6A: XXX(calculate_punpckhdq); break;
4690
4691 case 0x60: XXX(calculate_punpcklbw); break;
4692 case 0x61: XXX(calculate_punpcklwd); break;
4693 case 0x62: XXX(calculate_punpckldq); break;
4694
sewardj8d14a592004-11-21 17:04:50 +00004695 case 0xF1: XXX(calculate_shl16x4); break;
4696 case 0xF2: XXX(calculate_shl32x2); break;
4697 case 0xF3: XXX(calculate_shl64x1); break;
4698
4699 case 0xD1: XXX(calculate_shr16Ux4); break;
4700 case 0xD2: XXX(calculate_shr32Ux2); break;
4701 case 0xD3: XXX(calculate_shr64Ux1); break;
4702
4703 case 0xE1: XXX(calculate_shr16Sx4); break;
4704 case 0xE2: XXX(calculate_shr32Sx2); break;
4705
sewardj63ba4092004-11-21 12:30:18 +00004706 case 0xDB: break; /* AND */
4707 case 0xDF: break; /* ANDN */
4708 case 0xEB: break; /* OR */
4709 case 0xEF: break; /* XOR */
sewardj464efa42004-11-19 22:17:29 +00004710
4711 default:
4712 vex_printf("\n0x%x\n", (Int)opc);
4713 vpanic("dis_MMXop_regmem_to_reg");
4714 }
4715
4716# undef XXX
4717
sewardj63ba4092004-11-21 12:30:18 +00004718 argL = getMMXReg(gregOfRM(modrm));
4719
sewardj464efa42004-11-19 22:17:29 +00004720 if (isReg) {
sewardj63ba4092004-11-21 12:30:18 +00004721 vassert(0);
sewardj464efa42004-11-19 22:17:29 +00004722 delta++;
sewardj63ba4092004-11-21 12:30:18 +00004723 argR = getMMXReg(eregOfRM(modrm));
sewardj464efa42004-11-19 22:17:29 +00004724 } else {
4725 Int len;
4726 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4727 delta += len;
sewardj63ba4092004-11-21 12:30:18 +00004728 argR = loadLE(Ity_I64, mkexpr(addr));
sewardj464efa42004-11-19 22:17:29 +00004729 }
4730
sewardj63ba4092004-11-21 12:30:18 +00004731 switch (opc) {
4732 case 0xDB:
4733 assign(res, binop(Iop_And64, argL, argR) );
4734 break;
4735 case 0xDF:
sewardjb4acca52004-11-21 13:45:05 +00004736 assign(res, binop(Iop_And64, unop(Iop_Not64, argL), argR) );
sewardj63ba4092004-11-21 12:30:18 +00004737 break;
4738 case 0xEB:
4739 assign(res, binop(Iop_Or64, argL, argR) );
4740 break;
4741 case 0xEF:
4742 /* Possibly do better here if argL and argR are the same reg */
4743 assign(res, binop(Iop_Xor64, argL, argR) );
4744 break;
4745 default:
4746 vassert(hAddr);
4747 vassert(hName);
4748 assign( res,
4749 mkIRExprCCall(
4750 Ity_I64,
4751 0/*regparms*/, hName, hAddr,
4752 mkIRExprVec_2( argL, argR )
4753 )
4754 );
4755 break;
4756 }
4757
4758 putMMXReg( gregOfRM(modrm), mkexpr(res) );
4759
sewardj464efa42004-11-19 22:17:29 +00004760 DIP("%s%s %s, %s\n",
4761 name, show_granularity ? nameMMXGran(opc & 3) : (Char*)"",
4762 ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
4763 nameMMXReg(gregOfRM(modrm)) );
4764
4765 return delta;
4766}
4767
4768
4769
4770static
4771UInt dis_MMX ( Bool* decode_ok, UChar sorb, Int sz, UInt delta )
4772{
4773 Int len;
4774 UChar modrm;
4775 UChar dis_buf[50];
4776 UChar opc = getIByte(delta);
4777 delta++;
4778
4779 if (0) {
4780 } else {
4781 do_MMX_boilerplate();
4782 }
4783
4784 switch (opc) {
4785
4786 case 0x6F:
4787 /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
4788 vassert(sz == 4);
4789 modrm = getIByte(delta);
4790 if (epartIsReg(modrm)) {
4791 delta++;
4792 putMMXReg( gregOfRM(modrm), getMMXReg(eregOfRM(modrm)) );
4793 DIP("movq %s, %s\n",
4794 nameMMXReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
4795 } else {
4796 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4797 delta += len;
4798 putMMXReg( gregOfRM(modrm), loadLE(Ity_I64, mkexpr(addr)) );
4799 DIP("movq %s, %s\n",
4800 dis_buf, nameMMXReg(gregOfRM(modrm)));
4801 }
4802 break;
4803
4804 case 0x7F:
4805 /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
4806 vassert(sz == 4);
4807 modrm = getIByte(delta);
4808 if (epartIsReg(modrm)) {
sewardj63ba4092004-11-21 12:30:18 +00004809 vassert(0);
sewardj464efa42004-11-19 22:17:29 +00004810#if 0
4811 eip++;
4812 uInstr1(cb, MMX2, 0,
4813 Lit16,
4814 (((UShort)(opc)) << 8) | ((UShort)modrm) );
4815 DIP("movq %s, %s\n",
4816 nameMMXReg(gregOfRM(modrm)), nameMMXReg(eregOfRM(modrm)));
4817#endif
4818 } else {
4819 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
4820 delta += len;
4821 storeLE( mkexpr(addr), getMMXReg(gregOfRM(modrm)) );
4822 DIP("mov(nt)q %s, %s\n",
4823 nameMMXReg(gregOfRM(modrm)), dis_buf);
4824 }
4825 break;
4826
sewardj4340dac2004-11-20 13:17:04 +00004827 case 0xFC:
4828 case 0xFD:
4829 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +00004830 vassert(sz == 4);
4831 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padd", True );
4832 break;
4833
sewardj4340dac2004-11-20 13:17:04 +00004834 case 0xEC:
4835 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +00004836 vassert(sz == 4);
4837 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "padds", True );
4838 break;
4839
sewardj4340dac2004-11-20 13:17:04 +00004840 case 0xDC:
4841 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +00004842 vassert(sz == 4);
4843 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "paddus", True );
4844 break;
4845
sewardj4340dac2004-11-20 13:17:04 +00004846 case 0xF8:
4847 case 0xF9:
4848 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +00004849 vassert(sz == 4);
4850 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psub", True );
4851 break;
4852
sewardj4340dac2004-11-20 13:17:04 +00004853 case 0xE8:
4854 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +00004855 vassert(sz == 4);
4856 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubs", True );
4857 break;
4858
sewardj4340dac2004-11-20 13:17:04 +00004859 case 0xD8:
4860 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
sewardj464efa42004-11-19 22:17:29 +00004861 vassert(sz == 4);
4862 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psubus", True );
4863 break;
4864
4865 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
4866 vassert(sz == 4);
4867 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmulhw", False );
4868 break;
4869
4870 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
4871 vassert(sz == 4);
4872 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmullw", False );
4873 break;
4874
sewardj4340dac2004-11-20 13:17:04 +00004875 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
4876 vassert(sz == 4);
4877 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pmaddwd", False );
4878 break;
4879
4880 case 0x74:
4881 case 0x75:
4882 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
4883 vassert(sz == 4);
4884 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpeq", True );
4885 break;
4886
4887 case 0x64:
4888 case 0x65:
4889 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
4890 vassert(sz == 4);
4891 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pcmpgt", True );
4892 break;
4893
sewardj63ba4092004-11-21 12:30:18 +00004894 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
4895 vassert(sz == 4);
4896 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packssdw", False );
4897 break;
4898
4899 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
4900 vassert(sz == 4);
4901 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packsswb", False );
4902 break;
4903
4904 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
4905 vassert(sz == 4);
4906 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "packuswb", False );
4907 break;
4908
4909 case 0x68:
4910 case 0x69:
4911 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
4912 vassert(sz == 4);
4913 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckh", True );
4914 break;
4915
4916 case 0x60:
4917 case 0x61:
4918 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
4919 vassert(sz == 4);
4920 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "punpckl", True );
4921 break;
4922
4923 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
4924 vassert(sz == 4);
4925 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pand", False );
4926 break;
4927
4928 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
4929 vassert(sz == 4);
4930 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pandn", False );
4931 break;
4932
4933 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
4934 vassert(sz == 4);
4935 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "por", False );
4936 break;
4937
4938 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
4939 vassert(sz == 4);
4940 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pxor", False );
4941 break;
4942
sewardj8d14a592004-11-21 17:04:50 +00004943 case 0xF1:
4944 case 0xF2:
4945 case 0xF3: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
4946 vassert(sz == 4);
4947 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psll", True );
4948 break;
4949
4950 case 0xD1:
4951 case 0xD2:
4952 case 0xD3: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
4953 vassert(sz == 4);
4954 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psrl", True );
4955 break;
4956
4957 case 0xE1:
4958 case 0xE2: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
4959 vassert(sz == 4);
4960 delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psra", True );
4961 break;
4962
sewardj464efa42004-11-19 22:17:29 +00004963 default:
4964 *decode_ok = False;
4965 return delta; /* ignored */
4966
4967 }
4968
4969 *decode_ok = True;
4970 return delta;
4971}
4972
4973
4974/*------------------------------------------------------------*/
4975/*--- More misc arithmetic and other obscure insns. ---*/
4976/*------------------------------------------------------------*/
sewardja06e5562004-07-14 13:18:05 +00004977
4978/* Double length left and right shifts. Apparently only required in
4979 v-size (no b- variant). */
4980static
4981UInt dis_SHLRD_Gv_Ev ( UChar sorb,
4982 UInt delta, UChar modrm,
4983 Int sz,
4984 IRExpr* shift_amt,
4985 Bool amt_is_literal,
4986 Char* shift_amt_txt,
4987 Bool left_shift )
4988{
4989 /* shift_amt :: Ity_I8 is the amount to shift. shift_amt_txt is used
4990 for printing it. And eip on entry points at the modrm byte. */
4991 Int len;
4992 UChar dis_buf[50];
4993
sewardj6d2638e2004-07-15 09:38:27 +00004994 IRType ty = szToITy(sz);
4995 IRTemp gsrc = newTemp(ty);
4996 IRTemp esrc = newTemp(ty);
sewardj92d168d2004-11-15 14:22:12 +00004997 IRTemp addr = IRTemp_INVALID;
sewardj6d2638e2004-07-15 09:38:27 +00004998 IRTemp tmpSH = newTemp(Ity_I8);
sewardj92d168d2004-11-15 14:22:12 +00004999 IRTemp tmpL = IRTemp_INVALID;
5000 IRTemp tmpRes = IRTemp_INVALID;
5001 IRTemp tmpSubSh = IRTemp_INVALID;
sewardja06e5562004-07-14 13:18:05 +00005002 IROp mkpair;
5003 IROp getres;
5004 IROp shift;
sewardja06e5562004-07-14 13:18:05 +00005005 IRExpr* mask = NULL;
5006
5007 vassert(sz == 2 || sz == 4);
5008
5009 /* The E-part is the destination; this is shifted. The G-part
5010 supplies bits to be shifted into the E-part, but is not
5011 changed.
5012
5013 If shifting left, form a double-length word with E at the top
5014 and G at the bottom, and shift this left. The result is then in
5015 the high part.
5016
5017 If shifting right, form a double-length word with G at the top
5018 and E at the bottom, and shift this right. The result is then
5019 at the bottom. */
5020
5021 /* Fetch the operands. */
5022
5023 assign( gsrc, getIReg(sz, gregOfRM(modrm)) );
5024
5025 if (epartIsReg(modrm)) {
5026 delta++;
5027 assign( esrc, getIReg(sz, eregOfRM(modrm)) );
sewardj68511542004-07-28 00:15:44 +00005028 DIP("sh%cd%c %s, %s, %s\n",
sewardja06e5562004-07-14 13:18:05 +00005029 ( left_shift ? 'l' : 'r' ), nameISize(sz),
sewardj68511542004-07-28 00:15:44 +00005030 shift_amt_txt,
sewardja06e5562004-07-14 13:18:05 +00005031 nameIReg(sz, gregOfRM(modrm)), nameIReg(sz, eregOfRM(modrm)));
5032 } else {
5033 addr = disAMode ( &len, sorb, delta, dis_buf );
5034 delta += len;
5035 assign( esrc, loadLE(ty, mkexpr(addr)) );
sewardj68511542004-07-28 00:15:44 +00005036 DIP("sh%cd%c %s, %s, %s\n",
5037 ( left_shift ? 'l' : 'r' ), nameISize(sz),
5038 shift_amt_txt,
5039 nameIReg(sz, gregOfRM(modrm)), dis_buf);
sewardja06e5562004-07-14 13:18:05 +00005040 }
5041
5042 /* Round up the relevant primops. */
5043
5044 if (sz == 4) {
5045 tmpL = newTemp(Ity_I64);
5046 tmpRes = newTemp(Ity_I32);
5047 tmpSubSh = newTemp(Ity_I32);
sewardje539a402004-07-14 18:24:17 +00005048 mkpair = Iop_32HLto64;
sewardj8c7f1ab2004-07-29 20:31:09 +00005049 getres = left_shift ? Iop_64HIto32 : Iop_64to32;
sewardje539a402004-07-14 18:24:17 +00005050 shift = left_shift ? Iop_Shl64 : Iop_Shr64;
5051 mask = mkU8(31);
sewardja06e5562004-07-14 13:18:05 +00005052 } else {
5053 /* sz == 2 */
sewardj8c7f1ab2004-07-29 20:31:09 +00005054 tmpL = newTemp(Ity_I32);
5055 tmpRes = newTemp(Ity_I16);
5056 tmpSubSh = newTemp(Ity_I16);
5057 mkpair = Iop_16HLto32;
5058 getres = left_shift ? Iop_32HIto16 : Iop_32to16;
5059 shift = left_shift ? Iop_Shl32 : Iop_Shr32;
5060 mask = mkU8(15);
sewardja06e5562004-07-14 13:18:05 +00005061 }
5062
5063 /* Do the shift, calculate the subshift value, and set
5064 the flag thunk. */
5065
sewardj8c7f1ab2004-07-29 20:31:09 +00005066 assign( tmpSH, binop(Iop_And8, shift_amt, mask) );
5067
sewardja06e5562004-07-14 13:18:05 +00005068 if (left_shift)
5069 assign( tmpL, binop(mkpair, mkexpr(esrc), mkexpr(gsrc)) );
5070 else
5071 assign( tmpL, binop(mkpair, mkexpr(gsrc), mkexpr(esrc)) );
5072
5073 assign( tmpRes, unop(getres, binop(shift, mkexpr(tmpL), mkexpr(tmpSH)) ) );
5074 assign( tmpSubSh,
5075 unop(getres,
5076 binop(shift,
5077 mkexpr(tmpL),
5078 binop(Iop_And8,
5079 binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
5080 mask))) );
sewardja06e5562004-07-14 13:18:05 +00005081
sewardj2a2ba8b2004-11-08 13:14:06 +00005082 setFlags_DEP1_DEP2_shift ( left_shift ? Iop_Shl32 : Iop_Sar32,
5083 tmpRes, tmpSubSh, ty, tmpSH );
sewardja06e5562004-07-14 13:18:05 +00005084
5085 /* Put result back. */
5086
5087 if (epartIsReg(modrm)) {
5088 putIReg(sz, eregOfRM(modrm), mkexpr(tmpRes));
5089 } else {
5090 storeLE( mkexpr(addr), mkexpr(tmpRes) );
5091 }
5092
5093 if (amt_is_literal) delta++;
5094 return delta;
5095}
5096
5097
sewardj1c6f9912004-09-07 10:15:24 +00005098/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
5099 required. */
5100
5101typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
5102
5103static Char* nameBtOp ( BtOp op )
5104{
5105 switch (op) {
5106 case BtOpNone: return "";
5107 case BtOpSet: return "s";
5108 case BtOpReset: return "r";
5109 case BtOpComp: return "c";
5110 default: vpanic("nameBtOp(x86)");
5111 }
5112}
5113
5114
5115static
5116UInt dis_bt_G_E ( UChar sorb, Int sz, UInt delta, BtOp op )
5117{
5118 Char dis_buf[50];
5119 UChar modrm;
5120 Int len;
5121 IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
5122 t_addr1, t_esp, t_mask;
5123
5124 vassert(sz == 2 || sz == 4);
5125
5126 t_fetched = t_bitno0 = t_bitno1 = t_bitno2
sewardj92d168d2004-11-15 14:22:12 +00005127 = t_addr0 = t_addr1 = t_esp = t_mask = IRTemp_INVALID;
sewardj1c6f9912004-09-07 10:15:24 +00005128
5129 t_fetched = newTemp(Ity_I8);
5130 t_bitno0 = newTemp(Ity_I32);
5131 t_bitno1 = newTemp(Ity_I32);
5132 t_bitno2 = newTemp(Ity_I8);
5133 t_addr1 = newTemp(Ity_I32);
5134 modrm = getIByte(delta);
5135
5136 assign( t_bitno0, widenUto32(getIReg(sz, gregOfRM(modrm))) );
5137
5138 if (epartIsReg(modrm)) {
sewardj1c6f9912004-09-07 10:15:24 +00005139 delta++;
5140 /* Get it onto the client's stack. */
5141 t_esp = newTemp(Ity_I32);
5142 t_addr0 = newTemp(Ity_I32);
5143
5144 assign( t_esp, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
5145 putIReg(4, R_ESP, mkexpr(t_esp));
5146
5147 storeLE( mkexpr(t_esp), getIReg(sz, eregOfRM(modrm)) );
5148
5149 /* Make t_addr0 point at it. */
5150 assign( t_addr0, mkexpr(t_esp) );
5151
5152 /* Mask out upper bits of the shift amount, since we're doing a
5153 reg. */
5154 assign( t_bitno1, binop(Iop_And32,
5155 mkexpr(t_bitno0),
5156 mkU32(sz == 4 ? 31 : 15)) );
5157
5158 } else {
5159 t_addr0 = disAMode ( &len, sorb, delta, dis_buf );
5160 delta += len;
5161 assign( t_bitno1, mkexpr(t_bitno0) );
5162 }
5163
5164 /* At this point: t_addr0 is the address being operated on. If it
5165 was a reg, we will have pushed it onto the client's stack.
5166 t_bitno1 is the bit number, suitably masked in the case of a
5167 reg. */
5168
5169 /* Now the main sequence. */
5170 assign( t_addr1,
5171 binop(Iop_Add32,
5172 mkexpr(t_addr0),
5173 binop(Iop_Sar32, mkexpr(t_bitno1), mkU8(3))) );
5174
5175 /* t_addr1 now holds effective address */
5176
5177 assign( t_bitno2,
5178 unop(Iop_32to8,
5179 binop(Iop_And32, mkexpr(t_bitno1), mkU32(7))) );
5180
5181 /* t_bitno2 contains offset of bit within byte */
5182
5183 if (op != BtOpNone) {
5184 t_mask = newTemp(Ity_I8);
5185 assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
5186 }
sewardj4963a422004-10-14 23:34:03 +00005187
sewardj1c6f9912004-09-07 10:15:24 +00005188 /* t_mask is now a suitable byte mask */
5189
5190 assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
5191
5192 if (op != BtOpNone) {
5193 switch (op) {
5194 case BtOpSet:
5195 storeLE( mkexpr(t_addr1),
5196 binop(Iop_Or8, mkexpr(t_fetched),
5197 mkexpr(t_mask)) );
5198 break;
5199 case BtOpComp:
5200 storeLE( mkexpr(t_addr1),
5201 binop(Iop_Xor8, mkexpr(t_fetched),
5202 mkexpr(t_mask)) );
5203 break;
5204 case BtOpReset:
5205 storeLE( mkexpr(t_addr1),
5206 binop(Iop_And8, mkexpr(t_fetched),
5207 unop(Iop_Not8, mkexpr(t_mask))) );
5208 break;
5209 default:
5210 vpanic("dis_bt_G_E(x86)");
5211 }
5212 }
5213
5214 /* Side effect done; now get selected bit into Carry flag */
sewardj2a2ba8b2004-11-08 13:14:06 +00005215 /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
5216 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
5217 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardj1c6f9912004-09-07 10:15:24 +00005218 stmt( IRStmt_Put(
sewardj2a2ba8b2004-11-08 13:14:06 +00005219 OFFB_CC_DEP1,
sewardj1c6f9912004-09-07 10:15:24 +00005220 binop(Iop_And32,
5221 binop(Iop_Shr32,
5222 unop(Iop_8Uto32, mkexpr(t_fetched)),
sewardj5bd4d162004-11-10 13:02:48 +00005223 mkexpr(t_bitno2)),
5224 mkU32(1)))
sewardj1c6f9912004-09-07 10:15:24 +00005225 );
5226
5227 /* Move reg operand from stack back to reg */
5228 if (epartIsReg(modrm)) {
5229 /* t_esp still points at it. */
sewardj4963a422004-10-14 23:34:03 +00005230 putIReg(sz, eregOfRM(modrm), loadLE(szToITy(sz), mkexpr(t_esp)) );
sewardj1c6f9912004-09-07 10:15:24 +00005231 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t_esp), mkU32(sz)) );
5232 }
5233
5234 DIP("bt%s%c %s, %s\n",
5235 nameBtOp(op), nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
5236 ( epartIsReg(modrm) ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ) );
5237
5238 return delta;
5239}
sewardjce646f22004-08-31 23:55:54 +00005240
5241
5242
5243/* Handle BSF/BSR. Only v-size seems necessary. */
5244static
5245UInt dis_bs_E_G ( UChar sorb, Int sz, UInt delta, Bool fwds )
5246{
5247 Bool isReg;
5248 UChar modrm;
5249 Char dis_buf[50];
5250
5251 IRType ty = szToITy(sz);
5252 IRTemp src = newTemp(ty);
5253 IRTemp dst = newTemp(ty);
5254
5255 IRTemp src32 = newTemp(Ity_I32);
5256 IRTemp dst32 = newTemp(Ity_I32);
5257 IRTemp src8 = newTemp(Ity_I8);
5258
5259 vassert(sz == 4 || sz == 2);
sewardjce646f22004-08-31 23:55:54 +00005260
5261 modrm = getIByte(delta);
5262
5263 isReg = epartIsReg(modrm);
5264 if (isReg) {
5265 delta++;
5266 assign( src, getIReg(sz, eregOfRM(modrm)) );
5267 } else {
5268 Int len;
5269 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
5270 delta += len;
5271 assign( src, loadLE(ty, mkexpr(addr)) );
5272 }
5273
5274 DIP("bs%c%c %s, %s\n",
5275 fwds ? 'f' : 'r', nameISize(sz),
5276 ( isReg ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ),
5277 nameIReg(sz, gregOfRM(modrm)));
5278
5279 /* Generate an 8-bit expression which is zero iff the
5280 original is zero, and nonzero otherwise */
5281 assign( src8,
5282 unop(Iop_1Uto8, binop(mkSizedOp(ty,Iop_CmpNE8),
5283 mkexpr(src), mkU(ty,0))) );
5284
5285 /* Flags: Z is 1 iff source value is zero. All others
5286 are undefined -- we force them to zero. */
sewardj2a2ba8b2004-11-08 13:14:06 +00005287 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
5288 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
sewardjce646f22004-08-31 23:55:54 +00005289 stmt( IRStmt_Put(
sewardj2a2ba8b2004-11-08 13:14:06 +00005290 OFFB_CC_DEP1,
sewardjce646f22004-08-31 23:55:54 +00005291 IRExpr_Mux0X( mkexpr(src8),
5292 /* src==0 */
5293 mkU32(CC_MASK_Z),
5294 /* src!=0 */
5295 mkU32(0)
5296 )
5297 ));
5298
5299 /* Result: iff source value is zero, we can't use
5300 Iop_Clz32/Iop_Ctz32 as they have no defined result in that case.
5301 But anyway, Intel x86 semantics say the result is undefined in
5302 such situations. Hence handle the zero case specially. */
5303
5304 /* Bleh. What we compute:
5305
5306 bsf32: if src == 0 then 0 else Ctz32(src)
5307 bsr32: if src == 0 then 0 else 31 - Clz32(src)
5308
5309 bsf16: if src == 0 then 0 else Ctz32(16Uto32(src))
5310 bsr16: if src == 0 then 0 else 31 - Clz32(16Uto32(src))
5311
5312 First, widen src to 32 bits if it is not already.
sewardj37158712004-10-15 21:23:12 +00005313
5314 Postscript 15 Oct 04: it seems that at least VIA Nehemiah leaves the
5315 dst register unchanged when src == 0. Hence change accordingly.
sewardjce646f22004-08-31 23:55:54 +00005316 */
5317 if (sz == 2)
5318 assign( src32, unop(Iop_16Uto32, mkexpr(src)) );
5319 else
5320 assign( src32, mkexpr(src) );
5321
5322 /* The main computation, guarding against zero. */
5323 assign( dst32,
5324 IRExpr_Mux0X(
5325 mkexpr(src8),
sewardj37158712004-10-15 21:23:12 +00005326 /* src == 0 -- leave dst unchanged */
5327 widenUto32( getIReg( sz, gregOfRM(modrm) ) ),
sewardjce646f22004-08-31 23:55:54 +00005328 /* src != 0 */
5329 fwds ? unop(Iop_Ctz32, mkexpr(src32))
5330 : binop(Iop_Sub32,
5331 mkU32(31),
5332 unop(Iop_Clz32, mkexpr(src32)))
5333 )
5334 );
5335
5336 if (sz == 2)
5337 assign( dst, unop(Iop_32to16, mkexpr(dst32)) );
5338 else
5339 assign( dst, mkexpr(dst32) );
5340
5341 /* dump result back */
5342 putIReg( sz, gregOfRM(modrm), mkexpr(dst) );
5343
5344 return delta;
5345}
sewardj64e1d652004-07-12 14:00:46 +00005346
5347
5348static
5349void codegen_xchg_eAX_Reg ( Int sz, Int reg )
5350{
5351 IRType ty = szToITy(sz);
5352 IRTemp t1 = newTemp(ty);
5353 IRTemp t2 = newTemp(ty);
5354 vassert(sz == 2 || sz == 4);
5355 assign( t1, getIReg(sz, R_EAX) );
5356 assign( t2, getIReg(sz, reg) );
5357 putIReg( sz, R_EAX, mkexpr(t2) );
5358 putIReg( sz, reg, mkexpr(t1) );
5359 DIP("xchg%c %s, %s\n",
5360 nameISize(sz), nameIReg(sz, R_EAX), nameIReg(sz, reg));
5361}
5362
5363
sewardjbdc7d212004-09-09 02:46:40 +00005364static
5365void codegen_SAHF ( void )
5366{
5367 /* Set the flags to:
5368 (calculate_flags_all() & CC_MASK_O) -- retain the old O flag
5369 | (%AH & (CC_MASK_S|CC_MASK_Z|CC_MASK_A|CC_MASK_P|CC_MASK_C)
5370 */
sewardj2a2ba8b2004-11-08 13:14:06 +00005371 UInt mask_SZACP = CC_MASK_S|CC_MASK_Z|CC_MASK_A|CC_MASK_C|CC_MASK_P;
sewardjbdc7d212004-09-09 02:46:40 +00005372 IRTemp oldflags = newTemp(Ity_I32);
5373 assign( oldflags, mk_calculate_eflags_all() );
sewardj2a2ba8b2004-11-08 13:14:06 +00005374 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
5375 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
5376 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardjbdc7d212004-09-09 02:46:40 +00005377 binop(Iop_Or32,
5378 binop(Iop_And32, mkexpr(oldflags), mkU32(CC_MASK_O)),
5379 binop(Iop_And32,
5380 binop(Iop_Shr32, getIReg(4, R_EAX), mkU8(8)),
5381 mkU32(mask_SZACP))
5382 )
5383 ));
5384}
5385
5386
sewardjc9a65702004-07-07 16:32:57 +00005387//-- static
5388//-- void codegen_LAHF ( UCodeBlock* cb )
5389//-- {
5390//-- Int t = newTemp(cb);
5391//--
5392//-- /* Pushed arg is ignored, it just provides somewhere to put the
5393//-- return value. */
5394//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t);
5395//-- uInstr0(cb, CALLM_S, 0);
5396//-- uInstr1(cb, PUSH, 4, TempReg, t);
5397//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_LAHF));
5398//-- uFlagsRWU(cb, FlagsSZACP, FlagsEmpty, FlagsEmpty);
5399//-- uInstr1(cb, POP, 4, TempReg, t);
5400//-- uInstr0(cb, CALLM_E, 0);
5401//--
5402//-- /* At this point, the %ah sub-register in %eax has been updated,
5403//-- the rest is the same, so do a PUT of the whole thing. */
5404//-- uInstr2(cb, PUT, 4, TempReg, t, ArchReg, R_EAX);
5405//-- }
5406//--
sewardj458a6f82004-08-25 12:46:02 +00005407
5408static
5409UInt dis_cmpxchg_G_E ( UChar sorb,
5410 Int size,
5411 UInt delta0 )
5412{
5413 UChar dis_buf[50];
5414 Int len;
5415
5416 IRType ty = szToITy(size);
5417 IRTemp acc = newTemp(ty);
5418 IRTemp src = newTemp(ty);
sewardj2a2ba8b2004-11-08 13:14:06 +00005419 //IRTemp res = newTemp(ty);
sewardj458a6f82004-08-25 12:46:02 +00005420 IRTemp dest = newTemp(ty);
5421 IRTemp dest2 = newTemp(ty);
5422 IRTemp acc2 = newTemp(ty);
5423 IRTemp cond8 = newTemp(Ity_I8);
sewardj92d168d2004-11-15 14:22:12 +00005424 IRTemp addr = IRTemp_INVALID;
sewardj458a6f82004-08-25 12:46:02 +00005425 UChar rm = getUChar(delta0);
5426
5427 if (epartIsReg(rm)) {
5428 assign( dest, getIReg(size, eregOfRM(rm)) );
5429 delta0++;
5430 DIP("cmpxchg%c %s,%s\n", nameISize(size),
5431 nameIReg(size,gregOfRM(rm)),
5432 nameIReg(size,eregOfRM(rm)) );
sewardj458a6f82004-08-25 12:46:02 +00005433 } else {
5434 addr = disAMode ( &len, sorb, delta0, dis_buf );
5435 assign( dest, loadLE(ty, mkexpr(addr)) );
5436 delta0 += len;
5437 DIP("cmpxchg%c %s,%s\n", nameISize(size),
5438 nameIReg(size,gregOfRM(rm)), dis_buf);
5439 }
5440
5441 assign( src, getIReg(size, gregOfRM(rm)) );
5442 assign( acc, getIReg(size, R_EAX) );
sewardj2a2ba8b2004-11-08 13:14:06 +00005443 //assign( res, binop( mkSizedOp(ty,Iop_Sub8), mkexpr(acc), mkexpr(dest) ));
5444 setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
sewardj8ea867b2004-10-30 19:03:02 +00005445 assign( cond8, unop(Iop_1Uto8, mk_calculate_condition(CondZ)) );
sewardj458a6f82004-08-25 12:46:02 +00005446 assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
5447 assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
5448 putIReg(size, R_EAX, mkexpr(acc2));
5449
5450 if (epartIsReg(rm)) {
5451 putIReg(size, eregOfRM(rm), mkexpr(dest2));
5452 } else {
5453 storeLE( mkexpr(addr), mkexpr(dest2) );
5454 }
5455
5456 return delta0;
5457}
5458
5459
sewardjc9a65702004-07-07 16:32:57 +00005460//-- static
5461//-- Addr dis_cmpxchg8b ( UCodeBlock* cb,
5462//-- UChar sorb,
5463//-- Addr eip0 )
5464//-- {
5465//-- Int tal, tah, junkl, junkh, destl, desth, srcl, srch, accl, acch;
5466//-- UChar dis_buf[50];
5467//-- UChar rm;
5468//-- UInt pair;
5469//--
5470//-- rm = getUChar(eip0);
5471//-- accl = newTemp(cb);
5472//-- acch = newTemp(cb);
5473//-- srcl = newTemp(cb);
5474//-- srch = newTemp(cb);
5475//-- destl = newTemp(cb);
5476//-- desth = newTemp(cb);
5477//-- junkl = newTemp(cb);
5478//-- junkh = newTemp(cb);
5479//--
5480//-- vg_assert(!epartIsReg(rm));
5481//--
5482//-- pair = disAMode ( cb, sorb, eip0, dis_buf );
5483//-- tal = LOW24(pair);
5484//-- tah = newTemp(cb);
5485//-- uInstr2(cb, MOV, 4, TempReg, tal, TempReg, tah);
5486//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, tah);
5487//-- uLiteral(cb, 4);
5488//-- eip0 += HI8(pair);
5489//-- DIP("cmpxchg8b %s\n", dis_buf);
5490//--
5491//-- uInstr0(cb, CALLM_S, 0);
5492//--
5493//-- uInstr2(cb, LOAD, 4, TempReg, tah, TempReg, desth);
5494//-- uInstr1(cb, PUSH, 4, TempReg, desth);
5495//-- uInstr2(cb, LOAD, 4, TempReg, tal, TempReg, destl);
5496//-- uInstr1(cb, PUSH, 4, TempReg, destl);
5497//-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, srch);
5498//-- uInstr1(cb, PUSH, 4, TempReg, srch);
5499//-- uInstr2(cb, GET, 4, ArchReg, R_EBX, TempReg, srcl);
5500//-- uInstr1(cb, PUSH, 4, TempReg, srcl);
5501//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, acch);
5502//-- uInstr1(cb, PUSH, 4, TempReg, acch);
5503//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, accl);
5504//-- uInstr1(cb, PUSH, 4, TempReg, accl);
5505//--
5506//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_cmpxchg8b));
5507//-- uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsEmpty);
5508//--
5509//-- uInstr1(cb, POP, 4, TempReg, accl);
5510//-- uInstr2(cb, PUT, 4, TempReg, accl, ArchReg, R_EAX);
5511//-- uInstr1(cb, POP, 4, TempReg, acch);
5512//-- uInstr2(cb, PUT, 4, TempReg, acch, ArchReg, R_EDX);
5513//-- uInstr1(cb, POP, 4, TempReg, srcl);
5514//-- uInstr2(cb, PUT, 4, TempReg, srcl, ArchReg, R_EBX);
5515//-- uInstr1(cb, POP, 4, TempReg, srch);
5516//-- uInstr2(cb, PUT, 4, TempReg, srch, ArchReg, R_ECX);
5517//-- uInstr1(cb, POP, 4, TempReg, destl);
5518//-- uInstr2(cb, STORE, 4, TempReg, destl, TempReg, tal);
5519//-- uInstr1(cb, POP, 4, TempReg, desth);
5520//-- uInstr2(cb, STORE, 4, TempReg, desth, TempReg, tah);
5521//--
5522//-- uInstr0(cb, CALLM_E, 0);
5523//--
5524//-- return eip0;
5525//-- }
sewardj458a6f82004-08-25 12:46:02 +00005526
5527
5528/* Handle conditional move instructions of the form
5529 cmovcc E(reg-or-mem), G(reg)
5530
5531 E(src) is reg-or-mem
5532 G(dst) is reg.
5533
5534 If E is reg, --> GET %E, tmps
5535 GET %G, tmpd
5536 CMOVcc tmps, tmpd
5537 PUT tmpd, %G
5538
5539 If E is mem --> (getAddr E) -> tmpa
5540 LD (tmpa), tmps
5541 GET %G, tmpd
5542 CMOVcc tmps, tmpd
5543 PUT tmpd, %G
5544*/
5545static
5546UInt dis_cmov_E_G ( UChar sorb,
5547 Int sz,
5548 Condcode cond,
5549 UInt delta0 )
5550{
5551 UChar rm = getIByte(delta0);
5552 UChar dis_buf[50];
5553 Int len;
5554
sewardj883b00b2004-09-11 09:30:24 +00005555 IRType ty = szToITy(sz);
sewardj458a6f82004-08-25 12:46:02 +00005556 IRTemp tmps = newTemp(ty);
5557 IRTemp tmpd = newTemp(ty);
5558
5559 if (epartIsReg(rm)) {
5560 assign( tmps, getIReg(sz, eregOfRM(rm)) );
5561 assign( tmpd, getIReg(sz, gregOfRM(rm)) );
5562
5563 putIReg(sz, gregOfRM(rm),
sewardj8ea867b2004-10-30 19:03:02 +00005564 IRExpr_Mux0X( unop(Iop_1Uto8,mk_calculate_condition(cond)),
sewardj458a6f82004-08-25 12:46:02 +00005565 mkexpr(tmpd),
5566 mkexpr(tmps) )
5567 );
5568 DIP("cmov%c%s %s,%s\n", nameISize(sz),
5569 name_Condcode(cond),
5570 nameIReg(sz,eregOfRM(rm)),
5571 nameIReg(sz,gregOfRM(rm)));
5572 return 1+delta0;
5573 }
5574
5575 /* E refers to memory */
5576 {
5577 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
5578 assign( tmps, loadLE(ty, mkexpr(addr)) );
5579 assign( tmpd, getIReg(sz, gregOfRM(rm)) );
5580
5581 putIReg(sz, gregOfRM(rm),
sewardj8ea867b2004-10-30 19:03:02 +00005582 IRExpr_Mux0X( unop(Iop_1Uto8,mk_calculate_condition(cond)),
sewardj458a6f82004-08-25 12:46:02 +00005583 mkexpr(tmpd),
5584 mkexpr(tmps) )
5585 );
5586
5587 DIP("cmov%c%s %s,%s\n", nameISize(sz),
5588 name_Condcode(cond),
5589 dis_buf,
5590 nameIReg(sz,gregOfRM(rm)));
5591 return len+delta0;
5592 }
5593}
5594
5595
sewardj883b00b2004-09-11 09:30:24 +00005596static
5597UInt dis_xadd_G_E ( UChar sorb, Int sz, UInt delta0 )
5598{
5599 Int len;
5600 UChar rm = getIByte(delta0);
5601 UChar dis_buf[50];
5602
5603 // Int tmpd = newTemp(cb);
5604 //Int tmpt = newTemp(cb);
5605
5606 IRType ty = szToITy(sz);
5607 IRTemp tmpd = newTemp(ty);
5608 IRTemp tmpt0 = newTemp(ty);
5609 IRTemp tmpt1 = newTemp(ty);
5610
5611 if (epartIsReg(rm)) {
5612 vassert(0);
5613#if 0
5614 uInstr2(cb, GET, sz, ArchReg, eregOfRM(rm), TempReg, tmpd);
5615 uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
5616 uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
5617 setFlagsFromUOpcode(cb, ADD);
5618 uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
5619 uInstr2(cb, PUT, sz, TempReg, tmpt, ArchReg, eregOfRM(rm));
5620 DIP("xadd%c %s, %s\n",
5621 nameISize(sz), nameIReg(sz,gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
5622 return 1+eip0;
5623#endif
5624 } else {
5625 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
5626 assign( tmpd, loadLE(ty, mkexpr(addr)) );
5627 assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
sewardj883b00b2004-09-11 09:30:24 +00005628 assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8), mkexpr(tmpd), mkexpr(tmpt0)) );
sewardj2a2ba8b2004-11-08 13:14:06 +00005629 setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
sewardj883b00b2004-09-11 09:30:24 +00005630 storeLE( mkexpr(addr), mkexpr(tmpt1) );
5631 putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
5632 DIP("xadd%c %s, %s\n",
5633 nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
5634 return len+delta0;
5635 }
5636}
5637
sewardjc9a65702004-07-07 16:32:57 +00005638//-- /* Moves of Ew into a segment register.
5639//-- mov Ew, Sw meaning
5640//-- mov reg-or-mem, reg
5641//-- Is passed the a ptr to the modRM byte, and the data size. Returns
5642//-- the address advanced completely over this instruction.
5643//--
5644//-- Ew(src) is reg-or-mem
5645//-- Sw(dst) is seg reg.
5646//--
5647//-- If E is reg, --> GETw %Ew, tmpv
5648//-- PUTSEG tmpv, %Sw
5649//--
5650//-- If E is mem --> (getAddr E) -> tmpa
5651//-- LDw (tmpa), tmpb
5652//-- PUTSEG tmpb, %Sw
5653//-- */
5654//-- static
5655//-- Addr dis_mov_Ew_Sw ( UCodeBlock* cb,
5656//-- UChar sorb,
5657//-- Addr eip0 )
5658//-- {
5659//-- UChar rm = getUChar(eip0);
5660//-- UChar dis_buf[50];
5661//--
5662//-- if (epartIsReg(rm)) {
5663//-- Int tmpv = newTemp(cb);
5664//-- uInstr2(cb, GET, 2, ArchReg, eregOfRM(rm), TempReg, tmpv);
5665//-- uInstr2(cb, PUTSEG, 2, TempReg, tmpv, ArchRegS, gregOfRM(rm));
5666//-- DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
5667//-- return 1+eip0;
5668//-- }
5669//--
5670//-- /* E refers to memory */
5671//-- {
5672//-- UInt pair = disAMode ( cb, sorb, eip0, dis_buf );
5673//-- Int tmpa = LOW24(pair);
5674//-- Int tmpb = newTemp(cb);
5675//-- uInstr2(cb, LOAD, 2, TempReg, tmpa, TempReg, tmpb);
5676//-- uInstr2(cb, PUTSEG, 2, TempReg, tmpb, ArchRegS, gregOfRM(rm));
5677//-- DIP("movw %s,%s\n", dis_buf,nameSReg(gregOfRM(rm)));
5678//-- return HI8(pair)+eip0;
5679//-- }
5680//-- }
5681//--
5682//--
5683//-- /* Moves of a segment register to Ew.
5684//-- mov Sw, Ew meaning
5685//-- mov reg, reg-or-mem
5686//-- Is passed the a ptr to the modRM byte, and the data size. Returns
5687//-- the address advanced completely over this instruction.
5688//--
5689//-- Sw(src) is seg reg.
5690//-- Ew(dst) is reg-or-mem
5691//--
5692//-- If E is reg, --> GETSEG %Sw, tmp
5693//-- PUTW tmp, %Ew
5694//--
5695//-- If E is mem, --> (getAddr E) -> tmpa
5696//-- GETSEG %Sw, tmpv
5697//-- STW tmpv, (tmpa)
5698//-- */
sewardj063f02f2004-10-20 12:36:12 +00005699static
5700UInt dis_mov_Sw_Ew ( UChar sorb,
5701 Int sz,
5702 UInt delta0 )
5703{
5704 UChar rm = getIByte(delta0);
5705 //UChar dis_buf[50];
5706
5707 vassert(sz == 2 || sz == 4);
5708
5709 if (epartIsReg(rm)) {
5710 if (sz == 4)
5711 putIReg(4, eregOfRM(rm), unop(Iop_16Uto32, getSReg(gregOfRM(rm))));
5712 else
5713 putIReg(2, eregOfRM(rm), getSReg(gregOfRM(rm)));
5714
5715 DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
5716 return 1+delta0;
5717 }
5718
5719 vassert(0);
5720#if 0
5721 /* E refers to memory */
5722 {
5723 UInt pair = disAMode ( cb, sorb, eip0, dis_buf );
5724 Int tmpa = LOW24(pair);
5725 Int tmpv = newTemp(cb);
5726 uInstr2(cb, GETSEG, 2, ArchRegS, gregOfRM(rm), TempReg, tmpv);
5727 uInstr2(cb, STORE, 2, TempReg, tmpv, TempReg, tmpa);
5728 DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
5729 return HI8(pair)+eip0;
5730 }
5731#endif
5732}
5733
5734
5735
sewardjc9a65702004-07-07 16:32:57 +00005736//-- /* Simple MMX operations, either
5737//-- op (src)mmxreg, (dst)mmxreg
5738//-- or
5739//-- op (src)address, (dst)mmxreg
5740//-- opc is the byte following the 0x0F prefix.
5741//-- */
5742//-- static
5743//-- Addr dis_MMXop_regmem_to_reg ( UCodeBlock* cb,
5744//-- UChar sorb,
5745//-- Addr eip,
5746//-- UChar opc,
5747//-- Char* name,
5748//-- Bool show_granularity )
5749//-- {
5750//-- Char dis_buf[50];
5751//-- UChar modrm = getUChar(eip);
5752//-- Bool isReg = epartIsReg(modrm);
5753//--
5754//-- if (isReg) {
5755//-- eip++;
5756//-- uInstr1(cb, MMX2, 0,
5757//-- Lit16,
5758//-- (((UShort)(opc)) << 8) | ((UShort)modrm) );
5759//-- } else {
5760//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
5761//-- Int tmpa = LOW24(pair);
5762//-- eip += HI8(pair);
5763//-- uInstr2(cb, MMX2_MemRd, 8,
5764//-- Lit16,
5765//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
5766//-- TempReg, tmpa);
5767//-- }
5768//--
5769//-- DIP("%s%s %s, %s\n",
5770//-- name, show_granularity ? nameMMXGran(opc & 3) : (Char*)"",
5771//-- ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
5772//-- nameMMXReg(gregOfRM(modrm)) );
5773//--
5774//-- return eip;
5775//-- }
5776//--
5777//--
5778//-- /* Simple MMX operations, either
5779//-- op (src)mmxreg, (dst)mmxreg
5780//-- or
5781//-- op (src)address, (dst)mmxreg
5782//-- opc is the byte following the 0x0F prefix.
5783//-- */
5784//-- static
5785//-- Addr dis_MMXop_regmem_to_reg_Imm8 ( UCodeBlock* cb,
5786//-- UChar sorb,
5787//-- Addr eip,
5788//-- UChar opc,
5789//-- Char* name,
5790//-- Bool show_granularity )
5791//-- {
5792//-- Char dis_buf[50];
5793//-- UChar modrm = getUChar(eip);
5794//-- UChar imm8;
5795//-- Bool isReg = epartIsReg(modrm);
5796//--
5797//-- if (isReg) {
5798//-- eip++;
5799//-- imm8 = getUChar(eip);
5800//-- eip++;
5801//-- uInstr2(cb, MMX3, 0,
5802//-- Lit16,
5803//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
5804//-- Lit16,
5805//-- ((UShort)imm8));
5806//-- } else {
5807//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
5808//-- Int tmpa = LOW24(pair);
5809//-- eip += HI8(pair);
5810//-- imm8 = getUChar(eip);
5811//-- eip++;
5812//-- uInstr3(cb, MMX2a1_MemRd, 8,
5813//-- Lit16,
5814//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
5815//-- Lit16,
5816//-- ((UShort)imm8),
5817//-- TempReg, tmpa);
5818//-- }
5819//--
5820//-- DIP("%s%s %s, %s, $%d\n",
5821//-- name, show_granularity ? nameMMXGran(opc & 3) : (Char*)"",
5822//-- ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
5823//-- nameMMXReg(gregOfRM(modrm)), (Int)imm8 );
5824//--
5825//-- return eip;
5826//-- }
5827//--
5828//--
5829//--
5830//-- /* Simple SSE operations, either
5831//-- op (src)xmmreg, (dst)xmmreg
5832//-- or
5833//-- op (src)address, (dst)xmmreg
5834//-- 3 opcode bytes.
5835//-- Supplied eip points to the first address mode byte.
5836//-- */
5837//-- static
5838//-- Addr dis_SSE3_reg_or_mem ( UCodeBlock* cb,
5839//-- UChar sorb,
sewardj5bd4d162004-11-10 13:02:48 +00005840//-- Addr eip,
5841//-- Int sz,
sewardjc9a65702004-07-07 16:32:57 +00005842//-- Char* name,
5843//-- UChar opc1,
5844//-- UChar opc2,
5845//-- UChar opc3 )
5846//-- {
5847//-- Char dis_buf[50];
5848//-- UChar modrm = getUChar(eip);
5849//-- Bool isReg = epartIsReg(modrm);
5850//--
5851//-- if (isReg) {
5852//-- /* Completely internal SSE insn. */
5853//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
5854//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
5855//-- Lit16, (((UShort)opc3) << 8) | (UShort)modrm );
5856//-- eip++;
5857//-- } else {
5858//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
5859//-- Int tmpa = LOW24(pair);
5860//-- eip += HI8(pair);
5861//-- uInstr3(cb, SSE3a_MemRd, sz,
5862//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
5863//-- Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
5864//-- TempReg, tmpa);
5865//-- }
5866//--
5867//-- DIP("%s %s, %s\n",
5868//-- name,
5869//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
5870//-- nameXMMReg(gregOfRM(modrm)) );
5871//--
5872//-- return eip;
5873//-- }
5874//--
5875//--
5876//-- /* Simple SSE operations, either
5877//-- op (src)xmmreg, (dst)xmmreg
5878//-- or
5879//-- op (src)address, (dst)xmmreg
5880//-- 2 opcode bytes.
5881//-- Supplied eip points to the first address mode byte.
5882//-- */
5883//-- static
5884//-- Addr dis_SSE2_reg_or_mem ( UCodeBlock* cb,
5885//-- UChar sorb,
5886//-- Addr eip,
5887//-- Int sz,
5888//-- Char* name,
5889//-- UChar opc1,
5890//-- UChar opc2 )
5891//-- {
5892//-- Char dis_buf[50];
5893//-- UChar modrm = getUChar(eip);
5894//-- Bool isReg = epartIsReg(modrm);
5895//--
5896//-- if (isReg) {
5897//-- /* Completely internal SSE insn. */
5898//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
5899//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
5900//-- Lit16, (UShort)modrm );
5901//-- eip++;
5902//-- } else {
5903//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
5904//-- Int tmpa = LOW24(pair);
5905//-- eip += HI8(pair);
5906//-- uInstr3(cb, SSE2a_MemRd, sz,
5907//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
5908//-- Lit16, (UShort)modrm,
5909//-- TempReg, tmpa);
5910//-- }
5911//-- DIP("%s %s, %s\n",
5912//-- name,
5913//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
5914//-- nameXMMReg(gregOfRM(modrm)) );
5915//--
5916//-- return eip;
5917//-- }
5918//--
5919//--
5920//-- /* Simple SSE operations, either
5921//-- op (src)xmmreg, (dst)xmmreg
5922//-- or
5923//-- op (src)address, (dst)xmmreg
5924//-- 2 opcode bytes and an 8-bit immediate after the amode.
5925//-- Supplied eip points to the first address mode byte.
5926//-- */
5927//-- static
5928//-- Addr dis_SSE2_reg_or_mem_Imm8 ( UCodeBlock* cb,
5929//-- UChar sorb,
sewardj5bd4d162004-11-10 13:02:48 +00005930//-- Addr eip,
sewardjc9a65702004-07-07 16:32:57 +00005931//-- Int sz,
5932//-- Char* name,
sewardj5bd4d162004-11-10 13:02:48 +00005933//-- UChar opc1,
5934//-- UChar opc2 )
sewardjc9a65702004-07-07 16:32:57 +00005935//-- {
5936//-- Char dis_buf[50];
5937//-- UChar modrm = getUChar(eip);
5938//-- UChar imm8;
5939//-- Bool isReg = epartIsReg(modrm);
5940//--
5941//-- if (isReg) {
5942//-- /* Completely internal SSE insn. */
5943//-- eip++;
5944//-- imm8 = getUChar(eip);
5945//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
5946//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
5947//-- Lit16, (((UShort)modrm) << 8) | (UShort)imm8 );
5948//-- eip++;
5949//-- } else {
5950//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
5951//-- Int tmpa = LOW24(pair);
5952//-- eip += HI8(pair);
5953//-- imm8 = getUChar(eip);
5954//-- eip++;
5955//-- uInstr3(cb, SSE2a1_MemRd, sz,
5956//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
5957//-- Lit16, (((UShort)(modrm)) << 8) | ((UShort)imm8),
5958//-- TempReg, tmpa);
5959//-- }
5960//-- DIP("%s %s, %s, $%d\n",
5961//-- name, ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
5962//-- nameXMMReg(gregOfRM(modrm)), (Int)imm8 );
5963//-- return eip;
5964//-- }
5965//--
5966//--
5967//-- /* Simple SSE operations, either
5968//-- op (src)xmmreg, (dst)xmmreg
5969//-- or
5970//-- op (src)address, (dst)xmmreg
5971//-- 3 opcode bytes and an 8-bit immediate after the amode.
5972//-- Supplied eip points to the first address mode byte.
5973//-- */
5974//-- static
5975//-- Addr dis_SSE3_reg_or_mem_Imm8 ( UCodeBlock* cb,
5976//-- UChar sorb,
sewardj5bd4d162004-11-10 13:02:48 +00005977//-- Addr eip,
sewardjc9a65702004-07-07 16:32:57 +00005978//-- Int sz,
5979//-- Char* name,
sewardj5bd4d162004-11-10 13:02:48 +00005980//-- UChar opc1,
5981//-- UChar opc2,
sewardjc9a65702004-07-07 16:32:57 +00005982//-- UChar opc3 )
5983//-- {
5984//-- Char dis_buf[50];
5985//-- UChar modrm = getUChar(eip);
5986//-- UChar imm8;
5987//-- Bool isReg = epartIsReg(modrm);
5988//--
5989//-- if (isReg) {
5990//-- /* Completely internal SSE insn. */
5991//-- eip++;
5992//-- imm8 = getUChar(eip);
5993//-- uInstr3(cb, SSE5, 0, /* ignore sz for internal ops */
5994//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
5995//-- Lit16, (((UShort)opc3) << 8) | (UShort)modrm,
5996//-- Lit16, (UShort)imm8 );
5997//-- eip++;
5998//-- } else {
5999//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
6000//-- Int tmpa = LOW24(pair);
6001//-- eip += HI8(pair);
6002//-- imm8 = getUChar(eip);
6003//-- eip++;
6004//-- uInstr3(cb, SSE3a1_MemRd, sz,
6005//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
6006//-- Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
6007//-- TempReg, tmpa);
6008//-- uLiteral(cb, imm8);
6009//-- }
6010//-- DIP("%s %s, %s, $%d\n",
6011//-- name, ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
6012//-- nameXMMReg(gregOfRM(modrm)), (Int)imm8 );
6013//-- return eip;
6014//-- }
6015//--
6016//--
6017//-- /* Disassemble an SSE insn which is either a simple reg-reg move or a
6018//-- move between registers and memory. Supplied eip points to the
6019//-- first address mode byte.
6020//-- */
6021//-- static
6022//-- Addr dis_SSE3_load_store_or_mov ( UCodeBlock* cb,
6023//-- UChar sorb,
6024//-- Addr eip,
6025//-- Int sz,
sewardj5bd4d162004-11-10 13:02:48 +00006026//-- Bool is_store,
sewardjc9a65702004-07-07 16:32:57 +00006027//-- Char* name,
6028//-- UChar insn0,
6029//-- UChar insn1,
6030//-- UChar insn2 )
6031//-- {
6032//-- Char dis_buf[50];
6033//-- UChar modrm = getUChar(eip);
6034//-- Bool isReg = epartIsReg(modrm);
6035//-- UInt pair;
6036//-- Int t1;
6037//--
6038//-- if (isReg) {
6039//-- /* Completely internal; we can issue SSE4. */
6040//-- eip++;
6041//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
6042//-- Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
6043//-- Lit16, (((UShort)insn2) << 8) | (UShort)modrm );
6044//-- } else {
6045//-- pair = disAMode ( cb, sorb, eip, dis_buf );
6046//-- t1 = LOW24(pair);
6047//-- eip += HI8(pair);
6048//-- uInstr3(cb, is_store ? SSE3a_MemWr : SSE3a_MemRd, sz,
6049//-- Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
6050//-- Lit16, (((UShort)insn2) << 8) | (UShort)modrm,
6051//-- TempReg, t1 );
6052//-- }
6053//--
6054//-- if (is_store) {
6055//-- DIP("%s %s, %s\n",
6056//-- name,
6057//-- nameXMMReg(gregOfRM(modrm)),
6058//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ) );
6059//-- } else {
6060//-- DIP("%s %s, %s\n",
6061//-- name,
6062//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
6063//-- nameXMMReg(gregOfRM(modrm)) );
6064//-- }
6065//-- return eip;
6066//-- }
6067//--
6068//--
6069//-- /* Disassemble an SSE insn which is either a simple reg-reg move or a
6070//-- move between registers and memory. Supplied eip points to the
6071//-- first address mode byte. */
6072//-- static
6073//-- Addr dis_SSE2_load_store_or_mov ( UCodeBlock* cb,
6074//-- UChar sorb,
6075//-- Addr eip,
6076//-- Int sz,
sewardj5bd4d162004-11-10 13:02:48 +00006077//-- Bool is_store,
sewardjc9a65702004-07-07 16:32:57 +00006078//-- Char* name,
6079//-- UChar insn0,
6080//-- UChar insn1 )
6081//-- {
6082//-- Char dis_buf[50];
6083//-- UChar modrm = getUChar(eip);
6084//-- Bool isReg = epartIsReg(modrm);
6085//-- UInt pair;
6086//-- Int t1;
6087//--
6088//-- if (isReg) {
6089//-- /* Completely internal; we can issue SSE3. */
6090//-- eip++;
6091//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
6092//-- Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
6093//-- Lit16, (UShort)modrm );
6094//-- } else {
6095//-- pair = disAMode ( cb, sorb, eip, dis_buf );
6096//-- t1 = LOW24(pair);
6097//-- eip += HI8(pair);
6098//-- uInstr3(cb, is_store ? SSE2a_MemWr : SSE2a_MemRd, sz,
6099//-- Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
6100//-- Lit16, (UShort)modrm,
6101//-- TempReg, t1 );
6102//-- }
6103//--
6104//-- if (is_store) {
6105//-- DIP("%s %s, %s\n",
6106//-- name,
6107//-- nameXMMReg(gregOfRM(modrm)),
6108//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ) );
6109//-- } else {
6110//-- DIP("%s %s, %s\n",
6111//-- name,
6112//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
6113//-- nameXMMReg(gregOfRM(modrm)) );
6114//-- }
6115//-- return eip;
6116//-- }
6117//--
6118//--
6119//-- /* Simple SSE operations, either
6120//-- op (src)xmmreg, (dst)mmxreg
6121//-- or
6122//-- op (src)address, (dst)mmxreg
6123//-- 2 opcode bytes.
6124//-- Supplied eip points to the first address mode byte.
6125//-- */
6126//-- static
6127//-- Addr dis_SSE2_to_MMX ( UCodeBlock *cb,
6128//-- UChar sorb,
6129//-- Addr eip,
6130//-- Int sz,
6131//-- Char* name,
6132//-- UChar opc1,
6133//-- UChar opc2 )
6134//-- {
6135//-- UChar dis_buf[50];
6136//-- UChar modrm = getUChar(eip);
6137//-- if (epartIsReg(modrm)) {
6138//-- /* Completely internal SSE insn. */
6139//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
6140//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
6141//-- Lit16, (UShort)modrm );
6142//-- DIP("%s %s, %s\n",
6143//-- name, nameXMMReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)) );
6144//-- eip++;
6145//-- } else {
6146//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
6147//-- Int tmpa = LOW24(pair);
6148//-- eip += HI8(pair);
6149//-- uInstr3(cb, SSE2a_MemRd, sz,
6150//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
6151//-- Lit16, ((UShort)modrm),
6152//-- TempReg, tmpa);
6153//-- DIP("%s %s, %s\n", name, dis_buf, nameMMXReg(gregOfRM(modrm)));
6154//-- }
6155//-- return eip;
6156//-- }
6157//--
6158//--
6159//-- /* Simple SSE operations, either
6160//-- op (src)mmxreg, (dst)xmmreg
6161//-- or
6162//-- op (src)address, (dst)xmmreg
6163//-- 2 opcode bytes.
6164//-- Supplied eip points to the first address mode byte.
6165//-- */
6166//-- static
6167//-- Addr dis_SSE2_from_MMX ( UCodeBlock *cb,
6168//-- UChar sorb,
6169//-- Addr eip,
6170//-- Int sz,
6171//-- Char* name,
6172//-- UChar opc1,
6173//-- UChar opc2 )
6174//-- {
6175//-- UChar dis_buf[50];
6176//-- UChar modrm = getUChar(eip);
6177//-- if (epartIsReg(modrm)) {
6178//-- /* Completely internal SSE insn. */
6179//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
6180//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
6181//-- Lit16, (UShort)modrm );
6182//-- DIP("%s %s, %s\n",
6183//-- name, nameMMXReg(eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)) );
6184//-- eip++;
6185//-- } else {
6186//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
6187//-- Int tmpa = LOW24(pair);
6188//-- eip += HI8(pair);
6189//-- uInstr3(cb, SSE2a_MemRd, sz,
6190//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
6191//-- Lit16, ((UShort)modrm),
6192//-- TempReg, tmpa);
6193//-- DIP("%s %s, %s\n", name, dis_buf, nameXMMReg(gregOfRM(modrm)));
6194//-- }
6195//-- return eip;
6196//-- }
6197//--
6198//--
6199//-- /* Simple SSE operations, either
6200//-- op (src)xmmreg, (dst)mmxreg
6201//-- or
6202//-- op (src)address, (dst)mmxreg
6203//-- 3 opcode bytes.
6204//-- Supplied eip points to the first address mode byte.
6205//-- */
6206//-- static
6207//-- Addr dis_SSE3_to_MMX ( UCodeBlock *cb,
6208//-- UChar sorb,
6209//-- Addr eip,
6210//-- Int sz,
6211//-- Char* name,
6212//-- UChar opc1,
6213//-- UChar opc2,
6214//-- UChar opc3 )
6215//-- {
6216//-- UChar dis_buf[50];
6217//-- UChar modrm = getUChar(eip);
6218//-- if (epartIsReg(modrm)) {
6219//-- /* Completely internal SSE insn. */
6220//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
6221//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
6222//-- Lit16, (((UShort)opc3) << 8) | (UShort)modrm );
6223//-- DIP("%s %s, %s\n",
6224//-- name, nameXMMReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)) );
6225//-- eip++;
6226//-- } else {
6227//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
6228//-- Int tmpa = LOW24(pair);
6229//-- eip += HI8(pair);
6230//-- uInstr3(cb, SSE3a_MemRd, sz,
6231//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
6232//-- Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
6233//-- TempReg, tmpa);
6234//-- DIP("%s %s, %s\n", name, dis_buf, nameMMXReg(gregOfRM(modrm)));
6235//-- }
6236//-- return eip;
6237//-- }
6238//--
6239//--
6240//-- /* Simple SSE operations, either
6241//-- op (src)mmxreg, (dst)xmmreg
6242//-- or
6243//-- op (src)address, (dst)xmmreg
6244//-- 3 opcode bytes.
6245//-- Supplied eip points to the first address mode byte.
6246//-- */
6247//-- static
6248//-- Addr dis_SSE3_from_MMX ( UCodeBlock *cb,
6249//-- UChar sorb,
6250//-- Addr eip,
6251//-- Int sz,
6252//-- Char* name,
6253//-- UChar opc1,
6254//-- UChar opc2,
6255//-- UChar opc3 )
6256//-- {
6257//-- UChar dis_buf[50];
6258//-- UChar modrm = getUChar(eip);
6259//-- if (epartIsReg(modrm)) {
6260//-- /* Completely internal SSE insn. */
6261//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
6262//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
6263//-- Lit16, (((UShort)opc3) << 8) | (UShort)modrm );
6264//-- DIP("%s %s, %s\n",
6265//-- name, nameMMXReg(eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)) );
6266//-- eip++;
6267//-- } else {
6268//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
6269//-- Int tmpa = LOW24(pair);
6270//-- eip += HI8(pair);
6271//-- uInstr3(cb, SSE3a_MemRd, sz,
6272//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
6273//-- Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
6274//-- TempReg, tmpa);
6275//-- DIP("%s %s, %s\n", name, dis_buf, nameXMMReg(gregOfRM(modrm)));
6276//-- }
6277//-- return eip;
6278//-- }
6279//--
6280//--
6281//-- static
6282//-- void dis_push_segreg ( UCodeBlock* cb, UInt sreg, Int sz )
6283//-- {
6284//-- Int t1 = newTemp(cb), t2 = newTemp(cb);
6285//-- vg_assert(sz == 2 || sz == 4);
6286//-- uInstr2(cb, GETSEG, 2, ArchRegS, sreg, TempReg, t1);
6287//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
6288//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
6289//-- uLiteral(cb, sz);
6290//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
6291//-- uInstr2(cb, STORE, 2, TempReg, t1, TempReg, t2);
6292//-- DIP("push %s\n", VG_(name_of_seg_reg)(sreg));
6293//-- }
6294//--
6295//-- static
6296//-- void dis_pop_segreg ( UCodeBlock* cb, UInt sreg, Int sz )
6297//-- {
6298//-- Int t1 = newTemp(cb), t2 = newTemp(cb);
6299//-- vg_assert(sz == 2 || sz == 4);
6300//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
6301//-- uInstr2(cb, LOAD, 2, TempReg, t2, TempReg, t1);
6302//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
6303//-- uLiteral(cb, sz);
6304//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
6305//-- uInstr2(cb, PUTSEG, 2, TempReg, t1, ArchRegS, sreg);
6306//-- DIP("pop %s\n", VG_(name_of_seg_reg)(sreg));
6307//-- }
sewardje05c42c2004-07-08 20:25:10 +00006308
6309static
6310void dis_ret ( UInt d32 )
6311{
6312 IRTemp t1 = newTemp(Ity_I32), t2 = newTemp(Ity_I32);
6313 assign(t1, getIReg(4,R_ESP));
6314 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
6315 putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(4+d32)));
sewardj78c19df2004-07-12 22:49:27 +00006316 jmp_treg(Ijk_Ret,t2);
sewardje05c42c2004-07-08 20:25:10 +00006317}
6318
sewardjc9a65702004-07-07 16:32:57 +00006319
6320/*------------------------------------------------------------*/
sewardjce70a5c2004-10-18 14:09:54 +00006321/*--- Disassemble a single instruction ---*/
sewardjc9a65702004-07-07 16:32:57 +00006322/*------------------------------------------------------------*/
6323
sewardjce70a5c2004-10-18 14:09:54 +00006324/* Disassemble a single instruction into IR. The instruction
6325 is located in host memory at &guest_code[delta].
6326 Set *size to be the size of the instruction.
6327 If the returned value is Dis_Resteer,
6328 the next guest address is assigned to *whereNext. If resteerOK
6329 is False, disInstr may not return Dis_Resteer. */
6330
6331static DisResult disInstr ( /*IN*/ Bool resteerOK,
sewardj5bd4d162004-11-10 13:02:48 +00006332 /*IN*/ Bool (*resteerOkFn) ( Addr64 ),
sewardjce70a5c2004-10-18 14:09:54 +00006333 /*IN*/ UInt delta,
6334 /*OUT*/ UInt* size,
6335 /*OUT*/ Addr64* whereNext )
sewardjc9a65702004-07-07 16:32:57 +00006336{
sewardjce70a5c2004-10-18 14:09:54 +00006337 IRType ty;
6338 IRTemp addr, t1, t2;
6339 Int alen;
6340 UChar opc, modrm, abyte;
6341 UInt d32;
6342 UChar dis_buf[50];
6343 Int am_sz, d_sz;
6344 DisResult whatNext = Dis_Continue;
6345
sewardjc9a65702004-07-07 16:32:57 +00006346 //Char loc_buf[M_VG_ERRTXT];
6347
6348 /* Holds eip at the start of the insn, so that we can print
6349 consistent error messages for unimplemented insns. */
6350 UInt delta_start = delta;
6351
6352 /* sz denotes the nominal data-op size of the insn; we change it to
6353 2 if an 0x66 prefix is seen */
6354 Int sz = 4;
6355
6356 /* sorb holds the segment-override-prefix byte, if any. Zero if no
6357 prefix has been seen, else one of {0x26, 0x3E, 0x64, 0x65}
6358 indicating the prefix. */
6359 UChar sorb = 0;
6360
sewardjce70a5c2004-10-18 14:09:54 +00006361 /* If we don't set *size properly, this causes bbToIR_X86Instr to
6362 assert. */
6363 *size = 0;
6364
sewardj92d168d2004-11-15 14:22:12 +00006365 addr = t1 = t2 = IRTemp_INVALID;
6366 //t3 = t4 = IRTemp_INVALID;
sewardjc9a65702004-07-07 16:32:57 +00006367
sewardjce70a5c2004-10-18 14:09:54 +00006368 DIP("\t0x%x: ", guest_eip_bbstart+delta);
sewardjc9a65702004-07-07 16:32:57 +00006369
sewardj750f4072004-07-26 22:39:11 +00006370 /* Spot the client-request magic sequence. */
6371 {
6372 UChar* code = (UChar*)(guest_code + delta);
6373 /* Spot this:
6374 C1C01D roll $29, %eax
6375 C1C003 roll $3, %eax
6376 C1C81B rorl $27, %eax
6377 C1C805 rorl $5, %eax
6378 C1C00D roll $13, %eax
6379 C1C013 roll $19, %eax
6380 */
6381 if (code[ 0] == 0xC1 && code[ 1] == 0xC0 && code[ 2] == 0x1D &&
6382 code[ 3] == 0xC1 && code[ 4] == 0xC0 && code[ 5] == 0x03 &&
6383 code[ 6] == 0xC1 && code[ 7] == 0xC8 && code[ 8] == 0x1B &&
6384 code[ 9] == 0xC1 && code[10] == 0xC8 && code[11] == 0x05 &&
6385 code[12] == 0xC1 && code[13] == 0xC0 && code[14] == 0x0D &&
6386 code[15] == 0xC1 && code[16] == 0xC0 && code[17] == 0x13
6387 ) {
sewardjce70a5c2004-10-18 14:09:54 +00006388 DIP("%%edx = client_request ( %%eax )\n");
sewardj750f4072004-07-26 22:39:11 +00006389 delta += 18;
sewardjce70a5c2004-10-18 14:09:54 +00006390 jmp_lit(Ijk_ClientReq, guest_eip_bbstart+delta);
6391 whatNext = Dis_StopHere;
6392 goto decode_success;
sewardj750f4072004-07-26 22:39:11 +00006393 }
6394 }
sewardjc9a65702004-07-07 16:32:57 +00006395
6396 /* Skip a LOCK prefix. */
6397 if (getIByte(delta) == 0xF0) {
njn285f22c2004-11-23 17:11:49 +00006398 if (0) vex_printf("vex x86->IR: ignoring LOCK prefix\n");
sewardjc9a65702004-07-07 16:32:57 +00006399 delta++;
6400 }
6401
6402 /* Detect operand-size overrides. */
6403 if (getIByte(delta) == 0x66) { sz = 2; delta++; };
6404
6405 /* segment override prefixes come after the operand-size override,
6406 it seems */
6407 switch (getIByte(delta)) {
6408 case 0x3E: /* %DS: */
6409 case 0x26: /* %ES: */
6410 case 0x64: /* %FS: */
6411 case 0x65: /* %GS: */
6412 sorb = getIByte(delta); delta++;
6413 break;
6414 case 0x2E: /* %CS: */
6415 /* 2E prefix on a conditional branch instruction is a
6416 branch-prediction hint, which can safely be ignored. */
6417 {
6418 UChar op1 = getIByte(delta+1);
6419 UChar op2 = getIByte(delta+2);
6420 if ((op1 >= 0x70 && op1 <= 0x7F)
6421 || (op1 == 0xE3)
6422 || (op1 == 0x0F && op2 >= 0x80 && op2 <= 0x8F)) {
sewardjce70a5c2004-10-18 14:09:54 +00006423 vex_printf("vex x86->IR: ignoring branch hint\n");
sewardjc9a65702004-07-07 16:32:57 +00006424 sorb = getIByte(delta); delta++;
6425 break;
6426 }
6427 }
6428 unimplemented("x86 segment override (SEG=CS) prefix");
6429 /*NOTREACHED*/
6430 break;
6431 case 0x36: /* %SS: */
6432 unimplemented("x86 segment override (SEG=SS) prefix");
6433 /*NOTREACHED*/
6434 break;
6435 default:
6436 break;
6437 }
6438
6439//-- /* ---------------------------------------------------- */
6440//-- /* --- The SSE/SSE2 decoder. --- */
6441//-- /* ---------------------------------------------------- */
6442//--
6443//-- /* If it looks like this CPU might support SSE, try decoding SSE
6444//-- insns. */
6445//-- if (VG_(have_ssestate)) {
6446//-- UChar* insn = (UChar*)eip;
6447//--
6448//-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
6449//-- if (insn[0] == 0x0F && insn[1] == 0xAE
6450//-- && (!epartIsReg(insn[2]))
6451//-- && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
6452//-- Bool store = gregOfRM(insn[2]) == 0;
6453//-- vg_assert(sz == 4);
6454//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
6455//-- t1 = LOW24(pair);
6456//-- eip += 2+HI8(pair);
6457//-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
6458//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
6459//-- Lit16, (UShort)insn[2],
6460//-- TempReg, t1 );
6461//-- DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
6462//-- goto decode_success;
6463//-- }
6464//--
6465//-- /* STMXCSR/LDMXCSR m32 -- load/store the MXCSR register. */
6466//-- if (insn[0] == 0x0F && insn[1] == 0xAE
6467//-- && (!epartIsReg(insn[2]))
6468//-- && (gregOfRM(insn[2]) == 3 || gregOfRM(insn[2]) == 2) ) {
6469//-- Bool store = gregOfRM(insn[2]) == 3;
6470//-- vg_assert(sz == 4);
6471//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
6472//-- t1 = LOW24(pair);
6473//-- eip += 2+HI8(pair);
6474//-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 4,
6475//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
6476//-- Lit16, (UShort)insn[2],
6477//-- TempReg, t1 );
6478//-- DIP("%smxcsr %s\n", store ? "st" : "ld", dis_buf );
6479//-- goto decode_success;
6480//-- }
6481//--
6482//-- /* LFENCE/MFENCE/SFENCE -- flush pending operations to memory */
6483//-- if (insn[0] == 0x0F && insn[1] == 0xAE
6484//-- && (epartIsReg(insn[2]))
6485//-- && (gregOfRM(insn[2]) >= 5 && gregOfRM(insn[2]) <= 7))
6486//-- {
6487//-- vg_assert(sz == 4);
6488//-- eip += 3;
6489//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
6490//-- Lit16, (((UShort)0x0F) << 8) | (UShort)0xAE,
6491//-- Lit16, (UShort)insn[2] );
6492//-- DIP("sfence\n");
6493//-- goto decode_success;
6494//-- }
6495//--
6496//-- /* CLFLUSH -- flush cache line */
6497//-- if (insn[0] == 0x0F && insn[1] == 0xAE
6498//-- && (!epartIsReg(insn[2]))
6499//-- && (gregOfRM(insn[2]) == 7))
6500//-- {
6501//-- vg_assert(sz == 4);
6502//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
6503//-- t1 = LOW24(pair);
6504//-- eip += 2+HI8(pair);
6505//-- uInstr3(cb, SSE2a_MemRd, 0, /* ignore sz for internal ops */
6506//-- Lit16, (((UShort)0x0F) << 8) | (UShort)0xAE,
6507//-- Lit16, (UShort)insn[2],
6508//-- TempReg, t1 );
6509//-- DIP("clflush %s\n", dis_buf);
6510//-- goto decode_success;
6511//-- }
6512//--
6513//-- /* CVTPI2PS (0x0F,0x2A) -- mm/m64, xmm */
6514//-- /* CVTPI2PD (0x66,0x0F,0x2A) -- mm/m64, xmm */
6515//-- if (insn[0] == 0x0F && insn[1] == 0x2A) {
6516//-- if (sz == 4) {
6517//-- eip = dis_SSE2_from_MMX
6518//-- ( cb, sorb, eip+2, 8, "cvtpi2ps",
6519//-- insn[0], insn[1] );
6520//-- } else {
6521//-- eip = dis_SSE3_from_MMX
6522//-- ( cb, sorb, eip+2, 8, "cvtpi2pd",
6523//-- 0x66, insn[0], insn[1] );
6524//-- }
6525//-- goto decode_success;
6526//-- }
6527//--
6528//-- /* CVTTPS2PI (0x0F,0x2C) -- xmm/m64, mm */
6529//-- /* CVTPS2PI (0x0F,0x2D) -- xmm/m64, mm */
6530//-- /* CVTTPD2PI (0x66,0x0F,0x2C) -- xmm/m128, mm */
6531//-- /* CVTPD2PI (0x66,0x0F,0x2D) -- xmm/m128, mm */
6532//-- if (insn[0] == 0x0F
6533//-- && (insn[1] == 0x2C || insn[1] == 0x2D)) {
6534//-- if (sz == 4) {
6535//-- eip = dis_SSE2_to_MMX
6536//-- ( cb, sorb, eip+2, 8, "cvt{t}ps2pi",
6537//-- insn[0], insn[1] );
6538//-- } else {
6539//-- eip = dis_SSE3_to_MMX
6540//-- ( cb, sorb, eip+2, 16, "cvt{t}pd2pi",
6541//-- 0x66, insn[0], insn[1] );
6542//-- }
6543//-- goto decode_success;
6544//-- }
6545//--
6546//-- /* CVTTSD2SI (0xF2,0x0F,0x2C) -- convert a double-precision float
6547//-- value in memory or xmm reg to int and put it in an ireg.
6548//-- Truncate. */
6549//-- /* CVTTSS2SI (0xF3,0x0F,0x2C) -- convert a single-precision float
6550//-- value in memory or xmm reg to int and put it in an ireg.
6551//-- Truncate. */
6552//-- /* CVTSD2SI (0xF2,0x0F,0x2D) -- convert a double-precision float
6553//-- value in memory or xmm reg to int and put it in an ireg. Round
6554//-- as per MXCSR. */
6555//-- /* CVTSS2SI (0xF3,0x0F,0x2D) -- convert a single-precision float
6556//-- value in memory or xmm reg to int and put it in an ireg. Round
6557//-- as per MXCSR. */
6558//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
6559//-- && insn[1] == 0x0F
6560//-- && (insn[2] == 0x2C || insn[2] == 0x2D)) {
6561//-- vg_assert(sz == 4);
6562//-- modrm = insn[3];
6563//-- if (epartIsReg(modrm)) {
6564//-- /* We're moving a value in an xmm reg to an ireg. */
6565//-- eip += 4;
sewardj5bd4d162004-11-10 13:02:48 +00006566//-- t1 = newTemp(cb);
sewardjc9a65702004-07-07 16:32:57 +00006567//-- /* sz is 4 for all 4 insns. */
6568//-- vg_assert(epartIsReg(modrm));
6569//-- uInstr3(cb, SSE3g_RegWr, 4,
6570//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
6571//-- Lit16, (((UShort)insn[2]) << 8) | (UShort)modrm,
6572//-- TempReg, t1 );
6573//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
6574//-- DIP("cvt{t}s{s,d}2si %s, %s\n",
6575//-- nameXMMReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)) );
6576//-- } else {
6577//-- /* So, we're reading memory and writing an ireg. This calls
6578//-- for the ultra-horrible SSE3ag_MemRd_RegWr uinstr. We
6579//-- can't do it in a roundabout route because it does some
6580//-- kind of conversion on the way, which we need to have
6581//-- happen too. So our only choice is to re-emit a suitably
6582//-- rehashed version of the instruction. */
sewardj5bd4d162004-11-10 13:02:48 +00006583//-- /* Destination ireg is GREG. Address goes as EREG as
6584//-- usual. */
sewardjc9a65702004-07-07 16:32:57 +00006585//-- t1 = newTemp(cb); /* t1 holds value on its way to ireg */
6586//-- pair = disAMode ( cb, sorb, eip+3, dis_buf );
6587//-- t2 = LOW24(pair); /* t2 holds addr */
6588//-- eip += 3+HI8(pair);
6589//-- uInstr2(cb, SSE3ag_MemRd_RegWr, insn[0]==0xF2 ? 8 : 4,
6590//-- TempReg, t2, /* address */
6591//-- TempReg, t1 /* dest */);
6592//-- uLiteral(cb , (((UInt)insn[0]) << 24)
6593//-- | (((UInt)insn[1]) << 16)
6594//-- | (((UInt)insn[2]) << 8)
6595//-- | ((UInt)modrm) );
6596//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
6597//-- DIP("cvt{t}s{s,d}2si %s, %s\n",
6598//-- dis_buf, nameIReg(4,gregOfRM(modrm)) );
6599//-- }
6600//-- goto decode_success;
6601//-- }
6602//--
6603//-- /* CVTSI2SS -- convert int reg, or int value in memory, to low 4
6604//-- bytes of XMM reg. */
6605//-- /* CVTSI2SD -- convert int reg, or int value in memory, to low 8
6606//-- bytes of XMM reg. */
6607//-- if ((insn[0] == 0xF3 /*CVTSI2SS*/ || insn[0] == 0xF2 /* CVTSI2SD*/)
6608//-- && insn[1] == 0x0F && insn[2] == 0x2A) {
6609//-- Char* s_or_d = insn[0]==0xF3 ? "s" : "d";
6610//-- vg_assert(sz == 4);
6611//-- modrm = insn[3];
6612//-- t1 = newTemp(cb);
6613//-- if (epartIsReg(modrm)) {
6614//-- uInstr2(cb, GET, 4, ArchReg, eregOfRM(modrm), TempReg, t1);
6615//-- vg_assert(epartIsReg(modrm));
6616//-- uInstr3(cb, SSE3e_RegRd, 4,
6617//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
6618//-- Lit16, (((UShort)insn[2]) << 8) | (UShort)modrm,
6619//-- TempReg, t1 );
6620//-- eip += 4;
6621//-- DIP("cvtsi2s%s %s, %s\n", s_or_d,
6622//-- nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
6623//-- } else {
6624//-- pair = disAMode ( cb, sorb, eip+3, dis_buf );
6625//-- t2 = LOW24(pair);
6626//-- eip += 3+HI8(pair);
sewardj5bd4d162004-11-10 13:02:48 +00006627//-- uInstr3(cb, SSE3a_MemRd, 4,
sewardjc9a65702004-07-07 16:32:57 +00006628//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
6629//-- Lit16, (((UShort)insn[2]) << 8) | (UShort)modrm,
6630//-- TempReg, t2 );
6631//-- DIP("cvtsi2s%s %s, %s\n",
6632//-- s_or_d, dis_buf, nameXMMReg(gregOfRM(modrm)));
6633//-- }
6634//-- goto decode_success;
6635//-- }
6636//--
6637//-- /* CVTPS2PD -- convert two packed floats to two packed doubles. */
6638//-- /* 0x66: CVTPD2PS -- convert two packed doubles to two packed floats. */
6639//-- if (insn[0] == 0x0F && insn[1] == 0x5A) {
6640//-- vg_assert(sz == 2 || sz == 4);
6641//-- if (sz == 4) {
6642//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 8, "cvtps2pd",
6643//-- insn[0], insn[1] );
6644//-- } else {
6645//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "cvtpd2ps",
6646//-- 0x66, insn[0], insn[1] );
6647//-- }
6648//-- goto decode_success;
6649//-- }
6650//--
6651//-- /* CVTSS2SD -- convert one single float to double. */
6652//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5A) {
6653//-- vg_assert(sz == 4);
6654//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4, "cvtss2sd",
6655//-- insn[0], insn[1], insn[2] );
6656//-- goto decode_success;
6657//-- }
6658//--
6659//-- /* CVTSD2SS -- convert one single double. to float. */
6660//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5A) {
6661//-- vg_assert(sz == 4);
6662//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8, "cvtsd2ss",
6663//-- insn[0], insn[1], insn[2] );
6664//-- goto decode_success;
6665//-- }
6666//--
6667//-- /* CVTDQ2PS -- convert four ints to four packed floats. */
6668//-- /* 0x66: CVTPS2DQ -- convert four packed floats to four ints. */
6669//-- if (insn[0] == 0x0F && insn[1] == 0x5B) {
6670//-- vg_assert(sz == 2 || sz == 4);
6671//-- if (sz == 4) {
6672//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "cvtdq2ps",
6673//-- insn[0], insn[1] );
6674//-- } else {
6675//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "cvtps2dq",
6676//-- 0x66, insn[0], insn[1] );
6677//-- }
6678//-- goto decode_success;
6679//-- }
6680//--
6681//-- /* CVTPD2DQ -- convert two packed doubles to two ints. */
6682//-- if (sz == 2
6683//-- && insn[0] == 0x0F && insn[1] == 0xE6) {
6684//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 8, "cvtpd2dq",
6685//-- 0x66, insn[0], insn[1] );
6686//-- goto decode_success;
6687//-- }
6688//--
6689//-- /* CVTTPD2DQ -- convert two packed doubles to two ints with truncation. */
6690//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xE6) {
6691//-- vg_assert(sz == 4);
6692//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8, "cvttpd2dq",
6693//-- insn[0], insn[1], insn[2] );
6694//-- goto decode_success;
6695//-- }
6696//--
6697//-- /* CVTDQ2PD -- convert two ints to two packed doubles. */
6698//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xE6) {
6699//-- vg_assert(sz == 4);
6700//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8, "cvtdq2pd",
6701//-- insn[0], insn[1], insn[2] );
6702//-- goto decode_success;
6703//-- }
6704//--
6705//-- /* CVTTPS2DQ -- convert four packed floats to four ints with truncation. */
6706//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5B) {
6707//-- vg_assert(sz == 4);
6708//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 16, "cvttps2dq",
6709//-- insn[0], insn[1], insn[2] );
6710//-- goto decode_success;
6711//-- }
6712//--
6713//-- /* CMPSS -- compare scalar floats. */
6714//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xC2) {
6715//-- vg_assert(sz == 4);
6716//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 8, "cmpss",
6717//-- insn[0], insn[1], insn[2] );
6718//-- goto decode_success;
6719//-- }
6720//--
6721//-- /* CMPSD -- compare scalar doubles. */
6722//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xC2) {
6723//-- vg_assert(sz == 4);
6724//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 8, "cmpsd",
6725//-- insn[0], insn[1], insn[2] );
6726//-- goto decode_success;
6727//-- }
6728//--
6729//-- /* sz==4: CMPPS -- compare packed floats */
6730//-- /* sz==2: CMPPD -- compare packed doubles */
6731//-- if (insn[0] == 0x0F && insn[1] == 0xC2) {
6732//-- vg_assert(sz == 4 || sz == 2);
6733//-- if (sz == 4) {
6734//-- eip = dis_SSE2_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "cmpps",
6735//-- insn[0], insn[1] );
6736//-- } else {
6737//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "cmppd",
6738//-- 0x66, insn[0], insn[1] );
6739//-- }
6740//-- goto decode_success;
6741//-- }
6742//--
6743//-- /* PSHUFD */
6744//-- if (sz == 2
6745//-- && insn[0] == 0x0F && insn[1] == 0x70) {
6746//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16,
6747//-- "pshufd",
6748//-- 0x66, insn[0], insn[1] );
6749//-- goto decode_success;
6750//-- }
6751//--
6752//-- /* PSHUFLW */
6753//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x70) {
6754//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 16,
6755//-- "pshuflw",
6756//-- insn[0], insn[1], insn[2] );
6757//-- goto decode_success;
6758//-- }
6759//--
6760//-- /* PSHUFHW */
6761//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x70) {
6762//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 16,
6763//-- "pshufhw",
6764//-- insn[0], insn[1], insn[2] );
6765//-- goto decode_success;
6766//-- }
6767//--
6768//-- /* SHUFPD */
6769//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC6) {
6770//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "shufpd",
6771//-- 0x66, insn[0], insn[1] );
6772//-- goto decode_success;
6773//-- }
6774//--
6775//-- /* SHUFPS */
6776//-- if (insn[0] == 0x0F && insn[1] == 0xC6) {
6777//-- vg_assert(sz == 4);
6778//-- eip = dis_SSE2_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "shufps",
6779//-- insn[0], insn[1] );
6780//-- goto decode_success;
6781//-- }
6782//--
6783//-- /* 0xF2: MULSD */
6784//-- /* 0xF3: MULSS -- multiply low 4 bytes of XMM reg. */
6785//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
6786//-- && insn[1] == 0x0F && insn[2] == 0x59) {
6787//-- Bool sz8 = insn[0] == 0xF2;
6788//-- vg_assert(sz == 4);
6789//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
6790//-- sz8 ? "mulss" : "mulsd",
6791//-- insn[0], insn[1], insn[2] );
6792//-- goto decode_success;
6793//-- }
6794//--
6795//-- /* MULPS */
6796//-- /* 0x66: MULPD */
6797//-- if (insn[0] == 0x0F && insn[1] == 0x59) {
6798//-- vg_assert(sz == 4 || sz == 2);
6799//-- if (sz == 4) {
6800//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "mulps",
6801//-- insn[0], insn[1] );
6802//-- } else {
6803//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "mulpd",
6804//-- 0x66, insn[0], insn[1] );
6805//-- }
6806//-- goto decode_success;
6807//-- }
6808//--
6809//-- /* 0xF2: DIVSD */
6810//-- /* 0xF3: DIVSS -- divide low 4 bytes of XMM reg. */
6811//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
6812//-- && insn[1] == 0x0F && insn[2] == 0x5E) {
6813//-- Bool sz8 = insn[0] == 0xF2;
6814//-- vg_assert(sz == 4);
6815//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
6816//-- sz8 ? "divsd" : "divss",
6817//-- insn[0], insn[1], insn[2] );
6818//-- goto decode_success;
6819//-- }
6820//--
6821//-- /* DIVPS */
6822//-- /* 0x66: DIVPD */
6823//-- if (insn[0] == 0x0F && insn[1] == 0x5E) {
6824//-- vg_assert(sz == 4 || sz == 2);
6825//-- if (sz == 4) {
6826//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "divps",
6827//-- insn[0], insn[1] );
6828//-- } else {
6829//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "divpd",
6830//-- 0x66, insn[0], insn[1] );
6831//-- }
6832//-- goto decode_success;
6833//-- }
6834//--
6835//-- /* 0xF2: SUBSD */
6836//-- /* 0xF3: SUBSS */
6837//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
6838//-- && insn[1] == 0x0F && insn[2] == 0x5C) {
6839//-- Bool sz8 = insn[0] == 0xF2;
6840//-- vg_assert(sz == 4);
6841//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
6842//-- sz8 ? "subsd" : "subss",
6843//-- insn[0], insn[1], insn[2] );
6844//-- goto decode_success;
6845//-- }
6846//--
6847//-- /* SUBPS */
6848//-- /* 0x66: SUBPD */
6849//-- if (insn[0] == 0x0F && insn[1] == 0x5C) {
6850//-- vg_assert(sz == 4 || sz == 2);
6851//-- if (sz == 4) {
6852//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "subps",
6853//-- insn[0], insn[1] );
6854//-- } else {
6855//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "subpd",
6856//-- 0x66, insn[0], insn[1] );
6857//-- }
6858//-- goto decode_success;
6859//-- }
6860//--
6861//-- /* 0xF2: ADDSD */
6862//-- /* 0xF3: ADDSS */
6863//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
6864//-- && insn[1] == 0x0F && insn[2] == 0x58) {
6865//-- Bool sz8 = insn[0] == 0xF2;
6866//-- vg_assert(sz == 4);
6867//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
6868//-- sz8 ? "addsd" : "addss",
6869//-- insn[0], insn[1], insn[2] );
6870//-- goto decode_success;
6871//-- }
6872//--
6873//-- /* ADDPS */
6874//-- /* 0x66: ADDPD */
6875//-- if (insn[0] == 0x0F && insn[1] == 0x58) {
6876//-- vg_assert(sz == 4 || sz == 2);
6877//-- if (sz == 4) {
6878//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "addps",
6879//-- insn[0], insn[1] );
6880//-- } else {
6881//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "addpd",
6882//-- 0x66, insn[0], insn[1] );
6883//-- }
6884//-- goto decode_success;
6885//-- }
6886//--
6887//-- /* 0xF2: MINSD */
6888//-- /* 0xF3: MINSS */
6889//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
6890//-- && insn[1] == 0x0F && insn[2] == 0x5D) {
6891//-- Bool sz8 = insn[0] == 0xF2;
6892//-- vg_assert(sz == 4);
6893//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
6894//-- sz8 ? "minsd" : "minss",
6895//-- insn[0], insn[1], insn[2] );
6896//-- goto decode_success;
6897//-- }
6898//--
6899//-- /* MINPS */
6900//-- /* 0x66: MINPD */
6901//-- if (insn[0] == 0x0F && insn[1] == 0x5D) {
6902//-- vg_assert(sz == 4 || sz == 2);
6903//-- if (sz == 4) {
6904//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "minps",
6905//-- insn[0], insn[1] );
6906//-- } else {
6907//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "minpd",
6908//-- 0x66, insn[0], insn[1] );
6909//-- }
6910//-- goto decode_success;
6911//-- }
6912//--
6913//-- /* 0xF3: MAXSD */
6914//-- /* 0xF3: MAXSS */
6915//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
6916//-- && insn[1] == 0x0F && insn[2] == 0x5F) {
6917//-- Bool sz8 = insn[0] == 0xF2;
6918//-- vg_assert(sz == 4);
6919//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
6920//-- sz8 ? "maxsd" : "maxss",
6921//-- insn[0], insn[1], insn[2] );
6922//-- goto decode_success;
6923//-- }
6924//--
6925//-- /* MAXPS */
6926//-- /* 0x66: MAXPD */
6927//-- if (insn[0] == 0x0F && insn[1] == 0x5F) {
6928//-- vg_assert(sz == 4 || sz == 2);
6929//-- if (sz == 4) {
6930//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "maxps",
6931//-- insn[0], insn[1] );
6932//-- } else {
6933//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "maxpd",
6934//-- 0x66, insn[0], insn[1] );
6935//-- }
6936//-- goto decode_success;
6937//-- }
6938//--
6939//-- /* RCPPS -- reciprocal of packed floats */
6940//-- if (insn[0] == 0x0F && insn[1] == 0x53) {
6941//-- vg_assert(sz == 4);
6942//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "rcpps",
6943//-- insn[0], insn[1] );
6944//-- goto decode_success;
6945//-- }
6946//--
6947//-- /* XORPS */
6948//-- /* 0x66: XORPD (src)xmmreg-or-mem, (dst)xmmreg */
6949//-- if (insn[0] == 0x0F && insn[1] == 0x57) {
6950//-- vg_assert(sz == 4 || sz == 2);
6951//-- if (sz == 4) {
6952//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "xorps",
6953//-- insn[0], insn[1] );
6954//-- } else {
6955//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "xorpd",
6956//-- 0x66, insn[0], insn[1] );
6957//-- }
6958//-- goto decode_success;
6959//-- }
6960//--
6961//-- /* ANDPS */
6962//-- /* 0x66: ANDPD (src)xmmreg-or-mem, (dst)xmmreg */
6963//-- if (insn[0] == 0x0F && insn[1] == 0x54) {
6964//-- vg_assert(sz == 4 || sz == 2);
6965//-- if (sz == 4) {
6966//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "andps",
6967//-- insn[0], insn[1] );
6968//-- } else {
6969//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "andpd",
6970//-- 0x66, insn[0], insn[1] );
6971//-- }
6972//-- goto decode_success;
6973//-- }
6974//--
6975//-- /* ORPS */
6976//-- /* 0x66: ORPD (src)xmmreg-or-mem, (dst)xmmreg */
6977//-- if (insn[0] == 0x0F && insn[1] == 0x56) {
6978//-- vg_assert(sz == 4 || sz == 2);
6979//-- if (sz == 4) {
6980//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "orps",
6981//-- insn[0], insn[1] );
6982//-- } else {
6983//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "orpd",
6984//-- 0x66, insn[0], insn[1] );
6985//-- }
6986//-- goto decode_success;
6987//-- }
6988//--
6989//-- /* PXOR (src)xmmreg-or-mem, (dst)xmmreg */
6990//-- if (sz == 2
6991//-- && insn[0] == 0x0F && insn[1] == 0xEF) {
6992//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pxor",
6993//-- 0x66, insn[0], insn[1] );
6994//-- goto decode_success;
6995//-- }
6996//--
6997//-- /* PAND (src)xmmreg-or-mem, (dst)xmmreg */
6998//-- if (sz == 2
6999//-- && insn[0] == 0x0F && insn[1] == 0xDB) {
7000//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pand",
7001//-- 0x66, insn[0], insn[1] );
7002//-- goto decode_success;
7003//-- }
7004//--
7005//-- /* PANDN (src)xmmreg-or-mem, (dst)xmmreg */
7006//-- if (sz == 2
7007//-- && insn[0] == 0x0F && insn[1] == 0xDF) {
7008//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pandn",
7009//-- 0x66, insn[0], insn[1] );
7010//-- goto decode_success;
7011//-- }
7012//--
7013//-- /* POR (src)xmmreg-or-mem, (dst)xmmreg */
7014//-- if (sz == 2
7015//-- && insn[0] == 0x0F && insn[1] == 0xEB) {
7016//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "por",
7017//-- 0x66, insn[0], insn[1] );
7018//-- goto decode_success;
7019//-- }
7020//--
7021//-- /* 0xDA: PMINUB(src)xmmreg-or-mem, (dst)xmmreg */
7022//-- /* 0xEA: PMINSW(src)xmmreg-or-mem, (dst)xmmreg */
7023//-- if (sz == 2
7024//-- && insn[0] == 0x0F
7025//-- && (insn[1] == 0xDA || insn[1] == 0xEA)) {
7026//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmin{ub,sw}",
7027//-- 0x66, insn[0], insn[1] );
7028//-- goto decode_success;
7029//-- }
7030//--
7031//-- /* 0xDE: PMAXUB(src)xmmreg-or-mem, (dst)xmmreg */
7032//-- /* 0xEE: PMAXSW(src)xmmreg-or-mem, (dst)xmmreg */
7033//-- if (sz == 2
7034//-- && insn[0] == 0x0F
7035//-- && (insn[1] == 0xDE || insn[1] == 0xEE)) {
7036//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmax{ub,sw}",
7037//-- 0x66, insn[0], insn[1] );
7038//-- goto decode_success;
7039//-- }
7040//--
7041//-- /* 0xE0: PAVGB(src)xmmreg-or-mem, (dst)xmmreg */
7042//-- /* 0xE3: PAVGW(src)xmmreg-or-mem, (dst)xmmreg */
7043//-- if (sz == 2
7044//-- && insn[0] == 0x0F
7045//-- && (insn[1] == 0xE0 || insn[1] == 0xE3)) {
7046//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pavg{b,w}",
7047//-- 0x66, insn[0], insn[1] );
7048//-- goto decode_success;
7049//-- }
7050//--
7051//-- /* 0xF6: PSADBW(src)xmmreg-or-mem, (dst)xmmreg */
7052//-- if (sz == 2
7053//-- && insn[0] == 0x0F && insn[1] == 0xF6) {
7054//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psadbw",
7055//-- 0x66, insn[0], insn[1] );
7056//-- goto decode_success;
7057//-- }
7058//--
7059//-- /* 0x60: PUNPCKLBW (src)xmmreg-or-mem, (dst)xmmreg */
7060//-- /* 0x61: PUNPCKLWD (src)xmmreg-or-mem, (dst)xmmreg */
7061//-- /* 0x62: PUNPCKLDQ (src)xmmreg-or-mem, (dst)xmmreg */
7062//-- /* 0x6C: PUNPCKQLQDQ (src)xmmreg-or-mem, (dst)xmmreg */
7063//-- if (sz == 2
7064//-- && insn[0] == 0x0F
7065//-- && (insn[1] == 0x60 || insn[1] == 0x61
7066//-- || insn[1] == 0x62 || insn[1] == 0x6C)) {
7067//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16,
7068//-- "punpckl{bw,wd,dq,qdq}",
7069//-- 0x66, insn[0], insn[1] );
7070//-- goto decode_success;
7071//-- }
7072//--
7073//-- /* 0x68: PUNPCKHBW (src)xmmreg-or-mem, (dst)xmmreg */
7074//-- /* 0x69: PUNPCKHWD (src)xmmreg-or-mem, (dst)xmmreg */
7075//-- /* 0x6A: PUNPCKHDQ (src)xmmreg-or-mem, (dst)xmmreg */
7076//-- /* 0x6D: PUNPCKHQDQ (src)xmmreg-or-mem, (dst)xmmreg */
7077//-- if (sz == 2
7078//-- && insn[0] == 0x0F
7079//-- && (insn[1] == 0x68 || insn[1] == 0x69
7080//-- || insn[1] == 0x6A || insn[1] == 0x6D)) {
7081//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16,
7082//-- "punpckh{bw,wd,dq,qdq}",
7083//-- 0x66, insn[0], insn[1] );
7084//-- goto decode_success;
7085//-- }
7086//--
7087//-- /* 0x14: UNPCKLPD (src)xmmreg-or-mem, (dst)xmmreg. Reads a+0
7088//-- .. a+7, so we can say size 8 */
7089//-- /* 0x15: UNPCKHPD (src)xmmreg-or-mem, (dst)xmmreg. Reads a+8
7090//-- .. a+15, but we have no way to express this, so better say size
7091//-- 16. Sigh. */
7092//-- if (sz == 2
7093//-- && insn[0] == 0x0F
7094//-- && (insn[1] == 0x14 || insn[1] == 0x15)) {
7095//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2,
7096//-- insn[1]==0x14 ? 8 : 16,
7097//-- "unpck{l,h}pd",
7098//-- 0x66, insn[0], insn[1] );
7099//-- goto decode_success;
7100//-- }
7101//--
7102//-- /* 0x14: UNPCKLPS (src)xmmreg-or-mem, (dst)xmmreg Reads a+0
7103//-- .. a+7, so we can say size 8 */
7104//-- /* 0x15: UNPCKHPS (src)xmmreg-or-mem, (dst)xmmreg Reads a+8
7105//-- .. a+15, but we have no way to express this, so better say size
7106//-- 16. Sigh. */
7107//-- if (sz == 4
7108//-- && insn[0] == 0x0F
7109//-- && (insn[1] == 0x14 || insn[1] == 0x15)) {
7110//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2,
7111//-- insn[1]==0x14 ? 8 : 16,
7112//-- "unpck{l,h}ps",
7113//-- insn[0], insn[1] );
7114//-- goto decode_success;
7115//-- }
7116//--
7117//-- /* 0xFC: PADDB (src)xmmreg-or-mem, (dst)xmmreg */
7118//-- /* 0xFD: PADDW (src)xmmreg-or-mem, (dst)xmmreg */
7119//-- /* 0xFE: PADDD (src)xmmreg-or-mem, (dst)xmmreg */
7120//-- /* 0xD4: PADDQ (src)xmmreg-or-mem, (dst)xmmreg */
7121//-- if (sz == 2
7122//-- && insn[0] == 0x0F
7123//-- && (insn[1] == 0xFC || insn[1] == 0xFD
7124//-- || insn[1] == 0xFE || insn[1] == 0xD4)) {
7125//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "padd{b,w,d,q}",
7126//-- 0x66, insn[0], insn[1] );
7127//-- goto decode_success;
7128//-- }
7129//--
7130//-- /* 0xEC: PADDSB (src)xmmreg-or-mem, (dst)xmmreg */
7131//-- /* 0xED: PADDSW (src)xmmreg-or-mem, (dst)xmmreg */
7132//-- if (sz == 2
7133//-- && insn[0] == 0x0F
7134//-- && (insn[1] == 0xEC || insn[1] == 0xED)) {
7135//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "padds{b,w}",
7136//-- 0x66, insn[0], insn[1] );
7137//-- goto decode_success;
7138//-- }
7139//--
7140//-- /* 0xDC: PADDUSB (src)xmmreg-or-mem, (dst)xmmreg */
7141//-- /* 0xDD: PADDUSW (src)xmmreg-or-mem, (dst)xmmreg */
7142//-- if (sz == 2
7143//-- && insn[0] == 0x0F
7144//-- && (insn[1] == 0xDC || insn[1] == 0xDD)) {
7145//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "paddus{b,w}",
7146//-- 0x66, insn[0], insn[1] );
7147//-- goto decode_success;
7148//-- }
7149//--
7150//-- /* 0xF8: PSUBB (src)xmmreg-or-mem, (dst)xmmreg */
7151//-- /* 0xF9: PSUBW (src)xmmreg-or-mem, (dst)xmmreg */
7152//-- /* 0xFA: PSUBD (src)xmmreg-or-mem, (dst)xmmreg */
7153//-- /* 0xFB: PSUBQ (src)xmmreg-or-mem, (dst)xmmreg */
7154//-- if (sz == 2
7155//-- && insn[0] == 0x0F
7156//-- && (insn[1] == 0xF8 || insn[1] == 0xF9
7157//-- || insn[1] == 0xFA || insn[1] == 0xFB)) {
7158//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psub{b,w,d,q}",
7159//-- 0x66, insn[0], insn[1] );
7160//-- goto decode_success;
7161//-- }
7162//--
7163//-- /* 0xE8: PSUBSB (src)xmmreg-or-mem, (dst)xmmreg */
7164//-- /* 0xE9: PSUBSW (src)xmmreg-or-mem, (dst)xmmreg */
7165//-- if (sz == 2
7166//-- && insn[0] == 0x0F
7167//-- && (insn[1] == 0xE8 || insn[1] == 0xE9)) {
7168//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psubs{b,w}",
7169//-- 0x66, insn[0], insn[1] );
7170//-- goto decode_success;
7171//-- }
7172//--
7173//-- /* 0xD8: PSUBUSB (src)xmmreg-or-mem, (dst)xmmreg */
7174//-- /* 0xD9: PSUBUSW (src)xmmreg-or-mem, (dst)xmmreg */
7175//-- if (sz == 2
7176//-- && insn[0] == 0x0F
7177//-- && (insn[1] == 0xD8 || insn[1] == 0xD9)) {
7178//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psubus{b,w}",
7179//-- 0x66, insn[0], insn[1] );
7180//-- goto decode_success;
7181//-- }
7182//--
7183//-- /* 0xE4: PMULHUW(src)xmmreg-or-mem, (dst)xmmreg */
7184//-- /* 0xE5: PMULHW(src)xmmreg-or-mem, (dst)xmmreg */
7185//-- /* 0xD5: PMULLW(src)xmmreg-or-mem, (dst)xmmreg */
7186//-- if (sz == 2
7187//-- && insn[0] == 0x0F
7188//-- && (insn[1] == 0xE4 || insn[1] == 0xE5 || insn[1] == 0xD5)) {
7189//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmul{hu,h,l}w",
7190//-- 0x66, insn[0], insn[1] );
7191//-- goto decode_success;
7192//-- }
7193//--
7194//-- /* 0xD5: PMULUDQ(src)xmmreg-or-mem, (dst)xmmreg */
7195//-- if (sz == 2
7196//-- && insn[0] == 0x0F && insn[1] == 0xF4) {
7197//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmuludq",
7198//-- 0x66, insn[0], insn[1] );
7199//-- goto decode_success;
7200//-- }
7201//--
7202//-- /* 0xF5: PMADDWD(src)xmmreg-or-mem, (dst)xmmreg */
7203//-- if (sz == 2
7204//-- && insn[0] == 0x0F
7205//-- && insn[1] == 0xF5) {
7206//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmaddwd",
7207//-- 0x66, insn[0], insn[1] );
7208//-- goto decode_success;
7209//-- }
7210//--
7211//-- /* 0x74: PCMPEQB (src)xmmreg-or-mem, (dst)xmmreg */
7212//-- /* 0x75: PCMPEQW (src)xmmreg-or-mem, (dst)xmmreg */
7213//-- /* 0x76: PCMPEQD (src)xmmreg-or-mem, (dst)xmmreg */
7214//-- if (sz == 2
7215//-- && insn[0] == 0x0F
7216//-- && (insn[1] == 0x74 || insn[1] == 0x75 || insn[1] == 0x76)) {
7217//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pcmpeq{b,w,d}",
7218//-- 0x66, insn[0], insn[1] );
7219//-- goto decode_success;
7220//-- }
7221//--
7222//-- /* 0x64: PCMPGTB (src)xmmreg-or-mem, (dst)xmmreg */
7223//-- /* 0x65: PCMPGTW (src)xmmreg-or-mem, (dst)xmmreg */
7224//-- /* 0x66: PCMPGTD (src)xmmreg-or-mem, (dst)xmmreg */
7225//-- if (sz == 2
7226//-- && insn[0] == 0x0F
7227//-- && (insn[1] == 0x64 || insn[1] == 0x65 || insn[1] == 0x66)) {
7228//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pcmpgt{b,w,d}",
7229//-- 0x66, insn[0], insn[1] );
7230//-- goto decode_success;
7231//-- }
7232//--
7233//-- /* 0x63: PACKSSWB (src)xmmreg-or-mem, (dst)xmmreg */
7234//-- /* 0x6B: PACKSSDW (src)xmmreg-or-mem, (dst)xmmreg */
7235//-- if (sz == 2
7236//-- && insn[0] == 0x0F
7237//-- && (insn[1] == 0x63 || insn[1] == 0x6B)) {
7238//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "packss{wb,dw}",
7239//-- 0x66, insn[0], insn[1] );
7240//-- goto decode_success;
7241//-- }
7242//--
7243//-- /* 0x67: PACKUSWB (src)xmmreg-or-mem, (dst)xmmreg */
7244//-- if (sz == 2
7245//-- && insn[0] == 0x0F
7246//-- && insn[1] == 0x67) {
7247//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "packuswb",
7248//-- 0x66, insn[0], insn[1] );
7249//-- goto decode_success;
7250//-- }
7251//--
7252//-- /* 0xF1: PSLLW (src)xmmreg-or-mem, (dst)xmmreg */
7253//-- /* 0xF2: PSLLD (src)xmmreg-or-mem, (dst)xmmreg */
7254//-- /* 0xF3: PSLLQ (src)xmmreg-or-mem, (dst)xmmreg */
7255//-- if (sz == 2
7256//-- && insn[0] == 0x0F
7257//-- && (insn[1] == 0xF1 || insn[1] == 0xF2 || insn[1] == 0xF3)) {
7258//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psll{b,w,d}",
7259//-- 0x66, insn[0], insn[1] );
7260//-- goto decode_success;
7261//-- }
7262//--
7263//-- /* 0xD1: PSRLW (src)xmmreg-or-mem, (dst)xmmreg */
7264//-- /* 0xD2: PSRLD (src)xmmreg-or-mem, (dst)xmmreg */
7265//-- /* 0xD3: PSRLQ (src)xmmreg-or-mem, (dst)xmmreg */
7266//-- if (sz == 2
7267//-- && insn[0] == 0x0F
7268//-- && (insn[1] == 0xD1 || insn[1] == 0xD2 || insn[1] == 0xD3)) {
7269//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psrl{b,w,d}",
7270//-- 0x66, insn[0], insn[1] );
7271//-- goto decode_success;
7272//-- }
7273//--
7274//-- /* 0xE1: PSRAW (src)xmmreg-or-mem, (dst)xmmreg */
7275//-- /* 0xE2: PSRAD (src)xmmreg-or-mem, (dst)xmmreg */
7276//-- if (sz == 2
7277//-- && insn[0] == 0x0F
7278//-- && (insn[1] == 0xE1 || insn[1] == 0xE2)) {
7279//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psra{w,d}",
7280//-- 0x66, insn[0], insn[1] );
7281//-- goto decode_success;
7282//-- }
7283//--
7284//-- /* (U)COMISD (src)xmmreg-or-mem, (dst)xmmreg */
7285//-- if (sz == 2
7286//-- && insn[0] == 0x0F
7287//-- && ( insn[1] == 0x2E || insn[1] == 0x2F ) ) {
7288//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 8, "{u}comisd",
7289//-- 0x66, insn[0], insn[1] );
7290//-- vg_assert(LAST_UINSTR(cb).opcode == SSE3a_MemRd
7291//-- || LAST_UINSTR(cb).opcode == SSE4);
7292//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
7293//-- goto decode_success;
7294//-- }
7295//--
7296//-- /* (U)COMISS (src)xmmreg-or-mem, (dst)xmmreg */
7297//-- if (sz == 4
7298//-- && insn[0] == 0x0F
7299//-- && ( insn[1] == 0x2E || insn[ 1 ] == 0x2F )) {
7300//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 4, "{u}comiss",
7301//-- insn[0], insn[1] );
7302//-- vg_assert(LAST_UINSTR(cb).opcode == SSE2a_MemRd
7303//-- || LAST_UINSTR(cb).opcode == SSE3);
7304//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
7305//-- goto decode_success;
7306//-- }
7307//--
7308//-- /* MOVSD -- move 8 bytes of XMM reg to/from XMM reg or mem. */
7309//-- if (insn[0] == 0xF2
7310//-- && insn[1] == 0x0F
7311//-- && (insn[2] == 0x11 || insn[2] == 0x10)) {
7312//-- vg_assert(sz == 4);
7313//-- eip = dis_SSE3_load_store_or_mov
7314//-- ( cb, sorb, eip+3, 8, insn[2]==0x11, "movsd",
sewardj5bd4d162004-11-10 13:02:48 +00007315//-- insn[0], insn[1], insn[2] );
sewardjc9a65702004-07-07 16:32:57 +00007316//-- goto decode_success;
7317//-- }
7318//--
7319//-- /* MOVQ -- move 8 bytes of XMM reg to XMM reg or mem. How
7320//-- does this differ from MOVSD ?? */
7321//-- if (sz == 2
7322//-- && insn[0] == 0x0F
7323//-- && insn[1] == 0xD6) {
7324//-- eip = dis_SSE3_load_store_or_mov
7325//-- ( cb, sorb, eip+2, 8, True /*store*/, "movq",
7326//-- 0x66, insn[0], insn[1] );
7327//-- goto decode_success;
7328//-- }
7329//--
7330//-- /* MOVQ -- move 8 bytes of XMM reg or mem to XMM reg. How
7331//-- does this differ from MOVSD ?? */
7332//-- if (insn[0] == 0xF3
7333//-- && insn[1] == 0x0F
7334//-- && insn[2] == 0x7E) {
7335//-- eip = dis_SSE3_load_store_or_mov
7336//-- ( cb, sorb, eip+3, 8, False /*load*/, "movq",
7337//-- insn[0], insn[1], insn[2] );
7338//-- goto decode_success;
7339//-- }
7340//--
7341//-- /* MOVDQ2Q -- move low 4 bytes of XMM reg to MMX reg. */
7342//-- if (insn[0] == 0xF2
7343//-- && insn[1] == 0x0F
7344//-- && insn[2] == 0xD6) {
7345//-- eip = dis_SSE3_to_MMX
7346//-- ( cb, sorb, eip+3, 8, "movdq2q",
7347//-- insn[0], insn[1], insn[2] );
7348//-- goto decode_success;
7349//-- }
7350//--
7351//-- /* MOVQ2DQ -- move MMX reg to low 4 bytes of XMM reg. */
7352//-- if (insn[0] == 0xF3
7353//-- && insn[1] == 0x0F
7354//-- && insn[2] == 0xD6) {
7355//-- eip = dis_SSE3_from_MMX
7356//-- ( cb, sorb, eip+3, 8, "movq2dq",
7357//-- insn[0], insn[1], insn[2] );
7358//-- goto decode_success;
7359//-- }
7360//--
7361//-- /* MOVSS -- move 4 bytes of XMM reg to/from XMM reg or mem. */
7362//-- if (insn[0] == 0xF3
7363//-- && insn[1] == 0x0F
7364//-- && (insn[2] == 0x11 || insn[2] == 0x10)) {
7365//-- vg_assert(sz == 4);
7366//-- eip = dis_SSE3_load_store_or_mov
7367//-- ( cb, sorb, eip+3, 4, insn[2]==0x11, "movss",
7368//-- insn[0], insn[1], insn[2] );
7369//-- goto decode_success;
7370//-- }
7371//--
7372//-- /* I don't understand how MOVAPD differs from MOVAPS. */
7373//-- /* MOVAPD (28,29) -- aligned load/store of xmm reg, or xmm-xmm reg
7374//-- move */
7375//-- if (sz == 2
7376//-- && insn[0] == 0x0F && insn[1] == 0x28) {
7377//-- UChar* name = "movapd";
7378//-- //(insn[1] == 0x10 || insn[1] == 0x11)
7379//-- // ? "movups" : "movaps";
7380//-- Bool store = False; //insn[1] == 0x29 || insn[1] == 11;
7381//-- eip = dis_SSE3_load_store_or_mov
7382//-- ( cb, sorb, eip+2, 16, store, name,
7383//-- 0x66, insn[0], insn[1] );
7384//-- goto decode_success;
7385//-- }
7386//--
7387//-- /* sz==4: MOVAPS (28,29) -- aligned load/store of xmm reg, or
7388//-- xmm-xmm reg move */
7389//-- /* sz==4: MOVUPS (10,11) -- unaligned load/store of xmm reg, or
7390//-- xmm-xmm reg move */
7391//-- /* sz==2: MOVAPD (28,29) -- aligned load/store of xmm reg, or
7392//-- xmm-xmm reg move */
7393//-- /* sz==2: MOVUPD (10,11) -- unaligned load/store of xmm reg, or
7394//-- xmm-xmm reg move */
7395//-- if (insn[0] == 0x0F && (insn[1] == 0x28
7396//-- || insn[1] == 0x29
7397//-- || insn[1] == 0x10
7398//-- || insn[1] == 0x11)) {
7399//-- UChar* name = (insn[1] == 0x10 || insn[1] == 0x11)
7400//-- ? "movups" : "movaps";
7401//-- Bool store = insn[1] == 0x29 || insn[1] == 11;
7402//-- vg_assert(sz == 2 || sz == 4);
7403//-- if (sz == 4) {
7404//-- eip = dis_SSE2_load_store_or_mov
7405//-- ( cb, sorb, eip+2, 16, store, name,
7406//-- insn[0], insn[1] );
7407//-- } else {
7408//-- eip = dis_SSE3_load_store_or_mov
7409//-- ( cb, sorb, eip+2, 16, store, name,
7410//-- 0x66, insn[0], insn[1] );
7411//-- }
7412//-- goto decode_success;
7413//-- }
7414//--
7415//-- /* MOVDQA -- aligned 16-byte load/store. */
7416//-- if (sz == 2
7417//-- && insn[0] == 0x0F
7418//-- && (insn[1] == 0x6F || insn[1] == 0x7F)) {
7419//-- Bool is_store = insn[1]==0x7F;
7420//-- eip = dis_SSE3_load_store_or_mov
7421//-- (cb, sorb, eip+2, 16, is_store, "movdqa",
7422//-- 0x66, insn[0], insn[1] );
7423//-- goto decode_success;
7424//-- }
7425//--
7426//-- /* MOVDQU -- unaligned 16-byte load/store. */
7427//-- if (insn[0] == 0xF3
7428//-- && insn[1] == 0x0F
7429//-- && (insn[2] == 0x6F || insn[2] == 0x7F)) {
7430//-- Bool is_store = insn[2]==0x7F;
7431//-- eip = dis_SSE3_load_store_or_mov
7432//-- (cb, sorb, eip+3, 16, is_store, "movdqu",
7433//-- insn[0], insn[1], insn[2] );
7434//-- goto decode_success;
7435//-- }
7436//--
7437//-- /* MOVNTDQ -- 16-byte store with temporal hint (which we
7438//-- ignore). */
7439//-- if (sz == 2
7440//-- && insn[0] == 0x0F
7441//-- && insn[1] == 0xE7) {
7442//-- eip = dis_SSE3_load_store_or_mov
7443//-- (cb, sorb, eip+2, 16, True /* is_store */, "movntdq",
7444//-- 0x66, insn[0], insn[1] );
7445//-- goto decode_success;
7446//-- }
7447//--
7448//-- /* MOVNTPS -- 16-byte store with temporal hint (which we
7449//-- ignore). */
7450//-- if (insn[0] == 0x0F
7451//-- && insn[1] == 0x2B) {
7452//-- eip = dis_SSE2_load_store_or_mov
7453//-- (cb, sorb, eip+2, 16, True /* is_store */, "movntps",
7454//-- insn[0], insn[1] );
7455//-- goto decode_success;
7456//-- }
7457//--
7458//-- /* MOVNTPD -- 16-byte store with temporal hint (which we
7459//-- ignore). */
7460//-- if (sz == 2
7461//-- && insn[0] == 0x0F
7462//-- && insn[1] == 0x2B) {
7463//-- eip = dis_SSE3_load_store_or_mov
7464//-- (cb, sorb, eip+2, 16, True /* is_store */, "movntpd",
7465//-- 0x66, insn[0], insn[1] );
7466//-- goto decode_success;
7467//-- }
7468//--
7469//-- /* MOVD -- 4-byte move between xmmregs and (ireg or memory). */
7470//-- if (sz == 2
7471//-- && insn[0] == 0x0F
7472//-- && (insn[1] == 0x6E || insn[1] == 0x7E)) {
7473//-- Bool is_store = insn[1]==0x7E;
7474//-- modrm = insn[2];
7475//-- if (epartIsReg(modrm) && is_store) {
7476//-- t1 = newTemp(cb);
7477//-- uInstr3(cb, SSE3e_RegWr, 4,
7478//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
7479//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
7480//-- TempReg, t1 );
sewardj5bd4d162004-11-10 13:02:48 +00007481//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, eregOfRM(modrm));
7482//-- DIP("movd %s, %s\n",
sewardjc9a65702004-07-07 16:32:57 +00007483//-- nameXMMReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
7484//-- eip += 3;
7485//-- } else
7486//-- if (epartIsReg(modrm) && !is_store) {
7487//-- t1 = newTemp(cb);
sewardj5bd4d162004-11-10 13:02:48 +00007488//-- uInstr2(cb, GET, 4, ArchReg, eregOfRM(modrm), TempReg, t1);
sewardjc9a65702004-07-07 16:32:57 +00007489//-- uInstr3(cb, SSE3e_RegRd, 4,
7490//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
7491//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
7492//-- TempReg, t1 );
sewardj5bd4d162004-11-10 13:02:48 +00007493//-- DIP("movd %s, %s\n",
sewardjc9a65702004-07-07 16:32:57 +00007494//-- nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
7495//-- eip += 3;
7496//-- } else {
7497//-- eip = dis_SSE3_load_store_or_mov
7498//-- (cb, sorb, eip+2, 4, is_store, "movd",
7499//-- 0x66, insn[0], insn[1] );
7500//-- }
7501//-- goto decode_success;
7502//-- }
7503//--
7504//-- /* PEXTRW from SSE register; writes ireg */
7505//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC5) {
7506//-- t1 = newTemp(cb);
7507//-- modrm = insn[2];
7508//-- vg_assert(epartIsReg(modrm));
7509//-- vg_assert((modrm & 0xC0) == 0xC0);
7510//-- uInstr3(cb, SSE3g1_RegWr, 4,
7511//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
7512//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
7513//-- TempReg, t1 );
7514//-- uLiteral(cb, insn[3]);
7515//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
7516//-- DIP("pextrw %s, %d, %s\n",
7517//-- nameXMMReg(eregOfRM(modrm)), (Int)insn[3],
7518//-- nameIReg(4, gregOfRM(modrm)));
7519//-- eip += 4;
7520//-- goto decode_success;
7521//-- }
7522//--
7523//-- /* PINSRW to SSE register; reads mem or ireg */
7524//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC4) {
7525//-- t1 = newTemp(cb);
7526//-- modrm = insn[2];
7527//-- if (epartIsReg(modrm)) {
7528//-- uInstr2(cb, GET, 2, ArchReg, eregOfRM(modrm), TempReg, t1);
7529//-- vg_assert(epartIsReg(modrm));
7530//-- uInstr3(cb, SSE3e1_RegRd, 2,
7531//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
7532//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
7533//-- TempReg, t1 );
7534//-- uLiteral(cb, insn[3]);
7535//-- DIP("pinsrw %s, %d, %s\n",
7536//-- nameIReg(2, eregOfRM(modrm)), (Int)insn[3],
7537//-- nameXMMReg(gregOfRM(modrm)));
7538//-- eip += 4;
7539//-- } else {
sewardj5bd4d162004-11-10 13:02:48 +00007540//-- VG_(core_panic)("PINSRW mem");
sewardjc9a65702004-07-07 16:32:57 +00007541//-- }
7542//-- goto decode_success;
7543//-- }
7544//--
7545//-- /* SQRTSD: square root of scalar double. */
7546//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x51) {
7547//-- vg_assert(sz == 4);
7548//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8,
7549//-- "sqrtsd",
7550//-- insn[0], insn[1], insn[2] );
7551//-- goto decode_success;
7552//-- }
7553//--
7554//-- /* SQRTSS: square root of scalar float. */
7555//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x51) {
7556//-- vg_assert(sz == 4);
7557//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4,
7558//-- "sqrtss",
7559//-- insn[0], insn[1], insn[2] );
7560//-- goto decode_success;
7561//-- }
7562//--
7563//-- /* RSQRTSS: square root reciprocal of scalar float. */
7564//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x52) {
7565//-- vg_assert(sz == 4);
7566//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4,
7567//-- "sqrtss",
7568//-- insn[0], insn[1], insn[2] );
7569//-- goto decode_success;
7570//-- }
7571//--
7572//-- /* 0xF3: RCPSS -- reciprocal of scalar float */
7573//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x53) {
7574//-- vg_assert(sz == 4);
7575//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4,
7576//-- "rcpss",
7577//-- insn[0], insn[1], insn[2] );
7578//-- goto decode_success;
7579//-- }
7580//--
7581//-- /* MOVMSKPD -- extract 2 sign bits from a xmm reg and copy them to
7582//-- an ireg. Top 30 bits of ireg are set to zero. */
7583//-- /* MOVMSKPS -- extract 4 sign bits from a xmm reg and copy them to
7584//-- an ireg. Top 28 bits of ireg are set to zero. */
7585//-- if (insn[0] == 0x0F && insn[1] == 0x50) {
7586//-- vg_assert(sz == 4 || sz == 2);
7587//-- modrm = insn[2];
7588//-- /* Intel docs don't say anything about a memory source being
sewardj5bd4d162004-11-10 13:02:48 +00007589//-- allowed here. */
sewardjc9a65702004-07-07 16:32:57 +00007590//-- vg_assert(epartIsReg(modrm));
7591//-- t1 = newTemp(cb);
7592//-- if (sz == 4) {
7593//-- uInstr3(cb, SSE2g_RegWr, 4,
7594//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
7595//-- Lit16, (UShort)modrm,
7596//-- TempReg, t1 );
7597//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
7598//-- } else {
7599//-- uInstr3(cb, SSE3g_RegWr, 4,
7600//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
7601//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
7602//-- TempReg, t1 );
7603//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
7604//-- }
7605//-- DIP("movmskp%c %s, %s\n", sz == 4 ? 's' : 'd',
7606//-- nameXMMReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)));
7607//-- eip += 3;
7608//-- goto decode_success;
7609//-- }
7610//--
7611//-- /* ANDNPS */
7612//-- /* 0x66: ANDNPD (src)xmmreg-or-mem, (dst)xmmreg */
7613//-- if (insn[0] == 0x0F && insn[1] == 0x55) {
7614//-- vg_assert(sz == 4 || sz == 2);
7615//-- if (sz == 4) {
7616//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "andnps",
7617//-- insn[0], insn[1] );
7618//-- } else {
7619//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "andnpd",
7620//-- 0x66, insn[0], insn[1] );
7621//-- }
7622//-- goto decode_success;
7623//-- }
7624//--
7625//-- /* MOVHLPS -- move two packed floats from high quadword to low quadword */
7626//-- /* MOVLPS -- load/store two packed floats to/from low quadword. */
7627//-- /* MOVLPD -- load/store packed double to/from low quadword. */
7628//-- if (insn[0] == 0x0F
7629//-- && (insn[1] == 0x12 || insn[1] == 0x13)) {
7630//-- Bool is_store = insn[1]==0x13;
7631//-- vg_assert(sz == 4 || sz == 2);
7632//-- if (sz == 4) {
7633//-- if (epartIsReg(insn[2])) {
7634//-- vg_assert(insn[1]==0x12);
7635//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "movhlps",
7636//-- insn[0], insn[1] );
7637//-- } else {
7638//-- eip = dis_SSE2_load_store_or_mov
7639//-- (cb, sorb, eip+2, 8, is_store, "movlps",
7640//-- insn[0], insn[1] );
7641//-- }
7642//-- } else {
7643//-- vg_assert(!epartIsReg(insn[2]));
7644//-- eip = dis_SSE3_load_store_or_mov
7645//-- (cb, sorb, eip+2, 8, is_store, "movlpd",
7646//-- 0x66, insn[0], insn[1] );
7647//-- }
7648//-- goto decode_success;
7649//-- }
7650//--
7651//-- /* MOVLHPS -- move two packed floats from low quadword to high quadword */
7652//-- /* MOVHPS -- load/store two packed floats to/from high quadword. */
7653//-- /* MOVHPD -- load/store packed double to/from high quadword. */
7654//-- if (insn[0] == 0x0F
7655//-- && (insn[1] == 0x16 || insn[1] == 0x17)) {
7656//-- Bool is_store = insn[1]==0x17;
7657//-- vg_assert(sz == 4 || sz == 2);
7658//-- if (sz == 4) {
7659//-- if (epartIsReg(insn[2])) {
7660//-- vg_assert(insn[1]==0x16);
7661//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "movlhps",
7662//-- insn[0], insn[1] );
7663//-- } else {
7664//-- eip = dis_SSE2_load_store_or_mov
7665//-- (cb, sorb, eip+2, 8, is_store, "movhps",
7666//-- insn[0], insn[1] );
7667//-- }
7668//-- } else {
7669//-- vg_assert(!epartIsReg(insn[2]));
7670//-- eip = dis_SSE3_load_store_or_mov
7671//-- (cb, sorb, eip+2, 8, is_store, "movhpd",
7672//-- 0x66, insn[0], insn[1] );
7673//-- }
7674//-- goto decode_success;
7675//-- }
7676//--
7677//-- /* PMOVMSKB -- extract 16 sign bits from a xmm reg and copy them to
7678//-- an ireg. Top 16 bits of ireg are set to zero. */
7679//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD7) {
7680//-- modrm = insn[2];
7681//-- /* Intel docs don't say anything about a memory source being
sewardj5bd4d162004-11-10 13:02:48 +00007682//-- allowed here. */
sewardjc9a65702004-07-07 16:32:57 +00007683//-- vg_assert(epartIsReg(modrm));
7684//-- t1 = newTemp(cb);
7685//-- uInstr3(cb, SSE3g_RegWr, 4,
7686//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
7687//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
7688//-- TempReg, t1 );
7689//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
7690//-- DIP("pmovmskb %s, %s\n",
7691//-- nameXMMReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)));
7692//-- eip += 3;
7693//-- goto decode_success;
7694//-- }
7695//--
7696//-- /* sz==4: SQRTPS: square root of packed float. */
7697//-- /* sz==2: SQRTPD: square root of packed double. */
7698//-- if (insn[0] == 0x0F && insn[1] == 0x51) {
7699//-- vg_assert(sz == 2 || sz == 4);
7700//-- if (sz == 4) {
7701//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16,
7702//-- "sqrtps",
7703//-- insn[0], insn[1] );
7704//-- } else {
7705//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16,
7706//-- "sqrtpd",
7707//-- 0x66, insn[0], insn[1] );
7708//-- }
7709//-- goto decode_success;
7710//-- }
7711//--
7712//-- /* RSQRTPS: square root reciprocal of packed float. */
7713//-- if (insn[0] == 0x0F && insn[1] == 0x52) {
7714//-- vg_assert(sz == 4);
7715//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16,
7716//-- "rsqrtps",
7717//-- insn[0], insn[1] );
7718//-- goto decode_success;
7719//-- }
7720//--
7721//-- /* Fall through into the non-SSE decoder. */
7722//--
7723//-- } /* if (VG_(have_ssestate)) */
7724
7725
7726 /* ---------------------------------------------------- */
7727 /* --- end of the SSE/SSE2 decoder. --- */
7728 /* ---------------------------------------------------- */
7729
7730 /* Get the primary opcode. */
7731 opc = getIByte(delta); delta++;
7732
7733 /* We get here if the current insn isn't SSE, or this CPU doesn't
7734 support SSE. */
7735
7736 switch (opc) {
7737
7738 /* ------------------------ Control flow --------------- */
sewardj940e8c92004-07-11 16:53:24 +00007739
7740 case 0xC2: /* RET imm16 */
7741 d32 = getUDisp16(delta);
7742 delta += 2;
7743 dis_ret(d32);
sewardjce70a5c2004-10-18 14:09:54 +00007744 whatNext = Dis_StopHere;
sewardj940e8c92004-07-11 16:53:24 +00007745 DIP("ret %d\n", d32);
7746 break;
sewardje05c42c2004-07-08 20:25:10 +00007747 case 0xC3: /* RET */
7748 dis_ret(0);
sewardjce70a5c2004-10-18 14:09:54 +00007749 whatNext = Dis_StopHere;
sewardje05c42c2004-07-08 20:25:10 +00007750 DIP("ret\n");
7751 break;
sewardjd1061ab2004-07-08 01:45:30 +00007752
7753 case 0xE8: /* CALL J4 */
7754 d32 = getUDisp32(delta); delta += 4;
sewardjce70a5c2004-10-18 14:09:54 +00007755 d32 += (guest_eip_bbstart+delta);
7756 /* (guest_eip_bbstart+delta) == return-to addr, d32 == call-to addr */
7757 if (d32 == guest_eip_bbstart+delta && getIByte(delta) >= 0x58
7758 && getIByte(delta) <= 0x5F) {
sewardjd1061ab2004-07-08 01:45:30 +00007759 /* Specially treat the position-independent-code idiom
7760 call X
7761 X: popl %reg
7762 as
7763 movl %eip, %reg.
7764 since this generates better code, but for no other reason. */
7765 Int archReg = getIByte(delta) - 0x58;
sewardjc2ac51e2004-07-12 01:03:26 +00007766 /* vex_printf("-- fPIC thingy\n"); */
sewardjce70a5c2004-10-18 14:09:54 +00007767 putIReg(4, archReg, mkU32(guest_eip_bbstart+delta));
sewardjd1061ab2004-07-08 01:45:30 +00007768 delta++; /* Step over the POP */
7769 DIP("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
sewardjc2ac51e2004-07-12 01:03:26 +00007770 } else {
sewardjd1061ab2004-07-08 01:45:30 +00007771 /* The normal sequence for a call. */
7772 t1 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +00007773 assign(t1, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
7774 putIReg(4, R_ESP, mkexpr(t1));
sewardj5bd4d162004-11-10 13:02:48 +00007775 storeLE( mkexpr(t1), mkU32(guest_eip_bbstart+delta));
7776 if (resteerOK && resteerOkFn((Addr64)(Addr32)d32)) {
sewardjce70a5c2004-10-18 14:09:54 +00007777 /* follow into the call target. */
7778 whatNext = Dis_Resteer;
7779 *whereNext = d32;
7780 } else {
7781 jmp_lit(Ijk_Call,d32);
7782 whatNext = Dis_StopHere;
7783 }
sewardjd1061ab2004-07-08 01:45:30 +00007784 DIP("call 0x%x\n",d32);
7785 }
7786 break;
7787
sewardjc9a65702004-07-07 16:32:57 +00007788//-- case 0xC8: /* ENTER */
7789//-- d32 = getUDisp16(eip); eip += 2;
7790//-- abyte = getIByte(delta); delta++;
7791//--
7792//-- vg_assert(sz == 4);
7793//-- vg_assert(abyte == 0);
7794//--
7795//-- t1 = newTemp(cb); t2 = newTemp(cb);
7796//-- uInstr2(cb, GET, sz, ArchReg, R_EBP, TempReg, t1);
7797//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
7798//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
7799//-- uLiteral(cb, sz);
7800//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
7801//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
7802//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
7803//-- if (d32) {
7804//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
sewardj5bd4d162004-11-10 13:02:48 +00007805//-- uLiteral(cb, d32);
7806//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
sewardjc9a65702004-07-07 16:32:57 +00007807//-- }
7808//-- DIP("enter 0x%x, 0x%x", d32, abyte);
7809//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +00007810
7811 case 0xC9: /* LEAVE */
7812 vassert(sz == 4);
7813 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
7814 assign(t1, getIReg(4,R_EBP));
7815 /* First PUT ESP looks redundant, but need it because ESP must
7816 always be up-to-date for Memcheck to work... */
7817 putIReg(4, R_ESP, mkexpr(t1));
7818 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
7819 putIReg(4, R_EBP, mkexpr(t2));
7820 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(4)) );
7821 DIP("leave\n");
7822 break;
7823
sewardjc9a65702004-07-07 16:32:57 +00007824//-- /* ---------------- Misc weird-ass insns --------------- */
7825//--
7826//-- case 0x27: /* DAA */
7827//-- case 0x2F: /* DAS */
7828//-- t1 = newTemp(cb);
7829//-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
7830//-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
7831//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
7832//-- uWiden(cb, 1, False);
7833//-- uInstr0(cb, CALLM_S, 0);
7834//-- uInstr1(cb, PUSH, 4, TempReg, t1);
7835//-- uInstr1(cb, CALLM, 0, Lit16,
7836//-- opc == 0x27 ? VGOFF_(helper_DAA) : VGOFF_(helper_DAS) );
7837//-- uFlagsRWU(cb, FlagsAC, FlagsSZACP, FlagO);
7838//-- uInstr1(cb, POP, 4, TempReg, t1);
7839//-- uInstr0(cb, CALLM_E, 0);
7840//-- uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
7841//-- DIP(opc == 0x27 ? "daa\n" : "das\n");
7842//-- break;
7843//--
7844//-- case 0x37: /* AAA */
7845//-- case 0x3F: /* AAS */
7846//-- t1 = newTemp(cb);
7847//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
7848//-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
7849//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
7850//-- uWiden(cb, 2, False);
7851//-- uInstr0(cb, CALLM_S, 0);
7852//-- uInstr1(cb, PUSH, 4, TempReg, t1);
7853//-- uInstr1(cb, CALLM, 0, Lit16,
7854//-- opc == 0x37 ? VGOFF_(helper_AAA) : VGOFF_(helper_AAS) );
7855//-- uFlagsRWU(cb, FlagA, FlagsAC, FlagsEmpty);
7856//-- uInstr1(cb, POP, 4, TempReg, t1);
7857//-- uInstr0(cb, CALLM_E, 0);
7858//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
7859//-- DIP(opc == 0x37 ? "aaa\n" : "aas\n");
7860//-- break;
7861//--
7862//-- case 0xD4: /* AAM */
7863//-- case 0xD5: /* AAD */
7864//-- d32 = getIByte(delta); delta++;
7865//-- if (d32 != 10) VG_(core_panic)("disInstr: AAM/AAD but base not 10 !");
7866//-- t1 = newTemp(cb);
7867//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
7868//-- /* Widen %AX to 32 bits, so it's all defined when we push it. */
7869//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
7870//-- uWiden(cb, 2, False);
7871//-- uInstr0(cb, CALLM_S, 0);
7872//-- uInstr1(cb, PUSH, 4, TempReg, t1);
7873//-- uInstr1(cb, CALLM, 0, Lit16,
7874//-- opc == 0xD4 ? VGOFF_(helper_AAM) : VGOFF_(helper_AAD) );
7875//-- uFlagsRWU(cb, FlagsEmpty, FlagsSZP, FlagsEmpty);
7876//-- uInstr1(cb, POP, 4, TempReg, t1);
7877//-- uInstr0(cb, CALLM_E, 0);
7878//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
7879//-- DIP(opc == 0xD4 ? "aam\n" : "aad\n");
7880//-- break;
sewardj1c6f9912004-09-07 10:15:24 +00007881
7882 /* ------------------------ CWD/CDQ -------------------- */
7883
7884 case 0x98: /* CBW */
7885 if (sz == 4) {
7886 putIReg(4, R_EAX, unop(Iop_16Sto32, getIReg(2, R_EAX)));
7887 DIP("cwde\n");
7888 } else {
sewardj47341042004-09-19 11:55:46 +00007889 vassert(sz == 2);
7890 putIReg(2, R_EAX, unop(Iop_8Sto16, getIReg(1, R_EAX)));
7891 DIP("cbw\n");
sewardj1c6f9912004-09-07 10:15:24 +00007892 }
7893 break;
sewardj64e1d652004-07-12 14:00:46 +00007894
7895 case 0x99: /* CWD/CDQ */
7896 ty = szToITy(sz);
7897 putIReg(sz, R_EDX,
7898 binop(mkSizedOp(ty,Iop_Sar8),
7899 getIReg(sz, R_EAX),
sewardj5bd4d162004-11-10 13:02:48 +00007900 mkU8(sz == 2 ? 15 : 31)) );
sewardj64e1d652004-07-12 14:00:46 +00007901 DIP(sz == 2 ? "cwdq\n" : "cdqq\n");
7902 break;
7903
sewardjbdc7d212004-09-09 02:46:40 +00007904 /* ------------------------ FPU ops -------------------- */
7905
7906 case 0x9E: /* SAHF */
7907 codegen_SAHF();
7908 DIP("sahf\n");
7909 break;
7910
sewardjc9a65702004-07-07 16:32:57 +00007911//-- case 0x9F: /* LAHF */
7912//-- codegen_LAHF ( cb );
7913//-- DIP("lahf\n");
7914//-- break;
7915//--
sewardjbdc7d212004-09-09 02:46:40 +00007916 case 0x9B: /* FWAIT */
7917 /* ignore? */
7918 DIP("fwait\n");
7919 break;
7920
sewardjd1725d12004-08-12 20:46:53 +00007921 case 0xD8:
7922 case 0xD9:
7923 case 0xDA:
7924 case 0xDB:
7925 case 0xDC:
7926 case 0xDD:
7927 case 0xDE:
7928 case 0xDF: {
7929 UInt delta0 = delta;
7930 Bool decode_OK = False;
7931 delta = dis_FPU ( &decode_OK, sorb, delta );
7932 if (!decode_OK) {
7933 delta = delta0;
7934 goto decode_failure;
7935 }
7936 break;
7937 }
sewardj0611d802004-07-11 02:37:54 +00007938
7939 /* ------------------------ INC & DEC ------------------ */
7940
7941 case 0x40: /* INC eAX */
7942 case 0x41: /* INC eCX */
7943 case 0x42: /* INC eDX */
7944 case 0x43: /* INC eBX */
7945 case 0x44: /* INC eSP */
7946 case 0x45: /* INC eBP */
7947 case 0x46: /* INC eSI */
7948 case 0x47: /* INC eDI */
7949 vassert(sz == 2 || sz == 4);
7950 ty = szToITy(sz);
7951 t1 = newTemp(ty);
7952 assign( t1, binop(mkSizedOp(ty,Iop_Add8),
7953 getIReg(sz, (UInt)(opc - 0x40)),
7954 mkU(ty,1)) );
7955 setFlags_INC_DEC( True, t1, ty );
7956 putIReg(sz, (UInt)(opc - 0x40), mkexpr(t1));
7957 DIP("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
7958 break;
7959
7960 case 0x48: /* DEC eAX */
7961 case 0x49: /* DEC eCX */
7962 case 0x4A: /* DEC eDX */
7963 case 0x4B: /* DEC eBX */
7964 case 0x4C: /* DEC eSP */
7965 case 0x4D: /* DEC eBP */
7966 case 0x4E: /* DEC eSI */
7967 case 0x4F: /* DEC eDI */
7968 vassert(sz == 2 || sz == 4);
7969 ty = szToITy(sz);
7970 t1 = newTemp(ty);
7971 assign( t1, binop(mkSizedOp(ty,Iop_Sub8),
7972 getIReg(sz, (UInt)(opc - 0x48)),
7973 mkU(ty,1)) );
7974 setFlags_INC_DEC( False, t1, ty );
7975 putIReg(sz, (UInt)(opc - 0x48), mkexpr(t1));
7976 DIP("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
7977 break;
7978
7979 /* ------------------------ INT ------------------------ */
7980
7981 case 0xCD: /* INT imm8 */
7982 d32 = getIByte(delta); delta++;
7983 if (d32 != 0x80) goto decode_failure;
7984 /* It's important that all ArchRegs carry their up-to-date value
7985 at this point. So we declare an end-of-block here, which
7986 forces any TempRegs caching ArchRegs to be flushed. */
sewardj4fd30f22004-10-25 00:42:16 +00007987 jmp_lit(Ijk_Syscall,((Addr32)guest_eip_bbstart)+delta);
sewardjce70a5c2004-10-18 14:09:54 +00007988 whatNext = Dis_StopHere;
sewardj0611d802004-07-11 02:37:54 +00007989 DIP("int $0x80\n");
7990 break;
7991
sewardj77b86be2004-07-11 13:28:24 +00007992 /* ------------------------ Jcond, byte offset --------- */
7993
7994 case 0xEB: /* Jb (jump, byte offset) */
sewardj4fd30f22004-10-25 00:42:16 +00007995 d32 = (((Addr32)guest_eip_bbstart)+delta+1) + getSDisp8(delta);
sewardj77b86be2004-07-11 13:28:24 +00007996 delta++;
sewardj5bd4d162004-11-10 13:02:48 +00007997 if (resteerOK && resteerOkFn((Addr64)(Addr32)d32)) {
sewardjce70a5c2004-10-18 14:09:54 +00007998 whatNext = Dis_Resteer;
7999 *whereNext = d32;
8000 } else {
8001 jmp_lit(Ijk_Boring,d32);
8002 whatNext = Dis_StopHere;
8003 }
sewardj77b86be2004-07-11 13:28:24 +00008004 DIP("jmp-8 0x%x\n", d32);
8005 break;
sewardj0611d802004-07-11 02:37:54 +00008006
8007 case 0xE9: /* Jv (jump, 16/32 offset) */
8008 vassert(sz == 4); /* JRS added 2004 July 11 */
sewardj4fd30f22004-10-25 00:42:16 +00008009 d32 = (((Addr32)guest_eip_bbstart)+delta+sz) + getSDisp(sz,delta);
sewardj0611d802004-07-11 02:37:54 +00008010 delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00008011 if (resteerOK && resteerOkFn((Addr64)(Addr32)d32)) {
sewardjce70a5c2004-10-18 14:09:54 +00008012 whatNext = Dis_Resteer;
8013 *whereNext = d32;
8014 } else {
8015 jmp_lit(Ijk_Boring,d32);
8016 whatNext = Dis_StopHere;
8017 }
sewardj0611d802004-07-11 02:37:54 +00008018 DIP("jmp 0x%x\n", d32);
8019 break;
sewardje87b4842004-07-10 12:23:30 +00008020
8021 case 0x70:
8022 case 0x71:
8023 case 0x72: /* JBb/JNAEb (jump below) */
8024 case 0x73: /* JNBb/JAEb (jump not below) */
8025 case 0x74: /* JZb/JEb (jump zero) */
8026 case 0x75: /* JNZb/JNEb (jump not zero) */
8027 case 0x76: /* JBEb/JNAb (jump below or equal) */
8028 case 0x77: /* JNBEb/JAb (jump not below or equal) */
8029 case 0x78: /* JSb (jump negative) */
8030 case 0x79: /* JSb (jump not negative) */
8031 case 0x7A: /* JP (jump parity even) */
8032 case 0x7B: /* JNP/JPO (jump parity odd) */
8033 case 0x7C: /* JLb/JNGEb (jump less) */
8034 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
8035 case 0x7E: /* JLEb/JNGb (jump less or equal) */
8036 case 0x7F: /* JGb/JNLEb (jump greater) */
sewardj4fd30f22004-10-25 00:42:16 +00008037 d32 = (((Addr32)guest_eip_bbstart)+delta+1) + getSDisp8(delta);
sewardje87b4842004-07-10 12:23:30 +00008038 delta++;
sewardj4fd30f22004-10-25 00:42:16 +00008039 jcc_01((Condcode)(opc - 0x70), (Addr32)(guest_eip_bbstart+delta), d32);
sewardjce70a5c2004-10-18 14:09:54 +00008040 whatNext = Dis_StopHere;
sewardje87b4842004-07-10 12:23:30 +00008041 DIP("j%s-8 0x%x\n", name_Condcode(opc - 0x70), d32);
8042 break;
8043
sewardj458a6f82004-08-25 12:46:02 +00008044 case 0xE3: /* JECXZ or perhaps JCXZ, depending on OSO ? Intel
8045 manual says it depends on address size override,
8046 which doesn't sound right to me. */
8047 vassert(sz==4); /* possibly also OK for sz==2 */
sewardj4fd30f22004-10-25 00:42:16 +00008048 d32 = (((Addr32)guest_eip_bbstart)+delta+1) + getSDisp8(delta);
sewardj458a6f82004-08-25 12:46:02 +00008049 delta++;
8050 ty = szToITy(sz);
8051 stmt( IRStmt_Exit(
8052 binop(mkSizedOp(ty,Iop_CmpEQ8),
8053 getIReg(sz,R_ECX),
8054 mkU(ty,0)),
8055 IRConst_U32(d32))
8056 );
8057
8058 DIP("j%sz 0x%x\n", nameIReg(sz, R_ECX), d32);
8059 break;
8060
sewardjc9a65702004-07-07 16:32:57 +00008061//-- case 0xE0: /* LOOPNE disp8 */
8062//-- case 0xE1: /* LOOPE disp8 */
8063//-- case 0xE2: /* LOOP disp8 */
8064//-- /* Again, the docs say this uses ECX/CX as a count depending on
8065//-- the address size override, not the operand one. Since we
8066//-- don't handle address size overrides, I guess that means
8067//-- ECX. */
8068//-- d32 = (eip+1) + getSDisp8(eip); eip++;
8069//-- t1 = newTemp(cb);
8070//-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
8071//-- uInstr1(cb, DEC, 4, TempReg, t1);
8072//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ECX);
8073//-- uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
8074//-- uLiteral(cb, eip);
8075//-- if (opc == 0xE0 || opc == 0xE1) { /* LOOPE/LOOPNE */
8076//-- jcc_lit(cb, eip, (opc == 0xE1 ? CondNZ : CondZ));
8077//-- }
8078//-- jmp_lit(cb, d32);
sewardjce70a5c2004-10-18 14:09:54 +00008079//-- whatNext = Dis_StopHere;
sewardjc9a65702004-07-07 16:32:57 +00008080//-- DIP("loop 0x%x\n", d32);
8081//-- break;
sewardj1813dbe2004-07-28 17:09:04 +00008082
8083 /* ------------------------ IMUL ----------------------- */
8084
8085 case 0x69: /* IMUL Iv, Ev, Gv */
8086 delta = dis_imul_I_E_G ( sorb, sz, delta, sz );
8087 break;
8088 case 0x6B: /* IMUL Ib, Ev, Gv */
8089 delta = dis_imul_I_E_G ( sorb, sz, delta, 1 );
8090 break;
sewardj0611d802004-07-11 02:37:54 +00008091
8092 /* ------------------------ MOV ------------------------ */
8093
8094 case 0x88: /* MOV Gb,Eb */
8095 delta = dis_mov_G_E(sorb, 1, delta);
8096 break;
sewardjc9a65702004-07-07 16:32:57 +00008097
8098 case 0x89: /* MOV Gv,Ev */
8099 delta = dis_mov_G_E(sorb, sz, delta);
8100 break;
8101
sewardjc2ac51e2004-07-12 01:03:26 +00008102 case 0x8A: /* MOV Eb,Gb */
8103 delta = dis_mov_E_G(sorb, 1, delta);
8104 break;
sewardje05c42c2004-07-08 20:25:10 +00008105
8106 case 0x8B: /* MOV Ev,Gv */
8107 delta = dis_mov_E_G(sorb, sz, delta);
8108 break;
8109
sewardje87b4842004-07-10 12:23:30 +00008110 case 0x8D: /* LEA M,Gv */
sewardje05c42c2004-07-08 20:25:10 +00008111 vassert(sz == 4);
8112 modrm = getIByte(delta);
8113 if (epartIsReg(modrm))
8114 vpanic("LEA M,Gv: modRM refers to register (x86)");
8115 /* NOTE! this is the one place where a segment override prefix
8116 has no effect on the address calculation. Therefore we pass
8117 zero instead of sorb here. */
sewardje87b4842004-07-10 12:23:30 +00008118 addr = disAMode ( &alen, /*sorb*/ 0, delta, dis_buf );
8119 delta += alen;
sewardj940e8c92004-07-11 16:53:24 +00008120 putIReg(sz, gregOfRM(modrm), mkexpr(addr));
sewardje05c42c2004-07-08 20:25:10 +00008121 DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
8122 nameIReg(sz,gregOfRM(modrm)));
8123 break;
sewardje05c42c2004-07-08 20:25:10 +00008124
sewardj063f02f2004-10-20 12:36:12 +00008125 case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
8126 delta = dis_mov_Sw_Ew(sorb, sz, delta);
8127 break;
8128
sewardjc9a65702004-07-07 16:32:57 +00008129//-- case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
8130//-- eip = dis_mov_Ew_Sw(cb, sorb, eip);
8131//-- break;
8132//--
sewardj43852812004-10-16 23:10:08 +00008133 case 0xA0: /* MOV Ob,AL */
8134 sz = 1;
8135 /* Fall through ... */
sewardj0c12ea82004-07-12 08:18:16 +00008136 case 0xA1: /* MOV Ov,eAX */
8137 d32 = getUDisp32(delta); delta += 4;
8138 ty = szToITy(sz);
8139 addr = newTemp(Ity_I32);
8140 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
8141 putIReg(sz, R_EAX, loadLE(ty, mkexpr(addr)));
8142 DIP("mov%c %s0x%x, %s\n", nameISize(sz), sorbTxt(sorb),
8143 d32, nameIReg(sz,R_EAX));
8144 break;
8145
sewardj180e8b32004-07-29 01:40:11 +00008146 case 0xA2: /* MOV Ob,AL */
8147 sz = 1;
8148 /* Fall through ... */
sewardj750f4072004-07-26 22:39:11 +00008149 case 0xA3: /* MOV eAX,Ov */
8150 d32 = getUDisp32(delta); delta += 4;
8151 ty = szToITy(sz);
8152 addr = newTemp(Ity_I32);
8153 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
8154 storeLE( mkexpr(addr), getIReg(sz,R_EAX) );
8155 DIP("mov%c %s, %s0x%x\n", nameISize(sz), nameIReg(sz,R_EAX),
8156 sorbTxt(sorb), d32);
8157 break;
sewardje87b4842004-07-10 12:23:30 +00008158
sewardjc2ac51e2004-07-12 01:03:26 +00008159 case 0xB0: /* MOV imm,AL */
8160 case 0xB1: /* MOV imm,CL */
8161 case 0xB2: /* MOV imm,DL */
8162 case 0xB3: /* MOV imm,BL */
8163 case 0xB4: /* MOV imm,AH */
8164 case 0xB5: /* MOV imm,CH */
8165 case 0xB6: /* MOV imm,DH */
8166 case 0xB7: /* MOV imm,BH */
8167 d32 = getIByte(delta); delta += 1;
8168 putIReg(1, opc-0xB0, mkU8(d32));
8169 DIP("movb $0x%x,%s\n", d32, nameIReg(1,opc-0xB0));
8170 break;
sewardj7ed22952004-07-29 00:09:58 +00008171
sewardje87b4842004-07-10 12:23:30 +00008172 case 0xB8: /* MOV imm,eAX */
8173 case 0xB9: /* MOV imm,eCX */
8174 case 0xBA: /* MOV imm,eDX */
8175 case 0xBB: /* MOV imm,eBX */
8176 case 0xBC: /* MOV imm,eSP */
8177 case 0xBD: /* MOV imm,eBP */
8178 case 0xBE: /* MOV imm,eSI */
8179 case 0xBF: /* MOV imm,eDI */
8180 d32 = getUDisp(sz,delta); delta += sz;
8181 putIReg(sz, opc-0xB8, mkU(szToITy(sz), d32));
8182 DIP("mov%c $0x%x,%s\n", nameISize(sz), d32, nameIReg(sz,opc-0xB8));
8183 break;
8184
sewardj77b86be2004-07-11 13:28:24 +00008185 case 0xC6: /* MOV Ib,Eb */
8186 sz = 1;
8187 goto do_Mov_I_E;
sewardje87b4842004-07-10 12:23:30 +00008188 case 0xC7: /* MOV Iv,Ev */
8189 goto do_Mov_I_E;
8190
8191 do_Mov_I_E:
8192 modrm = getIByte(delta);
8193 if (epartIsReg(modrm)) {
8194 delta++; /* mod/rm byte */
8195 d32 = getUDisp(sz,delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00008196 putIReg(sz, eregOfRM(modrm), mkU(szToITy(sz), d32));
sewardje87b4842004-07-10 12:23:30 +00008197 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32,
8198 nameIReg(sz,eregOfRM(modrm)));
sewardj5bd4d162004-11-10 13:02:48 +00008199 vassert(0);
sewardje87b4842004-07-10 12:23:30 +00008200 } else {
8201 addr = disAMode ( &alen, sorb, delta, dis_buf );
8202 delta += alen;
8203 d32 = getUDisp(sz,delta); delta += sz;
sewardj5bd4d162004-11-10 13:02:48 +00008204 storeLE(mkexpr(addr), mkU(szToITy(sz), d32));
sewardje87b4842004-07-10 12:23:30 +00008205 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
8206 }
8207 break;
8208
sewardj1813dbe2004-07-28 17:09:04 +00008209 /* ------------------------ opl imm, A ----------------- */
8210
8211 case 0x04: /* ADD Ib, AL */
8212 delta = dis_op_imm_A( 1, Iop_Add8, True, delta, "add" );
8213 break;
sewardj77b86be2004-07-11 13:28:24 +00008214 case 0x05: /* ADD Iv, eAX */
8215 delta = dis_op_imm_A(sz, Iop_Add8, True, delta, "add" );
8216 break;
8217
sewardj940e8c92004-07-11 16:53:24 +00008218 case 0x0C: /* OR Ib, AL */
8219 delta = dis_op_imm_A( 1, Iop_Or8, True, delta, "or" );
8220 break;
sewardj82292882004-07-27 00:15:59 +00008221 case 0x0D: /* OR Iv, eAX */
8222 delta = dis_op_imm_A( sz, Iop_Or8, True, delta, "or" );
8223 break;
8224
sewardjc9a65702004-07-07 16:32:57 +00008225//-- case 0x14: /* ADC Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +00008226//-- delta = dis_op_imm_A( 1, ADC, True, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +00008227//-- break;
8228//-- case 0x15: /* ADC Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +00008229//-- delta = dis_op_imm_A( sz, ADC, True, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +00008230//-- break;
8231//--
8232//-- case 0x1C: /* SBB Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +00008233//-- delta = dis_op_imm_A( 1, SBB, True, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +00008234//-- break;
8235//-- case 0x1D: /* SBB Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +00008236//-- delta = dis_op_imm_A( sz, SBB, True, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +00008237//-- break;
8238//--
sewardj940e8c92004-07-11 16:53:24 +00008239 case 0x24: /* AND Ib, AL */
8240 delta = dis_op_imm_A( 1, Iop_And8, True, delta, "and" );
8241 break;
sewardjc2ac51e2004-07-12 01:03:26 +00008242 case 0x25: /* AND Iv, eAX */
8243 delta = dis_op_imm_A( sz, Iop_And8, True, delta, "and" );
8244 break;
sewardj0611d802004-07-11 02:37:54 +00008245
8246 case 0x2C: /* SUB Ib, AL */
8247 delta = dis_op_imm_A(1, Iop_Sub8, True, delta, "sub" );
8248 break;
sewardj68511542004-07-28 00:15:44 +00008249 case 0x2D: /* SUB Iv, eAX */
8250 delta = dis_op_imm_A( sz, Iop_Sub8, True, delta, "sub" );
8251 break;
8252
sewardj1c6f9912004-09-07 10:15:24 +00008253 case 0x34: /* XOR Ib, AL */
8254 delta = dis_op_imm_A( 1, Iop_Xor8, True, delta, "xor" );
8255 break;
sewardjcaca9d02004-07-28 07:11:32 +00008256 case 0x35: /* XOR Iv, eAX */
8257 delta = dis_op_imm_A( sz, Iop_Xor8, True, delta, "xor" );
8258 break;
8259
sewardj0611d802004-07-11 02:37:54 +00008260 case 0x3C: /* CMP Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +00008261 delta = dis_op_imm_A( 1, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +00008262 break;
8263 case 0x3D: /* CMP Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +00008264 delta = dis_op_imm_A( sz, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +00008265 break;
8266
sewardj77b86be2004-07-11 13:28:24 +00008267 case 0xA8: /* TEST Ib, AL */
8268 delta = dis_op_imm_A( 1, Iop_And8, False, delta, "test" );
8269 break;
sewardjc2ac51e2004-07-12 01:03:26 +00008270 case 0xA9: /* TEST Iv, eAX */
8271 delta = dis_op_imm_A( sz, Iop_And8, False, delta, "test" );
8272 break;
8273
sewardj1c6f9912004-09-07 10:15:24 +00008274 /* ------------------------ opl Ev, Gv ----------------- */
8275
sewardj89cd0932004-09-08 18:23:25 +00008276 case 0x02: /* ADD Eb,Gb */
8277 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, 1, delta, "add" );
8278 break;
sewardj9334b0f2004-07-10 22:43:54 +00008279 case 0x03: /* ADD Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00008280 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, sz, delta, "add" );
sewardj9334b0f2004-07-10 22:43:54 +00008281 break;
8282
sewardj7ed22952004-07-29 00:09:58 +00008283 case 0x0A: /* OR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00008284 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, 1, delta, "or" );
sewardj7ed22952004-07-29 00:09:58 +00008285 break;
sewardjc2ac51e2004-07-12 01:03:26 +00008286 case 0x0B: /* OR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00008287 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, sz, delta, "or" );
sewardjc2ac51e2004-07-12 01:03:26 +00008288 break;
sewardjc9a65702004-07-07 16:32:57 +00008289//--
8290//-- case 0x12: /* ADC Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00008291//-- delta = dis_op2_E_G ( sorb, True, ADC, True, 1, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +00008292//-- break;
sewardjc4eaff32004-09-10 20:25:11 +00008293 case 0x13: /* ADC Ev,Gv */
8294 delta = dis_op2_E_G ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
8295 break;
8296
sewardjc9a65702004-07-07 16:32:57 +00008297//-- case 0x1A: /* SBB Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00008298//-- delta = dis_op2_E_G ( sorb, True, SBB, True, 1, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +00008299//-- break;
sewardj180e8b32004-07-29 01:40:11 +00008300 case 0x1B: /* SBB Ev,Gv */
8301 delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
sewardj940e8c92004-07-11 16:53:24 +00008302 break;
8303
sewardj1c6f9912004-09-07 10:15:24 +00008304 case 0x22: /* AND Eb,Gb */
8305 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, 1, delta, "and" );
8306 break;
sewardj180e8b32004-07-29 01:40:11 +00008307 case 0x23: /* AND Ev,Gv */
8308 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, sz, delta, "and" );
8309 break;
8310
8311 case 0x2A: /* SUB Eb,Gb */
8312 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
8313 break;
sewardj0611d802004-07-11 02:37:54 +00008314 case 0x2B: /* SUB Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00008315 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
sewardj0611d802004-07-11 02:37:54 +00008316 break;
sewardjc2ac51e2004-07-12 01:03:26 +00008317
8318 case 0x32: /* XOR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00008319 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +00008320 break;
sewardj1813dbe2004-07-28 17:09:04 +00008321 case 0x33: /* XOR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00008322 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
sewardj1813dbe2004-07-28 17:09:04 +00008323 break;
8324
sewardjc2ac51e2004-07-12 01:03:26 +00008325 case 0x3A: /* CMP Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00008326 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardjc2ac51e2004-07-12 01:03:26 +00008327 break;
sewardje90ad6a2004-07-10 19:02:10 +00008328 case 0x3B: /* CMP Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00008329 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +00008330 break;
8331
sewardj0611d802004-07-11 02:37:54 +00008332 case 0x84: /* TEST Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00008333 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, 1, delta, "test" );
sewardj0611d802004-07-11 02:37:54 +00008334 break;
sewardje05c42c2004-07-08 20:25:10 +00008335 case 0x85: /* TEST Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00008336 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, sz, delta, "test" );
sewardje05c42c2004-07-08 20:25:10 +00008337 break;
8338
sewardj180e8b32004-07-29 01:40:11 +00008339 /* ------------------------ opl Gv, Ev ----------------- */
8340
8341 case 0x00: /* ADD Gb,Eb */
8342 delta = dis_op2_G_E ( sorb, False, Iop_Add8, True, 1, delta, "add" );
8343 break;
sewardje05c42c2004-07-08 20:25:10 +00008344 case 0x01: /* ADD Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00008345 delta = dis_op2_G_E ( sorb, False, Iop_Add8, True, sz, delta, "add" );
sewardje05c42c2004-07-08 20:25:10 +00008346 break;
8347
sewardj940e8c92004-07-11 16:53:24 +00008348 case 0x08: /* OR Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +00008349 delta = dis_op2_G_E ( sorb, False, Iop_Or8, True, 1, delta, "or" );
sewardj940e8c92004-07-11 16:53:24 +00008350 break;
sewardj9334b0f2004-07-10 22:43:54 +00008351 case 0x09: /* OR Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00008352 delta = dis_op2_G_E ( sorb, False, Iop_Or8, True, sz, delta, "or" );
sewardj9334b0f2004-07-10 22:43:54 +00008353 break;
8354
sewardja2384712004-07-29 14:36:40 +00008355 case 0x10: /* ADC Gb,Eb */
8356 delta = dis_op2_G_E ( sorb, True, Iop_Add8, True, 1, delta, "adc" );
8357 break;
sewardjcaca9d02004-07-28 07:11:32 +00008358 case 0x11: /* ADC Gv,Ev */
8359 delta = dis_op2_G_E ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
8360 break;
8361
sewardja2384712004-07-29 14:36:40 +00008362 case 0x18: /* SBB Gb,Eb */
8363 delta = dis_op2_G_E ( sorb, True, Iop_Sub8, True, 1, delta, "sbb" );
8364 break;
sewardjcaca9d02004-07-28 07:11:32 +00008365 case 0x19: /* SBB Gv,Ev */
8366 delta = dis_op2_G_E ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
8367 break;
8368
sewardja2384712004-07-29 14:36:40 +00008369 case 0x20: /* AND Gb,Eb */
8370 delta = dis_op2_G_E ( sorb, False, Iop_And8, True, 1, delta, "and" );
8371 break;
sewardj0611d802004-07-11 02:37:54 +00008372 case 0x21: /* AND Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00008373 delta = dis_op2_G_E ( sorb, False, Iop_And8, True, sz, delta, "and" );
sewardj0611d802004-07-11 02:37:54 +00008374 break;
8375
sewardj180e8b32004-07-29 01:40:11 +00008376 case 0x28: /* SUB Gb,Eb */
8377 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
8378 break;
sewardje05c42c2004-07-08 20:25:10 +00008379 case 0x29: /* SUB Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00008380 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
sewardje05c42c2004-07-08 20:25:10 +00008381 break;
8382
sewardjc2ac51e2004-07-12 01:03:26 +00008383 case 0x30: /* XOR Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +00008384 delta = dis_op2_G_E ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +00008385 break;
sewardje87b4842004-07-10 12:23:30 +00008386 case 0x31: /* XOR Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00008387 delta = dis_op2_G_E ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
sewardje87b4842004-07-10 12:23:30 +00008388 break;
8389
sewardj0611d802004-07-11 02:37:54 +00008390 case 0x38: /* CMP Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +00008391 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +00008392 break;
sewardje90ad6a2004-07-10 19:02:10 +00008393 case 0x39: /* CMP Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00008394 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +00008395 break;
8396
sewardj9334b0f2004-07-10 22:43:54 +00008397 /* ------------------------ POP ------------------------ */
8398
8399 case 0x58: /* POP eAX */
8400 case 0x59: /* POP eCX */
8401 case 0x5A: /* POP eDX */
8402 case 0x5B: /* POP eBX */
8403 case 0x5D: /* POP eBP */
8404 case 0x5E: /* POP eSI */
8405 case 0x5F: /* POP eDI */
8406 case 0x5C: /* POP eSP */
8407 vassert(sz == 2 || sz == 4);
8408 t1 = newTemp(szToITy(sz)); t2 = newTemp(Ity_I32);
8409 assign(t2, getIReg(4, R_ESP));
8410 assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
8411 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
8412 putIReg(sz, opc-0x58, mkexpr(t1));
8413 DIP("pop%c %s\n", nameISize(sz), nameIReg(sz,opc-0x58));
8414 break;
8415
sewardja2384712004-07-29 14:36:40 +00008416 case 0x9D: /* POPF */
8417 vassert(sz == 2 || sz == 4);
8418 vassert(sz == 4); // until we know a sz==2 test case exists
8419 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
8420 assign(t2, getIReg(4, R_ESP));
sewardjc22a6fd2004-07-29 23:41:47 +00008421 assign(t1, widenUto32(loadLE(szToITy(sz),mkexpr(t2))));
sewardja2384712004-07-29 14:36:40 +00008422 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
sewardj98169c52004-10-24 13:11:39 +00008423 /* t1 is the flag word. Mask out everything except OSZACP and
sewardj5bd4d162004-11-10 13:02:48 +00008424 set the flags thunk to CC_OP_COPY. */
sewardj2a2ba8b2004-11-08 13:14:06 +00008425 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
8426 stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
8427 stmt( IRStmt_Put( OFFB_CC_DEP1,
sewardj5bd4d162004-11-10 13:02:48 +00008428 binop(Iop_And32,
8429 mkexpr(t1),
8430 mkU32( CC_MASK_C | CC_MASK_P | CC_MASK_A
sewardja2384712004-07-29 14:36:40 +00008431 | CC_MASK_Z | CC_MASK_S| CC_MASK_O )
sewardj5bd4d162004-11-10 13:02:48 +00008432 )
8433 )
8434 );
sewardja2384712004-07-29 14:36:40 +00008435
8436 /* Also need to set the D flag, which is held in bit 10 of t1.
8437 If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
8438 stmt( IRStmt_Put(
8439 OFFB_DFLAG,
8440 IRExpr_Mux0X(
8441 unop(Iop_32to8,
8442 binop(Iop_And32,
8443 binop(Iop_Shr32, mkexpr(t1), mkU8(10)),
8444 mkU32(1))),
8445 mkU32(1),
8446 mkU32(0xFFFFFFFF)))
8447 );
8448
sewardj006a6a22004-10-26 00:50:52 +00008449 /* And set the ID flag */
8450 stmt( IRStmt_Put(
8451 OFFB_IDFLAG,
8452 IRExpr_Mux0X(
8453 unop(Iop_32to8,
8454 binop(Iop_And32,
8455 binop(Iop_Shr32, mkexpr(t1), mkU8(21)),
8456 mkU32(1))),
8457 mkU32(0),
8458 mkU32(1)))
8459 );
8460
sewardja2384712004-07-29 14:36:40 +00008461 DIP("popf%c\n", nameISize(sz));
8462 break;
8463
sewardjc9a65702004-07-07 16:32:57 +00008464//-- case 0x61: /* POPA */
8465//-- { Int reg;
8466//-- /* Just to keep things sane, we assert for a size 4. It's
8467//-- probably OK for size 2 as well, but I'd like to find a test
8468//-- case; ie, have the assertion fail, before committing to it.
8469//-- If it fails for you, uncomment the sz == 2 bit, try again,
8470//-- and let me know whether or not it works. (jseward@acm.org). */
8471//-- vg_assert(sz == 4 /* || sz == 2 */);
8472//--
8473//-- /* Eight values are popped, one per register, but the value of
8474//-- %esp on the stack is ignored and instead incremented (in one
8475//-- hit at the end) for each of the values. */
8476//-- t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
8477//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
8478//-- uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t3);
8479//--
8480//-- /* Do %edi, %esi, %ebp */
8481//-- for (reg = 7; reg >= 5; reg--) {
8482//-- uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
8483//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
8484//-- uLiteral(cb, sz);
8485//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
8486//-- }
8487//-- /* Ignore (skip) value of %esp on stack. */
8488//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
8489//-- uLiteral(cb, sz);
8490//-- /* Do %ebx, %edx, %ecx, %eax */
8491//-- for (reg = 3; reg >= 0; reg--) {
8492//-- uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
8493//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
8494//-- uLiteral(cb, sz);
8495//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
8496//-- }
8497//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t3);
8498//-- uLiteral(cb, sz * 8); /* One 'sz' per register */
8499//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
8500//-- DIP("popa%c\n", nameISize(sz));
8501//-- break;
8502//-- }
8503//--
8504//-- case 0x8F: /* POPL/POPW m32 */
8505//-- { UInt pair1;
8506//-- Int tmpa;
8507//-- UChar rm = getIByte(delta);
8508//--
8509//-- /* make sure this instruction is correct POP */
8510//-- vg_assert(!epartIsReg(rm) && (gregOfRM(rm) == 0));
8511//-- /* and has correct size */
8512//-- vg_assert(sz == 4);
8513//--
8514//-- t1 = newTemp(cb); t3 = newTemp(cb);
8515//-- /* set t1 to ESP: t1 = ESP */
8516//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
8517//-- /* load M[ESP] to virtual register t3: t3 = M[t1] */
8518//-- uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t3);
8519//--
8520//-- /* increase ESP; must be done before the STORE. Intel manual says:
8521//-- If the ESP register is used as a base register for addressing
8522//-- a destination operand in memory, the POP instruction computes
8523//-- the effective address of the operand after it increments the
8524//-- ESP register.
8525//-- */
8526//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1);
8527//-- uLiteral(cb, sz);
8528//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
8529//--
8530//-- /* resolve MODR/M */
8531//-- pair1 = disAMode ( cb, sorb, eip, dis_buf );
8532//--
8533//-- tmpa = LOW24(pair1);
8534//-- /* uInstr2(cb, LOAD, sz, TempReg, tmpa, TempReg, tmpa); */
8535//-- /* store value from stack in memory, M[m32] = t3 */
8536//-- uInstr2(cb, STORE, 4, TempReg, t3, TempReg, tmpa);
8537//--
8538//-- DIP("popl %s\n", dis_buf);
8539//--
8540//-- eip += HI8(pair1);
8541//-- break;
8542//-- }
8543//--
8544//-- case 0x1F: /* POP %DS */
8545//-- dis_pop_segreg( cb, R_DS, sz ); break;
8546//-- case 0x07: /* POP %ES */
8547//-- dis_pop_segreg( cb, R_ES, sz ); break;
8548//-- case 0x17: /* POP %SS */
8549//-- dis_pop_segreg( cb, R_SS, sz ); break;
sewardjd1061ab2004-07-08 01:45:30 +00008550
8551 /* ------------------------ PUSH ----------------------- */
8552
8553 case 0x50: /* PUSH eAX */
8554 case 0x51: /* PUSH eCX */
8555 case 0x52: /* PUSH eDX */
8556 case 0x53: /* PUSH eBX */
8557 case 0x55: /* PUSH eBP */
8558 case 0x56: /* PUSH eSI */
8559 case 0x57: /* PUSH eDI */
8560 case 0x54: /* PUSH eSP */
8561 /* This is the Right Way, in that the value to be pushed is
8562 established before %esp is changed, so that pushl %esp
8563 correctly pushes the old value. */
8564 vassert(sz == 2 || sz == 4);
8565 ty = sz==2 ? Ity_I16 : Ity_I32;
sewardj883b00b2004-09-11 09:30:24 +00008566 t1 = newTemp(ty); t2 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +00008567 assign(t1, getIReg(sz, opc-0x50));
8568 assign(t2, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)));
8569 putIReg(4, R_ESP, mkexpr(t2) );
8570 storeLE(mkexpr(t2),mkexpr(t1));
sewardjd1061ab2004-07-08 01:45:30 +00008571 DIP("push%c %s\n", nameISize(sz), nameIReg(sz,opc-0x50));
8572 break;
8573
8574
sewardj0c12ea82004-07-12 08:18:16 +00008575 case 0x68: /* PUSH Iv */
8576 d32 = getUDisp(sz,delta); delta += sz;
8577 goto do_push_I;
sewardj741153c2004-07-25 23:39:13 +00008578 case 0x6A: /* PUSH Ib, sign-extended to sz */
8579 d32 = getSDisp8(delta); delta += 1;
8580 goto do_push_I;
sewardj0c12ea82004-07-12 08:18:16 +00008581 do_push_I:
8582 ty = szToITy(sz);
8583 t1 = newTemp(Ity_I32); t2 = newTemp(ty);
8584 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
8585 putIReg(4, R_ESP, mkexpr(t1) );
8586 storeLE( mkexpr(t1), mkU(ty,d32) );
8587 DIP("push%c $0x%x\n", nameISize(sz), d32);
8588 break;
8589
sewardja2384712004-07-29 14:36:40 +00008590 case 0x9C: /* PUSHF */ {
sewardj006a6a22004-10-26 00:50:52 +00008591 IRTemp t3, t4;
sewardja2384712004-07-29 14:36:40 +00008592 vassert(sz == 2 || sz == 4);
8593 vassert(sz == 4); // wait for sz==2 test case
8594
8595 t1 = newTemp(Ity_I32);
8596 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
8597 putIReg(4, R_ESP, mkexpr(t1) );
8598
8599 t2 = newTemp(Ity_I32);
8600 assign( t2, mk_calculate_eflags_all() );
8601
8602 /* Patch in the D flag. This can simply be the inversion
sewardj5bd4d162004-11-10 13:02:48 +00008603 of bit 10 of baseBlock[OFFB_DFLAG]. */
sewardja2384712004-07-29 14:36:40 +00008604 t3 = newTemp(Ity_I32);
8605 assign( t3, binop(Iop_Or32,
8606 mkexpr(t2),
8607 binop(Iop_And32,
sewardj5bd4d162004-11-10 13:02:48 +00008608 unop(Iop_Not32, IRExpr_Get(OFFB_DFLAG,Ity_I32)),
8609 mkU32(1<<10)))
sewardja2384712004-07-29 14:36:40 +00008610 );
sewardj006a6a22004-10-26 00:50:52 +00008611
8612 /* And patch in the ID flag. */
8613 t4 = newTemp(Ity_I32);
8614 assign( t4, binop(Iop_Or32,
8615 mkexpr(t3),
8616 binop(Iop_And32,
sewardj5bd4d162004-11-10 13:02:48 +00008617 binop(Iop_Shl32, IRExpr_Get(OFFB_IDFLAG,Ity_I32),
sewardj006a6a22004-10-26 00:50:52 +00008618 mkU8(21)),
sewardj5bd4d162004-11-10 13:02:48 +00008619 mkU32(1<<21)))
sewardj006a6a22004-10-26 00:50:52 +00008620 );
8621
sewardja2384712004-07-29 14:36:40 +00008622 /* if sz==2, the stored value needs to be narrowed. */
8623 if (sz == 2)
sewardj5bd4d162004-11-10 13:02:48 +00008624 storeLE( mkexpr(t1), unop(Iop_32to16,mkexpr(t4)) );
sewardja2384712004-07-29 14:36:40 +00008625 else
sewardj5bd4d162004-11-10 13:02:48 +00008626 storeLE( mkexpr(t1), mkexpr(t4) );
sewardja2384712004-07-29 14:36:40 +00008627
8628 DIP("pushf%c\n", nameISize(sz));
8629 break;
8630 }
8631
sewardjc9a65702004-07-07 16:32:57 +00008632//-- case 0x60: /* PUSHA */
8633//-- { Int reg;
8634//-- /* Just to keep things sane, we assert for a size 4. It's
8635//-- probably OK for size 2 as well, but I'd like to find a test
8636//-- case; ie, have the assertion fail, before committing to it.
8637//-- If it fails for you, uncomment the sz == 2 bit, try again,
8638//-- and let me know whether or not it works. (jseward@acm.org). */
8639//-- vg_assert(sz == 4 /* || sz == 2 */);
8640//--
8641//-- /* This is the Right Way, in that the value to be pushed is
8642//-- established before %esp is changed, so that pusha
8643//-- correctly pushes the old %esp value. New value of %esp is
8644//-- pushed at start. */
8645//-- t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
8646//-- t4 = newTemp(cb);
8647//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
8648//-- uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
8649//-- uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t4);
8650//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t4);
8651//-- uLiteral(cb, sz * 8); /* One 'sz' per register. */
8652//-- uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_ESP);
8653//-- /* Do %eax, %ecx, %edx, %ebx */
8654//-- for (reg = 0; reg <= 3; reg++) {
8655//-- uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
8656//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
8657//-- uLiteral(cb, sz);
8658//-- uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
8659//-- }
8660//-- /* Push old value of %esp */
8661//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
8662//-- uLiteral(cb, sz);
8663//-- uInstr2(cb, STORE, sz, TempReg, t3, TempReg, t2);
8664//-- /* Do %ebp, %esi, %edi */
8665//-- for (reg = 5; reg <= 7; reg++) {
8666//-- uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
8667//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
8668//-- uLiteral(cb, sz);
8669//-- uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
8670//-- }
8671//-- DIP("pusha%c\n", nameISize(sz));
8672//-- break;
8673//-- }
8674//--
8675//-- case 0x0E: /* PUSH %CS */
8676//-- dis_push_segreg( cb, R_CS, sz ); break;
8677//-- case 0x1E: /* PUSH %DS */
8678//-- dis_push_segreg( cb, R_DS, sz ); break;
8679//-- case 0x06: /* PUSH %ES */
8680//-- dis_push_segreg( cb, R_ES, sz ); break;
8681//-- case 0x16: /* PUSH %SS */
8682//-- dis_push_segreg( cb, R_SS, sz ); break;
sewardj458a6f82004-08-25 12:46:02 +00008683
8684 /* ------------------------ SCAS et al ----------------- */
8685
8686 case 0xA4: /* MOVS, no REP prefix */
8687 case 0xA5:
8688 dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
8689 break;
8690
sewardjc9a65702004-07-07 16:32:57 +00008691//-- case 0xA6: /* CMPSb, no REP prefix */
8692//-- case 0xA7:
8693//-- dis_string_op( cb, dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
8694//-- break;
8695//--
sewardj883b00b2004-09-11 09:30:24 +00008696 case 0xAA: /* STOS, no REP prefix */
sewardj47341042004-09-19 11:55:46 +00008697 case 0xAB:
sewardj883b00b2004-09-11 09:30:24 +00008698 dis_string_op( dis_STOS, ( opc == 0xAA ? 1 : sz ), "stos", sorb );
8699 break;
sewardjc9a65702004-07-07 16:32:57 +00008700//--
8701//-- case 0xAC: /* LODS, no REP prefix */
8702//-- case 0xAD:
8703//-- dis_string_op( cb, dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
8704//-- break;
sewardj2d4c3a02004-10-15 00:03:23 +00008705
8706 case 0xAE: /* SCAS, no REP prefix */
8707 case 0xAF:
8708 dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
8709 break;
sewardj64e1d652004-07-12 14:00:46 +00008710
8711
8712 case 0xFC: /* CLD */
sewardjeeb9ef82004-07-15 12:39:03 +00008713 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(1)) );
sewardj64e1d652004-07-12 14:00:46 +00008714 DIP("cld\n");
8715 break;
8716
sewardj1813dbe2004-07-28 17:09:04 +00008717 case 0xFD: /* STD */
8718 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(0xFFFFFFFF)) );
8719 DIP("std\n");
8720 break;
8721
sewardjc9a65702004-07-07 16:32:57 +00008722//-- case 0xF8: /* CLC */
8723//-- uInstr0(cb, CALLM_S, 0);
8724//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CLC));
8725//-- uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
8726//-- uInstr0(cb, CALLM_E, 0);
8727//-- DIP("clc\n");
8728//-- break;
8729//--
8730//-- case 0xF9: /* STC */
8731//-- uInstr0(cb, CALLM_S, 0);
8732//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_STC));
8733//-- uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
8734//-- uInstr0(cb, CALLM_E, 0);
8735//-- DIP("stc\n");
8736//-- break;
8737//--
8738//-- case 0xF5: /* CMC */
8739//-- uInstr0(cb, CALLM_S, 0);
8740//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CMC));
8741//-- uFlagsRWU(cb, FlagC, FlagC, FlagsOSZAP);
8742//-- uInstr0(cb, CALLM_E, 0);
8743//-- DIP("cmc\n");
8744//-- break;
sewardj82292882004-07-27 00:15:59 +00008745
8746 /* REPNE prefix insn */
8747 case 0xF2: {
sewardjce70a5c2004-10-18 14:09:54 +00008748 Addr32 eip_orig = guest_eip_bbstart + delta - 1;
sewardj82292882004-07-27 00:15:59 +00008749 vassert(sorb == 0);
8750 abyte = getIByte(delta); delta++;
8751
8752 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
sewardjce70a5c2004-10-18 14:09:54 +00008753 whatNext = Dis_StopHere;
sewardj82292882004-07-27 00:15:59 +00008754
8755 switch (abyte) {
8756 /* According to the Intel manual, "repne movs" should never occur, but
8757 * in practice it has happened, so allow for it here... */
sewardj180e8b32004-07-29 01:40:11 +00008758 case 0xA4: sz = 1; /* REPNE MOVS<sz> */
sewardj5bd4d162004-11-10 13:02:48 +00008759 vassert(0);
sewardjc9a65702004-07-07 16:32:57 +00008760//-- case 0xA5:
sewardj5bd4d162004-11-10 13:02:48 +00008761 // dis_REP_op ( CondNZ, dis_MOVS, sz, eip_orig,
8762 // guest_eip_bbstart+delta, "repne movs" );
8763 // break;
sewardjc9a65702004-07-07 16:32:57 +00008764//--
8765//-- case 0xA6: sz = 1; /* REPNE CMPS<sz> */
8766//-- case 0xA7:
8767//-- dis_REP_op ( cb, CondNZ, dis_CMPS, sz, eip_orig, eip, "repne cmps" );
8768//-- break;
8769//--
sewardj82292882004-07-27 00:15:59 +00008770 case 0xAE: sz = 1; /* REPNE SCAS<sz> */
sewardj2d4c3a02004-10-15 00:03:23 +00008771 case 0xAF:
sewardj82292882004-07-27 00:15:59 +00008772 dis_REP_op ( CondNZ, dis_SCAS, sz, eip_orig,
sewardjce70a5c2004-10-18 14:09:54 +00008773 guest_eip_bbstart+delta, "repne scas" );
sewardj82292882004-07-27 00:15:59 +00008774 break;
8775
8776 default:
8777 goto decode_failure;
8778 }
8779 break;
8780 }
sewardj64e1d652004-07-12 14:00:46 +00008781
8782 /* REP/REPE prefix insn (for SCAS and CMPS, 0xF3 means REPE,
8783 for the rest, it means REP) */
8784 case 0xF3: {
sewardjce70a5c2004-10-18 14:09:54 +00008785 Addr32 eip_orig = guest_eip_bbstart + delta - 1;
sewardj64e1d652004-07-12 14:00:46 +00008786 vassert(sorb == 0);
8787 abyte = getIByte(delta); delta++;
8788
8789 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
sewardjce70a5c2004-10-18 14:09:54 +00008790 whatNext = Dis_StopHere;
sewardj64e1d652004-07-12 14:00:46 +00008791
8792 switch (abyte) {
8793 case 0xA4: sz = 1; /* REP MOVS<sz> */
8794 case 0xA5:
8795 dis_REP_op ( CondAlways, dis_MOVS, sz, eip_orig,
sewardjce70a5c2004-10-18 14:09:54 +00008796 guest_eip_bbstart+delta, "rep movs" );
sewardj64e1d652004-07-12 14:00:46 +00008797 break;
8798
8799 case 0xA6: sz = 1; /* REPE CMP<sz> */
sewardj2d4c3a02004-10-15 00:03:23 +00008800 case 0xA7:
sewardj64e1d652004-07-12 14:00:46 +00008801 dis_REP_op ( CondZ, dis_CMPS, sz, eip_orig,
sewardjce70a5c2004-10-18 14:09:54 +00008802 guest_eip_bbstart+delta, "repe cmps" );
sewardj64e1d652004-07-12 14:00:46 +00008803 break;
8804
8805 case 0xAA: sz = 1; /* REP STOS<sz> */
8806 case 0xAB:
8807 dis_REP_op ( CondAlways, dis_STOS, sz, eip_orig,
sewardjce70a5c2004-10-18 14:09:54 +00008808 guest_eip_bbstart+delta, "rep stos" );
sewardj64e1d652004-07-12 14:00:46 +00008809 break;
sewardjc9a65702004-07-07 16:32:57 +00008810//--
8811//-- case 0xAE: sz = 1; /* REPE SCAS<sz> */
8812//-- case 0xAF:
8813//-- dis_REP_op ( cb, CondZ, dis_SCAS, sz, eip_orig, eip, "repe scas" );
8814//-- break;
8815//--
8816//-- case 0x90: /* REP NOP (PAUSE) */
8817//-- /* a hint to the P4 re spin-wait loop */
8818//-- DIP("rep nop (P4 pause)\n");
8819//-- jmp_lit(cb, eip);
8820//-- LAST_UINSTR(cb).jmpkind = JmpYield;
8821//-- break;
8822//--
8823//-- case 0xC3: /* REP RET */
8824//-- /* AMD K7/K8-specific optimisation; faster than vanilla RET */
8825//-- dis_ret(cb, 0);
8826//-- DIP("rep ret\n");
8827//-- break;
sewardj64e1d652004-07-12 14:00:46 +00008828
8829 default:
8830 goto decode_failure;
8831 }
8832 break;
8833 }
sewardj0611d802004-07-11 02:37:54 +00008834
8835 /* ------------------------ XCHG ----------------------- */
8836
8837 case 0x86: /* XCHG Gb,Eb */
8838 sz = 1;
8839 /* Fall through ... */
8840 case 0x87: /* XCHG Gv,Ev */
8841 modrm = getIByte(delta);
8842 ty = szToITy(sz);
8843 t1 = newTemp(ty); t2 = newTemp(ty);
8844 if (epartIsReg(modrm)) {
sewardj5bd4d162004-11-10 13:02:48 +00008845 assign(t1, getIReg(sz, eregOfRM(modrm)));
8846 assign(t2, getIReg(sz, gregOfRM(modrm)));
8847 putIReg(sz, gregOfRM(modrm), mkexpr(t1));
8848 putIReg(sz, eregOfRM(modrm), mkexpr(t2));
sewardj0611d802004-07-11 02:37:54 +00008849 delta++;
8850 DIP("xchg%c %s, %s\n",
8851 nameISize(sz), nameIReg(sz,gregOfRM(modrm)),
8852 nameIReg(sz,eregOfRM(modrm)));
8853 } else {
sewardj0c12ea82004-07-12 08:18:16 +00008854 addr = disAMode ( &alen, sorb, delta, dis_buf );
sewardj5bd4d162004-11-10 13:02:48 +00008855 assign( t1, loadLE(ty,mkexpr(addr)) );
8856 assign( t2, getIReg(sz,gregOfRM(modrm)) );
8857 storeLE( mkexpr(addr), mkexpr(t2) );
8858 putIReg( sz, gregOfRM(modrm), mkexpr(t1) );
8859 delta += alen;
sewardj0611d802004-07-11 02:37:54 +00008860 DIP("xchg%c %s, %s\n", nameISize(sz),
8861 nameIReg(sz,gregOfRM(modrm)), dis_buf);
sewardj0611d802004-07-11 02:37:54 +00008862 }
8863 break;
sewardje87b4842004-07-10 12:23:30 +00008864
8865 case 0x90: /* XCHG eAX,eAX */
8866 DIP("nop\n");
8867 break;
sewardj64e1d652004-07-12 14:00:46 +00008868 case 0x91: /* XCHG eAX,eCX */
8869 case 0x92: /* XCHG eAX,eDX */
8870 case 0x93: /* XCHG eAX,eBX */
8871 case 0x94: /* XCHG eAX,eSP */
8872 case 0x95: /* XCHG eAX,eBP */
8873 case 0x96: /* XCHG eAX,eSI */
8874 case 0x97: /* XCHG eAX,eDI */
8875 codegen_xchg_eAX_Reg ( sz, opc - 0x90 );
8876 break;
8877
sewardjc9a65702004-07-07 16:32:57 +00008878//-- /* ------------------------ XLAT ----------------------- */
8879//--
8880//-- case 0xD7: /* XLAT */
8881//-- t1 = newTemp(cb); t2 = newTemp(cb);
8882//-- uInstr2(cb, GET, sz, ArchReg, R_EBX, TempReg, t1); /* get eBX */
8883//-- handleSegOverride( cb, sorb, t1 ); /* make t1 DS:eBX */
8884//-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t2); /* get AL */
8885//-- /* Widen %AL to 32 bits, so it's all defined when we add it. */
8886//-- uInstr1(cb, WIDEN, 4, TempReg, t2);
8887//-- uWiden(cb, 1, False);
8888//-- uInstr2(cb, ADD, sz, TempReg, t2, TempReg, t1); /* add AL to eBX */
8889//-- uInstr2(cb, LOAD, 1, TempReg, t1, TempReg, t2); /* get byte at t1 into t2 */
8890//-- uInstr2(cb, PUT, 1, TempReg, t2, ArchReg, R_AL); /* put byte into AL */
8891//--
8892//-- DIP("xlat%c [ebx]\n", nameISize(sz));
8893//-- break;
8894//--
8895//-- /* ------------------------ IN / OUT ----------------------- */
8896//--
8897//-- case 0xE4: /* IN ib, %al */
8898//-- case 0xE5: /* IN ib, %{e}ax */
8899//-- case 0xEC: /* IN (%dx),%al */
8900//-- case 0xED: /* IN (%dx),%{e}ax */
8901//-- t1 = newTemp(cb);
8902//-- t2 = newTemp(cb);
8903//-- t3 = newTemp(cb);
8904//--
8905//-- uInstr0(cb, CALLM_S, 0);
8906//-- /* operand size? */
8907//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
8908//-- uLiteral(cb, ( opc == 0xE4 || opc == 0xEC ) ? 1 : sz);
8909//-- uInstr1(cb, PUSH, 4, TempReg, t1);
8910//-- /* port number ? */
8911//-- if ( opc == 0xE4 || opc == 0xE5 ) {
8912//-- abyte = getUChar(eip); eip++;
8913//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
8914//-- uLiteral(cb, abyte);
8915//-- }
8916//-- else
8917//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
8918//--
8919//-- uInstr1(cb, PUSH, 4, TempReg, t2);
8920//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_IN));
8921//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
8922//-- uInstr1(cb, POP, 4, TempReg, t2);
8923//-- uInstr1(cb, CLEAR, 0, Lit16, 4);
8924//-- uInstr0(cb, CALLM_E, 0);
8925//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EAX);
8926//-- if ( opc == 0xE4 || opc == 0xE5 ) {
8927//-- DIP("in 0x%x, %%eax/%%ax/%%al\n", getUChar(eip-1) );
8928//-- } else {
8929//-- DIP("in (%%dx), %%eax/%%ax/%%al\n");
8930//-- }
8931//-- break;
8932//-- case 0xE6: /* OUT %al,ib */
8933//-- case 0xE7: /* OUT %{e}ax,ib */
8934//-- case 0xEE: /* OUT %al,(%dx) */
8935//-- case 0xEF: /* OUT %{e}ax,(%dx) */
8936//-- t1 = newTemp(cb);
8937//-- t2 = newTemp(cb);
8938//-- t3 = newTemp(cb);
8939//--
8940//-- uInstr0(cb, CALLM_S, 0);
8941//-- /* operand size? */
8942//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
8943//-- uLiteral(cb, ( opc == 0xE6 || opc == 0xEE ) ? 1 : sz);
8944//-- uInstr1(cb, PUSH, 4, TempReg, t1);
8945//-- /* port number ? */
8946//-- if ( opc == 0xE6 || opc == 0xE7 ) {
8947//-- abyte = getUChar(eip); eip++;
8948//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
8949//-- uLiteral(cb, abyte);
8950//-- }
8951//-- else
8952//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
8953//-- uInstr1(cb, PUSH, 4, TempReg, t2);
8954//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t3);
8955//-- uInstr1(cb, PUSH, 4, TempReg, t3);
8956//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_OUT));
8957//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
8958//-- uInstr1(cb, CLEAR, 0, Lit16, 12);
8959//-- uInstr0(cb, CALLM_E, 0);
8960//-- if ( opc == 0xE4 || opc == 0xE5 ) {
8961//-- DIP("out %%eax/%%ax/%%al, 0x%x\n", getUChar(eip-1) );
8962//-- } else {
8963//-- DIP("out %%eax/%%ax/%%al, (%%dx)\n");
8964//-- }
8965//-- break;
sewardj0611d802004-07-11 02:37:54 +00008966
8967 /* ------------------------ (Grp1 extensions) ---------- */
8968
8969 case 0x80: /* Grp1 Ib,Eb */
8970 modrm = getIByte(delta);
8971 am_sz = lengthAMode(delta);
8972 sz = 1;
8973 d_sz = 1;
sewardjc2ac51e2004-07-12 01:03:26 +00008974 d32 = getUChar(delta + am_sz);
sewardj0611d802004-07-11 02:37:54 +00008975 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
8976 break;
sewardje05c42c2004-07-08 20:25:10 +00008977
8978 case 0x81: /* Grp1 Iv,Ev */
8979 modrm = getIByte(delta);
8980 am_sz = lengthAMode(delta);
8981 d_sz = sz;
8982 d32 = getUDisp(d_sz, delta + am_sz);
8983 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
8984 break;
sewardjd1061ab2004-07-08 01:45:30 +00008985
8986 case 0x83: /* Grp1 Ib,Ev */
8987 modrm = getIByte(delta);
8988 am_sz = lengthAMode(delta);
8989 d_sz = 1;
8990 d32 = getSDisp8(delta + am_sz);
8991 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
8992 break;
8993
sewardjc2ac51e2004-07-12 01:03:26 +00008994 /* ------------------------ (Grp2 extensions) ---------- */
8995
8996 case 0xC0: /* Grp2 Ib,Eb */
8997 modrm = getIByte(delta);
8998 am_sz = lengthAMode(delta);
8999 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +00009000 d32 = getUChar(delta + am_sz);
sewardjc2ac51e2004-07-12 01:03:26 +00009001 sz = 1;
sewardj6d2638e2004-07-15 09:38:27 +00009002 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
9003 mkU8(d32 & 0xFF), NULL );
sewardjc2ac51e2004-07-12 01:03:26 +00009004 break;
sewardje90ad6a2004-07-10 19:02:10 +00009005
9006 case 0xC1: /* Grp2 Ib,Ev */
sewardjc2ac51e2004-07-12 01:03:26 +00009007 modrm = getIByte(delta);
sewardje90ad6a2004-07-10 19:02:10 +00009008 am_sz = lengthAMode(delta);
9009 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +00009010 d32 = getUChar(delta + am_sz);
sewardj6d2638e2004-07-15 09:38:27 +00009011 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
9012 mkU8(d32 & 0xFF), NULL );
sewardje90ad6a2004-07-10 19:02:10 +00009013 break;
9014
sewardj180e8b32004-07-29 01:40:11 +00009015 case 0xD0: /* Grp2 1,Eb */
9016 modrm = getIByte(delta);
9017 am_sz = lengthAMode(delta);
9018 d_sz = 0;
9019 d32 = 1;
9020 sz = 1;
9021 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
9022 mkU8(d32), NULL );
9023 break;
sewardjc2ac51e2004-07-12 01:03:26 +00009024
9025 case 0xD1: /* Grp2 1,Ev */
9026 modrm = getUChar(delta);
9027 am_sz = lengthAMode(delta);
9028 d_sz = 0;
9029 d32 = 1;
sewardj6d2638e2004-07-15 09:38:27 +00009030 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
9031 mkU8(d32), NULL );
sewardjc2ac51e2004-07-12 01:03:26 +00009032 break;
9033
sewardj8c7f1ab2004-07-29 20:31:09 +00009034 case 0xD2: /* Grp2 CL,Eb */
9035 modrm = getUChar(delta);
9036 am_sz = lengthAMode(delta);
9037 d_sz = 0;
9038 sz = 1;
9039 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
9040 getIReg(1,R_ECX), "%cl" );
9041 break;
sewardj9334b0f2004-07-10 22:43:54 +00009042
9043 case 0xD3: /* Grp2 CL,Ev */
9044 modrm = getIByte(delta);
9045 am_sz = lengthAMode(delta);
9046 d_sz = 0;
9047 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardj6d2638e2004-07-15 09:38:27 +00009048 getIReg(1,R_ECX), "%cl" );
sewardj9334b0f2004-07-10 22:43:54 +00009049 break;
9050
sewardj940e8c92004-07-11 16:53:24 +00009051 /* ------------------------ (Grp3 extensions) ---------- */
9052
9053 case 0xF6: /* Grp3 Eb */
9054 delta = dis_Grp3 ( sorb, 1, delta );
9055 break;
9056 case 0xF7: /* Grp3 Ev */
9057 delta = dis_Grp3 ( sorb, sz, delta );
9058 break;
9059
sewardjc2ac51e2004-07-12 01:03:26 +00009060 /* ------------------------ (Grp4 extensions) ---------- */
9061
9062 case 0xFE: /* Grp4 Eb */
9063 delta = dis_Grp4 ( sorb, delta );
9064 break;
sewardj0611d802004-07-11 02:37:54 +00009065
9066 /* ------------------------ (Grp5 extensions) ---------- */
9067
9068 case 0xFF: /* Grp5 Ev */
sewardjce70a5c2004-10-18 14:09:54 +00009069 delta = dis_Grp5 ( sorb, sz, delta, &whatNext );
sewardj0611d802004-07-11 02:37:54 +00009070 break;
sewardje87b4842004-07-10 12:23:30 +00009071
9072 /* ------------------------ Escapes to 2-byte opcodes -- */
9073
9074 case 0x0F: {
9075 opc = getIByte(delta); delta++;
9076 switch (opc) {
9077
sewardjc9a65702004-07-07 16:32:57 +00009078//-- /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
9079//--
9080//-- case 0xBA: /* Grp8 Ib,Ev */
9081//-- modrm = getUChar(eip);
9082//-- am_sz = lengthAMode(eip);
9083//-- d32 = getSDisp8(eip + am_sz);
9084//-- eip = dis_Grp8_BT ( cb, sorb, eip, modrm, am_sz, sz, d32 );
9085//-- break;
sewardjce646f22004-08-31 23:55:54 +00009086
9087 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
9088
9089 case 0xBC: /* BSF Gv,Ev */
9090 delta = dis_bs_E_G ( sorb, sz, delta, True );
9091 break;
9092 case 0xBD: /* BSR Gv,Ev */
9093 delta = dis_bs_E_G ( sorb, sz, delta, False );
9094 break;
sewardj1c4208f2004-08-25 13:25:29 +00009095
9096 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
9097
9098 case 0xC8: /* BSWAP %eax */
9099 case 0xC9:
9100 case 0xCA:
sewardjb4666cf2004-10-23 00:21:50 +00009101 case 0xCB:
9102 case 0xCC:
9103 case 0xCD:
sewardj1c4208f2004-08-25 13:25:29 +00009104 case 0xCE:
sewardj1c6f9912004-09-07 10:15:24 +00009105 case 0xCF: /* BSWAP %edi */
sewardj1c4208f2004-08-25 13:25:29 +00009106 /* AFAICS from the Intel docs, this only exists at size 4. */
9107 vassert(sz == 4);
9108 t1 = newTemp(Ity_I32);
9109 t2 = newTemp(Ity_I32);
9110 assign( t1, getIReg(4, opc-0xC8) );
9111
9112 assign( t2,
9113 binop(Iop_Or32,
9114 binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
9115 binop(Iop_Or32,
9116 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
9117 mkU32(0x00FF0000)),
9118 binop(Iop_Or32,
9119 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
9120 mkU32(0x0000FF00)),
9121 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
9122 mkU32(0x000000FF) )
9123 )))
9124 );
9125
9126 putIReg(4, opc-0xC8, mkexpr(t2));
sewardj1c4208f2004-08-25 13:25:29 +00009127 DIP("bswapl %s\n", nameIReg(4, opc-0xC8));
9128 break;
9129
sewardj1c6f9912004-09-07 10:15:24 +00009130 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
9131
9132 case 0xA3: /* BT Gv,Ev */
9133 delta = dis_bt_G_E ( sorb, sz, delta, BtOpNone );
9134 break;
sewardje6709112004-09-10 18:37:18 +00009135 case 0xB3: /* BTR Gv,Ev */
9136 delta = dis_bt_G_E ( sorb, sz, delta, BtOpReset );
9137 break;
sewardj1c6f9912004-09-07 10:15:24 +00009138 case 0xAB: /* BTS Gv,Ev */
9139 delta = dis_bt_G_E ( sorb, sz, delta, BtOpSet );
9140 break;
sewardj4963a422004-10-14 23:34:03 +00009141 case 0xBB: /* BTC Gv,Ev */
9142 delta = dis_bt_G_E ( sorb, sz, delta, BtOpComp );
9143 break;
sewardj458a6f82004-08-25 12:46:02 +00009144
9145 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
9146
sewardj2d4c3a02004-10-15 00:03:23 +00009147 case 0x40:
9148 case 0x41:
sewardj458a6f82004-08-25 12:46:02 +00009149 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
9150 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
9151 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
9152 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
9153 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
9154 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
sewardjce646f22004-08-31 23:55:54 +00009155 case 0x48: /* CMOVSb (cmov negative) */
sewardj458a6f82004-08-25 12:46:02 +00009156 case 0x49: /* CMOVSb (cmov not negative) */
sewardj2d4c3a02004-10-15 00:03:23 +00009157 case 0x4A: /* CMOVP (cmov parity even) */
9158 case 0x4B: /* CMOVNP (cmov parity odd) */
sewardj458a6f82004-08-25 12:46:02 +00009159 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
9160 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
9161 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
9162 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
9163 delta = dis_cmov_E_G(sorb, sz, (Condcode)(opc - 0x40), delta);
9164 break;
9165
9166 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
9167
sewardjc744e872004-08-26 11:24:39 +00009168 case 0xB0: /* CMPXCHG Gb,Eb */
9169 delta = dis_cmpxchg_G_E ( sorb, 1, delta );
9170 break;
sewardj458a6f82004-08-25 12:46:02 +00009171 case 0xB1: /* CMPXCHG Gv,Ev */
9172 delta = dis_cmpxchg_G_E ( sorb, sz, delta );
9173 break;
sewardjc9a65702004-07-07 16:32:57 +00009174//-- case 0xC7: /* CMPXCHG8B Gv */
9175//-- eip = dis_cmpxchg8b ( cb, sorb, eip );
9176//-- break;
9177//--
sewardj588ea762004-09-10 18:56:32 +00009178 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
9179
sewardj7cb49d72004-10-24 22:31:25 +00009180 case 0xA2: { /* CPUID */
9181 /* Uses dirty helper:
9182 void dirtyhelper_CPUID ( VexGuestX86State* )
9183 declared to mod eax, wr ebx, ecx, edx
9184 */
sewardjf9655262004-10-31 20:02:16 +00009185 IRDirty* d = unsafeIRDirty_0_N (
9186 0/*regparms*/,
9187 "dirtyhelper_CPUID", &dirtyhelper_CPUID,
9188 mkIRExprVec_0()
9189 );
sewardj7cb49d72004-10-24 22:31:25 +00009190 /* declare guest state effects */
sewardjc5fc7aa2004-10-27 23:00:55 +00009191 d->needsBBP = True;
sewardj7cb49d72004-10-24 22:31:25 +00009192 d->nFxState = 4;
9193 d->fxState[0].fx = Ifx_Modify;
9194 d->fxState[0].offset = OFFB_EAX;
9195 d->fxState[0].size = 4;
9196 d->fxState[1].fx = Ifx_Write;
9197 d->fxState[1].offset = OFFB_EBX;
9198 d->fxState[1].size = 4;
9199 d->fxState[2].fx = Ifx_Write;
9200 d->fxState[2].offset = OFFB_ECX;
9201 d->fxState[2].size = 4;
9202 d->fxState[3].fx = Ifx_Write;
9203 d->fxState[3].offset = OFFB_EDX;
9204 d->fxState[3].size = 4;
9205 /* execute the dirty call, side-effecting guest state */
9206 stmt( IRStmt_Dirty(d) );
sewardj517a7d62004-10-25 09:52:18 +00009207 DIP("cpuid\n");
sewardj588ea762004-09-10 18:56:32 +00009208 break;
sewardj7cb49d72004-10-24 22:31:25 +00009209 }
9210
sewardj5bd4d162004-11-10 13:02:48 +00009211//-- if (!VG_(cpu_has_feature)(VG_X86_FEAT_CPUID))
9212//-- goto decode_failure;
sewardjc9a65702004-07-07 16:32:57 +00009213//--
9214//-- t1 = newTemp(cb);
9215//-- t2 = newTemp(cb);
9216//-- t3 = newTemp(cb);
9217//-- t4 = newTemp(cb);
9218//-- uInstr0(cb, CALLM_S, 0);
9219//--
9220//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t1);
9221//-- uInstr1(cb, PUSH, 4, TempReg, t1);
9222//--
9223//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
9224//-- uLiteral(cb, 0);
9225//-- uInstr1(cb, PUSH, 4, TempReg, t2);
9226//--
9227//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t3);
9228//-- uLiteral(cb, 0);
9229//-- uInstr1(cb, PUSH, 4, TempReg, t3);
9230//--
9231//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
9232//-- uLiteral(cb, 0);
9233//-- uInstr1(cb, PUSH, 4, TempReg, t4);
9234//--
9235//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CPUID));
9236//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
9237//--
9238//-- uInstr1(cb, POP, 4, TempReg, t4);
9239//-- uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_EDX);
9240//--
9241//-- uInstr1(cb, POP, 4, TempReg, t3);
9242//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ECX);
9243//--
9244//-- uInstr1(cb, POP, 4, TempReg, t2);
9245//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBX);
9246//--
9247//-- uInstr1(cb, POP, 4, TempReg, t1);
9248//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
9249//--
9250//-- uInstr0(cb, CALLM_E, 0);
9251//-- DIP("cpuid\n");
9252//-- break;
9253//--
sewardj9334b0f2004-07-10 22:43:54 +00009254 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
9255
9256 case 0xB6: /* MOVZXb Eb,Gv */
9257 delta = dis_movx_E_G ( sorb, delta, 1, 4, False );
9258 break;
sewardj940e8c92004-07-11 16:53:24 +00009259 case 0xB7: /* MOVZXw Ew,Gv */
9260 delta = dis_movx_E_G ( sorb, delta, 2, 4, False );
9261 break;
9262
sewardj0611d802004-07-11 02:37:54 +00009263 case 0xBE: /* MOVSXb Eb,Gv */
9264 delta = dis_movx_E_G ( sorb, delta, 1, 4, True );
9265 break;
sewardj7ed22952004-07-29 00:09:58 +00009266 case 0xBF: /* MOVSXw Ew,Gv */
9267 delta = dis_movx_E_G ( sorb, delta, 2, 4, True );
9268 break;
9269
sewardjc9a65702004-07-07 16:32:57 +00009270//-- /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
9271//--
9272//-- case 0xC3: /* MOVNTI Gv,Ev */
9273//-- vg_assert(sz == 4);
9274//-- modrm = getUChar(eip);
9275//-- vg_assert(!epartIsReg(modrm));
9276//-- t1 = newTemp(cb);
9277//-- uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
9278//-- pair = disAMode ( cb, sorb, eip, dis_buf );
9279//-- t2 = LOW24(pair);
9280//-- eip += HI8(pair);
9281//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
9282//-- DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
9283//-- break;
sewardjcf780b42004-07-13 18:42:17 +00009284
9285 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
9286
9287 case 0xAF: /* IMUL Ev, Gv */
sewardj2a2ba8b2004-11-08 13:14:06 +00009288 delta = dis_mul_E_G ( sorb, sz, delta );
sewardjcf780b42004-07-13 18:42:17 +00009289 break;
sewardje87b4842004-07-10 12:23:30 +00009290
9291 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
9292 case 0x80:
9293 case 0x81:
9294 case 0x82: /* JBb/JNAEb (jump below) */
9295 case 0x83: /* JNBb/JAEb (jump not below) */
9296 case 0x84: /* JZb/JEb (jump zero) */
9297 case 0x85: /* JNZb/JNEb (jump not zero) */
9298 case 0x86: /* JBEb/JNAb (jump below or equal) */
9299 case 0x87: /* JNBEb/JAb (jump not below or equal) */
9300 case 0x88: /* JSb (jump negative) */
9301 case 0x89: /* JSb (jump not negative) */
9302 case 0x8A: /* JP (jump parity even) */
9303 case 0x8B: /* JNP/JPO (jump parity odd) */
9304 case 0x8C: /* JLb/JNGEb (jump less) */
9305 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
9306 case 0x8E: /* JLEb/JNGb (jump less or equal) */
9307 case 0x8F: /* JGb/JNLEb (jump greater) */
sewardj4fd30f22004-10-25 00:42:16 +00009308 d32 = (((Addr32)guest_eip_bbstart)+delta+4) + getUDisp32(delta);
sewardje87b4842004-07-10 12:23:30 +00009309 delta += 4;
sewardj4fd30f22004-10-25 00:42:16 +00009310 jcc_01((Condcode)(opc - 0x80), (Addr32)(guest_eip_bbstart+delta), d32);
sewardjce70a5c2004-10-18 14:09:54 +00009311 whatNext = Dis_StopHere;
sewardje87b4842004-07-10 12:23:30 +00009312 DIP("j%s-32 0x%x\n", name_Condcode(opc - 0x80), d32);
9313 break;
9314
sewardj89cd0932004-09-08 18:23:25 +00009315
9316 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
9317
9318 case 0x31: /* RDTSC */
9319 vex_printf("vex x86->IR: kludged rdtsc\n");
9320 putIReg(4, R_EAX, mkU32(0));
9321 putIReg(4, R_EDX, mkU32(0));
9322
sewardjc9a65702004-07-07 16:32:57 +00009323//-- t1 = newTemp(cb);
9324//-- t2 = newTemp(cb);
9325//-- t3 = newTemp(cb);
9326//-- uInstr0(cb, CALLM_S, 0);
9327//-- // Nb: even though these args aren't used by RDTSC_helper, need
9328//-- // them to be defined (for Memcheck). The TempRegs pushed must
9329//-- // also be distinct.
9330//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
9331//-- uLiteral(cb, 0);
9332//-- uInstr1(cb, PUSH, 4, TempReg, t1);
9333//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
9334//-- uLiteral(cb, 0);
9335//-- uInstr1(cb, PUSH, 4, TempReg, t2);
9336//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_RDTSC));
9337//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
9338//-- uInstr1(cb, POP, 4, TempReg, t3);
9339//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EDX);
9340//-- uInstr1(cb, POP, 4, TempReg, t3);
9341//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EAX);
9342//-- uInstr0(cb, CALLM_E, 0);
sewardj89cd0932004-09-08 18:23:25 +00009343 DIP("rdtsc\n");
9344 break;
sewardj77b86be2004-07-11 13:28:24 +00009345
9346 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
9347 case 0x90:
9348 case 0x91:
9349 case 0x92: /* set-Bb/set-NAEb (jump below) */
9350 case 0x93: /* set-NBb/set-AEb (jump not below) */
9351 case 0x94: /* set-Zb/set-Eb (jump zero) */
9352 case 0x95: /* set-NZb/set-NEb (jump not zero) */
9353 case 0x96: /* set-BEb/set-NAb (jump below or equal) */
9354 case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
9355 case 0x98: /* set-Sb (jump negative) */
9356 case 0x99: /* set-Sb (jump not negative) */
9357 case 0x9A: /* set-P (jump parity even) */
9358 case 0x9B: /* set-NP (jump parity odd) */
9359 case 0x9C: /* set-Lb/set-NGEb (jump less) */
9360 case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
9361 case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
9362 case 0x9F: /* set-Gb/set-NLEb (jump greater) */
sewardj5bd4d162004-11-10 13:02:48 +00009363 t1 = newTemp(Ity_I8);
9364 assign( t1, unop(Iop_1Uto8,mk_calculate_condition(opc-0x90)) );
sewardj77b86be2004-07-11 13:28:24 +00009365 modrm = getIByte(delta);
9366 if (epartIsReg(modrm)) {
9367 delta++;
sewardj5bd4d162004-11-10 13:02:48 +00009368 putIReg(1, eregOfRM(modrm), mkexpr(t1));
sewardj77b86be2004-07-11 13:28:24 +00009369 DIP("set%s %s\n", name_Condcode(opc-0x90),
9370 nameIReg(1,eregOfRM(modrm)));
9371 } else {
sewardj750f4072004-07-26 22:39:11 +00009372 addr = disAMode ( &alen, sorb, delta, dis_buf );
9373 delta += alen;
9374 storeLE( mkexpr(addr), mkexpr(t1) );
9375 DIP("set%s %s\n", name_Condcode(opc-0x90), dis_buf);
sewardj77b86be2004-07-11 13:28:24 +00009376 }
9377 break;
9378
sewardj180e8b32004-07-29 01:40:11 +00009379 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
9380
9381 case 0xA4: /* SHLDv imm8,Gv,Ev */
9382 modrm = getIByte(delta);
9383 d32 = delta + lengthAMode(delta);
9384 vex_sprintf(dis_buf, "$%d", delta);
9385 delta = dis_SHLRD_Gv_Ev (
9386 sorb, delta, modrm, sz,
9387 mkU8(getIByte(d32)), True, /* literal */
9388 dis_buf, True );
9389 break;
sewardja06e5562004-07-14 13:18:05 +00009390 case 0xA5: /* SHLDv %cl,Gv,Ev */
9391 modrm = getIByte(delta);
9392 delta = dis_SHLRD_Gv_Ev (
9393 sorb, delta, modrm, sz,
9394 getIReg(1,R_ECX), False, /* not literal */
9395 "%cl", True );
9396 break;
9397
sewardj68511542004-07-28 00:15:44 +00009398 case 0xAC: /* SHRDv imm8,Gv,Ev */
9399 modrm = getIByte(delta);
9400 d32 = delta + lengthAMode(delta);
9401 vex_sprintf(dis_buf, "$%d", delta);
9402 delta = dis_SHLRD_Gv_Ev (
9403 sorb, delta, modrm, sz,
9404 mkU8(getIByte(d32)), True, /* literal */
9405 dis_buf, False );
9406 break;
sewardja511afc2004-07-29 22:26:03 +00009407 case 0xAD: /* SHRDv %cl,Gv,Ev */
9408 modrm = getIByte(delta);
9409 delta = dis_SHLRD_Gv_Ev (
9410 sorb, delta, modrm, sz,
9411 getIReg(1,R_ECX), False, /* not literal */
9412 "%cl", False );
9413 break;
9414
sewardj464efa42004-11-19 22:17:29 +00009415 /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
9416
sewardjc9a65702004-07-07 16:32:57 +00009417//-- case 0xC0: /* XADD Gb,Eb */
9418//-- eip = dis_xadd_G_E ( cb, sorb, 1, eip );
9419//-- break;
sewardj883b00b2004-09-11 09:30:24 +00009420 case 0xC1: /* XADD Gv,Ev */
9421 delta = dis_xadd_G_E ( sorb, sz, delta );
9422 break;
9423
sewardjc9a65702004-07-07 16:32:57 +00009424//-- /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
9425//--
9426//-- case 0x0D: /* PREFETCH / PREFETCHW - 3Dnow!ery*/
9427//-- case 0x18: /* PREFETCHT0/PREFETCHT1/PREFETCHT2/PREFETCHNTA */
9428//--
9429//-- vg_assert(sz == 4);
9430//-- modrm = getUChar(eip);
9431//-- if (epartIsReg(modrm)) {
9432//-- goto decode_failure;
9433//-- }
9434//-- if (gregOfRM(modrm) > 3) {
9435//-- goto decode_failure;
9436//-- }
9437//-- eip += lengthAMode(eip);
9438//-- if (VG_(print_codegen)) {
9439//-- UChar* hintstr;
9440//-- if (opc == 0x0D) {
9441//-- switch (gregOfRM(modrm)) {
9442//-- case 0: hintstr = ""; break;
9443//-- case 1: hintstr = "w"; break;
9444//-- default: goto decode_failure;
9445//-- }
9446//-- }
9447//-- else {
9448//-- switch (gregOfRM(modrm)) {
9449//-- case 0: hintstr = "nta"; break;
9450//-- case 1: hintstr = "t0"; break;
9451//-- case 2: hintstr = "t1"; break;
9452//-- case 3: hintstr = "t2"; break;
9453//-- default: goto decode_failure;
9454//-- }
9455//-- }
9456//-- VG_(printf)("prefetch%s ...\n", hintstr);
9457//-- }
9458//-- break;
9459//--
9460//-- case 0x71: case 0x72: case 0x73: {
9461//-- /* (sz==4): PSLL/PSRA/PSRL mmxreg by imm8 */
9462//-- /* (sz==2): PSLL/PSRA/PSRL xmmreg by imm8 */
9463//-- UChar byte1, byte2, byte3, subopc, mmreg;
9464//-- vg_assert(sz == 4 || sz == 2);
9465//-- byte1 = opc; /* 0x71/72/73 */
9466//-- byte2 = getUChar(eip); eip++; /* amode / sub-opcode */
9467//-- byte3 = getUChar(eip); eip++; /* imm8 */
9468//-- mmreg = byte2 & 7;
9469//-- subopc = (byte2 >> 3) & 7;
9470//-- if (subopc == 2 || subopc == 6 || subopc == 4) {
9471//-- /* 2 == 010 == SRL, 6 == 110 == SLL, 4 == 100 == SRA */
9472//-- /* ok */
9473//-- } else
9474//-- if (sz == 2 && opc == 0x73 && (subopc == 7 || subopc == 3)) {
9475//-- /* 3 == PSRLDQ, 7 == PSLLDQ */
9476//-- /* This is allowable in SSE. Because sz==2 we fall thru to
9477//-- SSE5 below. */
9478//-- } else {
9479//-- eip -= (sz==2 ? 3 : 2);
9480//-- goto decode_failure;
9481//-- }
9482//-- if (sz == 4) {
9483//-- /* The leading 0x0F is implied for MMX*, so we don't
sewardj5bd4d162004-11-10 13:02:48 +00009484//-- include it. */
sewardjc9a65702004-07-07 16:32:57 +00009485//-- uInstr2(cb, MMX3, 0,
9486//-- Lit16, (((UShort)byte1) << 8) | ((UShort)byte2),
9487//-- Lit16, ((UShort)byte3) );
9488//-- DIP("ps%s%s $%d, %s\n",
9489//-- ( subopc == 2 ? "rl"
9490//-- : subopc == 6 ? "ll"
9491//-- : subopc == 4 ? "ra"
9492//-- : "??"),
9493//-- nameMMXGran(opc & 3), (Int)byte3, nameMMXReg(mmreg) );
sewardj5bd4d162004-11-10 13:02:48 +00009494//-- } else {
sewardjc9a65702004-07-07 16:32:57 +00009495//-- /* Whereas we have to include it for SSE. */
9496//-- uInstr3(cb, SSE5, 0,
9497//-- Lit16, (((UShort)0x66) << 8) | ((UShort)0x0F),
9498//-- Lit16, (((UShort)byte1) << 8) | ((UShort)byte2),
9499//-- Lit16, ((UShort)byte3) );
9500//-- DIP("ps%s%s $%d, %s\n",
9501//-- ( subopc == 2 ? "rl"
9502//-- : subopc == 6 ? "ll"
9503//-- : subopc == 4 ? "ra"
9504//-- : subopc == 3 ? "(PSRLDQ)"
9505//-- : subopc == 7 ? "(PSLLDQ)"
9506//-- : "??"),
9507//-- nameMMXGran(opc & 3), (Int)byte3, nameXMMReg(mmreg) );
sewardj5bd4d162004-11-10 13:02:48 +00009508//-- }
sewardjc9a65702004-07-07 16:32:57 +00009509//-- break;
9510//-- }
9511//--
sewardjc9a65702004-07-07 16:32:57 +00009512//-- case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
9513//-- vg_assert(sz == 4);
9514//-- modrm = getUChar(eip);
9515//-- if (epartIsReg(modrm)) {
9516//-- eip++;
9517//-- t1 = newTemp(cb);
9518//-- uInstr2(cb, MMX2_ERegWr, 4,
9519//-- Lit16,
9520//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
9521//-- TempReg, t1 );
9522//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, eregOfRM(modrm));
9523//-- DIP("movd %s, %s\n",
9524//-- nameMMXReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
9525//-- } else {
9526//-- Int tmpa;
9527//-- pair = disAMode ( cb, sorb, eip, dis_buf );
9528//-- tmpa = LOW24(pair);
9529//-- eip += HI8(pair);
9530//-- uInstr2(cb, MMX2_MemWr, 4,
9531//-- Lit16,
9532//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
9533//-- TempReg, tmpa);
9534//-- DIP("movd %s, %s\n", nameMMXReg(gregOfRM(modrm)), dis_buf);
9535//-- }
9536//-- break;
9537//--
9538//-- case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
9539//-- vg_assert(sz == 4);
9540//-- modrm = getUChar(eip);
9541//-- if (epartIsReg(modrm)) {
9542//-- eip++;
9543//-- t1 = newTemp(cb);
9544//-- uInstr2(cb, GET, 4, ArchReg, eregOfRM(modrm), TempReg, t1);
9545//-- uInstr2(cb, MMX2_ERegRd, 4,
9546//-- Lit16,
9547//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
9548//-- TempReg, t1 );
9549//-- DIP("movd %s, %s\n",
9550//-- nameIReg(4,eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
9551//-- } else {
9552//-- Int tmpa;
9553//-- pair = disAMode ( cb, sorb, eip, dis_buf );
9554//-- tmpa = LOW24(pair);
9555//-- eip += HI8(pair);
9556//-- uInstr2(cb, MMX2_MemRd, 4,
9557//-- Lit16,
9558//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
9559//-- TempReg, tmpa);
9560//-- DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregOfRM(modrm)));
9561//-- }
9562//-- break;
9563//--
sewardj464efa42004-11-19 22:17:29 +00009564
9565 case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
9566
9567 case 0xFC:
9568 case 0xFD:
9569 case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
9570
9571 case 0xEC:
9572 case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
9573
9574 case 0xDC:
9575 case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
9576
9577 case 0xF8:
9578 case 0xF9:
9579 case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
9580
9581 case 0xE8:
9582 case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
9583
9584 case 0xD8:
9585 case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
9586
9587 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
9588 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
9589
sewardj4340dac2004-11-20 13:17:04 +00009590 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
9591
9592 case 0x74:
9593 case 0x75:
9594 case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
9595
9596 case 0x64:
9597 case 0x65:
9598 case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
9599
sewardj63ba4092004-11-21 12:30:18 +00009600 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
9601 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
9602 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
9603
9604 case 0x68:
9605 case 0x69:
9606 case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
9607
9608 case 0x60:
9609 case 0x61:
9610 case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
9611
9612 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
9613 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
9614 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
9615 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
9616
sewardj8d14a592004-11-21 17:04:50 +00009617 case 0xF1:
9618 case 0xF2:
9619 case 0xF3: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
9620
9621 case 0xD1:
9622 case 0xD2:
9623 case 0xD3: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
9624
9625 case 0xE1:
9626 case 0xE2: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
9627
sewardj464efa42004-11-19 22:17:29 +00009628 case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
9629 {
9630 UInt delta0 = delta-1;
9631 Bool decode_OK = False;
9632 delta = dis_MMX ( &decode_OK, sorb, sz, delta-1 );
9633 if (!decode_OK) {
9634 delta = delta0;
9635 goto decode_failure;
9636 }
9637 break;
9638 }
9639
sewardj8d14a592004-11-21 17:04:50 +00009640 case 0x77: /* EMMS */
9641 vassert(sz == 4);
9642 do_EMMS_boilerplate();
9643 DIP("emms\n");
9644 break;
9645
sewardjc9a65702004-07-07 16:32:57 +00009646//-- case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
9647//-- case 0xE7: /* MOVNTQ (src)mmxreg, (dst)mmxreg-or-mem */
9648//-- vg_assert(sz == 4);
9649//-- modrm = getUChar(eip);
9650//-- if (epartIsReg(modrm)) {
9651//-- eip++;
9652//-- uInstr1(cb, MMX2, 0,
9653//-- Lit16,
9654//-- (((UShort)(opc)) << 8) | ((UShort)modrm) );
9655//-- DIP("movq %s, %s\n",
9656//-- nameMMXReg(gregOfRM(modrm)), nameMMXReg(eregOfRM(modrm)));
9657//-- } else {
9658//-- Int tmpa;
9659//-- pair = disAMode ( cb, sorb, eip, dis_buf );
9660//-- tmpa = LOW24(pair);
9661//-- eip += HI8(pair);
9662//-- uInstr2(cb, MMX2_MemWr, 8,
9663//-- Lit16,
9664//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
9665//-- TempReg, tmpa);
9666//-- DIP("mov(nt)q %s, %s\n",
9667//-- nameMMXReg(gregOfRM(modrm)), dis_buf);
9668//-- }
9669//-- break;
9670//--
9671//-- case 0xFC: case 0xFD: case 0xFE:
9672//-- /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
9673//-- vg_assert(sz == 4);
9674//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "padd", True );
9675//-- break;
9676//--
9677//-- case 0xD4:
9678//-- /* PADDQ (src)mmxreg-or-mem, (dst)mmxreg */
9679//-- vg_assert(sz == 4);
9680//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "paddq", False );
9681//-- break;
9682//--
9683//-- case 0xEC: case 0xED:
9684//-- /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
9685//-- vg_assert(sz == 4);
9686//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "padds", True );
9687//-- break;
9688//--
9689//-- case 0xDC: case 0xDD:
9690//-- /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
9691//-- vg_assert(sz == 4);
9692//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "paddus", True );
9693//-- break;
9694//--
9695//-- case 0xF8: case 0xF9: case 0xFA: case 0xFB:
9696//-- /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
9697//-- vg_assert(sz == 4);
9698//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psub", True );
9699//-- break;
9700//--
9701//-- case 0xE8: case 0xE9:
9702//-- /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
9703//-- vg_assert(sz == 4);
9704//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psubs", True );
9705//-- break;
9706//--
9707//-- case 0xD8: case 0xD9:
9708//-- /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
9709//-- vg_assert(sz == 4);
9710//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psubus", True );
9711//-- break;
9712//--
9713//-- case 0xE4: /* PMULHUW (src)mmxreg-or-mem, (dst)mmxreg */
9714//-- vg_assert(sz == 4);
9715//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmulhuw", False );
9716//-- break;
9717//--
9718//-- case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
9719//-- vg_assert(sz == 4);
9720//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmulhw", False );
9721//-- break;
9722//--
9723//-- case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
9724//-- vg_assert(sz == 4);
9725//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmullw", False );
9726//-- break;
9727//--
9728//-- case 0xF4: /* PMULUDQ (src)mmxreg-or-mem, (dst)mmxreg */
9729//-- vg_assert(sz == 4);
9730//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmuludq", False );
9731//-- break;
9732//--
9733//-- case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
9734//-- vg_assert(sz == 4);
9735//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmaddwd", False );
9736//-- break;
9737//--
9738//-- case 0x74: case 0x75: case 0x76:
9739//-- /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
9740//-- vg_assert(sz == 4);
9741//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pcmpeq", True );
9742//-- break;
9743//--
9744//-- case 0x64: case 0x65: case 0x66:
9745//-- /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
9746//-- vg_assert(sz == 4);
9747//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pcmpgt", True );
9748//-- break;
9749//--
9750//-- case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
9751//-- vg_assert(sz == 4);
9752//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "packssdw", False );
9753//-- break;
9754//--
9755//-- case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
9756//-- vg_assert(sz == 4);
9757//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "packsswb", False );
9758//-- break;
9759//--
9760//-- case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
9761//-- vg_assert(sz == 4);
9762//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "packuswb", False );
9763//-- break;
9764//--
9765//-- case 0x68: case 0x69: case 0x6A:
9766//-- /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
9767//-- vg_assert(sz == 4);
9768//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "punpckh", True );
9769//-- break;
9770//--
9771//-- case 0x60: case 0x61: case 0x62:
9772//-- /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
9773//-- vg_assert(sz == 4);
9774//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "punpckl", True );
9775//-- break;
9776//--
9777//-- case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
9778//-- vg_assert(sz == 4);
9779//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pand", False );
9780//-- break;
9781//--
9782//-- case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
9783//-- vg_assert(sz == 4);
9784//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pandn", False );
9785//-- break;
9786//--
9787//-- case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
9788//-- vg_assert(sz == 4);
9789//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "por", False );
9790//-- break;
9791//--
9792//-- case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
9793//-- vg_assert(sz == 4);
9794//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pxor", False );
9795//-- break;
9796//--
9797//-- case 0xF1: case 0xF2: case 0xF3:
9798//-- /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
9799//-- vg_assert(sz == 4);
9800//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psll", True );
9801//-- break;
9802//--
9803//-- case 0xD1: case 0xD2: case 0xD3:
9804//-- /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
9805//-- vg_assert(sz == 4);
9806//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psrl", True );
9807//-- break;
9808//--
9809//-- case 0xE1: case 0xE2:
9810//-- /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
9811//-- vg_assert(sz == 4);
9812//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psra", True );
9813//-- break;
9814//--
9815//-- case 0xDA:
9816//-- /* PMINUB (src)mmxreg-or-mem, (dst)mmxreg */
9817//-- vg_assert(sz == 4);
9818//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pminub", False );
9819//-- break;
9820//--
9821//-- case 0xDE:
9822//-- /* PMAXUB (src)mmxreg-or-mem, (dst)mmxreg */
9823//-- vg_assert(sz == 4);
9824//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmaxub", False );
9825//-- break;
9826//--
9827//-- case 0xEA:
9828//-- /* PMINSW (src)mmxreg-or-mem, (dst)mmxreg */
9829//-- vg_assert(sz == 4);
9830//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pminsw", False );
9831//-- break;
9832//--
9833//-- case 0xEE:
9834//-- /* PMAXSW (src)mmxreg-or-mem, (dst)mmxreg */
9835//-- vg_assert(sz == 4);
9836//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmaxsw", False );
9837//-- break;
9838//--
9839//-- case 0xE0:
9840//-- /* PAVGB (src)mmxreg-or-mem, (dst)mmxreg */
9841//-- vg_assert(sz == 4);
9842//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pavgb", False );
9843//-- break;
9844//--
9845//-- case 0xE3:
9846//-- /* PAVGW (src)mmxreg-or-mem, (dst)mmxreg */
9847//-- vg_assert(sz == 4);
9848//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pavgw", False );
9849//-- break;
9850//--
9851//-- case 0xF6:
9852//-- /* PSADBW (src)mmxreg-or-mem, (dst)mmxreg */
9853//-- vg_assert(sz == 4);
9854//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psadbw", False );
9855//-- break;
9856//--
9857//-- case 0x70:
9858//-- /* PSHUFW imm8, (src)mmxreg-or-mem, (dst)mmxreg */
9859//-- vg_assert(sz == 4);
9860//-- eip = dis_MMXop_regmem_to_reg_Imm8 ( cb, sorb, eip, opc, "pshufw", False );
9861//-- break;
9862//--
9863//-- case 0xD7:
9864//-- /* PMOVMSKB (src)mmxreg, (dst)ireg */
9865//-- vg_assert(sz == 4);
9866//-- modrm = getUChar(eip);
9867//-- vg_assert(epartIsReg(modrm));
9868//-- t1 = newTemp(cb);
9869//-- uInstr3(cb, SSE2g_RegWr, 4,
9870//-- Lit16, (((UShort)(0x0F)) << 8) | (UShort)(opc),
9871//-- Lit16, (UShort)modrm,
9872//-- TempReg, t1 );
9873//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
9874//-- DIP("pmovmskb %s, %s\n",
9875//-- nameMMXReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)));
9876//-- eip++;
9877//-- break;
9878//--
9879//-- case 0xC5:
9880//-- /* PEXTRW (src)mmxreg, (dst)ireg */
9881//-- vg_assert(sz == 4);
9882//-- t1 = newTemp(cb);
9883//-- modrm = getUChar(eip); eip++;
9884//-- abyte = getUChar(eip); eip++;
9885//-- vg_assert(epartIsReg(modrm));
9886//-- uInstr3(cb, SSE2g1_RegWr, 4,
9887//-- Lit16, (((UShort)(0x0F)) << 8) | (UShort)(opc),
9888//-- Lit16, (UShort)modrm,
9889//-- TempReg, t1 );
9890//-- uLiteral(cb, abyte);
9891//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
9892//-- DIP("pextrw %s, %d, %s\n",
9893//-- nameMMXReg(eregOfRM(modrm)), (Int)abyte,
9894//-- nameIReg(4, gregOfRM(modrm)));
9895//-- break;
9896//--
9897//-- case 0xC4:
9898//-- /* PINSRW (src)ireg, (dst)mmxreg */
9899//-- vg_assert(sz == 4);
9900//-- t1 = newTemp(cb);
9901//-- modrm = getUChar(eip); eip++;
9902//-- abyte = getUChar(eip); eip++;
9903//-- vg_assert(epartIsReg(modrm));
9904//-- uInstr2(cb, GET, 2, ArchReg, eregOfRM(modrm), TempReg, t1);
9905//-- uInstr3(cb, SSE2e1_RegRd, 2,
9906//-- Lit16, (((UShort)(0x0F)) << 8) | (UShort)(opc),
9907//-- Lit16, (UShort)modrm,
9908//-- TempReg, t1 );
9909//-- uLiteral(cb, abyte);
9910//-- DIP("pinsrw %s, %d, %s\n", nameIReg(2, eregOfRM(modrm)),
9911//-- (Int)abyte, nameMMXReg(gregOfRM(modrm)));
9912//-- break;
9913//--
9914//-- case 0xA1: /* POP %FS */
9915//-- dis_pop_segreg( cb, R_FS, sz ); break;
9916//-- case 0xA9: /* POP %GS */
9917//-- dis_pop_segreg( cb, R_GS, sz ); break;
9918//--
9919//-- case 0xA0: /* PUSH %FS */
9920//-- dis_push_segreg( cb, R_FS, sz ); break;
9921//-- case 0xA8: /* PUSH %GS */
9922//-- dis_push_segreg( cb, R_GS, sz ); break;
sewardje87b4842004-07-10 12:23:30 +00009923
9924 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
9925
9926 default:
9927 goto decode_failure;
9928 } /* switch (opc) for the 2-byte opcodes */
9929 goto decode_success;
9930 } /* case 0x0F: of primary opcode */
sewardjc9a65702004-07-07 16:32:57 +00009931
9932 /* ------------------------ ??? ------------------------ */
9933
9934 default:
sewardje87b4842004-07-10 12:23:30 +00009935 decode_failure:
sewardjc9a65702004-07-07 16:32:57 +00009936 /* All decode failures end up here. */
9937 vex_printf("disInstr(x86): unhandled instruction bytes: "
9938 "0x%x 0x%x 0x%x 0x%x\n",
9939 (Int)getIByte(delta_start+0),
9940 (Int)getIByte(delta_start+1),
9941 (Int)getIByte(delta_start+2),
9942 (Int)getIByte(delta_start+3) );
9943 vpanic("x86toIR: unimplemented insn");
9944 /* Print address of failing instruction. */
9945 //VG_(describe_eip)((Addr)eip_start, loc_buf, M_VG_ERRTXT);
9946 //VG_(printf)(" at %s\n", loc_buf);
9947
9948 //uInstr0(cb, CALLM_S, 0);
9949 //uInstr1(cb, CALLM, 0, Lit16,
9950 // VGOFF_(helper_undefined_instruction));
9951 //uInstr0(cb, CALLM_E, 0);
9952
9953 /* just because everything else insists the last instruction of
9954 a BB is a jmp */
9955 //jmp_lit(cb, eip);
sewardjce70a5c2004-10-18 14:09:54 +00009956 //whatNext = Dis_StopHere;
sewardjc9a65702004-07-07 16:32:57 +00009957 //break;
9958 //return eip;
9959
9960 } /* switch (opc) for the main (primary) opcode switch. */
9961
sewardje87b4842004-07-10 12:23:30 +00009962 decode_success:
sewardjc9a65702004-07-07 16:32:57 +00009963 /* All decode successes end up here. */
9964 DIP("\n");
sewardjc9a65702004-07-07 16:32:57 +00009965
sewardjce70a5c2004-10-18 14:09:54 +00009966 *size = delta - delta_start;
9967 return whatNext;
sewardjc9a65702004-07-07 16:32:57 +00009968}
9969
9970#undef DIP
9971#undef DIS
9972
9973/*--------------------------------------------------------------------*/
sewardjc0ee2ed2004-07-27 10:29:41 +00009974/*--- end guest-x86/toIR.c ---*/
sewardjc9a65702004-07-07 16:32:57 +00009975/*--------------------------------------------------------------------*/