blob: a1686d6d3508eaba02c296f3fb3e232fb4638c64 [file] [log] [blame]
sewardjc9a65702004-07-07 16:32:57 +00001
2/*--------------------------------------------------------------------*/
3/*--- ---*/
sewardjc0ee2ed2004-07-27 10:29:41 +00004/*--- This file (guest-x86/toIR.c) is ---*/
sewardjc9a65702004-07-07 16:32:57 +00005/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/
6/*--- ---*/
7/*--------------------------------------------------------------------*/
8
sewardj77b86be2004-07-11 13:28:24 +00009/* TODO:
sewardj1f40a0a2004-07-21 12:28:07 +000010 SBB reg with itself
sewardj940e8c92004-07-11 16:53:24 +000011 is Iop_Neg* used?
sewardj1f40a0a2004-07-21 12:28:07 +000012 xadd %reg,%reg fix
13 MOVAPS fix (vg_to_ucode rev 1.143)
sewardje05c42c2004-07-08 20:25:10 +000014*/
15
sewardjc9a65702004-07-07 16:32:57 +000016/* Translates x86 code to IR. */
17
18#include "libvex_basictypes.h"
19#include "libvex_ir.h"
sewardje87b4842004-07-10 12:23:30 +000020#include "libvex.h"
sewardjc0ee2ed2004-07-27 10:29:41 +000021
22#include "main/vex_util.h"
23#include "main/vex_globals.h"
24#include "guest-x86/gdefs.h"
sewardjc9a65702004-07-07 16:32:57 +000025
26
27/*------------------------------------------------------------*/
28/*--- Globals ---*/
29/*------------------------------------------------------------*/
30
31/* These are set at the start of the translation of a BB, so
32 that we don't have to pass them around endlessly. */
33
34/* We need to know this to do sub-register accesses correctly. */
35/* CONST */
36static Bool host_is_bigendian;
37
38/* Are we being verbose? */
39/* CONST */
40static Bool print_codegen;
41
42/* Pointer to the guest code area. */
43/* CONST */
44static UChar* guest_code;
45
46/* The guest address corresponding to guest_code[0]. */
47/* CONST */
48static Addr32 guest_eip;
49
sewardjd7cb8532004-08-17 23:59:23 +000050/* The IRBB* into which we're generating code. */
sewardjc9a65702004-07-07 16:32:57 +000051static IRBB* irbb;
52
sewardjc9a65702004-07-07 16:32:57 +000053
54/* Add a statement to the list held by "irbb". */
sewardjd7cb8532004-08-17 23:59:23 +000055static void stmt ( IRStmt* st )
sewardjc9a65702004-07-07 16:32:57 +000056{
sewardjd7cb8532004-08-17 23:59:23 +000057 addStmtToIRBB( irbb, st );
sewardjc9a65702004-07-07 16:32:57 +000058}
59
60/* Generate a new temporary of the given type. */
61static IRTemp newTemp ( IRType ty )
62{
sewardj6d2638e2004-07-15 09:38:27 +000063 vassert(isPlausibleType(ty));
sewardje539a402004-07-14 18:24:17 +000064 return newIRTemp( irbb->tyenv, ty );
sewardjc9a65702004-07-07 16:32:57 +000065}
66
sewardjc9a65702004-07-07 16:32:57 +000067/* Bomb out if we can't handle something. */
sewardjd1061ab2004-07-08 01:45:30 +000068__attribute__ ((noreturn))
sewardjc9a65702004-07-07 16:32:57 +000069static void unimplemented ( Char* str )
70{
71 vex_printf("x86toIR: unimplemented feature\n");
72 vpanic(str);
73}
74
75
76/*------------------------------------------------------------*/
77/*--- Debugging output ---*/
78/*------------------------------------------------------------*/
79
80#define DIP(format, args...) \
81 if (print_codegen) \
82 vex_printf(format, ## args)
83
84#define DIS(buf, format, args...) \
85 if (print_codegen) \
86 vex_sprintf(buf, format, ## args)
87
88
89/*------------------------------------------------------------*/
90/*--- Helper bits and pieces for deconstructing the ---*/
91/*--- x86 insn stream. ---*/
92/*------------------------------------------------------------*/
93
sewardjd1061ab2004-07-08 01:45:30 +000094/* This is the Intel register encoding -- integer regs. */
95#define R_EAX 0
96#define R_ECX 1
97#define R_EDX 2
98#define R_EBX 3
99#define R_ESP 4
100#define R_EBP 5
101#define R_ESI 6
102#define R_EDI 7
103
104
sewardje05c42c2004-07-08 20:25:10 +0000105static UInt extend_s_8to32( UInt x )
sewardjd1061ab2004-07-08 01:45:30 +0000106{
107 return (UInt)((((Int)x) << 24) >> 24);
108}
109
sewardj0611d802004-07-11 02:37:54 +0000110static UInt extend_s_16to32 ( UInt x )
111{
112 return (UInt)((((Int)x) << 16) >> 16);
113}
114
sewardjd1061ab2004-07-08 01:45:30 +0000115/* Fetch a byte from the guest insn stream. */
sewardje05c42c2004-07-08 20:25:10 +0000116static UChar getIByte ( UInt delta )
sewardjd1061ab2004-07-08 01:45:30 +0000117{
118 return guest_code[delta];
119}
120
sewardjc9a65702004-07-07 16:32:57 +0000121/* Extract the reg field from a modRM byte. */
sewardje05c42c2004-07-08 20:25:10 +0000122static Int gregOfRM ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000123{
124 return (Int)( (mod_reg_rm >> 3) & 7 );
125}
126
127/* Figure out whether the mod and rm parts of a modRM byte refer to a
128 register or memory. If so, the byte will have the form 11XXXYYY,
129 where YYY is the register number. */
sewardje05c42c2004-07-08 20:25:10 +0000130static Bool epartIsReg ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000131{
132 return (0xC0 == (mod_reg_rm & 0xC0));
133}
134
135/* ... and extract the register number ... */
sewardje05c42c2004-07-08 20:25:10 +0000136static Int eregOfRM ( UChar mod_reg_rm )
sewardjc9a65702004-07-07 16:32:57 +0000137{
138 return (Int)(mod_reg_rm & 0x7);
139}
140
sewardje05c42c2004-07-08 20:25:10 +0000141/* Get a 8/16/32-bit unsigned value out of the insn stream. */
142
143static UInt getUChar ( UInt delta )
144{
145 UInt v = guest_code[delta+0];
146 return v & 0xFF;
147}
148
149static UInt getUDisp16 ( UInt delta )
150{
151 UInt v = guest_code[delta+1]; v <<= 8;
152 v |= guest_code[delta+0];
153 return v & 0xFFFF;
154}
155
156static UInt getUDisp32 ( UInt delta )
sewardjd1061ab2004-07-08 01:45:30 +0000157{
158 UInt v = guest_code[delta+3]; v <<= 8;
159 v |= guest_code[delta+2]; v <<= 8;
160 v |= guest_code[delta+1]; v <<= 8;
161 v |= guest_code[delta+0];
162 return v;
163}
164
sewardje05c42c2004-07-08 20:25:10 +0000165static UInt getUDisp ( Int size, UInt delta )
166{
167 switch (size) {
168 case 4: return getUDisp32(delta);
169 case 2: return getUDisp16(delta);
170 case 1: return getUChar(delta);
171 default: vpanic("getUDisp(x86)");
172 }
173 return 0; /*notreached*/
174}
175
176
sewardjd1061ab2004-07-08 01:45:30 +0000177/* Get a byte value out of the insn stream and sign-extend to 32
178 bits. */
sewardje05c42c2004-07-08 20:25:10 +0000179static UInt getSDisp8 ( UInt delta )
sewardjd1061ab2004-07-08 01:45:30 +0000180{
181 return extend_s_8to32( (UInt) (guest_code[delta]) );
182}
183
sewardj0611d802004-07-11 02:37:54 +0000184static UInt getSDisp16 ( UInt delta0 )
185{
186 UChar* eip = (UChar*)(&guest_code[delta0]);
187 UInt d = *eip++;
188 d |= ((*eip++) << 8);
189 return extend_s_16to32(d);
190}
191
192static UInt getSDisp ( Int size, UInt delta )
193{
194 switch (size) {
195 case 4: return getUDisp32(delta);
196 case 2: return getSDisp16(delta);
197 case 1: return getSDisp8(delta);
198 default: vpanic("getSDisp(x86)");
199 }
200 return 0; /*notreached*/
201}
sewardjd1061ab2004-07-08 01:45:30 +0000202
sewardjc9a65702004-07-07 16:32:57 +0000203
204/*------------------------------------------------------------*/
205/*--- Helpers for constructing IR. ---*/
206/*------------------------------------------------------------*/
207
208/* Create a 1/2/4 byte read of an x86 integer registers. For 16/8 bit
209 register references, we need to take the host endianness into
210 account. Supplied value is 0 .. 7 and in the Intel instruction
211 encoding. */
sewardje05c42c2004-07-08 20:25:10 +0000212
sewardj9334b0f2004-07-10 22:43:54 +0000213static IRType szToITy ( Int n )
214{
215 switch (n) {
216 case 1: return Ity_I8;
217 case 2: return Ity_I16;
218 case 4: return Ity_I32;
219 default: vpanic("szToITy(x86)");
220 }
221}
222
223static Int integerGuestRegOffset ( Int sz, UInt archreg )
224{
225 vassert(archreg < 8);
226
227 vassert(!host_is_bigendian);
228
229 /* Correct for little-endian host only. */
230 switch (sz) {
231 case 2:
232 case 4: return OFFB_EAX + 4*archreg;
233 case 1: if (archreg < 4)
234 return OFFB_EAX + 4*archreg + 0;
235 else
236 return OFFB_EAX + 4*(archreg-4) + 1;
237 default: vpanic("integerGuestRegOffset(x86,le)");
238 }
239}
240
sewardjd1061ab2004-07-08 01:45:30 +0000241static IRExpr* getIReg ( Int sz, UInt archreg )
sewardjc9a65702004-07-07 16:32:57 +0000242{
243 vassert(sz == 1 || sz == 2 || sz == 4);
244 vassert(archreg < 8);
sewardj9334b0f2004-07-10 22:43:54 +0000245 return IRExpr_Get( integerGuestRegOffset(sz,archreg),
246 szToITy(sz) );
sewardjc9a65702004-07-07 16:32:57 +0000247}
248
249/* Ditto, but write to a reg instead. */
sewardj41f43bc2004-07-08 14:23:22 +0000250static void putIReg ( Int sz, UInt archreg, IRExpr* e )
sewardjc9a65702004-07-07 16:32:57 +0000251{
252 vassert(sz == 1 || sz == 2 || sz == 4);
253 vassert(archreg < 8);
sewardjeeb9ef82004-07-15 12:39:03 +0000254 stmt( IRStmt_Put(integerGuestRegOffset(sz,archreg), e) );
sewardjd1061ab2004-07-08 01:45:30 +0000255}
256
sewardj41f43bc2004-07-08 14:23:22 +0000257static void assign ( IRTemp dst, IRExpr* e )
sewardjd1061ab2004-07-08 01:45:30 +0000258{
sewardj41f43bc2004-07-08 14:23:22 +0000259 stmt( IRStmt_Tmp(dst, e) );
sewardjd1061ab2004-07-08 01:45:30 +0000260}
261
sewardj41f43bc2004-07-08 14:23:22 +0000262static void storeLE ( IRExpr* addr, IRExpr* data )
sewardjd1061ab2004-07-08 01:45:30 +0000263{
sewardj41f43bc2004-07-08 14:23:22 +0000264 stmt( IRStmt_STle(addr,data) );
sewardjd1061ab2004-07-08 01:45:30 +0000265}
266
sewardje87b4842004-07-10 12:23:30 +0000267static IRExpr* unop ( IROp op, IRExpr* a )
268{
269 return IRExpr_Unop(op, a);
270}
271
sewardjd1061ab2004-07-08 01:45:30 +0000272static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
273{
274 return IRExpr_Binop(op, a1, a2);
275}
276
277static IRExpr* mkexpr ( IRTemp tmp )
278{
279 return IRExpr_Tmp(tmp);
280}
281
sewardjc2ac51e2004-07-12 01:03:26 +0000282static IRExpr* mkU8 ( UInt i )
283{
284 vassert(i < 256);
285 return IRExpr_Const(IRConst_U8(i));
286}
287
288static IRExpr* mkU16 ( UInt i )
289{
290 vassert(i < 65536);
291 return IRExpr_Const(IRConst_U16(i));
292}
293
sewardjd1061ab2004-07-08 01:45:30 +0000294static IRExpr* mkU32 ( UInt i )
295{
296 return IRExpr_Const(IRConst_U32(i));
sewardjc9a65702004-07-07 16:32:57 +0000297}
298
sewardj41f43bc2004-07-08 14:23:22 +0000299static IRExpr* mkU ( IRType ty, UInt i )
300{
sewardjc2ac51e2004-07-12 01:03:26 +0000301 if (ty == Ity_I8) return mkU8(i);
302 if (ty == Ity_I16) return mkU16(i);
303 if (ty == Ity_I32) return mkU32(i);
sewardje90ad6a2004-07-10 19:02:10 +0000304 /* If this panics, it usually means you passed a size (1,2,4)
305 value as the IRType, rather than a real IRType. */
sewardj41f43bc2004-07-08 14:23:22 +0000306 vpanic("mkU(x86)");
307}
308
309static IRExpr* loadLE ( IRType ty, IRExpr* data )
310{
311 return IRExpr_LDle(ty,data);
312}
313
314static IROp mkSizedOp ( IRType ty, IROp op8 )
315{
sewardje05c42c2004-07-08 20:25:10 +0000316 Int adj;
sewardj41f43bc2004-07-08 14:23:22 +0000317 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
318 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8
sewardj41f43bc2004-07-08 14:23:22 +0000319 || op8 == Iop_Mul8
320 || op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
sewardjc22a6fd2004-07-29 23:41:47 +0000321 || op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8
sewardje90ad6a2004-07-10 19:02:10 +0000322 || op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8
sewardj41f43bc2004-07-08 14:23:22 +0000323 || op8 == Iop_Not8 || op8 == Iop_Neg8 );
sewardje05c42c2004-07-08 20:25:10 +0000324 adj = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
325 return adj + op8;
sewardj41f43bc2004-07-08 14:23:22 +0000326}
327
sewardj9334b0f2004-07-10 22:43:54 +0000328static IROp mkWidenOp ( Int szSmall, Int szBig, Bool signd )
sewardj41f43bc2004-07-08 14:23:22 +0000329{
sewardj9334b0f2004-07-10 22:43:54 +0000330 if (szSmall == 1 && szBig == 4) {
331 return signd ? Iop_8Sto32 : Iop_8Uto32;
sewardj41f43bc2004-07-08 14:23:22 +0000332 }
sewardj9334b0f2004-07-10 22:43:54 +0000333 if (szSmall == 1 && szBig == 2) {
334 return signd ? Iop_8Sto16 : Iop_8Uto16;
335 }
336 if (szSmall == 2 && szBig == 4) {
337 return signd ? Iop_16Sto32 : Iop_16Uto32;
338 }
339 vpanic("mkWidenOp(x86)");
sewardj41f43bc2004-07-08 14:23:22 +0000340}
341
342
343/*------------------------------------------------------------*/
344/*--- Helpers for %eflags. ---*/
345/*------------------------------------------------------------*/
346
sewardj0611d802004-07-11 02:37:54 +0000347/* -------------- Evaluating the flags-thunk. -------------- */
sewardjc9a65702004-07-07 16:32:57 +0000348
sewardje87b4842004-07-10 12:23:30 +0000349/* Build IR to calculate all the eflags from stored
sewardj77b86be2004-07-11 13:28:24 +0000350 CC_OP/CC_SRC/CC_DST. Returns an expression :: Ity_I32. */
sewardje87b4842004-07-10 12:23:30 +0000351static IRExpr* mk_calculate_eflags_all ( void )
352{
353 IRExpr** args = LibVEX_Alloc(4 * sizeof(IRExpr*));
354 args[0] = IRExpr_Get(OFFB_CC_OP, Ity_I32);
355 args[1] = IRExpr_Get(OFFB_CC_SRC, Ity_I32);
356 args[2] = IRExpr_Get(OFFB_CC_DST, Ity_I32);
357 args[3] = NULL;
358 return IRExpr_CCall("calculate_eflags_all", Ity_I32, args);
359}
360
sewardj84ff0652004-08-23 16:16:08 +0000361/* Build IR to calculate just the carry flag from stored
sewardj77b86be2004-07-11 13:28:24 +0000362 CC_OP/CC_SRC/CC_DST. Returns an expression :: Ity_I32. */
sewardje87b4842004-07-10 12:23:30 +0000363static IRExpr* mk_calculate_eflags_c ( void )
364{
365 IRExpr** args = LibVEX_Alloc(4 * sizeof(IRExpr*));
366 args[0] = IRExpr_Get(OFFB_CC_OP, Ity_I32);
367 args[1] = IRExpr_Get(OFFB_CC_SRC, Ity_I32);
368 args[2] = IRExpr_Get(OFFB_CC_DST, Ity_I32);
369 args[3] = NULL;
370 return IRExpr_CCall("calculate_eflags_c", Ity_I32, args);
371}
372
sewardj84ff0652004-08-23 16:16:08 +0000373/* Build IR to calculate some particular condition from stored
374 CC_OP/CC_SRC/CC_DST. Returns an expression :: Ity_Bit. */
375static IRExpr* calculate_condition ( Condcode cond )
376{
377 IRExpr** args = LibVEX_Alloc(5 * sizeof(IRExpr*));
378 args[0] = mkU32(cond);
379 args[1] = IRExpr_Get(OFFB_CC_OP, Ity_I32);
380 args[2] = IRExpr_Get(OFFB_CC_SRC, Ity_I32);
381 args[3] = IRExpr_Get(OFFB_CC_DST, Ity_I32);
382 args[4] = NULL;
383 return unop(Iop_32to1,
384 IRExpr_CCall("calculate_condition", Ity_I32, args));
385}
386
sewardje87b4842004-07-10 12:23:30 +0000387
sewardj0611d802004-07-11 02:37:54 +0000388/* -------------- Building the flags-thunk. -------------- */
389
sewardjb9c5cf62004-08-24 15:10:38 +0000390/* The machinery in this section builds the flag-thunk following a
391 flag-setting operation. Hence the various setFlags_* functions.
392 Note, in reality setFlags_ADD_SUB and setFlags_MUL are pretty much
393 the same -- they just store the two operands.
394*/
395
396static Bool isAddSub ( IROp op8 )
397{
398 return op8 == Iop_Add8 || op8 == Iop_Sub8;
399}
sewardj0611d802004-07-11 02:37:54 +0000400
sewardja2384712004-07-29 14:36:40 +0000401/* U-widen 8/16/32 bit int expr to 32. */
sewardjc22a6fd2004-07-29 23:41:47 +0000402static IRExpr* widenUto32 ( IRExpr* e )
sewardj443cd9d2004-07-18 23:06:45 +0000403{
404 switch (typeOfIRExpr(irbb->tyenv,e)) {
405 case Ity_I32: return e;
406 case Ity_I16: return unop(Iop_16Uto32,e);
407 case Ity_I8: return unop(Iop_8Uto32,e);
408 default: vpanic("widenUto32");
409 }
410}
411
sewardjc22a6fd2004-07-29 23:41:47 +0000412/* S-widen 8/16/32 bit int expr to 32. */
413static IRExpr* widenSto32 ( IRExpr* e )
414{
415 switch (typeOfIRExpr(irbb->tyenv,e)) {
416 case Ity_I32: return e;
417 case Ity_I16: return unop(Iop_16Sto32,e);
418 case Ity_I8: return unop(Iop_8Sto32,e);
419 default: vpanic("widenSto32");
420 }
421}
422
sewardja2384712004-07-29 14:36:40 +0000423/* Narrow 8/16/32 bit int expr to 8/16/32. Clearly only some
424 of these combinations make sense. */
425static IRExpr* narrowTo ( IRType dst_ty, IRExpr* e )
426{
427 IRType src_ty = typeOfIRExpr(irbb->tyenv,e);
428 if (src_ty == dst_ty)
429 return e;
430 if (src_ty == Ity_I32 && dst_ty == Ity_I16)
431 return unop(Iop_32to16, e);
432 if (src_ty == Ity_I32 && dst_ty == Ity_I8)
433 return unop(Iop_32to8, e);
434
435 vex_printf("\nsrc, dst tys are: ");
436 ppIRType(src_ty);
437 vex_printf(", ");
438 ppIRType(dst_ty);
439 vex_printf("\n");
440 vpanic("narrowTo(x86)");
441}
442
sewardj443cd9d2004-07-18 23:06:45 +0000443
sewardjb9c5cf62004-08-24 15:10:38 +0000444/* This is for add/sub/adc/sbb, where (like multiply) we simply store
445 the two arguments. Note, the args are reversed, so if op8
446 indicates subtract, then the value the program is trying to compute
447 is src1 - src2. */
sewardj0611d802004-07-11 02:37:54 +0000448
sewardjb9c5cf62004-08-24 15:10:38 +0000449static void setFlags_ADD_SUB ( IROp op8,
450 IRTemp src2,
451 IRTemp src1,
452 IRType ty )
sewardj0611d802004-07-11 02:37:54 +0000453{
sewardjb9c5cf62004-08-24 15:10:38 +0000454 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
455
456 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
457
458 switch (op8) {
459 case Iop_Add8: ccOp += CC_OP_ADDB; break;
460 case Iop_Sub8: ccOp += CC_OP_SUBB; break;
461 default: ppIROp(op8);
462 vpanic("setFlags_ADD_SUB(x86)");
463 }
464 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
465 stmt( IRStmt_Put( OFFB_CC_SRC, widenUto32(mkexpr(src2))) );
466 stmt( IRStmt_Put( OFFB_CC_DST, widenUto32(mkexpr(src1))) );
467}
468
469
470/* For and/or/xor, only the result is important. However, put zero in
471 CC_SRC to keep memcheck happy. */
472
473static void setFlags_LOGIC ( IROp op8,
474 IRTemp dst1,
475 IRType ty )
476{
477 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
sewardj0611d802004-07-11 02:37:54 +0000478
479 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
480
481 switch (op8) {
482 case Iop_Or8:
483 case Iop_And8:
sewardjb9c5cf62004-08-24 15:10:38 +0000484 case Iop_Xor8: ccOp += CC_OP_LOGICB; break;
sewardj0611d802004-07-11 02:37:54 +0000485 default: ppIROp(op8);
sewardjb9c5cf62004-08-24 15:10:38 +0000486 vpanic("setFlags_LOGIC(x86)");
sewardj0611d802004-07-11 02:37:54 +0000487 }
sewardjeeb9ef82004-07-15 12:39:03 +0000488 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
sewardjb9c5cf62004-08-24 15:10:38 +0000489 stmt( IRStmt_Put( OFFB_CC_SRC, mkU32(0)) );
sewardjc22a6fd2004-07-29 23:41:47 +0000490 stmt( IRStmt_Put( OFFB_CC_DST, widenUto32(mkexpr(dst1))) );
sewardj0611d802004-07-11 02:37:54 +0000491}
492
493
sewardjb9c5cf62004-08-24 15:10:38 +0000494/* For all shift and rotate cases, store the result value and the
495 result except shifted or rotated one bit less ("undershifted",
496 hence US). And then only when the guard is non-zero. */
sewardj0611d802004-07-11 02:37:54 +0000497
sewardjc22a6fd2004-07-29 23:41:47 +0000498static void setFlags_DSTus_DST1 ( IROp op32,
sewardj0611d802004-07-11 02:37:54 +0000499 IRTemp dstUS,
500 IRTemp dst1,
501 IRType ty,
sewardja06e5562004-07-14 13:18:05 +0000502 IRTemp guard )
sewardj0611d802004-07-11 02:37:54 +0000503{
sewardjc22a6fd2004-07-29 23:41:47 +0000504 Int ccOp = ty==Ity_I8 ? 2 : (ty==Ity_I16 ? 1 : 0);
sewardj0611d802004-07-11 02:37:54 +0000505
506 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
507 vassert(guard);
508
sewardjc22a6fd2004-07-29 23:41:47 +0000509 switch (op32) {
510 case Iop_Shr32:
511 case Iop_Sar32: ccOp = CC_OP_SARL - ccOp; break;
512 case Iop_Shl32: ccOp = CC_OP_SHLL - ccOp; break;
513 default: ppIROp(op32);
514 vpanic("setFlags_DSTus_DST1(x86)");
sewardj0611d802004-07-11 02:37:54 +0000515 }
516
517 /* CC_SRC = undershifted %d after, CC_DST = %d afterwards */
sewardjeeb9ef82004-07-15 12:39:03 +0000518 stmt( IRStmt_Put( OFFB_CC_OP,
sewardj4042c7e2004-07-18 01:28:30 +0000519 IRExpr_Mux0X( mkexpr(guard),
520 IRExpr_Get(OFFB_CC_OP,Ity_I32),
521 mkU32(ccOp))) );
sewardjeeb9ef82004-07-15 12:39:03 +0000522 stmt( IRStmt_Put( OFFB_CC_SRC,
sewardj4042c7e2004-07-18 01:28:30 +0000523 IRExpr_Mux0X( mkexpr(guard),
524 IRExpr_Get(OFFB_CC_SRC,Ity_I32),
sewardjc22a6fd2004-07-29 23:41:47 +0000525 widenUto32(mkexpr(dstUS)))) );
sewardjeeb9ef82004-07-15 12:39:03 +0000526 stmt( IRStmt_Put( OFFB_CC_DST,
sewardj4042c7e2004-07-18 01:28:30 +0000527 IRExpr_Mux0X( mkexpr(guard),
528 IRExpr_Get(OFFB_CC_DST,Ity_I32),
sewardjc22a6fd2004-07-29 23:41:47 +0000529 widenUto32(mkexpr(dst1)))) );
sewardj0611d802004-07-11 02:37:54 +0000530}
531
532
533/* For the inc/dec case, we store the result value and the former
534 value of the carry flag, which unfortunately we have to compute. */
535
536static void setFlags_INC_DEC ( Bool inc, IRTemp dst, IRType ty )
537{
sewardjeeb9ef82004-07-15 12:39:03 +0000538 Int ccOp = inc ? CC_OP_INCB : CC_OP_DECB;
sewardj0611d802004-07-11 02:37:54 +0000539
540 ccOp += ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
541 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
542
543 /* This has to come first, because calculating the C flag
544 may require reading all three OFFB_CC fields. */
sewardjeeb9ef82004-07-15 12:39:03 +0000545 stmt( IRStmt_Put( OFFB_CC_SRC, mk_calculate_eflags_c()) );
546 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
547 stmt( IRStmt_Put( OFFB_CC_DST, mkexpr(dst)) );
sewardj0611d802004-07-11 02:37:54 +0000548}
549
550
sewardjcf780b42004-07-13 18:42:17 +0000551/* For multiplies, just remember the two operands and a
552 description of what kind of multiply. */
553
554static
555void setFlags_MUL ( IRType ty, IRTemp src1, IRTemp src2, UInt base_op )
556{
557 switch (ty) {
558 case Ity_I8:
sewardjeeb9ef82004-07-15 12:39:03 +0000559 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+0) ) );
560 stmt( IRStmt_Put( OFFB_CC_SRC, unop(Iop_8Uto32,mkexpr(src1)) ) );
561 stmt( IRStmt_Put( OFFB_CC_DST, unop(Iop_8Uto32,mkexpr(src2)) ) );
sewardjcf780b42004-07-13 18:42:17 +0000562 break;
563 case Ity_I16:
sewardjeeb9ef82004-07-15 12:39:03 +0000564 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+1) ) );
565 stmt( IRStmt_Put( OFFB_CC_SRC, unop(Iop_16Uto32,mkexpr(src1)) ) );
566 stmt( IRStmt_Put( OFFB_CC_DST, unop(Iop_16Uto32,mkexpr(src2)) ) );
sewardjcf780b42004-07-13 18:42:17 +0000567 break;
568 case Ity_I32:
sewardjeeb9ef82004-07-15 12:39:03 +0000569 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+2) ) );
570 stmt( IRStmt_Put( OFFB_CC_SRC, mkexpr(src1) ) );
571 stmt( IRStmt_Put( OFFB_CC_DST, mkexpr(src2) ) );
sewardjcf780b42004-07-13 18:42:17 +0000572 break;
573 default:
574 vpanic("setFlags_MUL(x86)");
575 }
576}
577
578
sewardj3af115f2004-07-14 02:46:52 +0000579/* -------------- Condition codes. -------------- */
580
sewardje87b4842004-07-10 12:23:30 +0000581/* Condition codes, using the Intel encoding. */
sewardj0611d802004-07-11 02:37:54 +0000582
sewardje87b4842004-07-10 12:23:30 +0000583static Char* name_Condcode ( Condcode cond )
584{
585 switch (cond) {
586 case CondO: return "o";
587 case CondNO: return "no";
588 case CondB: return "b";
589 case CondNB: return "nb";
590 case CondZ: return "z";
591 case CondNZ: return "nz";
592 case CondBE: return "be";
593 case CondNBE: return "nbe";
594 case CondS: return "s";
595 case CondNS: return "ns";
596 case CondP: return "p";
597 case CondNP: return "np";
598 case CondL: return "l";
599 case CondNL: return "nl";
600 case CondLE: return "le";
601 case CondNLE: return "nle";
sewardj64e1d652004-07-12 14:00:46 +0000602 case CondAlways: return "ALWAYS";
sewardje87b4842004-07-10 12:23:30 +0000603 default: vpanic("name_Condcode");
604 }
605}
606
607static Condcode positiveIse_Condcode ( Condcode cond,
608 Bool* needInvert )
609{
610 vassert(cond >= CondO && cond <= CondNLE);
611 if (cond & 1) {
612 *needInvert = True;
613 return cond-1;
614 } else {
615 *needInvert = False;
616 return cond;
617 }
618}
619
620
sewardj84ff0652004-08-23 16:16:08 +0000621#if 0
622/* UNUSED -- DELETE */
sewardje87b4842004-07-10 12:23:30 +0000623/* Get some particular flag to the lowest bit in a word. It's not
624 masked, tho. */
625static IRExpr* flag_to_bit0 ( UInt ccmask, IRTemp eflags )
626{
627 Int shifts = 0;
628 vassert(ccmask == CC_MASK_C || ccmask == CC_MASK_P
629 || ccmask == CC_MASK_A || ccmask == CC_MASK_Z
630 || ccmask == CC_MASK_S || ccmask == CC_MASK_O);
631 while ((ccmask & 1) == 0) {
632 ccmask >>= 1;
633 shifts++;
634 vassert(ccmask != 0);
635 }
636 if (shifts == 0)
637 return mkexpr(eflags);
638 else
sewardj6d2638e2004-07-15 09:38:27 +0000639 return binop(Iop_Shr32, mkexpr(eflags), mkU8(shifts));
sewardje87b4842004-07-10 12:23:30 +0000640}
641
642
643/* Calculate the eflags, and hence return a 1-bit expression
644 which is 1 iff the given condition-code test would succeed.
sewardj77b86be2004-07-11 13:28:24 +0000645 Returns a value :: Ity_Bit.
sewardje87b4842004-07-10 12:23:30 +0000646*/
647static IRExpr* calculate_condition ( Condcode cond )
648{
649 IRExpr *e;
sewardj77b86be2004-07-11 13:28:24 +0000650 IRTemp eflags = newTemp(Ity_I32);
651 Bool invert = (cond & 1) == 1;
sewardje90ad6a2004-07-10 19:02:10 +0000652
653 assign( eflags, cond == CondB ? mk_calculate_eflags_c()
654 : mk_calculate_eflags_all() );
sewardje87b4842004-07-10 12:23:30 +0000655
656 switch (cond) {
sewardj56296d82004-07-30 01:52:45 +0000657 case CondNO:
658 case CondO: /* OF == 1 */
659 e = flag_to_bit0( CC_MASK_O, eflags );
660 break;
sewardj77b86be2004-07-11 13:28:24 +0000661 case CondNZ:
sewardje87b4842004-07-10 12:23:30 +0000662 case CondZ: /* ZF == 1 */
663 e = flag_to_bit0( CC_MASK_Z, eflags );
664 break;
sewardj71a65362004-07-28 01:48:34 +0000665 case CondNB:
sewardje90ad6a2004-07-10 19:02:10 +0000666 case CondB: /* CF == 1 */
667 e = flag_to_bit0( CC_MASK_C, eflags );
668 break;
sewardj77b86be2004-07-11 13:28:24 +0000669 case CondNBE:
sewardje87b4842004-07-10 12:23:30 +0000670 case CondBE: /* (CF or ZF) == 1 */
671 e = binop(Iop_Or32,
672 flag_to_bit0(CC_MASK_C,eflags),
673 flag_to_bit0(CC_MASK_Z,eflags) );
674 break;
sewardj940e8c92004-07-11 16:53:24 +0000675 case CondNS:
676 case CondS: /* SF == 1 */
677 e = flag_to_bit0( CC_MASK_S, eflags );
678 break;
sewardj56296d82004-07-30 01:52:45 +0000679 case CondNP:
sewardj0611d802004-07-11 02:37:54 +0000680 case CondP: /* PF == 1 */
681 e = flag_to_bit0( CC_MASK_P, eflags );
682 break;
sewardjc2ac51e2004-07-12 01:03:26 +0000683 case CondNL:
684 case CondL: /* (SF xor OF) == 1 */
685 e = binop(Iop_Xor32,
686 flag_to_bit0(CC_MASK_S,eflags),
687 flag_to_bit0(CC_MASK_O,eflags)
688 );
689 break;
sewardj1813dbe2004-07-28 17:09:04 +0000690 case CondNLE:
sewardje87b4842004-07-10 12:23:30 +0000691 case CondLE: /* ((SF xor OF) or ZF) == 1 */
692 e = binop(Iop_Or32,
693 binop(Iop_Xor32,
694 flag_to_bit0(CC_MASK_S,eflags),
695 flag_to_bit0(CC_MASK_O,eflags)
696 ),
697 flag_to_bit0(CC_MASK_Z,eflags));
698 break;
699 default:
700 vex_printf("calculate_condition(%d)\n", (Int)cond);
701 vpanic("calculate_condition(x86)");
702 }
sewardj77b86be2004-07-11 13:28:24 +0000703 return
704 invert ? unop(Iop_32to1, unop(Iop_Not32, e))
705 : unop(Iop_32to1, e);
sewardje87b4842004-07-10 12:23:30 +0000706}
sewardj84ff0652004-08-23 16:16:08 +0000707#endif
sewardje87b4842004-07-10 12:23:30 +0000708
709
sewardj3af115f2004-07-14 02:46:52 +0000710/* -------------- Helpers for ADD/SUB with carry. -------------- */
711
712/* Given ta1, ta2 and tdst, compute tdst = ADC(ta1,ta2) and set flags
713 appropriately. Depends critically on the relative ordering of
714 CC_OP_ADD{B,W,L} vs CC_OP_ADC{B,W,L}.
715*/
716static void helper_ADC ( Int sz,
717 IRTemp tdst, IRTemp ta1, IRTemp ta2 )
718{
719 UInt thunkOp;
720 IRExpr* thunkExpr;
721 IRType ty = szToITy(sz);
722 IRTemp oldc = newTemp(Ity_I32);
723 IROp plus = mkSizedOp(ty,Iop_Add8);
724
725 /* oldc = old carry flag, 0 or 1 */
sewardja2384712004-07-29 14:36:40 +0000726 assign( oldc, binop(Iop_And32,
sewardj3af115f2004-07-14 02:46:52 +0000727 mk_calculate_eflags_c(),
sewardja2384712004-07-29 14:36:40 +0000728 mkU32(1)) );
sewardj3af115f2004-07-14 02:46:52 +0000729
sewardja2384712004-07-29 14:36:40 +0000730 assign(tdst, binop(plus,
731 binop(plus,mkexpr(ta1),mkexpr(ta2)),
732 narrowTo(ty,mkexpr(oldc))));
733
734 vassert(sz == 1 || sz == 2 || sz == 4);
735 thunkOp = sz==4 ? CC_OP_ADDL : (sz==2 ? CC_OP_ADDW : CC_OP_ADDB);
sewardj3af115f2004-07-14 02:46:52 +0000736
737 /* This dynamically calculates the thunk op number.
738 3 * the old carry flag is added, so (eg) it gives
739 CC_OP_ADDL if old carry was zero, and CC_OP_ADCL if
740 old carry was one. */
741 thunkExpr = binop(Iop_Add32,
742 mkU32(thunkOp),
743 binop(Iop_Mul32, mkexpr(oldc), mkU32(3)));
744
sewardjeeb9ef82004-07-15 12:39:03 +0000745 stmt( IRStmt_Put( OFFB_CC_OP, thunkExpr ) );
746 stmt( IRStmt_Put( OFFB_CC_SRC, mkexpr(ta2) ) );
sewardjb9c5cf62004-08-24 15:10:38 +0000747 stmt( IRStmt_Put( OFFB_CC_DST, mkexpr(ta1) ) );
sewardj3af115f2004-07-14 02:46:52 +0000748}
749
750
sewardjcaca9d02004-07-28 07:11:32 +0000751/* Given ta1, ta2 and tdst, compute tdst = SBB(ta1,ta2) and set flags
752 appropriately. Depends critically on the relative ordering of
753 CC_OP_SUB{B,W,L} vs CC_OP_SBB{B,W,L}.
754*/
755static void helper_SBB ( Int sz,
756 IRTemp tdst, IRTemp ta1, IRTemp ta2 )
757{
758 UInt thunkOp;
759 IRExpr* thunkExpr;
760 IRType ty = szToITy(sz);
761 IRTemp oldc = newTemp(Ity_I32);
762 IROp minus = mkSizedOp(ty,Iop_Sub8);
763
764 /* oldc = old carry flag, 0 or 1 */
sewardja2384712004-07-29 14:36:40 +0000765 assign( oldc, binop(Iop_And32,
sewardjcaca9d02004-07-28 07:11:32 +0000766 mk_calculate_eflags_c(),
sewardja2384712004-07-29 14:36:40 +0000767 mkU32(1)) );
sewardjcaca9d02004-07-28 07:11:32 +0000768
sewardja2384712004-07-29 14:36:40 +0000769 assign(tdst, binop(minus,
770 binop(minus,mkexpr(ta1),mkexpr(ta2)),
771 narrowTo(ty,mkexpr(oldc))));
772
773 vassert(sz == 1 || sz == 2 || sz == 4);
774 thunkOp = sz==4 ? CC_OP_SUBL : (sz==2 ? CC_OP_SUBW : CC_OP_SUBB);
sewardjcaca9d02004-07-28 07:11:32 +0000775
776 /* This dynamically calculates the thunk op number.
777 3 * the old carry flag is added, so (eg) it gives
778 CC_OP_SUBL if old carry was zero, and CC_OP_SBBL if
779 old carry was one. */
780 thunkExpr = binop(Iop_Add32,
781 mkU32(thunkOp),
782 binop(Iop_Mul32, mkexpr(oldc), mkU32(3)));
783
784 stmt( IRStmt_Put( OFFB_CC_OP, thunkExpr ) );
785 stmt( IRStmt_Put( OFFB_CC_SRC, mkexpr(ta2) ) );
sewardjb9c5cf62004-08-24 15:10:38 +0000786 stmt( IRStmt_Put( OFFB_CC_DST, mkexpr(ta1) ) );
sewardjcaca9d02004-07-28 07:11:32 +0000787}
788
789
sewardjc9a65702004-07-07 16:32:57 +0000790//-- /*------------------------------------------------------------*/
791//-- /*--- CPU feature set stuff ---*/
792//-- /*--- This is a little out of place here, but it will do ---*/
793//-- /*--- for now. ---*/
794//-- /*------------------------------------------------------------*/
795//--
sewardje87b4842004-07-10 12:23:30 +0000796//-- #define VG_CPU_VENDOR_GENERIC 0
797//-- #define VG_CPU_VENDOR_INTEL 1
sewardjc9a65702004-07-07 16:32:57 +0000798//-- #define VG_CPU_VENDOR_AMD 2
799//--
800//-- static Int cpu_vendor = VG_CPU_VENDOR_GENERIC;
801//--
802//-- static const struct cpu_vendor {
803//-- const Char *vendorstr;
804//-- Int vendorid;
805//-- } cpu_vendors[] = {
806//-- { "GenuineIntel", VG_CPU_VENDOR_INTEL },
807//-- { "AuthenticAMD", VG_CPU_VENDOR_AMD },
808//-- };
809//--
810//-- static Int cpuid_level = -2; /* -2 -> not initialized */
811//-- static UInt cpu_features[VG_N_FEATURE_WORDS];
812//--
813//-- /* Standard macro to see if a specific flag is changeable */
814//-- static inline Bool flag_is_changeable(UInt flag)
815//-- {
816//-- UInt f1, f2;
817//--
818//-- asm("pushfl\n\t"
819//-- "pushfl\n\t"
820//-- "popl %0\n\t"
821//-- "movl %0,%1\n\t"
822//-- "xorl %2,%0\n\t"
823//-- "pushl %0\n\t"
824//-- "popfl\n\t"
825//-- "pushfl\n\t"
826//-- "popl %0\n\t"
827//-- "popfl\n\t"
828//-- : "=&r" (f1), "=&r" (f2)
829//-- : "ir" (flag));
830//--
831//-- return ((f1^f2) & flag) != 0;
832//-- }
833//--
834//--
835//-- /* Probe for the CPUID instruction */
836//-- static Bool has_cpuid(void)
837//-- {
838//-- return flag_is_changeable(EFlagID);
839//-- }
840//--
841//-- static void get_cpu_features(void)
842//-- {
843//-- Char vendorstr[13];
844//-- Int i;
845//--
846//-- if (!has_cpuid()) {
847//-- cpuid_level = -1;
848//-- return;
849//-- }
850//--
851//-- cpu_features[VG_INT_FEAT] |= (1 << (VG_X86_FEAT_CPUID%32));
852//--
853//-- VG_(cpuid)(0, &cpuid_level, (UInt *)&vendorstr[0], (UInt *)&vendorstr[8], (UInt *)&vendorstr[4]);
854//-- vendorstr[12] = '\0';
855//--
856//-- for(i = 0; i < sizeof(cpu_vendors)/sizeof(*cpu_vendors); i++)
857//-- if (VG_(memcmp)(vendorstr, cpu_vendors[i].vendorstr, 12) == 0) {
858//-- cpu_vendor = cpu_vendors[i].vendorid;
859//-- break;
860//-- }
861//--
862//-- if (cpuid_level >= 1)
863//-- VG_(cpuid)(1, NULL, NULL, &cpu_features[VG_EXT_FEAT], &cpu_features[VG_X86_FEAT]);
864//--
865//-- switch(cpu_vendor) {
866//-- case VG_CPU_VENDOR_AMD:
867//-- /* get AMD-specific flags */
868//-- VG_(cpuid)(0x80000001, NULL, NULL, NULL, &cpu_features[VG_AMD_FEAT]);
869//-- break;
870//--
871//-- default:
872//-- break;
873//-- }
874//-- }
875//--
876//-- Bool VG_(cpu_has_feature)(UInt feature)
877//-- {
878//-- UInt word = feature / 32;
879//-- UInt bit = feature % 32;
880//--
881//-- if (cpuid_level == -2)
882//-- get_cpu_features();
883//--
884//-- vg_assert(word >= 0 && word < VG_N_FEATURE_WORDS);
885//--
886//-- return !!(cpu_features[word] & (1 << bit));
887//-- }
888//--
889//-- /* The set of features we're willing to support for the client
890//--
891//-- This includes supported instruction set extensions, plus any
892//-- extensions which don't have any user-mode visible effect (but the
893//-- client may find interesting).
894//-- */
sewardjd1061ab2004-07-08 01:45:30 +0000895#define VG_X86_SUPPORTED_FEATURES \
896 ((1 << VG_X86_FEAT_FPU) | \
897 (1 << VG_X86_FEAT_VME) | \
898 (1 << VG_X86_FEAT_DE) | \
899 (1 << VG_X86_FEAT_PSE) | \
900 (1 << VG_X86_FEAT_TSC) | \
901 (0 << VG_X86_FEAT_MSR) | \
902 (1 << VG_X86_FEAT_PAE) | \
903 (1 << VG_X86_FEAT_MCE) | \
904 (1 << VG_X86_FEAT_CX8) | \
905 (1 << VG_X86_FEAT_APIC) | \
906 (0 << VG_X86_FEAT_SEP) | \
907 (1 << VG_X86_FEAT_MTRR) | \
908 (1 << VG_X86_FEAT_PGE) | \
909 (1 << VG_X86_FEAT_MCA) | \
910 (1 << VG_X86_FEAT_CMOV) | \
911 (1 << VG_X86_FEAT_PAT) | \
912 (1 << VG_X86_FEAT_PSE36) | \
913 (0 << VG_X86_FEAT_CLFSH) | \
914 (1 << VG_X86_FEAT_DS) | \
915 (1 << VG_X86_FEAT_ACPI) | \
916 (1 << VG_X86_FEAT_MMX) | \
917 (1 << VG_X86_FEAT_FXSR) | \
918 (1 << VG_X86_FEAT_SSE) | \
919 (1 << VG_X86_FEAT_SSE2) | \
920 (1 << VG_X86_FEAT_SS) | \
921 (1 << VG_X86_FEAT_HT) | \
922 (1 << VG_X86_FEAT_TM) | \
923 (0 << VG_X86_FEAT_IA64) | \
924 (1 << VG_X86_FEAT_PBE))
925
926#define VG_AMD_SUPPORTED_FEATURES \
927 ((0 << (VG_AMD_FEAT_SYSCALL % 32)) | \
928 (0 << (VG_AMD_FEAT_NXP % 32)) | \
929 (1 << (VG_AMD_FEAT_MMXEXT % 32)) | \
930 (0 << (VG_AMD_FEAT_FFXSR % 32)) | \
931 (0 << (VG_AMD_FEAT_LONGMODE % 32)) | \
932 (0 << (VG_AMD_FEAT_3DNOWEXT % 32)) | \
933 (0 << (VG_AMD_FEAT_3DNOW % 32)) | \
934 /* Common bits between standard features and AMD features */ \
935 (1 << VG_X86_FEAT_FPU) | \
936 (1 << VG_X86_FEAT_VME) | \
937 (1 << VG_X86_FEAT_DE) | \
938 (1 << VG_X86_FEAT_PSE) | \
939 (1 << VG_X86_FEAT_TSC) | \
940 (0 << VG_X86_FEAT_MSR) | \
941 (1 << VG_X86_FEAT_PAE) | \
942 (1 << VG_X86_FEAT_MCE) | \
943 (1 << VG_X86_FEAT_CX8) | \
944 (1 << VG_X86_FEAT_APIC) | \
945 (1 << VG_X86_FEAT_MTRR) | \
946 (1 << VG_X86_FEAT_PGE) | \
947 (1 << VG_X86_FEAT_MCA) | \
948 (1 << VG_X86_FEAT_CMOV) | \
949 (1 << VG_X86_FEAT_PAT) | \
950 (1 << VG_X86_FEAT_PSE36) | \
951 (1 << VG_X86_FEAT_MMX) | \
952 (1 << VG_X86_FEAT_FXSR))
953
954
sewardjc9a65702004-07-07 16:32:57 +0000955//-- /*
956//-- For simulating the cpuid instruction, we will
957//-- issue a "real" cpuid instruction and then mask out
958//-- the bits of the features we do not support currently (3dnow mostly).
959//-- We also claim to not support most CPUID operations.
960//--
961//-- Dirk Mueller <mueller@kde.org>
962//--
963//-- http://www.sandpile.org/ia32/cpuid.htm
964//--
965//-- references:
966//--
967//-- pre-MMX pentium:
968//--
969//-- <werner> cpuid words (0): 0x1 0x756e6547 0x6c65746e 0x49656e69
970//-- <werner> cpuid words (1): 0x52b 0x0 0x0 0x1bf
971//--
972//-- Updated to be more extensible about future vendor extensions and
973//-- vendor-specific parts of CPUID.
974//-- */
975//-- void VG_(helperc_CPUID)(UInt op, UInt *eax_ret, UInt *ebx_ret, UInt *ecx_ret, UInt *edx_ret)
976//-- {
977//-- UInt eax, ebx, ecx, edx;
978//--
979//-- if (cpuid_level == -2)
980//-- get_cpu_features(); /* for cpu_vendor */
981//--
982//-- VG_(cpuid)(op, &eax, &ebx, &ecx, &edx);
983//--
984//-- /* Common mangling */
985//-- switch(op) {
986//-- case 1:
987//-- edx &= VG_X86_SUPPORTED_FEATURES;
988//-- break;
989//--
990//-- case 0xd8000000: {
991//-- /* Implement some private information at 0xd8000000 */
992//-- static const Char valgrind_vendor[] = "ValgrindVCPU";
993//--
994//-- eax = 0xd8000000; /* max request */
995//-- ebx = *(UInt *)&valgrind_vendor[0];
996//-- ecx = *(UInt *)&valgrind_vendor[8];
997//-- edx = *(UInt *)&valgrind_vendor[4];
998//-- }
999//-- break;
1000//-- }
1001//--
1002//-- /* Vendor-specific mangling of the results */
1003//-- switch(cpu_vendor) {
1004//-- case VG_CPU_VENDOR_INTEL:
1005//-- switch(op) {
1006//-- case 1:
1007//-- ecx = 0; /* mask out all extended features for now */
1008//-- break;
1009//--
1010//-- case 0x80000001:
1011//-- ebx = ecx = edx = 0;
1012//-- break;
1013//-- }
1014//-- break;
1015//--
1016//-- case VG_CPU_VENDOR_AMD:
1017//-- switch(op) {
1018//-- case 0x80000001:
1019//-- edx &= VG_AMD_SUPPORTED_FEATURES;
1020//-- break;
1021//-- }
1022//-- break;
1023//-- }
1024//--
1025//-- *eax_ret = eax;
1026//-- *ebx_ret = ebx;
1027//-- *ecx_ret = ecx;
1028//-- *edx_ret = edx;
1029//-- }
1030//--
1031//--
1032//-- /*------------------------------------------------------------*/
1033//-- /*--- Here so it can be inlined everywhere. ---*/
1034//-- /*------------------------------------------------------------*/
1035//--
1036//-- /* Allocate a new temp reg number. */
1037//-- __inline__ Int VG_(get_new_temp) ( UCodeBlock* cb )
1038//-- {
1039//-- Int t = cb->nextTemp;
1040//-- cb->nextTemp += 2;
1041//-- return t;
1042//-- }
1043//--
1044//-- Int VG_(get_new_shadow) ( UCodeBlock* cb )
1045//-- {
1046//-- Int t = cb->nextTemp;
1047//-- cb->nextTemp += 2;
1048//-- return SHADOW(t);
1049//-- }
1050
1051
sewardj41f43bc2004-07-08 14:23:22 +00001052
1053static Char* nameGrp1 ( Int opc_aux )
1054{
1055 static Char* grp1_names[8]
1056 = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
1057 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp1(x86)");
1058 return grp1_names[opc_aux];
1059}
1060
sewardje90ad6a2004-07-10 19:02:10 +00001061static Char* nameGrp2 ( Int opc_aux )
1062{
1063 static Char* grp2_names[8]
1064 = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
sewardjc2ac51e2004-07-12 01:03:26 +00001065 if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp2(x86)");
sewardje90ad6a2004-07-10 19:02:10 +00001066 return grp2_names[opc_aux];
1067}
1068
sewardjc2ac51e2004-07-12 01:03:26 +00001069static Char* nameGrp4 ( Int opc_aux )
1070{
1071 static Char* grp4_names[8]
1072 = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
1073 if (opc_aux < 0 || opc_aux > 1) vpanic("nameGrp4(x86)");
1074 return grp4_names[opc_aux];
1075}
sewardj0611d802004-07-11 02:37:54 +00001076
1077static Char* nameGrp5 ( Int opc_aux )
1078{
1079 static Char* grp5_names[8]
1080 = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
1081 if (opc_aux < 0 || opc_aux > 6) vpanic("nameGrp5(x86)");
1082 return grp5_names[opc_aux];
1083}
1084
sewardjc9a65702004-07-07 16:32:57 +00001085//-- static Char* nameGrp8 ( Int opc_aux )
1086//-- {
1087//-- static Char* grp8_names[8]
1088//-- = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
1089//-- if (opc_aux < 4 || opc_aux > 7) VG_(core_panic)("nameGrp8");
1090//-- return grp8_names[opc_aux];
1091//-- }
1092
sewardj1813dbe2004-07-28 17:09:04 +00001093static Char* nameIReg ( Int size, Int reg )
sewardjc9a65702004-07-07 16:32:57 +00001094{
1095 static Char* ireg32_names[8]
1096 = { "%eax", "%ecx", "%edx", "%ebx",
1097 "%esp", "%ebp", "%esi", "%edi" };
1098 static Char* ireg16_names[8]
1099 = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di" };
1100 static Char* ireg8_names[8]
1101 = { "%al", "%cl", "%dl", "%bl",
1102 "%ah{sp}", "%ch{bp}", "%dh{si}", "%bh{di}" };
1103 if (reg < 0 || reg > 7) goto bad;
1104 switch (size) {
1105 case 4: return ireg32_names[reg];
1106 case 2: return ireg16_names[reg];
1107 case 1: return ireg8_names[reg];
1108 }
1109 bad:
1110 vpanic("nameIReg(X86)");
1111 return NULL; /*notreached*/
1112}
1113
1114//-- const Char* VG_(name_of_seg_reg) ( Int sreg )
1115//-- {
1116//-- switch (sreg) {
1117//-- case R_ES: return "%es";
1118//-- case R_CS: return "%cs";
1119//-- case R_SS: return "%ss";
1120//-- case R_DS: return "%ds";
1121//-- case R_FS: return "%fs";
1122//-- case R_GS: return "%gs";
1123//-- default: VG_(core_panic)("nameOfSegReg");
1124//-- }
1125//-- }
1126//--
1127//-- const Char* VG_(name_of_mmx_reg) ( Int mmxreg )
1128//-- {
1129//-- static const Char* mmx_names[8]
1130//-- = { "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" };
1131//-- if (mmxreg < 0 || mmxreg > 7) VG_(core_panic)("name_of_mmx_reg");
1132//-- return mmx_names[mmxreg];
1133//-- }
1134//--
1135//-- const Char* VG_(name_of_xmm_reg) ( Int xmmreg )
1136//-- {
1137//-- static const Char* xmm_names[8]
1138//-- = { "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7" };
1139//-- if (xmmreg < 0 || xmmreg > 7) VG_(core_panic)("name_of_xmm_reg");
1140//-- return xmm_names[xmmreg];
1141//-- }
1142//--
1143//-- const Char* VG_(name_of_mmx_gran) ( UChar gran )
1144//-- {
1145//-- switch (gran) {
1146//-- case 0: return "b";
1147//-- case 1: return "w";
1148//-- case 2: return "d";
1149//-- case 3: return "q";
1150//-- default: VG_(core_panic)("name_of_mmx_gran");
1151//-- }
1152//-- }
1153
sewardj41f43bc2004-07-08 14:23:22 +00001154static Char nameISize ( Int size )
sewardjc9a65702004-07-07 16:32:57 +00001155{
1156 switch (size) {
1157 case 4: return 'l';
1158 case 2: return 'w';
1159 case 1: return 'b';
1160 default: vpanic("nameISize(x86)");
1161 }
1162}
1163
sewardjc9a65702004-07-07 16:32:57 +00001164//-- __inline__ static UInt LOW24 ( UInt x )
1165//-- {
1166//-- return x & 0x00FFFFFF;
1167//-- }
1168//--
1169//-- __inline__ static UInt HI8 ( UInt x )
1170//-- {
1171//-- return x >> 24;
1172//-- }
1173//--
sewardjc9a65702004-07-07 16:32:57 +00001174//-- /*------------------------------------------------------------*/
1175//-- /*--- Flag-related helpers. ---*/
1176//-- /*------------------------------------------------------------*/
1177//--
1178//-- static void setFlagsFromUOpcode ( UCodeBlock* cb, Int uopc )
1179//-- {
1180//-- switch (uopc) {
1181//-- case XOR: case OR: case AND:
1182//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZCP, FlagA); break;
1183//-- case ADC: case SBB:
1184//-- uFlagsRWU(cb, FlagC, FlagsOSZACP, FlagsEmpty); break;
1185//-- case MUL: case UMUL:
1186//-- uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP); break;
1187//-- case ADD: case SUB: case NEG:
1188//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty); break;
1189//-- case INC: case DEC:
1190//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZAP, FlagsEmpty); break;
1191//-- case SHR: case SAR: case SHL:
1192//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZCP, FlagA); break;
1193//-- case ROL: case ROR:
1194//-- uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsEmpty); break;
1195//-- case RCR: case RCL:
1196//-- uFlagsRWU(cb, FlagC, FlagsOC, FlagsEmpty); break;
1197//-- case NOT:
1198//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty); break;
1199//-- default:
1200//-- VG_(printf)("unhandled case is %s\n",
1201//-- VG_(name_UOpcode)(True, uopc));
1202//-- VG_(core_panic)("setFlagsFromUOpcode: unhandled case");
1203//-- }
1204//-- }
sewardjd1061ab2004-07-08 01:45:30 +00001205
1206/*------------------------------------------------------------*/
1207/*--- JMP helpers ---*/
1208/*------------------------------------------------------------*/
1209
sewardj78c19df2004-07-12 22:49:27 +00001210static void jmp_lit( IRJumpKind kind, Addr32 d32 )
sewardjd1061ab2004-07-08 01:45:30 +00001211{
sewardje539a402004-07-14 18:24:17 +00001212 irbb->next = mkU32(d32);
1213 irbb->jumpkind = kind;
sewardjd1061ab2004-07-08 01:45:30 +00001214}
1215
sewardj78c19df2004-07-12 22:49:27 +00001216static void jmp_treg( IRJumpKind kind, IRTemp t )
sewardje05c42c2004-07-08 20:25:10 +00001217{
sewardje539a402004-07-14 18:24:17 +00001218 irbb->next = mkexpr(t);
1219 irbb->jumpkind = kind;
sewardje05c42c2004-07-08 20:25:10 +00001220}
sewardje87b4842004-07-10 12:23:30 +00001221
sewardj9334b0f2004-07-10 22:43:54 +00001222static void jcc_01( Condcode cond, Addr32 d32_false, Addr32 d32_true )
sewardje87b4842004-07-10 12:23:30 +00001223{
1224 Bool invert;
1225 Condcode condPos;
1226 condPos = positiveIse_Condcode ( cond, &invert );
1227 if (invert) {
sewardj78c19df2004-07-12 22:49:27 +00001228 stmt( IRStmt_Exit( calculate_condition(condPos),
1229 IRConst_U32(d32_false) ) );
sewardje539a402004-07-14 18:24:17 +00001230 irbb->next = mkU32(d32_true);
1231 irbb->jumpkind = Ijk_Boring;
sewardje87b4842004-07-10 12:23:30 +00001232 } else {
sewardj78c19df2004-07-12 22:49:27 +00001233 stmt( IRStmt_Exit( calculate_condition(condPos),
1234 IRConst_U32(d32_true) ) );
sewardje539a402004-07-14 18:24:17 +00001235 irbb->next = mkU32(d32_false);
1236 irbb->jumpkind = Ijk_Boring;
sewardje87b4842004-07-10 12:23:30 +00001237 }
1238}
sewardjc9a65702004-07-07 16:32:57 +00001239
1240
sewardjd1061ab2004-07-08 01:45:30 +00001241/*------------------------------------------------------------*/
1242/*--- Disassembling addressing modes ---*/
1243/*------------------------------------------------------------*/
sewardjc9a65702004-07-07 16:32:57 +00001244
sewardjd1061ab2004-07-08 01:45:30 +00001245static
1246UChar* sorbTxt ( UChar sorb )
1247{
1248 switch (sorb) {
1249 case 0: return ""; /* no override */
1250 case 0x3E: return "%ds";
1251 case 0x26: return "%es:";
1252 case 0x64: return "%fs:";
1253 case 0x65: return "%gs:";
1254 default: vpanic("sorbTxt(x86)");
1255 }
1256}
1257
1258
1259/* Tmp is a TempReg holding a virtual address. Convert it to a linear
1260 address by adding any required segment override as indicated by
1261 sorb. */
1262static
1263IRExpr* handleSegOverride ( UChar sorb, IRExpr* virtual )
1264{
1265 //Int sreg, tsreg;
1266
1267 if (sorb == 0)
1268 /* the common case - no override */
1269 return virtual;
1270
1271 unimplemented("segment overrides in new x86->IR phase");
1272#if 0
1273 switch (sorb) {
1274 case 0x3E: sreg = R_DS; break;
1275 case 0x26: sreg = R_ES; break;
1276 case 0x64: sreg = R_FS; break;
1277 case 0x65: sreg = R_GS; break;
1278 default: VG_(core_panic)("handleSegOverride");
1279 }
1280
1281 tsreg = newTemp(cb);
1282
1283 /* sreg -> tsreg */
1284 uInstr2(cb, GETSEG, 2, ArchRegS, sreg, TempReg, tsreg );
1285
1286 /* tmp += segment_base(ldt[tsreg]); also do limit check */
1287 uInstr2(cb, USESEG, 0, TempReg, tsreg, TempReg, tmp );
1288#endif
1289}
1290
1291
1292/* Generate IR to calculate an address indicated by a ModRM and
1293 following SIB bytes. The expression, and the number of bytes in
1294 the address mode, are returned. Note that this fn should not be
1295 called if the R/M part of the address denotes a register instead of
1296 memory. If print_codegen is true, text of the addressing mode is
sewardj940e8c92004-07-11 16:53:24 +00001297 placed in buf.
1298
1299 The computed address is stored in a new tempreg, and the
1300 identity of the tempreg is returned. */
1301
1302static IRTemp disAMode_copy2tmp ( IRExpr* addr32 )
1303{
1304 IRTemp tmp = newTemp(Ity_I32);
1305 assign( tmp, addr32 );
1306 return tmp;
1307}
sewardjd1061ab2004-07-08 01:45:30 +00001308
1309static
sewardj940e8c92004-07-11 16:53:24 +00001310IRTemp disAMode ( Int* len, UChar sorb, UInt delta, UChar* buf )
sewardjd1061ab2004-07-08 01:45:30 +00001311{
1312 UChar mod_reg_rm = getIByte(delta);
1313 delta++;
1314
1315 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1316 jump table seems a bit excessive.
1317 */
1318 mod_reg_rm &= 0xC7; /* is now XX000YYY */
1319 mod_reg_rm |= (mod_reg_rm >> 3); /* is now XX0XXYYY */
1320 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
1321 switch (mod_reg_rm) {
1322
1323 /* (%eax) .. (%edi), not including (%esp) or (%ebp).
1324 --> GET %reg, t
1325 */
1326 case 0x00: case 0x01: case 0x02: case 0x03:
1327 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1328 { UChar rm = mod_reg_rm;
1329 DIS(buf, "%s(%s)", sorbTxt(sorb), nameIReg(4,rm));
1330 *len = 1;
sewardj940e8c92004-07-11 16:53:24 +00001331 return disAMode_copy2tmp(
1332 handleSegOverride(sorb, getIReg(4,rm)));
sewardjd1061ab2004-07-08 01:45:30 +00001333 }
1334
1335 /* d8(%eax) ... d8(%edi), not including d8(%esp)
1336 --> GET %reg, t ; ADDL d8, t
1337 */
1338 case 0x08: case 0x09: case 0x0A: case 0x0B:
1339 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1340 { UChar rm = mod_reg_rm & 7;
1341 UInt d = getSDisp8(delta);
1342 DIS(buf, "%s%d(%s)", sorbTxt(sorb), d, nameIReg(4,rm));
1343 *len = 2;
sewardj940e8c92004-07-11 16:53:24 +00001344 return disAMode_copy2tmp(
1345 handleSegOverride(sorb,
1346 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001347 }
1348
1349 /* d32(%eax) ... d32(%edi), not including d32(%esp)
1350 --> GET %reg, t ; ADDL d8, t
1351 */
1352 case 0x10: case 0x11: case 0x12: case 0x13:
1353 /* ! 14 */ case 0x15: case 0x16: case 0x17:
1354 { UChar rm = mod_reg_rm & 7;
1355 UInt d = getUDisp32(delta);
1356 DIS(buf, "%s0x%x(%s)", sorbTxt(sorb), d, nameIReg(4,rm));
1357 *len = 5;
sewardj940e8c92004-07-11 16:53:24 +00001358 return disAMode_copy2tmp(
1359 handleSegOverride(sorb,
1360 binop(Iop_Add32,getIReg(4,rm),mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001361 }
1362
1363 /* a register, %eax .. %edi. This shouldn't happen. */
1364 case 0x18: case 0x19: case 0x1A: case 0x1B:
1365 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1366 vpanic("disAMode(x86): not an addr!");
1367
1368 /* a 32-bit literal address
1369 --> MOV d32, tmp
1370 */
1371 case 0x05:
1372 { UInt d = getUDisp32(delta);
1373 *len = 5;
1374 DIS(buf, "%s(0x%x)", sorbTxt(sorb), d);
sewardj940e8c92004-07-11 16:53:24 +00001375 return disAMode_copy2tmp(
1376 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001377 }
1378
1379 case 0x04: {
1380 /* SIB, with no displacement. Special cases:
1381 -- %esp cannot act as an index value.
1382 If index_r indicates %esp, zero is used for the index.
1383 -- when mod is zero and base indicates EBP, base is instead
1384 a 32-bit literal.
1385 It's all madness, I tell you. Extract %index, %base and
1386 scale from the SIB byte. The value denoted is then:
1387 | %index == %ESP && %base == %EBP
1388 = d32 following SIB byte
1389 | %index == %ESP && %base != %EBP
1390 = %base
1391 | %index != %ESP && %base == %EBP
1392 = d32 following SIB byte + (%index << scale)
1393 | %index != %ESP && %base != %ESP
1394 = %base + (%index << scale)
1395
1396 What happens to the souls of CPU architects who dream up such
1397 horrendous schemes, do you suppose?
1398 */
1399 UChar sib = getIByte(delta);
1400 UChar scale = (sib >> 6) & 3;
1401 UChar index_r = (sib >> 3) & 7;
1402 UChar base_r = sib & 7;
1403 delta++;
1404
1405 if (index_r != R_ESP && base_r != R_EBP) {
1406 DIS(buf, "%s(%s,%s,%d)", sorbTxt(sorb),
1407 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
1408 *len = 2;
sewardj940e8c92004-07-11 16:53:24 +00001409 return
1410 disAMode_copy2tmp(
sewardjd1061ab2004-07-08 01:45:30 +00001411 handleSegOverride(sorb,
1412 binop(Iop_Add32,
1413 getIReg(4,base_r),
1414 binop(Iop_Shl32, getIReg(4,index_r),
sewardj6d2638e2004-07-15 09:38:27 +00001415 mkU8(scale)))));
sewardjd1061ab2004-07-08 01:45:30 +00001416 }
1417
1418 if (index_r != R_ESP && base_r == R_EBP) {
1419 UInt d = getUDisp32(delta);
1420 DIS(buf, "%s0x%x(,%s,%d)", sorbTxt(sorb), d,
1421 nameIReg(4,index_r), 1<<scale);
1422 *len = 6;
1423 return
sewardj940e8c92004-07-11 16:53:24 +00001424 disAMode_copy2tmp(
sewardjd1061ab2004-07-08 01:45:30 +00001425 handleSegOverride(sorb,
1426 binop(Iop_Add32,
sewardj6d2638e2004-07-15 09:38:27 +00001427 binop(Iop_Shl32, getIReg(4,index_r), mkU8(scale)),
sewardj940e8c92004-07-11 16:53:24 +00001428 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001429 }
1430
1431 if (index_r == R_ESP && base_r != R_EBP) {
1432 DIS(buf, "%s(%s,,)", sorbTxt(sorb), nameIReg(4,base_r));
1433 *len = 2;
sewardj940e8c92004-07-11 16:53:24 +00001434 return disAMode_copy2tmp(
1435 handleSegOverride(sorb, getIReg(4,base_r)));
sewardjd1061ab2004-07-08 01:45:30 +00001436 }
1437
1438 if (index_r == R_ESP && base_r == R_EBP) {
1439 UInt d = getUDisp32(delta);
1440 DIS(buf, "%s0x%x()", sorbTxt(sorb), d);
1441 *len = 6;
sewardj41f43bc2004-07-08 14:23:22 +00001442 vpanic("amode 8");
sewardj940e8c92004-07-11 16:53:24 +00001443 return disAMode_copy2tmp(
1444 handleSegOverride(sorb, mkU32(d)));
sewardjd1061ab2004-07-08 01:45:30 +00001445 }
1446
1447 vassert(0);
1448 }
1449
1450 /* SIB, with 8-bit displacement. Special cases:
1451 -- %esp cannot act as an index value.
1452 If index_r indicates %esp, zero is used for the index.
1453 Denoted value is:
1454 | %index == %ESP
1455 = d8 + %base
1456 | %index != %ESP
1457 = d8 + %base + (%index << scale)
1458 */
1459 case 0x0C: {
1460 UChar sib = getIByte(delta);
1461 UChar scale = (sib >> 6) & 3;
1462 UChar index_r = (sib >> 3) & 7;
1463 UChar base_r = sib & 7;
1464 UInt d = getSDisp8(delta+1);
1465
1466 if (index_r == R_ESP) {
1467 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb), d, nameIReg(4,base_r));
1468 *len = 3;
sewardj940e8c92004-07-11 16:53:24 +00001469 return disAMode_copy2tmp(
1470 handleSegOverride(sorb,
1471 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001472 } else {
1473 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), d,
1474 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
1475 *len = 3;
sewardj77b86be2004-07-11 13:28:24 +00001476 return
sewardj940e8c92004-07-11 16:53:24 +00001477 disAMode_copy2tmp(
1478 handleSegOverride(sorb,
sewardj77b86be2004-07-11 13:28:24 +00001479 binop(Iop_Add32,
1480 binop(Iop_Add32,
1481 getIReg(4,base_r),
1482 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001483 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001484 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001485 }
1486 vassert(0);
1487 }
1488
1489 /* SIB, with 32-bit displacement. Special cases:
1490 -- %esp cannot act as an index value.
1491 If index_r indicates %esp, zero is used for the index.
1492 Denoted value is:
1493 | %index == %ESP
1494 = d32 + %base
1495 | %index != %ESP
1496 = d32 + %base + (%index << scale)
1497 */
1498 case 0x14: {
1499 UChar sib = getIByte(delta);
1500 UChar scale = (sib >> 6) & 3;
1501 UChar index_r = (sib >> 3) & 7;
1502 UChar base_r = sib & 7;
1503 UInt d = getUDisp32(delta+1);
1504
1505 if (index_r == R_ESP) {
1506 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb), d, nameIReg(4,base_r));
1507 *len = 6;
sewardj940e8c92004-07-11 16:53:24 +00001508 return disAMode_copy2tmp(
1509 handleSegOverride(sorb,
1510 binop(Iop_Add32, getIReg(4,base_r), mkU32(d)) ));
sewardjd1061ab2004-07-08 01:45:30 +00001511 } else {
1512 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), d,
1513 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
1514 *len = 6;
sewardj9334b0f2004-07-10 22:43:54 +00001515 return
sewardj940e8c92004-07-11 16:53:24 +00001516 disAMode_copy2tmp(
1517 handleSegOverride(sorb,
sewardj9334b0f2004-07-10 22:43:54 +00001518 binop(Iop_Add32,
1519 binop(Iop_Add32,
1520 getIReg(4,base_r),
1521 binop(Iop_Shl32,
sewardj6d2638e2004-07-15 09:38:27 +00001522 getIReg(4,index_r), mkU8(scale))),
sewardj940e8c92004-07-11 16:53:24 +00001523 mkU32(d))));
sewardjd1061ab2004-07-08 01:45:30 +00001524 }
1525 vassert(0);
1526 }
1527
1528 default:
1529 vpanic("disAMode(x86)");
1530 return 0; /*notreached*/
1531 }
1532}
1533
1534
1535/* Figure out the number of (insn-stream) bytes constituting the amode
1536 beginning at delta. Is useful for getting hold of literals beyond
1537 the end of the amode before it has been disassembled. */
1538
1539static UInt lengthAMode ( UInt delta )
1540{
1541 UChar mod_reg_rm = getIByte(delta); delta++;
1542
1543 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
1544 jump table seems a bit excessive.
1545 */
1546 mod_reg_rm &= 0xC7; /* is now XX000YYY */
1547 mod_reg_rm |= (mod_reg_rm >> 3); /* is now XX0XXYYY */
1548 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
1549 switch (mod_reg_rm) {
1550
1551 /* (%eax) .. (%edi), not including (%esp) or (%ebp). */
1552 case 0x00: case 0x01: case 0x02: case 0x03:
1553 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
1554 return 1;
1555
1556 /* d8(%eax) ... d8(%edi), not including d8(%esp). */
1557 case 0x08: case 0x09: case 0x0A: case 0x0B:
1558 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
1559 return 2;
1560
1561 /* d32(%eax) ... d32(%edi), not including d32(%esp). */
1562 case 0x10: case 0x11: case 0x12: case 0x13:
1563 /* ! 14 */ case 0x15: case 0x16: case 0x17:
1564 return 5;
1565
1566 /* a register, %eax .. %edi. (Not an addr, but still handled.) */
1567 case 0x18: case 0x19: case 0x1A: case 0x1B:
1568 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1569 return 1;
1570
1571 /* a 32-bit literal address. */
1572 case 0x05: return 5;
1573
1574 /* SIB, no displacement. */
1575 case 0x04: {
1576 UChar sib = getIByte(delta);
1577 UChar base_r = sib & 7;
1578 if (base_r == R_EBP) return 6; else return 2;
1579 }
1580 /* SIB, with 8-bit displacement. */
1581 case 0x0C: return 3;
1582
1583 /* SIB, with 32-bit displacement. */
1584 case 0x14: return 6;
1585
1586 default:
1587 vpanic("lengthAMode");
1588 return 0; /*notreached*/
1589 }
1590}
1591
1592/*------------------------------------------------------------*/
1593/*--- Disassembling common idioms ---*/
1594/*------------------------------------------------------------*/
1595
sewardj5df3bfe2004-07-27 09:30:31 +00001596static
1597void codegen_XOR_reg_with_itself ( Int size, Int ge_reg )
1598{
1599 IRType ty = szToITy(size);
1600 /* reg := 0 */
1601 putIReg(size, ge_reg, mkU(ty,0));
1602 /* Flags: C,A,O=0, Z=1, S=0, P=1 */
1603 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
1604 stmt( IRStmt_Put( OFFB_CC_SRC, mkU32(CC_MASK_Z|CC_MASK_P) ));
1605 stmt( IRStmt_Put( OFFB_CC_DST, mkU32(0) ));
1606 DIP("xor%c %s, %s\n", nameISize(size),
1607 nameIReg(size,ge_reg), nameIReg(size,ge_reg) );
1608}
1609
1610
sewardje87b4842004-07-10 12:23:30 +00001611/* Handle binary integer instructions of the form
1612 op E, G meaning
1613 op reg-or-mem, reg
1614 Is passed the a ptr to the modRM byte, the actual operation, and the
1615 data size. Returns the address advanced completely over this
1616 instruction.
1617
1618 E(src) is reg-or-mem
1619 G(dst) is reg.
1620
1621 If E is reg, --> GET %G, tmp
1622 OP %E, tmp
1623 PUT tmp, %G
1624
1625 If E is mem and OP is not reversible,
1626 --> (getAddr E) -> tmpa
1627 LD (tmpa), tmpa
1628 GET %G, tmp2
1629 OP tmpa, tmp2
1630 PUT tmp2, %G
1631
1632 If E is mem and OP is reversible
1633 --> (getAddr E) -> tmpa
1634 LD (tmpa), tmpa
1635 OP %G, tmpa
1636 PUT tmpa, %G
1637*/
1638static
1639UInt dis_op2_E_G ( UChar sorb,
sewardj180e8b32004-07-29 01:40:11 +00001640 Bool addSubCarry,
sewardje87b4842004-07-10 12:23:30 +00001641 IROp op8,
1642 Bool keep,
1643 Int size,
1644 UInt delta0,
1645 Char* t_x86opc )
1646{
sewardj9334b0f2004-07-10 22:43:54 +00001647 UChar dis_buf[50];
1648 Int len;
sewardje87b4842004-07-10 12:23:30 +00001649 IRType ty = szToITy(size);
1650 IRTemp dst1 = newTemp(ty);
1651 IRTemp src = newTemp(ty);
1652 IRTemp dst0 = newTemp(ty);
1653 UChar rm = getUChar(delta0);
sewardj940e8c92004-07-11 16:53:24 +00001654 IRTemp addr = INVALID_IRTEMP;
sewardje87b4842004-07-10 12:23:30 +00001655
sewardj180e8b32004-07-29 01:40:11 +00001656 /* addSubCarry == True indicates the intended operation is
1657 add-with-carry or subtract-with-borrow. */
1658 if (addSubCarry) {
1659 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1660 vassert(keep);
1661 }
1662
sewardje87b4842004-07-10 12:23:30 +00001663 if (epartIsReg(rm)) {
sewardje87b4842004-07-10 12:23:30 +00001664 /* Specially handle XOR reg,reg, because that doesn't really
1665 depend on reg, and doing the obvious thing potentially
1666 generates a spurious value check failure due to the bogus
1667 dependency. */
sewardj5df3bfe2004-07-27 09:30:31 +00001668 if (op8 == Iop_Xor8 && gregOfRM(rm) == eregOfRM(rm)) {
1669 codegen_XOR_reg_with_itself ( size, gregOfRM(rm) );
1670 return 1+delta0;
sewardje87b4842004-07-10 12:23:30 +00001671 }
sewardje87b4842004-07-10 12:23:30 +00001672 assign( dst0, getIReg(size,gregOfRM(rm)) );
1673 assign( src, getIReg(size,eregOfRM(rm)) );
sewardje87b4842004-07-10 12:23:30 +00001674
sewardj180e8b32004-07-29 01:40:11 +00001675 if (addSubCarry && op8 == Iop_Add8) {
1676 vassert(0);
1677 helper_ADC( size, dst1, dst0, src );
sewardje87b4842004-07-10 12:23:30 +00001678 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00001679 } else
1680 if (addSubCarry && op8 == Iop_Sub8) {
1681 vassert(0);
1682 helper_SBB( size, dst1, dst0, src );
1683 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1684 } else {
1685 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardjb9c5cf62004-08-24 15:10:38 +00001686 if (isAddSub(op8))
1687 setFlags_ADD_SUB(op8, src, dst0, ty);
1688 else
1689 setFlags_LOGIC(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00001690 if (keep)
1691 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1692 }
sewardje87b4842004-07-10 12:23:30 +00001693
1694 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1695 nameIReg(size,eregOfRM(rm)),
1696 nameIReg(size,gregOfRM(rm)));
1697 return 1+delta0;
sewardje87b4842004-07-10 12:23:30 +00001698 } else {
sewardj9334b0f2004-07-10 22:43:54 +00001699 /* E refers to memory */
1700 addr = disAMode ( &len, sorb, delta0, dis_buf);
1701 assign( dst0, getIReg(size,gregOfRM(rm)) );
sewardj940e8c92004-07-11 16:53:24 +00001702 assign( src, loadLE(szToITy(size), mkexpr(addr)) );
sewardj9334b0f2004-07-10 22:43:54 +00001703
sewardj180e8b32004-07-29 01:40:11 +00001704 if (addSubCarry && op8 == Iop_Add8) {
1705 vassert(0);
1706 helper_ADC( size, dst1, dst0, src );
sewardj9334b0f2004-07-10 22:43:54 +00001707 putIReg(size, gregOfRM(rm), mkexpr(dst1));
sewardj180e8b32004-07-29 01:40:11 +00001708 } else
1709 if (addSubCarry && op8 == Iop_Sub8) {
1710 helper_SBB( size, dst1, dst0, src );
1711 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1712 } else {
1713 assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardjb9c5cf62004-08-24 15:10:38 +00001714 if (isAddSub(op8))
1715 setFlags_ADD_SUB(op8, src, dst0, ty);
1716 else
1717 setFlags_LOGIC(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00001718 if (keep)
1719 putIReg(size, gregOfRM(rm), mkexpr(dst1));
1720 }
sewardj9334b0f2004-07-10 22:43:54 +00001721
sewardje87b4842004-07-10 12:23:30 +00001722 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1723 dis_buf,nameIReg(size,gregOfRM(rm)));
sewardj9334b0f2004-07-10 22:43:54 +00001724 return len+delta0;
sewardje87b4842004-07-10 12:23:30 +00001725 }
sewardje87b4842004-07-10 12:23:30 +00001726}
sewardje05c42c2004-07-08 20:25:10 +00001727
1728
1729
1730/* Handle binary integer instructions of the form
1731 op G, E meaning
1732 op reg, reg-or-mem
1733 Is passed the a ptr to the modRM byte, the actual operation, and the
1734 data size. Returns the address advanced completely over this
1735 instruction.
1736
1737 G(src) is reg.
1738 E(dst) is reg-or-mem
1739
1740 If E is reg, --> GET %E, tmp
1741 OP %G, tmp
1742 PUT tmp, %E
1743
1744 If E is mem, --> (getAddr E) -> tmpa
1745 LD (tmpa), tmpv
1746 OP %G, tmpv
1747 ST tmpv, (tmpa)
1748*/
1749static
1750UInt dis_op2_G_E ( UChar sorb,
sewardjcaca9d02004-07-28 07:11:32 +00001751 Bool addSubCarry,
sewardje05c42c2004-07-08 20:25:10 +00001752 IROp op8,
1753 Bool keep,
1754 Int size,
1755 UInt delta0,
1756 Char* t_x86opc )
1757{
sewardje87b4842004-07-10 12:23:30 +00001758 UChar dis_buf[50];
1759 Int len;
sewardje05c42c2004-07-08 20:25:10 +00001760 IRType ty = szToITy(size);
1761 IRTemp dst1 = newTemp(ty);
1762 IRTemp src = newTemp(ty);
1763 IRTemp dst0 = newTemp(ty);
1764 UChar rm = getIByte(delta0);
sewardj940e8c92004-07-11 16:53:24 +00001765 IRTemp addr = INVALID_IRTEMP;
sewardje05c42c2004-07-08 20:25:10 +00001766
sewardjcaca9d02004-07-28 07:11:32 +00001767 /* addSubCarry == True indicates the intended operation is
1768 add-with-carry or subtract-with-borrow. */
1769 if (addSubCarry) {
1770 vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
1771 vassert(keep);
1772 }
1773
sewardje05c42c2004-07-08 20:25:10 +00001774 if (epartIsReg(rm)) {
sewardje05c42c2004-07-08 20:25:10 +00001775 /* Specially handle XOR reg,reg, because that doesn't really
1776 depend on reg, and doing the obvious thing potentially
1777 generates a spurious value check failure due to the bogus
1778 dependency. */
sewardj5df3bfe2004-07-27 09:30:31 +00001779 if (op8 == Iop_Xor8 && gregOfRM(rm) == eregOfRM(rm)) {
1780 codegen_XOR_reg_with_itself ( size, gregOfRM(rm) );
1781 return 1+delta0;
sewardje05c42c2004-07-08 20:25:10 +00001782 }
sewardje05c42c2004-07-08 20:25:10 +00001783 assign(dst0, getIReg(size,eregOfRM(rm)));
1784 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00001785
sewardjcaca9d02004-07-28 07:11:32 +00001786 if (addSubCarry && op8 == Iop_Add8) {
sewardj1813dbe2004-07-28 17:09:04 +00001787 helper_ADC( size, dst1, dst0, src );
1788 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00001789 } else
1790 if (addSubCarry && op8 == Iop_Sub8) {
1791 helper_SBB( size, dst1, dst0, src );
sewardje05c42c2004-07-08 20:25:10 +00001792 putIReg(size, eregOfRM(rm), mkexpr(dst1));
sewardjcaca9d02004-07-28 07:11:32 +00001793 } else {
1794 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardjb9c5cf62004-08-24 15:10:38 +00001795 if (isAddSub(op8))
1796 setFlags_ADD_SUB(op8, src, dst0, ty);
1797 else
1798 setFlags_LOGIC(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00001799 if (keep)
1800 putIReg(size, eregOfRM(rm), mkexpr(dst1));
1801 }
sewardje05c42c2004-07-08 20:25:10 +00001802
1803 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1804 nameIReg(size,gregOfRM(rm)),
1805 nameIReg(size,eregOfRM(rm)));
1806 return 1+delta0;
1807 }
1808
1809 /* E refers to memory */
1810 {
sewardje87b4842004-07-10 12:23:30 +00001811 addr = disAMode ( &len, sorb, delta0, dis_buf);
sewardj940e8c92004-07-11 16:53:24 +00001812 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardje87b4842004-07-10 12:23:30 +00001813 assign(src, getIReg(size,gregOfRM(rm)));
sewardje05c42c2004-07-08 20:25:10 +00001814
sewardjcaca9d02004-07-28 07:11:32 +00001815 if (addSubCarry && op8 == Iop_Add8) {
1816 helper_ADC( size, dst1, dst0, src );
1817 storeLE(mkexpr(addr), mkexpr(dst1));
1818 } else
1819 if (addSubCarry && op8 == Iop_Sub8) {
1820 helper_SBB( size, dst1, dst0, src );
1821 storeLE(mkexpr(addr), mkexpr(dst1));
1822 } else {
1823 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardjb9c5cf62004-08-24 15:10:38 +00001824 if (isAddSub(op8))
1825 setFlags_ADD_SUB(op8, src, dst0, ty);
1826 else
1827 setFlags_LOGIC(op8, dst1, ty);
sewardjcaca9d02004-07-28 07:11:32 +00001828 if (keep)
1829 storeLE(mkexpr(addr), mkexpr(dst1));
1830 }
sewardje87b4842004-07-10 12:23:30 +00001831
sewardje05c42c2004-07-08 20:25:10 +00001832 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1833 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje87b4842004-07-10 12:23:30 +00001834 return len+delta0;
sewardje05c42c2004-07-08 20:25:10 +00001835 }
1836}
1837
1838
1839/* Handle move instructions of the form
1840 mov E, G meaning
1841 mov reg-or-mem, reg
1842 Is passed the a ptr to the modRM byte, and the data size. Returns
1843 the address advanced completely over this instruction.
1844
1845 E(src) is reg-or-mem
1846 G(dst) is reg.
1847
1848 If E is reg, --> GET %E, tmpv
1849 PUT tmpv, %G
1850
1851 If E is mem --> (getAddr E) -> tmpa
1852 LD (tmpa), tmpb
1853 PUT tmpb, %G
1854*/
1855static
1856UInt dis_mov_E_G ( UChar sorb,
1857 Int size,
1858 UInt delta0 )
1859{
1860 Int len;
1861 UChar rm = getIByte(delta0);
1862 UChar dis_buf[50];
1863
1864 if (epartIsReg(rm)) {
1865#if 0
1866 Int tmpv = newTemp(cb);
1867 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, tmpv);
1868 uInstr2(cb, PUT, size, TempReg, tmpv, ArchReg, gregOfRM(rm));
1869 DIP("mov%c %s,%s\n", nameISize(size),
1870 nameIReg(size,eregOfRM(rm)),
1871 nameIReg(size,gregOfRM(rm)));
1872 return 1+eip0;
1873#endif
1874 vassert(121221==0);
1875 }
1876
1877 /* E refers to memory */
1878 {
sewardj940e8c92004-07-11 16:53:24 +00001879 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf );
1880 putIReg(size, gregOfRM(rm), loadLE(szToITy(size), mkexpr(addr)));
sewardje05c42c2004-07-08 20:25:10 +00001881 DIP("mov%c %s,%s\n", nameISize(size),
1882 dis_buf,nameIReg(size,gregOfRM(rm)));
1883 return delta0+len;
1884 }
1885}
1886
1887
1888/* Handle move instructions of the form
1889 mov G, E meaning
1890 mov reg, reg-or-mem
1891 Is passed the a ptr to the modRM byte, and the data size. Returns
1892 the address advanced completely over this instruction.
1893
1894 G(src) is reg.
1895 E(dst) is reg-or-mem
1896
1897 If E is reg, --> GET %G, tmp
1898 PUT tmp, %E
1899
1900 If E is mem, --> (getAddr E) -> tmpa
1901 GET %G, tmpv
1902 ST tmpv, (tmpa)
1903*/
sewardjc9a65702004-07-07 16:32:57 +00001904static
1905UInt dis_mov_G_E ( UChar sorb,
1906 Int size,
1907 UInt delta0 )
1908{
sewardje05c42c2004-07-08 20:25:10 +00001909 Int len;
sewardjc9a65702004-07-07 16:32:57 +00001910 UChar rm = getIByte(delta0);
sewardje05c42c2004-07-08 20:25:10 +00001911 UChar dis_buf[50];
sewardjc9a65702004-07-07 16:32:57 +00001912
1913 if (epartIsReg(rm)) {
sewardj41f43bc2004-07-08 14:23:22 +00001914 putIReg(size, eregOfRM(rm), getIReg(size, gregOfRM(rm)));
sewardjc9a65702004-07-07 16:32:57 +00001915 DIP("mov%c %s,%s\n", nameISize(size),
1916 nameIReg(size,gregOfRM(rm)),
1917 nameIReg(size,eregOfRM(rm)));
1918 return 1+delta0;
1919 }
1920
sewardjc9a65702004-07-07 16:32:57 +00001921 /* E refers to memory */
1922 {
sewardj940e8c92004-07-11 16:53:24 +00001923 IRTemp addr = disAMode ( &len, sorb, delta0, dis_buf);
1924 storeLE( mkexpr(addr), getIReg(size, gregOfRM(rm)) );
sewardjc9a65702004-07-07 16:32:57 +00001925 DIP("mov%c %s,%s\n", nameISize(size),
1926 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardje05c42c2004-07-08 20:25:10 +00001927 return len+delta0;
sewardjc9a65702004-07-07 16:32:57 +00001928 }
sewardjc9a65702004-07-07 16:32:57 +00001929}
1930
1931
sewardj0611d802004-07-11 02:37:54 +00001932/* op $immediate, AL/AX/EAX. */
1933static
1934UInt dis_op_imm_A ( Int size,
1935 IROp op8,
1936 Bool keep,
1937 UInt delta,
1938 Char* t_x86opc )
1939{
1940 IRType ty = szToITy(size);
1941 IRTemp dst0 = newTemp(ty);
1942 IRTemp src = newTemp(ty);
1943 IRTemp dst1 = newTemp(ty);
1944 UInt lit = getUDisp(size,delta);
1945 assign(dst0, getIReg(size,R_EAX));
1946 assign(src, mkU(ty,lit));
1947 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
sewardjb9c5cf62004-08-24 15:10:38 +00001948 if (isAddSub(op8))
1949 setFlags_ADD_SUB(op8, src, dst0, ty);
1950 else
1951 setFlags_LOGIC(op8, dst1, ty);
sewardj0611d802004-07-11 02:37:54 +00001952
1953 if (keep)
1954 putIReg(size, R_EAX, mkexpr(dst1));
1955
1956 DIP("%s%c $0x%x, %s\n", t_x86opc, nameISize(size),
1957 lit, nameIReg(size,R_EAX));
1958 return delta+size;
1959}
sewardj9334b0f2004-07-10 22:43:54 +00001960
1961
1962/* Sign- and Zero-extending moves. */
1963static
1964UInt dis_movx_E_G ( UChar sorb,
1965 UInt delta, Int szs, Int szd, Bool sign_extend )
1966{
sewardj9334b0f2004-07-10 22:43:54 +00001967 UChar rm = getIByte(delta);
1968 if (epartIsReg(rm)) {
1969 putIReg(szd, gregOfRM(rm),
1970 unop(mkWidenOp(szs,szd,False),
1971 getIReg(szs,eregOfRM(rm))));
1972 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
1973 nameISize(szs), nameISize(szd),
1974 nameIReg(szs,eregOfRM(rm)),
1975 nameIReg(szd,gregOfRM(rm)));
1976 return 1+delta;
1977 }
1978
1979 /* E refers to memory */
1980 {
sewardj940e8c92004-07-11 16:53:24 +00001981 Int len;
1982 UChar dis_buf[50];
1983 IRTemp addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj0611d802004-07-11 02:37:54 +00001984
1985 putIReg(szd, gregOfRM(rm),
1986 unop(mkWidenOp(szs,szd,False),
sewardj940e8c92004-07-11 16:53:24 +00001987 loadLE(szToITy(szs),mkexpr(addr))));
sewardj9334b0f2004-07-10 22:43:54 +00001988 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
1989 nameISize(szs), nameISize(szd),
1990 dis_buf, nameIReg(szd,gregOfRM(rm)));
sewardj0611d802004-07-11 02:37:54 +00001991 return len+delta;
sewardj9334b0f2004-07-10 22:43:54 +00001992 }
1993}
1994
sewardj9690d922004-07-14 01:39:17 +00001995
1996/* Generate code to divide ArchRegs EDX:EAX / DX:AX / AX by the 32 /
1997 16 / 8 bit quantity in the given IRTemp. */
1998static
1999void codegen_div ( Int sz, IRTemp t, Bool signed_divide )
2000{
2001 switch (sz) {
2002 case 4: {
2003 IROp op = signed_divide ? Iop_DivModS64to32 : Iop_DivModU64to32;
2004 IRTemp src64 = newTemp(Ity_I64);
2005 IRTemp dst64 = newTemp(Ity_I64);
2006 assign( src64, binop(Iop_32HLto64,
2007 getIReg(4,R_EDX), getIReg(4,R_EAX)) );
2008 assign( dst64, binop(op, mkexpr(src64), mkexpr(t)) );
sewardj8c7f1ab2004-07-29 20:31:09 +00002009 putIReg( 4, R_EAX, unop(Iop_64to32,mkexpr(dst64)) );
sewardj9690d922004-07-14 01:39:17 +00002010 putIReg( 4, R_EDX, unop(Iop_64HIto32,mkexpr(dst64)) );
2011 break;
2012 }
2013 default: vpanic("codegen_div(x86)");
2014 }
2015}
sewardjc9a65702004-07-07 16:32:57 +00002016//-- Int helper;
2017//-- Int ta = newTemp(cb);
2018//-- Int td = newTemp(cb);
2019//--
2020//-- switch (sz) {
2021//-- case 4: helper = (signed_divide ? VGOFF_(helper_idiv_64_32)
2022//-- : VGOFF_(helper_div_64_32));
2023//-- break;
2024//-- case 2: helper = (signed_divide ? VGOFF_(helper_idiv_32_16)
2025//-- : VGOFF_(helper_div_32_16));
2026//-- break;
2027//-- case 1: helper = (signed_divide ? VGOFF_(helper_idiv_16_8)
2028//-- : VGOFF_(helper_div_16_8));
2029//-- break;
2030//-- default: VG_(core_panic)("codegen_div");
2031//-- }
2032//-- uInstr0(cb, CALLM_S, 0);
2033//-- if (sz == 4 || sz == 2) {
2034//-- uInstr1(cb, PUSH, sz, TempReg, t);
2035//-- uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
2036//-- uInstr1(cb, PUSH, sz, TempReg, ta);
2037//-- uInstr2(cb, GET, sz, ArchReg, R_EDX, TempReg, td);
2038//-- uInstr1(cb, PUSH, sz, TempReg, td);
2039//-- uInstr1(cb, CALLM, 0, Lit16, helper);
2040//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsOSZACP);
2041//-- uInstr1(cb, POP, sz, TempReg, t);
2042//-- uInstr2(cb, PUT, sz, TempReg, t, ArchReg, R_EDX);
2043//-- uInstr1(cb, POP, sz, TempReg, t);
2044//-- uInstr2(cb, PUT, sz, TempReg, t, ArchReg, R_EAX);
2045//-- uInstr1(cb, CLEAR, 0, Lit16, 4);
2046//-- } else {
2047//-- uInstr1(cb, PUSH, 1, TempReg, t);
2048//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, ta);
2049//-- uInstr1(cb, PUSH, 2, TempReg, ta);
2050//-- uInstr2(cb, MOV, 1, Literal, 0, TempReg, td);
2051//-- uLiteral(cb, 0);
2052//-- uInstr1(cb, PUSH, 1, TempReg, td);
2053//-- uInstr1(cb, CALLM, 0, Lit16, helper);
2054//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsOSZACP);
2055//-- uInstr1(cb, POP, 1, TempReg, t);
2056//-- uInstr2(cb, PUT, 1, TempReg, t, ArchReg, R_AL);
2057//-- uInstr1(cb, POP, 1, TempReg, t);
2058//-- uInstr2(cb, PUT, 1, TempReg, t, ArchReg, R_AH);
2059//-- uInstr1(cb, CLEAR, 0, Lit16, 4);
2060//-- }
2061//-- uInstr0(cb, CALLM_E, 0);
2062//-- }
sewardj41f43bc2004-07-08 14:23:22 +00002063
2064
2065static
sewardje90ad6a2004-07-10 19:02:10 +00002066UInt dis_Grp1 ( UChar sorb,
sewardj41f43bc2004-07-08 14:23:22 +00002067 UInt delta, UChar modrm,
2068 Int am_sz, Int d_sz, Int sz, UInt d32 )
2069{
sewardj41f43bc2004-07-08 14:23:22 +00002070 Int len;
2071 UChar dis_buf[50];
sewardje05c42c2004-07-08 20:25:10 +00002072 IRType ty = szToITy(sz);
2073 IRTemp dst1 = newTemp(ty);
2074 IRTemp src = newTemp(ty);
2075 IRTemp dst0 = newTemp(ty);
sewardj940e8c92004-07-11 16:53:24 +00002076 IRTemp addr = INVALID_IRTEMP;
sewardj66de2272004-07-16 21:19:05 +00002077 IROp op8 = Iop_INVALID;
sewardj180e8b32004-07-29 01:40:11 +00002078 UInt mask = sz==1 ? 0xFF : (sz==2 ? 0xFFFF : 0xFFFFFFFF);
sewardj41f43bc2004-07-08 14:23:22 +00002079
2080 switch (gregOfRM(modrm)) {
sewardje05c42c2004-07-08 20:25:10 +00002081 case 0: op8 = Iop_Add8; break; case 1: op8 = Iop_Or8; break;
sewardj66de2272004-07-16 21:19:05 +00002082 case 2: break; // ADC
2083 case 3: break; // SBB
sewardje05c42c2004-07-08 20:25:10 +00002084 case 4: op8 = Iop_And8; break; case 5: op8 = Iop_Sub8; break;
2085 case 6: op8 = Iop_Xor8; break; case 7: op8 = Iop_Sub8; break;
sewardj41f43bc2004-07-08 14:23:22 +00002086 default: vpanic("dis_Grp1: unhandled case");
2087 }
sewardj41f43bc2004-07-08 14:23:22 +00002088
2089 if (epartIsReg(modrm)) {
2090 vassert(am_sz == 1);
2091
2092 assign(dst0, getIReg(sz,eregOfRM(modrm)));
sewardj180e8b32004-07-29 01:40:11 +00002093 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002094
sewardj180e8b32004-07-29 01:40:11 +00002095 if (gregOfRM(modrm) == 2 /* ADC */) {
2096 helper_ADC( sz, dst1, dst0, src );
2097 } else
2098 if (gregOfRM(modrm) == 3 /* SBB */) {
2099 helper_SBB( sz, dst1, dst0, src );
2100 } else {
2101 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardjb9c5cf62004-08-24 15:10:38 +00002102 if (isAddSub(op8))
2103 setFlags_ADD_SUB(op8, src, dst0, ty);
2104 else
2105 setFlags_LOGIC(op8, dst1, ty);
sewardj180e8b32004-07-29 01:40:11 +00002106 }
sewardj41f43bc2004-07-08 14:23:22 +00002107
2108 if (gregOfRM(modrm) < 7)
sewardje05c42c2004-07-08 20:25:10 +00002109 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
sewardj41f43bc2004-07-08 14:23:22 +00002110
2111 delta += (am_sz + d_sz);
2112 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz), d32,
2113 nameIReg(sz,eregOfRM(modrm)));
2114 } else {
sewardje87b4842004-07-10 12:23:30 +00002115 addr = disAMode ( &len, sorb, delta, dis_buf);
sewardj41f43bc2004-07-08 14:23:22 +00002116
sewardj940e8c92004-07-11 16:53:24 +00002117 assign(dst0, loadLE(ty,mkexpr(addr)));
sewardj180e8b32004-07-29 01:40:11 +00002118 assign(src, mkU(ty,d32 & mask));
sewardj41f43bc2004-07-08 14:23:22 +00002119
sewardj66de2272004-07-16 21:19:05 +00002120 if (gregOfRM(modrm) == 2 /* ADC */) {
sewardj3af115f2004-07-14 02:46:52 +00002121 helper_ADC( sz, dst1, dst0, src );
2122 } else
sewardj66de2272004-07-16 21:19:05 +00002123 if (gregOfRM(modrm) == 3 /* SBB */) {
sewardj3af115f2004-07-14 02:46:52 +00002124 vassert(0);
2125 } else {
2126 assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
sewardjb9c5cf62004-08-24 15:10:38 +00002127 if (isAddSub(op8))
2128 setFlags_ADD_SUB(op8, src, dst0, ty);
2129 else
2130 setFlags_LOGIC(op8, dst1, ty);
sewardj3af115f2004-07-14 02:46:52 +00002131 }
sewardj41f43bc2004-07-08 14:23:22 +00002132
2133 if (gregOfRM(modrm) < 7)
sewardj940e8c92004-07-11 16:53:24 +00002134 storeLE(mkexpr(addr), mkexpr(dst1));
sewardj41f43bc2004-07-08 14:23:22 +00002135
2136 delta += (len+d_sz);
2137 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz),
2138 d32, dis_buf);
2139 }
2140 return delta;
2141}
2142
2143
sewardj6d2638e2004-07-15 09:38:27 +00002144/* Group 2 extended opcodes. shift_expr must be an 8-bit typed
2145 expression. */
2146
sewardje90ad6a2004-07-10 19:02:10 +00002147static
2148UInt dis_Grp2 ( UChar sorb,
2149 UInt delta, UChar modrm,
sewardj6d2638e2004-07-15 09:38:27 +00002150 Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
2151 Char* shift_expr_txt )
sewardje90ad6a2004-07-10 19:02:10 +00002152{
2153 /* delta on entry points at the modrm byte. */
sewardj6d2638e2004-07-15 09:38:27 +00002154 UChar dis_buf[50];
2155 Int len;
sewardj750f4072004-07-26 22:39:11 +00002156 Bool isShift, isRotate;
sewardj6d2638e2004-07-15 09:38:27 +00002157 IRType ty = szToITy(sz);
2158 IRTemp dst0 = newTemp(ty);
2159 IRTemp dst1 = newTemp(ty);
2160 IRTemp addr = INVALID_IRTEMP;
sewardje90ad6a2004-07-10 19:02:10 +00002161
2162 vassert(sz == 1 || sz == 2 || sz == 4);
2163
sewardje90ad6a2004-07-10 19:02:10 +00002164 /* Put value to shift/rotate in dst0. */
2165 if (epartIsReg(modrm)) {
2166 assign(dst0, getIReg(sz, eregOfRM(modrm)));
sewardj940e8c92004-07-11 16:53:24 +00002167 delta += (am_sz + d_sz);
sewardje90ad6a2004-07-10 19:02:10 +00002168 } else {
sewardj940e8c92004-07-11 16:53:24 +00002169 addr = disAMode ( &len, sorb, delta, dis_buf);
2170 assign(dst0, loadLE(ty,mkexpr(addr)));
2171 delta += len + d_sz;
sewardje90ad6a2004-07-10 19:02:10 +00002172 }
2173
2174 isShift = False;
2175 switch (gregOfRM(modrm)) { case 4: case 5: case 7: isShift = True; }
2176
sewardj750f4072004-07-26 22:39:11 +00002177 isRotate = False;
2178 switch (gregOfRM(modrm)) { case 0: case 1: isRotate = True; }
2179
sewardj8c7f1ab2004-07-29 20:31:09 +00002180 if (!isShift && !isRotate) {
2181 vex_printf("\ncase %d\n", gregOfRM(modrm));
2182 vpanic("dis_Grp2(Reg): unhandled case(x86)");
2183 }
2184
sewardje90ad6a2004-07-10 19:02:10 +00002185 if (isShift) {
2186
sewardjc22a6fd2004-07-29 23:41:47 +00002187 IRTemp pre32 = newTemp(Ity_I32);
2188 IRTemp res32 = newTemp(Ity_I32);
2189 IRTemp res32ss = newTemp(Ity_I32);
sewardj6d2638e2004-07-15 09:38:27 +00002190 IRTemp shift_amt = newTemp(Ity_I8);
sewardjc22a6fd2004-07-29 23:41:47 +00002191 IROp op32;
sewardje90ad6a2004-07-10 19:02:10 +00002192
2193 switch (gregOfRM(modrm)) {
sewardjc22a6fd2004-07-29 23:41:47 +00002194 case 4: op32 = Iop_Shl32; break;
2195 case 5: op32 = Iop_Shr32; break;
2196 case 7: op32 = Iop_Sar32; break;
sewardje90ad6a2004-07-10 19:02:10 +00002197 default: vpanic("dis_Grp2:shift"); break;
2198 }
2199
sewardjc22a6fd2004-07-29 23:41:47 +00002200 /* Widen the value to be shifted to 32 bits, do the shift, and
2201 narrow back down. This seems surprisingly long-winded, but
2202 unfortunately the Intel semantics requires that 8/16-bit
2203 shifts give defined results for shift values all the way up
2204 to 31, and this seems the simplest way to do it. It has the
2205 advantage that the only IR level shifts generated are of 32
2206 bit values, and the shift amount is guaranteed to be in the
2207 range 0 .. 31, thereby observing the IR semantics requiring
2208 all shift values to be in the range 0 .. 2^word_size-1. */
2209
2210 /* shift_amt = shift_expr & 31, regardless of operation size */
2211 assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(31)) );
2212
2213 /* suitably widen the value to be shifted to 32 bits. */
2214 assign( pre32, op32==Iop_Sar32 ? widenSto32(mkexpr(dst0))
2215 : widenUto32(mkexpr(dst0)) );
2216
2217 /* res32 = pre32 `shift` shift_amt */
2218 assign( res32, binop(op32, mkexpr(pre32), mkexpr(shift_amt)) );
2219
2220 /* res32ss = pre32 `shift` ((shift_amt - 1) & 31) */
2221 assign( res32ss,
2222 binop(op32,
2223 mkexpr(pre32),
2224 binop(Iop_And8,
2225 binop(Iop_Sub8,
2226 mkexpr(shift_amt), mkU8(1)),
2227 mkU8(31))) );
sewardje90ad6a2004-07-10 19:02:10 +00002228
2229 /* Build the flags thunk. */
sewardjc22a6fd2004-07-29 23:41:47 +00002230 setFlags_DSTus_DST1(op32, res32ss, res32, ty, shift_amt);
2231
2232 /* Narrow the result back down. */
2233 assign( dst1, narrowTo(ty, mkexpr(res32)) );
sewardj750f4072004-07-26 22:39:11 +00002234
sewardj1813dbe2004-07-28 17:09:04 +00002235 } /* if (isShift) */
2236
2237 else
sewardj750f4072004-07-26 22:39:11 +00002238 if (isRotate) {
sewardj1813dbe2004-07-28 17:09:04 +00002239 Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
2240 Bool left = gregOfRM(modrm) == 0;
2241 IRTemp rot_amt = newTemp(Ity_I8);
2242 IRTemp oldFlags = newTemp(Ity_I32);
sewardj750f4072004-07-26 22:39:11 +00002243
2244 /* rot_amt = shift_expr & mask */
sewardjc22a6fd2004-07-29 23:41:47 +00002245 /* By masking the rotate amount thusly, the IR-level Shl/Shr
2246 expressions never shift beyond the word size and thus remain
2247 well defined. */
sewardj750f4072004-07-26 22:39:11 +00002248 assign(rot_amt, binop(Iop_And8,
2249 shift_expr, mkU8(8*sz-1)));
2250
2251 if (left) {
sewardj1813dbe2004-07-28 17:09:04 +00002252
sewardj750f4072004-07-26 22:39:11 +00002253 /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
2254 assign(dst1,
2255 binop( mkSizedOp(ty,Iop_Or8),
2256 binop( mkSizedOp(ty,Iop_Shl8),
2257 mkexpr(dst0),
2258 mkexpr(rot_amt)
2259 ),
2260 binop( mkSizedOp(ty,Iop_Shr8),
2261 mkexpr(dst0),
2262 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
2263 )
2264 )
2265 );
sewardj1813dbe2004-07-28 17:09:04 +00002266 ccOp += CC_OP_ROLB;
sewardj750f4072004-07-26 22:39:11 +00002267
sewardj1813dbe2004-07-28 17:09:04 +00002268 } else { /* right */
sewardj750f4072004-07-26 22:39:11 +00002269
sewardj1813dbe2004-07-28 17:09:04 +00002270 /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
2271 assign(dst1,
2272 binop( mkSizedOp(ty,Iop_Or8),
2273 binop( mkSizedOp(ty,Iop_Shr8),
2274 mkexpr(dst0),
2275 mkexpr(rot_amt)
2276 ),
2277 binop( mkSizedOp(ty,Iop_Shl8),
2278 mkexpr(dst0),
2279 binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
sewardj750f4072004-07-26 22:39:11 +00002280 )
2281 )
2282 );
sewardj1813dbe2004-07-28 17:09:04 +00002283 ccOp += CC_OP_RORB;
sewardjc22a6fd2004-07-29 23:41:47 +00002284
sewardj750f4072004-07-26 22:39:11 +00002285 }
sewardjc22a6fd2004-07-29 23:41:47 +00002286
sewardj1813dbe2004-07-28 17:09:04 +00002287 /* dst1 now holds the rotated value. Build flag thunk. We
2288 need the resulting value for this, and the previous flags.
2289 Except don't set it if the rotate count is zero. */
2290
2291 assign(oldFlags, mk_calculate_eflags_all());
2292
2293 /* CC_DST is the rotated value. CC_SRC is flags before. */
2294 stmt( IRStmt_Put( OFFB_CC_OP,
2295 IRExpr_Mux0X( mkexpr(rot_amt),
2296 IRExpr_Get(OFFB_CC_OP,Ity_I32),
2297 mkU32(ccOp))) );
2298 stmt( IRStmt_Put( OFFB_CC_DST,
2299 IRExpr_Mux0X( mkexpr(rot_amt),
2300 IRExpr_Get(OFFB_CC_DST,Ity_I32),
sewardjc22a6fd2004-07-29 23:41:47 +00002301 widenUto32(mkexpr(dst1)))) );
sewardj1813dbe2004-07-28 17:09:04 +00002302 stmt( IRStmt_Put( OFFB_CC_SRC,
2303 IRExpr_Mux0X( mkexpr(rot_amt),
2304 IRExpr_Get(OFFB_CC_SRC,Ity_I32),
2305 mkexpr(oldFlags))) );
2306 } /* if (isRotate) */
sewardje90ad6a2004-07-10 19:02:10 +00002307
2308 /* Save result, and finish up. */
2309 if (epartIsReg(modrm)) {
2310 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
2311 if (print_codegen) {
2312 vex_printf("%s%c ",
2313 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002314 if (shift_expr_txt)
2315 vex_printf("%s", shift_expr_txt);
2316 else
2317 ppIRExpr(shift_expr);
sewardje90ad6a2004-07-10 19:02:10 +00002318 vex_printf(", %s\n", nameIReg(sz,eregOfRM(modrm)));
2319 }
sewardje90ad6a2004-07-10 19:02:10 +00002320 } else {
sewardj940e8c92004-07-11 16:53:24 +00002321 storeLE(mkexpr(addr), mkexpr(dst1));
2322 if (print_codegen) {
2323 vex_printf("%s%c ",
2324 nameGrp2(gregOfRM(modrm)), nameISize(sz) );
sewardj6d2638e2004-07-15 09:38:27 +00002325 if (shift_expr_txt)
2326 vex_printf("%s", shift_expr_txt);
2327 else
2328 ppIRExpr(shift_expr);
sewardj940e8c92004-07-11 16:53:24 +00002329 vex_printf(", %s\n", dis_buf);
2330 }
sewardje90ad6a2004-07-10 19:02:10 +00002331 }
sewardje90ad6a2004-07-10 19:02:10 +00002332 return delta;
2333}
2334
2335
2336
sewardjc9a65702004-07-07 16:32:57 +00002337//-- /* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
2338//-- static
2339//-- Addr dis_Grp8_BT ( UCodeBlock* cb,
2340//-- UChar sorb,
2341//-- Addr eip, UChar modrm,
2342//-- Int am_sz, Int sz, UInt src_val )
2343//-- {
sewardjd1061ab2004-07-08 01:45:30 +00002344# define MODIFY_t2_AND_SET_CARRY_FLAG \
2345 /* t2 is the value to be op'd on. Copy to t_fetched, then \
2346 modify t2, if non-BT. */ \
2347 uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t_fetched); \
2348 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
2349 uLiteral(cb, v_mask); \
2350 switch (gregOfRM(modrm)) { \
2351 case 4: /* BT */ break; \
2352 case 5: /* BTS */ \
2353 uInstr2(cb, OR, sz, TempReg, t_mask, TempReg, t2); break; \
2354 case 6: /* BTR */ \
2355 uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t2); break; \
2356 case 7: /* BTC */ \
2357 uInstr2(cb, XOR, sz, TempReg, t_mask, TempReg, t2); break; \
2358 } \
2359 /* Copy relevant bit from t_fetched into carry flag. */ \
2360 uInstr2(cb, SHR, sz, Literal, 0, TempReg, t_fetched); \
2361 uLiteral(cb, src_val); \
2362 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
2363 uLiteral(cb, 1); \
2364 uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t_fetched); \
2365 uInstr1(cb, NEG, sz, TempReg, t_fetched); \
2366 setFlagsFromUOpcode(cb, NEG);
2367
2368
sewardjc9a65702004-07-07 16:32:57 +00002369//-- /* src_val denotes a d8.
2370//-- And eip on entry points at the modrm byte. */
2371//-- Int t1, t2, t_fetched, t_mask;
2372//-- UInt pair;
2373//-- Char dis_buf[50];
2374//-- UInt v_mask;
2375//--
2376//-- /* There is no 1-byte form of this instruction, AFAICS. */
2377//-- vg_assert(sz == 2 || sz == 4);
2378//--
2379//-- /* Limit src_val -- the bit offset -- to something within a word.
2380//-- The Intel docs say that literal offsets larger than a word are
2381//-- masked in this way. */
2382//-- switch (sz) {
2383//-- case 2: src_val &= 15; break;
2384//-- case 4: src_val &= 31; break;
2385//-- default: VG_(core_panic)("dis_Grp8_BT: invalid size");
2386//-- }
2387//--
2388//-- /* Invent a mask suitable for the operation. */
2389//--
2390//-- switch (gregOfRM(modrm)) {
2391//-- case 4: /* BT */ v_mask = 0; break;
2392//-- case 5: /* BTS */ v_mask = 1 << src_val; break;
2393//-- case 6: /* BTR */ v_mask = ~(1 << src_val); break;
2394//-- case 7: /* BTC */ v_mask = 1 << src_val; break;
2395//-- /* If this needs to be extended, probably simplest to make a
2396//-- new function to handle the other cases (0 .. 3). The
2397//-- Intel docs do however not indicate any use for 0 .. 3, so
2398//-- we don't expect this to happen. */
2399//-- default: VG_(core_panic)("dis_Grp8_BT");
2400//-- }
2401//-- /* Probably excessively paranoid. */
2402//-- if (sz == 2)
2403//-- v_mask &= 0x0000FFFF;
2404//--
2405//-- t1 = INVALID_TEMPREG;
2406//-- t_fetched = newTemp(cb);
2407//-- t_mask = newTemp(cb);
2408//--
2409//-- if (epartIsReg(modrm)) {
2410//-- vg_assert(am_sz == 1);
2411//-- t2 = newTemp(cb);
2412//--
2413//-- /* Fetch the value to be tested and modified. */
2414//-- uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t2);
2415//-- /* Do it! */
2416//-- MODIFY_t2_AND_SET_CARRY_FLAG;
2417//-- /* Dump the result back, if non-BT. */
2418//-- if (gregOfRM(modrm) != 4 /* BT */)
2419//-- uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, eregOfRM(modrm));
2420//--
2421//-- eip += (am_sz + 1);
2422//-- DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2423//-- src_val, nameIReg(sz,eregOfRM(modrm)));
2424//-- } else {
2425//-- pair = disAMode ( cb, sorb, eip, dis_buf);
2426//-- t1 = LOW24(pair);
2427//-- t2 = newTemp(cb);
2428//-- eip += HI8(pair);
2429//-- eip += 1;
2430//--
2431//-- /* Fetch the value to be tested and modified. */
2432//-- uInstr2(cb, LOAD, sz, TempReg, t1, TempReg, t2);
2433//-- /* Do it! */
2434//-- MODIFY_t2_AND_SET_CARRY_FLAG;
2435//-- /* Dump the result back, if non-BT. */
2436//-- if (gregOfRM(modrm) != 4 /* BT */) {
2437//-- uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
2438//-- }
2439//-- DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
2440//-- src_val, dis_buf);
2441//-- }
2442//-- return eip;
2443//--
2444//-- # undef MODIFY_t2_AND_SET_CARRY_FLAG
2445//-- }
sewardjcf780b42004-07-13 18:42:17 +00002446
2447
2448
sewardj1813dbe2004-07-28 17:09:04 +00002449/* Signed/unsigned widening multiply. Generate IR to multiply the
2450 value in EAX/AX/AL by the given IRTemp, and park the result in
2451 EDX:EAX/DX:AX/AX.
sewardjcf780b42004-07-13 18:42:17 +00002452*/
sewardj1813dbe2004-07-28 17:09:04 +00002453static void codegen_mulL_A_D ( Int sz, Bool syned,
2454 IRTemp tmp, Char* tmp_txt )
sewardjcf780b42004-07-13 18:42:17 +00002455{
sewardjcf780b42004-07-13 18:42:17 +00002456 IRType ty = szToITy(sz);
2457 IRTemp t1 = newTemp(ty);
sewardjcf780b42004-07-13 18:42:17 +00002458
sewardj1813dbe2004-07-28 17:09:04 +00002459 assign( t1, getIReg(sz, R_EAX) );
sewardjcf780b42004-07-13 18:42:17 +00002460
2461 switch (ty) {
sewardjb81f8b32004-07-30 10:17:50 +00002462 case Ity_I32: {
2463 IRTemp res64 = newTemp(Ity_I64);
2464 IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32;
2465 UInt tBaseOp = syned ? CC_OP_SMULB : CC_OP_UMULB;
2466 setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
2467 assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
2468 putIReg(4, R_EDX, unop(Iop_64HIto32,mkexpr(res64)));
2469 putIReg(4, R_EAX, unop(Iop_64to32,mkexpr(res64)));
2470 break;
2471 }
2472 case Ity_I16: {
2473 IRTemp res32 = newTemp(Ity_I32);
2474 IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16;
2475 UInt tBaseOp = syned ? CC_OP_SMULB : CC_OP_UMULB;
2476 setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
2477 assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
2478 putIReg(2, R_EDX, unop(Iop_32HIto16,mkexpr(res32)));
2479 putIReg(2, R_EAX, unop(Iop_32to16,mkexpr(res32)));
2480 break;
2481 }
2482 case Ity_I8: {
2483 IRTemp res16 = newTemp(Ity_I16);
2484 IROp mulOp = syned ? Iop_MullS8 : Iop_MullU8;
2485 UInt tBaseOp = syned ? CC_OP_SMULB : CC_OP_UMULB;
2486 setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
2487 assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
2488 putIReg(2, R_EAX, mkexpr(res16));
2489 break;
2490 }
2491 default:
2492 vpanic("codegen_mulL_A_D(x86)");
sewardjcf780b42004-07-13 18:42:17 +00002493 }
sewardj1813dbe2004-07-28 17:09:04 +00002494 DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
sewardjcf780b42004-07-13 18:42:17 +00002495}
2496
sewardj940e8c92004-07-11 16:53:24 +00002497
2498/* Group 3 extended opcodes. */
2499static
2500UInt dis_Grp3 ( UChar sorb, Int sz, UInt delta )
2501{
sewardjc2ac51e2004-07-12 01:03:26 +00002502 UInt d32;
sewardj940e8c92004-07-11 16:53:24 +00002503 UChar modrm;
2504 UChar dis_buf[50];
sewardjc2ac51e2004-07-12 01:03:26 +00002505 Int len;
2506 IRTemp addr;
sewardj940e8c92004-07-11 16:53:24 +00002507 IRType ty = szToITy(sz);
2508 IRTemp t1 = newTemp(ty);
sewardjc2ac51e2004-07-12 01:03:26 +00002509 // IRTemp t2 = INVALID_IRTEMP;
sewardj940e8c92004-07-11 16:53:24 +00002510 IRTemp dst1, src, dst0;
2511 modrm = getIByte(delta);
2512 if (epartIsReg(modrm)) {
2513 switch (gregOfRM(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002514 case 0: { /* TEST */
2515 delta++; d32 = getUDisp(sz, delta); delta += sz;
2516 dst1 = newTemp(ty);
2517 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2518 getIReg(sz,eregOfRM(modrm)),
2519 mkU(ty,d32)));
sewardjb9c5cf62004-08-24 15:10:38 +00002520 setFlags_LOGIC( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002521 DIP("test%c $0x%x, %s\n", nameISize(sz), d32,
2522 nameIReg(sz, eregOfRM(modrm)));
2523 break;
2524 }
sewardj940e8c92004-07-11 16:53:24 +00002525 case 2: /* NOT */
2526 delta++;
2527 putIReg(sz, eregOfRM(modrm),
2528 unop(mkSizedOp(ty,Iop_Not8),
2529 getIReg(sz, eregOfRM(modrm))));
2530 DIP("not%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2531 break;
2532 case 3: /* NEG */
2533 delta++;
2534 dst0 = newTemp(ty);
2535 src = newTemp(ty);
2536 dst1 = newTemp(ty);
sewardja511afc2004-07-29 22:26:03 +00002537 assign(dst0, mkU(ty,0));
2538 assign(src, getIReg(sz,eregOfRM(modrm)));
2539 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
sewardjb9c5cf62004-08-24 15:10:38 +00002540 setFlags_ADD_SUB(Iop_Sub8, src, dst0, ty);
sewardj940e8c92004-07-11 16:53:24 +00002541 putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
2542 DIP("neg%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2543 break;
sewardjcf780b42004-07-13 18:42:17 +00002544 case 4: /* MUL (unsigned widening) */
2545 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002546 src = newTemp(ty);
2547 assign(src, getIReg(sz,eregOfRM(modrm)));
2548 codegen_mulL_A_D ( sz, False, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcf780b42004-07-13 18:42:17 +00002549 break;
sewardjcaca9d02004-07-28 07:11:32 +00002550 case 5: /* IMUL (signed widening) */
2551 delta++;
sewardj1813dbe2004-07-28 17:09:04 +00002552 src = newTemp(ty);
2553 assign(src, getIReg(sz,eregOfRM(modrm)));
2554 codegen_mulL_A_D ( sz, True, src, nameIReg(sz,eregOfRM(modrm)) );
sewardjcaca9d02004-07-28 07:11:32 +00002555 break;
sewardj68511542004-07-28 00:15:44 +00002556 case 6: /* DIV */
2557 delta++;
2558 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2559 codegen_div ( sz, t1, False );
2560 DIP("div%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2561 break;
sewardjcaca9d02004-07-28 07:11:32 +00002562 case 7: /* IDIV */
2563 delta++;
2564 assign( t1, getIReg(sz, eregOfRM(modrm)) );
2565 codegen_div ( sz, t1, True );
2566 DIP("idiv%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2567 break;
sewardj940e8c92004-07-11 16:53:24 +00002568 default:
2569 vex_printf(
2570 "unhandled Grp3(R) case %d\n", (UInt)gregOfRM(modrm));
2571 vpanic("Grp3(x86)");
2572 }
2573 } else {
sewardjc2ac51e2004-07-12 01:03:26 +00002574 addr = disAMode ( &len, sorb, delta, dis_buf );
2575 t1 = newTemp(ty);
2576 delta += len;
2577 assign(t1, loadLE(ty,mkexpr(addr)));
2578 switch (gregOfRM(modrm)) {
2579 case 0: { /* TEST */
2580 d32 = getUDisp(sz, delta); delta += sz;
2581 dst1 = newTemp(ty);
2582 assign(dst1, binop(mkSizedOp(ty,Iop_And8),
2583 mkexpr(t1), mkU(ty,d32)));
sewardjb9c5cf62004-08-24 15:10:38 +00002584 setFlags_LOGIC( Iop_And8, dst1, ty );
sewardjc2ac51e2004-07-12 01:03:26 +00002585 DIP("test%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
2586 break;
2587 }
sewardj78fe7912004-08-20 23:38:07 +00002588#if 0
2589 /* probably OK, but awaiting test case */
2590 case 2: /* NOT */
2591 storeLE( mkexpr(addr), unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
2592 DIP("not%c %s\n", nameISize(sz), dis_buf);
2593 break;
2594#endif
sewardj0c12ea82004-07-12 08:18:16 +00002595 case 3: /* NEG */
2596 dst0 = newTemp(ty);
2597 src = newTemp(ty);
2598 dst1 = newTemp(ty);
sewardja511afc2004-07-29 22:26:03 +00002599 assign(dst0, mkU(ty,0));
2600 assign(src, mkexpr(t1));
2601 assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
sewardjb9c5cf62004-08-24 15:10:38 +00002602 setFlags_ADD_SUB(Iop_Sub8, src, dst0, ty);
sewardj0c12ea82004-07-12 08:18:16 +00002603 storeLE( mkexpr(addr), mkexpr(dst1) );
2604 DIP("neg%c %s\n", nameISize(sz), dis_buf);
2605 break;
sewardj1813dbe2004-07-28 17:09:04 +00002606 case 4: /* MUL */
2607 codegen_mulL_A_D ( sz, False, t1, dis_buf );
2608 break;
2609 case 5: /* IMUL */
2610 codegen_mulL_A_D ( sz, True, t1, dis_buf );
2611 break;
sewardj9690d922004-07-14 01:39:17 +00002612 case 6: /* DIV */
2613 codegen_div ( sz, t1, False );
2614 DIP("div%c %s\n", nameISize(sz), dis_buf);
2615 break;
sewardj1813dbe2004-07-28 17:09:04 +00002616 case 7: /* IDIV */
2617 codegen_div ( sz, t1, True );
2618 DIP("idiv%c %s\n", nameISize(sz), dis_buf);
2619 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002620 default:
2621 vex_printf(
2622 "unhandled Grp3(M) case %d\n", (UInt)gregOfRM(modrm));
2623 vpanic("Grp3(x86)");
2624 }
sewardj940e8c92004-07-11 16:53:24 +00002625 }
2626 return delta;
2627}
2628
2629
sewardjc2ac51e2004-07-12 01:03:26 +00002630/* Group 4 extended opcodes. */
2631static
2632UInt dis_Grp4 ( UChar sorb, UInt delta )
2633{
sewardj7ed22952004-07-29 00:09:58 +00002634 Int alen;
sewardjc2ac51e2004-07-12 01:03:26 +00002635 UChar modrm;
sewardj7ed22952004-07-29 00:09:58 +00002636 UChar dis_buf[50];
sewardjc2ac51e2004-07-12 01:03:26 +00002637 IRType ty = Ity_I8;
sewardj7ed22952004-07-29 00:09:58 +00002638 IRTemp t1 = newTemp(ty);
2639 IRTemp t2 = newTemp(ty);
sewardjc2ac51e2004-07-12 01:03:26 +00002640
2641 modrm = getIByte(delta);
2642 if (epartIsReg(modrm)) {
sewardjc2ac51e2004-07-12 01:03:26 +00002643 assign(t1, getIReg(1, eregOfRM(modrm)));
2644 switch (gregOfRM(modrm)) {
sewardj7ed22952004-07-29 00:09:58 +00002645 case 0: /* INC */
2646 assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
2647 putIReg(1, eregOfRM(modrm), mkexpr(t2));
2648 setFlags_INC_DEC( True, t2, ty );
2649 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002650 case 1: /* DEC */
sewardjc2ac51e2004-07-12 01:03:26 +00002651 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
2652 putIReg(1, eregOfRM(modrm), mkexpr(t2));
2653 setFlags_INC_DEC( False, t2, ty );
2654 break;
2655 default:
2656 vex_printf(
2657 "unhandled Grp4(R) case %d\n", (UInt)gregOfRM(modrm));
sewardj7ed22952004-07-29 00:09:58 +00002658 vpanic("Grp4(x86,R)");
sewardjc2ac51e2004-07-12 01:03:26 +00002659 }
2660 delta++;
2661 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)),
2662 nameIReg(1, eregOfRM(modrm)));
2663 } else {
sewardj7ed22952004-07-29 00:09:58 +00002664 IRTemp addr = disAMode ( &alen, sorb, delta, dis_buf );
2665 assign( t1, loadLE(ty, mkexpr(addr)) );
2666 switch (gregOfRM(modrm)) {
sewardjc9a65702004-07-07 16:32:57 +00002667//-- case 0: /* INC */
2668//-- uInstr1(cb, INC, 1, TempReg, t1);
2669//-- setFlagsFromUOpcode(cb, INC);
2670//-- uInstr2(cb, STORE, 1, TempReg, t1, TempReg, t2);
2671//-- break;
sewardj7ed22952004-07-29 00:09:58 +00002672 case 1: /* DEC */
2673 assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
2674 storeLE( mkexpr(addr), mkexpr(t2) );
2675 setFlags_INC_DEC( False, t2, ty );
2676 break;
2677 default:
2678 vex_printf(
2679 "unhandled Grp4(M) case %d\n", (UInt)gregOfRM(modrm));
2680 vpanic("Grp4(x86,M)");
2681 }
2682 delta += alen;
2683 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)), dis_buf);
sewardjc2ac51e2004-07-12 01:03:26 +00002684 }
2685 return delta;
2686}
sewardj0611d802004-07-11 02:37:54 +00002687
2688
2689/* Group 5 extended opcodes. */
2690static
2691UInt dis_Grp5 ( UChar sorb, Int sz, UInt delta, Bool* isEnd )
2692{
2693 Int len;
2694 UChar modrm;
2695 UChar dis_buf[50];
sewardj940e8c92004-07-11 16:53:24 +00002696 IRTemp addr = INVALID_IRTEMP;
sewardj0611d802004-07-11 02:37:54 +00002697 IRType ty = szToITy(sz);
2698 IRTemp t1 = newTemp(ty);
2699 IRTemp t2 = INVALID_IRTEMP;
2700
2701 modrm = getIByte(delta);
2702 if (epartIsReg(modrm)) {
sewardj940e8c92004-07-11 16:53:24 +00002703 assign(t1, getIReg(sz,eregOfRM(modrm)));
sewardj0611d802004-07-11 02:37:54 +00002704 switch (gregOfRM(modrm)) {
sewardjc9a65702004-07-07 16:32:57 +00002705//-- case 0: /* INC */
2706//-- uInstr1(cb, INC, sz, TempReg, t1);
2707//-- setFlagsFromUOpcode(cb, INC);
2708//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
2709//-- break;
2710//-- case 1: /* DEC */
2711//-- uInstr1(cb, DEC, sz, TempReg, t1);
2712//-- setFlagsFromUOpcode(cb, DEC);
2713//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
2714//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +00002715 case 2: /* call Ev */
2716 vassert(sz == 4);
2717 t2 = newTemp(Ity_I32);
2718 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
2719 putIReg(4, R_ESP, mkexpr(t2));
2720 storeLE( mkexpr(t2), mkU32(guest_eip+delta+1));
sewardj78c19df2004-07-12 22:49:27 +00002721 jmp_treg(Ijk_Call,t1);
sewardjc2ac51e2004-07-12 01:03:26 +00002722 *isEnd = True;
2723 break;
sewardj0611d802004-07-11 02:37:54 +00002724 case 4: /* jmp Ev */
2725 vassert(sz == 4);
sewardj78c19df2004-07-12 22:49:27 +00002726 jmp_treg(Ijk_Boring,t1);
sewardj0611d802004-07-11 02:37:54 +00002727 *isEnd = True;
2728 break;
2729 default:
2730 vex_printf(
2731 "unhandled Grp5(R) case %d\n", (UInt)gregOfRM(modrm));
2732 vpanic("Grp5(x86)");
2733 }
2734 delta++;
2735 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
2736 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
2737 } else {
2738 addr = disAMode ( &len, sorb, delta, dis_buf );
sewardj940e8c92004-07-11 16:53:24 +00002739 assign(t1, loadLE(ty,mkexpr(addr)));
sewardj0611d802004-07-11 02:37:54 +00002740 switch (gregOfRM(modrm)) {
2741 case 0: /* INC */
2742 t2 = newTemp(ty);
2743 assign(t2, binop(mkSizedOp(ty,Iop_Add8),
2744 mkexpr(t1), mkU(ty,1)));
2745 setFlags_INC_DEC( True, t2, ty );
sewardj940e8c92004-07-11 16:53:24 +00002746 storeLE(mkexpr(addr),mkexpr(t2));
sewardj0611d802004-07-11 02:37:54 +00002747 break;
sewardjc2ac51e2004-07-12 01:03:26 +00002748 case 1: /* DEC */
2749 t2 = newTemp(ty);
2750 assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
2751 mkexpr(t1), mkU(ty,1)));
2752 setFlags_INC_DEC( False, t2, ty );
2753 storeLE(mkexpr(addr),mkexpr(t2));
2754 break;
sewardj77b86be2004-07-11 13:28:24 +00002755 case 2: /* call Ev */
2756 vassert(sz == 4);
2757 t2 = newTemp(Ity_I32);
2758 assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
2759 putIReg(4, R_ESP, mkexpr(t2));
2760 storeLE( mkexpr(t2), mkU32(guest_eip+delta+len));
sewardj78c19df2004-07-12 22:49:27 +00002761 jmp_treg(Ijk_Call,t1);
sewardj77b86be2004-07-11 13:28:24 +00002762 *isEnd = True;
2763 break;
2764 case 4: /* JMP Ev */
2765 vassert(sz == 4);
sewardj78c19df2004-07-12 22:49:27 +00002766 jmp_treg(Ijk_Boring,t1);
sewardj77b86be2004-07-11 13:28:24 +00002767 *isEnd = True;
2768 break;
sewardj0c12ea82004-07-12 08:18:16 +00002769 case 6: /* PUSH Ev */
2770 vassert(sz == 4 || sz == 2);
2771 t2 = newTemp(Ity_I32);
2772 assign( t2, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
2773 putIReg(4, R_ESP, mkexpr(t2) );
2774 storeLE( mkexpr(t2), mkexpr(t1) );
2775 break;
sewardj0611d802004-07-11 02:37:54 +00002776 default:
2777 vex_printf(
2778 "unhandled Grp5(M) case %d\n", (UInt)gregOfRM(modrm));
2779 vpanic("Grp5(x86)");
2780 }
2781 delta += len;
2782 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
2783 nameISize(sz), dis_buf);
2784 }
2785 return delta;
2786}
2787
sewardj64e1d652004-07-12 14:00:46 +00002788/*------------------------------------------------------------*/
2789/*--- Disassembling string ops (including REP prefixes) ---*/
2790/*------------------------------------------------------------*/
2791
2792/* Code shared by all the string ops */
2793static
2794void dis_string_op_increment(Int sz, Int t_inc)
2795{
2796 if (sz == 4 || sz == 2) {
2797 assign( t_inc,
2798 binop(Iop_Shl32, IRExpr_Get( OFFB_DFLAG, Ity_I32 ),
sewardj6d2638e2004-07-15 09:38:27 +00002799 mkU8(sz/2) ) );
sewardj64e1d652004-07-12 14:00:46 +00002800 } else {
2801 assign( t_inc,
2802 IRExpr_Get( OFFB_DFLAG, Ity_I32 ) );
2803 }
2804}
2805
2806#if 0
2807static
2808void dis_string_op( void (*dis_OP)( Int, IRTemp ),
2809 Int sz, Char* name, UChar sorb )
2810{
2811 IRTemp t_inc = newTemp(Ity_I32);
2812 vassert(sorb == 0);
2813 dis_string_op_increment(sz, t_inc);
2814 dis_OP( sz, t_inc );
2815 DIP("%s%c\n", name, nameISize(sz));
2816}
2817#endif
2818
2819static
2820void dis_MOVS ( Int sz, IRTemp t_inc )
2821{
2822 IRType ty = szToITy(sz);
2823 //IRTemp tv = newTemp(ty); /* value being copied */
2824 IRTemp td = newTemp(Ity_I32); /* EDI */
2825 IRTemp ts = newTemp(Ity_I32); /* ESI */
2826
2827 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
2828 //uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
2829 assign( td, getIReg(4, R_EDI) );
2830 assign( ts, getIReg(4, R_ESI) );
2831
2832 //uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tv);
2833 //uInstr2(cb, STORE,sz, TempReg, tv, TempReg, td);
2834 storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
2835
2836 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
2837 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
2838
2839 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2840 //uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
2841 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
2842 putIReg( 4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
2843}
2844
sewardjc9a65702004-07-07 16:32:57 +00002845//-- static
2846//-- void dis_LODS ( UCodeBlock* cb, Int sz, Int t_inc )
2847//-- {
2848//-- Int ta = newTemp(cb); /* EAX */
2849//-- Int ts = newTemp(cb); /* ESI */
2850//--
2851//-- uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
2852//-- uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, ta);
2853//-- uInstr2(cb, PUT, sz, TempReg, ta, ArchReg, R_EAX);
2854//--
2855//-- uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
2856//-- uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
2857//-- }
sewardj64e1d652004-07-12 14:00:46 +00002858
2859static
2860void dis_STOS ( Int sz, IRTemp t_inc )
2861{
2862 IRType ty = szToITy(sz);
2863 IRTemp ta = newTemp(ty); /* EAX */
2864 IRTemp td = newTemp(Ity_I32); /* EDI */
2865
2866 //uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
2867 assign( ta, getIReg(sz, R_EAX) );
2868
2869 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
2870 assign( td, getIReg(4, R_EDI) );
2871
2872 //uInstr2(cb, STORE, sz, TempReg, ta, TempReg, td);
sewardj6d2638e2004-07-15 09:38:27 +00002873 storeLE( mkexpr(td), mkexpr(ta) );
sewardj64e1d652004-07-12 14:00:46 +00002874
2875 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
2876 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2877 putIReg( 4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
2878}
2879
2880static
2881void dis_CMPS ( Int sz, IRTemp t_inc )
2882{
2883 IRType ty = szToITy(sz);
sewardj6d2638e2004-07-15 09:38:27 +00002884 IRTemp tdv = newTemp(ty); /* (EDI) */
2885 IRTemp tsv = newTemp(ty); /* (ESI) */
sewardj64e1d652004-07-12 14:00:46 +00002886 IRTemp td = newTemp(Ity_I32); /* EDI */
2887 IRTemp ts = newTemp(Ity_I32); /* ESI */
2888
2889 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
2890 assign( td, getIReg(4, R_EDI) );
2891
2892 //uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
2893 assign( ts, getIReg(4, R_ESI) );
2894
2895 //uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tdv);
2896 assign( tdv, loadLE(ty,mkexpr(td)) );
2897
2898 //uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tsv);
sewardjb9c5cf62004-08-24 15:10:38 +00002899 assign( tsv, loadLE(ty,mkexpr(ts)) );
sewardj64e1d652004-07-12 14:00:46 +00002900
2901 //uInstr2(cb, SUB, sz, TempReg, tdv, TempReg, tsv);
2902 //setFlagsFromUOpcode(cb, SUB);
sewardjb9c5cf62004-08-24 15:10:38 +00002903 setFlags_ADD_SUB ( Iop_Sub8, tdv, tsv, ty );
sewardj64e1d652004-07-12 14:00:46 +00002904
2905 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
2906 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
2907
2908 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2909 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
2910
2911 //uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
2912 putIReg(4, R_ESI, binop(Iop_Add32, mkexpr(ts), mkexpr(t_inc)) );
2913}
2914
sewardj64e1d652004-07-12 14:00:46 +00002915static
2916void dis_SCAS ( Int sz, IRTemp t_inc )
2917{
2918 IRType ty = szToITy(sz);
sewardj82292882004-07-27 00:15:59 +00002919 IRTemp ta = newTemp(ty); /* EAX */
sewardj64e1d652004-07-12 14:00:46 +00002920 IRTemp td = newTemp(Ity_I32); /* EDI */
2921 IRTemp tdv = newTemp(ty); /* (EDI) */
2922
2923 //uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
sewardjb9c5cf62004-08-24 15:10:38 +00002924 assign( ta, getIReg(sz, R_EAX) );
sewardj64e1d652004-07-12 14:00:46 +00002925
2926 //uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
2927 assign( td, getIReg(4, R_EDI) );
2928
2929 //uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tdv);
2930 assign( tdv, loadLE(ty,mkexpr(td)) );
2931
sewardj64e1d652004-07-12 14:00:46 +00002932 //uInstr2(cb, SUB, sz, TempReg, tdv, TempReg, ta);
2933 //setFlagsFromUOpcode(cb, SUB);
sewardjb9c5cf62004-08-24 15:10:38 +00002934 setFlags_ADD_SUB( Iop_Sub8, tdv, ta, ty );
sewardj64e1d652004-07-12 14:00:46 +00002935
2936 //uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
2937 //uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2938 putIReg(4, R_EDI, binop(Iop_Add32, mkexpr(td), mkexpr(t_inc)) );
2939}
sewardj82292882004-07-27 00:15:59 +00002940
sewardj64e1d652004-07-12 14:00:46 +00002941
2942/* Wrap the appropriate string op inside a REP/REPE/REPNE.
2943 We assume the insn is the last one in the basic block, and so emit a jump
2944 to the next insn, rather than just falling through. */
2945static
2946void dis_REP_op ( Condcode cond,
2947 void (*dis_OP)(Int, IRTemp),
2948 Int sz, Addr32 eip, Addr32 eip_next, Char* name )
2949{
2950 IRTemp t_inc = newTemp(Ity_I32);
2951 IRTemp tc = newTemp(Ity_I32); /* ECX */
2952
2953 //uInstr2 (cb, GET, 4, ArchReg, R_ECX, TempReg, tc);
2954 assign( tc, getIReg(4,R_ECX) );
2955
2956 //uInstr2 (cb, JIFZ, 4, TempReg, tc, Literal, 0);
2957 //uLiteral(cb, eip_next);
2958 stmt( IRStmt_Exit( binop(Iop_CmpEQ32,mkexpr(tc),mkU32(0)),
2959 IRConst_U32(eip_next) ) );
2960
2961 //uInstr1 (cb, DEC, 4, TempReg, tc);
2962 //uInstr2 (cb, PUT, 4, TempReg, tc, ArchReg, R_ECX);
2963 putIReg(4, R_ECX, binop(Iop_Sub32, mkexpr(tc), mkU32(1)) );
2964
2965 dis_string_op_increment(sz, t_inc);
2966 dis_OP (sz, t_inc);
2967
2968 if (cond == CondAlways) {
sewardj78c19df2004-07-12 22:49:27 +00002969 jmp_lit(Ijk_Boring,eip);
sewardj64e1d652004-07-12 14:00:46 +00002970 } else {
2971 stmt( IRStmt_Exit( calculate_condition(cond),
2972 IRConst_U32(eip) ) );
sewardj78c19df2004-07-12 22:49:27 +00002973 jmp_lit(Ijk_Boring,eip_next);
sewardj64e1d652004-07-12 14:00:46 +00002974 }
2975 DIP("%s%c\n", name, nameISize(sz));
2976}
2977
2978/*------------------------------------------------------------*/
2979/*--- Arithmetic, etc. ---*/
2980/*------------------------------------------------------------*/
2981
sewardjcf780b42004-07-13 18:42:17 +00002982/* (I)MUL E, G. Supplied eip points to the modR/M byte. */
2983static
2984UInt dis_mul_E_G ( UChar sorb,
2985 Int size,
2986 UInt delta0,
sewardj56296d82004-07-30 01:52:45 +00002987 Bool syned )
sewardjcf780b42004-07-13 18:42:17 +00002988{
sewardj71a65362004-07-28 01:48:34 +00002989 Int alen;
2990 UChar dis_buf[50];
sewardjcf780b42004-07-13 18:42:17 +00002991 UChar rm = getIByte(delta0);
2992 IRType ty = szToITy(size);
sewardj6d2638e2004-07-15 09:38:27 +00002993 IRTemp te = newTemp(ty);
2994 IRTemp tg = newTemp(ty);
sewardjcf780b42004-07-13 18:42:17 +00002995
sewardj56296d82004-07-30 01:52:45 +00002996 vassert(syned);
sewardj71a65362004-07-28 01:48:34 +00002997
sewardjcf780b42004-07-13 18:42:17 +00002998 if (epartIsReg(rm)) {
sewardjcf780b42004-07-13 18:42:17 +00002999 assign( tg, getIReg(size, gregOfRM(rm)) );
3000 assign( te, getIReg(size, eregOfRM(rm)) );
sewardj56296d82004-07-30 01:52:45 +00003001 setFlags_MUL ( ty, te, tg, syned ? CC_OP_SMULB : CC_OP_UMULB );
sewardjcf780b42004-07-13 18:42:17 +00003002 putIReg(size, gregOfRM(rm),
3003 binop(mkSizedOp(ty,Iop_Mul8),
3004 mkexpr(te), mkexpr(tg)));
3005
sewardj56296d82004-07-30 01:52:45 +00003006 DIP("%smul%c %s, %s\n", syned ? "i" : "",
sewardjcf780b42004-07-13 18:42:17 +00003007 nameISize(size),
3008 nameIReg(size,eregOfRM(rm)),
3009 nameIReg(size,gregOfRM(rm)));
3010 return 1+delta0;
3011 } else {
sewardj71a65362004-07-28 01:48:34 +00003012 IRTemp addr = disAMode( &alen, sorb, delta0, dis_buf );
3013 assign( tg, getIReg(size, gregOfRM(rm)) );
3014 assign( te, loadLE(ty,mkexpr(addr)) );
sewardj56296d82004-07-30 01:52:45 +00003015 setFlags_MUL ( ty, te, tg, syned ? CC_OP_SMULB : CC_OP_UMULB );
sewardj71a65362004-07-28 01:48:34 +00003016 putIReg(size, gregOfRM(rm),
3017 binop(mkSizedOp(ty,Iop_Mul8),
3018 mkexpr(te), mkexpr(tg)));
sewardjcf780b42004-07-13 18:42:17 +00003019
sewardj56296d82004-07-30 01:52:45 +00003020 DIP("%smul%c %s, %s\n", syned ? "i" : "",
sewardjcf780b42004-07-13 18:42:17 +00003021 nameISize(size),
3022 dis_buf, nameIReg(size,gregOfRM(rm)));
sewardj71a65362004-07-28 01:48:34 +00003023 return alen+delta0;
sewardjcf780b42004-07-13 18:42:17 +00003024 }
3025}
3026
3027
sewardj1813dbe2004-07-28 17:09:04 +00003028/* IMUL I * E -> G. Supplied eip points to the modR/M byte. */
3029static
3030UInt dis_imul_I_E_G ( UChar sorb,
3031 Int size,
3032 UInt delta,
3033 Int litsize )
3034{
sewardjb81f8b32004-07-30 10:17:50 +00003035 Int d32;
3036 Char dis_buf[50];
3037 UChar rm = getIByte(delta);
sewardj1813dbe2004-07-28 17:09:04 +00003038 IRType ty = szToITy(size);
3039 IRTemp te = newTemp(ty);
3040 IRTemp tl = newTemp(ty);
3041
sewardjb81f8b32004-07-30 10:17:50 +00003042 vassert(size == 1 || size == 2 || size == 4);
3043
sewardj1813dbe2004-07-28 17:09:04 +00003044 if (epartIsReg(rm)) {
3045 assign(te, getIReg(size, eregOfRM(rm)));
3046 delta++;
3047 } else {
3048 vassert(0);
3049#if 0
3050 UInt pair = disAMode ( cb, sorb, eip, dis_buf );
3051 ta = LOW24(pair);
3052 uInstr2(cb, LOAD, size, TempReg, ta, TempReg, te);
3053 eip += HI8(pair);
3054#endif
3055 }
3056 d32 = getSDisp(litsize,delta);
3057 delta += litsize;
3058
sewardjb81f8b32004-07-30 10:17:50 +00003059 if (size == 1) d32 &= 0xFF;
3060 if (size == 2) d32 &= 0xFFFF;
3061
sewardj1813dbe2004-07-28 17:09:04 +00003062 assign(tl, mkU(ty,d32));
sewardj56296d82004-07-30 01:52:45 +00003063 setFlags_MUL ( ty, te, tl, CC_OP_SMULB );
sewardj1813dbe2004-07-28 17:09:04 +00003064 putIReg(size, gregOfRM(rm),
3065 binop(mkSizedOp(ty,Iop_Mul8),
3066 mkexpr(te), mkexpr(tl)));
3067
3068 DIP("imul %d, %s, %s\n", d32,
3069 ( epartIsReg(rm) ? nameIReg(size,eregOfRM(rm)) : dis_buf ),
3070 nameIReg(size,gregOfRM(rm)) );
3071 return delta;
3072}
3073
3074
sewardjd1725d12004-08-12 20:46:53 +00003075/*------------------------------------------------------------*/
3076/*--- x87 floating point insns. ---*/
3077/*------------------------------------------------------------*/
3078
3079/* Get/set the top-of-stack pointer. */
3080
3081static IRExpr* get_ftop ( void )
3082{
3083 return IRExpr_Get( OFFB_FTOP, Ity_I32 );
3084}
3085
3086static IRStmt* put_ftop ( IRExpr* e )
3087{
3088 return IRStmt_Put( OFFB_FTOP, e );
3089}
3090
3091/* Given i, generate an expression which is the offset in the guest
3092 state of ST(i), considering the current value of FTOP. */
3093
3094static IRExpr* off_ST ( Int i )
3095{
3096 vassert(i >= 0 && i <= 7);
3097 return
3098 binop(Iop_Add32,
3099 binop(Iop_Mul32,
3100 binop(Iop_And32,
3101 binop(Iop_Add32, get_ftop(), mkU32(i)),
3102 mkU32(7)),
3103 mkU32(8)),
3104 mkU32(OFFB_F0)
3105 );
3106}
3107
3108/* Given i, and some expression e, generate 'ST(i) = e'. */
3109
3110static IRStmt* put_ST ( Int i, IRExpr* value )
3111{
3112 return
3113 IRStmt_PutI( off_ST(i), value, OFFB_F0, OFFB_F7+8-1 );
3114}
3115
3116/* Given i, generate an expression yielding 'ST(i)'. */
3117
3118static IRExpr* get_ST ( Int i )
3119{
3120 return
3121 IRExpr_GetI( off_ST(i), Ity_F64, OFFB_F0, OFFB_F7+8-1 );
3122}
3123
3124/* Adjust FTOP downwards by one register. */
3125
sewardja58ea662004-08-15 03:12:41 +00003126static IRStmt* fp_push ( void )
sewardjd1725d12004-08-12 20:46:53 +00003127{
3128 return
3129 put_ftop(
3130 binop(Iop_And32,
3131 binop(Iop_Sub32, get_ftop(), mkU32(1)),
3132 mkU32(7))
3133 );
3134}
3135
sewardja58ea662004-08-15 03:12:41 +00003136/* Adjust FTOP upwards by one register. */
3137
3138static IRStmt* fp_pop ( void )
3139{
3140 return
3141 put_ftop(
3142 binop(Iop_And32,
3143 binop(Iop_Add32, get_ftop(), mkU32(1)),
3144 mkU32(7))
3145 );
3146}
3147
3148static
3149void fp_do_op_mem_ST_0 ( IRTemp addr, UChar* op_txt, UChar* dis_buf,
3150 IROp op, Bool dbl )
3151{
3152 DIP("f%s%c %s", op_txt, dbl?'l':'s', dis_buf);
3153 if (dbl) {
3154 stmt( put_ST(0, binop(op, get_ST(0), loadLE(Ity_F64,mkexpr(addr)))));
3155 } else {
3156 vassert(0);
3157 }
3158}
3159
sewardjd1725d12004-08-12 20:46:53 +00003160
3161static
3162UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta )
3163{
sewardja58ea662004-08-15 03:12:41 +00003164 Int len;
3165 UInt r_src, r_dst;
3166 Char dis_buf[32];
sewardjbb53f8c2004-08-14 11:50:01 +00003167 IRTemp t1;
sewardjd1725d12004-08-12 20:46:53 +00003168
3169 /* On entry, delta points at the second byte of the insn (the modrm
3170 byte).*/
3171 UChar first_opcode = getIByte(delta-1);
3172 UChar modrm = getIByte(delta+0);
3173
3174 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
3175
3176 if (first_opcode == 0xD8) {
3177 goto decode_fail;
3178 }
3179
3180 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
3181 else
3182 if (first_opcode == 0xD9) {
sewardjbb53f8c2004-08-14 11:50:01 +00003183 if (modrm < 0xC0) {
3184 goto decode_fail;
3185 } else {
3186 delta++;
3187 switch (modrm) {
3188 case 0xC0 ... 0xC7: /* FLD %st(?) */
sewardja58ea662004-08-15 03:12:41 +00003189 r_src = (UInt)modrm - 0xC0;
3190 DIP("fld %%st(%d)\n", r_src);
sewardjbb53f8c2004-08-14 11:50:01 +00003191 t1 = newTemp(Ity_F64);
sewardja58ea662004-08-15 03:12:41 +00003192 assign(t1, get_ST(r_src));
3193 stmt( fp_push() );
sewardjbb53f8c2004-08-14 11:50:01 +00003194 stmt( put_ST(0, mkexpr(t1)) );
3195 break;
3196
sewardja58ea662004-08-15 03:12:41 +00003197 case 0xEE: /* FLDZ */
3198 DIP("fldz");
3199 stmt( fp_push() );
3200 stmt( put_ST(0, IRExpr_Const(IRConst_F64(0.0))) );
3201 break;
3202
sewardjbb53f8c2004-08-14 11:50:01 +00003203 default:
3204 goto decode_fail;
3205 }
3206 }
sewardjd1725d12004-08-12 20:46:53 +00003207 }
3208
3209 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
3210 else
3211 if (first_opcode == 0xDA) {
sewardjbb53f8c2004-08-14 11:50:01 +00003212
3213 if (modrm < 0xC0) {
3214
3215 /* bits 5,4,3 are an opcode extension, and the modRM also
3216 specifies an address. */
3217 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3218 delta += len;
3219
3220 switch (gregOfRM(modrm)) {
3221 case 1: /* FIMUL m32int */
3222 DIP("fimull %s", dis_buf);
3223 stmt( put_ST(0,
3224 binop(Iop_MulF64,
3225 get_ST(0),
3226 unop(Iop_I64toF64,
3227 unop(Iop_32Sto64,
3228 loadLE(Ity_I32, mkexpr(addr)))))));
3229 break;
3230
3231 default:
3232 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3233 vex_printf("first_opcode == 0xDA\n");
3234 goto decode_fail;
3235 }
3236 } else {
3237 goto decode_fail;
3238 }
sewardjd1725d12004-08-12 20:46:53 +00003239 }
3240
3241 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
3242 else
3243 if (first_opcode == 0xDB) {
3244 goto decode_fail;
3245 }
3246
3247 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
3248 else
3249 if (first_opcode == 0xDC) {
sewardja58ea662004-08-15 03:12:41 +00003250 if (modrm < 0xC0) {
3251
3252 /* bits 5,4,3 are an opcode extension, and the modRM also
3253 specifies an address. */
3254 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3255 delta += len;
3256
3257 switch (gregOfRM(modrm)) {
3258
3259 case 0: /* FADD double-real */
3260 fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
3261 break;
3262
3263 default:
3264 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3265 vex_printf("first_opcode == 0xDC\n");
3266 goto decode_fail;
3267 }
3268
3269 } else {
3270 goto decode_fail;
3271 }
sewardjd1725d12004-08-12 20:46:53 +00003272 }
3273
3274 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
3275 else
3276 if (first_opcode == 0xDD) {
3277
3278 if (modrm < 0xC0) {
3279
sewardjbb53f8c2004-08-14 11:50:01 +00003280 /* bits 5,4,3 are an opcode extension, and the modRM also
sewardjd1725d12004-08-12 20:46:53 +00003281 specifies an address. */
sewardjbb53f8c2004-08-14 11:50:01 +00003282 IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
3283 delta += len;
sewardjd1725d12004-08-12 20:46:53 +00003284
3285 switch (gregOfRM(modrm)) {
3286
3287 case 0: /* FLD double-real */
3288 DIP("fldD %s\n", dis_buf);
sewardja58ea662004-08-15 03:12:41 +00003289 stmt( fp_push() );
sewardjbb53f8c2004-08-14 11:50:01 +00003290 stmt( put_ST(0, IRExpr_LDle(Ity_F64, mkexpr(addr))) );
3291 break;
sewardjd1725d12004-08-12 20:46:53 +00003292
3293#if 0
3294 case 2: /* FST double-real */
3295 IFDB( if (dis) printf("\tfstD\t%s\n",t_addr); )
3296 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
3297 vd_addr = fp_get_reg_ST(0);
3298 } else {
3299 vd_addr = NAN;
3300 fp_set_stack_underflow();
3301 }
3302 setDMem(a_addr,vd_addr);
3303 break;
sewardjd1725d12004-08-12 20:46:53 +00003304#endif
sewardja58ea662004-08-15 03:12:41 +00003305 case 3: /* FSTP double-real */
3306 DIP("fstpD %s", dis_buf);
3307 storeLE(mkexpr(addr), get_ST(0));
3308 stmt( fp_pop() );
3309 break;
sewardjd1725d12004-08-12 20:46:53 +00003310
3311 default:
sewardjbb53f8c2004-08-14 11:50:01 +00003312 vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
3313 vex_printf("first_opcode == 0xDD\n");
sewardjd1725d12004-08-12 20:46:53 +00003314 goto decode_fail;
sewardjbb53f8c2004-08-14 11:50:01 +00003315 }
sewardjd1725d12004-08-12 20:46:53 +00003316 } else {
sewardja58ea662004-08-15 03:12:41 +00003317 delta++;
3318 switch (modrm) {
3319 case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
3320 r_dst = (UInt)modrm - 0xD8;
3321 DIP("fstp %%st(0),%%st(%d)\n", r_dst);
3322 stmt( put_ST(r_dst, get_ST(0)) );
3323 stmt( fp_pop() );
3324 break;
3325 default:
3326 goto decode_fail;
3327 }
sewardjd1725d12004-08-12 20:46:53 +00003328 }
3329 }
3330
3331 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
3332 else
3333 if (first_opcode == 0xDE) {
3334 goto decode_fail;
3335 }
3336
3337 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
3338 else
3339 if (first_opcode == 0xDF) {
3340 goto decode_fail;
3341 }
3342
3343 else
3344 vpanic("dis_FPU(x86): invalid primary opcode");
3345
3346 decode_success:
3347 *decode_ok = True;
3348 return delta;
3349
3350 decode_fail:
3351 *decode_ok = False;
3352 return delta;
3353}
3354
3355
sewardjc9a65702004-07-07 16:32:57 +00003356//-- /* Handle FPU insns which read/write memory. On entry, eip points to
3357//-- the second byte of the insn (the one following D8 .. DF). */
3358//-- static
3359//-- Addr dis_fpu_mem ( UCodeBlock* cb,
3360//-- UChar sorb,
3361//-- Int size, Bool is_write,
3362//-- Addr eip, UChar first_byte )
3363//-- {
3364//-- Int ta;
3365//-- UInt pair;
3366//-- UChar dis_buf[50];
3367//-- UChar second_byte = getIByte(delta);
3368//-- vg_assert(second_byte < 0xC0);
3369//-- second_byte &= 0x38;
3370//-- pair = disAMode ( cb, sorb, eip, dis_buf );
3371//-- ta = LOW24(pair);
3372//-- eip += HI8(pair);
3373//-- uInstr2(cb, is_write ? FPU_W : FPU_R, size,
3374//-- Lit16,
3375//-- (((UShort)first_byte) << 8) | ((UShort)second_byte),
3376//-- TempReg, ta);
3377//-- if (is_write) {
3378//-- DIP("fpu_w_%d 0x%x:0x%x, %s\n",
3379//-- size, (UInt)first_byte, (UInt)second_byte, dis_buf );
3380//-- } else {
3381//-- DIP("fpu_r_%d %s, 0x%x:0x%x\n",
3382//-- size, dis_buf, (UInt)first_byte, (UInt)second_byte );
3383//-- }
3384//-- return eip;
3385//-- }
3386//--
3387//--
3388//-- /* Handle FPU insns which don't reference memory. On entry, eip points to
3389//-- the second byte of the insn (the one following D8 .. DF). */
3390//-- static
3391//-- Addr dis_fpu_no_mem ( UCodeBlock* cb, Addr eip, UChar first_byte )
3392//-- {
3393//-- Bool sets_ZCP = False;
3394//-- Bool uses_ZCP = False;
3395//-- UChar second_byte = getUChar(eip); eip++;
3396//-- vg_assert(second_byte >= 0xC0);
3397//--
3398//-- /* Does the insn write any integer condition codes (%EIP) ? */
3399//--
3400//-- if (first_byte == 0xDB && second_byte >= 0xF0 && second_byte <= 0xF7) {
3401//-- /* FCOMI */
3402//-- sets_ZCP = True;
3403//-- } else
3404//-- if (first_byte == 0xDF && second_byte >= 0xF0 && second_byte <= 0xF7) {
3405//-- /* FCOMIP */
3406//-- sets_ZCP = True;
3407//-- } else
3408//-- if (first_byte == 0xDB && second_byte >= 0xE8 && second_byte <= 0xEF) {
3409//-- /* FUCOMI */
3410//-- sets_ZCP = True;
3411//-- } else
3412//-- if (first_byte == 0xDF && second_byte >= 0xE8 && second_byte <= 0xEF) {
3413//-- /* FUCOMIP */
3414//-- sets_ZCP = True;
3415//-- }
3416//--
3417//-- /* Dually, does the insn read any integer condition codes (%EIP) ? */
3418//--
3419//-- if (first_byte == 0xDA && second_byte >= 0xC0 && second_byte <= 0xDF) {
3420//-- /* FCMOVB %st(n), %st(0)
3421//-- FCMOVE %st(n), %st(0)
3422//-- FCMOVBE %st(n), %st(0)
3423//-- FCMOVU %st(n), %st(0)
3424//-- */
3425//-- uses_ZCP = True;
3426//-- } else
3427//-- if (first_byte == 0xDB && second_byte >= 0xC0 && second_byte <= 0xDF) {
3428//-- /* FCMOVNB %st(n), %st(0)
3429//-- FCMOVNE %st(n), %st(0)
3430//-- FCMOVNBE %st(n), %st(0)
3431//-- FCMOVNU %st(n), %st(0)
3432//-- */
3433//-- uses_ZCP = True;
3434//-- }
3435//--
3436//-- uInstr1(cb, FPU, 0,
3437//-- Lit16,
3438//-- (((UShort)first_byte) << 8) | ((UShort)second_byte)
3439//-- );
3440//-- if (uses_ZCP) {
3441//-- /* VG_(printf)("!!! --- FPU insn which reads %EFLAGS\n"); */
3442//-- uFlagsRWU(cb, FlagsZCP, FlagsEmpty, FlagsEmpty);
3443//-- vg_assert(!sets_ZCP);
3444//-- }
3445//-- if (sets_ZCP) {
3446//-- /* VG_(printf)("!!! --- FPU insn which writes %EFLAGS\n"); */
3447//-- uFlagsRWU(cb, FlagsEmpty, FlagsZCP, FlagsEmpty);
3448//-- vg_assert(!uses_ZCP);
3449//-- }
3450//--
3451//-- DIP("fpu 0x%x:0x%x%s%s\n", (UInt)first_byte, (UInt)second_byte,
3452//-- uses_ZCP ? " -rZCP" : "",
3453//-- sets_ZCP ? " -wZCP" : "" );
3454//-- return eip;
3455//-- }
3456//--
3457//--
3458//-- /* Top-level handler for all FPU insns. On entry, eip points to the
3459//-- second byte of the insn. */
3460//-- static
3461//-- Addr dis_fpu ( UCodeBlock* cb,
3462//-- UChar sorb,
3463//-- UChar first_byte, Addr eip )
3464//-- {
3465//-- const Bool rd = False;
3466//-- const Bool wr = True;
3467//-- UChar second_byte = getUChar(eip);
3468//--
3469//-- /* Handle FSTSW %ax specially. */
3470//-- if (first_byte == 0xDF && second_byte == 0xE0) {
3471//-- Int t1 = newTemp(cb);
3472//-- uInstr0(cb, CALLM_S, 0);
3473//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
3474//-- uLiteral(cb, 0);
3475//-- uInstr1(cb, PUSH, 4, TempReg, t1);
3476//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_fstsw_AX) );
3477//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
3478//-- uInstr1(cb, POP, 2, TempReg, t1);
3479//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
3480//-- uInstr0(cb, CALLM_E, 0);
3481//-- DIP("fstsw %%ax\n");
3482//-- eip++;
3483//-- return eip;
3484//-- }
3485//--
3486//-- /* Handle all non-memory FPU ops simply. */
3487//-- if (second_byte >= 0xC0)
3488//-- return dis_fpu_no_mem ( cb, eip, first_byte );
3489//--
3490//-- /* The insn references memory; need to determine
3491//-- whether it reads or writes, and at what size. */
3492//-- switch (first_byte) {
3493//--
3494//-- case 0xD8:
3495//-- switch ((second_byte >> 3) & 7) {
3496//-- case 0: /* FADDs */
3497//-- case 1: /* FMULs */
3498//-- case 2: /* FCOMs */
3499//-- case 3: /* FCOMPs */
3500//-- case 4: /* FSUBs */
3501//-- case 5: /* FSUBRs */
3502//-- case 6: /* FDIVs */
3503//-- case 7: /* FDIVRs */
3504//-- return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
3505//-- default:
3506//-- goto unhandled;
3507//-- }
3508//-- break;
3509//--
3510//-- case 0xD9:
3511//-- switch ((second_byte >> 3) & 7) {
3512//-- case 0: /* FLDs */
3513//-- return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
3514//-- case 2: /* FSTs */
3515//-- case 3: /* FSTPs */
3516//-- return dis_fpu_mem(cb, sorb, 4, wr, eip, first_byte);
3517//-- case 4: /* FLDENV */
3518//-- return dis_fpu_mem(cb, sorb, 28, rd, eip, first_byte);
3519//-- case 5: /* FLDCW */
3520//-- return dis_fpu_mem(cb, sorb, 2, rd, eip, first_byte);
3521//-- case 6: /* FNSTENV */
3522//-- return dis_fpu_mem(cb, sorb, 28, wr, eip, first_byte);
3523//-- case 7: /* FSTCW */
3524//-- /* HACK! FSTCW actually writes 2 bytes, not 4. glibc
3525//-- gets lots of moaning in __floor() if we do the right
3526//-- thing here. */
3527//-- /* Later ... hack disabled .. we do do the Right Thing. */
3528//-- return dis_fpu_mem(cb, sorb, /*4*/ 2, wr, eip, first_byte);
3529//-- default:
3530//-- goto unhandled;
3531//-- }
3532//-- break;
3533//--
3534//-- case 0xDA:
3535//-- switch ((second_byte >> 3) & 7) {
3536//-- case 0: /* FIADD dword-integer */
3537//-- case 1: /* FIMUL dword-integer */
3538//-- case 2: /* FICOM dword-integer */
3539//-- case 3: /* FICOMP dword-integer */
3540//-- case 4: /* FISUB dword-integer */
3541//-- case 5: /* FISUBR dword-integer */
3542//-- case 6: /* FIDIV dword-integer */
3543//-- case 7: /* FIDIVR dword-integer */
3544//-- return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
3545//-- default:
3546//-- goto unhandled;
3547//-- }
3548//-- break;
3549//--
3550//-- case 0xDB:
3551//-- switch ((second_byte >> 3) & 7) {
3552//-- case 0: /* FILD dword-integer */
3553//-- return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
3554//-- case 2: /* FIST dword-integer */
3555//-- return dis_fpu_mem(cb, sorb, 4, wr, eip, first_byte);
3556//-- case 3: /* FISTPl */
3557//-- return dis_fpu_mem(cb, sorb, 4, wr, eip, first_byte);
3558//-- case 5: /* FLD extended-real */
3559//-- return dis_fpu_mem(cb, sorb, 10, rd, eip, first_byte);
3560//-- case 7: /* FSTP extended-real */
3561//-- return dis_fpu_mem(cb, sorb, 10, wr, eip, first_byte);
3562//-- default:
3563//-- goto unhandled;
3564//-- }
3565//-- break;
3566//--
3567//-- case 0xDC:
3568//-- switch ((second_byte >> 3) & 7) {
3569//-- case 0: /* FADD double-real */
3570//-- case 1: /* FMUL double-real */
3571//-- case 2: /* FCOM double-real */
3572//-- case 3: /* FCOMP double-real */
3573//-- case 4: /* FSUB double-real */
3574//-- case 5: /* FSUBR double-real */
3575//-- case 6: /* FDIV double-real */
3576//-- case 7: /* FDIVR double-real */
3577//-- return dis_fpu_mem(cb, sorb, 8, rd, eip, first_byte);
3578//-- default:
3579//-- goto unhandled;
3580//-- }
3581//-- break;
3582//--
3583//-- case 0xDD:
3584//-- switch ((second_byte >> 3) & 7) {
3585//-- case 0: /* FLD double-real */
3586//-- return dis_fpu_mem(cb, sorb, 8, rd, eip, first_byte);
3587//-- case 2: /* FST double-real */
3588//-- case 3: /* FSTP double-real */
3589//-- return dis_fpu_mem(cb, sorb, 8, wr, eip, first_byte);
3590//-- case 4: /* FRSTOR */
3591//-- return dis_fpu_mem(cb, sorb, 108, rd, eip, first_byte);
3592//-- case 6: /* FSAVE */
3593//-- return dis_fpu_mem(cb, sorb, 108, wr, eip, first_byte);
3594//-- case 7: /* FSTSW */
3595//-- return dis_fpu_mem(cb, sorb, 2, wr, eip, first_byte);
3596//-- default:
3597//-- goto unhandled;
3598//-- }
3599//-- break;
3600//--
3601//-- case 0xDE:
3602//-- switch ((second_byte >> 3) & 7) {
3603//-- case 0: /* FIADD word-integer */
3604//-- case 1: /* FIMUL word-integer */
3605//-- case 2: /* FICOM word-integer */
3606//-- case 3: /* FICOMP word-integer */
3607//-- case 4: /* FISUB word-integer */
3608//-- case 5: /* FISUBR word-integer */
3609//-- case 6: /* FIDIV word-integer */
3610//-- case 7: /* FIDIVR word-integer */
3611//-- return dis_fpu_mem(cb, sorb, 2, rd, eip, first_byte);
3612//-- default:
3613//-- goto unhandled;
3614//-- }
3615//-- break;
3616//--
3617//-- case 0xDF:
3618//-- switch ((second_byte >> 3) & 7) {
3619//-- case 0: /* FILD word-integer */
3620//-- return dis_fpu_mem(cb, sorb, 2, rd, eip, first_byte);
3621//-- case 2: /* FIST word-integer */
3622//-- return dis_fpu_mem(cb, sorb, 2, wr, eip, first_byte);
3623//-- case 3: /* FISTP word-integer */
3624//-- return dis_fpu_mem(cb, sorb, 2, wr, eip, first_byte);
3625//-- case 5: /* FILD qword-integer */
3626//-- return dis_fpu_mem(cb, sorb, 8, rd, eip, first_byte);
3627//-- case 7: /* FISTP qword-integer */
3628//-- return dis_fpu_mem(cb, sorb, 8, wr, eip, first_byte);
3629//-- default:
3630//-- goto unhandled;
3631//-- }
3632//-- break;
3633//--
3634//-- default: goto unhandled;
3635//-- }
3636//--
3637//-- unhandled:
3638//-- VG_(printf)("dis_fpu: unhandled memory case 0x%2x:0x%2x(%d)\n",
3639//-- (UInt)first_byte, (UInt)second_byte,
3640//-- (UInt)((second_byte >> 3) & 7) );
3641//-- VG_(core_panic)("dis_fpu: unhandled opcodes");
3642//-- }
sewardja06e5562004-07-14 13:18:05 +00003643
3644
3645/* Double length left and right shifts. Apparently only required in
3646 v-size (no b- variant). */
3647static
3648UInt dis_SHLRD_Gv_Ev ( UChar sorb,
3649 UInt delta, UChar modrm,
3650 Int sz,
3651 IRExpr* shift_amt,
3652 Bool amt_is_literal,
3653 Char* shift_amt_txt,
3654 Bool left_shift )
3655{
3656 /* shift_amt :: Ity_I8 is the amount to shift. shift_amt_txt is used
3657 for printing it. And eip on entry points at the modrm byte. */
3658 Int len;
3659 UChar dis_buf[50];
3660
sewardj6d2638e2004-07-15 09:38:27 +00003661 IRType ty = szToITy(sz);
3662 IRTemp gsrc = newTemp(ty);
3663 IRTemp esrc = newTemp(ty);
3664 IRTemp addr = INVALID_IRTEMP;
3665 IRTemp tmpSH = newTemp(Ity_I8);
sewardj6d2638e2004-07-15 09:38:27 +00003666 IRTemp tmpL = INVALID_IRTEMP;
3667 IRTemp tmpRes = INVALID_IRTEMP;
sewardja06e5562004-07-14 13:18:05 +00003668 IRTemp tmpSubSh = INVALID_IRTEMP;
3669 IROp mkpair;
3670 IROp getres;
3671 IROp shift;
sewardja06e5562004-07-14 13:18:05 +00003672 IRExpr* mask = NULL;
3673
3674 vassert(sz == 2 || sz == 4);
3675
3676 /* The E-part is the destination; this is shifted. The G-part
3677 supplies bits to be shifted into the E-part, but is not
3678 changed.
3679
3680 If shifting left, form a double-length word with E at the top
3681 and G at the bottom, and shift this left. The result is then in
3682 the high part.
3683
3684 If shifting right, form a double-length word with G at the top
3685 and E at the bottom, and shift this right. The result is then
3686 at the bottom. */
3687
3688 /* Fetch the operands. */
3689
3690 assign( gsrc, getIReg(sz, gregOfRM(modrm)) );
3691
3692 if (epartIsReg(modrm)) {
3693 delta++;
3694 assign( esrc, getIReg(sz, eregOfRM(modrm)) );
sewardj68511542004-07-28 00:15:44 +00003695 DIP("sh%cd%c %s, %s, %s\n",
sewardja06e5562004-07-14 13:18:05 +00003696 ( left_shift ? 'l' : 'r' ), nameISize(sz),
sewardj68511542004-07-28 00:15:44 +00003697 shift_amt_txt,
sewardja06e5562004-07-14 13:18:05 +00003698 nameIReg(sz, gregOfRM(modrm)), nameIReg(sz, eregOfRM(modrm)));
3699 } else {
3700 addr = disAMode ( &len, sorb, delta, dis_buf );
3701 delta += len;
3702 assign( esrc, loadLE(ty, mkexpr(addr)) );
sewardj68511542004-07-28 00:15:44 +00003703 DIP("sh%cd%c %s, %s, %s\n",
3704 ( left_shift ? 'l' : 'r' ), nameISize(sz),
3705 shift_amt_txt,
3706 nameIReg(sz, gregOfRM(modrm)), dis_buf);
sewardja06e5562004-07-14 13:18:05 +00003707 }
3708
3709 /* Round up the relevant primops. */
3710
3711 if (sz == 4) {
3712 tmpL = newTemp(Ity_I64);
3713 tmpRes = newTemp(Ity_I32);
3714 tmpSubSh = newTemp(Ity_I32);
sewardje539a402004-07-14 18:24:17 +00003715 mkpair = Iop_32HLto64;
sewardj8c7f1ab2004-07-29 20:31:09 +00003716 getres = left_shift ? Iop_64HIto32 : Iop_64to32;
sewardje539a402004-07-14 18:24:17 +00003717 shift = left_shift ? Iop_Shl64 : Iop_Shr64;
3718 mask = mkU8(31);
sewardja06e5562004-07-14 13:18:05 +00003719 } else {
3720 /* sz == 2 */
sewardj8c7f1ab2004-07-29 20:31:09 +00003721 tmpL = newTemp(Ity_I32);
3722 tmpRes = newTemp(Ity_I16);
3723 tmpSubSh = newTemp(Ity_I16);
3724 mkpair = Iop_16HLto32;
3725 getres = left_shift ? Iop_32HIto16 : Iop_32to16;
3726 shift = left_shift ? Iop_Shl32 : Iop_Shr32;
3727 mask = mkU8(15);
sewardja06e5562004-07-14 13:18:05 +00003728 }
3729
3730 /* Do the shift, calculate the subshift value, and set
3731 the flag thunk. */
3732
sewardj8c7f1ab2004-07-29 20:31:09 +00003733 assign( tmpSH, binop(Iop_And8, shift_amt, mask) );
3734
sewardja06e5562004-07-14 13:18:05 +00003735 if (left_shift)
3736 assign( tmpL, binop(mkpair, mkexpr(esrc), mkexpr(gsrc)) );
3737 else
3738 assign( tmpL, binop(mkpair, mkexpr(gsrc), mkexpr(esrc)) );
3739
3740 assign( tmpRes, unop(getres, binop(shift, mkexpr(tmpL), mkexpr(tmpSH)) ) );
3741 assign( tmpSubSh,
3742 unop(getres,
3743 binop(shift,
3744 mkexpr(tmpL),
3745 binop(Iop_And8,
3746 binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
3747 mask))) );
sewardja06e5562004-07-14 13:18:05 +00003748
sewardjc22a6fd2004-07-29 23:41:47 +00003749 setFlags_DSTus_DST1 ( left_shift ? Iop_Shl32 : Iop_Sar32,
sewardjbb53f8c2004-08-14 11:50:01 +00003750 tmpSubSh, tmpRes, ty, tmpSH );
sewardja06e5562004-07-14 13:18:05 +00003751
3752 /* Put result back. */
3753
3754 if (epartIsReg(modrm)) {
3755 putIReg(sz, eregOfRM(modrm), mkexpr(tmpRes));
3756 } else {
3757 storeLE( mkexpr(addr), mkexpr(tmpRes) );
3758 }
3759
3760 if (amt_is_literal) delta++;
3761 return delta;
3762}
3763
3764
sewardjc9a65702004-07-07 16:32:57 +00003765//-- /* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
3766//-- required. */
3767//--
3768//-- typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
3769//--
3770//-- static Char* nameBtOp ( BtOp op )
3771//-- {
3772//-- switch (op) {
3773//-- case BtOpNone: return "";
3774//-- case BtOpSet: return "s";
3775//-- case BtOpReset: return "r";
3776//-- case BtOpComp: return "c";
3777//-- default: VG_(core_panic)("nameBtOp");
3778//-- }
3779//-- }
3780//--
3781//--
3782//-- static
3783//-- Addr dis_bt_G_E ( UCodeBlock* cb,
3784//-- UChar sorb,
3785//-- Int sz, Addr eip, BtOp op )
3786//-- {
3787//-- UInt pair;
3788//-- Char dis_buf[50];
3789//-- UChar modrm;
3790//--
3791//-- Int t_addr, t_bitno, t_mask, t_fetched, t_esp, temp, lit;
3792//--
3793//-- vg_assert(sz == 2 || sz == 4);
3794//--
3795//-- t_addr = t_bitno = t_mask
3796//-- = t_fetched = t_esp = temp = INVALID_TEMPREG;
3797//--
3798//-- t_fetched = newTemp(cb);
3799//-- t_bitno = newTemp(cb);
3800//-- temp = newTemp(cb);
3801//-- lit = newTemp(cb);
3802//--
3803//-- modrm = getUChar(eip);
3804//--
3805//-- uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t_bitno);
3806//--
3807//-- if (sz == 2) {
3808//-- uInstr1(cb, WIDEN, 4, TempReg, t_bitno);
3809//-- uWiden(cb, 2, False);
3810//-- }
3811//--
3812//-- if (epartIsReg(modrm)) {
3813//-- eip++;
3814//-- /* Get it onto the client's stack. */
3815//-- t_esp = newTemp(cb);
3816//-- t_addr = newTemp(cb);
3817//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t_esp);
3818//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t_esp);
3819//-- uLiteral(cb, sz);
3820//-- uInstr2(cb, PUT, 4, TempReg, t_esp, ArchReg, R_ESP);
3821//-- uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, temp);
3822//-- uInstr2(cb, STORE, sz, TempReg, temp, TempReg, t_esp);
3823//-- /* Make t_addr point at it. */
3824//-- uInstr2(cb, MOV, 4, TempReg, t_esp, TempReg, t_addr);
3825//-- /* Mask out upper bits of the shift amount, since we're doing a
3826//-- reg. */
3827//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, lit);
3828//-- uLiteral(cb, sz == 4 ? 31 : 15);
3829//-- uInstr2(cb, AND, 4, TempReg, lit, TempReg, t_bitno);
3830//-- } else {
3831//-- pair = disAMode ( cb, sorb, eip, dis_buf );
3832//-- t_addr = LOW24(pair);
3833//-- eip += HI8(pair);
3834//-- }
3835//--
3836//-- /* At this point: t_addr points to the address being operated on. If
3837//-- it was a reg, we will have pushed it onto the client's stack.
3838//-- t_bitno is the bit number, suitable masked in the case of a reg. */
3839//--
3840//-- /* Now the main sequence. */
3841//--
3842//-- uInstr2(cb, MOV, 4, TempReg, t_bitno, TempReg, temp);
3843//-- uInstr2(cb, SAR, 4, Literal, 0, TempReg, temp);
3844//-- uLiteral(cb, 3);
3845//-- uInstr2(cb, ADD, 4, TempReg, temp, TempReg, t_addr);
3846//-- /* t_addr now holds effective address */
3847//--
3848//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, lit);
3849//-- uLiteral(cb, 7);
3850//-- uInstr2(cb, AND, 4, TempReg, lit, TempReg, t_bitno);
3851//-- /* t_bitno contains offset of bit within byte */
3852//--
3853//-- if (op != BtOpNone) {
3854//-- t_mask = newTemp(cb);
3855//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_mask);
3856//-- uLiteral(cb, 1);
3857//-- uInstr2(cb, SHL, 4, TempReg, t_bitno, TempReg, t_mask);
3858//-- }
3859//-- /* t_mask is now a suitable byte mask */
3860//--
3861//-- uInstr2(cb, LOAD, 1, TempReg, t_addr, TempReg, t_fetched);
3862//-- if (op != BtOpNone) {
3863//-- uInstr2(cb, MOV, 4, TempReg, t_fetched, TempReg, temp);
3864//-- switch (op) {
3865//-- case BtOpSet:
3866//-- uInstr2(cb, OR, 4, TempReg, t_mask, TempReg, temp);
3867//-- break;
3868//-- case BtOpComp:
3869//-- uInstr2(cb, XOR, 4, TempReg, t_mask, TempReg, temp);
3870//-- break;
3871//-- case BtOpReset:
3872//-- uInstr1(cb, NOT, 4, TempReg, t_mask);
3873//-- uInstr2(cb, AND, 4, TempReg, t_mask, TempReg, temp);
3874//-- break;
3875//-- default:
3876//-- VG_(core_panic)("dis_bt_G_E");
3877//-- }
3878//-- uInstr2(cb, STORE, 1, TempReg, temp, TempReg, t_addr);
3879//-- }
3880//--
3881//-- /* Side effect done; now get selected bit into Carry flag */
3882//--
3883//-- uInstr2(cb, SHR, 4, TempReg, t_bitno, TempReg, t_fetched);
3884//-- /* at bit 0 of fetched */
3885//--
3886//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, lit);
3887//-- uLiteral(cb, 1);
3888//-- uInstr2(cb, AND, 4, TempReg, lit, TempReg, t_fetched);
3889//-- /* t_fetched is now 1 or 0 */
3890//--
3891//-- /* NEG is a handy way to convert zero/nonzero into the carry
3892//-- flag. */
3893//-- uInstr1(cb, NEG, 4, TempReg, t_fetched);
3894//-- setFlagsFromUOpcode(cb, NEG);
3895//-- /* t_fetched is now in carry flag */
3896//--
3897//-- /* Move reg operand from stack back to reg */
3898//-- if (epartIsReg(modrm)) {
3899//-- /* t_esp still points at it. */
3900//-- uInstr2(cb, LOAD, sz, TempReg, t_esp, TempReg, temp);
3901//-- uInstr2(cb, PUT, sz, TempReg, temp, ArchReg, eregOfRM(modrm));
3902//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t_esp);
3903//-- uLiteral(cb, sz);
3904//-- uInstr2(cb, PUT, 4, TempReg, t_esp, ArchReg, R_ESP);
3905//-- }
3906//--
3907//-- DIP("bt%s%c %s, %s\n",
3908//-- nameBtOp(op), nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
3909//-- ( epartIsReg(modrm) ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ) );
3910//--
3911//-- return eip;
3912//-- }
3913//--
3914//--
3915//--
3916//-- /* Handle BSF/BSR. Only v-size seems necessary. */
3917//-- static
3918//-- Addr dis_bs_E_G ( UCodeBlock* cb,
3919//-- UChar sorb,
3920//-- Int sz, Addr eip, Bool fwds )
3921//-- {
3922//-- Int t, t1, ta, helper;
3923//-- UInt pair;
3924//-- Char dis_buf[50];
3925//-- UChar modrm;
3926//-- Bool isReg;
3927//--
3928//-- vg_assert(sz == 2 || sz == 4);
3929//--
3930//-- if (fwds)
3931//-- helper = sz == 2 ? VGOFF_(helper_bsfw) : VGOFF_(helper_bsfl);
3932//-- else
3933//-- helper = sz == 2 ? VGOFF_(helper_bsrw) : VGOFF_(helper_bsrl);
3934//--
3935//-- modrm = getUChar(eip);
3936//-- t1 = newTemp(cb);
3937//-- t = newTemp(cb);
3938//--
3939//-- uInstr0(cb, CALLM_S, 0);
3940//-- uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t1);
3941//-- uInstr1(cb, PUSH, sz, TempReg, t1);
3942//--
3943//-- isReg = epartIsReg(modrm);
3944//-- if (isReg) {
3945//-- eip++;
3946//-- uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t);
3947//-- } else {
3948//-- pair = disAMode ( cb, sorb, eip, dis_buf );
3949//-- ta = LOW24(pair);
3950//-- eip += HI8(pair);
3951//-- uInstr2(cb, LOAD, sz, TempReg, ta, TempReg, t);
3952//-- }
3953//-- DIP("bs%c%c %s, %s\n",
3954//-- fwds ? 'f' : 'r', nameISize(sz),
3955//-- ( isReg ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ),
3956//-- nameIReg(sz, gregOfRM(modrm)));
3957//--
3958//-- uInstr1(cb, PUSH, sz, TempReg, t);
3959//-- uInstr1(cb, CALLM, 0, Lit16, helper);
3960//-- uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsOSACP);
3961//-- uInstr1(cb, POP, sz, TempReg, t);
3962//-- uInstr1(cb, POP, sz, TempReg, t);
3963//-- uInstr2(cb, PUT, sz, TempReg, t, ArchReg, gregOfRM(modrm));
3964//-- uInstr0(cb, CALLM_E, 0);
3965//--
3966//-- return eip;
3967//-- }
sewardj64e1d652004-07-12 14:00:46 +00003968
3969
3970static
3971void codegen_xchg_eAX_Reg ( Int sz, Int reg )
3972{
3973 IRType ty = szToITy(sz);
3974 IRTemp t1 = newTemp(ty);
3975 IRTemp t2 = newTemp(ty);
3976 vassert(sz == 2 || sz == 4);
3977 assign( t1, getIReg(sz, R_EAX) );
3978 assign( t2, getIReg(sz, reg) );
3979 putIReg( sz, R_EAX, mkexpr(t2) );
3980 putIReg( sz, reg, mkexpr(t1) );
3981 DIP("xchg%c %s, %s\n",
3982 nameISize(sz), nameIReg(sz, R_EAX), nameIReg(sz, reg));
3983}
3984
3985
sewardjc9a65702004-07-07 16:32:57 +00003986//-- static
3987//-- void codegen_SAHF ( UCodeBlock* cb )
3988//-- {
3989//-- Int t = newTemp(cb);
3990//-- Int t2 = newTemp(cb);
3991//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t);
3992//--
3993//-- /* Mask out parts of t not corresponding to %AH. This stops the
3994//-- instrumenter complaining if they are undefined. Otherwise, the
3995//-- instrumenter would check all 32 bits of t at the PUSH, which
3996//-- could be the cause of incorrect warnings. Discovered by Daniel
3997//-- Veillard <veillard@redhat.com>.
3998//-- */
3999//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
4000//-- uLiteral(cb, 0x0000FF00);
4001//-- uInstr2(cb, AND, 4, TempReg, t2, TempReg, t);
4002//-- /* We deliberately don't set the condition codes here, since this
4003//-- AND is purely internal to Valgrind and nothing to do with the
4004//-- client's state. */
4005//--
4006//-- uInstr0(cb, CALLM_S, 0);
4007//-- uInstr1(cb, PUSH, 4, TempReg, t);
4008//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_SAHF));
4009//-- uFlagsRWU(cb, FlagsEmpty, FlagsSZACP, FlagsEmpty);
4010//-- uInstr1(cb, CLEAR, 0, Lit16, 4);
4011//-- uInstr0(cb, CALLM_E, 0);
4012//-- }
4013//--
4014//-- static
4015//-- void codegen_LAHF ( UCodeBlock* cb )
4016//-- {
4017//-- Int t = newTemp(cb);
4018//--
4019//-- /* Pushed arg is ignored, it just provides somewhere to put the
4020//-- return value. */
4021//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t);
4022//-- uInstr0(cb, CALLM_S, 0);
4023//-- uInstr1(cb, PUSH, 4, TempReg, t);
4024//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_LAHF));
4025//-- uFlagsRWU(cb, FlagsSZACP, FlagsEmpty, FlagsEmpty);
4026//-- uInstr1(cb, POP, 4, TempReg, t);
4027//-- uInstr0(cb, CALLM_E, 0);
4028//--
4029//-- /* At this point, the %ah sub-register in %eax has been updated,
4030//-- the rest is the same, so do a PUT of the whole thing. */
4031//-- uInstr2(cb, PUT, 4, TempReg, t, ArchReg, R_EAX);
4032//-- }
4033//--
4034//--
4035//-- static
4036//-- Addr dis_cmpxchg_G_E ( UCodeBlock* cb,
4037//-- UChar sorb,
4038//-- Int size,
4039//-- Addr eip0 )
4040//-- {
4041//-- Int ta, junk, dest, src, acc;
4042//-- UChar dis_buf[50];
4043//-- UChar rm;
4044//--
4045//-- rm = getUChar(eip0);
4046//-- acc = newTemp(cb);
4047//-- src = newTemp(cb);
4048//-- dest = newTemp(cb);
4049//-- junk = newTemp(cb);
4050//-- /* Only needed to get gcc's dataflow analyser off my back. */
4051//-- ta = INVALID_TEMPREG;
4052//--
4053//-- if (epartIsReg(rm)) {
4054//-- uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, dest);
4055//-- eip0++;
4056//-- DIP("cmpxchg%c %s,%s\n", nameISize(size),
4057//-- nameIReg(size,gregOfRM(rm)),
4058//-- nameIReg(size,eregOfRM(rm)) );
4059//-- } else {
4060//-- UInt pair = disAMode ( cb, sorb, eip0, dis_buf );
4061//-- ta = LOW24(pair);
4062//-- uInstr2(cb, LOAD, size, TempReg, ta, TempReg, dest);
4063//-- eip0 += HI8(pair);
4064//-- DIP("cmpxchg%c %s,%s\n", nameISize(size),
4065//-- nameIReg(size,gregOfRM(rm)), dis_buf);
4066//-- }
4067//--
4068//-- uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, src);
4069//-- uInstr2(cb, GET, size, ArchReg, R_EAX, TempReg, acc);
4070//-- uInstr2(cb, MOV, 4, TempReg, acc, TempReg, junk);
4071//-- uInstr2(cb, SUB, size, TempReg, dest, TempReg, junk);
4072//-- setFlagsFromUOpcode(cb, SUB);
4073//--
4074//-- uInstr2(cb, CMOV, 4, TempReg, src, TempReg, dest);
4075//-- uCond(cb, CondZ);
4076//-- uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
4077//-- uInstr2(cb, CMOV, 4, TempReg, dest, TempReg, acc);
4078//-- uCond(cb, CondNZ);
4079//-- uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
4080//--
4081//-- uInstr2(cb, PUT, size, TempReg, acc, ArchReg, R_EAX);
4082//-- if (epartIsReg(rm)) {
4083//-- uInstr2(cb, PUT, size, TempReg, dest, ArchReg, eregOfRM(rm));
4084//-- } else {
4085//-- uInstr2(cb, STORE, size, TempReg, dest, TempReg, ta);
4086//-- }
4087//--
4088//-- return eip0;
4089//-- }
4090//--
4091//--
4092//-- static
4093//-- Addr dis_cmpxchg8b ( UCodeBlock* cb,
4094//-- UChar sorb,
4095//-- Addr eip0 )
4096//-- {
4097//-- Int tal, tah, junkl, junkh, destl, desth, srcl, srch, accl, acch;
4098//-- UChar dis_buf[50];
4099//-- UChar rm;
4100//-- UInt pair;
4101//--
4102//-- rm = getUChar(eip0);
4103//-- accl = newTemp(cb);
4104//-- acch = newTemp(cb);
4105//-- srcl = newTemp(cb);
4106//-- srch = newTemp(cb);
4107//-- destl = newTemp(cb);
4108//-- desth = newTemp(cb);
4109//-- junkl = newTemp(cb);
4110//-- junkh = newTemp(cb);
4111//--
4112//-- vg_assert(!epartIsReg(rm));
4113//--
4114//-- pair = disAMode ( cb, sorb, eip0, dis_buf );
4115//-- tal = LOW24(pair);
4116//-- tah = newTemp(cb);
4117//-- uInstr2(cb, MOV, 4, TempReg, tal, TempReg, tah);
4118//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, tah);
4119//-- uLiteral(cb, 4);
4120//-- eip0 += HI8(pair);
4121//-- DIP("cmpxchg8b %s\n", dis_buf);
4122//--
4123//-- uInstr0(cb, CALLM_S, 0);
4124//--
4125//-- uInstr2(cb, LOAD, 4, TempReg, tah, TempReg, desth);
4126//-- uInstr1(cb, PUSH, 4, TempReg, desth);
4127//-- uInstr2(cb, LOAD, 4, TempReg, tal, TempReg, destl);
4128//-- uInstr1(cb, PUSH, 4, TempReg, destl);
4129//-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, srch);
4130//-- uInstr1(cb, PUSH, 4, TempReg, srch);
4131//-- uInstr2(cb, GET, 4, ArchReg, R_EBX, TempReg, srcl);
4132//-- uInstr1(cb, PUSH, 4, TempReg, srcl);
4133//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, acch);
4134//-- uInstr1(cb, PUSH, 4, TempReg, acch);
4135//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, accl);
4136//-- uInstr1(cb, PUSH, 4, TempReg, accl);
4137//--
4138//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_cmpxchg8b));
4139//-- uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsEmpty);
4140//--
4141//-- uInstr1(cb, POP, 4, TempReg, accl);
4142//-- uInstr2(cb, PUT, 4, TempReg, accl, ArchReg, R_EAX);
4143//-- uInstr1(cb, POP, 4, TempReg, acch);
4144//-- uInstr2(cb, PUT, 4, TempReg, acch, ArchReg, R_EDX);
4145//-- uInstr1(cb, POP, 4, TempReg, srcl);
4146//-- uInstr2(cb, PUT, 4, TempReg, srcl, ArchReg, R_EBX);
4147//-- uInstr1(cb, POP, 4, TempReg, srch);
4148//-- uInstr2(cb, PUT, 4, TempReg, srch, ArchReg, R_ECX);
4149//-- uInstr1(cb, POP, 4, TempReg, destl);
4150//-- uInstr2(cb, STORE, 4, TempReg, destl, TempReg, tal);
4151//-- uInstr1(cb, POP, 4, TempReg, desth);
4152//-- uInstr2(cb, STORE, 4, TempReg, desth, TempReg, tah);
4153//--
4154//-- uInstr0(cb, CALLM_E, 0);
4155//--
4156//-- return eip0;
4157//-- }
4158//--
4159//--
4160//-- /* Handle conditional move instructions of the form
4161//-- cmovcc E(reg-or-mem), G(reg)
4162//--
4163//-- E(src) is reg-or-mem
4164//-- G(dst) is reg.
4165//--
4166//-- If E is reg, --> GET %E, tmps
4167//-- GET %G, tmpd
4168//-- CMOVcc tmps, tmpd
4169//-- PUT tmpd, %G
4170//--
4171//-- If E is mem --> (getAddr E) -> tmpa
4172//-- LD (tmpa), tmps
4173//-- GET %G, tmpd
4174//-- CMOVcc tmps, tmpd
4175//-- PUT tmpd, %G
4176//-- */
4177//-- static
4178//-- Addr dis_cmov_E_G ( UCodeBlock* cb,
4179//-- UChar sorb,
4180//-- Int size,
4181//-- Condcode cond,
4182//-- Addr eip0 )
4183//-- {
4184//-- UChar rm = getUChar(eip0);
4185//-- UChar dis_buf[50];
4186//--
4187//-- Int tmps = newTemp(cb);
4188//-- Int tmpd = newTemp(cb);
4189//--
4190//-- if (epartIsReg(rm)) {
4191//-- uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, tmps);
4192//-- uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmpd);
4193//-- uInstr2(cb, CMOV, 4, TempReg, tmps, TempReg, tmpd);
4194//-- uCond(cb, cond);
4195//-- uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
4196//-- uInstr2(cb, PUT, size, TempReg, tmpd, ArchReg, gregOfRM(rm));
4197//-- DIP("cmov%c%s %s,%s\n", nameISize(size),
4198//-- VG_(name_UCondcode)(cond),
4199//-- nameIReg(size,eregOfRM(rm)),
4200//-- nameIReg(size,gregOfRM(rm)));
4201//-- return 1+eip0;
4202//-- }
4203//--
4204//-- /* E refers to memory */
4205//-- {
4206//-- UInt pair = disAMode ( cb, sorb, eip0, dis_buf );
4207//-- Int tmpa = LOW24(pair);
4208//-- uInstr2(cb, LOAD, size, TempReg, tmpa, TempReg, tmps);
4209//-- uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmpd);
4210//-- uInstr2(cb, CMOV, 4, TempReg, tmps, TempReg, tmpd);
4211//-- uCond(cb, cond);
4212//-- uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
4213//-- uInstr2(cb, PUT, size, TempReg, tmpd, ArchReg, gregOfRM(rm));
4214//-- DIP("cmov%c%s %s,%s\n", nameISize(size),
4215//-- VG_(name_UCondcode)(cond),
4216//-- dis_buf,
4217//-- nameIReg(size,gregOfRM(rm)));
4218//-- return HI8(pair)+eip0;
4219//-- }
4220//-- }
4221//--
4222//--
4223//-- static
4224//-- Addr dis_xadd_G_E ( UCodeBlock* cb,
4225//-- UChar sorb,
4226//-- Int sz,
4227//-- Addr eip0 )
4228//-- {
4229//-- UChar rm = getUChar(eip0);
4230//-- UChar dis_buf[50];
4231//--
4232//-- Int tmpd = newTemp(cb);
4233//-- Int tmpt = newTemp(cb);
4234//--
4235//-- if (epartIsReg(rm)) {
4236//-- uInstr2(cb, GET, sz, ArchReg, eregOfRM(rm), TempReg, tmpd);
4237//-- uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
4238//-- uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
4239//-- setFlagsFromUOpcode(cb, ADD);
4240//-- uInstr2(cb, PUT, sz, TempReg, tmpt, ArchReg, eregOfRM(rm));
4241//-- uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
4242//-- DIP("xadd%c %s, %s\n",
4243//-- nameISize(sz), nameIReg(sz,gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
4244//-- return 1+eip0;
4245//-- } else {
4246//-- UInt pair = disAMode ( cb, sorb, eip0, dis_buf );
4247//-- Int tmpa = LOW24(pair);
4248//-- uInstr2(cb, LOAD, sz, TempReg, tmpa, TempReg, tmpd);
4249//-- uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
4250//-- uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
4251//-- setFlagsFromUOpcode(cb, ADD);
4252//-- uInstr2(cb, STORE, sz, TempReg, tmpt, TempReg, tmpa);
4253//-- uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
4254//-- DIP("xadd%c %s, %s\n",
4255//-- nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
4256//-- return HI8(pair)+eip0;
4257//-- }
4258//-- }
4259//--
4260//--
4261//-- /* Moves of Ew into a segment register.
4262//-- mov Ew, Sw meaning
4263//-- mov reg-or-mem, reg
4264//-- Is passed the a ptr to the modRM byte, and the data size. Returns
4265//-- the address advanced completely over this instruction.
4266//--
4267//-- Ew(src) is reg-or-mem
4268//-- Sw(dst) is seg reg.
4269//--
4270//-- If E is reg, --> GETw %Ew, tmpv
4271//-- PUTSEG tmpv, %Sw
4272//--
4273//-- If E is mem --> (getAddr E) -> tmpa
4274//-- LDw (tmpa), tmpb
4275//-- PUTSEG tmpb, %Sw
4276//-- */
4277//-- static
4278//-- Addr dis_mov_Ew_Sw ( UCodeBlock* cb,
4279//-- UChar sorb,
4280//-- Addr eip0 )
4281//-- {
4282//-- UChar rm = getUChar(eip0);
4283//-- UChar dis_buf[50];
4284//--
4285//-- if (epartIsReg(rm)) {
4286//-- Int tmpv = newTemp(cb);
4287//-- uInstr2(cb, GET, 2, ArchReg, eregOfRM(rm), TempReg, tmpv);
4288//-- uInstr2(cb, PUTSEG, 2, TempReg, tmpv, ArchRegS, gregOfRM(rm));
4289//-- DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
4290//-- return 1+eip0;
4291//-- }
4292//--
4293//-- /* E refers to memory */
4294//-- {
4295//-- UInt pair = disAMode ( cb, sorb, eip0, dis_buf );
4296//-- Int tmpa = LOW24(pair);
4297//-- Int tmpb = newTemp(cb);
4298//-- uInstr2(cb, LOAD, 2, TempReg, tmpa, TempReg, tmpb);
4299//-- uInstr2(cb, PUTSEG, 2, TempReg, tmpb, ArchRegS, gregOfRM(rm));
4300//-- DIP("movw %s,%s\n", dis_buf,nameSReg(gregOfRM(rm)));
4301//-- return HI8(pair)+eip0;
4302//-- }
4303//-- }
4304//--
4305//--
4306//-- /* Moves of a segment register to Ew.
4307//-- mov Sw, Ew meaning
4308//-- mov reg, reg-or-mem
4309//-- Is passed the a ptr to the modRM byte, and the data size. Returns
4310//-- the address advanced completely over this instruction.
4311//--
4312//-- Sw(src) is seg reg.
4313//-- Ew(dst) is reg-or-mem
4314//--
4315//-- If E is reg, --> GETSEG %Sw, tmp
4316//-- PUTW tmp, %Ew
4317//--
4318//-- If E is mem, --> (getAddr E) -> tmpa
4319//-- GETSEG %Sw, tmpv
4320//-- STW tmpv, (tmpa)
4321//-- */
4322//-- static
4323//-- Addr dis_mov_Sw_Ew ( UCodeBlock* cb,
4324//-- UChar sorb,
4325//-- Addr eip0 )
4326//-- {
4327//-- UChar rm = getUChar(eip0);
4328//-- UChar dis_buf[50];
4329//--
4330//-- if (epartIsReg(rm)) {
4331//-- Int tmpv = newTemp(cb);
4332//-- uInstr2(cb, GETSEG, 2, ArchRegS, gregOfRM(rm), TempReg, tmpv);
4333//-- uInstr2(cb, PUT, 2, TempReg, tmpv, ArchReg, eregOfRM(rm));
4334//-- DIP("movw %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(2,eregOfRM(rm)));
4335//-- return 1+eip0;
4336//-- }
4337//--
4338//-- /* E refers to memory */
4339//-- {
4340//-- UInt pair = disAMode ( cb, sorb, eip0, dis_buf );
4341//-- Int tmpa = LOW24(pair);
4342//-- Int tmpv = newTemp(cb);
4343//-- uInstr2(cb, GETSEG, 2, ArchRegS, gregOfRM(rm), TempReg, tmpv);
4344//-- uInstr2(cb, STORE, 2, TempReg, tmpv, TempReg, tmpa);
4345//-- DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
4346//-- return HI8(pair)+eip0;
4347//-- }
4348//-- }
4349//--
4350//--
4351//--
4352//-- /* Simple MMX operations, either
4353//-- op (src)mmxreg, (dst)mmxreg
4354//-- or
4355//-- op (src)address, (dst)mmxreg
4356//-- opc is the byte following the 0x0F prefix.
4357//-- */
4358//-- static
4359//-- Addr dis_MMXop_regmem_to_reg ( UCodeBlock* cb,
4360//-- UChar sorb,
4361//-- Addr eip,
4362//-- UChar opc,
4363//-- Char* name,
4364//-- Bool show_granularity )
4365//-- {
4366//-- Char dis_buf[50];
4367//-- UChar modrm = getUChar(eip);
4368//-- Bool isReg = epartIsReg(modrm);
4369//--
4370//-- if (isReg) {
4371//-- eip++;
4372//-- uInstr1(cb, MMX2, 0,
4373//-- Lit16,
4374//-- (((UShort)(opc)) << 8) | ((UShort)modrm) );
4375//-- } else {
4376//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
4377//-- Int tmpa = LOW24(pair);
4378//-- eip += HI8(pair);
4379//-- uInstr2(cb, MMX2_MemRd, 8,
4380//-- Lit16,
4381//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
4382//-- TempReg, tmpa);
4383//-- }
4384//--
4385//-- DIP("%s%s %s, %s\n",
4386//-- name, show_granularity ? nameMMXGran(opc & 3) : (Char*)"",
4387//-- ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
4388//-- nameMMXReg(gregOfRM(modrm)) );
4389//--
4390//-- return eip;
4391//-- }
4392//--
4393//--
4394//-- /* Simple MMX operations, either
4395//-- op (src)mmxreg, (dst)mmxreg
4396//-- or
4397//-- op (src)address, (dst)mmxreg
4398//-- opc is the byte following the 0x0F prefix.
4399//-- */
4400//-- static
4401//-- Addr dis_MMXop_regmem_to_reg_Imm8 ( UCodeBlock* cb,
4402//-- UChar sorb,
4403//-- Addr eip,
4404//-- UChar opc,
4405//-- Char* name,
4406//-- Bool show_granularity )
4407//-- {
4408//-- Char dis_buf[50];
4409//-- UChar modrm = getUChar(eip);
4410//-- UChar imm8;
4411//-- Bool isReg = epartIsReg(modrm);
4412//--
4413//-- if (isReg) {
4414//-- eip++;
4415//-- imm8 = getUChar(eip);
4416//-- eip++;
4417//-- uInstr2(cb, MMX3, 0,
4418//-- Lit16,
4419//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
4420//-- Lit16,
4421//-- ((UShort)imm8));
4422//-- } else {
4423//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
4424//-- Int tmpa = LOW24(pair);
4425//-- eip += HI8(pair);
4426//-- imm8 = getUChar(eip);
4427//-- eip++;
4428//-- uInstr3(cb, MMX2a1_MemRd, 8,
4429//-- Lit16,
4430//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
4431//-- Lit16,
4432//-- ((UShort)imm8),
4433//-- TempReg, tmpa);
4434//-- }
4435//--
4436//-- DIP("%s%s %s, %s, $%d\n",
4437//-- name, show_granularity ? nameMMXGran(opc & 3) : (Char*)"",
4438//-- ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
4439//-- nameMMXReg(gregOfRM(modrm)), (Int)imm8 );
4440//--
4441//-- return eip;
4442//-- }
4443//--
4444//--
4445//--
4446//-- /* Simple SSE operations, either
4447//-- op (src)xmmreg, (dst)xmmreg
4448//-- or
4449//-- op (src)address, (dst)xmmreg
4450//-- 3 opcode bytes.
4451//-- Supplied eip points to the first address mode byte.
4452//-- */
4453//-- static
4454//-- Addr dis_SSE3_reg_or_mem ( UCodeBlock* cb,
4455//-- UChar sorb,
sewardjbb53f8c2004-08-14 11:50:01 +00004456//-- Addr eip,
sewardjc9a65702004-07-07 16:32:57 +00004457//-- Int sz,
4458//-- Char* name,
4459//-- UChar opc1,
4460//-- UChar opc2,
4461//-- UChar opc3 )
4462//-- {
4463//-- Char dis_buf[50];
4464//-- UChar modrm = getUChar(eip);
4465//-- Bool isReg = epartIsReg(modrm);
4466//--
4467//-- if (isReg) {
4468//-- /* Completely internal SSE insn. */
4469//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
4470//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
4471//-- Lit16, (((UShort)opc3) << 8) | (UShort)modrm );
4472//-- eip++;
4473//-- } else {
4474//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
4475//-- Int tmpa = LOW24(pair);
4476//-- eip += HI8(pair);
4477//-- uInstr3(cb, SSE3a_MemRd, sz,
4478//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
4479//-- Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
4480//-- TempReg, tmpa);
4481//-- }
4482//--
4483//-- DIP("%s %s, %s\n",
4484//-- name,
4485//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
4486//-- nameXMMReg(gregOfRM(modrm)) );
4487//--
4488//-- return eip;
4489//-- }
4490//--
4491//--
4492//-- /* Simple SSE operations, either
4493//-- op (src)xmmreg, (dst)xmmreg
4494//-- or
4495//-- op (src)address, (dst)xmmreg
4496//-- 2 opcode bytes.
4497//-- Supplied eip points to the first address mode byte.
4498//-- */
4499//-- static
4500//-- Addr dis_SSE2_reg_or_mem ( UCodeBlock* cb,
4501//-- UChar sorb,
4502//-- Addr eip,
4503//-- Int sz,
4504//-- Char* name,
4505//-- UChar opc1,
4506//-- UChar opc2 )
4507//-- {
4508//-- Char dis_buf[50];
4509//-- UChar modrm = getUChar(eip);
4510//-- Bool isReg = epartIsReg(modrm);
4511//--
4512//-- if (isReg) {
4513//-- /* Completely internal SSE insn. */
4514//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
4515//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
4516//-- Lit16, (UShort)modrm );
4517//-- eip++;
4518//-- } else {
4519//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
4520//-- Int tmpa = LOW24(pair);
4521//-- eip += HI8(pair);
4522//-- uInstr3(cb, SSE2a_MemRd, sz,
4523//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
4524//-- Lit16, (UShort)modrm,
4525//-- TempReg, tmpa);
4526//-- }
4527//-- DIP("%s %s, %s\n",
4528//-- name,
4529//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
4530//-- nameXMMReg(gregOfRM(modrm)) );
4531//--
4532//-- return eip;
4533//-- }
4534//--
4535//--
4536//-- /* Simple SSE operations, either
4537//-- op (src)xmmreg, (dst)xmmreg
4538//-- or
4539//-- op (src)address, (dst)xmmreg
4540//-- 2 opcode bytes and an 8-bit immediate after the amode.
4541//-- Supplied eip points to the first address mode byte.
4542//-- */
4543//-- static
4544//-- Addr dis_SSE2_reg_or_mem_Imm8 ( UCodeBlock* cb,
4545//-- UChar sorb,
4546//-- Addr eip,
4547//-- Int sz,
4548//-- Char* name,
4549//-- UChar opc1,
4550//-- UChar opc2 )
4551//-- {
4552//-- Char dis_buf[50];
4553//-- UChar modrm = getUChar(eip);
4554//-- UChar imm8;
4555//-- Bool isReg = epartIsReg(modrm);
4556//--
4557//-- if (isReg) {
4558//-- /* Completely internal SSE insn. */
4559//-- eip++;
4560//-- imm8 = getUChar(eip);
4561//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
4562//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
4563//-- Lit16, (((UShort)modrm) << 8) | (UShort)imm8 );
4564//-- eip++;
4565//-- } else {
4566//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
4567//-- Int tmpa = LOW24(pair);
4568//-- eip += HI8(pair);
4569//-- imm8 = getUChar(eip);
4570//-- eip++;
4571//-- uInstr3(cb, SSE2a1_MemRd, sz,
4572//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
4573//-- Lit16, (((UShort)(modrm)) << 8) | ((UShort)imm8),
4574//-- TempReg, tmpa);
4575//-- }
4576//-- DIP("%s %s, %s, $%d\n",
4577//-- name, ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
4578//-- nameXMMReg(gregOfRM(modrm)), (Int)imm8 );
4579//-- return eip;
4580//-- }
4581//--
4582//--
4583//-- /* Simple SSE operations, either
4584//-- op (src)xmmreg, (dst)xmmreg
4585//-- or
4586//-- op (src)address, (dst)xmmreg
4587//-- 3 opcode bytes and an 8-bit immediate after the amode.
4588//-- Supplied eip points to the first address mode byte.
4589//-- */
4590//-- static
4591//-- Addr dis_SSE3_reg_or_mem_Imm8 ( UCodeBlock* cb,
4592//-- UChar sorb,
4593//-- Addr eip,
4594//-- Int sz,
4595//-- Char* name,
4596//-- UChar opc1,
4597//-- UChar opc2,
4598//-- UChar opc3 )
4599//-- {
4600//-- Char dis_buf[50];
4601//-- UChar modrm = getUChar(eip);
4602//-- UChar imm8;
4603//-- Bool isReg = epartIsReg(modrm);
4604//--
4605//-- if (isReg) {
4606//-- /* Completely internal SSE insn. */
4607//-- eip++;
4608//-- imm8 = getUChar(eip);
4609//-- uInstr3(cb, SSE5, 0, /* ignore sz for internal ops */
4610//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
4611//-- Lit16, (((UShort)opc3) << 8) | (UShort)modrm,
4612//-- Lit16, (UShort)imm8 );
4613//-- eip++;
4614//-- } else {
4615//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
4616//-- Int tmpa = LOW24(pair);
4617//-- eip += HI8(pair);
4618//-- imm8 = getUChar(eip);
4619//-- eip++;
4620//-- uInstr3(cb, SSE3a1_MemRd, sz,
4621//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
4622//-- Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
4623//-- TempReg, tmpa);
4624//-- uLiteral(cb, imm8);
4625//-- }
4626//-- DIP("%s %s, %s, $%d\n",
4627//-- name, ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
4628//-- nameXMMReg(gregOfRM(modrm)), (Int)imm8 );
4629//-- return eip;
4630//-- }
4631//--
4632//--
4633//-- /* Disassemble an SSE insn which is either a simple reg-reg move or a
4634//-- move between registers and memory. Supplied eip points to the
4635//-- first address mode byte.
4636//-- */
4637//-- static
4638//-- Addr dis_SSE3_load_store_or_mov ( UCodeBlock* cb,
4639//-- UChar sorb,
4640//-- Addr eip,
4641//-- Int sz,
4642//-- Bool is_store,
4643//-- Char* name,
4644//-- UChar insn0,
4645//-- UChar insn1,
4646//-- UChar insn2 )
4647//-- {
4648//-- Char dis_buf[50];
4649//-- UChar modrm = getUChar(eip);
4650//-- Bool isReg = epartIsReg(modrm);
4651//-- UInt pair;
4652//-- Int t1;
4653//--
4654//-- if (isReg) {
4655//-- /* Completely internal; we can issue SSE4. */
4656//-- eip++;
4657//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
4658//-- Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
4659//-- Lit16, (((UShort)insn2) << 8) | (UShort)modrm );
4660//-- } else {
4661//-- pair = disAMode ( cb, sorb, eip, dis_buf );
4662//-- t1 = LOW24(pair);
4663//-- eip += HI8(pair);
4664//-- uInstr3(cb, is_store ? SSE3a_MemWr : SSE3a_MemRd, sz,
4665//-- Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
4666//-- Lit16, (((UShort)insn2) << 8) | (UShort)modrm,
4667//-- TempReg, t1 );
4668//-- }
4669//--
4670//-- if (is_store) {
4671//-- DIP("%s %s, %s\n",
4672//-- name,
4673//-- nameXMMReg(gregOfRM(modrm)),
4674//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ) );
4675//-- } else {
4676//-- DIP("%s %s, %s\n",
4677//-- name,
4678//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
4679//-- nameXMMReg(gregOfRM(modrm)) );
4680//-- }
4681//-- return eip;
4682//-- }
4683//--
4684//--
4685//-- /* Disassemble an SSE insn which is either a simple reg-reg move or a
4686//-- move between registers and memory. Supplied eip points to the
4687//-- first address mode byte. */
4688//-- static
4689//-- Addr dis_SSE2_load_store_or_mov ( UCodeBlock* cb,
4690//-- UChar sorb,
4691//-- Addr eip,
4692//-- Int sz,
4693//-- Bool is_store,
4694//-- Char* name,
4695//-- UChar insn0,
4696//-- UChar insn1 )
4697//-- {
4698//-- Char dis_buf[50];
4699//-- UChar modrm = getUChar(eip);
4700//-- Bool isReg = epartIsReg(modrm);
4701//-- UInt pair;
4702//-- Int t1;
4703//--
4704//-- if (isReg) {
4705//-- /* Completely internal; we can issue SSE3. */
4706//-- eip++;
4707//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
4708//-- Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
4709//-- Lit16, (UShort)modrm );
4710//-- } else {
4711//-- pair = disAMode ( cb, sorb, eip, dis_buf );
4712//-- t1 = LOW24(pair);
4713//-- eip += HI8(pair);
4714//-- uInstr3(cb, is_store ? SSE2a_MemWr : SSE2a_MemRd, sz,
4715//-- Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
4716//-- Lit16, (UShort)modrm,
4717//-- TempReg, t1 );
4718//-- }
4719//--
4720//-- if (is_store) {
4721//-- DIP("%s %s, %s\n",
4722//-- name,
4723//-- nameXMMReg(gregOfRM(modrm)),
4724//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ) );
4725//-- } else {
4726//-- DIP("%s %s, %s\n",
4727//-- name,
4728//-- ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
4729//-- nameXMMReg(gregOfRM(modrm)) );
4730//-- }
4731//-- return eip;
4732//-- }
4733//--
4734//--
4735//-- /* Simple SSE operations, either
4736//-- op (src)xmmreg, (dst)mmxreg
4737//-- or
4738//-- op (src)address, (dst)mmxreg
4739//-- 2 opcode bytes.
4740//-- Supplied eip points to the first address mode byte.
4741//-- */
4742//-- static
4743//-- Addr dis_SSE2_to_MMX ( UCodeBlock *cb,
4744//-- UChar sorb,
4745//-- Addr eip,
4746//-- Int sz,
4747//-- Char* name,
4748//-- UChar opc1,
4749//-- UChar opc2 )
4750//-- {
4751//-- UChar dis_buf[50];
4752//-- UChar modrm = getUChar(eip);
4753//-- if (epartIsReg(modrm)) {
4754//-- /* Completely internal SSE insn. */
4755//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
4756//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
4757//-- Lit16, (UShort)modrm );
4758//-- DIP("%s %s, %s\n",
4759//-- name, nameXMMReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)) );
4760//-- eip++;
4761//-- } else {
4762//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
4763//-- Int tmpa = LOW24(pair);
4764//-- eip += HI8(pair);
4765//-- uInstr3(cb, SSE2a_MemRd, sz,
4766//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
4767//-- Lit16, ((UShort)modrm),
4768//-- TempReg, tmpa);
4769//-- DIP("%s %s, %s\n", name, dis_buf, nameMMXReg(gregOfRM(modrm)));
4770//-- }
4771//-- return eip;
4772//-- }
4773//--
4774//--
4775//-- /* Simple SSE operations, either
4776//-- op (src)mmxreg, (dst)xmmreg
4777//-- or
4778//-- op (src)address, (dst)xmmreg
4779//-- 2 opcode bytes.
4780//-- Supplied eip points to the first address mode byte.
4781//-- */
4782//-- static
4783//-- Addr dis_SSE2_from_MMX ( UCodeBlock *cb,
4784//-- UChar sorb,
4785//-- Addr eip,
4786//-- Int sz,
4787//-- Char* name,
4788//-- UChar opc1,
4789//-- UChar opc2 )
4790//-- {
4791//-- UChar dis_buf[50];
4792//-- UChar modrm = getUChar(eip);
4793//-- if (epartIsReg(modrm)) {
4794//-- /* Completely internal SSE insn. */
4795//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
4796//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
4797//-- Lit16, (UShort)modrm );
4798//-- DIP("%s %s, %s\n",
4799//-- name, nameMMXReg(eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)) );
4800//-- eip++;
4801//-- } else {
4802//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
4803//-- Int tmpa = LOW24(pair);
4804//-- eip += HI8(pair);
4805//-- uInstr3(cb, SSE2a_MemRd, sz,
4806//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
4807//-- Lit16, ((UShort)modrm),
4808//-- TempReg, tmpa);
4809//-- DIP("%s %s, %s\n", name, dis_buf, nameXMMReg(gregOfRM(modrm)));
4810//-- }
4811//-- return eip;
4812//-- }
4813//--
4814//--
4815//-- /* Simple SSE operations, either
4816//-- op (src)xmmreg, (dst)mmxreg
4817//-- or
4818//-- op (src)address, (dst)mmxreg
4819//-- 3 opcode bytes.
4820//-- Supplied eip points to the first address mode byte.
4821//-- */
4822//-- static
4823//-- Addr dis_SSE3_to_MMX ( UCodeBlock *cb,
4824//-- UChar sorb,
4825//-- Addr eip,
4826//-- Int sz,
4827//-- Char* name,
4828//-- UChar opc1,
4829//-- UChar opc2,
4830//-- UChar opc3 )
4831//-- {
4832//-- UChar dis_buf[50];
4833//-- UChar modrm = getUChar(eip);
4834//-- if (epartIsReg(modrm)) {
4835//-- /* Completely internal SSE insn. */
4836//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
4837//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
4838//-- Lit16, (((UShort)opc3) << 8) | (UShort)modrm );
4839//-- DIP("%s %s, %s\n",
4840//-- name, nameXMMReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)) );
4841//-- eip++;
4842//-- } else {
4843//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
4844//-- Int tmpa = LOW24(pair);
4845//-- eip += HI8(pair);
4846//-- uInstr3(cb, SSE3a_MemRd, sz,
4847//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
4848//-- Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
4849//-- TempReg, tmpa);
4850//-- DIP("%s %s, %s\n", name, dis_buf, nameMMXReg(gregOfRM(modrm)));
4851//-- }
4852//-- return eip;
4853//-- }
4854//--
4855//--
4856//-- /* Simple SSE operations, either
4857//-- op (src)mmxreg, (dst)xmmreg
4858//-- or
4859//-- op (src)address, (dst)xmmreg
4860//-- 3 opcode bytes.
4861//-- Supplied eip points to the first address mode byte.
4862//-- */
4863//-- static
4864//-- Addr dis_SSE3_from_MMX ( UCodeBlock *cb,
4865//-- UChar sorb,
4866//-- Addr eip,
4867//-- Int sz,
4868//-- Char* name,
4869//-- UChar opc1,
4870//-- UChar opc2,
4871//-- UChar opc3 )
4872//-- {
4873//-- UChar dis_buf[50];
4874//-- UChar modrm = getUChar(eip);
4875//-- if (epartIsReg(modrm)) {
4876//-- /* Completely internal SSE insn. */
4877//-- uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
4878//-- Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
4879//-- Lit16, (((UShort)opc3) << 8) | (UShort)modrm );
4880//-- DIP("%s %s, %s\n",
4881//-- name, nameMMXReg(eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)) );
4882//-- eip++;
4883//-- } else {
4884//-- UInt pair = disAMode ( cb, sorb, eip, dis_buf );
4885//-- Int tmpa = LOW24(pair);
4886//-- eip += HI8(pair);
4887//-- uInstr3(cb, SSE3a_MemRd, sz,
4888//-- Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
4889//-- Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
4890//-- TempReg, tmpa);
4891//-- DIP("%s %s, %s\n", name, dis_buf, nameXMMReg(gregOfRM(modrm)));
4892//-- }
4893//-- return eip;
4894//-- }
4895//--
4896//--
4897//-- static
4898//-- void dis_push_segreg ( UCodeBlock* cb, UInt sreg, Int sz )
4899//-- {
4900//-- Int t1 = newTemp(cb), t2 = newTemp(cb);
4901//-- vg_assert(sz == 2 || sz == 4);
4902//-- uInstr2(cb, GETSEG, 2, ArchRegS, sreg, TempReg, t1);
4903//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
4904//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
4905//-- uLiteral(cb, sz);
4906//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
4907//-- uInstr2(cb, STORE, 2, TempReg, t1, TempReg, t2);
4908//-- DIP("push %s\n", VG_(name_of_seg_reg)(sreg));
4909//-- }
4910//--
4911//-- static
4912//-- void dis_pop_segreg ( UCodeBlock* cb, UInt sreg, Int sz )
4913//-- {
4914//-- Int t1 = newTemp(cb), t2 = newTemp(cb);
4915//-- vg_assert(sz == 2 || sz == 4);
4916//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
4917//-- uInstr2(cb, LOAD, 2, TempReg, t2, TempReg, t1);
4918//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
4919//-- uLiteral(cb, sz);
4920//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
4921//-- uInstr2(cb, PUTSEG, 2, TempReg, t1, ArchRegS, sreg);
4922//-- DIP("pop %s\n", VG_(name_of_seg_reg)(sreg));
4923//-- }
sewardje05c42c2004-07-08 20:25:10 +00004924
4925static
4926void dis_ret ( UInt d32 )
4927{
4928 IRTemp t1 = newTemp(Ity_I32), t2 = newTemp(Ity_I32);
4929 assign(t1, getIReg(4,R_ESP));
4930 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
4931 putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(4+d32)));
sewardj78c19df2004-07-12 22:49:27 +00004932 jmp_treg(Ijk_Ret,t2);
sewardje05c42c2004-07-08 20:25:10 +00004933}
4934
sewardjc9a65702004-07-07 16:32:57 +00004935
4936/*------------------------------------------------------------*/
4937/*--- Disassembling entire basic blocks ---*/
4938/*------------------------------------------------------------*/
4939
4940/* Disassemble a single instruction into IR, returning the updated
4941 delta, and setting *isEnd to True if this is the last insn in a
4942 basic block. Also do debug printing if necessary. */
4943
4944static UInt disInstr ( UInt delta, Bool* isEnd )
4945{
sewardj0c12ea82004-07-12 08:18:16 +00004946 IRType ty;
4947 IRTemp addr, t1, t2;
sewardje87b4842004-07-10 12:23:30 +00004948 Int alen;
sewardj64e1d652004-07-12 14:00:46 +00004949 UChar opc, modrm, abyte;
4950 UInt d32;
sewardje87b4842004-07-10 12:23:30 +00004951 UChar dis_buf[50];
4952 Int am_sz, d_sz;
sewardjc9a65702004-07-07 16:32:57 +00004953 //Char loc_buf[M_VG_ERRTXT];
4954
4955 /* Holds eip at the start of the insn, so that we can print
4956 consistent error messages for unimplemented insns. */
4957 UInt delta_start = delta;
4958
4959 /* sz denotes the nominal data-op size of the insn; we change it to
4960 2 if an 0x66 prefix is seen */
4961 Int sz = 4;
4962
4963 /* sorb holds the segment-override-prefix byte, if any. Zero if no
4964 prefix has been seen, else one of {0x26, 0x3E, 0x64, 0x65}
4965 indicating the prefix. */
4966 UChar sorb = 0;
4967
4968 /* For printing the stmts after each insn. */
sewardjd7cb8532004-08-17 23:59:23 +00004969 Int first_stmt_idx = irbb->stmts_used;
sewardjc9a65702004-07-07 16:32:57 +00004970
4971 *isEnd = False;
sewardj940e8c92004-07-11 16:53:24 +00004972 addr = t1 = t2 = INVALID_IRTEMP;
sewardj41f43bc2004-07-08 14:23:22 +00004973 //t3 = t4 = INVALID_IRTEMP;
sewardjc9a65702004-07-07 16:32:57 +00004974
4975 DIP("\t0x%x: ", guest_eip+delta);
4976
sewardj750f4072004-07-26 22:39:11 +00004977 /* Spot the client-request magic sequence. */
4978 {
4979 UChar* code = (UChar*)(guest_code + delta);
4980 /* Spot this:
4981 C1C01D roll $29, %eax
4982 C1C003 roll $3, %eax
4983 C1C81B rorl $27, %eax
4984 C1C805 rorl $5, %eax
4985 C1C00D roll $13, %eax
4986 C1C013 roll $19, %eax
4987 */
4988 if (code[ 0] == 0xC1 && code[ 1] == 0xC0 && code[ 2] == 0x1D &&
4989 code[ 3] == 0xC1 && code[ 4] == 0xC0 && code[ 5] == 0x03 &&
4990 code[ 6] == 0xC1 && code[ 7] == 0xC8 && code[ 8] == 0x1B &&
4991 code[ 9] == 0xC1 && code[10] == 0xC8 && code[11] == 0x05 &&
4992 code[12] == 0xC1 && code[13] == 0xC0 && code[14] == 0x0D &&
4993 code[15] == 0xC1 && code[16] == 0xC0 && code[17] == 0x13
4994 ) {
4995 delta += 18;
4996 jmp_lit(Ijk_ClientReq, guest_eip+delta);
4997 *isEnd = True;
4998 DIP("%%edx = client_request ( %%eax )\n");
4999 return delta;
5000 }
5001 }
sewardjc9a65702004-07-07 16:32:57 +00005002
5003 /* Skip a LOCK prefix. */
5004 if (getIByte(delta) == 0xF0) {
5005 /* VG_(printf)("LOCK LOCK LOCK LOCK LOCK \n"); */
5006 vpanic("x86 LOCK. what to do?");
5007 delta++;
5008 }
5009
5010 /* Detect operand-size overrides. */
5011 if (getIByte(delta) == 0x66) { sz = 2; delta++; };
5012
5013 /* segment override prefixes come after the operand-size override,
5014 it seems */
5015 switch (getIByte(delta)) {
5016 case 0x3E: /* %DS: */
5017 case 0x26: /* %ES: */
5018 case 0x64: /* %FS: */
5019 case 0x65: /* %GS: */
5020 sorb = getIByte(delta); delta++;
5021 break;
5022 case 0x2E: /* %CS: */
5023 /* 2E prefix on a conditional branch instruction is a
5024 branch-prediction hint, which can safely be ignored. */
5025 {
5026 UChar op1 = getIByte(delta+1);
5027 UChar op2 = getIByte(delta+2);
5028 if ((op1 >= 0x70 && op1 <= 0x7F)
5029 || (op1 == 0xE3)
5030 || (op1 == 0x0F && op2 >= 0x80 && op2 <= 0x8F)) {
5031 sorb = getIByte(delta); delta++;
5032 break;
5033 }
5034 }
5035 unimplemented("x86 segment override (SEG=CS) prefix");
5036 /*NOTREACHED*/
5037 break;
5038 case 0x36: /* %SS: */
5039 unimplemented("x86 segment override (SEG=SS) prefix");
5040 /*NOTREACHED*/
5041 break;
5042 default:
5043 break;
5044 }
5045
5046//-- /* ---------------------------------------------------- */
5047//-- /* --- The SSE/SSE2 decoder. --- */
5048//-- /* ---------------------------------------------------- */
5049//--
5050//-- /* If it looks like this CPU might support SSE, try decoding SSE
5051//-- insns. */
5052//-- if (VG_(have_ssestate)) {
5053//-- UChar* insn = (UChar*)eip;
5054//--
5055//-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
5056//-- if (insn[0] == 0x0F && insn[1] == 0xAE
5057//-- && (!epartIsReg(insn[2]))
5058//-- && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
5059//-- Bool store = gregOfRM(insn[2]) == 0;
5060//-- vg_assert(sz == 4);
5061//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
5062//-- t1 = LOW24(pair);
5063//-- eip += 2+HI8(pair);
5064//-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
5065//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
5066//-- Lit16, (UShort)insn[2],
5067//-- TempReg, t1 );
5068//-- DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
5069//-- goto decode_success;
5070//-- }
5071//--
5072//-- /* STMXCSR/LDMXCSR m32 -- load/store the MXCSR register. */
5073//-- if (insn[0] == 0x0F && insn[1] == 0xAE
5074//-- && (!epartIsReg(insn[2]))
5075//-- && (gregOfRM(insn[2]) == 3 || gregOfRM(insn[2]) == 2) ) {
5076//-- Bool store = gregOfRM(insn[2]) == 3;
5077//-- vg_assert(sz == 4);
5078//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
5079//-- t1 = LOW24(pair);
5080//-- eip += 2+HI8(pair);
5081//-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 4,
5082//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
5083//-- Lit16, (UShort)insn[2],
5084//-- TempReg, t1 );
5085//-- DIP("%smxcsr %s\n", store ? "st" : "ld", dis_buf );
5086//-- goto decode_success;
5087//-- }
5088//--
5089//-- /* LFENCE/MFENCE/SFENCE -- flush pending operations to memory */
5090//-- if (insn[0] == 0x0F && insn[1] == 0xAE
5091//-- && (epartIsReg(insn[2]))
5092//-- && (gregOfRM(insn[2]) >= 5 && gregOfRM(insn[2]) <= 7))
5093//-- {
5094//-- vg_assert(sz == 4);
5095//-- eip += 3;
5096//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
5097//-- Lit16, (((UShort)0x0F) << 8) | (UShort)0xAE,
5098//-- Lit16, (UShort)insn[2] );
5099//-- DIP("sfence\n");
5100//-- goto decode_success;
5101//-- }
5102//--
5103//-- /* CLFLUSH -- flush cache line */
5104//-- if (insn[0] == 0x0F && insn[1] == 0xAE
5105//-- && (!epartIsReg(insn[2]))
5106//-- && (gregOfRM(insn[2]) == 7))
5107//-- {
5108//-- vg_assert(sz == 4);
5109//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
5110//-- t1 = LOW24(pair);
5111//-- eip += 2+HI8(pair);
5112//-- uInstr3(cb, SSE2a_MemRd, 0, /* ignore sz for internal ops */
5113//-- Lit16, (((UShort)0x0F) << 8) | (UShort)0xAE,
5114//-- Lit16, (UShort)insn[2],
5115//-- TempReg, t1 );
5116//-- DIP("clflush %s\n", dis_buf);
5117//-- goto decode_success;
5118//-- }
5119//--
5120//-- /* CVTPI2PS (0x0F,0x2A) -- mm/m64, xmm */
5121//-- /* CVTPI2PD (0x66,0x0F,0x2A) -- mm/m64, xmm */
5122//-- if (insn[0] == 0x0F && insn[1] == 0x2A) {
5123//-- if (sz == 4) {
5124//-- eip = dis_SSE2_from_MMX
5125//-- ( cb, sorb, eip+2, 8, "cvtpi2ps",
5126//-- insn[0], insn[1] );
5127//-- } else {
5128//-- eip = dis_SSE3_from_MMX
5129//-- ( cb, sorb, eip+2, 8, "cvtpi2pd",
5130//-- 0x66, insn[0], insn[1] );
5131//-- }
5132//-- goto decode_success;
5133//-- }
5134//--
5135//-- /* CVTTPS2PI (0x0F,0x2C) -- xmm/m64, mm */
5136//-- /* CVTPS2PI (0x0F,0x2D) -- xmm/m64, mm */
5137//-- /* CVTTPD2PI (0x66,0x0F,0x2C) -- xmm/m128, mm */
5138//-- /* CVTPD2PI (0x66,0x0F,0x2D) -- xmm/m128, mm */
5139//-- if (insn[0] == 0x0F
5140//-- && (insn[1] == 0x2C || insn[1] == 0x2D)) {
5141//-- if (sz == 4) {
5142//-- eip = dis_SSE2_to_MMX
5143//-- ( cb, sorb, eip+2, 8, "cvt{t}ps2pi",
5144//-- insn[0], insn[1] );
5145//-- } else {
5146//-- eip = dis_SSE3_to_MMX
5147//-- ( cb, sorb, eip+2, 16, "cvt{t}pd2pi",
5148//-- 0x66, insn[0], insn[1] );
5149//-- }
5150//-- goto decode_success;
5151//-- }
5152//--
5153//-- /* CVTTSD2SI (0xF2,0x0F,0x2C) -- convert a double-precision float
5154//-- value in memory or xmm reg to int and put it in an ireg.
5155//-- Truncate. */
5156//-- /* CVTTSS2SI (0xF3,0x0F,0x2C) -- convert a single-precision float
5157//-- value in memory or xmm reg to int and put it in an ireg.
5158//-- Truncate. */
5159//-- /* CVTSD2SI (0xF2,0x0F,0x2D) -- convert a double-precision float
5160//-- value in memory or xmm reg to int and put it in an ireg. Round
5161//-- as per MXCSR. */
5162//-- /* CVTSS2SI (0xF3,0x0F,0x2D) -- convert a single-precision float
5163//-- value in memory or xmm reg to int and put it in an ireg. Round
5164//-- as per MXCSR. */
5165//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
5166//-- && insn[1] == 0x0F
5167//-- && (insn[2] == 0x2C || insn[2] == 0x2D)) {
5168//-- vg_assert(sz == 4);
5169//-- modrm = insn[3];
5170//-- if (epartIsReg(modrm)) {
5171//-- /* We're moving a value in an xmm reg to an ireg. */
5172//-- eip += 4;
5173//-- t1 = newTemp(cb);
5174//-- /* sz is 4 for all 4 insns. */
5175//-- vg_assert(epartIsReg(modrm));
5176//-- uInstr3(cb, SSE3g_RegWr, 4,
5177//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
5178//-- Lit16, (((UShort)insn[2]) << 8) | (UShort)modrm,
5179//-- TempReg, t1 );
5180//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
5181//-- DIP("cvt{t}s{s,d}2si %s, %s\n",
5182//-- nameXMMReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)) );
5183//-- } else {
5184//-- /* So, we're reading memory and writing an ireg. This calls
5185//-- for the ultra-horrible SSE3ag_MemRd_RegWr uinstr. We
5186//-- can't do it in a roundabout route because it does some
5187//-- kind of conversion on the way, which we need to have
5188//-- happen too. So our only choice is to re-emit a suitably
5189//-- rehashed version of the instruction. */
5190//-- /* Destination ireg is GREG. Address goes as EREG as
5191//-- usual. */
5192//-- t1 = newTemp(cb); /* t1 holds value on its way to ireg */
5193//-- pair = disAMode ( cb, sorb, eip+3, dis_buf );
5194//-- t2 = LOW24(pair); /* t2 holds addr */
5195//-- eip += 3+HI8(pair);
5196//-- uInstr2(cb, SSE3ag_MemRd_RegWr, insn[0]==0xF2 ? 8 : 4,
5197//-- TempReg, t2, /* address */
5198//-- TempReg, t1 /* dest */);
5199//-- uLiteral(cb , (((UInt)insn[0]) << 24)
5200//-- | (((UInt)insn[1]) << 16)
5201//-- | (((UInt)insn[2]) << 8)
5202//-- | ((UInt)modrm) );
5203//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
5204//-- DIP("cvt{t}s{s,d}2si %s, %s\n",
5205//-- dis_buf, nameIReg(4,gregOfRM(modrm)) );
5206//-- }
5207//-- goto decode_success;
5208//-- }
5209//--
5210//-- /* CVTSI2SS -- convert int reg, or int value in memory, to low 4
5211//-- bytes of XMM reg. */
5212//-- /* CVTSI2SD -- convert int reg, or int value in memory, to low 8
5213//-- bytes of XMM reg. */
5214//-- if ((insn[0] == 0xF3 /*CVTSI2SS*/ || insn[0] == 0xF2 /* CVTSI2SD*/)
5215//-- && insn[1] == 0x0F && insn[2] == 0x2A) {
5216//-- Char* s_or_d = insn[0]==0xF3 ? "s" : "d";
5217//-- vg_assert(sz == 4);
5218//-- modrm = insn[3];
5219//-- t1 = newTemp(cb);
5220//-- if (epartIsReg(modrm)) {
5221//-- uInstr2(cb, GET, 4, ArchReg, eregOfRM(modrm), TempReg, t1);
5222//-- vg_assert(epartIsReg(modrm));
5223//-- uInstr3(cb, SSE3e_RegRd, 4,
5224//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
5225//-- Lit16, (((UShort)insn[2]) << 8) | (UShort)modrm,
5226//-- TempReg, t1 );
5227//-- eip += 4;
5228//-- DIP("cvtsi2s%s %s, %s\n", s_or_d,
5229//-- nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
5230//-- } else {
5231//-- pair = disAMode ( cb, sorb, eip+3, dis_buf );
5232//-- t2 = LOW24(pair);
5233//-- eip += 3+HI8(pair);
5234//-- uInstr3(cb, SSE3a_MemRd, 4,
5235//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
5236//-- Lit16, (((UShort)insn[2]) << 8) | (UShort)modrm,
5237//-- TempReg, t2 );
5238//-- DIP("cvtsi2s%s %s, %s\n",
5239//-- s_or_d, dis_buf, nameXMMReg(gregOfRM(modrm)));
5240//-- }
5241//-- goto decode_success;
5242//-- }
5243//--
5244//-- /* CVTPS2PD -- convert two packed floats to two packed doubles. */
5245//-- /* 0x66: CVTPD2PS -- convert two packed doubles to two packed floats. */
5246//-- if (insn[0] == 0x0F && insn[1] == 0x5A) {
5247//-- vg_assert(sz == 2 || sz == 4);
5248//-- if (sz == 4) {
5249//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 8, "cvtps2pd",
5250//-- insn[0], insn[1] );
5251//-- } else {
5252//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "cvtpd2ps",
5253//-- 0x66, insn[0], insn[1] );
5254//-- }
5255//-- goto decode_success;
5256//-- }
5257//--
5258//-- /* CVTSS2SD -- convert one single float to double. */
5259//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5A) {
5260//-- vg_assert(sz == 4);
5261//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4, "cvtss2sd",
5262//-- insn[0], insn[1], insn[2] );
5263//-- goto decode_success;
5264//-- }
5265//--
5266//-- /* CVTSD2SS -- convert one single double. to float. */
5267//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5A) {
5268//-- vg_assert(sz == 4);
5269//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8, "cvtsd2ss",
5270//-- insn[0], insn[1], insn[2] );
5271//-- goto decode_success;
5272//-- }
5273//--
5274//-- /* CVTDQ2PS -- convert four ints to four packed floats. */
5275//-- /* 0x66: CVTPS2DQ -- convert four packed floats to four ints. */
5276//-- if (insn[0] == 0x0F && insn[1] == 0x5B) {
5277//-- vg_assert(sz == 2 || sz == 4);
5278//-- if (sz == 4) {
5279//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "cvtdq2ps",
5280//-- insn[0], insn[1] );
5281//-- } else {
5282//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "cvtps2dq",
5283//-- 0x66, insn[0], insn[1] );
5284//-- }
5285//-- goto decode_success;
5286//-- }
5287//--
5288//-- /* CVTPD2DQ -- convert two packed doubles to two ints. */
5289//-- if (sz == 2
5290//-- && insn[0] == 0x0F && insn[1] == 0xE6) {
5291//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 8, "cvtpd2dq",
5292//-- 0x66, insn[0], insn[1] );
5293//-- goto decode_success;
5294//-- }
5295//--
5296//-- /* CVTTPD2DQ -- convert two packed doubles to two ints with truncation. */
5297//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xE6) {
5298//-- vg_assert(sz == 4);
5299//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8, "cvttpd2dq",
5300//-- insn[0], insn[1], insn[2] );
5301//-- goto decode_success;
5302//-- }
5303//--
5304//-- /* CVTDQ2PD -- convert two ints to two packed doubles. */
5305//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xE6) {
5306//-- vg_assert(sz == 4);
5307//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8, "cvtdq2pd",
5308//-- insn[0], insn[1], insn[2] );
5309//-- goto decode_success;
5310//-- }
5311//--
5312//-- /* CVTTPS2DQ -- convert four packed floats to four ints with truncation. */
5313//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5B) {
5314//-- vg_assert(sz == 4);
5315//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 16, "cvttps2dq",
5316//-- insn[0], insn[1], insn[2] );
5317//-- goto decode_success;
5318//-- }
5319//--
5320//-- /* CMPSS -- compare scalar floats. */
5321//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xC2) {
5322//-- vg_assert(sz == 4);
5323//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 8, "cmpss",
5324//-- insn[0], insn[1], insn[2] );
5325//-- goto decode_success;
5326//-- }
5327//--
5328//-- /* CMPSD -- compare scalar doubles. */
5329//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xC2) {
5330//-- vg_assert(sz == 4);
5331//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 8, "cmpsd",
5332//-- insn[0], insn[1], insn[2] );
5333//-- goto decode_success;
5334//-- }
5335//--
5336//-- /* sz==4: CMPPS -- compare packed floats */
5337//-- /* sz==2: CMPPD -- compare packed doubles */
5338//-- if (insn[0] == 0x0F && insn[1] == 0xC2) {
5339//-- vg_assert(sz == 4 || sz == 2);
5340//-- if (sz == 4) {
5341//-- eip = dis_SSE2_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "cmpps",
5342//-- insn[0], insn[1] );
5343//-- } else {
5344//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "cmppd",
5345//-- 0x66, insn[0], insn[1] );
5346//-- }
5347//-- goto decode_success;
5348//-- }
5349//--
5350//-- /* PSHUFD */
5351//-- if (sz == 2
5352//-- && insn[0] == 0x0F && insn[1] == 0x70) {
5353//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16,
5354//-- "pshufd",
5355//-- 0x66, insn[0], insn[1] );
5356//-- goto decode_success;
5357//-- }
5358//--
5359//-- /* PSHUFLW */
5360//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x70) {
5361//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 16,
5362//-- "pshuflw",
5363//-- insn[0], insn[1], insn[2] );
5364//-- goto decode_success;
5365//-- }
5366//--
5367//-- /* PSHUFHW */
5368//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x70) {
5369//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 16,
5370//-- "pshufhw",
5371//-- insn[0], insn[1], insn[2] );
5372//-- goto decode_success;
5373//-- }
5374//--
5375//-- /* SHUFPD */
5376//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC6) {
5377//-- eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "shufpd",
5378//-- 0x66, insn[0], insn[1] );
5379//-- goto decode_success;
5380//-- }
5381//--
5382//-- /* SHUFPS */
5383//-- if (insn[0] == 0x0F && insn[1] == 0xC6) {
5384//-- vg_assert(sz == 4);
5385//-- eip = dis_SSE2_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "shufps",
5386//-- insn[0], insn[1] );
5387//-- goto decode_success;
5388//-- }
5389//--
5390//-- /* 0xF2: MULSD */
5391//-- /* 0xF3: MULSS -- multiply low 4 bytes of XMM reg. */
5392//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
5393//-- && insn[1] == 0x0F && insn[2] == 0x59) {
5394//-- Bool sz8 = insn[0] == 0xF2;
5395//-- vg_assert(sz == 4);
5396//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
5397//-- sz8 ? "mulss" : "mulsd",
5398//-- insn[0], insn[1], insn[2] );
5399//-- goto decode_success;
5400//-- }
5401//--
5402//-- /* MULPS */
5403//-- /* 0x66: MULPD */
5404//-- if (insn[0] == 0x0F && insn[1] == 0x59) {
5405//-- vg_assert(sz == 4 || sz == 2);
5406//-- if (sz == 4) {
5407//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "mulps",
5408//-- insn[0], insn[1] );
5409//-- } else {
5410//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "mulpd",
5411//-- 0x66, insn[0], insn[1] );
5412//-- }
5413//-- goto decode_success;
5414//-- }
5415//--
5416//-- /* 0xF2: DIVSD */
5417//-- /* 0xF3: DIVSS -- divide low 4 bytes of XMM reg. */
5418//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
5419//-- && insn[1] == 0x0F && insn[2] == 0x5E) {
5420//-- Bool sz8 = insn[0] == 0xF2;
5421//-- vg_assert(sz == 4);
5422//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
5423//-- sz8 ? "divsd" : "divss",
5424//-- insn[0], insn[1], insn[2] );
5425//-- goto decode_success;
5426//-- }
5427//--
5428//-- /* DIVPS */
5429//-- /* 0x66: DIVPD */
5430//-- if (insn[0] == 0x0F && insn[1] == 0x5E) {
5431//-- vg_assert(sz == 4 || sz == 2);
5432//-- if (sz == 4) {
5433//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "divps",
5434//-- insn[0], insn[1] );
5435//-- } else {
5436//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "divpd",
5437//-- 0x66, insn[0], insn[1] );
5438//-- }
5439//-- goto decode_success;
5440//-- }
5441//--
5442//-- /* 0xF2: SUBSD */
5443//-- /* 0xF3: SUBSS */
5444//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
5445//-- && insn[1] == 0x0F && insn[2] == 0x5C) {
5446//-- Bool sz8 = insn[0] == 0xF2;
5447//-- vg_assert(sz == 4);
5448//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
5449//-- sz8 ? "subsd" : "subss",
5450//-- insn[0], insn[1], insn[2] );
5451//-- goto decode_success;
5452//-- }
5453//--
5454//-- /* SUBPS */
5455//-- /* 0x66: SUBPD */
5456//-- if (insn[0] == 0x0F && insn[1] == 0x5C) {
5457//-- vg_assert(sz == 4 || sz == 2);
5458//-- if (sz == 4) {
5459//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "subps",
5460//-- insn[0], insn[1] );
5461//-- } else {
5462//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "subpd",
5463//-- 0x66, insn[0], insn[1] );
5464//-- }
5465//-- goto decode_success;
5466//-- }
5467//--
5468//-- /* 0xF2: ADDSD */
5469//-- /* 0xF3: ADDSS */
5470//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
5471//-- && insn[1] == 0x0F && insn[2] == 0x58) {
5472//-- Bool sz8 = insn[0] == 0xF2;
5473//-- vg_assert(sz == 4);
5474//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
5475//-- sz8 ? "addsd" : "addss",
5476//-- insn[0], insn[1], insn[2] );
5477//-- goto decode_success;
5478//-- }
5479//--
5480//-- /* ADDPS */
5481//-- /* 0x66: ADDPD */
5482//-- if (insn[0] == 0x0F && insn[1] == 0x58) {
5483//-- vg_assert(sz == 4 || sz == 2);
5484//-- if (sz == 4) {
5485//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "addps",
5486//-- insn[0], insn[1] );
5487//-- } else {
5488//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "addpd",
5489//-- 0x66, insn[0], insn[1] );
5490//-- }
5491//-- goto decode_success;
5492//-- }
5493//--
5494//-- /* 0xF2: MINSD */
5495//-- /* 0xF3: MINSS */
5496//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
5497//-- && insn[1] == 0x0F && insn[2] == 0x5D) {
5498//-- Bool sz8 = insn[0] == 0xF2;
5499//-- vg_assert(sz == 4);
5500//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
5501//-- sz8 ? "minsd" : "minss",
5502//-- insn[0], insn[1], insn[2] );
5503//-- goto decode_success;
5504//-- }
5505//--
5506//-- /* MINPS */
5507//-- /* 0x66: MINPD */
5508//-- if (insn[0] == 0x0F && insn[1] == 0x5D) {
5509//-- vg_assert(sz == 4 || sz == 2);
5510//-- if (sz == 4) {
5511//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "minps",
5512//-- insn[0], insn[1] );
5513//-- } else {
5514//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "minpd",
5515//-- 0x66, insn[0], insn[1] );
5516//-- }
5517//-- goto decode_success;
5518//-- }
5519//--
5520//-- /* 0xF3: MAXSD */
5521//-- /* 0xF3: MAXSS */
5522//-- if ((insn[0] == 0xF2 || insn[0] == 0xF3)
5523//-- && insn[1] == 0x0F && insn[2] == 0x5F) {
5524//-- Bool sz8 = insn[0] == 0xF2;
5525//-- vg_assert(sz == 4);
5526//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
5527//-- sz8 ? "maxsd" : "maxss",
5528//-- insn[0], insn[1], insn[2] );
5529//-- goto decode_success;
5530//-- }
5531//--
5532//-- /* MAXPS */
5533//-- /* 0x66: MAXPD */
5534//-- if (insn[0] == 0x0F && insn[1] == 0x5F) {
5535//-- vg_assert(sz == 4 || sz == 2);
5536//-- if (sz == 4) {
5537//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "maxps",
5538//-- insn[0], insn[1] );
5539//-- } else {
5540//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "maxpd",
5541//-- 0x66, insn[0], insn[1] );
5542//-- }
5543//-- goto decode_success;
5544//-- }
5545//--
5546//-- /* RCPPS -- reciprocal of packed floats */
5547//-- if (insn[0] == 0x0F && insn[1] == 0x53) {
5548//-- vg_assert(sz == 4);
5549//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "rcpps",
5550//-- insn[0], insn[1] );
5551//-- goto decode_success;
5552//-- }
5553//--
5554//-- /* XORPS */
5555//-- /* 0x66: XORPD (src)xmmreg-or-mem, (dst)xmmreg */
5556//-- if (insn[0] == 0x0F && insn[1] == 0x57) {
5557//-- vg_assert(sz == 4 || sz == 2);
5558//-- if (sz == 4) {
5559//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "xorps",
5560//-- insn[0], insn[1] );
5561//-- } else {
5562//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "xorpd",
5563//-- 0x66, insn[0], insn[1] );
5564//-- }
5565//-- goto decode_success;
5566//-- }
5567//--
5568//-- /* ANDPS */
5569//-- /* 0x66: ANDPD (src)xmmreg-or-mem, (dst)xmmreg */
5570//-- if (insn[0] == 0x0F && insn[1] == 0x54) {
5571//-- vg_assert(sz == 4 || sz == 2);
5572//-- if (sz == 4) {
5573//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "andps",
5574//-- insn[0], insn[1] );
5575//-- } else {
5576//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "andpd",
5577//-- 0x66, insn[0], insn[1] );
5578//-- }
5579//-- goto decode_success;
5580//-- }
5581//--
5582//-- /* ORPS */
5583//-- /* 0x66: ORPD (src)xmmreg-or-mem, (dst)xmmreg */
5584//-- if (insn[0] == 0x0F && insn[1] == 0x56) {
5585//-- vg_assert(sz == 4 || sz == 2);
5586//-- if (sz == 4) {
5587//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "orps",
5588//-- insn[0], insn[1] );
5589//-- } else {
5590//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "orpd",
5591//-- 0x66, insn[0], insn[1] );
5592//-- }
5593//-- goto decode_success;
5594//-- }
5595//--
5596//-- /* PXOR (src)xmmreg-or-mem, (dst)xmmreg */
5597//-- if (sz == 2
5598//-- && insn[0] == 0x0F && insn[1] == 0xEF) {
5599//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pxor",
5600//-- 0x66, insn[0], insn[1] );
5601//-- goto decode_success;
5602//-- }
5603//--
5604//-- /* PAND (src)xmmreg-or-mem, (dst)xmmreg */
5605//-- if (sz == 2
5606//-- && insn[0] == 0x0F && insn[1] == 0xDB) {
5607//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pand",
5608//-- 0x66, insn[0], insn[1] );
5609//-- goto decode_success;
5610//-- }
5611//--
5612//-- /* PANDN (src)xmmreg-or-mem, (dst)xmmreg */
5613//-- if (sz == 2
5614//-- && insn[0] == 0x0F && insn[1] == 0xDF) {
5615//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pandn",
5616//-- 0x66, insn[0], insn[1] );
5617//-- goto decode_success;
5618//-- }
5619//--
5620//-- /* POR (src)xmmreg-or-mem, (dst)xmmreg */
5621//-- if (sz == 2
5622//-- && insn[0] == 0x0F && insn[1] == 0xEB) {
5623//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "por",
5624//-- 0x66, insn[0], insn[1] );
5625//-- goto decode_success;
5626//-- }
5627//--
5628//-- /* 0xDA: PMINUB(src)xmmreg-or-mem, (dst)xmmreg */
5629//-- /* 0xEA: PMINSW(src)xmmreg-or-mem, (dst)xmmreg */
5630//-- if (sz == 2
5631//-- && insn[0] == 0x0F
5632//-- && (insn[1] == 0xDA || insn[1] == 0xEA)) {
5633//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmin{ub,sw}",
5634//-- 0x66, insn[0], insn[1] );
5635//-- goto decode_success;
5636//-- }
5637//--
5638//-- /* 0xDE: PMAXUB(src)xmmreg-or-mem, (dst)xmmreg */
5639//-- /* 0xEE: PMAXSW(src)xmmreg-or-mem, (dst)xmmreg */
5640//-- if (sz == 2
5641//-- && insn[0] == 0x0F
5642//-- && (insn[1] == 0xDE || insn[1] == 0xEE)) {
5643//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmax{ub,sw}",
5644//-- 0x66, insn[0], insn[1] );
5645//-- goto decode_success;
5646//-- }
5647//--
5648//-- /* 0xE0: PAVGB(src)xmmreg-or-mem, (dst)xmmreg */
5649//-- /* 0xE3: PAVGW(src)xmmreg-or-mem, (dst)xmmreg */
5650//-- if (sz == 2
5651//-- && insn[0] == 0x0F
5652//-- && (insn[1] == 0xE0 || insn[1] == 0xE3)) {
5653//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pavg{b,w}",
5654//-- 0x66, insn[0], insn[1] );
5655//-- goto decode_success;
5656//-- }
5657//--
5658//-- /* 0xF6: PSADBW(src)xmmreg-or-mem, (dst)xmmreg */
5659//-- if (sz == 2
5660//-- && insn[0] == 0x0F && insn[1] == 0xF6) {
5661//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psadbw",
5662//-- 0x66, insn[0], insn[1] );
5663//-- goto decode_success;
5664//-- }
5665//--
5666//-- /* 0x60: PUNPCKLBW (src)xmmreg-or-mem, (dst)xmmreg */
5667//-- /* 0x61: PUNPCKLWD (src)xmmreg-or-mem, (dst)xmmreg */
5668//-- /* 0x62: PUNPCKLDQ (src)xmmreg-or-mem, (dst)xmmreg */
5669//-- /* 0x6C: PUNPCKQLQDQ (src)xmmreg-or-mem, (dst)xmmreg */
5670//-- if (sz == 2
5671//-- && insn[0] == 0x0F
5672//-- && (insn[1] == 0x60 || insn[1] == 0x61
5673//-- || insn[1] == 0x62 || insn[1] == 0x6C)) {
5674//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16,
5675//-- "punpckl{bw,wd,dq,qdq}",
5676//-- 0x66, insn[0], insn[1] );
5677//-- goto decode_success;
5678//-- }
5679//--
5680//-- /* 0x68: PUNPCKHBW (src)xmmreg-or-mem, (dst)xmmreg */
5681//-- /* 0x69: PUNPCKHWD (src)xmmreg-or-mem, (dst)xmmreg */
5682//-- /* 0x6A: PUNPCKHDQ (src)xmmreg-or-mem, (dst)xmmreg */
5683//-- /* 0x6D: PUNPCKHQDQ (src)xmmreg-or-mem, (dst)xmmreg */
5684//-- if (sz == 2
5685//-- && insn[0] == 0x0F
5686//-- && (insn[1] == 0x68 || insn[1] == 0x69
5687//-- || insn[1] == 0x6A || insn[1] == 0x6D)) {
5688//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16,
5689//-- "punpckh{bw,wd,dq,qdq}",
5690//-- 0x66, insn[0], insn[1] );
5691//-- goto decode_success;
5692//-- }
5693//--
5694//-- /* 0x14: UNPCKLPD (src)xmmreg-or-mem, (dst)xmmreg. Reads a+0
5695//-- .. a+7, so we can say size 8 */
5696//-- /* 0x15: UNPCKHPD (src)xmmreg-or-mem, (dst)xmmreg. Reads a+8
5697//-- .. a+15, but we have no way to express this, so better say size
5698//-- 16. Sigh. */
5699//-- if (sz == 2
5700//-- && insn[0] == 0x0F
5701//-- && (insn[1] == 0x14 || insn[1] == 0x15)) {
5702//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2,
5703//-- insn[1]==0x14 ? 8 : 16,
5704//-- "unpck{l,h}pd",
5705//-- 0x66, insn[0], insn[1] );
5706//-- goto decode_success;
5707//-- }
5708//--
5709//-- /* 0x14: UNPCKLPS (src)xmmreg-or-mem, (dst)xmmreg Reads a+0
5710//-- .. a+7, so we can say size 8 */
5711//-- /* 0x15: UNPCKHPS (src)xmmreg-or-mem, (dst)xmmreg Reads a+8
5712//-- .. a+15, but we have no way to express this, so better say size
5713//-- 16. Sigh. */
5714//-- if (sz == 4
5715//-- && insn[0] == 0x0F
5716//-- && (insn[1] == 0x14 || insn[1] == 0x15)) {
5717//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2,
5718//-- insn[1]==0x14 ? 8 : 16,
5719//-- "unpck{l,h}ps",
5720//-- insn[0], insn[1] );
5721//-- goto decode_success;
5722//-- }
5723//--
5724//-- /* 0xFC: PADDB (src)xmmreg-or-mem, (dst)xmmreg */
5725//-- /* 0xFD: PADDW (src)xmmreg-or-mem, (dst)xmmreg */
5726//-- /* 0xFE: PADDD (src)xmmreg-or-mem, (dst)xmmreg */
5727//-- /* 0xD4: PADDQ (src)xmmreg-or-mem, (dst)xmmreg */
5728//-- if (sz == 2
5729//-- && insn[0] == 0x0F
5730//-- && (insn[1] == 0xFC || insn[1] == 0xFD
5731//-- || insn[1] == 0xFE || insn[1] == 0xD4)) {
5732//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "padd{b,w,d,q}",
5733//-- 0x66, insn[0], insn[1] );
5734//-- goto decode_success;
5735//-- }
5736//--
5737//-- /* 0xEC: PADDSB (src)xmmreg-or-mem, (dst)xmmreg */
5738//-- /* 0xED: PADDSW (src)xmmreg-or-mem, (dst)xmmreg */
5739//-- if (sz == 2
5740//-- && insn[0] == 0x0F
5741//-- && (insn[1] == 0xEC || insn[1] == 0xED)) {
5742//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "padds{b,w}",
5743//-- 0x66, insn[0], insn[1] );
5744//-- goto decode_success;
5745//-- }
5746//--
5747//-- /* 0xDC: PADDUSB (src)xmmreg-or-mem, (dst)xmmreg */
5748//-- /* 0xDD: PADDUSW (src)xmmreg-or-mem, (dst)xmmreg */
5749//-- if (sz == 2
5750//-- && insn[0] == 0x0F
5751//-- && (insn[1] == 0xDC || insn[1] == 0xDD)) {
5752//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "paddus{b,w}",
5753//-- 0x66, insn[0], insn[1] );
5754//-- goto decode_success;
5755//-- }
5756//--
5757//-- /* 0xF8: PSUBB (src)xmmreg-or-mem, (dst)xmmreg */
5758//-- /* 0xF9: PSUBW (src)xmmreg-or-mem, (dst)xmmreg */
5759//-- /* 0xFA: PSUBD (src)xmmreg-or-mem, (dst)xmmreg */
5760//-- /* 0xFB: PSUBQ (src)xmmreg-or-mem, (dst)xmmreg */
5761//-- if (sz == 2
5762//-- && insn[0] == 0x0F
5763//-- && (insn[1] == 0xF8 || insn[1] == 0xF9
5764//-- || insn[1] == 0xFA || insn[1] == 0xFB)) {
5765//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psub{b,w,d,q}",
5766//-- 0x66, insn[0], insn[1] );
5767//-- goto decode_success;
5768//-- }
5769//--
5770//-- /* 0xE8: PSUBSB (src)xmmreg-or-mem, (dst)xmmreg */
5771//-- /* 0xE9: PSUBSW (src)xmmreg-or-mem, (dst)xmmreg */
5772//-- if (sz == 2
5773//-- && insn[0] == 0x0F
5774//-- && (insn[1] == 0xE8 || insn[1] == 0xE9)) {
5775//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psubs{b,w}",
5776//-- 0x66, insn[0], insn[1] );
5777//-- goto decode_success;
5778//-- }
5779//--
5780//-- /* 0xD8: PSUBUSB (src)xmmreg-or-mem, (dst)xmmreg */
5781//-- /* 0xD9: PSUBUSW (src)xmmreg-or-mem, (dst)xmmreg */
5782//-- if (sz == 2
5783//-- && insn[0] == 0x0F
5784//-- && (insn[1] == 0xD8 || insn[1] == 0xD9)) {
5785//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psubus{b,w}",
5786//-- 0x66, insn[0], insn[1] );
5787//-- goto decode_success;
5788//-- }
5789//--
5790//-- /* 0xE4: PMULHUW(src)xmmreg-or-mem, (dst)xmmreg */
5791//-- /* 0xE5: PMULHW(src)xmmreg-or-mem, (dst)xmmreg */
5792//-- /* 0xD5: PMULLW(src)xmmreg-or-mem, (dst)xmmreg */
5793//-- if (sz == 2
5794//-- && insn[0] == 0x0F
5795//-- && (insn[1] == 0xE4 || insn[1] == 0xE5 || insn[1] == 0xD5)) {
5796//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmul{hu,h,l}w",
5797//-- 0x66, insn[0], insn[1] );
5798//-- goto decode_success;
5799//-- }
5800//--
5801//-- /* 0xD5: PMULUDQ(src)xmmreg-or-mem, (dst)xmmreg */
5802//-- if (sz == 2
5803//-- && insn[0] == 0x0F && insn[1] == 0xF4) {
5804//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmuludq",
5805//-- 0x66, insn[0], insn[1] );
5806//-- goto decode_success;
5807//-- }
5808//--
5809//-- /* 0xF5: PMADDWD(src)xmmreg-or-mem, (dst)xmmreg */
5810//-- if (sz == 2
5811//-- && insn[0] == 0x0F
5812//-- && insn[1] == 0xF5) {
5813//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmaddwd",
5814//-- 0x66, insn[0], insn[1] );
5815//-- goto decode_success;
5816//-- }
5817//--
5818//-- /* 0x74: PCMPEQB (src)xmmreg-or-mem, (dst)xmmreg */
5819//-- /* 0x75: PCMPEQW (src)xmmreg-or-mem, (dst)xmmreg */
5820//-- /* 0x76: PCMPEQD (src)xmmreg-or-mem, (dst)xmmreg */
5821//-- if (sz == 2
5822//-- && insn[0] == 0x0F
5823//-- && (insn[1] == 0x74 || insn[1] == 0x75 || insn[1] == 0x76)) {
5824//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pcmpeq{b,w,d}",
5825//-- 0x66, insn[0], insn[1] );
5826//-- goto decode_success;
5827//-- }
5828//--
5829//-- /* 0x64: PCMPGTB (src)xmmreg-or-mem, (dst)xmmreg */
5830//-- /* 0x65: PCMPGTW (src)xmmreg-or-mem, (dst)xmmreg */
5831//-- /* 0x66: PCMPGTD (src)xmmreg-or-mem, (dst)xmmreg */
5832//-- if (sz == 2
5833//-- && insn[0] == 0x0F
5834//-- && (insn[1] == 0x64 || insn[1] == 0x65 || insn[1] == 0x66)) {
5835//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pcmpgt{b,w,d}",
5836//-- 0x66, insn[0], insn[1] );
5837//-- goto decode_success;
5838//-- }
5839//--
5840//-- /* 0x63: PACKSSWB (src)xmmreg-or-mem, (dst)xmmreg */
5841//-- /* 0x6B: PACKSSDW (src)xmmreg-or-mem, (dst)xmmreg */
5842//-- if (sz == 2
5843//-- && insn[0] == 0x0F
5844//-- && (insn[1] == 0x63 || insn[1] == 0x6B)) {
5845//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "packss{wb,dw}",
5846//-- 0x66, insn[0], insn[1] );
5847//-- goto decode_success;
5848//-- }
5849//--
5850//-- /* 0x67: PACKUSWB (src)xmmreg-or-mem, (dst)xmmreg */
5851//-- if (sz == 2
5852//-- && insn[0] == 0x0F
5853//-- && insn[1] == 0x67) {
5854//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "packuswb",
5855//-- 0x66, insn[0], insn[1] );
5856//-- goto decode_success;
5857//-- }
5858//--
5859//-- /* 0xF1: PSLLW (src)xmmreg-or-mem, (dst)xmmreg */
5860//-- /* 0xF2: PSLLD (src)xmmreg-or-mem, (dst)xmmreg */
5861//-- /* 0xF3: PSLLQ (src)xmmreg-or-mem, (dst)xmmreg */
5862//-- if (sz == 2
5863//-- && insn[0] == 0x0F
5864//-- && (insn[1] == 0xF1 || insn[1] == 0xF2 || insn[1] == 0xF3)) {
5865//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psll{b,w,d}",
5866//-- 0x66, insn[0], insn[1] );
5867//-- goto decode_success;
5868//-- }
5869//--
5870//-- /* 0xD1: PSRLW (src)xmmreg-or-mem, (dst)xmmreg */
5871//-- /* 0xD2: PSRLD (src)xmmreg-or-mem, (dst)xmmreg */
5872//-- /* 0xD3: PSRLQ (src)xmmreg-or-mem, (dst)xmmreg */
5873//-- if (sz == 2
5874//-- && insn[0] == 0x0F
5875//-- && (insn[1] == 0xD1 || insn[1] == 0xD2 || insn[1] == 0xD3)) {
5876//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psrl{b,w,d}",
5877//-- 0x66, insn[0], insn[1] );
5878//-- goto decode_success;
5879//-- }
5880//--
5881//-- /* 0xE1: PSRAW (src)xmmreg-or-mem, (dst)xmmreg */
5882//-- /* 0xE2: PSRAD (src)xmmreg-or-mem, (dst)xmmreg */
5883//-- if (sz == 2
5884//-- && insn[0] == 0x0F
5885//-- && (insn[1] == 0xE1 || insn[1] == 0xE2)) {
5886//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psra{w,d}",
5887//-- 0x66, insn[0], insn[1] );
5888//-- goto decode_success;
5889//-- }
5890//--
5891//-- /* (U)COMISD (src)xmmreg-or-mem, (dst)xmmreg */
5892//-- if (sz == 2
5893//-- && insn[0] == 0x0F
5894//-- && ( insn[1] == 0x2E || insn[1] == 0x2F ) ) {
5895//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 8, "{u}comisd",
5896//-- 0x66, insn[0], insn[1] );
5897//-- vg_assert(LAST_UINSTR(cb).opcode == SSE3a_MemRd
5898//-- || LAST_UINSTR(cb).opcode == SSE4);
5899//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
5900//-- goto decode_success;
5901//-- }
5902//--
5903//-- /* (U)COMISS (src)xmmreg-or-mem, (dst)xmmreg */
5904//-- if (sz == 4
5905//-- && insn[0] == 0x0F
5906//-- && ( insn[1] == 0x2E || insn[ 1 ] == 0x2F )) {
5907//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 4, "{u}comiss",
5908//-- insn[0], insn[1] );
5909//-- vg_assert(LAST_UINSTR(cb).opcode == SSE2a_MemRd
5910//-- || LAST_UINSTR(cb).opcode == SSE3);
5911//-- uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
5912//-- goto decode_success;
5913//-- }
5914//--
5915//-- /* MOVSD -- move 8 bytes of XMM reg to/from XMM reg or mem. */
5916//-- if (insn[0] == 0xF2
5917//-- && insn[1] == 0x0F
5918//-- && (insn[2] == 0x11 || insn[2] == 0x10)) {
5919//-- vg_assert(sz == 4);
5920//-- eip = dis_SSE3_load_store_or_mov
5921//-- ( cb, sorb, eip+3, 8, insn[2]==0x11, "movsd",
5922//-- insn[0], insn[1], insn[2] );
5923//-- goto decode_success;
5924//-- }
5925//--
5926//-- /* MOVQ -- move 8 bytes of XMM reg to XMM reg or mem. How
5927//-- does this differ from MOVSD ?? */
5928//-- if (sz == 2
5929//-- && insn[0] == 0x0F
5930//-- && insn[1] == 0xD6) {
5931//-- eip = dis_SSE3_load_store_or_mov
5932//-- ( cb, sorb, eip+2, 8, True /*store*/, "movq",
5933//-- 0x66, insn[0], insn[1] );
5934//-- goto decode_success;
5935//-- }
5936//--
5937//-- /* MOVQ -- move 8 bytes of XMM reg or mem to XMM reg. How
5938//-- does this differ from MOVSD ?? */
5939//-- if (insn[0] == 0xF3
5940//-- && insn[1] == 0x0F
5941//-- && insn[2] == 0x7E) {
5942//-- eip = dis_SSE3_load_store_or_mov
5943//-- ( cb, sorb, eip+3, 8, False /*load*/, "movq",
5944//-- insn[0], insn[1], insn[2] );
5945//-- goto decode_success;
5946//-- }
5947//--
5948//-- /* MOVDQ2Q -- move low 4 bytes of XMM reg to MMX reg. */
5949//-- if (insn[0] == 0xF2
5950//-- && insn[1] == 0x0F
5951//-- && insn[2] == 0xD6) {
5952//-- eip = dis_SSE3_to_MMX
5953//-- ( cb, sorb, eip+3, 8, "movdq2q",
5954//-- insn[0], insn[1], insn[2] );
5955//-- goto decode_success;
5956//-- }
5957//--
5958//-- /* MOVQ2DQ -- move MMX reg to low 4 bytes of XMM reg. */
5959//-- if (insn[0] == 0xF3
5960//-- && insn[1] == 0x0F
5961//-- && insn[2] == 0xD6) {
5962//-- eip = dis_SSE3_from_MMX
5963//-- ( cb, sorb, eip+3, 8, "movq2dq",
5964//-- insn[0], insn[1], insn[2] );
5965//-- goto decode_success;
5966//-- }
5967//--
5968//-- /* MOVSS -- move 4 bytes of XMM reg to/from XMM reg or mem. */
5969//-- if (insn[0] == 0xF3
5970//-- && insn[1] == 0x0F
5971//-- && (insn[2] == 0x11 || insn[2] == 0x10)) {
5972//-- vg_assert(sz == 4);
5973//-- eip = dis_SSE3_load_store_or_mov
5974//-- ( cb, sorb, eip+3, 4, insn[2]==0x11, "movss",
5975//-- insn[0], insn[1], insn[2] );
5976//-- goto decode_success;
5977//-- }
5978//--
5979//-- /* I don't understand how MOVAPD differs from MOVAPS. */
5980//-- /* MOVAPD (28,29) -- aligned load/store of xmm reg, or xmm-xmm reg
5981//-- move */
5982//-- if (sz == 2
5983//-- && insn[0] == 0x0F && insn[1] == 0x28) {
5984//-- UChar* name = "movapd";
5985//-- //(insn[1] == 0x10 || insn[1] == 0x11)
5986//-- // ? "movups" : "movaps";
5987//-- Bool store = False; //insn[1] == 0x29 || insn[1] == 11;
5988//-- eip = dis_SSE3_load_store_or_mov
5989//-- ( cb, sorb, eip+2, 16, store, name,
5990//-- 0x66, insn[0], insn[1] );
5991//-- goto decode_success;
5992//-- }
5993//--
5994//-- /* sz==4: MOVAPS (28,29) -- aligned load/store of xmm reg, or
5995//-- xmm-xmm reg move */
5996//-- /* sz==4: MOVUPS (10,11) -- unaligned load/store of xmm reg, or
5997//-- xmm-xmm reg move */
5998//-- /* sz==2: MOVAPD (28,29) -- aligned load/store of xmm reg, or
5999//-- xmm-xmm reg move */
6000//-- /* sz==2: MOVUPD (10,11) -- unaligned load/store of xmm reg, or
6001//-- xmm-xmm reg move */
6002//-- if (insn[0] == 0x0F && (insn[1] == 0x28
6003//-- || insn[1] == 0x29
6004//-- || insn[1] == 0x10
6005//-- || insn[1] == 0x11)) {
6006//-- UChar* name = (insn[1] == 0x10 || insn[1] == 0x11)
6007//-- ? "movups" : "movaps";
6008//-- Bool store = insn[1] == 0x29 || insn[1] == 11;
6009//-- vg_assert(sz == 2 || sz == 4);
6010//-- if (sz == 4) {
6011//-- eip = dis_SSE2_load_store_or_mov
6012//-- ( cb, sorb, eip+2, 16, store, name,
6013//-- insn[0], insn[1] );
6014//-- } else {
6015//-- eip = dis_SSE3_load_store_or_mov
6016//-- ( cb, sorb, eip+2, 16, store, name,
6017//-- 0x66, insn[0], insn[1] );
6018//-- }
6019//-- goto decode_success;
6020//-- }
6021//--
6022//-- /* MOVDQA -- aligned 16-byte load/store. */
6023//-- if (sz == 2
6024//-- && insn[0] == 0x0F
6025//-- && (insn[1] == 0x6F || insn[1] == 0x7F)) {
6026//-- Bool is_store = insn[1]==0x7F;
6027//-- eip = dis_SSE3_load_store_or_mov
6028//-- (cb, sorb, eip+2, 16, is_store, "movdqa",
6029//-- 0x66, insn[0], insn[1] );
6030//-- goto decode_success;
6031//-- }
6032//--
6033//-- /* MOVDQU -- unaligned 16-byte load/store. */
6034//-- if (insn[0] == 0xF3
6035//-- && insn[1] == 0x0F
6036//-- && (insn[2] == 0x6F || insn[2] == 0x7F)) {
6037//-- Bool is_store = insn[2]==0x7F;
6038//-- eip = dis_SSE3_load_store_or_mov
6039//-- (cb, sorb, eip+3, 16, is_store, "movdqu",
6040//-- insn[0], insn[1], insn[2] );
6041//-- goto decode_success;
6042//-- }
6043//--
6044//-- /* MOVNTDQ -- 16-byte store with temporal hint (which we
6045//-- ignore). */
6046//-- if (sz == 2
6047//-- && insn[0] == 0x0F
6048//-- && insn[1] == 0xE7) {
6049//-- eip = dis_SSE3_load_store_or_mov
6050//-- (cb, sorb, eip+2, 16, True /* is_store */, "movntdq",
6051//-- 0x66, insn[0], insn[1] );
6052//-- goto decode_success;
6053//-- }
6054//--
6055//-- /* MOVNTPS -- 16-byte store with temporal hint (which we
6056//-- ignore). */
6057//-- if (insn[0] == 0x0F
6058//-- && insn[1] == 0x2B) {
6059//-- eip = dis_SSE2_load_store_or_mov
6060//-- (cb, sorb, eip+2, 16, True /* is_store */, "movntps",
6061//-- insn[0], insn[1] );
6062//-- goto decode_success;
6063//-- }
6064//--
6065//-- /* MOVNTPD -- 16-byte store with temporal hint (which we
6066//-- ignore). */
6067//-- if (sz == 2
6068//-- && insn[0] == 0x0F
6069//-- && insn[1] == 0x2B) {
6070//-- eip = dis_SSE3_load_store_or_mov
6071//-- (cb, sorb, eip+2, 16, True /* is_store */, "movntpd",
6072//-- 0x66, insn[0], insn[1] );
6073//-- goto decode_success;
6074//-- }
6075//--
6076//-- /* MOVD -- 4-byte move between xmmregs and (ireg or memory). */
6077//-- if (sz == 2
6078//-- && insn[0] == 0x0F
6079//-- && (insn[1] == 0x6E || insn[1] == 0x7E)) {
6080//-- Bool is_store = insn[1]==0x7E;
6081//-- modrm = insn[2];
6082//-- if (epartIsReg(modrm) && is_store) {
6083//-- t1 = newTemp(cb);
6084//-- uInstr3(cb, SSE3e_RegWr, 4,
6085//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
6086//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
6087//-- TempReg, t1 );
6088//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, eregOfRM(modrm));
6089//-- DIP("movd %s, %s\n",
6090//-- nameXMMReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
6091//-- eip += 3;
6092//-- } else
6093//-- if (epartIsReg(modrm) && !is_store) {
6094//-- t1 = newTemp(cb);
6095//-- uInstr2(cb, GET, 4, ArchReg, eregOfRM(modrm), TempReg, t1);
6096//-- uInstr3(cb, SSE3e_RegRd, 4,
6097//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
6098//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
6099//-- TempReg, t1 );
6100//-- DIP("movd %s, %s\n",
6101//-- nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
6102//-- eip += 3;
6103//-- } else {
6104//-- eip = dis_SSE3_load_store_or_mov
6105//-- (cb, sorb, eip+2, 4, is_store, "movd",
6106//-- 0x66, insn[0], insn[1] );
6107//-- }
6108//-- goto decode_success;
6109//-- }
6110//--
6111//-- /* PEXTRW from SSE register; writes ireg */
6112//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC5) {
6113//-- t1 = newTemp(cb);
6114//-- modrm = insn[2];
6115//-- vg_assert(epartIsReg(modrm));
6116//-- vg_assert((modrm & 0xC0) == 0xC0);
6117//-- uInstr3(cb, SSE3g1_RegWr, 4,
6118//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
6119//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
6120//-- TempReg, t1 );
6121//-- uLiteral(cb, insn[3]);
6122//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
6123//-- DIP("pextrw %s, %d, %s\n",
6124//-- nameXMMReg(eregOfRM(modrm)), (Int)insn[3],
6125//-- nameIReg(4, gregOfRM(modrm)));
6126//-- eip += 4;
6127//-- goto decode_success;
6128//-- }
6129//--
6130//-- /* PINSRW to SSE register; reads mem or ireg */
6131//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC4) {
6132//-- t1 = newTemp(cb);
6133//-- modrm = insn[2];
6134//-- if (epartIsReg(modrm)) {
6135//-- uInstr2(cb, GET, 2, ArchReg, eregOfRM(modrm), TempReg, t1);
6136//-- vg_assert(epartIsReg(modrm));
6137//-- uInstr3(cb, SSE3e1_RegRd, 2,
6138//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
6139//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
6140//-- TempReg, t1 );
6141//-- uLiteral(cb, insn[3]);
6142//-- DIP("pinsrw %s, %d, %s\n",
6143//-- nameIReg(2, eregOfRM(modrm)), (Int)insn[3],
6144//-- nameXMMReg(gregOfRM(modrm)));
6145//-- eip += 4;
6146//-- } else {
6147//-- VG_(core_panic)("PINSRW mem");
6148//-- }
6149//-- goto decode_success;
6150//-- }
6151//--
6152//-- /* SQRTSD: square root of scalar double. */
6153//-- if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x51) {
6154//-- vg_assert(sz == 4);
6155//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8,
6156//-- "sqrtsd",
6157//-- insn[0], insn[1], insn[2] );
6158//-- goto decode_success;
6159//-- }
6160//--
6161//-- /* SQRTSS: square root of scalar float. */
6162//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x51) {
6163//-- vg_assert(sz == 4);
6164//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4,
6165//-- "sqrtss",
6166//-- insn[0], insn[1], insn[2] );
6167//-- goto decode_success;
6168//-- }
6169//--
6170//-- /* RSQRTSS: square root reciprocal of scalar float. */
6171//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x52) {
6172//-- vg_assert(sz == 4);
6173//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4,
6174//-- "sqrtss",
6175//-- insn[0], insn[1], insn[2] );
6176//-- goto decode_success;
6177//-- }
6178//--
6179//-- /* 0xF3: RCPSS -- reciprocal of scalar float */
6180//-- if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x53) {
6181//-- vg_assert(sz == 4);
6182//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4,
6183//-- "rcpss",
6184//-- insn[0], insn[1], insn[2] );
6185//-- goto decode_success;
6186//-- }
6187//--
6188//-- /* MOVMSKPD -- extract 2 sign bits from a xmm reg and copy them to
6189//-- an ireg. Top 30 bits of ireg are set to zero. */
6190//-- /* MOVMSKPS -- extract 4 sign bits from a xmm reg and copy them to
6191//-- an ireg. Top 28 bits of ireg are set to zero. */
6192//-- if (insn[0] == 0x0F && insn[1] == 0x50) {
6193//-- vg_assert(sz == 4 || sz == 2);
6194//-- modrm = insn[2];
6195//-- /* Intel docs don't say anything about a memory source being
6196//-- allowed here. */
6197//-- vg_assert(epartIsReg(modrm));
6198//-- t1 = newTemp(cb);
6199//-- if (sz == 4) {
6200//-- uInstr3(cb, SSE2g_RegWr, 4,
6201//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
6202//-- Lit16, (UShort)modrm,
6203//-- TempReg, t1 );
6204//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
6205//-- } else {
6206//-- uInstr3(cb, SSE3g_RegWr, 4,
6207//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
6208//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
6209//-- TempReg, t1 );
6210//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
6211//-- }
6212//-- DIP("movmskp%c %s, %s\n", sz == 4 ? 's' : 'd',
6213//-- nameXMMReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)));
6214//-- eip += 3;
6215//-- goto decode_success;
6216//-- }
6217//--
6218//-- /* ANDNPS */
6219//-- /* 0x66: ANDNPD (src)xmmreg-or-mem, (dst)xmmreg */
6220//-- if (insn[0] == 0x0F && insn[1] == 0x55) {
6221//-- vg_assert(sz == 4 || sz == 2);
6222//-- if (sz == 4) {
6223//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "andnps",
6224//-- insn[0], insn[1] );
6225//-- } else {
6226//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "andnpd",
6227//-- 0x66, insn[0], insn[1] );
6228//-- }
6229//-- goto decode_success;
6230//-- }
6231//--
6232//-- /* MOVHLPS -- move two packed floats from high quadword to low quadword */
6233//-- /* MOVLPS -- load/store two packed floats to/from low quadword. */
6234//-- /* MOVLPD -- load/store packed double to/from low quadword. */
6235//-- if (insn[0] == 0x0F
6236//-- && (insn[1] == 0x12 || insn[1] == 0x13)) {
6237//-- Bool is_store = insn[1]==0x13;
6238//-- vg_assert(sz == 4 || sz == 2);
6239//-- if (sz == 4) {
6240//-- if (epartIsReg(insn[2])) {
6241//-- vg_assert(insn[1]==0x12);
6242//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "movhlps",
6243//-- insn[0], insn[1] );
6244//-- } else {
6245//-- eip = dis_SSE2_load_store_or_mov
6246//-- (cb, sorb, eip+2, 8, is_store, "movlps",
6247//-- insn[0], insn[1] );
6248//-- }
6249//-- } else {
6250//-- vg_assert(!epartIsReg(insn[2]));
6251//-- eip = dis_SSE3_load_store_or_mov
6252//-- (cb, sorb, eip+2, 8, is_store, "movlpd",
6253//-- 0x66, insn[0], insn[1] );
6254//-- }
6255//-- goto decode_success;
6256//-- }
6257//--
6258//-- /* MOVLHPS -- move two packed floats from low quadword to high quadword */
6259//-- /* MOVHPS -- load/store two packed floats to/from high quadword. */
6260//-- /* MOVHPD -- load/store packed double to/from high quadword. */
6261//-- if (insn[0] == 0x0F
6262//-- && (insn[1] == 0x16 || insn[1] == 0x17)) {
6263//-- Bool is_store = insn[1]==0x17;
6264//-- vg_assert(sz == 4 || sz == 2);
6265//-- if (sz == 4) {
6266//-- if (epartIsReg(insn[2])) {
6267//-- vg_assert(insn[1]==0x16);
6268//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "movlhps",
6269//-- insn[0], insn[1] );
6270//-- } else {
6271//-- eip = dis_SSE2_load_store_or_mov
6272//-- (cb, sorb, eip+2, 8, is_store, "movhps",
6273//-- insn[0], insn[1] );
6274//-- }
6275//-- } else {
6276//-- vg_assert(!epartIsReg(insn[2]));
6277//-- eip = dis_SSE3_load_store_or_mov
6278//-- (cb, sorb, eip+2, 8, is_store, "movhpd",
6279//-- 0x66, insn[0], insn[1] );
6280//-- }
6281//-- goto decode_success;
6282//-- }
6283//--
6284//-- /* PMOVMSKB -- extract 16 sign bits from a xmm reg and copy them to
6285//-- an ireg. Top 16 bits of ireg are set to zero. */
6286//-- if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD7) {
6287//-- modrm = insn[2];
6288//-- /* Intel docs don't say anything about a memory source being
6289//-- allowed here. */
6290//-- vg_assert(epartIsReg(modrm));
6291//-- t1 = newTemp(cb);
6292//-- uInstr3(cb, SSE3g_RegWr, 4,
6293//-- Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
6294//-- Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
6295//-- TempReg, t1 );
6296//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
6297//-- DIP("pmovmskb %s, %s\n",
6298//-- nameXMMReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)));
6299//-- eip += 3;
6300//-- goto decode_success;
6301//-- }
6302//--
6303//-- /* sz==4: SQRTPS: square root of packed float. */
6304//-- /* sz==2: SQRTPD: square root of packed double. */
6305//-- if (insn[0] == 0x0F && insn[1] == 0x51) {
6306//-- vg_assert(sz == 2 || sz == 4);
6307//-- if (sz == 4) {
6308//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16,
6309//-- "sqrtps",
6310//-- insn[0], insn[1] );
6311//-- } else {
6312//-- eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16,
6313//-- "sqrtpd",
6314//-- 0x66, insn[0], insn[1] );
6315//-- }
6316//-- goto decode_success;
6317//-- }
6318//--
6319//-- /* RSQRTPS: square root reciprocal of packed float. */
6320//-- if (insn[0] == 0x0F && insn[1] == 0x52) {
6321//-- vg_assert(sz == 4);
6322//-- eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16,
6323//-- "rsqrtps",
6324//-- insn[0], insn[1] );
6325//-- goto decode_success;
6326//-- }
6327//--
6328//-- /* Fall through into the non-SSE decoder. */
6329//--
6330//-- } /* if (VG_(have_ssestate)) */
6331
6332
6333 /* ---------------------------------------------------- */
6334 /* --- end of the SSE/SSE2 decoder. --- */
6335 /* ---------------------------------------------------- */
6336
6337 /* Get the primary opcode. */
6338 opc = getIByte(delta); delta++;
6339
6340 /* We get here if the current insn isn't SSE, or this CPU doesn't
6341 support SSE. */
6342
6343 switch (opc) {
6344
6345 /* ------------------------ Control flow --------------- */
sewardj940e8c92004-07-11 16:53:24 +00006346
6347 case 0xC2: /* RET imm16 */
6348 d32 = getUDisp16(delta);
6349 delta += 2;
6350 dis_ret(d32);
6351 *isEnd = True;
6352 DIP("ret %d\n", d32);
6353 break;
sewardje05c42c2004-07-08 20:25:10 +00006354 case 0xC3: /* RET */
6355 dis_ret(0);
6356 *isEnd = True;
6357 DIP("ret\n");
6358 break;
sewardjd1061ab2004-07-08 01:45:30 +00006359
6360 case 0xE8: /* CALL J4 */
6361 d32 = getUDisp32(delta); delta += 4;
6362 d32 += (guest_eip+delta);
6363 /* (guest_eip+delta) == return-to addr, d32 == call-to addr */
sewardjc2ac51e2004-07-12 01:03:26 +00006364 if (d32 == guest_eip+delta && getIByte(delta) >= 0x58
6365 && getIByte(delta) <= 0x5F) {
sewardjd1061ab2004-07-08 01:45:30 +00006366 /* Specially treat the position-independent-code idiom
6367 call X
6368 X: popl %reg
6369 as
6370 movl %eip, %reg.
6371 since this generates better code, but for no other reason. */
6372 Int archReg = getIByte(delta) - 0x58;
sewardjc2ac51e2004-07-12 01:03:26 +00006373 /* vex_printf("-- fPIC thingy\n"); */
6374 putIReg(4, archReg, mkU32(guest_eip+delta));
sewardjd1061ab2004-07-08 01:45:30 +00006375 delta++; /* Step over the POP */
6376 DIP("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
sewardjc2ac51e2004-07-12 01:03:26 +00006377 } else {
sewardjd1061ab2004-07-08 01:45:30 +00006378 /* The normal sequence for a call. */
6379 t1 = newTemp(Ity_I32);
sewardj41f43bc2004-07-08 14:23:22 +00006380 assign(t1, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
6381 putIReg(4, R_ESP, mkexpr(t1));
6382 storeLE( mkexpr(t1), mkU32(guest_eip+delta));
sewardj78c19df2004-07-12 22:49:27 +00006383 jmp_lit(Ijk_Call,d32);
sewardjd1061ab2004-07-08 01:45:30 +00006384 *isEnd = True;
6385 DIP("call 0x%x\n",d32);
6386 }
6387 break;
6388
sewardjc9a65702004-07-07 16:32:57 +00006389//-- case 0xC8: /* ENTER */
6390//-- d32 = getUDisp16(eip); eip += 2;
6391//-- abyte = getIByte(delta); delta++;
6392//--
6393//-- vg_assert(sz == 4);
6394//-- vg_assert(abyte == 0);
6395//--
6396//-- t1 = newTemp(cb); t2 = newTemp(cb);
6397//-- uInstr2(cb, GET, sz, ArchReg, R_EBP, TempReg, t1);
6398//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
6399//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
6400//-- uLiteral(cb, sz);
6401//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
6402//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
6403//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
6404//-- if (d32) {
6405//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
6406//-- uLiteral(cb, d32);
6407//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
6408//-- }
6409//-- DIP("enter 0x%x, 0x%x", d32, abyte);
6410//-- break;
sewardjc2ac51e2004-07-12 01:03:26 +00006411
6412 case 0xC9: /* LEAVE */
6413 vassert(sz == 4);
6414 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
6415 assign(t1, getIReg(4,R_EBP));
6416 /* First PUT ESP looks redundant, but need it because ESP must
6417 always be up-to-date for Memcheck to work... */
6418 putIReg(4, R_ESP, mkexpr(t1));
6419 assign(t2, loadLE(Ity_I32,mkexpr(t1)));
6420 putIReg(4, R_EBP, mkexpr(t2));
6421 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t1), mkU32(4)) );
6422 DIP("leave\n");
6423 break;
6424
sewardjc9a65702004-07-07 16:32:57 +00006425//-- /* ---------------- Misc weird-ass insns --------------- */
6426//--
6427//-- case 0x27: /* DAA */
6428//-- case 0x2F: /* DAS */
6429//-- t1 = newTemp(cb);
6430//-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
6431//-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
6432//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
6433//-- uWiden(cb, 1, False);
6434//-- uInstr0(cb, CALLM_S, 0);
6435//-- uInstr1(cb, PUSH, 4, TempReg, t1);
6436//-- uInstr1(cb, CALLM, 0, Lit16,
6437//-- opc == 0x27 ? VGOFF_(helper_DAA) : VGOFF_(helper_DAS) );
6438//-- uFlagsRWU(cb, FlagsAC, FlagsSZACP, FlagO);
6439//-- uInstr1(cb, POP, 4, TempReg, t1);
6440//-- uInstr0(cb, CALLM_E, 0);
6441//-- uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
6442//-- DIP(opc == 0x27 ? "daa\n" : "das\n");
6443//-- break;
6444//--
6445//-- case 0x37: /* AAA */
6446//-- case 0x3F: /* AAS */
6447//-- t1 = newTemp(cb);
6448//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
6449//-- /* Widen %AL to 32 bits, so it's all defined when we push it. */
6450//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
6451//-- uWiden(cb, 2, False);
6452//-- uInstr0(cb, CALLM_S, 0);
6453//-- uInstr1(cb, PUSH, 4, TempReg, t1);
6454//-- uInstr1(cb, CALLM, 0, Lit16,
6455//-- opc == 0x37 ? VGOFF_(helper_AAA) : VGOFF_(helper_AAS) );
6456//-- uFlagsRWU(cb, FlagA, FlagsAC, FlagsEmpty);
6457//-- uInstr1(cb, POP, 4, TempReg, t1);
6458//-- uInstr0(cb, CALLM_E, 0);
6459//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
6460//-- DIP(opc == 0x37 ? "aaa\n" : "aas\n");
6461//-- break;
6462//--
6463//-- case 0xD4: /* AAM */
6464//-- case 0xD5: /* AAD */
6465//-- d32 = getIByte(delta); delta++;
6466//-- if (d32 != 10) VG_(core_panic)("disInstr: AAM/AAD but base not 10 !");
6467//-- t1 = newTemp(cb);
6468//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
6469//-- /* Widen %AX to 32 bits, so it's all defined when we push it. */
6470//-- uInstr1(cb, WIDEN, 4, TempReg, t1);
6471//-- uWiden(cb, 2, False);
6472//-- uInstr0(cb, CALLM_S, 0);
6473//-- uInstr1(cb, PUSH, 4, TempReg, t1);
6474//-- uInstr1(cb, CALLM, 0, Lit16,
6475//-- opc == 0xD4 ? VGOFF_(helper_AAM) : VGOFF_(helper_AAD) );
6476//-- uFlagsRWU(cb, FlagsEmpty, FlagsSZP, FlagsEmpty);
6477//-- uInstr1(cb, POP, 4, TempReg, t1);
6478//-- uInstr0(cb, CALLM_E, 0);
6479//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
6480//-- DIP(opc == 0xD4 ? "aam\n" : "aad\n");
6481//-- break;
6482//--
6483//-- /* ------------------------ CWD/CDQ -------------------- */
6484//--
6485//-- case 0x98: /* CBW */
6486//-- t1 = newTemp(cb);
6487//-- if (sz == 4) {
6488//-- uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
6489//-- uInstr1(cb, WIDEN, 4, TempReg, t1); /* 4 == dst size */
6490//-- uWiden(cb, 2, True);
6491//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
6492//-- DIP("cwd\n");
6493//-- } else {
6494//-- vg_assert(sz == 2);
6495//-- uInstr2(cb, GET, 1, ArchReg, R_EAX, TempReg, t1);
6496//-- uInstr1(cb, WIDEN, 2, TempReg, t1); /* 2 == dst size */
6497//-- uWiden(cb, 1, True);
6498//-- uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
6499//-- DIP("cbw\n");
6500//-- }
6501//-- break;
sewardj64e1d652004-07-12 14:00:46 +00006502
6503 case 0x99: /* CWD/CDQ */
6504 ty = szToITy(sz);
6505 putIReg(sz, R_EDX,
6506 binop(mkSizedOp(ty,Iop_Sar8),
6507 getIReg(sz, R_EAX),
sewardj6d2638e2004-07-15 09:38:27 +00006508 mkU8(sz == 2 ? 15 : 31)) );
sewardj64e1d652004-07-12 14:00:46 +00006509 DIP(sz == 2 ? "cwdq\n" : "cdqq\n");
6510 break;
6511
sewardjc9a65702004-07-07 16:32:57 +00006512//-- /* ------------------------ FPU ops -------------------- */
6513//--
6514//-- case 0x9E: /* SAHF */
6515//-- codegen_SAHF ( cb );
6516//-- DIP("sahf\n");
6517//-- break;
6518//--
6519//-- case 0x9F: /* LAHF */
6520//-- codegen_LAHF ( cb );
6521//-- DIP("lahf\n");
6522//-- break;
6523//--
6524//-- case 0x9B: /* FWAIT */
6525//-- /* ignore? */
6526//-- DIP("fwait\n");
6527//-- break;
6528//--
sewardjd1725d12004-08-12 20:46:53 +00006529 case 0xD8:
6530 case 0xD9:
6531 case 0xDA:
6532 case 0xDB:
6533 case 0xDC:
6534 case 0xDD:
6535 case 0xDE:
6536 case 0xDF: {
6537 UInt delta0 = delta;
6538 Bool decode_OK = False;
6539 delta = dis_FPU ( &decode_OK, sorb, delta );
6540 if (!decode_OK) {
6541 delta = delta0;
6542 goto decode_failure;
6543 }
6544 break;
6545 }
sewardj0611d802004-07-11 02:37:54 +00006546
6547 /* ------------------------ INC & DEC ------------------ */
6548
6549 case 0x40: /* INC eAX */
6550 case 0x41: /* INC eCX */
6551 case 0x42: /* INC eDX */
6552 case 0x43: /* INC eBX */
6553 case 0x44: /* INC eSP */
6554 case 0x45: /* INC eBP */
6555 case 0x46: /* INC eSI */
6556 case 0x47: /* INC eDI */
6557 vassert(sz == 2 || sz == 4);
6558 ty = szToITy(sz);
6559 t1 = newTemp(ty);
6560 assign( t1, binop(mkSizedOp(ty,Iop_Add8),
6561 getIReg(sz, (UInt)(opc - 0x40)),
6562 mkU(ty,1)) );
6563 setFlags_INC_DEC( True, t1, ty );
6564 putIReg(sz, (UInt)(opc - 0x40), mkexpr(t1));
6565 DIP("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
6566 break;
6567
6568 case 0x48: /* DEC eAX */
6569 case 0x49: /* DEC eCX */
6570 case 0x4A: /* DEC eDX */
6571 case 0x4B: /* DEC eBX */
6572 case 0x4C: /* DEC eSP */
6573 case 0x4D: /* DEC eBP */
6574 case 0x4E: /* DEC eSI */
6575 case 0x4F: /* DEC eDI */
6576 vassert(sz == 2 || sz == 4);
6577 ty = szToITy(sz);
6578 t1 = newTemp(ty);
6579 assign( t1, binop(mkSizedOp(ty,Iop_Sub8),
6580 getIReg(sz, (UInt)(opc - 0x48)),
6581 mkU(ty,1)) );
6582 setFlags_INC_DEC( False, t1, ty );
6583 putIReg(sz, (UInt)(opc - 0x48), mkexpr(t1));
6584 DIP("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
6585 break;
6586
6587 /* ------------------------ INT ------------------------ */
6588
6589 case 0xCD: /* INT imm8 */
6590 d32 = getIByte(delta); delta++;
6591 if (d32 != 0x80) goto decode_failure;
6592 /* It's important that all ArchRegs carry their up-to-date value
6593 at this point. So we declare an end-of-block here, which
6594 forces any TempRegs caching ArchRegs to be flushed. */
sewardj78c19df2004-07-12 22:49:27 +00006595 jmp_lit(Ijk_Syscall,((Addr32)guest_code)+delta);
sewardj0611d802004-07-11 02:37:54 +00006596 *isEnd = True;
6597 DIP("int $0x80\n");
6598 break;
6599
sewardj77b86be2004-07-11 13:28:24 +00006600 /* ------------------------ Jcond, byte offset --------- */
6601
6602 case 0xEB: /* Jb (jump, byte offset) */
6603 d32 = (((Addr32)guest_code)+delta+1) + getSDisp8(delta);
6604 delta++;
sewardj78c19df2004-07-12 22:49:27 +00006605 jmp_lit(Ijk_Boring,d32);
sewardj77b86be2004-07-11 13:28:24 +00006606 *isEnd = True;
6607 DIP("jmp-8 0x%x\n", d32);
6608 break;
sewardj0611d802004-07-11 02:37:54 +00006609
6610 case 0xE9: /* Jv (jump, 16/32 offset) */
6611 vassert(sz == 4); /* JRS added 2004 July 11 */
6612 d32 = (((Addr32)guest_code)+delta+sz) + getSDisp(sz,delta);
6613 delta += sz;
sewardj78c19df2004-07-12 22:49:27 +00006614 jmp_lit(Ijk_Boring,d32);
sewardj0611d802004-07-11 02:37:54 +00006615 *isEnd = True;
6616 DIP("jmp 0x%x\n", d32);
6617 break;
sewardje87b4842004-07-10 12:23:30 +00006618
6619 case 0x70:
6620 case 0x71:
6621 case 0x72: /* JBb/JNAEb (jump below) */
6622 case 0x73: /* JNBb/JAEb (jump not below) */
6623 case 0x74: /* JZb/JEb (jump zero) */
6624 case 0x75: /* JNZb/JNEb (jump not zero) */
6625 case 0x76: /* JBEb/JNAb (jump below or equal) */
6626 case 0x77: /* JNBEb/JAb (jump not below or equal) */
6627 case 0x78: /* JSb (jump negative) */
6628 case 0x79: /* JSb (jump not negative) */
6629 case 0x7A: /* JP (jump parity even) */
6630 case 0x7B: /* JNP/JPO (jump parity odd) */
6631 case 0x7C: /* JLb/JNGEb (jump less) */
6632 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
6633 case 0x7E: /* JLEb/JNGb (jump less or equal) */
6634 case 0x7F: /* JGb/JNLEb (jump greater) */
6635 d32 = (((Addr32)guest_code)+delta+1) + getSDisp8(delta);
6636 delta++;
6637 jcc_01((Condcode)(opc - 0x70), (Addr32)(guest_code+delta), d32);
6638 *isEnd = True;
6639 DIP("j%s-8 0x%x\n", name_Condcode(opc - 0x70), d32);
6640 break;
6641
sewardjc9a65702004-07-07 16:32:57 +00006642//-- case 0xE3: /* JECXZ or perhaps JCXZ, depending on OSO ? Intel
6643//-- manual says it depends on address size override,
6644//-- which doesn't sound right to me. */
6645//-- d32 = (eip+1) + getSDisp8(eip); eip++;
6646//-- t1 = newTemp(cb);
6647//-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
6648//-- uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
6649//-- uLiteral(cb, d32);
6650//-- DIP("j%sz 0x%x\n", nameIReg(sz, R_ECX), d32);
6651//-- break;
6652//--
6653//-- case 0xE0: /* LOOPNE disp8 */
6654//-- case 0xE1: /* LOOPE disp8 */
6655//-- case 0xE2: /* LOOP disp8 */
6656//-- /* Again, the docs say this uses ECX/CX as a count depending on
6657//-- the address size override, not the operand one. Since we
6658//-- don't handle address size overrides, I guess that means
6659//-- ECX. */
6660//-- d32 = (eip+1) + getSDisp8(eip); eip++;
6661//-- t1 = newTemp(cb);
6662//-- uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
6663//-- uInstr1(cb, DEC, 4, TempReg, t1);
6664//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ECX);
6665//-- uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
6666//-- uLiteral(cb, eip);
6667//-- if (opc == 0xE0 || opc == 0xE1) { /* LOOPE/LOOPNE */
6668//-- jcc_lit(cb, eip, (opc == 0xE1 ? CondNZ : CondZ));
6669//-- }
6670//-- jmp_lit(cb, d32);
6671//-- *isEnd = True;
6672//-- DIP("loop 0x%x\n", d32);
6673//-- break;
sewardj1813dbe2004-07-28 17:09:04 +00006674
6675 /* ------------------------ IMUL ----------------------- */
6676
6677 case 0x69: /* IMUL Iv, Ev, Gv */
6678 delta = dis_imul_I_E_G ( sorb, sz, delta, sz );
6679 break;
6680 case 0x6B: /* IMUL Ib, Ev, Gv */
6681 delta = dis_imul_I_E_G ( sorb, sz, delta, 1 );
6682 break;
sewardj0611d802004-07-11 02:37:54 +00006683
6684 /* ------------------------ MOV ------------------------ */
6685
6686 case 0x88: /* MOV Gb,Eb */
6687 delta = dis_mov_G_E(sorb, 1, delta);
6688 break;
sewardjc9a65702004-07-07 16:32:57 +00006689
6690 case 0x89: /* MOV Gv,Ev */
6691 delta = dis_mov_G_E(sorb, sz, delta);
6692 break;
6693
sewardjc2ac51e2004-07-12 01:03:26 +00006694 case 0x8A: /* MOV Eb,Gb */
6695 delta = dis_mov_E_G(sorb, 1, delta);
6696 break;
sewardje05c42c2004-07-08 20:25:10 +00006697
6698 case 0x8B: /* MOV Ev,Gv */
6699 delta = dis_mov_E_G(sorb, sz, delta);
6700 break;
6701
sewardje87b4842004-07-10 12:23:30 +00006702 case 0x8D: /* LEA M,Gv */
sewardje05c42c2004-07-08 20:25:10 +00006703 vassert(sz == 4);
6704 modrm = getIByte(delta);
6705 if (epartIsReg(modrm))
6706 vpanic("LEA M,Gv: modRM refers to register (x86)");
6707 /* NOTE! this is the one place where a segment override prefix
6708 has no effect on the address calculation. Therefore we pass
6709 zero instead of sorb here. */
sewardje87b4842004-07-10 12:23:30 +00006710 addr = disAMode ( &alen, /*sorb*/ 0, delta, dis_buf );
6711 delta += alen;
sewardj940e8c92004-07-11 16:53:24 +00006712 putIReg(sz, gregOfRM(modrm), mkexpr(addr));
sewardje05c42c2004-07-08 20:25:10 +00006713 DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
6714 nameIReg(sz,gregOfRM(modrm)));
6715 break;
sewardje05c42c2004-07-08 20:25:10 +00006716
sewardjc9a65702004-07-07 16:32:57 +00006717//-- case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
6718//-- eip = dis_mov_Sw_Ew(cb, sorb, eip);
6719//-- break;
6720//--
6721//-- case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
6722//-- eip = dis_mov_Ew_Sw(cb, sorb, eip);
6723//-- break;
6724//--
6725//-- case 0xA0: /* MOV Ob,AL */
6726//-- sz = 1;
6727//-- /* Fall through ... */
sewardj0c12ea82004-07-12 08:18:16 +00006728 case 0xA1: /* MOV Ov,eAX */
6729 d32 = getUDisp32(delta); delta += 4;
6730 ty = szToITy(sz);
6731 addr = newTemp(Ity_I32);
6732 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
6733 putIReg(sz, R_EAX, loadLE(ty, mkexpr(addr)));
6734 DIP("mov%c %s0x%x, %s\n", nameISize(sz), sorbTxt(sorb),
6735 d32, nameIReg(sz,R_EAX));
6736 break;
6737
sewardj180e8b32004-07-29 01:40:11 +00006738 case 0xA2: /* MOV Ob,AL */
6739 sz = 1;
6740 /* Fall through ... */
sewardj750f4072004-07-26 22:39:11 +00006741 case 0xA3: /* MOV eAX,Ov */
6742 d32 = getUDisp32(delta); delta += 4;
6743 ty = szToITy(sz);
6744 addr = newTemp(Ity_I32);
6745 assign( addr, handleSegOverride(sorb, mkU32(d32)) );
6746 storeLE( mkexpr(addr), getIReg(sz,R_EAX) );
6747 DIP("mov%c %s, %s0x%x\n", nameISize(sz), nameIReg(sz,R_EAX),
6748 sorbTxt(sorb), d32);
6749 break;
sewardje87b4842004-07-10 12:23:30 +00006750
sewardjc2ac51e2004-07-12 01:03:26 +00006751 case 0xB0: /* MOV imm,AL */
sewardj180e8b32004-07-29 01:40:11 +00006752#if 0
sewardjc2ac51e2004-07-12 01:03:26 +00006753 case 0xB1: /* MOV imm,CL */
sewardj7ed22952004-07-29 00:09:58 +00006754#endif
sewardjc2ac51e2004-07-12 01:03:26 +00006755 case 0xB2: /* MOV imm,DL */
sewardj7ed22952004-07-29 00:09:58 +00006756#if 0
sewardjc2ac51e2004-07-12 01:03:26 +00006757 case 0xB3: /* MOV imm,BL */
6758 case 0xB4: /* MOV imm,AH */
6759 case 0xB5: /* MOV imm,CH */
6760 case 0xB6: /* MOV imm,DH */
6761 case 0xB7: /* MOV imm,BH */
sewardj7ed22952004-07-29 00:09:58 +00006762#endif
sewardjc2ac51e2004-07-12 01:03:26 +00006763 d32 = getIByte(delta); delta += 1;
6764 putIReg(1, opc-0xB0, mkU8(d32));
6765 DIP("movb $0x%x,%s\n", d32, nameIReg(1,opc-0xB0));
6766 break;
sewardj7ed22952004-07-29 00:09:58 +00006767
sewardje87b4842004-07-10 12:23:30 +00006768 case 0xB8: /* MOV imm,eAX */
6769 case 0xB9: /* MOV imm,eCX */
6770 case 0xBA: /* MOV imm,eDX */
6771 case 0xBB: /* MOV imm,eBX */
6772 case 0xBC: /* MOV imm,eSP */
6773 case 0xBD: /* MOV imm,eBP */
6774 case 0xBE: /* MOV imm,eSI */
6775 case 0xBF: /* MOV imm,eDI */
6776 d32 = getUDisp(sz,delta); delta += sz;
6777 putIReg(sz, opc-0xB8, mkU(szToITy(sz), d32));
6778 DIP("mov%c $0x%x,%s\n", nameISize(sz), d32, nameIReg(sz,opc-0xB8));
6779 break;
6780
sewardj77b86be2004-07-11 13:28:24 +00006781 case 0xC6: /* MOV Ib,Eb */
6782 sz = 1;
6783 goto do_Mov_I_E;
sewardje87b4842004-07-10 12:23:30 +00006784 case 0xC7: /* MOV Iv,Ev */
6785 goto do_Mov_I_E;
6786
6787 do_Mov_I_E:
6788 modrm = getIByte(delta);
6789 if (epartIsReg(modrm)) {
6790 delta++; /* mod/rm byte */
6791 d32 = getUDisp(sz,delta); delta += sz;
6792 putIReg(sz, eregOfRM(modrm), mkU(szToITy(sz), d32));
6793 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32,
6794 nameIReg(sz,eregOfRM(modrm)));
6795 vassert(0);
6796 } else {
6797 addr = disAMode ( &alen, sorb, delta, dis_buf );
6798 delta += alen;
6799 d32 = getUDisp(sz,delta); delta += sz;
sewardj940e8c92004-07-11 16:53:24 +00006800 storeLE(mkexpr(addr), mkU(szToITy(sz), d32));
sewardje87b4842004-07-10 12:23:30 +00006801 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
6802 }
6803 break;
6804
sewardj1813dbe2004-07-28 17:09:04 +00006805 /* ------------------------ opl imm, A ----------------- */
6806
6807 case 0x04: /* ADD Ib, AL */
6808 delta = dis_op_imm_A( 1, Iop_Add8, True, delta, "add" );
6809 break;
sewardj77b86be2004-07-11 13:28:24 +00006810 case 0x05: /* ADD Iv, eAX */
6811 delta = dis_op_imm_A(sz, Iop_Add8, True, delta, "add" );
6812 break;
6813
sewardj940e8c92004-07-11 16:53:24 +00006814 case 0x0C: /* OR Ib, AL */
6815 delta = dis_op_imm_A( 1, Iop_Or8, True, delta, "or" );
6816 break;
sewardj82292882004-07-27 00:15:59 +00006817 case 0x0D: /* OR Iv, eAX */
6818 delta = dis_op_imm_A( sz, Iop_Or8, True, delta, "or" );
6819 break;
6820
sewardjc9a65702004-07-07 16:32:57 +00006821//-- case 0x14: /* ADC Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +00006822//-- delta = dis_op_imm_A( 1, ADC, True, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +00006823//-- break;
6824//-- case 0x15: /* ADC Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +00006825//-- delta = dis_op_imm_A( sz, ADC, True, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +00006826//-- break;
6827//--
6828//-- case 0x1C: /* SBB Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +00006829//-- delta = dis_op_imm_A( 1, SBB, True, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +00006830//-- break;
6831//-- case 0x1D: /* SBB Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +00006832//-- delta = dis_op_imm_A( sz, SBB, True, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +00006833//-- break;
6834//--
sewardj940e8c92004-07-11 16:53:24 +00006835 case 0x24: /* AND Ib, AL */
6836 delta = dis_op_imm_A( 1, Iop_And8, True, delta, "and" );
6837 break;
sewardjc2ac51e2004-07-12 01:03:26 +00006838 case 0x25: /* AND Iv, eAX */
6839 delta = dis_op_imm_A( sz, Iop_And8, True, delta, "and" );
6840 break;
sewardj0611d802004-07-11 02:37:54 +00006841
6842 case 0x2C: /* SUB Ib, AL */
6843 delta = dis_op_imm_A(1, Iop_Sub8, True, delta, "sub" );
6844 break;
sewardj68511542004-07-28 00:15:44 +00006845 case 0x2D: /* SUB Iv, eAX */
6846 delta = dis_op_imm_A( sz, Iop_Sub8, True, delta, "sub" );
6847 break;
6848
sewardjc9a65702004-07-07 16:32:57 +00006849//-- case 0x34: /* XOR Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +00006850//-- delta = dis_op_imm_A( 1, XOR, True, delta, "xor" );
sewardjc9a65702004-07-07 16:32:57 +00006851//-- break;
sewardjcaca9d02004-07-28 07:11:32 +00006852 case 0x35: /* XOR Iv, eAX */
6853 delta = dis_op_imm_A( sz, Iop_Xor8, True, delta, "xor" );
6854 break;
6855
sewardj0611d802004-07-11 02:37:54 +00006856 case 0x3C: /* CMP Ib, AL */
sewardj77b86be2004-07-11 13:28:24 +00006857 delta = dis_op_imm_A( 1, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +00006858 break;
6859 case 0x3D: /* CMP Iv, eAX */
sewardj77b86be2004-07-11 13:28:24 +00006860 delta = dis_op_imm_A( sz, Iop_Sub8, False, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +00006861 break;
6862
sewardj77b86be2004-07-11 13:28:24 +00006863 case 0xA8: /* TEST Ib, AL */
6864 delta = dis_op_imm_A( 1, Iop_And8, False, delta, "test" );
6865 break;
sewardjc2ac51e2004-07-12 01:03:26 +00006866 case 0xA9: /* TEST Iv, eAX */
6867 delta = dis_op_imm_A( sz, Iop_And8, False, delta, "test" );
6868 break;
6869
sewardjc9a65702004-07-07 16:32:57 +00006870//-- /* ------------------------ opl Ev, Gv ----------------- */
6871//--
6872//-- case 0x02: /* ADD Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00006873//-- delta = dis_op2_E_G ( cb, sorb, False, ADD, True, 1, delta, "add" );
sewardjc9a65702004-07-07 16:32:57 +00006874//-- break;
sewardj9334b0f2004-07-10 22:43:54 +00006875 case 0x03: /* ADD Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00006876 delta = dis_op2_E_G ( sorb, False, Iop_Add8, True, sz, delta, "add" );
sewardj9334b0f2004-07-10 22:43:54 +00006877 break;
6878
sewardj7ed22952004-07-29 00:09:58 +00006879 case 0x0A: /* OR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00006880 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, 1, delta, "or" );
sewardj7ed22952004-07-29 00:09:58 +00006881 break;
sewardjc2ac51e2004-07-12 01:03:26 +00006882 case 0x0B: /* OR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00006883 delta = dis_op2_E_G ( sorb, False, Iop_Or8, True, sz, delta, "or" );
sewardjc2ac51e2004-07-12 01:03:26 +00006884 break;
sewardjc9a65702004-07-07 16:32:57 +00006885//--
6886//-- case 0x12: /* ADC Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00006887//-- delta = dis_op2_E_G ( sorb, True, ADC, True, 1, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +00006888//-- break;
6889//-- case 0x13: /* ADC Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00006890//-- delta = dis_op2_E_G ( sorb, True, ADC, True, sz, delta, "adc" );
sewardjc9a65702004-07-07 16:32:57 +00006891//-- break;
6892//--
6893//-- case 0x1A: /* SBB Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00006894//-- delta = dis_op2_E_G ( sorb, True, SBB, True, 1, delta, "sbb" );
sewardjc9a65702004-07-07 16:32:57 +00006895//-- break;
sewardj180e8b32004-07-29 01:40:11 +00006896 case 0x1B: /* SBB Ev,Gv */
6897 delta = dis_op2_E_G ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
sewardj940e8c92004-07-11 16:53:24 +00006898 break;
6899
sewardj180e8b32004-07-29 01:40:11 +00006900//-- case 0x22: /* AND Eb,Gb */
6901//-- delta = dis_op2_E_G ( sorb, False, AND, True, 1, delta, "and" );
sewardjc9a65702004-07-07 16:32:57 +00006902//-- break;
sewardj180e8b32004-07-29 01:40:11 +00006903 case 0x23: /* AND Ev,Gv */
6904 delta = dis_op2_E_G ( sorb, False, Iop_And8, True, sz, delta, "and" );
6905 break;
6906
6907 case 0x2A: /* SUB Eb,Gb */
6908 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
6909 break;
sewardj0611d802004-07-11 02:37:54 +00006910 case 0x2B: /* SUB Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00006911 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
sewardj0611d802004-07-11 02:37:54 +00006912 break;
sewardjc2ac51e2004-07-12 01:03:26 +00006913
6914 case 0x32: /* XOR Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00006915 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +00006916 break;
sewardj1813dbe2004-07-28 17:09:04 +00006917 case 0x33: /* XOR Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00006918 delta = dis_op2_E_G ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
sewardj1813dbe2004-07-28 17:09:04 +00006919 break;
6920
sewardjc2ac51e2004-07-12 01:03:26 +00006921 case 0x3A: /* CMP Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00006922 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardjc2ac51e2004-07-12 01:03:26 +00006923 break;
sewardje90ad6a2004-07-10 19:02:10 +00006924 case 0x3B: /* CMP Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00006925 delta = dis_op2_E_G ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +00006926 break;
6927
sewardj0611d802004-07-11 02:37:54 +00006928 case 0x84: /* TEST Eb,Gb */
sewardj180e8b32004-07-29 01:40:11 +00006929 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, 1, delta, "test" );
sewardj0611d802004-07-11 02:37:54 +00006930 break;
sewardje05c42c2004-07-08 20:25:10 +00006931 case 0x85: /* TEST Ev,Gv */
sewardj180e8b32004-07-29 01:40:11 +00006932 delta = dis_op2_E_G ( sorb, False, Iop_And8, False, sz, delta, "test" );
sewardje05c42c2004-07-08 20:25:10 +00006933 break;
6934
sewardj180e8b32004-07-29 01:40:11 +00006935 /* ------------------------ opl Gv, Ev ----------------- */
6936
6937 case 0x00: /* ADD Gb,Eb */
6938 delta = dis_op2_G_E ( sorb, False, Iop_Add8, True, 1, delta, "add" );
6939 break;
sewardje05c42c2004-07-08 20:25:10 +00006940 case 0x01: /* ADD Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00006941 delta = dis_op2_G_E ( sorb, False, Iop_Add8, True, sz, delta, "add" );
sewardje05c42c2004-07-08 20:25:10 +00006942 break;
6943
sewardj940e8c92004-07-11 16:53:24 +00006944 case 0x08: /* OR Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +00006945 delta = dis_op2_G_E ( sorb, False, Iop_Or8, True, 1, delta, "or" );
sewardj940e8c92004-07-11 16:53:24 +00006946 break;
sewardj9334b0f2004-07-10 22:43:54 +00006947 case 0x09: /* OR Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00006948 delta = dis_op2_G_E ( sorb, False, Iop_Or8, True, sz, delta, "or" );
sewardj9334b0f2004-07-10 22:43:54 +00006949 break;
6950
sewardja2384712004-07-29 14:36:40 +00006951 case 0x10: /* ADC Gb,Eb */
6952 delta = dis_op2_G_E ( sorb, True, Iop_Add8, True, 1, delta, "adc" );
6953 break;
sewardjcaca9d02004-07-28 07:11:32 +00006954 case 0x11: /* ADC Gv,Ev */
6955 delta = dis_op2_G_E ( sorb, True, Iop_Add8, True, sz, delta, "adc" );
6956 break;
6957
sewardja2384712004-07-29 14:36:40 +00006958 case 0x18: /* SBB Gb,Eb */
6959 delta = dis_op2_G_E ( sorb, True, Iop_Sub8, True, 1, delta, "sbb" );
6960 break;
sewardjcaca9d02004-07-28 07:11:32 +00006961 case 0x19: /* SBB Gv,Ev */
6962 delta = dis_op2_G_E ( sorb, True, Iop_Sub8, True, sz, delta, "sbb" );
6963 break;
6964
sewardja2384712004-07-29 14:36:40 +00006965 case 0x20: /* AND Gb,Eb */
6966 delta = dis_op2_G_E ( sorb, False, Iop_And8, True, 1, delta, "and" );
6967 break;
sewardj0611d802004-07-11 02:37:54 +00006968 case 0x21: /* AND Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00006969 delta = dis_op2_G_E ( sorb, False, Iop_And8, True, sz, delta, "and" );
sewardj0611d802004-07-11 02:37:54 +00006970 break;
6971
sewardj180e8b32004-07-29 01:40:11 +00006972 case 0x28: /* SUB Gb,Eb */
6973 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, True, 1, delta, "sub" );
6974 break;
sewardje05c42c2004-07-08 20:25:10 +00006975 case 0x29: /* SUB Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00006976 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, True, sz, delta, "sub" );
sewardje05c42c2004-07-08 20:25:10 +00006977 break;
6978
sewardjc2ac51e2004-07-12 01:03:26 +00006979 case 0x30: /* XOR Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +00006980 delta = dis_op2_G_E ( sorb, False, Iop_Xor8, True, 1, delta, "xor" );
sewardjc2ac51e2004-07-12 01:03:26 +00006981 break;
sewardje87b4842004-07-10 12:23:30 +00006982 case 0x31: /* XOR Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00006983 delta = dis_op2_G_E ( sorb, False, Iop_Xor8, True, sz, delta, "xor" );
sewardje87b4842004-07-10 12:23:30 +00006984 break;
6985
sewardj0611d802004-07-11 02:37:54 +00006986 case 0x38: /* CMP Gb,Eb */
sewardjcaca9d02004-07-28 07:11:32 +00006987 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, False, 1, delta, "cmp" );
sewardj0611d802004-07-11 02:37:54 +00006988 break;
sewardje90ad6a2004-07-10 19:02:10 +00006989 case 0x39: /* CMP Gv,Ev */
sewardjcaca9d02004-07-28 07:11:32 +00006990 delta = dis_op2_G_E ( sorb, False, Iop_Sub8, False, sz, delta, "cmp" );
sewardje90ad6a2004-07-10 19:02:10 +00006991 break;
6992
sewardj9334b0f2004-07-10 22:43:54 +00006993 /* ------------------------ POP ------------------------ */
6994
6995 case 0x58: /* POP eAX */
6996 case 0x59: /* POP eCX */
6997 case 0x5A: /* POP eDX */
6998 case 0x5B: /* POP eBX */
6999 case 0x5D: /* POP eBP */
7000 case 0x5E: /* POP eSI */
7001 case 0x5F: /* POP eDI */
7002 case 0x5C: /* POP eSP */
7003 vassert(sz == 2 || sz == 4);
7004 t1 = newTemp(szToITy(sz)); t2 = newTemp(Ity_I32);
7005 assign(t2, getIReg(4, R_ESP));
7006 assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
7007 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
7008 putIReg(sz, opc-0x58, mkexpr(t1));
7009 DIP("pop%c %s\n", nameISize(sz), nameIReg(sz,opc-0x58));
7010 break;
7011
sewardja2384712004-07-29 14:36:40 +00007012 case 0x9D: /* POPF */
7013 vassert(sz == 2 || sz == 4);
7014 vassert(sz == 4); // until we know a sz==2 test case exists
7015 t1 = newTemp(Ity_I32); t2 = newTemp(Ity_I32);
7016 assign(t2, getIReg(4, R_ESP));
sewardjc22a6fd2004-07-29 23:41:47 +00007017 assign(t1, widenUto32(loadLE(szToITy(sz),mkexpr(t2))));
sewardja2384712004-07-29 14:36:40 +00007018 putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
7019 /* t1 is the flag word. Mask out everything OSZACP and
7020 set the flags thunk to CC_OP_COPY. */
7021 stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
7022 stmt( IRStmt_Put( OFFB_CC_DST, mkU32(0) ));
7023 stmt( IRStmt_Put( OFFB_CC_SRC,
7024 binop(Iop_And32,
7025 mkexpr(t1),
7026 mkU32( CC_MASK_C | CC_MASK_P | CC_MASK_A
7027 | CC_MASK_Z | CC_MASK_S| CC_MASK_O )
7028 )
7029 )
7030 );
7031
7032 /* Also need to set the D flag, which is held in bit 10 of t1.
7033 If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
7034 stmt( IRStmt_Put(
7035 OFFB_DFLAG,
7036 IRExpr_Mux0X(
7037 unop(Iop_32to8,
7038 binop(Iop_And32,
7039 binop(Iop_Shr32, mkexpr(t1), mkU8(10)),
7040 mkU32(1))),
7041 mkU32(1),
7042 mkU32(0xFFFFFFFF)))
7043 );
7044
7045 DIP("popf%c\n", nameISize(sz));
7046 break;
7047
sewardjc9a65702004-07-07 16:32:57 +00007048//-- case 0x61: /* POPA */
7049//-- { Int reg;
7050//-- /* Just to keep things sane, we assert for a size 4. It's
7051//-- probably OK for size 2 as well, but I'd like to find a test
7052//-- case; ie, have the assertion fail, before committing to it.
7053//-- If it fails for you, uncomment the sz == 2 bit, try again,
7054//-- and let me know whether or not it works. (jseward@acm.org). */
7055//-- vg_assert(sz == 4 /* || sz == 2 */);
7056//--
7057//-- /* Eight values are popped, one per register, but the value of
7058//-- %esp on the stack is ignored and instead incremented (in one
7059//-- hit at the end) for each of the values. */
7060//-- t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
7061//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
7062//-- uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t3);
7063//--
7064//-- /* Do %edi, %esi, %ebp */
7065//-- for (reg = 7; reg >= 5; reg--) {
7066//-- uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
7067//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
7068//-- uLiteral(cb, sz);
7069//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
7070//-- }
7071//-- /* Ignore (skip) value of %esp on stack. */
7072//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
7073//-- uLiteral(cb, sz);
7074//-- /* Do %ebx, %edx, %ecx, %eax */
7075//-- for (reg = 3; reg >= 0; reg--) {
7076//-- uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
7077//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
7078//-- uLiteral(cb, sz);
7079//-- uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
7080//-- }
7081//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t3);
7082//-- uLiteral(cb, sz * 8); /* One 'sz' per register */
7083//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
7084//-- DIP("popa%c\n", nameISize(sz));
7085//-- break;
7086//-- }
7087//--
7088//-- case 0x8F: /* POPL/POPW m32 */
7089//-- { UInt pair1;
7090//-- Int tmpa;
7091//-- UChar rm = getIByte(delta);
7092//--
7093//-- /* make sure this instruction is correct POP */
7094//-- vg_assert(!epartIsReg(rm) && (gregOfRM(rm) == 0));
7095//-- /* and has correct size */
7096//-- vg_assert(sz == 4);
7097//--
7098//-- t1 = newTemp(cb); t3 = newTemp(cb);
7099//-- /* set t1 to ESP: t1 = ESP */
7100//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
7101//-- /* load M[ESP] to virtual register t3: t3 = M[t1] */
7102//-- uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t3);
7103//--
7104//-- /* increase ESP; must be done before the STORE. Intel manual says:
7105//-- If the ESP register is used as a base register for addressing
7106//-- a destination operand in memory, the POP instruction computes
7107//-- the effective address of the operand after it increments the
7108//-- ESP register.
7109//-- */
7110//-- uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1);
7111//-- uLiteral(cb, sz);
7112//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
7113//--
7114//-- /* resolve MODR/M */
7115//-- pair1 = disAMode ( cb, sorb, eip, dis_buf );
7116//--
7117//-- tmpa = LOW24(pair1);
7118//-- /* uInstr2(cb, LOAD, sz, TempReg, tmpa, TempReg, tmpa); */
7119//-- /* store value from stack in memory, M[m32] = t3 */
7120//-- uInstr2(cb, STORE, 4, TempReg, t3, TempReg, tmpa);
7121//--
7122//-- DIP("popl %s\n", dis_buf);
7123//--
7124//-- eip += HI8(pair1);
7125//-- break;
7126//-- }
7127//--
7128//-- case 0x1F: /* POP %DS */
7129//-- dis_pop_segreg( cb, R_DS, sz ); break;
7130//-- case 0x07: /* POP %ES */
7131//-- dis_pop_segreg( cb, R_ES, sz ); break;
7132//-- case 0x17: /* POP %SS */
7133//-- dis_pop_segreg( cb, R_SS, sz ); break;
sewardjd1061ab2004-07-08 01:45:30 +00007134
7135 /* ------------------------ PUSH ----------------------- */
7136
7137 case 0x50: /* PUSH eAX */
7138 case 0x51: /* PUSH eCX */
7139 case 0x52: /* PUSH eDX */
7140 case 0x53: /* PUSH eBX */
7141 case 0x55: /* PUSH eBP */
7142 case 0x56: /* PUSH eSI */
7143 case 0x57: /* PUSH eDI */
7144 case 0x54: /* PUSH eSP */
7145 /* This is the Right Way, in that the value to be pushed is
7146 established before %esp is changed, so that pushl %esp
7147 correctly pushes the old value. */
7148 vassert(sz == 2 || sz == 4);
7149 ty = sz==2 ? Ity_I16 : Ity_I32;
7150 t1 = newTemp(ty); t2 = newTemp(ty);
sewardj41f43bc2004-07-08 14:23:22 +00007151 assign(t1, getIReg(sz, opc-0x50));
7152 assign(t2, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)));
7153 putIReg(4, R_ESP, mkexpr(t2) );
7154 storeLE(mkexpr(t2),mkexpr(t1));
sewardjd1061ab2004-07-08 01:45:30 +00007155 DIP("push%c %s\n", nameISize(sz), nameIReg(sz,opc-0x50));
7156 break;
7157
7158
sewardj0c12ea82004-07-12 08:18:16 +00007159 case 0x68: /* PUSH Iv */
7160 d32 = getUDisp(sz,delta); delta += sz;
7161 goto do_push_I;
sewardj741153c2004-07-25 23:39:13 +00007162 case 0x6A: /* PUSH Ib, sign-extended to sz */
7163 d32 = getSDisp8(delta); delta += 1;
7164 goto do_push_I;
sewardj0c12ea82004-07-12 08:18:16 +00007165 do_push_I:
7166 ty = szToITy(sz);
7167 t1 = newTemp(Ity_I32); t2 = newTemp(ty);
7168 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
7169 putIReg(4, R_ESP, mkexpr(t1) );
7170 storeLE( mkexpr(t1), mkU(ty,d32) );
7171 DIP("push%c $0x%x\n", nameISize(sz), d32);
7172 break;
7173
sewardja2384712004-07-29 14:36:40 +00007174 case 0x9C: /* PUSHF */ {
7175 IRTemp t3;
7176 vassert(sz == 2 || sz == 4);
7177 vassert(sz == 4); // wait for sz==2 test case
7178
7179 t1 = newTemp(Ity_I32);
7180 assign( t1, binop(Iop_Sub32,getIReg(4,R_ESP),mkU32(sz)) );
7181 putIReg(4, R_ESP, mkexpr(t1) );
7182
7183 t2 = newTemp(Ity_I32);
7184 assign( t2, mk_calculate_eflags_all() );
7185
7186 /* Patch in the D flag. This can simply be the inversion
7187 of bit 10 of baseBlock[OFFB_DFLAG]. */
7188 t3 = newTemp(Ity_I32);
7189 assign( t3, binop(Iop_Or32,
7190 mkexpr(t2),
7191 binop(Iop_And32,
7192 unop(Iop_Not32, IRExpr_Get(OFFB_DFLAG,Ity_I32)),
7193 mkU32(1<<10)))
7194 );
7195 /* if sz==2, the stored value needs to be narrowed. */
7196 if (sz == 2)
7197 storeLE( mkexpr(t1), unop(Iop_32to16,mkexpr(t3)) );
7198 else
7199 storeLE( mkexpr(t1), mkexpr(t3) );
7200
7201 DIP("pushf%c\n", nameISize(sz));
7202 break;
7203 }
7204
sewardjc9a65702004-07-07 16:32:57 +00007205//-- case 0x60: /* PUSHA */
7206//-- { Int reg;
7207//-- /* Just to keep things sane, we assert for a size 4. It's
7208//-- probably OK for size 2 as well, but I'd like to find a test
7209//-- case; ie, have the assertion fail, before committing to it.
7210//-- If it fails for you, uncomment the sz == 2 bit, try again,
7211//-- and let me know whether or not it works. (jseward@acm.org). */
7212//-- vg_assert(sz == 4 /* || sz == 2 */);
7213//--
7214//-- /* This is the Right Way, in that the value to be pushed is
7215//-- established before %esp is changed, so that pusha
7216//-- correctly pushes the old %esp value. New value of %esp is
7217//-- pushed at start. */
7218//-- t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
7219//-- t4 = newTemp(cb);
7220//-- uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
7221//-- uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
7222//-- uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t4);
7223//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t4);
7224//-- uLiteral(cb, sz * 8); /* One 'sz' per register. */
7225//-- uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_ESP);
7226//-- /* Do %eax, %ecx, %edx, %ebx */
7227//-- for (reg = 0; reg <= 3; reg++) {
7228//-- uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
7229//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
7230//-- uLiteral(cb, sz);
7231//-- uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
7232//-- }
7233//-- /* Push old value of %esp */
7234//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
7235//-- uLiteral(cb, sz);
7236//-- uInstr2(cb, STORE, sz, TempReg, t3, TempReg, t2);
7237//-- /* Do %ebp, %esi, %edi */
7238//-- for (reg = 5; reg <= 7; reg++) {
7239//-- uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
7240//-- uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
7241//-- uLiteral(cb, sz);
7242//-- uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
7243//-- }
7244//-- DIP("pusha%c\n", nameISize(sz));
7245//-- break;
7246//-- }
7247//--
7248//-- case 0x0E: /* PUSH %CS */
7249//-- dis_push_segreg( cb, R_CS, sz ); break;
7250//-- case 0x1E: /* PUSH %DS */
7251//-- dis_push_segreg( cb, R_DS, sz ); break;
7252//-- case 0x06: /* PUSH %ES */
7253//-- dis_push_segreg( cb, R_ES, sz ); break;
7254//-- case 0x16: /* PUSH %SS */
7255//-- dis_push_segreg( cb, R_SS, sz ); break;
7256//--
7257//-- /* ------------------------ SCAS et al ----------------- */
7258//--
7259//-- case 0xA4: /* MOVS, no REP prefix */
7260//-- case 0xA5:
7261//-- dis_string_op( cb, dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
7262//-- break;
7263//--
7264//-- case 0xA6: /* CMPSb, no REP prefix */
7265//-- case 0xA7:
7266//-- dis_string_op( cb, dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
7267//-- break;
7268//--
7269//-- case 0xAA: /* STOS, no REP prefix */
7270//-- case 0xAB:
7271//-- dis_string_op( cb, dis_STOS, ( opc == 0xAA ? 1 : sz ), "stos", sorb );
7272//-- break;
7273//--
7274//-- case 0xAC: /* LODS, no REP prefix */
7275//-- case 0xAD:
7276//-- dis_string_op( cb, dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
7277//-- break;
7278//--
7279//-- case 0xAE: /* SCAS, no REP prefix */
7280//-- case 0xAF:
sewardj64e1d652004-07-12 14:00:46 +00007281//-- dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
sewardjc9a65702004-07-07 16:32:57 +00007282//-- break;
sewardj64e1d652004-07-12 14:00:46 +00007283
7284
7285 case 0xFC: /* CLD */
sewardjeeb9ef82004-07-15 12:39:03 +00007286 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(1)) );
sewardj64e1d652004-07-12 14:00:46 +00007287 DIP("cld\n");
7288 break;
7289
sewardj1813dbe2004-07-28 17:09:04 +00007290 case 0xFD: /* STD */
7291 stmt( IRStmt_Put( OFFB_DFLAG, mkU32(0xFFFFFFFF)) );
7292 DIP("std\n");
7293 break;
7294
sewardjc9a65702004-07-07 16:32:57 +00007295//-- case 0xF8: /* CLC */
7296//-- uInstr0(cb, CALLM_S, 0);
7297//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CLC));
7298//-- uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
7299//-- uInstr0(cb, CALLM_E, 0);
7300//-- DIP("clc\n");
7301//-- break;
7302//--
7303//-- case 0xF9: /* STC */
7304//-- uInstr0(cb, CALLM_S, 0);
7305//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_STC));
7306//-- uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
7307//-- uInstr0(cb, CALLM_E, 0);
7308//-- DIP("stc\n");
7309//-- break;
7310//--
7311//-- case 0xF5: /* CMC */
7312//-- uInstr0(cb, CALLM_S, 0);
7313//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CMC));
7314//-- uFlagsRWU(cb, FlagC, FlagC, FlagsOSZAP);
7315//-- uInstr0(cb, CALLM_E, 0);
7316//-- DIP("cmc\n");
7317//-- break;
sewardj82292882004-07-27 00:15:59 +00007318
7319 /* REPNE prefix insn */
7320 case 0xF2: {
7321 Addr32 eip_orig = guest_eip + delta - 1;
7322 vassert(sorb == 0);
7323 abyte = getIByte(delta); delta++;
7324
7325 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
7326 *isEnd = True;
7327
7328 switch (abyte) {
7329 /* According to the Intel manual, "repne movs" should never occur, but
7330 * in practice it has happened, so allow for it here... */
sewardj180e8b32004-07-29 01:40:11 +00007331 case 0xA4: sz = 1; /* REPNE MOVS<sz> */
sewardjc9a65702004-07-07 16:32:57 +00007332//-- case 0xA5:
sewardj180e8b32004-07-29 01:40:11 +00007333 // dis_REP_op ( CondNZ, dis_MOVS, sz, eip_orig,
7334 // guest_eip+delta, "repne movs" );
7335 // break;
sewardjc9a65702004-07-07 16:32:57 +00007336//--
7337//-- case 0xA6: sz = 1; /* REPNE CMPS<sz> */
7338//-- case 0xA7:
7339//-- dis_REP_op ( cb, CondNZ, dis_CMPS, sz, eip_orig, eip, "repne cmps" );
7340//-- break;
7341//--
sewardj82292882004-07-27 00:15:59 +00007342 case 0xAE: sz = 1; /* REPNE SCAS<sz> */
sewardjc9a65702004-07-07 16:32:57 +00007343//-- case 0xAF:
sewardj82292882004-07-27 00:15:59 +00007344 dis_REP_op ( CondNZ, dis_SCAS, sz, eip_orig,
7345 guest_eip+delta, "repne scas" );
7346 break;
7347
7348 default:
7349 goto decode_failure;
7350 }
7351 break;
7352 }
sewardj64e1d652004-07-12 14:00:46 +00007353
7354 /* REP/REPE prefix insn (for SCAS and CMPS, 0xF3 means REPE,
7355 for the rest, it means REP) */
7356 case 0xF3: {
7357 Addr32 eip_orig = guest_eip + delta - 1;
7358 vassert(sorb == 0);
7359 abyte = getIByte(delta); delta++;
7360
7361 if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
7362 *isEnd = True;
7363
7364 switch (abyte) {
7365 case 0xA4: sz = 1; /* REP MOVS<sz> */
7366 case 0xA5:
7367 dis_REP_op ( CondAlways, dis_MOVS, sz, eip_orig,
7368 guest_eip+delta, "rep movs" );
7369 break;
7370
7371 case 0xA6: sz = 1; /* REPE CMP<sz> */
sewardjc9a65702004-07-07 16:32:57 +00007372//-- case 0xA7:
sewardj64e1d652004-07-12 14:00:46 +00007373 dis_REP_op ( CondZ, dis_CMPS, sz, eip_orig,
7374 guest_eip+delta, "repe cmps" );
7375 break;
7376
7377 case 0xAA: sz = 1; /* REP STOS<sz> */
7378 case 0xAB:
7379 dis_REP_op ( CondAlways, dis_STOS, sz, eip_orig,
7380 guest_eip+delta, "rep stos" );
7381 break;
sewardjc9a65702004-07-07 16:32:57 +00007382//--
7383//-- case 0xAE: sz = 1; /* REPE SCAS<sz> */
7384//-- case 0xAF:
7385//-- dis_REP_op ( cb, CondZ, dis_SCAS, sz, eip_orig, eip, "repe scas" );
7386//-- break;
7387//--
7388//-- case 0x90: /* REP NOP (PAUSE) */
7389//-- /* a hint to the P4 re spin-wait loop */
7390//-- DIP("rep nop (P4 pause)\n");
7391//-- jmp_lit(cb, eip);
7392//-- LAST_UINSTR(cb).jmpkind = JmpYield;
7393//-- break;
7394//--
7395//-- case 0xC3: /* REP RET */
7396//-- /* AMD K7/K8-specific optimisation; faster than vanilla RET */
7397//-- dis_ret(cb, 0);
7398//-- DIP("rep ret\n");
7399//-- break;
sewardj64e1d652004-07-12 14:00:46 +00007400
7401 default:
7402 goto decode_failure;
7403 }
7404 break;
7405 }
sewardj0611d802004-07-11 02:37:54 +00007406
7407 /* ------------------------ XCHG ----------------------- */
7408
7409 case 0x86: /* XCHG Gb,Eb */
7410 sz = 1;
7411 /* Fall through ... */
7412 case 0x87: /* XCHG Gv,Ev */
7413 modrm = getIByte(delta);
7414 ty = szToITy(sz);
7415 t1 = newTemp(ty); t2 = newTemp(ty);
7416 if (epartIsReg(modrm)) {
7417 assign(t1, getIReg(sz, eregOfRM(modrm)));
7418 assign(t2, getIReg(sz, gregOfRM(modrm)));
7419 putIReg(sz, gregOfRM(modrm), mkexpr(t1));
7420 putIReg(sz, eregOfRM(modrm), mkexpr(t2));
7421 delta++;
7422 DIP("xchg%c %s, %s\n",
7423 nameISize(sz), nameIReg(sz,gregOfRM(modrm)),
7424 nameIReg(sz,eregOfRM(modrm)));
7425 } else {
sewardj0c12ea82004-07-12 08:18:16 +00007426 addr = disAMode ( &alen, sorb, delta, dis_buf );
7427 assign( t1, loadLE(ty,mkexpr(addr)) );
7428 assign( t2, getIReg(sz,gregOfRM(modrm)) );
7429 storeLE( mkexpr(addr), mkexpr(t2) );
7430 putIReg( sz, gregOfRM(modrm), mkexpr(t1) );
7431 delta += alen;
sewardj0611d802004-07-11 02:37:54 +00007432 DIP("xchg%c %s, %s\n", nameISize(sz),
7433 nameIReg(sz,gregOfRM(modrm)), dis_buf);
sewardj0611d802004-07-11 02:37:54 +00007434 }
7435 break;
sewardje87b4842004-07-10 12:23:30 +00007436
7437 case 0x90: /* XCHG eAX,eAX */
7438 DIP("nop\n");
7439 break;
sewardj64e1d652004-07-12 14:00:46 +00007440 case 0x91: /* XCHG eAX,eCX */
7441 case 0x92: /* XCHG eAX,eDX */
7442 case 0x93: /* XCHG eAX,eBX */
7443 case 0x94: /* XCHG eAX,eSP */
7444 case 0x95: /* XCHG eAX,eBP */
7445 case 0x96: /* XCHG eAX,eSI */
7446 case 0x97: /* XCHG eAX,eDI */
7447 codegen_xchg_eAX_Reg ( sz, opc - 0x90 );
7448 break;
7449
sewardjc9a65702004-07-07 16:32:57 +00007450//-- /* ------------------------ XLAT ----------------------- */
7451//--
7452//-- case 0xD7: /* XLAT */
7453//-- t1 = newTemp(cb); t2 = newTemp(cb);
7454//-- uInstr2(cb, GET, sz, ArchReg, R_EBX, TempReg, t1); /* get eBX */
7455//-- handleSegOverride( cb, sorb, t1 ); /* make t1 DS:eBX */
7456//-- uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t2); /* get AL */
7457//-- /* Widen %AL to 32 bits, so it's all defined when we add it. */
7458//-- uInstr1(cb, WIDEN, 4, TempReg, t2);
7459//-- uWiden(cb, 1, False);
7460//-- uInstr2(cb, ADD, sz, TempReg, t2, TempReg, t1); /* add AL to eBX */
7461//-- uInstr2(cb, LOAD, 1, TempReg, t1, TempReg, t2); /* get byte at t1 into t2 */
7462//-- uInstr2(cb, PUT, 1, TempReg, t2, ArchReg, R_AL); /* put byte into AL */
7463//--
7464//-- DIP("xlat%c [ebx]\n", nameISize(sz));
7465//-- break;
7466//--
7467//-- /* ------------------------ IN / OUT ----------------------- */
7468//--
7469//-- case 0xE4: /* IN ib, %al */
7470//-- case 0xE5: /* IN ib, %{e}ax */
7471//-- case 0xEC: /* IN (%dx),%al */
7472//-- case 0xED: /* IN (%dx),%{e}ax */
7473//-- t1 = newTemp(cb);
7474//-- t2 = newTemp(cb);
7475//-- t3 = newTemp(cb);
7476//--
7477//-- uInstr0(cb, CALLM_S, 0);
7478//-- /* operand size? */
7479//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
7480//-- uLiteral(cb, ( opc == 0xE4 || opc == 0xEC ) ? 1 : sz);
7481//-- uInstr1(cb, PUSH, 4, TempReg, t1);
7482//-- /* port number ? */
7483//-- if ( opc == 0xE4 || opc == 0xE5 ) {
7484//-- abyte = getUChar(eip); eip++;
7485//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
7486//-- uLiteral(cb, abyte);
7487//-- }
7488//-- else
7489//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
7490//--
7491//-- uInstr1(cb, PUSH, 4, TempReg, t2);
7492//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_IN));
7493//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
7494//-- uInstr1(cb, POP, 4, TempReg, t2);
7495//-- uInstr1(cb, CLEAR, 0, Lit16, 4);
7496//-- uInstr0(cb, CALLM_E, 0);
7497//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EAX);
7498//-- if ( opc == 0xE4 || opc == 0xE5 ) {
7499//-- DIP("in 0x%x, %%eax/%%ax/%%al\n", getUChar(eip-1) );
7500//-- } else {
7501//-- DIP("in (%%dx), %%eax/%%ax/%%al\n");
7502//-- }
7503//-- break;
7504//-- case 0xE6: /* OUT %al,ib */
7505//-- case 0xE7: /* OUT %{e}ax,ib */
7506//-- case 0xEE: /* OUT %al,(%dx) */
7507//-- case 0xEF: /* OUT %{e}ax,(%dx) */
7508//-- t1 = newTemp(cb);
7509//-- t2 = newTemp(cb);
7510//-- t3 = newTemp(cb);
7511//--
7512//-- uInstr0(cb, CALLM_S, 0);
7513//-- /* operand size? */
7514//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
7515//-- uLiteral(cb, ( opc == 0xE6 || opc == 0xEE ) ? 1 : sz);
7516//-- uInstr1(cb, PUSH, 4, TempReg, t1);
7517//-- /* port number ? */
7518//-- if ( opc == 0xE6 || opc == 0xE7 ) {
7519//-- abyte = getUChar(eip); eip++;
7520//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
7521//-- uLiteral(cb, abyte);
7522//-- }
7523//-- else
7524//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
7525//-- uInstr1(cb, PUSH, 4, TempReg, t2);
7526//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t3);
7527//-- uInstr1(cb, PUSH, 4, TempReg, t3);
7528//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_OUT));
7529//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
7530//-- uInstr1(cb, CLEAR, 0, Lit16, 12);
7531//-- uInstr0(cb, CALLM_E, 0);
7532//-- if ( opc == 0xE4 || opc == 0xE5 ) {
7533//-- DIP("out %%eax/%%ax/%%al, 0x%x\n", getUChar(eip-1) );
7534//-- } else {
7535//-- DIP("out %%eax/%%ax/%%al, (%%dx)\n");
7536//-- }
7537//-- break;
sewardj0611d802004-07-11 02:37:54 +00007538
7539 /* ------------------------ (Grp1 extensions) ---------- */
7540
7541 case 0x80: /* Grp1 Ib,Eb */
7542 modrm = getIByte(delta);
7543 am_sz = lengthAMode(delta);
7544 sz = 1;
7545 d_sz = 1;
sewardjc2ac51e2004-07-12 01:03:26 +00007546 d32 = getUChar(delta + am_sz);
sewardj0611d802004-07-11 02:37:54 +00007547 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
7548 break;
sewardje05c42c2004-07-08 20:25:10 +00007549
7550 case 0x81: /* Grp1 Iv,Ev */
7551 modrm = getIByte(delta);
7552 am_sz = lengthAMode(delta);
7553 d_sz = sz;
7554 d32 = getUDisp(d_sz, delta + am_sz);
7555 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
7556 break;
sewardjd1061ab2004-07-08 01:45:30 +00007557
7558 case 0x83: /* Grp1 Ib,Ev */
7559 modrm = getIByte(delta);
7560 am_sz = lengthAMode(delta);
7561 d_sz = 1;
7562 d32 = getSDisp8(delta + am_sz);
7563 delta = dis_Grp1 ( sorb, delta, modrm, am_sz, d_sz, sz, d32 );
7564 break;
7565
sewardjc2ac51e2004-07-12 01:03:26 +00007566 /* ------------------------ (Grp2 extensions) ---------- */
7567
7568 case 0xC0: /* Grp2 Ib,Eb */
7569 modrm = getIByte(delta);
7570 am_sz = lengthAMode(delta);
7571 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +00007572 d32 = getUChar(delta + am_sz);
sewardjc2ac51e2004-07-12 01:03:26 +00007573 sz = 1;
sewardj6d2638e2004-07-15 09:38:27 +00007574 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
7575 mkU8(d32 & 0xFF), NULL );
sewardjc2ac51e2004-07-12 01:03:26 +00007576 break;
sewardje90ad6a2004-07-10 19:02:10 +00007577
7578 case 0xC1: /* Grp2 Ib,Ev */
sewardjc2ac51e2004-07-12 01:03:26 +00007579 modrm = getIByte(delta);
sewardje90ad6a2004-07-10 19:02:10 +00007580 am_sz = lengthAMode(delta);
7581 d_sz = 1;
sewardj180e8b32004-07-29 01:40:11 +00007582 d32 = getUChar(delta + am_sz);
sewardj6d2638e2004-07-15 09:38:27 +00007583 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
7584 mkU8(d32 & 0xFF), NULL );
sewardje90ad6a2004-07-10 19:02:10 +00007585 break;
7586
sewardj180e8b32004-07-29 01:40:11 +00007587 case 0xD0: /* Grp2 1,Eb */
7588 modrm = getIByte(delta);
7589 am_sz = lengthAMode(delta);
7590 d_sz = 0;
7591 d32 = 1;
7592 sz = 1;
7593 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
7594 mkU8(d32), NULL );
7595 break;
sewardjc2ac51e2004-07-12 01:03:26 +00007596
7597 case 0xD1: /* Grp2 1,Ev */
7598 modrm = getUChar(delta);
7599 am_sz = lengthAMode(delta);
7600 d_sz = 0;
7601 d32 = 1;
sewardj6d2638e2004-07-15 09:38:27 +00007602 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
7603 mkU8(d32), NULL );
sewardjc2ac51e2004-07-12 01:03:26 +00007604 break;
7605
sewardj8c7f1ab2004-07-29 20:31:09 +00007606 case 0xD2: /* Grp2 CL,Eb */
7607 modrm = getUChar(delta);
7608 am_sz = lengthAMode(delta);
7609 d_sz = 0;
7610 sz = 1;
7611 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
7612 getIReg(1,R_ECX), "%cl" );
7613 break;
sewardj9334b0f2004-07-10 22:43:54 +00007614
7615 case 0xD3: /* Grp2 CL,Ev */
7616 modrm = getIByte(delta);
7617 am_sz = lengthAMode(delta);
7618 d_sz = 0;
7619 delta = dis_Grp2 ( sorb, delta, modrm, am_sz, d_sz, sz,
sewardj6d2638e2004-07-15 09:38:27 +00007620 getIReg(1,R_ECX), "%cl" );
sewardj9334b0f2004-07-10 22:43:54 +00007621 break;
7622
sewardj940e8c92004-07-11 16:53:24 +00007623 /* ------------------------ (Grp3 extensions) ---------- */
7624
7625 case 0xF6: /* Grp3 Eb */
7626 delta = dis_Grp3 ( sorb, 1, delta );
7627 break;
7628 case 0xF7: /* Grp3 Ev */
7629 delta = dis_Grp3 ( sorb, sz, delta );
7630 break;
7631
sewardjc2ac51e2004-07-12 01:03:26 +00007632 /* ------------------------ (Grp4 extensions) ---------- */
7633
7634 case 0xFE: /* Grp4 Eb */
7635 delta = dis_Grp4 ( sorb, delta );
7636 break;
sewardj0611d802004-07-11 02:37:54 +00007637
7638 /* ------------------------ (Grp5 extensions) ---------- */
7639
7640 case 0xFF: /* Grp5 Ev */
7641 delta = dis_Grp5 ( sorb, sz, delta, isEnd );
7642 break;
sewardje87b4842004-07-10 12:23:30 +00007643
7644 /* ------------------------ Escapes to 2-byte opcodes -- */
7645
7646 case 0x0F: {
7647 opc = getIByte(delta); delta++;
7648 switch (opc) {
7649
sewardjc9a65702004-07-07 16:32:57 +00007650//-- /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
7651//--
7652//-- case 0xBA: /* Grp8 Ib,Ev */
7653//-- modrm = getUChar(eip);
7654//-- am_sz = lengthAMode(eip);
7655//-- d32 = getSDisp8(eip + am_sz);
7656//-- eip = dis_Grp8_BT ( cb, sorb, eip, modrm, am_sz, sz, d32 );
7657//-- break;
7658//--
7659//-- /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
7660//--
7661//-- case 0xBC: /* BSF Gv,Ev */
7662//-- eip = dis_bs_E_G ( cb, sorb, sz, eip, True );
7663//-- break;
7664//-- case 0xBD: /* BSR Gv,Ev */
7665//-- eip = dis_bs_E_G ( cb, sorb, sz, eip, False );
7666//-- break;
7667//--
7668//-- /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
7669//--
7670//-- case 0xC8: /* BSWAP %eax */
7671//-- case 0xC9:
7672//-- case 0xCA:
7673//-- case 0xCB:
7674//-- case 0xCC:
7675//-- case 0xCD:
7676//-- case 0xCE:
7677//-- case 0xCF: /* BSWAP %edi */
7678//-- /* AFAICS from the Intel docs, this only exists at size 4. */
7679//-- vg_assert(sz == 4);
7680//-- t1 = newTemp(cb);
7681//-- uInstr2(cb, GET, 4, ArchReg, opc-0xC8, TempReg, t1);
7682//-- uInstr1(cb, BSWAP, 4, TempReg, t1);
7683//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, opc-0xC8);
7684//-- DIP("bswapl %s\n", nameIReg(4, opc-0xC8));
7685//-- break;
7686//--
7687//-- /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
7688//--
7689//-- case 0xA3: /* BT Gv,Ev */
7690//-- eip = dis_bt_G_E ( cb, sorb, sz, eip, BtOpNone );
7691//-- break;
7692//-- case 0xB3: /* BTR Gv,Ev */
7693//-- eip = dis_bt_G_E ( cb, sorb, sz, eip, BtOpReset );
7694//-- break;
7695//-- case 0xAB: /* BTS Gv,Ev */
7696//-- eip = dis_bt_G_E ( cb, sorb, sz, eip, BtOpSet );
7697//-- break;
7698//-- case 0xBB: /* BTC Gv,Ev */
7699//-- eip = dis_bt_G_E ( cb, sorb, sz, eip, BtOpComp );
7700//-- break;
7701//--
7702//-- /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
7703//--
7704//-- case 0x40:
7705//-- case 0x41:
7706//-- case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
7707//-- case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
7708//-- case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
7709//-- case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
7710//-- case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
7711//-- case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
7712//-- case 0x48: /* CMOVSb (cmov negative) */
7713//-- case 0x49: /* CMOVSb (cmov not negative) */
7714//-- case 0x4A: /* CMOVP (cmov parity even) */
7715//-- case 0x4B: /* CMOVNP (cmov parity odd) */
7716//-- case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
7717//-- case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
7718//-- case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
7719//-- case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
7720//-- eip = dis_cmov_E_G(cb, sorb, sz, (Condcode)(opc - 0x40), eip);
7721//-- break;
7722//--
7723//-- /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
7724//--
7725//-- case 0xB0: /* CMPXCHG Gv,Ev */
7726//-- eip = dis_cmpxchg_G_E ( cb, sorb, 1, eip );
7727//-- break;
7728//-- case 0xB1: /* CMPXCHG Gv,Ev */
7729//-- eip = dis_cmpxchg_G_E ( cb, sorb, sz, eip );
7730//-- break;
7731//-- case 0xC7: /* CMPXCHG8B Gv */
7732//-- eip = dis_cmpxchg8b ( cb, sorb, eip );
7733//-- break;
7734//--
7735//-- /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
7736//--
7737//-- case 0xA2: /* CPUID */
7738//-- if (!VG_(cpu_has_feature)(VG_X86_FEAT_CPUID))
7739//-- goto decode_failure;
7740//--
7741//-- t1 = newTemp(cb);
7742//-- t2 = newTemp(cb);
7743//-- t3 = newTemp(cb);
7744//-- t4 = newTemp(cb);
7745//-- uInstr0(cb, CALLM_S, 0);
7746//--
7747//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t1);
7748//-- uInstr1(cb, PUSH, 4, TempReg, t1);
7749//--
7750//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
7751//-- uLiteral(cb, 0);
7752//-- uInstr1(cb, PUSH, 4, TempReg, t2);
7753//--
7754//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t3);
7755//-- uLiteral(cb, 0);
7756//-- uInstr1(cb, PUSH, 4, TempReg, t3);
7757//--
7758//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
7759//-- uLiteral(cb, 0);
7760//-- uInstr1(cb, PUSH, 4, TempReg, t4);
7761//--
7762//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CPUID));
7763//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
7764//--
7765//-- uInstr1(cb, POP, 4, TempReg, t4);
7766//-- uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_EDX);
7767//--
7768//-- uInstr1(cb, POP, 4, TempReg, t3);
7769//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ECX);
7770//--
7771//-- uInstr1(cb, POP, 4, TempReg, t2);
7772//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBX);
7773//--
7774//-- uInstr1(cb, POP, 4, TempReg, t1);
7775//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
7776//--
7777//-- uInstr0(cb, CALLM_E, 0);
7778//-- DIP("cpuid\n");
7779//-- break;
7780//--
sewardj9334b0f2004-07-10 22:43:54 +00007781 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
7782
7783 case 0xB6: /* MOVZXb Eb,Gv */
7784 delta = dis_movx_E_G ( sorb, delta, 1, 4, False );
7785 break;
sewardj940e8c92004-07-11 16:53:24 +00007786 case 0xB7: /* MOVZXw Ew,Gv */
7787 delta = dis_movx_E_G ( sorb, delta, 2, 4, False );
7788 break;
7789
sewardj0611d802004-07-11 02:37:54 +00007790 case 0xBE: /* MOVSXb Eb,Gv */
7791 delta = dis_movx_E_G ( sorb, delta, 1, 4, True );
7792 break;
sewardj7ed22952004-07-29 00:09:58 +00007793 case 0xBF: /* MOVSXw Ew,Gv */
7794 delta = dis_movx_E_G ( sorb, delta, 2, 4, True );
7795 break;
7796
sewardjc9a65702004-07-07 16:32:57 +00007797//-- /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
7798//--
7799//-- case 0xC3: /* MOVNTI Gv,Ev */
7800//-- vg_assert(sz == 4);
7801//-- modrm = getUChar(eip);
7802//-- vg_assert(!epartIsReg(modrm));
7803//-- t1 = newTemp(cb);
7804//-- uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
7805//-- pair = disAMode ( cb, sorb, eip, dis_buf );
7806//-- t2 = LOW24(pair);
7807//-- eip += HI8(pair);
7808//-- uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
7809//-- DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
7810//-- break;
sewardjcf780b42004-07-13 18:42:17 +00007811
7812 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
7813
7814 case 0xAF: /* IMUL Ev, Gv */
7815 delta = dis_mul_E_G ( sorb, sz, delta, True );
7816 break;
sewardje87b4842004-07-10 12:23:30 +00007817
7818 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
7819 case 0x80:
7820 case 0x81:
7821 case 0x82: /* JBb/JNAEb (jump below) */
7822 case 0x83: /* JNBb/JAEb (jump not below) */
7823 case 0x84: /* JZb/JEb (jump zero) */
7824 case 0x85: /* JNZb/JNEb (jump not zero) */
7825 case 0x86: /* JBEb/JNAb (jump below or equal) */
7826 case 0x87: /* JNBEb/JAb (jump not below or equal) */
7827 case 0x88: /* JSb (jump negative) */
7828 case 0x89: /* JSb (jump not negative) */
7829 case 0x8A: /* JP (jump parity even) */
7830 case 0x8B: /* JNP/JPO (jump parity odd) */
7831 case 0x8C: /* JLb/JNGEb (jump less) */
7832 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
7833 case 0x8E: /* JLEb/JNGb (jump less or equal) */
7834 case 0x8F: /* JGb/JNLEb (jump greater) */
7835 d32 = (((Addr32)guest_code)+delta+4) + getUDisp32(delta);
7836 delta += 4;
7837 jcc_01((Condcode)(opc - 0x80), (Addr32)(guest_code+delta), d32);
7838 *isEnd = True;
7839 DIP("j%s-32 0x%x\n", name_Condcode(opc - 0x80), d32);
7840 break;
7841
sewardjc9a65702004-07-07 16:32:57 +00007842//--
7843//-- /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
7844//--
7845//-- case 0x31: /* RDTSC */
7846//-- t1 = newTemp(cb);
7847//-- t2 = newTemp(cb);
7848//-- t3 = newTemp(cb);
7849//-- uInstr0(cb, CALLM_S, 0);
7850//-- // Nb: even though these args aren't used by RDTSC_helper, need
7851//-- // them to be defined (for Memcheck). The TempRegs pushed must
7852//-- // also be distinct.
7853//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
7854//-- uLiteral(cb, 0);
7855//-- uInstr1(cb, PUSH, 4, TempReg, t1);
7856//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
7857//-- uLiteral(cb, 0);
7858//-- uInstr1(cb, PUSH, 4, TempReg, t2);
7859//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_RDTSC));
7860//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
7861//-- uInstr1(cb, POP, 4, TempReg, t3);
7862//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EDX);
7863//-- uInstr1(cb, POP, 4, TempReg, t3);
7864//-- uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EAX);
7865//-- uInstr0(cb, CALLM_E, 0);
7866//-- DIP("rdtsc\n");
7867//-- break;
sewardj77b86be2004-07-11 13:28:24 +00007868
7869 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
7870 case 0x90:
7871 case 0x91:
7872 case 0x92: /* set-Bb/set-NAEb (jump below) */
7873 case 0x93: /* set-NBb/set-AEb (jump not below) */
7874 case 0x94: /* set-Zb/set-Eb (jump zero) */
7875 case 0x95: /* set-NZb/set-NEb (jump not zero) */
7876 case 0x96: /* set-BEb/set-NAb (jump below or equal) */
7877 case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
7878 case 0x98: /* set-Sb (jump negative) */
7879 case 0x99: /* set-Sb (jump not negative) */
7880 case 0x9A: /* set-P (jump parity even) */
7881 case 0x9B: /* set-NP (jump parity odd) */
7882 case 0x9C: /* set-Lb/set-NGEb (jump less) */
7883 case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
7884 case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
7885 case 0x9F: /* set-Gb/set-NLEb (jump greater) */
7886 t1 = newTemp(Ity_I8);
7887 assign( t1, unop(Iop_1Uto8,calculate_condition(opc-0x90)) );
7888 modrm = getIByte(delta);
7889 if (epartIsReg(modrm)) {
7890 delta++;
7891 putIReg(1, eregOfRM(modrm), mkexpr(t1));
7892 DIP("set%s %s\n", name_Condcode(opc-0x90),
7893 nameIReg(1,eregOfRM(modrm)));
7894 } else {
sewardj750f4072004-07-26 22:39:11 +00007895 addr = disAMode ( &alen, sorb, delta, dis_buf );
7896 delta += alen;
7897 storeLE( mkexpr(addr), mkexpr(t1) );
7898 DIP("set%s %s\n", name_Condcode(opc-0x90), dis_buf);
sewardj77b86be2004-07-11 13:28:24 +00007899 }
7900 break;
7901
sewardj180e8b32004-07-29 01:40:11 +00007902 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
7903
7904 case 0xA4: /* SHLDv imm8,Gv,Ev */
7905 modrm = getIByte(delta);
7906 d32 = delta + lengthAMode(delta);
7907 vex_sprintf(dis_buf, "$%d", delta);
7908 delta = dis_SHLRD_Gv_Ev (
7909 sorb, delta, modrm, sz,
7910 mkU8(getIByte(d32)), True, /* literal */
7911 dis_buf, True );
7912 break;
sewardja06e5562004-07-14 13:18:05 +00007913 case 0xA5: /* SHLDv %cl,Gv,Ev */
7914 modrm = getIByte(delta);
7915 delta = dis_SHLRD_Gv_Ev (
7916 sorb, delta, modrm, sz,
7917 getIReg(1,R_ECX), False, /* not literal */
7918 "%cl", True );
7919 break;
7920
sewardj68511542004-07-28 00:15:44 +00007921 case 0xAC: /* SHRDv imm8,Gv,Ev */
7922 modrm = getIByte(delta);
7923 d32 = delta + lengthAMode(delta);
7924 vex_sprintf(dis_buf, "$%d", delta);
7925 delta = dis_SHLRD_Gv_Ev (
7926 sorb, delta, modrm, sz,
7927 mkU8(getIByte(d32)), True, /* literal */
7928 dis_buf, False );
7929 break;
sewardja511afc2004-07-29 22:26:03 +00007930 case 0xAD: /* SHRDv %cl,Gv,Ev */
7931 modrm = getIByte(delta);
7932 delta = dis_SHLRD_Gv_Ev (
7933 sorb, delta, modrm, sz,
7934 getIReg(1,R_ECX), False, /* not literal */
7935 "%cl", False );
7936 break;
7937
sewardjc9a65702004-07-07 16:32:57 +00007938//-- /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
7939//--
7940//-- case 0xC0: /* XADD Gb,Eb */
7941//-- eip = dis_xadd_G_E ( cb, sorb, 1, eip );
7942//-- break;
7943//-- case 0xC1: /* XADD Gv,Ev */
7944//-- eip = dis_xadd_G_E ( cb, sorb, sz, eip );
7945//-- break;
7946//--
7947//-- /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
7948//--
7949//-- case 0x0D: /* PREFETCH / PREFETCHW - 3Dnow!ery*/
7950//-- case 0x18: /* PREFETCHT0/PREFETCHT1/PREFETCHT2/PREFETCHNTA */
7951//--
7952//-- vg_assert(sz == 4);
7953//-- modrm = getUChar(eip);
7954//-- if (epartIsReg(modrm)) {
7955//-- goto decode_failure;
7956//-- }
7957//-- if (gregOfRM(modrm) > 3) {
7958//-- goto decode_failure;
7959//-- }
7960//-- eip += lengthAMode(eip);
7961//-- if (VG_(print_codegen)) {
7962//-- UChar* hintstr;
7963//-- if (opc == 0x0D) {
7964//-- switch (gregOfRM(modrm)) {
7965//-- case 0: hintstr = ""; break;
7966//-- case 1: hintstr = "w"; break;
7967//-- default: goto decode_failure;
7968//-- }
7969//-- }
7970//-- else {
7971//-- switch (gregOfRM(modrm)) {
7972//-- case 0: hintstr = "nta"; break;
7973//-- case 1: hintstr = "t0"; break;
7974//-- case 2: hintstr = "t1"; break;
7975//-- case 3: hintstr = "t2"; break;
7976//-- default: goto decode_failure;
7977//-- }
7978//-- }
7979//-- VG_(printf)("prefetch%s ...\n", hintstr);
7980//-- }
7981//-- break;
7982//--
7983//-- case 0x71: case 0x72: case 0x73: {
7984//-- /* (sz==4): PSLL/PSRA/PSRL mmxreg by imm8 */
7985//-- /* (sz==2): PSLL/PSRA/PSRL xmmreg by imm8 */
7986//-- UChar byte1, byte2, byte3, subopc, mmreg;
7987//-- vg_assert(sz == 4 || sz == 2);
7988//-- byte1 = opc; /* 0x71/72/73 */
7989//-- byte2 = getUChar(eip); eip++; /* amode / sub-opcode */
7990//-- byte3 = getUChar(eip); eip++; /* imm8 */
7991//-- mmreg = byte2 & 7;
7992//-- subopc = (byte2 >> 3) & 7;
7993//-- if (subopc == 2 || subopc == 6 || subopc == 4) {
7994//-- /* 2 == 010 == SRL, 6 == 110 == SLL, 4 == 100 == SRA */
7995//-- /* ok */
7996//-- } else
7997//-- if (sz == 2 && opc == 0x73 && (subopc == 7 || subopc == 3)) {
7998//-- /* 3 == PSRLDQ, 7 == PSLLDQ */
7999//-- /* This is allowable in SSE. Because sz==2 we fall thru to
8000//-- SSE5 below. */
8001//-- } else {
8002//-- eip -= (sz==2 ? 3 : 2);
8003//-- goto decode_failure;
8004//-- }
8005//-- if (sz == 4) {
8006//-- /* The leading 0x0F is implied for MMX*, so we don't
8007//-- include it. */
8008//-- uInstr2(cb, MMX3, 0,
8009//-- Lit16, (((UShort)byte1) << 8) | ((UShort)byte2),
8010//-- Lit16, ((UShort)byte3) );
8011//-- DIP("ps%s%s $%d, %s\n",
8012//-- ( subopc == 2 ? "rl"
8013//-- : subopc == 6 ? "ll"
8014//-- : subopc == 4 ? "ra"
8015//-- : "??"),
8016//-- nameMMXGran(opc & 3), (Int)byte3, nameMMXReg(mmreg) );
8017//-- } else {
8018//-- /* Whereas we have to include it for SSE. */
8019//-- uInstr3(cb, SSE5, 0,
8020//-- Lit16, (((UShort)0x66) << 8) | ((UShort)0x0F),
8021//-- Lit16, (((UShort)byte1) << 8) | ((UShort)byte2),
8022//-- Lit16, ((UShort)byte3) );
8023//-- DIP("ps%s%s $%d, %s\n",
8024//-- ( subopc == 2 ? "rl"
8025//-- : subopc == 6 ? "ll"
8026//-- : subopc == 4 ? "ra"
8027//-- : subopc == 3 ? "(PSRLDQ)"
8028//-- : subopc == 7 ? "(PSLLDQ)"
8029//-- : "??"),
8030//-- nameMMXGran(opc & 3), (Int)byte3, nameXMMReg(mmreg) );
8031//-- }
8032//-- break;
8033//-- }
8034//--
8035//-- case 0x77: /* EMMS */
8036//-- vg_assert(sz == 4);
8037//-- uInstr1(cb, MMX1, 0, Lit16, ((UShort)(opc)) );
8038//-- DIP("emms\n");
8039//-- break;
8040//--
8041//-- case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
8042//-- vg_assert(sz == 4);
8043//-- modrm = getUChar(eip);
8044//-- if (epartIsReg(modrm)) {
8045//-- eip++;
8046//-- t1 = newTemp(cb);
8047//-- uInstr2(cb, MMX2_ERegWr, 4,
8048//-- Lit16,
8049//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
8050//-- TempReg, t1 );
8051//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, eregOfRM(modrm));
8052//-- DIP("movd %s, %s\n",
8053//-- nameMMXReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
8054//-- } else {
8055//-- Int tmpa;
8056//-- pair = disAMode ( cb, sorb, eip, dis_buf );
8057//-- tmpa = LOW24(pair);
8058//-- eip += HI8(pair);
8059//-- uInstr2(cb, MMX2_MemWr, 4,
8060//-- Lit16,
8061//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
8062//-- TempReg, tmpa);
8063//-- DIP("movd %s, %s\n", nameMMXReg(gregOfRM(modrm)), dis_buf);
8064//-- }
8065//-- break;
8066//--
8067//-- case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
8068//-- vg_assert(sz == 4);
8069//-- modrm = getUChar(eip);
8070//-- if (epartIsReg(modrm)) {
8071//-- eip++;
8072//-- t1 = newTemp(cb);
8073//-- uInstr2(cb, GET, 4, ArchReg, eregOfRM(modrm), TempReg, t1);
8074//-- uInstr2(cb, MMX2_ERegRd, 4,
8075//-- Lit16,
8076//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
8077//-- TempReg, t1 );
8078//-- DIP("movd %s, %s\n",
8079//-- nameIReg(4,eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
8080//-- } else {
8081//-- Int tmpa;
8082//-- pair = disAMode ( cb, sorb, eip, dis_buf );
8083//-- tmpa = LOW24(pair);
8084//-- eip += HI8(pair);
8085//-- uInstr2(cb, MMX2_MemRd, 4,
8086//-- Lit16,
8087//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
8088//-- TempReg, tmpa);
8089//-- DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregOfRM(modrm)));
8090//-- }
8091//-- break;
8092//--
8093//-- case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
8094//-- vg_assert(sz == 4);
8095//-- modrm = getUChar(eip);
8096//-- if (epartIsReg(modrm)) {
8097//-- eip++;
8098//-- uInstr1(cb, MMX2, 0,
8099//-- Lit16,
8100//-- (((UShort)(opc)) << 8) | ((UShort)modrm) );
8101//-- DIP("movq %s, %s\n",
8102//-- nameMMXReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
8103//-- } else {
8104//-- Int tmpa;
8105//-- pair = disAMode ( cb, sorb, eip, dis_buf );
8106//-- tmpa = LOW24(pair);
8107//-- eip += HI8(pair);
8108//-- uInstr2(cb, MMX2_MemRd, 8,
8109//-- Lit16,
8110//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
8111//-- TempReg, tmpa);
8112//-- DIP("movq %s, %s\n",
8113//-- dis_buf, nameMMXReg(gregOfRM(modrm)));
8114//-- }
8115//-- break;
8116//--
8117//-- case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
8118//-- case 0xE7: /* MOVNTQ (src)mmxreg, (dst)mmxreg-or-mem */
8119//-- vg_assert(sz == 4);
8120//-- modrm = getUChar(eip);
8121//-- if (epartIsReg(modrm)) {
8122//-- eip++;
8123//-- uInstr1(cb, MMX2, 0,
8124//-- Lit16,
8125//-- (((UShort)(opc)) << 8) | ((UShort)modrm) );
8126//-- DIP("movq %s, %s\n",
8127//-- nameMMXReg(gregOfRM(modrm)), nameMMXReg(eregOfRM(modrm)));
8128//-- } else {
8129//-- Int tmpa;
8130//-- pair = disAMode ( cb, sorb, eip, dis_buf );
8131//-- tmpa = LOW24(pair);
8132//-- eip += HI8(pair);
8133//-- uInstr2(cb, MMX2_MemWr, 8,
8134//-- Lit16,
8135//-- (((UShort)(opc)) << 8) | ((UShort)modrm),
8136//-- TempReg, tmpa);
8137//-- DIP("mov(nt)q %s, %s\n",
8138//-- nameMMXReg(gregOfRM(modrm)), dis_buf);
8139//-- }
8140//-- break;
8141//--
8142//-- case 0xFC: case 0xFD: case 0xFE:
8143//-- /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
8144//-- vg_assert(sz == 4);
8145//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "padd", True );
8146//-- break;
8147//--
8148//-- case 0xD4:
8149//-- /* PADDQ (src)mmxreg-or-mem, (dst)mmxreg */
8150//-- vg_assert(sz == 4);
8151//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "paddq", False );
8152//-- break;
8153//--
8154//-- case 0xEC: case 0xED:
8155//-- /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
8156//-- vg_assert(sz == 4);
8157//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "padds", True );
8158//-- break;
8159//--
8160//-- case 0xDC: case 0xDD:
8161//-- /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
8162//-- vg_assert(sz == 4);
8163//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "paddus", True );
8164//-- break;
8165//--
8166//-- case 0xF8: case 0xF9: case 0xFA: case 0xFB:
8167//-- /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
8168//-- vg_assert(sz == 4);
8169//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psub", True );
8170//-- break;
8171//--
8172//-- case 0xE8: case 0xE9:
8173//-- /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
8174//-- vg_assert(sz == 4);
8175//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psubs", True );
8176//-- break;
8177//--
8178//-- case 0xD8: case 0xD9:
8179//-- /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
8180//-- vg_assert(sz == 4);
8181//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psubus", True );
8182//-- break;
8183//--
8184//-- case 0xE4: /* PMULHUW (src)mmxreg-or-mem, (dst)mmxreg */
8185//-- vg_assert(sz == 4);
8186//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmulhuw", False );
8187//-- break;
8188//--
8189//-- case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
8190//-- vg_assert(sz == 4);
8191//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmulhw", False );
8192//-- break;
8193//--
8194//-- case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
8195//-- vg_assert(sz == 4);
8196//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmullw", False );
8197//-- break;
8198//--
8199//-- case 0xF4: /* PMULUDQ (src)mmxreg-or-mem, (dst)mmxreg */
8200//-- vg_assert(sz == 4);
8201//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmuludq", False );
8202//-- break;
8203//--
8204//-- case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
8205//-- vg_assert(sz == 4);
8206//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmaddwd", False );
8207//-- break;
8208//--
8209//-- case 0x74: case 0x75: case 0x76:
8210//-- /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
8211//-- vg_assert(sz == 4);
8212//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pcmpeq", True );
8213//-- break;
8214//--
8215//-- case 0x64: case 0x65: case 0x66:
8216//-- /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
8217//-- vg_assert(sz == 4);
8218//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pcmpgt", True );
8219//-- break;
8220//--
8221//-- case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
8222//-- vg_assert(sz == 4);
8223//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "packssdw", False );
8224//-- break;
8225//--
8226//-- case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
8227//-- vg_assert(sz == 4);
8228//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "packsswb", False );
8229//-- break;
8230//--
8231//-- case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
8232//-- vg_assert(sz == 4);
8233//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "packuswb", False );
8234//-- break;
8235//--
8236//-- case 0x68: case 0x69: case 0x6A:
8237//-- /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
8238//-- vg_assert(sz == 4);
8239//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "punpckh", True );
8240//-- break;
8241//--
8242//-- case 0x60: case 0x61: case 0x62:
8243//-- /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
8244//-- vg_assert(sz == 4);
8245//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "punpckl", True );
8246//-- break;
8247//--
8248//-- case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
8249//-- vg_assert(sz == 4);
8250//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pand", False );
8251//-- break;
8252//--
8253//-- case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
8254//-- vg_assert(sz == 4);
8255//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pandn", False );
8256//-- break;
8257//--
8258//-- case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
8259//-- vg_assert(sz == 4);
8260//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "por", False );
8261//-- break;
8262//--
8263//-- case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
8264//-- vg_assert(sz == 4);
8265//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pxor", False );
8266//-- break;
8267//--
8268//-- case 0xF1: case 0xF2: case 0xF3:
8269//-- /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
8270//-- vg_assert(sz == 4);
8271//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psll", True );
8272//-- break;
8273//--
8274//-- case 0xD1: case 0xD2: case 0xD3:
8275//-- /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
8276//-- vg_assert(sz == 4);
8277//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psrl", True );
8278//-- break;
8279//--
8280//-- case 0xE1: case 0xE2:
8281//-- /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
8282//-- vg_assert(sz == 4);
8283//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psra", True );
8284//-- break;
8285//--
8286//-- case 0xDA:
8287//-- /* PMINUB (src)mmxreg-or-mem, (dst)mmxreg */
8288//-- vg_assert(sz == 4);
8289//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pminub", False );
8290//-- break;
8291//--
8292//-- case 0xDE:
8293//-- /* PMAXUB (src)mmxreg-or-mem, (dst)mmxreg */
8294//-- vg_assert(sz == 4);
8295//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmaxub", False );
8296//-- break;
8297//--
8298//-- case 0xEA:
8299//-- /* PMINSW (src)mmxreg-or-mem, (dst)mmxreg */
8300//-- vg_assert(sz == 4);
8301//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pminsw", False );
8302//-- break;
8303//--
8304//-- case 0xEE:
8305//-- /* PMAXSW (src)mmxreg-or-mem, (dst)mmxreg */
8306//-- vg_assert(sz == 4);
8307//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmaxsw", False );
8308//-- break;
8309//--
8310//-- case 0xE0:
8311//-- /* PAVGB (src)mmxreg-or-mem, (dst)mmxreg */
8312//-- vg_assert(sz == 4);
8313//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pavgb", False );
8314//-- break;
8315//--
8316//-- case 0xE3:
8317//-- /* PAVGW (src)mmxreg-or-mem, (dst)mmxreg */
8318//-- vg_assert(sz == 4);
8319//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pavgw", False );
8320//-- break;
8321//--
8322//-- case 0xF6:
8323//-- /* PSADBW (src)mmxreg-or-mem, (dst)mmxreg */
8324//-- vg_assert(sz == 4);
8325//-- eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psadbw", False );
8326//-- break;
8327//--
8328//-- case 0x70:
8329//-- /* PSHUFW imm8, (src)mmxreg-or-mem, (dst)mmxreg */
8330//-- vg_assert(sz == 4);
8331//-- eip = dis_MMXop_regmem_to_reg_Imm8 ( cb, sorb, eip, opc, "pshufw", False );
8332//-- break;
8333//--
8334//-- case 0xD7:
8335//-- /* PMOVMSKB (src)mmxreg, (dst)ireg */
8336//-- vg_assert(sz == 4);
8337//-- modrm = getUChar(eip);
8338//-- vg_assert(epartIsReg(modrm));
8339//-- t1 = newTemp(cb);
8340//-- uInstr3(cb, SSE2g_RegWr, 4,
8341//-- Lit16, (((UShort)(0x0F)) << 8) | (UShort)(opc),
8342//-- Lit16, (UShort)modrm,
8343//-- TempReg, t1 );
8344//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
8345//-- DIP("pmovmskb %s, %s\n",
8346//-- nameMMXReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)));
8347//-- eip++;
8348//-- break;
8349//--
8350//-- case 0xC5:
8351//-- /* PEXTRW (src)mmxreg, (dst)ireg */
8352//-- vg_assert(sz == 4);
8353//-- t1 = newTemp(cb);
8354//-- modrm = getUChar(eip); eip++;
8355//-- abyte = getUChar(eip); eip++;
8356//-- vg_assert(epartIsReg(modrm));
8357//-- uInstr3(cb, SSE2g1_RegWr, 4,
8358//-- Lit16, (((UShort)(0x0F)) << 8) | (UShort)(opc),
8359//-- Lit16, (UShort)modrm,
8360//-- TempReg, t1 );
8361//-- uLiteral(cb, abyte);
8362//-- uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
8363//-- DIP("pextrw %s, %d, %s\n",
8364//-- nameMMXReg(eregOfRM(modrm)), (Int)abyte,
8365//-- nameIReg(4, gregOfRM(modrm)));
8366//-- break;
8367//--
8368//-- case 0xC4:
8369//-- /* PINSRW (src)ireg, (dst)mmxreg */
8370//-- vg_assert(sz == 4);
8371//-- t1 = newTemp(cb);
8372//-- modrm = getUChar(eip); eip++;
8373//-- abyte = getUChar(eip); eip++;
8374//-- vg_assert(epartIsReg(modrm));
8375//-- uInstr2(cb, GET, 2, ArchReg, eregOfRM(modrm), TempReg, t1);
8376//-- uInstr3(cb, SSE2e1_RegRd, 2,
8377//-- Lit16, (((UShort)(0x0F)) << 8) | (UShort)(opc),
8378//-- Lit16, (UShort)modrm,
8379//-- TempReg, t1 );
8380//-- uLiteral(cb, abyte);
8381//-- DIP("pinsrw %s, %d, %s\n", nameIReg(2, eregOfRM(modrm)),
8382//-- (Int)abyte, nameMMXReg(gregOfRM(modrm)));
8383//-- break;
8384//--
8385//-- case 0xA1: /* POP %FS */
8386//-- dis_pop_segreg( cb, R_FS, sz ); break;
8387//-- case 0xA9: /* POP %GS */
8388//-- dis_pop_segreg( cb, R_GS, sz ); break;
8389//--
8390//-- case 0xA0: /* PUSH %FS */
8391//-- dis_push_segreg( cb, R_FS, sz ); break;
8392//-- case 0xA8: /* PUSH %GS */
8393//-- dis_push_segreg( cb, R_GS, sz ); break;
sewardje87b4842004-07-10 12:23:30 +00008394
8395 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
8396
8397 default:
8398 goto decode_failure;
8399 } /* switch (opc) for the 2-byte opcodes */
8400 goto decode_success;
8401 } /* case 0x0F: of primary opcode */
sewardjc9a65702004-07-07 16:32:57 +00008402
8403 /* ------------------------ ??? ------------------------ */
8404
8405 default:
sewardje87b4842004-07-10 12:23:30 +00008406 decode_failure:
sewardjc9a65702004-07-07 16:32:57 +00008407 /* All decode failures end up here. */
8408 vex_printf("disInstr(x86): unhandled instruction bytes: "
8409 "0x%x 0x%x 0x%x 0x%x\n",
8410 (Int)getIByte(delta_start+0),
8411 (Int)getIByte(delta_start+1),
8412 (Int)getIByte(delta_start+2),
8413 (Int)getIByte(delta_start+3) );
8414 vpanic("x86toIR: unimplemented insn");
8415 /* Print address of failing instruction. */
8416 //VG_(describe_eip)((Addr)eip_start, loc_buf, M_VG_ERRTXT);
8417 //VG_(printf)(" at %s\n", loc_buf);
8418
8419 //uInstr0(cb, CALLM_S, 0);
8420 //uInstr1(cb, CALLM, 0, Lit16,
8421 // VGOFF_(helper_undefined_instruction));
8422 //uInstr0(cb, CALLM_E, 0);
8423
8424 /* just because everything else insists the last instruction of
8425 a BB is a jmp */
8426 //jmp_lit(cb, eip);
8427 //*isEnd = True;
8428 //break;
8429 //return eip;
8430
8431 } /* switch (opc) for the main (primary) opcode switch. */
8432
sewardje87b4842004-07-10 12:23:30 +00008433 decode_success:
sewardjc9a65702004-07-07 16:32:57 +00008434 /* All decode successes end up here. */
8435 DIP("\n");
sewardjd7cb8532004-08-17 23:59:23 +00008436 { Int i;
8437 for (i = first_stmt_idx; i < irbb->stmts_used; i++) {
8438 if (print_codegen) {
8439 vex_printf(" ");
8440 ppIRStmt(irbb->stmts[i]);
8441 vex_printf("\n");
8442 }
8443 }
sewardjc9a65702004-07-07 16:32:57 +00008444 }
sewardjd1061ab2004-07-08 01:45:30 +00008445 if (*isEnd) {
8446 vassert(irbb->next != NULL);
sewardje539a402004-07-14 18:24:17 +00008447 if (print_codegen) {
8448 vex_printf(" ");
8449 vex_printf( "goto {");
8450 ppIRJumpKind(irbb->jumpkind);
8451 vex_printf( "} ");
8452 ppIRExpr( irbb->next );
8453 vex_printf( "\n");
8454 }
sewardjd1061ab2004-07-08 01:45:30 +00008455 }
sewardjc9a65702004-07-07 16:32:57 +00008456 //for (; first_uinstr < cb->used; first_uinstr++) {
8457 // Bool sane = VG_(saneUInstr)(True, True, &cb->instrs[first_uinstr]);
8458 // if (!sane)
8459 // VG_(up_UInstr)(first_uinstr, &cb->instrs[first_uinstr]);
8460 // else if (VG_(print_codegen))
8461 // VG_(pp_UInstr)(first_uinstr, &cb->instrs[first_uinstr]);
8462 // vg_assert(sane);
8463 // }
8464 return delta;
8465}
8466
8467
8468/* Disassemble a complete basic block, starting at eip, and dumping
8469 the ucode into cb. Returns the size, in bytes, of the basic
8470 block. */
sewardj41f43bc2004-07-08 14:23:22 +00008471IRBB* bbToIR_X86Instr ( UChar* x86code,
sewardjc9a65702004-07-07 16:32:57 +00008472 Addr64 eip,
8473 Int* guest_bytes_read,
8474 Bool (*byte_accessible)(Addr64),
8475 Bool host_bigendian )
8476{
8477 UInt delta;
8478 Int n_instrs;
8479 Bool isEnd;
8480
8481 /* Set up globals. */
8482 host_is_bigendian = host_bigendian;
8483 print_codegen = (vex_verbosity >= 1);
8484 guest_code = x86code;
8485 guest_eip = (Addr32)eip;
sewardjd7cb8532004-08-17 23:59:23 +00008486 irbb = emptyIRBB();
sewardjc9a65702004-07-07 16:32:57 +00008487
8488 vassert((eip >> 32) == 0);
sewardjb2dc8092004-07-25 17:25:06 +00008489 vassert(vex_guest_insns_per_bb >= 1);
sewardjc9a65702004-07-07 16:32:57 +00008490
8491 DIP("Original x86 code to IR:\n\n");
8492
8493 /* Delta keeps track of how far along the x86code array we
8494 have so far gone. */
8495 isEnd = False;
8496 delta = 0;
8497 n_instrs = 0;
8498 while (True) {
8499 if (isEnd) break;
sewardjb2dc8092004-07-25 17:25:06 +00008500 if (n_instrs == vex_guest_insns_per_bb) {
8501 vassert(irbb->next == NULL);
8502 irbb->next = mkU32(((Addr32)eip)+delta);
8503 break;
8504 }
sewardjc9a65702004-07-07 16:32:57 +00008505 vassert(n_instrs < vex_guest_insns_per_bb);
8506 delta = disInstr ( delta, &isEnd );
8507 n_instrs++;
8508 DIP("\n");
8509 }
8510
sewardjd1061ab2004-07-08 01:45:30 +00008511 *guest_bytes_read = delta;
sewardjc9a65702004-07-07 16:32:57 +00008512 return irbb;
8513}
8514
8515#undef DIP
8516#undef DIS
8517
8518/*--------------------------------------------------------------------*/
sewardjc0ee2ed2004-07-27 10:29:41 +00008519/*--- end guest-x86/toIR.c ---*/
sewardjc9a65702004-07-07 16:32:57 +00008520/*--------------------------------------------------------------------*/