blob: afd4804b6bc200ebbac6db7c0689c24ad1d7adc3 [file] [log] [blame]
nethercotebb1c9912004-01-04 16:43:23 +00001
sewardjde4a1d02002-03-22 01:27:54 +00002/*--------------------------------------------------------------------*/
3/*--- The JITter: translate x86 code to ucode. ---*/
4/*--- vg_to_ucode.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
njnc9539842002-10-02 13:26:35 +00008 This file is part of Valgrind, an extensible x86 protected-mode
9 emulator for monitoring program execution on x86-Unixes.
sewardjde4a1d02002-03-22 01:27:54 +000010
nethercotebb1c9912004-01-04 16:43:23 +000011 Copyright (C) 2000-2004 Julian Seward
sewardjde4a1d02002-03-22 01:27:54 +000012 jseward@acm.org
sewardjde4a1d02002-03-22 01:27:54 +000013
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
njn25e49d8e72002-09-23 09:36:25 +000029 The GNU General Public License is contained in the file COPYING.
sewardjde4a1d02002-03-22 01:27:54 +000030*/
31
nethercotef1e5e152004-09-01 23:58:16 +000032#include "core.h"
sewardjde4a1d02002-03-22 01:27:54 +000033
34
35/*------------------------------------------------------------*/
nethercotee8601122004-01-26 17:14:17 +000036/*--- Debugging output ---*/
sewardjde4a1d02002-03-22 01:27:54 +000037/*------------------------------------------------------------*/
38
nethercotee8601122004-01-26 17:14:17 +000039#define DIP(format, args...) \
40 if (VG_(print_codegen)) \
41 VG_(printf)(format, ## args)
sewardjde4a1d02002-03-22 01:27:54 +000042
nethercotee8601122004-01-26 17:14:17 +000043#define DIS(buf, format, args...) \
44 if (VG_(print_codegen)) \
45 VG_(sprintf)(buf, format, ## args)
sewardje1042472002-09-30 12:33:11 +000046
sewardjde4a1d02002-03-22 01:27:54 +000047/*------------------------------------------------------------*/
fitzhardingec2dbbac2004-01-23 23:09:01 +000048/*--- CPU feature set stuff ---*/
49/*--- This is a little out of place here, but it will do ---*/
50/*--- for now. ---*/
51/*------------------------------------------------------------*/
52
fitzhardinge27574172004-01-26 21:11:51 +000053#define VG_CPU_VENDOR_GENERIC 0
54#define VG_CPU_VENDOR_INTEL 1
55#define VG_CPU_VENDOR_AMD 2
56
fitzhardingec2dbbac2004-01-23 23:09:01 +000057/* Standard macro to see if a specific flag is changeable */
58static inline Bool flag_is_changeable(UInt flag)
59{
60 UInt f1, f2;
61
62 asm("pushfl\n\t"
63 "pushfl\n\t"
64 "popl %0\n\t"
65 "movl %0,%1\n\t"
66 "xorl %2,%0\n\t"
67 "pushl %0\n\t"
68 "popfl\n\t"
69 "pushfl\n\t"
70 "popl %0\n\t"
71 "popfl\n\t"
72 : "=&r" (f1), "=&r" (f2)
73 : "ir" (flag));
74
75 return ((f1^f2) & flag) != 0;
76}
77
78
79/* Probe for the CPUID instruction */
80static Bool has_cpuid(void)
81{
82 return flag_is_changeable(EFlagID);
83}
84
nethercoteb253abe2004-08-06 17:06:14 +000085// Returns the CPU features, and also the vendorid. Only ever calls CPUID
86// once, and caches the necessary info in static variables for later reuse.
87static UInt* get_cpu_features(Int* cpu_vendorid_ptr)
fitzhardingec2dbbac2004-01-23 23:09:01 +000088{
fitzhardinge27574172004-01-26 21:11:51 +000089 Char vendorstr[13];
nethercoteb253abe2004-08-06 17:06:14 +000090 Int i, cpuid_level;
91 static Bool done_before = False;
92 static Int cpu_vendorid = VG_CPU_VENDOR_GENERIC;
93 static UInt cpu_features[VG_N_FEATURE_WORDS];
94 static const struct {
95 const Char *vendorstr;
96 Int vendorid;
97 } cpu_vendors[] = {
98 { "GenuineIntel", VG_CPU_VENDOR_INTEL },
99 { "AuthenticAMD", VG_CPU_VENDOR_AMD },
100 };
fitzhardinge27574172004-01-26 21:11:51 +0000101
nethercoteb253abe2004-08-06 17:06:14 +0000102 // If we haven't already worked this stuff out...
103 if (!done_before && has_cpuid()) {
fitzhardingec2dbbac2004-01-23 23:09:01 +0000104
nethercoteb253abe2004-08-06 17:06:14 +0000105 cpu_features[VG_INT_FEAT] |= (1 << (VG_X86_FEAT_CPUID%32));
fitzhardinge0df2ac22004-01-25 02:38:29 +0000106
nethercoteb253abe2004-08-06 17:06:14 +0000107 // Get vendor string, eg. "GenuineIntel". Note characteristically
108 // stupid word order chosen by Intel.
109 VG_(cpuid)(0, &cpuid_level, (UInt *)&vendorstr[0],
110 (UInt *)&vendorstr[8],
111 (UInt *)&vendorstr[4]);
112 vendorstr[12] = '\0';
fitzhardinge27574172004-01-26 21:11:51 +0000113
nethercoteb253abe2004-08-06 17:06:14 +0000114 // Determine vendor ID
115 for (i = 0; i < sizeof(cpu_vendors)/sizeof(*cpu_vendors); i++)
116 if (VG_(memcmp)(vendorstr, cpu_vendors[i].vendorstr, 12) == 0) {
117 cpu_vendorid = cpu_vendors[i].vendorid;
118 break;
119 }
120
121 // Determine CPU features
122 if (cpuid_level >= 1)
123 VG_(cpuid)(1, NULL, NULL, &cpu_features[VG_EXT_FEAT],
124 &cpu_features[VG_X86_FEAT]);
125
126 if (VG_CPU_VENDOR_AMD == cpu_vendorid) {
127 /* get AMD-specific flags */
128 VG_(cpuid)(0x80000001, NULL, NULL, NULL, &cpu_features[VG_AMD_FEAT]);
fitzhardinge27574172004-01-26 21:11:51 +0000129 }
fitzhardinge27574172004-01-26 21:11:51 +0000130 }
nethercoteb253abe2004-08-06 17:06:14 +0000131 if (NULL != cpu_vendorid_ptr) *cpu_vendorid_ptr = cpu_vendorid;
132 return cpu_features;
fitzhardingec2dbbac2004-01-23 23:09:01 +0000133}
134
135Bool VG_(cpu_has_feature)(UInt feature)
136{
nethercoteb253abe2004-08-06 17:06:14 +0000137 UInt word = feature / 32;
138 UInt bit = feature % 32;
139 UInt* cpu_features;
fitzhardingec2dbbac2004-01-23 23:09:01 +0000140
141 vg_assert(word >= 0 && word < VG_N_FEATURE_WORDS);
142
nethercoteb253abe2004-08-06 17:06:14 +0000143 cpu_features = get_cpu_features(NULL);
144
145 return !!( cpu_features[word] & (1 << bit) );
fitzhardingec2dbbac2004-01-23 23:09:01 +0000146}
147
fitzhardinge27574172004-01-26 21:11:51 +0000148/* The set of features we're willing to support for the client
149
150 This includes supported instruction set extensions, plus any
151 extensions which don't have any user-mode visible effect (but the
152 client may find interesting).
153 */
154#define VG_X86_SUPPORTED_FEATURES \
155 ((1 << VG_X86_FEAT_FPU) | \
156 (1 << VG_X86_FEAT_VME) | \
157 (1 << VG_X86_FEAT_DE) | \
158 (1 << VG_X86_FEAT_PSE) | \
159 (1 << VG_X86_FEAT_TSC) | \
160 (0 << VG_X86_FEAT_MSR) | \
161 (1 << VG_X86_FEAT_PAE) | \
162 (1 << VG_X86_FEAT_MCE) | \
163 (1 << VG_X86_FEAT_CX8) | \
164 (1 << VG_X86_FEAT_APIC) | \
165 (0 << VG_X86_FEAT_SEP) | \
166 (1 << VG_X86_FEAT_MTRR) | \
167 (1 << VG_X86_FEAT_PGE) | \
168 (1 << VG_X86_FEAT_MCA) | \
169 (1 << VG_X86_FEAT_CMOV) | \
170 (1 << VG_X86_FEAT_PAT) | \
171 (1 << VG_X86_FEAT_PSE36) | \
172 (0 << VG_X86_FEAT_CLFSH) | \
173 (1 << VG_X86_FEAT_DS) | \
174 (1 << VG_X86_FEAT_ACPI) | \
175 (1 << VG_X86_FEAT_MMX) | \
176 (1 << VG_X86_FEAT_FXSR) | \
177 (1 << VG_X86_FEAT_SSE) | \
178 (1 << VG_X86_FEAT_SSE2) | \
179 (1 << VG_X86_FEAT_SS) | \
180 (1 << VG_X86_FEAT_HT) | \
181 (1 << VG_X86_FEAT_TM) | \
182 (0 << VG_X86_FEAT_IA64) | \
183 (1 << VG_X86_FEAT_PBE))
184
185#define VG_AMD_SUPPORTED_FEATURES \
186 ((0 << (VG_AMD_FEAT_SYSCALL % 32)) | \
187 (0 << (VG_AMD_FEAT_NXP % 32)) | \
188 (1 << (VG_AMD_FEAT_MMXEXT % 32)) | \
189 (0 << (VG_AMD_FEAT_FFXSR % 32)) | \
190 (0 << (VG_AMD_FEAT_LONGMODE % 32)) | \
191 (0 << (VG_AMD_FEAT_3DNOWEXT % 32)) | \
192 (0 << (VG_AMD_FEAT_3DNOW % 32)) | \
193 /* Common bits between standard features and AMD features */ \
194 (1 << VG_X86_FEAT_FPU) | \
195 (1 << VG_X86_FEAT_VME) | \
196 (1 << VG_X86_FEAT_DE) | \
197 (1 << VG_X86_FEAT_PSE) | \
198 (1 << VG_X86_FEAT_TSC) | \
199 (0 << VG_X86_FEAT_MSR) | \
200 (1 << VG_X86_FEAT_PAE) | \
201 (1 << VG_X86_FEAT_MCE) | \
202 (1 << VG_X86_FEAT_CX8) | \
203 (1 << VG_X86_FEAT_APIC) | \
204 (1 << VG_X86_FEAT_MTRR) | \
205 (1 << VG_X86_FEAT_PGE) | \
206 (1 << VG_X86_FEAT_MCA) | \
207 (1 << VG_X86_FEAT_CMOV) | \
208 (1 << VG_X86_FEAT_PAT) | \
209 (1 << VG_X86_FEAT_PSE36) | \
210 (1 << VG_X86_FEAT_MMX) | \
211 (1 << VG_X86_FEAT_FXSR))
212
213
214/*
215 For simulating the cpuid instruction, we will
216 issue a "real" cpuid instruction and then mask out
217 the bits of the features we do not support currently (3dnow mostly).
218 We also claim to not support most CPUID operations.
219
220 Dirk Mueller <mueller@kde.org>
221
222 http://www.sandpile.org/ia32/cpuid.htm
223
224 references:
225
226 pre-MMX pentium:
227
228 <werner> cpuid words (0): 0x1 0x756e6547 0x6c65746e 0x49656e69
229 <werner> cpuid words (1): 0x52b 0x0 0x0 0x1bf
230
231 Updated to be more extensible about future vendor extensions and
232 vendor-specific parts of CPUID.
233*/
nethercoteb253abe2004-08-06 17:06:14 +0000234void VG_(helperc_CPUID)(UInt op, UInt *eax_ret, UInt *ebx_ret,
235 UInt *ecx_ret, UInt *edx_ret)
fitzhardinge27574172004-01-26 21:11:51 +0000236{
237 UInt eax, ebx, ecx, edx;
nethercoteb253abe2004-08-06 17:06:14 +0000238 Int cpu_vendorid;
fitzhardinge27574172004-01-26 21:11:51 +0000239
nethercoteb253abe2004-08-06 17:06:14 +0000240 // This function should not be called unless the CPU has CPUID.
241 vg_assert( VG_(cpu_has_feature)(VG_X86_FEAT_CPUID) );
242
243 // Get vendor ID.
244 get_cpu_features( &cpu_vendorid );
fitzhardinge27574172004-01-26 21:11:51 +0000245
thughes4ee64962004-06-16 20:51:45 +0000246 VG_(cpuid)(op, &eax, &ebx, &ecx, &edx);
fitzhardinge27574172004-01-26 21:11:51 +0000247
248 /* Common mangling */
249 switch(op) {
250 case 1:
251 edx &= VG_X86_SUPPORTED_FEATURES;
252 break;
253
254 case 0xd8000000: {
255 /* Implement some private information at 0xd8000000 */
256 static const Char valgrind_vendor[] = "ValgrindVCPU";
257
258 eax = 0xd8000000; /* max request */
259 ebx = *(UInt *)&valgrind_vendor[0];
260 ecx = *(UInt *)&valgrind_vendor[8];
261 edx = *(UInt *)&valgrind_vendor[4];
262 }
263 break;
264 }
265
266 /* Vendor-specific mangling of the results */
nethercoteb253abe2004-08-06 17:06:14 +0000267 switch (cpu_vendorid) {
fitzhardinge27574172004-01-26 21:11:51 +0000268 case VG_CPU_VENDOR_INTEL:
269 switch(op) {
270 case 1:
271 ecx = 0; /* mask out all extended features for now */
272 break;
273
274 case 0x80000001:
275 ebx = ecx = edx = 0;
276 break;
277 }
278 break;
279
280 case VG_CPU_VENDOR_AMD:
281 switch(op) {
282 case 0x80000001:
283 edx &= VG_AMD_SUPPORTED_FEATURES;
284 break;
285 }
286 break;
287 }
288
289 *eax_ret = eax;
290 *ebx_ret = ebx;
291 *ecx_ret = ecx;
292 *edx_ret = edx;
293}
294
295
fitzhardingec2dbbac2004-01-23 23:09:01 +0000296/*------------------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +0000297/*--- Here so it can be inlined everywhere. ---*/
298/*------------------------------------------------------------*/
299
300/* Allocate a new temp reg number. */
njn4ba5a792002-09-30 10:23:54 +0000301__inline__ Int VG_(get_new_temp) ( UCodeBlock* cb )
sewardjde4a1d02002-03-22 01:27:54 +0000302{
303 Int t = cb->nextTemp;
304 cb->nextTemp += 2;
305 return t;
306}
307
njn4ba5a792002-09-30 10:23:54 +0000308Int VG_(get_new_shadow) ( UCodeBlock* cb )
sewardjde4a1d02002-03-22 01:27:54 +0000309{
310 Int t = cb->nextTemp;
311 cb->nextTemp += 2;
312 return SHADOW(t);
313}
314
sewardjde4a1d02002-03-22 01:27:54 +0000315
316/*------------------------------------------------------------*/
317/*--- Helper bits and pieces for deconstructing the ---*/
318/*--- x86 insn stream. ---*/
319/*------------------------------------------------------------*/
320
321static Char* nameGrp1 ( Int opc_aux )
322{
323 static Char* grp1_names[8]
324 = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
njne427a662002-10-02 11:08:25 +0000325 if (opc_aux < 0 || opc_aux > 7) VG_(core_panic)("nameGrp1");
sewardjde4a1d02002-03-22 01:27:54 +0000326 return grp1_names[opc_aux];
327}
328
329static Char* nameGrp2 ( Int opc_aux )
330{
331 static Char* grp2_names[8]
332 = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
njne427a662002-10-02 11:08:25 +0000333 if (opc_aux < 0 || opc_aux > 7) VG_(core_panic)("nameGrp2");
sewardjde4a1d02002-03-22 01:27:54 +0000334 return grp2_names[opc_aux];
335}
336
337static Char* nameGrp4 ( Int opc_aux )
338{
339 static Char* grp4_names[8]
340 = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
njne427a662002-10-02 11:08:25 +0000341 if (opc_aux < 0 || opc_aux > 1) VG_(core_panic)("nameGrp4");
sewardjde4a1d02002-03-22 01:27:54 +0000342 return grp4_names[opc_aux];
343}
344
345static Char* nameGrp5 ( Int opc_aux )
346{
347 static Char* grp5_names[8]
348 = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
njne427a662002-10-02 11:08:25 +0000349 if (opc_aux < 0 || opc_aux > 6) VG_(core_panic)("nameGrp5");
sewardjde4a1d02002-03-22 01:27:54 +0000350 return grp5_names[opc_aux];
351}
352
353static Char* nameGrp8 ( Int opc_aux )
354{
355 static Char* grp8_names[8]
356 = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
njne427a662002-10-02 11:08:25 +0000357 if (opc_aux < 4 || opc_aux > 7) VG_(core_panic)("nameGrp8");
sewardjde4a1d02002-03-22 01:27:54 +0000358 return grp8_names[opc_aux];
359}
360
daywalker5d945de2003-09-26 00:32:53 +0000361const Char* VG_(name_of_int_reg) ( Int size, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000362{
363 static Char* ireg32_names[8]
364 = { "%eax", "%ecx", "%edx", "%ebx",
365 "%esp", "%ebp", "%esi", "%edi" };
366 static Char* ireg16_names[8]
367 = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di" };
368 static Char* ireg8_names[8]
sewardj3d7c9c82003-03-26 21:08:13 +0000369 = { "%al", "%cl", "%dl", "%bl",
370 "%ah{sp}", "%ch{bp}", "%dh{si}", "%bh{di}" };
sewardjde4a1d02002-03-22 01:27:54 +0000371 if (reg < 0 || reg > 7) goto bad;
372 switch (size) {
373 case 4: return ireg32_names[reg];
374 case 2: return ireg16_names[reg];
375 case 1: return ireg8_names[reg];
376 }
377 bad:
njne427a662002-10-02 11:08:25 +0000378 VG_(core_panic)("name_of_int_reg");
sewardjde4a1d02002-03-22 01:27:54 +0000379 return NULL; /*notreached*/
380}
381
daywalker5d945de2003-09-26 00:32:53 +0000382const Char* VG_(name_of_seg_reg) ( Int sreg )
sewardje1042472002-09-30 12:33:11 +0000383{
384 switch (sreg) {
385 case R_ES: return "%es";
386 case R_CS: return "%cs";
387 case R_SS: return "%ss";
388 case R_DS: return "%ds";
389 case R_FS: return "%fs";
390 case R_GS: return "%gs";
njne427a662002-10-02 11:08:25 +0000391 default: VG_(core_panic)("nameOfSegReg");
sewardje1042472002-09-30 12:33:11 +0000392 }
393}
394
daywalker5d945de2003-09-26 00:32:53 +0000395const Char* VG_(name_of_mmx_reg) ( Int mmxreg )
sewardj3d7c9c82003-03-26 21:08:13 +0000396{
daywalker5d945de2003-09-26 00:32:53 +0000397 static const Char* mmx_names[8]
sewardj3d7c9c82003-03-26 21:08:13 +0000398 = { "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" };
399 if (mmxreg < 0 || mmxreg > 7) VG_(core_panic)("name_of_mmx_reg");
400 return mmx_names[mmxreg];
401}
402
daywalker5d945de2003-09-26 00:32:53 +0000403const Char* VG_(name_of_xmm_reg) ( Int xmmreg )
sewardjfebaa3b2003-05-25 01:07:34 +0000404{
daywalker5d945de2003-09-26 00:32:53 +0000405 static const Char* xmm_names[8]
sewardjfebaa3b2003-05-25 01:07:34 +0000406 = { "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7" };
407 if (xmmreg < 0 || xmmreg > 7) VG_(core_panic)("name_of_xmm_reg");
408 return xmm_names[xmmreg];
409}
410
daywalker5d945de2003-09-26 00:32:53 +0000411const Char* VG_(name_of_mmx_gran) ( UChar gran )
sewardj3d7c9c82003-03-26 21:08:13 +0000412{
413 switch (gran) {
414 case 0: return "b";
415 case 1: return "w";
416 case 2: return "d";
417 case 3: return "q";
418 default: VG_(core_panic)("name_of_mmx_gran");
419 }
420}
421
daywalker5d945de2003-09-26 00:32:53 +0000422const Char VG_(name_of_int_size) ( Int size )
sewardjde4a1d02002-03-22 01:27:54 +0000423{
424 switch (size) {
425 case 4: return 'l';
426 case 2: return 'w';
427 case 1: return 'b';
njne427a662002-10-02 11:08:25 +0000428 default: VG_(core_panic)("name_of_int_size");
sewardjde4a1d02002-03-22 01:27:54 +0000429 }
430}
431
432__inline__ UInt VG_(extend_s_8to32) ( UInt x )
433{
434 return (UInt)((((Int)x) << 24) >> 24);
435}
436
437__inline__ static UInt extend_s_16to32 ( UInt x )
438{
439 return (UInt)((((Int)x) << 16) >> 16);
440}
441
442
443/* Get a byte value out of the insn stream and sign-extend to 32
444 bits. */
445__inline__ static UInt getSDisp8 ( Addr eip0 )
446{
447 UChar* eip = (UChar*)eip0;
448 return VG_(extend_s_8to32)( (UInt) (eip[0]) );
449}
450
451__inline__ static UInt getSDisp16 ( Addr eip0 )
452{
453 UChar* eip = (UChar*)eip0;
454 UInt d = *eip++;
455 d |= ((*eip++) << 8);
456 return extend_s_16to32(d);
457}
458
459/* Get a 32-bit value out of the insn stream. */
460__inline__ static UInt getUDisp32 ( Addr eip0 )
461{
462 UChar* eip = (UChar*)eip0;
463 UInt v = eip[3]; v <<= 8;
464 v |= eip[2]; v <<= 8;
465 v |= eip[1]; v <<= 8;
466 v |= eip[0];
467 return v;
468}
469
470__inline__ static UInt getUDisp16 ( Addr eip0 )
471{
472 UChar* eip = (UChar*)eip0;
473 UInt v = eip[1]; v <<= 8;
474 v |= eip[0];
475 return v;
476}
477
478__inline__ static UChar getUChar ( Addr eip0 )
479{
480 UChar* eip = (UChar*)eip0;
481 return eip[0];
482}
483
484__inline__ static UInt LOW24 ( UInt x )
485{
486 return x & 0x00FFFFFF;
487}
488
489__inline__ static UInt HI8 ( UInt x )
490{
491 return x >> 24;
492}
493
494__inline__ static UInt getUDisp ( Int size, Addr eip )
495{
496 switch (size) {
497 case 4: return getUDisp32(eip);
498 case 2: return getUDisp16(eip);
499 case 1: return getUChar(eip);
njne427a662002-10-02 11:08:25 +0000500 default: VG_(core_panic)("getUDisp");
sewardjde4a1d02002-03-22 01:27:54 +0000501 }
502 return 0; /*notreached*/
503}
504
505__inline__ static UInt getSDisp ( Int size, Addr eip )
506{
507 switch (size) {
508 case 4: return getUDisp32(eip);
509 case 2: return getSDisp16(eip);
510 case 1: return getSDisp8(eip);
njne427a662002-10-02 11:08:25 +0000511 default: VG_(core_panic)("getUDisp");
sewardjde4a1d02002-03-22 01:27:54 +0000512 }
513 return 0; /*notreached*/
514}
515
sewardjde4a1d02002-03-22 01:27:54 +0000516/*------------------------------------------------------------*/
517/*--- Flag-related helpers. ---*/
518/*------------------------------------------------------------*/
519
sewardjde4a1d02002-03-22 01:27:54 +0000520static void setFlagsFromUOpcode ( UCodeBlock* cb, Int uopc )
521{
522 switch (uopc) {
523 case XOR: case OR: case AND:
524 uFlagsRWU(cb, FlagsEmpty, FlagsOSZCP, FlagA); break;
525 case ADC: case SBB:
526 uFlagsRWU(cb, FlagC, FlagsOSZACP, FlagsEmpty); break;
jsgf5efa4fd2003-10-14 21:49:11 +0000527 case MUL: case UMUL:
528 uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP); break;
sewardjde4a1d02002-03-22 01:27:54 +0000529 case ADD: case SUB: case NEG:
530 uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty); break;
531 case INC: case DEC:
532 uFlagsRWU(cb, FlagsEmpty, FlagsOSZAP, FlagsEmpty); break;
533 case SHR: case SAR: case SHL:
534 uFlagsRWU(cb, FlagsEmpty, FlagsOSZCP, FlagA); break;
535 case ROL: case ROR:
536 uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsEmpty); break;
537 case RCR: case RCL:
538 uFlagsRWU(cb, FlagC, FlagsOC, FlagsEmpty); break;
539 case NOT:
540 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty); break;
541 default:
542 VG_(printf)("unhandled case is %s\n",
njn4ba5a792002-09-30 10:23:54 +0000543 VG_(name_UOpcode)(True, uopc));
njne427a662002-10-02 11:08:25 +0000544 VG_(core_panic)("setFlagsFromUOpcode: unhandled case");
sewardjde4a1d02002-03-22 01:27:54 +0000545 }
546}
547
nethercotee8601122004-01-26 17:14:17 +0000548/*------------------------------------------------------------*/
549/*--- JMP helpers ---*/
550/*------------------------------------------------------------*/
551
552static __inline__
553void jmp_lit( UCodeBlock* cb, Addr d32 )
554{
555 uInstr1 (cb, JMP, 0, Literal, 0);
556 uLiteral(cb, d32);
557 uCond (cb, CondAlways);
558}
559
560static __inline__
561void jmp_treg( UCodeBlock* cb, Int t )
562{
563 uInstr1 (cb, JMP, 0, TempReg, t);
564 uCond (cb, CondAlways);
565}
566
567static __inline__
568void jcc_lit( UCodeBlock* cb, Addr d32, Condcode cond )
569{
570 uInstr1 (cb, JMP, 0, Literal, 0);
571 uLiteral (cb, d32);
572 uCond (cb, cond);
573 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
574}
575
sewardjde4a1d02002-03-22 01:27:54 +0000576
577/*------------------------------------------------------------*/
578/*--- Disassembling addressing modes ---*/
579/*------------------------------------------------------------*/
580
sewardje1042472002-09-30 12:33:11 +0000581static
582UChar* sorbTxt ( UChar sorb )
583{
584 switch (sorb) {
585 case 0: return ""; /* no override */
586 case 0x3E: return "%ds";
587 case 0x26: return "%es:";
588 case 0x64: return "%fs:";
589 case 0x65: return "%gs:";
njne427a662002-10-02 11:08:25 +0000590 default: VG_(core_panic)("sorbTxt");
sewardje1042472002-09-30 12:33:11 +0000591 }
592}
593
594
595/* Tmp is a TempReg holding a virtual address. Convert it to a linear
596 address by adding any required segment override as indicated by
597 sorb. */
598static
599void handleSegOverride ( UCodeBlock* cb, UChar sorb, Int tmp )
600{
601 Int sreg, tsreg;
602
603 if (sorb == 0)
604 /* the common case - no override */
605 return;
606
607 switch (sorb) {
608 case 0x3E: sreg = R_DS; break;
609 case 0x26: sreg = R_ES; break;
610 case 0x64: sreg = R_FS; break;
611 case 0x65: sreg = R_GS; break;
njne427a662002-10-02 11:08:25 +0000612 default: VG_(core_panic)("handleSegOverride");
sewardje1042472002-09-30 12:33:11 +0000613 }
614
615 tsreg = newTemp(cb);
616
617 /* sreg -> tsreg */
618 uInstr2(cb, GETSEG, 2, ArchRegS, sreg, TempReg, tsreg );
619
620 /* tmp += segment_base(ldt[tsreg]); also do limit check */
621 uInstr2(cb, USESEG, 0, TempReg, tsreg, TempReg, tmp );
622}
623
624
sewardjde4a1d02002-03-22 01:27:54 +0000625/* Generate ucode to calculate an address indicated by a ModRM and
626 following SIB bytes, getting the value in a new temporary. The
627 temporary, and the number of bytes in the address mode, are
sewardje1042472002-09-30 12:33:11 +0000628 returned, as a pair (length << 24) | temp. Note that this fn should
sewardjde4a1d02002-03-22 01:27:54 +0000629 not be called if the R/M part of the address denotes a register
nethercotee8601122004-01-26 17:14:17 +0000630 instead of memory. If VG_(print_codegen) is true, text of the addressing
631 mode is placed therein. */
sewardjde4a1d02002-03-22 01:27:54 +0000632
sewardje1042472002-09-30 12:33:11 +0000633static
634UInt disAMode ( UCodeBlock* cb, UChar sorb, Addr eip0, UChar* buf )
sewardjde4a1d02002-03-22 01:27:54 +0000635{
636 UChar* eip = (UChar*)eip0;
637 UChar mod_reg_rm = *eip++;
638 Int tmp = newTemp(cb);
639
640 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
641 jump table seems a bit excessive.
642 */
643 mod_reg_rm &= 0xC7; /* is now XX000YYY */
644 mod_reg_rm |= (mod_reg_rm >> 3); /* is now XX0XXYYY */
645 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
646 switch (mod_reg_rm) {
647
648 /* (%eax) .. (%edi), not including (%esp) or (%ebp).
649 --> GET %reg, t
650 */
651 case 0x00: case 0x01: case 0x02: case 0x03:
652 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
653 { UChar rm = mod_reg_rm;
654 uInstr2(cb, GET, 4, ArchReg, rm, TempReg, tmp);
sewardje1042472002-09-30 12:33:11 +0000655 handleSegOverride(cb, sorb, tmp);
nethercotee8601122004-01-26 17:14:17 +0000656 DIS(buf, "%s(%s)", sorbTxt(sorb), nameIReg(4,rm));
sewardjde4a1d02002-03-22 01:27:54 +0000657 return (1<<24 | tmp);
658 }
659
660 /* d8(%eax) ... d8(%edi), not including d8(%esp)
661 --> GET %reg, t ; ADDL d8, t
662 */
663 case 0x08: case 0x09: case 0x0A: case 0x0B:
664 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
665 { UChar rm = mod_reg_rm & 7;
666 Int tmq = newTemp(cb);
667 UInt d = getSDisp8((Addr)eip); eip++;
668 uInstr2(cb, GET, 4, ArchReg, rm, TempReg, tmq);
669 uInstr2(cb, LEA1, 4, TempReg, tmq, TempReg, tmp);
nethercotee8601122004-01-26 17:14:17 +0000670 uLiteral(cb, d);
sewardje1042472002-09-30 12:33:11 +0000671 handleSegOverride(cb, sorb, tmp);
nethercotee8601122004-01-26 17:14:17 +0000672 DIS(buf, "%s%d(%s)", sorbTxt(sorb), d, nameIReg(4,rm));
sewardjde4a1d02002-03-22 01:27:54 +0000673 return (2<<24 | tmp);
674 }
675
676 /* d32(%eax) ... d32(%edi), not including d32(%esp)
677 --> GET %reg, t ; ADDL d8, t
678 */
679 case 0x10: case 0x11: case 0x12: case 0x13:
680 /* ! 14 */ case 0x15: case 0x16: case 0x17:
681 { UChar rm = mod_reg_rm & 7;
682 Int tmq = newTemp(cb);
683 UInt d = getUDisp32((Addr)eip); eip += 4;
684 uInstr2(cb, GET, 4, ArchReg, rm, TempReg, tmq);
685 uInstr2(cb, LEA1, 4, TempReg, tmq, TempReg, tmp);
nethercotee8601122004-01-26 17:14:17 +0000686 uLiteral(cb, d);
sewardje1042472002-09-30 12:33:11 +0000687 handleSegOverride(cb, sorb, tmp);
nethercotee8601122004-01-26 17:14:17 +0000688 DIS(buf, "%s0x%x(%s)", sorbTxt(sorb), d, nameIReg(4,rm));
sewardjde4a1d02002-03-22 01:27:54 +0000689 return (5<<24 | tmp);
690 }
691
692 /* a register, %eax .. %edi. This shouldn't happen. */
693 case 0x18: case 0x19: case 0x1A: case 0x1B:
694 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
njne427a662002-10-02 11:08:25 +0000695 VG_(core_panic)("disAMode: not an addr!");
sewardjde4a1d02002-03-22 01:27:54 +0000696
697 /* a 32-bit literal address
698 --> MOV d32, tmp
699 */
700 case 0x05:
701 { UInt d = getUDisp32((Addr)eip); eip += 4;
702 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tmp);
703 uLiteral(cb, d);
sewardje1042472002-09-30 12:33:11 +0000704 handleSegOverride(cb, sorb, tmp);
nethercotee8601122004-01-26 17:14:17 +0000705 DIS(buf, "%s(0x%x)", sorbTxt(sorb), d);
sewardjde4a1d02002-03-22 01:27:54 +0000706 return (5<<24 | tmp);
707 }
708
709 case 0x04: {
710 /* SIB, with no displacement. Special cases:
711 -- %esp cannot act as an index value.
712 If index_r indicates %esp, zero is used for the index.
713 -- when mod is zero and base indicates EBP, base is instead
714 a 32-bit literal.
715 It's all madness, I tell you. Extract %index, %base and
716 scale from the SIB byte. The value denoted is then:
717 | %index == %ESP && %base == %EBP
718 = d32 following SIB byte
719 | %index == %ESP && %base != %EBP
720 = %base
721 | %index != %ESP && %base == %EBP
722 = d32 following SIB byte + (%index << scale)
723 | %index != %ESP && %base != %ESP
724 = %base + (%index << scale)
725
726 What happens to the souls of CPU architects who dream up such
727 horrendous schemes, do you suppose?
728 */
729 UChar sib = *eip++;
730 UChar scale = (sib >> 6) & 3;
731 UChar index_r = (sib >> 3) & 7;
732 UChar base_r = sib & 7;
733
734 if (index_r != R_ESP && base_r != R_EBP) {
735 Int index_tmp = newTemp(cb);
736 Int base_tmp = newTemp(cb);
737 uInstr2(cb, GET, 4, ArchReg, index_r, TempReg, index_tmp);
738 uInstr2(cb, GET, 4, ArchReg, base_r, TempReg, base_tmp);
739 uInstr3(cb, LEA2, 4, TempReg, base_tmp, TempReg, index_tmp,
740 TempReg, tmp);
nethercotee8601122004-01-26 17:14:17 +0000741 uLiteral(cb, 0);
sewardjde4a1d02002-03-22 01:27:54 +0000742 LAST_UINSTR(cb).extra4b = 1 << scale;
sewardje1042472002-09-30 12:33:11 +0000743 handleSegOverride(cb, sorb, tmp);
nethercotee8601122004-01-26 17:14:17 +0000744 DIS(buf, "%s(%s,%s,%d)", sorbTxt(sorb),
745 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardjde4a1d02002-03-22 01:27:54 +0000746 return (2<<24 | tmp);
747 }
748
749 if (index_r != R_ESP && base_r == R_EBP) {
750 Int index_tmp = newTemp(cb);
751 UInt d = getUDisp32((Addr)eip); eip += 4;
752 uInstr2(cb, GET, 4, ArchReg, index_r, TempReg, index_tmp);
753 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tmp);
754 uLiteral(cb, 0);
755 uInstr3(cb, LEA2, 4, TempReg, tmp, TempReg, index_tmp,
756 TempReg, tmp);
nethercotee8601122004-01-26 17:14:17 +0000757 uLiteral(cb, d);
sewardjde4a1d02002-03-22 01:27:54 +0000758 LAST_UINSTR(cb).extra4b = 1 << scale;
sewardje1042472002-09-30 12:33:11 +0000759 handleSegOverride(cb, sorb, tmp);
nethercotee8601122004-01-26 17:14:17 +0000760 DIS(buf, "%s0x%x(,%s,%d)", sorbTxt(sorb), d,
761 nameIReg(4,index_r), 1<<scale);
sewardjde4a1d02002-03-22 01:27:54 +0000762 return (6<<24 | tmp);
763 }
764
765 if (index_r == R_ESP && base_r != R_EBP) {
766 uInstr2(cb, GET, 4, ArchReg, base_r, TempReg, tmp);
sewardje1042472002-09-30 12:33:11 +0000767 handleSegOverride(cb, sorb, tmp);
nethercotee8601122004-01-26 17:14:17 +0000768 DIS(buf, "%s(%s,,)", sorbTxt(sorb), nameIReg(4,base_r));
sewardjde4a1d02002-03-22 01:27:54 +0000769 return (2<<24 | tmp);
770 }
771
772 if (index_r == R_ESP && base_r == R_EBP) {
773 UInt d = getUDisp32((Addr)eip); eip += 4;
774 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tmp);
775 uLiteral(cb, d);
sewardje1042472002-09-30 12:33:11 +0000776 handleSegOverride(cb, sorb, tmp);
nethercotee8601122004-01-26 17:14:17 +0000777 DIS(buf, "%s0x%x()", sorbTxt(sorb), d);
sewardjde4a1d02002-03-22 01:27:54 +0000778 return (6<<24 | tmp);
779 }
780
781 vg_assert(0);
782 }
783
784 /* SIB, with 8-bit displacement. Special cases:
785 -- %esp cannot act as an index value.
786 If index_r indicates %esp, zero is used for the index.
787 Denoted value is:
788 | %index == %ESP
789 = d8 + %base
790 | %index != %ESP
791 = d8 + %base + (%index << scale)
792 */
793 case 0x0C: {
794 UChar sib = *eip++;
795 UChar scale = (sib >> 6) & 3;
796 UChar index_r = (sib >> 3) & 7;
797 UChar base_r = sib & 7;
798 UInt d = getSDisp8((Addr)eip); eip++;
799
800 if (index_r == R_ESP) {
801 Int tmq = newTemp(cb);
802 uInstr2(cb, GET, 4, ArchReg, base_r, TempReg, tmq);
803 uInstr2(cb, LEA1, 4, TempReg, tmq, TempReg, tmp);
nethercotee8601122004-01-26 17:14:17 +0000804 uLiteral(cb, d);
sewardje1042472002-09-30 12:33:11 +0000805 handleSegOverride(cb, sorb, tmp);
nethercotee8601122004-01-26 17:14:17 +0000806 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb), d, nameIReg(4,base_r));
sewardjde4a1d02002-03-22 01:27:54 +0000807 return (3<<24 | tmp);
808 } else {
809 Int index_tmp = newTemp(cb);
810 Int base_tmp = newTemp(cb);
811 uInstr2(cb, GET, 4, ArchReg, index_r, TempReg, index_tmp);
812 uInstr2(cb, GET, 4, ArchReg, base_r, TempReg, base_tmp);
813 uInstr3(cb, LEA2, 4, TempReg, base_tmp, TempReg, index_tmp,
814 TempReg, tmp);
nethercotee8601122004-01-26 17:14:17 +0000815 uLiteral(cb, d);
sewardjde4a1d02002-03-22 01:27:54 +0000816 LAST_UINSTR(cb).extra4b = 1 << scale;
sewardje1042472002-09-30 12:33:11 +0000817 handleSegOverride(cb, sorb, tmp);
nethercotee8601122004-01-26 17:14:17 +0000818 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), d,
819 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardjde4a1d02002-03-22 01:27:54 +0000820 return (3<<24 | tmp);
821 }
822 vg_assert(0);
823 }
824
825 /* SIB, with 32-bit displacement. Special cases:
826 -- %esp cannot act as an index value.
827 If index_r indicates %esp, zero is used for the index.
828 Denoted value is:
829 | %index == %ESP
830 = d32 + %base
831 | %index != %ESP
832 = d32 + %base + (%index << scale)
833 */
834 case 0x14: {
835 UChar sib = *eip++;
836 UChar scale = (sib >> 6) & 3;
837 UChar index_r = (sib >> 3) & 7;
838 UChar base_r = sib & 7;
839 UInt d = getUDisp32((Addr)eip); eip += 4;
840
841 if (index_r == R_ESP) {
842 Int tmq = newTemp(cb);
843 uInstr2(cb, GET, 4, ArchReg, base_r, TempReg, tmq);
844 uInstr2(cb, LEA1, 4, TempReg, tmq, TempReg, tmp);
nethercotee8601122004-01-26 17:14:17 +0000845 uLiteral(cb, d);
sewardje1042472002-09-30 12:33:11 +0000846 handleSegOverride(cb, sorb, tmp);
nethercotee8601122004-01-26 17:14:17 +0000847 DIS(buf, "%s%d(%s,,)", sorbTxt(sorb), d, nameIReg(4,base_r));
sewardjde4a1d02002-03-22 01:27:54 +0000848 return (6<<24 | tmp);
849 } else {
850 Int index_tmp = newTemp(cb);
851 Int base_tmp = newTemp(cb);
852 uInstr2(cb, GET, 4, ArchReg, index_r, TempReg, index_tmp);
853 uInstr2(cb, GET, 4, ArchReg, base_r, TempReg, base_tmp);
854 uInstr3(cb, LEA2, 4, TempReg, base_tmp, TempReg, index_tmp,
855 TempReg, tmp);
nethercotee8601122004-01-26 17:14:17 +0000856 uLiteral(cb, d);
sewardjde4a1d02002-03-22 01:27:54 +0000857 LAST_UINSTR(cb).extra4b = 1 << scale;
sewardje1042472002-09-30 12:33:11 +0000858 handleSegOverride(cb, sorb, tmp);
nethercotee8601122004-01-26 17:14:17 +0000859 DIS(buf, "%s%d(%s,%s,%d)", sorbTxt(sorb), d,
860 nameIReg(4,base_r), nameIReg(4,index_r), 1<<scale);
sewardjde4a1d02002-03-22 01:27:54 +0000861 return (6<<24 | tmp);
862 }
863 vg_assert(0);
864 }
865
866 default:
njne427a662002-10-02 11:08:25 +0000867 VG_(core_panic)("disAMode");
sewardjde4a1d02002-03-22 01:27:54 +0000868 return 0; /*notreached*/
869 }
870}
871
872
873/* Figure out the number of (insn-stream) bytes constituting the amode
874 beginning at eip0. Is useful for getting hold of literals beyond
875 the end of the amode before it has been disassembled. */
876
877static UInt lengthAMode ( Addr eip0 )
878{
879 UChar* eip = (UChar*)eip0;
880 UChar mod_reg_rm = *eip++;
881
882 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
883 jump table seems a bit excessive.
884 */
885 mod_reg_rm &= 0xC7; /* is now XX000YYY */
886 mod_reg_rm |= (mod_reg_rm >> 3); /* is now XX0XXYYY */
887 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
888 switch (mod_reg_rm) {
889
890 /* (%eax) .. (%edi), not including (%esp) or (%ebp). */
891 case 0x00: case 0x01: case 0x02: case 0x03:
892 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
893 return 1;
894
895 /* d8(%eax) ... d8(%edi), not including d8(%esp). */
896 case 0x08: case 0x09: case 0x0A: case 0x0B:
897 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
898 return 2;
899
900 /* d32(%eax) ... d32(%edi), not including d32(%esp). */
901 case 0x10: case 0x11: case 0x12: case 0x13:
902 /* ! 14 */ case 0x15: case 0x16: case 0x17:
903 return 5;
904
905 /* a register, %eax .. %edi. (Not an addr, but still handled.) */
906 case 0x18: case 0x19: case 0x1A: case 0x1B:
907 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
908 return 1;
909
910 /* a 32-bit literal address. */
911 case 0x05: return 5;
912
913 /* SIB, no displacement. */
914 case 0x04: {
915 UChar sib = *eip++;
916 UChar base_r = sib & 7;
917 if (base_r == R_EBP) return 6; else return 2;
918 }
919 /* SIB, with 8-bit displacement. */
920 case 0x0C: return 3;
921
922 /* SIB, with 32-bit displacement. */
923 case 0x14: return 6;
924
925 default:
njne427a662002-10-02 11:08:25 +0000926 VG_(core_panic)("amode_from_RM");
sewardjde4a1d02002-03-22 01:27:54 +0000927 return 0; /*notreached*/
928 }
929}
930
931
932/* Extract the reg field from a modRM byte. */
933static __inline__ Int gregOfRM ( UChar mod_reg_rm )
934{
935 return (Int)( (mod_reg_rm >> 3) & 7 );
936}
937
938/* Figure out whether the mod and rm parts of a modRM byte refer to a
939 register or memory. If so, the byte will have the form 11XXXYYY,
940 where YYY is the register number. */
941static __inline__ Bool epartIsReg ( UChar mod_reg_rm )
942{
943 return (0xC0 == (mod_reg_rm & 0xC0));
944}
945
946/* ... and extract the register number ... */
947static __inline__ Int eregOfRM ( UChar mod_reg_rm )
948{
949 return (Int)(mod_reg_rm & 0x7);
950}
951
952
953/*------------------------------------------------------------*/
954/*--- Disassembling common idioms ---*/
955/*------------------------------------------------------------*/
956
957static
958void codegen_XOR_reg_with_itself ( UCodeBlock* cb, Int size,
959 Int ge_reg, Int tmp )
960{
nethercotee8601122004-01-26 17:14:17 +0000961 DIP("xor%c %s, %s\n", nameISize(size),
962 nameIReg(size,ge_reg), nameIReg(size,ge_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000963 uInstr2(cb, MOV, size, Literal, 0, TempReg, tmp);
964 uLiteral(cb, 0);
965 uInstr2(cb, XOR, size, TempReg, tmp, TempReg, tmp);
966 setFlagsFromUOpcode(cb, XOR);
967 uInstr2(cb, PUT, size, TempReg, tmp, ArchReg, ge_reg);
968}
969
sewardjde4a1d02002-03-22 01:27:54 +0000970/* Handle binary integer instructions of the form
971 op E, G meaning
972 op reg-or-mem, reg
973 Is passed the a ptr to the modRM byte, the actual operation, and the
974 data size. Returns the address advanced completely over this
975 instruction.
976
977 E(src) is reg-or-mem
978 G(dst) is reg.
979
980 If E is reg, --> GET %G, tmp
981 OP %E, tmp
982 PUT tmp, %G
983
984 If E is mem and OP is not reversible,
985 --> (getAddr E) -> tmpa
986 LD (tmpa), tmpa
987 GET %G, tmp2
988 OP tmpa, tmp2
989 PUT tmp2, %G
990
991 If E is mem and OP is reversible
992 --> (getAddr E) -> tmpa
993 LD (tmpa), tmpa
994 OP %G, tmpa
995 PUT tmpa, %G
996*/
997static
sewardje1042472002-09-30 12:33:11 +0000998Addr dis_op2_E_G ( UCodeBlock* cb,
999 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +00001000 Opcode opc,
1001 Bool keep,
1002 Int size,
1003 Addr eip0,
1004 Char* t_x86opc )
1005{
1006 Bool reversible;
1007 UChar rm = getUChar(eip0);
1008 UChar dis_buf[50];
1009
1010 if (epartIsReg(rm)) {
1011 Int tmp = newTemp(cb);
1012
1013 /* Specially handle XOR reg,reg, because that doesn't really
1014 depend on reg, and doing the obvious thing potentially
1015 generates a spurious value check failure due to the bogus
1016 dependency. */
1017 if (opc == XOR && gregOfRM(rm) == eregOfRM(rm)) {
1018 codegen_XOR_reg_with_itself ( cb, size, gregOfRM(rm), tmp );
1019 return 1+eip0;
1020 }
1021
1022 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmp);
1023 if (opc == AND || opc == OR) {
1024 Int tao = newTemp(cb);
1025 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, tao);
1026 uInstr2(cb, opc, size, TempReg, tao, TempReg, tmp);
1027 setFlagsFromUOpcode(cb, opc);
1028 } else {
1029 uInstr2(cb, opc, size, ArchReg, eregOfRM(rm), TempReg, tmp);
1030 setFlagsFromUOpcode(cb, opc);
1031 }
1032 if (keep)
1033 uInstr2(cb, PUT, size, TempReg, tmp, ArchReg, gregOfRM(rm));
nethercotee8601122004-01-26 17:14:17 +00001034 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1035 nameIReg(size,eregOfRM(rm)),
1036 nameIReg(size,gregOfRM(rm)));
sewardjde4a1d02002-03-22 01:27:54 +00001037 return 1+eip0;
1038 }
1039
1040 /* E refers to memory */
1041 reversible
1042 = (opc == ADD || opc == OR || opc == AND || opc == XOR || opc == ADC)
1043 ? True : False;
1044 if (reversible) {
nethercotee8601122004-01-26 17:14:17 +00001045 UInt pair = disAMode ( cb, sorb, eip0, dis_buf);
sewardjde4a1d02002-03-22 01:27:54 +00001046 Int tmpa = LOW24(pair);
1047 uInstr2(cb, LOAD, size, TempReg, tmpa, TempReg, tmpa);
1048
1049 if (opc == AND || opc == OR) {
1050 Int tao = newTemp(cb);
1051 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tao);
1052 uInstr2(cb, opc, size, TempReg, tao, TempReg, tmpa);
1053 setFlagsFromUOpcode(cb, opc);
1054 } else {
1055 uInstr2(cb, opc, size, ArchReg, gregOfRM(rm), TempReg, tmpa);
1056 setFlagsFromUOpcode(cb, opc);
1057 }
1058 if (keep)
1059 uInstr2(cb, PUT, size, TempReg, tmpa, ArchReg, gregOfRM(rm));
nethercotee8601122004-01-26 17:14:17 +00001060 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1061 dis_buf,nameIReg(size,gregOfRM(rm)));
sewardjde4a1d02002-03-22 01:27:54 +00001062 return HI8(pair)+eip0;
1063 } else {
nethercotee8601122004-01-26 17:14:17 +00001064 UInt pair = disAMode ( cb, sorb, eip0, dis_buf);
sewardjde4a1d02002-03-22 01:27:54 +00001065 Int tmpa = LOW24(pair);
1066 Int tmp2 = newTemp(cb);
1067 uInstr2(cb, LOAD, size, TempReg, tmpa, TempReg, tmpa);
1068 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmp2);
1069 uInstr2(cb, opc, size, TempReg, tmpa, TempReg, tmp2);
1070 setFlagsFromUOpcode(cb, opc);
1071 if (keep)
1072 uInstr2(cb, PUT, size, TempReg, tmp2, ArchReg, gregOfRM(rm));
nethercotee8601122004-01-26 17:14:17 +00001073 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1074 dis_buf,nameIReg(size,gregOfRM(rm)));
sewardjde4a1d02002-03-22 01:27:54 +00001075 return HI8(pair)+eip0;
1076 }
1077}
1078
1079
1080
1081/* Handle binary integer instructions of the form
1082 op G, E meaning
1083 op reg, reg-or-mem
1084 Is passed the a ptr to the modRM byte, the actual operation, and the
1085 data size. Returns the address advanced completely over this
1086 instruction.
1087
1088 G(src) is reg.
1089 E(dst) is reg-or-mem
1090
1091 If E is reg, --> GET %E, tmp
1092 OP %G, tmp
1093 PUT tmp, %E
1094
1095 If E is mem, --> (getAddr E) -> tmpa
1096 LD (tmpa), tmpv
1097 OP %G, tmpv
1098 ST tmpv, (tmpa)
1099*/
1100static
1101Addr dis_op2_G_E ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +00001102 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +00001103 Opcode opc,
1104 Bool keep,
1105 Int size,
1106 Addr eip0,
1107 Char* t_x86opc )
1108{
1109 UChar rm = getUChar(eip0);
1110 UChar dis_buf[50];
1111
1112 if (epartIsReg(rm)) {
1113 Int tmp = newTemp(cb);
1114
1115 /* Specially handle XOR reg,reg, because that doesn't really
1116 depend on reg, and doing the obvious thing potentially
1117 generates a spurious value check failure due to the bogus
1118 dependency. */
1119 if (opc == XOR && gregOfRM(rm) == eregOfRM(rm)) {
1120 codegen_XOR_reg_with_itself ( cb, size, gregOfRM(rm), tmp );
1121 return 1+eip0;
1122 }
1123
jseward43bfaee2004-07-20 11:42:24 +00001124 /* gcc sometimes generates "sbbl %reg,%reg" to convert the carry
1125 flag into 0 or -1 in reg. This has no actual dependency on
1126 reg, but memcheck can't see that, and so will yelp if reg
1127 contains garbage. A simple fix is to put zero into reg
1128 before we start, zapping any undefinedness it might otherwise
1129 contain.
1130 */
1131 if (opc == SBB && gregOfRM(rm) == eregOfRM(rm)) {
1132 Int tzero = newTemp(cb);
1133 uInstr2(cb, MOV, size, Literal, 0, TempReg, tzero);
1134 uLiteral(cb, 0);
1135 uInstr2(cb, PUT, size, TempReg, tzero, ArchReg, eregOfRM(rm));
1136 }
1137
sewardjde4a1d02002-03-22 01:27:54 +00001138 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, tmp);
1139
1140 if (opc == AND || opc == OR) {
1141 Int tao = newTemp(cb);
1142 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tao);
1143 uInstr2(cb, opc, size, TempReg, tao, TempReg, tmp);
1144 setFlagsFromUOpcode(cb, opc);
1145 } else {
1146 uInstr2(cb, opc, size, ArchReg, gregOfRM(rm), TempReg, tmp);
1147 setFlagsFromUOpcode(cb, opc);
1148 }
1149 if (keep)
1150 uInstr2(cb, PUT, size, TempReg, tmp, ArchReg, eregOfRM(rm));
nethercotee8601122004-01-26 17:14:17 +00001151 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1152 nameIReg(size,gregOfRM(rm)),
1153 nameIReg(size,eregOfRM(rm)));
sewardjde4a1d02002-03-22 01:27:54 +00001154 return 1+eip0;
1155 }
1156
1157 /* E refers to memory */
1158 {
nethercotee8601122004-01-26 17:14:17 +00001159 UInt pair = disAMode ( cb, sorb, eip0, dis_buf);
sewardjde4a1d02002-03-22 01:27:54 +00001160 Int tmpa = LOW24(pair);
1161 Int tmpv = newTemp(cb);
1162 uInstr2(cb, LOAD, size, TempReg, tmpa, TempReg, tmpv);
1163
1164 if (opc == AND || opc == OR) {
1165 Int tao = newTemp(cb);
1166 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tao);
1167 uInstr2(cb, opc, size, TempReg, tao, TempReg, tmpv);
1168 setFlagsFromUOpcode(cb, opc);
1169 } else {
1170 uInstr2(cb, opc, size, ArchReg, gregOfRM(rm), TempReg, tmpv);
1171 setFlagsFromUOpcode(cb, opc);
1172 }
1173 if (keep) {
1174 uInstr2(cb, STORE, size, TempReg, tmpv, TempReg, tmpa);
sewardjde4a1d02002-03-22 01:27:54 +00001175 }
nethercotee8601122004-01-26 17:14:17 +00001176 DIP("%s%c %s,%s\n", t_x86opc, nameISize(size),
1177 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardjde4a1d02002-03-22 01:27:54 +00001178 return HI8(pair)+eip0;
1179 }
1180}
1181
1182
1183/* Handle move instructions of the form
1184 mov E, G meaning
1185 mov reg-or-mem, reg
1186 Is passed the a ptr to the modRM byte, and the data size. Returns
1187 the address advanced completely over this instruction.
1188
1189 E(src) is reg-or-mem
1190 G(dst) is reg.
1191
sewardje1042472002-09-30 12:33:11 +00001192 If E is reg, --> GET %E, tmpv
sewardjde4a1d02002-03-22 01:27:54 +00001193 PUT tmpv, %G
1194
1195 If E is mem --> (getAddr E) -> tmpa
1196 LD (tmpa), tmpb
1197 PUT tmpb, %G
1198*/
1199static
1200Addr dis_mov_E_G ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +00001201 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +00001202 Int size,
1203 Addr eip0 )
1204{
1205 UChar rm = getUChar(eip0);
1206 UChar dis_buf[50];
1207
1208 if (epartIsReg(rm)) {
1209 Int tmpv = newTemp(cb);
1210 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, tmpv);
1211 uInstr2(cb, PUT, size, TempReg, tmpv, ArchReg, gregOfRM(rm));
nethercotee8601122004-01-26 17:14:17 +00001212 DIP("mov%c %s,%s\n", nameISize(size),
sewardjde4a1d02002-03-22 01:27:54 +00001213 nameIReg(size,eregOfRM(rm)),
1214 nameIReg(size,gregOfRM(rm)));
1215 return 1+eip0;
1216 }
1217
1218 /* E refers to memory */
1219 {
nethercotee8601122004-01-26 17:14:17 +00001220 UInt pair = disAMode ( cb, sorb, eip0, dis_buf);
sewardjde4a1d02002-03-22 01:27:54 +00001221 Int tmpa = LOW24(pair);
1222 Int tmpb = newTemp(cb);
1223 uInstr2(cb, LOAD, size, TempReg, tmpa, TempReg, tmpb);
1224 uInstr2(cb, PUT, size, TempReg, tmpb, ArchReg, gregOfRM(rm));
nethercotee8601122004-01-26 17:14:17 +00001225 DIP("mov%c %s,%s\n", nameISize(size),
sewardjde4a1d02002-03-22 01:27:54 +00001226 dis_buf,nameIReg(size,gregOfRM(rm)));
1227 return HI8(pair)+eip0;
1228 }
1229}
1230
1231
1232/* Handle move instructions of the form
1233 mov G, E meaning
1234 mov reg, reg-or-mem
1235 Is passed the a ptr to the modRM byte, and the data size. Returns
1236 the address advanced completely over this instruction.
1237
1238 G(src) is reg.
1239 E(dst) is reg-or-mem
1240
1241 If E is reg, --> GET %G, tmp
1242 PUT tmp, %E
1243
1244 If E is mem, --> (getAddr E) -> tmpa
1245 GET %G, tmpv
1246 ST tmpv, (tmpa)
1247*/
1248static
1249Addr dis_mov_G_E ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +00001250 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +00001251 Int size,
1252 Addr eip0 )
1253{
1254 UChar rm = getUChar(eip0);
1255 UChar dis_buf[50];
1256
1257 if (epartIsReg(rm)) {
1258 Int tmpv = newTemp(cb);
1259 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmpv);
1260 uInstr2(cb, PUT, size, TempReg, tmpv, ArchReg, eregOfRM(rm));
nethercotee8601122004-01-26 17:14:17 +00001261 DIP("mov%c %s,%s\n", nameISize(size),
sewardjde4a1d02002-03-22 01:27:54 +00001262 nameIReg(size,gregOfRM(rm)),
1263 nameIReg(size,eregOfRM(rm)));
1264 return 1+eip0;
1265 }
1266
1267 /* E refers to memory */
1268 {
nethercotee8601122004-01-26 17:14:17 +00001269 UInt pair = disAMode ( cb, sorb, eip0, dis_buf);
sewardjde4a1d02002-03-22 01:27:54 +00001270 Int tmpa = LOW24(pair);
1271 Int tmpv = newTemp(cb);
1272 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmpv);
1273 uInstr2(cb, STORE, size, TempReg, tmpv, TempReg, tmpa);
nethercotee8601122004-01-26 17:14:17 +00001274 DIP("mov%c %s,%s\n", nameISize(size),
sewardjde4a1d02002-03-22 01:27:54 +00001275 nameIReg(size,gregOfRM(rm)), dis_buf);
1276 return HI8(pair)+eip0;
1277 }
1278}
1279
1280
1281/* op $immediate, AL/AX/EAX. */
1282static
1283Addr dis_op_imm_A ( UCodeBlock* cb,
1284 Int size,
1285 Opcode opc,
1286 Bool keep,
1287 Addr eip,
1288 Char* t_x86opc )
1289{
1290 Int tmp = newTemp(cb);
1291 UInt lit = getUDisp(size,eip);
1292 uInstr2(cb, GET, size, ArchReg, R_EAX, TempReg, tmp);
1293 if (opc == AND || opc == OR) {
1294 Int tao = newTemp(cb);
1295 uInstr2(cb, MOV, size, Literal, 0, TempReg, tao);
1296 uLiteral(cb, lit);
1297 uInstr2(cb, opc, size, TempReg, tao, TempReg, tmp);
1298 setFlagsFromUOpcode(cb, opc);
1299 } else {
1300 uInstr2(cb, opc, size, Literal, 0, TempReg, tmp);
1301 uLiteral(cb, lit);
1302 setFlagsFromUOpcode(cb, opc);
1303 }
1304 if (keep)
1305 uInstr2(cb, PUT, size, TempReg, tmp, ArchReg, R_EAX);
nethercotee8601122004-01-26 17:14:17 +00001306 DIP("%s%c $0x%x, %s\n", t_x86opc, nameISize(size),
1307 lit, nameIReg(size,R_EAX));
sewardjde4a1d02002-03-22 01:27:54 +00001308 return eip+size;
1309}
1310
1311
1312/* Sign- and Zero-extending moves. */
1313static
1314Addr dis_movx_E_G ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +00001315 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +00001316 Addr eip, Int szs, Int szd, Bool sign_extend )
1317{
1318 UChar dis_buf[50];
1319 UChar rm = getUChar(eip);
1320 if (epartIsReg(rm)) {
1321 Int tmpv = newTemp(cb);
1322 uInstr2(cb, GET, szs, ArchReg, eregOfRM(rm), TempReg, tmpv);
1323 uInstr1(cb, WIDEN, szd, TempReg, tmpv);
nethercote911cc372004-04-18 12:23:02 +00001324 uWiden(cb, szs, sign_extend);
sewardjde4a1d02002-03-22 01:27:54 +00001325 uInstr2(cb, PUT, szd, TempReg, tmpv, ArchReg, gregOfRM(rm));
nethercotee8601122004-01-26 17:14:17 +00001326 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
1327 nameISize(szs), nameISize(szd),
1328 nameIReg(szs,eregOfRM(rm)),
1329 nameIReg(szd,gregOfRM(rm)));
sewardjde4a1d02002-03-22 01:27:54 +00001330 return 1+eip;
1331 }
1332
1333 /* E refers to memory */
1334 {
nethercotee8601122004-01-26 17:14:17 +00001335 UInt pair = disAMode ( cb, sorb, eip, dis_buf);
sewardjde4a1d02002-03-22 01:27:54 +00001336 Int tmpa = LOW24(pair);
1337 uInstr2(cb, LOAD, szs, TempReg, tmpa, TempReg, tmpa);
1338 uInstr1(cb, WIDEN, szd, TempReg, tmpa);
nethercote911cc372004-04-18 12:23:02 +00001339 uWiden(cb, szs, sign_extend);
sewardjde4a1d02002-03-22 01:27:54 +00001340 uInstr2(cb, PUT, szd, TempReg, tmpa, ArchReg, gregOfRM(rm));
nethercotee8601122004-01-26 17:14:17 +00001341 DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
1342 nameISize(szs), nameISize(szd),
1343 dis_buf, nameIReg(szd,gregOfRM(rm)));
sewardjde4a1d02002-03-22 01:27:54 +00001344 return HI8(pair)+eip;
1345 }
1346}
1347
1348
1349/* Generate code to divide ArchRegs EDX:EAX / DX:AX / AX by the 32 /
1350 16 / 8 bit quantity in the given TempReg. */
1351static
1352void codegen_div ( UCodeBlock* cb, Int sz, Int t, Bool signed_divide )
1353{
1354 Int helper;
1355 Int ta = newTemp(cb);
1356 Int td = newTemp(cb);
1357
1358 switch (sz) {
1359 case 4: helper = (signed_divide ? VGOFF_(helper_idiv_64_32)
1360 : VGOFF_(helper_div_64_32));
1361 break;
1362 case 2: helper = (signed_divide ? VGOFF_(helper_idiv_32_16)
1363 : VGOFF_(helper_div_32_16));
1364 break;
1365 case 1: helper = (signed_divide ? VGOFF_(helper_idiv_16_8)
1366 : VGOFF_(helper_div_16_8));
1367 break;
njne427a662002-10-02 11:08:25 +00001368 default: VG_(core_panic)("codegen_div");
sewardjde4a1d02002-03-22 01:27:54 +00001369 }
1370 uInstr0(cb, CALLM_S, 0);
1371 if (sz == 4 || sz == 2) {
1372 uInstr1(cb, PUSH, sz, TempReg, t);
1373 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
1374 uInstr1(cb, PUSH, sz, TempReg, ta);
1375 uInstr2(cb, GET, sz, ArchReg, R_EDX, TempReg, td);
1376 uInstr1(cb, PUSH, sz, TempReg, td);
1377 uInstr1(cb, CALLM, 0, Lit16, helper);
1378 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsOSZACP);
1379 uInstr1(cb, POP, sz, TempReg, t);
1380 uInstr2(cb, PUT, sz, TempReg, t, ArchReg, R_EDX);
1381 uInstr1(cb, POP, sz, TempReg, t);
1382 uInstr2(cb, PUT, sz, TempReg, t, ArchReg, R_EAX);
1383 uInstr1(cb, CLEAR, 0, Lit16, 4);
1384 } else {
1385 uInstr1(cb, PUSH, 1, TempReg, t);
1386 uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, ta);
1387 uInstr1(cb, PUSH, 2, TempReg, ta);
1388 uInstr2(cb, MOV, 1, Literal, 0, TempReg, td);
1389 uLiteral(cb, 0);
1390 uInstr1(cb, PUSH, 1, TempReg, td);
1391 uInstr1(cb, CALLM, 0, Lit16, helper);
1392 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsOSZACP);
1393 uInstr1(cb, POP, 1, TempReg, t);
1394 uInstr2(cb, PUT, 1, TempReg, t, ArchReg, R_AL);
1395 uInstr1(cb, POP, 1, TempReg, t);
1396 uInstr2(cb, PUT, 1, TempReg, t, ArchReg, R_AH);
1397 uInstr1(cb, CLEAR, 0, Lit16, 4);
1398 }
1399 uInstr0(cb, CALLM_E, 0);
1400}
1401
1402
1403static
sewardje1042472002-09-30 12:33:11 +00001404Addr dis_Grp1 ( UCodeBlock* cb,
1405 UChar sorb,
1406 Addr eip, UChar modrm,
sewardjde4a1d02002-03-22 01:27:54 +00001407 Int am_sz, Int d_sz, Int sz, UInt d32 )
1408{
1409 Int t1, t2, uopc;
1410 UInt pair;
1411 UChar dis_buf[50];
1412 if (epartIsReg(modrm)) {
1413 vg_assert(am_sz == 1);
1414 t1 = newTemp(cb);
1415 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1416 switch (gregOfRM(modrm)) {
1417 case 0: uopc = ADD; break; case 1: uopc = OR; break;
1418 case 2: uopc = ADC; break; case 3: uopc = SBB; break;
1419 case 4: uopc = AND; break; case 5: uopc = SUB; break;
1420 case 6: uopc = XOR; break; case 7: uopc = SUB; break;
njne427a662002-10-02 11:08:25 +00001421 default: VG_(core_panic)("dis_Grp1(Reg): unhandled case");
sewardjde4a1d02002-03-22 01:27:54 +00001422 }
1423 if (uopc == AND || uopc == OR) {
1424 Int tao = newTemp(cb);
1425 uInstr2(cb, MOV, sz, Literal, 0, TempReg, tao);
1426 uLiteral(cb, d32);
1427 uInstr2(cb, uopc, sz, TempReg, tao, TempReg, t1);
1428 setFlagsFromUOpcode(cb, uopc);
1429 } else {
1430 uInstr2(cb, uopc, sz, Literal, 0, TempReg, t1);
1431 uLiteral(cb, d32);
1432 setFlagsFromUOpcode(cb, uopc);
1433 }
1434 if (gregOfRM(modrm) < 7)
1435 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
1436 eip += (am_sz + d_sz);
nethercotee8601122004-01-26 17:14:17 +00001437 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz), d32,
1438 nameIReg(sz,eregOfRM(modrm)));
sewardjde4a1d02002-03-22 01:27:54 +00001439 } else {
nethercotee8601122004-01-26 17:14:17 +00001440 pair = disAMode ( cb, sorb, eip, dis_buf);
sewardjde4a1d02002-03-22 01:27:54 +00001441 t1 = LOW24(pair);
1442 t2 = newTemp(cb);
1443 eip += HI8(pair);
1444 eip += d_sz;
1445 uInstr2(cb, LOAD, sz, TempReg, t1, TempReg, t2);
1446 switch (gregOfRM(modrm)) {
1447 case 0: uopc = ADD; break; case 1: uopc = OR; break;
1448 case 2: uopc = ADC; break; case 3: uopc = SBB; break;
1449 case 4: uopc = AND; break; case 5: uopc = SUB; break;
1450 case 6: uopc = XOR; break; case 7: uopc = SUB; break;
njne427a662002-10-02 11:08:25 +00001451 default: VG_(core_panic)("dis_Grp1(Mem): unhandled case");
sewardjde4a1d02002-03-22 01:27:54 +00001452 }
1453 if (uopc == AND || uopc == OR) {
1454 Int tao = newTemp(cb);
1455 uInstr2(cb, MOV, sz, Literal, 0, TempReg, tao);
1456 uLiteral(cb, d32);
1457 uInstr2(cb, uopc, sz, TempReg, tao, TempReg, t2);
1458 setFlagsFromUOpcode(cb, uopc);
1459 } else {
1460 uInstr2(cb, uopc, sz, Literal, 0, TempReg, t2);
1461 uLiteral(cb, d32);
1462 setFlagsFromUOpcode(cb, uopc);
1463 }
1464 if (gregOfRM(modrm) < 7) {
1465 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
sewardjde4a1d02002-03-22 01:27:54 +00001466 }
nethercotee8601122004-01-26 17:14:17 +00001467 DIP("%s%c $0x%x, %s\n", nameGrp1(gregOfRM(modrm)), nameISize(sz),
1468 d32, dis_buf);
sewardjde4a1d02002-03-22 01:27:54 +00001469 }
1470 return eip;
1471}
1472
1473
1474/* Group 2 extended opcodes. */
1475static
sewardje1042472002-09-30 12:33:11 +00001476Addr dis_Grp2 ( UCodeBlock* cb,
1477 UChar sorb,
1478 Addr eip, UChar modrm,
sewardjde4a1d02002-03-22 01:27:54 +00001479 Int am_sz, Int d_sz, Int sz,
1480 Tag orig_src_tag, UInt orig_src_val )
1481{
1482 /* orig_src_tag and orig_src_val denote either ArchReg(%CL) or a
1483 Literal. And eip on entry points at the modrm byte. */
1484 Int t1, t2, uopc;
1485 UInt pair;
1486 UChar dis_buf[50];
1487 UInt src_val;
1488 Tag src_tag;
1489
1490 /* Get the amount to be shifted by into src_tag/src_val. */
1491 if (orig_src_tag == ArchReg) {
1492 src_val = newTemp(cb);
1493 src_tag = TempReg;
1494 uInstr2(cb, GET, 1, orig_src_tag, orig_src_val, TempReg, src_val);
1495 } else {
1496 src_val = orig_src_val;
1497 src_tag = Literal;
1498 }
1499
1500 if (epartIsReg(modrm)) {
1501 vg_assert(am_sz == 1);
1502 t1 = newTemp(cb);
1503 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1504 switch (gregOfRM(modrm)) {
1505 case 0: uopc = ROL; break; case 1: uopc = ROR; break;
1506 case 2: uopc = RCL; break; case 3: uopc = RCR; break;
1507 case 4: uopc = SHL; break; case 5: uopc = SHR; break;
1508 case 7: uopc = SAR; break;
njne427a662002-10-02 11:08:25 +00001509 default: VG_(core_panic)("dis_Grp2(Reg): unhandled case");
sewardjde4a1d02002-03-22 01:27:54 +00001510 }
1511 if (src_tag == Literal) {
1512 uInstr2(cb, uopc, sz, Literal, 0, TempReg, t1);
1513 uLiteral(cb, src_val);
1514 } else {
1515 uInstr2(cb, uopc, sz, src_tag, src_val, TempReg, t1);
1516 }
1517 setFlagsFromUOpcode(cb, uopc);
1518 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
1519 eip += (am_sz + d_sz);
nethercotee8601122004-01-26 17:14:17 +00001520 if (VG_(print_codegen)) {
sewardjde4a1d02002-03-22 01:27:54 +00001521 if (orig_src_tag == Literal)
1522 VG_(printf)("%s%c $0x%x, %s\n",
1523 nameGrp2(gregOfRM(modrm)), nameISize(sz),
1524 orig_src_val, nameIReg(sz,eregOfRM(modrm)));
1525 else
1526 VG_(printf)("%s%c %s, %s\n",
1527 nameGrp2(gregOfRM(modrm)), nameISize(sz),
1528 nameIReg(1,orig_src_val),
1529 nameIReg(sz,eregOfRM(modrm)));
1530 }
1531 } else {
nethercotee8601122004-01-26 17:14:17 +00001532 pair = disAMode ( cb, sorb, eip, dis_buf);
sewardjde4a1d02002-03-22 01:27:54 +00001533 t1 = LOW24(pair);
1534 t2 = newTemp(cb);
1535 eip += HI8(pair);
1536 eip += d_sz;
1537 uInstr2(cb, LOAD, sz, TempReg, t1, TempReg, t2);
1538 switch (gregOfRM(modrm)) {
1539 case 0: uopc = ROL; break; case 1: uopc = ROR; break;
1540 case 2: uopc = RCL; break; case 3: uopc = RCR; break;
1541 case 4: uopc = SHL; break; case 5: uopc = SHR; break;
1542 case 7: uopc = SAR; break;
njne427a662002-10-02 11:08:25 +00001543 default: VG_(core_panic)("dis_Grp2(Reg): unhandled case");
sewardjde4a1d02002-03-22 01:27:54 +00001544 }
1545 if (src_tag == Literal) {
1546 uInstr2(cb, uopc, sz, Literal, 0, TempReg, t2);
1547 uLiteral(cb, src_val);
1548 } else {
1549 uInstr2(cb, uopc, sz, src_tag, src_val, TempReg, t2);
1550 }
1551 setFlagsFromUOpcode(cb, uopc);
1552 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
nethercotee8601122004-01-26 17:14:17 +00001553 if (VG_(print_codegen)) {
sewardjde4a1d02002-03-22 01:27:54 +00001554 if (orig_src_tag == Literal)
1555 VG_(printf)("%s%c $0x%x, %s\n",
1556 nameGrp2(gregOfRM(modrm)), nameISize(sz),
1557 orig_src_val, dis_buf);
1558 else
1559 VG_(printf)("%s%c %s, %s\n",
1560 nameGrp2(gregOfRM(modrm)), nameISize(sz),
1561 nameIReg(1,orig_src_val),
1562 dis_buf);
1563 }
1564 }
1565 return eip;
1566}
1567
1568
sewardj0ece28b2002-04-16 00:42:12 +00001569
1570/* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
sewardjde4a1d02002-03-22 01:27:54 +00001571static
sewardje1042472002-09-30 12:33:11 +00001572Addr dis_Grp8_BT ( UCodeBlock* cb,
1573 UChar sorb,
1574 Addr eip, UChar modrm,
sewardj0ece28b2002-04-16 00:42:12 +00001575 Int am_sz, Int sz, UInt src_val )
sewardjde4a1d02002-03-22 01:27:54 +00001576{
sewardj0ece28b2002-04-16 00:42:12 +00001577# define MODIFY_t2_AND_SET_CARRY_FLAG \
1578 /* t2 is the value to be op'd on. Copy to t_fetched, then \
1579 modify t2, if non-BT. */ \
1580 uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t_fetched); \
1581 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
1582 uLiteral(cb, v_mask); \
1583 switch (gregOfRM(modrm)) { \
1584 case 4: /* BT */ break; \
1585 case 5: /* BTS */ \
1586 uInstr2(cb, OR, sz, TempReg, t_mask, TempReg, t2); break; \
1587 case 6: /* BTR */ \
1588 uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t2); break; \
1589 case 7: /* BTC */ \
1590 uInstr2(cb, XOR, sz, TempReg, t_mask, TempReg, t2); break; \
1591 } \
1592 /* Copy relevant bit from t_fetched into carry flag. */ \
1593 uInstr2(cb, SHR, sz, Literal, 0, TempReg, t_fetched); \
1594 uLiteral(cb, src_val); \
1595 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
1596 uLiteral(cb, 1); \
1597 uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t_fetched); \
1598 uInstr1(cb, NEG, sz, TempReg, t_fetched); \
1599 setFlagsFromUOpcode(cb, NEG);
1600
1601
sewardjde4a1d02002-03-22 01:27:54 +00001602 /* src_val denotes a d8.
1603 And eip on entry points at the modrm byte. */
sewardj0ece28b2002-04-16 00:42:12 +00001604 Int t1, t2, t_fetched, t_mask;
sewardjde4a1d02002-03-22 01:27:54 +00001605 UInt pair;
nethercotee8601122004-01-26 17:14:17 +00001606 Char dis_buf[50];
sewardj0ece28b2002-04-16 00:42:12 +00001607 UInt v_mask;
sewardjde4a1d02002-03-22 01:27:54 +00001608
sewardj0ece28b2002-04-16 00:42:12 +00001609 /* There is no 1-byte form of this instruction, AFAICS. */
1610 vg_assert(sz == 2 || sz == 4);
1611
1612 /* Limit src_val -- the bit offset -- to something within a word.
1613 The Intel docs say that literal offsets larger than a word are
1614 masked in this way. */
1615 switch (sz) {
1616 case 2: src_val &= 15; break;
1617 case 4: src_val &= 31; break;
njne427a662002-10-02 11:08:25 +00001618 default: VG_(core_panic)("dis_Grp8_BT: invalid size");
sewardjde4a1d02002-03-22 01:27:54 +00001619 }
1620
sewardj0ece28b2002-04-16 00:42:12 +00001621 /* Invent a mask suitable for the operation. */
1622
1623 switch (gregOfRM(modrm)) {
1624 case 4: /* BT */ v_mask = 0; break;
1625 case 5: /* BTS */ v_mask = 1 << src_val; break;
1626 case 6: /* BTR */ v_mask = ~(1 << src_val); break;
1627 case 7: /* BTC */ v_mask = 1 << src_val; break;
1628 /* If this needs to be extended, probably simplest to make a
1629 new function to handle the other cases (0 .. 3). The
1630 Intel docs do however not indicate any use for 0 .. 3, so
1631 we don't expect this to happen. */
njne427a662002-10-02 11:08:25 +00001632 default: VG_(core_panic)("dis_Grp8_BT");
sewardj0ece28b2002-04-16 00:42:12 +00001633 }
1634 /* Probably excessively paranoid. */
1635 if (sz == 2)
1636 v_mask &= 0x0000FFFF;
1637
1638 t1 = INVALID_TEMPREG;
1639 t_fetched = newTemp(cb);
1640 t_mask = newTemp(cb);
1641
sewardjde4a1d02002-03-22 01:27:54 +00001642 if (epartIsReg(modrm)) {
1643 vg_assert(am_sz == 1);
1644 t2 = newTemp(cb);
sewardj0ece28b2002-04-16 00:42:12 +00001645
1646 /* Fetch the value to be tested and modified. */
1647 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t2);
1648 /* Do it! */
1649 MODIFY_t2_AND_SET_CARRY_FLAG;
1650 /* Dump the result back, if non-BT. */
1651 if (gregOfRM(modrm) != 4 /* BT */)
1652 uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, eregOfRM(modrm));
1653
sewardjde4a1d02002-03-22 01:27:54 +00001654 eip += (am_sz + 1);
nethercotee8601122004-01-26 17:14:17 +00001655 DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
1656 src_val, nameIReg(sz,eregOfRM(modrm)));
sewardjde4a1d02002-03-22 01:27:54 +00001657 } else {
nethercotee8601122004-01-26 17:14:17 +00001658 pair = disAMode ( cb, sorb, eip, dis_buf);
sewardjde4a1d02002-03-22 01:27:54 +00001659 t1 = LOW24(pair);
1660 t2 = newTemp(cb);
1661 eip += HI8(pair);
1662 eip += 1;
sewardj0ece28b2002-04-16 00:42:12 +00001663
1664 /* Fetch the value to be tested and modified. */
sewardjde4a1d02002-03-22 01:27:54 +00001665 uInstr2(cb, LOAD, sz, TempReg, t1, TempReg, t2);
sewardj0ece28b2002-04-16 00:42:12 +00001666 /* Do it! */
1667 MODIFY_t2_AND_SET_CARRY_FLAG;
1668 /* Dump the result back, if non-BT. */
1669 if (gregOfRM(modrm) != 4 /* BT */) {
1670 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
sewardj0ece28b2002-04-16 00:42:12 +00001671 }
nethercotee8601122004-01-26 17:14:17 +00001672 DIP("%s%c $0x%x, %s\n", nameGrp8(gregOfRM(modrm)), nameISize(sz),
1673 src_val, dis_buf);
sewardjde4a1d02002-03-22 01:27:54 +00001674 }
sewardjde4a1d02002-03-22 01:27:54 +00001675 return eip;
sewardj0ece28b2002-04-16 00:42:12 +00001676
1677# undef MODIFY_t2_AND_SET_CARRY_FLAG
sewardjde4a1d02002-03-22 01:27:54 +00001678}
sewardjde4a1d02002-03-22 01:27:54 +00001679
1680
1681
1682/* Generate ucode to multiply the value in EAX/AX/AL by the register
1683 specified by the ereg of modrm, and park the result in
1684 EDX:EAX/DX:AX/AX. */
1685static void codegen_mul_A_D_Reg ( UCodeBlock* cb, Int sz,
1686 UChar modrm, Bool signed_multiply )
1687{
1688 Int helper = signed_multiply
1689 ?
1690 (sz==1 ? VGOFF_(helper_imul_8_16)
1691 : (sz==2 ? VGOFF_(helper_imul_16_32)
1692 : VGOFF_(helper_imul_32_64)))
1693 :
1694 (sz==1 ? VGOFF_(helper_mul_8_16)
1695 : (sz==2 ? VGOFF_(helper_mul_16_32)
1696 : VGOFF_(helper_mul_32_64)));
1697 Int t1 = newTemp(cb);
1698 Int ta = newTemp(cb);
1699 uInstr0(cb, CALLM_S, 0);
1700 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1701 uInstr1(cb, PUSH, sz, TempReg, t1);
1702 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
1703 uInstr1(cb, PUSH, sz, TempReg, ta);
1704 uInstr1(cb, CALLM, 0, Lit16, helper);
1705 uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP);
1706 if (sz > 1) {
1707 uInstr1(cb, POP, sz, TempReg, t1);
1708 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EDX);
1709 uInstr1(cb, POP, sz, TempReg, t1);
1710 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EAX);
1711 } else {
1712 uInstr1(cb, CLEAR, 0, Lit16, 4);
1713 uInstr1(cb, POP, 2, TempReg, t1);
1714 uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
1715 }
jsgf5efa4fd2003-10-14 21:49:11 +00001716 uInstr0(cb, CALLM_E, 0);
nethercotee8601122004-01-26 17:14:17 +00001717 DIP("%s%c %s\n", signed_multiply ? "imul" : "mul",
1718 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
sewardjde4a1d02002-03-22 01:27:54 +00001719
1720}
1721
1722
1723/* Generate ucode to multiply the value in EAX/AX/AL by the value in
1724 TempReg temp, and park the result in EDX:EAX/DX:AX/AX. */
1725static void codegen_mul_A_D_Temp ( UCodeBlock* cb, Int sz,
1726 Int temp, Bool signed_multiply,
1727 UChar* dis_buf )
1728{
1729 Int helper = signed_multiply
1730 ?
1731 (sz==1 ? VGOFF_(helper_imul_8_16)
1732 : (sz==2 ? VGOFF_(helper_imul_16_32)
1733 : VGOFF_(helper_imul_32_64)))
1734 :
1735 (sz==1 ? VGOFF_(helper_mul_8_16)
1736 : (sz==2 ? VGOFF_(helper_mul_16_32)
1737 : VGOFF_(helper_mul_32_64)));
1738 Int t1 = newTemp(cb);
1739 uInstr0(cb, CALLM_S, 0);
1740 uInstr1(cb, PUSH, sz, TempReg, temp);
1741 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
1742 uInstr1(cb, PUSH, sz, TempReg, t1);
1743 uInstr1(cb, CALLM, 0, Lit16, helper);
1744 uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP);
1745 if (sz > 1) {
1746 uInstr1(cb, POP, sz, TempReg, t1);
1747 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EDX);
1748 uInstr1(cb, POP, sz, TempReg, t1);
1749 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EAX);
1750 } else {
1751 uInstr1(cb, CLEAR, 0, Lit16, 4);
1752 uInstr1(cb, POP, 2, TempReg, t1);
1753 uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
1754 }
1755 uInstr0(cb, CALLM_E, 0);
nethercotee8601122004-01-26 17:14:17 +00001756 DIP("%s%c %s\n", signed_multiply ? "imul" : "mul",
1757 nameISize(sz), dis_buf);
sewardjde4a1d02002-03-22 01:27:54 +00001758}
1759
1760
1761/* Group 3 extended opcodes. */
1762static
sewardje1042472002-09-30 12:33:11 +00001763Addr dis_Grp3 ( UCodeBlock* cb,
1764 UChar sorb,
1765 Int sz, Addr eip )
sewardjde4a1d02002-03-22 01:27:54 +00001766{
1767 Int t1, t2;
1768 UInt pair, d32;
1769 UChar modrm;
1770 UChar dis_buf[50];
1771 t1 = t2 = INVALID_TEMPREG;
1772 modrm = getUChar(eip);
1773 if (epartIsReg(modrm)) {
1774 t1 = newTemp(cb);
1775 switch (gregOfRM(modrm)) {
1776 case 0: { /* TEST */
1777 Int tao = newTemp(cb);
1778 eip++; d32 = getUDisp(sz, eip); eip += sz;
1779 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1780 uInstr2(cb, MOV, sz, Literal, 0, TempReg, tao);
1781 uLiteral(cb, d32);
1782 uInstr2(cb, AND, sz, TempReg, tao, TempReg, t1);
1783 setFlagsFromUOpcode(cb, AND);
nethercotee8601122004-01-26 17:14:17 +00001784 DIP("test%c $0x%x, %s\n",
1785 nameISize(sz), d32, nameIReg(sz, eregOfRM(modrm)));
sewardjde4a1d02002-03-22 01:27:54 +00001786 break;
1787 }
1788 case 2: /* NOT */
1789 eip++;
1790 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1791 uInstr1(cb, NOT, sz, TempReg, t1);
1792 setFlagsFromUOpcode(cb, NOT);
1793 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
nethercotee8601122004-01-26 17:14:17 +00001794 DIP("not%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
sewardjde4a1d02002-03-22 01:27:54 +00001795 break;
1796 case 3: /* NEG */
1797 eip++;
1798 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1799 uInstr1(cb, NEG, sz, TempReg, t1);
1800 setFlagsFromUOpcode(cb, NEG);
1801 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
nethercotee8601122004-01-26 17:14:17 +00001802 DIP("neg%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
sewardjde4a1d02002-03-22 01:27:54 +00001803 break;
1804 case 4: /* MUL */
1805 eip++;
1806 codegen_mul_A_D_Reg ( cb, sz, modrm, False );
1807 break;
1808 case 5: /* IMUL */
1809 eip++;
1810 codegen_mul_A_D_Reg ( cb, sz, modrm, True );
1811 break;
1812 case 6: /* DIV */
1813 eip++;
1814 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1815 codegen_div ( cb, sz, t1, False );
nethercotee8601122004-01-26 17:14:17 +00001816 DIP("div%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
sewardjde4a1d02002-03-22 01:27:54 +00001817 break;
1818 case 7: /* IDIV */
1819 eip++;
1820 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1821 codegen_div ( cb, sz, t1, True );
nethercotee8601122004-01-26 17:14:17 +00001822 DIP("idiv%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
sewardjde4a1d02002-03-22 01:27:54 +00001823 break;
1824 default:
1825 VG_(printf)(
1826 "unhandled Grp3(R) case %d\n", (UInt)gregOfRM(modrm));
njne427a662002-10-02 11:08:25 +00001827 VG_(core_panic)("Grp3");
sewardjde4a1d02002-03-22 01:27:54 +00001828 }
1829 } else {
nethercotee8601122004-01-26 17:14:17 +00001830 pair = disAMode ( cb, sorb, eip, dis_buf );
sewardjde4a1d02002-03-22 01:27:54 +00001831 t2 = LOW24(pair);
1832 t1 = newTemp(cb);
1833 eip += HI8(pair);
1834 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
1835 switch (gregOfRM(modrm)) {
1836 case 0: { /* TEST */
1837 Int tao = newTemp(cb);
1838 d32 = getUDisp(sz, eip); eip += sz;
1839 uInstr2(cb, MOV, sz, Literal, 0, TempReg, tao);
1840 uLiteral(cb, d32);
1841 uInstr2(cb, AND, sz, TempReg, tao, TempReg, t1);
1842 setFlagsFromUOpcode(cb, AND);
nethercotee8601122004-01-26 17:14:17 +00001843 DIP("test%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
sewardjde4a1d02002-03-22 01:27:54 +00001844 break;
1845 }
1846 case 2: /* NOT */
1847 uInstr1(cb, NOT, sz, TempReg, t1);
1848 setFlagsFromUOpcode(cb, NOT);
1849 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
nethercotee8601122004-01-26 17:14:17 +00001850 DIP("not%c %s\n", nameISize(sz), dis_buf);
sewardjde4a1d02002-03-22 01:27:54 +00001851 break;
1852 case 3: /* NEG */
1853 uInstr1(cb, NEG, sz, TempReg, t1);
1854 setFlagsFromUOpcode(cb, NEG);
1855 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
nethercotee8601122004-01-26 17:14:17 +00001856 DIP("neg%c %s\n", nameISize(sz), dis_buf);
sewardjde4a1d02002-03-22 01:27:54 +00001857 break;
1858 case 4: /* MUL */
1859 codegen_mul_A_D_Temp ( cb, sz, t1, False,
nethercotee8601122004-01-26 17:14:17 +00001860 dis_buf );
sewardjde4a1d02002-03-22 01:27:54 +00001861 break;
1862 case 5: /* IMUL */
nethercotee8601122004-01-26 17:14:17 +00001863 codegen_mul_A_D_Temp ( cb, sz, t1, True, dis_buf );
sewardjde4a1d02002-03-22 01:27:54 +00001864 break;
1865 case 6: /* DIV */
1866 codegen_div ( cb, sz, t1, False );
nethercotee8601122004-01-26 17:14:17 +00001867 DIP("div%c %s\n", nameISize(sz), dis_buf);
sewardjde4a1d02002-03-22 01:27:54 +00001868 break;
1869 case 7: /* IDIV */
1870 codegen_div ( cb, sz, t1, True );
nethercotee8601122004-01-26 17:14:17 +00001871 DIP("idiv%c %s\n", nameISize(sz), dis_buf);
sewardjde4a1d02002-03-22 01:27:54 +00001872 break;
1873 default:
1874 VG_(printf)(
1875 "unhandled Grp3(M) case %d\n", (UInt)gregOfRM(modrm));
njne427a662002-10-02 11:08:25 +00001876 VG_(core_panic)("Grp3");
sewardjde4a1d02002-03-22 01:27:54 +00001877 }
1878 }
1879 return eip;
1880}
1881
1882
1883/* Group 4 extended opcodes. */
1884static
sewardje1042472002-09-30 12:33:11 +00001885Addr dis_Grp4 ( UCodeBlock* cb,
1886 UChar sorb,
1887 Addr eip )
sewardjde4a1d02002-03-22 01:27:54 +00001888{
1889 Int t1, t2;
1890 UInt pair;
1891 UChar modrm;
1892 UChar dis_buf[50];
1893 t1 = t2 = INVALID_TEMPREG;
1894
1895 modrm = getUChar(eip);
1896 if (epartIsReg(modrm)) {
1897 t1 = newTemp(cb);
1898 uInstr2(cb, GET, 1, ArchReg, eregOfRM(modrm), TempReg, t1);
1899 switch (gregOfRM(modrm)) {
1900 case 0: /* INC */
1901 uInstr1(cb, INC, 1, TempReg, t1);
1902 setFlagsFromUOpcode(cb, INC);
1903 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, eregOfRM(modrm));
1904 break;
1905 case 1: /* DEC */
1906 uInstr1(cb, DEC, 1, TempReg, t1);
1907 setFlagsFromUOpcode(cb, DEC);
1908 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, eregOfRM(modrm));
1909 break;
1910 default:
1911 VG_(printf)(
1912 "unhandled Grp4(R) case %d\n", (UInt)gregOfRM(modrm));
njne427a662002-10-02 11:08:25 +00001913 VG_(core_panic)("Grp4");
sewardjde4a1d02002-03-22 01:27:54 +00001914 }
1915 eip++;
nethercotee8601122004-01-26 17:14:17 +00001916 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)),
1917 nameIReg(1, eregOfRM(modrm)));
sewardjde4a1d02002-03-22 01:27:54 +00001918 } else {
nethercotee8601122004-01-26 17:14:17 +00001919 pair = disAMode ( cb, sorb, eip, dis_buf );
sewardjde4a1d02002-03-22 01:27:54 +00001920 t2 = LOW24(pair);
1921 t1 = newTemp(cb);
1922 uInstr2(cb, LOAD, 1, TempReg, t2, TempReg, t1);
1923 switch (gregOfRM(modrm)) {
1924 case 0: /* INC */
1925 uInstr1(cb, INC, 1, TempReg, t1);
1926 setFlagsFromUOpcode(cb, INC);
1927 uInstr2(cb, STORE, 1, TempReg, t1, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00001928 break;
1929 case 1: /* DEC */
1930 uInstr1(cb, DEC, 1, TempReg, t1);
1931 setFlagsFromUOpcode(cb, DEC);
1932 uInstr2(cb, STORE, 1, TempReg, t1, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00001933 break;
1934 default:
1935 VG_(printf)(
1936 "unhandled Grp4(M) case %d\n", (UInt)gregOfRM(modrm));
njne427a662002-10-02 11:08:25 +00001937 VG_(core_panic)("Grp4");
sewardjde4a1d02002-03-22 01:27:54 +00001938 }
1939 eip += HI8(pair);
nethercotee8601122004-01-26 17:14:17 +00001940 DIP("%sb %s\n", nameGrp4(gregOfRM(modrm)), dis_buf);
sewardjde4a1d02002-03-22 01:27:54 +00001941 }
1942 return eip;
1943}
1944
1945
1946/* Group 5 extended opcodes. */
1947static
sewardje1042472002-09-30 12:33:11 +00001948Addr dis_Grp5 ( UCodeBlock* cb,
1949 UChar sorb,
1950 Int sz, Addr eip, Bool* isEnd )
sewardjde4a1d02002-03-22 01:27:54 +00001951{
1952 Int t1, t2, t3, t4;
1953 UInt pair;
1954 UChar modrm;
1955 UChar dis_buf[50];
1956 t1 = t2 = t3 = t4 = INVALID_TEMPREG;
1957
1958 modrm = getUChar(eip);
1959 if (epartIsReg(modrm)) {
1960 t1 = newTemp(cb);
1961 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1962 switch (gregOfRM(modrm)) {
1963 case 0: /* INC */
1964 uInstr1(cb, INC, sz, TempReg, t1);
1965 setFlagsFromUOpcode(cb, INC);
1966 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
1967 break;
1968 case 1: /* DEC */
1969 uInstr1(cb, DEC, sz, TempReg, t1);
1970 setFlagsFromUOpcode(cb, DEC);
1971 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
1972 break;
1973 case 2: /* call Ev */
1974 t3 = newTemp(cb); t4 = newTemp(cb);
1975 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
1976 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t3);
1977 uLiteral(cb, 4);
1978 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
1979 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
1980 uLiteral(cb, eip+1);
1981 uInstr2(cb, STORE, 4, TempReg, t4, TempReg, t3);
nethercotee8601122004-01-26 17:14:17 +00001982 jmp_treg(cb, t1);
sewardj2e93c502002-04-12 11:12:52 +00001983 LAST_UINSTR(cb).jmpkind = JmpCall;
sewardjde4a1d02002-03-22 01:27:54 +00001984 *isEnd = True;
1985 break;
1986 case 4: /* jmp Ev */
nethercotee8601122004-01-26 17:14:17 +00001987 jmp_treg(cb, t1);
sewardjde4a1d02002-03-22 01:27:54 +00001988 *isEnd = True;
1989 break;
1990 default:
1991 VG_(printf)(
1992 "unhandled Grp5(R) case %d\n", (UInt)gregOfRM(modrm));
njne427a662002-10-02 11:08:25 +00001993 VG_(core_panic)("Grp5");
sewardjde4a1d02002-03-22 01:27:54 +00001994 }
1995 eip++;
nethercotee8601122004-01-26 17:14:17 +00001996 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
1997 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
sewardjde4a1d02002-03-22 01:27:54 +00001998 } else {
nethercotee8601122004-01-26 17:14:17 +00001999 pair = disAMode ( cb, sorb, eip, dis_buf );
sewardjde4a1d02002-03-22 01:27:54 +00002000 t2 = LOW24(pair);
2001 t1 = newTemp(cb);
2002 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
2003 switch (gregOfRM(modrm)) {
2004 case 0: /* INC */
2005 uInstr1(cb, INC, sz, TempReg, t1);
2006 setFlagsFromUOpcode(cb, INC);
2007 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00002008 break;
2009 case 1: /* DEC */
2010 uInstr1(cb, DEC, sz, TempReg, t1);
2011 setFlagsFromUOpcode(cb, DEC);
2012 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00002013 break;
2014 case 2: /* call Ev */
2015 t3 = newTemp(cb); t4 = newTemp(cb);
2016 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
2017 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t3);
2018 uLiteral(cb, 4);
2019 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
2020 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
2021 uLiteral(cb, eip+HI8(pair));
2022 uInstr2(cb, STORE, 4, TempReg, t4, TempReg, t3);
nethercotee8601122004-01-26 17:14:17 +00002023 jmp_treg(cb, t1);
sewardj2e93c502002-04-12 11:12:52 +00002024 LAST_UINSTR(cb).jmpkind = JmpCall;
sewardjde4a1d02002-03-22 01:27:54 +00002025 *isEnd = True;
2026 break;
2027 case 4: /* JMP Ev */
nethercotee8601122004-01-26 17:14:17 +00002028 jmp_treg(cb, t1);
sewardjde4a1d02002-03-22 01:27:54 +00002029 *isEnd = True;
2030 break;
2031 case 6: /* PUSH Ev */
2032 t3 = newTemp(cb);
2033 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
2034 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t3);
2035 uLiteral(cb, sz);
2036 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
2037 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t3);
sewardjde4a1d02002-03-22 01:27:54 +00002038 break;
2039 default:
2040 VG_(printf)(
2041 "unhandled Grp5(M) case %d\n", (UInt)gregOfRM(modrm));
njne427a662002-10-02 11:08:25 +00002042 VG_(core_panic)("Grp5");
sewardjde4a1d02002-03-22 01:27:54 +00002043 }
2044 eip += HI8(pair);
nethercotee8601122004-01-26 17:14:17 +00002045 DIP("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
2046 nameISize(sz), dis_buf);
sewardjde4a1d02002-03-22 01:27:54 +00002047 }
2048 return eip;
2049}
2050
nethercotee33453f2003-11-27 16:15:17 +00002051/*------------------------------------------------------------*/
2052/*--- Disassembling string ops (including REP prefixes) ---*/
2053/*------------------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00002054
nethercotee33453f2003-11-27 16:15:17 +00002055/* Code shared by all the string ops */
2056static
2057void dis_string_op_increment(UCodeBlock* cb, Int sz, Int t_inc)
2058{
2059 uInstr0 (cb, CALLM_S, 0);
2060 uInstr2 (cb, MOV, 4, Literal, 0, TempReg, t_inc);
2061 uLiteral(cb, 0);
2062 uInstr1 (cb, PUSH, 4, TempReg, t_inc);
2063
2064 uInstr1 (cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
2065 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
2066
2067 uInstr1(cb, POP, 4, TempReg, t_inc);
2068 uInstr0(cb, CALLM_E, 0);
2069
2070 if (sz == 4 || sz == 2) {
2071 uInstr2(cb, SHL, 4, Literal, 0, TempReg, t_inc);
2072 uLiteral(cb, sz/2);
2073 }
2074}
2075
2076static
2077void dis_string_op( UCodeBlock* cb, void (*dis_OP)( UCodeBlock*, Int, Int ),
2078 Int sz, Char* name, UChar sorb )
2079{
2080 Int t_inc = newTemp(cb);
2081 vg_assert(sorb == 0);
2082 dis_string_op_increment(cb, sz, t_inc);
2083 dis_OP( cb, sz, t_inc );
nethercotee8601122004-01-26 17:14:17 +00002084 DIP("%s%c\n", name, nameISize(sz));
nethercotee33453f2003-11-27 16:15:17 +00002085}
2086
2087
2088static
2089void dis_MOVS ( UCodeBlock* cb, Int sz, Int t_inc )
2090{
2091 Int tv = newTemp(cb); /* value being copied */
2092 Int td = newTemp(cb); /* EDI */
2093 Int ts = newTemp(cb); /* ESI */
sewardjde4a1d02002-03-22 01:27:54 +00002094
2095 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
2096 uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
2097
nethercotee33453f2003-11-27 16:15:17 +00002098 uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tv);
2099 uInstr2(cb, STORE,sz, TempReg, tv, TempReg, td);
sewardjde4a1d02002-03-22 01:27:54 +00002100
nethercotee33453f2003-11-27 16:15:17 +00002101 uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
2102 uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
sewardjde4a1d02002-03-22 01:27:54 +00002103
2104 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2105 uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
sewardjde4a1d02002-03-22 01:27:54 +00002106}
2107
sewardjde4a1d02002-03-22 01:27:54 +00002108static
nethercotee33453f2003-11-27 16:15:17 +00002109void dis_LODS ( UCodeBlock* cb, Int sz, Int t_inc )
sewardjde4a1d02002-03-22 01:27:54 +00002110{
nethercotee33453f2003-11-27 16:15:17 +00002111 Int ta = newTemp(cb); /* EAX */
2112 Int ts = newTemp(cb); /* ESI */
sewardjde4a1d02002-03-22 01:27:54 +00002113
nethercotee33453f2003-11-27 16:15:17 +00002114 uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
2115 uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, ta);
2116 uInstr2(cb, PUT, sz, TempReg, ta, ArchReg, R_EAX);
2117
2118 uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
2119 uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
2120}
2121
2122static
2123void dis_STOS ( UCodeBlock* cb, Int sz, Int t_inc )
2124{
2125 Int ta = newTemp(cb); /* EAX */
2126 Int td = newTemp(cb); /* EDI */
sewardjde4a1d02002-03-22 01:27:54 +00002127
2128 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
2129 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
2130 uInstr2(cb, STORE, sz, TempReg, ta, TempReg, td);
sewardjde4a1d02002-03-22 01:27:54 +00002131
nethercotee33453f2003-11-27 16:15:17 +00002132 uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
sewardjde4a1d02002-03-22 01:27:54 +00002133 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
sewardjde4a1d02002-03-22 01:27:54 +00002134}
2135
sewardjde4a1d02002-03-22 01:27:54 +00002136static
nethercotee33453f2003-11-27 16:15:17 +00002137void dis_CMPS ( UCodeBlock* cb, Int sz, Int t_inc )
sewardjde4a1d02002-03-22 01:27:54 +00002138{
nethercotee33453f2003-11-27 16:15:17 +00002139 Int tdv = newTemp(cb); /* (EDI) */
2140 Int tsv = newTemp(cb); /* (ESI) */
2141 Int td = newTemp(cb); /* EDI */
2142 Int ts = newTemp(cb); /* ESI */
sewardjde4a1d02002-03-22 01:27:54 +00002143
2144 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
2145 uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
2146
2147 uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tdv);
2148 uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tsv);
2149
2150 uInstr2(cb, SUB, sz, TempReg, tdv, TempReg, tsv);
2151 setFlagsFromUOpcode(cb, SUB);
2152
nethercotee33453f2003-11-27 16:15:17 +00002153 uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
2154 uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
sewardjde4a1d02002-03-22 01:27:54 +00002155
2156 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2157 uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
2158}
2159
sewardjde4a1d02002-03-22 01:27:54 +00002160static
nethercotee33453f2003-11-27 16:15:17 +00002161void dis_SCAS ( UCodeBlock* cb, Int sz, Int t_inc )
sewardjde4a1d02002-03-22 01:27:54 +00002162{
nethercotee33453f2003-11-27 16:15:17 +00002163 Int ta = newTemp(cb); /* EAX */
2164 Int td = newTemp(cb); /* EDI */
2165 Int tdv = newTemp(cb); /* (EDI) */
sewardjde4a1d02002-03-22 01:27:54 +00002166
2167 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
2168 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
nethercotee33453f2003-11-27 16:15:17 +00002169 uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tdv);
sewardjde4a1d02002-03-22 01:27:54 +00002170 /* next uinstr kills ta, but that's ok -- don't need it again */
nethercotee33453f2003-11-27 16:15:17 +00002171 uInstr2(cb, SUB, sz, TempReg, tdv, TempReg, ta);
sewardjde4a1d02002-03-22 01:27:54 +00002172 setFlagsFromUOpcode(cb, SUB);
2173
nethercotee33453f2003-11-27 16:15:17 +00002174 uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
sewardjde4a1d02002-03-22 01:27:54 +00002175 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2176}
2177
2178
nethercotee33453f2003-11-27 16:15:17 +00002179/* Wrap the appropriate string op inside a REP/REPE/REPNE.
2180 We assume the insn is the last one in the basic block, and so emit a jump
2181 to the next insn, rather than just falling through. */
2182static
2183void dis_REP_op ( UCodeBlock* cb, Int cond,
2184 void (*dis_OP)(UCodeBlock*, Int, Int),
2185 Int sz, Addr eip, Addr eip_next, Char* name )
2186{
2187 Int t_inc = newTemp(cb);
2188 Int tc = newTemp(cb); /* ECX */
2189
2190 dis_string_op_increment(cb, sz, t_inc);
2191
2192 uInstr2 (cb, GET, 4, ArchReg, R_ECX, TempReg, tc);
2193 uInstr2 (cb, JIFZ, 4, TempReg, tc, Literal, 0);
2194 uLiteral(cb, eip_next);
2195 uInstr1 (cb, DEC, 4, TempReg, tc);
2196 uInstr2 (cb, PUT, 4, TempReg, tc, ArchReg, R_ECX);
2197
2198 dis_OP (cb, sz, t_inc);
2199
2200 if (cond == CondAlways) {
nethercotee8601122004-01-26 17:14:17 +00002201 jmp_lit(cb, eip);
nethercotee33453f2003-11-27 16:15:17 +00002202 } else {
nethercotee8601122004-01-26 17:14:17 +00002203 jcc_lit(cb, eip, cond);
2204 jmp_lit(cb, eip_next);
nethercotee33453f2003-11-27 16:15:17 +00002205 }
nethercotee8601122004-01-26 17:14:17 +00002206 DIP("%s%c\n", name, nameISize(sz));
nethercotee33453f2003-11-27 16:15:17 +00002207}
2208
2209/*------------------------------------------------------------*/
2210/*--- Arithmetic, etc. ---*/
2211/*------------------------------------------------------------*/
2212
sewardjde4a1d02002-03-22 01:27:54 +00002213/* (I)MUL E, G. Supplied eip points to the modR/M byte. */
2214static
2215Addr dis_mul_E_G ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +00002216 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +00002217 Int size,
2218 Addr eip0,
2219 Bool signed_multiply )
2220{
jsgf5efa4fd2003-10-14 21:49:11 +00002221 Int ta, tg, te;
sewardjde4a1d02002-03-22 01:27:54 +00002222 UChar dis_buf[50];
2223 UChar rm = getUChar(eip0);
2224 ta = INVALID_TEMPREG;
2225 te = newTemp(cb);
2226 tg = newTemp(cb);
2227
sewardjde4a1d02002-03-22 01:27:54 +00002228 if (epartIsReg(rm)) {
jsgf5efa4fd2003-10-14 21:49:11 +00002229 vg_assert(signed_multiply);
2230 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tg);
2231 uInstr2(cb, MUL, size, ArchReg, eregOfRM(rm), TempReg, tg);
2232 setFlagsFromUOpcode(cb, MUL);
2233 uInstr2(cb, PUT, size, TempReg, tg, ArchReg, gregOfRM(rm));
nethercotee8601122004-01-26 17:14:17 +00002234 DIP("%smul%c %s, %s\n", signed_multiply ? "i" : "",
2235 nameISize(size),
2236 nameIReg(size,eregOfRM(rm)),
2237 nameIReg(size,gregOfRM(rm)));
sewardjde4a1d02002-03-22 01:27:54 +00002238 return 1+eip0;
2239 } else {
jsgf5efa4fd2003-10-14 21:49:11 +00002240 UInt pair;
2241 vg_assert(signed_multiply);
nethercotee8601122004-01-26 17:14:17 +00002242 pair = disAMode ( cb, sorb, eip0, dis_buf );
sewardjde4a1d02002-03-22 01:27:54 +00002243 ta = LOW24(pair);
2244 uInstr2(cb, LOAD, size, TempReg, ta, TempReg, te);
2245 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tg);
jsgf5efa4fd2003-10-14 21:49:11 +00002246 uInstr2(cb, MUL, size, TempReg, te, TempReg, tg);
2247 setFlagsFromUOpcode(cb, MUL);
2248 uInstr2(cb, PUT, size, TempReg, tg, ArchReg, gregOfRM(rm));
2249
nethercotee8601122004-01-26 17:14:17 +00002250 DIP("%smul%c %s, %s\n", signed_multiply ? "i" : "",
2251 nameISize(size),
2252 dis_buf, nameIReg(size,gregOfRM(rm)));
sewardjde4a1d02002-03-22 01:27:54 +00002253 return HI8(pair)+eip0;
2254 }
2255}
2256
2257
2258/* IMUL I * E -> G. Supplied eip points to the modR/M byte. */
2259static
2260Addr dis_imul_I_E_G ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +00002261 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +00002262 Int size,
2263 Addr eip,
2264 Int litsize )
2265{
jsgf5efa4fd2003-10-14 21:49:11 +00002266 Int ta, te, tl, d32;
nethercotee8601122004-01-26 17:14:17 +00002267 Char dis_buf[50];
sewardjde4a1d02002-03-22 01:27:54 +00002268 UChar rm = getUChar(eip);
2269 ta = INVALID_TEMPREG;
2270 te = newTemp(cb);
2271 tl = newTemp(cb);
2272
sewardjde4a1d02002-03-22 01:27:54 +00002273 if (epartIsReg(rm)) {
2274 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, te);
sewardjde4a1d02002-03-22 01:27:54 +00002275 eip++;
2276 } else {
nethercotee8601122004-01-26 17:14:17 +00002277 UInt pair = disAMode ( cb, sorb, eip, dis_buf );
sewardjde4a1d02002-03-22 01:27:54 +00002278 ta = LOW24(pair);
2279 uInstr2(cb, LOAD, size, TempReg, ta, TempReg, te);
sewardjde4a1d02002-03-22 01:27:54 +00002280 eip += HI8(pair);
2281 }
2282
2283 d32 = getSDisp(litsize,eip);
2284 eip += litsize;
2285
2286 uInstr2(cb, MOV, size, Literal, 0, TempReg, tl);
2287 uLiteral(cb, d32);
jsgf5efa4fd2003-10-14 21:49:11 +00002288 uInstr2(cb, MUL, size, TempReg, tl, TempReg, te);
2289 setFlagsFromUOpcode(cb, MUL);
sewardjde4a1d02002-03-22 01:27:54 +00002290 uInstr2(cb, PUT, size, TempReg, te, ArchReg, gregOfRM(rm));
sewardjde4a1d02002-03-22 01:27:54 +00002291
nethercotee8601122004-01-26 17:14:17 +00002292 DIP("imul %d, %s, %s\n", d32,
2293 ( epartIsReg(rm) ? nameIReg(size,eregOfRM(rm)) : dis_buf ),
2294 nameIReg(size,gregOfRM(rm)) );
sewardjde4a1d02002-03-22 01:27:54 +00002295
2296 return eip;
2297}
2298
2299
2300/* Handle FPU insns which read/write memory. On entry, eip points to
2301 the second byte of the insn (the one following D8 .. DF). */
2302static
sewardje1042472002-09-30 12:33:11 +00002303Addr dis_fpu_mem ( UCodeBlock* cb,
2304 UChar sorb,
2305 Int size, Bool is_write,
sewardjde4a1d02002-03-22 01:27:54 +00002306 Addr eip, UChar first_byte )
2307{
2308 Int ta;
2309 UInt pair;
2310 UChar dis_buf[50];
2311 UChar second_byte = getUChar(eip);
2312 vg_assert(second_byte < 0xC0);
2313 second_byte &= 0x38;
nethercotee8601122004-01-26 17:14:17 +00002314 pair = disAMode ( cb, sorb, eip, dis_buf );
sewardjde4a1d02002-03-22 01:27:54 +00002315 ta = LOW24(pair);
2316 eip += HI8(pair);
2317 uInstr2(cb, is_write ? FPU_W : FPU_R, size,
2318 Lit16,
2319 (((UShort)first_byte) << 8) | ((UShort)second_byte),
2320 TempReg, ta);
nethercotee8601122004-01-26 17:14:17 +00002321 if (is_write) {
2322 DIP("fpu_w_%d 0x%x:0x%x, %s\n",
2323 size, (UInt)first_byte, (UInt)second_byte, dis_buf );
2324 } else {
2325 DIP("fpu_r_%d %s, 0x%x:0x%x\n",
2326 size, dis_buf, (UInt)first_byte, (UInt)second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00002327 }
2328 return eip;
2329}
2330
2331
2332/* Handle FPU insns which don't reference memory. On entry, eip points to
2333 the second byte of the insn (the one following D8 .. DF). */
2334static
2335Addr dis_fpu_no_mem ( UCodeBlock* cb, Addr eip, UChar first_byte )
2336{
sewardj4a7456e2002-03-24 13:52:19 +00002337 Bool sets_ZCP = False;
sewardj8d32be72002-04-18 02:18:24 +00002338 Bool uses_ZCP = False;
sewardjde4a1d02002-03-22 01:27:54 +00002339 UChar second_byte = getUChar(eip); eip++;
2340 vg_assert(second_byte >= 0xC0);
sewardj4a7456e2002-03-24 13:52:19 +00002341
sewardj8d32be72002-04-18 02:18:24 +00002342 /* Does the insn write any integer condition codes (%EIP) ? */
2343
sewardj4a7456e2002-03-24 13:52:19 +00002344 if (first_byte == 0xDB && second_byte >= 0xF0 && second_byte <= 0xF7) {
2345 /* FCOMI */
2346 sets_ZCP = True;
2347 } else
2348 if (first_byte == 0xDF && second_byte >= 0xF0 && second_byte <= 0xF7) {
2349 /* FCOMIP */
2350 sets_ZCP = True;
2351 } else
2352 if (first_byte == 0xDB && second_byte >= 0xE8 && second_byte <= 0xEF) {
2353 /* FUCOMI */
2354 sets_ZCP = True;
2355 } else
2356 if (first_byte == 0xDF && second_byte >= 0xE8 && second_byte <= 0xEF) {
2357 /* FUCOMIP */
2358 sets_ZCP = True;
2359 }
2360
sewardj8d32be72002-04-18 02:18:24 +00002361 /* Dually, does the insn read any integer condition codes (%EIP) ? */
2362
2363 if (first_byte == 0xDA && second_byte >= 0xC0 && second_byte <= 0xDF) {
2364 /* FCMOVB %st(n), %st(0)
2365 FCMOVE %st(n), %st(0)
2366 FCMOVBE %st(n), %st(0)
2367 FCMOVU %st(n), %st(0)
2368 */
2369 uses_ZCP = True;
2370 } else
2371 if (first_byte == 0xDB && second_byte >= 0xC0 && second_byte <= 0xDF) {
2372 /* FCMOVNB %st(n), %st(0)
2373 FCMOVNE %st(n), %st(0)
2374 FCMOVNBE %st(n), %st(0)
2375 FCMOVNU %st(n), %st(0)
2376 */
2377 uses_ZCP = True;
2378 }
2379
sewardjde4a1d02002-03-22 01:27:54 +00002380 uInstr1(cb, FPU, 0,
2381 Lit16,
2382 (((UShort)first_byte) << 8) | ((UShort)second_byte)
2383 );
sewardj8d32be72002-04-18 02:18:24 +00002384 if (uses_ZCP) {
2385 /* VG_(printf)("!!! --- FPU insn which reads %EFLAGS\n"); */
2386 uFlagsRWU(cb, FlagsZCP, FlagsEmpty, FlagsEmpty);
2387 vg_assert(!sets_ZCP);
2388 }
sewardj4a7456e2002-03-24 13:52:19 +00002389 if (sets_ZCP) {
2390 /* VG_(printf)("!!! --- FPU insn which writes %EFLAGS\n"); */
2391 uFlagsRWU(cb, FlagsEmpty, FlagsZCP, FlagsEmpty);
sewardj8d32be72002-04-18 02:18:24 +00002392 vg_assert(!uses_ZCP);
sewardj4a7456e2002-03-24 13:52:19 +00002393 }
2394
nethercotee8601122004-01-26 17:14:17 +00002395 DIP("fpu 0x%x:0x%x%s%s\n", (UInt)first_byte, (UInt)second_byte,
2396 uses_ZCP ? " -rZCP" : "",
2397 sets_ZCP ? " -wZCP" : "" );
sewardjde4a1d02002-03-22 01:27:54 +00002398 return eip;
2399}
2400
2401
2402/* Top-level handler for all FPU insns. On entry, eip points to the
2403 second byte of the insn. */
2404static
sewardje1042472002-09-30 12:33:11 +00002405Addr dis_fpu ( UCodeBlock* cb,
2406 UChar sorb,
2407 UChar first_byte, Addr eip )
sewardjde4a1d02002-03-22 01:27:54 +00002408{
2409 const Bool rd = False;
2410 const Bool wr = True;
2411 UChar second_byte = getUChar(eip);
2412
2413 /* Handle FSTSW %ax specially. */
2414 if (first_byte == 0xDF && second_byte == 0xE0) {
2415 Int t1 = newTemp(cb);
2416 uInstr0(cb, CALLM_S, 0);
2417 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
2418 uLiteral(cb, 0);
2419 uInstr1(cb, PUSH, 4, TempReg, t1);
2420 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_fstsw_AX) );
2421 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
2422 uInstr1(cb, POP, 2, TempReg, t1);
2423 uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
2424 uInstr0(cb, CALLM_E, 0);
nethercotee8601122004-01-26 17:14:17 +00002425 DIP("fstsw %%ax\n");
sewardjde4a1d02002-03-22 01:27:54 +00002426 eip++;
2427 return eip;
2428 }
2429
2430 /* Handle all non-memory FPU ops simply. */
2431 if (second_byte >= 0xC0)
2432 return dis_fpu_no_mem ( cb, eip, first_byte );
2433
2434 /* The insn references memory; need to determine
2435 whether it reads or writes, and at what size. */
2436 switch (first_byte) {
2437
2438 case 0xD8:
2439 switch ((second_byte >> 3) & 7) {
2440 case 0: /* FADDs */
2441 case 1: /* FMULs */
2442 case 2: /* FCOMs */
2443 case 3: /* FCOMPs */
2444 case 4: /* FSUBs */
2445 case 5: /* FSUBRs */
2446 case 6: /* FDIVs */
2447 case 7: /* FDIVRs */
sewardje1042472002-09-30 12:33:11 +00002448 return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002449 default:
2450 goto unhandled;
2451 }
2452 break;
2453
2454 case 0xD9:
2455 switch ((second_byte >> 3) & 7) {
2456 case 0: /* FLDs */
sewardje1042472002-09-30 12:33:11 +00002457 return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002458 case 2: /* FSTs */
2459 case 3: /* FSTPs */
sewardje1042472002-09-30 12:33:11 +00002460 return dis_fpu_mem(cb, sorb, 4, wr, eip, first_byte);
sewardj35a916c2002-07-23 18:48:39 +00002461 case 4: /* FLDENV */
sewardje1042472002-09-30 12:33:11 +00002462 return dis_fpu_mem(cb, sorb, 28, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002463 case 5: /* FLDCW */
sewardje1042472002-09-30 12:33:11 +00002464 return dis_fpu_mem(cb, sorb, 2, rd, eip, first_byte);
sewardj2a8141a2002-07-13 12:27:12 +00002465 case 6: /* FNSTENV */
sewardje1042472002-09-30 12:33:11 +00002466 return dis_fpu_mem(cb, sorb, 28, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002467 case 7: /* FSTCW */
2468 /* HACK! FSTCW actually writes 2 bytes, not 4. glibc
2469 gets lots of moaning in __floor() if we do the right
2470 thing here. */
2471 /* Later ... hack disabled .. we do do the Right Thing. */
sewardje1042472002-09-30 12:33:11 +00002472 return dis_fpu_mem(cb, sorb, /*4*/ 2, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002473 default:
2474 goto unhandled;
2475 }
2476 break;
2477
2478 case 0xDA:
2479 switch ((second_byte >> 3) & 7) {
thughes1052ce02004-03-27 18:03:26 +00002480 case 0: /* FIADD dword-integer */
2481 case 1: /* FIMUL dword-integer */
2482 case 2: /* FICOM dword-integer */
2483 case 3: /* FICOMP dword-integer */
2484 case 4: /* FISUB dword-integer */
2485 case 5: /* FISUBR dword-integer */
2486 case 6: /* FIDIV dword-integer */
2487 case 7: /* FIDIVR dword-integer */
sewardje1042472002-09-30 12:33:11 +00002488 return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002489 default:
2490 goto unhandled;
2491 }
2492 break;
2493
2494 case 0xDB:
2495 switch ((second_byte >> 3) & 7) {
2496 case 0: /* FILD dword-integer */
sewardje1042472002-09-30 12:33:11 +00002497 return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002498 case 2: /* FIST dword-integer */
sewardje1042472002-09-30 12:33:11 +00002499 return dis_fpu_mem(cb, sorb, 4, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002500 case 3: /* FISTPl */
sewardje1042472002-09-30 12:33:11 +00002501 return dis_fpu_mem(cb, sorb, 4, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002502 case 5: /* FLD extended-real */
sewardje1042472002-09-30 12:33:11 +00002503 return dis_fpu_mem(cb, sorb, 10, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002504 case 7: /* FSTP extended-real */
sewardje1042472002-09-30 12:33:11 +00002505 return dis_fpu_mem(cb, sorb, 10, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002506 default:
2507 goto unhandled;
2508 }
2509 break;
2510
2511 case 0xDC:
2512 switch ((second_byte >> 3) & 7) {
2513 case 0: /* FADD double-real */
2514 case 1: /* FMUL double-real */
2515 case 2: /* FCOM double-real */
2516 case 3: /* FCOMP double-real */
2517 case 4: /* FSUB double-real */
2518 case 5: /* FSUBR double-real */
2519 case 6: /* FDIV double-real */
2520 case 7: /* FDIVR double-real */
sewardje1042472002-09-30 12:33:11 +00002521 return dis_fpu_mem(cb, sorb, 8, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002522 default:
2523 goto unhandled;
2524 }
2525 break;
2526
2527 case 0xDD:
2528 switch ((second_byte >> 3) & 7) {
2529 case 0: /* FLD double-real */
sewardje1042472002-09-30 12:33:11 +00002530 return dis_fpu_mem(cb, sorb, 8, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002531 case 2: /* FST double-real */
2532 case 3: /* FSTP double-real */
sewardje1042472002-09-30 12:33:11 +00002533 return dis_fpu_mem(cb, sorb, 8, wr, eip, first_byte);
njn25e49d8e72002-09-23 09:36:25 +00002534 case 4: /* FRSTOR */
sewardje1042472002-09-30 12:33:11 +00002535 return dis_fpu_mem(cb, sorb, 108, rd, eip, first_byte);
njn25e49d8e72002-09-23 09:36:25 +00002536 case 6: /* FSAVE */
sewardje1042472002-09-30 12:33:11 +00002537 return dis_fpu_mem(cb, sorb, 108, wr, eip, first_byte);
njn25e49d8e72002-09-23 09:36:25 +00002538 case 7: /* FSTSW */
sewardje1042472002-09-30 12:33:11 +00002539 return dis_fpu_mem(cb, sorb, 2, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002540 default:
2541 goto unhandled;
2542 }
2543 break;
2544
thughes1052ce02004-03-27 18:03:26 +00002545 case 0xDE:
2546 switch ((second_byte >> 3) & 7) {
2547 case 0: /* FIADD word-integer */
2548 case 1: /* FIMUL word-integer */
2549 case 2: /* FICOM word-integer */
2550 case 3: /* FICOMP word-integer */
2551 case 4: /* FISUB word-integer */
2552 case 5: /* FISUBR word-integer */
2553 case 6: /* FIDIV word-integer */
2554 case 7: /* FIDIVR word-integer */
2555 return dis_fpu_mem(cb, sorb, 2, rd, eip, first_byte);
2556 default:
2557 goto unhandled;
2558 }
2559 break;
2560
sewardjde4a1d02002-03-22 01:27:54 +00002561 case 0xDF:
2562 switch ((second_byte >> 3) & 7) {
2563 case 0: /* FILD word-integer */
sewardje1042472002-09-30 12:33:11 +00002564 return dis_fpu_mem(cb, sorb, 2, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002565 case 2: /* FIST word-integer */
sewardje1042472002-09-30 12:33:11 +00002566 return dis_fpu_mem(cb, sorb, 2, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002567 case 3: /* FISTP word-integer */
sewardje1042472002-09-30 12:33:11 +00002568 return dis_fpu_mem(cb, sorb, 2, wr, eip, first_byte);
nethercote85cf45e2004-07-17 10:01:51 +00002569 case 4: /* FBLD extended-real */
2570 return dis_fpu_mem(cb, sorb, 10, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002571 case 5: /* FILD qword-integer */
sewardje1042472002-09-30 12:33:11 +00002572 return dis_fpu_mem(cb, sorb, 8, rd, eip, first_byte);
nethercote85cf45e2004-07-17 10:01:51 +00002573 case 6: /* FBSTP extended-real */
2574 return dis_fpu_mem(cb, sorb, 10, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002575 case 7: /* FISTP qword-integer */
sewardje1042472002-09-30 12:33:11 +00002576 return dis_fpu_mem(cb, sorb, 8, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002577 default:
2578 goto unhandled;
2579 }
2580 break;
2581
2582 default: goto unhandled;
2583 }
2584
2585 unhandled:
2586 VG_(printf)("dis_fpu: unhandled memory case 0x%2x:0x%2x(%d)\n",
2587 (UInt)first_byte, (UInt)second_byte,
2588 (UInt)((second_byte >> 3) & 7) );
njne427a662002-10-02 11:08:25 +00002589 VG_(core_panic)("dis_fpu: unhandled opcodes");
sewardjde4a1d02002-03-22 01:27:54 +00002590}
2591
2592
2593/* Double length left shifts. Apparently only required in v-size (no
2594 b- variant). */
2595static
sewardje1042472002-09-30 12:33:11 +00002596Addr dis_SHLRD_Gv_Ev ( UCodeBlock* cb,
2597 UChar sorb,
2598 Addr eip, UChar modrm,
sewardjde4a1d02002-03-22 01:27:54 +00002599 Int sz,
2600 Tag amt_tag, UInt amt_val,
2601 Bool left_shift )
2602{
2603 /* amt_tag and amt_val denote either ArchReg(%CL) or a Literal.
2604 And eip on entry points at the modrm byte. */
2605 Int t, t1, t2, ta, helper;
2606 UInt pair;
2607 UChar dis_buf[50];
2608
2609 vg_assert(sz == 2 || sz == 4);
2610
2611 helper = left_shift
2612 ? (sz==4 ? VGOFF_(helper_shldl)
2613 : VGOFF_(helper_shldw))
2614 : (sz==4 ? VGOFF_(helper_shrdl)
2615 : VGOFF_(helper_shrdw));
2616
2617 /* Get the amount to be shifted by onto the stack. */
2618 t = newTemp(cb);
2619 t1 = newTemp(cb);
2620 t2 = newTemp(cb);
2621 if (amt_tag == ArchReg) {
2622 vg_assert(amt_val == R_CL);
2623 uInstr2(cb, GET, 1, ArchReg, amt_val, TempReg, t);
2624 } else {
2625 uInstr2(cb, MOV, 1, Literal, 0, TempReg, t);
2626 uLiteral(cb, amt_val);
2627 }
2628
2629 uInstr0(cb, CALLM_S, 0);
2630 uInstr1(cb, PUSH, 1, TempReg, t);
2631
2632 /* The E-part is the destination; this is shifted. The G-part
2633 supplies bits to be shifted into the E-part, but is not
2634 changed. */
2635
2636 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t1);
2637 uInstr1(cb, PUSH, sz, TempReg, t1);
2638
2639 if (epartIsReg(modrm)) {
2640 eip++;
2641 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t2);
2642 uInstr1(cb, PUSH, sz, TempReg, t2);
2643 uInstr1(cb, CALLM, 0, Lit16, helper);
2644 uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
2645 uInstr1(cb, POP, sz, TempReg, t);
2646 uInstr2(cb, PUT, sz, TempReg, t, ArchReg, eregOfRM(modrm));
nethercotee8601122004-01-26 17:14:17 +00002647 DIP("sh%cd%c %%cl, %s, %s\n",
2648 ( left_shift ? 'l' : 'r' ), nameISize(sz),
2649 nameIReg(sz, gregOfRM(modrm)), nameIReg(sz, eregOfRM(modrm)));
sewardjde4a1d02002-03-22 01:27:54 +00002650 } else {
nethercotee8601122004-01-26 17:14:17 +00002651 pair = disAMode ( cb, sorb, eip, dis_buf );
sewardjde4a1d02002-03-22 01:27:54 +00002652 ta = LOW24(pair);
2653 eip += HI8(pair);
2654 uInstr2(cb, LOAD, sz, TempReg, ta, TempReg, t2);
2655 uInstr1(cb, PUSH, sz, TempReg, t2);
2656 uInstr1(cb, CALLM, 0, Lit16, helper);
2657 uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
2658 uInstr1(cb, POP, sz, TempReg, t);
2659 uInstr2(cb, STORE, sz, TempReg, t, TempReg, ta);
nethercotee8601122004-01-26 17:14:17 +00002660 DIP("sh%cd%c %%cl, %s, %s\n", ( left_shift ? 'l' : 'r' ),
2661 nameISize(sz), nameIReg(sz, gregOfRM(modrm)), dis_buf);
sewardjde4a1d02002-03-22 01:27:54 +00002662 }
2663
2664 if (amt_tag == Literal) eip++;
2665 uInstr1(cb, CLEAR, 0, Lit16, 8);
2666
2667 uInstr0(cb, CALLM_E, 0);
2668 return eip;
2669}
2670
2671
2672/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
2673 required. */
2674
2675typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
2676
2677static Char* nameBtOp ( BtOp op )
2678{
2679 switch (op) {
2680 case BtOpNone: return "";
2681 case BtOpSet: return "s";
2682 case BtOpReset: return "r";
2683 case BtOpComp: return "c";
njne427a662002-10-02 11:08:25 +00002684 default: VG_(core_panic)("nameBtOp");
sewardjde4a1d02002-03-22 01:27:54 +00002685 }
2686}
2687
sewardj7f2a8bf2002-04-15 14:35:28 +00002688
2689static
sewardje1042472002-09-30 12:33:11 +00002690Addr dis_bt_G_E ( UCodeBlock* cb,
2691 UChar sorb,
2692 Int sz, Addr eip, BtOp op )
sewardj7f2a8bf2002-04-15 14:35:28 +00002693{
2694 UInt pair;
nethercotee8601122004-01-26 17:14:17 +00002695 Char dis_buf[50];
sewardj7f2a8bf2002-04-15 14:35:28 +00002696 UChar modrm;
2697
2698 Int t_addr, t_bitno, t_mask, t_fetched, t_esp, temp, lit;
2699
sewardj7f2a8bf2002-04-15 14:35:28 +00002700 vg_assert(sz == 2 || sz == 4);
sewardj7f2a8bf2002-04-15 14:35:28 +00002701
2702 t_addr = t_bitno = t_mask
2703 = t_fetched = t_esp = temp = INVALID_TEMPREG;
2704
2705 t_fetched = newTemp(cb);
2706 t_bitno = newTemp(cb);
2707 temp = newTemp(cb);
2708 lit = newTemp(cb);
2709
2710 modrm = getUChar(eip);
2711
2712 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t_bitno);
2713
nethercote1018bdd2004-02-11 23:33:29 +00002714 if (sz == 2) {
2715 uInstr1(cb, WIDEN, 4, TempReg, t_bitno);
nethercote911cc372004-04-18 12:23:02 +00002716 uWiden(cb, 2, False);
nethercote1018bdd2004-02-11 23:33:29 +00002717 }
2718
sewardj7f2a8bf2002-04-15 14:35:28 +00002719 if (epartIsReg(modrm)) {
2720 eip++;
2721 /* Get it onto the client's stack. */
2722 t_esp = newTemp(cb);
2723 t_addr = newTemp(cb);
2724 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t_esp);
nethercote1018bdd2004-02-11 23:33:29 +00002725 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t_esp);
sewardj7f2a8bf2002-04-15 14:35:28 +00002726 uLiteral(cb, sz);
2727 uInstr2(cb, PUT, 4, TempReg, t_esp, ArchReg, R_ESP);
2728 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, temp);
2729 uInstr2(cb, STORE, sz, TempReg, temp, TempReg, t_esp);
nethercote1018bdd2004-02-11 23:33:29 +00002730 /* Make t_addr point at it. */
sewardj7f2a8bf2002-04-15 14:35:28 +00002731 uInstr2(cb, MOV, 4, TempReg, t_esp, TempReg, t_addr);
2732 /* Mask out upper bits of the shift amount, since we're doing a
2733 reg. */
2734 uInstr2(cb, MOV, 4, Literal, 0, TempReg, lit);
2735 uLiteral(cb, sz == 4 ? 31 : 15);
2736 uInstr2(cb, AND, 4, TempReg, lit, TempReg, t_bitno);
2737 } else {
nethercotee8601122004-01-26 17:14:17 +00002738 pair = disAMode ( cb, sorb, eip, dis_buf );
sewardj7f2a8bf2002-04-15 14:35:28 +00002739 t_addr = LOW24(pair);
2740 eip += HI8(pair);
2741 }
2742
nethercote1018bdd2004-02-11 23:33:29 +00002743 /* At this point: t_addr points to the address being operated on. If
sewardj7f2a8bf2002-04-15 14:35:28 +00002744 it was a reg, we will have pushed it onto the client's stack.
2745 t_bitno is the bit number, suitable masked in the case of a reg. */
2746
2747 /* Now the main sequence. */
2748
2749 uInstr2(cb, MOV, 4, TempReg, t_bitno, TempReg, temp);
2750 uInstr2(cb, SAR, 4, Literal, 0, TempReg, temp);
2751 uLiteral(cb, 3);
2752 uInstr2(cb, ADD, 4, TempReg, temp, TempReg, t_addr);
nethercote1018bdd2004-02-11 23:33:29 +00002753 /* t_addr now holds effective address */
sewardj7f2a8bf2002-04-15 14:35:28 +00002754
2755 uInstr2(cb, MOV, 4, Literal, 0, TempReg, lit);
2756 uLiteral(cb, 7);
2757 uInstr2(cb, AND, 4, TempReg, lit, TempReg, t_bitno);
nethercote1018bdd2004-02-11 23:33:29 +00002758 /* t_bitno contains offset of bit within byte */
sewardj7f2a8bf2002-04-15 14:35:28 +00002759
2760 if (op != BtOpNone) {
2761 t_mask = newTemp(cb);
2762 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_mask);
2763 uLiteral(cb, 1);
2764 uInstr2(cb, SHL, 4, TempReg, t_bitno, TempReg, t_mask);
2765 }
nethercote1018bdd2004-02-11 23:33:29 +00002766 /* t_mask is now a suitable byte mask */
sewardj7f2a8bf2002-04-15 14:35:28 +00002767
2768 uInstr2(cb, LOAD, 1, TempReg, t_addr, TempReg, t_fetched);
2769 if (op != BtOpNone) {
2770 uInstr2(cb, MOV, 4, TempReg, t_fetched, TempReg, temp);
2771 switch (op) {
2772 case BtOpSet:
2773 uInstr2(cb, OR, 4, TempReg, t_mask, TempReg, temp);
2774 break;
2775 case BtOpComp:
2776 uInstr2(cb, XOR, 4, TempReg, t_mask, TempReg, temp);
2777 break;
2778 case BtOpReset:
2779 uInstr1(cb, NOT, 4, TempReg, t_mask);
2780 uInstr2(cb, AND, 4, TempReg, t_mask, TempReg, temp);
2781 break;
2782 default:
njne427a662002-10-02 11:08:25 +00002783 VG_(core_panic)("dis_bt_G_E");
sewardj7f2a8bf2002-04-15 14:35:28 +00002784 }
2785 uInstr2(cb, STORE, 1, TempReg, temp, TempReg, t_addr);
2786 }
2787
2788 /* Side effect done; now get selected bit into Carry flag */
2789
2790 uInstr2(cb, SHR, 4, TempReg, t_bitno, TempReg, t_fetched);
2791 /* at bit 0 of fetched */
2792
2793 uInstr2(cb, MOV, 4, Literal, 0, TempReg, lit);
2794 uLiteral(cb, 1);
2795 uInstr2(cb, AND, 4, TempReg, lit, TempReg, t_fetched);
nethercote1018bdd2004-02-11 23:33:29 +00002796 /* t_fetched is now 1 or 0 */
sewardj7f2a8bf2002-04-15 14:35:28 +00002797
2798 /* NEG is a handy way to convert zero/nonzero into the carry
2799 flag. */
2800 uInstr1(cb, NEG, 4, TempReg, t_fetched);
2801 setFlagsFromUOpcode(cb, NEG);
nethercote1018bdd2004-02-11 23:33:29 +00002802 /* t_fetched is now in carry flag */
sewardj7f2a8bf2002-04-15 14:35:28 +00002803
2804 /* Move reg operand from stack back to reg */
2805 if (epartIsReg(modrm)) {
2806 /* t_esp still points at it. */
2807 uInstr2(cb, LOAD, sz, TempReg, t_esp, TempReg, temp);
2808 uInstr2(cb, PUT, sz, TempReg, temp, ArchReg, eregOfRM(modrm));
nethercote1018bdd2004-02-11 23:33:29 +00002809 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t_esp);
sewardj7f2a8bf2002-04-15 14:35:28 +00002810 uLiteral(cb, sz);
2811 uInstr2(cb, PUT, 4, TempReg, t_esp, ArchReg, R_ESP);
2812 }
2813
nethercotee8601122004-01-26 17:14:17 +00002814 DIP("bt%s%c %s, %s\n",
2815 nameBtOp(op), nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
2816 ( epartIsReg(modrm) ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ) );
sewardj7f2a8bf2002-04-15 14:35:28 +00002817
2818 return eip;
2819}
2820
2821
sewardjde4a1d02002-03-22 01:27:54 +00002822
sewardjde4a1d02002-03-22 01:27:54 +00002823/* Handle BSF/BSR. Only v-size seems necessary. */
2824static
sewardje1042472002-09-30 12:33:11 +00002825Addr dis_bs_E_G ( UCodeBlock* cb,
2826 UChar sorb,
2827 Int sz, Addr eip, Bool fwds )
sewardjde4a1d02002-03-22 01:27:54 +00002828{
sewardj9316cba2002-05-03 20:52:53 +00002829 Int t, t1, ta, helper;
sewardjde4a1d02002-03-22 01:27:54 +00002830 UInt pair;
nethercotee8601122004-01-26 17:14:17 +00002831 Char dis_buf[50];
sewardjde4a1d02002-03-22 01:27:54 +00002832 UChar modrm;
nethercotee8601122004-01-26 17:14:17 +00002833 Bool isReg;
sewardjde4a1d02002-03-22 01:27:54 +00002834
2835 vg_assert(sz == 2 || sz == 4);
sewardjde4a1d02002-03-22 01:27:54 +00002836
nethercote1018bdd2004-02-11 23:33:29 +00002837 if (fwds)
2838 helper = sz == 2 ? VGOFF_(helper_bsfw) : VGOFF_(helper_bsfl);
2839 else
2840 helper = sz == 2 ? VGOFF_(helper_bsrw) : VGOFF_(helper_bsrl);
2841
sewardjde4a1d02002-03-22 01:27:54 +00002842 modrm = getUChar(eip);
sewardj9316cba2002-05-03 20:52:53 +00002843 t1 = newTemp(cb);
sewardjde4a1d02002-03-22 01:27:54 +00002844 t = newTemp(cb);
2845
sewardj9316cba2002-05-03 20:52:53 +00002846 uInstr0(cb, CALLM_S, 0);
2847 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t1);
2848 uInstr1(cb, PUSH, sz, TempReg, t1);
2849
nethercotee8601122004-01-26 17:14:17 +00002850 isReg = epartIsReg(modrm);
2851 if (isReg) {
sewardjde4a1d02002-03-22 01:27:54 +00002852 eip++;
2853 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t);
sewardjde4a1d02002-03-22 01:27:54 +00002854 } else {
nethercotee8601122004-01-26 17:14:17 +00002855 pair = disAMode ( cb, sorb, eip, dis_buf );
sewardjde4a1d02002-03-22 01:27:54 +00002856 ta = LOW24(pair);
2857 eip += HI8(pair);
2858 uInstr2(cb, LOAD, sz, TempReg, ta, TempReg, t);
sewardjde4a1d02002-03-22 01:27:54 +00002859 }
nethercotee8601122004-01-26 17:14:17 +00002860 DIP("bs%c%c %s, %s\n",
2861 fwds ? 'f' : 'r', nameISize(sz),
2862 ( isReg ? nameIReg(sz, eregOfRM(modrm)) : dis_buf ),
2863 nameIReg(sz, gregOfRM(modrm)));
sewardjde4a1d02002-03-22 01:27:54 +00002864
sewardjde4a1d02002-03-22 01:27:54 +00002865 uInstr1(cb, PUSH, sz, TempReg, t);
2866 uInstr1(cb, CALLM, 0, Lit16, helper);
2867 uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsOSACP);
2868 uInstr1(cb, POP, sz, TempReg, t);
sewardj9316cba2002-05-03 20:52:53 +00002869 uInstr1(cb, POP, sz, TempReg, t);
sewardjde4a1d02002-03-22 01:27:54 +00002870 uInstr2(cb, PUT, sz, TempReg, t, ArchReg, gregOfRM(modrm));
2871 uInstr0(cb, CALLM_E, 0);
2872
2873 return eip;
2874}
2875
2876
2877static
2878void codegen_xchg_eAX_Reg ( UCodeBlock* cb, Int sz, Int reg )
2879{
2880 Int t1, t2;
2881 vg_assert(sz == 2 || sz == 4);
2882 t1 = newTemp(cb);
2883 t2 = newTemp(cb);
2884 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
2885 uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t2);
2886 uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, R_EAX);
2887 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
nethercotee8601122004-01-26 17:14:17 +00002888 DIP("xchg%c %s, %s\n",
2889 nameISize(sz), nameIReg(sz, R_EAX), nameIReg(sz, reg));
sewardjde4a1d02002-03-22 01:27:54 +00002890}
2891
2892
2893static
2894void codegen_SAHF ( UCodeBlock* cb )
2895{
sewardj3a72df02002-03-24 10:03:17 +00002896 Int t = newTemp(cb);
2897 Int t2 = newTemp(cb);
sewardjde4a1d02002-03-22 01:27:54 +00002898 uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t);
sewardj3a72df02002-03-24 10:03:17 +00002899
2900 /* Mask out parts of t not corresponding to %AH. This stops the
2901 instrumenter complaining if they are undefined. Otherwise, the
2902 instrumenter would check all 32 bits of t at the PUSH, which
2903 could be the cause of incorrect warnings. Discovered by Daniel
2904 Veillard <veillard@redhat.com>.
2905 */
2906 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
2907 uLiteral(cb, 0x0000FF00);
2908 uInstr2(cb, AND, 4, TempReg, t2, TempReg, t);
2909 /* We deliberately don't set the condition codes here, since this
2910 AND is purely internal to Valgrind and nothing to do with the
2911 client's state. */
2912
sewardjde4a1d02002-03-22 01:27:54 +00002913 uInstr0(cb, CALLM_S, 0);
2914 uInstr1(cb, PUSH, 4, TempReg, t);
2915 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_SAHF));
2916 uFlagsRWU(cb, FlagsEmpty, FlagsSZACP, FlagsEmpty);
2917 uInstr1(cb, CLEAR, 0, Lit16, 4);
2918 uInstr0(cb, CALLM_E, 0);
2919}
2920
njnd6251f12003-06-03 13:38:51 +00002921static
2922void codegen_LAHF ( UCodeBlock* cb )
2923{
2924 Int t = newTemp(cb);
2925
2926 /* Pushed arg is ignored, it just provides somewhere to put the
2927 return value. */
njnb7a818d2003-06-03 14:56:41 +00002928 uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t);
njn4d1a9bf2003-06-03 14:12:08 +00002929 uInstr0(cb, CALLM_S, 0);
njnd6251f12003-06-03 13:38:51 +00002930 uInstr1(cb, PUSH, 4, TempReg, t);
2931 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_LAHF));
njnbfa6bce2003-06-05 21:56:00 +00002932 uFlagsRWU(cb, FlagsSZACP, FlagsEmpty, FlagsEmpty);
njnd6251f12003-06-03 13:38:51 +00002933 uInstr1(cb, POP, 4, TempReg, t);
2934 uInstr0(cb, CALLM_E, 0);
2935
njnb7a818d2003-06-03 14:56:41 +00002936 /* At this point, the %ah sub-register in %eax has been updated,
2937 the rest is the same, so do a PUT of the whole thing. */
2938 uInstr2(cb, PUT, 4, TempReg, t, ArchReg, R_EAX);
njnd6251f12003-06-03 13:38:51 +00002939}
2940
sewardjde4a1d02002-03-22 01:27:54 +00002941
2942static
2943Addr dis_cmpxchg_G_E ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +00002944 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +00002945 Int size,
2946 Addr eip0 )
2947{
2948 Int ta, junk, dest, src, acc;
2949 UChar dis_buf[50];
2950 UChar rm;
2951
2952 rm = getUChar(eip0);
2953 acc = newTemp(cb);
2954 src = newTemp(cb);
2955 dest = newTemp(cb);
2956 junk = newTemp(cb);
2957 /* Only needed to get gcc's dataflow analyser off my back. */
2958 ta = INVALID_TEMPREG;
2959
2960 if (epartIsReg(rm)) {
2961 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, dest);
2962 eip0++;
nethercotee8601122004-01-26 17:14:17 +00002963 DIP("cmpxchg%c %s,%s\n", nameISize(size),
2964 nameIReg(size,gregOfRM(rm)),
2965 nameIReg(size,eregOfRM(rm)) );
sewardjde4a1d02002-03-22 01:27:54 +00002966 } else {
nethercotee8601122004-01-26 17:14:17 +00002967 UInt pair = disAMode ( cb, sorb, eip0, dis_buf );
sewardjde4a1d02002-03-22 01:27:54 +00002968 ta = LOW24(pair);
2969 uInstr2(cb, LOAD, size, TempReg, ta, TempReg, dest);
2970 eip0 += HI8(pair);
nethercotee8601122004-01-26 17:14:17 +00002971 DIP("cmpxchg%c %s,%s\n", nameISize(size),
2972 nameIReg(size,gregOfRM(rm)), dis_buf);
sewardjde4a1d02002-03-22 01:27:54 +00002973 }
2974
2975 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, src);
2976 uInstr2(cb, GET, size, ArchReg, R_EAX, TempReg, acc);
muellerf217c732004-01-02 22:42:29 +00002977 uInstr2(cb, MOV, 4, TempReg, acc, TempReg, junk);
sewardjde4a1d02002-03-22 01:27:54 +00002978 uInstr2(cb, SUB, size, TempReg, dest, TempReg, junk);
2979 setFlagsFromUOpcode(cb, SUB);
2980
2981 uInstr2(cb, CMOV, 4, TempReg, src, TempReg, dest);
2982 uCond(cb, CondZ);
2983 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
2984 uInstr2(cb, CMOV, 4, TempReg, dest, TempReg, acc);
2985 uCond(cb, CondNZ);
2986 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
2987
2988 uInstr2(cb, PUT, size, TempReg, acc, ArchReg, R_EAX);
2989 if (epartIsReg(rm)) {
2990 uInstr2(cb, PUT, size, TempReg, dest, ArchReg, eregOfRM(rm));
2991 } else {
2992 uInstr2(cb, STORE, size, TempReg, dest, TempReg, ta);
2993 }
2994
2995 return eip0;
2996}
2997
2998
muellerf217c732004-01-02 22:42:29 +00002999static
3000Addr dis_cmpxchg8b ( UCodeBlock* cb,
3001 UChar sorb,
3002 Addr eip0 )
3003{
3004 Int tal, tah, junkl, junkh, destl, desth, srcl, srch, accl, acch;
3005 UChar dis_buf[50];
3006 UChar rm;
3007 UInt pair;
3008
3009 rm = getUChar(eip0);
3010 accl = newTemp(cb);
3011 acch = newTemp(cb);
3012 srcl = newTemp(cb);
3013 srch = newTemp(cb);
3014 destl = newTemp(cb);
3015 desth = newTemp(cb);
3016 junkl = newTemp(cb);
3017 junkh = newTemp(cb);
3018
3019 vg_assert(!epartIsReg(rm));
3020
nethercotee8601122004-01-26 17:14:17 +00003021 pair = disAMode ( cb, sorb, eip0, dis_buf );
muellerf217c732004-01-02 22:42:29 +00003022 tal = LOW24(pair);
3023 tah = newTemp(cb);
3024 uInstr2(cb, MOV, 4, TempReg, tal, TempReg, tah);
3025 uInstr2(cb, ADD, 4, Literal, 0, TempReg, tah);
3026 uLiteral(cb, 4);
3027 eip0 += HI8(pair);
nethercotee8601122004-01-26 17:14:17 +00003028 DIP("cmpxchg8b %s\n", dis_buf);
muellerf217c732004-01-02 22:42:29 +00003029
3030 uInstr0(cb, CALLM_S, 0);
3031
3032 uInstr2(cb, LOAD, 4, TempReg, tah, TempReg, desth);
3033 uInstr1(cb, PUSH, 4, TempReg, desth);
3034 uInstr2(cb, LOAD, 4, TempReg, tal, TempReg, destl);
3035 uInstr1(cb, PUSH, 4, TempReg, destl);
3036 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, srch);
3037 uInstr1(cb, PUSH, 4, TempReg, srch);
3038 uInstr2(cb, GET, 4, ArchReg, R_EBX, TempReg, srcl);
3039 uInstr1(cb, PUSH, 4, TempReg, srcl);
3040 uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, acch);
3041 uInstr1(cb, PUSH, 4, TempReg, acch);
3042 uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, accl);
3043 uInstr1(cb, PUSH, 4, TempReg, accl);
3044
3045 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_cmpxchg8b));
3046 uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsEmpty);
3047
3048 uInstr1(cb, POP, 4, TempReg, accl);
3049 uInstr2(cb, PUT, 4, TempReg, accl, ArchReg, R_EAX);
3050 uInstr1(cb, POP, 4, TempReg, acch);
3051 uInstr2(cb, PUT, 4, TempReg, acch, ArchReg, R_EDX);
3052 uInstr1(cb, POP, 4, TempReg, srcl);
3053 uInstr2(cb, PUT, 4, TempReg, srcl, ArchReg, R_EBX);
3054 uInstr1(cb, POP, 4, TempReg, srch);
3055 uInstr2(cb, PUT, 4, TempReg, srch, ArchReg, R_ECX);
3056 uInstr1(cb, POP, 4, TempReg, destl);
3057 uInstr2(cb, STORE, 4, TempReg, destl, TempReg, tal);
3058 uInstr1(cb, POP, 4, TempReg, desth);
3059 uInstr2(cb, STORE, 4, TempReg, desth, TempReg, tah);
3060
3061 uInstr0(cb, CALLM_E, 0);
3062
3063 return eip0;
3064}
3065
3066
sewardjde4a1d02002-03-22 01:27:54 +00003067/* Handle conditional move instructions of the form
3068 cmovcc E(reg-or-mem), G(reg)
3069
3070 E(src) is reg-or-mem
3071 G(dst) is reg.
3072
3073 If E is reg, --> GET %E, tmps
3074 GET %G, tmpd
3075 CMOVcc tmps, tmpd
3076 PUT tmpd, %G
3077
3078 If E is mem --> (getAddr E) -> tmpa
3079 LD (tmpa), tmps
3080 GET %G, tmpd
3081 CMOVcc tmps, tmpd
3082 PUT tmpd, %G
3083*/
3084static
3085Addr dis_cmov_E_G ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +00003086 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +00003087 Int size,
3088 Condcode cond,
3089 Addr eip0 )
3090{
3091 UChar rm = getUChar(eip0);
3092 UChar dis_buf[50];
3093
3094 Int tmps = newTemp(cb);
3095 Int tmpd = newTemp(cb);
3096
3097 if (epartIsReg(rm)) {
3098 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, tmps);
3099 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmpd);
3100 uInstr2(cb, CMOV, 4, TempReg, tmps, TempReg, tmpd);
3101 uCond(cb, cond);
3102 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
3103 uInstr2(cb, PUT, size, TempReg, tmpd, ArchReg, gregOfRM(rm));
nethercotee8601122004-01-26 17:14:17 +00003104 DIP("cmov%c%s %s,%s\n", nameISize(size),
3105 VG_(name_UCondcode)(cond),
3106 nameIReg(size,eregOfRM(rm)),
3107 nameIReg(size,gregOfRM(rm)));
sewardjde4a1d02002-03-22 01:27:54 +00003108 return 1+eip0;
3109 }
3110
3111 /* E refers to memory */
3112 {
nethercotee8601122004-01-26 17:14:17 +00003113 UInt pair = disAMode ( cb, sorb, eip0, dis_buf );
sewardjde4a1d02002-03-22 01:27:54 +00003114 Int tmpa = LOW24(pair);
3115 uInstr2(cb, LOAD, size, TempReg, tmpa, TempReg, tmps);
3116 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmpd);
3117 uInstr2(cb, CMOV, 4, TempReg, tmps, TempReg, tmpd);
3118 uCond(cb, cond);
3119 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
3120 uInstr2(cb, PUT, size, TempReg, tmpd, ArchReg, gregOfRM(rm));
nethercotee8601122004-01-26 17:14:17 +00003121 DIP("cmov%c%s %s,%s\n", nameISize(size),
3122 VG_(name_UCondcode)(cond),
3123 dis_buf,
3124 nameIReg(size,gregOfRM(rm)));
sewardjde4a1d02002-03-22 01:27:54 +00003125 return HI8(pair)+eip0;
3126 }
3127}
3128
3129
3130static
3131Addr dis_xadd_G_E ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +00003132 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +00003133 Int sz,
3134 Addr eip0 )
3135{
3136 UChar rm = getUChar(eip0);
3137 UChar dis_buf[50];
3138
3139 Int tmpd = newTemp(cb);
3140 Int tmpt = newTemp(cb);
3141
3142 if (epartIsReg(rm)) {
3143 uInstr2(cb, GET, sz, ArchReg, eregOfRM(rm), TempReg, tmpd);
3144 uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
3145 uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
3146 setFlagsFromUOpcode(cb, ADD);
sewardjde4a1d02002-03-22 01:27:54 +00003147 uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
jsewardb60be8b2004-07-20 12:24:53 +00003148 uInstr2(cb, PUT, sz, TempReg, tmpt, ArchReg, eregOfRM(rm));
nethercotee8601122004-01-26 17:14:17 +00003149 DIP("xadd%c %s, %s\n",
3150 nameISize(sz), nameIReg(sz,gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
sewardjde4a1d02002-03-22 01:27:54 +00003151 return 1+eip0;
3152 } else {
nethercotee8601122004-01-26 17:14:17 +00003153 UInt pair = disAMode ( cb, sorb, eip0, dis_buf );
sewardjde4a1d02002-03-22 01:27:54 +00003154 Int tmpa = LOW24(pair);
3155 uInstr2(cb, LOAD, sz, TempReg, tmpa, TempReg, tmpd);
3156 uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
3157 uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
3158 setFlagsFromUOpcode(cb, ADD);
3159 uInstr2(cb, STORE, sz, TempReg, tmpt, TempReg, tmpa);
sewardjde4a1d02002-03-22 01:27:54 +00003160 uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
nethercotee8601122004-01-26 17:14:17 +00003161 DIP("xadd%c %s, %s\n",
3162 nameISize(sz), nameIReg(sz,gregOfRM(rm)), dis_buf);
sewardjde4a1d02002-03-22 01:27:54 +00003163 return HI8(pair)+eip0;
3164 }
3165}
3166
3167
sewardje1042472002-09-30 12:33:11 +00003168/* Moves of Ew into a segment register.
3169 mov Ew, Sw meaning
3170 mov reg-or-mem, reg
3171 Is passed the a ptr to the modRM byte, and the data size. Returns
3172 the address advanced completely over this instruction.
3173
3174 Ew(src) is reg-or-mem
3175 Sw(dst) is seg reg.
3176
3177 If E is reg, --> GETw %Ew, tmpv
3178 PUTSEG tmpv, %Sw
3179
3180 If E is mem --> (getAddr E) -> tmpa
3181 LDw (tmpa), tmpb
3182 PUTSEG tmpb, %Sw
3183*/
3184static
3185Addr dis_mov_Ew_Sw ( UCodeBlock* cb,
sewardjd077f532002-09-30 21:52:50 +00003186 UChar sorb,
sewardje1042472002-09-30 12:33:11 +00003187 Addr eip0 )
3188{
3189 UChar rm = getUChar(eip0);
3190 UChar dis_buf[50];
3191
3192 if (epartIsReg(rm)) {
3193 Int tmpv = newTemp(cb);
3194 uInstr2(cb, GET, 2, ArchReg, eregOfRM(rm), TempReg, tmpv);
3195 uInstr2(cb, PUTSEG, 2, TempReg, tmpv, ArchRegS, gregOfRM(rm));
nethercotee8601122004-01-26 17:14:17 +00003196 DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
sewardje1042472002-09-30 12:33:11 +00003197 return 1+eip0;
3198 }
3199
3200 /* E refers to memory */
3201 {
nethercotee8601122004-01-26 17:14:17 +00003202 UInt pair = disAMode ( cb, sorb, eip0, dis_buf );
sewardje1042472002-09-30 12:33:11 +00003203 Int tmpa = LOW24(pair);
3204 Int tmpb = newTemp(cb);
3205 uInstr2(cb, LOAD, 2, TempReg, tmpa, TempReg, tmpb);
3206 uInstr2(cb, PUTSEG, 2, TempReg, tmpb, ArchRegS, gregOfRM(rm));
nethercotee8601122004-01-26 17:14:17 +00003207 DIP("movw %s,%s\n", dis_buf,nameSReg(gregOfRM(rm)));
sewardje1042472002-09-30 12:33:11 +00003208 return HI8(pair)+eip0;
3209 }
3210}
3211
3212
sewardjd077f532002-09-30 21:52:50 +00003213/* Moves of a segment register to Ew.
3214 mov Sw, Ew meaning
3215 mov reg, reg-or-mem
3216 Is passed the a ptr to the modRM byte, and the data size. Returns
3217 the address advanced completely over this instruction.
3218
3219 Sw(src) is seg reg.
3220 Ew(dst) is reg-or-mem
3221
3222 If E is reg, --> GETSEG %Sw, tmp
3223 PUTW tmp, %Ew
3224
3225 If E is mem, --> (getAddr E) -> tmpa
3226 GETSEG %Sw, tmpv
3227 STW tmpv, (tmpa)
3228*/
3229static
3230Addr dis_mov_Sw_Ew ( UCodeBlock* cb,
3231 UChar sorb,
3232 Addr eip0 )
3233{
3234 UChar rm = getUChar(eip0);
3235 UChar dis_buf[50];
3236
3237 if (epartIsReg(rm)) {
3238 Int tmpv = newTemp(cb);
3239 uInstr2(cb, GETSEG, 2, ArchRegS, gregOfRM(rm), TempReg, tmpv);
3240 uInstr2(cb, PUT, 2, TempReg, tmpv, ArchReg, eregOfRM(rm));
nethercotee8601122004-01-26 17:14:17 +00003241 DIP("movw %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(2,eregOfRM(rm)));
sewardjd077f532002-09-30 21:52:50 +00003242 return 1+eip0;
3243 }
3244
3245 /* E refers to memory */
3246 {
nethercotee8601122004-01-26 17:14:17 +00003247 UInt pair = disAMode ( cb, sorb, eip0, dis_buf );
sewardjd077f532002-09-30 21:52:50 +00003248 Int tmpa = LOW24(pair);
3249 Int tmpv = newTemp(cb);
3250 uInstr2(cb, GETSEG, 2, ArchRegS, gregOfRM(rm), TempReg, tmpv);
3251 uInstr2(cb, STORE, 2, TempReg, tmpv, TempReg, tmpa);
nethercotee8601122004-01-26 17:14:17 +00003252 DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
sewardjd077f532002-09-30 21:52:50 +00003253 return HI8(pair)+eip0;
3254 }
3255}
3256
3257
sewardj3d7c9c82003-03-26 21:08:13 +00003258
3259/* Simple MMX operations, either
3260 op (src)mmxreg, (dst)mmxreg
3261 or
3262 op (src)address, (dst)mmxreg
3263 opc is the byte following the 0x0F prefix.
3264*/
3265static
3266Addr dis_MMXop_regmem_to_reg ( UCodeBlock* cb,
3267 UChar sorb,
3268 Addr eip,
3269 UChar opc,
3270 Char* name,
3271 Bool show_granularity )
3272{
nethercotee8601122004-01-26 17:14:17 +00003273 Char dis_buf[50];
3274 UChar modrm = getUChar(eip);
3275 Bool isReg = epartIsReg(modrm);
3276
3277 if (isReg) {
sewardj3d7c9c82003-03-26 21:08:13 +00003278 eip++;
3279 uInstr1(cb, MMX2, 0,
3280 Lit16,
3281 (((UShort)(opc)) << 8) | ((UShort)modrm) );
sewardj3d7c9c82003-03-26 21:08:13 +00003282 } else {
nethercotee8601122004-01-26 17:14:17 +00003283 UInt pair = disAMode ( cb, sorb, eip, dis_buf );
sewardj3d7c9c82003-03-26 21:08:13 +00003284 Int tmpa = LOW24(pair);
3285 eip += HI8(pair);
3286 uInstr2(cb, MMX2_MemRd, 8,
3287 Lit16,
3288 (((UShort)(opc)) << 8) | ((UShort)modrm),
3289 TempReg, tmpa);
sewardj3d7c9c82003-03-26 21:08:13 +00003290 }
nethercotee8601122004-01-26 17:14:17 +00003291
3292 DIP("%s%s %s, %s\n",
3293 name, show_granularity ? nameMMXGran(opc & 3) : (Char*)"",
3294 ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
3295 nameMMXReg(gregOfRM(modrm)) );
3296
sewardj3d7c9c82003-03-26 21:08:13 +00003297 return eip;
3298}
3299
3300
thughes96b466a2004-03-15 16:43:58 +00003301/* Simple MMX operations, either
3302 op (src)mmxreg, (dst)mmxreg
3303 or
3304 op (src)address, (dst)mmxreg
3305 opc is the byte following the 0x0F prefix.
3306*/
3307static
3308Addr dis_MMXop_regmem_to_reg_Imm8 ( UCodeBlock* cb,
3309 UChar sorb,
3310 Addr eip,
3311 UChar opc,
3312 Char* name,
3313 Bool show_granularity )
3314{
3315 Char dis_buf[50];
3316 UChar modrm = getUChar(eip);
3317 UChar imm8;
3318 Bool isReg = epartIsReg(modrm);
3319
3320 if (isReg) {
3321 eip++;
3322 imm8 = getUChar(eip);
3323 eip++;
3324 uInstr2(cb, MMX3, 0,
3325 Lit16,
3326 (((UShort)(opc)) << 8) | ((UShort)modrm),
3327 Lit16,
3328 ((UShort)imm8));
3329 } else {
3330 UInt pair = disAMode ( cb, sorb, eip, dis_buf );
3331 Int tmpa = LOW24(pair);
3332 eip += HI8(pair);
3333 imm8 = getUChar(eip);
3334 eip++;
3335 uInstr3(cb, MMX2a1_MemRd, 8,
3336 Lit16,
3337 (((UShort)(opc)) << 8) | ((UShort)modrm),
3338 Lit16,
3339 ((UShort)imm8),
3340 TempReg, tmpa);
3341 }
3342
3343 DIP("%s%s %s, %s, $%d\n",
3344 name, show_granularity ? nameMMXGran(opc & 3) : (Char*)"",
3345 ( isReg ? nameMMXReg(eregOfRM(modrm)) : dis_buf ),
3346 nameMMXReg(gregOfRM(modrm)), (Int)imm8 );
3347
3348 return eip;
3349}
3350
3351
sewardjfebaa3b2003-05-25 01:07:34 +00003352
3353/* Simple SSE operations, either
3354 op (src)xmmreg, (dst)xmmreg
3355 or
3356 op (src)address, (dst)xmmreg
sewardjde8aecf2003-05-27 00:46:28 +00003357 3 opcode bytes.
3358 Supplied eip points to the first address mode byte.
sewardjfebaa3b2003-05-25 01:07:34 +00003359*/
3360static
3361Addr dis_SSE3_reg_or_mem ( UCodeBlock* cb,
3362 UChar sorb,
sewardjde8aecf2003-05-27 00:46:28 +00003363 Addr eip,
3364 Int sz,
sewardjfebaa3b2003-05-25 01:07:34 +00003365 Char* name,
sewardjde8aecf2003-05-27 00:46:28 +00003366 UChar opc1,
3367 UChar opc2,
3368 UChar opc3 )
sewardjfebaa3b2003-05-25 01:07:34 +00003369{
nethercotee8601122004-01-26 17:14:17 +00003370 Char dis_buf[50];
sewardjde8aecf2003-05-27 00:46:28 +00003371 UChar modrm = getUChar(eip);
nethercotee8601122004-01-26 17:14:17 +00003372 Bool isReg = epartIsReg(modrm);
3373
3374 if (isReg) {
sewardjfebaa3b2003-05-25 01:07:34 +00003375 /* Completely internal SSE insn. */
3376 uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
3377 Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
3378 Lit16, (((UShort)opc3) << 8) | (UShort)modrm );
sewardja60be0e2003-05-26 08:47:27 +00003379 eip++;
sewardjfebaa3b2003-05-25 01:07:34 +00003380 } else {
nethercotee8601122004-01-26 17:14:17 +00003381 UInt pair = disAMode ( cb, sorb, eip, dis_buf );
sewardj02af6bc2003-06-12 00:56:06 +00003382 Int tmpa = LOW24(pair);
3383 eip += HI8(pair);
3384 uInstr3(cb, SSE3a_MemRd, sz,
3385 Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
3386 Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
3387 TempReg, tmpa);
sewardjfebaa3b2003-05-25 01:07:34 +00003388 }
nethercotee8601122004-01-26 17:14:17 +00003389
3390 DIP("%s %s, %s\n",
3391 name,
3392 ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
3393 nameXMMReg(gregOfRM(modrm)) );
3394
sewardjfebaa3b2003-05-25 01:07:34 +00003395 return eip;
3396}
3397
3398
sewardja60be0e2003-05-26 08:47:27 +00003399/* Simple SSE operations, either
3400 op (src)xmmreg, (dst)xmmreg
3401 or
3402 op (src)address, (dst)xmmreg
sewardjde8aecf2003-05-27 00:46:28 +00003403 2 opcode bytes.
3404 Supplied eip points to the first address mode byte.
sewardja60be0e2003-05-26 08:47:27 +00003405*/
3406static
3407Addr dis_SSE2_reg_or_mem ( UCodeBlock* cb,
3408 UChar sorb,
sewardjde8aecf2003-05-27 00:46:28 +00003409 Addr eip,
sewardja60be0e2003-05-26 08:47:27 +00003410 Int sz,
sewardjde8aecf2003-05-27 00:46:28 +00003411 Char* name,
3412 UChar opc1,
3413 UChar opc2 )
sewardja60be0e2003-05-26 08:47:27 +00003414{
nethercotee8601122004-01-26 17:14:17 +00003415 Char dis_buf[50];
sewardjde8aecf2003-05-27 00:46:28 +00003416 UChar modrm = getUChar(eip);
nethercotee8601122004-01-26 17:14:17 +00003417 Bool isReg = epartIsReg(modrm);
3418
3419 if (isReg) {
sewardja60be0e2003-05-26 08:47:27 +00003420 /* Completely internal SSE insn. */
3421 uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
3422 Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
3423 Lit16, (UShort)modrm );
sewardja60be0e2003-05-26 08:47:27 +00003424 eip++;
3425 } else {
nethercotee8601122004-01-26 17:14:17 +00003426 UInt pair = disAMode ( cb, sorb, eip, dis_buf );
sewardj1e86b8b2003-06-16 23:34:12 +00003427 Int tmpa = LOW24(pair);
3428 eip += HI8(pair);
3429 uInstr3(cb, SSE2a_MemRd, sz,
3430 Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
3431 Lit16, (UShort)modrm,
3432 TempReg, tmpa);
sewardja60be0e2003-05-26 08:47:27 +00003433 }
nethercotee8601122004-01-26 17:14:17 +00003434 DIP("%s %s, %s\n",
3435 name,
3436 ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
3437 nameXMMReg(gregOfRM(modrm)) );
3438
sewardja60be0e2003-05-26 08:47:27 +00003439 return eip;
3440}
3441
3442
3443/* Simple SSE operations, either
3444 op (src)xmmreg, (dst)xmmreg
3445 or
3446 op (src)address, (dst)xmmreg
sewardjde8aecf2003-05-27 00:46:28 +00003447 2 opcode bytes and an 8-bit immediate after the amode.
3448 Supplied eip points to the first address mode byte.
sewardja60be0e2003-05-26 08:47:27 +00003449*/
3450static
3451Addr dis_SSE2_reg_or_mem_Imm8 ( UCodeBlock* cb,
3452 UChar sorb,
sewardjde8aecf2003-05-27 00:46:28 +00003453 Addr eip,
sewardja60be0e2003-05-26 08:47:27 +00003454 Int sz,
sewardjde8aecf2003-05-27 00:46:28 +00003455 Char* name,
3456 UChar opc1,
3457 UChar opc2 )
sewardja60be0e2003-05-26 08:47:27 +00003458{
nethercotee8601122004-01-26 17:14:17 +00003459 Char dis_buf[50];
sewardjde8aecf2003-05-27 00:46:28 +00003460 UChar modrm = getUChar(eip);
sewardja60be0e2003-05-26 08:47:27 +00003461 UChar imm8;
nethercotee8601122004-01-26 17:14:17 +00003462 Bool isReg = epartIsReg(modrm);
3463
3464 if (isReg) {
sewardja60be0e2003-05-26 08:47:27 +00003465 /* Completely internal SSE insn. */
3466 eip++;
3467 imm8 = getUChar(eip);
3468 uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
3469 Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
3470 Lit16, (((UShort)modrm) << 8) | (UShort)imm8 );
sewardja60be0e2003-05-26 08:47:27 +00003471 eip++;
3472 } else {
nethercotee8601122004-01-26 17:14:17 +00003473 UInt pair = disAMode ( cb, sorb, eip, dis_buf );
sewardj9dd209f2003-06-18 23:30:52 +00003474 Int tmpa = LOW24(pair);
3475 eip += HI8(pair);
3476 imm8 = getUChar(eip);
3477 eip++;
3478 uInstr3(cb, SSE2a1_MemRd, sz,
3479 Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
3480 Lit16, (((UShort)(modrm)) << 8) | ((UShort)imm8),
3481 TempReg, tmpa);
sewardja60be0e2003-05-26 08:47:27 +00003482 }
nethercotee8601122004-01-26 17:14:17 +00003483 DIP("%s %s, %s, $%d\n",
3484 name, ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
3485 nameXMMReg(gregOfRM(modrm)), (Int)imm8 );
sewardja60be0e2003-05-26 08:47:27 +00003486 return eip;
3487}
3488
sewardjfebaa3b2003-05-25 01:07:34 +00003489
sewardja453fb02003-06-14 13:22:36 +00003490/* Simple SSE operations, either
3491 op (src)xmmreg, (dst)xmmreg
3492 or
3493 op (src)address, (dst)xmmreg
3494 3 opcode bytes and an 8-bit immediate after the amode.
3495 Supplied eip points to the first address mode byte.
3496*/
3497static
3498Addr dis_SSE3_reg_or_mem_Imm8 ( UCodeBlock* cb,
3499 UChar sorb,
3500 Addr eip,
3501 Int sz,
3502 Char* name,
3503 UChar opc1,
3504 UChar opc2,
3505 UChar opc3 )
3506{
nethercotee8601122004-01-26 17:14:17 +00003507 Char dis_buf[50];
sewardja453fb02003-06-14 13:22:36 +00003508 UChar modrm = getUChar(eip);
3509 UChar imm8;
nethercotee8601122004-01-26 17:14:17 +00003510 Bool isReg = epartIsReg(modrm);
3511
3512 if (isReg) {
sewardja453fb02003-06-14 13:22:36 +00003513 /* Completely internal SSE insn. */
3514 eip++;
3515 imm8 = getUChar(eip);
3516 uInstr3(cb, SSE5, 0, /* ignore sz for internal ops */
3517 Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
3518 Lit16, (((UShort)opc3) << 8) | (UShort)modrm,
3519 Lit16, (UShort)imm8 );
sewardja453fb02003-06-14 13:22:36 +00003520 eip++;
3521 } else {
nethercotee8601122004-01-26 17:14:17 +00003522 UInt pair = disAMode ( cb, sorb, eip, dis_buf );
sewardj77d30a22003-10-19 08:18:52 +00003523 Int tmpa = LOW24(pair);
3524 eip += HI8(pair);
3525 imm8 = getUChar(eip);
3526 eip++;
3527 uInstr3(cb, SSE3a1_MemRd, sz,
3528 Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
3529 Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
3530 TempReg, tmpa);
3531 uLiteral(cb, imm8);
sewardja453fb02003-06-14 13:22:36 +00003532 }
nethercotee8601122004-01-26 17:14:17 +00003533 DIP("%s %s, %s, $%d\n",
3534 name, ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
3535 nameXMMReg(gregOfRM(modrm)), (Int)imm8 );
sewardja453fb02003-06-14 13:22:36 +00003536 return eip;
3537}
3538
3539
sewardjde8aecf2003-05-27 00:46:28 +00003540/* Disassemble an SSE insn which is either a simple reg-reg move or a
3541 move between registers and memory. Supplied eip points to the
3542 first address mode byte.
3543*/
3544static
3545Addr dis_SSE3_load_store_or_mov ( UCodeBlock* cb,
3546 UChar sorb,
3547 Addr eip,
3548 Int sz,
3549 Bool is_store,
3550 Char* name,
3551 UChar insn0,
3552 UChar insn1,
3553 UChar insn2 )
3554{
nethercotee8601122004-01-26 17:14:17 +00003555 Char dis_buf[50];
3556 UChar modrm = getUChar(eip);
3557 Bool isReg = epartIsReg(modrm);
sewardjde8aecf2003-05-27 00:46:28 +00003558 UInt pair;
3559 Int t1;
nethercotee8601122004-01-26 17:14:17 +00003560
3561 if (isReg) {
sewardjde8aecf2003-05-27 00:46:28 +00003562 /* Completely internal; we can issue SSE4. */
3563 eip++;
3564 uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
3565 Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
3566 Lit16, (((UShort)insn2) << 8) | (UShort)modrm );
sewardjde8aecf2003-05-27 00:46:28 +00003567 } else {
nethercotee8601122004-01-26 17:14:17 +00003568 pair = disAMode ( cb, sorb, eip, dis_buf );
sewardjde8aecf2003-05-27 00:46:28 +00003569 t1 = LOW24(pair);
3570 eip += HI8(pair);
3571 uInstr3(cb, is_store ? SSE3a_MemWr : SSE3a_MemRd, sz,
3572 Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
3573 Lit16, (((UShort)insn2) << 8) | (UShort)modrm,
3574 TempReg, t1 );
nethercotee8601122004-01-26 17:14:17 +00003575 }
3576
3577 if (is_store) {
3578 DIP("%s %s, %s\n",
3579 name,
3580 nameXMMReg(gregOfRM(modrm)),
3581 ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ) );
3582 } else {
3583 DIP("%s %s, %s\n",
3584 name,
3585 ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
3586 nameXMMReg(gregOfRM(modrm)) );
sewardjde8aecf2003-05-27 00:46:28 +00003587 }
3588 return eip;
3589}
3590
3591
3592/* Disassemble an SSE insn which is either a simple reg-reg move or a
3593 move between registers and memory. Supplied eip points to the
3594 first address mode byte. */
3595static
3596Addr dis_SSE2_load_store_or_mov ( UCodeBlock* cb,
3597 UChar sorb,
3598 Addr eip,
3599 Int sz,
3600 Bool is_store,
3601 Char* name,
3602 UChar insn0,
3603 UChar insn1 )
3604{
nethercotee8601122004-01-26 17:14:17 +00003605 Char dis_buf[50];
3606 UChar modrm = getUChar(eip);
3607 Bool isReg = epartIsReg(modrm);
sewardjde8aecf2003-05-27 00:46:28 +00003608 UInt pair;
3609 Int t1;
nethercotee8601122004-01-26 17:14:17 +00003610
3611 if (isReg) {
sewardjde8aecf2003-05-27 00:46:28 +00003612 /* Completely internal; we can issue SSE3. */
3613 eip++;
3614 uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
3615 Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
3616 Lit16, (UShort)modrm );
sewardjde8aecf2003-05-27 00:46:28 +00003617 } else {
nethercotee8601122004-01-26 17:14:17 +00003618 pair = disAMode ( cb, sorb, eip, dis_buf );
sewardjde8aecf2003-05-27 00:46:28 +00003619 t1 = LOW24(pair);
3620 eip += HI8(pair);
3621 uInstr3(cb, is_store ? SSE2a_MemWr : SSE2a_MemRd, sz,
3622 Lit16, (((UShort)insn0) << 8) | (UShort)insn1,
3623 Lit16, (UShort)modrm,
3624 TempReg, t1 );
nethercotee8601122004-01-26 17:14:17 +00003625 }
3626
3627 if (is_store) {
3628 DIP("%s %s, %s\n",
3629 name,
3630 nameXMMReg(gregOfRM(modrm)),
3631 ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ) );
3632 } else {
3633 DIP("%s %s, %s\n",
3634 name,
3635 ( isReg ? nameXMMReg(eregOfRM(modrm)) : dis_buf ),
3636 nameXMMReg(gregOfRM(modrm)) );
sewardjde8aecf2003-05-27 00:46:28 +00003637 }
3638 return eip;
3639}
3640
nethercoteb1affa82004-01-19 19:14:18 +00003641
3642/* Simple SSE operations, either
3643 op (src)xmmreg, (dst)mmxreg
3644 or
3645 op (src)address, (dst)mmxreg
3646 2 opcode bytes.
3647 Supplied eip points to the first address mode byte.
3648*/
3649static
3650Addr dis_SSE2_to_MMX ( UCodeBlock *cb,
3651 UChar sorb,
3652 Addr eip,
3653 Int sz,
3654 Char* name,
3655 UChar opc1,
3656 UChar opc2 )
3657{
3658 UChar dis_buf[50];
3659 UChar modrm = getUChar(eip);
3660 if (epartIsReg(modrm)) {
3661 /* Completely internal SSE insn. */
3662 uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
3663 Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
3664 Lit16, (UShort)modrm );
nethercotee8601122004-01-26 17:14:17 +00003665 DIP("%s %s, %s\n",
3666 name, nameXMMReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)) );
nethercoteb1affa82004-01-19 19:14:18 +00003667 eip++;
3668 } else {
nethercotee8601122004-01-26 17:14:17 +00003669 UInt pair = disAMode ( cb, sorb, eip, dis_buf );
nethercoteb1affa82004-01-19 19:14:18 +00003670 Int tmpa = LOW24(pair);
3671 eip += HI8(pair);
3672 uInstr3(cb, SSE2a_MemRd, sz,
3673 Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
3674 Lit16, ((UShort)modrm),
3675 TempReg, tmpa);
nethercotee8601122004-01-26 17:14:17 +00003676 DIP("%s %s, %s\n", name, dis_buf, nameMMXReg(gregOfRM(modrm)));
nethercoteb1affa82004-01-19 19:14:18 +00003677 }
3678 return eip;
3679}
3680
3681
3682/* Simple SSE operations, either
3683 op (src)mmxreg, (dst)xmmreg
3684 or
3685 op (src)address, (dst)xmmreg
3686 2 opcode bytes.
3687 Supplied eip points to the first address mode byte.
3688*/
3689static
3690Addr dis_SSE2_from_MMX ( UCodeBlock *cb,
3691 UChar sorb,
3692 Addr eip,
3693 Int sz,
3694 Char* name,
3695 UChar opc1,
3696 UChar opc2 )
3697{
3698 UChar dis_buf[50];
3699 UChar modrm = getUChar(eip);
3700 if (epartIsReg(modrm)) {
3701 /* Completely internal SSE insn. */
3702 uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
3703 Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
3704 Lit16, (UShort)modrm );
nethercotee8601122004-01-26 17:14:17 +00003705 DIP("%s %s, %s\n",
3706 name, nameMMXReg(eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)) );
nethercoteb1affa82004-01-19 19:14:18 +00003707 eip++;
3708 } else {
nethercotee8601122004-01-26 17:14:17 +00003709 UInt pair = disAMode ( cb, sorb, eip, dis_buf );
nethercoteb1affa82004-01-19 19:14:18 +00003710 Int tmpa = LOW24(pair);
3711 eip += HI8(pair);
3712 uInstr3(cb, SSE2a_MemRd, sz,
3713 Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
3714 Lit16, ((UShort)modrm),
3715 TempReg, tmpa);
nethercotee8601122004-01-26 17:14:17 +00003716 DIP("%s %s, %s\n", name, dis_buf, nameXMMReg(gregOfRM(modrm)));
nethercoteb1affa82004-01-19 19:14:18 +00003717 }
3718 return eip;
3719}
3720
3721
3722/* Simple SSE operations, either
3723 op (src)xmmreg, (dst)mmxreg
3724 or
3725 op (src)address, (dst)mmxreg
3726 3 opcode bytes.
3727 Supplied eip points to the first address mode byte.
3728*/
3729static
3730Addr dis_SSE3_to_MMX ( UCodeBlock *cb,
3731 UChar sorb,
3732 Addr eip,
3733 Int sz,
3734 Char* name,
3735 UChar opc1,
3736 UChar opc2,
3737 UChar opc3 )
3738{
3739 UChar dis_buf[50];
3740 UChar modrm = getUChar(eip);
3741 if (epartIsReg(modrm)) {
3742 /* Completely internal SSE insn. */
3743 uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
3744 Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
3745 Lit16, (((UShort)opc3) << 8) | (UShort)modrm );
nethercotee8601122004-01-26 17:14:17 +00003746 DIP("%s %s, %s\n",
3747 name, nameXMMReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)) );
nethercoteb1affa82004-01-19 19:14:18 +00003748 eip++;
3749 } else {
nethercotee8601122004-01-26 17:14:17 +00003750 UInt pair = disAMode ( cb, sorb, eip, dis_buf );
nethercoteb1affa82004-01-19 19:14:18 +00003751 Int tmpa = LOW24(pair);
3752 eip += HI8(pair);
3753 uInstr3(cb, SSE3a_MemRd, sz,
3754 Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
3755 Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
3756 TempReg, tmpa);
nethercotee8601122004-01-26 17:14:17 +00003757 DIP("%s %s, %s\n", name, dis_buf, nameMMXReg(gregOfRM(modrm)));
nethercoteb1affa82004-01-19 19:14:18 +00003758 }
3759 return eip;
3760}
3761
3762
3763/* Simple SSE operations, either
3764 op (src)mmxreg, (dst)xmmreg
3765 or
3766 op (src)address, (dst)xmmreg
3767 3 opcode bytes.
3768 Supplied eip points to the first address mode byte.
3769*/
3770static
3771Addr dis_SSE3_from_MMX ( UCodeBlock *cb,
3772 UChar sorb,
3773 Addr eip,
3774 Int sz,
3775 Char* name,
3776 UChar opc1,
3777 UChar opc2,
3778 UChar opc3 )
3779{
3780 UChar dis_buf[50];
3781 UChar modrm = getUChar(eip);
3782 if (epartIsReg(modrm)) {
3783 /* Completely internal SSE insn. */
3784 uInstr2(cb, SSE4, 0, /* ignore sz for internal ops */
3785 Lit16, (((UShort)opc1) << 8) | (UShort)opc2,
3786 Lit16, (((UShort)opc3) << 8) | (UShort)modrm );
nethercotee8601122004-01-26 17:14:17 +00003787 DIP("%s %s, %s\n",
3788 name, nameMMXReg(eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)) );
nethercoteb1affa82004-01-19 19:14:18 +00003789 eip++;
3790 } else {
nethercotee8601122004-01-26 17:14:17 +00003791 UInt pair = disAMode ( cb, sorb, eip, dis_buf );
nethercoteb1affa82004-01-19 19:14:18 +00003792 Int tmpa = LOW24(pair);
3793 eip += HI8(pair);
3794 uInstr3(cb, SSE3a_MemRd, sz,
3795 Lit16, (((UShort)(opc1)) << 8) | ((UShort)opc2),
3796 Lit16, (((UShort)(opc3)) << 8) | ((UShort)modrm),
3797 TempReg, tmpa);
nethercotee8601122004-01-26 17:14:17 +00003798 DIP("%s %s, %s\n", name, dis_buf, nameXMMReg(gregOfRM(modrm)));
nethercoteb1affa82004-01-19 19:14:18 +00003799 }
3800 return eip;
3801}
3802
3803
nethercote561f6e02003-11-02 17:00:23 +00003804static
3805void dis_push_segreg ( UCodeBlock* cb, UInt sreg, Int sz )
3806{
nethercote561f6e02003-11-02 17:00:23 +00003807 Int t1 = newTemp(cb), t2 = newTemp(cb);
thughes0ee72ef2004-03-04 23:36:58 +00003808 vg_assert(sz == 2 || sz == 4);
nethercote561f6e02003-11-02 17:00:23 +00003809 uInstr2(cb, GETSEG, 2, ArchRegS, sreg, TempReg, t1);
3810 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
3811 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
thughes0ee72ef2004-03-04 23:36:58 +00003812 uLiteral(cb, sz);
nethercote561f6e02003-11-02 17:00:23 +00003813 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
3814 uInstr2(cb, STORE, 2, TempReg, t1, TempReg, t2);
nethercotee8601122004-01-26 17:14:17 +00003815 DIP("push %s\n", VG_(name_of_seg_reg)(sreg));
nethercote561f6e02003-11-02 17:00:23 +00003816}
3817
3818static
3819void dis_pop_segreg ( UCodeBlock* cb, UInt sreg, Int sz )
3820{
nethercote561f6e02003-11-02 17:00:23 +00003821 Int t1 = newTemp(cb), t2 = newTemp(cb);
thughes0ee72ef2004-03-04 23:36:58 +00003822 vg_assert(sz == 2 || sz == 4);
nethercote561f6e02003-11-02 17:00:23 +00003823 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
3824 uInstr2(cb, LOAD, 2, TempReg, t2, TempReg, t1);
3825 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3826 uLiteral(cb, sz);
3827 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
3828 uInstr2(cb, PUTSEG, 2, TempReg, t1, ArchRegS, sreg);
nethercotee8601122004-01-26 17:14:17 +00003829 DIP("pop %s\n", VG_(name_of_seg_reg)(sreg));
nethercote561f6e02003-11-02 17:00:23 +00003830}
sewardjde8aecf2003-05-27 00:46:28 +00003831
nethercotebd126912004-02-22 16:56:28 +00003832static
3833void dis_ret ( UCodeBlock* cb, UInt d32 )
3834{
3835 Int t1 = newTemp(cb), t2 = newTemp(cb);
3836 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
3837 uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t2);
3838 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1);
3839 uLiteral(cb, 4+d32);
3840 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3841 jmp_treg(cb, t2);
3842 LAST_UINSTR(cb).jmpkind = JmpRet;
3843}
3844
sewardjde4a1d02002-03-22 01:27:54 +00003845/*------------------------------------------------------------*/
3846/*--- Disassembling entire basic blocks ---*/
3847/*------------------------------------------------------------*/
3848
sewardjfebaa3b2003-05-25 01:07:34 +00003849/* Disassemble a single instruction into ucode, returning the updated
sewardjde4a1d02002-03-22 01:27:54 +00003850 eip, and setting *isEnd to True if this is the last insn in a basic
nethercotee8601122004-01-26 17:14:17 +00003851 block. Also do debug printing if necessary. */
sewardjde4a1d02002-03-22 01:27:54 +00003852
3853static Addr disInstr ( UCodeBlock* cb, Addr eip, Bool* isEnd )
3854{
3855 UChar opc, modrm, abyte;
3856 UInt d32, pair;
3857 Int t1, t2, t3, t4;
3858 UChar dis_buf[50];
3859 Int am_sz, d_sz;
nethercote3b38c1d2004-10-18 15:47:18 +00003860 static Char loc_buf[M_VG_ERRTXT];
sewardjde4a1d02002-03-22 01:27:54 +00003861
sewardja60be0e2003-05-26 08:47:27 +00003862 /* Holds eip at the start of the insn, so that we can print
3863 consistent error messages for unimplemented insns. */
3864 UChar* eip_start = (UChar*)eip;
3865
sewardje1042472002-09-30 12:33:11 +00003866 /* sz denotes the nominal data-op size of the insn; we change it to
3867 2 if an 0x66 prefix is seen */
3868 Int sz = 4;
3869
3870 /* sorb holds the segment-override-prefix byte, if any. Zero if no
3871 prefix has been seen, else one of {0x26, 0x3E, 0x64, 0x65}
3872 indicating the prefix. */
3873 UChar sorb = 0;
3874
3875 Int first_uinstr = cb->used;
sewardjde4a1d02002-03-22 01:27:54 +00003876 *isEnd = False;
3877 t1 = t2 = t3 = t4 = INVALID_TEMPREG;
3878
nethercotee8601122004-01-26 17:14:17 +00003879 DIP("\t0x%x: ", eip);
sewardjde4a1d02002-03-22 01:27:54 +00003880
sewardjc7529c32002-04-16 01:55:18 +00003881 /* Spot the client-request magic sequence. */
3882 {
sewardjde4a1d02002-03-22 01:27:54 +00003883 UChar* myeip = (UChar*)eip;
3884 /* Spot this:
3885 C1C01D roll $29, %eax
3886 C1C003 roll $3, %eax
sewardj2e93c502002-04-12 11:12:52 +00003887 C1C81B rorl $27, %eax
3888 C1C805 rorl $5, %eax
3889 C1C00D roll $13, %eax
3890 C1C013 roll $19, %eax
sewardjde4a1d02002-03-22 01:27:54 +00003891 */
sewardj2e93c502002-04-12 11:12:52 +00003892 if (myeip[ 0] == 0xC1 && myeip[ 1] == 0xC0 && myeip[ 2] == 0x1D &&
3893 myeip[ 3] == 0xC1 && myeip[ 4] == 0xC0 && myeip[ 5] == 0x03 &&
3894 myeip[ 6] == 0xC1 && myeip[ 7] == 0xC8 && myeip[ 8] == 0x1B &&
3895 myeip[ 9] == 0xC1 && myeip[10] == 0xC8 && myeip[11] == 0x05 &&
3896 myeip[12] == 0xC1 && myeip[13] == 0xC0 && myeip[14] == 0x0D &&
3897 myeip[15] == 0xC1 && myeip[16] == 0xC0 && myeip[17] == 0x13
3898 ) {
3899 eip += 18;
nethercotee8601122004-01-26 17:14:17 +00003900 jmp_lit(cb, eip);
sewardj2e93c502002-04-12 11:12:52 +00003901 LAST_UINSTR(cb).jmpkind = JmpClientReq;
3902 *isEnd = True;
nethercotee8601122004-01-26 17:14:17 +00003903 DIP("%%edx = client_request ( %%eax )\n");
sewardjde4a1d02002-03-22 01:27:54 +00003904 return eip;
3905 }
3906 }
3907
3908 /* Skip a LOCK prefix. */
sewardj5716dbb2002-04-26 03:28:18 +00003909 if (getUChar(eip) == 0xF0) {
3910 /* VG_(printf)("LOCK LOCK LOCK LOCK LOCK \n"); */
sewardj7a5ebcf2002-11-13 22:42:13 +00003911 uInstr0(cb, LOCK, 0);
sewardj5716dbb2002-04-26 03:28:18 +00003912 eip++;
3913 }
sewardjde4a1d02002-03-22 01:27:54 +00003914
sewardjde4a1d02002-03-22 01:27:54 +00003915 /* Detect operand-size overrides. */
3916 if (getUChar(eip) == 0x66) { sz = 2; eip++; };
3917
sewardje1042472002-09-30 12:33:11 +00003918 /* segment override prefixes come after the operand-size override,
3919 it seems */
3920 switch (getUChar(eip)) {
3921 case 0x3E: /* %DS: */
3922 case 0x26: /* %ES: */
3923 case 0x64: /* %FS: */
3924 case 0x65: /* %GS: */
3925 sorb = getUChar(eip); eip++;
3926 break;
3927 case 0x2E: /* %CS: */
sewardj3058e042003-07-06 01:05:10 +00003928 /* 2E prefix on a conditional branch instruction is a
3929 branch-prediction hint, which can safely be ignored. */
3930 {
3931 UChar op1 = getUChar(eip+1);
3932 UChar op2 = getUChar(eip+2);
3933 if ((op1 >= 0x70 && op1 <= 0x7F)
3934 || (op1 == 0xE3)
3935 || (op1 == 0x0F && op2 >= 0x80 && op2 <= 0x8F)) {
3936 sorb = getUChar(eip); eip++;
3937 break;
3938 }
3939 }
sewardje1042472002-09-30 12:33:11 +00003940 VG_(unimplemented)("x86 segment override (SEG=CS) prefix");
3941 /*NOTREACHED*/
3942 break;
3943 case 0x36: /* %SS: */
3944 VG_(unimplemented)("x86 segment override (SEG=SS) prefix");
3945 /*NOTREACHED*/
3946 break;
3947 default:
3948 break;
3949 }
3950
sewardjfebaa3b2003-05-25 01:07:34 +00003951 /* ---------------------------------------------------- */
3952 /* --- The SSE/SSE2 decoder. --- */
3953 /* ---------------------------------------------------- */
sewardje1042472002-09-30 12:33:11 +00003954
sewardjfebaa3b2003-05-25 01:07:34 +00003955 /* If it looks like this CPU might support SSE, try decoding SSE
3956 insns. */
3957 if (VG_(have_ssestate)) {
3958 UChar* insn = (UChar*)eip;
3959
jsewardfca60182004-01-04 23:30:55 +00003960 /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
3961 if (insn[0] == 0x0F && insn[1] == 0xAE
3962 && (!epartIsReg(insn[2]))
3963 && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
3964 Bool store = gregOfRM(insn[2]) == 0;
3965 vg_assert(sz == 4);
nethercotee8601122004-01-26 17:14:17 +00003966 pair = disAMode ( cb, sorb, eip+2, dis_buf );
jsewardfca60182004-01-04 23:30:55 +00003967 t1 = LOW24(pair);
3968 eip += 2+HI8(pair);
3969 uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
3970 Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
3971 Lit16, (UShort)insn[2],
3972 TempReg, t1 );
nethercotee8601122004-01-26 17:14:17 +00003973 DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
jsewardfca60182004-01-04 23:30:55 +00003974 goto decode_success;
3975 }
3976
sewardja60be0e2003-05-26 08:47:27 +00003977 /* STMXCSR/LDMXCSR m32 -- load/store the MXCSR register. */
sewardjfebaa3b2003-05-25 01:07:34 +00003978 if (insn[0] == 0x0F && insn[1] == 0xAE
jsewardfca60182004-01-04 23:30:55 +00003979 && (!epartIsReg(insn[2]))
sewardjfebaa3b2003-05-25 01:07:34 +00003980 && (gregOfRM(insn[2]) == 3 || gregOfRM(insn[2]) == 2) ) {
3981 Bool store = gregOfRM(insn[2]) == 3;
sewardja60be0e2003-05-26 08:47:27 +00003982 vg_assert(sz == 4);
nethercotee8601122004-01-26 17:14:17 +00003983 pair = disAMode ( cb, sorb, eip+2, dis_buf );
sewardjfebaa3b2003-05-25 01:07:34 +00003984 t1 = LOW24(pair);
3985 eip += 2+HI8(pair);
3986 uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 4,
3987 Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
3988 Lit16, (UShort)insn[2],
3989 TempReg, t1 );
nethercotee8601122004-01-26 17:14:17 +00003990 DIP("%smxcsr %s\n", store ? "st" : "ld", dis_buf );
sewardja60be0e2003-05-26 08:47:27 +00003991 goto decode_success;
sewardjfebaa3b2003-05-25 01:07:34 +00003992 }
3993
thughes1f17f7c2004-07-25 15:43:00 +00003994 /* LFENCE/MFENCE -- flush pending operations to memory */
nethercote382a8922003-12-02 15:25:39 +00003995 if (insn[0] == 0x0F && insn[1] == 0xAE
3996 && (epartIsReg(insn[2]))
thughes1f17f7c2004-07-25 15:43:00 +00003997 && (gregOfRM(insn[2]) >= 5 && gregOfRM(insn[2]) <= 6))
nethercote382a8922003-12-02 15:25:39 +00003998 {
daywalker5d945de2003-09-26 00:32:53 +00003999 vg_assert(sz == 4);
4000 eip += 3;
4001 uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
4002 Lit16, (((UShort)0x0F) << 8) | (UShort)0xAE,
4003 Lit16, (UShort)insn[2] );
thughes1f17f7c2004-07-25 15:43:00 +00004004 DIP("%sfence\n", gregOfRM(insn[2]) == 5 ? "l" : "m");
daywalker5d945de2003-09-26 00:32:53 +00004005 goto decode_success;
4006 }
4007
nethercoteb1affa82004-01-19 19:14:18 +00004008 /* CLFLUSH -- flush cache line */
4009 if (insn[0] == 0x0F && insn[1] == 0xAE
4010 && (!epartIsReg(insn[2]))
4011 && (gregOfRM(insn[2]) == 7))
4012 {
4013 vg_assert(sz == 4);
nethercotee8601122004-01-26 17:14:17 +00004014 pair = disAMode ( cb, sorb, eip+2, dis_buf );
nethercoteb1affa82004-01-19 19:14:18 +00004015 t1 = LOW24(pair);
4016 eip += 2+HI8(pair);
4017 uInstr3(cb, SSE2a_MemRd, 0, /* ignore sz for internal ops */
4018 Lit16, (((UShort)0x0F) << 8) | (UShort)0xAE,
4019 Lit16, (UShort)insn[2],
4020 TempReg, t1 );
nethercotee8601122004-01-26 17:14:17 +00004021 DIP("clflush %s\n", dis_buf);
nethercoteb1affa82004-01-19 19:14:18 +00004022 goto decode_success;
4023 }
4024
4025 /* CVTPI2PS (0x0F,0x2A) -- mm/m64, xmm */
4026 /* CVTPI2PD (0x66,0x0F,0x2A) -- mm/m64, xmm */
4027 if (insn[0] == 0x0F && insn[1] == 0x2A) {
4028 if (sz == 4) {
4029 eip = dis_SSE2_from_MMX
4030 ( cb, sorb, eip+2, 8, "cvtpi2ps",
4031 insn[0], insn[1] );
4032 } else {
4033 eip = dis_SSE3_from_MMX
4034 ( cb, sorb, eip+2, 8, "cvtpi2pd",
4035 0x66, insn[0], insn[1] );
4036 }
4037 goto decode_success;
4038 }
4039
4040 /* CVTTPS2PI (0x0F,0x2C) -- xmm/m64, mm */
4041 /* CVTPS2PI (0x0F,0x2D) -- xmm/m64, mm */
4042 /* CVTTPD2PI (0x66,0x0F,0x2C) -- xmm/m128, mm */
4043 /* CVTPD2PI (0x66,0x0F,0x2D) -- xmm/m128, mm */
4044 if (insn[0] == 0x0F
4045 && (insn[1] == 0x2C || insn[1] == 0x2D)) {
4046 if (sz == 4) {
4047 eip = dis_SSE2_to_MMX
4048 ( cb, sorb, eip+2, 8, "cvt{t}ps2pi",
4049 insn[0], insn[1] );
4050 } else {
4051 eip = dis_SSE3_to_MMX
4052 ( cb, sorb, eip+2, 16, "cvt{t}pd2pi",
4053 0x66, insn[0], insn[1] );
4054 }
4055 goto decode_success;
4056 }
4057
sewardj095c3bc2003-06-15 23:26:04 +00004058 /* CVTTSD2SI (0xF2,0x0F,0x2C) -- convert a double-precision float
4059 value in memory or xmm reg to int and put it in an ireg.
4060 Truncate. */
4061 /* CVTTSS2SI (0xF3,0x0F,0x2C) -- convert a single-precision float
4062 value in memory or xmm reg to int and put it in an ireg.
4063 Truncate. */
4064 /* CVTSD2SI (0xF2,0x0F,0x2D) -- convert a double-precision float
4065 value in memory or xmm reg to int and put it in an ireg. Round
4066 as per MXCSR. */
4067 /* CVTSS2SI (0xF3,0x0F,0x2D) -- convert a single-precision float
4068 value in memory or xmm reg to int and put it in an ireg. Round
4069 as per MXCSR. */
sewardjea691a12003-06-14 12:05:29 +00004070 if ((insn[0] == 0xF2 || insn[0] == 0xF3)
sewardje3891fa2003-06-15 03:13:48 +00004071 && insn[1] == 0x0F
4072 && (insn[2] == 0x2C || insn[2] == 0x2D)) {
sewardj02af6bc2003-06-12 00:56:06 +00004073 vg_assert(sz == 4);
4074 modrm = insn[3];
4075 if (epartIsReg(modrm)) {
4076 /* We're moving a value in an xmm reg to an ireg. */
4077 eip += 4;
4078 t1 = newTemp(cb);
sewardje3891fa2003-06-15 03:13:48 +00004079 /* sz is 4 for all 4 insns. */
sewardj6bc40552003-06-15 01:40:58 +00004080 vg_assert(epartIsReg(modrm));
sewardj02af6bc2003-06-12 00:56:06 +00004081 uInstr3(cb, SSE3g_RegWr, 4,
4082 Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
4083 Lit16, (((UShort)insn[2]) << 8) | (UShort)modrm,
4084 TempReg, t1 );
4085 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
nethercotee8601122004-01-26 17:14:17 +00004086 DIP("cvt{t}s{s,d}2si %s, %s\n",
4087 nameXMMReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)) );
sewardj02af6bc2003-06-12 00:56:06 +00004088 } else {
sewardj02af6bc2003-06-12 00:56:06 +00004089 /* So, we're reading memory and writing an ireg. This calls
sewardje3891fa2003-06-15 03:13:48 +00004090 for the ultra-horrible SSE3ag_MemRd_RegWr uinstr. We
4091 can't do it in a roundabout route because it does some
4092 kind of conversion on the way, which we need to have
4093 happen too. So our only choice is to re-emit a suitably
4094 rehashed version of the instruction. */
4095 /* Destination ireg is GREG. Address goes as EREG as
4096 usual. */
sewardj02af6bc2003-06-12 00:56:06 +00004097 t1 = newTemp(cb); /* t1 holds value on its way to ireg */
nethercotee8601122004-01-26 17:14:17 +00004098 pair = disAMode ( cb, sorb, eip+3, dis_buf );
sewardj02af6bc2003-06-12 00:56:06 +00004099 t2 = LOW24(pair); /* t2 holds addr */
4100 eip += 3+HI8(pair);
sewardje3891fa2003-06-15 03:13:48 +00004101 uInstr2(cb, SSE3ag_MemRd_RegWr, insn[0]==0xF2 ? 8 : 4,
sewardj02af6bc2003-06-12 00:56:06 +00004102 TempReg, t2, /* address */
4103 TempReg, t1 /* dest */);
sewardje3891fa2003-06-15 03:13:48 +00004104 uLiteral(cb , (((UInt)insn[0]) << 24)
4105 | (((UInt)insn[1]) << 16)
4106 | (((UInt)insn[2]) << 8)
4107 | ((UInt)modrm) );
sewardj02af6bc2003-06-12 00:56:06 +00004108 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
nethercotee8601122004-01-26 17:14:17 +00004109 DIP("cvt{t}s{s,d}2si %s, %s\n",
4110 dis_buf, nameIReg(4,gregOfRM(modrm)) );
sewardj02af6bc2003-06-12 00:56:06 +00004111 }
4112 goto decode_success;
4113 }
4114
4115 /* CVTSI2SS -- convert int reg, or int value in memory, to low 4
4116 bytes of XMM reg. */
4117 /* CVTSI2SD -- convert int reg, or int value in memory, to low 8
4118 bytes of XMM reg. */
4119 if ((insn[0] == 0xF3 /*CVTSI2SS*/ || insn[0] == 0xF2 /* CVTSI2SD*/)
4120 && insn[1] == 0x0F && insn[2] == 0x2A) {
4121 Char* s_or_d = insn[0]==0xF3 ? "s" : "d";
sewardja60be0e2003-05-26 08:47:27 +00004122 vg_assert(sz == 4);
sewardjfebaa3b2003-05-25 01:07:34 +00004123 modrm = insn[3];
4124 t1 = newTemp(cb);
4125 if (epartIsReg(modrm)) {
4126 uInstr2(cb, GET, 4, ArchReg, eregOfRM(modrm), TempReg, t1);
sewardj6bc40552003-06-15 01:40:58 +00004127 vg_assert(epartIsReg(modrm));
sewardj4fbe6e92003-06-15 21:54:34 +00004128 uInstr3(cb, SSE3e_RegRd, 4,
sewardjfebaa3b2003-05-25 01:07:34 +00004129 Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
sewardj6bc40552003-06-15 01:40:58 +00004130 Lit16, (((UShort)insn[2]) << 8) | (UShort)modrm,
sewardjfebaa3b2003-05-25 01:07:34 +00004131 TempReg, t1 );
4132 eip += 4;
nethercotee8601122004-01-26 17:14:17 +00004133 DIP("cvtsi2s%s %s, %s\n", s_or_d,
4134 nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
sewardjfebaa3b2003-05-25 01:07:34 +00004135 } else {
nethercotee8601122004-01-26 17:14:17 +00004136 pair = disAMode ( cb, sorb, eip+3, dis_buf );
sewardjfebaa3b2003-05-25 01:07:34 +00004137 t2 = LOW24(pair);
4138 eip += 3+HI8(pair);
sewardj6bc40552003-06-15 01:40:58 +00004139 uInstr3(cb, SSE3a_MemRd, 4,
sewardjfebaa3b2003-05-25 01:07:34 +00004140 Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
sewardj6bc40552003-06-15 01:40:58 +00004141 Lit16, (((UShort)insn[2]) << 8) | (UShort)modrm,
4142 TempReg, t2 );
nethercotee8601122004-01-26 17:14:17 +00004143 DIP("cvtsi2s%s %s, %s\n",
4144 s_or_d, dis_buf, nameXMMReg(gregOfRM(modrm)));
sewardjfebaa3b2003-05-25 01:07:34 +00004145 }
sewardja60be0e2003-05-26 08:47:27 +00004146 goto decode_success;
sewardjfebaa3b2003-05-25 01:07:34 +00004147 }
4148
nethercoteb1affa82004-01-19 19:14:18 +00004149 /* CVTPS2PD -- convert two packed floats to two packed doubles. */
4150 /* 0x66: CVTPD2PS -- convert two packed doubles to two packed floats. */
4151 if (insn[0] == 0x0F && insn[1] == 0x5A) {
4152 vg_assert(sz == 2 || sz == 4);
4153 if (sz == 4) {
4154 eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 8, "cvtps2pd",
4155 insn[0], insn[1] );
4156 } else {
4157 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "cvtpd2ps",
4158 0x66, insn[0], insn[1] );
4159 }
4160 goto decode_success;
4161 }
4162
sewardj35a17792003-06-01 18:49:12 +00004163 /* CVTSS2SD -- convert one single float to double. */
4164 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5A) {
4165 vg_assert(sz == 4);
4166 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4, "cvtss2sd",
4167 insn[0], insn[1], insn[2] );
4168 goto decode_success;
4169 }
4170
sewardj02af6bc2003-06-12 00:56:06 +00004171 /* CVTSD2SS -- convert one single double. to float. */
4172 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5A) {
4173 vg_assert(sz == 4);
4174 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8, "cvtsd2ss",
4175 insn[0], insn[1], insn[2] );
4176 goto decode_success;
4177 }
4178
nethercoteb1affa82004-01-19 19:14:18 +00004179 /* CVTDQ2PS -- convert four ints to four packed floats. */
4180 /* 0x66: CVTPS2DQ -- convert four packed floats to four ints. */
4181 if (insn[0] == 0x0F && insn[1] == 0x5B) {
4182 vg_assert(sz == 2 || sz == 4);
4183 if (sz == 4) {
4184 eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "cvtdq2ps",
4185 insn[0], insn[1] );
4186 } else {
4187 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "cvtps2dq",
4188 0x66, insn[0], insn[1] );
4189 }
4190 goto decode_success;
4191 }
4192
4193 /* CVTPD2DQ -- convert two packed doubles to two ints. */
4194 if (sz == 2
4195 && insn[0] == 0x0F && insn[1] == 0xE6) {
4196 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 8, "cvtpd2dq",
4197 0x66, insn[0], insn[1] );
4198 goto decode_success;
4199 }
4200
4201 /* CVTTPD2DQ -- convert two packed doubles to two ints with truncation. */
4202 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xE6) {
4203 vg_assert(sz == 4);
4204 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8, "cvttpd2dq",
4205 insn[0], insn[1], insn[2] );
4206 goto decode_success;
4207 }
4208
4209 /* CVTDQ2PD -- convert two ints to two packed doubles. */
4210 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xE6) {
4211 vg_assert(sz == 4);
4212 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8, "cvtdq2pd",
4213 insn[0], insn[1], insn[2] );
4214 goto decode_success;
4215 }
4216
4217 /* CVTTPS2DQ -- convert four packed floats to four ints with truncation. */
4218 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5B) {
4219 vg_assert(sz == 4);
4220 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 16, "cvttps2dq",
4221 insn[0], insn[1], insn[2] );
4222 goto decode_success;
4223 }
4224
4225 /* CMPSS -- compare scalar floats. */
4226 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xC2) {
4227 vg_assert(sz == 4);
4228 eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 8, "cmpss",
4229 insn[0], insn[1], insn[2] );
4230 goto decode_success;
4231 }
4232
sewardj1e86b8b2003-06-16 23:34:12 +00004233 /* CMPSD -- compare scalar doubles. */
4234 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xC2) {
4235 vg_assert(sz == 4);
4236 eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 8, "cmpsd",
4237 insn[0], insn[1], insn[2] );
4238 goto decode_success;
4239 }
4240
sewardj77d30a22003-10-19 08:18:52 +00004241 /* sz==4: CMPPS -- compare packed floats */
4242 /* sz==2: CMPPD -- compare packed doubles */
sewardj9dd209f2003-06-18 23:30:52 +00004243 if (insn[0] == 0x0F && insn[1] == 0xC2) {
sewardj77d30a22003-10-19 08:18:52 +00004244 vg_assert(sz == 4 || sz == 2);
4245 if (sz == 4) {
4246 eip = dis_SSE2_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "cmpps",
4247 insn[0], insn[1] );
4248 } else {
4249 eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "cmppd",
4250 0x66, insn[0], insn[1] );
4251 }
sewardj9dd209f2003-06-18 23:30:52 +00004252 goto decode_success;
4253 }
4254
sewardja453fb02003-06-14 13:22:36 +00004255 /* PSHUFD */
4256 if (sz == 2
4257 && insn[0] == 0x0F && insn[1] == 0x70) {
4258 eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16,
4259 "pshufd",
4260 0x66, insn[0], insn[1] );
4261 goto decode_success;
4262 }
4263
nethercoteb1affa82004-01-19 19:14:18 +00004264 /* PSHUFLW */
4265 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x70) {
4266 eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 16,
4267 "pshuflw",
4268 insn[0], insn[1], insn[2] );
4269 goto decode_success;
4270 }
4271
4272 /* PSHUFHW */
4273 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x70) {
4274 eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+3, 16,
4275 "pshufhw",
4276 insn[0], insn[1], insn[2] );
4277 goto decode_success;
4278 }
4279
muelleraa5c6262003-11-19 22:02:08 +00004280 /* SHUFPD */
4281 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC6) {
4282 eip = dis_SSE3_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "shufpd",
4283 0x66, insn[0], insn[1] );
4284 goto decode_success;
4285 }
4286
sewardja60be0e2003-05-26 08:47:27 +00004287 /* SHUFPS */
4288 if (insn[0] == 0x0F && insn[1] == 0xC6) {
4289 vg_assert(sz == 4);
sewardjde8aecf2003-05-27 00:46:28 +00004290 eip = dis_SSE2_reg_or_mem_Imm8 ( cb, sorb, eip+2, 16, "shufps",
4291 insn[0], insn[1] );
sewardja60be0e2003-05-26 08:47:27 +00004292 goto decode_success;
4293 }
4294
sewardj2db567e2003-06-18 00:22:01 +00004295 /* 0xF2: MULSD */
4296 /* 0xF3: MULSS -- multiply low 4 bytes of XMM reg. */
4297 if ((insn[0] == 0xF2 || insn[0] == 0xF3)
4298 && insn[1] == 0x0F && insn[2] == 0x59) {
sewardj2db567e2003-06-18 00:22:01 +00004299 Bool sz8 = insn[0] == 0xF2;
njn2aaa2ca2003-06-19 10:14:15 +00004300 vg_assert(sz == 4);
sewardj2db567e2003-06-18 00:22:01 +00004301 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
4302 sz8 ? "mulss" : "mulsd",
4303 insn[0], insn[1], insn[2] );
4304 goto decode_success;
4305 }
4306
sewardja60be0e2003-05-26 08:47:27 +00004307 /* MULPS */
sewardj095c3bc2003-06-15 23:26:04 +00004308 /* 0x66: MULPD */
sewardja60be0e2003-05-26 08:47:27 +00004309 if (insn[0] == 0x0F && insn[1] == 0x59) {
sewardj095c3bc2003-06-15 23:26:04 +00004310 vg_assert(sz == 4 || sz == 2);
4311 if (sz == 4) {
4312 eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "mulps",
4313 insn[0], insn[1] );
4314 } else {
4315 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "mulpd",
4316 0x66, insn[0], insn[1] );
4317 }
4318 goto decode_success;
4319 }
4320
sewardj2db567e2003-06-18 00:22:01 +00004321 /* 0xF2: DIVSD */
4322 /* 0xF3: DIVSS -- divide low 4 bytes of XMM reg. */
4323 if ((insn[0] == 0xF2 || insn[0] == 0xF3)
4324 && insn[1] == 0x0F && insn[2] == 0x5E) {
sewardj2db567e2003-06-18 00:22:01 +00004325 Bool sz8 = insn[0] == 0xF2;
njn2aaa2ca2003-06-19 10:14:15 +00004326 vg_assert(sz == 4);
sewardj2db567e2003-06-18 00:22:01 +00004327 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
4328 sz8 ? "divsd" : "divss",
4329 insn[0], insn[1], insn[2] );
4330 goto decode_success;
4331 }
4332
sewardj737a3752003-10-12 08:38:36 +00004333 /* DIVPS */
4334 /* 0x66: DIVPD */
4335 if (insn[0] == 0x0F && insn[1] == 0x5E) {
4336 vg_assert(sz == 4 || sz == 2);
4337 if (sz == 4) {
4338 eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "divps",
4339 insn[0], insn[1] );
4340 } else {
4341 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "divpd",
4342 0x66, insn[0], insn[1] );
4343 }
4344 goto decode_success;
4345 }
4346
sewardj2db567e2003-06-18 00:22:01 +00004347 /* 0xF2: SUBSD */
4348 /* 0xF3: SUBSS */
4349 if ((insn[0] == 0xF2 || insn[0] == 0xF3)
4350 && insn[1] == 0x0F && insn[2] == 0x5C) {
4351 Bool sz8 = insn[0] == 0xF2;
4352 vg_assert(sz == 4);
4353 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
4354 sz8 ? "subsd" : "subss",
4355 insn[0], insn[1], insn[2] );
4356 goto decode_success;
4357 }
4358
4359 /* SUBPS */
sewardj095c3bc2003-06-15 23:26:04 +00004360 /* 0x66: SUBPD */
sewardj2db567e2003-06-18 00:22:01 +00004361 if (insn[0] == 0x0F && insn[1] == 0x5C) {
4362 vg_assert(sz == 4 || sz == 2);
4363 if (sz == 4) {
4364 eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "subps",
4365 insn[0], insn[1] );
4366 } else {
sewardj095c3bc2003-06-15 23:26:04 +00004367 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "subpd",
4368 0x66, insn[0], insn[1] );
4369 }
sewardja60be0e2003-05-26 08:47:27 +00004370 goto decode_success;
4371 }
4372
sewardj2db567e2003-06-18 00:22:01 +00004373 /* 0xF2: ADDSD */
4374 /* 0xF3: ADDSS */
4375 if ((insn[0] == 0xF2 || insn[0] == 0xF3)
4376 && insn[1] == 0x0F && insn[2] == 0x58) {
4377 Bool sz8 = insn[0] == 0xF2;
sewardj35a17792003-06-01 18:49:12 +00004378 vg_assert(sz == 4);
sewardj2db567e2003-06-18 00:22:01 +00004379 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
4380 sz8 ? "addsd" : "addss",
sewardj1e86b8b2003-06-16 23:34:12 +00004381 insn[0], insn[1], insn[2] );
4382 goto decode_success;
4383 }
4384
sewardja60be0e2003-05-26 08:47:27 +00004385 /* ADDPS */
sewardj095c3bc2003-06-15 23:26:04 +00004386 /* 0x66: ADDPD */
sewardja60be0e2003-05-26 08:47:27 +00004387 if (insn[0] == 0x0F && insn[1] == 0x58) {
sewardj095c3bc2003-06-15 23:26:04 +00004388 vg_assert(sz == 4 || sz == 2);
4389 if (sz == 4) {
4390 eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "addps",
4391 insn[0], insn[1] );
4392 } else {
4393 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "addpd",
4394 0x66, insn[0], insn[1] );
4395 }
sewardjde8aecf2003-05-27 00:46:28 +00004396 goto decode_success;
4397 }
4398
sewardj2db567e2003-06-18 00:22:01 +00004399 /* 0xF2: MINSD */
sewardj77d30a22003-10-19 08:18:52 +00004400 /* 0xF3: MINSS */
4401 if ((insn[0] == 0xF2 || insn[0] == 0xF3)
4402 && insn[1] == 0x0F && insn[2] == 0x5D) {
4403 Bool sz8 = insn[0] == 0xF2;
sewardj2db567e2003-06-18 00:22:01 +00004404 vg_assert(sz == 4);
sewardj77d30a22003-10-19 08:18:52 +00004405 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
4406 sz8 ? "minsd" : "minss",
sewardj2db567e2003-06-18 00:22:01 +00004407 insn[0], insn[1], insn[2] );
4408 goto decode_success;
4409 }
4410
nethercoteb1affa82004-01-19 19:14:18 +00004411 /* MINPS */
4412 /* 0x66: MINPD */
4413 if (insn[0] == 0x0F && insn[1] == 0x5D) {
4414 vg_assert(sz == 4 || sz == 2);
4415 if (sz == 4) {
4416 eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "minps",
4417 insn[0], insn[1] );
4418 } else {
4419 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "minpd",
4420 0x66, insn[0], insn[1] );
4421 }
4422 goto decode_success;
4423 }
4424
sewardj2db567e2003-06-18 00:22:01 +00004425 /* 0xF3: MAXSD */
4426 /* 0xF3: MAXSS */
4427 if ((insn[0] == 0xF2 || insn[0] == 0xF3)
4428 && insn[1] == 0x0F && insn[2] == 0x5F) {
4429 Bool sz8 = insn[0] == 0xF2;
4430 vg_assert(sz == 4);
4431 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, sz8 ? 8 : 4,
4432 sz8 ? "maxsd" : "maxss",
4433 insn[0], insn[1], insn[2] );
4434 goto decode_success;
4435 }
4436
4437 /* MAXPS */
4438 /* 0x66: MAXPD */
4439 if (insn[0] == 0x0F && insn[1] == 0x5F) {
4440 vg_assert(sz == 4 || sz == 2);
4441 if (sz == 4) {
4442 eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "maxps",
4443 insn[0], insn[1] );
4444 } else {
4445 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "maxpd",
4446 0x66, insn[0], insn[1] );
4447 }
4448 goto decode_success;
4449 }
4450
4451 /* RCPPS -- reciprocal of packed floats */
4452 if (insn[0] == 0x0F && insn[1] == 0x53) {
4453 vg_assert(sz == 4);
4454 eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "rcpps",
4455 insn[0], insn[1] );
4456 goto decode_success;
4457 }
4458
4459 /* XORPS */
4460 /* 0x66: XORPD (src)xmmreg-or-mem, (dst)xmmreg */
4461 if (insn[0] == 0x0F && insn[1] == 0x57) {
4462 vg_assert(sz == 4 || sz == 2);
4463 if (sz == 4) {
4464 eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "xorps",
4465 insn[0], insn[1] );
4466 } else {
4467 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "xorpd",
4468 0x66, insn[0], insn[1] );
4469 }
sewardje3891fa2003-06-15 03:13:48 +00004470 goto decode_success;
4471 }
4472
sewardj9dd209f2003-06-18 23:30:52 +00004473 /* ANDPS */
4474 /* 0x66: ANDPD (src)xmmreg-or-mem, (dst)xmmreg */
4475 if (insn[0] == 0x0F && insn[1] == 0x54) {
4476 vg_assert(sz == 4 || sz == 2);
4477 if (sz == 4) {
4478 eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "andps",
4479 insn[0], insn[1] );
4480 } else {
4481 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "andpd",
4482 0x66, insn[0], insn[1] );
4483 }
sewardj095c3bc2003-06-15 23:26:04 +00004484 goto decode_success;
4485 }
4486
nethercoteb1affa82004-01-19 19:14:18 +00004487 /* ORPS */
4488 /* 0x66: ORPD (src)xmmreg-or-mem, (dst)xmmreg */
4489 if (insn[0] == 0x0F && insn[1] == 0x56) {
4490 vg_assert(sz == 4 || sz == 2);
4491 if (sz == 4) {
4492 eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "orps",
4493 insn[0], insn[1] );
4494 } else {
sewardj095c3bc2003-06-15 23:26:04 +00004495 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "orpd",
4496 0x66, insn[0], insn[1] );
nethercoteb1affa82004-01-19 19:14:18 +00004497 }
sewardj095c3bc2003-06-15 23:26:04 +00004498 goto decode_success;
4499 }
4500
sewardjde8aecf2003-05-27 00:46:28 +00004501 /* PXOR (src)xmmreg-or-mem, (dst)xmmreg */
4502 if (sz == 2
4503 && insn[0] == 0x0F && insn[1] == 0xEF) {
4504 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pxor",
4505 0x66, insn[0], insn[1] );
4506 goto decode_success;
4507 }
4508
sewardja453fb02003-06-14 13:22:36 +00004509 /* PAND (src)xmmreg-or-mem, (dst)xmmreg */
4510 if (sz == 2
4511 && insn[0] == 0x0F && insn[1] == 0xDB) {
4512 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pand",
4513 0x66, insn[0], insn[1] );
4514 goto decode_success;
4515 }
4516
sewardjbc148f22003-06-15 11:46:30 +00004517 /* PANDN (src)xmmreg-or-mem, (dst)xmmreg */
4518 if (sz == 2
4519 && insn[0] == 0x0F && insn[1] == 0xDF) {
4520 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pandn",
4521 0x66, insn[0], insn[1] );
4522 goto decode_success;
4523 }
4524
sewardja453fb02003-06-14 13:22:36 +00004525 /* POR (src)xmmreg-or-mem, (dst)xmmreg */
4526 if (sz == 2
4527 && insn[0] == 0x0F && insn[1] == 0xEB) {
4528 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "por",
4529 0x66, insn[0], insn[1] );
4530 goto decode_success;
4531 }
4532
sewardjbc148f22003-06-15 11:46:30 +00004533 /* 0xDA: PMINUB(src)xmmreg-or-mem, (dst)xmmreg */
4534 /* 0xEA: PMINSW(src)xmmreg-or-mem, (dst)xmmreg */
sewardj35a17792003-06-01 18:49:12 +00004535 if (sz == 2
sewardja453fb02003-06-14 13:22:36 +00004536 && insn[0] == 0x0F
sewardjbc148f22003-06-15 11:46:30 +00004537 && (insn[1] == 0xDA || insn[1] == 0xEA)) {
4538 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmin{ub,sw}",
4539 0x66, insn[0], insn[1] );
4540 goto decode_success;
4541 }
4542
4543 /* 0xDE: PMAXUB(src)xmmreg-or-mem, (dst)xmmreg */
4544 /* 0xEE: PMAXSW(src)xmmreg-or-mem, (dst)xmmreg */
4545 if (sz == 2
4546 && insn[0] == 0x0F
4547 && (insn[1] == 0xDE || insn[1] == 0xEE)) {
4548 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmax{ub,sw}",
4549 0x66, insn[0], insn[1] );
4550 goto decode_success;
4551 }
4552
4553 /* 0xE0: PAVGB(src)xmmreg-or-mem, (dst)xmmreg */
4554 /* 0xE3: PAVGW(src)xmmreg-or-mem, (dst)xmmreg */
4555 if (sz == 2
4556 && insn[0] == 0x0F
4557 && (insn[1] == 0xE0 || insn[1] == 0xE3)) {
4558 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pavg{b,w}",
4559 0x66, insn[0], insn[1] );
4560 goto decode_success;
4561 }
nethercoteb1affa82004-01-19 19:14:18 +00004562
4563 /* 0xF6: PSADBW(src)xmmreg-or-mem, (dst)xmmreg */
4564 if (sz == 2
4565 && insn[0] == 0x0F && insn[1] == 0xF6) {
4566 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psadbw",
4567 0x66, insn[0], insn[1] );
daywalker5d945de2003-09-26 00:32:53 +00004568 goto decode_success;
4569 }
4570
sewardjbc148f22003-06-15 11:46:30 +00004571 /* 0x60: PUNPCKLBW (src)xmmreg-or-mem, (dst)xmmreg */
4572 /* 0x61: PUNPCKLWD (src)xmmreg-or-mem, (dst)xmmreg */
4573 /* 0x62: PUNPCKLDQ (src)xmmreg-or-mem, (dst)xmmreg */
nethercoteb1affa82004-01-19 19:14:18 +00004574 /* 0x6C: PUNPCKQLQDQ (src)xmmreg-or-mem, (dst)xmmreg */
sewardjbc148f22003-06-15 11:46:30 +00004575 if (sz == 2
4576 && insn[0] == 0x0F
nethercoteb1affa82004-01-19 19:14:18 +00004577 && (insn[1] == 0x60 || insn[1] == 0x61
4578 || insn[1] == 0x62 || insn[1] == 0x6C)) {
sewardja453fb02003-06-14 13:22:36 +00004579 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16,
nethercoteb1affa82004-01-19 19:14:18 +00004580 "punpckl{bw,wd,dq,qdq}",
sewardj35a17792003-06-01 18:49:12 +00004581 0x66, insn[0], insn[1] );
4582 goto decode_success;
4583 }
4584
sewardjbc148f22003-06-15 11:46:30 +00004585 /* 0x68: PUNPCKHBW (src)xmmreg-or-mem, (dst)xmmreg */
4586 /* 0x69: PUNPCKHWD (src)xmmreg-or-mem, (dst)xmmreg */
4587 /* 0x6A: PUNPCKHDQ (src)xmmreg-or-mem, (dst)xmmreg */
nethercoteb1affa82004-01-19 19:14:18 +00004588 /* 0x6D: PUNPCKHQDQ (src)xmmreg-or-mem, (dst)xmmreg */
sewardj35a17792003-06-01 18:49:12 +00004589 if (sz == 2
sewardjea691a12003-06-14 12:05:29 +00004590 && insn[0] == 0x0F
nethercoteb1affa82004-01-19 19:14:18 +00004591 && (insn[1] == 0x68 || insn[1] == 0x69
4592 || insn[1] == 0x6A || insn[1] == 0x6D)) {
sewardjbc148f22003-06-15 11:46:30 +00004593 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16,
nethercoteb1affa82004-01-19 19:14:18 +00004594 "punpckh{bw,wd,dq,qdq}",
sewardjbc148f22003-06-15 11:46:30 +00004595 0x66, insn[0], insn[1] );
4596 goto decode_success;
4597 }
4598
sewardj632b8a12003-10-19 18:26:36 +00004599 /* 0x14: UNPCKLPD (src)xmmreg-or-mem, (dst)xmmreg. Reads a+0
4600 .. a+7, so we can say size 8 */
4601 /* 0x15: UNPCKHPD (src)xmmreg-or-mem, (dst)xmmreg. Reads a+8
4602 .. a+15, but we have no way to express this, so better say size
4603 16. Sigh. */
sewardj095c3bc2003-06-15 23:26:04 +00004604 if (sz == 2
4605 && insn[0] == 0x0F
4606 && (insn[1] == 0x14 || insn[1] == 0x15)) {
sewardj632b8a12003-10-19 18:26:36 +00004607 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2,
4608 insn[1]==0x14 ? 8 : 16,
sewardj095c3bc2003-06-15 23:26:04 +00004609 "unpck{l,h}pd",
4610 0x66, insn[0], insn[1] );
4611 goto decode_success;
4612 }
4613
sewardj632b8a12003-10-19 18:26:36 +00004614 /* 0x14: UNPCKLPS (src)xmmreg-or-mem, (dst)xmmreg Reads a+0
4615 .. a+7, so we can say size 8 */
4616 /* 0x15: UNPCKHPS (src)xmmreg-or-mem, (dst)xmmreg Reads a+8
4617 .. a+15, but we have no way to express this, so better say size
4618 16. Sigh. */
4619 if (sz == 4
4620 && insn[0] == 0x0F
4621 && (insn[1] == 0x14 || insn[1] == 0x15)) {
4622 eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2,
4623 insn[1]==0x14 ? 8 : 16,
4624 "unpck{l,h}ps",
4625 insn[0], insn[1] );
4626 goto decode_success;
4627 }
4628
sewardjbc148f22003-06-15 11:46:30 +00004629 /* 0xFC: PADDB (src)xmmreg-or-mem, (dst)xmmreg */
4630 /* 0xFD: PADDW (src)xmmreg-or-mem, (dst)xmmreg */
4631 /* 0xFE: PADDD (src)xmmreg-or-mem, (dst)xmmreg */
4632 /* 0xD4: PADDQ (src)xmmreg-or-mem, (dst)xmmreg */
4633 if (sz == 2
4634 && insn[0] == 0x0F
4635 && (insn[1] == 0xFC || insn[1] == 0xFD
4636 || insn[1] == 0xFE || insn[1] == 0xD4)) {
4637 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "padd{b,w,d,q}",
4638 0x66, insn[0], insn[1] );
4639 goto decode_success;
4640 }
4641
4642 /* 0xEC: PADDSB (src)xmmreg-or-mem, (dst)xmmreg */
4643 /* 0xED: PADDSW (src)xmmreg-or-mem, (dst)xmmreg */
4644 if (sz == 2
4645 && insn[0] == 0x0F
4646 && (insn[1] == 0xEC || insn[1] == 0xED)) {
4647 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "padds{b,w}",
4648 0x66, insn[0], insn[1] );
4649 goto decode_success;
4650 }
4651
4652 /* 0xDC: PADDUSB (src)xmmreg-or-mem, (dst)xmmreg */
4653 /* 0xDD: PADDUSW (src)xmmreg-or-mem, (dst)xmmreg */
4654 if (sz == 2
4655 && insn[0] == 0x0F
4656 && (insn[1] == 0xDC || insn[1] == 0xDD)) {
4657 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "paddus{b,w}",
4658 0x66, insn[0], insn[1] );
4659 goto decode_success;
4660 }
4661
4662 /* 0xF8: PSUBB (src)xmmreg-or-mem, (dst)xmmreg */
4663 /* 0xF9: PSUBW (src)xmmreg-or-mem, (dst)xmmreg */
4664 /* 0xFA: PSUBD (src)xmmreg-or-mem, (dst)xmmreg */
4665 /* 0xFB: PSUBQ (src)xmmreg-or-mem, (dst)xmmreg */
4666 if (sz == 2
4667 && insn[0] == 0x0F
4668 && (insn[1] == 0xF8 || insn[1] == 0xF9
4669 || insn[1] == 0xFA || insn[1] == 0xFB)) {
4670 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psub{b,w,d,q}",
4671 0x66, insn[0], insn[1] );
4672 goto decode_success;
4673 }
4674
4675 /* 0xE8: PSUBSB (src)xmmreg-or-mem, (dst)xmmreg */
4676 /* 0xE9: PSUBSW (src)xmmreg-or-mem, (dst)xmmreg */
4677 if (sz == 2
4678 && insn[0] == 0x0F
4679 && (insn[1] == 0xE8 || insn[1] == 0xE9)) {
4680 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psubs{b,w}",
4681 0x66, insn[0], insn[1] );
4682 goto decode_success;
4683 }
4684
4685 /* 0xD8: PSUBUSB (src)xmmreg-or-mem, (dst)xmmreg */
4686 /* 0xD9: PSUBUSW (src)xmmreg-or-mem, (dst)xmmreg */
4687 if (sz == 2
4688 && insn[0] == 0x0F
4689 && (insn[1] == 0xD8 || insn[1] == 0xD9)) {
4690 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psubus{b,w}",
4691 0x66, insn[0], insn[1] );
4692 goto decode_success;
4693 }
4694
nethercoteb1affa82004-01-19 19:14:18 +00004695 /* 0xE4: PMULHUW(src)xmmreg-or-mem, (dst)xmmreg */
sewardjbc148f22003-06-15 11:46:30 +00004696 /* 0xE5: PMULHW(src)xmmreg-or-mem, (dst)xmmreg */
4697 /* 0xD5: PMULLW(src)xmmreg-or-mem, (dst)xmmreg */
4698 if (sz == 2
4699 && insn[0] == 0x0F
nethercoteb1affa82004-01-19 19:14:18 +00004700 && (insn[1] == 0xE4 || insn[1] == 0xE5 || insn[1] == 0xD5)) {
4701 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmul{hu,h,l}w",
4702 0x66, insn[0], insn[1] );
4703 goto decode_success;
4704 }
4705
4706 /* 0xD5: PMULUDQ(src)xmmreg-or-mem, (dst)xmmreg */
4707 if (sz == 2
4708 && insn[0] == 0x0F && insn[1] == 0xF4) {
4709 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmuludq",
sewardjbc148f22003-06-15 11:46:30 +00004710 0x66, insn[0], insn[1] );
4711 goto decode_success;
4712 }
4713
4714 /* 0xF5: PMADDWD(src)xmmreg-or-mem, (dst)xmmreg */
4715 if (sz == 2
4716 && insn[0] == 0x0F
4717 && insn[1] == 0xF5) {
4718 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pmaddwd",
4719 0x66, insn[0], insn[1] );
4720 goto decode_success;
4721 }
4722
4723 /* 0x74: PCMPEQB (src)xmmreg-or-mem, (dst)xmmreg */
4724 /* 0x75: PCMPEQW (src)xmmreg-or-mem, (dst)xmmreg */
4725 /* 0x76: PCMPEQD (src)xmmreg-or-mem, (dst)xmmreg */
4726 if (sz == 2
4727 && insn[0] == 0x0F
4728 && (insn[1] == 0x74 || insn[1] == 0x75 || insn[1] == 0x76)) {
4729 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pcmpeq{b,w,d}",
4730 0x66, insn[0], insn[1] );
4731 goto decode_success;
4732 }
4733
4734 /* 0x64: PCMPGTB (src)xmmreg-or-mem, (dst)xmmreg */
4735 /* 0x65: PCMPGTW (src)xmmreg-or-mem, (dst)xmmreg */
4736 /* 0x66: PCMPGTD (src)xmmreg-or-mem, (dst)xmmreg */
4737 if (sz == 2
4738 && insn[0] == 0x0F
4739 && (insn[1] == 0x64 || insn[1] == 0x65 || insn[1] == 0x66)) {
4740 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "pcmpgt{b,w,d}",
4741 0x66, insn[0], insn[1] );
4742 goto decode_success;
4743 }
4744
4745 /* 0x63: PACKSSWB (src)xmmreg-or-mem, (dst)xmmreg */
4746 /* 0x6B: PACKSSDW (src)xmmreg-or-mem, (dst)xmmreg */
4747 if (sz == 2
4748 && insn[0] == 0x0F
4749 && (insn[1] == 0x63 || insn[1] == 0x6B)) {
4750 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "packss{wb,dw}",
4751 0x66, insn[0], insn[1] );
4752 goto decode_success;
4753 }
4754
4755 /* 0x67: PACKUSWB (src)xmmreg-or-mem, (dst)xmmreg */
4756 if (sz == 2
4757 && insn[0] == 0x0F
4758 && insn[1] == 0x67) {
4759 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "packuswb",
4760 0x66, insn[0], insn[1] );
4761 goto decode_success;
4762 }
4763
4764 /* 0xF1: PSLLW (src)xmmreg-or-mem, (dst)xmmreg */
4765 /* 0xF2: PSLLD (src)xmmreg-or-mem, (dst)xmmreg */
4766 /* 0xF3: PSLLQ (src)xmmreg-or-mem, (dst)xmmreg */
4767 if (sz == 2
4768 && insn[0] == 0x0F
4769 && (insn[1] == 0xF1 || insn[1] == 0xF2 || insn[1] == 0xF3)) {
4770 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psll{b,w,d}",
4771 0x66, insn[0], insn[1] );
4772 goto decode_success;
4773 }
4774
4775 /* 0xD1: PSRLW (src)xmmreg-or-mem, (dst)xmmreg */
4776 /* 0xD2: PSRLD (src)xmmreg-or-mem, (dst)xmmreg */
4777 /* 0xD3: PSRLQ (src)xmmreg-or-mem, (dst)xmmreg */
4778 if (sz == 2
4779 && insn[0] == 0x0F
4780 && (insn[1] == 0xD1 || insn[1] == 0xD2 || insn[1] == 0xD3)) {
4781 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psrl{b,w,d}",
4782 0x66, insn[0], insn[1] );
4783 goto decode_success;
4784 }
4785
4786 /* 0xE1: PSRAW (src)xmmreg-or-mem, (dst)xmmreg */
4787 /* 0xE2: PSRAD (src)xmmreg-or-mem, (dst)xmmreg */
4788 if (sz == 2
4789 && insn[0] == 0x0F
4790 && (insn[1] == 0xE1 || insn[1] == 0xE2)) {
4791 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "psra{w,d}",
sewardj35a17792003-06-01 18:49:12 +00004792 0x66, insn[0], insn[1] );
4793 goto decode_success;
4794 }
4795
daywalkerb270ea52003-10-18 17:04:24 +00004796 /* (U)COMISD (src)xmmreg-or-mem, (dst)xmmreg */
sewardj02af6bc2003-06-12 00:56:06 +00004797 if (sz == 2
daywalkerb270ea52003-10-18 17:04:24 +00004798 && insn[0] == 0x0F
4799 && ( insn[1] == 0x2E || insn[1] == 0x2F ) ) {
4800 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 8, "{u}comisd",
sewardj02af6bc2003-06-12 00:56:06 +00004801 0x66, insn[0], insn[1] );
4802 vg_assert(LAST_UINSTR(cb).opcode == SSE3a_MemRd
4803 || LAST_UINSTR(cb).opcode == SSE4);
sewardj1e86b8b2003-06-16 23:34:12 +00004804 uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
4805 goto decode_success;
4806 }
4807
daywalker5d945de2003-09-26 00:32:53 +00004808 /* (U)COMISS (src)xmmreg-or-mem, (dst)xmmreg */
sewardj1e86b8b2003-06-16 23:34:12 +00004809 if (sz == 4
daywalker5d945de2003-09-26 00:32:53 +00004810 && insn[0] == 0x0F
4811 && ( insn[1] == 0x2E || insn[ 1 ] == 0x2F )) {
4812 eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 4, "{u}comiss",
sewardj1e86b8b2003-06-16 23:34:12 +00004813 insn[0], insn[1] );
4814 vg_assert(LAST_UINSTR(cb).opcode == SSE2a_MemRd
4815 || LAST_UINSTR(cb).opcode == SSE3);
4816 uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
sewardj02af6bc2003-06-12 00:56:06 +00004817 goto decode_success;
4818 }
4819
sewardjde8aecf2003-05-27 00:46:28 +00004820 /* MOVSD -- move 8 bytes of XMM reg to/from XMM reg or mem. */
4821 if (insn[0] == 0xF2
4822 && insn[1] == 0x0F
4823 && (insn[2] == 0x11 || insn[2] == 0x10)) {
4824 vg_assert(sz == 4);
4825 eip = dis_SSE3_load_store_or_mov
4826 ( cb, sorb, eip+3, 8, insn[2]==0x11, "movsd",
4827 insn[0], insn[1], insn[2] );
4828 goto decode_success;
4829 }
4830
sewardj6bc40552003-06-15 01:40:58 +00004831 /* MOVQ -- move 8 bytes of XMM reg to XMM reg or mem. How
sewardjde8aecf2003-05-27 00:46:28 +00004832 does this differ from MOVSD ?? */
4833 if (sz == 2
4834 && insn[0] == 0x0F
4835 && insn[1] == 0xD6) {
4836 eip = dis_SSE3_load_store_or_mov
sewardj6bc40552003-06-15 01:40:58 +00004837 ( cb, sorb, eip+2, 8, True /*store*/, "movq",
sewardjde8aecf2003-05-27 00:46:28 +00004838 0x66, insn[0], insn[1] );
sewardja60be0e2003-05-26 08:47:27 +00004839 goto decode_success;
4840 }
4841
sewardj8988f932003-09-30 00:12:54 +00004842 /* MOVQ -- move 8 bytes of XMM reg or mem to XMM reg. How
4843 does this differ from MOVSD ?? */
4844 if (insn[0] == 0xF3
4845 && insn[1] == 0x0F
4846 && insn[2] == 0x7E) {
4847 eip = dis_SSE3_load_store_or_mov
4848 ( cb, sorb, eip+3, 8, False /*load*/, "movq",
4849 insn[0], insn[1], insn[2] );
4850 goto decode_success;
4851 }
4852
nethercoteb1affa82004-01-19 19:14:18 +00004853 /* MOVDQ2Q -- move low 4 bytes of XMM reg to MMX reg. */
4854 if (insn[0] == 0xF2
4855 && insn[1] == 0x0F
4856 && insn[2] == 0xD6) {
4857 eip = dis_SSE3_to_MMX
4858 ( cb, sorb, eip+3, 8, "movdq2q",
4859 insn[0], insn[1], insn[2] );
4860 goto decode_success;
4861 }
4862
4863 /* MOVQ2DQ -- move MMX reg to low 4 bytes of XMM reg. */
4864 if (insn[0] == 0xF3
4865 && insn[1] == 0x0F
4866 && insn[2] == 0xD6) {
4867 eip = dis_SSE3_from_MMX
4868 ( cb, sorb, eip+3, 8, "movq2dq",
4869 insn[0], insn[1], insn[2] );
4870 goto decode_success;
4871 }
4872
sewardja60be0e2003-05-26 08:47:27 +00004873 /* MOVSS -- move 4 bytes of XMM reg to/from XMM reg or mem. */
sewardjde8aecf2003-05-27 00:46:28 +00004874 if (insn[0] == 0xF3
4875 && insn[1] == 0x0F
4876 && (insn[2] == 0x11 || insn[2] == 0x10)) {
sewardja60be0e2003-05-26 08:47:27 +00004877 vg_assert(sz == 4);
sewardjde8aecf2003-05-27 00:46:28 +00004878 eip = dis_SSE3_load_store_or_mov
4879 ( cb, sorb, eip+3, 4, insn[2]==0x11, "movss",
4880 insn[0], insn[1], insn[2] );
sewardja60be0e2003-05-26 08:47:27 +00004881 goto decode_success;
4882 }
4883
sewardja453fb02003-06-14 13:22:36 +00004884 /* I don't understand how MOVAPD differs from MOVAPS. */
4885 /* MOVAPD (28,29) -- aligned load/store of xmm reg, or xmm-xmm reg
sewardjde8aecf2003-05-27 00:46:28 +00004886 move */
sewardja453fb02003-06-14 13:22:36 +00004887 if (sz == 2
4888 && insn[0] == 0x0F && insn[1] == 0x28) {
4889 UChar* name = "movapd";
4890 //(insn[1] == 0x10 || insn[1] == 0x11)
4891 // ? "movups" : "movaps";
jseward24168682004-07-20 23:49:22 +00004892 Bool store = False; //insn[1] == 0x29 || insn[1] == 0x11;
sewardja453fb02003-06-14 13:22:36 +00004893 eip = dis_SSE3_load_store_or_mov
4894 ( cb, sorb, eip+2, 16, store, name,
4895 0x66, insn[0], insn[1] );
4896 goto decode_success;
4897 }
4898
sewardj77d30a22003-10-19 08:18:52 +00004899 /* sz==4: MOVAPS (28,29) -- aligned load/store of xmm reg, or
4900 xmm-xmm reg move */
4901 /* sz==4: MOVUPS (10,11) -- unaligned load/store of xmm reg, or
4902 xmm-xmm reg move */
4903 /* sz==2: MOVAPD (28,29) -- aligned load/store of xmm reg, or
4904 xmm-xmm reg move */
4905 /* sz==2: MOVUPD (10,11) -- unaligned load/store of xmm reg, or
4906 xmm-xmm reg move */
sewardja60be0e2003-05-26 08:47:27 +00004907 if (insn[0] == 0x0F && (insn[1] == 0x28
4908 || insn[1] == 0x29
4909 || insn[1] == 0x10
4910 || insn[1] == 0x11)) {
sewardjde8aecf2003-05-27 00:46:28 +00004911 UChar* name = (insn[1] == 0x10 || insn[1] == 0x11)
4912 ? "movups" : "movaps";
jseward24168682004-07-20 23:49:22 +00004913 Bool store = insn[1] == 0x29 || insn[1] == 0x11;
sewardj77d30a22003-10-19 08:18:52 +00004914 vg_assert(sz == 2 || sz == 4);
4915 if (sz == 4) {
4916 eip = dis_SSE2_load_store_or_mov
4917 ( cb, sorb, eip+2, 16, store, name,
4918 insn[0], insn[1] );
4919 } else {
4920 eip = dis_SSE3_load_store_or_mov
4921 ( cb, sorb, eip+2, 16, store, name,
4922 0x66, insn[0], insn[1] );
4923 }
sewardjde8aecf2003-05-27 00:46:28 +00004924 goto decode_success;
4925 }
4926
4927 /* MOVDQA -- aligned 16-byte load/store. */
4928 if (sz == 2
4929 && insn[0] == 0x0F
4930 && (insn[1] == 0x6F || insn[1] == 0x7F)) {
4931 Bool is_store = insn[1]==0x7F;
4932 eip = dis_SSE3_load_store_or_mov
4933 (cb, sorb, eip+2, 16, is_store, "movdqa",
4934 0x66, insn[0], insn[1] );
4935 goto decode_success;
4936 }
4937
sewardjbc148f22003-06-15 11:46:30 +00004938 /* MOVDQU -- unaligned 16-byte load/store. */
4939 if (insn[0] == 0xF3
4940 && insn[1] == 0x0F
4941 && (insn[2] == 0x6F || insn[2] == 0x7F)) {
4942 Bool is_store = insn[2]==0x7F;
4943 eip = dis_SSE3_load_store_or_mov
4944 (cb, sorb, eip+3, 16, is_store, "movdqu",
4945 insn[0], insn[1], insn[2] );
4946 goto decode_success;
4947 }
4948
sewardjbb6ac7c2003-10-17 21:50:30 +00004949 /* MOVNTDQ -- 16-byte store with temporal hint (which we
4950 ignore). */
4951 if (sz == 2
4952 && insn[0] == 0x0F
4953 && insn[1] == 0xE7) {
4954 eip = dis_SSE3_load_store_or_mov
4955 (cb, sorb, eip+2, 16, True /* is_store */, "movntdq",
4956 0x66, insn[0], insn[1] );
4957 goto decode_success;
4958 }
4959
mueller97da4762004-01-02 22:50:04 +00004960 /* MOVNTPS -- 16-byte store with temporal hint (which we
4961 ignore). */
4962 if (insn[0] == 0x0F
4963 && insn[1] == 0x2B) {
4964 eip = dis_SSE2_load_store_or_mov
4965 (cb, sorb, eip+2, 16, True /* is_store */, "movntps",
4966 insn[0], insn[1] );
4967 goto decode_success;
4968 }
4969
4970 /* MOVNTPD -- 16-byte store with temporal hint (which we
4971 ignore). */
4972 if (sz == 2
4973 && insn[0] == 0x0F
4974 && insn[1] == 0x2B) {
4975 eip = dis_SSE3_load_store_or_mov
4976 (cb, sorb, eip+2, 16, True /* is_store */, "movntpd",
4977 0x66, insn[0], insn[1] );
4978 goto decode_success;
4979 }
4980
sewardj6bc40552003-06-15 01:40:58 +00004981 /* MOVD -- 4-byte move between xmmregs and (ireg or memory). */
sewardjde8aecf2003-05-27 00:46:28 +00004982 if (sz == 2
4983 && insn[0] == 0x0F
4984 && (insn[1] == 0x6E || insn[1] == 0x7E)) {
4985 Bool is_store = insn[1]==0x7E;
sewardj6bc40552003-06-15 01:40:58 +00004986 modrm = insn[2];
4987 if (epartIsReg(modrm) && is_store) {
sewardjabf8bf82003-06-15 22:28:05 +00004988 t1 = newTemp(cb);
4989 uInstr3(cb, SSE3e_RegWr, 4,
4990 Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
4991 Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
4992 TempReg, t1 );
4993 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, eregOfRM(modrm));
nethercotee8601122004-01-26 17:14:17 +00004994 DIP("movd %s, %s\n",
4995 nameXMMReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
sewardj1e86b8b2003-06-16 23:34:12 +00004996 eip += 3;
sewardj6bc40552003-06-15 01:40:58 +00004997 } else
4998 if (epartIsReg(modrm) && !is_store) {
4999 t1 = newTemp(cb);
5000 uInstr2(cb, GET, 4, ArchReg, eregOfRM(modrm), TempReg, t1);
sewardj4fbe6e92003-06-15 21:54:34 +00005001 uInstr3(cb, SSE3e_RegRd, 4,
sewardj6bc40552003-06-15 01:40:58 +00005002 Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
5003 Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
5004 TempReg, t1 );
nethercotee8601122004-01-26 17:14:17 +00005005 DIP("movd %s, %s\n",
5006 nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm)));
sewardj1e86b8b2003-06-16 23:34:12 +00005007 eip += 3;
sewardj6bc40552003-06-15 01:40:58 +00005008 } else {
5009 eip = dis_SSE3_load_store_or_mov
5010 (cb, sorb, eip+2, 4, is_store, "movd",
5011 0x66, insn[0], insn[1] );
5012 }
sewardja60be0e2003-05-26 08:47:27 +00005013 goto decode_success;
sewardjfebaa3b2003-05-25 01:07:34 +00005014 }
5015
sewardjb31b06d2003-06-13 00:26:02 +00005016 /* PEXTRW from SSE register; writes ireg */
5017 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC5) {
5018 t1 = newTemp(cb);
5019 modrm = insn[2];
5020 vg_assert(epartIsReg(modrm));
5021 vg_assert((modrm & 0xC0) == 0xC0);
5022 uInstr3(cb, SSE3g1_RegWr, 4,
5023 Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
5024 Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
5025 TempReg, t1 );
5026 uLiteral(cb, insn[3]);
5027 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
nethercotee8601122004-01-26 17:14:17 +00005028 DIP("pextrw %s, %d, %s\n",
5029 nameXMMReg(eregOfRM(modrm)), (Int)insn[3],
5030 nameIReg(4, gregOfRM(modrm)));
sewardjb31b06d2003-06-13 00:26:02 +00005031 eip += 4;
5032 goto decode_success;
5033 }
5034
5035 /* PINSRW to SSE register; reads mem or ireg */
5036 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC4) {
5037 t1 = newTemp(cb);
5038 modrm = insn[2];
5039 if (epartIsReg(modrm)) {
5040 uInstr2(cb, GET, 2, ArchReg, eregOfRM(modrm), TempReg, t1);
sewardj6bc40552003-06-15 01:40:58 +00005041 vg_assert(epartIsReg(modrm));
sewardj4fbe6e92003-06-15 21:54:34 +00005042 uInstr3(cb, SSE3e1_RegRd, 2,
sewardjb31b06d2003-06-13 00:26:02 +00005043 Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
5044 Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
5045 TempReg, t1 );
5046 uLiteral(cb, insn[3]);
nethercotee8601122004-01-26 17:14:17 +00005047 DIP("pinsrw %s, %d, %s\n",
5048 nameIReg(2, eregOfRM(modrm)), (Int)insn[3],
5049 nameXMMReg(gregOfRM(modrm)));
sewardjb31b06d2003-06-13 00:26:02 +00005050 eip += 4;
5051 } else {
5052 VG_(core_panic)("PINSRW mem");
5053 }
5054 goto decode_success;
5055 }
5056
sewardj77d30a22003-10-19 08:18:52 +00005057 /* SQRTSD: square root of scalar double. */
5058 if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x51) {
5059 vg_assert(sz == 4);
5060 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 8,
5061 "sqrtsd",
5062 insn[0], insn[1], insn[2] );
5063 goto decode_success;
5064 }
5065
sewardje3436492003-10-19 22:08:20 +00005066 /* SQRTSS: square root of scalar float. */
5067 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x51) {
5068 vg_assert(sz == 4);
5069 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4,
5070 "sqrtss",
5071 insn[0], insn[1], insn[2] );
5072 goto decode_success;
5073 }
5074
mueller33dbc122004-01-07 19:07:02 +00005075 /* RSQRTSS: square root reciprocal of scalar float. */
5076 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x52) {
5077 vg_assert(sz == 4);
5078 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4,
5079 "sqrtss",
5080 insn[0], insn[1], insn[2] );
5081 goto decode_success;
5082 }
5083
sewardj77d30a22003-10-19 08:18:52 +00005084 /* 0xF3: RCPSS -- reciprocal of scalar float */
5085 if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x53) {
5086 vg_assert(sz == 4);
5087 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+3, 4,
5088 "rcpss",
5089 insn[0], insn[1], insn[2] );
5090 goto decode_success;
5091 }
5092
5093 /* MOVMSKPD -- extract 2 sign bits from a xmm reg and copy them to
5094 an ireg. Top 30 bits of ireg are set to zero. */
nethercoteb1affa82004-01-19 19:14:18 +00005095 /* MOVMSKPS -- extract 4 sign bits from a xmm reg and copy them to
5096 an ireg. Top 28 bits of ireg are set to zero. */
5097 if (insn[0] == 0x0F && insn[1] == 0x50) {
5098 vg_assert(sz == 4 || sz == 2);
sewardj77d30a22003-10-19 08:18:52 +00005099 modrm = insn[2];
5100 /* Intel docs don't say anything about a memory source being
5101 allowed here. */
5102 vg_assert(epartIsReg(modrm));
5103 t1 = newTemp(cb);
nethercoteb1affa82004-01-19 19:14:18 +00005104 if (sz == 4) {
5105 uInstr3(cb, SSE2g_RegWr, 4,
5106 Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
5107 Lit16, (UShort)modrm,
5108 TempReg, t1 );
5109 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
5110 } else {
5111 uInstr3(cb, SSE3g_RegWr, 4,
5112 Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
5113 Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
5114 TempReg, t1 );
5115 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
5116 }
nethercotee8601122004-01-26 17:14:17 +00005117 DIP("movmskp%c %s, %s\n", sz == 4 ? 's' : 'd',
5118 nameXMMReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)));
sewardj77d30a22003-10-19 08:18:52 +00005119 eip += 3;
5120 goto decode_success;
5121 }
5122
5123 /* ANDNPS */
5124 /* 0x66: ANDNPD (src)xmmreg-or-mem, (dst)xmmreg */
5125 if (insn[0] == 0x0F && insn[1] == 0x55) {
5126 vg_assert(sz == 4 || sz == 2);
5127 if (sz == 4) {
5128 eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "andnps",
5129 insn[0], insn[1] );
5130 } else {
5131 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16, "andnpd",
5132 0x66, insn[0], insn[1] );
5133 }
5134 goto decode_success;
5135 }
5136
nethercoteb1affa82004-01-19 19:14:18 +00005137 /* MOVHLPS -- move two packed floats from high quadword to low quadword */
5138 /* MOVLPS -- load/store two packed floats to/from low quadword. */
5139 /* MOVLPD -- load/store packed double to/from low quadword. */
5140 if (insn[0] == 0x0F
5141 && (insn[1] == 0x12 || insn[1] == 0x13)) {
5142 Bool is_store = insn[1]==0x13;
5143 vg_assert(sz == 4 || sz == 2);
5144 if (sz == 4) {
5145 if (epartIsReg(insn[2])) {
5146 vg_assert(insn[1]==0x12);
5147 eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "movhlps",
5148 insn[0], insn[1] );
5149 } else {
5150 eip = dis_SSE2_load_store_or_mov
5151 (cb, sorb, eip+2, 8, is_store, "movlps",
5152 insn[0], insn[1] );
5153 }
5154 } else {
5155 vg_assert(!epartIsReg(insn[2]));
5156 eip = dis_SSE3_load_store_or_mov
5157 (cb, sorb, eip+2, 8, is_store, "movlpd",
5158 0x66, insn[0], insn[1] );
5159 }
5160 goto decode_success;
5161 }
5162
5163 /* MOVLHPS -- move two packed floats from low quadword to high quadword */
5164 /* MOVHPS -- load/store two packed floats to/from high quadword. */
5165 /* MOVHPD -- load/store packed double to/from high quadword. */
5166 if (insn[0] == 0x0F
sewardj77d30a22003-10-19 08:18:52 +00005167 && (insn[1] == 0x16 || insn[1] == 0x17)) {
5168 Bool is_store = insn[1]==0x17;
nethercoteb1affa82004-01-19 19:14:18 +00005169 vg_assert(sz == 4 || sz == 2);
5170 if (sz == 4) {
5171 if (epartIsReg(insn[2])) {
5172 vg_assert(insn[1]==0x16);
5173 eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16, "movlhps",
5174 insn[0], insn[1] );
5175 } else {
5176 eip = dis_SSE2_load_store_or_mov
5177 (cb, sorb, eip+2, 8, is_store, "movhps",
5178 insn[0], insn[1] );
5179 }
5180 } else {
sewardj77d30a22003-10-19 08:18:52 +00005181 vg_assert(!epartIsReg(insn[2]));
5182 eip = dis_SSE3_load_store_or_mov
5183 (cb, sorb, eip+2, 8, is_store, "movhpd",
5184 0x66, insn[0], insn[1] );
nethercoteb1affa82004-01-19 19:14:18 +00005185 }
sewardj77d30a22003-10-19 08:18:52 +00005186 goto decode_success;
5187 }
5188
5189 /* PMOVMSKB -- extract 16 sign bits from a xmm reg and copy them to
5190 an ireg. Top 16 bits of ireg are set to zero. */
5191 if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD7) {
5192 modrm = insn[2];
5193 /* Intel docs don't say anything about a memory source being
5194 allowed here. */
5195 vg_assert(epartIsReg(modrm));
5196 t1 = newTemp(cb);
5197 uInstr3(cb, SSE3g_RegWr, 4,
5198 Lit16, (((UShort)0x66) << 8) | (UShort)insn[0],
5199 Lit16, (((UShort)insn[1]) << 8) | (UShort)modrm,
5200 TempReg, t1 );
5201 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
nethercotee8601122004-01-26 17:14:17 +00005202 DIP("pmovmskb %s, %s\n",
5203 nameXMMReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)));
sewardj77d30a22003-10-19 08:18:52 +00005204 eip += 3;
5205 goto decode_success;
5206 }
5207
nethercoteb1affa82004-01-19 19:14:18 +00005208 /* sz==4: SQRTPS: square root of packed float. */
5209 /* sz==2: SQRTPD: square root of packed double. */
5210 if (insn[0] == 0x0F && insn[1] == 0x51) {
5211 vg_assert(sz == 2 || sz == 4);
5212 if (sz == 4) {
5213 eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16,
5214 "sqrtps",
5215 insn[0], insn[1] );
5216 } else {
5217 eip = dis_SSE3_reg_or_mem ( cb, sorb, eip+2, 16,
5218 "sqrtpd",
muelleraa5fd3c2003-11-19 17:00:58 +00005219 0x66, insn[0], insn[1] );
nethercoteb1affa82004-01-19 19:14:18 +00005220 }
muelleraa5fd3c2003-11-19 17:00:58 +00005221 goto decode_success;
5222 }
5223
nethercoteb1affa82004-01-19 19:14:18 +00005224 /* RSQRTPS: square root reciprocal of packed float. */
5225 if (insn[0] == 0x0F && insn[1] == 0x52) {
5226 vg_assert(sz == 4);
5227 eip = dis_SSE2_reg_or_mem ( cb, sorb, eip+2, 16,
5228 "rsqrtps",
5229 insn[0], insn[1] );
sewardj77d30a22003-10-19 08:18:52 +00005230 goto decode_success;
5231 }
5232
sewardjfebaa3b2003-05-25 01:07:34 +00005233 /* Fall through into the non-SSE decoder. */
5234
5235 } /* if (VG_(have_ssestate)) */
5236
5237
5238 /* ---------------------------------------------------- */
5239 /* --- end of the SSE/SSE2 decoder. --- */
5240 /* ---------------------------------------------------- */
5241
5242 /* Get the primary opcode. */
sewardjde4a1d02002-03-22 01:27:54 +00005243 opc = getUChar(eip); eip++;
5244
sewardjfebaa3b2003-05-25 01:07:34 +00005245 /* We get here if the current insn isn't SSE, or this CPU doesn't
5246 support SSE. */
5247
sewardjde4a1d02002-03-22 01:27:54 +00005248 switch (opc) {
5249
5250 /* ------------------------ Control flow --------------- */
5251
5252 case 0xC2: /* RET imm16 */
5253 d32 = getUDisp16(eip); eip += 2;
nethercotebd126912004-02-22 16:56:28 +00005254 dis_ret(cb, d32);
sewardjde4a1d02002-03-22 01:27:54 +00005255 *isEnd = True;
nethercotebd126912004-02-22 16:56:28 +00005256 DIP("ret %d\n", d32);
5257 break;
5258 case 0xC3: /* RET */
5259 dis_ret(cb, 0);
5260 *isEnd = True;
5261 DIP("ret\n");
sewardjde4a1d02002-03-22 01:27:54 +00005262 break;
5263
5264 case 0xE8: /* CALL J4 */
5265 d32 = getUDisp32(eip); eip += 4;
5266 d32 += eip; /* eip now holds return-to addr, d32 is call-to addr */
sewardjde4a1d02002-03-22 01:27:54 +00005267 if (d32 == eip && getUChar(eip) >= 0x58
5268 && getUChar(eip) <= 0x5F) {
5269 /* Specially treat the position-independent-code idiom
5270 call X
5271 X: popl %reg
5272 as
5273 movl %eip, %reg.
5274 since this generates better code, but for no other reason. */
5275 Int archReg = getUChar(eip) - 0x58;
5276 /* VG_(printf)("-- fPIC thingy\n"); */
5277 t1 = newTemp(cb);
5278 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
5279 uLiteral(cb, eip);
5280 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, archReg);
5281 eip++; /* Step over the POP */
nethercotee8601122004-01-26 17:14:17 +00005282 DIP("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
sewardjde4a1d02002-03-22 01:27:54 +00005283 } else {
5284 /* The normal sequence for a call. */
5285 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
5286 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
5287 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t1);
5288 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t1);
5289 uLiteral(cb, 4);
5290 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
5291 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
5292 uLiteral(cb, eip);
5293 uInstr2(cb, STORE, 4, TempReg, t2, TempReg, t1);
nethercotee8601122004-01-26 17:14:17 +00005294 jmp_lit(cb, d32);
sewardj2e93c502002-04-12 11:12:52 +00005295 LAST_UINSTR(cb).jmpkind = JmpCall;
sewardjde4a1d02002-03-22 01:27:54 +00005296 *isEnd = True;
nethercotee8601122004-01-26 17:14:17 +00005297 DIP("call 0x%x\n",d32);
sewardjde4a1d02002-03-22 01:27:54 +00005298 }
5299 break;
5300
daywalker5d945de2003-09-26 00:32:53 +00005301 case 0xC8: /* ENTER */
5302 d32 = getUDisp16(eip); eip += 2;
5303 abyte = getUChar(eip); eip++;
5304
5305 vg_assert(sz == 4);
5306 vg_assert(abyte == 0);
5307
5308 t1 = newTemp(cb); t2 = newTemp(cb);
5309 uInstr2(cb, GET, sz, ArchReg, R_EBP, TempReg, t1);
5310 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
5311 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
5312 uLiteral(cb, sz);
5313 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
5314 uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
5315 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
5316 if (d32) {
5317 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
5318 uLiteral(cb, d32);
5319 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
5320 }
nethercotee8601122004-01-26 17:14:17 +00005321 DIP("enter 0x%x, 0x%x", d32, abyte);
daywalker5d945de2003-09-26 00:32:53 +00005322 break;
5323
sewardjde4a1d02002-03-22 01:27:54 +00005324 case 0xC9: /* LEAVE */
5325 t1 = newTemp(cb); t2 = newTemp(cb);
5326 uInstr2(cb, GET, 4, ArchReg, R_EBP, TempReg, t1);
njn8399f6a2003-10-13 07:30:40 +00005327 /* First PUT ESP looks redundant, but need it because ESP must
5328 always be up-to-date for Memcheck to work... */
sewardjde4a1d02002-03-22 01:27:54 +00005329 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
5330 uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t2);
5331 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
5332 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1);
5333 uLiteral(cb, 4);
5334 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
nethercotee8601122004-01-26 17:14:17 +00005335 DIP("leave");
sewardjde4a1d02002-03-22 01:27:54 +00005336 break;
5337
daywalker7e73e5f2003-07-04 16:18:15 +00005338 /* ---------------- Misc weird-ass insns --------------- */
sewardj4d0ab1f2002-03-24 10:00:09 +00005339
sewardjfe8a1662002-03-24 11:54:07 +00005340 case 0x27: /* DAA */
sewardj4d0ab1f2002-03-24 10:00:09 +00005341 case 0x2F: /* DAS */
5342 t1 = newTemp(cb);
5343 uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
5344 /* Widen %AL to 32 bits, so it's all defined when we push it. */
5345 uInstr1(cb, WIDEN, 4, TempReg, t1);
nethercote911cc372004-04-18 12:23:02 +00005346 uWiden(cb, 1, False);
sewardj4d0ab1f2002-03-24 10:00:09 +00005347 uInstr0(cb, CALLM_S, 0);
5348 uInstr1(cb, PUSH, 4, TempReg, t1);
sewardjfe8a1662002-03-24 11:54:07 +00005349 uInstr1(cb, CALLM, 0, Lit16,
5350 opc == 0x27 ? VGOFF_(helper_DAA) : VGOFF_(helper_DAS) );
nethercote1018bdd2004-02-11 23:33:29 +00005351 uFlagsRWU(cb, FlagsAC, FlagsSZACP, FlagO);
sewardj4d0ab1f2002-03-24 10:00:09 +00005352 uInstr1(cb, POP, 4, TempReg, t1);
5353 uInstr0(cb, CALLM_E, 0);
5354 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
nethercotee8601122004-01-26 17:14:17 +00005355 DIP(opc == 0x27 ? "daa\n" : "das\n");
sewardjfe8a1662002-03-24 11:54:07 +00005356 break;
sewardj4d0ab1f2002-03-24 10:00:09 +00005357
nethercote1018bdd2004-02-11 23:33:29 +00005358 case 0x37: /* AAA */
5359 case 0x3F: /* AAS */
5360 t1 = newTemp(cb);
5361 uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
5362 /* Widen %AL to 32 bits, so it's all defined when we push it. */
5363 uInstr1(cb, WIDEN, 4, TempReg, t1);
nethercote911cc372004-04-18 12:23:02 +00005364 uWiden(cb, 2, False);
nethercote1018bdd2004-02-11 23:33:29 +00005365 uInstr0(cb, CALLM_S, 0);
5366 uInstr1(cb, PUSH, 4, TempReg, t1);
5367 uInstr1(cb, CALLM, 0, Lit16,
5368 opc == 0x37 ? VGOFF_(helper_AAA) : VGOFF_(helper_AAS) );
5369 uFlagsRWU(cb, FlagA, FlagsAC, FlagsEmpty);
5370 uInstr1(cb, POP, 4, TempReg, t1);
5371 uInstr0(cb, CALLM_E, 0);
5372 uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
5373 DIP(opc == 0x37 ? "aaa\n" : "aas\n");
5374 break;
5375
5376 case 0xD4: /* AAM */
5377 case 0xD5: /* AAD */
5378 d32 = getUChar(eip); eip++;
5379 if (d32 != 10) VG_(core_panic)("disInstr: AAM/AAD but base not 10 !");
5380 t1 = newTemp(cb);
5381 uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
5382 /* Widen %AX to 32 bits, so it's all defined when we push it. */
5383 uInstr1(cb, WIDEN, 4, TempReg, t1);
nethercote911cc372004-04-18 12:23:02 +00005384 uWiden(cb, 2, False);
nethercote1018bdd2004-02-11 23:33:29 +00005385 uInstr0(cb, CALLM_S, 0);
5386 uInstr1(cb, PUSH, 4, TempReg, t1);
5387 uInstr1(cb, CALLM, 0, Lit16,
5388 opc == 0xD4 ? VGOFF_(helper_AAM) : VGOFF_(helper_AAD) );
5389 uFlagsRWU(cb, FlagsEmpty, FlagsSZP, FlagsEmpty);
5390 uInstr1(cb, POP, 4, TempReg, t1);
5391 uInstr0(cb, CALLM_E, 0);
5392 uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
5393 DIP(opc == 0xD4 ? "aam\n" : "aad\n");
5394 break;
5395
sewardjde4a1d02002-03-22 01:27:54 +00005396 /* ------------------------ CWD/CDQ -------------------- */
5397
5398 case 0x98: /* CBW */
5399 t1 = newTemp(cb);
5400 if (sz == 4) {
5401 uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
5402 uInstr1(cb, WIDEN, 4, TempReg, t1); /* 4 == dst size */
nethercote911cc372004-04-18 12:23:02 +00005403 uWiden(cb, 2, True);
sewardjde4a1d02002-03-22 01:27:54 +00005404 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
nethercotee8601122004-01-26 17:14:17 +00005405 DIP("cwd\n");
sewardjde4a1d02002-03-22 01:27:54 +00005406 } else {
5407 vg_assert(sz == 2);
5408 uInstr2(cb, GET, 1, ArchReg, R_EAX, TempReg, t1);
5409 uInstr1(cb, WIDEN, 2, TempReg, t1); /* 2 == dst size */
nethercote911cc372004-04-18 12:23:02 +00005410 uWiden(cb, 1, True);
sewardjde4a1d02002-03-22 01:27:54 +00005411 uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
nethercotee8601122004-01-26 17:14:17 +00005412 DIP("cbw\n");
sewardjde4a1d02002-03-22 01:27:54 +00005413 }
5414 break;
5415
5416 case 0x99: /* CWD/CDQ */
5417 t1 = newTemp(cb);
5418 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
5419 uInstr2(cb, SAR, sz, Literal, 0, TempReg, t1);
5420 uLiteral(cb, sz == 2 ? 15 : 31);
5421 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EDX);
nethercotee8601122004-01-26 17:14:17 +00005422 DIP(sz == 2 ? "cwdq\n" : "cdqq\n");
sewardjde4a1d02002-03-22 01:27:54 +00005423 break;
5424
5425 /* ------------------------ FPU ops -------------------- */
5426
5427 case 0x9E: /* SAHF */
5428 codegen_SAHF ( cb );
nethercotee8601122004-01-26 17:14:17 +00005429 DIP("sahf\n");
sewardjde4a1d02002-03-22 01:27:54 +00005430 break;
5431
njnd6251f12003-06-03 13:38:51 +00005432 case 0x9F: /* LAHF */
5433 codegen_LAHF ( cb );
nethercotee8601122004-01-26 17:14:17 +00005434 DIP("lahf\n");
njnd6251f12003-06-03 13:38:51 +00005435 break;
5436
sewardjde4a1d02002-03-22 01:27:54 +00005437 case 0x9B: /* FWAIT */
5438 /* ignore? */
nethercotee8601122004-01-26 17:14:17 +00005439 DIP("fwait\n");
sewardjde4a1d02002-03-22 01:27:54 +00005440 break;
5441
5442 case 0xD8:
5443 case 0xD9:
5444 case 0xDA:
5445 case 0xDB:
5446 case 0xDC:
5447 case 0xDD:
5448 case 0xDE:
5449 case 0xDF:
sewardje1042472002-09-30 12:33:11 +00005450 eip = dis_fpu ( cb, sorb, opc, eip );
sewardjde4a1d02002-03-22 01:27:54 +00005451 break;
5452
5453 /* ------------------------ INC & DEC ------------------ */
5454
5455 case 0x40: /* INC eAX */
5456 case 0x41: /* INC eCX */
5457 case 0x42: /* INC eDX */
5458 case 0x43: /* INC eBX */
daywalker79aad842003-09-30 22:58:12 +00005459 case 0x44: /* INC eSP */
sewardjde4a1d02002-03-22 01:27:54 +00005460 case 0x45: /* INC eBP */
5461 case 0x46: /* INC eSI */
5462 case 0x47: /* INC eDI */
5463 t1 = newTemp(cb);
5464 uInstr2(cb, GET, sz, ArchReg, (UInt)(opc - 0x40),
5465 TempReg, t1);
5466 uInstr1(cb, INC, sz, TempReg, t1);
5467 setFlagsFromUOpcode(cb, INC);
5468 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg,
5469 (UInt)(opc - 0x40));
nethercotee8601122004-01-26 17:14:17 +00005470 DIP("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
sewardjde4a1d02002-03-22 01:27:54 +00005471 break;
5472
5473 case 0x48: /* DEC eAX */
5474 case 0x49: /* DEC eCX */
5475 case 0x4A: /* DEC eDX */
5476 case 0x4B: /* DEC eBX */
daywalker79aad842003-09-30 22:58:12 +00005477 case 0x4C: /* DEC eSP */
sewardjde4a1d02002-03-22 01:27:54 +00005478 case 0x4D: /* DEC eBP */
5479 case 0x4E: /* DEC eSI */
5480 case 0x4F: /* DEC eDI */
5481 t1 = newTemp(cb);
5482 uInstr2(cb, GET, sz, ArchReg, (UInt)(opc - 0x48),
5483 TempReg, t1);
5484 uInstr1(cb, DEC, sz, TempReg, t1);
5485 setFlagsFromUOpcode(cb, DEC);
5486 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg,
5487 (UInt)(opc - 0x48));
nethercotee8601122004-01-26 17:14:17 +00005488 DIP("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
sewardjde4a1d02002-03-22 01:27:54 +00005489 break;
5490
5491 /* ------------------------ INT ------------------------ */
5492
5493 case 0xCD: /* INT imm8 */
5494 d32 = getUChar(eip); eip++;
thughes91e082b2004-03-06 12:53:24 +00005495 if (d32 != 0x80) goto decode_failure;
sewardjde4a1d02002-03-22 01:27:54 +00005496 /* It's important that all ArchRegs carry their up-to-date value
5497 at this point. So we declare an end-of-block here, which
5498 forces any TempRegs caching ArchRegs to be flushed. */
nethercotee8601122004-01-26 17:14:17 +00005499 jmp_lit(cb, eip);
sewardj2e93c502002-04-12 11:12:52 +00005500 LAST_UINSTR(cb).jmpkind = JmpSyscall;
sewardjde4a1d02002-03-22 01:27:54 +00005501 *isEnd = True;
nethercotee8601122004-01-26 17:14:17 +00005502 DIP("int $0x80\n");
sewardjde4a1d02002-03-22 01:27:54 +00005503 break;
5504
5505 /* ------------------------ Jcond, byte offset --------- */
5506
5507 case 0xEB: /* Jb (jump, byte offset) */
5508 d32 = (eip+1) + getSDisp8(eip); eip++;
nethercotee8601122004-01-26 17:14:17 +00005509 jmp_lit(cb, d32);
sewardjde4a1d02002-03-22 01:27:54 +00005510 *isEnd = True;
nethercotee8601122004-01-26 17:14:17 +00005511 DIP("jmp-8 0x%x\n", d32);
sewardjde4a1d02002-03-22 01:27:54 +00005512 break;
5513
5514 case 0xE9: /* Jv (jump, 16/32 offset) */
5515 d32 = (eip+sz) + getSDisp(sz,eip); eip += sz;
nethercotee8601122004-01-26 17:14:17 +00005516 jmp_lit(cb, d32);
sewardjde4a1d02002-03-22 01:27:54 +00005517 *isEnd = True;
nethercotee8601122004-01-26 17:14:17 +00005518 DIP("jmp 0x%x\n", d32);
sewardjde4a1d02002-03-22 01:27:54 +00005519 break;
5520
5521 case 0x70:
5522 case 0x71:
5523 case 0x72: /* JBb/JNAEb (jump below) */
5524 case 0x73: /* JNBb/JAEb (jump not below) */
5525 case 0x74: /* JZb/JEb (jump zero) */
5526 case 0x75: /* JNZb/JNEb (jump not zero) */
5527 case 0x76: /* JBEb/JNAb (jump below or equal) */
5528 case 0x77: /* JNBEb/JAb (jump not below or equal) */
5529 case 0x78: /* JSb (jump negative) */
5530 case 0x79: /* JSb (jump not negative) */
5531 case 0x7A: /* JP (jump parity even) */
5532 case 0x7B: /* JNP/JPO (jump parity odd) */
5533 case 0x7C: /* JLb/JNGEb (jump less) */
5534 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
5535 case 0x7E: /* JLEb/JNGb (jump less or equal) */
5536 case 0x7F: /* JGb/JNLEb (jump greater) */
5537 d32 = (eip+1) + getSDisp8(eip); eip++;
nethercotee8601122004-01-26 17:14:17 +00005538 jcc_lit(cb, d32, (Condcode)(opc - 0x70));
sewardjde4a1d02002-03-22 01:27:54 +00005539 /* It's actually acceptable not to end this basic block at a
5540 control transfer, reducing the number of jumps through
5541 vg_dispatch, at the expense of possibly translating the insns
5542 following this jump twice. This does give faster code, but
5543 on the whole I don't think the effort is worth it. */
nethercotee8601122004-01-26 17:14:17 +00005544 jmp_lit(cb, eip);
sewardjde4a1d02002-03-22 01:27:54 +00005545 *isEnd = True;
5546 /* The above 3 lines would be removed if the bb was not to end
5547 here. */
nethercotee8601122004-01-26 17:14:17 +00005548 DIP("j%s-8 0x%x\n", VG_(name_UCondcode)(opc - 0x70), d32);
sewardjde4a1d02002-03-22 01:27:54 +00005549 break;
5550
5551 case 0xE3: /* JECXZ or perhaps JCXZ, depending on OSO ? Intel
5552 manual says it depends on address size override,
5553 which doesn't sound right to me. */
5554 d32 = (eip+1) + getSDisp8(eip); eip++;
5555 t1 = newTemp(cb);
5556 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
5557 uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
5558 uLiteral(cb, d32);
nethercotee8601122004-01-26 17:14:17 +00005559 DIP("j%sz 0x%x\n", nameIReg(sz, R_ECX), d32);
sewardjde4a1d02002-03-22 01:27:54 +00005560 break;
5561
nethercotee33453f2003-11-27 16:15:17 +00005562 case 0xE0: /* LOOPNE disp8 */
5563 case 0xE1: /* LOOPE disp8 */
5564 case 0xE2: /* LOOP disp8 */
sewardjde4a1d02002-03-22 01:27:54 +00005565 /* Again, the docs say this uses ECX/CX as a count depending on
5566 the address size override, not the operand one. Since we
5567 don't handle address size overrides, I guess that means
5568 ECX. */
5569 d32 = (eip+1) + getSDisp8(eip); eip++;
5570 t1 = newTemp(cb);
5571 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
5572 uInstr1(cb, DEC, 4, TempReg, t1);
5573 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ECX);
5574 uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
5575 uLiteral(cb, eip);
nethercotecf539de2003-11-28 09:44:21 +00005576 if (opc == 0xE0 || opc == 0xE1) { /* LOOPE/LOOPNE */
nethercotee8601122004-01-26 17:14:17 +00005577 jcc_lit(cb, eip, (opc == 0xE1 ? CondNZ : CondZ));
nethercotee33453f2003-11-27 16:15:17 +00005578 }
nethercotee8601122004-01-26 17:14:17 +00005579 jmp_lit(cb, d32);
sewardjde4a1d02002-03-22 01:27:54 +00005580 *isEnd = True;
nethercotee8601122004-01-26 17:14:17 +00005581 DIP("loop 0x%x\n", d32);
sewardjde4a1d02002-03-22 01:27:54 +00005582 break;
5583
5584 /* ------------------------ IMUL ----------------------- */
5585
5586 case 0x69: /* IMUL Iv, Ev, Gv */
sewardje1042472002-09-30 12:33:11 +00005587 eip = dis_imul_I_E_G ( cb, sorb, sz, eip, sz );
sewardjde4a1d02002-03-22 01:27:54 +00005588 break;
5589 case 0x6B: /* IMUL Ib, Ev, Gv */
sewardje1042472002-09-30 12:33:11 +00005590 eip = dis_imul_I_E_G ( cb, sorb, sz, eip, 1 );
sewardjde4a1d02002-03-22 01:27:54 +00005591 break;
5592
5593 /* ------------------------ MOV ------------------------ */
5594
5595 case 0x88: /* MOV Gb,Eb */
sewardje1042472002-09-30 12:33:11 +00005596 eip = dis_mov_G_E(cb, sorb, 1, eip);
sewardjde4a1d02002-03-22 01:27:54 +00005597 break;
5598
5599 case 0x89: /* MOV Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00005600 eip = dis_mov_G_E(cb, sorb, sz, eip);
sewardjde4a1d02002-03-22 01:27:54 +00005601 break;
5602
5603 case 0x8A: /* MOV Eb,Gb */
sewardje1042472002-09-30 12:33:11 +00005604 eip = dis_mov_E_G(cb, sorb, 1, eip);
sewardjde4a1d02002-03-22 01:27:54 +00005605 break;
5606
5607 case 0x8B: /* MOV Ev,Gv */
sewardje1042472002-09-30 12:33:11 +00005608 eip = dis_mov_E_G(cb, sorb, sz, eip);
sewardjde4a1d02002-03-22 01:27:54 +00005609 break;
5610
5611 case 0x8D: /* LEA M,Gv */
5612 modrm = getUChar(eip);
5613 if (epartIsReg(modrm))
njne427a662002-10-02 11:08:25 +00005614 VG_(core_panic)("LEA M,Gv: modRM refers to register");
sewardje1042472002-09-30 12:33:11 +00005615 /* NOTE! this is the one place where a segment override prefix
5616 has no effect on the address calculation. Therefore we pass
5617 zero instead of sorb here. */
nethercotee8601122004-01-26 17:14:17 +00005618 pair = disAMode ( cb, /*sorb*/ 0, eip, dis_buf );
sewardjde4a1d02002-03-22 01:27:54 +00005619 eip += HI8(pair);
5620 t1 = LOW24(pair);
5621 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, gregOfRM(modrm));
nethercotee8601122004-01-26 17:14:17 +00005622 DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
5623 nameIReg(sz,gregOfRM(modrm)));
sewardjde4a1d02002-03-22 01:27:54 +00005624 break;
5625
sewardjd077f532002-09-30 21:52:50 +00005626 case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
5627 eip = dis_mov_Sw_Ew(cb, sorb, eip);
5628 break;
5629
sewardje1042472002-09-30 12:33:11 +00005630 case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
5631 eip = dis_mov_Ew_Sw(cb, sorb, eip);
5632 break;
5633
sewardjde4a1d02002-03-22 01:27:54 +00005634 case 0xA0: /* MOV Ob,AL */
5635 sz = 1;
5636 /* Fall through ... */
5637 case 0xA1: /* MOV Ov,eAX */
5638 d32 = getUDisp32(eip); eip += 4;
5639 t1 = newTemp(cb); t2 = newTemp(cb);
5640 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
5641 uLiteral(cb, d32);
sewardjbe4015a2002-10-03 16:14:57 +00005642 handleSegOverride(cb, sorb, t2);
sewardjde4a1d02002-03-22 01:27:54 +00005643 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
5644 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EAX);
nethercotee8601122004-01-26 17:14:17 +00005645 DIP("mov%c %s0x%x, %s\n", nameISize(sz), sorbTxt(sorb),
5646 d32, nameIReg(sz,R_EAX));
sewardjde4a1d02002-03-22 01:27:54 +00005647 break;
5648
5649 case 0xA2: /* MOV AL,Ob */
5650 sz = 1;
5651 /* Fall through ... */
5652 case 0xA3: /* MOV eAX,Ov */
5653 d32 = getUDisp32(eip); eip += 4;
5654 t1 = newTemp(cb); t2 = newTemp(cb);
5655 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
5656 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
5657 uLiteral(cb, d32);
sewardjbe4015a2002-10-03 16:14:57 +00005658 handleSegOverride(cb, sorb, t2);
sewardjde4a1d02002-03-22 01:27:54 +00005659 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
nethercotee8601122004-01-26 17:14:17 +00005660 DIP("mov%c %s, %s0x%x\n", nameISize(sz), nameIReg(sz,R_EAX),
5661 sorbTxt(sorb), d32);
sewardjde4a1d02002-03-22 01:27:54 +00005662 break;
5663
5664 case 0xB0: /* MOV imm,AL */
5665 case 0xB1: /* MOV imm,CL */
5666 case 0xB2: /* MOV imm,DL */
5667 case 0xB3: /* MOV imm,BL */
5668 case 0xB4: /* MOV imm,AH */
5669 case 0xB5: /* MOV imm,CH */
5670 case 0xB6: /* MOV imm,DH */
5671 case 0xB7: /* MOV imm,BH */
5672 d32 = getUChar(eip); eip += 1;
5673 t1 = newTemp(cb);
5674 uInstr2(cb, MOV, 1, Literal, 0, TempReg, t1);
5675 uLiteral(cb, d32);
5676 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, opc-0xB0);
nethercotee8601122004-01-26 17:14:17 +00005677 DIP("movb $0x%x,%s\n", d32, nameIReg(1,opc-0xB0));
sewardjde4a1d02002-03-22 01:27:54 +00005678 break;
5679
5680 case 0xB8: /* MOV imm,eAX */
5681 case 0xB9: /* MOV imm,eCX */
5682 case 0xBA: /* MOV imm,eDX */
5683 case 0xBB: /* MOV imm,eBX */
njn7443bb52003-09-26 09:11:51 +00005684 case 0xBC: /* MOV imm,eSP */
sewardjde4a1d02002-03-22 01:27:54 +00005685 case 0xBD: /* MOV imm,eBP */
5686 case 0xBE: /* MOV imm,eSI */
5687 case 0xBF: /* MOV imm,eDI */
5688 d32 = getUDisp(sz,eip); eip += sz;
5689 t1 = newTemp(cb);
5690 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t1);
5691 uLiteral(cb, d32);
5692 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, opc-0xB8);
nethercotee8601122004-01-26 17:14:17 +00005693 DIP("mov%c $0x%x,%s\n", nameISize(sz), d32, nameIReg(sz,opc-0xB8));
sewardjde4a1d02002-03-22 01:27:54 +00005694 break;
5695
5696 case 0xC6: /* MOV Ib,Eb */
5697 sz = 1;
5698 goto do_Mov_I_E;
5699 case 0xC7: /* MOV Iv,Ev */
5700 goto do_Mov_I_E;
5701
5702 do_Mov_I_E:
5703 modrm = getUChar(eip);
5704 if (epartIsReg(modrm)) {
sewardj48987df2002-12-16 00:10:30 +00005705 eip++; /* mod/rm byte */
sewardjde4a1d02002-03-22 01:27:54 +00005706 d32 = getUDisp(sz,eip); eip += sz;
5707 t1 = newTemp(cb);
5708 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t1);
5709 uLiteral(cb, d32);
5710 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
nethercotee8601122004-01-26 17:14:17 +00005711 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32,
5712 nameIReg(sz,eregOfRM(modrm)));
sewardjde4a1d02002-03-22 01:27:54 +00005713 } else {
nethercotee8601122004-01-26 17:14:17 +00005714 pair = disAMode ( cb, sorb, eip, dis_buf );
sewardjde4a1d02002-03-22 01:27:54 +00005715 eip += HI8(pair);
5716 d32 = getUDisp(sz,eip); eip += sz;
5717 t1 = newTemp(cb);
5718 t2 = LOW24(pair);
5719 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t1);
5720 uLiteral(cb, d32);
5721 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
nethercotee8601122004-01-26 17:14:17 +00005722 DIP("mov%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
sewardjde4a1d02002-03-22 01:27:54 +00005723 }
5724 break;
5725
5726 /* ------------------------ opl imm, A ----------------- */
5727
5728 case 0x04: /* ADD Ib, AL */
5729 eip = dis_op_imm_A(cb, 1, ADD, True, eip, "add" );
5730 break;
5731 case 0x05: /* ADD Iv, eAX */
5732 eip = dis_op_imm_A(cb, sz, ADD, True, eip, "add" );
5733 break;
5734
5735 case 0x0C: /* OR Ib, AL */
5736 eip = dis_op_imm_A(cb, 1, OR, True, eip, "or" );
5737 break;
5738 case 0x0D: /* OR Iv, eAX */
5739 eip = dis_op_imm_A(cb, sz, OR, True, eip, "or" );
5740 break;
5741
sewardj279236e2002-12-16 00:14:02 +00005742 case 0x14: /* ADC Ib, AL */
5743 eip = dis_op_imm_A(cb, 1, ADC, True, eip, "adc" );
5744 break;
njn25e49d8e72002-09-23 09:36:25 +00005745 case 0x15: /* ADC Iv, eAX */
5746 eip = dis_op_imm_A(cb, sz, ADC, True, eip, "adc" );
5747 break;
5748
sewardje9c06f12002-05-08 01:44:03 +00005749 case 0x1C: /* SBB Ib, AL */
5750 eip = dis_op_imm_A(cb, 1, SBB, True, eip, "sbb" );
5751 break;
nethercote1018bdd2004-02-11 23:33:29 +00005752 case 0x1D: /* SBB Iv, eAX */
5753 eip = dis_op_imm_A(cb, sz, SBB, True, eip, "sbb" );
5754 break;
sewardje9c06f12002-05-08 01:44:03 +00005755
sewardjde4a1d02002-03-22 01:27:54 +00005756 case 0x24: /* AND Ib, AL */
5757 eip = dis_op_imm_A(cb, 1, AND, True, eip, "and" );
5758 break;
5759 case 0x25: /* AND Iv, eAX */
5760 eip = dis_op_imm_A(cb, sz, AND, True, eip, "and" );
5761 break;
5762
5763 case 0x2C: /* SUB Ib, AL */
5764 eip = dis_op_imm_A(cb, 1, SUB, True, eip, "sub" );
5765 break;
5766 case 0x2D: /* SUB Iv, eAX */
5767 eip = dis_op_imm_A(cb, sz, SUB, True, eip, "sub" );
5768 break;
5769
5770 case 0x34: /* XOR Ib, AL */
5771 eip = dis_op_imm_A(cb, 1, XOR, True, eip, "xor" );
5772 break;
5773 case 0x35: /* XOR Iv, eAX */
5774 eip = dis_op_imm_A(cb, sz, XOR, True, eip, "xor" );
5775 break;
5776
5777 case 0x3C: /* CMP Ib, AL */
5778 eip = dis_op_imm_A(cb, 1, SUB, False, eip, "cmp" );
5779 break;
5780 case 0x3D: /* CMP Iv, eAX */
5781 eip = dis_op_imm_A(cb, sz, SUB, False, eip, "cmp" );
5782 break;
5783
5784 case 0xA8: /* TEST Ib, AL */
5785 eip = dis_op_imm_A(cb, 1, AND, False, eip, "test" );
5786 break;
5787 case 0xA9: /* TEST Iv, eAX */
5788 eip = dis_op_imm_A(cb, sz, AND, False, eip, "test" );
5789 break;
5790
5791 /* ------------------------ opl Ev, Gv ----------------- */
5792
5793 case 0x02: /* ADD Eb,Gb */
sewardje1042472002-09-30 12:33:11 +00005794 eip = dis_op2_E_G ( cb, sorb, ADD, True, 1, eip, "add" );
sewardjde4a1d02002-03-22 01:27:54 +00005795 break;
5796 case 0x03: /* ADD Ev,Gv */
sewardje1042472002-09-30 12:33:11 +00005797 eip = dis_op2_E_G ( cb, sorb, ADD, True, sz, eip, "add" );
sewardjde4a1d02002-03-22 01:27:54 +00005798 break;
5799
5800 case 0x0A: /* OR Eb,Gb */
sewardje1042472002-09-30 12:33:11 +00005801 eip = dis_op2_E_G ( cb, sorb, OR, True, 1, eip, "or" );
sewardjde4a1d02002-03-22 01:27:54 +00005802 break;
5803 case 0x0B: /* OR Ev,Gv */
sewardje1042472002-09-30 12:33:11 +00005804 eip = dis_op2_E_G ( cb, sorb, OR, True, sz, eip, "or" );
sewardjde4a1d02002-03-22 01:27:54 +00005805 break;
5806
sewardja4b87f62002-05-29 23:38:23 +00005807 case 0x12: /* ADC Eb,Gb */
sewardje1042472002-09-30 12:33:11 +00005808 eip = dis_op2_E_G ( cb, sorb, ADC, True, 1, eip, "adc" );
sewardja4b87f62002-05-29 23:38:23 +00005809 break;
sewardjde4a1d02002-03-22 01:27:54 +00005810 case 0x13: /* ADC Ev,Gv */
sewardje1042472002-09-30 12:33:11 +00005811 eip = dis_op2_E_G ( cb, sorb, ADC, True, sz, eip, "adc" );
sewardjde4a1d02002-03-22 01:27:54 +00005812 break;
5813
sewardj6d12f912002-10-16 19:40:04 +00005814 case 0x1A: /* SBB Eb,Gb */
5815 eip = dis_op2_E_G ( cb, sorb, SBB, True, 1, eip, "sbb" );
5816 break;
sewardjde4a1d02002-03-22 01:27:54 +00005817 case 0x1B: /* SBB Ev,Gv */
sewardje1042472002-09-30 12:33:11 +00005818 eip = dis_op2_E_G ( cb, sorb, SBB, True, sz, eip, "sbb" );
sewardjde4a1d02002-03-22 01:27:54 +00005819 break;
5820
5821 case 0x22: /* AND Eb,Gb */
sewardje1042472002-09-30 12:33:11 +00005822 eip = dis_op2_E_G ( cb, sorb, AND, True, 1, eip, "and" );
sewardjde4a1d02002-03-22 01:27:54 +00005823 break;
5824 case 0x23: /* AND Ev,Gv */
sewardje1042472002-09-30 12:33:11 +00005825 eip = dis_op2_E_G ( cb, sorb, AND, True, sz, eip, "and" );
sewardjde4a1d02002-03-22 01:27:54 +00005826 break;
5827
5828 case 0x2A: /* SUB Eb,Gb */
sewardje1042472002-09-30 12:33:11 +00005829 eip = dis_op2_E_G ( cb, sorb, SUB, True, 1, eip, "sub" );
sewardjde4a1d02002-03-22 01:27:54 +00005830 break;
5831 case 0x2B: /* SUB Ev,Gv */
sewardje1042472002-09-30 12:33:11 +00005832 eip = dis_op2_E_G ( cb, sorb, SUB, True, sz, eip, "sub" );
sewardjde4a1d02002-03-22 01:27:54 +00005833 break;
5834
5835 case 0x32: /* XOR Eb,Gb */
sewardje1042472002-09-30 12:33:11 +00005836 eip = dis_op2_E_G ( cb, sorb, XOR, True, 1, eip, "xor" );
sewardjde4a1d02002-03-22 01:27:54 +00005837 break;
5838 case 0x33: /* XOR Ev,Gv */
sewardje1042472002-09-30 12:33:11 +00005839 eip = dis_op2_E_G ( cb, sorb, XOR, True, sz, eip, "xor" );
sewardjde4a1d02002-03-22 01:27:54 +00005840 break;
5841
5842 case 0x3A: /* CMP Eb,Gb */
sewardje1042472002-09-30 12:33:11 +00005843 eip = dis_op2_E_G ( cb, sorb, SUB, False, 1, eip, "cmp" );
sewardjde4a1d02002-03-22 01:27:54 +00005844 break;
5845 case 0x3B: /* CMP Ev,Gv */
sewardje1042472002-09-30 12:33:11 +00005846 eip = dis_op2_E_G ( cb, sorb, SUB, False, sz, eip, "cmp" );
sewardjde4a1d02002-03-22 01:27:54 +00005847 break;
5848
5849 case 0x84: /* TEST Eb,Gb */
sewardje1042472002-09-30 12:33:11 +00005850 eip = dis_op2_E_G ( cb, sorb, AND, False, 1, eip, "test" );
sewardjde4a1d02002-03-22 01:27:54 +00005851 break;
5852 case 0x85: /* TEST Ev,Gv */
sewardje1042472002-09-30 12:33:11 +00005853 eip = dis_op2_E_G ( cb, sorb, AND, False, sz, eip, "test" );
sewardjde4a1d02002-03-22 01:27:54 +00005854 break;
5855
5856 /* ------------------------ opl Gv, Ev ----------------- */
5857
5858 case 0x00: /* ADD Gb,Eb */
sewardje1042472002-09-30 12:33:11 +00005859 eip = dis_op2_G_E ( cb, sorb, ADD, True, 1, eip, "add" );
sewardjde4a1d02002-03-22 01:27:54 +00005860 break;
5861 case 0x01: /* ADD Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00005862 eip = dis_op2_G_E ( cb, sorb, ADD, True, sz, eip, "add" );
sewardjde4a1d02002-03-22 01:27:54 +00005863 break;
5864
5865 case 0x08: /* OR Gb,Eb */
sewardje1042472002-09-30 12:33:11 +00005866 eip = dis_op2_G_E ( cb, sorb, OR, True, 1, eip, "or" );
sewardjde4a1d02002-03-22 01:27:54 +00005867 break;
5868 case 0x09: /* OR Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00005869 eip = dis_op2_G_E ( cb, sorb, OR, True, sz, eip, "or" );
sewardjde4a1d02002-03-22 01:27:54 +00005870 break;
5871
sewardj72bbd222002-09-27 01:29:26 +00005872 case 0x10: /* ADC Gb,Eb */
sewardje1042472002-09-30 12:33:11 +00005873 eip = dis_op2_G_E ( cb, sorb, ADC, True, 1, eip, "adc" );
sewardj72bbd222002-09-27 01:29:26 +00005874 break;
sewardjde4a1d02002-03-22 01:27:54 +00005875 case 0x11: /* ADC Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00005876 eip = dis_op2_G_E ( cb, sorb, ADC, True, sz, eip, "adc" );
sewardjde4a1d02002-03-22 01:27:54 +00005877 break;
5878
nethercote1018bdd2004-02-11 23:33:29 +00005879 case 0x18: /* SBB Gb,Eb */
5880 eip = dis_op2_G_E ( cb, sorb, SBB, True, 1, eip, "sbb" );
5881 break;
sewardjde4a1d02002-03-22 01:27:54 +00005882 case 0x19: /* SBB Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00005883 eip = dis_op2_G_E ( cb, sorb, SBB, True, sz, eip, "sbb" );
sewardjde4a1d02002-03-22 01:27:54 +00005884 break;
5885
5886 case 0x20: /* AND Gb,Eb */
sewardje1042472002-09-30 12:33:11 +00005887 eip = dis_op2_G_E ( cb, sorb, AND, True, 1, eip, "and" );
sewardjde4a1d02002-03-22 01:27:54 +00005888 break;
5889 case 0x21: /* AND Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00005890 eip = dis_op2_G_E ( cb, sorb, AND, True, sz, eip, "and" );
sewardjde4a1d02002-03-22 01:27:54 +00005891 break;
5892
5893 case 0x28: /* SUB Gb,Eb */
sewardje1042472002-09-30 12:33:11 +00005894 eip = dis_op2_G_E ( cb, sorb, SUB, True, 1, eip, "sub" );
sewardjde4a1d02002-03-22 01:27:54 +00005895 break;
5896 case 0x29: /* SUB Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00005897 eip = dis_op2_G_E ( cb, sorb, SUB, True, sz, eip, "sub" );
sewardjde4a1d02002-03-22 01:27:54 +00005898 break;
5899
5900 case 0x30: /* XOR Gb,Eb */
sewardje1042472002-09-30 12:33:11 +00005901 eip = dis_op2_G_E ( cb, sorb, XOR, True, 1, eip, "xor" );
sewardjde4a1d02002-03-22 01:27:54 +00005902 break;
5903 case 0x31: /* XOR Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00005904 eip = dis_op2_G_E ( cb, sorb, XOR, True, sz, eip, "xor" );
sewardjde4a1d02002-03-22 01:27:54 +00005905 break;
5906
5907 case 0x38: /* CMP Gb,Eb */
sewardje1042472002-09-30 12:33:11 +00005908 eip = dis_op2_G_E ( cb, sorb, SUB, False, 1, eip, "cmp" );
sewardjde4a1d02002-03-22 01:27:54 +00005909 break;
5910 case 0x39: /* CMP Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00005911 eip = dis_op2_G_E ( cb, sorb, SUB, False, sz, eip, "cmp" );
sewardjde4a1d02002-03-22 01:27:54 +00005912 break;
5913
5914 /* ------------------------ POP ------------------------ */
5915
5916 case 0x58: /* POP eAX */
5917 case 0x59: /* POP eCX */
5918 case 0x5A: /* POP eDX */
5919 case 0x5B: /* POP eBX */
sewardjde4a1d02002-03-22 01:27:54 +00005920 case 0x5D: /* POP eBP */
5921 case 0x5E: /* POP eSI */
5922 case 0x5F: /* POP eDI */
sewardj4f51f9a2002-05-07 23:38:30 +00005923 case 0x5C: /* POP eSP */
sewardjde4a1d02002-03-22 01:27:54 +00005924 t1 = newTemp(cb); t2 = newTemp(cb);
5925 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
5926 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
5927 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
5928 uLiteral(cb, sz);
5929 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
5930 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, opc-0x58);
nethercotee8601122004-01-26 17:14:17 +00005931 DIP("pop%c %s\n", nameISize(sz), nameIReg(sz,opc-0x58));
sewardjde4a1d02002-03-22 01:27:54 +00005932 break;
5933
5934 case 0x9D: /* POPF */
5935 vg_assert(sz == 2 || sz == 4);
5936 t1 = newTemp(cb); t2 = newTemp(cb);
5937 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
5938 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
5939 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
5940 uLiteral(cb, sz);
5941 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
5942 uInstr1(cb, PUTF, sz, TempReg, t1);
5943 /* PUTF writes all the flags we are interested in */
5944 uFlagsRWU(cb, FlagsEmpty, FlagsALL, FlagsEmpty);
nethercotee8601122004-01-26 17:14:17 +00005945 DIP("popf%c\n", nameISize(sz));
sewardjde4a1d02002-03-22 01:27:54 +00005946 break;
5947
5948 case 0x61: /* POPA */
5949 { Int reg;
5950 /* Just to keep things sane, we assert for a size 4. It's
5951 probably OK for size 2 as well, but I'd like to find a test
5952 case; ie, have the assertion fail, before committing to it.
5953 If it fails for you, uncomment the sz == 2 bit, try again,
5954 and let me know whether or not it works. (jseward@acm.org). */
5955 vg_assert(sz == 4 /* || sz == 2 */);
5956
5957 /* Eight values are popped, one per register, but the value of
5958 %esp on the stack is ignored and instead incremented (in one
5959 hit at the end) for each of the values. */
5960 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
5961 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
5962 uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t3);
5963
5964 /* Do %edi, %esi, %ebp */
5965 for (reg = 7; reg >= 5; reg--) {
5966 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
5967 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
5968 uLiteral(cb, sz);
5969 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
5970 }
5971 /* Ignore (skip) value of %esp on stack. */
5972 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
5973 uLiteral(cb, sz);
5974 /* Do %ebx, %edx, %ecx, %eax */
5975 for (reg = 3; reg >= 0; reg--) {
5976 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
5977 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
5978 uLiteral(cb, sz);
5979 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
5980 }
5981 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t3);
5982 uLiteral(cb, sz * 8); /* One 'sz' per register */
5983 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
nethercotee8601122004-01-26 17:14:17 +00005984 DIP("popa%c\n", nameISize(sz));
sewardjde4a1d02002-03-22 01:27:54 +00005985 break;
5986 }
5987
sewardj363e6062002-05-22 11:55:35 +00005988 case 0x8F: /* POPL/POPW m32 */
5989 { UInt pair1;
5990 Int tmpa;
5991 UChar rm = getUChar(eip);
5992
5993 /* make sure this instruction is correct POP */
5994 vg_assert(!epartIsReg(rm) && (gregOfRM(rm) == 0));
5995 /* and has correct size */
5996 vg_assert(sz == 4);
5997
5998 t1 = newTemp(cb); t3 = newTemp(cb);
5999 /* set t1 to ESP: t1 = ESP */
6000 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
6001 /* load M[ESP] to virtual register t3: t3 = M[t1] */
6002 uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t3);
njn8399f6a2003-10-13 07:30:40 +00006003
6004 /* increase ESP; must be done before the STORE. Intel manual says:
6005 If the ESP register is used as a base register for addressing
6006 a destination operand in memory, the POP instruction computes
6007 the effective address of the operand after it increments the
6008 ESP register.
6009 */
6010 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1);
6011 uLiteral(cb, sz);
6012 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
6013
sewardj363e6062002-05-22 11:55:35 +00006014 /* resolve MODR/M */
nethercotee8601122004-01-26 17:14:17 +00006015 pair1 = disAMode ( cb, sorb, eip, dis_buf );
sewardj363e6062002-05-22 11:55:35 +00006016
6017 tmpa = LOW24(pair1);
6018 /* uInstr2(cb, LOAD, sz, TempReg, tmpa, TempReg, tmpa); */
6019 /* store value from stack in memory, M[m32] = t3 */
6020 uInstr2(cb, STORE, 4, TempReg, t3, TempReg, tmpa);
6021
nethercotee8601122004-01-26 17:14:17 +00006022 DIP("popl %s\n", dis_buf);
sewardj363e6062002-05-22 11:55:35 +00006023
6024 eip += HI8(pair1);
6025 break;
6026 }
6027
daywalker5d945de2003-09-26 00:32:53 +00006028 case 0x1F: /* POP %DS */
nethercote561f6e02003-11-02 17:00:23 +00006029 dis_pop_segreg( cb, R_DS, sz ); break;
daywalker5d945de2003-09-26 00:32:53 +00006030 case 0x07: /* POP %ES */
nethercote561f6e02003-11-02 17:00:23 +00006031 dis_pop_segreg( cb, R_ES, sz ); break;
njn9e4c1f92003-10-12 17:32:27 +00006032 case 0x17: /* POP %SS */
nethercote561f6e02003-11-02 17:00:23 +00006033 dis_pop_segreg( cb, R_SS, sz ); break;
daywalker5d945de2003-09-26 00:32:53 +00006034
sewardjde4a1d02002-03-22 01:27:54 +00006035 /* ------------------------ PUSH ----------------------- */
6036
6037 case 0x50: /* PUSH eAX */
6038 case 0x51: /* PUSH eCX */
6039 case 0x52: /* PUSH eDX */
sewardjde4a1d02002-03-22 01:27:54 +00006040 case 0x53: /* PUSH eBX */
6041 case 0x55: /* PUSH eBP */
6042 case 0x56: /* PUSH eSI */
6043 case 0x57: /* PUSH eDI */
sewardj4f51f9a2002-05-07 23:38:30 +00006044 case 0x54: /* PUSH eSP */
sewardjde4a1d02002-03-22 01:27:54 +00006045 /* This is the Right Way, in that the value to be pushed is
6046 established before %esp is changed, so that pushl %esp
6047 correctly pushes the old value. */
6048 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
6049 uInstr2(cb, GET, sz, ArchReg, opc-0x50, TempReg, t1);
6050 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
6051 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
6052 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
6053 uLiteral(cb, sz);
6054 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
6055 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
nethercotee8601122004-01-26 17:14:17 +00006056 DIP("push%c %s\n", nameISize(sz), nameIReg(sz,opc-0x50));
sewardjde4a1d02002-03-22 01:27:54 +00006057 break;
6058
6059 case 0x68: /* PUSH Iv */
6060 d32 = getUDisp(sz,eip); eip += sz;
6061 goto do_push_I;
6062 case 0x6A: /* PUSH Ib, sign-extended to sz */
6063 d32 = getSDisp8(eip); eip += 1;
6064 goto do_push_I;
6065 do_push_I:
6066 t1 = newTemp(cb); t2 = newTemp(cb);
6067 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
6068 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t1);
6069 uLiteral(cb, sz);
6070 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
6071 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t2);
6072 uLiteral(cb, d32);
6073 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
nethercotee8601122004-01-26 17:14:17 +00006074 DIP("push%c $0x%x\n", nameISize(sz), d32);
sewardjde4a1d02002-03-22 01:27:54 +00006075 break;
6076
6077 case 0x9C: /* PUSHF */
6078 vg_assert(sz == 2 || sz == 4);
6079 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
6080 uInstr1(cb, GETF, sz, TempReg, t1);
6081 /* GETF reads all the flags we are interested in */
6082 uFlagsRWU(cb, FlagsALL, FlagsEmpty, FlagsEmpty);
6083 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
6084 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
6085 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
6086 uLiteral(cb, sz);
6087 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
6088 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
nethercotee8601122004-01-26 17:14:17 +00006089 DIP("pushf%c\n", nameISize(sz));
sewardjde4a1d02002-03-22 01:27:54 +00006090 break;
6091
6092 case 0x60: /* PUSHA */
6093 { Int reg;
6094 /* Just to keep things sane, we assert for a size 4. It's
6095 probably OK for size 2 as well, but I'd like to find a test
6096 case; ie, have the assertion fail, before committing to it.
6097 If it fails for you, uncomment the sz == 2 bit, try again,
6098 and let me know whether or not it works. (jseward@acm.org). */
6099 vg_assert(sz == 4 /* || sz == 2 */);
6100
6101 /* This is the Right Way, in that the value to be pushed is
6102 established before %esp is changed, so that pusha
6103 correctly pushes the old %esp value. New value of %esp is
6104 pushed at start. */
6105 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
6106 t4 = newTemp(cb);
6107 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
6108 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
6109 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t4);
6110 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t4);
6111 uLiteral(cb, sz * 8); /* One 'sz' per register. */
6112 uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_ESP);
6113 /* Do %eax, %ecx, %edx, %ebx */
6114 for (reg = 0; reg <= 3; reg++) {
6115 uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
6116 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
6117 uLiteral(cb, sz);
6118 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00006119 }
6120 /* Push old value of %esp */
6121 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
6122 uLiteral(cb, sz);
6123 uInstr2(cb, STORE, sz, TempReg, t3, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00006124 /* Do %ebp, %esi, %edi */
6125 for (reg = 5; reg <= 7; reg++) {
6126 uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
6127 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
6128 uLiteral(cb, sz);
6129 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00006130 }
nethercotee8601122004-01-26 17:14:17 +00006131 DIP("pusha%c\n", nameISize(sz));
sewardjde4a1d02002-03-22 01:27:54 +00006132 break;
nethercote561f6e02003-11-02 17:00:23 +00006133 }
sewardjde4a1d02002-03-22 01:27:54 +00006134
nethercote561f6e02003-11-02 17:00:23 +00006135 case 0x0E: /* PUSH %CS */
6136 dis_push_segreg( cb, R_CS, sz ); break;
6137 case 0x1E: /* PUSH %DS */
6138 dis_push_segreg( cb, R_DS, sz ); break;
6139 case 0x06: /* PUSH %ES */
6140 dis_push_segreg( cb, R_ES, sz ); break;
6141 case 0x16: /* PUSH %SS */
6142 dis_push_segreg( cb, R_SS, sz ); break;
daywalker5d945de2003-09-26 00:32:53 +00006143
sewardjde4a1d02002-03-22 01:27:54 +00006144 /* ------------------------ SCAS et al ----------------- */
6145
nethercotee33453f2003-11-27 16:15:17 +00006146 case 0xA4: /* MOVS, no REP prefix */
6147 case 0xA5:
6148 dis_string_op( cb, dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
sewardjde4a1d02002-03-22 01:27:54 +00006149 break;
6150
6151 case 0xA6: /* CMPSb, no REP prefix */
nethercotee33453f2003-11-27 16:15:17 +00006152 case 0xA7:
6153 dis_string_op( cb, dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
sewardjde4a1d02002-03-22 01:27:54 +00006154 break;
6155
nethercotee33453f2003-11-27 16:15:17 +00006156 case 0xAA: /* STOS, no REP prefix */
6157 case 0xAB:
6158 dis_string_op( cb, dis_STOS, ( opc == 0xAA ? 1 : sz ), "stos", sorb );
sewardjde4a1d02002-03-22 01:27:54 +00006159 break;
nethercotee33453f2003-11-27 16:15:17 +00006160
6161 case 0xAC: /* LODS, no REP prefix */
6162 case 0xAD:
6163 dis_string_op( cb, dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", sorb );
sewardjde4a1d02002-03-22 01:27:54 +00006164 break;
6165
nethercotee33453f2003-11-27 16:15:17 +00006166 case 0xAE: /* SCAS, no REP prefix */
6167 case 0xAF:
6168 dis_string_op( cb, dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
sewardj64a8cc42002-05-08 01:38:43 +00006169 break;
sewardjde4a1d02002-03-22 01:27:54 +00006170
jsgfd1b5b1d2003-10-14 22:17:19 +00006171
sewardjde4a1d02002-03-22 01:27:54 +00006172 case 0xFC: /* CLD */
6173 uInstr0(cb, CALLM_S, 0);
6174 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CLD));
6175 uFlagsRWU(cb, FlagsEmpty, FlagD, FlagsEmpty);
6176 uInstr0(cb, CALLM_E, 0);
nethercotee8601122004-01-26 17:14:17 +00006177 DIP("cld\n");
sewardjde4a1d02002-03-22 01:27:54 +00006178 break;
6179
6180 case 0xFD: /* STD */
6181 uInstr0(cb, CALLM_S, 0);
6182 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_STD));
6183 uFlagsRWU(cb, FlagsEmpty, FlagD, FlagsEmpty);
6184 uInstr0(cb, CALLM_E, 0);
nethercotee8601122004-01-26 17:14:17 +00006185 DIP("std\n");
sewardjde4a1d02002-03-22 01:27:54 +00006186 break;
6187
sewardj7d78e782002-06-02 00:04:00 +00006188 case 0xF8: /* CLC */
6189 uInstr0(cb, CALLM_S, 0);
6190 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CLC));
6191 uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
6192 uInstr0(cb, CALLM_E, 0);
nethercotee8601122004-01-26 17:14:17 +00006193 DIP("clc\n");
sewardj7d78e782002-06-02 00:04:00 +00006194 break;
6195
6196 case 0xF9: /* STC */
6197 uInstr0(cb, CALLM_S, 0);
6198 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_STC));
nethercote1018bdd2004-02-11 23:33:29 +00006199 uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
sewardj7d78e782002-06-02 00:04:00 +00006200 uInstr0(cb, CALLM_E, 0);
nethercotee8601122004-01-26 17:14:17 +00006201 DIP("stc\n");
sewardj7d78e782002-06-02 00:04:00 +00006202 break;
6203
nethercote1018bdd2004-02-11 23:33:29 +00006204 case 0xF5: /* CMC */
6205 uInstr0(cb, CALLM_S, 0);
6206 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CMC));
6207 uFlagsRWU(cb, FlagC, FlagC, FlagsOSZAP);
6208 uInstr0(cb, CALLM_E, 0);
6209 DIP("cmc\n");
6210 break;
6211
nethercote5305d412004-06-02 14:48:16 +00006212 /* REPNE prefix insn */
6213 case 0xF2: {
sewardjde4a1d02002-03-22 01:27:54 +00006214 Addr eip_orig = eip - 1;
sewardj1cff0e02002-10-05 14:42:39 +00006215 vg_assert(sorb == 0);
sewardjde4a1d02002-03-22 01:27:54 +00006216 abyte = getUChar(eip); eip++;
sewardjde4a1d02002-03-22 01:27:54 +00006217
nethercote5305d412004-06-02 14:48:16 +00006218 if (abyte == 0x66) { sz = 2; abyte = getUChar(eip); eip++; }
6219 *isEnd = True;
6220
6221 switch (abyte) {
6222 /* According to the Intel manual, "repne movs" should never occur, but
6223 * in practice it has happened, so allow for it here... */
6224 case 0xA4: sz = 1; /* REPNE MOVS<sz> */
6225 case 0xA5:
6226 dis_REP_op ( cb, CondNZ, dis_MOVS, sz, eip_orig, eip, "repne movs" );
6227 break;
6228
6229 case 0xA6: sz = 1; /* REPNE CMPS<sz> */
6230 case 0xA7:
6231 dis_REP_op ( cb, CondNZ, dis_CMPS, sz, eip_orig, eip, "repne cmps" );
6232 break;
6233
6234 case 0xAE: sz = 1; /* REPNE SCAS<sz> */
6235 case 0xAF:
nethercotee33453f2003-11-27 16:15:17 +00006236 dis_REP_op ( cb, CondNZ, dis_SCAS, sz, eip_orig, eip, "repne scas" );
nethercote5305d412004-06-02 14:48:16 +00006237 break;
6238
6239 default:
sewardja60be0e2003-05-26 08:47:27 +00006240 goto decode_failure;
sewardjde4a1d02002-03-22 01:27:54 +00006241 }
6242 break;
6243 }
6244
nethercotee33453f2003-11-27 16:15:17 +00006245 /* REP/REPE prefix insn (for SCAS and CMPS, 0xF3 means REPE,
6246 for the rest, it means REP) */
6247 case 0xF3: {
sewardjde4a1d02002-03-22 01:27:54 +00006248 Addr eip_orig = eip - 1;
sewardj1cff0e02002-10-05 14:42:39 +00006249 vg_assert(sorb == 0);
sewardjde4a1d02002-03-22 01:27:54 +00006250 abyte = getUChar(eip); eip++;
nethercotee33453f2003-11-27 16:15:17 +00006251
sewardjde4a1d02002-03-22 01:27:54 +00006252 if (abyte == 0x66) { sz = 2; abyte = getUChar(eip); eip++; }
nethercote5305d412004-06-02 14:48:16 +00006253 *isEnd = True;
sewardjde4a1d02002-03-22 01:27:54 +00006254
nethercote5305d412004-06-02 14:48:16 +00006255 switch (abyte) {
6256 case 0xA4: sz = 1; /* REP MOVS<sz> */
6257 case 0xA5:
nethercotee33453f2003-11-27 16:15:17 +00006258 dis_REP_op ( cb, CondAlways, dis_MOVS, sz, eip_orig, eip, "rep movs" );
nethercote5305d412004-06-02 14:48:16 +00006259 break;
6260
6261 case 0xA6: sz = 1; /* REPE CMP<sz> */
6262 case 0xA7:
nethercotee33453f2003-11-27 16:15:17 +00006263 dis_REP_op ( cb, CondZ, dis_CMPS, sz, eip_orig, eip, "repe cmps" );
nethercote5305d412004-06-02 14:48:16 +00006264 break;
6265
6266 case 0xAA: sz = 1; /* REP STOS<sz> */
6267 case 0XAB:
nethercotee33453f2003-11-27 16:15:17 +00006268 dis_REP_op ( cb, CondAlways, dis_STOS, sz, eip_orig, eip, "rep stos" );
nethercote5305d412004-06-02 14:48:16 +00006269 break;
6270
6271 case 0xAE: sz = 1; /* REPE SCAS<sz> */
6272 case 0xAF:
nethercotee33453f2003-11-27 16:15:17 +00006273 dis_REP_op ( cb, CondZ, dis_SCAS, sz, eip_orig, eip, "repe scas" );
nethercote5305d412004-06-02 14:48:16 +00006274 break;
6275
6276 case 0x90: /* REP NOP (PAUSE) */
nethercotee8601122004-01-26 17:14:17 +00006277 /* a hint to the P4 re spin-wait loop */
6278 DIP("rep nop (P4 pause)\n");
6279 jmp_lit(cb, eip);
fitzhardingea02f8812003-12-18 09:06:09 +00006280 LAST_UINSTR(cb).jmpkind = JmpYield;
nethercote5305d412004-06-02 14:48:16 +00006281 break;
6282
6283 case 0xC3: /* REP RET */
nethercotebd126912004-02-22 16:56:28 +00006284 /* AMD K7/K8-specific optimisation; faster than vanilla RET */
6285 dis_ret(cb, 0);
nethercotebd126912004-02-22 16:56:28 +00006286 DIP("rep ret\n");
nethercote5305d412004-06-02 14:48:16 +00006287 break;
6288
6289 default:
sewardja60be0e2003-05-26 08:47:27 +00006290 goto decode_failure;
sewardjde4a1d02002-03-22 01:27:54 +00006291 }
6292 break;
6293 }
6294
6295 /* ------------------------ XCHG ----------------------- */
6296
6297 case 0x86: /* XCHG Gb,Eb */
6298 sz = 1;
6299 /* Fall through ... */
6300 case 0x87: /* XCHG Gv,Ev */
6301 modrm = getUChar(eip);
6302 t1 = newTemp(cb); t2 = newTemp(cb);
6303 if (epartIsReg(modrm)) {
6304 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
6305 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t2);
6306 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, gregOfRM(modrm));
6307 uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, eregOfRM(modrm));
6308 eip++;
nethercotee8601122004-01-26 17:14:17 +00006309 DIP("xchg%c %s, %s\n",
6310 nameISize(sz), nameIReg(sz,gregOfRM(modrm)),
6311 nameIReg(sz,eregOfRM(modrm)));
sewardjde4a1d02002-03-22 01:27:54 +00006312 } else {
nethercotee8601122004-01-26 17:14:17 +00006313 pair = disAMode ( cb, sorb, eip, dis_buf );
sewardjde4a1d02002-03-22 01:27:54 +00006314 t3 = LOW24(pair);
6315 uInstr2(cb, LOAD, sz, TempReg, t3, TempReg, t1);
6316 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t2);
6317 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t3);
sewardjde4a1d02002-03-22 01:27:54 +00006318 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, gregOfRM(modrm));
6319 eip += HI8(pair);
nethercotee8601122004-01-26 17:14:17 +00006320 DIP("xchg%c %s, %s\n", nameISize(sz),
6321 nameIReg(sz,gregOfRM(modrm)), dis_buf);
sewardjde4a1d02002-03-22 01:27:54 +00006322 }
6323 break;
6324
6325 case 0x90: /* XCHG eAX,eAX */
nethercotee8601122004-01-26 17:14:17 +00006326 DIP("nop\n");
sewardjde4a1d02002-03-22 01:27:54 +00006327 break;
sewardj6ca4c022002-10-05 14:36:26 +00006328 case 0x91: /* XCHG eAX,eCX */
6329 case 0x92: /* XCHG eAX,eDX */
6330 case 0x93: /* XCHG eAX,eBX */
njn43953562003-06-29 17:28:23 +00006331 case 0x94: /* XCHG eAX,eSP */
sewardja51cc092003-07-06 01:17:33 +00006332 case 0x95: /* XCHG eAX,eBP */
sewardjde4a1d02002-03-22 01:27:54 +00006333 case 0x96: /* XCHG eAX,eSI */
6334 case 0x97: /* XCHG eAX,eDI */
6335 codegen_xchg_eAX_Reg ( cb, sz, opc - 0x90 );
6336 break;
6337
sewardj87c85ee2003-04-02 20:10:56 +00006338 /* ------------------------ XLAT ----------------------- */
6339
6340 case 0xD7: /* XLAT */
6341 t1 = newTemp(cb); t2 = newTemp(cb);
6342 uInstr2(cb, GET, sz, ArchReg, R_EBX, TempReg, t1); /* get eBX */
6343 handleSegOverride( cb, sorb, t1 ); /* make t1 DS:eBX */
6344 uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t2); /* get AL */
6345 /* Widen %AL to 32 bits, so it's all defined when we add it. */
6346 uInstr1(cb, WIDEN, 4, TempReg, t2);
nethercote911cc372004-04-18 12:23:02 +00006347 uWiden(cb, 1, False);
sewardj87c85ee2003-04-02 20:10:56 +00006348 uInstr2(cb, ADD, sz, TempReg, t2, TempReg, t1); /* add AL to eBX */
6349 uInstr2(cb, LOAD, 1, TempReg, t1, TempReg, t2); /* get byte at t1 into t2 */
6350 uInstr2(cb, PUT, 1, TempReg, t2, ArchReg, R_AL); /* put byte into AL */
6351
nethercotee8601122004-01-26 17:14:17 +00006352 DIP("xlat%c [ebx]\n", nameISize(sz));
sewardj87c85ee2003-04-02 20:10:56 +00006353 break;
6354
daywalkerb18d2532003-09-27 20:15:01 +00006355 /* ------------------------ IN / OUT ----------------------- */
6356
6357 case 0xE4: /* IN ib, %al */
6358 case 0xE5: /* IN ib, %{e}ax */
6359 case 0xEC: /* IN (%dx),%al */
6360 case 0xED: /* IN (%dx),%{e}ax */
6361 t1 = newTemp(cb);
6362 t2 = newTemp(cb);
6363 t3 = newTemp(cb);
6364
6365 uInstr0(cb, CALLM_S, 0);
6366 /* operand size? */
6367 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
6368 uLiteral(cb, ( opc == 0xE4 || opc == 0xEC ) ? 1 : sz);
6369 uInstr1(cb, PUSH, 4, TempReg, t1);
6370 /* port number ? */
6371 if ( opc == 0xE4 || opc == 0xE5 ) {
6372 abyte = getUChar(eip); eip++;
6373 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
6374 uLiteral(cb, abyte);
6375 }
6376 else
6377 uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
6378
6379 uInstr1(cb, PUSH, 4, TempReg, t2);
6380 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_IN));
6381 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
6382 uInstr1(cb, POP, 4, TempReg, t2);
6383 uInstr1(cb, CLEAR, 0, Lit16, 4);
6384 uInstr0(cb, CALLM_E, 0);
6385 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EAX);
nethercotee8601122004-01-26 17:14:17 +00006386 if ( opc == 0xE4 || opc == 0xE5 ) {
6387 DIP("in 0x%x, %%eax/%%ax/%%al\n", getUChar(eip-1) );
6388 } else {
6389 DIP("in (%%dx), %%eax/%%ax/%%al\n");
daywalkerb18d2532003-09-27 20:15:01 +00006390 }
6391 break;
6392 case 0xE6: /* OUT %al,ib */
6393 case 0xE7: /* OUT %{e}ax,ib */
6394 case 0xEE: /* OUT %al,(%dx) */
6395 case 0xEF: /* OUT %{e}ax,(%dx) */
6396 t1 = newTemp(cb);
6397 t2 = newTemp(cb);
6398 t3 = newTemp(cb);
6399
6400 uInstr0(cb, CALLM_S, 0);
6401 /* operand size? */
6402 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
6403 uLiteral(cb, ( opc == 0xE6 || opc == 0xEE ) ? 1 : sz);
6404 uInstr1(cb, PUSH, 4, TempReg, t1);
6405 /* port number ? */
6406 if ( opc == 0xE6 || opc == 0xE7 ) {
6407 abyte = getUChar(eip); eip++;
6408 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
6409 uLiteral(cb, abyte);
6410 }
6411 else
6412 uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2);
6413 uInstr1(cb, PUSH, 4, TempReg, t2);
6414 uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t3);
6415 uInstr1(cb, PUSH, 4, TempReg, t3);
6416 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_OUT));
6417 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
6418 uInstr1(cb, CLEAR, 0, Lit16, 12);
6419 uInstr0(cb, CALLM_E, 0);
nethercotee8601122004-01-26 17:14:17 +00006420 if ( opc == 0xE4 || opc == 0xE5 ) {
6421 DIP("out %%eax/%%ax/%%al, 0x%x\n", getUChar(eip-1) );
6422 } else {
6423 DIP("out %%eax/%%ax/%%al, (%%dx)\n");
daywalkerb18d2532003-09-27 20:15:01 +00006424 }
6425 break;
6426
sewardjde4a1d02002-03-22 01:27:54 +00006427 /* ------------------------ (Grp1 extensions) ---------- */
6428
6429 case 0x80: /* Grp1 Ib,Eb */
6430 modrm = getUChar(eip);
6431 am_sz = lengthAMode(eip);
6432 sz = 1;
6433 d_sz = 1;
6434 d32 = getSDisp8(eip + am_sz);
sewardje1042472002-09-30 12:33:11 +00006435 eip = dis_Grp1 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00006436 break;
6437
6438 case 0x81: /* Grp1 Iv,Ev */
6439 modrm = getUChar(eip);
6440 am_sz = lengthAMode(eip);
6441 d_sz = sz;
6442 d32 = getUDisp(d_sz, eip + am_sz);
sewardje1042472002-09-30 12:33:11 +00006443 eip = dis_Grp1 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00006444 break;
6445
6446 case 0x83: /* Grp1 Ib,Ev */
6447 modrm = getUChar(eip);
6448 am_sz = lengthAMode(eip);
6449 d_sz = 1;
6450 d32 = getSDisp8(eip + am_sz);
sewardje1042472002-09-30 12:33:11 +00006451 eip = dis_Grp1 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00006452 break;
6453
6454 /* ------------------------ (Grp2 extensions) ---------- */
6455
6456 case 0xC0: /* Grp2 Ib,Eb */
6457 modrm = getUChar(eip);
6458 am_sz = lengthAMode(eip);
6459 d_sz = 1;
6460 d32 = getSDisp8(eip + am_sz);
6461 sz = 1;
sewardje1042472002-09-30 12:33:11 +00006462 eip = dis_Grp2 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00006463 break;
6464
6465 case 0xC1: /* Grp2 Ib,Ev */
6466 modrm = getUChar(eip);
6467 am_sz = lengthAMode(eip);
6468 d_sz = 1;
6469 d32 = getSDisp8(eip + am_sz);
sewardje1042472002-09-30 12:33:11 +00006470 eip = dis_Grp2 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00006471 break;
6472
6473 case 0xD0: /* Grp2 1,Eb */
6474 modrm = getUChar(eip);
6475 am_sz = lengthAMode(eip);
6476 d_sz = 0;
6477 d32 = 1;
6478 sz = 1;
sewardje1042472002-09-30 12:33:11 +00006479 eip = dis_Grp2 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00006480 break;
6481
6482 case 0xD1: /* Grp2 1,Ev */
6483 modrm = getUChar(eip);
6484 am_sz = lengthAMode(eip);
6485 d_sz = 0;
6486 d32 = 1;
sewardje1042472002-09-30 12:33:11 +00006487 eip = dis_Grp2 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00006488 break;
6489
njn25e49d8e72002-09-23 09:36:25 +00006490 case 0xD2: /* Grp2 CL,Eb */
6491 modrm = getUChar(eip);
6492 am_sz = lengthAMode(eip);
6493 d_sz = 0;
6494 sz = 1;
sewardje1042472002-09-30 12:33:11 +00006495 eip = dis_Grp2 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, ArchReg, R_ECX );
njn25e49d8e72002-09-23 09:36:25 +00006496 break;
6497
sewardjde4a1d02002-03-22 01:27:54 +00006498 case 0xD3: /* Grp2 CL,Ev */
6499 modrm = getUChar(eip);
6500 am_sz = lengthAMode(eip);
6501 d_sz = 0;
sewardje1042472002-09-30 12:33:11 +00006502 eip = dis_Grp2 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, ArchReg, R_ECX );
sewardjde4a1d02002-03-22 01:27:54 +00006503 break;
6504
6505 /* ------------------------ (Grp3 extensions) ---------- */
6506
6507 case 0xF6: /* Grp3 Eb */
sewardje1042472002-09-30 12:33:11 +00006508 eip = dis_Grp3 ( cb, sorb, 1, eip );
sewardjde4a1d02002-03-22 01:27:54 +00006509 break;
6510 case 0xF7: /* Grp3 Ev */
sewardje1042472002-09-30 12:33:11 +00006511 eip = dis_Grp3 ( cb, sorb, sz, eip );
sewardjde4a1d02002-03-22 01:27:54 +00006512 break;
6513
6514 /* ------------------------ (Grp4 extensions) ---------- */
6515
6516 case 0xFE: /* Grp4 Eb */
sewardje1042472002-09-30 12:33:11 +00006517 eip = dis_Grp4 ( cb, sorb, eip );
sewardjde4a1d02002-03-22 01:27:54 +00006518 break;
6519
6520 /* ------------------------ (Grp5 extensions) ---------- */
6521
6522 case 0xFF: /* Grp5 Ev */
sewardje1042472002-09-30 12:33:11 +00006523 eip = dis_Grp5 ( cb, sorb, sz, eip, isEnd );
sewardjde4a1d02002-03-22 01:27:54 +00006524 break;
6525
6526 /* ------------------------ Escapes to 2-byte opcodes -- */
6527
6528 case 0x0F: {
6529 opc = getUChar(eip); eip++;
6530 switch (opc) {
6531
6532 /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
6533
6534 case 0xBA: /* Grp8 Ib,Ev */
6535 modrm = getUChar(eip);
6536 am_sz = lengthAMode(eip);
6537 d32 = getSDisp8(eip + am_sz);
sewardje1042472002-09-30 12:33:11 +00006538 eip = dis_Grp8_BT ( cb, sorb, eip, modrm, am_sz, sz, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00006539 break;
sewardj0ece28b2002-04-16 00:42:12 +00006540
sewardjde4a1d02002-03-22 01:27:54 +00006541 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
6542
6543 case 0xBC: /* BSF Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00006544 eip = dis_bs_E_G ( cb, sorb, sz, eip, True );
sewardjde4a1d02002-03-22 01:27:54 +00006545 break;
6546 case 0xBD: /* BSR Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00006547 eip = dis_bs_E_G ( cb, sorb, sz, eip, False );
sewardjde4a1d02002-03-22 01:27:54 +00006548 break;
6549
6550 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
6551
6552 case 0xC8: /* BSWAP %eax */
6553 case 0xC9:
6554 case 0xCA:
6555 case 0xCB:
6556 case 0xCC:
6557 case 0xCD:
6558 case 0xCE:
6559 case 0xCF: /* BSWAP %edi */
6560 /* AFAICS from the Intel docs, this only exists at size 4. */
6561 vg_assert(sz == 4);
6562 t1 = newTemp(cb);
6563 uInstr2(cb, GET, 4, ArchReg, opc-0xC8, TempReg, t1);
6564 uInstr1(cb, BSWAP, 4, TempReg, t1);
6565 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, opc-0xC8);
nethercotee8601122004-01-26 17:14:17 +00006566 DIP("bswapl %s\n", nameIReg(4, opc-0xC8));
sewardjde4a1d02002-03-22 01:27:54 +00006567 break;
6568
6569 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
6570
6571 case 0xA3: /* BT Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00006572 eip = dis_bt_G_E ( cb, sorb, sz, eip, BtOpNone );
sewardjde4a1d02002-03-22 01:27:54 +00006573 break;
6574 case 0xB3: /* BTR Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00006575 eip = dis_bt_G_E ( cb, sorb, sz, eip, BtOpReset );
sewardjde4a1d02002-03-22 01:27:54 +00006576 break;
6577 case 0xAB: /* BTS Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00006578 eip = dis_bt_G_E ( cb, sorb, sz, eip, BtOpSet );
sewardjde4a1d02002-03-22 01:27:54 +00006579 break;
6580 case 0xBB: /* BTC Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00006581 eip = dis_bt_G_E ( cb, sorb, sz, eip, BtOpComp );
sewardjde4a1d02002-03-22 01:27:54 +00006582 break;
6583
6584 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
6585
6586 case 0x40:
6587 case 0x41:
6588 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
6589 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
6590 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
6591 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
6592 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
6593 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
6594 case 0x48: /* CMOVSb (cmov negative) */
6595 case 0x49: /* CMOVSb (cmov not negative) */
6596 case 0x4A: /* CMOVP (cmov parity even) */
sewardj969129d2002-04-21 11:43:11 +00006597 case 0x4B: /* CMOVNP (cmov parity odd) */
sewardjde4a1d02002-03-22 01:27:54 +00006598 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
6599 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
6600 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
6601 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
sewardje1042472002-09-30 12:33:11 +00006602 eip = dis_cmov_E_G(cb, sorb, sz, (Condcode)(opc - 0x40), eip);
sewardjde4a1d02002-03-22 01:27:54 +00006603 break;
6604
6605 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
6606
muellerf217c732004-01-02 22:42:29 +00006607 case 0xB0: /* CMPXCHG Gv,Ev */
6608 eip = dis_cmpxchg_G_E ( cb, sorb, 1, eip );
6609 break;
sewardjde4a1d02002-03-22 01:27:54 +00006610 case 0xB1: /* CMPXCHG Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00006611 eip = dis_cmpxchg_G_E ( cb, sorb, sz, eip );
sewardjde4a1d02002-03-22 01:27:54 +00006612 break;
muellerf217c732004-01-02 22:42:29 +00006613 case 0xC7: /* CMPXCHG8B Gv */
6614 eip = dis_cmpxchg8b ( cb, sorb, eip );
6615 break;
sewardjde4a1d02002-03-22 01:27:54 +00006616
6617 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
6618
6619 case 0xA2: /* CPUID */
fitzhardinge0df2ac22004-01-25 02:38:29 +00006620 if (!VG_(cpu_has_feature)(VG_X86_FEAT_CPUID))
6621 goto decode_failure;
6622
sewardjde4a1d02002-03-22 01:27:54 +00006623 t1 = newTemp(cb);
6624 t2 = newTemp(cb);
6625 t3 = newTemp(cb);
6626 t4 = newTemp(cb);
6627 uInstr0(cb, CALLM_S, 0);
6628
6629 uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t1);
6630 uInstr1(cb, PUSH, 4, TempReg, t1);
6631
6632 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
6633 uLiteral(cb, 0);
6634 uInstr1(cb, PUSH, 4, TempReg, t2);
6635
6636 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t3);
6637 uLiteral(cb, 0);
6638 uInstr1(cb, PUSH, 4, TempReg, t3);
6639
6640 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
6641 uLiteral(cb, 0);
6642 uInstr1(cb, PUSH, 4, TempReg, t4);
6643
6644 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CPUID));
6645 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
6646
6647 uInstr1(cb, POP, 4, TempReg, t4);
6648 uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_EDX);
6649
6650 uInstr1(cb, POP, 4, TempReg, t3);
6651 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ECX);
6652
6653 uInstr1(cb, POP, 4, TempReg, t2);
6654 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBX);
6655
6656 uInstr1(cb, POP, 4, TempReg, t1);
6657 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
6658
6659 uInstr0(cb, CALLM_E, 0);
nethercotee8601122004-01-26 17:14:17 +00006660 DIP("cpuid\n");
sewardjde4a1d02002-03-22 01:27:54 +00006661 break;
6662
6663 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
6664
6665 case 0xB6: /* MOVZXb Eb,Gv */
sewardje1042472002-09-30 12:33:11 +00006666 eip = dis_movx_E_G ( cb, sorb, eip, 1, 4, False );
sewardjde4a1d02002-03-22 01:27:54 +00006667 break;
6668 case 0xB7: /* MOVZXw Ew,Gv */
sewardje1042472002-09-30 12:33:11 +00006669 eip = dis_movx_E_G ( cb, sorb, eip, 2, 4, False );
sewardjde4a1d02002-03-22 01:27:54 +00006670 break;
6671
6672 case 0xBE: /* MOVSXb Eb,Gv */
sewardje1042472002-09-30 12:33:11 +00006673 eip = dis_movx_E_G ( cb, sorb, eip, 1, 4, True );
sewardjde4a1d02002-03-22 01:27:54 +00006674 break;
6675 case 0xBF: /* MOVSXw Ew,Gv */
sewardje1042472002-09-30 12:33:11 +00006676 eip = dis_movx_E_G ( cb, sorb, eip, 2, 4, True );
sewardjde4a1d02002-03-22 01:27:54 +00006677 break;
6678
nethercoteb1affa82004-01-19 19:14:18 +00006679 /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
6680
6681 case 0xC3: /* MOVNTI Gv,Ev */
6682 vg_assert(sz == 4);
6683 modrm = getUChar(eip);
6684 vg_assert(!epartIsReg(modrm));
6685 t1 = newTemp(cb);
6686 uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
nethercotee8601122004-01-26 17:14:17 +00006687 pair = disAMode ( cb, sorb, eip, dis_buf );
nethercoteb1affa82004-01-19 19:14:18 +00006688 t2 = LOW24(pair);
6689 eip += HI8(pair);
6690 uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
nethercotee8601122004-01-26 17:14:17 +00006691 DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
nethercoteb1affa82004-01-19 19:14:18 +00006692 break;
6693
sewardjde4a1d02002-03-22 01:27:54 +00006694 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
6695
6696 case 0xAF: /* IMUL Ev, Gv */
sewardje1042472002-09-30 12:33:11 +00006697 eip = dis_mul_E_G ( cb, sorb, sz, eip, True );
sewardjde4a1d02002-03-22 01:27:54 +00006698 break;
6699
6700 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
6701 case 0x80:
6702 case 0x81:
6703 case 0x82: /* JBb/JNAEb (jump below) */
6704 case 0x83: /* JNBb/JAEb (jump not below) */
6705 case 0x84: /* JZb/JEb (jump zero) */
6706 case 0x85: /* JNZb/JNEb (jump not zero) */
6707 case 0x86: /* JBEb/JNAb (jump below or equal) */
6708 case 0x87: /* JNBEb/JAb (jump not below or equal) */
6709 case 0x88: /* JSb (jump negative) */
6710 case 0x89: /* JSb (jump not negative) */
6711 case 0x8A: /* JP (jump parity even) */
sewardj969129d2002-04-21 11:43:11 +00006712 case 0x8B: /* JNP/JPO (jump parity odd) */
sewardjde4a1d02002-03-22 01:27:54 +00006713 case 0x8C: /* JLb/JNGEb (jump less) */
6714 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
6715 case 0x8E: /* JLEb/JNGb (jump less or equal) */
6716 case 0x8F: /* JGb/JNLEb (jump greater) */
6717 d32 = (eip+4) + getUDisp32(eip); eip += 4;
nethercotee8601122004-01-26 17:14:17 +00006718 jcc_lit(cb, d32, (Condcode)(opc - 0x80));
6719 jmp_lit(cb, eip);
sewardjde4a1d02002-03-22 01:27:54 +00006720 *isEnd = True;
nethercotee8601122004-01-26 17:14:17 +00006721 DIP("j%s-32 0x%x\n", VG_(name_UCondcode)(opc - 0x80), d32);
sewardjde4a1d02002-03-22 01:27:54 +00006722 break;
6723
6724 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
6725
6726 case 0x31: /* RDTSC */
6727 t1 = newTemp(cb);
6728 t2 = newTemp(cb);
6729 t3 = newTemp(cb);
6730 uInstr0(cb, CALLM_S, 0);
nethercote165ad332004-04-16 22:21:18 +00006731 // Nb: even though these args aren't used by RDTSC_helper, need
6732 // them to be defined (for Memcheck). The TempRegs pushed must
6733 // also be distinct.
sewardjde4a1d02002-03-22 01:27:54 +00006734 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
6735 uLiteral(cb, 0);
6736 uInstr1(cb, PUSH, 4, TempReg, t1);
6737 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
6738 uLiteral(cb, 0);
6739 uInstr1(cb, PUSH, 4, TempReg, t2);
6740 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_RDTSC));
6741 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
6742 uInstr1(cb, POP, 4, TempReg, t3);
6743 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EDX);
6744 uInstr1(cb, POP, 4, TempReg, t3);
6745 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EAX);
6746 uInstr0(cb, CALLM_E, 0);
nethercotee8601122004-01-26 17:14:17 +00006747 DIP("rdtsc\n");
sewardjde4a1d02002-03-22 01:27:54 +00006748 break;
6749
6750 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
6751 case 0x90:
6752 case 0x91:
6753 case 0x92: /* set-Bb/set-NAEb (jump below) */
6754 case 0x93: /* set-NBb/set-AEb (jump not below) */
6755 case 0x94: /* set-Zb/set-Eb (jump zero) */
6756 case 0x95: /* set-NZb/set-NEb (jump not zero) */
6757 case 0x96: /* set-BEb/set-NAb (jump below or equal) */
6758 case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
6759 case 0x98: /* set-Sb (jump negative) */
6760 case 0x99: /* set-Sb (jump not negative) */
6761 case 0x9A: /* set-P (jump parity even) */
6762 case 0x9B: /* set-NP (jump parity odd) */
6763 case 0x9C: /* set-Lb/set-NGEb (jump less) */
6764 case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
6765 case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
6766 case 0x9F: /* set-Gb/set-NLEb (jump greater) */
6767 modrm = getUChar(eip);
6768 t1 = newTemp(cb);
6769 if (epartIsReg(modrm)) {
6770 eip++;
6771 uInstr1(cb, CC2VAL, 1, TempReg, t1);
6772 uCond(cb, (Condcode)(opc-0x90));
6773 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
6774 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, eregOfRM(modrm));
nethercotee8601122004-01-26 17:14:17 +00006775 DIP("set%s %s\n", VG_(name_UCondcode)(opc-0x90),
6776 nameIReg(1,eregOfRM(modrm)));
sewardjde4a1d02002-03-22 01:27:54 +00006777 } else {
nethercotee8601122004-01-26 17:14:17 +00006778 pair = disAMode ( cb, sorb, eip, dis_buf );
sewardjde4a1d02002-03-22 01:27:54 +00006779 t2 = LOW24(pair);
6780 eip += HI8(pair);
6781 uInstr1(cb, CC2VAL, 1, TempReg, t1);
6782 uCond(cb, (Condcode)(opc-0x90));
6783 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
6784 uInstr2(cb, STORE, 1, TempReg, t1, TempReg, t2);
nethercotee8601122004-01-26 17:14:17 +00006785 DIP("set%s %s\n", VG_(name_UCondcode)(opc-0x90), dis_buf);
sewardjde4a1d02002-03-22 01:27:54 +00006786 }
6787 break;
6788
6789 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
6790
6791 case 0xA4: /* SHLDv imm8,Gv,Ev */
6792 modrm = getUChar(eip);
6793 eip = dis_SHLRD_Gv_Ev (
sewardje1042472002-09-30 12:33:11 +00006794 cb, sorb, eip, modrm, sz,
sewardjde4a1d02002-03-22 01:27:54 +00006795 Literal, getUChar(eip + lengthAMode(eip)),
6796 True );
6797 break;
6798 case 0xA5: /* SHLDv %cl,Gv,Ev */
6799 modrm = getUChar(eip);
6800 eip = dis_SHLRD_Gv_Ev (
sewardje1042472002-09-30 12:33:11 +00006801 cb, sorb, eip, modrm, sz, ArchReg, R_CL, True );
sewardjde4a1d02002-03-22 01:27:54 +00006802 break;
6803
6804 case 0xAC: /* SHRDv imm8,Gv,Ev */
6805 modrm = getUChar(eip);
6806 eip = dis_SHLRD_Gv_Ev (
sewardje1042472002-09-30 12:33:11 +00006807 cb, sorb, eip, modrm, sz,
sewardjde4a1d02002-03-22 01:27:54 +00006808 Literal, getUChar(eip + lengthAMode(eip)),
6809 False );
6810 break;
6811 case 0xAD: /* SHRDv %cl,Gv,Ev */
6812 modrm = getUChar(eip);
6813 eip = dis_SHLRD_Gv_Ev (
sewardje1042472002-09-30 12:33:11 +00006814 cb, sorb, eip, modrm, sz, ArchReg, R_CL, False );
sewardjde4a1d02002-03-22 01:27:54 +00006815 break;
6816
6817 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
6818
nethercote1018bdd2004-02-11 23:33:29 +00006819 case 0xC0: /* XADD Gb,Eb */
6820 eip = dis_xadd_G_E ( cb, sorb, 1, eip );
6821 break;
sewardjde4a1d02002-03-22 01:27:54 +00006822 case 0xC1: /* XADD Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00006823 eip = dis_xadd_G_E ( cb, sorb, sz, eip );
sewardjde4a1d02002-03-22 01:27:54 +00006824 break;
6825
sewardj3d7c9c82003-03-26 21:08:13 +00006826 /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
6827
muellerc29dcb52003-11-20 20:45:51 +00006828 case 0x0D: /* PREFETCH / PREFETCHW - 3Dnow!ery*/
sewardjca860012003-03-27 23:52:58 +00006829 case 0x18: /* PREFETCHT0/PREFETCHT1/PREFETCHT2/PREFETCHNTA */
muellerc29dcb52003-11-20 20:45:51 +00006830
sewardjca860012003-03-27 23:52:58 +00006831 vg_assert(sz == 4);
6832 modrm = getUChar(eip);
6833 if (epartIsReg(modrm)) {
sewardja60be0e2003-05-26 08:47:27 +00006834 goto decode_failure;
sewardjca860012003-03-27 23:52:58 +00006835 }
6836 if (gregOfRM(modrm) > 3) {
sewardja60be0e2003-05-26 08:47:27 +00006837 goto decode_failure;
sewardjca860012003-03-27 23:52:58 +00006838 }
6839 eip += lengthAMode(eip);
nethercotee8601122004-01-26 17:14:17 +00006840 if (VG_(print_codegen)) {
sewardjca860012003-03-27 23:52:58 +00006841 UChar* hintstr;
nethercotee8601122004-01-26 17:14:17 +00006842 if (opc == 0x0D) {
muellerc29dcb52003-11-20 20:45:51 +00006843 switch (gregOfRM(modrm)) {
6844 case 0: hintstr = ""; break;
6845 case 1: hintstr = "w"; break;
6846 default: goto decode_failure;
6847 }
6848 }
6849 else {
6850 switch (gregOfRM(modrm)) {
6851 case 0: hintstr = "nta"; break;
6852 case 1: hintstr = "t0"; break;
6853 case 2: hintstr = "t1"; break;
6854 case 3: hintstr = "t2"; break;
6855 default: goto decode_failure;
6856 }
sewardjca860012003-03-27 23:52:58 +00006857 }
6858 VG_(printf)("prefetch%s ...\n", hintstr);
6859 }
6860 break;
6861
thughes1f17f7c2004-07-25 15:43:00 +00006862 case 0xAE: /* SFENCE */
6863 vg_assert(sz == 4);
6864 modrm = getUChar(eip);
6865 if (!epartIsReg(modrm)) {
6866 goto decode_failure;
6867 }
6868 if (gregOfRM(modrm) != 7) {
6869 goto decode_failure;
6870 }
6871 eip += lengthAMode(eip);
6872 uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
6873 Lit16, (((UShort)0x0F) << 8) | (UShort)0xAE,
6874 Lit16, (UShort)modrm );
6875 DIP("sfence\n");
6876 break;
6877
nethercotee8601122004-01-26 17:14:17 +00006878 case 0x71: case 0x72: case 0x73: {
sewardja453fb02003-06-14 13:22:36 +00006879 /* (sz==4): PSLL/PSRA/PSRL mmxreg by imm8 */
6880 /* (sz==2): PSLL/PSRA/PSRL xmmreg by imm8 */
sewardja453fb02003-06-14 13:22:36 +00006881 UChar byte1, byte2, byte3, subopc, mmreg;
6882 vg_assert(sz == 4 || sz == 2);
6883 byte1 = opc; /* 0x71/72/73 */
6884 byte2 = getUChar(eip); eip++; /* amode / sub-opcode */
6885 byte3 = getUChar(eip); eip++; /* imm8 */
6886 mmreg = byte2 & 7;
sewardjca860012003-03-27 23:52:58 +00006887 subopc = (byte2 >> 3) & 7;
sewardj6b46fa82003-04-01 23:20:43 +00006888 if (subopc == 2 || subopc == 6 || subopc == 4) {
6889 /* 2 == 010 == SRL, 6 == 110 == SLL, 4 == 100 == SRA */
sewardjca860012003-03-27 23:52:58 +00006890 /* ok */
sewardj5d58cb42003-06-14 15:49:25 +00006891 } else
6892 if (sz == 2 && opc == 0x73 && (subopc == 7 || subopc == 3)) {
6893 /* 3 == PSRLDQ, 7 == PSLLDQ */
6894 /* This is allowable in SSE. Because sz==2 we fall thru to
6895 SSE5 below. */
sewardjca860012003-03-27 23:52:58 +00006896 } else {
sewardja453fb02003-06-14 13:22:36 +00006897 eip -= (sz==2 ? 3 : 2);
sewardja60be0e2003-05-26 08:47:27 +00006898 goto decode_failure;
sewardjca860012003-03-27 23:52:58 +00006899 }
sewardja453fb02003-06-14 13:22:36 +00006900 if (sz == 4) {
6901 /* The leading 0x0F is implied for MMX*, so we don't
6902 include it. */
6903 uInstr2(cb, MMX3, 0,
6904 Lit16, (((UShort)byte1) << 8) | ((UShort)byte2),
6905 Lit16, ((UShort)byte3) );
nethercotee8601122004-01-26 17:14:17 +00006906 DIP("ps%s%s $%d, %s\n",
6907 ( subopc == 2 ? "rl"
6908 : subopc == 6 ? "ll"
6909 : subopc == 4 ? "ra"
6910 : "??"),
6911 nameMMXGran(opc & 3), (Int)byte3, nameMMXReg(mmreg) );
sewardja453fb02003-06-14 13:22:36 +00006912 } else {
6913 /* Whereas we have to include it for SSE. */
6914 uInstr3(cb, SSE5, 0,
6915 Lit16, (((UShort)0x66) << 8) | ((UShort)0x0F),
6916 Lit16, (((UShort)byte1) << 8) | ((UShort)byte2),
6917 Lit16, ((UShort)byte3) );
nethercotee8601122004-01-26 17:14:17 +00006918 DIP("ps%s%s $%d, %s\n",
6919 ( subopc == 2 ? "rl"
6920 : subopc == 6 ? "ll"
6921 : subopc == 4 ? "ra"
6922 : subopc == 3 ? "(PSRLDQ)"
6923 : subopc == 7 ? "(PSLLDQ)"
6924 : "??"),
6925 nameMMXGran(opc & 3), (Int)byte3, nameXMMReg(mmreg) );
sewardja453fb02003-06-14 13:22:36 +00006926 }
sewardjca860012003-03-27 23:52:58 +00006927 break;
nethercotee8601122004-01-26 17:14:17 +00006928 }
sewardjca860012003-03-27 23:52:58 +00006929
sewardj3d7c9c82003-03-26 21:08:13 +00006930 case 0x77: /* EMMS */
6931 vg_assert(sz == 4);
6932 uInstr1(cb, MMX1, 0, Lit16, ((UShort)(opc)) );
nethercotee8601122004-01-26 17:14:17 +00006933 DIP("emms\n");
sewardj3d7c9c82003-03-26 21:08:13 +00006934 break;
6935
sewardjd1c9e432003-04-04 20:40:34 +00006936 case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
6937 vg_assert(sz == 4);
6938 modrm = getUChar(eip);
6939 if (epartIsReg(modrm)) {
6940 eip++;
6941 t1 = newTemp(cb);
sewardj4fbe6e92003-06-15 21:54:34 +00006942 uInstr2(cb, MMX2_ERegWr, 4,
sewardjd1c9e432003-04-04 20:40:34 +00006943 Lit16,
6944 (((UShort)(opc)) << 8) | ((UShort)modrm),
6945 TempReg, t1 );
6946 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, eregOfRM(modrm));
nethercotee8601122004-01-26 17:14:17 +00006947 DIP("movd %s, %s\n",
6948 nameMMXReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm)));
sewardjd1c9e432003-04-04 20:40:34 +00006949 } else {
6950 Int tmpa;
nethercotee8601122004-01-26 17:14:17 +00006951 pair = disAMode ( cb, sorb, eip, dis_buf );
sewardjd1c9e432003-04-04 20:40:34 +00006952 tmpa = LOW24(pair);
6953 eip += HI8(pair);
6954 uInstr2(cb, MMX2_MemWr, 4,
6955 Lit16,
6956 (((UShort)(opc)) << 8) | ((UShort)modrm),
6957 TempReg, tmpa);
nethercotee8601122004-01-26 17:14:17 +00006958 DIP("movd %s, %s\n", nameMMXReg(gregOfRM(modrm)), dis_buf);
sewardjd1c9e432003-04-04 20:40:34 +00006959 }
6960 break;
6961
sewardjca860012003-03-27 23:52:58 +00006962 case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
6963 vg_assert(sz == 4);
6964 modrm = getUChar(eip);
6965 if (epartIsReg(modrm)) {
6966 eip++;
6967 t1 = newTemp(cb);
6968 uInstr2(cb, GET, 4, ArchReg, eregOfRM(modrm), TempReg, t1);
sewardj4fbe6e92003-06-15 21:54:34 +00006969 uInstr2(cb, MMX2_ERegRd, 4,
sewardjca860012003-03-27 23:52:58 +00006970 Lit16,
6971 (((UShort)(opc)) << 8) | ((UShort)modrm),
6972 TempReg, t1 );
nethercotee8601122004-01-26 17:14:17 +00006973 DIP("movd %s, %s\n",
6974 nameIReg(4,eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
sewardjca860012003-03-27 23:52:58 +00006975 } else {
6976 Int tmpa;
nethercotee8601122004-01-26 17:14:17 +00006977 pair = disAMode ( cb, sorb, eip, dis_buf );
sewardjca860012003-03-27 23:52:58 +00006978 tmpa = LOW24(pair);
6979 eip += HI8(pair);
sewardjd7971012003-04-04 00:21:58 +00006980 uInstr2(cb, MMX2_MemRd, 4,
sewardjca860012003-03-27 23:52:58 +00006981 Lit16,
6982 (((UShort)(opc)) << 8) | ((UShort)modrm),
6983 TempReg, tmpa);
nethercotee8601122004-01-26 17:14:17 +00006984 DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregOfRM(modrm)));
sewardjca860012003-03-27 23:52:58 +00006985 }
6986 break;
6987
sewardj3d7c9c82003-03-26 21:08:13 +00006988 case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
6989 vg_assert(sz == 4);
6990 modrm = getUChar(eip);
6991 if (epartIsReg(modrm)) {
sewardjca860012003-03-27 23:52:58 +00006992 eip++;
sewardj3d7c9c82003-03-26 21:08:13 +00006993 uInstr1(cb, MMX2, 0,
6994 Lit16,
6995 (((UShort)(opc)) << 8) | ((UShort)modrm) );
nethercotee8601122004-01-26 17:14:17 +00006996 DIP("movq %s, %s\n",
6997 nameMMXReg(eregOfRM(modrm)), nameMMXReg(gregOfRM(modrm)));
sewardj3d7c9c82003-03-26 21:08:13 +00006998 } else {
sewardj6b627da2003-03-27 07:48:28 +00006999 Int tmpa;
nethercotee8601122004-01-26 17:14:17 +00007000 pair = disAMode ( cb, sorb, eip, dis_buf );
sewardj6b627da2003-03-27 07:48:28 +00007001 tmpa = LOW24(pair);
sewardj3d7c9c82003-03-26 21:08:13 +00007002 eip += HI8(pair);
7003 uInstr2(cb, MMX2_MemRd, 8,
7004 Lit16,
7005 (((UShort)(opc)) << 8) | ((UShort)modrm),
7006 TempReg, tmpa);
nethercotee8601122004-01-26 17:14:17 +00007007 DIP("movq %s, %s\n",
7008 dis_buf, nameMMXReg(gregOfRM(modrm)));
sewardj3d7c9c82003-03-26 21:08:13 +00007009 }
7010 break;
7011
7012 case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
daywalker5d945de2003-09-26 00:32:53 +00007013 case 0xE7: /* MOVNTQ (src)mmxreg, (dst)mmxreg-or-mem */
sewardj3d7c9c82003-03-26 21:08:13 +00007014 vg_assert(sz == 4);
7015 modrm = getUChar(eip);
7016 if (epartIsReg(modrm)) {
nethercote46c7b8d2004-01-20 22:28:26 +00007017 eip++;
7018 uInstr1(cb, MMX2, 0,
7019 Lit16,
7020 (((UShort)(opc)) << 8) | ((UShort)modrm) );
nethercotee8601122004-01-26 17:14:17 +00007021 DIP("movq %s, %s\n",
7022 nameMMXReg(gregOfRM(modrm)), nameMMXReg(eregOfRM(modrm)));
sewardj3d7c9c82003-03-26 21:08:13 +00007023 } else {
sewardj1ef2b1d2003-03-27 00:39:21 +00007024 Int tmpa;
nethercotee8601122004-01-26 17:14:17 +00007025 pair = disAMode ( cb, sorb, eip, dis_buf );
sewardj1ef2b1d2003-03-27 00:39:21 +00007026 tmpa = LOW24(pair);
sewardj3d7c9c82003-03-26 21:08:13 +00007027 eip += HI8(pair);
7028 uInstr2(cb, MMX2_MemWr, 8,
7029 Lit16,
7030 (((UShort)(opc)) << 8) | ((UShort)modrm),
7031 TempReg, tmpa);
nethercotee8601122004-01-26 17:14:17 +00007032 DIP("mov(nt)q %s, %s\n",
7033 nameMMXReg(gregOfRM(modrm)), dis_buf);
sewardj3d7c9c82003-03-26 21:08:13 +00007034 }
7035 break;
7036
7037 case 0xFC: case 0xFD: case 0xFE:
7038 /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
7039 vg_assert(sz == 4);
7040 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "padd", True );
7041 break;
7042
nethercoteb1affa82004-01-19 19:14:18 +00007043 case 0xD4:
7044 /* PADDQ (src)mmxreg-or-mem, (dst)mmxreg */
7045 vg_assert(sz == 4);
7046 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "paddq", False );
7047 break;
7048
sewardj3d7c9c82003-03-26 21:08:13 +00007049 case 0xEC: case 0xED:
7050 /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
7051 vg_assert(sz == 4);
7052 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "padds", True );
7053 break;
7054
7055 case 0xDC: case 0xDD:
7056 /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
7057 vg_assert(sz == 4);
7058 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "paddus", True );
7059 break;
7060
nethercoteb1affa82004-01-19 19:14:18 +00007061 case 0xF8: case 0xF9: case 0xFA: case 0xFB:
sewardj3d7c9c82003-03-26 21:08:13 +00007062 /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
7063 vg_assert(sz == 4);
7064 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psub", True );
7065 break;
7066
7067 case 0xE8: case 0xE9:
7068 /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
7069 vg_assert(sz == 4);
7070 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psubs", True );
7071 break;
7072
7073 case 0xD8: case 0xD9:
7074 /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
7075 vg_assert(sz == 4);
7076 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psubus", True );
7077 break;
7078
nethercoteb1affa82004-01-19 19:14:18 +00007079 case 0xE4: /* PMULHUW (src)mmxreg-or-mem, (dst)mmxreg */
7080 vg_assert(sz == 4);
7081 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmulhuw", False );
7082 break;
7083
sewardj3d7c9c82003-03-26 21:08:13 +00007084 case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
7085 vg_assert(sz == 4);
7086 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmulhw", False );
7087 break;
7088
7089 case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
7090 vg_assert(sz == 4);
7091 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmullw", False );
7092 break;
7093
nethercoteb1affa82004-01-19 19:14:18 +00007094 case 0xF4: /* PMULUDQ (src)mmxreg-or-mem, (dst)mmxreg */
7095 vg_assert(sz == 4);
7096 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmuludq", False );
7097 break;
7098
sewardj3d7c9c82003-03-26 21:08:13 +00007099 case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
7100 vg_assert(sz == 4);
7101 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmaddwd", False );
7102 break;
7103
7104 case 0x74: case 0x75: case 0x76:
7105 /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
7106 vg_assert(sz == 4);
7107 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pcmpeq", True );
7108 break;
7109
7110 case 0x64: case 0x65: case 0x66:
7111 /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
7112 vg_assert(sz == 4);
7113 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pcmpgt", True );
7114 break;
7115
7116 case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
7117 vg_assert(sz == 4);
7118 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "packssdw", False );
7119 break;
7120
7121 case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
7122 vg_assert(sz == 4);
7123 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "packsswb", False );
7124 break;
7125
7126 case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
7127 vg_assert(sz == 4);
7128 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "packuswb", False );
7129 break;
7130
7131 case 0x68: case 0x69: case 0x6A:
7132 /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
7133 vg_assert(sz == 4);
7134 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "punpckh", True );
7135 break;
7136
7137 case 0x60: case 0x61: case 0x62:
7138 /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
7139 vg_assert(sz == 4);
7140 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "punpckl", True );
7141 break;
7142
7143 case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
7144 vg_assert(sz == 4);
7145 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pand", False );
7146 break;
7147
7148 case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
7149 vg_assert(sz == 4);
7150 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pandn", False );
7151 break;
7152
7153 case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
7154 vg_assert(sz == 4);
7155 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "por", False );
7156 break;
7157
7158 case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
7159 vg_assert(sz == 4);
7160 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pxor", False );
7161 break;
7162
7163 case 0xF1: case 0xF2: case 0xF3:
7164 /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
7165 vg_assert(sz == 4);
7166 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psll", True );
7167 break;
7168
7169 case 0xD1: case 0xD2: case 0xD3:
7170 /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
7171 vg_assert(sz == 4);
7172 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psrl", True );
7173 break;
7174
7175 case 0xE1: case 0xE2:
7176 /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
7177 vg_assert(sz == 4);
7178 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psra", True );
7179 break;
7180
nethercoteb1affa82004-01-19 19:14:18 +00007181 case 0xDA:
7182 /* PMINUB (src)mmxreg-or-mem, (dst)mmxreg */
7183 vg_assert(sz == 4);
7184 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pminub", False );
7185 break;
7186
7187 case 0xDE:
7188 /* PMAXUB (src)mmxreg-or-mem, (dst)mmxreg */
7189 vg_assert(sz == 4);
7190 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmaxub", False );
7191 break;
7192
7193 case 0xEA:
7194 /* PMINSW (src)mmxreg-or-mem, (dst)mmxreg */
7195 vg_assert(sz == 4);
7196 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pminsw", False );
7197 break;
7198
7199 case 0xEE:
7200 /* PMAXSW (src)mmxreg-or-mem, (dst)mmxreg */
7201 vg_assert(sz == 4);
7202 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pmaxsw", False );
7203 break;
7204
7205 case 0xE0:
7206 /* PAVGB (src)mmxreg-or-mem, (dst)mmxreg */
7207 vg_assert(sz == 4);
7208 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pavgb", False );
7209 break;
7210
7211 case 0xE3:
7212 /* PAVGW (src)mmxreg-or-mem, (dst)mmxreg */
7213 vg_assert(sz == 4);
7214 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "pavgw", False );
7215 break;
7216
7217 case 0xF6:
7218 /* PSADBW (src)mmxreg-or-mem, (dst)mmxreg */
7219 vg_assert(sz == 4);
7220 eip = dis_MMXop_regmem_to_reg ( cb, sorb, eip, opc, "psadbw", False );
7221 break;
7222
thughes96b466a2004-03-15 16:43:58 +00007223 case 0x70:
7224 /* PSHUFW imm8, (src)mmxreg-or-mem, (dst)mmxreg */
7225 vg_assert(sz == 4);
7226 eip = dis_MMXop_regmem_to_reg_Imm8 ( cb, sorb, eip, opc, "pshufw", False );
7227 break;
7228
nethercoteb1affa82004-01-19 19:14:18 +00007229 case 0xD7:
7230 /* PMOVMSKB (src)mmxreg, (dst)ireg */
7231 vg_assert(sz == 4);
7232 modrm = getUChar(eip);
7233 vg_assert(epartIsReg(modrm));
7234 t1 = newTemp(cb);
7235 uInstr3(cb, SSE2g_RegWr, 4,
7236 Lit16, (((UShort)(0x0F)) << 8) | (UShort)(opc),
7237 Lit16, (UShort)modrm,
7238 TempReg, t1 );
7239 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
nethercotee8601122004-01-26 17:14:17 +00007240 DIP("pmovmskb %s, %s\n",
7241 nameMMXReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm)));
nethercoteb1affa82004-01-19 19:14:18 +00007242 eip++;
7243 break;
7244
7245 case 0xC5:
7246 /* PEXTRW (src)mmxreg, (dst)ireg */
7247 vg_assert(sz == 4);
7248 t1 = newTemp(cb);
7249 modrm = getUChar(eip); eip++;
7250 abyte = getUChar(eip); eip++;
7251 vg_assert(epartIsReg(modrm));
7252 uInstr3(cb, SSE2g1_RegWr, 4,
7253 Lit16, (((UShort)(0x0F)) << 8) | (UShort)(opc),
7254 Lit16, (UShort)modrm,
7255 TempReg, t1 );
7256 uLiteral(cb, abyte);
7257 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, gregOfRM(modrm));
nethercotee8601122004-01-26 17:14:17 +00007258 DIP("pextrw %s, %d, %s\n",
7259 nameMMXReg(eregOfRM(modrm)), (Int)abyte,
7260 nameIReg(4, gregOfRM(modrm)));
nethercoteb1affa82004-01-19 19:14:18 +00007261 break;
7262
7263 case 0xC4:
7264 /* PINSRW (src)ireg, (dst)mmxreg */
7265 vg_assert(sz == 4);
7266 t1 = newTemp(cb);
7267 modrm = getUChar(eip); eip++;
7268 abyte = getUChar(eip); eip++;
7269 vg_assert(epartIsReg(modrm));
7270 uInstr2(cb, GET, 2, ArchReg, eregOfRM(modrm), TempReg, t1);
7271 uInstr3(cb, SSE2e1_RegRd, 2,
7272 Lit16, (((UShort)(0x0F)) << 8) | (UShort)(opc),
7273 Lit16, (UShort)modrm,
7274 TempReg, t1 );
7275 uLiteral(cb, abyte);
nethercotee8601122004-01-26 17:14:17 +00007276 DIP("pinsrw %s, %d, %s\n", nameIReg(2, eregOfRM(modrm)),
7277 (Int)abyte, nameMMXReg(gregOfRM(modrm)));
nethercoteb1affa82004-01-19 19:14:18 +00007278 break;
7279
nethercote561f6e02003-11-02 17:00:23 +00007280 case 0xA1: /* POP %FS */
7281 dis_pop_segreg( cb, R_FS, sz ); break;
7282 case 0xA9: /* POP %GS */
7283 dis_pop_segreg( cb, R_GS, sz ); break;
7284
7285 case 0xA0: /* PUSH %FS */
7286 dis_push_segreg( cb, R_FS, sz ); break;
7287 case 0xA8: /* PUSH %GS */
7288 dis_push_segreg( cb, R_GS, sz ); break;
7289
sewardjde4a1d02002-03-22 01:27:54 +00007290 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
7291
7292 default:
sewardja60be0e2003-05-26 08:47:27 +00007293 goto decode_failure;
7294 } /* switch (opc) for the 2-byte opcodes */
7295 goto decode_success;
7296 } /* case 0x0F: of primary opcode */
sewardjde4a1d02002-03-22 01:27:54 +00007297
7298 /* ------------------------ ??? ------------------------ */
sewardja60be0e2003-05-26 08:47:27 +00007299
7300 default:
7301 decode_failure:
7302 /* All decode failures end up here. */
7303 VG_(printf)("disInstr: unhandled instruction bytes: "
7304 "0x%x 0x%x 0x%x 0x%x\n",
7305 (Int)eip_start[0],
7306 (Int)eip_start[1],
7307 (Int)eip_start[2],
7308 (Int)eip_start[3] );
sewardjde4a1d02002-03-22 01:27:54 +00007309
njn6c846552003-09-16 07:41:43 +00007310 /* Print address of failing instruction. */
njn7fd598c2003-09-18 08:37:20 +00007311 VG_(describe_eip)((Addr)eip_start, loc_buf, M_VG_ERRTXT);
njn6c846552003-09-16 07:41:43 +00007312 VG_(printf)(" at %s\n", loc_buf);
7313
sewardja60be0e2003-05-26 08:47:27 +00007314 uInstr0(cb, CALLM_S, 0);
7315 uInstr1(cb, CALLM, 0, Lit16,
7316 VGOFF_(helper_undefined_instruction));
7317 uInstr0(cb, CALLM_E, 0);
sewardjde4a1d02002-03-22 01:27:54 +00007318
sewardja60be0e2003-05-26 08:47:27 +00007319 /* just because everything else insists the last instruction of
7320 a BB is a jmp */
nethercotee8601122004-01-26 17:14:17 +00007321 jmp_lit(cb, eip);
sewardja60be0e2003-05-26 08:47:27 +00007322 *isEnd = True;
7323 break;
7324 return eip;
7325
7326 } /* switch (opc) for the main (primary) opcode switch. */
7327
7328 decode_success:
7329 /* All decode successes end up here. */
nethercotee8601122004-01-26 17:14:17 +00007330 DIP("\n");
sewardjde4a1d02002-03-22 01:27:54 +00007331 for (; first_uinstr < cb->used; first_uinstr++) {
nethercote885dd912004-08-03 23:14:00 +00007332 VG_(sanity_check_UInstr)( first_uinstr, &cb->instrs[first_uinstr] );
7333 if (VG_(print_codegen))
njn4ba5a792002-09-30 10:23:54 +00007334 VG_(pp_UInstr)(first_uinstr, &cb->instrs[first_uinstr]);
sewardjde4a1d02002-03-22 01:27:54 +00007335 }
sewardjde4a1d02002-03-22 01:27:54 +00007336 return eip;
7337}
7338
7339
7340/* Disassemble a complete basic block, starting at eip, and dumping
7341 the ucode into cb. Returns the size, in bytes, of the basic
7342 block. */
7343
7344Int VG_(disBB) ( UCodeBlock* cb, Addr eip0 )
7345{
7346 Addr eip = eip0;
7347 Bool isEnd = False;
njn4f9c9342002-04-29 16:03:24 +00007348 Int delta = 0;
7349
nethercotee8601122004-01-26 17:14:17 +00007350 DIP("Original x86 code to UCode:\n\n");
sewardjde4a1d02002-03-22 01:27:54 +00007351
njn25e49d8e72002-09-23 09:36:25 +00007352 /* After every x86 instruction do an INCEIP, except for the final one
7353 * in the basic block. For them we patch in the x86 instruction size
7354 * into the `extra4b' field of the basic-block-ending JMP.
njn4f9c9342002-04-29 16:03:24 +00007355 *
nethercote7cc9c232004-01-21 15:08:04 +00007356 * The INCEIPs and JMP.extra4b fields allows a tool to track x86
7357 * instruction sizes, important for some tools (eg. Cachegrind).
njn4f9c9342002-04-29 16:03:24 +00007358 */
sewardjde4a1d02002-03-22 01:27:54 +00007359 if (VG_(clo_single_step)) {
7360 eip = disInstr ( cb, eip, &isEnd );
njn4f9c9342002-04-29 16:03:24 +00007361
7362 /* Add a JMP to the next (single x86 instruction) BB if it doesn't
7363 * already end with a JMP instr. We also need to check for no UCode,
7364 * which occurs if the x86 instr was a nop */
7365 if (cb->used == 0 || LAST_UINSTR(cb).opcode != JMP) {
nethercotee8601122004-01-26 17:14:17 +00007366 jmp_lit(cb, eip);
njn25e49d8e72002-09-23 09:36:25 +00007367 /* Print added JMP */
nethercotee8601122004-01-26 17:14:17 +00007368 if (VG_(print_codegen))
7369 VG_(pp_UInstr)(cb->used-1, &cb->instrs[cb->used-1]);
njn4f9c9342002-04-29 16:03:24 +00007370 }
nethercotee8601122004-01-26 17:14:17 +00007371 DIP("\n");
njn4f9c9342002-04-29 16:03:24 +00007372 delta = eip - eip0;
7373
sewardjde4a1d02002-03-22 01:27:54 +00007374 } else {
sewardjde4a1d02002-03-22 01:27:54 +00007375 Addr eip2;
njn4f9c9342002-04-29 16:03:24 +00007376 while (!isEnd) {
sewardjde4a1d02002-03-22 01:27:54 +00007377 eip2 = disInstr ( cb, eip, &isEnd );
njn25e49d8e72002-09-23 09:36:25 +00007378 delta = (eip2 - eip);
sewardjde4a1d02002-03-22 01:27:54 +00007379 eip = eip2;
sewardjde4a1d02002-03-22 01:27:54 +00007380 /* Split up giant basic blocks into pieces, so the
7381 translations fall within 64k. */
njn4f9c9342002-04-29 16:03:24 +00007382 if (eip - eip0 > 2000 && !isEnd) {
sewardja0f921a2002-05-08 00:42:25 +00007383 if (VG_(clo_verbosity) > 2)
njn4f9c9342002-04-29 16:03:24 +00007384 VG_(message)(Vg_DebugMsg,
fitzhardinge98abfc72003-12-16 02:05:15 +00007385 "Warning: splitting giant basic block into pieces at %p %(y",
7386 eip, eip);
nethercotee8601122004-01-26 17:14:17 +00007387 jmp_lit(cb, eip);
njn25e49d8e72002-09-23 09:36:25 +00007388 /* Print added JMP */
nethercotee8601122004-01-26 17:14:17 +00007389 if (VG_(print_codegen))
7390 VG_(pp_UInstr)(cb->used-1, &cb->instrs[cb->used-1]);
njn4f9c9342002-04-29 16:03:24 +00007391 isEnd = True;
7392
njn25e49d8e72002-09-23 09:36:25 +00007393 } else if (!isEnd) {
njn4f9c9342002-04-29 16:03:24 +00007394 uInstr1(cb, INCEIP, 0, Lit16, delta);
njn25e49d8e72002-09-23 09:36:25 +00007395 /* Print added INCEIP */
nethercotee8601122004-01-26 17:14:17 +00007396 if (VG_(print_codegen))
7397 VG_(pp_UInstr)(cb->used-1, &cb->instrs[cb->used-1]);
sewardjde4a1d02002-03-22 01:27:54 +00007398 }
nethercotee8601122004-01-26 17:14:17 +00007399 DIP("\n");
sewardjde4a1d02002-03-22 01:27:54 +00007400 }
7401 }
sewardjde4a1d02002-03-22 01:27:54 +00007402
njn25e49d8e72002-09-23 09:36:25 +00007403 /* Patch instruction size into final JMP. */
7404 LAST_UINSTR(cb).extra4b = delta;
7405
sewardjde4a1d02002-03-22 01:27:54 +00007406 return eip - eip0;
7407}
7408
nethercotee8601122004-01-26 17:14:17 +00007409#undef DIP
7410#undef DIS
sewardjde4a1d02002-03-22 01:27:54 +00007411
7412/*--------------------------------------------------------------------*/
7413/*--- end vg_to_ucode.c ---*/
7414/*--------------------------------------------------------------------*/