blob: 82e505cd235a89ec06a8a7abf842dbc64c85ae10 [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
239/* For the last uinsn inserted into cb, set the read, written and
240 undefined flags. Undefined flags are counted as written, but it
241 seems worthwhile to distinguish them.
242*/
243static __inline__ void uFlagsRWU ( UCodeBlock* cb,
244 FlagSet rr, FlagSet ww, FlagSet uu )
245{
njn4ba5a792002-09-30 10:23:54 +0000246 VG_(set_flag_RW)(
sewardjde4a1d02002-03-22 01:27:54 +0000247 &LAST_UINSTR(cb), rr, VG_UNION_FLAG_SETS(ww,uu)
248 );
249}
250
251
252static void setFlagsFromUOpcode ( UCodeBlock* cb, Int uopc )
253{
254 switch (uopc) {
255 case XOR: case OR: case AND:
256 uFlagsRWU(cb, FlagsEmpty, FlagsOSZCP, FlagA); break;
257 case ADC: case SBB:
258 uFlagsRWU(cb, FlagC, FlagsOSZACP, FlagsEmpty); break;
259 case ADD: case SUB: case NEG:
260 uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty); break;
261 case INC: case DEC:
262 uFlagsRWU(cb, FlagsEmpty, FlagsOSZAP, FlagsEmpty); break;
263 case SHR: case SAR: case SHL:
264 uFlagsRWU(cb, FlagsEmpty, FlagsOSZCP, FlagA); break;
265 case ROL: case ROR:
266 uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsEmpty); break;
267 case RCR: case RCL:
268 uFlagsRWU(cb, FlagC, FlagsOC, FlagsEmpty); break;
269 case NOT:
270 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty); break;
271 default:
272 VG_(printf)("unhandled case is %s\n",
njn4ba5a792002-09-30 10:23:54 +0000273 VG_(name_UOpcode)(True, uopc));
njne427a662002-10-02 11:08:25 +0000274 VG_(core_panic)("setFlagsFromUOpcode: unhandled case");
sewardjde4a1d02002-03-22 01:27:54 +0000275 }
276}
277
278static __inline__ void uCond ( UCodeBlock* cb, Condcode cond )
279{
280 LAST_UINSTR(cb).cond = cond;
281}
282
283
284/*------------------------------------------------------------*/
285/*--- Disassembling addressing modes ---*/
286/*------------------------------------------------------------*/
287
sewardje1042472002-09-30 12:33:11 +0000288static
289UChar* sorbTxt ( UChar sorb )
290{
291 switch (sorb) {
292 case 0: return ""; /* no override */
293 case 0x3E: return "%ds";
294 case 0x26: return "%es:";
295 case 0x64: return "%fs:";
296 case 0x65: return "%gs:";
njne427a662002-10-02 11:08:25 +0000297 default: VG_(core_panic)("sorbTxt");
sewardje1042472002-09-30 12:33:11 +0000298 }
299}
300
301
302/* Tmp is a TempReg holding a virtual address. Convert it to a linear
303 address by adding any required segment override as indicated by
304 sorb. */
305static
306void handleSegOverride ( UCodeBlock* cb, UChar sorb, Int tmp )
307{
308 Int sreg, tsreg;
309
310 if (sorb == 0)
311 /* the common case - no override */
312 return;
313
314 switch (sorb) {
315 case 0x3E: sreg = R_DS; break;
316 case 0x26: sreg = R_ES; break;
317 case 0x64: sreg = R_FS; break;
318 case 0x65: sreg = R_GS; break;
njne427a662002-10-02 11:08:25 +0000319 default: VG_(core_panic)("handleSegOverride");
sewardje1042472002-09-30 12:33:11 +0000320 }
321
322 tsreg = newTemp(cb);
323
324 /* sreg -> tsreg */
325 uInstr2(cb, GETSEG, 2, ArchRegS, sreg, TempReg, tsreg );
326
327 /* tmp += segment_base(ldt[tsreg]); also do limit check */
328 uInstr2(cb, USESEG, 0, TempReg, tsreg, TempReg, tmp );
329}
330
331
sewardjde4a1d02002-03-22 01:27:54 +0000332/* Generate ucode to calculate an address indicated by a ModRM and
333 following SIB bytes, getting the value in a new temporary. The
334 temporary, and the number of bytes in the address mode, are
sewardje1042472002-09-30 12:33:11 +0000335 returned, as a pair (length << 24) | temp. Note that this fn should
sewardjde4a1d02002-03-22 01:27:54 +0000336 not be called if the R/M part of the address denotes a register
337 instead of memory. If buf is non-NULL, text of the addressing mode
338 is placed therein. */
339
sewardje1042472002-09-30 12:33:11 +0000340static
341UInt disAMode ( UCodeBlock* cb, UChar sorb, Addr eip0, UChar* buf )
sewardjde4a1d02002-03-22 01:27:54 +0000342{
343 UChar* eip = (UChar*)eip0;
344 UChar mod_reg_rm = *eip++;
345 Int tmp = newTemp(cb);
346
347 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
348 jump table seems a bit excessive.
349 */
350 mod_reg_rm &= 0xC7; /* is now XX000YYY */
351 mod_reg_rm |= (mod_reg_rm >> 3); /* is now XX0XXYYY */
352 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
353 switch (mod_reg_rm) {
354
355 /* (%eax) .. (%edi), not including (%esp) or (%ebp).
356 --> GET %reg, t
357 */
358 case 0x00: case 0x01: case 0x02: case 0x03:
359 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
360 { UChar rm = mod_reg_rm;
361 uInstr2(cb, GET, 4, ArchReg, rm, TempReg, tmp);
sewardje1042472002-09-30 12:33:11 +0000362 handleSegOverride(cb, sorb, tmp);
363 if (buf) VG_(sprintf)(buf,"%s(%s)", sorbTxt(sorb),
364 nameIReg(4,rm));
sewardjde4a1d02002-03-22 01:27:54 +0000365 return (1<<24 | tmp);
366 }
367
368 /* d8(%eax) ... d8(%edi), not including d8(%esp)
369 --> GET %reg, t ; ADDL d8, t
370 */
371 case 0x08: case 0x09: case 0x0A: case 0x0B:
372 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
373 { UChar rm = mod_reg_rm & 7;
374 Int tmq = newTemp(cb);
375 UInt d = getSDisp8((Addr)eip); eip++;
376 uInstr2(cb, GET, 4, ArchReg, rm, TempReg, tmq);
377 uInstr2(cb, LEA1, 4, TempReg, tmq, TempReg, tmp);
378 LAST_UINSTR(cb).lit32 = d;
sewardje1042472002-09-30 12:33:11 +0000379 handleSegOverride(cb, sorb, tmp);
380 if (buf) VG_(sprintf)(buf,"%s%d(%s)", sorbTxt(sorb),
381 d, nameIReg(4,rm));
sewardjde4a1d02002-03-22 01:27:54 +0000382 return (2<<24 | tmp);
383 }
384
385 /* d32(%eax) ... d32(%edi), not including d32(%esp)
386 --> GET %reg, t ; ADDL d8, t
387 */
388 case 0x10: case 0x11: case 0x12: case 0x13:
389 /* ! 14 */ case 0x15: case 0x16: case 0x17:
390 { UChar rm = mod_reg_rm & 7;
391 Int tmq = newTemp(cb);
392 UInt d = getUDisp32((Addr)eip); eip += 4;
393 uInstr2(cb, GET, 4, ArchReg, rm, TempReg, tmq);
394 uInstr2(cb, LEA1, 4, TempReg, tmq, TempReg, tmp);
395 LAST_UINSTR(cb).lit32 = d;
sewardje1042472002-09-30 12:33:11 +0000396 handleSegOverride(cb, sorb, tmp);
397 if (buf) VG_(sprintf)(buf,"%s0x%x(%s)", sorbTxt(sorb),
398 d, nameIReg(4,rm));
sewardjde4a1d02002-03-22 01:27:54 +0000399 return (5<<24 | tmp);
400 }
401
402 /* a register, %eax .. %edi. This shouldn't happen. */
403 case 0x18: case 0x19: case 0x1A: case 0x1B:
404 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
njne427a662002-10-02 11:08:25 +0000405 VG_(core_panic)("disAMode: not an addr!");
sewardjde4a1d02002-03-22 01:27:54 +0000406
407 /* a 32-bit literal address
408 --> MOV d32, tmp
409 */
410 case 0x05:
411 { UInt d = getUDisp32((Addr)eip); eip += 4;
412 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tmp);
413 uLiteral(cb, d);
sewardje1042472002-09-30 12:33:11 +0000414 handleSegOverride(cb, sorb, tmp);
415 if (buf) VG_(sprintf)(buf,"%s(0x%x)", sorbTxt(sorb), d);
sewardjde4a1d02002-03-22 01:27:54 +0000416 return (5<<24 | tmp);
417 }
418
419 case 0x04: {
420 /* SIB, with no displacement. Special cases:
421 -- %esp cannot act as an index value.
422 If index_r indicates %esp, zero is used for the index.
423 -- when mod is zero and base indicates EBP, base is instead
424 a 32-bit literal.
425 It's all madness, I tell you. Extract %index, %base and
426 scale from the SIB byte. The value denoted is then:
427 | %index == %ESP && %base == %EBP
428 = d32 following SIB byte
429 | %index == %ESP && %base != %EBP
430 = %base
431 | %index != %ESP && %base == %EBP
432 = d32 following SIB byte + (%index << scale)
433 | %index != %ESP && %base != %ESP
434 = %base + (%index << scale)
435
436 What happens to the souls of CPU architects who dream up such
437 horrendous schemes, do you suppose?
438 */
439 UChar sib = *eip++;
440 UChar scale = (sib >> 6) & 3;
441 UChar index_r = (sib >> 3) & 7;
442 UChar base_r = sib & 7;
443
444 if (index_r != R_ESP && base_r != R_EBP) {
445 Int index_tmp = newTemp(cb);
446 Int base_tmp = newTemp(cb);
447 uInstr2(cb, GET, 4, ArchReg, index_r, TempReg, index_tmp);
448 uInstr2(cb, GET, 4, ArchReg, base_r, TempReg, base_tmp);
449 uInstr3(cb, LEA2, 4, TempReg, base_tmp, TempReg, index_tmp,
450 TempReg, tmp);
451 LAST_UINSTR(cb).lit32 = 0;
452 LAST_UINSTR(cb).extra4b = 1 << scale;
sewardje1042472002-09-30 12:33:11 +0000453 handleSegOverride(cb, sorb, tmp);
454 if (buf) VG_(sprintf)(buf,"%s(%s,%s,%d)", sorbTxt(sorb),
455 nameIReg(4,base_r),
sewardjde4a1d02002-03-22 01:27:54 +0000456 nameIReg(4,index_r),1<<scale);
457 return (2<<24 | tmp);
458 }
459
460 if (index_r != R_ESP && base_r == R_EBP) {
461 Int index_tmp = newTemp(cb);
462 UInt d = getUDisp32((Addr)eip); eip += 4;
463 uInstr2(cb, GET, 4, ArchReg, index_r, TempReg, index_tmp);
464 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tmp);
465 uLiteral(cb, 0);
466 uInstr3(cb, LEA2, 4, TempReg, tmp, TempReg, index_tmp,
467 TempReg, tmp);
468 LAST_UINSTR(cb).lit32 = d;
469 LAST_UINSTR(cb).extra4b = 1 << scale;
sewardje1042472002-09-30 12:33:11 +0000470 handleSegOverride(cb, sorb, tmp);
471 if (buf) VG_(sprintf)(buf,"%s0x%x(,%s,%d)", sorbTxt(sorb), d,
sewardjde4a1d02002-03-22 01:27:54 +0000472 nameIReg(4,index_r),1<<scale);
473 return (6<<24 | tmp);
474 }
475
476 if (index_r == R_ESP && base_r != R_EBP) {
477 uInstr2(cb, GET, 4, ArchReg, base_r, TempReg, tmp);
sewardje1042472002-09-30 12:33:11 +0000478 handleSegOverride(cb, sorb, tmp);
479 if (buf) VG_(sprintf)(buf,"%s(%s,,)",
480 sorbTxt(sorb), nameIReg(4,base_r));
sewardjde4a1d02002-03-22 01:27:54 +0000481 return (2<<24 | tmp);
482 }
483
484 if (index_r == R_ESP && base_r == R_EBP) {
485 UInt d = getUDisp32((Addr)eip); eip += 4;
486 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tmp);
487 uLiteral(cb, d);
sewardje1042472002-09-30 12:33:11 +0000488 handleSegOverride(cb, sorb, tmp);
489 if (buf) VG_(sprintf)(buf,"%s0x%x()", sorbTxt(sorb), d);
sewardjde4a1d02002-03-22 01:27:54 +0000490 return (6<<24 | tmp);
491 }
492
493 vg_assert(0);
494 }
495
496 /* SIB, with 8-bit displacement. Special cases:
497 -- %esp cannot act as an index value.
498 If index_r indicates %esp, zero is used for the index.
499 Denoted value is:
500 | %index == %ESP
501 = d8 + %base
502 | %index != %ESP
503 = d8 + %base + (%index << scale)
504 */
505 case 0x0C: {
506 UChar sib = *eip++;
507 UChar scale = (sib >> 6) & 3;
508 UChar index_r = (sib >> 3) & 7;
509 UChar base_r = sib & 7;
510 UInt d = getSDisp8((Addr)eip); eip++;
511
512 if (index_r == R_ESP) {
513 Int tmq = newTemp(cb);
514 uInstr2(cb, GET, 4, ArchReg, base_r, TempReg, tmq);
515 uInstr2(cb, LEA1, 4, TempReg, tmq, TempReg, tmp);
516 LAST_UINSTR(cb).lit32 = d;
sewardje1042472002-09-30 12:33:11 +0000517 handleSegOverride(cb, sorb, tmp);
518 if (buf) VG_(sprintf)(buf,"%s%d(%s,,)", sorbTxt(sorb),
519 d, nameIReg(4,base_r));
sewardjde4a1d02002-03-22 01:27:54 +0000520 return (3<<24 | tmp);
521 } else {
522 Int index_tmp = newTemp(cb);
523 Int base_tmp = newTemp(cb);
524 uInstr2(cb, GET, 4, ArchReg, index_r, TempReg, index_tmp);
525 uInstr2(cb, GET, 4, ArchReg, base_r, TempReg, base_tmp);
526 uInstr3(cb, LEA2, 4, TempReg, base_tmp, TempReg, index_tmp,
527 TempReg, tmp);
528 LAST_UINSTR(cb).lit32 = d;
529 LAST_UINSTR(cb).extra4b = 1 << scale;
sewardje1042472002-09-30 12:33:11 +0000530 handleSegOverride(cb, sorb, tmp);
531 if (buf) VG_(sprintf)(buf,"%s%d(%s,%s,%d)",
532 sorbTxt(sorb), d, nameIReg(4,base_r),
sewardjde4a1d02002-03-22 01:27:54 +0000533 nameIReg(4,index_r), 1<<scale);
534 return (3<<24 | tmp);
535 }
536 vg_assert(0);
537 }
538
539 /* SIB, with 32-bit displacement. Special cases:
540 -- %esp cannot act as an index value.
541 If index_r indicates %esp, zero is used for the index.
542 Denoted value is:
543 | %index == %ESP
544 = d32 + %base
545 | %index != %ESP
546 = d32 + %base + (%index << scale)
547 */
548 case 0x14: {
549 UChar sib = *eip++;
550 UChar scale = (sib >> 6) & 3;
551 UChar index_r = (sib >> 3) & 7;
552 UChar base_r = sib & 7;
553 UInt d = getUDisp32((Addr)eip); eip += 4;
554
555 if (index_r == R_ESP) {
556 Int tmq = newTemp(cb);
557 uInstr2(cb, GET, 4, ArchReg, base_r, TempReg, tmq);
558 uInstr2(cb, LEA1, 4, TempReg, tmq, TempReg, tmp);
559 LAST_UINSTR(cb).lit32 = d;
sewardje1042472002-09-30 12:33:11 +0000560 handleSegOverride(cb, sorb, tmp);
561 if (buf) VG_(sprintf)(buf,"%s%d(%s,,)",
562 sorbTxt(sorb), d, nameIReg(4,base_r));
sewardjde4a1d02002-03-22 01:27:54 +0000563 return (6<<24 | tmp);
564 } else {
565 Int index_tmp = newTemp(cb);
566 Int base_tmp = newTemp(cb);
567 uInstr2(cb, GET, 4, ArchReg, index_r, TempReg, index_tmp);
568 uInstr2(cb, GET, 4, ArchReg, base_r, TempReg, base_tmp);
569 uInstr3(cb, LEA2, 4, TempReg, base_tmp, TempReg, index_tmp,
570 TempReg, tmp);
571 LAST_UINSTR(cb).lit32 = d;
572 LAST_UINSTR(cb).extra4b = 1 << scale;
sewardje1042472002-09-30 12:33:11 +0000573 handleSegOverride(cb, sorb, tmp);
574 if (buf) VG_(sprintf)(buf,"%s%d(%s,%s,%d)",
575 sorbTxt(sorb), d, nameIReg(4,base_r),
sewardjde4a1d02002-03-22 01:27:54 +0000576 nameIReg(4,index_r), 1<<scale);
577 return (6<<24 | tmp);
578 }
579 vg_assert(0);
580 }
581
582 default:
njne427a662002-10-02 11:08:25 +0000583 VG_(core_panic)("disAMode");
sewardjde4a1d02002-03-22 01:27:54 +0000584 return 0; /*notreached*/
585 }
586}
587
588
589/* Figure out the number of (insn-stream) bytes constituting the amode
590 beginning at eip0. Is useful for getting hold of literals beyond
591 the end of the amode before it has been disassembled. */
592
593static UInt lengthAMode ( Addr eip0 )
594{
595 UChar* eip = (UChar*)eip0;
596 UChar mod_reg_rm = *eip++;
597
598 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
599 jump table seems a bit excessive.
600 */
601 mod_reg_rm &= 0xC7; /* is now XX000YYY */
602 mod_reg_rm |= (mod_reg_rm >> 3); /* is now XX0XXYYY */
603 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
604 switch (mod_reg_rm) {
605
606 /* (%eax) .. (%edi), not including (%esp) or (%ebp). */
607 case 0x00: case 0x01: case 0x02: case 0x03:
608 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
609 return 1;
610
611 /* d8(%eax) ... d8(%edi), not including d8(%esp). */
612 case 0x08: case 0x09: case 0x0A: case 0x0B:
613 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
614 return 2;
615
616 /* d32(%eax) ... d32(%edi), not including d32(%esp). */
617 case 0x10: case 0x11: case 0x12: case 0x13:
618 /* ! 14 */ case 0x15: case 0x16: case 0x17:
619 return 5;
620
621 /* a register, %eax .. %edi. (Not an addr, but still handled.) */
622 case 0x18: case 0x19: case 0x1A: case 0x1B:
623 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
624 return 1;
625
626 /* a 32-bit literal address. */
627 case 0x05: return 5;
628
629 /* SIB, no displacement. */
630 case 0x04: {
631 UChar sib = *eip++;
632 UChar base_r = sib & 7;
633 if (base_r == R_EBP) return 6; else return 2;
634 }
635 /* SIB, with 8-bit displacement. */
636 case 0x0C: return 3;
637
638 /* SIB, with 32-bit displacement. */
639 case 0x14: return 6;
640
641 default:
njne427a662002-10-02 11:08:25 +0000642 VG_(core_panic)("amode_from_RM");
sewardjde4a1d02002-03-22 01:27:54 +0000643 return 0; /*notreached*/
644 }
645}
646
647
648/* Extract the reg field from a modRM byte. */
649static __inline__ Int gregOfRM ( UChar mod_reg_rm )
650{
651 return (Int)( (mod_reg_rm >> 3) & 7 );
652}
653
654/* Figure out whether the mod and rm parts of a modRM byte refer to a
655 register or memory. If so, the byte will have the form 11XXXYYY,
656 where YYY is the register number. */
657static __inline__ Bool epartIsReg ( UChar mod_reg_rm )
658{
659 return (0xC0 == (mod_reg_rm & 0xC0));
660}
661
662/* ... and extract the register number ... */
663static __inline__ Int eregOfRM ( UChar mod_reg_rm )
664{
665 return (Int)(mod_reg_rm & 0x7);
666}
667
668
669/*------------------------------------------------------------*/
670/*--- Disassembling common idioms ---*/
671/*------------------------------------------------------------*/
672
673static
674void codegen_XOR_reg_with_itself ( UCodeBlock* cb, Int size,
675 Int ge_reg, Int tmp )
676{
677 if (dis)
678 VG_(printf)("xor%c %s, %s\n", nameISize(size),
679 nameIReg(size,ge_reg), nameIReg(size,ge_reg) );
680 uInstr2(cb, MOV, size, Literal, 0, TempReg, tmp);
681 uLiteral(cb, 0);
682 uInstr2(cb, XOR, size, TempReg, tmp, TempReg, tmp);
683 setFlagsFromUOpcode(cb, XOR);
684 uInstr2(cb, PUT, size, TempReg, tmp, ArchReg, ge_reg);
685}
686
687
688/* Handle binary integer instructions of the form
689 op E, G meaning
690 op reg-or-mem, reg
691 Is passed the a ptr to the modRM byte, the actual operation, and the
692 data size. Returns the address advanced completely over this
693 instruction.
694
695 E(src) is reg-or-mem
696 G(dst) is reg.
697
698 If E is reg, --> GET %G, tmp
699 OP %E, tmp
700 PUT tmp, %G
701
702 If E is mem and OP is not reversible,
703 --> (getAddr E) -> tmpa
704 LD (tmpa), tmpa
705 GET %G, tmp2
706 OP tmpa, tmp2
707 PUT tmp2, %G
708
709 If E is mem and OP is reversible
710 --> (getAddr E) -> tmpa
711 LD (tmpa), tmpa
712 OP %G, tmpa
713 PUT tmpa, %G
714*/
715static
sewardje1042472002-09-30 12:33:11 +0000716Addr dis_op2_E_G ( UCodeBlock* cb,
717 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +0000718 Opcode opc,
719 Bool keep,
720 Int size,
721 Addr eip0,
722 Char* t_x86opc )
723{
724 Bool reversible;
725 UChar rm = getUChar(eip0);
726 UChar dis_buf[50];
727
728 if (epartIsReg(rm)) {
729 Int tmp = newTemp(cb);
730
731 /* Specially handle XOR reg,reg, because that doesn't really
732 depend on reg, and doing the obvious thing potentially
733 generates a spurious value check failure due to the bogus
734 dependency. */
735 if (opc == XOR && gregOfRM(rm) == eregOfRM(rm)) {
736 codegen_XOR_reg_with_itself ( cb, size, gregOfRM(rm), tmp );
737 return 1+eip0;
738 }
739
740 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmp);
741 if (opc == AND || opc == OR) {
742 Int tao = newTemp(cb);
743 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, tao);
744 uInstr2(cb, opc, size, TempReg, tao, TempReg, tmp);
745 setFlagsFromUOpcode(cb, opc);
746 } else {
747 uInstr2(cb, opc, size, ArchReg, eregOfRM(rm), TempReg, tmp);
748 setFlagsFromUOpcode(cb, opc);
749 }
750 if (keep)
751 uInstr2(cb, PUT, size, TempReg, tmp, ArchReg, gregOfRM(rm));
752 if (dis) VG_(printf)("%s%c %s,%s\n", t_x86opc, nameISize(size),
753 nameIReg(size,eregOfRM(rm)),
754 nameIReg(size,gregOfRM(rm)));
755 return 1+eip0;
756 }
757
758 /* E refers to memory */
759 reversible
760 = (opc == ADD || opc == OR || opc == AND || opc == XOR || opc == ADC)
761 ? True : False;
762 if (reversible) {
sewardje1042472002-09-30 12:33:11 +0000763 UInt pair = disAMode ( cb, sorb, eip0, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +0000764 Int tmpa = LOW24(pair);
765 uInstr2(cb, LOAD, size, TempReg, tmpa, TempReg, tmpa);
766
767 if (opc == AND || opc == OR) {
768 Int tao = newTemp(cb);
769 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tao);
770 uInstr2(cb, opc, size, TempReg, tao, TempReg, tmpa);
771 setFlagsFromUOpcode(cb, opc);
772 } else {
773 uInstr2(cb, opc, size, ArchReg, gregOfRM(rm), TempReg, tmpa);
774 setFlagsFromUOpcode(cb, opc);
775 }
776 if (keep)
777 uInstr2(cb, PUT, size, TempReg, tmpa, ArchReg, gregOfRM(rm));
778 if (dis) VG_(printf)("%s%c %s,%s\n", t_x86opc, nameISize(size),
779 dis_buf,nameIReg(size,gregOfRM(rm)));
780 return HI8(pair)+eip0;
781 } else {
sewardje1042472002-09-30 12:33:11 +0000782 UInt pair = disAMode ( cb, sorb, eip0, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +0000783 Int tmpa = LOW24(pair);
784 Int tmp2 = newTemp(cb);
785 uInstr2(cb, LOAD, size, TempReg, tmpa, TempReg, tmpa);
786 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmp2);
787 uInstr2(cb, opc, size, TempReg, tmpa, TempReg, tmp2);
788 setFlagsFromUOpcode(cb, opc);
789 if (keep)
790 uInstr2(cb, PUT, size, TempReg, tmp2, ArchReg, gregOfRM(rm));
791 if (dis) VG_(printf)("%s%c %s,%s\n", t_x86opc, nameISize(size),
792 dis_buf,nameIReg(size,gregOfRM(rm)));
793 return HI8(pair)+eip0;
794 }
795}
796
797
798
799/* Handle binary integer instructions of the form
800 op G, E meaning
801 op reg, reg-or-mem
802 Is passed the a ptr to the modRM byte, the actual operation, and the
803 data size. Returns the address advanced completely over this
804 instruction.
805
806 G(src) is reg.
807 E(dst) is reg-or-mem
808
809 If E is reg, --> GET %E, tmp
810 OP %G, tmp
811 PUT tmp, %E
812
813 If E is mem, --> (getAddr E) -> tmpa
814 LD (tmpa), tmpv
815 OP %G, tmpv
816 ST tmpv, (tmpa)
817*/
818static
819Addr dis_op2_G_E ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +0000820 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +0000821 Opcode opc,
822 Bool keep,
823 Int size,
824 Addr eip0,
825 Char* t_x86opc )
826{
827 UChar rm = getUChar(eip0);
828 UChar dis_buf[50];
829
830 if (epartIsReg(rm)) {
831 Int tmp = newTemp(cb);
832
833 /* Specially handle XOR reg,reg, because that doesn't really
834 depend on reg, and doing the obvious thing potentially
835 generates a spurious value check failure due to the bogus
836 dependency. */
837 if (opc == XOR && gregOfRM(rm) == eregOfRM(rm)) {
838 codegen_XOR_reg_with_itself ( cb, size, gregOfRM(rm), tmp );
839 return 1+eip0;
840 }
841
842 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, tmp);
843
844 if (opc == AND || opc == OR) {
845 Int tao = newTemp(cb);
846 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tao);
847 uInstr2(cb, opc, size, TempReg, tao, TempReg, tmp);
848 setFlagsFromUOpcode(cb, opc);
849 } else {
850 uInstr2(cb, opc, size, ArchReg, gregOfRM(rm), TempReg, tmp);
851 setFlagsFromUOpcode(cb, opc);
852 }
853 if (keep)
854 uInstr2(cb, PUT, size, TempReg, tmp, ArchReg, eregOfRM(rm));
855 if (dis) VG_(printf)("%s%c %s,%s\n", t_x86opc, nameISize(size),
856 nameIReg(size,gregOfRM(rm)),
857 nameIReg(size,eregOfRM(rm)));
858 return 1+eip0;
859 }
860
861 /* E refers to memory */
862 {
sewardje1042472002-09-30 12:33:11 +0000863 UInt pair = disAMode ( cb, sorb, eip0, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +0000864 Int tmpa = LOW24(pair);
865 Int tmpv = newTemp(cb);
866 uInstr2(cb, LOAD, size, TempReg, tmpa, TempReg, tmpv);
867
868 if (opc == AND || opc == OR) {
869 Int tao = newTemp(cb);
870 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tao);
871 uInstr2(cb, opc, size, TempReg, tao, TempReg, tmpv);
872 setFlagsFromUOpcode(cb, opc);
873 } else {
874 uInstr2(cb, opc, size, ArchReg, gregOfRM(rm), TempReg, tmpv);
875 setFlagsFromUOpcode(cb, opc);
876 }
877 if (keep) {
878 uInstr2(cb, STORE, size, TempReg, tmpv, TempReg, tmpa);
sewardjde4a1d02002-03-22 01:27:54 +0000879 }
880 if (dis) VG_(printf)("%s%c %s,%s\n", t_x86opc, nameISize(size),
881 nameIReg(size,gregOfRM(rm)), dis_buf);
882 return HI8(pair)+eip0;
883 }
884}
885
886
887/* Handle move instructions of the form
888 mov E, G meaning
889 mov reg-or-mem, reg
890 Is passed the a ptr to the modRM byte, and the data size. Returns
891 the address advanced completely over this instruction.
892
893 E(src) is reg-or-mem
894 G(dst) is reg.
895
sewardje1042472002-09-30 12:33:11 +0000896 If E is reg, --> GET %E, tmpv
sewardjde4a1d02002-03-22 01:27:54 +0000897 PUT tmpv, %G
898
899 If E is mem --> (getAddr E) -> tmpa
900 LD (tmpa), tmpb
901 PUT tmpb, %G
902*/
903static
904Addr dis_mov_E_G ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +0000905 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +0000906 Int size,
907 Addr eip0 )
908{
909 UChar rm = getUChar(eip0);
910 UChar dis_buf[50];
911
912 if (epartIsReg(rm)) {
913 Int tmpv = newTemp(cb);
914 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, tmpv);
915 uInstr2(cb, PUT, size, TempReg, tmpv, ArchReg, gregOfRM(rm));
916 if (dis) VG_(printf)("mov%c %s,%s\n", nameISize(size),
917 nameIReg(size,eregOfRM(rm)),
918 nameIReg(size,gregOfRM(rm)));
919 return 1+eip0;
920 }
921
922 /* E refers to memory */
923 {
sewardje1042472002-09-30 12:33:11 +0000924 UInt pair = disAMode ( cb, sorb, eip0, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +0000925 Int tmpa = LOW24(pair);
926 Int tmpb = newTemp(cb);
927 uInstr2(cb, LOAD, size, TempReg, tmpa, TempReg, tmpb);
928 uInstr2(cb, PUT, size, TempReg, tmpb, ArchReg, gregOfRM(rm));
929 if (dis) VG_(printf)("mov%c %s,%s\n", nameISize(size),
930 dis_buf,nameIReg(size,gregOfRM(rm)));
931 return HI8(pair)+eip0;
932 }
933}
934
935
936/* Handle move instructions of the form
937 mov G, E meaning
938 mov reg, reg-or-mem
939 Is passed the a ptr to the modRM byte, and the data size. Returns
940 the address advanced completely over this instruction.
941
942 G(src) is reg.
943 E(dst) is reg-or-mem
944
945 If E is reg, --> GET %G, tmp
946 PUT tmp, %E
947
948 If E is mem, --> (getAddr E) -> tmpa
949 GET %G, tmpv
950 ST tmpv, (tmpa)
951*/
952static
953Addr dis_mov_G_E ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +0000954 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +0000955 Int size,
956 Addr eip0 )
957{
958 UChar rm = getUChar(eip0);
959 UChar dis_buf[50];
960
961 if (epartIsReg(rm)) {
962 Int tmpv = newTemp(cb);
963 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmpv);
964 uInstr2(cb, PUT, size, TempReg, tmpv, ArchReg, eregOfRM(rm));
965 if (dis) VG_(printf)("mov%c %s,%s\n", nameISize(size),
966 nameIReg(size,gregOfRM(rm)),
967 nameIReg(size,eregOfRM(rm)));
968 return 1+eip0;
969 }
970
971 /* E refers to memory */
972 {
sewardje1042472002-09-30 12:33:11 +0000973 UInt pair = disAMode ( cb, sorb, eip0, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +0000974 Int tmpa = LOW24(pair);
975 Int tmpv = newTemp(cb);
976 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmpv);
977 uInstr2(cb, STORE, size, TempReg, tmpv, TempReg, tmpa);
sewardjde4a1d02002-03-22 01:27:54 +0000978 if (dis) VG_(printf)("mov%c %s,%s\n", nameISize(size),
979 nameIReg(size,gregOfRM(rm)), dis_buf);
980 return HI8(pair)+eip0;
981 }
982}
983
984
985/* op $immediate, AL/AX/EAX. */
986static
987Addr dis_op_imm_A ( UCodeBlock* cb,
988 Int size,
989 Opcode opc,
990 Bool keep,
991 Addr eip,
992 Char* t_x86opc )
993{
994 Int tmp = newTemp(cb);
995 UInt lit = getUDisp(size,eip);
996 uInstr2(cb, GET, size, ArchReg, R_EAX, TempReg, tmp);
997 if (opc == AND || opc == OR) {
998 Int tao = newTemp(cb);
999 uInstr2(cb, MOV, size, Literal, 0, TempReg, tao);
1000 uLiteral(cb, lit);
1001 uInstr2(cb, opc, size, TempReg, tao, TempReg, tmp);
1002 setFlagsFromUOpcode(cb, opc);
1003 } else {
1004 uInstr2(cb, opc, size, Literal, 0, TempReg, tmp);
1005 uLiteral(cb, lit);
1006 setFlagsFromUOpcode(cb, opc);
1007 }
1008 if (keep)
1009 uInstr2(cb, PUT, size, TempReg, tmp, ArchReg, R_EAX);
1010 if (dis) VG_(printf)("%s%c $0x%x, %s\n", t_x86opc, nameISize(size),
1011 lit, nameIReg(size,R_EAX));
1012 return eip+size;
1013}
1014
1015
1016/* Sign- and Zero-extending moves. */
1017static
1018Addr dis_movx_E_G ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +00001019 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +00001020 Addr eip, Int szs, Int szd, Bool sign_extend )
1021{
1022 UChar dis_buf[50];
1023 UChar rm = getUChar(eip);
1024 if (epartIsReg(rm)) {
1025 Int tmpv = newTemp(cb);
1026 uInstr2(cb, GET, szs, ArchReg, eregOfRM(rm), TempReg, tmpv);
1027 uInstr1(cb, WIDEN, szd, TempReg, tmpv);
1028 LAST_UINSTR(cb).extra4b = szs;
1029 LAST_UINSTR(cb).signed_widen = sign_extend;
1030 uInstr2(cb, PUT, szd, TempReg, tmpv, ArchReg, gregOfRM(rm));
1031 if (dis) VG_(printf)("mov%c%c%c %s,%s\n",
1032 sign_extend ? 's' : 'z',
1033 nameISize(szs), nameISize(szd),
1034 nameIReg(szs,eregOfRM(rm)),
1035 nameIReg(szd,gregOfRM(rm)));
1036 return 1+eip;
1037 }
1038
1039 /* E refers to memory */
1040 {
sewardje1042472002-09-30 12:33:11 +00001041 UInt pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +00001042 Int tmpa = LOW24(pair);
1043 uInstr2(cb, LOAD, szs, TempReg, tmpa, TempReg, tmpa);
1044 uInstr1(cb, WIDEN, szd, TempReg, tmpa);
1045 LAST_UINSTR(cb).extra4b = szs;
1046 LAST_UINSTR(cb).signed_widen = sign_extend;
1047 uInstr2(cb, PUT, szd, TempReg, tmpa, ArchReg, gregOfRM(rm));
1048 if (dis) VG_(printf)("mov%c%c%c %s,%s\n",
1049 sign_extend ? 's' : 'z',
1050 nameISize(szs), nameISize(szd),
1051 dis_buf,
1052 nameIReg(szd,gregOfRM(rm)));
1053 return HI8(pair)+eip;
1054 }
1055}
1056
1057
1058/* Generate code to divide ArchRegs EDX:EAX / DX:AX / AX by the 32 /
1059 16 / 8 bit quantity in the given TempReg. */
1060static
1061void codegen_div ( UCodeBlock* cb, Int sz, Int t, Bool signed_divide )
1062{
1063 Int helper;
1064 Int ta = newTemp(cb);
1065 Int td = newTemp(cb);
1066
1067 switch (sz) {
1068 case 4: helper = (signed_divide ? VGOFF_(helper_idiv_64_32)
1069 : VGOFF_(helper_div_64_32));
1070 break;
1071 case 2: helper = (signed_divide ? VGOFF_(helper_idiv_32_16)
1072 : VGOFF_(helper_div_32_16));
1073 break;
1074 case 1: helper = (signed_divide ? VGOFF_(helper_idiv_16_8)
1075 : VGOFF_(helper_div_16_8));
1076 break;
njne427a662002-10-02 11:08:25 +00001077 default: VG_(core_panic)("codegen_div");
sewardjde4a1d02002-03-22 01:27:54 +00001078 }
1079 uInstr0(cb, CALLM_S, 0);
1080 if (sz == 4 || sz == 2) {
1081 uInstr1(cb, PUSH, sz, TempReg, t);
1082 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
1083 uInstr1(cb, PUSH, sz, TempReg, ta);
1084 uInstr2(cb, GET, sz, ArchReg, R_EDX, TempReg, td);
1085 uInstr1(cb, PUSH, sz, TempReg, td);
1086 uInstr1(cb, CALLM, 0, Lit16, helper);
1087 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsOSZACP);
1088 uInstr1(cb, POP, sz, TempReg, t);
1089 uInstr2(cb, PUT, sz, TempReg, t, ArchReg, R_EDX);
1090 uInstr1(cb, POP, sz, TempReg, t);
1091 uInstr2(cb, PUT, sz, TempReg, t, ArchReg, R_EAX);
1092 uInstr1(cb, CLEAR, 0, Lit16, 4);
1093 } else {
1094 uInstr1(cb, PUSH, 1, TempReg, t);
1095 uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, ta);
1096 uInstr1(cb, PUSH, 2, TempReg, ta);
1097 uInstr2(cb, MOV, 1, Literal, 0, TempReg, td);
1098 uLiteral(cb, 0);
1099 uInstr1(cb, PUSH, 1, TempReg, td);
1100 uInstr1(cb, CALLM, 0, Lit16, helper);
1101 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsOSZACP);
1102 uInstr1(cb, POP, 1, TempReg, t);
1103 uInstr2(cb, PUT, 1, TempReg, t, ArchReg, R_AL);
1104 uInstr1(cb, POP, 1, TempReg, t);
1105 uInstr2(cb, PUT, 1, TempReg, t, ArchReg, R_AH);
1106 uInstr1(cb, CLEAR, 0, Lit16, 4);
1107 }
1108 uInstr0(cb, CALLM_E, 0);
1109}
1110
1111
1112static
sewardje1042472002-09-30 12:33:11 +00001113Addr dis_Grp1 ( UCodeBlock* cb,
1114 UChar sorb,
1115 Addr eip, UChar modrm,
sewardjde4a1d02002-03-22 01:27:54 +00001116 Int am_sz, Int d_sz, Int sz, UInt d32 )
1117{
1118 Int t1, t2, uopc;
1119 UInt pair;
1120 UChar dis_buf[50];
1121 if (epartIsReg(modrm)) {
1122 vg_assert(am_sz == 1);
1123 t1 = newTemp(cb);
1124 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1125 switch (gregOfRM(modrm)) {
1126 case 0: uopc = ADD; break; case 1: uopc = OR; break;
1127 case 2: uopc = ADC; break; case 3: uopc = SBB; break;
1128 case 4: uopc = AND; break; case 5: uopc = SUB; break;
1129 case 6: uopc = XOR; break; case 7: uopc = SUB; break;
njne427a662002-10-02 11:08:25 +00001130 default: VG_(core_panic)("dis_Grp1(Reg): unhandled case");
sewardjde4a1d02002-03-22 01:27:54 +00001131 }
1132 if (uopc == AND || uopc == OR) {
1133 Int tao = newTemp(cb);
1134 uInstr2(cb, MOV, sz, Literal, 0, TempReg, tao);
1135 uLiteral(cb, d32);
1136 uInstr2(cb, uopc, sz, TempReg, tao, TempReg, t1);
1137 setFlagsFromUOpcode(cb, uopc);
1138 } else {
1139 uInstr2(cb, uopc, sz, Literal, 0, TempReg, t1);
1140 uLiteral(cb, d32);
1141 setFlagsFromUOpcode(cb, uopc);
1142 }
1143 if (gregOfRM(modrm) < 7)
1144 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
1145 eip += (am_sz + d_sz);
1146 if (dis)
1147 VG_(printf)("%s%c $0x%x, %s\n",
1148 nameGrp1(gregOfRM(modrm)), nameISize(sz), d32,
1149 nameIReg(sz,eregOfRM(modrm)));
1150 } else {
sewardje1042472002-09-30 12:33:11 +00001151 pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +00001152 t1 = LOW24(pair);
1153 t2 = newTemp(cb);
1154 eip += HI8(pair);
1155 eip += d_sz;
1156 uInstr2(cb, LOAD, sz, TempReg, t1, TempReg, t2);
1157 switch (gregOfRM(modrm)) {
1158 case 0: uopc = ADD; break; case 1: uopc = OR; break;
1159 case 2: uopc = ADC; break; case 3: uopc = SBB; break;
1160 case 4: uopc = AND; break; case 5: uopc = SUB; break;
1161 case 6: uopc = XOR; break; case 7: uopc = SUB; break;
njne427a662002-10-02 11:08:25 +00001162 default: VG_(core_panic)("dis_Grp1(Mem): unhandled case");
sewardjde4a1d02002-03-22 01:27:54 +00001163 }
1164 if (uopc == AND || uopc == OR) {
1165 Int tao = newTemp(cb);
1166 uInstr2(cb, MOV, sz, Literal, 0, TempReg, tao);
1167 uLiteral(cb, d32);
1168 uInstr2(cb, uopc, sz, TempReg, tao, TempReg, t2);
1169 setFlagsFromUOpcode(cb, uopc);
1170 } else {
1171 uInstr2(cb, uopc, sz, Literal, 0, TempReg, t2);
1172 uLiteral(cb, d32);
1173 setFlagsFromUOpcode(cb, uopc);
1174 }
1175 if (gregOfRM(modrm) < 7) {
1176 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
sewardjde4a1d02002-03-22 01:27:54 +00001177 }
1178 if (dis)
1179 VG_(printf)("%s%c $0x%x, %s\n",
1180 nameGrp1(gregOfRM(modrm)), nameISize(sz), d32,
1181 dis_buf);
1182 }
1183 return eip;
1184}
1185
1186
1187/* Group 2 extended opcodes. */
1188static
sewardje1042472002-09-30 12:33:11 +00001189Addr dis_Grp2 ( UCodeBlock* cb,
1190 UChar sorb,
1191 Addr eip, UChar modrm,
sewardjde4a1d02002-03-22 01:27:54 +00001192 Int am_sz, Int d_sz, Int sz,
1193 Tag orig_src_tag, UInt orig_src_val )
1194{
1195 /* orig_src_tag and orig_src_val denote either ArchReg(%CL) or a
1196 Literal. And eip on entry points at the modrm byte. */
1197 Int t1, t2, uopc;
1198 UInt pair;
1199 UChar dis_buf[50];
1200 UInt src_val;
1201 Tag src_tag;
1202
1203 /* Get the amount to be shifted by into src_tag/src_val. */
1204 if (orig_src_tag == ArchReg) {
1205 src_val = newTemp(cb);
1206 src_tag = TempReg;
1207 uInstr2(cb, GET, 1, orig_src_tag, orig_src_val, TempReg, src_val);
1208 } else {
1209 src_val = orig_src_val;
1210 src_tag = Literal;
1211 }
1212
1213 if (epartIsReg(modrm)) {
1214 vg_assert(am_sz == 1);
1215 t1 = newTemp(cb);
1216 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1217 switch (gregOfRM(modrm)) {
1218 case 0: uopc = ROL; break; case 1: uopc = ROR; break;
1219 case 2: uopc = RCL; break; case 3: uopc = RCR; break;
1220 case 4: uopc = SHL; break; case 5: uopc = SHR; break;
1221 case 7: uopc = SAR; break;
njne427a662002-10-02 11:08:25 +00001222 default: VG_(core_panic)("dis_Grp2(Reg): unhandled case");
sewardjde4a1d02002-03-22 01:27:54 +00001223 }
1224 if (src_tag == Literal) {
1225 uInstr2(cb, uopc, sz, Literal, 0, TempReg, t1);
1226 uLiteral(cb, src_val);
1227 } else {
1228 uInstr2(cb, uopc, sz, src_tag, src_val, TempReg, t1);
1229 }
1230 setFlagsFromUOpcode(cb, uopc);
1231 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
1232 eip += (am_sz + d_sz);
1233 if (dis) {
1234 if (orig_src_tag == Literal)
1235 VG_(printf)("%s%c $0x%x, %s\n",
1236 nameGrp2(gregOfRM(modrm)), nameISize(sz),
1237 orig_src_val, nameIReg(sz,eregOfRM(modrm)));
1238 else
1239 VG_(printf)("%s%c %s, %s\n",
1240 nameGrp2(gregOfRM(modrm)), nameISize(sz),
1241 nameIReg(1,orig_src_val),
1242 nameIReg(sz,eregOfRM(modrm)));
1243 }
1244 } else {
sewardje1042472002-09-30 12:33:11 +00001245 pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +00001246 t1 = LOW24(pair);
1247 t2 = newTemp(cb);
1248 eip += HI8(pair);
1249 eip += d_sz;
1250 uInstr2(cb, LOAD, sz, TempReg, t1, TempReg, t2);
1251 switch (gregOfRM(modrm)) {
1252 case 0: uopc = ROL; break; case 1: uopc = ROR; break;
1253 case 2: uopc = RCL; break; case 3: uopc = RCR; break;
1254 case 4: uopc = SHL; break; case 5: uopc = SHR; break;
1255 case 7: uopc = SAR; break;
njne427a662002-10-02 11:08:25 +00001256 default: VG_(core_panic)("dis_Grp2(Reg): unhandled case");
sewardjde4a1d02002-03-22 01:27:54 +00001257 }
1258 if (src_tag == Literal) {
1259 uInstr2(cb, uopc, sz, Literal, 0, TempReg, t2);
1260 uLiteral(cb, src_val);
1261 } else {
1262 uInstr2(cb, uopc, sz, src_tag, src_val, TempReg, t2);
1263 }
1264 setFlagsFromUOpcode(cb, uopc);
1265 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
sewardjde4a1d02002-03-22 01:27:54 +00001266 if (dis) {
1267 if (orig_src_tag == Literal)
1268 VG_(printf)("%s%c $0x%x, %s\n",
1269 nameGrp2(gregOfRM(modrm)), nameISize(sz),
1270 orig_src_val, dis_buf);
1271 else
1272 VG_(printf)("%s%c %s, %s\n",
1273 nameGrp2(gregOfRM(modrm)), nameISize(sz),
1274 nameIReg(1,orig_src_val),
1275 dis_buf);
1276 }
1277 }
1278 return eip;
1279}
1280
1281
sewardj0ece28b2002-04-16 00:42:12 +00001282
1283/* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
sewardjde4a1d02002-03-22 01:27:54 +00001284static
sewardje1042472002-09-30 12:33:11 +00001285Addr dis_Grp8_BT ( UCodeBlock* cb,
1286 UChar sorb,
1287 Addr eip, UChar modrm,
sewardj0ece28b2002-04-16 00:42:12 +00001288 Int am_sz, Int sz, UInt src_val )
sewardjde4a1d02002-03-22 01:27:54 +00001289{
sewardj0ece28b2002-04-16 00:42:12 +00001290# define MODIFY_t2_AND_SET_CARRY_FLAG \
1291 /* t2 is the value to be op'd on. Copy to t_fetched, then \
1292 modify t2, if non-BT. */ \
1293 uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t_fetched); \
1294 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
1295 uLiteral(cb, v_mask); \
1296 switch (gregOfRM(modrm)) { \
1297 case 4: /* BT */ break; \
1298 case 5: /* BTS */ \
1299 uInstr2(cb, OR, sz, TempReg, t_mask, TempReg, t2); break; \
1300 case 6: /* BTR */ \
1301 uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t2); break; \
1302 case 7: /* BTC */ \
1303 uInstr2(cb, XOR, sz, TempReg, t_mask, TempReg, t2); break; \
1304 } \
1305 /* Copy relevant bit from t_fetched into carry flag. */ \
1306 uInstr2(cb, SHR, sz, Literal, 0, TempReg, t_fetched); \
1307 uLiteral(cb, src_val); \
1308 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
1309 uLiteral(cb, 1); \
1310 uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t_fetched); \
1311 uInstr1(cb, NEG, sz, TempReg, t_fetched); \
1312 setFlagsFromUOpcode(cb, NEG);
1313
1314
sewardjde4a1d02002-03-22 01:27:54 +00001315 /* src_val denotes a d8.
1316 And eip on entry points at the modrm byte. */
sewardj0ece28b2002-04-16 00:42:12 +00001317 Int t1, t2, t_fetched, t_mask;
sewardjde4a1d02002-03-22 01:27:54 +00001318 UInt pair;
1319 UChar dis_buf[50];
sewardj0ece28b2002-04-16 00:42:12 +00001320 UInt v_mask;
sewardjde4a1d02002-03-22 01:27:54 +00001321
sewardj0ece28b2002-04-16 00:42:12 +00001322 /* There is no 1-byte form of this instruction, AFAICS. */
1323 vg_assert(sz == 2 || sz == 4);
1324
1325 /* Limit src_val -- the bit offset -- to something within a word.
1326 The Intel docs say that literal offsets larger than a word are
1327 masked in this way. */
1328 switch (sz) {
1329 case 2: src_val &= 15; break;
1330 case 4: src_val &= 31; break;
njne427a662002-10-02 11:08:25 +00001331 default: VG_(core_panic)("dis_Grp8_BT: invalid size");
sewardjde4a1d02002-03-22 01:27:54 +00001332 }
1333
sewardj0ece28b2002-04-16 00:42:12 +00001334 /* Invent a mask suitable for the operation. */
1335
1336 switch (gregOfRM(modrm)) {
1337 case 4: /* BT */ v_mask = 0; break;
1338 case 5: /* BTS */ v_mask = 1 << src_val; break;
1339 case 6: /* BTR */ v_mask = ~(1 << src_val); break;
1340 case 7: /* BTC */ v_mask = 1 << src_val; break;
1341 /* If this needs to be extended, probably simplest to make a
1342 new function to handle the other cases (0 .. 3). The
1343 Intel docs do however not indicate any use for 0 .. 3, so
1344 we don't expect this to happen. */
njne427a662002-10-02 11:08:25 +00001345 default: VG_(core_panic)("dis_Grp8_BT");
sewardj0ece28b2002-04-16 00:42:12 +00001346 }
1347 /* Probably excessively paranoid. */
1348 if (sz == 2)
1349 v_mask &= 0x0000FFFF;
1350
1351 t1 = INVALID_TEMPREG;
1352 t_fetched = newTemp(cb);
1353 t_mask = newTemp(cb);
1354
sewardjde4a1d02002-03-22 01:27:54 +00001355 if (epartIsReg(modrm)) {
1356 vg_assert(am_sz == 1);
1357 t2 = newTemp(cb);
sewardj0ece28b2002-04-16 00:42:12 +00001358
1359 /* Fetch the value to be tested and modified. */
1360 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t2);
1361 /* Do it! */
1362 MODIFY_t2_AND_SET_CARRY_FLAG;
1363 /* Dump the result back, if non-BT. */
1364 if (gregOfRM(modrm) != 4 /* BT */)
1365 uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, eregOfRM(modrm));
1366
sewardjde4a1d02002-03-22 01:27:54 +00001367 eip += (am_sz + 1);
1368 if (dis)
1369 VG_(printf)("%s%c $0x%x, %s\n",
1370 nameGrp8(gregOfRM(modrm)), nameISize(sz),
1371 src_val,
1372 nameIReg(sz,eregOfRM(modrm)));
1373 } else {
sewardje1042472002-09-30 12:33:11 +00001374 pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +00001375 t1 = LOW24(pair);
1376 t2 = newTemp(cb);
1377 eip += HI8(pair);
1378 eip += 1;
sewardj0ece28b2002-04-16 00:42:12 +00001379
1380 /* Fetch the value to be tested and modified. */
sewardjde4a1d02002-03-22 01:27:54 +00001381 uInstr2(cb, LOAD, sz, TempReg, t1, TempReg, t2);
sewardj0ece28b2002-04-16 00:42:12 +00001382 /* Do it! */
1383 MODIFY_t2_AND_SET_CARRY_FLAG;
1384 /* Dump the result back, if non-BT. */
1385 if (gregOfRM(modrm) != 4 /* BT */) {
1386 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
sewardj0ece28b2002-04-16 00:42:12 +00001387 }
sewardjde4a1d02002-03-22 01:27:54 +00001388 if (dis)
1389 VG_(printf)("%s%c $0x%x, %s\n",
1390 nameGrp8(gregOfRM(modrm)), nameISize(sz), src_val,
1391 dis_buf);
1392 }
sewardjde4a1d02002-03-22 01:27:54 +00001393 return eip;
sewardj0ece28b2002-04-16 00:42:12 +00001394
1395# undef MODIFY_t2_AND_SET_CARRY_FLAG
sewardjde4a1d02002-03-22 01:27:54 +00001396}
sewardjde4a1d02002-03-22 01:27:54 +00001397
1398
1399
1400/* Generate ucode to multiply the value in EAX/AX/AL by the register
1401 specified by the ereg of modrm, and park the result in
1402 EDX:EAX/DX:AX/AX. */
1403static void codegen_mul_A_D_Reg ( UCodeBlock* cb, Int sz,
1404 UChar modrm, Bool signed_multiply )
1405{
1406 Int helper = signed_multiply
1407 ?
1408 (sz==1 ? VGOFF_(helper_imul_8_16)
1409 : (sz==2 ? VGOFF_(helper_imul_16_32)
1410 : VGOFF_(helper_imul_32_64)))
1411 :
1412 (sz==1 ? VGOFF_(helper_mul_8_16)
1413 : (sz==2 ? VGOFF_(helper_mul_16_32)
1414 : VGOFF_(helper_mul_32_64)));
1415 Int t1 = newTemp(cb);
1416 Int ta = newTemp(cb);
1417 uInstr0(cb, CALLM_S, 0);
1418 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1419 uInstr1(cb, PUSH, sz, TempReg, t1);
1420 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
1421 uInstr1(cb, PUSH, sz, TempReg, ta);
1422 uInstr1(cb, CALLM, 0, Lit16, helper);
1423 uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP);
1424 if (sz > 1) {
1425 uInstr1(cb, POP, sz, TempReg, t1);
1426 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EDX);
1427 uInstr1(cb, POP, sz, TempReg, t1);
1428 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EAX);
1429 } else {
1430 uInstr1(cb, CLEAR, 0, Lit16, 4);
1431 uInstr1(cb, POP, 2, TempReg, t1);
1432 uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
1433 }
1434 uInstr0(cb, CALLM_E, 0);
1435 if (dis) VG_(printf)("%s%c %s\n", signed_multiply ? "imul" : "mul",
1436 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
1437
1438}
1439
1440
1441/* Generate ucode to multiply the value in EAX/AX/AL by the value in
1442 TempReg temp, and park the result in EDX:EAX/DX:AX/AX. */
1443static void codegen_mul_A_D_Temp ( UCodeBlock* cb, Int sz,
1444 Int temp, Bool signed_multiply,
1445 UChar* dis_buf )
1446{
1447 Int helper = signed_multiply
1448 ?
1449 (sz==1 ? VGOFF_(helper_imul_8_16)
1450 : (sz==2 ? VGOFF_(helper_imul_16_32)
1451 : VGOFF_(helper_imul_32_64)))
1452 :
1453 (sz==1 ? VGOFF_(helper_mul_8_16)
1454 : (sz==2 ? VGOFF_(helper_mul_16_32)
1455 : VGOFF_(helper_mul_32_64)));
1456 Int t1 = newTemp(cb);
1457 uInstr0(cb, CALLM_S, 0);
1458 uInstr1(cb, PUSH, sz, TempReg, temp);
1459 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
1460 uInstr1(cb, PUSH, sz, TempReg, t1);
1461 uInstr1(cb, CALLM, 0, Lit16, helper);
1462 uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP);
1463 if (sz > 1) {
1464 uInstr1(cb, POP, sz, TempReg, t1);
1465 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EDX);
1466 uInstr1(cb, POP, sz, TempReg, t1);
1467 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EAX);
1468 } else {
1469 uInstr1(cb, CLEAR, 0, Lit16, 4);
1470 uInstr1(cb, POP, 2, TempReg, t1);
1471 uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
1472 }
1473 uInstr0(cb, CALLM_E, 0);
1474 if (dis) VG_(printf)("%s%c %s\n", signed_multiply ? "imul" : "mul",
1475 nameISize(sz), dis_buf);
1476}
1477
1478
1479/* Group 3 extended opcodes. */
1480static
sewardje1042472002-09-30 12:33:11 +00001481Addr dis_Grp3 ( UCodeBlock* cb,
1482 UChar sorb,
1483 Int sz, Addr eip )
sewardjde4a1d02002-03-22 01:27:54 +00001484{
1485 Int t1, t2;
1486 UInt pair, d32;
1487 UChar modrm;
1488 UChar dis_buf[50];
1489 t1 = t2 = INVALID_TEMPREG;
1490 modrm = getUChar(eip);
1491 if (epartIsReg(modrm)) {
1492 t1 = newTemp(cb);
1493 switch (gregOfRM(modrm)) {
1494 case 0: { /* TEST */
1495 Int tao = newTemp(cb);
1496 eip++; d32 = getUDisp(sz, eip); eip += sz;
1497 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1498 uInstr2(cb, MOV, sz, Literal, 0, TempReg, tao);
1499 uLiteral(cb, d32);
1500 uInstr2(cb, AND, sz, TempReg, tao, TempReg, t1);
1501 setFlagsFromUOpcode(cb, AND);
1502 if (dis)
1503 VG_(printf)("test%c $0x%x, %s\n",
1504 nameISize(sz), d32, nameIReg(sz, eregOfRM(modrm)));
1505 break;
1506 }
1507 case 2: /* NOT */
1508 eip++;
1509 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1510 uInstr1(cb, NOT, sz, TempReg, t1);
1511 setFlagsFromUOpcode(cb, NOT);
1512 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
1513 if (dis)
1514 VG_(printf)("not%c %s\n",
1515 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
1516 break;
1517 case 3: /* NEG */
1518 eip++;
1519 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1520 uInstr1(cb, NEG, sz, TempReg, t1);
1521 setFlagsFromUOpcode(cb, NEG);
1522 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
1523 if (dis)
1524 VG_(printf)("neg%c %s\n",
1525 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
1526 break;
1527 case 4: /* MUL */
1528 eip++;
1529 codegen_mul_A_D_Reg ( cb, sz, modrm, False );
1530 break;
1531 case 5: /* IMUL */
1532 eip++;
1533 codegen_mul_A_D_Reg ( cb, sz, modrm, True );
1534 break;
1535 case 6: /* DIV */
1536 eip++;
1537 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1538 codegen_div ( cb, sz, t1, False );
1539 if (dis)
1540 VG_(printf)("div%c %s\n", nameISize(sz),
1541 nameIReg(sz, eregOfRM(modrm)));
1542 break;
1543 case 7: /* IDIV */
1544 eip++;
1545 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1546 codegen_div ( cb, sz, t1, True );
1547 if (dis)
1548 VG_(printf)("idiv%c %s\n", nameISize(sz),
1549 nameIReg(sz, eregOfRM(modrm)));
1550 break;
1551 default:
1552 VG_(printf)(
1553 "unhandled Grp3(R) case %d\n", (UInt)gregOfRM(modrm));
njne427a662002-10-02 11:08:25 +00001554 VG_(core_panic)("Grp3");
sewardjde4a1d02002-03-22 01:27:54 +00001555 }
1556 } else {
sewardje1042472002-09-30 12:33:11 +00001557 pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL );
sewardjde4a1d02002-03-22 01:27:54 +00001558 t2 = LOW24(pair);
1559 t1 = newTemp(cb);
1560 eip += HI8(pair);
1561 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
1562 switch (gregOfRM(modrm)) {
1563 case 0: { /* TEST */
1564 Int tao = newTemp(cb);
1565 d32 = getUDisp(sz, eip); eip += sz;
1566 uInstr2(cb, MOV, sz, Literal, 0, TempReg, tao);
1567 uLiteral(cb, d32);
1568 uInstr2(cb, AND, sz, TempReg, tao, TempReg, t1);
1569 setFlagsFromUOpcode(cb, AND);
1570 if (dis)
1571 VG_(printf)("test%c $0x%x, %s\n",
1572 nameISize(sz), d32, dis_buf);
1573 break;
1574 }
1575 case 2: /* NOT */
1576 uInstr1(cb, NOT, sz, TempReg, t1);
1577 setFlagsFromUOpcode(cb, NOT);
1578 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00001579 if (dis)
1580 VG_(printf)("not%c %s\n", nameISize(sz), dis_buf);
1581 break;
1582 case 3: /* NEG */
1583 uInstr1(cb, NEG, sz, TempReg, t1);
1584 setFlagsFromUOpcode(cb, NEG);
1585 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00001586 if (dis)
1587 VG_(printf)("neg%c %s\n", nameISize(sz), dis_buf);
1588 break;
1589 case 4: /* MUL */
1590 codegen_mul_A_D_Temp ( cb, sz, t1, False,
1591 dis?dis_buf:NULL );
1592 break;
1593 case 5: /* IMUL */
1594 codegen_mul_A_D_Temp ( cb, sz, t1, True, dis?dis_buf:NULL );
1595 break;
1596 case 6: /* DIV */
1597 codegen_div ( cb, sz, t1, False );
1598 if (dis)
1599 VG_(printf)("div%c %s\n", nameISize(sz), dis_buf);
1600 break;
1601 case 7: /* IDIV */
1602 codegen_div ( cb, sz, t1, True );
1603 if (dis)
1604 VG_(printf)("idiv%c %s\n", nameISize(sz), dis_buf);
1605 break;
1606 default:
1607 VG_(printf)(
1608 "unhandled Grp3(M) case %d\n", (UInt)gregOfRM(modrm));
njne427a662002-10-02 11:08:25 +00001609 VG_(core_panic)("Grp3");
sewardjde4a1d02002-03-22 01:27:54 +00001610 }
1611 }
1612 return eip;
1613}
1614
1615
1616/* Group 4 extended opcodes. */
1617static
sewardje1042472002-09-30 12:33:11 +00001618Addr dis_Grp4 ( UCodeBlock* cb,
1619 UChar sorb,
1620 Addr eip )
sewardjde4a1d02002-03-22 01:27:54 +00001621{
1622 Int t1, t2;
1623 UInt pair;
1624 UChar modrm;
1625 UChar dis_buf[50];
1626 t1 = t2 = INVALID_TEMPREG;
1627
1628 modrm = getUChar(eip);
1629 if (epartIsReg(modrm)) {
1630 t1 = newTemp(cb);
1631 uInstr2(cb, GET, 1, ArchReg, eregOfRM(modrm), TempReg, t1);
1632 switch (gregOfRM(modrm)) {
1633 case 0: /* INC */
1634 uInstr1(cb, INC, 1, TempReg, t1);
1635 setFlagsFromUOpcode(cb, INC);
1636 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, eregOfRM(modrm));
1637 break;
1638 case 1: /* DEC */
1639 uInstr1(cb, DEC, 1, TempReg, t1);
1640 setFlagsFromUOpcode(cb, DEC);
1641 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, eregOfRM(modrm));
1642 break;
1643 default:
1644 VG_(printf)(
1645 "unhandled Grp4(R) case %d\n", (UInt)gregOfRM(modrm));
njne427a662002-10-02 11:08:25 +00001646 VG_(core_panic)("Grp4");
sewardjde4a1d02002-03-22 01:27:54 +00001647 }
1648 eip++;
1649 if (dis)
1650 VG_(printf)("%sb %s\n", nameGrp4(gregOfRM(modrm)),
1651 nameIReg(1, eregOfRM(modrm)));
1652 } else {
sewardje1042472002-09-30 12:33:11 +00001653 pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL );
sewardjde4a1d02002-03-22 01:27:54 +00001654 t2 = LOW24(pair);
1655 t1 = newTemp(cb);
1656 uInstr2(cb, LOAD, 1, TempReg, t2, TempReg, t1);
1657 switch (gregOfRM(modrm)) {
1658 case 0: /* INC */
1659 uInstr1(cb, INC, 1, TempReg, t1);
1660 setFlagsFromUOpcode(cb, INC);
1661 uInstr2(cb, STORE, 1, TempReg, t1, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00001662 break;
1663 case 1: /* DEC */
1664 uInstr1(cb, DEC, 1, TempReg, t1);
1665 setFlagsFromUOpcode(cb, DEC);
1666 uInstr2(cb, STORE, 1, TempReg, t1, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00001667 break;
1668 default:
1669 VG_(printf)(
1670 "unhandled Grp4(M) case %d\n", (UInt)gregOfRM(modrm));
njne427a662002-10-02 11:08:25 +00001671 VG_(core_panic)("Grp4");
sewardjde4a1d02002-03-22 01:27:54 +00001672 }
1673 eip += HI8(pair);
1674 if (dis)
1675 VG_(printf)("%sb %s\n", nameGrp4(gregOfRM(modrm)), dis_buf);
1676 }
1677 return eip;
1678}
1679
1680
1681/* Group 5 extended opcodes. */
1682static
sewardje1042472002-09-30 12:33:11 +00001683Addr dis_Grp5 ( UCodeBlock* cb,
1684 UChar sorb,
1685 Int sz, Addr eip, Bool* isEnd )
sewardjde4a1d02002-03-22 01:27:54 +00001686{
1687 Int t1, t2, t3, t4;
1688 UInt pair;
1689 UChar modrm;
1690 UChar dis_buf[50];
1691 t1 = t2 = t3 = t4 = INVALID_TEMPREG;
1692
1693 modrm = getUChar(eip);
1694 if (epartIsReg(modrm)) {
1695 t1 = newTemp(cb);
1696 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1697 switch (gregOfRM(modrm)) {
1698 case 0: /* INC */
1699 uInstr1(cb, INC, sz, TempReg, t1);
1700 setFlagsFromUOpcode(cb, INC);
1701 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
1702 break;
1703 case 1: /* DEC */
1704 uInstr1(cb, DEC, sz, TempReg, t1);
1705 setFlagsFromUOpcode(cb, DEC);
1706 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
1707 break;
1708 case 2: /* call Ev */
1709 t3 = newTemp(cb); t4 = newTemp(cb);
1710 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
1711 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t3);
1712 uLiteral(cb, 4);
1713 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
1714 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
1715 uLiteral(cb, eip+1);
1716 uInstr2(cb, STORE, 4, TempReg, t4, TempReg, t3);
sewardjde4a1d02002-03-22 01:27:54 +00001717 uInstr1(cb, JMP, 0, TempReg, t1);
1718 uCond(cb, CondAlways);
sewardj2e93c502002-04-12 11:12:52 +00001719 LAST_UINSTR(cb).jmpkind = JmpCall;
sewardjde4a1d02002-03-22 01:27:54 +00001720 *isEnd = True;
1721 break;
1722 case 4: /* jmp Ev */
1723 uInstr1(cb, JMP, 0, TempReg, t1);
1724 uCond(cb, CondAlways);
1725 *isEnd = True;
1726 break;
1727 default:
1728 VG_(printf)(
1729 "unhandled Grp5(R) case %d\n", (UInt)gregOfRM(modrm));
njne427a662002-10-02 11:08:25 +00001730 VG_(core_panic)("Grp5");
sewardjde4a1d02002-03-22 01:27:54 +00001731 }
1732 eip++;
1733 if (dis)
1734 VG_(printf)("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
1735 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
1736 } else {
sewardje1042472002-09-30 12:33:11 +00001737 pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL );
sewardjde4a1d02002-03-22 01:27:54 +00001738 t2 = LOW24(pair);
1739 t1 = newTemp(cb);
1740 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
1741 switch (gregOfRM(modrm)) {
1742 case 0: /* INC */
1743 uInstr1(cb, INC, sz, TempReg, t1);
1744 setFlagsFromUOpcode(cb, INC);
1745 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00001746 break;
1747 case 1: /* DEC */
1748 uInstr1(cb, DEC, sz, TempReg, t1);
1749 setFlagsFromUOpcode(cb, DEC);
1750 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00001751 break;
1752 case 2: /* call Ev */
1753 t3 = newTemp(cb); t4 = newTemp(cb);
1754 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
1755 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t3);
1756 uLiteral(cb, 4);
1757 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
1758 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
1759 uLiteral(cb, eip+HI8(pair));
1760 uInstr2(cb, STORE, 4, TempReg, t4, TempReg, t3);
sewardjde4a1d02002-03-22 01:27:54 +00001761 uInstr1(cb, JMP, 0, TempReg, t1);
1762 uCond(cb, CondAlways);
sewardj2e93c502002-04-12 11:12:52 +00001763 LAST_UINSTR(cb).jmpkind = JmpCall;
sewardjde4a1d02002-03-22 01:27:54 +00001764 *isEnd = True;
1765 break;
1766 case 4: /* JMP Ev */
1767 uInstr1(cb, JMP, 0, TempReg, t1);
1768 uCond(cb, CondAlways);
1769 *isEnd = True;
1770 break;
1771 case 6: /* PUSH Ev */
1772 t3 = newTemp(cb);
1773 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
1774 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t3);
1775 uLiteral(cb, sz);
1776 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
1777 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t3);
sewardjde4a1d02002-03-22 01:27:54 +00001778 break;
1779 default:
1780 VG_(printf)(
1781 "unhandled Grp5(M) case %d\n", (UInt)gregOfRM(modrm));
njne427a662002-10-02 11:08:25 +00001782 VG_(core_panic)("Grp5");
sewardjde4a1d02002-03-22 01:27:54 +00001783 }
1784 eip += HI8(pair);
1785 if (dis)
1786 VG_(printf)("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
1787 nameISize(sz), dis_buf);
1788 }
1789 return eip;
1790}
1791
1792
1793/* Template for REPE CMPS<sz>. Assumes this insn is the last one in
1794 the basic block, and so emits a jump to the next insn. */
1795static
1796void codegen_REPE_CMPS ( UCodeBlock* cb, Int sz, Addr eip, Addr eip_next )
1797{
1798 Int tc, /* ECX */
1799 td, /* EDI */ ts, /* ESI */
1800 tdv, /* (EDI) */ tsv /* (ESI) */;
1801
1802 tdv = newTemp(cb);
1803 tsv = newTemp(cb);
1804 td = newTemp(cb);
1805 ts = newTemp(cb);
1806 tc = newTemp(cb);
1807
1808 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, tc);
1809 uInstr2(cb, JIFZ, 4, TempReg, tc, Literal, 0);
1810 uLiteral(cb, eip_next);
1811 uInstr1(cb, DEC, 4, TempReg, tc);
1812 uInstr2(cb, PUT, 4, TempReg, tc, ArchReg, R_ECX);
1813
1814 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
1815 uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
1816
1817 uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tdv);
1818 uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tsv);
1819
1820 uInstr2(cb, SUB, sz, TempReg, tdv, TempReg, tsv);
1821 setFlagsFromUOpcode(cb, SUB);
1822
1823 uInstr0(cb, CALLM_S, 0);
1824 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tdv);
1825 uLiteral(cb, 0);
1826 uInstr1(cb, PUSH, 4, TempReg, tdv);
1827
1828 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
1829 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
1830
1831 uInstr1(cb, POP, 4, TempReg, tdv);
1832 uInstr0(cb, CALLM_E, 0);
1833 if (sz == 4 || sz == 2) {
1834 uInstr2(cb, SHL, 4, Literal, 0, TempReg, tdv);
1835 uLiteral(cb, sz/2);
1836 }
1837 uInstr2(cb, ADD, 4, TempReg, tdv, TempReg, td);
1838 uInstr2(cb, ADD, 4, TempReg, tdv, TempReg, ts);
1839
1840 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
1841 uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
1842
1843 uInstr1(cb, JMP, 0, Literal, 0);
1844 uLiteral(cb, eip);
1845 uCond(cb, CondZ);
1846 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
1847 uInstr1(cb, JMP, 0, Literal, 0);
1848 uLiteral(cb, eip_next);
1849 uCond(cb, CondAlways);
1850}
1851
1852
1853/* Template for REPNE SCAS<sz>. Assumes this insn is the last one in
1854 the basic block, and so emits a jump to the next insn. */
1855static
1856void codegen_REPNE_SCAS ( UCodeBlock* cb, Int sz, Addr eip, Addr eip_next )
1857{
1858 Int ta /* EAX */, tc /* ECX */, td /* EDI */, tv;
1859 ta = newTemp(cb);
1860 tc = newTemp(cb);
1861 tv = newTemp(cb);
1862 td = newTemp(cb);
1863
1864 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, tc);
1865 uInstr2(cb, JIFZ, 4, TempReg, tc, Literal, 0);
1866 uLiteral(cb, eip_next);
1867 uInstr1(cb, DEC, 4, TempReg, tc);
1868 uInstr2(cb, PUT, 4, TempReg, tc, ArchReg, R_ECX);
1869
1870 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
1871 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
1872 uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tv);
1873 /* next uinstr kills ta, but that's ok -- don't need it again */
1874 uInstr2(cb, SUB, sz, TempReg, tv, TempReg, ta);
1875 setFlagsFromUOpcode(cb, SUB);
1876
1877 uInstr0(cb, CALLM_S, 0);
1878 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tv);
1879 uLiteral(cb, 0);
1880 uInstr1(cb, PUSH, 4, TempReg, tv);
1881
1882 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
1883 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
1884
1885 uInstr1(cb, POP, 4, TempReg, tv);
1886 uInstr0(cb, CALLM_E, 0);
1887
1888 if (sz == 4 || sz == 2) {
1889 uInstr2(cb, SHL, 4, Literal, 0, TempReg, tv);
1890 uLiteral(cb, sz/2);
1891 }
1892 uInstr2(cb, ADD, 4, TempReg, tv, TempReg, td);
1893 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
1894 uInstr1(cb, JMP, 0, Literal, 0);
1895 uLiteral(cb, eip);
1896 uCond(cb, CondNZ);
1897 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
1898 uInstr1(cb, JMP, 0, Literal, 0);
1899 uLiteral(cb, eip_next);
1900 uCond(cb, CondAlways);
1901}
1902
1903
1904/* Template for REPE MOVS<sz>. Assumes this insn is the last one in
1905 the basic block, and so emits a jump to the next insn. */
1906static
1907void codegen_REPE_MOVS ( UCodeBlock* cb, Int sz, Addr eip, Addr eip_next )
1908{
1909 Int ts /* ESI */, tc /* ECX */, td /* EDI */, tv;
1910 tc = newTemp(cb);
1911 td = newTemp(cb);
1912 ts = newTemp(cb);
1913 tv = newTemp(cb);
1914
1915 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, tc);
1916 uInstr2(cb, JIFZ, 4, TempReg, tc, Literal, 0);
1917 uLiteral(cb, eip_next);
1918 uInstr1(cb, DEC, 4, TempReg, tc);
1919 uInstr2(cb, PUT, 4, TempReg, tc, ArchReg, R_ECX);
1920
1921 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
1922 uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
1923
1924 uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tv);
1925 uInstr2(cb, STORE, sz, TempReg, tv, TempReg, td);
sewardjde4a1d02002-03-22 01:27:54 +00001926
1927 uInstr0(cb, CALLM_S, 0);
1928 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tv);
1929 uLiteral(cb, 0);
1930 uInstr1(cb, PUSH, 4, TempReg, tv);
1931
1932 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
1933 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
1934
1935 uInstr1(cb, POP, 4, TempReg, tv);
1936 uInstr0(cb, CALLM_E, 0);
1937
1938 if (sz == 4 || sz == 2) {
1939 uInstr2(cb, SHL, 4, Literal, 0, TempReg, tv);
1940 uLiteral(cb, sz/2);
1941 }
1942 uInstr2(cb, ADD, 4, TempReg, tv, TempReg, td);
1943 uInstr2(cb, ADD, 4, TempReg, tv, TempReg, ts);
1944
1945 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
1946 uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
1947
1948 uInstr1(cb, JMP, 0, Literal, 0);
1949 uLiteral(cb, eip);
1950 uCond(cb, CondAlways);
1951}
1952
1953
1954/* Template for REPE STOS<sz>. Assumes this insn is the last one in
1955 the basic block, and so emits a jump to the next insn. */
1956static
1957void codegen_REPE_STOS ( UCodeBlock* cb, Int sz, Addr eip, Addr eip_next )
1958{
1959 Int ta /* EAX */, tc /* ECX */, td /* EDI */;
1960 ta = newTemp(cb);
1961 tc = newTemp(cb);
1962 td = newTemp(cb);
1963
1964 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, tc);
1965 uInstr2(cb, JIFZ, 4, TempReg, tc, Literal, 0);
1966 uLiteral(cb, eip_next);
1967 uInstr1(cb, DEC, 4, TempReg, tc);
1968 uInstr2(cb, PUT, 4, TempReg, tc, ArchReg, R_ECX);
1969
1970 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
1971 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
1972 uInstr2(cb, STORE, sz, TempReg, ta, TempReg, td);
sewardjde4a1d02002-03-22 01:27:54 +00001973
1974 uInstr0(cb, CALLM_S, 0);
1975 uInstr2(cb, MOV, 4, Literal, 0, TempReg, ta);
1976 uLiteral(cb, 0);
1977 uInstr1(cb, PUSH, 4, TempReg, ta);
1978
1979 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
1980 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
1981
1982 uInstr1(cb, POP, 4, TempReg, ta);
1983 uInstr0(cb, CALLM_E, 0);
1984
1985 if (sz == 4 || sz == 2) {
1986 uInstr2(cb, SHL, 4, Literal, 0, TempReg, ta);
1987 uLiteral(cb, sz/2);
1988 }
1989 uInstr2(cb, ADD, 4, TempReg, ta, TempReg, td);
1990 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
1991
1992 uInstr1(cb, JMP, 0, Literal, 0);
1993 uLiteral(cb, eip);
1994 uCond(cb, CondAlways);
1995}
1996
1997
1998/* Template for CMPS<sz>, _not_ preceded by a REP prefix. */
1999static
2000void codegen_CMPS ( UCodeBlock* cb, Int sz )
2001{
2002 Int td, /* EDI */ ts, /* ESI */
2003 tdv, /* (EDI) */ tsv /* (ESI) */;
2004 tdv = newTemp(cb);
2005 tsv = newTemp(cb);
2006 td = newTemp(cb);
2007 ts = newTemp(cb);
2008
2009 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
2010 uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
2011
2012 uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tdv);
2013 uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tsv);
2014
2015 uInstr2(cb, SUB, sz, TempReg, tdv, TempReg, tsv);
2016 setFlagsFromUOpcode(cb, SUB);
2017
2018 uInstr0(cb, CALLM_S, 0);
2019 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tdv);
2020 uLiteral(cb, 0);
2021 uInstr1(cb, PUSH, 4, TempReg, tdv);
2022
2023 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
2024 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
2025
2026 uInstr1(cb, POP, 4, TempReg, tdv);
2027 uInstr0(cb, CALLM_E, 0);
2028
2029 if (sz == 4 || sz == 2) {
2030 uInstr2(cb, SHL, 4, Literal, 0, TempReg, tdv);
2031 uLiteral(cb, sz/2);
2032 }
2033 uInstr2(cb, ADD, 4, TempReg, tdv, TempReg, td);
2034 uInstr2(cb, ADD, 4, TempReg, tdv, TempReg, ts);
2035
2036 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2037 uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
2038}
2039
2040
2041/* Template for MOVS<sz>, _not_ preceded by a REP prefix. */
2042static
2043void codegen_MOVS ( UCodeBlock* cb, Int sz )
2044{
2045 Int tv, /* the value being copied */
2046 td, /* EDI */ ts /* ESI */;
2047 tv = newTemp(cb);
2048 td = newTemp(cb);
2049 ts = newTemp(cb);
2050
2051 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
2052 uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
2053
2054 uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tv);
2055 uInstr2(cb, STORE, sz, TempReg, tv, TempReg, td);
sewardjde4a1d02002-03-22 01:27:54 +00002056
2057 uInstr0(cb, CALLM_S, 0);
2058 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tv);
2059 uLiteral(cb, 0);
2060 uInstr1(cb, PUSH, 4, TempReg, tv);
2061
2062 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
2063 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
2064
2065 uInstr1(cb, POP, 4, TempReg, tv);
2066 uInstr0(cb, CALLM_E, 0);
2067
2068 if (sz == 4 || sz == 2) {
2069 uInstr2(cb, SHL, 4, Literal, 0, TempReg, tv);
2070 uLiteral(cb, sz/2);
2071 }
2072 uInstr2(cb, ADD, 4, TempReg, tv, TempReg, td);
2073 uInstr2(cb, ADD, 4, TempReg, tv, TempReg, ts);
2074
2075 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2076 uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
2077}
2078
2079
2080/* Template for STOS<sz>, _not_ preceded by a REP prefix. */
2081static
2082void codegen_STOS ( UCodeBlock* cb, Int sz )
2083{
2084 Int ta /* EAX */, td /* EDI */;
2085 ta = newTemp(cb);
2086 td = newTemp(cb);
2087
2088 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
2089 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
2090 uInstr2(cb, STORE, sz, TempReg, ta, TempReg, td);
sewardjde4a1d02002-03-22 01:27:54 +00002091
2092 uInstr0(cb, CALLM_S, 0);
2093 uInstr2(cb, MOV, 4, Literal, 0, TempReg, ta);
2094 uLiteral(cb, 0);
2095 uInstr1(cb, PUSH, 4, TempReg, ta);
2096
2097 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
2098 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
2099
2100 uInstr1(cb, POP, 4, TempReg, ta);
2101 uInstr0(cb, CALLM_E, 0);
2102
2103 if (sz == 4 || sz == 2) {
2104 uInstr2(cb, SHL, 4, Literal, 0, TempReg, ta);
2105 uLiteral(cb, sz/2);
2106 }
2107 uInstr2(cb, ADD, 4, TempReg, ta, TempReg, td);
2108 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2109}
2110
2111
2112/* Template for LODS<sz>, _not_ preceded by a REP prefix. */
2113static
2114void codegen_LODS ( UCodeBlock* cb, Int sz )
2115{
2116 Int ta /* EAX */, ts /* ESI */;
2117 ta = newTemp(cb);
2118 ts = newTemp(cb);
2119
2120 uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
2121 uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, ta);
2122 uInstr2(cb, PUT, sz, TempReg, ta, ArchReg, R_EAX);
2123
2124 uInstr0(cb, CALLM_S, 0);
2125 uInstr2(cb, MOV, 4, Literal, 0, TempReg, ta);
2126 uLiteral(cb, 0);
2127 uInstr1(cb, PUSH, 4, TempReg, ta);
2128
2129 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
2130 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
2131
2132 uInstr1(cb, POP, 4, TempReg, ta);
2133 uInstr0(cb, CALLM_E, 0);
2134
2135 if (sz == 4 || sz == 2) {
2136 uInstr2(cb, SHL, 4, Literal, 0, TempReg, ta);
2137 uLiteral(cb, sz/2);
2138 }
2139 uInstr2(cb, ADD, 4, TempReg, ta, TempReg, ts);
2140 uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
2141}
2142
2143
2144/* Template for REPNE SCAS<sz>, _not_ preceded by a REP prefix. */
2145static
2146void codegen_SCAS ( UCodeBlock* cb, Int sz )
2147{
2148 Int ta /* EAX */, td /* EDI */, tv;
2149 ta = newTemp(cb);
2150 tv = newTemp(cb);
2151 td = newTemp(cb);
2152
2153 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
2154 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
2155 uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tv);
2156 /* next uinstr kills ta, but that's ok -- don't need it again */
2157 uInstr2(cb, SUB, sz, TempReg, tv, TempReg, ta);
2158 setFlagsFromUOpcode(cb, SUB);
2159
2160 uInstr0(cb, CALLM_S, 0);
2161 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tv);
2162 uLiteral(cb, 0);
2163 uInstr1(cb, PUSH, 4, TempReg, tv);
2164
2165 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
2166 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
2167
2168 uInstr1(cb, POP, 4, TempReg, tv);
2169 uInstr0(cb, CALLM_E, 0);
2170
2171 if (sz == 4 || sz == 2) {
2172 uInstr2(cb, SHL, 4, Literal, 0, TempReg, tv);
2173 uLiteral(cb, sz/2);
2174 }
2175 uInstr2(cb, ADD, 4, TempReg, tv, TempReg, td);
2176 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2177}
2178
2179
2180/* (I)MUL E, G. Supplied eip points to the modR/M byte. */
2181static
2182Addr dis_mul_E_G ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +00002183 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +00002184 Int size,
2185 Addr eip0,
2186 Bool signed_multiply )
2187{
2188 Int ta, tg, te, helper;
2189 UChar dis_buf[50];
2190 UChar rm = getUChar(eip0);
2191 ta = INVALID_TEMPREG;
2192 te = newTemp(cb);
2193 tg = newTemp(cb);
2194
2195 switch (size) {
2196 case 4: helper = signed_multiply ? VGOFF_(helper_imul_32_64)
2197 : VGOFF_(helper_mul_32_64);
2198 break;
2199 case 2: helper = signed_multiply ? VGOFF_(helper_imul_16_32)
2200 : VGOFF_(helper_mul_16_32);
2201 break;
2202 case 1: helper = signed_multiply ? VGOFF_(helper_imul_8_16)
2203 : VGOFF_(helper_mul_8_16);
2204 break;
njne427a662002-10-02 11:08:25 +00002205 default: VG_(core_panic)("dis_mul_E_G");
sewardjde4a1d02002-03-22 01:27:54 +00002206 }
2207
2208 uInstr0(cb, CALLM_S, 0);
2209 if (epartIsReg(rm)) {
2210 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, te);
2211 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tg);
2212 uInstr1(cb, PUSH, size, TempReg, te);
2213 uInstr1(cb, PUSH, size, TempReg, tg);
2214 uInstr1(cb, CALLM, 0, Lit16, helper);
2215 uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP);
2216 uInstr1(cb, CLEAR, 0, Lit16, 4);
2217 uInstr1(cb, POP, size, TempReg, tg);
2218 uInstr2(cb, PUT, size, TempReg, tg, ArchReg, gregOfRM(rm));
2219 uInstr0(cb, CALLM_E, 0);
2220 if (dis) VG_(printf)("%smul%c %s, %s\n",
2221 signed_multiply ? "i" : "",
2222 nameISize(size),
2223 nameIReg(size,eregOfRM(rm)),
2224 nameIReg(size,gregOfRM(rm)));
2225 return 1+eip0;
2226 } else {
sewardje1042472002-09-30 12:33:11 +00002227 UInt pair = disAMode ( cb, sorb, eip0, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +00002228 ta = LOW24(pair);
2229 uInstr2(cb, LOAD, size, TempReg, ta, TempReg, te);
2230 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tg);
2231 uInstr1(cb, PUSH, size, TempReg, te);
2232 uInstr1(cb, PUSH, size, TempReg, tg);
2233 uInstr1(cb, CALLM, 0, Lit16, helper);
2234 uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP);
2235 uInstr1(cb, CLEAR, 0, Lit16, 4);
2236 uInstr1(cb, POP, size, TempReg, tg);
2237 uInstr2(cb, PUT, size, TempReg, tg, ArchReg, gregOfRM(rm));
2238 uInstr0(cb, CALLM_E, 0);
2239 if (dis) VG_(printf)("%smul%c %s, %s\n",
2240 signed_multiply ? "i" : "",
2241 nameISize(size),
2242 dis_buf,nameIReg(size,gregOfRM(rm)));
2243 return HI8(pair)+eip0;
2244 }
2245}
2246
2247
2248/* IMUL I * E -> G. Supplied eip points to the modR/M byte. */
2249static
2250Addr dis_imul_I_E_G ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +00002251 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +00002252 Int size,
2253 Addr eip,
2254 Int litsize )
2255{
2256 Int ta, te, tl, helper, d32;
2257 UChar dis_buf[50];
2258 UChar rm = getUChar(eip);
2259 ta = INVALID_TEMPREG;
2260 te = newTemp(cb);
2261 tl = newTemp(cb);
2262
2263 switch (size) {
2264 case 4: helper = VGOFF_(helper_imul_32_64); break;
2265 case 2: helper = VGOFF_(helper_imul_16_32); break;
2266 case 1: helper = VGOFF_(helper_imul_8_16); break;
njne427a662002-10-02 11:08:25 +00002267 default: VG_(core_panic)("dis_imul_I_E_G");
sewardjde4a1d02002-03-22 01:27:54 +00002268 }
2269
2270 uInstr0(cb, CALLM_S, 0);
2271 if (epartIsReg(rm)) {
2272 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, te);
2273 uInstr1(cb, PUSH, size, TempReg, te);
2274 eip++;
2275 } else {
sewardje1042472002-09-30 12:33:11 +00002276 UInt pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +00002277 ta = LOW24(pair);
2278 uInstr2(cb, LOAD, size, TempReg, ta, TempReg, te);
2279 uInstr1(cb, PUSH, size, TempReg, te);
2280 eip += HI8(pair);
2281 }
2282
2283 d32 = getSDisp(litsize,eip);
2284 eip += litsize;
2285
2286 uInstr2(cb, MOV, size, Literal, 0, TempReg, tl);
2287 uLiteral(cb, d32);
2288 uInstr1(cb, PUSH, size, TempReg, tl);
2289 uInstr1(cb, CALLM, 0, Lit16, helper);
2290 uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP);
2291 uInstr1(cb, CLEAR, 0, Lit16, 4);
2292 uInstr1(cb, POP, size, TempReg, te);
2293 uInstr2(cb, PUT, size, TempReg, te, ArchReg, gregOfRM(rm));
2294 uInstr0(cb, CALLM_E, 0);
2295
2296 if (dis) {
2297 if (epartIsReg(rm)) {
2298 VG_(printf)("imul %d, %s, %s\n", d32, nameIReg(size,eregOfRM(rm)),
2299 nameIReg(size,gregOfRM(rm)));
2300 } else {
2301 VG_(printf)("imul %d, %s, %s\n", d32, dis_buf,
2302 nameIReg(size,gregOfRM(rm)));
2303 }
2304 }
2305
2306 return eip;
2307}
2308
2309
2310/* Handle FPU insns which read/write memory. On entry, eip points to
2311 the second byte of the insn (the one following D8 .. DF). */
2312static
sewardje1042472002-09-30 12:33:11 +00002313Addr dis_fpu_mem ( UCodeBlock* cb,
2314 UChar sorb,
2315 Int size, Bool is_write,
sewardjde4a1d02002-03-22 01:27:54 +00002316 Addr eip, UChar first_byte )
2317{
2318 Int ta;
2319 UInt pair;
2320 UChar dis_buf[50];
2321 UChar second_byte = getUChar(eip);
2322 vg_assert(second_byte < 0xC0);
2323 second_byte &= 0x38;
sewardje1042472002-09-30 12:33:11 +00002324 pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL );
sewardjde4a1d02002-03-22 01:27:54 +00002325 ta = LOW24(pair);
2326 eip += HI8(pair);
2327 uInstr2(cb, is_write ? FPU_W : FPU_R, size,
2328 Lit16,
2329 (((UShort)first_byte) << 8) | ((UShort)second_byte),
2330 TempReg, ta);
sewardjde4a1d02002-03-22 01:27:54 +00002331 if (dis) {
2332 if (is_write)
2333 VG_(printf)("fpu_w_%d 0x%x:0x%x, %s\n",
2334 size, (UInt)first_byte,
2335 (UInt)second_byte, dis_buf );
2336 else
2337 VG_(printf)("fpu_r_%d %s, 0x%x:0x%x\n",
2338 size, dis_buf,
2339 (UInt)first_byte,
2340 (UInt)second_byte );
2341 }
2342 return eip;
2343}
2344
2345
2346/* Handle FPU insns which don't reference memory. On entry, eip points to
2347 the second byte of the insn (the one following D8 .. DF). */
2348static
2349Addr dis_fpu_no_mem ( UCodeBlock* cb, Addr eip, UChar first_byte )
2350{
sewardj4a7456e2002-03-24 13:52:19 +00002351 Bool sets_ZCP = False;
sewardj8d32be72002-04-18 02:18:24 +00002352 Bool uses_ZCP = False;
sewardjde4a1d02002-03-22 01:27:54 +00002353 UChar second_byte = getUChar(eip); eip++;
2354 vg_assert(second_byte >= 0xC0);
sewardj4a7456e2002-03-24 13:52:19 +00002355
sewardj8d32be72002-04-18 02:18:24 +00002356 /* Does the insn write any integer condition codes (%EIP) ? */
2357
sewardj4a7456e2002-03-24 13:52:19 +00002358 if (first_byte == 0xDB && second_byte >= 0xF0 && second_byte <= 0xF7) {
2359 /* FCOMI */
2360 sets_ZCP = True;
2361 } else
2362 if (first_byte == 0xDF && second_byte >= 0xF0 && second_byte <= 0xF7) {
2363 /* FCOMIP */
2364 sets_ZCP = True;
2365 } else
2366 if (first_byte == 0xDB && second_byte >= 0xE8 && second_byte <= 0xEF) {
2367 /* FUCOMI */
2368 sets_ZCP = True;
2369 } else
2370 if (first_byte == 0xDF && second_byte >= 0xE8 && second_byte <= 0xEF) {
2371 /* FUCOMIP */
2372 sets_ZCP = True;
2373 }
2374
sewardj8d32be72002-04-18 02:18:24 +00002375 /* Dually, does the insn read any integer condition codes (%EIP) ? */
2376
2377 if (first_byte == 0xDA && second_byte >= 0xC0 && second_byte <= 0xDF) {
2378 /* FCMOVB %st(n), %st(0)
2379 FCMOVE %st(n), %st(0)
2380 FCMOVBE %st(n), %st(0)
2381 FCMOVU %st(n), %st(0)
2382 */
2383 uses_ZCP = True;
2384 } else
2385 if (first_byte == 0xDB && second_byte >= 0xC0 && second_byte <= 0xDF) {
2386 /* FCMOVNB %st(n), %st(0)
2387 FCMOVNE %st(n), %st(0)
2388 FCMOVNBE %st(n), %st(0)
2389 FCMOVNU %st(n), %st(0)
2390 */
2391 uses_ZCP = True;
2392 }
2393
sewardjde4a1d02002-03-22 01:27:54 +00002394 uInstr1(cb, FPU, 0,
2395 Lit16,
2396 (((UShort)first_byte) << 8) | ((UShort)second_byte)
2397 );
sewardj8d32be72002-04-18 02:18:24 +00002398 if (uses_ZCP) {
2399 /* VG_(printf)("!!! --- FPU insn which reads %EFLAGS\n"); */
2400 uFlagsRWU(cb, FlagsZCP, FlagsEmpty, FlagsEmpty);
2401 vg_assert(!sets_ZCP);
2402 }
sewardj4a7456e2002-03-24 13:52:19 +00002403 if (sets_ZCP) {
2404 /* VG_(printf)("!!! --- FPU insn which writes %EFLAGS\n"); */
2405 uFlagsRWU(cb, FlagsEmpty, FlagsZCP, FlagsEmpty);
sewardj8d32be72002-04-18 02:18:24 +00002406 vg_assert(!uses_ZCP);
sewardj4a7456e2002-03-24 13:52:19 +00002407 }
2408
sewardj8d32be72002-04-18 02:18:24 +00002409 if (dis) VG_(printf)("fpu 0x%x:0x%x%s%s\n",
sewardj4a7456e2002-03-24 13:52:19 +00002410 (UInt)first_byte, (UInt)second_byte,
sewardj8d32be72002-04-18 02:18:24 +00002411 uses_ZCP ? " -rZCP" : "",
sewardj4a7456e2002-03-24 13:52:19 +00002412 sets_ZCP ? " -wZCP" : "" );
sewardjde4a1d02002-03-22 01:27:54 +00002413 return eip;
2414}
2415
2416
2417/* Top-level handler for all FPU insns. On entry, eip points to the
2418 second byte of the insn. */
2419static
sewardje1042472002-09-30 12:33:11 +00002420Addr dis_fpu ( UCodeBlock* cb,
2421 UChar sorb,
2422 UChar first_byte, Addr eip )
sewardjde4a1d02002-03-22 01:27:54 +00002423{
2424 const Bool rd = False;
2425 const Bool wr = True;
2426 UChar second_byte = getUChar(eip);
2427
2428 /* Handle FSTSW %ax specially. */
2429 if (first_byte == 0xDF && second_byte == 0xE0) {
2430 Int t1 = newTemp(cb);
2431 uInstr0(cb, CALLM_S, 0);
2432 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
2433 uLiteral(cb, 0);
2434 uInstr1(cb, PUSH, 4, TempReg, t1);
2435 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_fstsw_AX) );
2436 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
2437 uInstr1(cb, POP, 2, TempReg, t1);
2438 uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
2439 uInstr0(cb, CALLM_E, 0);
2440 if (dis) VG_(printf)("fstsw %%ax\n");
2441 eip++;
2442 return eip;
2443 }
2444
2445 /* Handle all non-memory FPU ops simply. */
2446 if (second_byte >= 0xC0)
2447 return dis_fpu_no_mem ( cb, eip, first_byte );
2448
2449 /* The insn references memory; need to determine
2450 whether it reads or writes, and at what size. */
2451 switch (first_byte) {
2452
2453 case 0xD8:
2454 switch ((second_byte >> 3) & 7) {
2455 case 0: /* FADDs */
2456 case 1: /* FMULs */
2457 case 2: /* FCOMs */
2458 case 3: /* FCOMPs */
2459 case 4: /* FSUBs */
2460 case 5: /* FSUBRs */
2461 case 6: /* FDIVs */
2462 case 7: /* FDIVRs */
sewardje1042472002-09-30 12:33:11 +00002463 return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002464 default:
2465 goto unhandled;
2466 }
2467 break;
2468
2469 case 0xD9:
2470 switch ((second_byte >> 3) & 7) {
2471 case 0: /* FLDs */
sewardje1042472002-09-30 12:33:11 +00002472 return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002473 case 2: /* FSTs */
2474 case 3: /* FSTPs */
sewardje1042472002-09-30 12:33:11 +00002475 return dis_fpu_mem(cb, sorb, 4, wr, eip, first_byte);
sewardj35a916c2002-07-23 18:48:39 +00002476 case 4: /* FLDENV */
sewardje1042472002-09-30 12:33:11 +00002477 return dis_fpu_mem(cb, sorb, 28, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002478 case 5: /* FLDCW */
sewardje1042472002-09-30 12:33:11 +00002479 return dis_fpu_mem(cb, sorb, 2, rd, eip, first_byte);
sewardj2a8141a2002-07-13 12:27:12 +00002480 case 6: /* FNSTENV */
sewardje1042472002-09-30 12:33:11 +00002481 return dis_fpu_mem(cb, sorb, 28, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002482 case 7: /* FSTCW */
2483 /* HACK! FSTCW actually writes 2 bytes, not 4. glibc
2484 gets lots of moaning in __floor() if we do the right
2485 thing here. */
2486 /* Later ... hack disabled .. we do do the Right Thing. */
sewardje1042472002-09-30 12:33:11 +00002487 return dis_fpu_mem(cb, sorb, /*4*/ 2, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002488 default:
2489 goto unhandled;
2490 }
2491 break;
2492
2493 case 0xDA:
2494 switch ((second_byte >> 3) & 7) {
2495 case 0: /* FIADD */
2496 case 1: /* FIMUL */
2497 case 2: /* FICOM */
2498 case 3: /* FICOMP */
2499 case 4: /* FISUB */
2500 case 5: /* FISUBR */
2501 case 6: /* FIDIV */
2502 case 7: /* FIDIVR */
sewardje1042472002-09-30 12:33:11 +00002503 return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002504 default:
2505 goto unhandled;
2506 }
2507 break;
2508
2509 case 0xDB:
2510 switch ((second_byte >> 3) & 7) {
2511 case 0: /* FILD dword-integer */
sewardje1042472002-09-30 12:33:11 +00002512 return dis_fpu_mem(cb, sorb, 4, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002513 case 2: /* FIST dword-integer */
sewardje1042472002-09-30 12:33:11 +00002514 return dis_fpu_mem(cb, sorb, 4, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002515 case 3: /* FISTPl */
sewardje1042472002-09-30 12:33:11 +00002516 return dis_fpu_mem(cb, sorb, 4, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002517 case 5: /* FLD extended-real */
sewardje1042472002-09-30 12:33:11 +00002518 return dis_fpu_mem(cb, sorb, 10, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002519 case 7: /* FSTP extended-real */
sewardje1042472002-09-30 12:33:11 +00002520 return dis_fpu_mem(cb, sorb, 10, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002521 default:
2522 goto unhandled;
2523 }
2524 break;
2525
2526 case 0xDC:
2527 switch ((second_byte >> 3) & 7) {
2528 case 0: /* FADD double-real */
2529 case 1: /* FMUL double-real */
2530 case 2: /* FCOM double-real */
2531 case 3: /* FCOMP double-real */
2532 case 4: /* FSUB double-real */
2533 case 5: /* FSUBR double-real */
2534 case 6: /* FDIV double-real */
2535 case 7: /* FDIVR double-real */
sewardje1042472002-09-30 12:33:11 +00002536 return dis_fpu_mem(cb, sorb, 8, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002537 default:
2538 goto unhandled;
2539 }
2540 break;
2541
2542 case 0xDD:
2543 switch ((second_byte >> 3) & 7) {
2544 case 0: /* FLD double-real */
sewardje1042472002-09-30 12:33:11 +00002545 return dis_fpu_mem(cb, sorb, 8, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002546 case 2: /* FST double-real */
2547 case 3: /* FSTP double-real */
sewardje1042472002-09-30 12:33:11 +00002548 return dis_fpu_mem(cb, sorb, 8, wr, eip, first_byte);
njn25e49d8e72002-09-23 09:36:25 +00002549 case 4: /* FRSTOR */
sewardje1042472002-09-30 12:33:11 +00002550 return dis_fpu_mem(cb, sorb, 108, rd, eip, first_byte);
njn25e49d8e72002-09-23 09:36:25 +00002551 case 6: /* FSAVE */
sewardje1042472002-09-30 12:33:11 +00002552 return dis_fpu_mem(cb, sorb, 108, wr, eip, first_byte);
njn25e49d8e72002-09-23 09:36:25 +00002553 case 7: /* FSTSW */
sewardje1042472002-09-30 12:33:11 +00002554 return dis_fpu_mem(cb, sorb, 2, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002555 default:
2556 goto unhandled;
2557 }
2558 break;
2559
2560 case 0xDF:
2561 switch ((second_byte >> 3) & 7) {
2562 case 0: /* FILD word-integer */
sewardje1042472002-09-30 12:33:11 +00002563 return dis_fpu_mem(cb, sorb, 2, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002564 case 2: /* FIST word-integer */
sewardje1042472002-09-30 12:33:11 +00002565 return dis_fpu_mem(cb, sorb, 2, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002566 case 3: /* FISTP word-integer */
sewardje1042472002-09-30 12:33:11 +00002567 return dis_fpu_mem(cb, sorb, 2, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002568 case 5: /* FILD qword-integer */
sewardje1042472002-09-30 12:33:11 +00002569 return dis_fpu_mem(cb, sorb, 8, rd, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002570 case 7: /* FISTP qword-integer */
sewardje1042472002-09-30 12:33:11 +00002571 return dis_fpu_mem(cb, sorb, 8, wr, eip, first_byte);
sewardjde4a1d02002-03-22 01:27:54 +00002572 default:
2573 goto unhandled;
2574 }
2575 break;
2576
2577 default: goto unhandled;
2578 }
2579
2580 unhandled:
2581 VG_(printf)("dis_fpu: unhandled memory case 0x%2x:0x%2x(%d)\n",
2582 (UInt)first_byte, (UInt)second_byte,
2583 (UInt)((second_byte >> 3) & 7) );
njne427a662002-10-02 11:08:25 +00002584 VG_(core_panic)("dis_fpu: unhandled opcodes");
sewardjde4a1d02002-03-22 01:27:54 +00002585}
2586
2587
2588/* Double length left shifts. Apparently only required in v-size (no
2589 b- variant). */
2590static
sewardje1042472002-09-30 12:33:11 +00002591Addr dis_SHLRD_Gv_Ev ( UCodeBlock* cb,
2592 UChar sorb,
2593 Addr eip, UChar modrm,
sewardjde4a1d02002-03-22 01:27:54 +00002594 Int sz,
2595 Tag amt_tag, UInt amt_val,
2596 Bool left_shift )
2597{
2598 /* amt_tag and amt_val denote either ArchReg(%CL) or a Literal.
2599 And eip on entry points at the modrm byte. */
2600 Int t, t1, t2, ta, helper;
2601 UInt pair;
2602 UChar dis_buf[50];
2603
2604 vg_assert(sz == 2 || sz == 4);
2605
2606 helper = left_shift
2607 ? (sz==4 ? VGOFF_(helper_shldl)
2608 : VGOFF_(helper_shldw))
2609 : (sz==4 ? VGOFF_(helper_shrdl)
2610 : VGOFF_(helper_shrdw));
2611
2612 /* Get the amount to be shifted by onto the stack. */
2613 t = newTemp(cb);
2614 t1 = newTemp(cb);
2615 t2 = newTemp(cb);
2616 if (amt_tag == ArchReg) {
2617 vg_assert(amt_val == R_CL);
2618 uInstr2(cb, GET, 1, ArchReg, amt_val, TempReg, t);
2619 } else {
2620 uInstr2(cb, MOV, 1, Literal, 0, TempReg, t);
2621 uLiteral(cb, amt_val);
2622 }
2623
2624 uInstr0(cb, CALLM_S, 0);
2625 uInstr1(cb, PUSH, 1, TempReg, t);
2626
2627 /* The E-part is the destination; this is shifted. The G-part
2628 supplies bits to be shifted into the E-part, but is not
2629 changed. */
2630
2631 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t1);
2632 uInstr1(cb, PUSH, sz, TempReg, t1);
2633
2634 if (epartIsReg(modrm)) {
2635 eip++;
2636 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t2);
2637 uInstr1(cb, PUSH, sz, TempReg, t2);
2638 uInstr1(cb, CALLM, 0, Lit16, helper);
2639 uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
2640 uInstr1(cb, POP, sz, TempReg, t);
2641 uInstr2(cb, PUT, sz, TempReg, t, ArchReg, eregOfRM(modrm));
2642 if (dis)
2643 VG_(printf)("shld%c %%cl, %s, %s\n",
2644 nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
2645 nameIReg(sz, eregOfRM(modrm)));
2646 } else {
sewardje1042472002-09-30 12:33:11 +00002647 pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL );
sewardjde4a1d02002-03-22 01:27:54 +00002648 ta = LOW24(pair);
2649 eip += HI8(pair);
2650 uInstr2(cb, LOAD, sz, TempReg, ta, TempReg, t2);
2651 uInstr1(cb, PUSH, sz, TempReg, t2);
2652 uInstr1(cb, CALLM, 0, Lit16, helper);
2653 uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
2654 uInstr1(cb, POP, sz, TempReg, t);
2655 uInstr2(cb, STORE, sz, TempReg, t, TempReg, ta);
sewardjde4a1d02002-03-22 01:27:54 +00002656 if (dis)
2657 VG_(printf)("shld%c %%cl, %s, %s\n",
2658 nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
2659 dis_buf);
2660 }
2661
2662 if (amt_tag == Literal) eip++;
2663 uInstr1(cb, CLEAR, 0, Lit16, 8);
2664
2665 uInstr0(cb, CALLM_E, 0);
2666 return eip;
2667}
2668
2669
2670/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
2671 required. */
2672
2673typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
2674
2675static Char* nameBtOp ( BtOp op )
2676{
2677 switch (op) {
2678 case BtOpNone: return "";
2679 case BtOpSet: return "s";
2680 case BtOpReset: return "r";
2681 case BtOpComp: return "c";
njne427a662002-10-02 11:08:25 +00002682 default: VG_(core_panic)("nameBtOp");
sewardjde4a1d02002-03-22 01:27:54 +00002683 }
2684}
2685
sewardj7f2a8bf2002-04-15 14:35:28 +00002686
2687static
sewardje1042472002-09-30 12:33:11 +00002688Addr dis_bt_G_E ( UCodeBlock* cb,
2689 UChar sorb,
2690 Int sz, Addr eip, BtOp op )
sewardj7f2a8bf2002-04-15 14:35:28 +00002691{
2692 UInt pair;
2693 UChar dis_buf[50];
2694 UChar modrm;
2695
2696 Int t_addr, t_bitno, t_mask, t_fetched, t_esp, temp, lit;
2697
2698 /* 2 and 4 are actually possible. */
2699 vg_assert(sz == 2 || sz == 4);
2700 /* We only handle 4. */
2701 vg_assert(sz == 4);
2702
2703 t_addr = t_bitno = t_mask
2704 = t_fetched = t_esp = temp = INVALID_TEMPREG;
2705
2706 t_fetched = newTemp(cb);
2707 t_bitno = newTemp(cb);
2708 temp = newTemp(cb);
2709 lit = newTemp(cb);
2710
2711 modrm = getUChar(eip);
2712
2713 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t_bitno);
2714
2715 if (epartIsReg(modrm)) {
2716 eip++;
2717 /* Get it onto the client's stack. */
2718 t_esp = newTemp(cb);
2719 t_addr = newTemp(cb);
2720 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t_esp);
2721 uInstr2(cb, SUB, sz, Literal, 0, TempReg, t_esp);
2722 uLiteral(cb, sz);
2723 uInstr2(cb, PUT, 4, TempReg, t_esp, ArchReg, R_ESP);
2724 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, temp);
2725 uInstr2(cb, STORE, sz, TempReg, temp, TempReg, t_esp);
2726 /* Make ta point at it. */
2727 uInstr2(cb, MOV, 4, TempReg, t_esp, TempReg, t_addr);
2728 /* Mask out upper bits of the shift amount, since we're doing a
2729 reg. */
2730 uInstr2(cb, MOV, 4, Literal, 0, TempReg, lit);
2731 uLiteral(cb, sz == 4 ? 31 : 15);
2732 uInstr2(cb, AND, 4, TempReg, lit, TempReg, t_bitno);
2733 } else {
sewardje1042472002-09-30 12:33:11 +00002734 pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL );
sewardj7f2a8bf2002-04-15 14:35:28 +00002735 t_addr = LOW24(pair);
2736 eip += HI8(pair);
2737 }
2738
2739 /* At this point: ta points to the address being operated on. If
2740 it was a reg, we will have pushed it onto the client's stack.
2741 t_bitno is the bit number, suitable masked in the case of a reg. */
2742
2743 /* Now the main sequence. */
2744
2745 uInstr2(cb, MOV, 4, TempReg, t_bitno, TempReg, temp);
2746 uInstr2(cb, SAR, 4, Literal, 0, TempReg, temp);
2747 uLiteral(cb, 3);
2748 uInstr2(cb, ADD, 4, TempReg, temp, TempReg, t_addr);
2749 /* ta now holds effective address */
2750
2751 uInstr2(cb, MOV, 4, Literal, 0, TempReg, lit);
2752 uLiteral(cb, 7);
2753 uInstr2(cb, AND, 4, TempReg, lit, TempReg, t_bitno);
2754 /* bitno contains offset of bit within byte */
2755
2756 if (op != BtOpNone) {
2757 t_mask = newTemp(cb);
2758 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_mask);
2759 uLiteral(cb, 1);
2760 uInstr2(cb, SHL, 4, TempReg, t_bitno, TempReg, t_mask);
2761 }
2762 /* mask is now a suitable byte mask */
2763
2764 uInstr2(cb, LOAD, 1, TempReg, t_addr, TempReg, t_fetched);
2765 if (op != BtOpNone) {
2766 uInstr2(cb, MOV, 4, TempReg, t_fetched, TempReg, temp);
2767 switch (op) {
2768 case BtOpSet:
2769 uInstr2(cb, OR, 4, TempReg, t_mask, TempReg, temp);
2770 break;
2771 case BtOpComp:
2772 uInstr2(cb, XOR, 4, TempReg, t_mask, TempReg, temp);
2773 break;
2774 case BtOpReset:
2775 uInstr1(cb, NOT, 4, TempReg, t_mask);
2776 uInstr2(cb, AND, 4, TempReg, t_mask, TempReg, temp);
2777 break;
2778 default:
njne427a662002-10-02 11:08:25 +00002779 VG_(core_panic)("dis_bt_G_E");
sewardj7f2a8bf2002-04-15 14:35:28 +00002780 }
2781 uInstr2(cb, STORE, 1, TempReg, temp, TempReg, t_addr);
2782 }
2783
2784 /* Side effect done; now get selected bit into Carry flag */
2785
2786 uInstr2(cb, SHR, 4, TempReg, t_bitno, TempReg, t_fetched);
2787 /* at bit 0 of fetched */
2788
2789 uInstr2(cb, MOV, 4, Literal, 0, TempReg, lit);
2790 uLiteral(cb, 1);
2791 uInstr2(cb, AND, 4, TempReg, lit, TempReg, t_fetched);
2792 /* fetched is now 1 or 0 */
2793
2794 /* NEG is a handy way to convert zero/nonzero into the carry
2795 flag. */
2796 uInstr1(cb, NEG, 4, TempReg, t_fetched);
2797 setFlagsFromUOpcode(cb, NEG);
2798 /* fetched is now in carry flag */
2799
2800 /* Move reg operand from stack back to reg */
2801 if (epartIsReg(modrm)) {
2802 /* t_esp still points at it. */
2803 uInstr2(cb, LOAD, sz, TempReg, t_esp, TempReg, temp);
2804 uInstr2(cb, PUT, sz, TempReg, temp, ArchReg, eregOfRM(modrm));
2805 uInstr2(cb, ADD, sz, Literal, 0, TempReg, t_esp);
2806 uLiteral(cb, sz);
2807 uInstr2(cb, PUT, 4, TempReg, t_esp, ArchReg, R_ESP);
2808 }
2809
2810 if (epartIsReg(modrm)) {
2811 if (dis)
2812 VG_(printf)("bt%s%c %s, %s\n",
2813 nameBtOp(op),
2814 nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
2815 nameIReg(sz, eregOfRM(modrm)));
2816 } else {
2817 if (dis)
2818 VG_(printf)("bt%s%c %s, %s\n",
2819 nameBtOp(op),
2820 nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
2821 dis_buf);
2822 }
2823
2824 return eip;
2825}
2826
2827
sewardjde4a1d02002-03-22 01:27:54 +00002828
2829
2830/* Handle BSF/BSR. Only v-size seems necessary. */
2831static
sewardje1042472002-09-30 12:33:11 +00002832Addr dis_bs_E_G ( UCodeBlock* cb,
2833 UChar sorb,
2834 Int sz, Addr eip, Bool fwds )
sewardjde4a1d02002-03-22 01:27:54 +00002835{
sewardj9316cba2002-05-03 20:52:53 +00002836 Int t, t1, ta, helper;
sewardjde4a1d02002-03-22 01:27:54 +00002837 UInt pair;
2838 UChar dis_buf[50];
2839 UChar modrm;
2840
2841 vg_assert(sz == 2 || sz == 4);
2842 vg_assert(sz==4);
2843
2844 helper = fwds ? VGOFF_(helper_bsf) : VGOFF_(helper_bsr);
2845 modrm = getUChar(eip);
sewardj9316cba2002-05-03 20:52:53 +00002846 t1 = newTemp(cb);
sewardjde4a1d02002-03-22 01:27:54 +00002847 t = newTemp(cb);
2848
sewardj9316cba2002-05-03 20:52:53 +00002849 uInstr0(cb, CALLM_S, 0);
2850 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t1);
2851 uInstr1(cb, PUSH, sz, TempReg, t1);
2852
sewardjde4a1d02002-03-22 01:27:54 +00002853 if (epartIsReg(modrm)) {
2854 eip++;
2855 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t);
2856 if (dis)
2857 VG_(printf)("bs%c%c %s, %s\n",
2858 fwds ? 'f' : 'r',
2859 nameISize(sz), nameIReg(sz, eregOfRM(modrm)),
2860 nameIReg(sz, gregOfRM(modrm)));
2861 } else {
sewardje1042472002-09-30 12:33:11 +00002862 pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL );
sewardjde4a1d02002-03-22 01:27:54 +00002863 ta = LOW24(pair);
2864 eip += HI8(pair);
2865 uInstr2(cb, LOAD, sz, TempReg, ta, TempReg, t);
2866 if (dis)
2867 VG_(printf)("bs%c%c %s, %s\n",
2868 fwds ? 'f' : 'r',
2869 nameISize(sz), dis_buf,
2870 nameIReg(sz, gregOfRM(modrm)));
2871 }
2872
sewardjde4a1d02002-03-22 01:27:54 +00002873 uInstr1(cb, PUSH, sz, TempReg, t);
2874 uInstr1(cb, CALLM, 0, Lit16, helper);
2875 uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsOSACP);
2876 uInstr1(cb, POP, sz, TempReg, t);
sewardj9316cba2002-05-03 20:52:53 +00002877 uInstr1(cb, POP, sz, TempReg, t);
sewardjde4a1d02002-03-22 01:27:54 +00002878 uInstr2(cb, PUT, sz, TempReg, t, ArchReg, gregOfRM(modrm));
2879 uInstr0(cb, CALLM_E, 0);
2880
2881 return eip;
2882}
2883
2884
2885static
2886void codegen_xchg_eAX_Reg ( UCodeBlock* cb, Int sz, Int reg )
2887{
2888 Int t1, t2;
2889 vg_assert(sz == 2 || sz == 4);
2890 t1 = newTemp(cb);
2891 t2 = newTemp(cb);
2892 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
2893 uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t2);
2894 uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, R_EAX);
2895 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
2896 if (dis)
2897 VG_(printf)("xchg%c %s, %s\n", nameISize(sz),
2898 nameIReg(sz, R_EAX), nameIReg(sz, reg));
2899}
2900
2901
2902static
2903void codegen_SAHF ( UCodeBlock* cb )
2904{
sewardj3a72df02002-03-24 10:03:17 +00002905 Int t = newTemp(cb);
2906 Int t2 = newTemp(cb);
sewardjde4a1d02002-03-22 01:27:54 +00002907 uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t);
sewardj3a72df02002-03-24 10:03:17 +00002908
2909 /* Mask out parts of t not corresponding to %AH. This stops the
2910 instrumenter complaining if they are undefined. Otherwise, the
2911 instrumenter would check all 32 bits of t at the PUSH, which
2912 could be the cause of incorrect warnings. Discovered by Daniel
2913 Veillard <veillard@redhat.com>.
2914 */
2915 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
2916 uLiteral(cb, 0x0000FF00);
2917 uInstr2(cb, AND, 4, TempReg, t2, TempReg, t);
2918 /* We deliberately don't set the condition codes here, since this
2919 AND is purely internal to Valgrind and nothing to do with the
2920 client's state. */
2921
sewardjde4a1d02002-03-22 01:27:54 +00002922 uInstr0(cb, CALLM_S, 0);
2923 uInstr1(cb, PUSH, 4, TempReg, t);
2924 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_SAHF));
2925 uFlagsRWU(cb, FlagsEmpty, FlagsSZACP, FlagsEmpty);
2926 uInstr1(cb, CLEAR, 0, Lit16, 4);
2927 uInstr0(cb, CALLM_E, 0);
2928}
2929
2930
2931static
2932Addr dis_cmpxchg_G_E ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +00002933 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +00002934 Int size,
2935 Addr eip0 )
2936{
2937 Int ta, junk, dest, src, acc;
2938 UChar dis_buf[50];
2939 UChar rm;
2940
2941 rm = getUChar(eip0);
2942 acc = newTemp(cb);
2943 src = newTemp(cb);
2944 dest = newTemp(cb);
2945 junk = newTemp(cb);
2946 /* Only needed to get gcc's dataflow analyser off my back. */
2947 ta = INVALID_TEMPREG;
2948
2949 if (epartIsReg(rm)) {
2950 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, dest);
2951 eip0++;
2952 if (dis) VG_(printf)("cmpxchg%c %s,%s\n",
2953 nameISize(size),
2954 nameIReg(size,gregOfRM(rm)),
2955 nameIReg(size,eregOfRM(rm)) );
2956 nameIReg(size,eregOfRM(rm));
2957 } else {
sewardje1042472002-09-30 12:33:11 +00002958 UInt pair = disAMode ( cb, sorb, eip0, dis?dis_buf:NULL );
sewardjde4a1d02002-03-22 01:27:54 +00002959 ta = LOW24(pair);
2960 uInstr2(cb, LOAD, size, TempReg, ta, TempReg, dest);
2961 eip0 += HI8(pair);
2962 if (dis) VG_(printf)("cmpxchg%c %s,%s\n", nameISize(size),
2963 nameIReg(size,gregOfRM(rm)), dis_buf);
2964 }
2965
2966 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, src);
2967 uInstr2(cb, GET, size, ArchReg, R_EAX, TempReg, acc);
2968 uInstr2(cb, MOV, size, TempReg, acc, TempReg, junk);
2969 uInstr2(cb, SUB, size, TempReg, dest, TempReg, junk);
2970 setFlagsFromUOpcode(cb, SUB);
2971
2972 uInstr2(cb, CMOV, 4, TempReg, src, TempReg, dest);
2973 uCond(cb, CondZ);
2974 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
2975 uInstr2(cb, CMOV, 4, TempReg, dest, TempReg, acc);
2976 uCond(cb, CondNZ);
2977 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
2978
2979 uInstr2(cb, PUT, size, TempReg, acc, ArchReg, R_EAX);
2980 if (epartIsReg(rm)) {
2981 uInstr2(cb, PUT, size, TempReg, dest, ArchReg, eregOfRM(rm));
2982 } else {
2983 uInstr2(cb, STORE, size, TempReg, dest, TempReg, ta);
2984 }
2985
2986 return eip0;
2987}
2988
2989
2990/* Handle conditional move instructions of the form
2991 cmovcc E(reg-or-mem), G(reg)
2992
2993 E(src) is reg-or-mem
2994 G(dst) is reg.
2995
2996 If E is reg, --> GET %E, tmps
2997 GET %G, tmpd
2998 CMOVcc tmps, tmpd
2999 PUT tmpd, %G
3000
3001 If E is mem --> (getAddr E) -> tmpa
3002 LD (tmpa), tmps
3003 GET %G, tmpd
3004 CMOVcc tmps, tmpd
3005 PUT tmpd, %G
3006*/
3007static
3008Addr dis_cmov_E_G ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +00003009 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +00003010 Int size,
3011 Condcode cond,
3012 Addr eip0 )
3013{
3014 UChar rm = getUChar(eip0);
3015 UChar dis_buf[50];
3016
3017 Int tmps = newTemp(cb);
3018 Int tmpd = newTemp(cb);
3019
3020 if (epartIsReg(rm)) {
3021 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, tmps);
3022 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmpd);
3023 uInstr2(cb, CMOV, 4, TempReg, tmps, TempReg, tmpd);
3024 uCond(cb, cond);
3025 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
3026 uInstr2(cb, PUT, size, TempReg, tmpd, ArchReg, gregOfRM(rm));
3027 if (dis) VG_(printf)("cmov%c%s %s,%s\n",
3028 nameISize(size),
3029 VG_(nameCondcode)(cond),
3030 nameIReg(size,eregOfRM(rm)),
3031 nameIReg(size,gregOfRM(rm)));
3032 return 1+eip0;
3033 }
3034
3035 /* E refers to memory */
3036 {
sewardje1042472002-09-30 12:33:11 +00003037 UInt pair = disAMode ( cb, sorb, eip0, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +00003038 Int tmpa = LOW24(pair);
3039 uInstr2(cb, LOAD, size, TempReg, tmpa, TempReg, tmps);
3040 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmpd);
3041 uInstr2(cb, CMOV, 4, TempReg, tmps, TempReg, tmpd);
3042 uCond(cb, cond);
3043 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
3044 uInstr2(cb, PUT, size, TempReg, tmpd, ArchReg, gregOfRM(rm));
3045 if (dis) VG_(printf)("cmov%c%s %s,%s\n",
3046 nameISize(size),
3047 VG_(nameCondcode)(cond),
3048 dis_buf,
3049 nameIReg(size,gregOfRM(rm)));
3050 return HI8(pair)+eip0;
3051 }
3052}
3053
3054
3055static
3056Addr dis_xadd_G_E ( UCodeBlock* cb,
sewardje1042472002-09-30 12:33:11 +00003057 UChar sorb,
sewardjde4a1d02002-03-22 01:27:54 +00003058 Int sz,
3059 Addr eip0 )
3060{
3061 UChar rm = getUChar(eip0);
3062 UChar dis_buf[50];
3063
3064 Int tmpd = newTemp(cb);
3065 Int tmpt = newTemp(cb);
3066
3067 if (epartIsReg(rm)) {
3068 uInstr2(cb, GET, sz, ArchReg, eregOfRM(rm), TempReg, tmpd);
3069 uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
3070 uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
3071 setFlagsFromUOpcode(cb, ADD);
3072 uInstr2(cb, PUT, sz, TempReg, tmpt, ArchReg, eregOfRM(rm));
3073 uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
3074 if (dis)
3075 VG_(printf)("xadd%c %s, %s\n", nameISize(sz),
3076 nameIReg(sz,gregOfRM(rm)),
3077 nameIReg(sz,eregOfRM(rm)));
3078 return 1+eip0;
3079 } else {
sewardje1042472002-09-30 12:33:11 +00003080 UInt pair = disAMode ( cb, sorb, eip0, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +00003081 Int tmpa = LOW24(pair);
3082 uInstr2(cb, LOAD, sz, TempReg, tmpa, TempReg, tmpd);
3083 uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
3084 uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
3085 setFlagsFromUOpcode(cb, ADD);
3086 uInstr2(cb, STORE, sz, TempReg, tmpt, TempReg, tmpa);
sewardjde4a1d02002-03-22 01:27:54 +00003087 uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
3088 if (dis)
3089 VG_(printf)("xadd%c %s, %s\n", nameISize(sz),
3090 nameIReg(sz,gregOfRM(rm)),
3091 dis_buf);
3092 return HI8(pair)+eip0;
3093 }
3094}
3095
3096
sewardje1042472002-09-30 12:33:11 +00003097/* Moves of Ew into a segment register.
3098 mov Ew, Sw meaning
3099 mov reg-or-mem, reg
3100 Is passed the a ptr to the modRM byte, and the data size. Returns
3101 the address advanced completely over this instruction.
3102
3103 Ew(src) is reg-or-mem
3104 Sw(dst) is seg reg.
3105
3106 If E is reg, --> GETw %Ew, tmpv
3107 PUTSEG tmpv, %Sw
3108
3109 If E is mem --> (getAddr E) -> tmpa
3110 LDw (tmpa), tmpb
3111 PUTSEG tmpb, %Sw
3112*/
3113static
3114Addr dis_mov_Ew_Sw ( UCodeBlock* cb,
sewardjd077f532002-09-30 21:52:50 +00003115 UChar sorb,
sewardje1042472002-09-30 12:33:11 +00003116 Addr eip0 )
3117{
3118 UChar rm = getUChar(eip0);
3119 UChar dis_buf[50];
3120
3121 if (epartIsReg(rm)) {
3122 Int tmpv = newTemp(cb);
3123 uInstr2(cb, GET, 2, ArchReg, eregOfRM(rm), TempReg, tmpv);
3124 uInstr2(cb, PUTSEG, 2, TempReg, tmpv, ArchRegS, gregOfRM(rm));
3125 if (dis) VG_(printf)("movw %s,%s\n",
3126 nameIReg(2,eregOfRM(rm)),
3127 nameSReg(gregOfRM(rm)));
3128 return 1+eip0;
3129 }
3130
3131 /* E refers to memory */
3132 {
3133 UInt pair = disAMode ( cb, sorb, eip0, dis?dis_buf:NULL);
3134 Int tmpa = LOW24(pair);
3135 Int tmpb = newTemp(cb);
3136 uInstr2(cb, LOAD, 2, TempReg, tmpa, TempReg, tmpb);
3137 uInstr2(cb, PUTSEG, 2, TempReg, tmpb, ArchRegS, gregOfRM(rm));
3138 if (dis) VG_(printf)("movw %s,%s\n",
3139 dis_buf,nameSReg(gregOfRM(rm)));
3140 return HI8(pair)+eip0;
3141 }
3142}
3143
3144
sewardjd077f532002-09-30 21:52:50 +00003145/* Moves of a segment register to Ew.
3146 mov Sw, Ew meaning
3147 mov reg, reg-or-mem
3148 Is passed the a ptr to the modRM byte, and the data size. Returns
3149 the address advanced completely over this instruction.
3150
3151 Sw(src) is seg reg.
3152 Ew(dst) is reg-or-mem
3153
3154 If E is reg, --> GETSEG %Sw, tmp
3155 PUTW tmp, %Ew
3156
3157 If E is mem, --> (getAddr E) -> tmpa
3158 GETSEG %Sw, tmpv
3159 STW tmpv, (tmpa)
3160*/
3161static
3162Addr dis_mov_Sw_Ew ( UCodeBlock* cb,
3163 UChar sorb,
3164 Addr eip0 )
3165{
3166 UChar rm = getUChar(eip0);
3167 UChar dis_buf[50];
3168
3169 if (epartIsReg(rm)) {
3170 Int tmpv = newTemp(cb);
3171 uInstr2(cb, GETSEG, 2, ArchRegS, gregOfRM(rm), TempReg, tmpv);
3172 uInstr2(cb, PUT, 2, TempReg, tmpv, ArchReg, eregOfRM(rm));
3173 if (dis) VG_(printf)("movw %s,%s\n",
3174 nameSReg(gregOfRM(rm)),
3175 nameIReg(2,eregOfRM(rm)));
3176 return 1+eip0;
3177 }
3178
3179 /* E refers to memory */
3180 {
3181 UInt pair = disAMode ( cb, sorb, eip0, dis?dis_buf:NULL);
3182 Int tmpa = LOW24(pair);
3183 Int tmpv = newTemp(cb);
3184 uInstr2(cb, GETSEG, 2, ArchRegS, gregOfRM(rm), TempReg, tmpv);
3185 uInstr2(cb, STORE, 2, TempReg, tmpv, TempReg, tmpa);
3186 if (dis) VG_(printf)("mov %s,%s\n",
3187 nameSReg(gregOfRM(rm)), dis_buf);
3188 return HI8(pair)+eip0;
3189 }
3190}
3191
3192
sewardjde4a1d02002-03-22 01:27:54 +00003193/*------------------------------------------------------------*/
3194/*--- Disassembling entire basic blocks ---*/
3195/*------------------------------------------------------------*/
3196
3197/* Disassemble a single instruction into ucode, returning the update
3198 eip, and setting *isEnd to True if this is the last insn in a basic
3199 block. Also do debug printing if (dis). */
3200
3201static Addr disInstr ( UCodeBlock* cb, Addr eip, Bool* isEnd )
3202{
3203 UChar opc, modrm, abyte;
3204 UInt d32, pair;
3205 Int t1, t2, t3, t4;
3206 UChar dis_buf[50];
3207 Int am_sz, d_sz;
3208
sewardje1042472002-09-30 12:33:11 +00003209 /* sz denotes the nominal data-op size of the insn; we change it to
3210 2 if an 0x66 prefix is seen */
3211 Int sz = 4;
3212
3213 /* sorb holds the segment-override-prefix byte, if any. Zero if no
3214 prefix has been seen, else one of {0x26, 0x3E, 0x64, 0x65}
3215 indicating the prefix. */
3216 UChar sorb = 0;
3217
3218 Int first_uinstr = cb->used;
sewardjde4a1d02002-03-22 01:27:54 +00003219 *isEnd = False;
3220 t1 = t2 = t3 = t4 = INVALID_TEMPREG;
3221
3222 if (dis) VG_(printf)("\t0x%x: ", eip);
3223
sewardjc7529c32002-04-16 01:55:18 +00003224 /* Spot the client-request magic sequence. */
3225 {
sewardjde4a1d02002-03-22 01:27:54 +00003226 UChar* myeip = (UChar*)eip;
3227 /* Spot this:
3228 C1C01D roll $29, %eax
3229 C1C003 roll $3, %eax
sewardj2e93c502002-04-12 11:12:52 +00003230 C1C81B rorl $27, %eax
3231 C1C805 rorl $5, %eax
3232 C1C00D roll $13, %eax
3233 C1C013 roll $19, %eax
sewardjde4a1d02002-03-22 01:27:54 +00003234 */
sewardj2e93c502002-04-12 11:12:52 +00003235 if (myeip[ 0] == 0xC1 && myeip[ 1] == 0xC0 && myeip[ 2] == 0x1D &&
3236 myeip[ 3] == 0xC1 && myeip[ 4] == 0xC0 && myeip[ 5] == 0x03 &&
3237 myeip[ 6] == 0xC1 && myeip[ 7] == 0xC8 && myeip[ 8] == 0x1B &&
3238 myeip[ 9] == 0xC1 && myeip[10] == 0xC8 && myeip[11] == 0x05 &&
3239 myeip[12] == 0xC1 && myeip[13] == 0xC0 && myeip[14] == 0x0D &&
3240 myeip[15] == 0xC1 && myeip[16] == 0xC0 && myeip[17] == 0x13
3241 ) {
3242 eip += 18;
3243 uInstr1(cb, JMP, 0, Literal, 0);
3244 uLiteral(cb, eip);
3245 uCond(cb, CondAlways);
3246 LAST_UINSTR(cb).jmpkind = JmpClientReq;
3247 *isEnd = True;
3248 if (dis)
3249 VG_(printf)("%%edx = client_request ( %%eax )\n");
sewardjde4a1d02002-03-22 01:27:54 +00003250 return eip;
3251 }
3252 }
3253
3254 /* Skip a LOCK prefix. */
sewardj5716dbb2002-04-26 03:28:18 +00003255 if (getUChar(eip) == 0xF0) {
3256 /* VG_(printf)("LOCK LOCK LOCK LOCK LOCK \n"); */
3257 eip++;
3258 }
sewardjde4a1d02002-03-22 01:27:54 +00003259
sewardjde4a1d02002-03-22 01:27:54 +00003260 /* Detect operand-size overrides. */
3261 if (getUChar(eip) == 0x66) { sz = 2; eip++; };
3262
sewardje1042472002-09-30 12:33:11 +00003263 /* segment override prefixes come after the operand-size override,
3264 it seems */
3265 switch (getUChar(eip)) {
3266 case 0x3E: /* %DS: */
3267 case 0x26: /* %ES: */
3268 case 0x64: /* %FS: */
3269 case 0x65: /* %GS: */
3270 sorb = getUChar(eip); eip++;
3271 break;
3272 case 0x2E: /* %CS: */
3273 VG_(unimplemented)("x86 segment override (SEG=CS) prefix");
3274 /*NOTREACHED*/
3275 break;
3276 case 0x36: /* %SS: */
3277 VG_(unimplemented)("x86 segment override (SEG=SS) prefix");
3278 /*NOTREACHED*/
3279 break;
3280 default:
3281 break;
3282 }
3283
3284
sewardjde4a1d02002-03-22 01:27:54 +00003285 opc = getUChar(eip); eip++;
3286
3287 switch (opc) {
3288
3289 /* ------------------------ Control flow --------------- */
3290
3291 case 0xC2: /* RET imm16 */
3292 d32 = getUDisp16(eip); eip += 2;
3293 goto do_Ret;
3294 case 0xC3: /* RET */
3295 d32 = 0;
3296 goto do_Ret;
3297 do_Ret:
3298 t1 = newTemp(cb); t2 = newTemp(cb);
3299 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
3300 uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t2);
3301 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1);
3302 uLiteral(cb, 4+d32);
3303 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3304 uInstr1(cb, JMP, 0, TempReg, t2);
3305 uCond(cb, CondAlways);
sewardj2e93c502002-04-12 11:12:52 +00003306 LAST_UINSTR(cb).jmpkind = JmpRet;
sewardjde4a1d02002-03-22 01:27:54 +00003307
3308 *isEnd = True;
3309 if (dis) {
3310 if (d32 == 0) VG_(printf)("ret\n");
3311 else VG_(printf)("ret %d\n", d32);
3312 }
3313 break;
3314
3315 case 0xE8: /* CALL J4 */
3316 d32 = getUDisp32(eip); eip += 4;
3317 d32 += eip; /* eip now holds return-to addr, d32 is call-to addr */
sewardjde4a1d02002-03-22 01:27:54 +00003318 if (d32 == eip && getUChar(eip) >= 0x58
3319 && getUChar(eip) <= 0x5F) {
3320 /* Specially treat the position-independent-code idiom
3321 call X
3322 X: popl %reg
3323 as
3324 movl %eip, %reg.
3325 since this generates better code, but for no other reason. */
3326 Int archReg = getUChar(eip) - 0x58;
3327 /* VG_(printf)("-- fPIC thingy\n"); */
3328 t1 = newTemp(cb);
3329 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
3330 uLiteral(cb, eip);
3331 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, archReg);
3332 eip++; /* Step over the POP */
3333 if (dis)
3334 VG_(printf)("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
3335 } else {
3336 /* The normal sequence for a call. */
3337 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3338 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
3339 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t1);
3340 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t1);
3341 uLiteral(cb, 4);
3342 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3343 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
3344 uLiteral(cb, eip);
3345 uInstr2(cb, STORE, 4, TempReg, t2, TempReg, t1);
sewardjde4a1d02002-03-22 01:27:54 +00003346 uInstr1(cb, JMP, 0, Literal, 0);
3347 uLiteral(cb, d32);
3348 uCond(cb, CondAlways);
sewardj2e93c502002-04-12 11:12:52 +00003349 LAST_UINSTR(cb).jmpkind = JmpCall;
sewardjde4a1d02002-03-22 01:27:54 +00003350 *isEnd = True;
3351 if (dis) VG_(printf)("call 0x%x\n",d32);
3352 }
3353 break;
3354
3355 case 0xC9: /* LEAVE */
3356 t1 = newTemp(cb); t2 = newTemp(cb);
3357 uInstr2(cb, GET, 4, ArchReg, R_EBP, TempReg, t1);
3358 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3359 uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t2);
3360 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
3361 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1);
3362 uLiteral(cb, 4);
3363 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3364 if (dis) VG_(printf)("leave");
3365 break;
3366
sewardj4d0ab1f2002-03-24 10:00:09 +00003367 /* ---------------- Misc wierd-ass insns --------------- */
3368
sewardjfe8a1662002-03-24 11:54:07 +00003369 case 0x27: /* DAA */
sewardj4d0ab1f2002-03-24 10:00:09 +00003370 case 0x2F: /* DAS */
3371 t1 = newTemp(cb);
3372 uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
3373 /* Widen %AL to 32 bits, so it's all defined when we push it. */
3374 uInstr1(cb, WIDEN, 4, TempReg, t1);
3375 LAST_UINSTR(cb).extra4b = 1;
3376 LAST_UINSTR(cb).signed_widen = False;
3377 uInstr0(cb, CALLM_S, 0);
3378 uInstr1(cb, PUSH, 4, TempReg, t1);
sewardjfe8a1662002-03-24 11:54:07 +00003379 uInstr1(cb, CALLM, 0, Lit16,
3380 opc == 0x27 ? VGOFF_(helper_DAA) : VGOFF_(helper_DAS) );
sewardj4d0ab1f2002-03-24 10:00:09 +00003381 uFlagsRWU(cb, FlagsAC, FlagsOSZACP, FlagsEmpty);
3382 uInstr1(cb, POP, 4, TempReg, t1);
3383 uInstr0(cb, CALLM_E, 0);
3384 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
sewardjfe8a1662002-03-24 11:54:07 +00003385 if (dis) VG_(printf)(opc == 0x27 ? "daa\n" : "das\n");
3386 break;
sewardj4d0ab1f2002-03-24 10:00:09 +00003387
sewardjde4a1d02002-03-22 01:27:54 +00003388 /* ------------------------ CWD/CDQ -------------------- */
3389
3390 case 0x98: /* CBW */
3391 t1 = newTemp(cb);
3392 if (sz == 4) {
3393 uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
3394 uInstr1(cb, WIDEN, 4, TempReg, t1); /* 4 == dst size */
3395 LAST_UINSTR(cb).extra4b = 2; /* the source size */
3396 LAST_UINSTR(cb).signed_widen = True;
3397 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
3398 if (dis) VG_(printf)("cwd\n");
3399 } else {
3400 vg_assert(sz == 2);
3401 uInstr2(cb, GET, 1, ArchReg, R_EAX, TempReg, t1);
3402 uInstr1(cb, WIDEN, 2, TempReg, t1); /* 2 == dst size */
3403 LAST_UINSTR(cb).extra4b = 1; /* the source size */
3404 LAST_UINSTR(cb).signed_widen = True;
3405 uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
3406 if (dis) VG_(printf)("cbw\n");
3407 }
3408 break;
3409
3410 case 0x99: /* CWD/CDQ */
3411 t1 = newTemp(cb);
3412 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
3413 uInstr2(cb, SAR, sz, Literal, 0, TempReg, t1);
3414 uLiteral(cb, sz == 2 ? 15 : 31);
3415 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EDX);
3416 if (dis) VG_(printf)(sz == 2 ? "cwdq\n" : "cdqq\n");
3417 break;
3418
3419 /* ------------------------ FPU ops -------------------- */
3420
3421 case 0x9E: /* SAHF */
3422 codegen_SAHF ( cb );
3423 if (dis) VG_(printf)("sahf\n");
3424 break;
3425
3426 case 0x9B: /* FWAIT */
3427 /* ignore? */
3428 if (dis) VG_(printf)("fwait\n");
3429 break;
3430
3431 case 0xD8:
3432 case 0xD9:
3433 case 0xDA:
3434 case 0xDB:
3435 case 0xDC:
3436 case 0xDD:
3437 case 0xDE:
3438 case 0xDF:
sewardje1042472002-09-30 12:33:11 +00003439 eip = dis_fpu ( cb, sorb, opc, eip );
sewardjde4a1d02002-03-22 01:27:54 +00003440 break;
3441
3442 /* ------------------------ INC & DEC ------------------ */
3443
3444 case 0x40: /* INC eAX */
3445 case 0x41: /* INC eCX */
3446 case 0x42: /* INC eDX */
3447 case 0x43: /* INC eBX */
3448 case 0x45: /* INC eBP */
3449 case 0x46: /* INC eSI */
3450 case 0x47: /* INC eDI */
3451 t1 = newTemp(cb);
3452 uInstr2(cb, GET, sz, ArchReg, (UInt)(opc - 0x40),
3453 TempReg, t1);
3454 uInstr1(cb, INC, sz, TempReg, t1);
3455 setFlagsFromUOpcode(cb, INC);
3456 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg,
3457 (UInt)(opc - 0x40));
3458 if (dis)
3459 VG_(printf)("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
3460 break;
3461
3462 case 0x48: /* DEC eAX */
3463 case 0x49: /* DEC eCX */
3464 case 0x4A: /* DEC eDX */
3465 case 0x4B: /* DEC eBX */
3466 case 0x4D: /* DEC eBP */
3467 case 0x4E: /* DEC eSI */
3468 case 0x4F: /* DEC eDI */
3469 t1 = newTemp(cb);
3470 uInstr2(cb, GET, sz, ArchReg, (UInt)(opc - 0x48),
3471 TempReg, t1);
3472 uInstr1(cb, DEC, sz, TempReg, t1);
3473 setFlagsFromUOpcode(cb, DEC);
3474 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg,
3475 (UInt)(opc - 0x48));
3476 if (dis)
3477 VG_(printf)("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
3478 break;
3479
3480 /* ------------------------ INT ------------------------ */
3481
3482 case 0xCD: /* INT imm8 */
3483 d32 = getUChar(eip); eip++;
njne427a662002-10-02 11:08:25 +00003484 if (d32 != 0x80) VG_(core_panic)("disInstr: INT but not 0x80 !");
sewardjde4a1d02002-03-22 01:27:54 +00003485 /* It's important that all ArchRegs carry their up-to-date value
3486 at this point. So we declare an end-of-block here, which
3487 forces any TempRegs caching ArchRegs to be flushed. */
sewardjde4a1d02002-03-22 01:27:54 +00003488 uInstr1(cb, JMP, 0, Literal, 0);
3489 uLiteral(cb, eip);
3490 uCond(cb, CondAlways);
sewardj2e93c502002-04-12 11:12:52 +00003491 LAST_UINSTR(cb).jmpkind = JmpSyscall;
sewardjde4a1d02002-03-22 01:27:54 +00003492 *isEnd = True;
3493 if (dis) VG_(printf)("int $0x80\n");
3494 break;
3495
3496 /* ------------------------ Jcond, byte offset --------- */
3497
3498 case 0xEB: /* Jb (jump, byte offset) */
3499 d32 = (eip+1) + getSDisp8(eip); eip++;
3500 uInstr1(cb, JMP, 0, Literal, 0);
3501 uLiteral(cb, d32);
3502 uCond(cb, CondAlways);
3503 *isEnd = True;
3504 if (dis)
3505 VG_(printf)("jmp-8 0x%x\n", d32);
3506 break;
3507
3508 case 0xE9: /* Jv (jump, 16/32 offset) */
3509 d32 = (eip+sz) + getSDisp(sz,eip); eip += sz;
3510 uInstr1(cb, JMP, 0, Literal, 0);
3511 uLiteral(cb, d32);
3512 uCond(cb, CondAlways);
3513 *isEnd = True;
3514 if (dis)
3515 VG_(printf)("jmp 0x%x\n", d32);
3516 break;
3517
3518 case 0x70:
3519 case 0x71:
3520 case 0x72: /* JBb/JNAEb (jump below) */
3521 case 0x73: /* JNBb/JAEb (jump not below) */
3522 case 0x74: /* JZb/JEb (jump zero) */
3523 case 0x75: /* JNZb/JNEb (jump not zero) */
3524 case 0x76: /* JBEb/JNAb (jump below or equal) */
3525 case 0x77: /* JNBEb/JAb (jump not below or equal) */
3526 case 0x78: /* JSb (jump negative) */
3527 case 0x79: /* JSb (jump not negative) */
3528 case 0x7A: /* JP (jump parity even) */
3529 case 0x7B: /* JNP/JPO (jump parity odd) */
3530 case 0x7C: /* JLb/JNGEb (jump less) */
3531 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
3532 case 0x7E: /* JLEb/JNGb (jump less or equal) */
3533 case 0x7F: /* JGb/JNLEb (jump greater) */
3534 d32 = (eip+1) + getSDisp8(eip); eip++;
3535 uInstr1(cb, JMP, 0, Literal, 0);
3536 uLiteral(cb, d32);
3537 uCond(cb, (Condcode)(opc - 0x70));
3538 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
3539 /* It's actually acceptable not to end this basic block at a
3540 control transfer, reducing the number of jumps through
3541 vg_dispatch, at the expense of possibly translating the insns
3542 following this jump twice. This does give faster code, but
3543 on the whole I don't think the effort is worth it. */
3544 uInstr1(cb, JMP, 0, Literal, 0);
3545 uLiteral(cb, eip);
3546 uCond(cb, CondAlways);
3547 *isEnd = True;
3548 /* The above 3 lines would be removed if the bb was not to end
3549 here. */
3550 if (dis)
3551 VG_(printf)("j%s-8 0x%x\n", VG_(nameCondcode)(opc - 0x70), d32);
3552 break;
3553
3554 case 0xE3: /* JECXZ or perhaps JCXZ, depending on OSO ? Intel
3555 manual says it depends on address size override,
3556 which doesn't sound right to me. */
3557 d32 = (eip+1) + getSDisp8(eip); eip++;
3558 t1 = newTemp(cb);
3559 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
3560 uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
3561 uLiteral(cb, d32);
3562 if (dis)
3563 VG_(printf)("j%sz 0x%x\n", nameIReg(sz, R_ECX), d32);
3564 break;
3565
3566 case 0xE2: /* LOOP disp8 */
3567 /* Again, the docs say this uses ECX/CX as a count depending on
3568 the address size override, not the operand one. Since we
3569 don't handle address size overrides, I guess that means
3570 ECX. */
3571 d32 = (eip+1) + getSDisp8(eip); eip++;
3572 t1 = newTemp(cb);
3573 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
3574 uInstr1(cb, DEC, 4, TempReg, t1);
3575 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ECX);
3576 uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
3577 uLiteral(cb, eip);
3578 uInstr1(cb, JMP, 0, Literal, 0);
3579 uLiteral(cb, d32);
3580 uCond(cb, CondAlways);
3581 *isEnd = True;
3582 if (dis)
3583 VG_(printf)("loop 0x%x\n", d32);
3584 break;
3585
3586 /* ------------------------ IMUL ----------------------- */
3587
3588 case 0x69: /* IMUL Iv, Ev, Gv */
sewardje1042472002-09-30 12:33:11 +00003589 eip = dis_imul_I_E_G ( cb, sorb, sz, eip, sz );
sewardjde4a1d02002-03-22 01:27:54 +00003590 break;
3591 case 0x6B: /* IMUL Ib, Ev, Gv */
sewardje1042472002-09-30 12:33:11 +00003592 eip = dis_imul_I_E_G ( cb, sorb, sz, eip, 1 );
sewardjde4a1d02002-03-22 01:27:54 +00003593 break;
3594
3595 /* ------------------------ MOV ------------------------ */
3596
3597 case 0x88: /* MOV Gb,Eb */
sewardje1042472002-09-30 12:33:11 +00003598 eip = dis_mov_G_E(cb, sorb, 1, eip);
sewardjde4a1d02002-03-22 01:27:54 +00003599 break;
3600
3601 case 0x89: /* MOV Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00003602 eip = dis_mov_G_E(cb, sorb, sz, eip);
sewardjde4a1d02002-03-22 01:27:54 +00003603 break;
3604
3605 case 0x8A: /* MOV Eb,Gb */
sewardje1042472002-09-30 12:33:11 +00003606 eip = dis_mov_E_G(cb, sorb, 1, eip);
sewardjde4a1d02002-03-22 01:27:54 +00003607 break;
3608
3609 case 0x8B: /* MOV Ev,Gv */
sewardje1042472002-09-30 12:33:11 +00003610 eip = dis_mov_E_G(cb, sorb, sz, eip);
sewardjde4a1d02002-03-22 01:27:54 +00003611 break;
3612
3613 case 0x8D: /* LEA M,Gv */
3614 modrm = getUChar(eip);
3615 if (epartIsReg(modrm))
njne427a662002-10-02 11:08:25 +00003616 VG_(core_panic)("LEA M,Gv: modRM refers to register");
sewardje1042472002-09-30 12:33:11 +00003617 /* NOTE! this is the one place where a segment override prefix
3618 has no effect on the address calculation. Therefore we pass
3619 zero instead of sorb here. */
3620 pair = disAMode ( cb, /*sorb*/ 0, eip, dis?dis_buf:NULL );
sewardjde4a1d02002-03-22 01:27:54 +00003621 eip += HI8(pair);
3622 t1 = LOW24(pair);
3623 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, gregOfRM(modrm));
3624 if (dis)
3625 VG_(printf)("lea%c %s, %s\n", nameISize(sz), dis_buf,
3626 nameIReg(sz,gregOfRM(modrm)));
3627 break;
3628
sewardjd077f532002-09-30 21:52:50 +00003629 case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
3630 eip = dis_mov_Sw_Ew(cb, sorb, eip);
3631 break;
3632
sewardje1042472002-09-30 12:33:11 +00003633 case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
3634 eip = dis_mov_Ew_Sw(cb, sorb, eip);
3635 break;
3636
sewardjde4a1d02002-03-22 01:27:54 +00003637 case 0xA0: /* MOV Ob,AL */
3638 sz = 1;
3639 /* Fall through ... */
3640 case 0xA1: /* MOV Ov,eAX */
3641 d32 = getUDisp32(eip); eip += 4;
3642 t1 = newTemp(cb); t2 = newTemp(cb);
3643 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
3644 uLiteral(cb, d32);
sewardjbe4015a2002-10-03 16:14:57 +00003645 handleSegOverride(cb, sorb, t2);
sewardjde4a1d02002-03-22 01:27:54 +00003646 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3647 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EAX);
sewardjbe4015a2002-10-03 16:14:57 +00003648 if (dis) VG_(printf)("mov%c %s0x%x,%s\n", nameISize(sz),
3649 sorbTxt(sorb),
sewardjde4a1d02002-03-22 01:27:54 +00003650 d32, nameIReg(sz,R_EAX));
3651 break;
3652
3653 case 0xA2: /* MOV AL,Ob */
3654 sz = 1;
3655 /* Fall through ... */
3656 case 0xA3: /* MOV eAX,Ov */
3657 d32 = getUDisp32(eip); eip += 4;
3658 t1 = newTemp(cb); t2 = newTemp(cb);
3659 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
3660 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
3661 uLiteral(cb, d32);
sewardjbe4015a2002-10-03 16:14:57 +00003662 handleSegOverride(cb, sorb, t2);
sewardjde4a1d02002-03-22 01:27:54 +00003663 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
sewardjbe4015a2002-10-03 16:14:57 +00003664 if (dis) VG_(printf)("mov%c %s,%s0x%x\n", nameISize(sz),
3665 sorbTxt(sorb),
sewardjde4a1d02002-03-22 01:27:54 +00003666 nameIReg(sz,R_EAX), d32);
3667 break;
3668
3669 case 0xB0: /* MOV imm,AL */
3670 case 0xB1: /* MOV imm,CL */
3671 case 0xB2: /* MOV imm,DL */
3672 case 0xB3: /* MOV imm,BL */
3673 case 0xB4: /* MOV imm,AH */
3674 case 0xB5: /* MOV imm,CH */
3675 case 0xB6: /* MOV imm,DH */
3676 case 0xB7: /* MOV imm,BH */
3677 d32 = getUChar(eip); eip += 1;
3678 t1 = newTemp(cb);
3679 uInstr2(cb, MOV, 1, Literal, 0, TempReg, t1);
3680 uLiteral(cb, d32);
3681 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, opc-0xB0);
3682 if (dis) VG_(printf)("movb $0x%x,%s\n", d32,
3683 nameIReg(1,opc-0xB0));
3684 break;
3685
3686 case 0xB8: /* MOV imm,eAX */
3687 case 0xB9: /* MOV imm,eCX */
3688 case 0xBA: /* MOV imm,eDX */
3689 case 0xBB: /* MOV imm,eBX */
3690 case 0xBD: /* MOV imm,eBP */
3691 case 0xBE: /* MOV imm,eSI */
3692 case 0xBF: /* MOV imm,eDI */
3693 d32 = getUDisp(sz,eip); eip += sz;
3694 t1 = newTemp(cb);
3695 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t1);
3696 uLiteral(cb, d32);
3697 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, opc-0xB8);
3698 if (dis) VG_(printf)("mov%c $0x%x,%s\n", nameISize(sz), d32,
3699 nameIReg(sz,opc-0xB8));
3700 break;
3701
3702 case 0xC6: /* MOV Ib,Eb */
3703 sz = 1;
3704 goto do_Mov_I_E;
3705 case 0xC7: /* MOV Iv,Ev */
3706 goto do_Mov_I_E;
3707
3708 do_Mov_I_E:
3709 modrm = getUChar(eip);
3710 if (epartIsReg(modrm)) {
3711 d32 = getUDisp(sz,eip); eip += sz;
3712 t1 = newTemp(cb);
3713 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t1);
3714 uLiteral(cb, d32);
3715 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
3716 if (dis) VG_(printf)("mov%c $0x%x, %s\n", nameISize(sz), d32,
3717 nameIReg(sz,eregOfRM(modrm)));
3718 } else {
sewardje1042472002-09-30 12:33:11 +00003719 pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL );
sewardjde4a1d02002-03-22 01:27:54 +00003720 eip += HI8(pair);
3721 d32 = getUDisp(sz,eip); eip += sz;
3722 t1 = newTemp(cb);
3723 t2 = LOW24(pair);
3724 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t1);
3725 uLiteral(cb, d32);
3726 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00003727 if (dis) VG_(printf)("mov%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
3728 }
3729 break;
3730
3731 /* ------------------------ opl imm, A ----------------- */
3732
3733 case 0x04: /* ADD Ib, AL */
3734 eip = dis_op_imm_A(cb, 1, ADD, True, eip, "add" );
3735 break;
3736 case 0x05: /* ADD Iv, eAX */
3737 eip = dis_op_imm_A(cb, sz, ADD, True, eip, "add" );
3738 break;
3739
3740 case 0x0C: /* OR Ib, AL */
3741 eip = dis_op_imm_A(cb, 1, OR, True, eip, "or" );
3742 break;
3743 case 0x0D: /* OR Iv, eAX */
3744 eip = dis_op_imm_A(cb, sz, OR, True, eip, "or" );
3745 break;
3746
njn25e49d8e72002-09-23 09:36:25 +00003747 case 0x15: /* ADC Iv, eAX */
3748 eip = dis_op_imm_A(cb, sz, ADC, True, eip, "adc" );
3749 break;
3750
sewardje9c06f12002-05-08 01:44:03 +00003751 case 0x1C: /* SBB Ib, AL */
3752 eip = dis_op_imm_A(cb, 1, SBB, True, eip, "sbb" );
3753 break;
3754
sewardjde4a1d02002-03-22 01:27:54 +00003755 case 0x24: /* AND Ib, AL */
3756 eip = dis_op_imm_A(cb, 1, AND, True, eip, "and" );
3757 break;
3758 case 0x25: /* AND Iv, eAX */
3759 eip = dis_op_imm_A(cb, sz, AND, True, eip, "and" );
3760 break;
3761
3762 case 0x2C: /* SUB Ib, AL */
3763 eip = dis_op_imm_A(cb, 1, SUB, True, eip, "sub" );
3764 break;
3765 case 0x2D: /* SUB Iv, eAX */
3766 eip = dis_op_imm_A(cb, sz, SUB, True, eip, "sub" );
3767 break;
3768
3769 case 0x34: /* XOR Ib, AL */
3770 eip = dis_op_imm_A(cb, 1, XOR, True, eip, "xor" );
3771 break;
3772 case 0x35: /* XOR Iv, eAX */
3773 eip = dis_op_imm_A(cb, sz, XOR, True, eip, "xor" );
3774 break;
3775
3776 case 0x3C: /* CMP Ib, AL */
3777 eip = dis_op_imm_A(cb, 1, SUB, False, eip, "cmp" );
3778 break;
3779 case 0x3D: /* CMP Iv, eAX */
3780 eip = dis_op_imm_A(cb, sz, SUB, False, eip, "cmp" );
3781 break;
3782
3783 case 0xA8: /* TEST Ib, AL */
3784 eip = dis_op_imm_A(cb, 1, AND, False, eip, "test" );
3785 break;
3786 case 0xA9: /* TEST Iv, eAX */
3787 eip = dis_op_imm_A(cb, sz, AND, False, eip, "test" );
3788 break;
3789
3790 /* ------------------------ opl Ev, Gv ----------------- */
3791
3792 case 0x02: /* ADD Eb,Gb */
sewardje1042472002-09-30 12:33:11 +00003793 eip = dis_op2_E_G ( cb, sorb, ADD, True, 1, eip, "add" );
sewardjde4a1d02002-03-22 01:27:54 +00003794 break;
3795 case 0x03: /* ADD Ev,Gv */
sewardje1042472002-09-30 12:33:11 +00003796 eip = dis_op2_E_G ( cb, sorb, ADD, True, sz, eip, "add" );
sewardjde4a1d02002-03-22 01:27:54 +00003797 break;
3798
3799 case 0x0A: /* OR Eb,Gb */
sewardje1042472002-09-30 12:33:11 +00003800 eip = dis_op2_E_G ( cb, sorb, OR, True, 1, eip, "or" );
sewardjde4a1d02002-03-22 01:27:54 +00003801 break;
3802 case 0x0B: /* OR Ev,Gv */
sewardje1042472002-09-30 12:33:11 +00003803 eip = dis_op2_E_G ( cb, sorb, OR, True, sz, eip, "or" );
sewardjde4a1d02002-03-22 01:27:54 +00003804 break;
3805
sewardja4b87f62002-05-29 23:38:23 +00003806 case 0x12: /* ADC Eb,Gb */
sewardje1042472002-09-30 12:33:11 +00003807 eip = dis_op2_E_G ( cb, sorb, ADC, True, 1, eip, "adc" );
sewardja4b87f62002-05-29 23:38:23 +00003808 break;
sewardjde4a1d02002-03-22 01:27:54 +00003809 case 0x13: /* ADC Ev,Gv */
sewardje1042472002-09-30 12:33:11 +00003810 eip = dis_op2_E_G ( cb, sorb, ADC, True, sz, eip, "adc" );
sewardjde4a1d02002-03-22 01:27:54 +00003811 break;
3812
3813 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 */
4126 codegen_MOVS ( cb, 1 );
4127 if (dis) VG_(printf)("movsb\n");
4128 break;
4129 case 0xA5: /* MOVSv, no REP prefix */
4130 codegen_MOVS ( cb, sz );
4131 if (dis) VG_(printf)("movs%c\n", nameISize(sz));
4132 break;
4133
4134 case 0xA6: /* CMPSb, no REP prefix */
4135 codegen_CMPS ( cb, 1 );
4136 if (dis) VG_(printf)("cmpsb\n");
4137 break;
4138
4139 case 0xAA: /* STOSb, no REP prefix */
4140 codegen_STOS ( cb, 1 );
4141 if (dis) VG_(printf)("stosb\n");
4142 break;
4143 case 0xAB: /* STOSv, no REP prefix */
4144 codegen_STOS ( cb, sz );
4145 if (dis) VG_(printf)("stos%c\n", nameISize(sz));
4146 break;
4147
4148 case 0xAC: /* LODSb, no REP prefix */
4149 codegen_LODS ( cb, 1 );
4150 if (dis) VG_(printf)("lodsb\n");
4151 break;
sewardj64a8cc42002-05-08 01:38:43 +00004152 case 0xAD: /* LODSv, no REP prefix */
4153 codegen_LODS ( cb, sz );
4154 if (dis) VG_(printf)("lods%c\n", nameISize(sz));
4155 break;
sewardjde4a1d02002-03-22 01:27:54 +00004156
4157 case 0xAE: /* SCASb, no REP prefix */
4158 codegen_SCAS ( cb, 1 );
4159 if (dis) VG_(printf)("scasb\n");
4160 break;
4161
4162 case 0xFC: /* CLD */
4163 uInstr0(cb, CALLM_S, 0);
4164 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CLD));
4165 uFlagsRWU(cb, FlagsEmpty, FlagD, FlagsEmpty);
4166 uInstr0(cb, CALLM_E, 0);
4167 if (dis) VG_(printf)("cld\n");
4168 break;
4169
4170 case 0xFD: /* STD */
4171 uInstr0(cb, CALLM_S, 0);
4172 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_STD));
4173 uFlagsRWU(cb, FlagsEmpty, FlagD, FlagsEmpty);
4174 uInstr0(cb, CALLM_E, 0);
4175 if (dis) VG_(printf)("std\n");
4176 break;
4177
sewardj7d78e782002-06-02 00:04:00 +00004178 case 0xF8: /* CLC */
4179 uInstr0(cb, CALLM_S, 0);
4180 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CLC));
4181 uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
4182 uInstr0(cb, CALLM_E, 0);
4183 if (dis) VG_(printf)("clc\n");
4184 break;
4185
4186 case 0xF9: /* STC */
4187 uInstr0(cb, CALLM_S, 0);
4188 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_STC));
4189 uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZCP);
4190 uInstr0(cb, CALLM_E, 0);
4191 if (dis) VG_(printf)("stc\n");
4192 break;
4193
sewardjde4a1d02002-03-22 01:27:54 +00004194 case 0xF2: { /* REPNE prefix insn */
4195 Addr eip_orig = eip - 1;
4196 abyte = getUChar(eip); eip++;
4197 if (abyte == 0x66) { sz = 2; abyte = getUChar(eip); eip++; }
4198
4199 if (abyte == 0xAE || 0xAF) { /* REPNE SCAS<sz> */
4200 if (abyte == 0xAE) sz = 1;
4201 codegen_REPNE_SCAS ( cb, sz, eip_orig, eip );
4202 *isEnd = True;
4203 if (dis) VG_(printf)("repne scas%c\n", nameISize(sz));
4204 }
4205 else {
4206 VG_(printf)("REPNE then 0x%x\n", (UInt)abyte);
njne427a662002-10-02 11:08:25 +00004207 VG_(core_panic)("Unhandled REPNE case");
sewardjde4a1d02002-03-22 01:27:54 +00004208 }
4209 break;
4210 }
4211
4212 case 0xF3: { /* REPE prefix insn */
4213 Addr eip_orig = eip - 1;
4214 abyte = getUChar(eip); eip++;
4215 if (abyte == 0x66) { sz = 2; abyte = getUChar(eip); eip++; }
4216
4217 if (abyte == 0xA4 || abyte == 0xA5) { /* REPE MOV<sz> */
4218 if (abyte == 0xA4) sz = 1;
4219 codegen_REPE_MOVS ( cb, sz, eip_orig, eip );
4220 *isEnd = True;
4221 if (dis) VG_(printf)("repe mov%c\n", nameISize(sz));
4222 }
4223 else
4224 if (abyte == 0xA6 || abyte == 0xA7) { /* REPE CMP<sz> */
4225 if (abyte == 0xA6) sz = 1;
4226 codegen_REPE_CMPS ( cb, sz, eip_orig, eip );
4227 *isEnd = True;
4228 if (dis) VG_(printf)("repe cmps%c\n", nameISize(sz));
4229 }
4230 else
4231 if (abyte == 0xAA || abyte == 0xAB) { /* REPE STOS<sz> */
4232 if (abyte == 0xAA) sz = 1;
4233 codegen_REPE_STOS ( cb, sz, eip_orig, eip );
4234 *isEnd = True;
4235 if (dis) VG_(printf)("repe stos%c\n", nameISize(sz));
sewardj7cba7152002-07-13 12:32:16 +00004236 }
4237 else
4238 if (abyte == 0x90) { /* REPE NOP (PAUSE) */
4239 if (dis) VG_(printf)("repe nop (P4 pause)\n");
4240 /* do nothing; apparently a hint to the P4 re spin-wait loop */
sewardjde4a1d02002-03-22 01:27:54 +00004241 } else {
4242 VG_(printf)("REPE then 0x%x\n", (UInt)abyte);
njne427a662002-10-02 11:08:25 +00004243 VG_(core_panic)("Unhandled REPE case");
sewardjde4a1d02002-03-22 01:27:54 +00004244 }
4245 break;
4246 }
4247
4248 /* ------------------------ XCHG ----------------------- */
4249
4250 case 0x86: /* XCHG Gb,Eb */
4251 sz = 1;
4252 /* Fall through ... */
4253 case 0x87: /* XCHG Gv,Ev */
4254 modrm = getUChar(eip);
4255 t1 = newTemp(cb); t2 = newTemp(cb);
4256 if (epartIsReg(modrm)) {
4257 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
4258 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t2);
4259 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, gregOfRM(modrm));
4260 uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, eregOfRM(modrm));
4261 eip++;
4262 if (dis)
4263 VG_(printf)("xchg%c %s, %s\n", nameISize(sz),
4264 nameIReg(sz,gregOfRM(modrm)),
4265 nameIReg(sz,eregOfRM(modrm)));
4266 } else {
sewardje1042472002-09-30 12:33:11 +00004267 pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL);
sewardjde4a1d02002-03-22 01:27:54 +00004268 t3 = LOW24(pair);
4269 uInstr2(cb, LOAD, sz, TempReg, t3, TempReg, t1);
4270 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t2);
4271 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t3);
sewardjde4a1d02002-03-22 01:27:54 +00004272 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, gregOfRM(modrm));
4273 eip += HI8(pair);
4274 if (dis)
4275 VG_(printf)("xchg%c %s, %s\n", nameISize(sz),
4276 nameIReg(sz,gregOfRM(modrm)),
4277 dis_buf);
4278 }
4279 break;
4280
4281 case 0x90: /* XCHG eAX,eAX */
4282 if (dis) VG_(printf)("nop\n");
4283 break;
sewardj6ca4c022002-10-05 14:36:26 +00004284 case 0x91: /* XCHG eAX,eCX */
4285 case 0x92: /* XCHG eAX,eDX */
4286 case 0x93: /* XCHG eAX,eBX */
sewardjde4a1d02002-03-22 01:27:54 +00004287 case 0x96: /* XCHG eAX,eSI */
4288 case 0x97: /* XCHG eAX,eDI */
4289 codegen_xchg_eAX_Reg ( cb, sz, opc - 0x90 );
4290 break;
4291
4292 /* ------------------------ (Grp1 extensions) ---------- */
4293
4294 case 0x80: /* Grp1 Ib,Eb */
4295 modrm = getUChar(eip);
4296 am_sz = lengthAMode(eip);
4297 sz = 1;
4298 d_sz = 1;
4299 d32 = getSDisp8(eip + am_sz);
sewardje1042472002-09-30 12:33:11 +00004300 eip = dis_Grp1 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00004301 break;
4302
4303 case 0x81: /* Grp1 Iv,Ev */
4304 modrm = getUChar(eip);
4305 am_sz = lengthAMode(eip);
4306 d_sz = sz;
4307 d32 = getUDisp(d_sz, eip + am_sz);
sewardje1042472002-09-30 12:33:11 +00004308 eip = dis_Grp1 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00004309 break;
4310
4311 case 0x83: /* Grp1 Ib,Ev */
4312 modrm = getUChar(eip);
4313 am_sz = lengthAMode(eip);
4314 d_sz = 1;
4315 d32 = getSDisp8(eip + am_sz);
sewardje1042472002-09-30 12:33:11 +00004316 eip = dis_Grp1 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00004317 break;
4318
4319 /* ------------------------ (Grp2 extensions) ---------- */
4320
4321 case 0xC0: /* Grp2 Ib,Eb */
4322 modrm = getUChar(eip);
4323 am_sz = lengthAMode(eip);
4324 d_sz = 1;
4325 d32 = getSDisp8(eip + am_sz);
4326 sz = 1;
sewardje1042472002-09-30 12:33:11 +00004327 eip = dis_Grp2 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00004328 break;
4329
4330 case 0xC1: /* Grp2 Ib,Ev */
4331 modrm = getUChar(eip);
4332 am_sz = lengthAMode(eip);
4333 d_sz = 1;
4334 d32 = getSDisp8(eip + am_sz);
sewardje1042472002-09-30 12:33:11 +00004335 eip = dis_Grp2 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00004336 break;
4337
4338 case 0xD0: /* Grp2 1,Eb */
4339 modrm = getUChar(eip);
4340 am_sz = lengthAMode(eip);
4341 d_sz = 0;
4342 d32 = 1;
4343 sz = 1;
sewardje1042472002-09-30 12:33:11 +00004344 eip = dis_Grp2 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00004345 break;
4346
4347 case 0xD1: /* Grp2 1,Ev */
4348 modrm = getUChar(eip);
4349 am_sz = lengthAMode(eip);
4350 d_sz = 0;
4351 d32 = 1;
sewardje1042472002-09-30 12:33:11 +00004352 eip = dis_Grp2 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00004353 break;
4354
njn25e49d8e72002-09-23 09:36:25 +00004355 case 0xD2: /* Grp2 CL,Eb */
4356 modrm = getUChar(eip);
4357 am_sz = lengthAMode(eip);
4358 d_sz = 0;
4359 sz = 1;
sewardje1042472002-09-30 12:33:11 +00004360 eip = dis_Grp2 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, ArchReg, R_ECX );
njn25e49d8e72002-09-23 09:36:25 +00004361 break;
4362
sewardjde4a1d02002-03-22 01:27:54 +00004363 case 0xD3: /* Grp2 CL,Ev */
4364 modrm = getUChar(eip);
4365 am_sz = lengthAMode(eip);
4366 d_sz = 0;
sewardje1042472002-09-30 12:33:11 +00004367 eip = dis_Grp2 ( cb, sorb, eip, modrm, am_sz, d_sz, sz, ArchReg, R_ECX );
sewardjde4a1d02002-03-22 01:27:54 +00004368 break;
4369
4370 /* ------------------------ (Grp3 extensions) ---------- */
4371
4372 case 0xF6: /* Grp3 Eb */
sewardje1042472002-09-30 12:33:11 +00004373 eip = dis_Grp3 ( cb, sorb, 1, eip );
sewardjde4a1d02002-03-22 01:27:54 +00004374 break;
4375 case 0xF7: /* Grp3 Ev */
sewardje1042472002-09-30 12:33:11 +00004376 eip = dis_Grp3 ( cb, sorb, sz, eip );
sewardjde4a1d02002-03-22 01:27:54 +00004377 break;
4378
4379 /* ------------------------ (Grp4 extensions) ---------- */
4380
4381 case 0xFE: /* Grp4 Eb */
sewardje1042472002-09-30 12:33:11 +00004382 eip = dis_Grp4 ( cb, sorb, eip );
sewardjde4a1d02002-03-22 01:27:54 +00004383 break;
4384
4385 /* ------------------------ (Grp5 extensions) ---------- */
4386
4387 case 0xFF: /* Grp5 Ev */
sewardje1042472002-09-30 12:33:11 +00004388 eip = dis_Grp5 ( cb, sorb, sz, eip, isEnd );
sewardjde4a1d02002-03-22 01:27:54 +00004389 break;
4390
4391 /* ------------------------ Escapes to 2-byte opcodes -- */
4392
4393 case 0x0F: {
4394 opc = getUChar(eip); eip++;
4395 switch (opc) {
4396
4397 /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
4398
4399 case 0xBA: /* Grp8 Ib,Ev */
4400 modrm = getUChar(eip);
4401 am_sz = lengthAMode(eip);
4402 d32 = getSDisp8(eip + am_sz);
sewardje1042472002-09-30 12:33:11 +00004403 eip = dis_Grp8_BT ( cb, sorb, eip, modrm, am_sz, sz, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00004404 break;
sewardj0ece28b2002-04-16 00:42:12 +00004405
sewardjde4a1d02002-03-22 01:27:54 +00004406 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
4407
4408 case 0xBC: /* BSF Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00004409 eip = dis_bs_E_G ( cb, sorb, sz, eip, True );
sewardjde4a1d02002-03-22 01:27:54 +00004410 break;
4411 case 0xBD: /* BSR Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00004412 eip = dis_bs_E_G ( cb, sorb, sz, eip, False );
sewardjde4a1d02002-03-22 01:27:54 +00004413 break;
4414
4415 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
4416
4417 case 0xC8: /* BSWAP %eax */
4418 case 0xC9:
4419 case 0xCA:
4420 case 0xCB:
4421 case 0xCC:
4422 case 0xCD:
4423 case 0xCE:
4424 case 0xCF: /* BSWAP %edi */
4425 /* AFAICS from the Intel docs, this only exists at size 4. */
4426 vg_assert(sz == 4);
4427 t1 = newTemp(cb);
4428 uInstr2(cb, GET, 4, ArchReg, opc-0xC8, TempReg, t1);
4429 uInstr1(cb, BSWAP, 4, TempReg, t1);
4430 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, opc-0xC8);
4431 if (dis) VG_(printf)("bswapl %s\n", nameIReg(4, opc-0xC8));
4432 break;
4433
4434 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
4435
4436 case 0xA3: /* BT Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00004437 eip = dis_bt_G_E ( cb, sorb, sz, eip, BtOpNone );
sewardjde4a1d02002-03-22 01:27:54 +00004438 break;
4439 case 0xB3: /* BTR Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00004440 eip = dis_bt_G_E ( cb, sorb, sz, eip, BtOpReset );
sewardjde4a1d02002-03-22 01:27:54 +00004441 break;
4442 case 0xAB: /* BTS Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00004443 eip = dis_bt_G_E ( cb, sorb, sz, eip, BtOpSet );
sewardjde4a1d02002-03-22 01:27:54 +00004444 break;
4445 case 0xBB: /* BTC Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00004446 eip = dis_bt_G_E ( cb, sorb, sz, eip, BtOpComp );
sewardjde4a1d02002-03-22 01:27:54 +00004447 break;
4448
4449 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
4450
4451 case 0x40:
4452 case 0x41:
4453 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
4454 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
4455 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
4456 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
4457 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
4458 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
4459 case 0x48: /* CMOVSb (cmov negative) */
4460 case 0x49: /* CMOVSb (cmov not negative) */
4461 case 0x4A: /* CMOVP (cmov parity even) */
sewardj969129d2002-04-21 11:43:11 +00004462 case 0x4B: /* CMOVNP (cmov parity odd) */
sewardjde4a1d02002-03-22 01:27:54 +00004463 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
4464 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
4465 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
4466 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
sewardje1042472002-09-30 12:33:11 +00004467 eip = dis_cmov_E_G(cb, sorb, sz, (Condcode)(opc - 0x40), eip);
sewardjde4a1d02002-03-22 01:27:54 +00004468 break;
4469
4470 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
4471
4472 case 0xB1: /* CMPXCHG Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00004473 eip = dis_cmpxchg_G_E ( cb, sorb, sz, eip );
sewardjde4a1d02002-03-22 01:27:54 +00004474 break;
4475
4476 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
4477
4478 case 0xA2: /* CPUID */
4479 t1 = newTemp(cb);
4480 t2 = newTemp(cb);
4481 t3 = newTemp(cb);
4482 t4 = newTemp(cb);
4483 uInstr0(cb, CALLM_S, 0);
4484
4485 uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t1);
4486 uInstr1(cb, PUSH, 4, TempReg, t1);
4487
4488 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
4489 uLiteral(cb, 0);
4490 uInstr1(cb, PUSH, 4, TempReg, t2);
4491
4492 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t3);
4493 uLiteral(cb, 0);
4494 uInstr1(cb, PUSH, 4, TempReg, t3);
4495
4496 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
4497 uLiteral(cb, 0);
4498 uInstr1(cb, PUSH, 4, TempReg, t4);
4499
4500 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CPUID));
4501 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
4502
4503 uInstr1(cb, POP, 4, TempReg, t4);
4504 uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_EDX);
4505
4506 uInstr1(cb, POP, 4, TempReg, t3);
4507 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ECX);
4508
4509 uInstr1(cb, POP, 4, TempReg, t2);
4510 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBX);
4511
4512 uInstr1(cb, POP, 4, TempReg, t1);
4513 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
4514
4515 uInstr0(cb, CALLM_E, 0);
4516 if (dis) VG_(printf)("cpuid\n");
4517 break;
4518
4519 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
4520
4521 case 0xB6: /* MOVZXb Eb,Gv */
sewardje1042472002-09-30 12:33:11 +00004522 eip = dis_movx_E_G ( cb, sorb, eip, 1, 4, False );
sewardjde4a1d02002-03-22 01:27:54 +00004523 break;
4524 case 0xB7: /* MOVZXw Ew,Gv */
sewardje1042472002-09-30 12:33:11 +00004525 eip = dis_movx_E_G ( cb, sorb, eip, 2, 4, False );
sewardjde4a1d02002-03-22 01:27:54 +00004526 break;
4527
4528 case 0xBE: /* MOVSXb Eb,Gv */
sewardje1042472002-09-30 12:33:11 +00004529 eip = dis_movx_E_G ( cb, sorb, eip, 1, 4, True );
sewardjde4a1d02002-03-22 01:27:54 +00004530 break;
4531 case 0xBF: /* MOVSXw Ew,Gv */
sewardje1042472002-09-30 12:33:11 +00004532 eip = dis_movx_E_G ( cb, sorb, eip, 2, 4, True );
sewardjde4a1d02002-03-22 01:27:54 +00004533 break;
4534
4535 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
4536
4537 case 0xAF: /* IMUL Ev, Gv */
sewardje1042472002-09-30 12:33:11 +00004538 eip = dis_mul_E_G ( cb, sorb, sz, eip, True );
sewardjde4a1d02002-03-22 01:27:54 +00004539 break;
4540
4541 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
4542 case 0x80:
4543 case 0x81:
4544 case 0x82: /* JBb/JNAEb (jump below) */
4545 case 0x83: /* JNBb/JAEb (jump not below) */
4546 case 0x84: /* JZb/JEb (jump zero) */
4547 case 0x85: /* JNZb/JNEb (jump not zero) */
4548 case 0x86: /* JBEb/JNAb (jump below or equal) */
4549 case 0x87: /* JNBEb/JAb (jump not below or equal) */
4550 case 0x88: /* JSb (jump negative) */
4551 case 0x89: /* JSb (jump not negative) */
4552 case 0x8A: /* JP (jump parity even) */
sewardj969129d2002-04-21 11:43:11 +00004553 case 0x8B: /* JNP/JPO (jump parity odd) */
sewardjde4a1d02002-03-22 01:27:54 +00004554 case 0x8C: /* JLb/JNGEb (jump less) */
4555 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
4556 case 0x8E: /* JLEb/JNGb (jump less or equal) */
4557 case 0x8F: /* JGb/JNLEb (jump greater) */
4558 d32 = (eip+4) + getUDisp32(eip); eip += 4;
4559 uInstr1(cb, JMP, 0, Literal, 0);
4560 uLiteral(cb, d32);
4561 uCond(cb, (Condcode)(opc - 0x80));
4562 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
4563 uInstr1(cb, JMP, 0, Literal, 0);
4564 uLiteral(cb, eip);
4565 uCond(cb, CondAlways);
4566 *isEnd = True;
4567 if (dis)
4568 VG_(printf)("j%s-32 0x%x\n",
4569 VG_(nameCondcode)(opc - 0x80), d32);
4570 break;
4571
4572 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
4573
4574 case 0x31: /* RDTSC */
4575 t1 = newTemp(cb);
4576 t2 = newTemp(cb);
4577 t3 = newTemp(cb);
4578 uInstr0(cb, CALLM_S, 0);
4579 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
4580 uLiteral(cb, 0);
4581 uInstr1(cb, PUSH, 4, TempReg, t1);
4582 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
4583 uLiteral(cb, 0);
4584 uInstr1(cb, PUSH, 4, TempReg, t2);
4585 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_RDTSC));
4586 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
4587 uInstr1(cb, POP, 4, TempReg, t3);
4588 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EDX);
4589 uInstr1(cb, POP, 4, TempReg, t3);
4590 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EAX);
4591 uInstr0(cb, CALLM_E, 0);
4592 if (dis) VG_(printf)("rdtsc\n");
4593 break;
4594
4595 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
4596 case 0x90:
4597 case 0x91:
4598 case 0x92: /* set-Bb/set-NAEb (jump below) */
4599 case 0x93: /* set-NBb/set-AEb (jump not below) */
4600 case 0x94: /* set-Zb/set-Eb (jump zero) */
4601 case 0x95: /* set-NZb/set-NEb (jump not zero) */
4602 case 0x96: /* set-BEb/set-NAb (jump below or equal) */
4603 case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
4604 case 0x98: /* set-Sb (jump negative) */
4605 case 0x99: /* set-Sb (jump not negative) */
4606 case 0x9A: /* set-P (jump parity even) */
4607 case 0x9B: /* set-NP (jump parity odd) */
4608 case 0x9C: /* set-Lb/set-NGEb (jump less) */
4609 case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
4610 case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
4611 case 0x9F: /* set-Gb/set-NLEb (jump greater) */
4612 modrm = getUChar(eip);
4613 t1 = newTemp(cb);
4614 if (epartIsReg(modrm)) {
4615 eip++;
4616 uInstr1(cb, CC2VAL, 1, TempReg, t1);
4617 uCond(cb, (Condcode)(opc-0x90));
4618 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
4619 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, eregOfRM(modrm));
4620 if (dis) VG_(printf)("set%s %s\n",
4621 VG_(nameCondcode)(opc-0x90),
4622 nameIReg(1,eregOfRM(modrm)));
4623 } else {
sewardje1042472002-09-30 12:33:11 +00004624 pair = disAMode ( cb, sorb, eip, dis?dis_buf:NULL );
sewardjde4a1d02002-03-22 01:27:54 +00004625 t2 = LOW24(pair);
4626 eip += HI8(pair);
4627 uInstr1(cb, CC2VAL, 1, TempReg, t1);
4628 uCond(cb, (Condcode)(opc-0x90));
4629 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
4630 uInstr2(cb, STORE, 1, TempReg, t1, TempReg, t2);
sewardjde4a1d02002-03-22 01:27:54 +00004631 if (dis) VG_(printf)("set%s %s\n",
4632 VG_(nameCondcode)(opc-0x90),
4633 dis_buf);
4634 }
4635 break;
4636
4637 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
4638
4639 case 0xA4: /* SHLDv imm8,Gv,Ev */
4640 modrm = getUChar(eip);
4641 eip = dis_SHLRD_Gv_Ev (
sewardje1042472002-09-30 12:33:11 +00004642 cb, sorb, eip, modrm, sz,
sewardjde4a1d02002-03-22 01:27:54 +00004643 Literal, getUChar(eip + lengthAMode(eip)),
4644 True );
4645 break;
4646 case 0xA5: /* SHLDv %cl,Gv,Ev */
4647 modrm = getUChar(eip);
4648 eip = dis_SHLRD_Gv_Ev (
sewardje1042472002-09-30 12:33:11 +00004649 cb, sorb, eip, modrm, sz, ArchReg, R_CL, True );
sewardjde4a1d02002-03-22 01:27:54 +00004650 break;
4651
4652 case 0xAC: /* SHRDv imm8,Gv,Ev */
4653 modrm = getUChar(eip);
4654 eip = dis_SHLRD_Gv_Ev (
sewardje1042472002-09-30 12:33:11 +00004655 cb, sorb, eip, modrm, sz,
sewardjde4a1d02002-03-22 01:27:54 +00004656 Literal, getUChar(eip + lengthAMode(eip)),
4657 False );
4658 break;
4659 case 0xAD: /* SHRDv %cl,Gv,Ev */
4660 modrm = getUChar(eip);
4661 eip = dis_SHLRD_Gv_Ev (
sewardje1042472002-09-30 12:33:11 +00004662 cb, sorb, eip, modrm, sz, ArchReg, R_CL, False );
sewardjde4a1d02002-03-22 01:27:54 +00004663 break;
4664
4665 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
4666
4667 case 0xC1: /* XADD Gv,Ev */
sewardje1042472002-09-30 12:33:11 +00004668 eip = dis_xadd_G_E ( cb, sorb, sz, eip );
sewardjde4a1d02002-03-22 01:27:54 +00004669 break;
4670
4671 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
4672
4673 default:
4674 VG_(printf)("disInstr: unhandled 2-byte opcode 0x%x\n",
4675 (UInt)opc);
sewardj12ffdac2002-07-25 22:41:40 +00004676 VG_(printf)("This _might_ be the result of executing an "
4677 "MMX, SSE, SSE2 or 3DNow!\n" );
4678 VG_(printf)("instruction. Valgrind does not currently "
4679 "support such instructions. Sorry.\n" );
sewardjde4a1d02002-03-22 01:27:54 +00004680 VG_(unimplemented)("unhandled x86 0x0F 2-byte opcode");
4681 }
4682
4683 break;
4684 }
4685
4686 /* ------------------------ ??? ------------------------ */
4687
4688 default:
4689 VG_(printf)("disInstr: unhandled opcode 0x%x then 0x%x\n",
4690 (UInt)opc, (UInt)getUChar(eip));
njne427a662002-10-02 11:08:25 +00004691 VG_(core_panic)("unhandled x86 opcode");
sewardjde4a1d02002-03-22 01:27:54 +00004692 }
4693
4694 if (dis)
4695 VG_(printf)("\n");
4696 for (; first_uinstr < cb->used; first_uinstr++) {
njn25e49d8e72002-09-23 09:36:25 +00004697 Bool sane = VG_(saneUInstr)(True, True, &cb->instrs[first_uinstr]);
4698 if (dis)
njn4ba5a792002-09-30 10:23:54 +00004699 VG_(pp_UInstr)(first_uinstr, &cb->instrs[first_uinstr]);
njn25e49d8e72002-09-23 09:36:25 +00004700 else if (!sane)
njn4ba5a792002-09-30 10:23:54 +00004701 VG_(up_UInstr)(-1, &cb->instrs[first_uinstr]);
sewardjde4a1d02002-03-22 01:27:54 +00004702 vg_assert(sane);
4703 }
4704
4705 return eip;
4706}
4707
4708
4709/* Disassemble a complete basic block, starting at eip, and dumping
4710 the ucode into cb. Returns the size, in bytes, of the basic
4711 block. */
4712
4713Int VG_(disBB) ( UCodeBlock* cb, Addr eip0 )
4714{
4715 Addr eip = eip0;
4716 Bool isEnd = False;
4717 Bool block_sane;
njn4f9c9342002-04-29 16:03:24 +00004718 Int delta = 0;
4719
njn25e49d8e72002-09-23 09:36:25 +00004720 if (dis) VG_(printf)("Original x86 code to UCode:\n\n");
sewardjde4a1d02002-03-22 01:27:54 +00004721
njn25e49d8e72002-09-23 09:36:25 +00004722 /* After every x86 instruction do an INCEIP, except for the final one
4723 * in the basic block. For them we patch in the x86 instruction size
4724 * into the `extra4b' field of the basic-block-ending JMP.
njn4f9c9342002-04-29 16:03:24 +00004725 *
njn25e49d8e72002-09-23 09:36:25 +00004726 * The INCEIPs and JMP.extra4b fields allows a skin to track x86
4727 * instruction sizes, important for some skins (eg. cache simulation).
njn4f9c9342002-04-29 16:03:24 +00004728 */
sewardjde4a1d02002-03-22 01:27:54 +00004729 if (VG_(clo_single_step)) {
4730 eip = disInstr ( cb, eip, &isEnd );
njn4f9c9342002-04-29 16:03:24 +00004731
4732 /* Add a JMP to the next (single x86 instruction) BB if it doesn't
4733 * already end with a JMP instr. We also need to check for no UCode,
4734 * which occurs if the x86 instr was a nop */
4735 if (cb->used == 0 || LAST_UINSTR(cb).opcode != JMP) {
4736 uInstr1(cb, JMP, 0, Literal, 0);
4737 uLiteral(cb, eip);
4738 uCond(cb, CondAlways);
njn25e49d8e72002-09-23 09:36:25 +00004739 /* Print added JMP */
njn4ba5a792002-09-30 10:23:54 +00004740 if (dis) VG_(pp_UInstr)(cb->used-1, &cb->instrs[cb->used-1]);
njn4f9c9342002-04-29 16:03:24 +00004741 }
njn25e49d8e72002-09-23 09:36:25 +00004742 if (dis) VG_(printf)("\n");
njn4f9c9342002-04-29 16:03:24 +00004743 delta = eip - eip0;
4744
sewardjde4a1d02002-03-22 01:27:54 +00004745 } else {
sewardjde4a1d02002-03-22 01:27:54 +00004746 Addr eip2;
njn4f9c9342002-04-29 16:03:24 +00004747 while (!isEnd) {
sewardjde4a1d02002-03-22 01:27:54 +00004748 eip2 = disInstr ( cb, eip, &isEnd );
njn25e49d8e72002-09-23 09:36:25 +00004749 delta = (eip2 - eip);
sewardjde4a1d02002-03-22 01:27:54 +00004750 eip = eip2;
sewardjde4a1d02002-03-22 01:27:54 +00004751 /* Split up giant basic blocks into pieces, so the
4752 translations fall within 64k. */
njn4f9c9342002-04-29 16:03:24 +00004753 if (eip - eip0 > 2000 && !isEnd) {
sewardja0f921a2002-05-08 00:42:25 +00004754 if (VG_(clo_verbosity) > 2)
njn4f9c9342002-04-29 16:03:24 +00004755 VG_(message)(Vg_DebugMsg,
sewardjde4a1d02002-03-22 01:27:54 +00004756 "Warning: splitting giant basic block into pieces");
4757 uInstr1(cb, JMP, 0, Literal, 0);
4758 uLiteral(cb, eip);
4759 uCond(cb, CondAlways);
njn25e49d8e72002-09-23 09:36:25 +00004760 /* Print added JMP */
njn4ba5a792002-09-30 10:23:54 +00004761 if (dis) VG_(pp_UInstr)(cb->used-1, &cb->instrs[cb->used-1]);
njn4f9c9342002-04-29 16:03:24 +00004762 isEnd = True;
4763
njn25e49d8e72002-09-23 09:36:25 +00004764 } else if (!isEnd) {
njn4f9c9342002-04-29 16:03:24 +00004765 uInstr1(cb, INCEIP, 0, Lit16, delta);
njn25e49d8e72002-09-23 09:36:25 +00004766 /* Print added INCEIP */
njn4ba5a792002-09-30 10:23:54 +00004767 if (dis) VG_(pp_UInstr)(cb->used-1, &cb->instrs[cb->used-1]);
sewardjde4a1d02002-03-22 01:27:54 +00004768 }
4769 if (dis) VG_(printf)("\n");
4770 }
4771 }
sewardjde4a1d02002-03-22 01:27:54 +00004772
njn25e49d8e72002-09-23 09:36:25 +00004773 /* Patch instruction size into final JMP. */
4774 LAST_UINSTR(cb).extra4b = delta;
4775
4776 block_sane = VG_(saneUCodeBlockCalls)(cb);
sewardjde4a1d02002-03-22 01:27:54 +00004777 if (!block_sane) {
njn4ba5a792002-09-30 10:23:54 +00004778 VG_(pp_UCodeBlock)(cb, "block failing sanity check");
sewardjde4a1d02002-03-22 01:27:54 +00004779 vg_assert(block_sane);
4780 }
4781
4782 return eip - eip0;
4783}
4784
njn25e49d8e72002-09-23 09:36:25 +00004785#undef dis
sewardjde4a1d02002-03-22 01:27:54 +00004786
4787/*--------------------------------------------------------------------*/
4788/*--- end vg_to_ucode.c ---*/
4789/*--------------------------------------------------------------------*/