blob: 60a1ec885dc7a45af4eee6b7b4534e372de2c236 [file] [log] [blame]
sewardjde4a1d02002-03-22 01:27:54 +00001
2/*--------------------------------------------------------------------*/
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
11 Copyright (C) 2000-2002 Julian Seward
12 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
32#include "vg_include.h"
33
34
35/*------------------------------------------------------------*/
36/*--- Renamings of frequently-used global functions. ---*/
37/*------------------------------------------------------------*/
38
njn25e49d8e72002-09-23 09:36:25 +000039#define dis VG_(print_codegen)
sewardjde4a1d02002-03-22 01:27:54 +000040
sewardje1042472002-09-30 12:33:11 +000041
sewardjde4a1d02002-03-22 01:27:54 +000042/*------------------------------------------------------------*/
43/*--- Here so it can be inlined everywhere. ---*/
44/*------------------------------------------------------------*/
45
46/* Allocate a new temp reg number. */
njn4ba5a792002-09-30 10:23:54 +000047__inline__ Int VG_(get_new_temp) ( UCodeBlock* cb )
sewardjde4a1d02002-03-22 01:27:54 +000048{
49 Int t = cb->nextTemp;
50 cb->nextTemp += 2;
51 return t;
52}
53
njn4ba5a792002-09-30 10:23:54 +000054Int VG_(get_new_shadow) ( UCodeBlock* cb )
sewardjde4a1d02002-03-22 01:27:54 +000055{
56 Int t = cb->nextTemp;
57 cb->nextTemp += 2;
58 return SHADOW(t);
59}
60
sewardjde4a1d02002-03-22 01:27:54 +000061
62/*------------------------------------------------------------*/
63/*--- Helper bits and pieces for deconstructing the ---*/
64/*--- x86 insn stream. ---*/
65/*------------------------------------------------------------*/
66
67static Char* nameGrp1 ( Int opc_aux )
68{
69 static Char* grp1_names[8]
70 = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
njne427a662002-10-02 11:08:25 +000071 if (opc_aux < 0 || opc_aux > 7) VG_(core_panic)("nameGrp1");
sewardjde4a1d02002-03-22 01:27:54 +000072 return grp1_names[opc_aux];
73}
74
75static Char* nameGrp2 ( Int opc_aux )
76{
77 static Char* grp2_names[8]
78 = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
njne427a662002-10-02 11:08:25 +000079 if (opc_aux < 0 || opc_aux > 7) VG_(core_panic)("nameGrp2");
sewardjde4a1d02002-03-22 01:27:54 +000080 return grp2_names[opc_aux];
81}
82
83static Char* nameGrp4 ( Int opc_aux )
84{
85 static Char* grp4_names[8]
86 = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
njne427a662002-10-02 11:08:25 +000087 if (opc_aux < 0 || opc_aux > 1) VG_(core_panic)("nameGrp4");
sewardjde4a1d02002-03-22 01:27:54 +000088 return grp4_names[opc_aux];
89}
90
91static Char* nameGrp5 ( Int opc_aux )
92{
93 static Char* grp5_names[8]
94 = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
njne427a662002-10-02 11:08:25 +000095 if (opc_aux < 0 || opc_aux > 6) VG_(core_panic)("nameGrp5");
sewardjde4a1d02002-03-22 01:27:54 +000096 return grp5_names[opc_aux];
97}
98
99static Char* nameGrp8 ( Int opc_aux )
100{
101 static Char* grp8_names[8]
102 = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
njne427a662002-10-02 11:08:25 +0000103 if (opc_aux < 4 || opc_aux > 7) VG_(core_panic)("nameGrp8");
sewardjde4a1d02002-03-22 01:27:54 +0000104 return grp8_names[opc_aux];
105}
106
njn4ba5a792002-09-30 10:23:54 +0000107Char* VG_(name_of_int_reg) ( Int size, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000108{
109 static Char* ireg32_names[8]
110 = { "%eax", "%ecx", "%edx", "%ebx",
111 "%esp", "%ebp", "%esi", "%edi" };
112 static Char* ireg16_names[8]
113 = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di" };
114 static Char* ireg8_names[8]
115 = { "%al", "%cl", "%dl", "%bl", "%ah{sp}", "%ch{bp}", "%dh{si}", "%bh{di}" };
116 if (reg < 0 || reg > 7) goto bad;
117 switch (size) {
118 case 4: return ireg32_names[reg];
119 case 2: return ireg16_names[reg];
120 case 1: return ireg8_names[reg];
121 }
122 bad:
njne427a662002-10-02 11:08:25 +0000123 VG_(core_panic)("name_of_int_reg");
sewardjde4a1d02002-03-22 01:27:54 +0000124 return NULL; /*notreached*/
125}
126
sewardje1042472002-09-30 12:33:11 +0000127Char* VG_(name_of_seg_reg) ( Int sreg )
128{
129 switch (sreg) {
130 case R_ES: return "%es";
131 case R_CS: return "%cs";
132 case R_SS: return "%ss";
133 case R_DS: return "%ds";
134 case R_FS: return "%fs";
135 case R_GS: return "%gs";
njne427a662002-10-02 11:08:25 +0000136 default: VG_(core_panic)("nameOfSegReg");
sewardje1042472002-09-30 12:33:11 +0000137 }
138}
139
njn4ba5a792002-09-30 10:23:54 +0000140Char VG_(name_of_int_size) ( Int size )
sewardjde4a1d02002-03-22 01:27:54 +0000141{
142 switch (size) {
143 case 4: return 'l';
144 case 2: return 'w';
145 case 1: return 'b';
njne427a662002-10-02 11:08:25 +0000146 default: VG_(core_panic)("name_of_int_size");
sewardjde4a1d02002-03-22 01:27:54 +0000147 }
148}
149
150__inline__ UInt VG_(extend_s_8to32) ( UInt x )
151{
152 return (UInt)((((Int)x) << 24) >> 24);
153}
154
155__inline__ static UInt extend_s_16to32 ( UInt x )
156{
157 return (UInt)((((Int)x) << 16) >> 16);
158}
159
160
161/* Get a byte value out of the insn stream and sign-extend to 32
162 bits. */
163__inline__ static UInt getSDisp8 ( Addr eip0 )
164{
165 UChar* eip = (UChar*)eip0;
166 return VG_(extend_s_8to32)( (UInt) (eip[0]) );
167}
168
169__inline__ static UInt getSDisp16 ( Addr eip0 )
170{
171 UChar* eip = (UChar*)eip0;
172 UInt d = *eip++;
173 d |= ((*eip++) << 8);
174 return extend_s_16to32(d);
175}
176
177/* Get a 32-bit value out of the insn stream. */
178__inline__ static UInt getUDisp32 ( Addr eip0 )
179{
180 UChar* eip = (UChar*)eip0;
181 UInt v = eip[3]; v <<= 8;
182 v |= eip[2]; v <<= 8;
183 v |= eip[1]; v <<= 8;
184 v |= eip[0];
185 return v;
186}
187
188__inline__ static UInt getUDisp16 ( Addr eip0 )
189{
190 UChar* eip = (UChar*)eip0;
191 UInt v = eip[1]; v <<= 8;
192 v |= eip[0];
193 return v;
194}
195
196__inline__ static UChar getUChar ( Addr eip0 )
197{
198 UChar* eip = (UChar*)eip0;
199 return eip[0];
200}
201
202__inline__ static UInt LOW24 ( UInt x )
203{
204 return x & 0x00FFFFFF;
205}
206
207__inline__ static UInt HI8 ( UInt x )
208{
209 return x >> 24;
210}
211
212__inline__ static UInt getUDisp ( Int size, Addr eip )
213{
214 switch (size) {
215 case 4: return getUDisp32(eip);
216 case 2: return getUDisp16(eip);
217 case 1: return getUChar(eip);
njne427a662002-10-02 11:08:25 +0000218 default: VG_(core_panic)("getUDisp");
sewardjde4a1d02002-03-22 01:27:54 +0000219 }
220 return 0; /*notreached*/
221}
222
223__inline__ static UInt getSDisp ( Int size, Addr eip )
224{
225 switch (size) {
226 case 4: return getUDisp32(eip);
227 case 2: return getSDisp16(eip);
228 case 1: return getSDisp8(eip);
njne427a662002-10-02 11:08:25 +0000229 default: VG_(core_panic)("getUDisp");
sewardjde4a1d02002-03-22 01:27:54 +0000230 }
231 return 0; /*notreached*/
232}
233
234
235/*------------------------------------------------------------*/
236/*--- Flag-related helpers. ---*/
237/*------------------------------------------------------------*/
238
sewardjde4a1d02002-03-22 01:27:54 +0000239static void setFlagsFromUOpcode ( UCodeBlock* cb, Int uopc )
240{
241 switch (uopc) {
242 case XOR: case OR: case AND:
243 uFlagsRWU(cb, FlagsEmpty, FlagsOSZCP, FlagA); break;
244 case ADC: case SBB:
245 uFlagsRWU(cb, FlagC, FlagsOSZACP, FlagsEmpty); break;
246 case ADD: case SUB: case NEG:
247 uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty); break;
248 case INC: case DEC:
249 uFlagsRWU(cb, FlagsEmpty, FlagsOSZAP, FlagsEmpty); break;
250 case SHR: case SAR: case SHL:
251 uFlagsRWU(cb, FlagsEmpty, FlagsOSZCP, FlagA); break;
252 case ROL: case ROR:
253 uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsEmpty); break;
254 case RCR: case RCL:
255 uFlagsRWU(cb, FlagC, FlagsOC, FlagsEmpty); break;
256 case NOT:
257 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty); break;
258 default:
259 VG_(printf)("unhandled case is %s\n",
njn4ba5a792002-09-30 10:23:54 +0000260 VG_(name_UOpcode)(True, uopc));
njne427a662002-10-02 11:08:25 +0000261 VG_(core_panic)("setFlagsFromUOpcode: unhandled case");
sewardjde4a1d02002-03-22 01:27:54 +0000262 }
263}
264
njn810086f2002-11-14 12:42:47 +0000265__inline__
266void VG_(set_cond_field) ( UCodeBlock* cb, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +0000267{
268 LAST_UINSTR(cb).cond = cond;
269}
270
271
272/*------------------------------------------------------------*/
273/*--- Disassembling addressing modes ---*/
274/*------------------------------------------------------------*/
275
sewardje1042472002-09-30 12:33:11 +0000276static
277UChar* sorbTxt ( UChar sorb )
278{
279 switch (sorb) {
280 case 0: return ""; /* no override */
281 case 0x3E: return "%ds";
282 case 0x26: return "%es:";
283 case 0x64: return "%fs:";
284 case 0x65: return "%gs:";
njne427a662002-10-02 11:08:25 +0000285 default: VG_(core_panic)("sorbTxt");
sewardje1042472002-09-30 12:33:11 +0000286 }
287}
288
289
290/* Tmp is a TempReg holding a virtual address. Convert it to a linear
291 address by adding any required segment override as indicated by
292 sorb. */
293static
294void handleSegOverride ( UCodeBlock* cb, UChar sorb, Int tmp )
295{
296 Int sreg, tsreg;
297
298 if (sorb == 0)
299 /* the common case - no override */
300 return;
301
302 switch (sorb) {
303 case 0x3E: sreg = R_DS; break;
304 case 0x26: sreg = R_ES; break;
305 case 0x64: sreg = R_FS; break;
306 case 0x65: sreg = R_GS; break;
njne427a662002-10-02 11:08:25 +0000307 default: VG_(core_panic)("handleSegOverride");
sewardje1042472002-09-30 12:33:11 +0000308 }
309
310 tsreg = newTemp(cb);
311
312 /* sreg -> tsreg */
313 uInstr2(cb, GETSEG, 2, ArchRegS, sreg, TempReg, tsreg );
314
315 /* tmp += segment_base(ldt[tsreg]); also do limit check */
316 uInstr2(cb, USESEG, 0, TempReg, tsreg, TempReg, tmp );
317}
318
319
sewardjde4a1d02002-03-22 01:27:54 +0000320/* Generate ucode to calculate an address indicated by a ModRM and
321 following SIB bytes, getting the value in a new temporary. The
322 temporary, and the number of bytes in the address mode, are
sewardje1042472002-09-30 12:33:11 +0000323 returned, as a pair (length << 24) | temp. Note that this fn should
sewardjde4a1d02002-03-22 01:27:54 +0000324 not be called if the R/M part of the address denotes a register
325 instead of memory. If buf is non-NULL, text of the addressing mode
326 is placed therein. */
327
sewardje1042472002-09-30 12:33:11 +0000328static
329UInt disAMode ( UCodeBlock* cb, UChar sorb, Addr eip0, UChar* buf )
sewardjde4a1d02002-03-22 01:27:54 +0000330{
331 UChar* eip = (UChar*)eip0;
332 UChar mod_reg_rm = *eip++;
333 Int tmp = newTemp(cb);
334
335 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
336 jump table seems a bit excessive.
337 */
338 mod_reg_rm &= 0xC7; /* is now XX000YYY */
339 mod_reg_rm |= (mod_reg_rm >> 3); /* is now XX0XXYYY */
340 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
341 switch (mod_reg_rm) {
342
343 /* (%eax) .. (%edi), not including (%esp) or (%ebp).
344 --> GET %reg, t
345 */
346 case 0x00: case 0x01: case 0x02: case 0x03:
347 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
348 { UChar rm = mod_reg_rm;
349 uInstr2(cb, GET, 4, ArchReg, rm, TempReg, tmp);
sewardje1042472002-09-30 12:33:11 +0000350 handleSegOverride(cb, sorb, tmp);
351 if (buf) VG_(sprintf)(buf,"%s(%s)", sorbTxt(sorb),
352 nameIReg(4,rm));
sewardjde4a1d02002-03-22 01:27:54 +0000353 return (1<<24 | tmp);
354 }
355
356 /* d8(%eax) ... d8(%edi), not including d8(%esp)
357 --> GET %reg, t ; ADDL d8, t
358 */
359 case 0x08: case 0x09: case 0x0A: case 0x0B:
360 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
361 { UChar rm = mod_reg_rm & 7;
362 Int tmq = newTemp(cb);
363 UInt d = getSDisp8((Addr)eip); eip++;
364 uInstr2(cb, GET, 4, ArchReg, rm, TempReg, tmq);
365 uInstr2(cb, LEA1, 4, TempReg, tmq, TempReg, tmp);
366 LAST_UINSTR(cb).lit32 = d;
sewardje1042472002-09-30 12:33:11 +0000367 handleSegOverride(cb, sorb, tmp);
368 if (buf) VG_(sprintf)(buf,"%s%d(%s)", sorbTxt(sorb),
369 d, nameIReg(4,rm));
sewardjde4a1d02002-03-22 01:27:54 +0000370 return (2<<24 | tmp);
371 }
372
373 /* d32(%eax) ... d32(%edi), not including d32(%esp)
374 --> GET %reg, t ; ADDL d8, t
375 */
376 case 0x10: case 0x11: case 0x12: case 0x13:
377 /* ! 14 */ case 0x15: case 0x16: case 0x17:
378 { UChar rm = mod_reg_rm & 7;
379 Int tmq = newTemp(cb);
380 UInt d = getUDisp32((Addr)eip); eip += 4;
381 uInstr2(cb, GET, 4, ArchReg, rm, TempReg, tmq);
382 uInstr2(cb, LEA1, 4, TempReg, tmq, TempReg, tmp);
383 LAST_UINSTR(cb).lit32 = d;
sewardje1042472002-09-30 12:33:11 +0000384 handleSegOverride(cb, sorb, tmp);
385 if (buf) VG_(sprintf)(buf,"%s0x%x(%s)", sorbTxt(sorb),
386 d, nameIReg(4,rm));
sewardjde4a1d02002-03-22 01:27:54 +0000387 return (5<<24 | tmp);
388 }
389
390 /* a register, %eax .. %edi. This shouldn't happen. */
391 case 0x18: case 0x19: case 0x1A: case 0x1B:
392 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
njne427a662002-10-02 11:08:25 +0000393 VG_(core_panic)("disAMode: not an addr!");
sewardjde4a1d02002-03-22 01:27:54 +0000394
395 /* a 32-bit literal address
396 --> MOV d32, tmp
397 */
398 case 0x05:
399 { UInt d = getUDisp32((Addr)eip); eip += 4;
400 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tmp);
401 uLiteral(cb, d);
sewardje1042472002-09-30 12:33:11 +0000402 handleSegOverride(cb, sorb, tmp);
403 if (buf) VG_(sprintf)(buf,"%s(0x%x)", sorbTxt(sorb), d);
sewardjde4a1d02002-03-22 01:27:54 +0000404 return (5<<24 | tmp);
405 }
406
407 case 0x04: {
408 /* SIB, with no displacement. Special cases:
409 -- %esp cannot act as an index value.
410 If index_r indicates %esp, zero is used for the index.
411 -- when mod is zero and base indicates EBP, base is instead
412 a 32-bit literal.
413 It's all madness, I tell you. Extract %index, %base and
414 scale from the SIB byte. The value denoted is then:
415 | %index == %ESP && %base == %EBP
416 = d32 following SIB byte
417 | %index == %ESP && %base != %EBP
418 = %base
419 | %index != %ESP && %base == %EBP
420 = d32 following SIB byte + (%index << scale)
421 | %index != %ESP && %base != %ESP
422 = %base + (%index << scale)
423
424 What happens to the souls of CPU architects who dream up such
425 horrendous schemes, do you suppose?
426 */
427 UChar sib = *eip++;
428 UChar scale = (sib >> 6) & 3;
429 UChar index_r = (sib >> 3) & 7;
430 UChar base_r = sib & 7;
431
432 if (index_r != R_ESP && base_r != R_EBP) {
433 Int index_tmp = newTemp(cb);
434 Int base_tmp = newTemp(cb);
435 uInstr2(cb, GET, 4, ArchReg, index_r, TempReg, index_tmp);
436 uInstr2(cb, GET, 4, ArchReg, base_r, TempReg, base_tmp);
437 uInstr3(cb, LEA2, 4, TempReg, base_tmp, TempReg, index_tmp,
438 TempReg, tmp);
439 LAST_UINSTR(cb).lit32 = 0;
440 LAST_UINSTR(cb).extra4b = 1 << scale;
sewardje1042472002-09-30 12:33:11 +0000441 handleSegOverride(cb, sorb, tmp);
442 if (buf) VG_(sprintf)(buf,"%s(%s,%s,%d)", sorbTxt(sorb),
443 nameIReg(4,base_r),
sewardjde4a1d02002-03-22 01:27:54 +0000444 nameIReg(4,index_r),1<<scale);
445 return (2<<24 | tmp);
446 }
447
448 if (index_r != R_ESP && base_r == R_EBP) {
449 Int index_tmp = newTemp(cb);
450 UInt d = getUDisp32((Addr)eip); eip += 4;
451 uInstr2(cb, GET, 4, ArchReg, index_r, TempReg, index_tmp);
452 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tmp);
453 uLiteral(cb, 0);
454 uInstr3(cb, LEA2, 4, TempReg, tmp, TempReg, index_tmp,
455 TempReg, tmp);
456 LAST_UINSTR(cb).lit32 = d;
457 LAST_UINSTR(cb).extra4b = 1 << scale;
sewardje1042472002-09-30 12:33:11 +0000458 handleSegOverride(cb, sorb, tmp);
459 if (buf) VG_(sprintf)(buf,"%s0x%x(,%s,%d)", sorbTxt(sorb), d,
sewardjde4a1d02002-03-22 01:27:54 +0000460 nameIReg(4,index_r),1<<scale);
461 return (6<<24 | tmp);
462 }
463
464 if (index_r == R_ESP && base_r != R_EBP) {
465 uInstr2(cb, GET, 4, ArchReg, base_r, TempReg, tmp);
sewardje1042472002-09-30 12:33:11 +0000466 handleSegOverride(cb, sorb, tmp);
467 if (buf) VG_(sprintf)(buf,"%s(%s,,)",
468 sorbTxt(sorb), nameIReg(4,base_r));
sewardjde4a1d02002-03-22 01:27:54 +0000469 return (2<<24 | tmp);
470 }
471
472 if (index_r == R_ESP && base_r == R_EBP) {
473 UInt d = getUDisp32((Addr)eip); eip += 4;
474 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tmp);
475 uLiteral(cb, d);
sewardje1042472002-09-30 12:33:11 +0000476 handleSegOverride(cb, sorb, tmp);
477 if (buf) VG_(sprintf)(buf,"%s0x%x()", sorbTxt(sorb), d);
sewardjde4a1d02002-03-22 01:27:54 +0000478 return (6<<24 | tmp);
479 }
480
481 vg_assert(0);
482 }
483
484 /* SIB, with 8-bit displacement. Special cases:
485 -- %esp cannot act as an index value.
486 If index_r indicates %esp, zero is used for the index.
487 Denoted value is:
488 | %index == %ESP
489 = d8 + %base
490 | %index != %ESP
491 = d8 + %base + (%index << scale)
492 */
493 case 0x0C: {
494 UChar sib = *eip++;
495 UChar scale = (sib >> 6) & 3;
496 UChar index_r = (sib >> 3) & 7;
497 UChar base_r = sib & 7;
498 UInt d = getSDisp8((Addr)eip); eip++;
499
500 if (index_r == R_ESP) {
501 Int tmq = newTemp(cb);
502 uInstr2(cb, GET, 4, ArchReg, base_r, TempReg, tmq);
503 uInstr2(cb, LEA1, 4, TempReg, tmq, TempReg, tmp);
504 LAST_UINSTR(cb).lit32 = d;
sewardje1042472002-09-30 12:33:11 +0000505 handleSegOverride(cb, sorb, tmp);
506 if (buf) VG_(sprintf)(buf,"%s%d(%s,,)", sorbTxt(sorb),
507 d, nameIReg(4,base_r));
sewardjde4a1d02002-03-22 01:27:54 +0000508 return (3<<24 | tmp);
509 } else {
510 Int index_tmp = newTemp(cb);
511 Int base_tmp = newTemp(cb);
512 uInstr2(cb, GET, 4, ArchReg, index_r, TempReg, index_tmp);
513 uInstr2(cb, GET, 4, ArchReg, base_r, TempReg, base_tmp);
514 uInstr3(cb, LEA2, 4, TempReg, base_tmp, TempReg, index_tmp,
515 TempReg, tmp);
516 LAST_UINSTR(cb).lit32 = d;
517 LAST_UINSTR(cb).extra4b = 1 << scale;
sewardje1042472002-09-30 12:33:11 +0000518 handleSegOverride(cb, sorb, tmp);
519 if (buf) VG_(sprintf)(buf,"%s%d(%s,%s,%d)",
520 sorbTxt(sorb), d, nameIReg(4,base_r),
sewardjde4a1d02002-03-22 01:27:54 +0000521 nameIReg(4,index_r), 1<<scale);
522 return (3<<24 | tmp);
523 }
524 vg_assert(0);
525 }
526
527 /* SIB, with 32-bit displacement. Special cases:
528 -- %esp cannot act as an index value.
529 If index_r indicates %esp, zero is used for the index.
530 Denoted value is:
531 | %index == %ESP
532 = d32 + %base
533 | %index != %ESP
534 = d32 + %base + (%index << scale)
535 */
536 case 0x14: {
537 UChar sib = *eip++;
538 UChar scale = (sib >> 6) & 3;
539 UChar index_r = (sib >> 3) & 7;
540 UChar base_r = sib & 7;
541 UInt d = getUDisp32((Addr)eip); eip += 4;
542
543 if (index_r == R_ESP) {
544 Int tmq = newTemp(cb);
545 uInstr2(cb, GET, 4, ArchReg, base_r, TempReg, tmq);
546 uInstr2(cb, LEA1, 4, TempReg, tmq, TempReg, tmp);
547 LAST_UINSTR(cb).lit32 = d;
sewardje1042472002-09-30 12:33:11 +0000548 handleSegOverride(cb, sorb, tmp);
549 if (buf) VG_(sprintf)(buf,"%s%d(%s,,)",
550 sorbTxt(sorb), d, nameIReg(4,base_r));
sewardjde4a1d02002-03-22 01:27:54 +0000551 return (6<<24 | tmp);
552 } else {
553 Int index_tmp = newTemp(cb);
554 Int base_tmp = newTemp(cb);
555 uInstr2(cb, GET, 4, ArchReg, index_r, TempReg, index_tmp);
556 uInstr2(cb, GET, 4, ArchReg, base_r, TempReg, base_tmp);
557 uInstr3(cb, LEA2, 4, TempReg, base_tmp, TempReg, index_tmp,
558 TempReg, tmp);
559 LAST_UINSTR(cb).lit32 = d;
560 LAST_UINSTR(cb).extra4b = 1 << scale;
sewardje1042472002-09-30 12:33:11 +0000561 handleSegOverride(cb, sorb, tmp);
562 if (buf) VG_(sprintf)(buf,"%s%d(%s,%s,%d)",
563 sorbTxt(sorb), d, nameIReg(4,base_r),
sewardjde4a1d02002-03-22 01:27:54 +0000564 nameIReg(4,index_r), 1<<scale);
565 return (6<<24 | tmp);
566 }
567 vg_assert(0);
568 }
569
570 default:
njne427a662002-10-02 11:08:25 +0000571 VG_(core_panic)("disAMode");
sewardjde4a1d02002-03-22 01:27:54 +0000572 return 0; /*notreached*/
573 }
574}
575
576
577/* Figure out the number of (insn-stream) bytes constituting the amode
578 beginning at eip0. Is useful for getting hold of literals beyond
579 the end of the amode before it has been disassembled. */
580
581static UInt lengthAMode ( Addr eip0 )
582{
583 UChar* eip = (UChar*)eip0;
584 UChar mod_reg_rm = *eip++;
585
586 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
587 jump table seems a bit excessive.
588 */
589 mod_reg_rm &= 0xC7; /* is now XX000YYY */
590 mod_reg_rm |= (mod_reg_rm >> 3); /* is now XX0XXYYY */
591 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
592 switch (mod_reg_rm) {
593
594 /* (%eax) .. (%edi), not including (%esp) or (%ebp). */
595 case 0x00: case 0x01: case 0x02: case 0x03:
596 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
597 return 1;
598
599 /* d8(%eax) ... d8(%edi), not including d8(%esp). */
600 case 0x08: case 0x09: case 0x0A: case 0x0B:
601 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
602 return 2;
603
604 /* d32(%eax) ... d32(%edi), not including d32(%esp). */
605 case 0x10: case 0x11: case 0x12: case 0x13:
606 /* ! 14 */ case 0x15: case 0x16: case 0x17:
607 return 5;
608
609 /* a register, %eax .. %edi. (Not an addr, but still handled.) */
610 case 0x18: case 0x19: case 0x1A: case 0x1B:
611 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
612 return 1;
613
614 /* a 32-bit literal address. */
615 case 0x05: return 5;
616
617 /* SIB, no displacement. */
618 case 0x04: {
619 UChar sib = *eip++;
620 UChar base_r = sib & 7;
621 if (base_r == R_EBP) return 6; else return 2;
622 }
623 /* SIB, with 8-bit displacement. */
624 case 0x0C: return 3;
625
626 /* SIB, with 32-bit displacement. */
627 case 0x14: return 6;
628
629 default:
njne427a662002-10-02 11:08:25 +0000630 VG_(core_panic)("amode_from_RM");
sewardjde4a1d02002-03-22 01:27:54 +0000631 return 0; /*notreached*/
632 }
633}
634
635
636/* Extract the reg field from a modRM byte. */
637static __inline__ Int gregOfRM ( UChar mod_reg_rm )
638{
639 return (Int)( (mod_reg_rm >> 3) & 7 );
640}
641
642/* Figure out whether the mod and rm parts of a modRM byte refer to a
643 register or memory. If so, the byte will have the form 11XXXYYY,
644 where YYY is the register number. */
645static __inline__ Bool epartIsReg ( UChar mod_reg_rm )
646{
647 return (0xC0 == (mod_reg_rm & 0xC0));
648}
649
650/* ... and extract the register number ... */
651static __inline__ Int eregOfRM ( UChar mod_reg_rm )
652{
653 return (Int)(mod_reg_rm & 0x7);
654}
655
656
657/*------------------------------------------------------------*/
658/*--- Disassembling common idioms ---*/
659/*------------------------------------------------------------*/
660
661static
662void codegen_XOR_reg_with_itself ( UCodeBlock* cb, Int size,
663 Int ge_reg, Int tmp )
664{
665 if (dis)
666 VG_(printf)("xor%c %s, %s\n", nameISize(size),
667 nameIReg(size,ge_reg), nameIReg(size,ge_reg) );
668 uInstr2(cb, MOV, size, Literal, 0, TempReg, tmp);
669 uLiteral(cb, 0);
670 uInstr2(cb, XOR, size, TempReg, tmp, TempReg, tmp);
671 setFlagsFromUOpcode(cb, XOR);
672 uInstr2(cb, PUT, size, TempReg, tmp, ArchReg, ge_reg);
673}
674
675
676/* Handle binary integer instructions of the form
677 op E, G meaning
678 op reg-or-mem, reg
679 Is passed the a ptr to the modRM byte, the actual operation, and the
680 data size. Returns the address advanced completely over this
681 instruction.
682
683 E(src) is reg-or-mem
684 G(dst) is reg.
685
686 If E is reg, --> GET %G, tmp
687 OP %E, tmp
688 PUT tmp, %G
689
690 If E is mem and OP is not reversible,
691 --> (getAddr E) -> tmpa
692 LD (tmpa), tmpa
693 GET %G, tmp2
694 OP tmpa, tmp2
695 PUT tmp2, %G
696
697 If E is mem and OP is reversible
698 --> (getAddr E) -> tmpa
699 LD (tmpa), tmpa
700 OP %G, tmpa
701 PUT tmpa, %G
702*/
703static
sewardje1042472002-09-30 12:33:11 +0000704Addr dis_op2_E_G ( UCodeBlock* cb,
705 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +0000706 Opcode opc,
707 Bool keep,
708 Int size,
709 Addr eip0,
710 Char* t_x86opc )
711{
712 Bool reversible;
713 UChar rm = getUChar(eip0);
714 UChar dis_buf[50];
715
716 if (epartIsReg(rm)) {
717 Int tmp = newTemp(cb);
718
719 /* Specially handle XOR reg,reg, because that doesn't really
720 depend on reg, and doing the obvious thing potentially
721 generates a spurious value check failure due to the bogus
722 dependency. */
723 if (opc == XOR && gregOfRM(rm) == eregOfRM(rm)) {
724 codegen_XOR_reg_with_itself ( cb, size, gregOfRM(rm), tmp );
725 return 1+eip0;
726 }
727
728 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmp);
729 if (opc == AND || opc == OR) {
730 Int tao = newTemp(cb);
731 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, tao);
732 uInstr2(cb, opc, size, TempReg, tao, TempReg, tmp);
733 setFlagsFromUOpcode(cb, opc);
734 } else {
735 uInstr2(cb, opc, size, ArchReg, eregOfRM(rm), TempReg, tmp);
736 setFlagsFromUOpcode(cb, opc);
737 }
738 if (keep)
739 uInstr2(cb, PUT, size, TempReg, tmp, ArchReg, gregOfRM(rm));
740 if (dis) VG_(printf)("%s%c %s,%s\n", t_x86opc, nameISize(size),
741 nameIReg(size,eregOfRM(rm)),
742 nameIReg(size,gregOfRM(rm)));
743 return 1+eip0;
744 }
745
746 /* E refers to memory */
747 reversible
748 = (opc == ADD || opc == OR || opc == AND || opc == XOR || opc == ADC)
749 ? True : False;
750 if (reversible) {
sewardje1042472002-09-30 12:33:11 +0000751 UInt pair = disAMode ( cb, sorb, eip0, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +0000752 Int tmpa = LOW24(pair);
753 uInstr2(cb, LOAD, size, TempReg, tmpa, TempReg, tmpa);
754
755 if (opc == AND || opc == OR) {
756 Int tao = newTemp(cb);
757 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tao);
758 uInstr2(cb, opc, size, TempReg, tao, TempReg, tmpa);
759 setFlagsFromUOpcode(cb, opc);
760 } else {
761 uInstr2(cb, opc, size, ArchReg, gregOfRM(rm), TempReg, tmpa);
762 setFlagsFromUOpcode(cb, opc);
763 }
764 if (keep)
765 uInstr2(cb, PUT, size, TempReg, tmpa, ArchReg, gregOfRM(rm));
766 if (dis) VG_(printf)("%s%c %s,%s\n", t_x86opc, nameISize(size),
767 dis_buf,nameIReg(size,gregOfRM(rm)));
768 return HI8(pair)+eip0;
769 } else {
sewardje1042472002-09-30 12:33:11 +0000770 UInt pair = disAMode ( cb, sorb, eip0, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +0000771 Int tmpa = LOW24(pair);
772 Int tmp2 = newTemp(cb);
773 uInstr2(cb, LOAD, size, TempReg, tmpa, TempReg, tmpa);
774 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmp2);
775 uInstr2(cb, opc, size, TempReg, tmpa, TempReg, tmp2);
776 setFlagsFromUOpcode(cb, opc);
777 if (keep)
778 uInstr2(cb, PUT, size, TempReg, tmp2, ArchReg, gregOfRM(rm));
779 if (dis) VG_(printf)("%s%c %s,%s\n", t_x86opc, nameISize(size),
780 dis_buf,nameIReg(size,gregOfRM(rm)));
781 return HI8(pair)+eip0;
782 }
783}
784
785
786
787/* Handle binary integer instructions of the form
788 op G, E meaning
789 op reg, reg-or-mem
790 Is passed the a ptr to the modRM byte, the actual operation, and the
791 data size. Returns the address advanced completely over this
792 instruction.
793
794 G(src) is reg.
795 E(dst) is reg-or-mem
796
797 If E is reg, --> GET %E, tmp
798 OP %G, tmp
799 PUT tmp, %E
800
801 If E is mem, --> (getAddr E) -> tmpa
802 LD (tmpa), tmpv
803 OP %G, tmpv
804 ST tmpv, (tmpa)
805*/
806static
807Addr dis_op2_G_E ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +0000808 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +0000809 Opcode opc,
810 Bool keep,
811 Int size,
812 Addr eip0,
813 Char* t_x86opc )
814{
815 UChar rm = getUChar(eip0);
816 UChar dis_buf[50];
817
818 if (epartIsReg(rm)) {
819 Int tmp = newTemp(cb);
820
821 /* Specially handle XOR reg,reg, because that doesn't really
822 depend on reg, and doing the obvious thing potentially
823 generates a spurious value check failure due to the bogus
824 dependency. */
825 if (opc == XOR && gregOfRM(rm) == eregOfRM(rm)) {
826 codegen_XOR_reg_with_itself ( cb, size, gregOfRM(rm), tmp );
827 return 1+eip0;
828 }
829
830 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, tmp);
831
832 if (opc == AND || opc == OR) {
833 Int tao = newTemp(cb);
834 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tao);
835 uInstr2(cb, opc, size, TempReg, tao, TempReg, tmp);
836 setFlagsFromUOpcode(cb, opc);
837 } else {
838 uInstr2(cb, opc, size, ArchReg, gregOfRM(rm), TempReg, tmp);
839 setFlagsFromUOpcode(cb, opc);
840 }
841 if (keep)
842 uInstr2(cb, PUT, size, TempReg, tmp, ArchReg, eregOfRM(rm));
843 if (dis) VG_(printf)("%s%c %s,%s\n", t_x86opc, nameISize(size),
844 nameIReg(size,gregOfRM(rm)),
845 nameIReg(size,eregOfRM(rm)));
846 return 1+eip0;
847 }
848
849 /* E refers to memory */
850 {
sewardje1042472002-09-30 12:33:11 +0000851 UInt pair = disAMode ( cb, sorb, eip0, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +0000852 Int tmpa = LOW24(pair);
853 Int tmpv = newTemp(cb);
854 uInstr2(cb, LOAD, size, TempReg, tmpa, TempReg, tmpv);
855
856 if (opc == AND || opc == OR) {
857 Int tao = newTemp(cb);
858 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tao);
859 uInstr2(cb, opc, size, TempReg, tao, TempReg, tmpv);
860 setFlagsFromUOpcode(cb, opc);
861 } else {
862 uInstr2(cb, opc, size, ArchReg, gregOfRM(rm), TempReg, tmpv);
863 setFlagsFromUOpcode(cb, opc);
864 }
865 if (keep) {
866 uInstr2(cb, STORE, size, TempReg, tmpv, TempReg, tmpa);
sewardjde4a1d02002-03-22 01:27:54 +0000867 }
868 if (dis) VG_(printf)("%s%c %s,%s\n", t_x86opc, nameISize(size),
869 nameIReg(size,gregOfRM(rm)), dis_buf);
870 return HI8(pair)+eip0;
871 }
872}
873
874
875/* Handle move instructions of the form
876 mov E, G meaning
877 mov reg-or-mem, reg
878 Is passed the a ptr to the modRM byte, and the data size. Returns
879 the address advanced completely over this instruction.
880
881 E(src) is reg-or-mem
882 G(dst) is reg.
883
sewardje1042472002-09-30 12:33:11 +0000884 If E is reg, --> GET %E, tmpv
sewardjde4a1d02002-03-22 01:27:54 +0000885 PUT tmpv, %G
886
887 If E is mem --> (getAddr E) -> tmpa
888 LD (tmpa), tmpb
889 PUT tmpb, %G
890*/
891static
892Addr dis_mov_E_G ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +0000893 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +0000894 Int size,
895 Addr eip0 )
896{
897 UChar rm = getUChar(eip0);
898 UChar dis_buf[50];
899
900 if (epartIsReg(rm)) {
901 Int tmpv = newTemp(cb);
902 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, tmpv);
903 uInstr2(cb, PUT, size, TempReg, tmpv, ArchReg, gregOfRM(rm));
904 if (dis) VG_(printf)("mov%c %s,%s\n", nameISize(size),
905 nameIReg(size,eregOfRM(rm)),
906 nameIReg(size,gregOfRM(rm)));
907 return 1+eip0;
908 }
909
910 /* E refers to memory */
911 {
sewardje1042472002-09-30 12:33:11 +0000912 UInt pair = disAMode ( cb, sorb, eip0, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +0000913 Int tmpa = LOW24(pair);
914 Int tmpb = newTemp(cb);
915 uInstr2(cb, LOAD, size, TempReg, tmpa, TempReg, tmpb);
916 uInstr2(cb, PUT, size, TempReg, tmpb, ArchReg, gregOfRM(rm));
917 if (dis) VG_(printf)("mov%c %s,%s\n", nameISize(size),
918 dis_buf,nameIReg(size,gregOfRM(rm)));
919 return HI8(pair)+eip0;
920 }
921}
922
923
924/* Handle move instructions of the form
925 mov G, E meaning
926 mov reg, reg-or-mem
927 Is passed the a ptr to the modRM byte, and the data size. Returns
928 the address advanced completely over this instruction.
929
930 G(src) is reg.
931 E(dst) is reg-or-mem
932
933 If E is reg, --> GET %G, tmp
934 PUT tmp, %E
935
936 If E is mem, --> (getAddr E) -> tmpa
937 GET %G, tmpv
938 ST tmpv, (tmpa)
939*/
940static
941Addr dis_mov_G_E ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +0000942 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +0000943 Int size,
944 Addr eip0 )
945{
946 UChar rm = getUChar(eip0);
947 UChar dis_buf[50];
948
949 if (epartIsReg(rm)) {
950 Int tmpv = newTemp(cb);
951 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmpv);
952 uInstr2(cb, PUT, size, TempReg, tmpv, ArchReg, eregOfRM(rm));
953 if (dis) VG_(printf)("mov%c %s,%s\n", nameISize(size),
954 nameIReg(size,gregOfRM(rm)),
955 nameIReg(size,eregOfRM(rm)));
956 return 1+eip0;
957 }
958
959 /* E refers to memory */
960 {
sewardje1042472002-09-30 12:33:11 +0000961 UInt pair = disAMode ( cb, sorb, eip0, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +0000962 Int tmpa = LOW24(pair);
963 Int tmpv = newTemp(cb);
964 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmpv);
965 uInstr2(cb, STORE, size, TempReg, tmpv, TempReg, tmpa);
sewardjde4a1d02002-03-22 01:27:54 +0000966 if (dis) VG_(printf)("mov%c %s,%s\n", nameISize(size),
967 nameIReg(size,gregOfRM(rm)), dis_buf);
968 return HI8(pair)+eip0;
969 }
970}
971
972
973/* op $immediate, AL/AX/EAX. */
974static
975Addr dis_op_imm_A ( UCodeBlock* cb,
976 Int size,
977 Opcode opc,
978 Bool keep,
979 Addr eip,
980 Char* t_x86opc )
981{
982 Int tmp = newTemp(cb);
983 UInt lit = getUDisp(size,eip);
984 uInstr2(cb, GET, size, ArchReg, R_EAX, TempReg, tmp);
985 if (opc == AND || opc == OR) {
986 Int tao = newTemp(cb);
987 uInstr2(cb, MOV, size, Literal, 0, TempReg, tao);
988 uLiteral(cb, lit);
989 uInstr2(cb, opc, size, TempReg, tao, TempReg, tmp);
990 setFlagsFromUOpcode(cb, opc);
991 } else {
992 uInstr2(cb, opc, size, Literal, 0, TempReg, tmp);
993 uLiteral(cb, lit);
994 setFlagsFromUOpcode(cb, opc);
995 }
996 if (keep)
997 uInstr2(cb, PUT, size, TempReg, tmp, ArchReg, R_EAX);
998 if (dis) VG_(printf)("%s%c $0x%x, %s\n", t_x86opc, nameISize(size),
999 lit, nameIReg(size,R_EAX));
1000 return eip+size;
1001}
1002
1003
1004/* Sign- and Zero-extending moves. */
1005static
1006Addr dis_movx_E_G ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +00001007 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +00001008 Addr eip, Int szs, Int szd, Bool sign_extend )
1009{
1010 UChar dis_buf[50];
1011 UChar rm = getUChar(eip);
1012 if (epartIsReg(rm)) {
1013 Int tmpv = newTemp(cb);
1014 uInstr2(cb, GET, szs, ArchReg, eregOfRM(rm), TempReg, tmpv);
1015 uInstr1(cb, WIDEN, szd, TempReg, tmpv);
1016 LAST_UINSTR(cb).extra4b = szs;
1017 LAST_UINSTR(cb).signed_widen = sign_extend;
1018 uInstr2(cb, PUT, szd, TempReg, tmpv, ArchReg, gregOfRM(rm));
1019 if (dis) VG_(printf)("mov%c%c%c %s,%s\n",
1020 sign_extend ? 's' : 'z',
1021 nameISize(szs), nameISize(szd),
1022 nameIReg(szs,eregOfRM(rm)),
1023 nameIReg(szd,gregOfRM(rm)));
1024 return 1+eip;
1025 }
1026
1027 /* E refers to memory */
1028 {
sewardje1042472002-09-30 12:33:11 +00001029 UInt pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +00001030 Int tmpa = LOW24(pair);
1031 uInstr2(cb, LOAD, szs, TempReg, tmpa, TempReg, tmpa);
1032 uInstr1(cb, WIDEN, szd, TempReg, tmpa);
1033 LAST_UINSTR(cb).extra4b = szs;
1034 LAST_UINSTR(cb).signed_widen = sign_extend;
1035 uInstr2(cb, PUT, szd, TempReg, tmpa, ArchReg, gregOfRM(rm));
1036 if (dis) VG_(printf)("mov%c%c%c %s,%s\n",
1037 sign_extend ? 's' : 'z',
1038 nameISize(szs), nameISize(szd),
1039 dis_buf,
1040 nameIReg(szd,gregOfRM(rm)));
1041 return HI8(pair)+eip;
1042 }
1043}
1044
1045
1046/* Generate code to divide ArchRegs EDX:EAX / DX:AX / AX by the 32 /
1047 16 / 8 bit quantity in the given TempReg. */
1048static
1049void codegen_div ( UCodeBlock* cb, Int sz, Int t, Bool signed_divide )
1050{
1051 Int helper;
1052 Int ta = newTemp(cb);
1053 Int td = newTemp(cb);
1054
1055 switch (sz) {
1056 case 4: helper = (signed_divide ? VGOFF_(helper_idiv_64_32)
1057 : VGOFF_(helper_div_64_32));
1058 break;
1059 case 2: helper = (signed_divide ? VGOFF_(helper_idiv_32_16)
1060 : VGOFF_(helper_div_32_16));
1061 break;
1062 case 1: helper = (signed_divide ? VGOFF_(helper_idiv_16_8)
1063 : VGOFF_(helper_div_16_8));
1064 break;
njne427a662002-10-02 11:08:25 +00001065 default: VG_(core_panic)("codegen_div");
sewardjde4a1d02002-03-22 01:27:54 +00001066 }
1067 uInstr0(cb, CALLM_S, 0);
1068 if (sz == 4 || sz == 2) {
1069 uInstr1(cb, PUSH, sz, TempReg, t);
1070 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
1071 uInstr1(cb, PUSH, sz, TempReg, ta);
1072 uInstr2(cb, GET, sz, ArchReg, R_EDX, TempReg, td);
1073 uInstr1(cb, PUSH, sz, TempReg, td);
1074 uInstr1(cb, CALLM, 0, Lit16, helper);
1075 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsOSZACP);
1076 uInstr1(cb, POP, sz, TempReg, t);
1077 uInstr2(cb, PUT, sz, TempReg, t, ArchReg, R_EDX);
1078 uInstr1(cb, POP, sz, TempReg, t);
1079 uInstr2(cb, PUT, sz, TempReg, t, ArchReg, R_EAX);
1080 uInstr1(cb, CLEAR, 0, Lit16, 4);
1081 } else {
1082 uInstr1(cb, PUSH, 1, TempReg, t);
1083 uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, ta);
1084 uInstr1(cb, PUSH, 2, TempReg, ta);
1085 uInstr2(cb, MOV, 1, Literal, 0, TempReg, td);
1086 uLiteral(cb, 0);
1087 uInstr1(cb, PUSH, 1, TempReg, td);
1088 uInstr1(cb, CALLM, 0, Lit16, helper);
1089 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsOSZACP);
1090 uInstr1(cb, POP, 1, TempReg, t);
1091 uInstr2(cb, PUT, 1, TempReg, t, ArchReg, R_AL);
1092 uInstr1(cb, POP, 1, TempReg, t);
1093 uInstr2(cb, PUT, 1, TempReg, t, ArchReg, R_AH);
1094 uInstr1(cb, CLEAR, 0, Lit16, 4);
1095 }
1096 uInstr0(cb, CALLM_E, 0);
1097}
1098
1099
1100static
sewardje1042472002-09-30 12:33:11 +00001101Addr dis_Grp1 ( UCodeBlock* cb,
1102 UChar sorb,
1103 Addr eip, UChar modrm,
sewardjde4a1d02002-03-22 01:27:54 +00001104 Int am_sz, Int d_sz, Int sz, UInt d32 )
1105{
1106 Int t1, t2, uopc;
1107 UInt pair;
1108 UChar dis_buf[50];
1109 if (epartIsReg(modrm)) {
1110 vg_assert(am_sz == 1);
1111 t1 = newTemp(cb);
1112 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1113 switch (gregOfRM(modrm)) {
1114 case 0: uopc = ADD; break; case 1: uopc = OR; break;
1115 case 2: uopc = ADC; break; case 3: uopc = SBB; break;
1116 case 4: uopc = AND; break; case 5: uopc = SUB; break;
1117 case 6: uopc = XOR; break; case 7: uopc = SUB; break;
njne427a662002-10-02 11:08:25 +00001118 default: VG_(core_panic)("dis_Grp1(Reg): unhandled case");
sewardjde4a1d02002-03-22 01:27:54 +00001119 }
1120 if (uopc == AND || uopc == OR) {
1121 Int tao = newTemp(cb);
1122 uInstr2(cb, MOV, sz, Literal, 0, TempReg, tao);
1123 uLiteral(cb, d32);
1124 uInstr2(cb, uopc, sz, TempReg, tao, TempReg, t1);
1125 setFlagsFromUOpcode(cb, uopc);
1126 } else {
1127 uInstr2(cb, uopc, sz, Literal, 0, TempReg, t1);
1128 uLiteral(cb, d32);
1129 setFlagsFromUOpcode(cb, uopc);
1130 }
1131 if (gregOfRM(modrm) < 7)
1132 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
1133 eip += (am_sz + d_sz);
1134 if (dis)
1135 VG_(printf)("%s%c $0x%x, %s\n",
1136 nameGrp1(gregOfRM(modrm)), nameISize(sz), d32,
1137 nameIReg(sz,eregOfRM(modrm)));
1138 } else {
sewardje1042472002-09-30 12:33:11 +00001139 pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +00001140 t1 = LOW24(pair);
1141 t2 = newTemp(cb);
1142 eip += HI8(pair);
1143 eip += d_sz;
1144 uInstr2(cb, LOAD, sz, TempReg, t1, TempReg, t2);
1145 switch (gregOfRM(modrm)) {
1146 case 0: uopc = ADD; break; case 1: uopc = OR; break;
1147 case 2: uopc = ADC; break; case 3: uopc = SBB; break;
1148 case 4: uopc = AND; break; case 5: uopc = SUB; break;
1149 case 6: uopc = XOR; break; case 7: uopc = SUB; break;
njne427a662002-10-02 11:08:25 +00001150 default: VG_(core_panic)("dis_Grp1(Mem): unhandled case");
sewardjde4a1d02002-03-22 01:27:54 +00001151 }
1152 if (uopc == AND || uopc == OR) {
1153 Int tao = newTemp(cb);
1154 uInstr2(cb, MOV, sz, Literal, 0, TempReg, tao);
1155 uLiteral(cb, d32);
1156 uInstr2(cb, uopc, sz, TempReg, tao, TempReg, t2);
1157 setFlagsFromUOpcode(cb, uopc);
1158 } else {
1159 uInstr2(cb, uopc, sz, Literal, 0, TempReg, t2);
1160 uLiteral(cb, d32);
1161 setFlagsFromUOpcode(cb, uopc);
1162 }
1163 if (gregOfRM(modrm) < 7) {
1164 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
sewardjde4a1d02002-03-22 01:27:54 +00001165 }
1166 if (dis)
1167 VG_(printf)("%s%c $0x%x, %s\n",
1168 nameGrp1(gregOfRM(modrm)), nameISize(sz), d32,
1169 dis_buf);
1170 }
1171 return eip;
1172}
1173
1174
1175/* Group 2 extended opcodes. */
1176static
sewardje1042472002-09-30 12:33:11 +00001177Addr dis_Grp2 ( UCodeBlock* cb,
1178 UChar sorb,
1179 Addr eip, UChar modrm,
sewardjde4a1d02002-03-22 01:27:54 +00001180 Int am_sz, Int d_sz, Int sz,
1181 Tag orig_src_tag, UInt orig_src_val )
1182{
1183 /* orig_src_tag and orig_src_val denote either ArchReg(%CL) or a
1184 Literal. And eip on entry points at the modrm byte. */
1185 Int t1, t2, uopc;
1186 UInt pair;
1187 UChar dis_buf[50];
1188 UInt src_val;
1189 Tag src_tag;
1190
1191 /* Get the amount to be shifted by into src_tag/src_val. */
1192 if (orig_src_tag == ArchReg) {
1193 src_val = newTemp(cb);
1194 src_tag = TempReg;
1195 uInstr2(cb, GET, 1, orig_src_tag, orig_src_val, TempReg, src_val);
1196 } else {
1197 src_val = orig_src_val;
1198 src_tag = Literal;
1199 }
1200
1201 if (epartIsReg(modrm)) {
1202 vg_assert(am_sz == 1);
1203 t1 = newTemp(cb);
1204 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1205 switch (gregOfRM(modrm)) {
1206 case 0: uopc = ROL; break; case 1: uopc = ROR; break;
1207 case 2: uopc = RCL; break; case 3: uopc = RCR; break;
1208 case 4: uopc = SHL; break; case 5: uopc = SHR; break;
1209 case 7: uopc = SAR; break;
njne427a662002-10-02 11:08:25 +00001210 default: VG_(core_panic)("dis_Grp2(Reg): unhandled case");
sewardjde4a1d02002-03-22 01:27:54 +00001211 }
1212 if (src_tag == Literal) {
1213 uInstr2(cb, uopc, sz, Literal, 0, TempReg, t1);
1214 uLiteral(cb, src_val);
1215 } else {
1216 uInstr2(cb, uopc, sz, src_tag, src_val, TempReg, t1);
1217 }
1218 setFlagsFromUOpcode(cb, uopc);
1219 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
1220 eip += (am_sz + d_sz);
1221 if (dis) {
1222 if (orig_src_tag == Literal)
1223 VG_(printf)("%s%c $0x%x, %s\n",
1224 nameGrp2(gregOfRM(modrm)), nameISize(sz),
1225 orig_src_val, nameIReg(sz,eregOfRM(modrm)));
1226 else
1227 VG_(printf)("%s%c %s, %s\n",
1228 nameGrp2(gregOfRM(modrm)), nameISize(sz),
1229 nameIReg(1,orig_src_val),
1230 nameIReg(sz,eregOfRM(modrm)));
1231 }
1232 } else {
sewardje1042472002-09-30 12:33:11 +00001233 pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +00001234 t1 = LOW24(pair);
1235 t2 = newTemp(cb);
1236 eip += HI8(pair);
1237 eip += d_sz;
1238 uInstr2(cb, LOAD, sz, TempReg, t1, TempReg, t2);
1239 switch (gregOfRM(modrm)) {
1240 case 0: uopc = ROL; break; case 1: uopc = ROR; break;
1241 case 2: uopc = RCL; break; case 3: uopc = RCR; break;
1242 case 4: uopc = SHL; break; case 5: uopc = SHR; break;
1243 case 7: uopc = SAR; break;
njne427a662002-10-02 11:08:25 +00001244 default: VG_(core_panic)("dis_Grp2(Reg): unhandled case");
sewardjde4a1d02002-03-22 01:27:54 +00001245 }
1246 if (src_tag == Literal) {
1247 uInstr2(cb, uopc, sz, Literal, 0, TempReg, t2);
1248 uLiteral(cb, src_val);
1249 } else {
1250 uInstr2(cb, uopc, sz, src_tag, src_val, TempReg, t2);
1251 }
1252 setFlagsFromUOpcode(cb, uopc);
1253 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
sewardjde4a1d02002-03-22 01:27:54 +00001254 if (dis) {
1255 if (orig_src_tag == Literal)
1256 VG_(printf)("%s%c $0x%x, %s\n",
1257 nameGrp2(gregOfRM(modrm)), nameISize(sz),
1258 orig_src_val, dis_buf);
1259 else
1260 VG_(printf)("%s%c %s, %s\n",
1261 nameGrp2(gregOfRM(modrm)), nameISize(sz),
1262 nameIReg(1,orig_src_val),
1263 dis_buf);
1264 }
1265 }
1266 return eip;
1267}
1268
1269
sewardj0ece28b2002-04-16 00:42:12 +00001270
1271/* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
sewardjde4a1d02002-03-22 01:27:54 +00001272static
sewardje1042472002-09-30 12:33:11 +00001273Addr dis_Grp8_BT ( UCodeBlock* cb,
1274 UChar sorb,
1275 Addr eip, UChar modrm,
sewardj0ece28b2002-04-16 00:42:12 +00001276 Int am_sz, Int sz, UInt src_val )
sewardjde4a1d02002-03-22 01:27:54 +00001277{
sewardj0ece28b2002-04-16 00:42:12 +00001278# define MODIFY_t2_AND_SET_CARRY_FLAG \
1279 /* t2 is the value to be op'd on. Copy to t_fetched, then \
1280 modify t2, if non-BT. */ \
1281 uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t_fetched); \
1282 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
1283 uLiteral(cb, v_mask); \
1284 switch (gregOfRM(modrm)) { \
1285 case 4: /* BT */ break; \
1286 case 5: /* BTS */ \
1287 uInstr2(cb, OR, sz, TempReg, t_mask, TempReg, t2); break; \
1288 case 6: /* BTR */ \
1289 uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t2); break; \
1290 case 7: /* BTC */ \
1291 uInstr2(cb, XOR, sz, TempReg, t_mask, TempReg, t2); break; \
1292 } \
1293 /* Copy relevant bit from t_fetched into carry flag. */ \
1294 uInstr2(cb, SHR, sz, Literal, 0, TempReg, t_fetched); \
1295 uLiteral(cb, src_val); \
1296 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
1297 uLiteral(cb, 1); \
1298 uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t_fetched); \
1299 uInstr1(cb, NEG, sz, TempReg, t_fetched); \
1300 setFlagsFromUOpcode(cb, NEG);
1301
1302
sewardjde4a1d02002-03-22 01:27:54 +00001303 /* src_val denotes a d8.
1304 And eip on entry points at the modrm byte. */
sewardj0ece28b2002-04-16 00:42:12 +00001305 Int t1, t2, t_fetched, t_mask;
sewardjde4a1d02002-03-22 01:27:54 +00001306 UInt pair;
1307 UChar dis_buf[50];
sewardj0ece28b2002-04-16 00:42:12 +00001308 UInt v_mask;
sewardjde4a1d02002-03-22 01:27:54 +00001309
sewardj0ece28b2002-04-16 00:42:12 +00001310 /* There is no 1-byte form of this instruction, AFAICS. */
1311 vg_assert(sz == 2 || sz == 4);
1312
1313 /* Limit src_val -- the bit offset -- to something within a word.
1314 The Intel docs say that literal offsets larger than a word are
1315 masked in this way. */
1316 switch (sz) {
1317 case 2: src_val &= 15; break;
1318 case 4: src_val &= 31; break;
njne427a662002-10-02 11:08:25 +00001319 default: VG_(core_panic)("dis_Grp8_BT: invalid size");
sewardjde4a1d02002-03-22 01:27:54 +00001320 }
1321
sewardj0ece28b2002-04-16 00:42:12 +00001322 /* Invent a mask suitable for the operation. */
1323
1324 switch (gregOfRM(modrm)) {
1325 case 4: /* BT */ v_mask = 0; break;
1326 case 5: /* BTS */ v_mask = 1 << src_val; break;
1327 case 6: /* BTR */ v_mask = ~(1 << src_val); break;
1328 case 7: /* BTC */ v_mask = 1 << src_val; break;
1329 /* If this needs to be extended, probably simplest to make a
1330 new function to handle the other cases (0 .. 3). The
1331 Intel docs do however not indicate any use for 0 .. 3, so
1332 we don't expect this to happen. */
njne427a662002-10-02 11:08:25 +00001333 default: VG_(core_panic)("dis_Grp8_BT");
sewardj0ece28b2002-04-16 00:42:12 +00001334 }
1335 /* Probably excessively paranoid. */
1336 if (sz == 2)
1337 v_mask &= 0x0000FFFF;
1338
1339 t1 = INVALID_TEMPREG;
1340 t_fetched = newTemp(cb);
1341 t_mask = newTemp(cb);
1342
sewardjde4a1d02002-03-22 01:27:54 +00001343 if (epartIsReg(modrm)) {
1344 vg_assert(am_sz == 1);
1345 t2 = newTemp(cb);
sewardj0ece28b2002-04-16 00:42:12 +00001346
1347 /* Fetch the value to be tested and modified. */
1348 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t2);
1349 /* Do it! */
1350 MODIFY_t2_AND_SET_CARRY_FLAG;
1351 /* Dump the result back, if non-BT. */
1352 if (gregOfRM(modrm) != 4 /* BT */)
1353 uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, eregOfRM(modrm));
1354
sewardjde4a1d02002-03-22 01:27:54 +00001355 eip += (am_sz + 1);
1356 if (dis)
1357 VG_(printf)("%s%c $0x%x, %s\n",
1358 nameGrp8(gregOfRM(modrm)), nameISize(sz),
1359 src_val,
1360 nameIReg(sz,eregOfRM(modrm)));
1361 } else {
sewardje1042472002-09-30 12:33:11 +00001362 pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +00001363 t1 = LOW24(pair);
1364 t2 = newTemp(cb);
1365 eip += HI8(pair);
1366 eip += 1;
sewardj0ece28b2002-04-16 00:42:12 +00001367
1368 /* Fetch the value to be tested and modified. */
sewardjde4a1d02002-03-22 01:27:54 +00001369 uInstr2(cb, LOAD, sz, TempReg, t1, TempReg, t2);
sewardj0ece28b2002-04-16 00:42:12 +00001370 /* Do it! */
1371 MODIFY_t2_AND_SET_CARRY_FLAG;
1372 /* Dump the result back, if non-BT. */
1373 if (gregOfRM(modrm) != 4 /* BT */) {
1374 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
sewardj0ece28b2002-04-16 00:42:12 +00001375 }
sewardjde4a1d02002-03-22 01:27:54 +00001376 if (dis)
1377 VG_(printf)("%s%c $0x%x, %s\n",
1378 nameGrp8(gregOfRM(modrm)), nameISize(sz), src_val,
1379 dis_buf);
1380 }
sewardjde4a1d02002-03-22 01:27:54 +00001381 return eip;
sewardj0ece28b2002-04-16 00:42:12 +00001382
1383# undef MODIFY_t2_AND_SET_CARRY_FLAG
sewardjde4a1d02002-03-22 01:27:54 +00001384}
sewardjde4a1d02002-03-22 01:27:54 +00001385
1386
1387
1388/* Generate ucode to multiply the value in EAX/AX/AL by the register
1389 specified by the ereg of modrm, and park the result in
1390 EDX:EAX/DX:AX/AX. */
1391static void codegen_mul_A_D_Reg ( UCodeBlock* cb, Int sz,
1392 UChar modrm, Bool signed_multiply )
1393{
1394 Int helper = signed_multiply
1395 ?
1396 (sz==1 ? VGOFF_(helper_imul_8_16)
1397 : (sz==2 ? VGOFF_(helper_imul_16_32)
1398 : VGOFF_(helper_imul_32_64)))
1399 :
1400 (sz==1 ? VGOFF_(helper_mul_8_16)
1401 : (sz==2 ? VGOFF_(helper_mul_16_32)
1402 : VGOFF_(helper_mul_32_64)));
1403 Int t1 = newTemp(cb);
1404 Int ta = newTemp(cb);
1405 uInstr0(cb, CALLM_S, 0);
1406 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1407 uInstr1(cb, PUSH, sz, TempReg, t1);
1408 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
1409 uInstr1(cb, PUSH, sz, TempReg, ta);
1410 uInstr1(cb, CALLM, 0, Lit16, helper);
1411 uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP);
1412 if (sz > 1) {
1413 uInstr1(cb, POP, sz, TempReg, t1);
1414 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EDX);
1415 uInstr1(cb, POP, sz, TempReg, t1);
1416 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EAX);
1417 } else {
1418 uInstr1(cb, CLEAR, 0, Lit16, 4);
1419 uInstr1(cb, POP, 2, TempReg, t1);
1420 uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
1421 }
1422 uInstr0(cb, CALLM_E, 0);
1423 if (dis) VG_(printf)("%s%c %s\n", signed_multiply ? "imul" : "mul",
1424 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
1425
1426}
1427
1428
1429/* Generate ucode to multiply the value in EAX/AX/AL by the value in
1430 TempReg temp, and park the result in EDX:EAX/DX:AX/AX. */
1431static void codegen_mul_A_D_Temp ( UCodeBlock* cb, Int sz,
1432 Int temp, Bool signed_multiply,
1433 UChar* dis_buf )
1434{
1435 Int helper = signed_multiply
1436 ?
1437 (sz==1 ? VGOFF_(helper_imul_8_16)
1438 : (sz==2 ? VGOFF_(helper_imul_16_32)
1439 : VGOFF_(helper_imul_32_64)))
1440 :
1441 (sz==1 ? VGOFF_(helper_mul_8_16)
1442 : (sz==2 ? VGOFF_(helper_mul_16_32)
1443 : VGOFF_(helper_mul_32_64)));
1444 Int t1 = newTemp(cb);
1445 uInstr0(cb, CALLM_S, 0);
1446 uInstr1(cb, PUSH, sz, TempReg, temp);
1447 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
1448 uInstr1(cb, PUSH, sz, TempReg, t1);
1449 uInstr1(cb, CALLM, 0, Lit16, helper);
1450 uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP);
1451 if (sz > 1) {
1452 uInstr1(cb, POP, sz, TempReg, t1);
1453 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EDX);
1454 uInstr1(cb, POP, sz, TempReg, t1);
1455 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EAX);
1456 } else {
1457 uInstr1(cb, CLEAR, 0, Lit16, 4);
1458 uInstr1(cb, POP, 2, TempReg, t1);
1459 uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
1460 }
1461 uInstr0(cb, CALLM_E, 0);
1462 if (dis) VG_(printf)("%s%c %s\n", signed_multiply ? "imul" : "mul",
1463 nameISize(sz), dis_buf);
1464}
1465
1466
1467/* Group 3 extended opcodes. */
1468static
sewardje1042472002-09-30 12:33:11 +00001469Addr dis_Grp3 ( UCodeBlock* cb,
1470 UChar sorb,
1471 Int sz, Addr eip )
sewardjde4a1d02002-03-22 01:27:54 +00001472{
1473 Int t1, t2;
1474 UInt pair, d32;
1475 UChar modrm;
1476 UChar dis_buf[50];
1477 t1 = t2 = INVALID_TEMPREG;
1478 modrm = getUChar(eip);
1479 if (epartIsReg(modrm)) {
1480 t1 = newTemp(cb);
1481 switch (gregOfRM(modrm)) {
1482 case 0: { /* TEST */
1483 Int tao = newTemp(cb);
1484 eip++; d32 = getUDisp(sz, eip); eip += sz;
1485 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1486 uInstr2(cb, MOV, sz, Literal, 0, TempReg, tao);
1487 uLiteral(cb, d32);
1488 uInstr2(cb, AND, sz, TempReg, tao, TempReg, t1);
1489 setFlagsFromUOpcode(cb, AND);
1490 if (dis)
1491 VG_(printf)("test%c $0x%x, %s\n",
1492 nameISize(sz), d32, nameIReg(sz, eregOfRM(modrm)));
1493 break;
1494 }
1495 case 2: /* NOT */
1496 eip++;
1497 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1498 uInstr1(cb, NOT, sz, TempReg, t1);
1499 setFlagsFromUOpcode(cb, NOT);
1500 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
1501 if (dis)
1502 VG_(printf)("not%c %s\n",
1503 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
1504 break;
1505 case 3: /* NEG */
1506 eip++;
1507 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1508 uInstr1(cb, NEG, sz, TempReg, t1);
1509 setFlagsFromUOpcode(cb, NEG);
1510 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
1511 if (dis)
1512 VG_(printf)("neg%c %s\n",
1513 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
1514 break;
1515 case 4: /* MUL */
1516 eip++;
1517 codegen_mul_A_D_Reg ( cb, sz, modrm, False );
1518 break;
1519 case 5: /* IMUL */
1520 eip++;
1521 codegen_mul_A_D_Reg ( cb, sz, modrm, True );
1522 break;
1523 case 6: /* DIV */
1524 eip++;
1525 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1526 codegen_div ( cb, sz, t1, False );
1527 if (dis)
1528 VG_(printf)("div%c %s\n", nameISize(sz),
1529 nameIReg(sz, eregOfRM(modrm)));
1530 break;
1531 case 7: /* IDIV */
1532 eip++;
1533 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1534 codegen_div ( cb, sz, t1, True );
1535 if (dis)
1536 VG_(printf)("idiv%c %s\n", nameISize(sz),
1537 nameIReg(sz, eregOfRM(modrm)));
1538 break;
1539 default:
1540 VG_(printf)(
1541 "unhandled Grp3(R) case %d\n", (UInt)gregOfRM(modrm));
njne427a662002-10-02 11:08:25 +00001542 VG_(core_panic)("Grp3");
sewardjde4a1d02002-03-22 01:27:54 +00001543 }
1544 } else {
sewardje1042472002-09-30 12:33:11 +00001545 pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL );
sewardjde4a1d02002-03-22 01:27:54 +00001546 t2 = LOW24(pair);
1547 t1 = newTemp(cb);
1548 eip += HI8(pair);
1549 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
1550 switch (gregOfRM(modrm)) {
1551 case 0: { /* TEST */
1552 Int tao = newTemp(cb);
1553 d32 = getUDisp(sz, eip); eip += sz;
1554 uInstr2(cb, MOV, sz, Literal, 0, TempReg, tao);
1555 uLiteral(cb, d32);
1556 uInstr2(cb, AND, sz, TempReg, tao, TempReg, t1);
1557 setFlagsFromUOpcode(cb, AND);
1558 if (dis)
1559 VG_(printf)("test%c $0x%x, %s\n",
1560 nameISize(sz), d32, dis_buf);
1561 break;
1562 }
1563 case 2: /* NOT */
1564 uInstr1(cb, NOT, sz, TempReg, t1);
1565 setFlagsFromUOpcode(cb, NOT);
1566 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00001567 if (dis)
1568 VG_(printf)("not%c %s\n", nameISize(sz), dis_buf);
1569 break;
1570 case 3: /* NEG */
1571 uInstr1(cb, NEG, sz, TempReg, t1);
1572 setFlagsFromUOpcode(cb, NEG);
1573 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00001574 if (dis)
1575 VG_(printf)("neg%c %s\n", nameISize(sz), dis_buf);
1576 break;
1577 case 4: /* MUL */
1578 codegen_mul_A_D_Temp ( cb, sz, t1, False,
1579 dis?dis_buf:NULL );
1580 break;
1581 case 5: /* IMUL */
1582 codegen_mul_A_D_Temp ( cb, sz, t1, True, dis?dis_buf:NULL );
1583 break;
1584 case 6: /* DIV */
1585 codegen_div ( cb, sz, t1, False );
1586 if (dis)
1587 VG_(printf)("div%c %s\n", nameISize(sz), dis_buf);
1588 break;
1589 case 7: /* IDIV */
1590 codegen_div ( cb, sz, t1, True );
1591 if (dis)
1592 VG_(printf)("idiv%c %s\n", nameISize(sz), dis_buf);
1593 break;
1594 default:
1595 VG_(printf)(
1596 "unhandled Grp3(M) case %d\n", (UInt)gregOfRM(modrm));
njne427a662002-10-02 11:08:25 +00001597 VG_(core_panic)("Grp3");
sewardjde4a1d02002-03-22 01:27:54 +00001598 }
1599 }
1600 return eip;
1601}
1602
1603
1604/* Group 4 extended opcodes. */
1605static
sewardje1042472002-09-30 12:33:11 +00001606Addr dis_Grp4 ( UCodeBlock* cb,
1607 UChar sorb,
1608 Addr eip )
sewardjde4a1d02002-03-22 01:27:54 +00001609{
1610 Int t1, t2;
1611 UInt pair;
1612 UChar modrm;
1613 UChar dis_buf[50];
1614 t1 = t2 = INVALID_TEMPREG;
1615
1616 modrm = getUChar(eip);
1617 if (epartIsReg(modrm)) {
1618 t1 = newTemp(cb);
1619 uInstr2(cb, GET, 1, ArchReg, eregOfRM(modrm), TempReg, t1);
1620 switch (gregOfRM(modrm)) {
1621 case 0: /* INC */
1622 uInstr1(cb, INC, 1, TempReg, t1);
1623 setFlagsFromUOpcode(cb, INC);
1624 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, eregOfRM(modrm));
1625 break;
1626 case 1: /* DEC */
1627 uInstr1(cb, DEC, 1, TempReg, t1);
1628 setFlagsFromUOpcode(cb, DEC);
1629 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, eregOfRM(modrm));
1630 break;
1631 default:
1632 VG_(printf)(
1633 "unhandled Grp4(R) case %d\n", (UInt)gregOfRM(modrm));
njne427a662002-10-02 11:08:25 +00001634 VG_(core_panic)("Grp4");
sewardjde4a1d02002-03-22 01:27:54 +00001635 }
1636 eip++;
1637 if (dis)
1638 VG_(printf)("%sb %s\n", nameGrp4(gregOfRM(modrm)),
1639 nameIReg(1, eregOfRM(modrm)));
1640 } else {
sewardje1042472002-09-30 12:33:11 +00001641 pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL );
sewardjde4a1d02002-03-22 01:27:54 +00001642 t2 = LOW24(pair);
1643 t1 = newTemp(cb);
1644 uInstr2(cb, LOAD, 1, TempReg, t2, TempReg, t1);
1645 switch (gregOfRM(modrm)) {
1646 case 0: /* INC */
1647 uInstr1(cb, INC, 1, TempReg, t1);
1648 setFlagsFromUOpcode(cb, INC);
1649 uInstr2(cb, STORE, 1, TempReg, t1, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00001650 break;
1651 case 1: /* DEC */
1652 uInstr1(cb, DEC, 1, TempReg, t1);
1653 setFlagsFromUOpcode(cb, DEC);
1654 uInstr2(cb, STORE, 1, TempReg, t1, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00001655 break;
1656 default:
1657 VG_(printf)(
1658 "unhandled Grp4(M) case %d\n", (UInt)gregOfRM(modrm));
njne427a662002-10-02 11:08:25 +00001659 VG_(core_panic)("Grp4");
sewardjde4a1d02002-03-22 01:27:54 +00001660 }
1661 eip += HI8(pair);
1662 if (dis)
1663 VG_(printf)("%sb %s\n", nameGrp4(gregOfRM(modrm)), dis_buf);
1664 }
1665 return eip;
1666}
1667
1668
1669/* Group 5 extended opcodes. */
1670static
sewardje1042472002-09-30 12:33:11 +00001671Addr dis_Grp5 ( UCodeBlock* cb,
1672 UChar sorb,
1673 Int sz, Addr eip, Bool* isEnd )
sewardjde4a1d02002-03-22 01:27:54 +00001674{
1675 Int t1, t2, t3, t4;
1676 UInt pair;
1677 UChar modrm;
1678 UChar dis_buf[50];
1679 t1 = t2 = t3 = t4 = INVALID_TEMPREG;
1680
1681 modrm = getUChar(eip);
1682 if (epartIsReg(modrm)) {
1683 t1 = newTemp(cb);
1684 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1685 switch (gregOfRM(modrm)) {
1686 case 0: /* INC */
1687 uInstr1(cb, INC, sz, TempReg, t1);
1688 setFlagsFromUOpcode(cb, INC);
1689 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
1690 break;
1691 case 1: /* DEC */
1692 uInstr1(cb, DEC, sz, TempReg, t1);
1693 setFlagsFromUOpcode(cb, DEC);
1694 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
1695 break;
1696 case 2: /* call Ev */
1697 t3 = newTemp(cb); t4 = newTemp(cb);
1698 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
1699 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t3);
1700 uLiteral(cb, 4);
1701 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
1702 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
1703 uLiteral(cb, eip+1);
1704 uInstr2(cb, STORE, 4, TempReg, t4, TempReg, t3);
sewardjde4a1d02002-03-22 01:27:54 +00001705 uInstr1(cb, JMP, 0, TempReg, t1);
1706 uCond(cb, CondAlways);
sewardj2e93c502002-04-12 11:12:52 +00001707 LAST_UINSTR(cb).jmpkind = JmpCall;
sewardjde4a1d02002-03-22 01:27:54 +00001708 *isEnd = True;
1709 break;
1710 case 4: /* jmp Ev */
1711 uInstr1(cb, JMP, 0, TempReg, t1);
1712 uCond(cb, CondAlways);
1713 *isEnd = True;
1714 break;
1715 default:
1716 VG_(printf)(
1717 "unhandled Grp5(R) case %d\n", (UInt)gregOfRM(modrm));
njne427a662002-10-02 11:08:25 +00001718 VG_(core_panic)("Grp5");
sewardjde4a1d02002-03-22 01:27:54 +00001719 }
1720 eip++;
1721 if (dis)
1722 VG_(printf)("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
1723 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
1724 } else {
sewardje1042472002-09-30 12:33:11 +00001725 pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL );
sewardjde4a1d02002-03-22 01:27:54 +00001726 t2 = LOW24(pair);
1727 t1 = newTemp(cb);
1728 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
1729 switch (gregOfRM(modrm)) {
1730 case 0: /* INC */
1731 uInstr1(cb, INC, sz, TempReg, t1);
1732 setFlagsFromUOpcode(cb, INC);
1733 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00001734 break;
1735 case 1: /* DEC */
1736 uInstr1(cb, DEC, sz, TempReg, t1);
1737 setFlagsFromUOpcode(cb, DEC);
1738 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00001739 break;
1740 case 2: /* call Ev */
1741 t3 = newTemp(cb); t4 = newTemp(cb);
1742 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
1743 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t3);
1744 uLiteral(cb, 4);
1745 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
1746 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
1747 uLiteral(cb, eip+HI8(pair));
1748 uInstr2(cb, STORE, 4, TempReg, t4, TempReg, t3);
sewardjde4a1d02002-03-22 01:27:54 +00001749 uInstr1(cb, JMP, 0, TempReg, t1);
1750 uCond(cb, CondAlways);
sewardj2e93c502002-04-12 11:12:52 +00001751 LAST_UINSTR(cb).jmpkind = JmpCall;
sewardjde4a1d02002-03-22 01:27:54 +00001752 *isEnd = True;
1753 break;
1754 case 4: /* JMP Ev */
1755 uInstr1(cb, JMP, 0, TempReg, t1);
1756 uCond(cb, CondAlways);
1757 *isEnd = True;
1758 break;
1759 case 6: /* PUSH Ev */
1760 t3 = newTemp(cb);
1761 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
1762 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t3);
1763 uLiteral(cb, sz);
1764 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
1765 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t3);
sewardjde4a1d02002-03-22 01:27:54 +00001766 break;
1767 default:
1768 VG_(printf)(
1769 "unhandled Grp5(M) case %d\n", (UInt)gregOfRM(modrm));
njne427a662002-10-02 11:08:25 +00001770 VG_(core_panic)("Grp5");
sewardjde4a1d02002-03-22 01:27:54 +00001771 }
1772 eip += HI8(pair);
1773 if (dis)
1774 VG_(printf)("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
1775 nameISize(sz), dis_buf);
1776 }
1777 return eip;
1778}
1779
1780
1781/* Template for REPE CMPS<sz>. Assumes this insn is the last one in
1782 the basic block, and so emits a jump to the next insn. */
1783static
1784void codegen_REPE_CMPS ( UCodeBlock* cb, Int sz, Addr eip, Addr eip_next )
1785{
1786 Int tc, /* ECX */
1787 td, /* EDI */ ts, /* ESI */
1788 tdv, /* (EDI) */ tsv /* (ESI) */;
1789
1790 tdv = newTemp(cb);
1791 tsv = newTemp(cb);
1792 td = newTemp(cb);
1793 ts = newTemp(cb);
1794 tc = newTemp(cb);
1795
1796 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, tc);
1797 uInstr2(cb, JIFZ, 4, TempReg, tc, Literal, 0);
1798 uLiteral(cb, eip_next);
1799 uInstr1(cb, DEC, 4, TempReg, tc);
1800 uInstr2(cb, PUT, 4, TempReg, tc, ArchReg, R_ECX);
1801
1802 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
1803 uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
1804
1805 uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tdv);
1806 uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tsv);
1807
1808 uInstr2(cb, SUB, sz, TempReg, tdv, TempReg, tsv);
1809 setFlagsFromUOpcode(cb, SUB);
1810
1811 uInstr0(cb, CALLM_S, 0);
1812 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tdv);
1813 uLiteral(cb, 0);
1814 uInstr1(cb, PUSH, 4, TempReg, tdv);
1815
1816 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
1817 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
1818
1819 uInstr1(cb, POP, 4, TempReg, tdv);
1820 uInstr0(cb, CALLM_E, 0);
1821 if (sz == 4 || sz == 2) {
1822 uInstr2(cb, SHL, 4, Literal, 0, TempReg, tdv);
1823 uLiteral(cb, sz/2);
1824 }
1825 uInstr2(cb, ADD, 4, TempReg, tdv, TempReg, td);
1826 uInstr2(cb, ADD, 4, TempReg, tdv, TempReg, ts);
1827
1828 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
1829 uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
1830
1831 uInstr1(cb, JMP, 0, Literal, 0);
1832 uLiteral(cb, eip);
1833 uCond(cb, CondZ);
1834 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
1835 uInstr1(cb, JMP, 0, Literal, 0);
1836 uLiteral(cb, eip_next);
1837 uCond(cb, CondAlways);
1838}
1839
1840
1841/* Template for REPNE SCAS<sz>. Assumes this insn is the last one in
1842 the basic block, and so emits a jump to the next insn. */
1843static
1844void codegen_REPNE_SCAS ( UCodeBlock* cb, Int sz, Addr eip, Addr eip_next )
1845{
1846 Int ta /* EAX */, tc /* ECX */, td /* EDI */, tv;
1847 ta = newTemp(cb);
1848 tc = newTemp(cb);
1849 tv = newTemp(cb);
1850 td = newTemp(cb);
1851
1852 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, tc);
1853 uInstr2(cb, JIFZ, 4, TempReg, tc, Literal, 0);
1854 uLiteral(cb, eip_next);
1855 uInstr1(cb, DEC, 4, TempReg, tc);
1856 uInstr2(cb, PUT, 4, TempReg, tc, ArchReg, R_ECX);
1857
1858 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
1859 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
1860 uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tv);
1861 /* next uinstr kills ta, but that's ok -- don't need it again */
1862 uInstr2(cb, SUB, sz, TempReg, tv, TempReg, ta);
1863 setFlagsFromUOpcode(cb, SUB);
1864
1865 uInstr0(cb, CALLM_S, 0);
1866 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tv);
1867 uLiteral(cb, 0);
1868 uInstr1(cb, PUSH, 4, TempReg, tv);
1869
1870 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
1871 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
1872
1873 uInstr1(cb, POP, 4, TempReg, tv);
1874 uInstr0(cb, CALLM_E, 0);
1875
1876 if (sz == 4 || sz == 2) {
1877 uInstr2(cb, SHL, 4, Literal, 0, TempReg, tv);
1878 uLiteral(cb, sz/2);
1879 }
1880 uInstr2(cb, ADD, 4, TempReg, tv, TempReg, td);
1881 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
1882 uInstr1(cb, JMP, 0, Literal, 0);
1883 uLiteral(cb, eip);
1884 uCond(cb, CondNZ);
1885 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
1886 uInstr1(cb, JMP, 0, Literal, 0);
1887 uLiteral(cb, eip_next);
1888 uCond(cb, CondAlways);
1889}
1890
1891
1892/* Template for REPE MOVS<sz>. Assumes this insn is the last one in
1893 the basic block, and so emits a jump to the next insn. */
1894static
1895void codegen_REPE_MOVS ( UCodeBlock* cb, Int sz, Addr eip, Addr eip_next )
1896{
1897 Int ts /* ESI */, tc /* ECX */, td /* EDI */, tv;
1898 tc = newTemp(cb);
1899 td = newTemp(cb);
1900 ts = newTemp(cb);
1901 tv = newTemp(cb);
1902
1903 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, tc);
1904 uInstr2(cb, JIFZ, 4, TempReg, tc, Literal, 0);
1905 uLiteral(cb, eip_next);
1906 uInstr1(cb, DEC, 4, TempReg, tc);
1907 uInstr2(cb, PUT, 4, TempReg, tc, ArchReg, R_ECX);
1908
1909 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
1910 uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
1911
1912 uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tv);
1913 uInstr2(cb, STORE, sz, TempReg, tv, TempReg, td);
sewardjde4a1d02002-03-22 01:27:54 +00001914
1915 uInstr0(cb, CALLM_S, 0);
1916 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tv);
1917 uLiteral(cb, 0);
1918 uInstr1(cb, PUSH, 4, TempReg, tv);
1919
1920 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
1921 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
1922
1923 uInstr1(cb, POP, 4, TempReg, tv);
1924 uInstr0(cb, CALLM_E, 0);
1925
1926 if (sz == 4 || sz == 2) {
1927 uInstr2(cb, SHL, 4, Literal, 0, TempReg, tv);
1928 uLiteral(cb, sz/2);
1929 }
1930 uInstr2(cb, ADD, 4, TempReg, tv, TempReg, td);
1931 uInstr2(cb, ADD, 4, TempReg, tv, TempReg, ts);
1932
1933 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
1934 uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
1935
1936 uInstr1(cb, JMP, 0, Literal, 0);
1937 uLiteral(cb, eip);
1938 uCond(cb, CondAlways);
1939}
1940
1941
1942/* Template for REPE STOS<sz>. Assumes this insn is the last one in
1943 the basic block, and so emits a jump to the next insn. */
1944static
1945void codegen_REPE_STOS ( UCodeBlock* cb, Int sz, Addr eip, Addr eip_next )
1946{
1947 Int ta /* EAX */, tc /* ECX */, td /* EDI */;
1948 ta = newTemp(cb);
1949 tc = newTemp(cb);
1950 td = newTemp(cb);
1951
1952 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, tc);
1953 uInstr2(cb, JIFZ, 4, TempReg, tc, Literal, 0);
1954 uLiteral(cb, eip_next);
1955 uInstr1(cb, DEC, 4, TempReg, tc);
1956 uInstr2(cb, PUT, 4, TempReg, tc, ArchReg, R_ECX);
1957
1958 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
1959 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
1960 uInstr2(cb, STORE, sz, TempReg, ta, TempReg, td);
sewardjde4a1d02002-03-22 01:27:54 +00001961
1962 uInstr0(cb, CALLM_S, 0);
1963 uInstr2(cb, MOV, 4, Literal, 0, TempReg, ta);
1964 uLiteral(cb, 0);
1965 uInstr1(cb, PUSH, 4, TempReg, ta);
1966
1967 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
1968 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
1969
1970 uInstr1(cb, POP, 4, TempReg, ta);
1971 uInstr0(cb, CALLM_E, 0);
1972
1973 if (sz == 4 || sz == 2) {
1974 uInstr2(cb, SHL, 4, Literal, 0, TempReg, ta);
1975 uLiteral(cb, sz/2);
1976 }
1977 uInstr2(cb, ADD, 4, TempReg, ta, TempReg, td);
1978 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
1979
1980 uInstr1(cb, JMP, 0, Literal, 0);
1981 uLiteral(cb, eip);
1982 uCond(cb, CondAlways);
1983}
1984
1985
1986/* Template for CMPS<sz>, _not_ preceded by a REP prefix. */
1987static
1988void codegen_CMPS ( UCodeBlock* cb, Int sz )
1989{
1990 Int td, /* EDI */ ts, /* ESI */
1991 tdv, /* (EDI) */ tsv /* (ESI) */;
1992 tdv = newTemp(cb);
1993 tsv = newTemp(cb);
1994 td = newTemp(cb);
1995 ts = newTemp(cb);
1996
1997 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
1998 uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
1999
2000 uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tdv);
2001 uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tsv);
2002
2003 uInstr2(cb, SUB, sz, TempReg, tdv, TempReg, tsv);
2004 setFlagsFromUOpcode(cb, SUB);
2005
2006 uInstr0(cb, CALLM_S, 0);
2007 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tdv);
2008 uLiteral(cb, 0);
2009 uInstr1(cb, PUSH, 4, TempReg, tdv);
2010
2011 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
2012 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
2013
2014 uInstr1(cb, POP, 4, TempReg, tdv);
2015 uInstr0(cb, CALLM_E, 0);
2016
2017 if (sz == 4 || sz == 2) {
2018 uInstr2(cb, SHL, 4, Literal, 0, TempReg, tdv);
2019 uLiteral(cb, sz/2);
2020 }
2021 uInstr2(cb, ADD, 4, TempReg, tdv, TempReg, td);
2022 uInstr2(cb, ADD, 4, TempReg, tdv, TempReg, ts);
2023
2024 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2025 uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
2026}
2027
2028
2029/* Template for MOVS<sz>, _not_ preceded by a REP prefix. */
2030static
2031void codegen_MOVS ( UCodeBlock* cb, Int sz )
2032{
2033 Int tv, /* the value being copied */
2034 td, /* EDI */ ts /* ESI */;
2035 tv = newTemp(cb);
2036 td = newTemp(cb);
2037 ts = newTemp(cb);
2038
2039 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
2040 uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
2041
2042 uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tv);
2043 uInstr2(cb, STORE, sz, TempReg, tv, TempReg, td);
sewardjde4a1d02002-03-22 01:27:54 +00002044
2045 uInstr0(cb, CALLM_S, 0);
2046 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tv);
2047 uLiteral(cb, 0);
2048 uInstr1(cb, PUSH, 4, TempReg, tv);
2049
2050 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
2051 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
2052
2053 uInstr1(cb, POP, 4, TempReg, tv);
2054 uInstr0(cb, CALLM_E, 0);
2055
2056 if (sz == 4 || sz == 2) {
2057 uInstr2(cb, SHL, 4, Literal, 0, TempReg, tv);
2058 uLiteral(cb, sz/2);
2059 }
2060 uInstr2(cb, ADD, 4, TempReg, tv, TempReg, td);
2061 uInstr2(cb, ADD, 4, TempReg, tv, TempReg, ts);
2062
2063 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2064 uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
2065}
2066
2067
2068/* Template for STOS<sz>, _not_ preceded by a REP prefix. */
2069static
2070void codegen_STOS ( UCodeBlock* cb, Int sz )
2071{
2072 Int ta /* EAX */, td /* EDI */;
2073 ta = newTemp(cb);
2074 td = newTemp(cb);
2075
2076 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
2077 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
2078 uInstr2(cb, STORE, sz, TempReg, ta, TempReg, td);
sewardjde4a1d02002-03-22 01:27:54 +00002079
2080 uInstr0(cb, CALLM_S, 0);
2081 uInstr2(cb, MOV, 4, Literal, 0, TempReg, ta);
2082 uLiteral(cb, 0);
2083 uInstr1(cb, PUSH, 4, TempReg, ta);
2084
2085 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
2086 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
2087
2088 uInstr1(cb, POP, 4, TempReg, ta);
2089 uInstr0(cb, CALLM_E, 0);
2090
2091 if (sz == 4 || sz == 2) {
2092 uInstr2(cb, SHL, 4, Literal, 0, TempReg, ta);
2093 uLiteral(cb, sz/2);
2094 }
2095 uInstr2(cb, ADD, 4, TempReg, ta, TempReg, td);
2096 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2097}
2098
2099
2100/* Template for LODS<sz>, _not_ preceded by a REP prefix. */
2101static
2102void codegen_LODS ( UCodeBlock* cb, Int sz )
2103{
2104 Int ta /* EAX */, ts /* ESI */;
2105 ta = newTemp(cb);
2106 ts = newTemp(cb);
2107
2108 uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
2109 uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, ta);
2110 uInstr2(cb, PUT, sz, TempReg, ta, ArchReg, R_EAX);
2111
2112 uInstr0(cb, CALLM_S, 0);
2113 uInstr2(cb, MOV, 4, Literal, 0, TempReg, ta);
2114 uLiteral(cb, 0);
2115 uInstr1(cb, PUSH, 4, TempReg, ta);
2116
2117 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
2118 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
2119
2120 uInstr1(cb, POP, 4, TempReg, ta);
2121 uInstr0(cb, CALLM_E, 0);
2122
2123 if (sz == 4 || sz == 2) {
2124 uInstr2(cb, SHL, 4, Literal, 0, TempReg, ta);
2125 uLiteral(cb, sz/2);
2126 }
2127 uInstr2(cb, ADD, 4, TempReg, ta, TempReg, ts);
2128 uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
2129}
2130
2131
2132/* Template for REPNE SCAS<sz>, _not_ preceded by a REP prefix. */
2133static
2134void codegen_SCAS ( UCodeBlock* cb, Int sz )
2135{
2136 Int ta /* EAX */, td /* EDI */, tv;
2137 ta = newTemp(cb);
2138 tv = newTemp(cb);
2139 td = newTemp(cb);
2140
2141 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
2142 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
2143 uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tv);
2144 /* next uinstr kills ta, but that's ok -- don't need it again */
2145 uInstr2(cb, SUB, sz, TempReg, tv, TempReg, ta);
2146 setFlagsFromUOpcode(cb, SUB);
2147
2148 uInstr0(cb, CALLM_S, 0);
2149 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tv);
2150 uLiteral(cb, 0);
2151 uInstr1(cb, PUSH, 4, TempReg, tv);
2152
2153 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
2154 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
2155
2156 uInstr1(cb, POP, 4, TempReg, tv);
2157 uInstr0(cb, CALLM_E, 0);
2158
2159 if (sz == 4 || sz == 2) {
2160 uInstr2(cb, SHL, 4, Literal, 0, TempReg, tv);
2161 uLiteral(cb, sz/2);
2162 }
2163 uInstr2(cb, ADD, 4, TempReg, tv, TempReg, td);
2164 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2165}
2166
2167
2168/* (I)MUL E, G. Supplied eip points to the modR/M byte. */
2169static
2170Addr dis_mul_E_G ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +00002171 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +00002172 Int size,
2173 Addr eip0,
2174 Bool signed_multiply )
2175{
2176 Int ta, tg, te, helper;
2177 UChar dis_buf[50];
2178 UChar rm = getUChar(eip0);
2179 ta = INVALID_TEMPREG;
2180 te = newTemp(cb);
2181 tg = newTemp(cb);
2182
2183 switch (size) {
2184 case 4: helper = signed_multiply ? VGOFF_(helper_imul_32_64)
2185 : VGOFF_(helper_mul_32_64);
2186 break;
2187 case 2: helper = signed_multiply ? VGOFF_(helper_imul_16_32)
2188 : VGOFF_(helper_mul_16_32);
2189 break;
2190 case 1: helper = signed_multiply ? VGOFF_(helper_imul_8_16)
2191 : VGOFF_(helper_mul_8_16);
2192 break;
njne427a662002-10-02 11:08:25 +00002193 default: VG_(core_panic)("dis_mul_E_G");
sewardjde4a1d02002-03-22 01:27:54 +00002194 }
2195
2196 uInstr0(cb, CALLM_S, 0);
2197 if (epartIsReg(rm)) {
2198 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, te);
2199 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tg);
2200 uInstr1(cb, PUSH, size, TempReg, te);
2201 uInstr1(cb, PUSH, size, TempReg, tg);
2202 uInstr1(cb, CALLM, 0, Lit16, helper);
2203 uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP);
2204 uInstr1(cb, CLEAR, 0, Lit16, 4);
2205 uInstr1(cb, POP, size, TempReg, tg);
2206 uInstr2(cb, PUT, size, TempReg, tg, ArchReg, gregOfRM(rm));
2207 uInstr0(cb, CALLM_E, 0);
2208 if (dis) VG_(printf)("%smul%c %s, %s\n",
2209 signed_multiply ? "i" : "",
2210 nameISize(size),
2211 nameIReg(size,eregOfRM(rm)),
2212 nameIReg(size,gregOfRM(rm)));
2213 return 1+eip0;
2214 } else {
sewardje1042472002-09-30 12:33:11 +00002215 UInt pair = disAMode ( cb, sorb, eip0, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +00002216 ta = LOW24(pair);
2217 uInstr2(cb, LOAD, size, TempReg, ta, TempReg, te);
2218 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tg);
2219 uInstr1(cb, PUSH, size, TempReg, te);
2220 uInstr1(cb, PUSH, size, TempReg, tg);
2221 uInstr1(cb, CALLM, 0, Lit16, helper);
2222 uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP);
2223 uInstr1(cb, CLEAR, 0, Lit16, 4);
2224 uInstr1(cb, POP, size, TempReg, tg);
2225 uInstr2(cb, PUT, size, TempReg, tg, ArchReg, gregOfRM(rm));
2226 uInstr0(cb, CALLM_E, 0);
2227 if (dis) VG_(printf)("%smul%c %s, %s\n",
2228 signed_multiply ? "i" : "",
2229 nameISize(size),
2230 dis_buf,nameIReg(size,gregOfRM(rm)));
2231 return HI8(pair)+eip0;
2232 }
2233}
2234
2235
2236/* IMUL I * E -> G. Supplied eip points to the modR/M byte. */
2237static
2238Addr dis_imul_I_E_G ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +00002239 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +00002240 Int size,
2241 Addr eip,
2242 Int litsize )
2243{
2244 Int ta, te, tl, helper, d32;
2245 UChar dis_buf[50];
2246 UChar rm = getUChar(eip);
2247 ta = INVALID_TEMPREG;
2248 te = newTemp(cb);
2249 tl = newTemp(cb);
2250
2251 switch (size) {
2252 case 4: helper = VGOFF_(helper_imul_32_64); break;
2253 case 2: helper = VGOFF_(helper_imul_16_32); break;
2254 case 1: helper = VGOFF_(helper_imul_8_16); break;
njne427a662002-10-02 11:08:25 +00002255 default: VG_(core_panic)("dis_imul_I_E_G");
sewardjde4a1d02002-03-22 01:27:54 +00002256 }
2257
2258 uInstr0(cb, CALLM_S, 0);
2259 if (epartIsReg(rm)) {
2260 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, te);
2261 uInstr1(cb, PUSH, size, TempReg, te);
2262 eip++;
2263 } else {
sewardje1042472002-09-30 12:33:11 +00002264 UInt pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +00002265 ta = LOW24(pair);
2266 uInstr2(cb, LOAD, size, TempReg, ta, TempReg, te);
2267 uInstr1(cb, PUSH, size, TempReg, te);
2268 eip += HI8(pair);
2269 }
2270
2271 d32 = getSDisp(litsize,eip);
2272 eip += litsize;
2273
2274 uInstr2(cb, MOV, size, Literal, 0, TempReg, tl);
2275 uLiteral(cb, d32);
2276 uInstr1(cb, PUSH, size, TempReg, tl);
2277 uInstr1(cb, CALLM, 0, Lit16, helper);
2278 uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP);
2279 uInstr1(cb, CLEAR, 0, Lit16, 4);
2280 uInstr1(cb, POP, size, TempReg, te);
2281 uInstr2(cb, PUT, size, TempReg, te, ArchReg, gregOfRM(rm));
2282 uInstr0(cb, CALLM_E, 0);
2283
2284 if (dis) {
2285 if (epartIsReg(rm)) {
2286 VG_(printf)("imul %d, %s, %s\n", d32, nameIReg(size,eregOfRM(rm)),
2287 nameIReg(size,gregOfRM(rm)));
2288 } else {
2289 VG_(printf)("imul %d, %s, %s\n", d32, dis_buf,
2290 nameIReg(size,gregOfRM(rm)));
2291 }
2292 }
2293
2294 return eip;
2295}
2296
2297
2298/* Handle FPU insns which read/write memory. On entry, eip points to
2299 the second byte of the insn (the one following D8 .. DF). */
2300static
sewardje1042472002-09-30 12:33:11 +00002301Addr dis_fpu_mem ( UCodeBlock* cb,
2302 UChar sorb,
2303 Int size, Bool is_write,
sewardjde4a1d02002-03-22 01:27:54 +00002304 Addr eip, UChar first_byte )
2305{
2306 Int ta;
2307 UInt pair;
2308 UChar dis_buf[50];
2309 UChar second_byte = getUChar(eip);
2310 vg_assert(second_byte < 0xC0);
2311 second_byte &= 0x38;
sewardje1042472002-09-30 12:33:11 +00002312 pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL );
sewardjde4a1d02002-03-22 01:27:54 +00002313 ta = LOW24(pair);
2314 eip += HI8(pair);
2315 uInstr2(cb, is_write ? FPU_W : FPU_R, size,
2316 Lit16,
2317 (((UShort)first_byte) << 8) | ((UShort)second_byte),
2318 TempReg, ta);
sewardjde4a1d02002-03-22 01:27:54 +00002319 if (dis) {
2320 if (is_write)
2321 VG_(printf)("fpu_w_%d 0x%x:0x%x, %s\n",
2322 size, (UInt)first_byte,
2323 (UInt)second_byte, dis_buf );
2324 else
2325 VG_(printf)("fpu_r_%d %s, 0x%x:0x%x\n",
2326 size, dis_buf,
2327 (UInt)first_byte,
2328 (UInt)second_byte );
2329 }
2330 return eip;
2331}
2332
2333
2334/* Handle FPU insns which don't reference memory. On entry, eip points to
2335 the second byte of the insn (the one following D8 .. DF). */
2336static
2337Addr dis_fpu_no_mem ( UCodeBlock* cb, Addr eip, UChar first_byte )
2338{
sewardj4a7456e2002-03-24 13:52:19 +00002339 Bool sets_ZCP = False;
sewardj8d32be72002-04-18 02:18:24 +00002340 Bool uses_ZCP = False;
sewardjde4a1d02002-03-22 01:27:54 +00002341 UChar second_byte = getUChar(eip); eip++;
2342 vg_assert(second_byte >= 0xC0);
sewardj4a7456e2002-03-24 13:52:19 +00002343
sewardj8d32be72002-04-18 02:18:24 +00002344 /* Does the insn write any integer condition codes (%EIP) ? */
2345
sewardj4a7456e2002-03-24 13:52:19 +00002346 if (first_byte == 0xDB && second_byte >= 0xF0 && second_byte <= 0xF7) {
2347 /* FCOMI */
2348 sets_ZCP = True;
2349 } else
2350 if (first_byte == 0xDF && second_byte >= 0xF0 && second_byte <= 0xF7) {
2351 /* FCOMIP */
2352 sets_ZCP = True;
2353 } else
2354 if (first_byte == 0xDB && second_byte >= 0xE8 && second_byte <= 0xEF) {
2355 /* FUCOMI */
2356 sets_ZCP = True;
2357 } else
2358 if (first_byte == 0xDF && second_byte >= 0xE8 && second_byte <= 0xEF) {
2359 /* FUCOMIP */
2360 sets_ZCP = True;
2361 }
2362
sewardj8d32be72002-04-18 02:18:24 +00002363 /* Dually, does the insn read any integer condition codes (%EIP) ? */
2364
2365 if (first_byte == 0xDA && second_byte >= 0xC0 && second_byte <= 0xDF) {
2366 /* FCMOVB %st(n), %st(0)
2367 FCMOVE %st(n), %st(0)
2368 FCMOVBE %st(n), %st(0)
2369 FCMOVU %st(n), %st(0)
2370 */
2371 uses_ZCP = True;
2372 } else
2373 if (first_byte == 0xDB && second_byte >= 0xC0 && second_byte <= 0xDF) {
2374 /* FCMOVNB %st(n), %st(0)
2375 FCMOVNE %st(n), %st(0)
2376 FCMOVNBE %st(n), %st(0)
2377 FCMOVNU %st(n), %st(0)
2378 */
2379 uses_ZCP = True;
2380 }
2381
sewardjde4a1d02002-03-22 01:27:54 +00002382 uInstr1(cb, FPU, 0,
2383 Lit16,
2384 (((UShort)first_byte) << 8) | ((UShort)second_byte)
2385 );
sewardj8d32be72002-04-18 02:18:24 +00002386 if (uses_ZCP) {
2387 /* VG_(printf)("!!! --- FPU insn which reads %EFLAGS\n"); */
2388 uFlagsRWU(cb, FlagsZCP, FlagsEmpty, FlagsEmpty);
2389 vg_assert(!sets_ZCP);
2390 }
sewardj4a7456e2002-03-24 13:52:19 +00002391 if (sets_ZCP) {
2392 /* VG_(printf)("!!! --- FPU insn which writes %EFLAGS\n"); */
2393 uFlagsRWU(cb, FlagsEmpty, FlagsZCP, FlagsEmpty);
sewardj8d32be72002-04-18 02:18:24 +00002394 vg_assert(!uses_ZCP);
sewardj4a7456e2002-03-24 13:52:19 +00002395 }
2396
sewardj8d32be72002-04-18 02:18:24 +00002397 if (dis) VG_(printf)("fpu 0x%x:0x%x%s%s\n",
sewardj4a7456e2002-03-24 13:52:19 +00002398 (UInt)first_byte, (UInt)second_byte,
sewardj8d32be72002-04-18 02:18:24 +00002399 uses_ZCP ? " -rZCP" : "",
sewardj4a7456e2002-03-24 13:52:19 +00002400 sets_ZCP ? " -wZCP" : "" );
sewardjde4a1d02002-03-22 01:27:54 +00002401 return eip;
2402}
2403
2404
2405/* Top-level handler for all FPU insns. On entry, eip points to the
2406 second byte of the insn. */
2407static
sewardje1042472002-09-30 12:33:11 +00002408Addr dis_fpu ( UCodeBlock* cb,
2409 UChar sorb,
2410 UChar first_byte, Addr eip )
sewardjde4a1d02002-03-22 01:27:54 +00002411{
2412 const Bool rd = False;
2413 const Bool wr = True;
2414 UChar second_byte = getUChar(eip);
2415
2416 /* Handle FSTSW %ax specially. */
2417 if (first_byte == 0xDF && second_byte == 0xE0) {
2418 Int t1 = newTemp(cb);
2419 uInstr0(cb, CALLM_S, 0);
2420 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
2421 uLiteral(cb, 0);
2422 uInstr1(cb, PUSH, 4, TempReg, t1);
2423 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_fstsw_AX) );
2424 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
2425 uInstr1(cb, POP, 2, TempReg, t1);
2426 uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
2427 uInstr0(cb, CALLM_E, 0);
2428 if (dis) VG_(printf)("fstsw %%ax\n");
2429 eip++;
2430 return eip;
2431 }
2432
2433 /* Handle all non-memory FPU ops simply. */
2434 if (second_byte >= 0xC0)
2435 return dis_fpu_no_mem ( cb, eip, first_byte );
2436
2437 /* The insn references memory; need to determine
2438 whether it reads or writes, and at what size. */
2439 switch (first_byte) {
2440
2441 case 0xD8:
2442 switch ((second_byte >> 3) & 7) {
2443 case 0: /* FADDs */
2444 case 1: /* FMULs */
2445 case 2: /* FCOMs */
2446 case 3: /* FCOMPs */
2447 case 4: /* FSUBs */
2448 case 5: /* FSUBRs */
2449 case 6: /* FDIVs */
2450 case 7: /* FDIVRs */
sewardje1042472002-09-30 12:33:11 +00002451 return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002452 default:
2453 goto unhandled;
2454 }
2455 break;
2456
2457 case 0xD9:
2458 switch ((second_byte >> 3) & 7) {
2459 case 0: /* FLDs */
sewardje1042472002-09-30 12:33:11 +00002460 return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002461 case 2: /* FSTs */
2462 case 3: /* FSTPs */
sewardje1042472002-09-30 12:33:11 +00002463 return dis_fpu_mem(cb, sorb, 4, wr, eip, first_byte);
sewardj35a916c2002-07-23 18:48:39 +00002464 case 4: /* FLDENV */
sewardje1042472002-09-30 12:33:11 +00002465 return dis_fpu_mem(cb, sorb, 28, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002466 case 5: /* FLDCW */
sewardje1042472002-09-30 12:33:11 +00002467 return dis_fpu_mem(cb, sorb, 2, rd, eip, first_byte);
sewardj2a8141a2002-07-13 12:27:12 +00002468 case 6: /* FNSTENV */
sewardje1042472002-09-30 12:33:11 +00002469 return dis_fpu_mem(cb, sorb, 28, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002470 case 7: /* FSTCW */
2471 /* HACK! FSTCW actually writes 2 bytes, not 4. glibc
2472 gets lots of moaning in __floor() if we do the right
2473 thing here. */
2474 /* Later ... hack disabled .. we do do the Right Thing. */
sewardje1042472002-09-30 12:33:11 +00002475 return dis_fpu_mem(cb, sorb, /*4*/ 2, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002476 default:
2477 goto unhandled;
2478 }
2479 break;
2480
2481 case 0xDA:
2482 switch ((second_byte >> 3) & 7) {
2483 case 0: /* FIADD */
2484 case 1: /* FIMUL */
2485 case 2: /* FICOM */
2486 case 3: /* FICOMP */
2487 case 4: /* FISUB */
2488 case 5: /* FISUBR */
2489 case 6: /* FIDIV */
2490 case 7: /* FIDIVR */
sewardje1042472002-09-30 12:33:11 +00002491 return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002492 default:
2493 goto unhandled;
2494 }
2495 break;
2496
2497 case 0xDB:
2498 switch ((second_byte >> 3) & 7) {
2499 case 0: /* FILD dword-integer */
sewardje1042472002-09-30 12:33:11 +00002500 return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002501 case 2: /* FIST dword-integer */
sewardje1042472002-09-30 12:33:11 +00002502 return dis_fpu_mem(cb, sorb, 4, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002503 case 3: /* FISTPl */
sewardje1042472002-09-30 12:33:11 +00002504 return dis_fpu_mem(cb, sorb, 4, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002505 case 5: /* FLD extended-real */
sewardje1042472002-09-30 12:33:11 +00002506 return dis_fpu_mem(cb, sorb, 10, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002507 case 7: /* FSTP extended-real */
sewardje1042472002-09-30 12:33:11 +00002508 return dis_fpu_mem(cb, sorb, 10, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002509 default:
2510 goto unhandled;
2511 }
2512 break;
2513
2514 case 0xDC:
2515 switch ((second_byte >> 3) & 7) {
2516 case 0: /* FADD double-real */
2517 case 1: /* FMUL double-real */
2518 case 2: /* FCOM double-real */
2519 case 3: /* FCOMP double-real */
2520 case 4: /* FSUB double-real */
2521 case 5: /* FSUBR double-real */
2522 case 6: /* FDIV double-real */
2523 case 7: /* FDIVR double-real */
sewardje1042472002-09-30 12:33:11 +00002524 return dis_fpu_mem(cb, sorb, 8, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002525 default:
2526 goto unhandled;
2527 }
2528 break;
2529
2530 case 0xDD:
2531 switch ((second_byte >> 3) & 7) {
2532 case 0: /* FLD double-real */
sewardje1042472002-09-30 12:33:11 +00002533 return dis_fpu_mem(cb, sorb, 8, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002534 case 2: /* FST double-real */
2535 case 3: /* FSTP double-real */
sewardje1042472002-09-30 12:33:11 +00002536 return dis_fpu_mem(cb, sorb, 8, wr, eip, first_byte);
njn25e49d8e72002-09-23 09:36:25 +00002537 case 4: /* FRSTOR */
sewardje1042472002-09-30 12:33:11 +00002538 return dis_fpu_mem(cb, sorb, 108, rd, eip, first_byte);
njn25e49d8e72002-09-23 09:36:25 +00002539 case 6: /* FSAVE */
sewardje1042472002-09-30 12:33:11 +00002540 return dis_fpu_mem(cb, sorb, 108, wr, eip, first_byte);
njn25e49d8e72002-09-23 09:36:25 +00002541 case 7: /* FSTSW */
sewardje1042472002-09-30 12:33:11 +00002542 return dis_fpu_mem(cb, sorb, 2, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002543 default:
2544 goto unhandled;
2545 }
2546 break;
2547
2548 case 0xDF:
2549 switch ((second_byte >> 3) & 7) {
2550 case 0: /* FILD word-integer */
sewardje1042472002-09-30 12:33:11 +00002551 return dis_fpu_mem(cb, sorb, 2, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002552 case 2: /* FIST word-integer */
sewardje1042472002-09-30 12:33:11 +00002553 return dis_fpu_mem(cb, sorb, 2, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002554 case 3: /* FISTP word-integer */
sewardje1042472002-09-30 12:33:11 +00002555 return dis_fpu_mem(cb, sorb, 2, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002556 case 5: /* FILD qword-integer */
sewardje1042472002-09-30 12:33:11 +00002557 return dis_fpu_mem(cb, sorb, 8, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002558 case 7: /* FISTP qword-integer */
sewardje1042472002-09-30 12:33:11 +00002559 return dis_fpu_mem(cb, sorb, 8, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002560 default:
2561 goto unhandled;
2562 }
2563 break;
2564
2565 default: goto unhandled;
2566 }
2567
2568 unhandled:
2569 VG_(printf)("dis_fpu: unhandled memory case 0x%2x:0x%2x(%d)\n",
2570 (UInt)first_byte, (UInt)second_byte,
2571 (UInt)((second_byte >> 3) & 7) );
njne427a662002-10-02 11:08:25 +00002572 VG_(core_panic)("dis_fpu: unhandled opcodes");
sewardjde4a1d02002-03-22 01:27:54 +00002573}
2574
2575
2576/* Double length left shifts. Apparently only required in v-size (no
2577 b- variant). */
2578static
sewardje1042472002-09-30 12:33:11 +00002579Addr dis_SHLRD_Gv_Ev ( UCodeBlock* cb,
2580 UChar sorb,
2581 Addr eip, UChar modrm,
sewardjde4a1d02002-03-22 01:27:54 +00002582 Int sz,
2583 Tag amt_tag, UInt amt_val,
2584 Bool left_shift )
2585{
2586 /* amt_tag and amt_val denote either ArchReg(%CL) or a Literal.
2587 And eip on entry points at the modrm byte. */
2588 Int t, t1, t2, ta, helper;
2589 UInt pair;
2590 UChar dis_buf[50];
2591
2592 vg_assert(sz == 2 || sz == 4);
2593
2594 helper = left_shift
2595 ? (sz==4 ? VGOFF_(helper_shldl)
2596 : VGOFF_(helper_shldw))
2597 : (sz==4 ? VGOFF_(helper_shrdl)
2598 : VGOFF_(helper_shrdw));
2599
2600 /* Get the amount to be shifted by onto the stack. */
2601 t = newTemp(cb);
2602 t1 = newTemp(cb);
2603 t2 = newTemp(cb);
2604 if (amt_tag == ArchReg) {
2605 vg_assert(amt_val == R_CL);
2606 uInstr2(cb, GET, 1, ArchReg, amt_val, TempReg, t);
2607 } else {
2608 uInstr2(cb, MOV, 1, Literal, 0, TempReg, t);
2609 uLiteral(cb, amt_val);
2610 }
2611
2612 uInstr0(cb, CALLM_S, 0);
2613 uInstr1(cb, PUSH, 1, TempReg, t);
2614
2615 /* The E-part is the destination; this is shifted. The G-part
2616 supplies bits to be shifted into the E-part, but is not
2617 changed. */
2618
2619 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t1);
2620 uInstr1(cb, PUSH, sz, TempReg, t1);
2621
2622 if (epartIsReg(modrm)) {
2623 eip++;
2624 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t2);
2625 uInstr1(cb, PUSH, sz, TempReg, t2);
2626 uInstr1(cb, CALLM, 0, Lit16, helper);
2627 uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
2628 uInstr1(cb, POP, sz, TempReg, t);
2629 uInstr2(cb, PUT, sz, TempReg, t, ArchReg, eregOfRM(modrm));
2630 if (dis)
njn5b3b0f32003-02-03 11:08:52 +00002631 VG_(printf)("sh%cd%c %%cl, %s, %s\n",
2632 ( left_shift ? 'l' : 'r' ),
sewardjde4a1d02002-03-22 01:27:54 +00002633 nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
2634 nameIReg(sz, eregOfRM(modrm)));
2635 } else {
sewardje1042472002-09-30 12:33:11 +00002636 pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL );
sewardjde4a1d02002-03-22 01:27:54 +00002637 ta = LOW24(pair);
2638 eip += HI8(pair);
2639 uInstr2(cb, LOAD, sz, TempReg, ta, TempReg, t2);
2640 uInstr1(cb, PUSH, sz, TempReg, t2);
2641 uInstr1(cb, CALLM, 0, Lit16, helper);
2642 uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
2643 uInstr1(cb, POP, sz, TempReg, t);
2644 uInstr2(cb, STORE, sz, TempReg, t, TempReg, ta);
sewardjde4a1d02002-03-22 01:27:54 +00002645 if (dis)
njn5b3b0f32003-02-03 11:08:52 +00002646 VG_(printf)("sh%cd%c %%cl, %s, %s\n",
2647 ( left_shift ? 'l' : 'r' ),
sewardjde4a1d02002-03-22 01:27:54 +00002648 nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
2649 dis_buf);
2650 }
2651
2652 if (amt_tag == Literal) eip++;
2653 uInstr1(cb, CLEAR, 0, Lit16, 8);
2654
2655 uInstr0(cb, CALLM_E, 0);
2656 return eip;
2657}
2658
2659
2660/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
2661 required. */
2662
2663typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
2664
2665static Char* nameBtOp ( BtOp op )
2666{
2667 switch (op) {
2668 case BtOpNone: return "";
2669 case BtOpSet: return "s";
2670 case BtOpReset: return "r";
2671 case BtOpComp: return "c";
njne427a662002-10-02 11:08:25 +00002672 default: VG_(core_panic)("nameBtOp");
sewardjde4a1d02002-03-22 01:27:54 +00002673 }
2674}
2675
sewardj7f2a8bf2002-04-15 14:35:28 +00002676
2677static
sewardje1042472002-09-30 12:33:11 +00002678Addr dis_bt_G_E ( UCodeBlock* cb,
2679 UChar sorb,
2680 Int sz, Addr eip, BtOp op )
sewardj7f2a8bf2002-04-15 14:35:28 +00002681{
2682 UInt pair;
2683 UChar dis_buf[50];
2684 UChar modrm;
2685
2686 Int t_addr, t_bitno, t_mask, t_fetched, t_esp, temp, lit;
2687
2688 /* 2 and 4 are actually possible. */
2689 vg_assert(sz == 2 || sz == 4);
2690 /* We only handle 4. */
2691 vg_assert(sz == 4);
2692
2693 t_addr = t_bitno = t_mask
2694 = t_fetched = t_esp = temp = INVALID_TEMPREG;
2695
2696 t_fetched = newTemp(cb);
2697 t_bitno = newTemp(cb);
2698 temp = newTemp(cb);
2699 lit = newTemp(cb);
2700
2701 modrm = getUChar(eip);
2702
2703 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t_bitno);
2704
2705 if (epartIsReg(modrm)) {
2706 eip++;
2707 /* Get it onto the client's stack. */
2708 t_esp = newTemp(cb);
2709 t_addr = newTemp(cb);
2710 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t_esp);
2711 uInstr2(cb, SUB, sz, Literal, 0, TempReg, t_esp);
2712 uLiteral(cb, sz);
2713 uInstr2(cb, PUT, 4, TempReg, t_esp, ArchReg, R_ESP);
2714 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, temp);
2715 uInstr2(cb, STORE, sz, TempReg, temp, TempReg, t_esp);
2716 /* Make ta point at it. */
2717 uInstr2(cb, MOV, 4, TempReg, t_esp, TempReg, t_addr);
2718 /* Mask out upper bits of the shift amount, since we're doing a
2719 reg. */
2720 uInstr2(cb, MOV, 4, Literal, 0, TempReg, lit);
2721 uLiteral(cb, sz == 4 ? 31 : 15);
2722 uInstr2(cb, AND, 4, TempReg, lit, TempReg, t_bitno);
2723 } else {
sewardje1042472002-09-30 12:33:11 +00002724 pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL );
sewardj7f2a8bf2002-04-15 14:35:28 +00002725 t_addr = LOW24(pair);
2726 eip += HI8(pair);
2727 }
2728
2729 /* At this point: ta points to the address being operated on. If
2730 it was a reg, we will have pushed it onto the client's stack.
2731 t_bitno is the bit number, suitable masked in the case of a reg. */
2732
2733 /* Now the main sequence. */
2734
2735 uInstr2(cb, MOV, 4, TempReg, t_bitno, TempReg, temp);
2736 uInstr2(cb, SAR, 4, Literal, 0, TempReg, temp);
2737 uLiteral(cb, 3);
2738 uInstr2(cb, ADD, 4, TempReg, temp, TempReg, t_addr);
2739 /* ta now holds effective address */
2740
2741 uInstr2(cb, MOV, 4, Literal, 0, TempReg, lit);
2742 uLiteral(cb, 7);
2743 uInstr2(cb, AND, 4, TempReg, lit, TempReg, t_bitno);
2744 /* bitno contains offset of bit within byte */
2745
2746 if (op != BtOpNone) {
2747 t_mask = newTemp(cb);
2748 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_mask);
2749 uLiteral(cb, 1);
2750 uInstr2(cb, SHL, 4, TempReg, t_bitno, TempReg, t_mask);
2751 }
2752 /* mask is now a suitable byte mask */
2753
2754 uInstr2(cb, LOAD, 1, TempReg, t_addr, TempReg, t_fetched);
2755 if (op != BtOpNone) {
2756 uInstr2(cb, MOV, 4, TempReg, t_fetched, TempReg, temp);
2757 switch (op) {
2758 case BtOpSet:
2759 uInstr2(cb, OR, 4, TempReg, t_mask, TempReg, temp);
2760 break;
2761 case BtOpComp:
2762 uInstr2(cb, XOR, 4, TempReg, t_mask, TempReg, temp);
2763 break;
2764 case BtOpReset:
2765 uInstr1(cb, NOT, 4, TempReg, t_mask);
2766 uInstr2(cb, AND, 4, TempReg, t_mask, TempReg, temp);
2767 break;
2768 default:
njne427a662002-10-02 11:08:25 +00002769 VG_(core_panic)("dis_bt_G_E");
sewardj7f2a8bf2002-04-15 14:35:28 +00002770 }
2771 uInstr2(cb, STORE, 1, TempReg, temp, TempReg, t_addr);
2772 }
2773
2774 /* Side effect done; now get selected bit into Carry flag */
2775
2776 uInstr2(cb, SHR, 4, TempReg, t_bitno, TempReg, t_fetched);
2777 /* at bit 0 of fetched */
2778
2779 uInstr2(cb, MOV, 4, Literal, 0, TempReg, lit);
2780 uLiteral(cb, 1);
2781 uInstr2(cb, AND, 4, TempReg, lit, TempReg, t_fetched);
2782 /* fetched is now 1 or 0 */
2783
2784 /* NEG is a handy way to convert zero/nonzero into the carry
2785 flag. */
2786 uInstr1(cb, NEG, 4, TempReg, t_fetched);
2787 setFlagsFromUOpcode(cb, NEG);
2788 /* fetched is now in carry flag */
2789
2790 /* Move reg operand from stack back to reg */
2791 if (epartIsReg(modrm)) {
2792 /* t_esp still points at it. */
2793 uInstr2(cb, LOAD, sz, TempReg, t_esp, TempReg, temp);
2794 uInstr2(cb, PUT, sz, TempReg, temp, ArchReg, eregOfRM(modrm));
2795 uInstr2(cb, ADD, sz, Literal, 0, TempReg, t_esp);
2796 uLiteral(cb, sz);
2797 uInstr2(cb, PUT, 4, TempReg, t_esp, ArchReg, R_ESP);
2798 }
2799
2800 if (epartIsReg(modrm)) {
2801 if (dis)
2802 VG_(printf)("bt%s%c %s, %s\n",
2803 nameBtOp(op),
2804 nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
2805 nameIReg(sz, eregOfRM(modrm)));
2806 } else {
2807 if (dis)
2808 VG_(printf)("bt%s%c %s, %s\n",
2809 nameBtOp(op),
2810 nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
2811 dis_buf);
2812 }
2813
2814 return eip;
2815}
2816
2817
sewardjde4a1d02002-03-22 01:27:54 +00002818
2819
2820/* Handle BSF/BSR. Only v-size seems necessary. */
2821static
sewardje1042472002-09-30 12:33:11 +00002822Addr dis_bs_E_G ( UCodeBlock* cb,
2823 UChar sorb,
2824 Int sz, Addr eip, Bool fwds )
sewardjde4a1d02002-03-22 01:27:54 +00002825{
sewardj9316cba2002-05-03 20:52:53 +00002826 Int t, t1, ta, helper;
sewardjde4a1d02002-03-22 01:27:54 +00002827 UInt pair;
2828 UChar dis_buf[50];
2829 UChar modrm;
2830
2831 vg_assert(sz == 2 || sz == 4);
2832 vg_assert(sz==4);
2833
2834 helper = fwds ? VGOFF_(helper_bsf) : VGOFF_(helper_bsr);
2835 modrm = getUChar(eip);
sewardj9316cba2002-05-03 20:52:53 +00002836 t1 = newTemp(cb);
sewardjde4a1d02002-03-22 01:27:54 +00002837 t = newTemp(cb);
2838
sewardj9316cba2002-05-03 20:52:53 +00002839 uInstr0(cb, CALLM_S, 0);
2840 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t1);
2841 uInstr1(cb, PUSH, sz, TempReg, t1);
2842
sewardjde4a1d02002-03-22 01:27:54 +00002843 if (epartIsReg(modrm)) {
2844 eip++;
2845 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t);
2846 if (dis)
2847 VG_(printf)("bs%c%c %s, %s\n",
2848 fwds ? 'f' : 'r',
2849 nameISize(sz), nameIReg(sz, eregOfRM(modrm)),
2850 nameIReg(sz, gregOfRM(modrm)));
2851 } else {
sewardje1042472002-09-30 12:33:11 +00002852 pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL );
sewardjde4a1d02002-03-22 01:27:54 +00002853 ta = LOW24(pair);
2854 eip += HI8(pair);
2855 uInstr2(cb, LOAD, sz, TempReg, ta, TempReg, t);
2856 if (dis)
2857 VG_(printf)("bs%c%c %s, %s\n",
2858 fwds ? 'f' : 'r',
2859 nameISize(sz), dis_buf,
2860 nameIReg(sz, gregOfRM(modrm)));
2861 }
2862
sewardjde4a1d02002-03-22 01:27:54 +00002863 uInstr1(cb, PUSH, sz, TempReg, t);
2864 uInstr1(cb, CALLM, 0, Lit16, helper);
2865 uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsOSACP);
2866 uInstr1(cb, POP, sz, TempReg, t);
sewardj9316cba2002-05-03 20:52:53 +00002867 uInstr1(cb, POP, sz, TempReg, t);
sewardjde4a1d02002-03-22 01:27:54 +00002868 uInstr2(cb, PUT, sz, TempReg, t, ArchReg, gregOfRM(modrm));
2869 uInstr0(cb, CALLM_E, 0);
2870
2871 return eip;
2872}
2873
2874
2875static
2876void codegen_xchg_eAX_Reg ( UCodeBlock* cb, Int sz, Int reg )
2877{
2878 Int t1, t2;
2879 vg_assert(sz == 2 || sz == 4);
2880 t1 = newTemp(cb);
2881 t2 = newTemp(cb);
2882 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
2883 uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t2);
2884 uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, R_EAX);
2885 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
2886 if (dis)
2887 VG_(printf)("xchg%c %s, %s\n", nameISize(sz),
2888 nameIReg(sz, R_EAX), nameIReg(sz, reg));
2889}
2890
2891
2892static
2893void codegen_SAHF ( UCodeBlock* cb )
2894{
sewardj3a72df02002-03-24 10:03:17 +00002895 Int t = newTemp(cb);
2896 Int t2 = newTemp(cb);
sewardjde4a1d02002-03-22 01:27:54 +00002897 uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t);
sewardj3a72df02002-03-24 10:03:17 +00002898
2899 /* Mask out parts of t not corresponding to %AH. This stops the
2900 instrumenter complaining if they are undefined. Otherwise, the
2901 instrumenter would check all 32 bits of t at the PUSH, which
2902 could be the cause of incorrect warnings. Discovered by Daniel
2903 Veillard <veillard@redhat.com>.
2904 */
2905 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
2906 uLiteral(cb, 0x0000FF00);
2907 uInstr2(cb, AND, 4, TempReg, t2, TempReg, t);
2908 /* We deliberately don't set the condition codes here, since this
2909 AND is purely internal to Valgrind and nothing to do with the
2910 client's state. */
2911
sewardjde4a1d02002-03-22 01:27:54 +00002912 uInstr0(cb, CALLM_S, 0);
2913 uInstr1(cb, PUSH, 4, TempReg, t);
2914 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_SAHF));
2915 uFlagsRWU(cb, FlagsEmpty, FlagsSZACP, FlagsEmpty);
2916 uInstr1(cb, CLEAR, 0, Lit16, 4);
2917 uInstr0(cb, CALLM_E, 0);
2918}
2919
2920
2921static
2922Addr dis_cmpxchg_G_E ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +00002923 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +00002924 Int size,
2925 Addr eip0 )
2926{
2927 Int ta, junk, dest, src, acc;
2928 UChar dis_buf[50];
2929 UChar rm;
2930
2931 rm = getUChar(eip0);
2932 acc = newTemp(cb);
2933 src = newTemp(cb);
2934 dest = newTemp(cb);
2935 junk = newTemp(cb);
2936 /* Only needed to get gcc's dataflow analyser off my back. */
2937 ta = INVALID_TEMPREG;
2938
2939 if (epartIsReg(rm)) {
2940 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, dest);
2941 eip0++;
2942 if (dis) VG_(printf)("cmpxchg%c %s,%s\n",
2943 nameISize(size),
2944 nameIReg(size,gregOfRM(rm)),
2945 nameIReg(size,eregOfRM(rm)) );
2946 nameIReg(size,eregOfRM(rm));
2947 } else {
sewardje1042472002-09-30 12:33:11 +00002948 UInt pair = disAMode ( cb, sorb, eip0, dis?dis_buf:NULL );
sewardjde4a1d02002-03-22 01:27:54 +00002949 ta = LOW24(pair);
2950 uInstr2(cb, LOAD, size, TempReg, ta, TempReg, dest);
2951 eip0 += HI8(pair);
2952 if (dis) VG_(printf)("cmpxchg%c %s,%s\n", nameISize(size),
2953 nameIReg(size,gregOfRM(rm)), dis_buf);
2954 }
2955
2956 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, src);
2957 uInstr2(cb, GET, size, ArchReg, R_EAX, TempReg, acc);
2958 uInstr2(cb, MOV, size, TempReg, acc, TempReg, junk);
2959 uInstr2(cb, SUB, size, TempReg, dest, TempReg, junk);
2960 setFlagsFromUOpcode(cb, SUB);
2961
2962 uInstr2(cb, CMOV, 4, TempReg, src, TempReg, dest);
2963 uCond(cb, CondZ);
2964 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
2965 uInstr2(cb, CMOV, 4, TempReg, dest, TempReg, acc);
2966 uCond(cb, CondNZ);
2967 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
2968
2969 uInstr2(cb, PUT, size, TempReg, acc, ArchReg, R_EAX);
2970 if (epartIsReg(rm)) {
2971 uInstr2(cb, PUT, size, TempReg, dest, ArchReg, eregOfRM(rm));
2972 } else {
2973 uInstr2(cb, STORE, size, TempReg, dest, TempReg, ta);
2974 }
2975
2976 return eip0;
2977}
2978
2979
2980/* Handle conditional move instructions of the form
2981 cmovcc E(reg-or-mem), G(reg)
2982
2983 E(src) is reg-or-mem
2984 G(dst) is reg.
2985
2986 If E is reg, --> GET %E, tmps
2987 GET %G, tmpd
2988 CMOVcc tmps, tmpd
2989 PUT tmpd, %G
2990
2991 If E is mem --> (getAddr E) -> tmpa
2992 LD (tmpa), tmps
2993 GET %G, tmpd
2994 CMOVcc tmps, tmpd
2995 PUT tmpd, %G
2996*/
2997static
2998Addr dis_cmov_E_G ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +00002999 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +00003000 Int size,
3001 Condcode cond,
3002 Addr eip0 )
3003{
3004 UChar rm = getUChar(eip0);
3005 UChar dis_buf[50];
3006
3007 Int tmps = newTemp(cb);
3008 Int tmpd = newTemp(cb);
3009
3010 if (epartIsReg(rm)) {
3011 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, tmps);
3012 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmpd);
3013 uInstr2(cb, CMOV, 4, TempReg, tmps, TempReg, tmpd);
3014 uCond(cb, cond);
3015 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
3016 uInstr2(cb, PUT, size, TempReg, tmpd, ArchReg, gregOfRM(rm));
3017 if (dis) VG_(printf)("cmov%c%s %s,%s\n",
3018 nameISize(size),
njn563f96f2003-02-03 11:17:46 +00003019 VG_(name_UCondcode)(cond),
sewardjde4a1d02002-03-22 01:27:54 +00003020 nameIReg(size,eregOfRM(rm)),
3021 nameIReg(size,gregOfRM(rm)));
3022 return 1+eip0;
3023 }
3024
3025 /* E refers to memory */
3026 {
sewardje1042472002-09-30 12:33:11 +00003027 UInt pair = disAMode ( cb, sorb, eip0, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +00003028 Int tmpa = LOW24(pair);
3029 uInstr2(cb, LOAD, size, TempReg, tmpa, TempReg, tmps);
3030 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmpd);
3031 uInstr2(cb, CMOV, 4, TempReg, tmps, TempReg, tmpd);
3032 uCond(cb, cond);
3033 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
3034 uInstr2(cb, PUT, size, TempReg, tmpd, ArchReg, gregOfRM(rm));
3035 if (dis) VG_(printf)("cmov%c%s %s,%s\n",
3036 nameISize(size),
njn563f96f2003-02-03 11:17:46 +00003037 VG_(name_UCondcode)(cond),
sewardjde4a1d02002-03-22 01:27:54 +00003038 dis_buf,
3039 nameIReg(size,gregOfRM(rm)));
3040 return HI8(pair)+eip0;
3041 }
3042}
3043
3044
3045static
3046Addr dis_xadd_G_E ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +00003047 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +00003048 Int sz,
3049 Addr eip0 )
3050{
3051 UChar rm = getUChar(eip0);
3052 UChar dis_buf[50];
3053
3054 Int tmpd = newTemp(cb);
3055 Int tmpt = newTemp(cb);
3056
3057 if (epartIsReg(rm)) {
3058 uInstr2(cb, GET, sz, ArchReg, eregOfRM(rm), TempReg, tmpd);
3059 uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
3060 uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
3061 setFlagsFromUOpcode(cb, ADD);
3062 uInstr2(cb, PUT, sz, TempReg, tmpt, ArchReg, eregOfRM(rm));
3063 uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
3064 if (dis)
3065 VG_(printf)("xadd%c %s, %s\n", nameISize(sz),
3066 nameIReg(sz,gregOfRM(rm)),
3067 nameIReg(sz,eregOfRM(rm)));
3068 return 1+eip0;
3069 } else {
sewardje1042472002-09-30 12:33:11 +00003070 UInt pair = disAMode ( cb, sorb, eip0, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +00003071 Int tmpa = LOW24(pair);
3072 uInstr2(cb, LOAD, sz, TempReg, tmpa, TempReg, tmpd);
3073 uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
3074 uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
3075 setFlagsFromUOpcode(cb, ADD);
3076 uInstr2(cb, STORE, sz, TempReg, tmpt, TempReg, tmpa);
sewardjde4a1d02002-03-22 01:27:54 +00003077 uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
3078 if (dis)
3079 VG_(printf)("xadd%c %s, %s\n", nameISize(sz),
3080 nameIReg(sz,gregOfRM(rm)),
3081 dis_buf);
3082 return HI8(pair)+eip0;
3083 }
3084}
3085
3086
sewardje1042472002-09-30 12:33:11 +00003087/* Moves of Ew into a segment register.
3088 mov Ew, Sw meaning
3089 mov reg-or-mem, reg
3090 Is passed the a ptr to the modRM byte, and the data size. Returns
3091 the address advanced completely over this instruction.
3092
3093 Ew(src) is reg-or-mem
3094 Sw(dst) is seg reg.
3095
3096 If E is reg, --> GETw %Ew, tmpv
3097 PUTSEG tmpv, %Sw
3098
3099 If E is mem --> (getAddr E) -> tmpa
3100 LDw (tmpa), tmpb
3101 PUTSEG tmpb, %Sw
3102*/
3103static
3104Addr dis_mov_Ew_Sw ( UCodeBlock* cb,
sewardjd077f532002-09-30 21:52:50 +00003105 UChar sorb,
sewardje1042472002-09-30 12:33:11 +00003106 Addr eip0 )
3107{
3108 UChar rm = getUChar(eip0);
3109 UChar dis_buf[50];
3110
3111 if (epartIsReg(rm)) {
3112 Int tmpv = newTemp(cb);
3113 uInstr2(cb, GET, 2, ArchReg, eregOfRM(rm), TempReg, tmpv);
3114 uInstr2(cb, PUTSEG, 2, TempReg, tmpv, ArchRegS, gregOfRM(rm));
3115 if (dis) VG_(printf)("movw %s,%s\n",
3116 nameIReg(2,eregOfRM(rm)),
3117 nameSReg(gregOfRM(rm)));
3118 return 1+eip0;
3119 }
3120
3121 /* E refers to memory */
3122 {
3123 UInt pair = disAMode ( cb, sorb, eip0, dis?dis_buf:NULL);
3124 Int tmpa = LOW24(pair);
3125 Int tmpb = newTemp(cb);
3126 uInstr2(cb, LOAD, 2, TempReg, tmpa, TempReg, tmpb);
3127 uInstr2(cb, PUTSEG, 2, TempReg, tmpb, ArchRegS, gregOfRM(rm));
3128 if (dis) VG_(printf)("movw %s,%s\n",
3129 dis_buf,nameSReg(gregOfRM(rm)));
3130 return HI8(pair)+eip0;
3131 }
3132}
3133
3134
sewardjd077f532002-09-30 21:52:50 +00003135/* Moves of a segment register to Ew.
3136 mov Sw, Ew meaning
3137 mov reg, reg-or-mem
3138 Is passed the a ptr to the modRM byte, and the data size. Returns
3139 the address advanced completely over this instruction.
3140
3141 Sw(src) is seg reg.
3142 Ew(dst) is reg-or-mem
3143
3144 If E is reg, --> GETSEG %Sw, tmp
3145 PUTW tmp, %Ew
3146
3147 If E is mem, --> (getAddr E) -> tmpa
3148 GETSEG %Sw, tmpv
3149 STW tmpv, (tmpa)
3150*/
3151static
3152Addr dis_mov_Sw_Ew ( UCodeBlock* cb,
3153 UChar sorb,
3154 Addr eip0 )
3155{
3156 UChar rm = getUChar(eip0);
3157 UChar dis_buf[50];
3158
3159 if (epartIsReg(rm)) {
3160 Int tmpv = newTemp(cb);
3161 uInstr2(cb, GETSEG, 2, ArchRegS, gregOfRM(rm), TempReg, tmpv);
3162 uInstr2(cb, PUT, 2, TempReg, tmpv, ArchReg, eregOfRM(rm));
3163 if (dis) VG_(printf)("movw %s,%s\n",
3164 nameSReg(gregOfRM(rm)),
3165 nameIReg(2,eregOfRM(rm)));
3166 return 1+eip0;
3167 }
3168
3169 /* E refers to memory */
3170 {
3171 UInt pair = disAMode ( cb, sorb, eip0, dis?dis_buf:NULL);
3172 Int tmpa = LOW24(pair);
3173 Int tmpv = newTemp(cb);
3174 uInstr2(cb, GETSEG, 2, ArchRegS, gregOfRM(rm), TempReg, tmpv);
3175 uInstr2(cb, STORE, 2, TempReg, tmpv, TempReg, tmpa);
3176 if (dis) VG_(printf)("mov %s,%s\n",
3177 nameSReg(gregOfRM(rm)), dis_buf);
3178 return HI8(pair)+eip0;
3179 }
3180}
3181
3182
sewardjde4a1d02002-03-22 01:27:54 +00003183/*------------------------------------------------------------*/
3184/*--- Disassembling entire basic blocks ---*/
3185/*------------------------------------------------------------*/
3186
3187/* Disassemble a single instruction into ucode, returning the update
3188 eip, and setting *isEnd to True if this is the last insn in a basic
3189 block. Also do debug printing if (dis). */
3190
3191static Addr disInstr ( UCodeBlock* cb, Addr eip, Bool* isEnd )
3192{
3193 UChar opc, modrm, abyte;
3194 UInt d32, pair;
3195 Int t1, t2, t3, t4;
3196 UChar dis_buf[50];
3197 Int am_sz, d_sz;
3198
sewardje1042472002-09-30 12:33:11 +00003199 /* sz denotes the nominal data-op size of the insn; we change it to
3200 2 if an 0x66 prefix is seen */
3201 Int sz = 4;
3202
3203 /* sorb holds the segment-override-prefix byte, if any. Zero if no
3204 prefix has been seen, else one of {0x26, 0x3E, 0x64, 0x65}
3205 indicating the prefix. */
3206 UChar sorb = 0;
3207
3208 Int first_uinstr = cb->used;
sewardjde4a1d02002-03-22 01:27:54 +00003209 *isEnd = False;
3210 t1 = t2 = t3 = t4 = INVALID_TEMPREG;
3211
3212 if (dis) VG_(printf)("\t0x%x: ", eip);
3213
sewardjc7529c32002-04-16 01:55:18 +00003214 /* Spot the client-request magic sequence. */
3215 {
sewardjde4a1d02002-03-22 01:27:54 +00003216 UChar* myeip = (UChar*)eip;
3217 /* Spot this:
3218 C1C01D roll $29, %eax
3219 C1C003 roll $3, %eax
sewardj2e93c502002-04-12 11:12:52 +00003220 C1C81B rorl $27, %eax
3221 C1C805 rorl $5, %eax
3222 C1C00D roll $13, %eax
3223 C1C013 roll $19, %eax
sewardjde4a1d02002-03-22 01:27:54 +00003224 */
sewardj2e93c502002-04-12 11:12:52 +00003225 if (myeip[ 0] == 0xC1 && myeip[ 1] == 0xC0 && myeip[ 2] == 0x1D &&
3226 myeip[ 3] == 0xC1 && myeip[ 4] == 0xC0 && myeip[ 5] == 0x03 &&
3227 myeip[ 6] == 0xC1 && myeip[ 7] == 0xC8 && myeip[ 8] == 0x1B &&
3228 myeip[ 9] == 0xC1 && myeip[10] == 0xC8 && myeip[11] == 0x05 &&
3229 myeip[12] == 0xC1 && myeip[13] == 0xC0 && myeip[14] == 0x0D &&
3230 myeip[15] == 0xC1 && myeip[16] == 0xC0 && myeip[17] == 0x13
3231 ) {
3232 eip += 18;
3233 uInstr1(cb, JMP, 0, Literal, 0);
3234 uLiteral(cb, eip);
3235 uCond(cb, CondAlways);
3236 LAST_UINSTR(cb).jmpkind = JmpClientReq;
3237 *isEnd = True;
3238 if (dis)
3239 VG_(printf)("%%edx = client_request ( %%eax )\n");
sewardjde4a1d02002-03-22 01:27:54 +00003240 return eip;
3241 }
3242 }
3243
3244 /* Skip a LOCK prefix. */
sewardj5716dbb2002-04-26 03:28:18 +00003245 if (getUChar(eip) == 0xF0) {
3246 /* VG_(printf)("LOCK LOCK LOCK LOCK LOCK \n"); */
sewardj7a5ebcf2002-11-13 22:42:13 +00003247 uInstr0(cb, LOCK, 0);
sewardj5716dbb2002-04-26 03:28:18 +00003248 eip++;
3249 }
sewardjde4a1d02002-03-22 01:27:54 +00003250
sewardjde4a1d02002-03-22 01:27:54 +00003251 /* Detect operand-size overrides. */
3252 if (getUChar(eip) == 0x66) { sz = 2; eip++; };
3253
sewardje1042472002-09-30 12:33:11 +00003254 /* segment override prefixes come after the operand-size override,
3255 it seems */
3256 switch (getUChar(eip)) {
3257 case 0x3E: /* %DS: */
3258 case 0x26: /* %ES: */
3259 case 0x64: /* %FS: */
3260 case 0x65: /* %GS: */
3261 sorb = getUChar(eip); eip++;
3262 break;
3263 case 0x2E: /* %CS: */
3264 VG_(unimplemented)("x86 segment override (SEG=CS) prefix");
3265 /*NOTREACHED*/
3266 break;
3267 case 0x36: /* %SS: */
3268 VG_(unimplemented)("x86 segment override (SEG=SS) prefix");
3269 /*NOTREACHED*/
3270 break;
3271 default:
3272 break;
3273 }
3274
3275
sewardjde4a1d02002-03-22 01:27:54 +00003276 opc = getUChar(eip); eip++;
3277
3278 switch (opc) {
3279
3280 /* ------------------------ Control flow --------------- */
3281
3282 case 0xC2: /* RET imm16 */
3283 d32 = getUDisp16(eip); eip += 2;
3284 goto do_Ret;
3285 case 0xC3: /* RET */
3286 d32 = 0;
3287 goto do_Ret;
3288 do_Ret:
3289 t1 = newTemp(cb); t2 = newTemp(cb);
3290 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
3291 uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t2);
3292 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1);
3293 uLiteral(cb, 4+d32);
3294 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3295 uInstr1(cb, JMP, 0, TempReg, t2);
3296 uCond(cb, CondAlways);
sewardj2e93c502002-04-12 11:12:52 +00003297 LAST_UINSTR(cb).jmpkind = JmpRet;
sewardjde4a1d02002-03-22 01:27:54 +00003298
3299 *isEnd = True;
3300 if (dis) {
3301 if (d32 == 0) VG_(printf)("ret\n");
3302 else VG_(printf)("ret %d\n", d32);
3303 }
3304 break;
3305
3306 case 0xE8: /* CALL J4 */
3307 d32 = getUDisp32(eip); eip += 4;
3308 d32 += eip; /* eip now holds return-to addr, d32 is call-to addr */
sewardjde4a1d02002-03-22 01:27:54 +00003309 if (d32 == eip && getUChar(eip) >= 0x58
3310 && getUChar(eip) <= 0x5F) {
3311 /* Specially treat the position-independent-code idiom
3312 call X
3313 X: popl %reg
3314 as
3315 movl %eip, %reg.
3316 since this generates better code, but for no other reason. */
3317 Int archReg = getUChar(eip) - 0x58;
3318 /* VG_(printf)("-- fPIC thingy\n"); */
3319 t1 = newTemp(cb);
3320 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
3321 uLiteral(cb, eip);
3322 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, archReg);
3323 eip++; /* Step over the POP */
3324 if (dis)
3325 VG_(printf)("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
3326 } else {
3327 /* The normal sequence for a call. */
3328 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3329 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
3330 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t1);
3331 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t1);
3332 uLiteral(cb, 4);
3333 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3334 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
3335 uLiteral(cb, eip);
3336 uInstr2(cb, STORE, 4, TempReg, t2, TempReg, t1);
sewardjde4a1d02002-03-22 01:27:54 +00003337 uInstr1(cb, JMP, 0, Literal, 0);
3338 uLiteral(cb, d32);
3339 uCond(cb, CondAlways);
sewardj2e93c502002-04-12 11:12:52 +00003340 LAST_UINSTR(cb).jmpkind = JmpCall;
sewardjde4a1d02002-03-22 01:27:54 +00003341 *isEnd = True;
3342 if (dis) VG_(printf)("call 0x%x\n",d32);
3343 }
3344 break;
3345
3346 case 0xC9: /* LEAVE */
3347 t1 = newTemp(cb); t2 = newTemp(cb);
3348 uInstr2(cb, GET, 4, ArchReg, R_EBP, TempReg, t1);
3349 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3350 uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t2);
3351 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
3352 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1);
3353 uLiteral(cb, 4);
njn24f35792003-02-03 11:25:34 +00003354 /* This 2nd PUT looks redundant, but Julian thinks it's not.
3355 * --njn 03-feb-2003 */
sewardjde4a1d02002-03-22 01:27:54 +00003356 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3357 if (dis) VG_(printf)("leave");
3358 break;
3359
sewardj4d0ab1f2002-03-24 10:00:09 +00003360 /* ---------------- Misc wierd-ass insns --------------- */
3361
sewardjfe8a1662002-03-24 11:54:07 +00003362 case 0x27: /* DAA */
sewardj4d0ab1f2002-03-24 10:00:09 +00003363 case 0x2F: /* DAS */
3364 t1 = newTemp(cb);
3365 uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
3366 /* Widen %AL to 32 bits, so it's all defined when we push it. */
3367 uInstr1(cb, WIDEN, 4, TempReg, t1);
3368 LAST_UINSTR(cb).extra4b = 1;
3369 LAST_UINSTR(cb).signed_widen = False;
3370 uInstr0(cb, CALLM_S, 0);
3371 uInstr1(cb, PUSH, 4, TempReg, t1);
sewardjfe8a1662002-03-24 11:54:07 +00003372 uInstr1(cb, CALLM, 0, Lit16,
3373 opc == 0x27 ? VGOFF_(helper_DAA) : VGOFF_(helper_DAS) );
sewardj4d0ab1f2002-03-24 10:00:09 +00003374 uFlagsRWU(cb, FlagsAC, FlagsOSZACP, FlagsEmpty);
3375 uInstr1(cb, POP, 4, TempReg, t1);
3376 uInstr0(cb, CALLM_E, 0);
3377 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
sewardjfe8a1662002-03-24 11:54:07 +00003378 if (dis) VG_(printf)(opc == 0x27 ? "daa\n" : "das\n");
3379 break;
sewardj4d0ab1f2002-03-24 10:00:09 +00003380
sewardjde4a1d02002-03-22 01:27:54 +00003381 /* ------------------------ CWD/CDQ -------------------- */
3382
3383 case 0x98: /* CBW */
3384 t1 = newTemp(cb);
3385 if (sz == 4) {
3386 uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
3387 uInstr1(cb, WIDEN, 4, TempReg, t1); /* 4 == dst size */
3388 LAST_UINSTR(cb).extra4b = 2; /* the source size */
3389 LAST_UINSTR(cb).signed_widen = True;
3390 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
3391 if (dis) VG_(printf)("cwd\n");
3392 } else {
3393 vg_assert(sz == 2);
3394 uInstr2(cb, GET, 1, ArchReg, R_EAX, TempReg, t1);
3395 uInstr1(cb, WIDEN, 2, TempReg, t1); /* 2 == dst size */
3396 LAST_UINSTR(cb).extra4b = 1; /* the source size */
3397 LAST_UINSTR(cb).signed_widen = True;
3398 uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
3399 if (dis) VG_(printf)("cbw\n");
3400 }
3401 break;
3402
3403 case 0x99: /* CWD/CDQ */
3404 t1 = newTemp(cb);
3405 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
3406 uInstr2(cb, SAR, sz, Literal, 0, TempReg, t1);
3407 uLiteral(cb, sz == 2 ? 15 : 31);
3408 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EDX);
3409 if (dis) VG_(printf)(sz == 2 ? "cwdq\n" : "cdqq\n");
3410 break;
3411
3412 /* ------------------------ FPU ops -------------------- */
3413
3414 case 0x9E: /* SAHF */
3415 codegen_SAHF ( cb );
3416 if (dis) VG_(printf)("sahf\n");
3417 break;
3418
3419 case 0x9B: /* FWAIT */
3420 /* ignore? */
3421 if (dis) VG_(printf)("fwait\n");
3422 break;
3423
3424 case 0xD8:
3425 case 0xD9:
3426 case 0xDA:
3427 case 0xDB:
3428 case 0xDC:
3429 case 0xDD:
3430 case 0xDE:
3431 case 0xDF:
sewardje1042472002-09-30 12:33:11 +00003432 eip = dis_fpu ( cb, sorb, opc, eip );
sewardjde4a1d02002-03-22 01:27:54 +00003433 break;
3434
3435 /* ------------------------ INC & DEC ------------------ */
3436
3437 case 0x40: /* INC eAX */
3438 case 0x41: /* INC eCX */
3439 case 0x42: /* INC eDX */
3440 case 0x43: /* INC eBX */
3441 case 0x45: /* INC eBP */
3442 case 0x46: /* INC eSI */
3443 case 0x47: /* INC eDI */
3444 t1 = newTemp(cb);
3445 uInstr2(cb, GET, sz, ArchReg, (UInt)(opc - 0x40),
3446 TempReg, t1);
3447 uInstr1(cb, INC, sz, TempReg, t1);
3448 setFlagsFromUOpcode(cb, INC);
3449 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg,
3450 (UInt)(opc - 0x40));
3451 if (dis)
3452 VG_(printf)("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
3453 break;
3454
3455 case 0x48: /* DEC eAX */
3456 case 0x49: /* DEC eCX */
3457 case 0x4A: /* DEC eDX */
3458 case 0x4B: /* DEC eBX */
3459 case 0x4D: /* DEC eBP */
3460 case 0x4E: /* DEC eSI */
3461 case 0x4F: /* DEC eDI */
3462 t1 = newTemp(cb);
3463 uInstr2(cb, GET, sz, ArchReg, (UInt)(opc - 0x48),
3464 TempReg, t1);
3465 uInstr1(cb, DEC, sz, TempReg, t1);
3466 setFlagsFromUOpcode(cb, DEC);
3467 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg,
3468 (UInt)(opc - 0x48));
3469 if (dis)
3470 VG_(printf)("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
3471 break;
3472
3473 /* ------------------------ INT ------------------------ */
3474
3475 case 0xCD: /* INT imm8 */
3476 d32 = getUChar(eip); eip++;
njne427a662002-10-02 11:08:25 +00003477 if (d32 != 0x80) VG_(core_panic)("disInstr: INT but not 0x80 !");
sewardjde4a1d02002-03-22 01:27:54 +00003478 /* It's important that all ArchRegs carry their up-to-date value
3479 at this point. So we declare an end-of-block here, which
3480 forces any TempRegs caching ArchRegs to be flushed. */
sewardjde4a1d02002-03-22 01:27:54 +00003481 uInstr1(cb, JMP, 0, Literal, 0);
3482 uLiteral(cb, eip);
3483 uCond(cb, CondAlways);
sewardj2e93c502002-04-12 11:12:52 +00003484 LAST_UINSTR(cb).jmpkind = JmpSyscall;
sewardjde4a1d02002-03-22 01:27:54 +00003485 *isEnd = True;
3486 if (dis) VG_(printf)("int $0x80\n");
3487 break;
3488
3489 /* ------------------------ Jcond, byte offset --------- */
3490
3491 case 0xEB: /* Jb (jump, byte offset) */
3492 d32 = (eip+1) + getSDisp8(eip); eip++;
3493 uInstr1(cb, JMP, 0, Literal, 0);
3494 uLiteral(cb, d32);
3495 uCond(cb, CondAlways);
3496 *isEnd = True;
3497 if (dis)
3498 VG_(printf)("jmp-8 0x%x\n", d32);
3499 break;
3500
3501 case 0xE9: /* Jv (jump, 16/32 offset) */
3502 d32 = (eip+sz) + getSDisp(sz,eip); eip += sz;
3503 uInstr1(cb, JMP, 0, Literal, 0);
3504 uLiteral(cb, d32);
3505 uCond(cb, CondAlways);
3506 *isEnd = True;
3507 if (dis)
3508 VG_(printf)("jmp 0x%x\n", d32);
3509 break;
3510
3511 case 0x70:
3512 case 0x71:
3513 case 0x72: /* JBb/JNAEb (jump below) */
3514 case 0x73: /* JNBb/JAEb (jump not below) */
3515 case 0x74: /* JZb/JEb (jump zero) */
3516 case 0x75: /* JNZb/JNEb (jump not zero) */
3517 case 0x76: /* JBEb/JNAb (jump below or equal) */
3518 case 0x77: /* JNBEb/JAb (jump not below or equal) */
3519 case 0x78: /* JSb (jump negative) */
3520 case 0x79: /* JSb (jump not negative) */
3521 case 0x7A: /* JP (jump parity even) */
3522 case 0x7B: /* JNP/JPO (jump parity odd) */
3523 case 0x7C: /* JLb/JNGEb (jump less) */
3524 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
3525 case 0x7E: /* JLEb/JNGb (jump less or equal) */
3526 case 0x7F: /* JGb/JNLEb (jump greater) */
3527 d32 = (eip+1) + getSDisp8(eip); eip++;
3528 uInstr1(cb, JMP, 0, Literal, 0);
3529 uLiteral(cb, d32);
3530 uCond(cb, (Condcode)(opc - 0x70));
3531 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
3532 /* It's actually acceptable not to end this basic block at a
3533 control transfer, reducing the number of jumps through
3534 vg_dispatch, at the expense of possibly translating the insns
3535 following this jump twice. This does give faster code, but
3536 on the whole I don't think the effort is worth it. */
3537 uInstr1(cb, JMP, 0, Literal, 0);
3538 uLiteral(cb, eip);
3539 uCond(cb, CondAlways);
3540 *isEnd = True;
3541 /* The above 3 lines would be removed if the bb was not to end
3542 here. */
3543 if (dis)
njn563f96f2003-02-03 11:17:46 +00003544 VG_(printf)("j%s-8 0x%x\n", VG_(name_UCondcode)(opc - 0x70), d32);
sewardjde4a1d02002-03-22 01:27:54 +00003545 break;
3546
3547 case 0xE3: /* JECXZ or perhaps JCXZ, depending on OSO ? Intel
3548 manual says it depends on address size override,
3549 which doesn't sound right to me. */
3550 d32 = (eip+1) + getSDisp8(eip); eip++;
3551 t1 = newTemp(cb);
3552 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
3553 uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
3554 uLiteral(cb, d32);
3555 if (dis)
3556 VG_(printf)("j%sz 0x%x\n", nameIReg(sz, R_ECX), d32);
3557 break;
3558
3559 case 0xE2: /* LOOP disp8 */
3560 /* Again, the docs say this uses ECX/CX as a count depending on
3561 the address size override, not the operand one. Since we
3562 don't handle address size overrides, I guess that means
3563 ECX. */
3564 d32 = (eip+1) + getSDisp8(eip); eip++;
3565 t1 = newTemp(cb);
3566 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
3567 uInstr1(cb, DEC, 4, TempReg, t1);
3568 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ECX);
3569 uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
3570 uLiteral(cb, eip);
3571 uInstr1(cb, JMP, 0, Literal, 0);
3572 uLiteral(cb, d32);
3573 uCond(cb, CondAlways);
3574 *isEnd = True;
3575 if (dis)
3576 VG_(printf)("loop 0x%x\n", d32);
3577 break;
3578
3579 /* ------------------------ IMUL ----------------------- */
3580
3581 case 0x69: /* IMUL Iv, Ev, Gv */
sewardje1042472002-09-30 12:33:11 +00003582 eip = dis_imul_I_E_G ( cb, sorb, sz, eip, sz );
sewardjde4a1d02002-03-22 01:27:54 +00003583 break;
3584 case 0x6B: /* IMUL Ib, Ev, Gv */
sewardje1042472002-09-30 12:33:11 +00003585 eip = dis_imul_I_E_G ( cb, sorb, sz, eip, 1 );
sewardjde4a1d02002-03-22 01:27:54 +00003586 break;
3587
3588 /* ------------------------ MOV ------------------------ */
3589
3590 case 0x88: /* MOV Gb,Eb */
sewardje1042472002-09-30 12:33:11 +00003591 eip = dis_mov_G_E(cb, sorb, 1, eip);
sewardjde4a1d02002-03-22 01:27:54 +00003592 break;
3593
3594 case 0x89: /* MOV Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00003595 eip = dis_mov_G_E(cb, sorb, sz, eip);
sewardjde4a1d02002-03-22 01:27:54 +00003596 break;
3597
3598 case 0x8A: /* MOV Eb,Gb */
sewardje1042472002-09-30 12:33:11 +00003599 eip = dis_mov_E_G(cb, sorb, 1, eip);
sewardjde4a1d02002-03-22 01:27:54 +00003600 break;
3601
3602 case 0x8B: /* MOV Ev,Gv */
sewardje1042472002-09-30 12:33:11 +00003603 eip = dis_mov_E_G(cb, sorb, sz, eip);
sewardjde4a1d02002-03-22 01:27:54 +00003604 break;
3605
3606 case 0x8D: /* LEA M,Gv */
3607 modrm = getUChar(eip);
3608 if (epartIsReg(modrm))
njne427a662002-10-02 11:08:25 +00003609 VG_(core_panic)("LEA M,Gv: modRM refers to register");
sewardje1042472002-09-30 12:33:11 +00003610 /* NOTE! this is the one place where a segment override prefix
3611 has no effect on the address calculation. Therefore we pass
3612 zero instead of sorb here. */
3613 pair = disAMode ( cb, /*sorb*/ 0, eip, dis?dis_buf:NULL );
sewardjde4a1d02002-03-22 01:27:54 +00003614 eip += HI8(pair);
3615 t1 = LOW24(pair);
3616 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, gregOfRM(modrm));
3617 if (dis)
3618 VG_(printf)("lea%c %s, %s\n", nameISize(sz), dis_buf,
3619 nameIReg(sz,gregOfRM(modrm)));
3620 break;
3621
sewardjd077f532002-09-30 21:52:50 +00003622 case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
3623 eip = dis_mov_Sw_Ew(cb, sorb, eip);
3624 break;
3625
sewardje1042472002-09-30 12:33:11 +00003626 case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
3627 eip = dis_mov_Ew_Sw(cb, sorb, eip);
3628 break;
3629
sewardjde4a1d02002-03-22 01:27:54 +00003630 case 0xA0: /* MOV Ob,AL */
3631 sz = 1;
3632 /* Fall through ... */
3633 case 0xA1: /* MOV Ov,eAX */
3634 d32 = getUDisp32(eip); eip += 4;
3635 t1 = newTemp(cb); t2 = newTemp(cb);
3636 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
3637 uLiteral(cb, d32);
sewardjbe4015a2002-10-03 16:14:57 +00003638 handleSegOverride(cb, sorb, t2);
sewardjde4a1d02002-03-22 01:27:54 +00003639 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3640 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EAX);
sewardjbe4015a2002-10-03 16:14:57 +00003641 if (dis) VG_(printf)("mov%c %s0x%x,%s\n", nameISize(sz),
3642 sorbTxt(sorb),
sewardjde4a1d02002-03-22 01:27:54 +00003643 d32, nameIReg(sz,R_EAX));
3644 break;
3645
3646 case 0xA2: /* MOV AL,Ob */
3647 sz = 1;
3648 /* Fall through ... */
3649 case 0xA3: /* MOV eAX,Ov */
3650 d32 = getUDisp32(eip); eip += 4;
3651 t1 = newTemp(cb); t2 = newTemp(cb);
3652 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
3653 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
3654 uLiteral(cb, d32);
sewardjbe4015a2002-10-03 16:14:57 +00003655 handleSegOverride(cb, sorb, t2);
sewardjde4a1d02002-03-22 01:27:54 +00003656 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
sewardjbe4015a2002-10-03 16:14:57 +00003657 if (dis) VG_(printf)("mov%c %s,%s0x%x\n", nameISize(sz),
3658 sorbTxt(sorb),
sewardjde4a1d02002-03-22 01:27:54 +00003659 nameIReg(sz,R_EAX), d32);
3660 break;
3661
3662 case 0xB0: /* MOV imm,AL */
3663 case 0xB1: /* MOV imm,CL */
3664 case 0xB2: /* MOV imm,DL */
3665 case 0xB3: /* MOV imm,BL */
3666 case 0xB4: /* MOV imm,AH */
3667 case 0xB5: /* MOV imm,CH */
3668 case 0xB6: /* MOV imm,DH */
3669 case 0xB7: /* MOV imm,BH */
3670 d32 = getUChar(eip); eip += 1;
3671 t1 = newTemp(cb);
3672 uInstr2(cb, MOV, 1, Literal, 0, TempReg, t1);
3673 uLiteral(cb, d32);
3674 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, opc-0xB0);
3675 if (dis) VG_(printf)("movb $0x%x,%s\n", d32,
3676 nameIReg(1,opc-0xB0));
3677 break;
3678
3679 case 0xB8: /* MOV imm,eAX */
3680 case 0xB9: /* MOV imm,eCX */
3681 case 0xBA: /* MOV imm,eDX */
3682 case 0xBB: /* MOV imm,eBX */
3683 case 0xBD: /* MOV imm,eBP */
3684 case 0xBE: /* MOV imm,eSI */
3685 case 0xBF: /* MOV imm,eDI */
3686 d32 = getUDisp(sz,eip); eip += sz;
3687 t1 = newTemp(cb);
3688 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t1);
3689 uLiteral(cb, d32);
3690 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, opc-0xB8);
3691 if (dis) VG_(printf)("mov%c $0x%x,%s\n", nameISize(sz), d32,
3692 nameIReg(sz,opc-0xB8));
3693 break;
3694
3695 case 0xC6: /* MOV Ib,Eb */
3696 sz = 1;
3697 goto do_Mov_I_E;
3698 case 0xC7: /* MOV Iv,Ev */
3699 goto do_Mov_I_E;
3700
3701 do_Mov_I_E:
3702 modrm = getUChar(eip);
3703 if (epartIsReg(modrm)) {
sewardj48987df2002-12-16 00:10:30 +00003704 eip++; /* mod/rm byte */
sewardjde4a1d02002-03-22 01:27:54 +00003705 d32 = getUDisp(sz,eip); eip += sz;
3706 t1 = newTemp(cb);
3707 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t1);
3708 uLiteral(cb, d32);
3709 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
3710 if (dis) VG_(printf)("mov%c $0x%x, %s\n", nameISize(sz), d32,
3711 nameIReg(sz,eregOfRM(modrm)));
3712 } else {
sewardje1042472002-09-30 12:33:11 +00003713 pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL );
sewardjde4a1d02002-03-22 01:27:54 +00003714 eip += HI8(pair);
3715 d32 = getUDisp(sz,eip); eip += sz;
3716 t1 = newTemp(cb);
3717 t2 = LOW24(pair);
3718 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t1);
3719 uLiteral(cb, d32);
3720 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00003721 if (dis) VG_(printf)("mov%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
3722 }
3723 break;
3724
3725 /* ------------------------ opl imm, A ----------------- */
3726
3727 case 0x04: /* ADD Ib, AL */
3728 eip = dis_op_imm_A(cb, 1, ADD, True, eip, "add" );
3729 break;
3730 case 0x05: /* ADD Iv, eAX */
3731 eip = dis_op_imm_A(cb, sz, ADD, True, eip, "add" );
3732 break;
3733
3734 case 0x0C: /* OR Ib, AL */
3735 eip = dis_op_imm_A(cb, 1, OR, True, eip, "or" );
3736 break;
3737 case 0x0D: /* OR Iv, eAX */
3738 eip = dis_op_imm_A(cb, sz, OR, True, eip, "or" );
3739 break;
3740
sewardj279236e2002-12-16 00:14:02 +00003741 case 0x14: /* ADC Ib, AL */
3742 eip = dis_op_imm_A(cb, 1, ADC, True, eip, "adc" );
3743 break;
njn25e49d8e72002-09-23 09:36:25 +00003744 case 0x15: /* ADC Iv, eAX */
3745 eip = dis_op_imm_A(cb, sz, ADC, True, eip, "adc" );
3746 break;
3747
sewardje9c06f12002-05-08 01:44:03 +00003748 case 0x1C: /* SBB Ib, AL */
3749 eip = dis_op_imm_A(cb, 1, SBB, True, eip, "sbb" );
3750 break;
3751
sewardjde4a1d02002-03-22 01:27:54 +00003752 case 0x24: /* AND Ib, AL */
3753 eip = dis_op_imm_A(cb, 1, AND, True, eip, "and" );
3754 break;
3755 case 0x25: /* AND Iv, eAX */
3756 eip = dis_op_imm_A(cb, sz, AND, True, eip, "and" );
3757 break;
3758
3759 case 0x2C: /* SUB Ib, AL */
3760 eip = dis_op_imm_A(cb, 1, SUB, True, eip, "sub" );
3761 break;
3762 case 0x2D: /* SUB Iv, eAX */
3763 eip = dis_op_imm_A(cb, sz, SUB, True, eip, "sub" );
3764 break;
3765
3766 case 0x34: /* XOR Ib, AL */
3767 eip = dis_op_imm_A(cb, 1, XOR, True, eip, "xor" );
3768 break;
3769 case 0x35: /* XOR Iv, eAX */
3770 eip = dis_op_imm_A(cb, sz, XOR, True, eip, "xor" );
3771 break;
3772
3773 case 0x3C: /* CMP Ib, AL */
3774 eip = dis_op_imm_A(cb, 1, SUB, False, eip, "cmp" );
3775 break;
3776 case 0x3D: /* CMP Iv, eAX */
3777 eip = dis_op_imm_A(cb, sz, SUB, False, eip, "cmp" );
3778 break;
3779
3780 case 0xA8: /* TEST Ib, AL */
3781 eip = dis_op_imm_A(cb, 1, AND, False, eip, "test" );
3782 break;
3783 case 0xA9: /* TEST Iv, eAX */
3784 eip = dis_op_imm_A(cb, sz, AND, False, eip, "test" );
3785 break;
3786
3787 /* ------------------------ opl Ev, Gv ----------------- */
3788
3789 case 0x02: /* ADD Eb,Gb */
sewardje1042472002-09-30 12:33:11 +00003790 eip = dis_op2_E_G ( cb, sorb, ADD, True, 1, eip, "add" );
sewardjde4a1d02002-03-22 01:27:54 +00003791 break;
3792 case 0x03: /* ADD Ev,Gv */
sewardje1042472002-09-30 12:33:11 +00003793 eip = dis_op2_E_G ( cb, sorb, ADD, True, sz, eip, "add" );
sewardjde4a1d02002-03-22 01:27:54 +00003794 break;
3795
3796 case 0x0A: /* OR Eb,Gb */
sewardje1042472002-09-30 12:33:11 +00003797 eip = dis_op2_E_G ( cb, sorb, OR, True, 1, eip, "or" );
sewardjde4a1d02002-03-22 01:27:54 +00003798 break;
3799 case 0x0B: /* OR Ev,Gv */
sewardje1042472002-09-30 12:33:11 +00003800 eip = dis_op2_E_G ( cb, sorb, OR, True, sz, eip, "or" );
sewardjde4a1d02002-03-22 01:27:54 +00003801 break;
3802
sewardja4b87f62002-05-29 23:38:23 +00003803 case 0x12: /* ADC Eb,Gb */
sewardje1042472002-09-30 12:33:11 +00003804 eip = dis_op2_E_G ( cb, sorb, ADC, True, 1, eip, "adc" );
sewardja4b87f62002-05-29 23:38:23 +00003805 break;
sewardjde4a1d02002-03-22 01:27:54 +00003806 case 0x13: /* ADC Ev,Gv */
sewardje1042472002-09-30 12:33:11 +00003807 eip = dis_op2_E_G ( cb, sorb, ADC, True, sz, eip, "adc" );
sewardjde4a1d02002-03-22 01:27:54 +00003808 break;
3809
sewardj6d12f912002-10-16 19:40:04 +00003810 case 0x1A: /* SBB Eb,Gb */
3811 eip = dis_op2_E_G ( cb, sorb, SBB, True, 1, eip, "sbb" );
3812 break;
sewardjde4a1d02002-03-22 01:27:54 +00003813 case 0x1B: /* SBB Ev,Gv */
sewardje1042472002-09-30 12:33:11 +00003814 eip = dis_op2_E_G ( cb, sorb, SBB, True, sz, eip, "sbb" );
sewardjde4a1d02002-03-22 01:27:54 +00003815 break;
3816
3817 case 0x22: /* AND Eb,Gb */
sewardje1042472002-09-30 12:33:11 +00003818 eip = dis_op2_E_G ( cb, sorb, AND, True, 1, eip, "and" );
sewardjde4a1d02002-03-22 01:27:54 +00003819 break;
3820 case 0x23: /* AND Ev,Gv */
sewardje1042472002-09-30 12:33:11 +00003821 eip = dis_op2_E_G ( cb, sorb, AND, True, sz, eip, "and" );
sewardjde4a1d02002-03-22 01:27:54 +00003822 break;
3823
3824 case 0x2A: /* SUB Eb,Gb */
sewardje1042472002-09-30 12:33:11 +00003825 eip = dis_op2_E_G ( cb, sorb, SUB, True, 1, eip, "sub" );
sewardjde4a1d02002-03-22 01:27:54 +00003826 break;
3827 case 0x2B: /* SUB Ev,Gv */
sewardje1042472002-09-30 12:33:11 +00003828 eip = dis_op2_E_G ( cb, sorb, SUB, True, sz, eip, "sub" );
sewardjde4a1d02002-03-22 01:27:54 +00003829 break;
3830
3831 case 0x32: /* XOR Eb,Gb */
sewardje1042472002-09-30 12:33:11 +00003832 eip = dis_op2_E_G ( cb, sorb, XOR, True, 1, eip, "xor" );
sewardjde4a1d02002-03-22 01:27:54 +00003833 break;
3834 case 0x33: /* XOR Ev,Gv */
sewardje1042472002-09-30 12:33:11 +00003835 eip = dis_op2_E_G ( cb, sorb, XOR, True, sz, eip, "xor" );
sewardjde4a1d02002-03-22 01:27:54 +00003836 break;
3837
3838 case 0x3A: /* CMP Eb,Gb */
sewardje1042472002-09-30 12:33:11 +00003839 eip = dis_op2_E_G ( cb, sorb, SUB, False, 1, eip, "cmp" );
sewardjde4a1d02002-03-22 01:27:54 +00003840 break;
3841 case 0x3B: /* CMP Ev,Gv */
sewardje1042472002-09-30 12:33:11 +00003842 eip = dis_op2_E_G ( cb, sorb, SUB, False, sz, eip, "cmp" );
sewardjde4a1d02002-03-22 01:27:54 +00003843 break;
3844
3845 case 0x84: /* TEST Eb,Gb */
sewardje1042472002-09-30 12:33:11 +00003846 eip = dis_op2_E_G ( cb, sorb, AND, False, 1, eip, "test" );
sewardjde4a1d02002-03-22 01:27:54 +00003847 break;
3848 case 0x85: /* TEST Ev,Gv */
sewardje1042472002-09-30 12:33:11 +00003849 eip = dis_op2_E_G ( cb, sorb, AND, False, sz, eip, "test" );
sewardjde4a1d02002-03-22 01:27:54 +00003850 break;
3851
3852 /* ------------------------ opl Gv, Ev ----------------- */
3853
3854 case 0x00: /* ADD Gb,Eb */
sewardje1042472002-09-30 12:33:11 +00003855 eip = dis_op2_G_E ( cb, sorb, ADD, True, 1, eip, "add" );
sewardjde4a1d02002-03-22 01:27:54 +00003856 break;
3857 case 0x01: /* ADD Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00003858 eip = dis_op2_G_E ( cb, sorb, ADD, True, sz, eip, "add" );
sewardjde4a1d02002-03-22 01:27:54 +00003859 break;
3860
3861 case 0x08: /* OR Gb,Eb */
sewardje1042472002-09-30 12:33:11 +00003862 eip = dis_op2_G_E ( cb, sorb, OR, True, 1, eip, "or" );
sewardjde4a1d02002-03-22 01:27:54 +00003863 break;
3864 case 0x09: /* OR Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00003865 eip = dis_op2_G_E ( cb, sorb, OR, True, sz, eip, "or" );
sewardjde4a1d02002-03-22 01:27:54 +00003866 break;
3867
sewardj72bbd222002-09-27 01:29:26 +00003868 case 0x10: /* ADC Gb,Eb */
sewardje1042472002-09-30 12:33:11 +00003869 eip = dis_op2_G_E ( cb, sorb, ADC, True, 1, eip, "adc" );
sewardj72bbd222002-09-27 01:29:26 +00003870 break;
sewardjde4a1d02002-03-22 01:27:54 +00003871 case 0x11: /* ADC Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00003872 eip = dis_op2_G_E ( cb, sorb, ADC, True, sz, eip, "adc" );
sewardjde4a1d02002-03-22 01:27:54 +00003873 break;
3874
3875 case 0x19: /* SBB Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00003876 eip = dis_op2_G_E ( cb, sorb, SBB, True, sz, eip, "sbb" );
sewardjde4a1d02002-03-22 01:27:54 +00003877 break;
3878
3879 case 0x20: /* AND Gb,Eb */
sewardje1042472002-09-30 12:33:11 +00003880 eip = dis_op2_G_E ( cb, sorb, AND, True, 1, eip, "and" );
sewardjde4a1d02002-03-22 01:27:54 +00003881 break;
3882 case 0x21: /* AND Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00003883 eip = dis_op2_G_E ( cb, sorb, AND, True, sz, eip, "and" );
sewardjde4a1d02002-03-22 01:27:54 +00003884 break;
3885
3886 case 0x28: /* SUB Gb,Eb */
sewardje1042472002-09-30 12:33:11 +00003887 eip = dis_op2_G_E ( cb, sorb, SUB, True, 1, eip, "sub" );
sewardjde4a1d02002-03-22 01:27:54 +00003888 break;
3889 case 0x29: /* SUB Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00003890 eip = dis_op2_G_E ( cb, sorb, SUB, True, sz, eip, "sub" );
sewardjde4a1d02002-03-22 01:27:54 +00003891 break;
3892
3893 case 0x30: /* XOR Gb,Eb */
sewardje1042472002-09-30 12:33:11 +00003894 eip = dis_op2_G_E ( cb, sorb, XOR, True, 1, eip, "xor" );
sewardjde4a1d02002-03-22 01:27:54 +00003895 break;
3896 case 0x31: /* XOR Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00003897 eip = dis_op2_G_E ( cb, sorb, XOR, True, sz, eip, "xor" );
sewardjde4a1d02002-03-22 01:27:54 +00003898 break;
3899
3900 case 0x38: /* CMP Gb,Eb */
sewardje1042472002-09-30 12:33:11 +00003901 eip = dis_op2_G_E ( cb, sorb, SUB, False, 1, eip, "cmp" );
sewardjde4a1d02002-03-22 01:27:54 +00003902 break;
3903 case 0x39: /* CMP Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00003904 eip = dis_op2_G_E ( cb, sorb, SUB, False, sz, eip, "cmp" );
sewardjde4a1d02002-03-22 01:27:54 +00003905 break;
3906
3907 /* ------------------------ POP ------------------------ */
3908
3909 case 0x58: /* POP eAX */
3910 case 0x59: /* POP eCX */
3911 case 0x5A: /* POP eDX */
3912 case 0x5B: /* POP eBX */
sewardjde4a1d02002-03-22 01:27:54 +00003913 case 0x5D: /* POP eBP */
3914 case 0x5E: /* POP eSI */
3915 case 0x5F: /* POP eDI */
sewardj4f51f9a2002-05-07 23:38:30 +00003916 case 0x5C: /* POP eSP */
sewardjde4a1d02002-03-22 01:27:54 +00003917 t1 = newTemp(cb); t2 = newTemp(cb);
3918 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
3919 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3920 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3921 uLiteral(cb, sz);
3922 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
3923 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, opc-0x58);
3924 if (dis)
3925 VG_(printf)("pop%c %s\n", nameISize(sz), nameIReg(sz,opc-0x58));
3926 break;
3927
3928 case 0x9D: /* POPF */
3929 vg_assert(sz == 2 || sz == 4);
3930 t1 = newTemp(cb); t2 = newTemp(cb);
3931 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
3932 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3933 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3934 uLiteral(cb, sz);
3935 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
3936 uInstr1(cb, PUTF, sz, TempReg, t1);
3937 /* PUTF writes all the flags we are interested in */
3938 uFlagsRWU(cb, FlagsEmpty, FlagsALL, FlagsEmpty);
3939 if (dis)
3940 VG_(printf)("popf%c\n", nameISize(sz));
3941 break;
3942
3943 case 0x61: /* POPA */
3944 { Int reg;
3945 /* Just to keep things sane, we assert for a size 4. It's
3946 probably OK for size 2 as well, but I'd like to find a test
3947 case; ie, have the assertion fail, before committing to it.
3948 If it fails for you, uncomment the sz == 2 bit, try again,
3949 and let me know whether or not it works. (jseward@acm.org). */
3950 vg_assert(sz == 4 /* || sz == 2 */);
3951
3952 /* Eight values are popped, one per register, but the value of
3953 %esp on the stack is ignored and instead incremented (in one
3954 hit at the end) for each of the values. */
3955 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3956 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
3957 uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t3);
3958
3959 /* Do %edi, %esi, %ebp */
3960 for (reg = 7; reg >= 5; reg--) {
3961 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3962 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3963 uLiteral(cb, sz);
3964 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
3965 }
3966 /* Ignore (skip) value of %esp on stack. */
3967 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3968 uLiteral(cb, sz);
3969 /* Do %ebx, %edx, %ecx, %eax */
3970 for (reg = 3; reg >= 0; reg--) {
3971 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3972 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3973 uLiteral(cb, sz);
3974 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
3975 }
3976 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t3);
3977 uLiteral(cb, sz * 8); /* One 'sz' per register */
3978 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
3979 if (dis)
3980 VG_(printf)("popa%c\n", nameISize(sz));
3981 break;
3982 }
3983
sewardj363e6062002-05-22 11:55:35 +00003984 case 0x8F: /* POPL/POPW m32 */
3985 { UInt pair1;
3986 Int tmpa;
3987 UChar rm = getUChar(eip);
3988
3989 /* make sure this instruction is correct POP */
3990 vg_assert(!epartIsReg(rm) && (gregOfRM(rm) == 0));
3991 /* and has correct size */
3992 vg_assert(sz == 4);
3993
3994 t1 = newTemp(cb); t3 = newTemp(cb);
3995 /* set t1 to ESP: t1 = ESP */
3996 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
3997 /* load M[ESP] to virtual register t3: t3 = M[t1] */
3998 uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t3);
3999 /* resolve MODR/M */
sewardje1042472002-09-30 12:33:11 +00004000 pair1 = disAMode ( cb, sorb, eip, dis?dis_buf:NULL);
sewardj363e6062002-05-22 11:55:35 +00004001
4002 tmpa = LOW24(pair1);
4003 /* uInstr2(cb, LOAD, sz, TempReg, tmpa, TempReg, tmpa); */
4004 /* store value from stack in memory, M[m32] = t3 */
4005 uInstr2(cb, STORE, 4, TempReg, t3, TempReg, tmpa);
4006
4007 /* increase ESP */
4008 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1);
4009 uLiteral(cb, sz);
4010 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
4011
4012 if (dis)
4013 VG_(printf)("popl %s\n", dis_buf);
4014
4015 eip += HI8(pair1);
4016 break;
4017 }
4018
sewardjde4a1d02002-03-22 01:27:54 +00004019 /* ------------------------ PUSH ----------------------- */
4020
4021 case 0x50: /* PUSH eAX */
4022 case 0x51: /* PUSH eCX */
4023 case 0x52: /* PUSH eDX */
sewardjde4a1d02002-03-22 01:27:54 +00004024 case 0x53: /* PUSH eBX */
4025 case 0x55: /* PUSH eBP */
4026 case 0x56: /* PUSH eSI */
4027 case 0x57: /* PUSH eDI */
sewardj4f51f9a2002-05-07 23:38:30 +00004028 case 0x54: /* PUSH eSP */
sewardjde4a1d02002-03-22 01:27:54 +00004029 /* This is the Right Way, in that the value to be pushed is
4030 established before %esp is changed, so that pushl %esp
4031 correctly pushes the old value. */
4032 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
4033 uInstr2(cb, GET, sz, ArchReg, opc-0x50, TempReg, t1);
4034 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
4035 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
4036 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
4037 uLiteral(cb, sz);
4038 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
4039 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00004040 if (dis)
4041 VG_(printf)("push%c %s\n", nameISize(sz), nameIReg(sz,opc-0x50));
4042 break;
4043
4044 case 0x68: /* PUSH Iv */
4045 d32 = getUDisp(sz,eip); eip += sz;
4046 goto do_push_I;
4047 case 0x6A: /* PUSH Ib, sign-extended to sz */
4048 d32 = getSDisp8(eip); eip += 1;
4049 goto do_push_I;
4050 do_push_I:
4051 t1 = newTemp(cb); t2 = newTemp(cb);
4052 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
4053 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t1);
4054 uLiteral(cb, sz);
4055 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
4056 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t2);
4057 uLiteral(cb, d32);
4058 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
sewardjde4a1d02002-03-22 01:27:54 +00004059 if (dis)
4060 VG_(printf)("push%c $0x%x\n", nameISize(sz), d32);
4061 break;
4062
4063 case 0x9C: /* PUSHF */
4064 vg_assert(sz == 2 || sz == 4);
4065 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
4066 uInstr1(cb, GETF, sz, TempReg, t1);
4067 /* GETF reads all the flags we are interested in */
4068 uFlagsRWU(cb, FlagsALL, FlagsEmpty, FlagsEmpty);
4069 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
4070 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
4071 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
4072 uLiteral(cb, sz);
4073 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
4074 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00004075 if (dis)
4076 VG_(printf)("pushf%c\n", nameISize(sz));
4077 break;
4078
4079 case 0x60: /* PUSHA */
4080 { Int reg;
4081 /* Just to keep things sane, we assert for a size 4. It's
4082 probably OK for size 2 as well, but I'd like to find a test
4083 case; ie, have the assertion fail, before committing to it.
4084 If it fails for you, uncomment the sz == 2 bit, try again,
4085 and let me know whether or not it works. (jseward@acm.org). */
4086 vg_assert(sz == 4 /* || sz == 2 */);
4087
4088 /* This is the Right Way, in that the value to be pushed is
4089 established before %esp is changed, so that pusha
4090 correctly pushes the old %esp value. New value of %esp is
4091 pushed at start. */
4092 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
4093 t4 = newTemp(cb);
4094 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
4095 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
4096 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t4);
4097 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t4);
4098 uLiteral(cb, sz * 8); /* One 'sz' per register. */
4099 uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_ESP);
4100 /* Do %eax, %ecx, %edx, %ebx */
4101 for (reg = 0; reg <= 3; reg++) {
4102 uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
4103 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
4104 uLiteral(cb, sz);
4105 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00004106 }
4107 /* Push old value of %esp */
4108 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
4109 uLiteral(cb, sz);
4110 uInstr2(cb, STORE, sz, TempReg, t3, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00004111 /* Do %ebp, %esi, %edi */
4112 for (reg = 5; reg <= 7; reg++) {
4113 uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
4114 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
4115 uLiteral(cb, sz);
4116 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00004117 }
4118 if (dis)
4119 VG_(printf)("pusha%c\n", nameISize(sz));
4120 break;
4121 }
4122
4123 /* ------------------------ SCAS et al ----------------- */
4124
4125 case 0xA4: /* MOVSb, no REP prefix */
sewardj1cff0e02002-10-05 14:42:39 +00004126 vg_assert(sorb == 0);
sewardjde4a1d02002-03-22 01:27:54 +00004127 codegen_MOVS ( cb, 1 );
4128 if (dis) VG_(printf)("movsb\n");
4129 break;
4130 case 0xA5: /* MOVSv, no REP prefix */
sewardj1cff0e02002-10-05 14:42:39 +00004131 vg_assert(sorb == 0);
sewardjde4a1d02002-03-22 01:27:54 +00004132 codegen_MOVS ( cb, sz );
4133 if (dis) VG_(printf)("movs%c\n", nameISize(sz));
4134 break;
4135
4136 case 0xA6: /* CMPSb, no REP prefix */
sewardj1cff0e02002-10-05 14:42:39 +00004137 vg_assert(sorb == 0);
sewardjde4a1d02002-03-22 01:27:54 +00004138 codegen_CMPS ( cb, 1 );
4139 if (dis) VG_(printf)("cmpsb\n");
4140 break;
4141
4142 case 0xAA: /* STOSb, no REP prefix */
sewardj1cff0e02002-10-05 14:42:39 +00004143 vg_assert(sorb == 0);
sewardjde4a1d02002-03-22 01:27:54 +00004144 codegen_STOS ( cb, 1 );
4145 if (dis) VG_(printf)("stosb\n");
4146 break;
4147 case 0xAB: /* STOSv, no REP prefix */
sewardj1cff0e02002-10-05 14:42:39 +00004148 vg_assert(sorb == 0);
sewardjde4a1d02002-03-22 01:27:54 +00004149 codegen_STOS ( cb, sz );
4150 if (dis) VG_(printf)("stos%c\n", nameISize(sz));
4151 break;
4152
4153 case 0xAC: /* LODSb, no REP prefix */
sewardj1cff0e02002-10-05 14:42:39 +00004154 vg_assert(sorb == 0);
sewardjde4a1d02002-03-22 01:27:54 +00004155 codegen_LODS ( cb, 1 );
4156 if (dis) VG_(printf)("lodsb\n");
4157 break;
sewardj64a8cc42002-05-08 01:38:43 +00004158 case 0xAD: /* LODSv, no REP prefix */
sewardj1cff0e02002-10-05 14:42:39 +00004159 vg_assert(sorb == 0);
sewardj64a8cc42002-05-08 01:38:43 +00004160 codegen_LODS ( cb, sz );
4161 if (dis) VG_(printf)("lods%c\n", nameISize(sz));
4162 break;
sewardjde4a1d02002-03-22 01:27:54 +00004163
4164 case 0xAE: /* SCASb, no REP prefix */
sewardj1cff0e02002-10-05 14:42:39 +00004165 vg_assert(sorb == 0);
sewardjde4a1d02002-03-22 01:27:54 +00004166 codegen_SCAS ( cb, 1 );
4167 if (dis) VG_(printf)("scasb\n");
4168 break;
4169
4170 case 0xFC: /* CLD */
4171 uInstr0(cb, CALLM_S, 0);
4172 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CLD));
4173 uFlagsRWU(cb, FlagsEmpty, FlagD, FlagsEmpty);
4174 uInstr0(cb, CALLM_E, 0);
4175 if (dis) VG_(printf)("cld\n");
4176 break;
4177
4178 case 0xFD: /* STD */
4179 uInstr0(cb, CALLM_S, 0);
4180 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_STD));
4181 uFlagsRWU(cb, FlagsEmpty, FlagD, FlagsEmpty);
4182 uInstr0(cb, CALLM_E, 0);
4183 if (dis) VG_(printf)("std\n");
4184 break;
4185
sewardj7d78e782002-06-02 00:04:00 +00004186 case 0xF8: /* CLC */
4187 uInstr0(cb, CALLM_S, 0);
4188 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CLC));
4189 uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
4190 uInstr0(cb, CALLM_E, 0);
4191 if (dis) VG_(printf)("clc\n");
4192 break;
4193
4194 case 0xF9: /* STC */
4195 uInstr0(cb, CALLM_S, 0);
4196 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_STC));
4197 uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZCP);
4198 uInstr0(cb, CALLM_E, 0);
4199 if (dis) VG_(printf)("stc\n");
4200 break;
4201
sewardjde4a1d02002-03-22 01:27:54 +00004202 case 0xF2: { /* REPNE prefix insn */
4203 Addr eip_orig = eip - 1;
sewardj1cff0e02002-10-05 14:42:39 +00004204 vg_assert(sorb == 0);
sewardjde4a1d02002-03-22 01:27:54 +00004205 abyte = getUChar(eip); eip++;
4206 if (abyte == 0x66) { sz = 2; abyte = getUChar(eip); eip++; }
4207
sewardj1cff0e02002-10-05 14:42:39 +00004208 if (abyte == 0xAE || abyte == 0xAF) { /* REPNE SCAS<sz> */
sewardjde4a1d02002-03-22 01:27:54 +00004209 if (abyte == 0xAE) sz = 1;
4210 codegen_REPNE_SCAS ( cb, sz, eip_orig, eip );
4211 *isEnd = True;
4212 if (dis) VG_(printf)("repne scas%c\n", nameISize(sz));
4213 }
4214 else {
4215 VG_(printf)("REPNE then 0x%x\n", (UInt)abyte);
njne427a662002-10-02 11:08:25 +00004216 VG_(core_panic)("Unhandled REPNE case");
sewardjde4a1d02002-03-22 01:27:54 +00004217 }
4218 break;
4219 }
4220
4221 case 0xF3: { /* REPE prefix insn */
4222 Addr eip_orig = eip - 1;
sewardj1cff0e02002-10-05 14:42:39 +00004223 vg_assert(sorb == 0);
sewardjde4a1d02002-03-22 01:27:54 +00004224 abyte = getUChar(eip); eip++;
4225 if (abyte == 0x66) { sz = 2; abyte = getUChar(eip); eip++; }
4226
4227 if (abyte == 0xA4 || abyte == 0xA5) { /* REPE MOV<sz> */
4228 if (abyte == 0xA4) sz = 1;
4229 codegen_REPE_MOVS ( cb, sz, eip_orig, eip );
4230 *isEnd = True;
4231 if (dis) VG_(printf)("repe mov%c\n", nameISize(sz));
4232 }
4233 else
4234 if (abyte == 0xA6 || abyte == 0xA7) { /* REPE CMP<sz> */
4235 if (abyte == 0xA6) sz = 1;
4236 codegen_REPE_CMPS ( cb, sz, eip_orig, eip );
4237 *isEnd = True;
4238 if (dis) VG_(printf)("repe cmps%c\n", nameISize(sz));
4239 }
4240 else
4241 if (abyte == 0xAA || abyte == 0xAB) { /* REPE STOS<sz> */
4242 if (abyte == 0xAA) sz = 1;
4243 codegen_REPE_STOS ( cb, sz, eip_orig, eip );
4244 *isEnd = True;
4245 if (dis) VG_(printf)("repe stos%c\n", nameISize(sz));
sewardj7cba7152002-07-13 12:32:16 +00004246 }
4247 else
4248 if (abyte == 0x90) { /* REPE NOP (PAUSE) */
4249 if (dis) VG_(printf)("repe nop (P4 pause)\n");
4250 /* do nothing; apparently a hint to the P4 re spin-wait loop */
sewardjde4a1d02002-03-22 01:27:54 +00004251 } else {
4252 VG_(printf)("REPE then 0x%x\n", (UInt)abyte);
njne427a662002-10-02 11:08:25 +00004253 VG_(core_panic)("Unhandled REPE case");
sewardjde4a1d02002-03-22 01:27:54 +00004254 }
4255 break;
4256 }
4257
4258 /* ------------------------ XCHG ----------------------- */
4259
4260 case 0x86: /* XCHG Gb,Eb */
4261 sz = 1;
4262 /* Fall through ... */
4263 case 0x87: /* XCHG Gv,Ev */
4264 modrm = getUChar(eip);
4265 t1 = newTemp(cb); t2 = newTemp(cb);
4266 if (epartIsReg(modrm)) {
4267 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
4268 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t2);
4269 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, gregOfRM(modrm));
4270 uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, eregOfRM(modrm));
4271 eip++;
4272 if (dis)
4273 VG_(printf)("xchg%c %s, %s\n", nameISize(sz),
4274 nameIReg(sz,gregOfRM(modrm)),
4275 nameIReg(sz,eregOfRM(modrm)));
4276 } else {
sewardje1042472002-09-30 12:33:11 +00004277 pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +00004278 t3 = LOW24(pair);
4279 uInstr2(cb, LOAD, sz, TempReg, t3, TempReg, t1);
4280 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t2);
4281 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t3);
sewardjde4a1d02002-03-22 01:27:54 +00004282 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, gregOfRM(modrm));
4283 eip += HI8(pair);
4284 if (dis)
4285 VG_(printf)("xchg%c %s, %s\n", nameISize(sz),
4286 nameIReg(sz,gregOfRM(modrm)),
4287 dis_buf);
4288 }
4289 break;
4290
4291 case 0x90: /* XCHG eAX,eAX */
4292 if (dis) VG_(printf)("nop\n");
4293 break;
sewardj6ca4c022002-10-05 14:36:26 +00004294 case 0x91: /* XCHG eAX,eCX */
4295 case 0x92: /* XCHG eAX,eDX */
4296 case 0x93: /* XCHG eAX,eBX */
sewardjde4a1d02002-03-22 01:27:54 +00004297 case 0x96: /* XCHG eAX,eSI */
4298 case 0x97: /* XCHG eAX,eDI */
4299 codegen_xchg_eAX_Reg ( cb, sz, opc - 0x90 );
4300 break;
4301
4302 /* ------------------------ (Grp1 extensions) ---------- */
4303
4304 case 0x80: /* Grp1 Ib,Eb */
4305 modrm = getUChar(eip);
4306 am_sz = lengthAMode(eip);
4307 sz = 1;
4308 d_sz = 1;
4309 d32 = getSDisp8(eip + am_sz);
sewardje1042472002-09-30 12:33:11 +00004310 eip = dis_Grp1 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00004311 break;
4312
4313 case 0x81: /* Grp1 Iv,Ev */
4314 modrm = getUChar(eip);
4315 am_sz = lengthAMode(eip);
4316 d_sz = sz;
4317 d32 = getUDisp(d_sz, eip + am_sz);
sewardje1042472002-09-30 12:33:11 +00004318 eip = dis_Grp1 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00004319 break;
4320
4321 case 0x83: /* Grp1 Ib,Ev */
4322 modrm = getUChar(eip);
4323 am_sz = lengthAMode(eip);
4324 d_sz = 1;
4325 d32 = getSDisp8(eip + am_sz);
sewardje1042472002-09-30 12:33:11 +00004326 eip = dis_Grp1 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00004327 break;
4328
4329 /* ------------------------ (Grp2 extensions) ---------- */
4330
4331 case 0xC0: /* Grp2 Ib,Eb */
4332 modrm = getUChar(eip);
4333 am_sz = lengthAMode(eip);
4334 d_sz = 1;
4335 d32 = getSDisp8(eip + am_sz);
4336 sz = 1;
sewardje1042472002-09-30 12:33:11 +00004337 eip = dis_Grp2 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00004338 break;
4339
4340 case 0xC1: /* Grp2 Ib,Ev */
4341 modrm = getUChar(eip);
4342 am_sz = lengthAMode(eip);
4343 d_sz = 1;
4344 d32 = getSDisp8(eip + am_sz);
sewardje1042472002-09-30 12:33:11 +00004345 eip = dis_Grp2 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00004346 break;
4347
4348 case 0xD0: /* Grp2 1,Eb */
4349 modrm = getUChar(eip);
4350 am_sz = lengthAMode(eip);
4351 d_sz = 0;
4352 d32 = 1;
4353 sz = 1;
sewardje1042472002-09-30 12:33:11 +00004354 eip = dis_Grp2 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00004355 break;
4356
4357 case 0xD1: /* Grp2 1,Ev */
4358 modrm = getUChar(eip);
4359 am_sz = lengthAMode(eip);
4360 d_sz = 0;
4361 d32 = 1;
sewardje1042472002-09-30 12:33:11 +00004362 eip = dis_Grp2 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00004363 break;
4364
njn25e49d8e72002-09-23 09:36:25 +00004365 case 0xD2: /* Grp2 CL,Eb */
4366 modrm = getUChar(eip);
4367 am_sz = lengthAMode(eip);
4368 d_sz = 0;
4369 sz = 1;
sewardje1042472002-09-30 12:33:11 +00004370 eip = dis_Grp2 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, ArchReg, R_ECX );
njn25e49d8e72002-09-23 09:36:25 +00004371 break;
4372
sewardjde4a1d02002-03-22 01:27:54 +00004373 case 0xD3: /* Grp2 CL,Ev */
4374 modrm = getUChar(eip);
4375 am_sz = lengthAMode(eip);
4376 d_sz = 0;
sewardje1042472002-09-30 12:33:11 +00004377 eip = dis_Grp2 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, ArchReg, R_ECX );
sewardjde4a1d02002-03-22 01:27:54 +00004378 break;
4379
4380 /* ------------------------ (Grp3 extensions) ---------- */
4381
4382 case 0xF6: /* Grp3 Eb */
sewardje1042472002-09-30 12:33:11 +00004383 eip = dis_Grp3 ( cb, sorb, 1, eip );
sewardjde4a1d02002-03-22 01:27:54 +00004384 break;
4385 case 0xF7: /* Grp3 Ev */
sewardje1042472002-09-30 12:33:11 +00004386 eip = dis_Grp3 ( cb, sorb, sz, eip );
sewardjde4a1d02002-03-22 01:27:54 +00004387 break;
4388
4389 /* ------------------------ (Grp4 extensions) ---------- */
4390
4391 case 0xFE: /* Grp4 Eb */
sewardje1042472002-09-30 12:33:11 +00004392 eip = dis_Grp4 ( cb, sorb, eip );
sewardjde4a1d02002-03-22 01:27:54 +00004393 break;
4394
4395 /* ------------------------ (Grp5 extensions) ---------- */
4396
4397 case 0xFF: /* Grp5 Ev */
sewardje1042472002-09-30 12:33:11 +00004398 eip = dis_Grp5 ( cb, sorb, sz, eip, isEnd );
sewardjde4a1d02002-03-22 01:27:54 +00004399 break;
4400
4401 /* ------------------------ Escapes to 2-byte opcodes -- */
4402
4403 case 0x0F: {
4404 opc = getUChar(eip); eip++;
4405 switch (opc) {
4406
4407 /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
4408
4409 case 0xBA: /* Grp8 Ib,Ev */
4410 modrm = getUChar(eip);
4411 am_sz = lengthAMode(eip);
4412 d32 = getSDisp8(eip + am_sz);
sewardje1042472002-09-30 12:33:11 +00004413 eip = dis_Grp8_BT ( cb, sorb, eip, modrm, am_sz, sz, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00004414 break;
sewardj0ece28b2002-04-16 00:42:12 +00004415
sewardjde4a1d02002-03-22 01:27:54 +00004416 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
4417
4418 case 0xBC: /* BSF Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00004419 eip = dis_bs_E_G ( cb, sorb, sz, eip, True );
sewardjde4a1d02002-03-22 01:27:54 +00004420 break;
4421 case 0xBD: /* BSR Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00004422 eip = dis_bs_E_G ( cb, sorb, sz, eip, False );
sewardjde4a1d02002-03-22 01:27:54 +00004423 break;
4424
4425 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
4426
4427 case 0xC8: /* BSWAP %eax */
4428 case 0xC9:
4429 case 0xCA:
4430 case 0xCB:
4431 case 0xCC:
4432 case 0xCD:
4433 case 0xCE:
4434 case 0xCF: /* BSWAP %edi */
4435 /* AFAICS from the Intel docs, this only exists at size 4. */
4436 vg_assert(sz == 4);
4437 t1 = newTemp(cb);
4438 uInstr2(cb, GET, 4, ArchReg, opc-0xC8, TempReg, t1);
4439 uInstr1(cb, BSWAP, 4, TempReg, t1);
4440 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, opc-0xC8);
4441 if (dis) VG_(printf)("bswapl %s\n", nameIReg(4, opc-0xC8));
4442 break;
4443
4444 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
4445
4446 case 0xA3: /* BT Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00004447 eip = dis_bt_G_E ( cb, sorb, sz, eip, BtOpNone );
sewardjde4a1d02002-03-22 01:27:54 +00004448 break;
4449 case 0xB3: /* BTR Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00004450 eip = dis_bt_G_E ( cb, sorb, sz, eip, BtOpReset );
sewardjde4a1d02002-03-22 01:27:54 +00004451 break;
4452 case 0xAB: /* BTS Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00004453 eip = dis_bt_G_E ( cb, sorb, sz, eip, BtOpSet );
sewardjde4a1d02002-03-22 01:27:54 +00004454 break;
4455 case 0xBB: /* BTC Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00004456 eip = dis_bt_G_E ( cb, sorb, sz, eip, BtOpComp );
sewardjde4a1d02002-03-22 01:27:54 +00004457 break;
4458
4459 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
4460
4461 case 0x40:
4462 case 0x41:
4463 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
4464 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
4465 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
4466 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
4467 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
4468 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
4469 case 0x48: /* CMOVSb (cmov negative) */
4470 case 0x49: /* CMOVSb (cmov not negative) */
4471 case 0x4A: /* CMOVP (cmov parity even) */
sewardj969129d2002-04-21 11:43:11 +00004472 case 0x4B: /* CMOVNP (cmov parity odd) */
sewardjde4a1d02002-03-22 01:27:54 +00004473 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
4474 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
4475 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
4476 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
sewardje1042472002-09-30 12:33:11 +00004477 eip = dis_cmov_E_G(cb, sorb, sz, (Condcode)(opc - 0x40), eip);
sewardjde4a1d02002-03-22 01:27:54 +00004478 break;
4479
4480 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
4481
4482 case 0xB1: /* CMPXCHG Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00004483 eip = dis_cmpxchg_G_E ( cb, sorb, sz, eip );
sewardjde4a1d02002-03-22 01:27:54 +00004484 break;
4485
4486 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
4487
4488 case 0xA2: /* CPUID */
4489 t1 = newTemp(cb);
4490 t2 = newTemp(cb);
4491 t3 = newTemp(cb);
4492 t4 = newTemp(cb);
4493 uInstr0(cb, CALLM_S, 0);
4494
4495 uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t1);
4496 uInstr1(cb, PUSH, 4, TempReg, t1);
4497
4498 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
4499 uLiteral(cb, 0);
4500 uInstr1(cb, PUSH, 4, TempReg, t2);
4501
4502 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t3);
4503 uLiteral(cb, 0);
4504 uInstr1(cb, PUSH, 4, TempReg, t3);
4505
4506 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
4507 uLiteral(cb, 0);
4508 uInstr1(cb, PUSH, 4, TempReg, t4);
4509
4510 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CPUID));
4511 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
4512
4513 uInstr1(cb, POP, 4, TempReg, t4);
4514 uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_EDX);
4515
4516 uInstr1(cb, POP, 4, TempReg, t3);
4517 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ECX);
4518
4519 uInstr1(cb, POP, 4, TempReg, t2);
4520 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBX);
4521
4522 uInstr1(cb, POP, 4, TempReg, t1);
4523 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
4524
4525 uInstr0(cb, CALLM_E, 0);
4526 if (dis) VG_(printf)("cpuid\n");
4527 break;
4528
4529 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
4530
4531 case 0xB6: /* MOVZXb Eb,Gv */
sewardje1042472002-09-30 12:33:11 +00004532 eip = dis_movx_E_G ( cb, sorb, eip, 1, 4, False );
sewardjde4a1d02002-03-22 01:27:54 +00004533 break;
4534 case 0xB7: /* MOVZXw Ew,Gv */
sewardje1042472002-09-30 12:33:11 +00004535 eip = dis_movx_E_G ( cb, sorb, eip, 2, 4, False );
sewardjde4a1d02002-03-22 01:27:54 +00004536 break;
4537
4538 case 0xBE: /* MOVSXb Eb,Gv */
sewardje1042472002-09-30 12:33:11 +00004539 eip = dis_movx_E_G ( cb, sorb, eip, 1, 4, True );
sewardjde4a1d02002-03-22 01:27:54 +00004540 break;
4541 case 0xBF: /* MOVSXw Ew,Gv */
sewardje1042472002-09-30 12:33:11 +00004542 eip = dis_movx_E_G ( cb, sorb, eip, 2, 4, True );
sewardjde4a1d02002-03-22 01:27:54 +00004543 break;
4544
4545 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
4546
4547 case 0xAF: /* IMUL Ev, Gv */
sewardje1042472002-09-30 12:33:11 +00004548 eip = dis_mul_E_G ( cb, sorb, sz, eip, True );
sewardjde4a1d02002-03-22 01:27:54 +00004549 break;
4550
4551 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
4552 case 0x80:
4553 case 0x81:
4554 case 0x82: /* JBb/JNAEb (jump below) */
4555 case 0x83: /* JNBb/JAEb (jump not below) */
4556 case 0x84: /* JZb/JEb (jump zero) */
4557 case 0x85: /* JNZb/JNEb (jump not zero) */
4558 case 0x86: /* JBEb/JNAb (jump below or equal) */
4559 case 0x87: /* JNBEb/JAb (jump not below or equal) */
4560 case 0x88: /* JSb (jump negative) */
4561 case 0x89: /* JSb (jump not negative) */
4562 case 0x8A: /* JP (jump parity even) */
sewardj969129d2002-04-21 11:43:11 +00004563 case 0x8B: /* JNP/JPO (jump parity odd) */
sewardjde4a1d02002-03-22 01:27:54 +00004564 case 0x8C: /* JLb/JNGEb (jump less) */
4565 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
4566 case 0x8E: /* JLEb/JNGb (jump less or equal) */
4567 case 0x8F: /* JGb/JNLEb (jump greater) */
4568 d32 = (eip+4) + getUDisp32(eip); eip += 4;
4569 uInstr1(cb, JMP, 0, Literal, 0);
4570 uLiteral(cb, d32);
4571 uCond(cb, (Condcode)(opc - 0x80));
4572 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
4573 uInstr1(cb, JMP, 0, Literal, 0);
4574 uLiteral(cb, eip);
4575 uCond(cb, CondAlways);
4576 *isEnd = True;
4577 if (dis)
4578 VG_(printf)("j%s-32 0x%x\n",
njn563f96f2003-02-03 11:17:46 +00004579 VG_(name_UCondcode)(opc - 0x80), d32);
sewardjde4a1d02002-03-22 01:27:54 +00004580 break;
4581
4582 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
4583
4584 case 0x31: /* RDTSC */
4585 t1 = newTemp(cb);
4586 t2 = newTemp(cb);
4587 t3 = newTemp(cb);
4588 uInstr0(cb, CALLM_S, 0);
4589 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
4590 uLiteral(cb, 0);
4591 uInstr1(cb, PUSH, 4, TempReg, t1);
4592 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
4593 uLiteral(cb, 0);
4594 uInstr1(cb, PUSH, 4, TempReg, t2);
4595 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_RDTSC));
4596 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
4597 uInstr1(cb, POP, 4, TempReg, t3);
4598 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EDX);
4599 uInstr1(cb, POP, 4, TempReg, t3);
4600 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EAX);
4601 uInstr0(cb, CALLM_E, 0);
4602 if (dis) VG_(printf)("rdtsc\n");
4603 break;
4604
4605 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
4606 case 0x90:
4607 case 0x91:
4608 case 0x92: /* set-Bb/set-NAEb (jump below) */
4609 case 0x93: /* set-NBb/set-AEb (jump not below) */
4610 case 0x94: /* set-Zb/set-Eb (jump zero) */
4611 case 0x95: /* set-NZb/set-NEb (jump not zero) */
4612 case 0x96: /* set-BEb/set-NAb (jump below or equal) */
4613 case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
4614 case 0x98: /* set-Sb (jump negative) */
4615 case 0x99: /* set-Sb (jump not negative) */
4616 case 0x9A: /* set-P (jump parity even) */
4617 case 0x9B: /* set-NP (jump parity odd) */
4618 case 0x9C: /* set-Lb/set-NGEb (jump less) */
4619 case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
4620 case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
4621 case 0x9F: /* set-Gb/set-NLEb (jump greater) */
4622 modrm = getUChar(eip);
4623 t1 = newTemp(cb);
4624 if (epartIsReg(modrm)) {
4625 eip++;
4626 uInstr1(cb, CC2VAL, 1, TempReg, t1);
4627 uCond(cb, (Condcode)(opc-0x90));
4628 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
4629 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, eregOfRM(modrm));
4630 if (dis) VG_(printf)("set%s %s\n",
njn563f96f2003-02-03 11:17:46 +00004631 VG_(name_UCondcode)(opc-0x90),
sewardjde4a1d02002-03-22 01:27:54 +00004632 nameIReg(1,eregOfRM(modrm)));
4633 } else {
sewardje1042472002-09-30 12:33:11 +00004634 pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL );
sewardjde4a1d02002-03-22 01:27:54 +00004635 t2 = LOW24(pair);
4636 eip += HI8(pair);
4637 uInstr1(cb, CC2VAL, 1, TempReg, t1);
4638 uCond(cb, (Condcode)(opc-0x90));
4639 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
4640 uInstr2(cb, STORE, 1, TempReg, t1, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00004641 if (dis) VG_(printf)("set%s %s\n",
njn563f96f2003-02-03 11:17:46 +00004642 VG_(name_UCondcode)(opc-0x90),
sewardjde4a1d02002-03-22 01:27:54 +00004643 dis_buf);
4644 }
4645 break;
4646
4647 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
4648
4649 case 0xA4: /* SHLDv imm8,Gv,Ev */
4650 modrm = getUChar(eip);
4651 eip = dis_SHLRD_Gv_Ev (
sewardje1042472002-09-30 12:33:11 +00004652 cb, sorb, eip, modrm, sz,
sewardjde4a1d02002-03-22 01:27:54 +00004653 Literal, getUChar(eip + lengthAMode(eip)),
4654 True );
4655 break;
4656 case 0xA5: /* SHLDv %cl,Gv,Ev */
4657 modrm = getUChar(eip);
4658 eip = dis_SHLRD_Gv_Ev (
sewardje1042472002-09-30 12:33:11 +00004659 cb, sorb, eip, modrm, sz, ArchReg, R_CL, True );
sewardjde4a1d02002-03-22 01:27:54 +00004660 break;
4661
4662 case 0xAC: /* SHRDv imm8,Gv,Ev */
4663 modrm = getUChar(eip);
4664 eip = dis_SHLRD_Gv_Ev (
sewardje1042472002-09-30 12:33:11 +00004665 cb, sorb, eip, modrm, sz,
sewardjde4a1d02002-03-22 01:27:54 +00004666 Literal, getUChar(eip + lengthAMode(eip)),
4667 False );
4668 break;
4669 case 0xAD: /* SHRDv %cl,Gv,Ev */
4670 modrm = getUChar(eip);
4671 eip = dis_SHLRD_Gv_Ev (
sewardje1042472002-09-30 12:33:11 +00004672 cb, sorb, eip, modrm, sz, ArchReg, R_CL, False );
sewardjde4a1d02002-03-22 01:27:54 +00004673 break;
4674
4675 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
4676
4677 case 0xC1: /* XADD Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00004678 eip = dis_xadd_G_E ( cb, sorb, sz, eip );
sewardjde4a1d02002-03-22 01:27:54 +00004679 break;
4680
4681 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
4682
4683 default:
4684 VG_(printf)("disInstr: unhandled 2-byte opcode 0x%x\n",
4685 (UInt)opc);
sewardj12ffdac2002-07-25 22:41:40 +00004686 VG_(printf)("This _might_ be the result of executing an "
4687 "MMX, SSE, SSE2 or 3DNow!\n" );
4688 VG_(printf)("instruction. Valgrind does not currently "
4689 "support such instructions. Sorry.\n" );
sewardj51096432002-12-14 23:59:09 +00004690 uInstr0(cb, CALLM_S, 0);
4691 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_undefined_instruction));
4692 uInstr0(cb, CALLM_E, 0);
4693
4694 /* just because everything else insists the last instruction
4695 of a BB is a jmp */
4696 uInstr1(cb, JMP, 0, Literal, 0);
4697 uCond(cb, CondAlways);
4698 uLiteral(cb, eip);
4699 *isEnd = True;
sewardjde4a1d02002-03-22 01:27:54 +00004700 }
4701
4702 break;
4703 }
4704
4705 /* ------------------------ ??? ------------------------ */
4706
4707 default:
4708 VG_(printf)("disInstr: unhandled opcode 0x%x then 0x%x\n",
4709 (UInt)opc, (UInt)getUChar(eip));
njne427a662002-10-02 11:08:25 +00004710 VG_(core_panic)("unhandled x86 opcode");
sewardjde4a1d02002-03-22 01:27:54 +00004711 }
4712
4713 if (dis)
4714 VG_(printf)("\n");
4715 for (; first_uinstr < cb->used; first_uinstr++) {
njn25e49d8e72002-09-23 09:36:25 +00004716 Bool sane = VG_(saneUInstr)(True, True, &cb->instrs[first_uinstr]);
4717 if (dis)
njn4ba5a792002-09-30 10:23:54 +00004718 VG_(pp_UInstr)(first_uinstr, &cb->instrs[first_uinstr]);
njn25e49d8e72002-09-23 09:36:25 +00004719 else if (!sane)
njn4ba5a792002-09-30 10:23:54 +00004720 VG_(up_UInstr)(-1, &cb->instrs[first_uinstr]);
sewardjde4a1d02002-03-22 01:27:54 +00004721 vg_assert(sane);
4722 }
4723
4724 return eip;
4725}
4726
4727
4728/* Disassemble a complete basic block, starting at eip, and dumping
4729 the ucode into cb. Returns the size, in bytes, of the basic
4730 block. */
4731
4732Int VG_(disBB) ( UCodeBlock* cb, Addr eip0 )
4733{
4734 Addr eip = eip0;
4735 Bool isEnd = False;
4736 Bool block_sane;
njn4f9c9342002-04-29 16:03:24 +00004737 Int delta = 0;
4738
njn25e49d8e72002-09-23 09:36:25 +00004739 if (dis) VG_(printf)("Original x86 code to UCode:\n\n");
sewardjde4a1d02002-03-22 01:27:54 +00004740
njn25e49d8e72002-09-23 09:36:25 +00004741 /* After every x86 instruction do an INCEIP, except for the final one
4742 * in the basic block. For them we patch in the x86 instruction size
4743 * into the `extra4b' field of the basic-block-ending JMP.
njn4f9c9342002-04-29 16:03:24 +00004744 *
njn25e49d8e72002-09-23 09:36:25 +00004745 * The INCEIPs and JMP.extra4b fields allows a skin to track x86
4746 * instruction sizes, important for some skins (eg. cache simulation).
njn4f9c9342002-04-29 16:03:24 +00004747 */
sewardjde4a1d02002-03-22 01:27:54 +00004748 if (VG_(clo_single_step)) {
4749 eip = disInstr ( cb, eip, &isEnd );
njn4f9c9342002-04-29 16:03:24 +00004750
4751 /* Add a JMP to the next (single x86 instruction) BB if it doesn't
4752 * already end with a JMP instr. We also need to check for no UCode,
4753 * which occurs if the x86 instr was a nop */
4754 if (cb->used == 0 || LAST_UINSTR(cb).opcode != JMP) {
4755 uInstr1(cb, JMP, 0, Literal, 0);
4756 uLiteral(cb, eip);
4757 uCond(cb, CondAlways);
njn25e49d8e72002-09-23 09:36:25 +00004758 /* Print added JMP */
njn4ba5a792002-09-30 10:23:54 +00004759 if (dis) VG_(pp_UInstr)(cb->used-1, &cb->instrs[cb->used-1]);
njn4f9c9342002-04-29 16:03:24 +00004760 }
njn25e49d8e72002-09-23 09:36:25 +00004761 if (dis) VG_(printf)("\n");
njn4f9c9342002-04-29 16:03:24 +00004762 delta = eip - eip0;
4763
sewardjde4a1d02002-03-22 01:27:54 +00004764 } else {
sewardjde4a1d02002-03-22 01:27:54 +00004765 Addr eip2;
njn4f9c9342002-04-29 16:03:24 +00004766 while (!isEnd) {
sewardjde4a1d02002-03-22 01:27:54 +00004767 eip2 = disInstr ( cb, eip, &isEnd );
njn25e49d8e72002-09-23 09:36:25 +00004768 delta = (eip2 - eip);
sewardjde4a1d02002-03-22 01:27:54 +00004769 eip = eip2;
sewardjde4a1d02002-03-22 01:27:54 +00004770 /* Split up giant basic blocks into pieces, so the
4771 translations fall within 64k. */
njn4f9c9342002-04-29 16:03:24 +00004772 if (eip - eip0 > 2000 && !isEnd) {
sewardja0f921a2002-05-08 00:42:25 +00004773 if (VG_(clo_verbosity) > 2)
njn4f9c9342002-04-29 16:03:24 +00004774 VG_(message)(Vg_DebugMsg,
sewardjde4a1d02002-03-22 01:27:54 +00004775 "Warning: splitting giant basic block into pieces");
4776 uInstr1(cb, JMP, 0, Literal, 0);
4777 uLiteral(cb, eip);
4778 uCond(cb, CondAlways);
njn25e49d8e72002-09-23 09:36:25 +00004779 /* Print added JMP */
njn4ba5a792002-09-30 10:23:54 +00004780 if (dis) VG_(pp_UInstr)(cb->used-1, &cb->instrs[cb->used-1]);
njn4f9c9342002-04-29 16:03:24 +00004781 isEnd = True;
4782
njn25e49d8e72002-09-23 09:36:25 +00004783 } else if (!isEnd) {
njn4f9c9342002-04-29 16:03:24 +00004784 uInstr1(cb, INCEIP, 0, Lit16, delta);
njn25e49d8e72002-09-23 09:36:25 +00004785 /* Print added INCEIP */
njn4ba5a792002-09-30 10:23:54 +00004786 if (dis) VG_(pp_UInstr)(cb->used-1, &cb->instrs[cb->used-1]);
sewardjde4a1d02002-03-22 01:27:54 +00004787 }
4788 if (dis) VG_(printf)("\n");
4789 }
4790 }
sewardjde4a1d02002-03-22 01:27:54 +00004791
njn25e49d8e72002-09-23 09:36:25 +00004792 /* Patch instruction size into final JMP. */
4793 LAST_UINSTR(cb).extra4b = delta;
4794
4795 block_sane = VG_(saneUCodeBlockCalls)(cb);
sewardjde4a1d02002-03-22 01:27:54 +00004796 if (!block_sane) {
njn4ba5a792002-09-30 10:23:54 +00004797 VG_(pp_UCodeBlock)(cb, "block failing sanity check");
sewardjde4a1d02002-03-22 01:27:54 +00004798 vg_assert(block_sane);
4799 }
4800
4801 return eip - eip0;
4802}
4803
njn25e49d8e72002-09-23 09:36:25 +00004804#undef dis
sewardjde4a1d02002-03-22 01:27:54 +00004805
4806/*--------------------------------------------------------------------*/
4807/*--- end vg_to_ucode.c ---*/
4808/*--------------------------------------------------------------------*/