blob: 3bc7bb016e8c3f626fcfa5e3de1bbfdc84e11f24 [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/*
8 This file is part of Valgrind, an x86 protected-mode emulator
9 designed for debugging and profiling binaries on x86-Unixes.
10
11 Copyright (C) 2000-2002 Julian Seward
12 jseward@acm.org
13 Julian_Seward@muraroa.demon.co.uk
14
15 This program is free software; you can redistribute it and/or
16 modify it under the terms of the GNU General Public License as
17 published by the Free Software Foundation; either version 2 of the
18 License, or (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, write to the Free Software
27 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28 02111-1307, USA.
29
30 The GNU General Public License is contained in the file LICENSE.
31*/
32
33#include "vg_include.h"
34
35
36/*------------------------------------------------------------*/
37/*--- Renamings of frequently-used global functions. ---*/
38/*------------------------------------------------------------*/
39
40#define uInstr0 VG_(newUInstr0)
41#define uInstr1 VG_(newUInstr1)
42#define uInstr2 VG_(newUInstr2)
43#define uInstr3 VG_(newUInstr3)
44#define dis VG_(disassemble)
45#define nameIReg VG_(nameOfIntReg)
46#define nameISize VG_(nameOfIntSize)
47#define newTemp VG_(getNewTemp)
48#define uLiteral VG_(setLiteralField)
49
50
51/*------------------------------------------------------------*/
52/*--- Here so it can be inlined everywhere. ---*/
53/*------------------------------------------------------------*/
54
55/* Allocate a new temp reg number. */
56__inline__ Int VG_(getNewTemp) ( UCodeBlock* cb )
57{
58 Int t = cb->nextTemp;
59 cb->nextTemp += 2;
60 return t;
61}
62
63Int VG_(getNewShadow) ( UCodeBlock* cb )
64{
65 Int t = cb->nextTemp;
66 cb->nextTemp += 2;
67 return SHADOW(t);
68}
69
70/* Handy predicates. */
71#define SMC_IF_SOME(cb) \
72 do { \
73 if (VG_(clo_smc_check) >= VG_CLO_SMC_SOME) { \
74 LAST_UINSTR((cb)).smc_check = True; \
75 } \
76 } while (0)
77
78#define SMC_IF_ALL(cb) \
79 do { \
80 if (VG_(clo_smc_check) == VG_CLO_SMC_ALL) { \
81 LAST_UINSTR((cb)).smc_check = True; \
82 } \
83 } while (0)
84
85
86/*------------------------------------------------------------*/
87/*--- Helper bits and pieces for deconstructing the ---*/
88/*--- x86 insn stream. ---*/
89/*------------------------------------------------------------*/
90
91static Char* nameGrp1 ( Int opc_aux )
92{
93 static Char* grp1_names[8]
94 = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
95 if (opc_aux < 0 || opc_aux > 7) VG_(panic)("nameGrp1");
96 return grp1_names[opc_aux];
97}
98
99static Char* nameGrp2 ( Int opc_aux )
100{
101 static Char* grp2_names[8]
102 = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
103 if (opc_aux < 0 || opc_aux > 7) VG_(panic)("nameGrp2");
104 return grp2_names[opc_aux];
105}
106
107static Char* nameGrp4 ( Int opc_aux )
108{
109 static Char* grp4_names[8]
110 = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
111 if (opc_aux < 0 || opc_aux > 1) VG_(panic)("nameGrp4");
112 return grp4_names[opc_aux];
113}
114
115static Char* nameGrp5 ( Int opc_aux )
116{
117 static Char* grp5_names[8]
118 = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
119 if (opc_aux < 0 || opc_aux > 6) VG_(panic)("nameGrp5");
120 return grp5_names[opc_aux];
121}
122
123static Char* nameGrp8 ( Int opc_aux )
124{
125 static Char* grp8_names[8]
126 = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
127 if (opc_aux < 4 || opc_aux > 7) VG_(panic)("nameGrp8");
128 return grp8_names[opc_aux];
129}
130
131Char* VG_(nameOfIntReg) ( Int size, Int reg )
132{
133 static Char* ireg32_names[8]
134 = { "%eax", "%ecx", "%edx", "%ebx",
135 "%esp", "%ebp", "%esi", "%edi" };
136 static Char* ireg16_names[8]
137 = { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di" };
138 static Char* ireg8_names[8]
139 = { "%al", "%cl", "%dl", "%bl", "%ah{sp}", "%ch{bp}", "%dh{si}", "%bh{di}" };
140 if (reg < 0 || reg > 7) goto bad;
141 switch (size) {
142 case 4: return ireg32_names[reg];
143 case 2: return ireg16_names[reg];
144 case 1: return ireg8_names[reg];
145 }
146 bad:
147 VG_(panic)("nameOfIntReg");
148 return NULL; /*notreached*/
149}
150
151Char VG_(nameOfIntSize) ( Int size )
152{
153 switch (size) {
154 case 4: return 'l';
155 case 2: return 'w';
156 case 1: return 'b';
157 default: VG_(panic)("nameOfIntSize");
158 }
159}
160
161__inline__ UInt VG_(extend_s_8to32) ( UInt x )
162{
163 return (UInt)((((Int)x) << 24) >> 24);
164}
165
166__inline__ static UInt extend_s_16to32 ( UInt x )
167{
168 return (UInt)((((Int)x) << 16) >> 16);
169}
170
171
172/* Get a byte value out of the insn stream and sign-extend to 32
173 bits. */
174__inline__ static UInt getSDisp8 ( Addr eip0 )
175{
176 UChar* eip = (UChar*)eip0;
177 return VG_(extend_s_8to32)( (UInt) (eip[0]) );
178}
179
180__inline__ static UInt getSDisp16 ( Addr eip0 )
181{
182 UChar* eip = (UChar*)eip0;
183 UInt d = *eip++;
184 d |= ((*eip++) << 8);
185 return extend_s_16to32(d);
186}
187
188/* Get a 32-bit value out of the insn stream. */
189__inline__ static UInt getUDisp32 ( Addr eip0 )
190{
191 UChar* eip = (UChar*)eip0;
192 UInt v = eip[3]; v <<= 8;
193 v |= eip[2]; v <<= 8;
194 v |= eip[1]; v <<= 8;
195 v |= eip[0];
196 return v;
197}
198
199__inline__ static UInt getUDisp16 ( Addr eip0 )
200{
201 UChar* eip = (UChar*)eip0;
202 UInt v = eip[1]; v <<= 8;
203 v |= eip[0];
204 return v;
205}
206
207__inline__ static UChar getUChar ( Addr eip0 )
208{
209 UChar* eip = (UChar*)eip0;
210 return eip[0];
211}
212
213__inline__ static UInt LOW24 ( UInt x )
214{
215 return x & 0x00FFFFFF;
216}
217
218__inline__ static UInt HI8 ( UInt x )
219{
220 return x >> 24;
221}
222
223__inline__ static UInt getUDisp ( Int size, Addr eip )
224{
225 switch (size) {
226 case 4: return getUDisp32(eip);
227 case 2: return getUDisp16(eip);
228 case 1: return getUChar(eip);
229 default: VG_(panic)("getUDisp");
230 }
231 return 0; /*notreached*/
232}
233
234__inline__ static UInt getSDisp ( Int size, Addr eip )
235{
236 switch (size) {
237 case 4: return getUDisp32(eip);
238 case 2: return getSDisp16(eip);
239 case 1: return getSDisp8(eip);
240 default: VG_(panic)("getUDisp");
241 }
242 return 0; /*notreached*/
243}
244
245
246/*------------------------------------------------------------*/
247/*--- Flag-related helpers. ---*/
248/*------------------------------------------------------------*/
249
250/* For the last uinsn inserted into cb, set the read, written and
251 undefined flags. Undefined flags are counted as written, but it
252 seems worthwhile to distinguish them.
253*/
254static __inline__ void uFlagsRWU ( UCodeBlock* cb,
255 FlagSet rr, FlagSet ww, FlagSet uu )
256{
257 VG_(setFlagRW)(
258 &LAST_UINSTR(cb), rr, VG_UNION_FLAG_SETS(ww,uu)
259 );
260}
261
262
263static void setFlagsFromUOpcode ( UCodeBlock* cb, Int uopc )
264{
265 switch (uopc) {
266 case XOR: case OR: case AND:
267 uFlagsRWU(cb, FlagsEmpty, FlagsOSZCP, FlagA); break;
268 case ADC: case SBB:
269 uFlagsRWU(cb, FlagC, FlagsOSZACP, FlagsEmpty); break;
270 case ADD: case SUB: case NEG:
271 uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty); break;
272 case INC: case DEC:
273 uFlagsRWU(cb, FlagsEmpty, FlagsOSZAP, FlagsEmpty); break;
274 case SHR: case SAR: case SHL:
275 uFlagsRWU(cb, FlagsEmpty, FlagsOSZCP, FlagA); break;
276 case ROL: case ROR:
277 uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsEmpty); break;
278 case RCR: case RCL:
279 uFlagsRWU(cb, FlagC, FlagsOC, FlagsEmpty); break;
280 case NOT:
281 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty); break;
282 default:
283 VG_(printf)("unhandled case is %s\n",
284 VG_(nameUOpcode)(True, uopc));
285 VG_(panic)("setFlagsFromUOpcode: unhandled case");
286 }
287}
288
289static __inline__ void uCond ( UCodeBlock* cb, Condcode cond )
290{
291 LAST_UINSTR(cb).cond = cond;
292}
293
294
295/*------------------------------------------------------------*/
296/*--- Disassembling addressing modes ---*/
297/*------------------------------------------------------------*/
298
299/* Generate ucode to calculate an address indicated by a ModRM and
300 following SIB bytes, getting the value in a new temporary. The
301 temporary, and the number of bytes in the address mode, are
302 returned, as a pair (length << 8) | temp. Note that this fn should
303 not be called if the R/M part of the address denotes a register
304 instead of memory. If buf is non-NULL, text of the addressing mode
305 is placed therein. */
306
307static UInt disAMode ( UCodeBlock* cb, Addr eip0, UChar* buf )
308{
309 UChar* eip = (UChar*)eip0;
310 UChar mod_reg_rm = *eip++;
311 Int tmp = newTemp(cb);
312
313 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
314 jump table seems a bit excessive.
315 */
316 mod_reg_rm &= 0xC7; /* is now XX000YYY */
317 mod_reg_rm |= (mod_reg_rm >> 3); /* is now XX0XXYYY */
318 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
319 switch (mod_reg_rm) {
320
321 /* (%eax) .. (%edi), not including (%esp) or (%ebp).
322 --> GET %reg, t
323 */
324 case 0x00: case 0x01: case 0x02: case 0x03:
325 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
326 { UChar rm = mod_reg_rm;
327 uInstr2(cb, GET, 4, ArchReg, rm, TempReg, tmp);
328 if (buf) VG_(sprintf)(buf,"(%s)", nameIReg(4,rm));
329 return (1<<24 | tmp);
330 }
331
332 /* d8(%eax) ... d8(%edi), not including d8(%esp)
333 --> GET %reg, t ; ADDL d8, t
334 */
335 case 0x08: case 0x09: case 0x0A: case 0x0B:
336 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
337 { UChar rm = mod_reg_rm & 7;
338 Int tmq = newTemp(cb);
339 UInt d = getSDisp8((Addr)eip); eip++;
340 uInstr2(cb, GET, 4, ArchReg, rm, TempReg, tmq);
341 uInstr2(cb, LEA1, 4, TempReg, tmq, TempReg, tmp);
342 LAST_UINSTR(cb).lit32 = d;
343 if (buf) VG_(sprintf)(buf,"%d(%s)", d, nameIReg(4,rm));
344 return (2<<24 | tmp);
345 }
346
347 /* d32(%eax) ... d32(%edi), not including d32(%esp)
348 --> GET %reg, t ; ADDL d8, t
349 */
350 case 0x10: case 0x11: case 0x12: case 0x13:
351 /* ! 14 */ case 0x15: case 0x16: case 0x17:
352 { UChar rm = mod_reg_rm & 7;
353 Int tmq = newTemp(cb);
354 UInt d = getUDisp32((Addr)eip); eip += 4;
355 uInstr2(cb, GET, 4, ArchReg, rm, TempReg, tmq);
356 uInstr2(cb, LEA1, 4, TempReg, tmq, TempReg, tmp);
357 LAST_UINSTR(cb).lit32 = d;
358 if (buf) VG_(sprintf)(buf,"0x%x(%s)", d, nameIReg(4,rm));
359 return (5<<24 | tmp);
360 }
361
362 /* a register, %eax .. %edi. This shouldn't happen. */
363 case 0x18: case 0x19: case 0x1A: case 0x1B:
364 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
365 VG_(panic)("disAMode: not an addr!");
366
367 /* a 32-bit literal address
368 --> MOV d32, tmp
369 */
370 case 0x05:
371 { UInt d = getUDisp32((Addr)eip); eip += 4;
372 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tmp);
373 uLiteral(cb, d);
374 if (buf) VG_(sprintf)(buf,"(0x%x)", d);
375 return (5<<24 | tmp);
376 }
377
378 case 0x04: {
379 /* SIB, with no displacement. Special cases:
380 -- %esp cannot act as an index value.
381 If index_r indicates %esp, zero is used for the index.
382 -- when mod is zero and base indicates EBP, base is instead
383 a 32-bit literal.
384 It's all madness, I tell you. Extract %index, %base and
385 scale from the SIB byte. The value denoted is then:
386 | %index == %ESP && %base == %EBP
387 = d32 following SIB byte
388 | %index == %ESP && %base != %EBP
389 = %base
390 | %index != %ESP && %base == %EBP
391 = d32 following SIB byte + (%index << scale)
392 | %index != %ESP && %base != %ESP
393 = %base + (%index << scale)
394
395 What happens to the souls of CPU architects who dream up such
396 horrendous schemes, do you suppose?
397 */
398 UChar sib = *eip++;
399 UChar scale = (sib >> 6) & 3;
400 UChar index_r = (sib >> 3) & 7;
401 UChar base_r = sib & 7;
402
403 if (index_r != R_ESP && base_r != R_EBP) {
404 Int index_tmp = newTemp(cb);
405 Int base_tmp = newTemp(cb);
406 uInstr2(cb, GET, 4, ArchReg, index_r, TempReg, index_tmp);
407 uInstr2(cb, GET, 4, ArchReg, base_r, TempReg, base_tmp);
408 uInstr3(cb, LEA2, 4, TempReg, base_tmp, TempReg, index_tmp,
409 TempReg, tmp);
410 LAST_UINSTR(cb).lit32 = 0;
411 LAST_UINSTR(cb).extra4b = 1 << scale;
412 if (buf) VG_(sprintf)(buf,"(%s,%s,%d)", nameIReg(4,base_r),
413 nameIReg(4,index_r),1<<scale);
414 return (2<<24 | tmp);
415 }
416
417 if (index_r != R_ESP && base_r == R_EBP) {
418 Int index_tmp = newTemp(cb);
419 UInt d = getUDisp32((Addr)eip); eip += 4;
420 uInstr2(cb, GET, 4, ArchReg, index_r, TempReg, index_tmp);
421 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tmp);
422 uLiteral(cb, 0);
423 uInstr3(cb, LEA2, 4, TempReg, tmp, TempReg, index_tmp,
424 TempReg, tmp);
425 LAST_UINSTR(cb).lit32 = d;
426 LAST_UINSTR(cb).extra4b = 1 << scale;
427 if (buf) VG_(sprintf)(buf,"0x%x(,%s,%d)", d,
428 nameIReg(4,index_r),1<<scale);
429 return (6<<24 | tmp);
430 }
431
432 if (index_r == R_ESP && base_r != R_EBP) {
433 uInstr2(cb, GET, 4, ArchReg, base_r, TempReg, tmp);
434 if (buf) VG_(sprintf)(buf,"(%s,,)", nameIReg(4,base_r));
435 return (2<<24 | tmp);
436 }
437
438 if (index_r == R_ESP && base_r == R_EBP) {
439 UInt d = getUDisp32((Addr)eip); eip += 4;
440 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tmp);
441 uLiteral(cb, d);
442 if (buf) VG_(sprintf)(buf,"0x%x()", d);
443 return (6<<24 | tmp);
444 }
445
446 vg_assert(0);
447 }
448
449 /* SIB, with 8-bit displacement. Special cases:
450 -- %esp cannot act as an index value.
451 If index_r indicates %esp, zero is used for the index.
452 Denoted value is:
453 | %index == %ESP
454 = d8 + %base
455 | %index != %ESP
456 = d8 + %base + (%index << scale)
457 */
458 case 0x0C: {
459 UChar sib = *eip++;
460 UChar scale = (sib >> 6) & 3;
461 UChar index_r = (sib >> 3) & 7;
462 UChar base_r = sib & 7;
463 UInt d = getSDisp8((Addr)eip); eip++;
464
465 if (index_r == R_ESP) {
466 Int tmq = newTemp(cb);
467 uInstr2(cb, GET, 4, ArchReg, base_r, TempReg, tmq);
468 uInstr2(cb, LEA1, 4, TempReg, tmq, TempReg, tmp);
469 LAST_UINSTR(cb).lit32 = d;
470 if (buf) VG_(sprintf)(buf,"%d(%s,,)", d, nameIReg(4,base_r));
471 return (3<<24 | tmp);
472 } else {
473 Int index_tmp = newTemp(cb);
474 Int base_tmp = newTemp(cb);
475 uInstr2(cb, GET, 4, ArchReg, index_r, TempReg, index_tmp);
476 uInstr2(cb, GET, 4, ArchReg, base_r, TempReg, base_tmp);
477 uInstr3(cb, LEA2, 4, TempReg, base_tmp, TempReg, index_tmp,
478 TempReg, tmp);
479 LAST_UINSTR(cb).lit32 = d;
480 LAST_UINSTR(cb).extra4b = 1 << scale;
481 if (buf) VG_(sprintf)(buf,"%d(%s,%s,%d)", d, nameIReg(4,base_r),
482 nameIReg(4,index_r), 1<<scale);
483 return (3<<24 | tmp);
484 }
485 vg_assert(0);
486 }
487
488 /* SIB, with 32-bit displacement. Special cases:
489 -- %esp cannot act as an index value.
490 If index_r indicates %esp, zero is used for the index.
491 Denoted value is:
492 | %index == %ESP
493 = d32 + %base
494 | %index != %ESP
495 = d32 + %base + (%index << scale)
496 */
497 case 0x14: {
498 UChar sib = *eip++;
499 UChar scale = (sib >> 6) & 3;
500 UChar index_r = (sib >> 3) & 7;
501 UChar base_r = sib & 7;
502 UInt d = getUDisp32((Addr)eip); eip += 4;
503
504 if (index_r == R_ESP) {
505 Int tmq = newTemp(cb);
506 uInstr2(cb, GET, 4, ArchReg, base_r, TempReg, tmq);
507 uInstr2(cb, LEA1, 4, TempReg, tmq, TempReg, tmp);
508 LAST_UINSTR(cb).lit32 = d;
509 if (buf) VG_(sprintf)(buf,"%d(%s,,)", d, nameIReg(4,base_r));
510 return (6<<24 | tmp);
511 } else {
512 Int index_tmp = newTemp(cb);
513 Int base_tmp = newTemp(cb);
514 uInstr2(cb, GET, 4, ArchReg, index_r, TempReg, index_tmp);
515 uInstr2(cb, GET, 4, ArchReg, base_r, TempReg, base_tmp);
516 uInstr3(cb, LEA2, 4, TempReg, base_tmp, TempReg, index_tmp,
517 TempReg, tmp);
518 LAST_UINSTR(cb).lit32 = d;
519 LAST_UINSTR(cb).extra4b = 1 << scale;
520 if (buf) VG_(sprintf)(buf,"%d(%s,%s,%d)", d, nameIReg(4,base_r),
521 nameIReg(4,index_r), 1<<scale);
522 return (6<<24 | tmp);
523 }
524 vg_assert(0);
525 }
526
527 default:
528 VG_(panic)("disAMode");
529 return 0; /*notreached*/
530 }
531}
532
533
534/* Figure out the number of (insn-stream) bytes constituting the amode
535 beginning at eip0. Is useful for getting hold of literals beyond
536 the end of the amode before it has been disassembled. */
537
538static UInt lengthAMode ( Addr eip0 )
539{
540 UChar* eip = (UChar*)eip0;
541 UChar mod_reg_rm = *eip++;
542
543 /* squeeze out the reg field from mod_reg_rm, since a 256-entry
544 jump table seems a bit excessive.
545 */
546 mod_reg_rm &= 0xC7; /* is now XX000YYY */
547 mod_reg_rm |= (mod_reg_rm >> 3); /* is now XX0XXYYY */
548 mod_reg_rm &= 0x1F; /* is now 000XXYYY */
549 switch (mod_reg_rm) {
550
551 /* (%eax) .. (%edi), not including (%esp) or (%ebp). */
552 case 0x00: case 0x01: case 0x02: case 0x03:
553 /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
554 return 1;
555
556 /* d8(%eax) ... d8(%edi), not including d8(%esp). */
557 case 0x08: case 0x09: case 0x0A: case 0x0B:
558 /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
559 return 2;
560
561 /* d32(%eax) ... d32(%edi), not including d32(%esp). */
562 case 0x10: case 0x11: case 0x12: case 0x13:
563 /* ! 14 */ case 0x15: case 0x16: case 0x17:
564 return 5;
565
566 /* a register, %eax .. %edi. (Not an addr, but still handled.) */
567 case 0x18: case 0x19: case 0x1A: case 0x1B:
568 case 0x1C: case 0x1D: case 0x1E: case 0x1F:
569 return 1;
570
571 /* a 32-bit literal address. */
572 case 0x05: return 5;
573
574 /* SIB, no displacement. */
575 case 0x04: {
576 UChar sib = *eip++;
577 UChar base_r = sib & 7;
578 if (base_r == R_EBP) return 6; else return 2;
579 }
580 /* SIB, with 8-bit displacement. */
581 case 0x0C: return 3;
582
583 /* SIB, with 32-bit displacement. */
584 case 0x14: return 6;
585
586 default:
587 VG_(panic)("amode_from_RM");
588 return 0; /*notreached*/
589 }
590}
591
592
593/* Extract the reg field from a modRM byte. */
594static __inline__ Int gregOfRM ( UChar mod_reg_rm )
595{
596 return (Int)( (mod_reg_rm >> 3) & 7 );
597}
598
599/* Figure out whether the mod and rm parts of a modRM byte refer to a
600 register or memory. If so, the byte will have the form 11XXXYYY,
601 where YYY is the register number. */
602static __inline__ Bool epartIsReg ( UChar mod_reg_rm )
603{
604 return (0xC0 == (mod_reg_rm & 0xC0));
605}
606
607/* ... and extract the register number ... */
608static __inline__ Int eregOfRM ( UChar mod_reg_rm )
609{
610 return (Int)(mod_reg_rm & 0x7);
611}
612
613
614/*------------------------------------------------------------*/
615/*--- Disassembling common idioms ---*/
616/*------------------------------------------------------------*/
617
618static
619void codegen_XOR_reg_with_itself ( UCodeBlock* cb, Int size,
620 Int ge_reg, Int tmp )
621{
622 if (dis)
623 VG_(printf)("xor%c %s, %s\n", nameISize(size),
624 nameIReg(size,ge_reg), nameIReg(size,ge_reg) );
625 uInstr2(cb, MOV, size, Literal, 0, TempReg, tmp);
626 uLiteral(cb, 0);
627 uInstr2(cb, XOR, size, TempReg, tmp, TempReg, tmp);
628 setFlagsFromUOpcode(cb, XOR);
629 uInstr2(cb, PUT, size, TempReg, tmp, ArchReg, ge_reg);
630}
631
632
633/* Handle binary integer instructions of the form
634 op E, G meaning
635 op reg-or-mem, reg
636 Is passed the a ptr to the modRM byte, the actual operation, and the
637 data size. Returns the address advanced completely over this
638 instruction.
639
640 E(src) is reg-or-mem
641 G(dst) is reg.
642
643 If E is reg, --> GET %G, tmp
644 OP %E, tmp
645 PUT tmp, %G
646
647 If E is mem and OP is not reversible,
648 --> (getAddr E) -> tmpa
649 LD (tmpa), tmpa
650 GET %G, tmp2
651 OP tmpa, tmp2
652 PUT tmp2, %G
653
654 If E is mem and OP is reversible
655 --> (getAddr E) -> tmpa
656 LD (tmpa), tmpa
657 OP %G, tmpa
658 PUT tmpa, %G
659*/
660static
661Addr dis_op2_E_G ( UCodeBlock* cb,
662 Opcode opc,
663 Bool keep,
664 Int size,
665 Addr eip0,
666 Char* t_x86opc )
667{
668 Bool reversible;
669 UChar rm = getUChar(eip0);
670 UChar dis_buf[50];
671
672 if (epartIsReg(rm)) {
673 Int tmp = newTemp(cb);
674
675 /* Specially handle XOR reg,reg, because that doesn't really
676 depend on reg, and doing the obvious thing potentially
677 generates a spurious value check failure due to the bogus
678 dependency. */
679 if (opc == XOR && gregOfRM(rm) == eregOfRM(rm)) {
680 codegen_XOR_reg_with_itself ( cb, size, gregOfRM(rm), tmp );
681 return 1+eip0;
682 }
683
684 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmp);
685 if (opc == AND || opc == OR) {
686 Int tao = newTemp(cb);
687 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, tao);
688 uInstr2(cb, opc, size, TempReg, tao, TempReg, tmp);
689 setFlagsFromUOpcode(cb, opc);
690 } else {
691 uInstr2(cb, opc, size, ArchReg, eregOfRM(rm), TempReg, tmp);
692 setFlagsFromUOpcode(cb, opc);
693 }
694 if (keep)
695 uInstr2(cb, PUT, size, TempReg, tmp, ArchReg, gregOfRM(rm));
696 if (dis) VG_(printf)("%s%c %s,%s\n", t_x86opc, nameISize(size),
697 nameIReg(size,eregOfRM(rm)),
698 nameIReg(size,gregOfRM(rm)));
699 return 1+eip0;
700 }
701
702 /* E refers to memory */
703 reversible
704 = (opc == ADD || opc == OR || opc == AND || opc == XOR || opc == ADC)
705 ? True : False;
706 if (reversible) {
707 UInt pair = disAMode ( cb, eip0, dis?dis_buf:NULL);
708 Int tmpa = LOW24(pair);
709 uInstr2(cb, LOAD, size, TempReg, tmpa, TempReg, tmpa);
710
711 if (opc == AND || opc == OR) {
712 Int tao = newTemp(cb);
713 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tao);
714 uInstr2(cb, opc, size, TempReg, tao, TempReg, tmpa);
715 setFlagsFromUOpcode(cb, opc);
716 } else {
717 uInstr2(cb, opc, size, ArchReg, gregOfRM(rm), TempReg, tmpa);
718 setFlagsFromUOpcode(cb, opc);
719 }
720 if (keep)
721 uInstr2(cb, PUT, size, TempReg, tmpa, ArchReg, gregOfRM(rm));
722 if (dis) VG_(printf)("%s%c %s,%s\n", t_x86opc, nameISize(size),
723 dis_buf,nameIReg(size,gregOfRM(rm)));
724 return HI8(pair)+eip0;
725 } else {
726 UInt pair = disAMode ( cb, eip0, dis?dis_buf:NULL);
727 Int tmpa = LOW24(pair);
728 Int tmp2 = newTemp(cb);
729 uInstr2(cb, LOAD, size, TempReg, tmpa, TempReg, tmpa);
730 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmp2);
731 uInstr2(cb, opc, size, TempReg, tmpa, TempReg, tmp2);
732 setFlagsFromUOpcode(cb, opc);
733 if (keep)
734 uInstr2(cb, PUT, size, TempReg, tmp2, ArchReg, gregOfRM(rm));
735 if (dis) VG_(printf)("%s%c %s,%s\n", t_x86opc, nameISize(size),
736 dis_buf,nameIReg(size,gregOfRM(rm)));
737 return HI8(pair)+eip0;
738 }
739}
740
741
742
743/* Handle binary integer instructions of the form
744 op G, E meaning
745 op reg, reg-or-mem
746 Is passed the a ptr to the modRM byte, the actual operation, and the
747 data size. Returns the address advanced completely over this
748 instruction.
749
750 G(src) is reg.
751 E(dst) is reg-or-mem
752
753 If E is reg, --> GET %E, tmp
754 OP %G, tmp
755 PUT tmp, %E
756
757 If E is mem, --> (getAddr E) -> tmpa
758 LD (tmpa), tmpv
759 OP %G, tmpv
760 ST tmpv, (tmpa)
761*/
762static
763Addr dis_op2_G_E ( UCodeBlock* cb,
764 Opcode opc,
765 Bool keep,
766 Int size,
767 Addr eip0,
768 Char* t_x86opc )
769{
770 UChar rm = getUChar(eip0);
771 UChar dis_buf[50];
772
773 if (epartIsReg(rm)) {
774 Int tmp = newTemp(cb);
775
776 /* Specially handle XOR reg,reg, because that doesn't really
777 depend on reg, and doing the obvious thing potentially
778 generates a spurious value check failure due to the bogus
779 dependency. */
780 if (opc == XOR && gregOfRM(rm) == eregOfRM(rm)) {
781 codegen_XOR_reg_with_itself ( cb, size, gregOfRM(rm), tmp );
782 return 1+eip0;
783 }
784
785 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, tmp);
786
787 if (opc == AND || opc == OR) {
788 Int tao = newTemp(cb);
789 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tao);
790 uInstr2(cb, opc, size, TempReg, tao, TempReg, tmp);
791 setFlagsFromUOpcode(cb, opc);
792 } else {
793 uInstr2(cb, opc, size, ArchReg, gregOfRM(rm), TempReg, tmp);
794 setFlagsFromUOpcode(cb, opc);
795 }
796 if (keep)
797 uInstr2(cb, PUT, size, TempReg, tmp, ArchReg, eregOfRM(rm));
798 if (dis) VG_(printf)("%s%c %s,%s\n", t_x86opc, nameISize(size),
799 nameIReg(size,gregOfRM(rm)),
800 nameIReg(size,eregOfRM(rm)));
801 return 1+eip0;
802 }
803
804 /* E refers to memory */
805 {
806 UInt pair = disAMode ( cb, eip0, dis?dis_buf:NULL);
807 Int tmpa = LOW24(pair);
808 Int tmpv = newTemp(cb);
809 uInstr2(cb, LOAD, size, TempReg, tmpa, TempReg, tmpv);
810
811 if (opc == AND || opc == OR) {
812 Int tao = newTemp(cb);
813 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tao);
814 uInstr2(cb, opc, size, TempReg, tao, TempReg, tmpv);
815 setFlagsFromUOpcode(cb, opc);
816 } else {
817 uInstr2(cb, opc, size, ArchReg, gregOfRM(rm), TempReg, tmpv);
818 setFlagsFromUOpcode(cb, opc);
819 }
820 if (keep) {
821 uInstr2(cb, STORE, size, TempReg, tmpv, TempReg, tmpa);
822 SMC_IF_ALL(cb);
823 }
824 if (dis) VG_(printf)("%s%c %s,%s\n", t_x86opc, nameISize(size),
825 nameIReg(size,gregOfRM(rm)), dis_buf);
826 return HI8(pair)+eip0;
827 }
828}
829
830
831/* Handle move instructions of the form
832 mov E, G meaning
833 mov reg-or-mem, reg
834 Is passed the a ptr to the modRM byte, and the data size. Returns
835 the address advanced completely over this instruction.
836
837 E(src) is reg-or-mem
838 G(dst) is reg.
839
840 If E is reg, --> GET %G, tmpv
841 PUT tmpv, %G
842
843 If E is mem --> (getAddr E) -> tmpa
844 LD (tmpa), tmpb
845 PUT tmpb, %G
846*/
847static
848Addr dis_mov_E_G ( UCodeBlock* cb,
849 Int size,
850 Addr eip0 )
851{
852 UChar rm = getUChar(eip0);
853 UChar dis_buf[50];
854
855 if (epartIsReg(rm)) {
856 Int tmpv = newTemp(cb);
857 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, tmpv);
858 uInstr2(cb, PUT, size, TempReg, tmpv, ArchReg, gregOfRM(rm));
859 if (dis) VG_(printf)("mov%c %s,%s\n", nameISize(size),
860 nameIReg(size,eregOfRM(rm)),
861 nameIReg(size,gregOfRM(rm)));
862 return 1+eip0;
863 }
864
865 /* E refers to memory */
866 {
867 UInt pair = disAMode ( cb, eip0, dis?dis_buf:NULL);
868 Int tmpa = LOW24(pair);
869 Int tmpb = newTemp(cb);
870 uInstr2(cb, LOAD, size, TempReg, tmpa, TempReg, tmpb);
871 uInstr2(cb, PUT, size, TempReg, tmpb, ArchReg, gregOfRM(rm));
872 if (dis) VG_(printf)("mov%c %s,%s\n", nameISize(size),
873 dis_buf,nameIReg(size,gregOfRM(rm)));
874 return HI8(pair)+eip0;
875 }
876}
877
878
879/* Handle move instructions of the form
880 mov G, E meaning
881 mov reg, reg-or-mem
882 Is passed the a ptr to the modRM byte, and the data size. Returns
883 the address advanced completely over this instruction.
884
885 G(src) is reg.
886 E(dst) is reg-or-mem
887
888 If E is reg, --> GET %G, tmp
889 PUT tmp, %E
890
891 If E is mem, --> (getAddr E) -> tmpa
892 GET %G, tmpv
893 ST tmpv, (tmpa)
894*/
895static
896Addr dis_mov_G_E ( UCodeBlock* cb,
897 Int size,
898 Addr eip0 )
899{
900 UChar rm = getUChar(eip0);
901 UChar dis_buf[50];
902
903 if (epartIsReg(rm)) {
904 Int tmpv = newTemp(cb);
905 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmpv);
906 uInstr2(cb, PUT, size, TempReg, tmpv, ArchReg, eregOfRM(rm));
907 if (dis) VG_(printf)("mov%c %s,%s\n", nameISize(size),
908 nameIReg(size,gregOfRM(rm)),
909 nameIReg(size,eregOfRM(rm)));
910 return 1+eip0;
911 }
912
913 /* E refers to memory */
914 {
915 UInt pair = disAMode ( cb, eip0, dis?dis_buf:NULL);
916 Int tmpa = LOW24(pair);
917 Int tmpv = newTemp(cb);
918 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmpv);
919 uInstr2(cb, STORE, size, TempReg, tmpv, TempReg, tmpa);
920 SMC_IF_SOME(cb);
921 if (dis) VG_(printf)("mov%c %s,%s\n", nameISize(size),
922 nameIReg(size,gregOfRM(rm)), dis_buf);
923 return HI8(pair)+eip0;
924 }
925}
926
927
928/* op $immediate, AL/AX/EAX. */
929static
930Addr dis_op_imm_A ( UCodeBlock* cb,
931 Int size,
932 Opcode opc,
933 Bool keep,
934 Addr eip,
935 Char* t_x86opc )
936{
937 Int tmp = newTemp(cb);
938 UInt lit = getUDisp(size,eip);
939 uInstr2(cb, GET, size, ArchReg, R_EAX, TempReg, tmp);
940 if (opc == AND || opc == OR) {
941 Int tao = newTemp(cb);
942 uInstr2(cb, MOV, size, Literal, 0, TempReg, tao);
943 uLiteral(cb, lit);
944 uInstr2(cb, opc, size, TempReg, tao, TempReg, tmp);
945 setFlagsFromUOpcode(cb, opc);
946 } else {
947 uInstr2(cb, opc, size, Literal, 0, TempReg, tmp);
948 uLiteral(cb, lit);
949 setFlagsFromUOpcode(cb, opc);
950 }
951 if (keep)
952 uInstr2(cb, PUT, size, TempReg, tmp, ArchReg, R_EAX);
953 if (dis) VG_(printf)("%s%c $0x%x, %s\n", t_x86opc, nameISize(size),
954 lit, nameIReg(size,R_EAX));
955 return eip+size;
956}
957
958
959/* Sign- and Zero-extending moves. */
960static
961Addr dis_movx_E_G ( UCodeBlock* cb,
962 Addr eip, Int szs, Int szd, Bool sign_extend )
963{
964 UChar dis_buf[50];
965 UChar rm = getUChar(eip);
966 if (epartIsReg(rm)) {
967 Int tmpv = newTemp(cb);
968 uInstr2(cb, GET, szs, ArchReg, eregOfRM(rm), TempReg, tmpv);
969 uInstr1(cb, WIDEN, szd, TempReg, tmpv);
970 LAST_UINSTR(cb).extra4b = szs;
971 LAST_UINSTR(cb).signed_widen = sign_extend;
972 uInstr2(cb, PUT, szd, TempReg, tmpv, ArchReg, gregOfRM(rm));
973 if (dis) VG_(printf)("mov%c%c%c %s,%s\n",
974 sign_extend ? 's' : 'z',
975 nameISize(szs), nameISize(szd),
976 nameIReg(szs,eregOfRM(rm)),
977 nameIReg(szd,gregOfRM(rm)));
978 return 1+eip;
979 }
980
981 /* E refers to memory */
982 {
983 UInt pair = disAMode ( cb, eip, dis?dis_buf:NULL);
984 Int tmpa = LOW24(pair);
985 uInstr2(cb, LOAD, szs, TempReg, tmpa, TempReg, tmpa);
986 uInstr1(cb, WIDEN, szd, TempReg, tmpa);
987 LAST_UINSTR(cb).extra4b = szs;
988 LAST_UINSTR(cb).signed_widen = sign_extend;
989 uInstr2(cb, PUT, szd, TempReg, tmpa, ArchReg, gregOfRM(rm));
990 if (dis) VG_(printf)("mov%c%c%c %s,%s\n",
991 sign_extend ? 's' : 'z',
992 nameISize(szs), nameISize(szd),
993 dis_buf,
994 nameIReg(szd,gregOfRM(rm)));
995 return HI8(pair)+eip;
996 }
997}
998
999
1000/* Generate code to divide ArchRegs EDX:EAX / DX:AX / AX by the 32 /
1001 16 / 8 bit quantity in the given TempReg. */
1002static
1003void codegen_div ( UCodeBlock* cb, Int sz, Int t, Bool signed_divide )
1004{
1005 Int helper;
1006 Int ta = newTemp(cb);
1007 Int td = newTemp(cb);
1008
1009 switch (sz) {
1010 case 4: helper = (signed_divide ? VGOFF_(helper_idiv_64_32)
1011 : VGOFF_(helper_div_64_32));
1012 break;
1013 case 2: helper = (signed_divide ? VGOFF_(helper_idiv_32_16)
1014 : VGOFF_(helper_div_32_16));
1015 break;
1016 case 1: helper = (signed_divide ? VGOFF_(helper_idiv_16_8)
1017 : VGOFF_(helper_div_16_8));
1018 break;
1019 default: VG_(panic)("codegen_div");
1020 }
1021 uInstr0(cb, CALLM_S, 0);
1022 if (sz == 4 || sz == 2) {
1023 uInstr1(cb, PUSH, sz, TempReg, t);
1024 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
1025 uInstr1(cb, PUSH, sz, TempReg, ta);
1026 uInstr2(cb, GET, sz, ArchReg, R_EDX, TempReg, td);
1027 uInstr1(cb, PUSH, sz, TempReg, td);
1028 uInstr1(cb, CALLM, 0, Lit16, helper);
1029 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsOSZACP);
1030 uInstr1(cb, POP, sz, TempReg, t);
1031 uInstr2(cb, PUT, sz, TempReg, t, ArchReg, R_EDX);
1032 uInstr1(cb, POP, sz, TempReg, t);
1033 uInstr2(cb, PUT, sz, TempReg, t, ArchReg, R_EAX);
1034 uInstr1(cb, CLEAR, 0, Lit16, 4);
1035 } else {
1036 uInstr1(cb, PUSH, 1, TempReg, t);
1037 uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, ta);
1038 uInstr1(cb, PUSH, 2, TempReg, ta);
1039 uInstr2(cb, MOV, 1, Literal, 0, TempReg, td);
1040 uLiteral(cb, 0);
1041 uInstr1(cb, PUSH, 1, TempReg, td);
1042 uInstr1(cb, CALLM, 0, Lit16, helper);
1043 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsOSZACP);
1044 uInstr1(cb, POP, 1, TempReg, t);
1045 uInstr2(cb, PUT, 1, TempReg, t, ArchReg, R_AL);
1046 uInstr1(cb, POP, 1, TempReg, t);
1047 uInstr2(cb, PUT, 1, TempReg, t, ArchReg, R_AH);
1048 uInstr1(cb, CLEAR, 0, Lit16, 4);
1049 }
1050 uInstr0(cb, CALLM_E, 0);
1051}
1052
1053
1054static
1055Addr dis_Grp1 ( UCodeBlock* cb, Addr eip, UChar modrm,
1056 Int am_sz, Int d_sz, Int sz, UInt d32 )
1057{
1058 Int t1, t2, uopc;
1059 UInt pair;
1060 UChar dis_buf[50];
1061 if (epartIsReg(modrm)) {
1062 vg_assert(am_sz == 1);
1063 t1 = newTemp(cb);
1064 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1065 switch (gregOfRM(modrm)) {
1066 case 0: uopc = ADD; break; case 1: uopc = OR; break;
1067 case 2: uopc = ADC; break; case 3: uopc = SBB; break;
1068 case 4: uopc = AND; break; case 5: uopc = SUB; break;
1069 case 6: uopc = XOR; break; case 7: uopc = SUB; break;
1070 default: VG_(panic)("dis_Grp1(Reg): unhandled case");
1071 }
1072 if (uopc == AND || uopc == OR) {
1073 Int tao = newTemp(cb);
1074 uInstr2(cb, MOV, sz, Literal, 0, TempReg, tao);
1075 uLiteral(cb, d32);
1076 uInstr2(cb, uopc, sz, TempReg, tao, TempReg, t1);
1077 setFlagsFromUOpcode(cb, uopc);
1078 } else {
1079 uInstr2(cb, uopc, sz, Literal, 0, TempReg, t1);
1080 uLiteral(cb, d32);
1081 setFlagsFromUOpcode(cb, uopc);
1082 }
1083 if (gregOfRM(modrm) < 7)
1084 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
1085 eip += (am_sz + d_sz);
1086 if (dis)
1087 VG_(printf)("%s%c $0x%x, %s\n",
1088 nameGrp1(gregOfRM(modrm)), nameISize(sz), d32,
1089 nameIReg(sz,eregOfRM(modrm)));
1090 } else {
1091 pair = disAMode ( cb, eip, dis?dis_buf:NULL);
1092 t1 = LOW24(pair);
1093 t2 = newTemp(cb);
1094 eip += HI8(pair);
1095 eip += d_sz;
1096 uInstr2(cb, LOAD, sz, TempReg, t1, TempReg, t2);
1097 switch (gregOfRM(modrm)) {
1098 case 0: uopc = ADD; break; case 1: uopc = OR; break;
1099 case 2: uopc = ADC; break; case 3: uopc = SBB; break;
1100 case 4: uopc = AND; break; case 5: uopc = SUB; break;
1101 case 6: uopc = XOR; break; case 7: uopc = SUB; break;
1102 default: VG_(panic)("dis_Grp1(Mem): unhandled case");
1103 }
1104 if (uopc == AND || uopc == OR) {
1105 Int tao = newTemp(cb);
1106 uInstr2(cb, MOV, sz, Literal, 0, TempReg, tao);
1107 uLiteral(cb, d32);
1108 uInstr2(cb, uopc, sz, TempReg, tao, TempReg, t2);
1109 setFlagsFromUOpcode(cb, uopc);
1110 } else {
1111 uInstr2(cb, uopc, sz, Literal, 0, TempReg, t2);
1112 uLiteral(cb, d32);
1113 setFlagsFromUOpcode(cb, uopc);
1114 }
1115 if (gregOfRM(modrm) < 7) {
1116 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
1117 SMC_IF_ALL(cb);
1118 }
1119 if (dis)
1120 VG_(printf)("%s%c $0x%x, %s\n",
1121 nameGrp1(gregOfRM(modrm)), nameISize(sz), d32,
1122 dis_buf);
1123 }
1124 return eip;
1125}
1126
1127
1128/* Group 2 extended opcodes. */
1129static
1130Addr dis_Grp2 ( UCodeBlock* cb, Addr eip, UChar modrm,
1131 Int am_sz, Int d_sz, Int sz,
1132 Tag orig_src_tag, UInt orig_src_val )
1133{
1134 /* orig_src_tag and orig_src_val denote either ArchReg(%CL) or a
1135 Literal. And eip on entry points at the modrm byte. */
1136 Int t1, t2, uopc;
1137 UInt pair;
1138 UChar dis_buf[50];
1139 UInt src_val;
1140 Tag src_tag;
1141
1142 /* Get the amount to be shifted by into src_tag/src_val. */
1143 if (orig_src_tag == ArchReg) {
1144 src_val = newTemp(cb);
1145 src_tag = TempReg;
1146 uInstr2(cb, GET, 1, orig_src_tag, orig_src_val, TempReg, src_val);
1147 } else {
1148 src_val = orig_src_val;
1149 src_tag = Literal;
1150 }
1151
1152 if (epartIsReg(modrm)) {
1153 vg_assert(am_sz == 1);
1154 t1 = newTemp(cb);
1155 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1156 switch (gregOfRM(modrm)) {
1157 case 0: uopc = ROL; break; case 1: uopc = ROR; break;
1158 case 2: uopc = RCL; break; case 3: uopc = RCR; break;
1159 case 4: uopc = SHL; break; case 5: uopc = SHR; break;
1160 case 7: uopc = SAR; break;
1161 default: VG_(panic)("dis_Grp2(Reg): unhandled case");
1162 }
1163 if (src_tag == Literal) {
1164 uInstr2(cb, uopc, sz, Literal, 0, TempReg, t1);
1165 uLiteral(cb, src_val);
1166 } else {
1167 uInstr2(cb, uopc, sz, src_tag, src_val, TempReg, t1);
1168 }
1169 setFlagsFromUOpcode(cb, uopc);
1170 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
1171 eip += (am_sz + d_sz);
1172 if (dis) {
1173 if (orig_src_tag == Literal)
1174 VG_(printf)("%s%c $0x%x, %s\n",
1175 nameGrp2(gregOfRM(modrm)), nameISize(sz),
1176 orig_src_val, nameIReg(sz,eregOfRM(modrm)));
1177 else
1178 VG_(printf)("%s%c %s, %s\n",
1179 nameGrp2(gregOfRM(modrm)), nameISize(sz),
1180 nameIReg(1,orig_src_val),
1181 nameIReg(sz,eregOfRM(modrm)));
1182 }
1183 } else {
1184 pair = disAMode ( cb, eip, dis?dis_buf:NULL);
1185 t1 = LOW24(pair);
1186 t2 = newTemp(cb);
1187 eip += HI8(pair);
1188 eip += d_sz;
1189 uInstr2(cb, LOAD, sz, TempReg, t1, TempReg, t2);
1190 switch (gregOfRM(modrm)) {
1191 case 0: uopc = ROL; break; case 1: uopc = ROR; break;
1192 case 2: uopc = RCL; break; case 3: uopc = RCR; break;
1193 case 4: uopc = SHL; break; case 5: uopc = SHR; break;
1194 case 7: uopc = SAR; break;
1195 default: VG_(panic)("dis_Grp2(Reg): unhandled case");
1196 }
1197 if (src_tag == Literal) {
1198 uInstr2(cb, uopc, sz, Literal, 0, TempReg, t2);
1199 uLiteral(cb, src_val);
1200 } else {
1201 uInstr2(cb, uopc, sz, src_tag, src_val, TempReg, t2);
1202 }
1203 setFlagsFromUOpcode(cb, uopc);
1204 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
1205 SMC_IF_ALL(cb);
1206 if (dis) {
1207 if (orig_src_tag == Literal)
1208 VG_(printf)("%s%c $0x%x, %s\n",
1209 nameGrp2(gregOfRM(modrm)), nameISize(sz),
1210 orig_src_val, dis_buf);
1211 else
1212 VG_(printf)("%s%c %s, %s\n",
1213 nameGrp2(gregOfRM(modrm)), nameISize(sz),
1214 nameIReg(1,orig_src_val),
1215 dis_buf);
1216 }
1217 }
1218 return eip;
1219}
1220
1221
sewardj0ece28b2002-04-16 00:42:12 +00001222
1223/* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
sewardjde4a1d02002-03-22 01:27:54 +00001224static
sewardj0ece28b2002-04-16 00:42:12 +00001225Addr dis_Grp8_BT ( UCodeBlock* cb, Addr eip, UChar modrm,
1226 Int am_sz, Int sz, UInt src_val )
sewardjde4a1d02002-03-22 01:27:54 +00001227{
sewardj0ece28b2002-04-16 00:42:12 +00001228# define MODIFY_t2_AND_SET_CARRY_FLAG \
1229 /* t2 is the value to be op'd on. Copy to t_fetched, then \
1230 modify t2, if non-BT. */ \
1231 uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t_fetched); \
1232 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
1233 uLiteral(cb, v_mask); \
1234 switch (gregOfRM(modrm)) { \
1235 case 4: /* BT */ break; \
1236 case 5: /* BTS */ \
1237 uInstr2(cb, OR, sz, TempReg, t_mask, TempReg, t2); break; \
1238 case 6: /* BTR */ \
1239 uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t2); break; \
1240 case 7: /* BTC */ \
1241 uInstr2(cb, XOR, sz, TempReg, t_mask, TempReg, t2); break; \
1242 } \
1243 /* Copy relevant bit from t_fetched into carry flag. */ \
1244 uInstr2(cb, SHR, sz, Literal, 0, TempReg, t_fetched); \
1245 uLiteral(cb, src_val); \
1246 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t_mask); \
1247 uLiteral(cb, 1); \
1248 uInstr2(cb, AND, sz, TempReg, t_mask, TempReg, t_fetched); \
1249 uInstr1(cb, NEG, sz, TempReg, t_fetched); \
1250 setFlagsFromUOpcode(cb, NEG);
1251
1252
sewardjde4a1d02002-03-22 01:27:54 +00001253 /* src_val denotes a d8.
1254 And eip on entry points at the modrm byte. */
sewardj0ece28b2002-04-16 00:42:12 +00001255 Int t1, t2, t_fetched, t_mask;
sewardjde4a1d02002-03-22 01:27:54 +00001256 UInt pair;
1257 UChar dis_buf[50];
sewardj0ece28b2002-04-16 00:42:12 +00001258 UInt v_mask;
sewardjde4a1d02002-03-22 01:27:54 +00001259
sewardj0ece28b2002-04-16 00:42:12 +00001260 /* There is no 1-byte form of this instruction, AFAICS. */
1261 vg_assert(sz == 2 || sz == 4);
1262
1263 /* Limit src_val -- the bit offset -- to something within a word.
1264 The Intel docs say that literal offsets larger than a word are
1265 masked in this way. */
1266 switch (sz) {
1267 case 2: src_val &= 15; break;
1268 case 4: src_val &= 31; break;
1269 default: VG_(panic)("dis_Grp8_BT: invalid size");
sewardjde4a1d02002-03-22 01:27:54 +00001270 }
1271
sewardj0ece28b2002-04-16 00:42:12 +00001272 /* Invent a mask suitable for the operation. */
1273
1274 switch (gregOfRM(modrm)) {
1275 case 4: /* BT */ v_mask = 0; break;
1276 case 5: /* BTS */ v_mask = 1 << src_val; break;
1277 case 6: /* BTR */ v_mask = ~(1 << src_val); break;
1278 case 7: /* BTC */ v_mask = 1 << src_val; break;
1279 /* If this needs to be extended, probably simplest to make a
1280 new function to handle the other cases (0 .. 3). The
1281 Intel docs do however not indicate any use for 0 .. 3, so
1282 we don't expect this to happen. */
1283 default: VG_(panic)("dis_Grp8_BT");
1284 }
1285 /* Probably excessively paranoid. */
1286 if (sz == 2)
1287 v_mask &= 0x0000FFFF;
1288
1289 t1 = INVALID_TEMPREG;
1290 t_fetched = newTemp(cb);
1291 t_mask = newTemp(cb);
1292
sewardjde4a1d02002-03-22 01:27:54 +00001293 if (epartIsReg(modrm)) {
1294 vg_assert(am_sz == 1);
1295 t2 = newTemp(cb);
sewardj0ece28b2002-04-16 00:42:12 +00001296
1297 /* Fetch the value to be tested and modified. */
1298 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t2);
1299 /* Do it! */
1300 MODIFY_t2_AND_SET_CARRY_FLAG;
1301 /* Dump the result back, if non-BT. */
1302 if (gregOfRM(modrm) != 4 /* BT */)
1303 uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, eregOfRM(modrm));
1304
sewardjde4a1d02002-03-22 01:27:54 +00001305 eip += (am_sz + 1);
1306 if (dis)
1307 VG_(printf)("%s%c $0x%x, %s\n",
1308 nameGrp8(gregOfRM(modrm)), nameISize(sz),
1309 src_val,
1310 nameIReg(sz,eregOfRM(modrm)));
1311 } else {
1312 pair = disAMode ( cb, eip, dis?dis_buf:NULL);
1313 t1 = LOW24(pair);
1314 t2 = newTemp(cb);
1315 eip += HI8(pair);
1316 eip += 1;
sewardj0ece28b2002-04-16 00:42:12 +00001317
1318 /* Fetch the value to be tested and modified. */
sewardjde4a1d02002-03-22 01:27:54 +00001319 uInstr2(cb, LOAD, sz, TempReg, t1, TempReg, t2);
sewardj0ece28b2002-04-16 00:42:12 +00001320 /* Do it! */
1321 MODIFY_t2_AND_SET_CARRY_FLAG;
1322 /* Dump the result back, if non-BT. */
1323 if (gregOfRM(modrm) != 4 /* BT */) {
1324 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
1325 SMC_IF_ALL(cb);
1326 }
sewardjde4a1d02002-03-22 01:27:54 +00001327 if (dis)
1328 VG_(printf)("%s%c $0x%x, %s\n",
1329 nameGrp8(gregOfRM(modrm)), nameISize(sz), src_val,
1330 dis_buf);
1331 }
sewardjde4a1d02002-03-22 01:27:54 +00001332 return eip;
sewardj0ece28b2002-04-16 00:42:12 +00001333
1334# undef MODIFY_t2_AND_SET_CARRY_FLAG
sewardjde4a1d02002-03-22 01:27:54 +00001335}
sewardjde4a1d02002-03-22 01:27:54 +00001336
1337
1338
1339/* Generate ucode to multiply the value in EAX/AX/AL by the register
1340 specified by the ereg of modrm, and park the result in
1341 EDX:EAX/DX:AX/AX. */
1342static void codegen_mul_A_D_Reg ( UCodeBlock* cb, Int sz,
1343 UChar modrm, Bool signed_multiply )
1344{
1345 Int helper = signed_multiply
1346 ?
1347 (sz==1 ? VGOFF_(helper_imul_8_16)
1348 : (sz==2 ? VGOFF_(helper_imul_16_32)
1349 : VGOFF_(helper_imul_32_64)))
1350 :
1351 (sz==1 ? VGOFF_(helper_mul_8_16)
1352 : (sz==2 ? VGOFF_(helper_mul_16_32)
1353 : VGOFF_(helper_mul_32_64)));
1354 Int t1 = newTemp(cb);
1355 Int ta = newTemp(cb);
1356 uInstr0(cb, CALLM_S, 0);
1357 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1358 uInstr1(cb, PUSH, sz, TempReg, t1);
1359 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
1360 uInstr1(cb, PUSH, sz, TempReg, ta);
1361 uInstr1(cb, CALLM, 0, Lit16, helper);
1362 uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP);
1363 if (sz > 1) {
1364 uInstr1(cb, POP, sz, TempReg, t1);
1365 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EDX);
1366 uInstr1(cb, POP, sz, TempReg, t1);
1367 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EAX);
1368 } else {
1369 uInstr1(cb, CLEAR, 0, Lit16, 4);
1370 uInstr1(cb, POP, 2, TempReg, t1);
1371 uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
1372 }
1373 uInstr0(cb, CALLM_E, 0);
1374 if (dis) VG_(printf)("%s%c %s\n", signed_multiply ? "imul" : "mul",
1375 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
1376
1377}
1378
1379
1380/* Generate ucode to multiply the value in EAX/AX/AL by the value in
1381 TempReg temp, and park the result in EDX:EAX/DX:AX/AX. */
1382static void codegen_mul_A_D_Temp ( UCodeBlock* cb, Int sz,
1383 Int temp, Bool signed_multiply,
1384 UChar* dis_buf )
1385{
1386 Int helper = signed_multiply
1387 ?
1388 (sz==1 ? VGOFF_(helper_imul_8_16)
1389 : (sz==2 ? VGOFF_(helper_imul_16_32)
1390 : VGOFF_(helper_imul_32_64)))
1391 :
1392 (sz==1 ? VGOFF_(helper_mul_8_16)
1393 : (sz==2 ? VGOFF_(helper_mul_16_32)
1394 : VGOFF_(helper_mul_32_64)));
1395 Int t1 = newTemp(cb);
1396 uInstr0(cb, CALLM_S, 0);
1397 uInstr1(cb, PUSH, sz, TempReg, temp);
1398 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
1399 uInstr1(cb, PUSH, sz, TempReg, t1);
1400 uInstr1(cb, CALLM, 0, Lit16, helper);
1401 uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP);
1402 if (sz > 1) {
1403 uInstr1(cb, POP, sz, TempReg, t1);
1404 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EDX);
1405 uInstr1(cb, POP, sz, TempReg, t1);
1406 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EAX);
1407 } else {
1408 uInstr1(cb, CLEAR, 0, Lit16, 4);
1409 uInstr1(cb, POP, 2, TempReg, t1);
1410 uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
1411 }
1412 uInstr0(cb, CALLM_E, 0);
1413 if (dis) VG_(printf)("%s%c %s\n", signed_multiply ? "imul" : "mul",
1414 nameISize(sz), dis_buf);
1415}
1416
1417
1418/* Group 3 extended opcodes. */
1419static
1420Addr dis_Grp3 ( UCodeBlock* cb, Int sz, Addr eip )
1421{
1422 Int t1, t2;
1423 UInt pair, d32;
1424 UChar modrm;
1425 UChar dis_buf[50];
1426 t1 = t2 = INVALID_TEMPREG;
1427 modrm = getUChar(eip);
1428 if (epartIsReg(modrm)) {
1429 t1 = newTemp(cb);
1430 switch (gregOfRM(modrm)) {
1431 case 0: { /* TEST */
1432 Int tao = newTemp(cb);
1433 eip++; d32 = getUDisp(sz, eip); eip += sz;
1434 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1435 uInstr2(cb, MOV, sz, Literal, 0, TempReg, tao);
1436 uLiteral(cb, d32);
1437 uInstr2(cb, AND, sz, TempReg, tao, TempReg, t1);
1438 setFlagsFromUOpcode(cb, AND);
1439 if (dis)
1440 VG_(printf)("test%c $0x%x, %s\n",
1441 nameISize(sz), d32, nameIReg(sz, eregOfRM(modrm)));
1442 break;
1443 }
1444 case 2: /* NOT */
1445 eip++;
1446 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1447 uInstr1(cb, NOT, sz, TempReg, t1);
1448 setFlagsFromUOpcode(cb, NOT);
1449 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
1450 if (dis)
1451 VG_(printf)("not%c %s\n",
1452 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
1453 break;
1454 case 3: /* NEG */
1455 eip++;
1456 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1457 uInstr1(cb, NEG, sz, TempReg, t1);
1458 setFlagsFromUOpcode(cb, NEG);
1459 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
1460 if (dis)
1461 VG_(printf)("neg%c %s\n",
1462 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
1463 break;
1464 case 4: /* MUL */
1465 eip++;
1466 codegen_mul_A_D_Reg ( cb, sz, modrm, False );
1467 break;
1468 case 5: /* IMUL */
1469 eip++;
1470 codegen_mul_A_D_Reg ( cb, sz, modrm, True );
1471 break;
1472 case 6: /* DIV */
1473 eip++;
1474 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1475 codegen_div ( cb, sz, t1, False );
1476 if (dis)
1477 VG_(printf)("div%c %s\n", nameISize(sz),
1478 nameIReg(sz, eregOfRM(modrm)));
1479 break;
1480 case 7: /* IDIV */
1481 eip++;
1482 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1483 codegen_div ( cb, sz, t1, True );
1484 if (dis)
1485 VG_(printf)("idiv%c %s\n", nameISize(sz),
1486 nameIReg(sz, eregOfRM(modrm)));
1487 break;
1488 default:
1489 VG_(printf)(
1490 "unhandled Grp3(R) case %d\n", (UInt)gregOfRM(modrm));
1491 VG_(panic)("Grp3");
1492 }
1493 } else {
1494 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
1495 t2 = LOW24(pair);
1496 t1 = newTemp(cb);
1497 eip += HI8(pair);
1498 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
1499 switch (gregOfRM(modrm)) {
1500 case 0: { /* TEST */
1501 Int tao = newTemp(cb);
1502 d32 = getUDisp(sz, eip); eip += sz;
1503 uInstr2(cb, MOV, sz, Literal, 0, TempReg, tao);
1504 uLiteral(cb, d32);
1505 uInstr2(cb, AND, sz, TempReg, tao, TempReg, t1);
1506 setFlagsFromUOpcode(cb, AND);
1507 if (dis)
1508 VG_(printf)("test%c $0x%x, %s\n",
1509 nameISize(sz), d32, dis_buf);
1510 break;
1511 }
1512 case 2: /* NOT */
1513 uInstr1(cb, NOT, sz, TempReg, t1);
1514 setFlagsFromUOpcode(cb, NOT);
1515 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
1516 SMC_IF_ALL(cb);
1517 if (dis)
1518 VG_(printf)("not%c %s\n", nameISize(sz), dis_buf);
1519 break;
1520 case 3: /* NEG */
1521 uInstr1(cb, NEG, sz, TempReg, t1);
1522 setFlagsFromUOpcode(cb, NEG);
1523 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
1524 SMC_IF_ALL(cb);
1525 if (dis)
1526 VG_(printf)("neg%c %s\n", nameISize(sz), dis_buf);
1527 break;
1528 case 4: /* MUL */
1529 codegen_mul_A_D_Temp ( cb, sz, t1, False,
1530 dis?dis_buf:NULL );
1531 break;
1532 case 5: /* IMUL */
1533 codegen_mul_A_D_Temp ( cb, sz, t1, True, dis?dis_buf:NULL );
1534 break;
1535 case 6: /* DIV */
1536 codegen_div ( cb, sz, t1, False );
1537 if (dis)
1538 VG_(printf)("div%c %s\n", nameISize(sz), dis_buf);
1539 break;
1540 case 7: /* IDIV */
1541 codegen_div ( cb, sz, t1, True );
1542 if (dis)
1543 VG_(printf)("idiv%c %s\n", nameISize(sz), dis_buf);
1544 break;
1545 default:
1546 VG_(printf)(
1547 "unhandled Grp3(M) case %d\n", (UInt)gregOfRM(modrm));
1548 VG_(panic)("Grp3");
1549 }
1550 }
1551 return eip;
1552}
1553
1554
1555/* Group 4 extended opcodes. */
1556static
1557Addr dis_Grp4 ( UCodeBlock* cb, Addr eip )
1558{
1559 Int t1, t2;
1560 UInt pair;
1561 UChar modrm;
1562 UChar dis_buf[50];
1563 t1 = t2 = INVALID_TEMPREG;
1564
1565 modrm = getUChar(eip);
1566 if (epartIsReg(modrm)) {
1567 t1 = newTemp(cb);
1568 uInstr2(cb, GET, 1, ArchReg, eregOfRM(modrm), TempReg, t1);
1569 switch (gregOfRM(modrm)) {
1570 case 0: /* INC */
1571 uInstr1(cb, INC, 1, TempReg, t1);
1572 setFlagsFromUOpcode(cb, INC);
1573 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, eregOfRM(modrm));
1574 break;
1575 case 1: /* DEC */
1576 uInstr1(cb, DEC, 1, TempReg, t1);
1577 setFlagsFromUOpcode(cb, DEC);
1578 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, eregOfRM(modrm));
1579 break;
1580 default:
1581 VG_(printf)(
1582 "unhandled Grp4(R) case %d\n", (UInt)gregOfRM(modrm));
1583 VG_(panic)("Grp4");
1584 }
1585 eip++;
1586 if (dis)
1587 VG_(printf)("%sb %s\n", nameGrp4(gregOfRM(modrm)),
1588 nameIReg(1, eregOfRM(modrm)));
1589 } else {
1590 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
1591 t2 = LOW24(pair);
1592 t1 = newTemp(cb);
1593 uInstr2(cb, LOAD, 1, TempReg, t2, TempReg, t1);
1594 switch (gregOfRM(modrm)) {
1595 case 0: /* INC */
1596 uInstr1(cb, INC, 1, TempReg, t1);
1597 setFlagsFromUOpcode(cb, INC);
1598 uInstr2(cb, STORE, 1, TempReg, t1, TempReg, t2);
1599 SMC_IF_ALL(cb);
1600 break;
1601 case 1: /* DEC */
1602 uInstr1(cb, DEC, 1, TempReg, t1);
1603 setFlagsFromUOpcode(cb, DEC);
1604 uInstr2(cb, STORE, 1, TempReg, t1, TempReg, t2);
1605 SMC_IF_ALL(cb);
1606 break;
1607 default:
1608 VG_(printf)(
1609 "unhandled Grp4(M) case %d\n", (UInt)gregOfRM(modrm));
1610 VG_(panic)("Grp4");
1611 }
1612 eip += HI8(pair);
1613 if (dis)
1614 VG_(printf)("%sb %s\n", nameGrp4(gregOfRM(modrm)), dis_buf);
1615 }
1616 return eip;
1617}
1618
1619
1620/* Group 5 extended opcodes. */
1621static
1622Addr dis_Grp5 ( UCodeBlock* cb, Int sz, Addr eip, Bool* isEnd )
1623{
1624 Int t1, t2, t3, t4;
1625 UInt pair;
1626 UChar modrm;
1627 UChar dis_buf[50];
1628 t1 = t2 = t3 = t4 = INVALID_TEMPREG;
1629
1630 modrm = getUChar(eip);
1631 if (epartIsReg(modrm)) {
1632 t1 = newTemp(cb);
1633 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1634 switch (gregOfRM(modrm)) {
1635 case 0: /* INC */
1636 uInstr1(cb, INC, sz, TempReg, t1);
1637 setFlagsFromUOpcode(cb, INC);
1638 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
1639 break;
1640 case 1: /* DEC */
1641 uInstr1(cb, DEC, sz, TempReg, t1);
1642 setFlagsFromUOpcode(cb, DEC);
1643 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
1644 break;
1645 case 2: /* call Ev */
1646 t3 = newTemp(cb); t4 = newTemp(cb);
1647 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
1648 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t3);
1649 uLiteral(cb, 4);
1650 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
1651 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
1652 uLiteral(cb, eip+1);
1653 uInstr2(cb, STORE, 4, TempReg, t4, TempReg, t3);
1654 SMC_IF_ALL(cb);
1655 uInstr1(cb, JMP, 0, TempReg, t1);
1656 uCond(cb, CondAlways);
sewardj2e93c502002-04-12 11:12:52 +00001657 LAST_UINSTR(cb).jmpkind = JmpCall;
sewardjde4a1d02002-03-22 01:27:54 +00001658 *isEnd = True;
1659 break;
1660 case 4: /* jmp Ev */
1661 uInstr1(cb, JMP, 0, TempReg, t1);
1662 uCond(cb, CondAlways);
1663 *isEnd = True;
1664 break;
1665 default:
1666 VG_(printf)(
1667 "unhandled Grp5(R) case %d\n", (UInt)gregOfRM(modrm));
1668 VG_(panic)("Grp5");
1669 }
1670 eip++;
1671 if (dis)
1672 VG_(printf)("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
1673 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
1674 } else {
1675 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
1676 t2 = LOW24(pair);
1677 t1 = newTemp(cb);
1678 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
1679 switch (gregOfRM(modrm)) {
1680 case 0: /* INC */
1681 uInstr1(cb, INC, sz, TempReg, t1);
1682 setFlagsFromUOpcode(cb, INC);
1683 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
1684 SMC_IF_ALL(cb);
1685 break;
1686 case 1: /* DEC */
1687 uInstr1(cb, DEC, sz, TempReg, t1);
1688 setFlagsFromUOpcode(cb, DEC);
1689 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
1690 SMC_IF_ALL(cb);
1691 break;
1692 case 2: /* call Ev */
1693 t3 = newTemp(cb); t4 = newTemp(cb);
1694 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
1695 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t3);
1696 uLiteral(cb, 4);
1697 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
1698 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
1699 uLiteral(cb, eip+HI8(pair));
1700 uInstr2(cb, STORE, 4, TempReg, t4, TempReg, t3);
1701 SMC_IF_ALL(cb);
1702 uInstr1(cb, JMP, 0, TempReg, t1);
1703 uCond(cb, CondAlways);
sewardj2e93c502002-04-12 11:12:52 +00001704 LAST_UINSTR(cb).jmpkind = JmpCall;
sewardjde4a1d02002-03-22 01:27:54 +00001705 *isEnd = True;
1706 break;
1707 case 4: /* JMP Ev */
1708 uInstr1(cb, JMP, 0, TempReg, t1);
1709 uCond(cb, CondAlways);
1710 *isEnd = True;
1711 break;
1712 case 6: /* PUSH Ev */
1713 t3 = newTemp(cb);
1714 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
1715 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t3);
1716 uLiteral(cb, sz);
1717 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
1718 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t3);
1719 SMC_IF_ALL(cb);
1720 break;
1721 default:
1722 VG_(printf)(
1723 "unhandled Grp5(M) case %d\n", (UInt)gregOfRM(modrm));
1724 VG_(panic)("Grp5");
1725 }
1726 eip += HI8(pair);
1727 if (dis)
1728 VG_(printf)("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
1729 nameISize(sz), dis_buf);
1730 }
1731 return eip;
1732}
1733
1734
1735/* Template for REPE CMPS<sz>. Assumes this insn is the last one in
1736 the basic block, and so emits a jump to the next insn. */
1737static
1738void codegen_REPE_CMPS ( UCodeBlock* cb, Int sz, Addr eip, Addr eip_next )
1739{
1740 Int tc, /* ECX */
1741 td, /* EDI */ ts, /* ESI */
1742 tdv, /* (EDI) */ tsv /* (ESI) */;
1743
1744 tdv = newTemp(cb);
1745 tsv = newTemp(cb);
1746 td = newTemp(cb);
1747 ts = newTemp(cb);
1748 tc = newTemp(cb);
1749
1750 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, tc);
1751 uInstr2(cb, JIFZ, 4, TempReg, tc, Literal, 0);
1752 uLiteral(cb, eip_next);
1753 uInstr1(cb, DEC, 4, TempReg, tc);
1754 uInstr2(cb, PUT, 4, TempReg, tc, ArchReg, R_ECX);
1755
1756 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
1757 uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
1758
1759 uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tdv);
1760 uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tsv);
1761
1762 uInstr2(cb, SUB, sz, TempReg, tdv, TempReg, tsv);
1763 setFlagsFromUOpcode(cb, SUB);
1764
1765 uInstr0(cb, CALLM_S, 0);
1766 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tdv);
1767 uLiteral(cb, 0);
1768 uInstr1(cb, PUSH, 4, TempReg, tdv);
1769
1770 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
1771 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
1772
1773 uInstr1(cb, POP, 4, TempReg, tdv);
1774 uInstr0(cb, CALLM_E, 0);
1775 if (sz == 4 || sz == 2) {
1776 uInstr2(cb, SHL, 4, Literal, 0, TempReg, tdv);
1777 uLiteral(cb, sz/2);
1778 }
1779 uInstr2(cb, ADD, 4, TempReg, tdv, TempReg, td);
1780 uInstr2(cb, ADD, 4, TempReg, tdv, TempReg, ts);
1781
1782 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
1783 uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
1784
1785 uInstr1(cb, JMP, 0, Literal, 0);
1786 uLiteral(cb, eip);
1787 uCond(cb, CondZ);
1788 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
1789 uInstr1(cb, JMP, 0, Literal, 0);
1790 uLiteral(cb, eip_next);
1791 uCond(cb, CondAlways);
1792}
1793
1794
1795/* Template for REPNE SCAS<sz>. Assumes this insn is the last one in
1796 the basic block, and so emits a jump to the next insn. */
1797static
1798void codegen_REPNE_SCAS ( UCodeBlock* cb, Int sz, Addr eip, Addr eip_next )
1799{
1800 Int ta /* EAX */, tc /* ECX */, td /* EDI */, tv;
1801 ta = newTemp(cb);
1802 tc = newTemp(cb);
1803 tv = newTemp(cb);
1804 td = newTemp(cb);
1805
1806 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, tc);
1807 uInstr2(cb, JIFZ, 4, TempReg, tc, Literal, 0);
1808 uLiteral(cb, eip_next);
1809 uInstr1(cb, DEC, 4, TempReg, tc);
1810 uInstr2(cb, PUT, 4, TempReg, tc, ArchReg, R_ECX);
1811
1812 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
1813 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
1814 uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tv);
1815 /* next uinstr kills ta, but that's ok -- don't need it again */
1816 uInstr2(cb, SUB, sz, TempReg, tv, TempReg, ta);
1817 setFlagsFromUOpcode(cb, SUB);
1818
1819 uInstr0(cb, CALLM_S, 0);
1820 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tv);
1821 uLiteral(cb, 0);
1822 uInstr1(cb, PUSH, 4, TempReg, tv);
1823
1824 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
1825 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
1826
1827 uInstr1(cb, POP, 4, TempReg, tv);
1828 uInstr0(cb, CALLM_E, 0);
1829
1830 if (sz == 4 || sz == 2) {
1831 uInstr2(cb, SHL, 4, Literal, 0, TempReg, tv);
1832 uLiteral(cb, sz/2);
1833 }
1834 uInstr2(cb, ADD, 4, TempReg, tv, TempReg, td);
1835 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
1836 uInstr1(cb, JMP, 0, Literal, 0);
1837 uLiteral(cb, eip);
1838 uCond(cb, CondNZ);
1839 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
1840 uInstr1(cb, JMP, 0, Literal, 0);
1841 uLiteral(cb, eip_next);
1842 uCond(cb, CondAlways);
1843}
1844
1845
1846/* Template for REPE MOVS<sz>. Assumes this insn is the last one in
1847 the basic block, and so emits a jump to the next insn. */
1848static
1849void codegen_REPE_MOVS ( UCodeBlock* cb, Int sz, Addr eip, Addr eip_next )
1850{
1851 Int ts /* ESI */, tc /* ECX */, td /* EDI */, tv;
1852 tc = newTemp(cb);
1853 td = newTemp(cb);
1854 ts = newTemp(cb);
1855 tv = newTemp(cb);
1856
1857 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, tc);
1858 uInstr2(cb, JIFZ, 4, TempReg, tc, Literal, 0);
1859 uLiteral(cb, eip_next);
1860 uInstr1(cb, DEC, 4, TempReg, tc);
1861 uInstr2(cb, PUT, 4, TempReg, tc, ArchReg, R_ECX);
1862
1863 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
1864 uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
1865
1866 uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tv);
1867 uInstr2(cb, STORE, sz, TempReg, tv, TempReg, td);
1868 SMC_IF_SOME(cb);
1869
1870 uInstr0(cb, CALLM_S, 0);
1871 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tv);
1872 uLiteral(cb, 0);
1873 uInstr1(cb, PUSH, 4, TempReg, tv);
1874
1875 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
1876 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
1877
1878 uInstr1(cb, POP, 4, TempReg, tv);
1879 uInstr0(cb, CALLM_E, 0);
1880
1881 if (sz == 4 || sz == 2) {
1882 uInstr2(cb, SHL, 4, Literal, 0, TempReg, tv);
1883 uLiteral(cb, sz/2);
1884 }
1885 uInstr2(cb, ADD, 4, TempReg, tv, TempReg, td);
1886 uInstr2(cb, ADD, 4, TempReg, tv, TempReg, ts);
1887
1888 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
1889 uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
1890
1891 uInstr1(cb, JMP, 0, Literal, 0);
1892 uLiteral(cb, eip);
1893 uCond(cb, CondAlways);
1894}
1895
1896
1897/* Template for REPE STOS<sz>. Assumes this insn is the last one in
1898 the basic block, and so emits a jump to the next insn. */
1899static
1900void codegen_REPE_STOS ( UCodeBlock* cb, Int sz, Addr eip, Addr eip_next )
1901{
1902 Int ta /* EAX */, tc /* ECX */, td /* EDI */;
1903 ta = newTemp(cb);
1904 tc = newTemp(cb);
1905 td = newTemp(cb);
1906
1907 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, tc);
1908 uInstr2(cb, JIFZ, 4, TempReg, tc, Literal, 0);
1909 uLiteral(cb, eip_next);
1910 uInstr1(cb, DEC, 4, TempReg, tc);
1911 uInstr2(cb, PUT, 4, TempReg, tc, ArchReg, R_ECX);
1912
1913 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
1914 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
1915 uInstr2(cb, STORE, sz, TempReg, ta, TempReg, td);
1916 SMC_IF_SOME(cb);
1917
1918 uInstr0(cb, CALLM_S, 0);
1919 uInstr2(cb, MOV, 4, Literal, 0, TempReg, ta);
1920 uLiteral(cb, 0);
1921 uInstr1(cb, PUSH, 4, TempReg, ta);
1922
1923 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
1924 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
1925
1926 uInstr1(cb, POP, 4, TempReg, ta);
1927 uInstr0(cb, CALLM_E, 0);
1928
1929 if (sz == 4 || sz == 2) {
1930 uInstr2(cb, SHL, 4, Literal, 0, TempReg, ta);
1931 uLiteral(cb, sz/2);
1932 }
1933 uInstr2(cb, ADD, 4, TempReg, ta, TempReg, td);
1934 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
1935
1936 uInstr1(cb, JMP, 0, Literal, 0);
1937 uLiteral(cb, eip);
1938 uCond(cb, CondAlways);
1939}
1940
1941
1942/* Template for CMPS<sz>, _not_ preceded by a REP prefix. */
1943static
1944void codegen_CMPS ( UCodeBlock* cb, Int sz )
1945{
1946 Int td, /* EDI */ ts, /* ESI */
1947 tdv, /* (EDI) */ tsv /* (ESI) */;
1948 tdv = newTemp(cb);
1949 tsv = newTemp(cb);
1950 td = newTemp(cb);
1951 ts = newTemp(cb);
1952
1953 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
1954 uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
1955
1956 uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tdv);
1957 uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tsv);
1958
1959 uInstr2(cb, SUB, sz, TempReg, tdv, TempReg, tsv);
1960 setFlagsFromUOpcode(cb, SUB);
1961
1962 uInstr0(cb, CALLM_S, 0);
1963 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tdv);
1964 uLiteral(cb, 0);
1965 uInstr1(cb, PUSH, 4, TempReg, tdv);
1966
1967 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
1968 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
1969
1970 uInstr1(cb, POP, 4, TempReg, tdv);
1971 uInstr0(cb, CALLM_E, 0);
1972
1973 if (sz == 4 || sz == 2) {
1974 uInstr2(cb, SHL, 4, Literal, 0, TempReg, tdv);
1975 uLiteral(cb, sz/2);
1976 }
1977 uInstr2(cb, ADD, 4, TempReg, tdv, TempReg, td);
1978 uInstr2(cb, ADD, 4, TempReg, tdv, TempReg, ts);
1979
1980 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
1981 uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
1982}
1983
1984
1985/* Template for MOVS<sz>, _not_ preceded by a REP prefix. */
1986static
1987void codegen_MOVS ( UCodeBlock* cb, Int sz )
1988{
1989 Int tv, /* the value being copied */
1990 td, /* EDI */ ts /* ESI */;
1991 tv = newTemp(cb);
1992 td = newTemp(cb);
1993 ts = newTemp(cb);
1994
1995 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
1996 uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
1997
1998 uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tv);
1999 uInstr2(cb, STORE, sz, TempReg, tv, TempReg, td);
2000 SMC_IF_SOME(cb);
2001
2002 uInstr0(cb, CALLM_S, 0);
2003 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tv);
2004 uLiteral(cb, 0);
2005 uInstr1(cb, PUSH, 4, TempReg, tv);
2006
2007 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
2008 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
2009
2010 uInstr1(cb, POP, 4, TempReg, tv);
2011 uInstr0(cb, CALLM_E, 0);
2012
2013 if (sz == 4 || sz == 2) {
2014 uInstr2(cb, SHL, 4, Literal, 0, TempReg, tv);
2015 uLiteral(cb, sz/2);
2016 }
2017 uInstr2(cb, ADD, 4, TempReg, tv, TempReg, td);
2018 uInstr2(cb, ADD, 4, TempReg, tv, TempReg, ts);
2019
2020 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2021 uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
2022}
2023
2024
2025/* Template for STOS<sz>, _not_ preceded by a REP prefix. */
2026static
2027void codegen_STOS ( UCodeBlock* cb, Int sz )
2028{
2029 Int ta /* EAX */, td /* EDI */;
2030 ta = newTemp(cb);
2031 td = newTemp(cb);
2032
2033 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
2034 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
2035 uInstr2(cb, STORE, sz, TempReg, ta, TempReg, td);
2036 SMC_IF_SOME(cb);
2037
2038 uInstr0(cb, CALLM_S, 0);
2039 uInstr2(cb, MOV, 4, Literal, 0, TempReg, ta);
2040 uLiteral(cb, 0);
2041 uInstr1(cb, PUSH, 4, TempReg, ta);
2042
2043 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
2044 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
2045
2046 uInstr1(cb, POP, 4, TempReg, ta);
2047 uInstr0(cb, CALLM_E, 0);
2048
2049 if (sz == 4 || sz == 2) {
2050 uInstr2(cb, SHL, 4, Literal, 0, TempReg, ta);
2051 uLiteral(cb, sz/2);
2052 }
2053 uInstr2(cb, ADD, 4, TempReg, ta, TempReg, td);
2054 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2055}
2056
2057
2058/* Template for LODS<sz>, _not_ preceded by a REP prefix. */
2059static
2060void codegen_LODS ( UCodeBlock* cb, Int sz )
2061{
2062 Int ta /* EAX */, ts /* ESI */;
2063 ta = newTemp(cb);
2064 ts = newTemp(cb);
2065
2066 uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
2067 uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, ta);
2068 uInstr2(cb, PUT, sz, TempReg, ta, ArchReg, R_EAX);
2069
2070 uInstr0(cb, CALLM_S, 0);
2071 uInstr2(cb, MOV, 4, Literal, 0, TempReg, ta);
2072 uLiteral(cb, 0);
2073 uInstr1(cb, PUSH, 4, TempReg, ta);
2074
2075 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
2076 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
2077
2078 uInstr1(cb, POP, 4, TempReg, ta);
2079 uInstr0(cb, CALLM_E, 0);
2080
2081 if (sz == 4 || sz == 2) {
2082 uInstr2(cb, SHL, 4, Literal, 0, TempReg, ta);
2083 uLiteral(cb, sz/2);
2084 }
2085 uInstr2(cb, ADD, 4, TempReg, ta, TempReg, ts);
2086 uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
2087}
2088
2089
2090/* Template for REPNE SCAS<sz>, _not_ preceded by a REP prefix. */
2091static
2092void codegen_SCAS ( UCodeBlock* cb, Int sz )
2093{
2094 Int ta /* EAX */, td /* EDI */, tv;
2095 ta = newTemp(cb);
2096 tv = newTemp(cb);
2097 td = newTemp(cb);
2098
2099 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
2100 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
2101 uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tv);
2102 /* next uinstr kills ta, but that's ok -- don't need it again */
2103 uInstr2(cb, SUB, sz, TempReg, tv, TempReg, ta);
2104 setFlagsFromUOpcode(cb, SUB);
2105
2106 uInstr0(cb, CALLM_S, 0);
2107 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tv);
2108 uLiteral(cb, 0);
2109 uInstr1(cb, PUSH, 4, TempReg, tv);
2110
2111 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
2112 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
2113
2114 uInstr1(cb, POP, 4, TempReg, tv);
2115 uInstr0(cb, CALLM_E, 0);
2116
2117 if (sz == 4 || sz == 2) {
2118 uInstr2(cb, SHL, 4, Literal, 0, TempReg, tv);
2119 uLiteral(cb, sz/2);
2120 }
2121 uInstr2(cb, ADD, 4, TempReg, tv, TempReg, td);
2122 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2123}
2124
2125
2126/* (I)MUL E, G. Supplied eip points to the modR/M byte. */
2127static
2128Addr dis_mul_E_G ( UCodeBlock* cb,
2129 Int size,
2130 Addr eip0,
2131 Bool signed_multiply )
2132{
2133 Int ta, tg, te, helper;
2134 UChar dis_buf[50];
2135 UChar rm = getUChar(eip0);
2136 ta = INVALID_TEMPREG;
2137 te = newTemp(cb);
2138 tg = newTemp(cb);
2139
2140 switch (size) {
2141 case 4: helper = signed_multiply ? VGOFF_(helper_imul_32_64)
2142 : VGOFF_(helper_mul_32_64);
2143 break;
2144 case 2: helper = signed_multiply ? VGOFF_(helper_imul_16_32)
2145 : VGOFF_(helper_mul_16_32);
2146 break;
2147 case 1: helper = signed_multiply ? VGOFF_(helper_imul_8_16)
2148 : VGOFF_(helper_mul_8_16);
2149 break;
2150 default: VG_(panic)("dis_mul_E_G");
2151 }
2152
2153 uInstr0(cb, CALLM_S, 0);
2154 if (epartIsReg(rm)) {
2155 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, te);
2156 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tg);
2157 uInstr1(cb, PUSH, size, TempReg, te);
2158 uInstr1(cb, PUSH, size, TempReg, tg);
2159 uInstr1(cb, CALLM, 0, Lit16, helper);
2160 uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP);
2161 uInstr1(cb, CLEAR, 0, Lit16, 4);
2162 uInstr1(cb, POP, size, TempReg, tg);
2163 uInstr2(cb, PUT, size, TempReg, tg, ArchReg, gregOfRM(rm));
2164 uInstr0(cb, CALLM_E, 0);
2165 if (dis) VG_(printf)("%smul%c %s, %s\n",
2166 signed_multiply ? "i" : "",
2167 nameISize(size),
2168 nameIReg(size,eregOfRM(rm)),
2169 nameIReg(size,gregOfRM(rm)));
2170 return 1+eip0;
2171 } else {
2172 UInt pair = disAMode ( cb, eip0, dis?dis_buf:NULL);
2173 ta = LOW24(pair);
2174 uInstr2(cb, LOAD, size, TempReg, ta, TempReg, te);
2175 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tg);
2176 uInstr1(cb, PUSH, size, TempReg, te);
2177 uInstr1(cb, PUSH, size, TempReg, tg);
2178 uInstr1(cb, CALLM, 0, Lit16, helper);
2179 uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP);
2180 uInstr1(cb, CLEAR, 0, Lit16, 4);
2181 uInstr1(cb, POP, size, TempReg, tg);
2182 uInstr2(cb, PUT, size, TempReg, tg, ArchReg, gregOfRM(rm));
2183 uInstr0(cb, CALLM_E, 0);
2184 if (dis) VG_(printf)("%smul%c %s, %s\n",
2185 signed_multiply ? "i" : "",
2186 nameISize(size),
2187 dis_buf,nameIReg(size,gregOfRM(rm)));
2188 return HI8(pair)+eip0;
2189 }
2190}
2191
2192
2193/* IMUL I * E -> G. Supplied eip points to the modR/M byte. */
2194static
2195Addr dis_imul_I_E_G ( UCodeBlock* cb,
2196 Int size,
2197 Addr eip,
2198 Int litsize )
2199{
2200 Int ta, te, tl, helper, d32;
2201 UChar dis_buf[50];
2202 UChar rm = getUChar(eip);
2203 ta = INVALID_TEMPREG;
2204 te = newTemp(cb);
2205 tl = newTemp(cb);
2206
2207 switch (size) {
2208 case 4: helper = VGOFF_(helper_imul_32_64); break;
2209 case 2: helper = VGOFF_(helper_imul_16_32); break;
2210 case 1: helper = VGOFF_(helper_imul_8_16); break;
2211 default: VG_(panic)("dis_imul_I_E_G");
2212 }
2213
2214 uInstr0(cb, CALLM_S, 0);
2215 if (epartIsReg(rm)) {
2216 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, te);
2217 uInstr1(cb, PUSH, size, TempReg, te);
2218 eip++;
2219 } else {
2220 UInt pair = disAMode ( cb, eip, dis?dis_buf:NULL);
2221 ta = LOW24(pair);
2222 uInstr2(cb, LOAD, size, TempReg, ta, TempReg, te);
2223 uInstr1(cb, PUSH, size, TempReg, te);
2224 eip += HI8(pair);
2225 }
2226
2227 d32 = getSDisp(litsize,eip);
2228 eip += litsize;
2229
2230 uInstr2(cb, MOV, size, Literal, 0, TempReg, tl);
2231 uLiteral(cb, d32);
2232 uInstr1(cb, PUSH, size, TempReg, tl);
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, te);
2237 uInstr2(cb, PUT, size, TempReg, te, ArchReg, gregOfRM(rm));
2238 uInstr0(cb, CALLM_E, 0);
2239
2240 if (dis) {
2241 if (epartIsReg(rm)) {
2242 VG_(printf)("imul %d, %s, %s\n", d32, nameIReg(size,eregOfRM(rm)),
2243 nameIReg(size,gregOfRM(rm)));
2244 } else {
2245 VG_(printf)("imul %d, %s, %s\n", d32, dis_buf,
2246 nameIReg(size,gregOfRM(rm)));
2247 }
2248 }
2249
2250 return eip;
2251}
2252
2253
2254/* Handle FPU insns which read/write memory. On entry, eip points to
2255 the second byte of the insn (the one following D8 .. DF). */
2256static
2257Addr dis_fpu_mem ( UCodeBlock* cb, Int size, Bool is_write,
2258 Addr eip, UChar first_byte )
2259{
2260 Int ta;
2261 UInt pair;
2262 UChar dis_buf[50];
2263 UChar second_byte = getUChar(eip);
2264 vg_assert(second_byte < 0xC0);
2265 second_byte &= 0x38;
2266 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
2267 ta = LOW24(pair);
2268 eip += HI8(pair);
2269 uInstr2(cb, is_write ? FPU_W : FPU_R, size,
2270 Lit16,
2271 (((UShort)first_byte) << 8) | ((UShort)second_byte),
2272 TempReg, ta);
2273 if (is_write) SMC_IF_ALL(cb);
2274 if (dis) {
2275 if (is_write)
2276 VG_(printf)("fpu_w_%d 0x%x:0x%x, %s\n",
2277 size, (UInt)first_byte,
2278 (UInt)second_byte, dis_buf );
2279 else
2280 VG_(printf)("fpu_r_%d %s, 0x%x:0x%x\n",
2281 size, dis_buf,
2282 (UInt)first_byte,
2283 (UInt)second_byte );
2284 }
2285 return eip;
2286}
2287
2288
2289/* Handle FPU insns which don't reference memory. On entry, eip points to
2290 the second byte of the insn (the one following D8 .. DF). */
2291static
2292Addr dis_fpu_no_mem ( UCodeBlock* cb, Addr eip, UChar first_byte )
2293{
sewardj4a7456e2002-03-24 13:52:19 +00002294 Bool sets_ZCP = False;
sewardjde4a1d02002-03-22 01:27:54 +00002295 UChar second_byte = getUChar(eip); eip++;
2296 vg_assert(second_byte >= 0xC0);
sewardj4a7456e2002-03-24 13:52:19 +00002297
2298 if (first_byte == 0xDB && second_byte >= 0xF0 && second_byte <= 0xF7) {
2299 /* FCOMI */
2300 sets_ZCP = True;
2301 } else
2302 if (first_byte == 0xDF && second_byte >= 0xF0 && second_byte <= 0xF7) {
2303 /* FCOMIP */
2304 sets_ZCP = True;
2305 } else
2306 if (first_byte == 0xDB && second_byte >= 0xE8 && second_byte <= 0xEF) {
2307 /* FUCOMI */
2308 sets_ZCP = True;
2309 } else
2310 if (first_byte == 0xDF && second_byte >= 0xE8 && second_byte <= 0xEF) {
2311 /* FUCOMIP */
2312 sets_ZCP = True;
2313 }
2314
sewardjde4a1d02002-03-22 01:27:54 +00002315 uInstr1(cb, FPU, 0,
2316 Lit16,
2317 (((UShort)first_byte) << 8) | ((UShort)second_byte)
2318 );
sewardj4a7456e2002-03-24 13:52:19 +00002319 if (sets_ZCP) {
2320 /* VG_(printf)("!!! --- FPU insn which writes %EFLAGS\n"); */
2321 uFlagsRWU(cb, FlagsEmpty, FlagsZCP, FlagsEmpty);
2322 }
2323
2324 if (dis) VG_(printf)("fpu 0x%x:0x%x%s\n",
2325 (UInt)first_byte, (UInt)second_byte,
2326 sets_ZCP ? " -wZCP" : "" );
sewardjde4a1d02002-03-22 01:27:54 +00002327 return eip;
2328}
2329
2330
2331/* Top-level handler for all FPU insns. On entry, eip points to the
2332 second byte of the insn. */
2333static
2334Addr dis_fpu ( UCodeBlock* cb, UChar first_byte, Addr eip )
2335{
2336 const Bool rd = False;
2337 const Bool wr = True;
2338 UChar second_byte = getUChar(eip);
2339
2340 /* Handle FSTSW %ax specially. */
2341 if (first_byte == 0xDF && second_byte == 0xE0) {
2342 Int t1 = newTemp(cb);
2343 uInstr0(cb, CALLM_S, 0);
2344 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
2345 uLiteral(cb, 0);
2346 uInstr1(cb, PUSH, 4, TempReg, t1);
2347 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_fstsw_AX) );
2348 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
2349 uInstr1(cb, POP, 2, TempReg, t1);
2350 uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
2351 uInstr0(cb, CALLM_E, 0);
2352 if (dis) VG_(printf)("fstsw %%ax\n");
2353 eip++;
2354 return eip;
2355 }
2356
2357 /* Handle all non-memory FPU ops simply. */
2358 if (second_byte >= 0xC0)
2359 return dis_fpu_no_mem ( cb, eip, first_byte );
2360
2361 /* The insn references memory; need to determine
2362 whether it reads or writes, and at what size. */
2363 switch (first_byte) {
2364
2365 case 0xD8:
2366 switch ((second_byte >> 3) & 7) {
2367 case 0: /* FADDs */
2368 case 1: /* FMULs */
2369 case 2: /* FCOMs */
2370 case 3: /* FCOMPs */
2371 case 4: /* FSUBs */
2372 case 5: /* FSUBRs */
2373 case 6: /* FDIVs */
2374 case 7: /* FDIVRs */
2375 return dis_fpu_mem(cb, 4, rd, eip, first_byte);
2376 default:
2377 goto unhandled;
2378 }
2379 break;
2380
2381 case 0xD9:
2382 switch ((second_byte >> 3) & 7) {
2383 case 0: /* FLDs */
2384 return dis_fpu_mem(cb, 4, rd, eip, first_byte);
2385 case 2: /* FSTs */
2386 case 3: /* FSTPs */
2387 return dis_fpu_mem(cb, 4, wr, eip, first_byte);
2388 case 5: /* FLDCW */
2389 return dis_fpu_mem(cb, 2, rd, eip, first_byte);
2390 case 7: /* FSTCW */
2391 /* HACK! FSTCW actually writes 2 bytes, not 4. glibc
2392 gets lots of moaning in __floor() if we do the right
2393 thing here. */
2394 /* Later ... hack disabled .. we do do the Right Thing. */
2395 return dis_fpu_mem(cb, /*4*/ 2, wr, eip, first_byte);
2396 default:
2397 goto unhandled;
2398 }
2399 break;
2400
2401 case 0xDA:
2402 switch ((second_byte >> 3) & 7) {
2403 case 0: /* FIADD */
2404 case 1: /* FIMUL */
2405 case 2: /* FICOM */
2406 case 3: /* FICOMP */
2407 case 4: /* FISUB */
2408 case 5: /* FISUBR */
2409 case 6: /* FIDIV */
2410 case 7: /* FIDIVR */
2411 return dis_fpu_mem(cb, 4, rd, eip, first_byte);
2412 default:
2413 goto unhandled;
2414 }
2415 break;
2416
2417 case 0xDB:
2418 switch ((second_byte >> 3) & 7) {
2419 case 0: /* FILD dword-integer */
2420 return dis_fpu_mem(cb, 4, rd, eip, first_byte);
2421 case 2: /* FIST dword-integer */
2422 return dis_fpu_mem(cb, 4, wr, eip, first_byte);
2423 case 3: /* FISTPl */
2424 return dis_fpu_mem(cb, 4, wr, eip, first_byte);
2425 case 5: /* FLD extended-real */
2426 return dis_fpu_mem(cb, 10, rd, eip, first_byte);
2427 case 7: /* FSTP extended-real */
2428 return dis_fpu_mem(cb, 10, wr, eip, first_byte);
2429 default:
2430 goto unhandled;
2431 }
2432 break;
2433
2434 case 0xDC:
2435 switch ((second_byte >> 3) & 7) {
2436 case 0: /* FADD double-real */
2437 case 1: /* FMUL double-real */
2438 case 2: /* FCOM double-real */
2439 case 3: /* FCOMP double-real */
2440 case 4: /* FSUB double-real */
2441 case 5: /* FSUBR double-real */
2442 case 6: /* FDIV double-real */
2443 case 7: /* FDIVR double-real */
2444 return dis_fpu_mem(cb, 8, rd, eip, first_byte);
2445 default:
2446 goto unhandled;
2447 }
2448 break;
2449
2450 case 0xDD:
2451 switch ((second_byte >> 3) & 7) {
2452 case 0: /* FLD double-real */
2453 return dis_fpu_mem(cb, 8, rd, eip, first_byte);
2454 case 2: /* FST double-real */
2455 case 3: /* FSTP double-real */
2456 return dis_fpu_mem(cb, 8, wr, eip, first_byte);
2457 default:
2458 goto unhandled;
2459 }
2460 break;
2461
2462 case 0xDF:
2463 switch ((second_byte >> 3) & 7) {
2464 case 0: /* FILD word-integer */
2465 return dis_fpu_mem(cb, 2, rd, eip, first_byte);
2466 case 2: /* FIST word-integer */
2467 return dis_fpu_mem(cb, 2, wr, eip, first_byte);
2468 case 3: /* FISTP word-integer */
2469 return dis_fpu_mem(cb, 2, wr, eip, first_byte);
2470 case 5: /* FILD qword-integer */
2471 return dis_fpu_mem(cb, 8, rd, eip, first_byte);
2472 case 7: /* FISTP qword-integer */
2473 return dis_fpu_mem(cb, 8, wr, eip, first_byte);
2474 default:
2475 goto unhandled;
2476 }
2477 break;
2478
2479 default: goto unhandled;
2480 }
2481
2482 unhandled:
2483 VG_(printf)("dis_fpu: unhandled memory case 0x%2x:0x%2x(%d)\n",
2484 (UInt)first_byte, (UInt)second_byte,
2485 (UInt)((second_byte >> 3) & 7) );
2486 VG_(panic)("dis_fpu: unhandled opcodes");
2487}
2488
2489
2490/* Double length left shifts. Apparently only required in v-size (no
2491 b- variant). */
2492static
2493Addr dis_SHLRD_Gv_Ev ( UCodeBlock* cb, Addr eip, UChar modrm,
2494 Int sz,
2495 Tag amt_tag, UInt amt_val,
2496 Bool left_shift )
2497{
2498 /* amt_tag and amt_val denote either ArchReg(%CL) or a Literal.
2499 And eip on entry points at the modrm byte. */
2500 Int t, t1, t2, ta, helper;
2501 UInt pair;
2502 UChar dis_buf[50];
2503
2504 vg_assert(sz == 2 || sz == 4);
2505
2506 helper = left_shift
2507 ? (sz==4 ? VGOFF_(helper_shldl)
2508 : VGOFF_(helper_shldw))
2509 : (sz==4 ? VGOFF_(helper_shrdl)
2510 : VGOFF_(helper_shrdw));
2511
2512 /* Get the amount to be shifted by onto the stack. */
2513 t = newTemp(cb);
2514 t1 = newTemp(cb);
2515 t2 = newTemp(cb);
2516 if (amt_tag == ArchReg) {
2517 vg_assert(amt_val == R_CL);
2518 uInstr2(cb, GET, 1, ArchReg, amt_val, TempReg, t);
2519 } else {
2520 uInstr2(cb, MOV, 1, Literal, 0, TempReg, t);
2521 uLiteral(cb, amt_val);
2522 }
2523
2524 uInstr0(cb, CALLM_S, 0);
2525 uInstr1(cb, PUSH, 1, TempReg, t);
2526
2527 /* The E-part is the destination; this is shifted. The G-part
2528 supplies bits to be shifted into the E-part, but is not
2529 changed. */
2530
2531 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t1);
2532 uInstr1(cb, PUSH, sz, TempReg, t1);
2533
2534 if (epartIsReg(modrm)) {
2535 eip++;
2536 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t2);
2537 uInstr1(cb, PUSH, sz, TempReg, t2);
2538 uInstr1(cb, CALLM, 0, Lit16, helper);
2539 uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
2540 uInstr1(cb, POP, sz, TempReg, t);
2541 uInstr2(cb, PUT, sz, TempReg, t, ArchReg, eregOfRM(modrm));
2542 if (dis)
2543 VG_(printf)("shld%c %%cl, %s, %s\n",
2544 nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
2545 nameIReg(sz, eregOfRM(modrm)));
2546 } else {
2547 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
2548 ta = LOW24(pair);
2549 eip += HI8(pair);
2550 uInstr2(cb, LOAD, sz, TempReg, ta, TempReg, t2);
2551 uInstr1(cb, PUSH, sz, TempReg, t2);
2552 uInstr1(cb, CALLM, 0, Lit16, helper);
2553 uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
2554 uInstr1(cb, POP, sz, TempReg, t);
2555 uInstr2(cb, STORE, sz, TempReg, t, TempReg, ta);
2556 SMC_IF_ALL(cb);
2557 if (dis)
2558 VG_(printf)("shld%c %%cl, %s, %s\n",
2559 nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
2560 dis_buf);
2561 }
2562
2563 if (amt_tag == Literal) eip++;
2564 uInstr1(cb, CLEAR, 0, Lit16, 8);
2565
2566 uInstr0(cb, CALLM_E, 0);
2567 return eip;
2568}
2569
2570
2571/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
2572 required. */
2573
2574typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
2575
2576static Char* nameBtOp ( BtOp op )
2577{
2578 switch (op) {
2579 case BtOpNone: return "";
2580 case BtOpSet: return "s";
2581 case BtOpReset: return "r";
2582 case BtOpComp: return "c";
2583 default: VG_(panic)("nameBtOp");
2584 }
2585}
2586
sewardj7f2a8bf2002-04-15 14:35:28 +00002587
2588static
2589Addr dis_bt_G_E ( UCodeBlock* cb, Int sz, Addr eip, BtOp op )
2590{
2591 UInt pair;
2592 UChar dis_buf[50];
2593 UChar modrm;
2594
2595 Int t_addr, t_bitno, t_mask, t_fetched, t_esp, temp, lit;
2596
2597 /* 2 and 4 are actually possible. */
2598 vg_assert(sz == 2 || sz == 4);
2599 /* We only handle 4. */
2600 vg_assert(sz == 4);
2601
2602 t_addr = t_bitno = t_mask
2603 = t_fetched = t_esp = temp = INVALID_TEMPREG;
2604
2605 t_fetched = newTemp(cb);
2606 t_bitno = newTemp(cb);
2607 temp = newTemp(cb);
2608 lit = newTemp(cb);
2609
2610 modrm = getUChar(eip);
2611
2612 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t_bitno);
2613
2614 if (epartIsReg(modrm)) {
2615 eip++;
2616 /* Get it onto the client's stack. */
2617 t_esp = newTemp(cb);
2618 t_addr = newTemp(cb);
2619 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t_esp);
2620 uInstr2(cb, SUB, sz, Literal, 0, TempReg, t_esp);
2621 uLiteral(cb, sz);
2622 uInstr2(cb, PUT, 4, TempReg, t_esp, ArchReg, R_ESP);
2623 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, temp);
2624 uInstr2(cb, STORE, sz, TempReg, temp, TempReg, t_esp);
2625 /* Make ta point at it. */
2626 uInstr2(cb, MOV, 4, TempReg, t_esp, TempReg, t_addr);
2627 /* Mask out upper bits of the shift amount, since we're doing a
2628 reg. */
2629 uInstr2(cb, MOV, 4, Literal, 0, TempReg, lit);
2630 uLiteral(cb, sz == 4 ? 31 : 15);
2631 uInstr2(cb, AND, 4, TempReg, lit, TempReg, t_bitno);
2632 } else {
2633 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
2634 t_addr = LOW24(pair);
2635 eip += HI8(pair);
2636 }
2637
2638 /* At this point: ta points to the address being operated on. If
2639 it was a reg, we will have pushed it onto the client's stack.
2640 t_bitno is the bit number, suitable masked in the case of a reg. */
2641
2642 /* Now the main sequence. */
2643
2644 uInstr2(cb, MOV, 4, TempReg, t_bitno, TempReg, temp);
2645 uInstr2(cb, SAR, 4, Literal, 0, TempReg, temp);
2646 uLiteral(cb, 3);
2647 uInstr2(cb, ADD, 4, TempReg, temp, TempReg, t_addr);
2648 /* ta now holds effective address */
2649
2650 uInstr2(cb, MOV, 4, Literal, 0, TempReg, lit);
2651 uLiteral(cb, 7);
2652 uInstr2(cb, AND, 4, TempReg, lit, TempReg, t_bitno);
2653 /* bitno contains offset of bit within byte */
2654
2655 if (op != BtOpNone) {
2656 t_mask = newTemp(cb);
2657 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_mask);
2658 uLiteral(cb, 1);
2659 uInstr2(cb, SHL, 4, TempReg, t_bitno, TempReg, t_mask);
2660 }
2661 /* mask is now a suitable byte mask */
2662
2663 uInstr2(cb, LOAD, 1, TempReg, t_addr, TempReg, t_fetched);
2664 if (op != BtOpNone) {
2665 uInstr2(cb, MOV, 4, TempReg, t_fetched, TempReg, temp);
2666 switch (op) {
2667 case BtOpSet:
2668 uInstr2(cb, OR, 4, TempReg, t_mask, TempReg, temp);
2669 break;
2670 case BtOpComp:
2671 uInstr2(cb, XOR, 4, TempReg, t_mask, TempReg, temp);
2672 break;
2673 case BtOpReset:
2674 uInstr1(cb, NOT, 4, TempReg, t_mask);
2675 uInstr2(cb, AND, 4, TempReg, t_mask, TempReg, temp);
2676 break;
2677 default:
2678 VG_(panic)("dis_bt_G_E");
2679 }
2680 uInstr2(cb, STORE, 1, TempReg, temp, TempReg, t_addr);
2681 }
2682
2683 /* Side effect done; now get selected bit into Carry flag */
2684
2685 uInstr2(cb, SHR, 4, TempReg, t_bitno, TempReg, t_fetched);
2686 /* at bit 0 of fetched */
2687
2688 uInstr2(cb, MOV, 4, Literal, 0, TempReg, lit);
2689 uLiteral(cb, 1);
2690 uInstr2(cb, AND, 4, TempReg, lit, TempReg, t_fetched);
2691 /* fetched is now 1 or 0 */
2692
2693 /* NEG is a handy way to convert zero/nonzero into the carry
2694 flag. */
2695 uInstr1(cb, NEG, 4, TempReg, t_fetched);
2696 setFlagsFromUOpcode(cb, NEG);
2697 /* fetched is now in carry flag */
2698
2699 /* Move reg operand from stack back to reg */
2700 if (epartIsReg(modrm)) {
2701 /* t_esp still points at it. */
2702 uInstr2(cb, LOAD, sz, TempReg, t_esp, TempReg, temp);
2703 uInstr2(cb, PUT, sz, TempReg, temp, ArchReg, eregOfRM(modrm));
2704 uInstr2(cb, ADD, sz, Literal, 0, TempReg, t_esp);
2705 uLiteral(cb, sz);
2706 uInstr2(cb, PUT, 4, TempReg, t_esp, ArchReg, R_ESP);
2707 }
2708
2709 if (epartIsReg(modrm)) {
2710 if (dis)
2711 VG_(printf)("bt%s%c %s, %s\n",
2712 nameBtOp(op),
2713 nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
2714 nameIReg(sz, eregOfRM(modrm)));
2715 } else {
2716 if (dis)
2717 VG_(printf)("bt%s%c %s, %s\n",
2718 nameBtOp(op),
2719 nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
2720 dis_buf);
2721 }
2722
2723 return eip;
2724}
2725
2726
sewardjde4a1d02002-03-22 01:27:54 +00002727
2728
2729/* Handle BSF/BSR. Only v-size seems necessary. */
2730static
2731Addr dis_bs_E_G ( UCodeBlock* cb, Int sz, Addr eip, Bool fwds )
2732{
2733 Int t, ta, helper;
2734 UInt pair;
2735 UChar dis_buf[50];
2736 UChar modrm;
2737
2738 vg_assert(sz == 2 || sz == 4);
2739 vg_assert(sz==4);
2740
2741 helper = fwds ? VGOFF_(helper_bsf) : VGOFF_(helper_bsr);
2742 modrm = getUChar(eip);
2743 t = newTemp(cb);
2744
2745 if (epartIsReg(modrm)) {
2746 eip++;
2747 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t);
2748 if (dis)
2749 VG_(printf)("bs%c%c %s, %s\n",
2750 fwds ? 'f' : 'r',
2751 nameISize(sz), nameIReg(sz, eregOfRM(modrm)),
2752 nameIReg(sz, gregOfRM(modrm)));
2753 } else {
2754 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
2755 ta = LOW24(pair);
2756 eip += HI8(pair);
2757 uInstr2(cb, LOAD, sz, TempReg, ta, TempReg, t);
2758 if (dis)
2759 VG_(printf)("bs%c%c %s, %s\n",
2760 fwds ? 'f' : 'r',
2761 nameISize(sz), dis_buf,
2762 nameIReg(sz, gregOfRM(modrm)));
2763 }
2764
2765 uInstr0(cb, CALLM_S, 0);
2766 uInstr1(cb, PUSH, sz, TempReg, t);
2767 uInstr1(cb, CALLM, 0, Lit16, helper);
2768 uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsOSACP);
2769 uInstr1(cb, POP, sz, TempReg, t);
2770 uInstr2(cb, PUT, sz, TempReg, t, ArchReg, gregOfRM(modrm));
2771 uInstr0(cb, CALLM_E, 0);
2772
2773 return eip;
2774}
2775
2776
2777static
2778void codegen_xchg_eAX_Reg ( UCodeBlock* cb, Int sz, Int reg )
2779{
2780 Int t1, t2;
2781 vg_assert(sz == 2 || sz == 4);
2782 t1 = newTemp(cb);
2783 t2 = newTemp(cb);
2784 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
2785 uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t2);
2786 uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, R_EAX);
2787 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
2788 if (dis)
2789 VG_(printf)("xchg%c %s, %s\n", nameISize(sz),
2790 nameIReg(sz, R_EAX), nameIReg(sz, reg));
2791}
2792
2793
2794static
2795void codegen_SAHF ( UCodeBlock* cb )
2796{
sewardj3a72df02002-03-24 10:03:17 +00002797 Int t = newTemp(cb);
2798 Int t2 = newTemp(cb);
sewardjde4a1d02002-03-22 01:27:54 +00002799 uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t);
sewardj3a72df02002-03-24 10:03:17 +00002800
2801 /* Mask out parts of t not corresponding to %AH. This stops the
2802 instrumenter complaining if they are undefined. Otherwise, the
2803 instrumenter would check all 32 bits of t at the PUSH, which
2804 could be the cause of incorrect warnings. Discovered by Daniel
2805 Veillard <veillard@redhat.com>.
2806 */
2807 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
2808 uLiteral(cb, 0x0000FF00);
2809 uInstr2(cb, AND, 4, TempReg, t2, TempReg, t);
2810 /* We deliberately don't set the condition codes here, since this
2811 AND is purely internal to Valgrind and nothing to do with the
2812 client's state. */
2813
sewardjde4a1d02002-03-22 01:27:54 +00002814 uInstr0(cb, CALLM_S, 0);
2815 uInstr1(cb, PUSH, 4, TempReg, t);
2816 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_SAHF));
2817 uFlagsRWU(cb, FlagsEmpty, FlagsSZACP, FlagsEmpty);
2818 uInstr1(cb, CLEAR, 0, Lit16, 4);
2819 uInstr0(cb, CALLM_E, 0);
2820}
2821
2822
2823static
2824Addr dis_cmpxchg_G_E ( UCodeBlock* cb,
2825 Int size,
2826 Addr eip0 )
2827{
2828 Int ta, junk, dest, src, acc;
2829 UChar dis_buf[50];
2830 UChar rm;
2831
2832 rm = getUChar(eip0);
2833 acc = newTemp(cb);
2834 src = newTemp(cb);
2835 dest = newTemp(cb);
2836 junk = newTemp(cb);
2837 /* Only needed to get gcc's dataflow analyser off my back. */
2838 ta = INVALID_TEMPREG;
2839
2840 if (epartIsReg(rm)) {
2841 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, dest);
2842 eip0++;
2843 if (dis) VG_(printf)("cmpxchg%c %s,%s\n",
2844 nameISize(size),
2845 nameIReg(size,gregOfRM(rm)),
2846 nameIReg(size,eregOfRM(rm)) );
2847 nameIReg(size,eregOfRM(rm));
2848 } else {
2849 UInt pair = disAMode ( cb, eip0, dis?dis_buf:NULL );
2850 ta = LOW24(pair);
2851 uInstr2(cb, LOAD, size, TempReg, ta, TempReg, dest);
2852 eip0 += HI8(pair);
2853 if (dis) VG_(printf)("cmpxchg%c %s,%s\n", nameISize(size),
2854 nameIReg(size,gregOfRM(rm)), dis_buf);
2855 }
2856
2857 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, src);
2858 uInstr2(cb, GET, size, ArchReg, R_EAX, TempReg, acc);
2859 uInstr2(cb, MOV, size, TempReg, acc, TempReg, junk);
2860 uInstr2(cb, SUB, size, TempReg, dest, TempReg, junk);
2861 setFlagsFromUOpcode(cb, SUB);
2862
2863 uInstr2(cb, CMOV, 4, TempReg, src, TempReg, dest);
2864 uCond(cb, CondZ);
2865 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
2866 uInstr2(cb, CMOV, 4, TempReg, dest, TempReg, acc);
2867 uCond(cb, CondNZ);
2868 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
2869
2870 uInstr2(cb, PUT, size, TempReg, acc, ArchReg, R_EAX);
2871 if (epartIsReg(rm)) {
2872 uInstr2(cb, PUT, size, TempReg, dest, ArchReg, eregOfRM(rm));
2873 } else {
2874 uInstr2(cb, STORE, size, TempReg, dest, TempReg, ta);
2875 }
2876
2877 return eip0;
2878}
2879
2880
2881/* Handle conditional move instructions of the form
2882 cmovcc E(reg-or-mem), G(reg)
2883
2884 E(src) is reg-or-mem
2885 G(dst) is reg.
2886
2887 If E is reg, --> GET %E, tmps
2888 GET %G, tmpd
2889 CMOVcc tmps, tmpd
2890 PUT tmpd, %G
2891
2892 If E is mem --> (getAddr E) -> tmpa
2893 LD (tmpa), tmps
2894 GET %G, tmpd
2895 CMOVcc tmps, tmpd
2896 PUT tmpd, %G
2897*/
2898static
2899Addr dis_cmov_E_G ( UCodeBlock* cb,
2900 Int size,
2901 Condcode cond,
2902 Addr eip0 )
2903{
2904 UChar rm = getUChar(eip0);
2905 UChar dis_buf[50];
2906
2907 Int tmps = newTemp(cb);
2908 Int tmpd = newTemp(cb);
2909
2910 if (epartIsReg(rm)) {
2911 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, tmps);
2912 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmpd);
2913 uInstr2(cb, CMOV, 4, TempReg, tmps, TempReg, tmpd);
2914 uCond(cb, cond);
2915 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
2916 uInstr2(cb, PUT, size, TempReg, tmpd, ArchReg, gregOfRM(rm));
2917 if (dis) VG_(printf)("cmov%c%s %s,%s\n",
2918 nameISize(size),
2919 VG_(nameCondcode)(cond),
2920 nameIReg(size,eregOfRM(rm)),
2921 nameIReg(size,gregOfRM(rm)));
2922 return 1+eip0;
2923 }
2924
2925 /* E refers to memory */
2926 {
2927 UInt pair = disAMode ( cb, eip0, dis?dis_buf:NULL);
2928 Int tmpa = LOW24(pair);
2929 uInstr2(cb, LOAD, size, TempReg, tmpa, TempReg, tmps);
2930 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmpd);
2931 uInstr2(cb, CMOV, 4, TempReg, tmps, TempReg, tmpd);
2932 uCond(cb, cond);
2933 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
2934 uInstr2(cb, PUT, size, TempReg, tmpd, ArchReg, gregOfRM(rm));
2935 if (dis) VG_(printf)("cmov%c%s %s,%s\n",
2936 nameISize(size),
2937 VG_(nameCondcode)(cond),
2938 dis_buf,
2939 nameIReg(size,gregOfRM(rm)));
2940 return HI8(pair)+eip0;
2941 }
2942}
2943
2944
2945static
2946Addr dis_xadd_G_E ( UCodeBlock* cb,
2947 Int sz,
2948 Addr eip0 )
2949{
2950 UChar rm = getUChar(eip0);
2951 UChar dis_buf[50];
2952
2953 Int tmpd = newTemp(cb);
2954 Int tmpt = newTemp(cb);
2955
2956 if (epartIsReg(rm)) {
2957 uInstr2(cb, GET, sz, ArchReg, eregOfRM(rm), TempReg, tmpd);
2958 uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
2959 uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
2960 setFlagsFromUOpcode(cb, ADD);
2961 uInstr2(cb, PUT, sz, TempReg, tmpt, ArchReg, eregOfRM(rm));
2962 uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
2963 if (dis)
2964 VG_(printf)("xadd%c %s, %s\n", nameISize(sz),
2965 nameIReg(sz,gregOfRM(rm)),
2966 nameIReg(sz,eregOfRM(rm)));
2967 return 1+eip0;
2968 } else {
2969 UInt pair = disAMode ( cb, eip0, dis?dis_buf:NULL);
2970 Int tmpa = LOW24(pair);
2971 uInstr2(cb, LOAD, sz, TempReg, tmpa, TempReg, tmpd);
2972 uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
2973 uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
2974 setFlagsFromUOpcode(cb, ADD);
2975 uInstr2(cb, STORE, sz, TempReg, tmpt, TempReg, tmpa);
2976 SMC_IF_SOME(cb);
2977 uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
2978 if (dis)
2979 VG_(printf)("xadd%c %s, %s\n", nameISize(sz),
2980 nameIReg(sz,gregOfRM(rm)),
2981 dis_buf);
2982 return HI8(pair)+eip0;
2983 }
2984}
2985
2986
sewardjde4a1d02002-03-22 01:27:54 +00002987/*------------------------------------------------------------*/
2988/*--- Disassembling entire basic blocks ---*/
2989/*------------------------------------------------------------*/
2990
2991/* Disassemble a single instruction into ucode, returning the update
2992 eip, and setting *isEnd to True if this is the last insn in a basic
2993 block. Also do debug printing if (dis). */
2994
2995static Addr disInstr ( UCodeBlock* cb, Addr eip, Bool* isEnd )
2996{
2997 UChar opc, modrm, abyte;
2998 UInt d32, pair;
2999 Int t1, t2, t3, t4;
3000 UChar dis_buf[50];
3001 Int am_sz, d_sz;
3002
3003 Int sz = 4;
3004 Int first_uinstr = cb->used;
3005 *isEnd = False;
3006 t1 = t2 = t3 = t4 = INVALID_TEMPREG;
3007
3008 if (dis) VG_(printf)("\t0x%x: ", eip);
3009
sewardjc7529c32002-04-16 01:55:18 +00003010 /* Spot the client-request magic sequence. */
3011 {
sewardjde4a1d02002-03-22 01:27:54 +00003012 UChar* myeip = (UChar*)eip;
3013 /* Spot this:
3014 C1C01D roll $29, %eax
3015 C1C003 roll $3, %eax
sewardj2e93c502002-04-12 11:12:52 +00003016 C1C81B rorl $27, %eax
3017 C1C805 rorl $5, %eax
3018 C1C00D roll $13, %eax
3019 C1C013 roll $19, %eax
sewardjde4a1d02002-03-22 01:27:54 +00003020 */
sewardj2e93c502002-04-12 11:12:52 +00003021 if (myeip[ 0] == 0xC1 && myeip[ 1] == 0xC0 && myeip[ 2] == 0x1D &&
3022 myeip[ 3] == 0xC1 && myeip[ 4] == 0xC0 && myeip[ 5] == 0x03 &&
3023 myeip[ 6] == 0xC1 && myeip[ 7] == 0xC8 && myeip[ 8] == 0x1B &&
3024 myeip[ 9] == 0xC1 && myeip[10] == 0xC8 && myeip[11] == 0x05 &&
3025 myeip[12] == 0xC1 && myeip[13] == 0xC0 && myeip[14] == 0x0D &&
3026 myeip[15] == 0xC1 && myeip[16] == 0xC0 && myeip[17] == 0x13
3027 ) {
3028 eip += 18;
3029 uInstr1(cb, JMP, 0, Literal, 0);
3030 uLiteral(cb, eip);
3031 uCond(cb, CondAlways);
3032 LAST_UINSTR(cb).jmpkind = JmpClientReq;
3033 *isEnd = True;
3034 if (dis)
3035 VG_(printf)("%%edx = client_request ( %%eax )\n");
sewardjde4a1d02002-03-22 01:27:54 +00003036 return eip;
3037 }
3038 }
3039
3040 /* Skip a LOCK prefix. */
3041 if (getUChar(eip) == 0xF0) eip++;
3042
3043 /* Crap out if we see a segment override prefix. */
3044 if (getUChar(eip) == 0x65) {
3045 VG_(message)(Vg_DebugMsg, "");
3046 VG_(message)(Vg_DebugMsg, "Possible workaround for the following abort: do not use special");
3047 VG_(message)(Vg_DebugMsg, "PII/PIII-specific pthreads library (possibly in /lib/i686/*.so).");
3048 VG_(message)(Vg_DebugMsg, "You might be able to kludge around this by renaming /lib/i686 to");
3049 VG_(message)(Vg_DebugMsg, "/lib/i686-HIDDEN. On RedHat 7.2 this causes ld.so to fall back");
3050 VG_(message)(Vg_DebugMsg, "to using the less specialised versions in /lib instead, which");
3051 VG_(message)(Vg_DebugMsg, "valgrind might be able to better deal with.");
3052 VG_(message)(Vg_DebugMsg, "");
3053 VG_(message)(Vg_DebugMsg, "WARNING. WARNING. WARNING. WARNING. WARNING. WARNING. WARNING.");
3054 VG_(message)(Vg_DebugMsg, "WARNING: The suggested kludge may also render your system unbootable");
3055 VG_(message)(Vg_DebugMsg, "WARNING: or otherwise totally screw it up. Only try this if you");
3056 VG_(message)(Vg_DebugMsg, "WARNING: know what you are doing, and are prepared to take risks.");
3057 VG_(message)(Vg_DebugMsg, "YOU HAVE BEEN WARNED. YOU HAVE BEEN WARNED. YOU HAVE BEEN WARNED.");
3058 VG_(message)(Vg_DebugMsg, "");
3059 VG_(message)(Vg_DebugMsg, "Another consideration is that this may well mean your application");
3060 VG_(message)(Vg_DebugMsg, "uses threads, which valgrind doesn't currently support, so even if");
3061 VG_(message)(Vg_DebugMsg, "you work around this problem, valgrind may abort later if it sees");
3062 VG_(message)(Vg_DebugMsg, "a clone() system call.");
3063 VG_(unimplemented)("x86 segment override (SEG=GS) prefix; see above for details");
3064 }
3065
3066 /* Detect operand-size overrides. */
3067 if (getUChar(eip) == 0x66) { sz = 2; eip++; };
3068
3069 opc = getUChar(eip); eip++;
3070
3071 switch (opc) {
3072
3073 /* ------------------------ Control flow --------------- */
3074
3075 case 0xC2: /* RET imm16 */
3076 d32 = getUDisp16(eip); eip += 2;
3077 goto do_Ret;
3078 case 0xC3: /* RET */
3079 d32 = 0;
3080 goto do_Ret;
3081 do_Ret:
3082 t1 = newTemp(cb); t2 = newTemp(cb);
3083 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
3084 uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t2);
3085 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1);
3086 uLiteral(cb, 4+d32);
3087 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3088 uInstr1(cb, JMP, 0, TempReg, t2);
3089 uCond(cb, CondAlways);
sewardj2e93c502002-04-12 11:12:52 +00003090 LAST_UINSTR(cb).jmpkind = JmpRet;
sewardjde4a1d02002-03-22 01:27:54 +00003091
3092 *isEnd = True;
3093 if (dis) {
3094 if (d32 == 0) VG_(printf)("ret\n");
3095 else VG_(printf)("ret %d\n", d32);
3096 }
3097 break;
3098
3099 case 0xE8: /* CALL J4 */
3100 d32 = getUDisp32(eip); eip += 4;
3101 d32 += eip; /* eip now holds return-to addr, d32 is call-to addr */
sewardjde4a1d02002-03-22 01:27:54 +00003102 if (d32 == eip && getUChar(eip) >= 0x58
3103 && getUChar(eip) <= 0x5F) {
3104 /* Specially treat the position-independent-code idiom
3105 call X
3106 X: popl %reg
3107 as
3108 movl %eip, %reg.
3109 since this generates better code, but for no other reason. */
3110 Int archReg = getUChar(eip) - 0x58;
3111 /* VG_(printf)("-- fPIC thingy\n"); */
3112 t1 = newTemp(cb);
3113 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
3114 uLiteral(cb, eip);
3115 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, archReg);
3116 eip++; /* Step over the POP */
3117 if (dis)
3118 VG_(printf)("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
3119 } else {
3120 /* The normal sequence for a call. */
3121 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3122 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
3123 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t1);
3124 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t1);
3125 uLiteral(cb, 4);
3126 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3127 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
3128 uLiteral(cb, eip);
3129 uInstr2(cb, STORE, 4, TempReg, t2, TempReg, t1);
3130 SMC_IF_ALL(cb);
3131 uInstr1(cb, JMP, 0, Literal, 0);
3132 uLiteral(cb, d32);
3133 uCond(cb, CondAlways);
sewardj2e93c502002-04-12 11:12:52 +00003134 LAST_UINSTR(cb).jmpkind = JmpCall;
sewardjde4a1d02002-03-22 01:27:54 +00003135 *isEnd = True;
3136 if (dis) VG_(printf)("call 0x%x\n",d32);
3137 }
3138 break;
3139
3140 case 0xC9: /* LEAVE */
3141 t1 = newTemp(cb); t2 = newTemp(cb);
3142 uInstr2(cb, GET, 4, ArchReg, R_EBP, TempReg, t1);
3143 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3144 uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t2);
3145 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
3146 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1);
3147 uLiteral(cb, 4);
3148 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3149 if (dis) VG_(printf)("leave");
3150 break;
3151
sewardj4d0ab1f2002-03-24 10:00:09 +00003152 /* ---------------- Misc wierd-ass insns --------------- */
3153
sewardjfe8a1662002-03-24 11:54:07 +00003154 case 0x27: /* DAA */
sewardj4d0ab1f2002-03-24 10:00:09 +00003155 case 0x2F: /* DAS */
3156 t1 = newTemp(cb);
3157 uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
3158 /* Widen %AL to 32 bits, so it's all defined when we push it. */
3159 uInstr1(cb, WIDEN, 4, TempReg, t1);
3160 LAST_UINSTR(cb).extra4b = 1;
3161 LAST_UINSTR(cb).signed_widen = False;
3162 uInstr0(cb, CALLM_S, 0);
3163 uInstr1(cb, PUSH, 4, TempReg, t1);
sewardjfe8a1662002-03-24 11:54:07 +00003164 uInstr1(cb, CALLM, 0, Lit16,
3165 opc == 0x27 ? VGOFF_(helper_DAA) : VGOFF_(helper_DAS) );
sewardj4d0ab1f2002-03-24 10:00:09 +00003166 uFlagsRWU(cb, FlagsAC, FlagsOSZACP, FlagsEmpty);
3167 uInstr1(cb, POP, 4, TempReg, t1);
3168 uInstr0(cb, CALLM_E, 0);
3169 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
sewardjfe8a1662002-03-24 11:54:07 +00003170 if (dis) VG_(printf)(opc == 0x27 ? "daa\n" : "das\n");
3171 break;
sewardj4d0ab1f2002-03-24 10:00:09 +00003172
sewardjde4a1d02002-03-22 01:27:54 +00003173 /* ------------------------ CWD/CDQ -------------------- */
3174
3175 case 0x98: /* CBW */
3176 t1 = newTemp(cb);
3177 if (sz == 4) {
3178 uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
3179 uInstr1(cb, WIDEN, 4, TempReg, t1); /* 4 == dst size */
3180 LAST_UINSTR(cb).extra4b = 2; /* the source size */
3181 LAST_UINSTR(cb).signed_widen = True;
3182 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
3183 if (dis) VG_(printf)("cwd\n");
3184 } else {
3185 vg_assert(sz == 2);
3186 uInstr2(cb, GET, 1, ArchReg, R_EAX, TempReg, t1);
3187 uInstr1(cb, WIDEN, 2, TempReg, t1); /* 2 == dst size */
3188 LAST_UINSTR(cb).extra4b = 1; /* the source size */
3189 LAST_UINSTR(cb).signed_widen = True;
3190 uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
3191 if (dis) VG_(printf)("cbw\n");
3192 }
3193 break;
3194
3195 case 0x99: /* CWD/CDQ */
3196 t1 = newTemp(cb);
3197 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
3198 uInstr2(cb, SAR, sz, Literal, 0, TempReg, t1);
3199 uLiteral(cb, sz == 2 ? 15 : 31);
3200 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EDX);
3201 if (dis) VG_(printf)(sz == 2 ? "cwdq\n" : "cdqq\n");
3202 break;
3203
3204 /* ------------------------ FPU ops -------------------- */
3205
3206 case 0x9E: /* SAHF */
3207 codegen_SAHF ( cb );
3208 if (dis) VG_(printf)("sahf\n");
3209 break;
3210
3211 case 0x9B: /* FWAIT */
3212 /* ignore? */
3213 if (dis) VG_(printf)("fwait\n");
3214 break;
3215
3216 case 0xD8:
3217 case 0xD9:
3218 case 0xDA:
3219 case 0xDB:
3220 case 0xDC:
3221 case 0xDD:
3222 case 0xDE:
3223 case 0xDF:
3224 eip = dis_fpu ( cb, opc, eip );
3225 break;
3226
3227 /* ------------------------ INC & DEC ------------------ */
3228
3229 case 0x40: /* INC eAX */
3230 case 0x41: /* INC eCX */
3231 case 0x42: /* INC eDX */
3232 case 0x43: /* INC eBX */
3233 case 0x45: /* INC eBP */
3234 case 0x46: /* INC eSI */
3235 case 0x47: /* INC eDI */
3236 t1 = newTemp(cb);
3237 uInstr2(cb, GET, sz, ArchReg, (UInt)(opc - 0x40),
3238 TempReg, t1);
3239 uInstr1(cb, INC, sz, TempReg, t1);
3240 setFlagsFromUOpcode(cb, INC);
3241 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg,
3242 (UInt)(opc - 0x40));
3243 if (dis)
3244 VG_(printf)("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
3245 break;
3246
3247 case 0x48: /* DEC eAX */
3248 case 0x49: /* DEC eCX */
3249 case 0x4A: /* DEC eDX */
3250 case 0x4B: /* DEC eBX */
3251 case 0x4D: /* DEC eBP */
3252 case 0x4E: /* DEC eSI */
3253 case 0x4F: /* DEC eDI */
3254 t1 = newTemp(cb);
3255 uInstr2(cb, GET, sz, ArchReg, (UInt)(opc - 0x48),
3256 TempReg, t1);
3257 uInstr1(cb, DEC, sz, TempReg, t1);
3258 setFlagsFromUOpcode(cb, DEC);
3259 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg,
3260 (UInt)(opc - 0x48));
3261 if (dis)
3262 VG_(printf)("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
3263 break;
3264
3265 /* ------------------------ INT ------------------------ */
3266
3267 case 0xCD: /* INT imm8 */
3268 d32 = getUChar(eip); eip++;
3269 if (d32 != 0x80) VG_(panic)("disInstr: INT but not 0x80 !");
3270 /* It's important that all ArchRegs carry their up-to-date value
3271 at this point. So we declare an end-of-block here, which
3272 forces any TempRegs caching ArchRegs to be flushed. */
sewardjde4a1d02002-03-22 01:27:54 +00003273 uInstr1(cb, JMP, 0, Literal, 0);
3274 uLiteral(cb, eip);
3275 uCond(cb, CondAlways);
sewardj2e93c502002-04-12 11:12:52 +00003276 LAST_UINSTR(cb).jmpkind = JmpSyscall;
sewardjde4a1d02002-03-22 01:27:54 +00003277 *isEnd = True;
3278 if (dis) VG_(printf)("int $0x80\n");
3279 break;
3280
3281 /* ------------------------ Jcond, byte offset --------- */
3282
3283 case 0xEB: /* Jb (jump, byte offset) */
3284 d32 = (eip+1) + getSDisp8(eip); eip++;
3285 uInstr1(cb, JMP, 0, Literal, 0);
3286 uLiteral(cb, d32);
3287 uCond(cb, CondAlways);
3288 *isEnd = True;
3289 if (dis)
3290 VG_(printf)("jmp-8 0x%x\n", d32);
3291 break;
3292
3293 case 0xE9: /* Jv (jump, 16/32 offset) */
3294 d32 = (eip+sz) + getSDisp(sz,eip); eip += sz;
3295 uInstr1(cb, JMP, 0, Literal, 0);
3296 uLiteral(cb, d32);
3297 uCond(cb, CondAlways);
3298 *isEnd = True;
3299 if (dis)
3300 VG_(printf)("jmp 0x%x\n", d32);
3301 break;
3302
3303 case 0x70:
3304 case 0x71:
3305 case 0x72: /* JBb/JNAEb (jump below) */
3306 case 0x73: /* JNBb/JAEb (jump not below) */
3307 case 0x74: /* JZb/JEb (jump zero) */
3308 case 0x75: /* JNZb/JNEb (jump not zero) */
3309 case 0x76: /* JBEb/JNAb (jump below or equal) */
3310 case 0x77: /* JNBEb/JAb (jump not below or equal) */
3311 case 0x78: /* JSb (jump negative) */
3312 case 0x79: /* JSb (jump not negative) */
3313 case 0x7A: /* JP (jump parity even) */
3314 case 0x7B: /* JNP/JPO (jump parity odd) */
3315 case 0x7C: /* JLb/JNGEb (jump less) */
3316 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
3317 case 0x7E: /* JLEb/JNGb (jump less or equal) */
3318 case 0x7F: /* JGb/JNLEb (jump greater) */
3319 d32 = (eip+1) + getSDisp8(eip); eip++;
3320 uInstr1(cb, JMP, 0, Literal, 0);
3321 uLiteral(cb, d32);
3322 uCond(cb, (Condcode)(opc - 0x70));
3323 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
3324 /* It's actually acceptable not to end this basic block at a
3325 control transfer, reducing the number of jumps through
3326 vg_dispatch, at the expense of possibly translating the insns
3327 following this jump twice. This does give faster code, but
3328 on the whole I don't think the effort is worth it. */
3329 uInstr1(cb, JMP, 0, Literal, 0);
3330 uLiteral(cb, eip);
3331 uCond(cb, CondAlways);
3332 *isEnd = True;
3333 /* The above 3 lines would be removed if the bb was not to end
3334 here. */
3335 if (dis)
3336 VG_(printf)("j%s-8 0x%x\n", VG_(nameCondcode)(opc - 0x70), d32);
3337 break;
3338
3339 case 0xE3: /* JECXZ or perhaps JCXZ, depending on OSO ? Intel
3340 manual says it depends on address size override,
3341 which doesn't sound right to me. */
3342 d32 = (eip+1) + getSDisp8(eip); eip++;
3343 t1 = newTemp(cb);
3344 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
3345 uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
3346 uLiteral(cb, d32);
3347 if (dis)
3348 VG_(printf)("j%sz 0x%x\n", nameIReg(sz, R_ECX), d32);
3349 break;
3350
3351 case 0xE2: /* LOOP disp8 */
3352 /* Again, the docs say this uses ECX/CX as a count depending on
3353 the address size override, not the operand one. Since we
3354 don't handle address size overrides, I guess that means
3355 ECX. */
3356 d32 = (eip+1) + getSDisp8(eip); eip++;
3357 t1 = newTemp(cb);
3358 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
3359 uInstr1(cb, DEC, 4, TempReg, t1);
3360 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ECX);
3361 uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
3362 uLiteral(cb, eip);
3363 uInstr1(cb, JMP, 0, Literal, 0);
3364 uLiteral(cb, d32);
3365 uCond(cb, CondAlways);
3366 *isEnd = True;
3367 if (dis)
3368 VG_(printf)("loop 0x%x\n", d32);
3369 break;
3370
3371 /* ------------------------ IMUL ----------------------- */
3372
3373 case 0x69: /* IMUL Iv, Ev, Gv */
3374 eip = dis_imul_I_E_G ( cb, sz, eip, sz );
3375 break;
3376 case 0x6B: /* IMUL Ib, Ev, Gv */
3377 eip = dis_imul_I_E_G ( cb, sz, eip, 1 );
3378 break;
3379
3380 /* ------------------------ MOV ------------------------ */
3381
3382 case 0x88: /* MOV Gb,Eb */
3383 eip = dis_mov_G_E(cb, 1, eip);
3384 break;
3385
3386 case 0x89: /* MOV Gv,Ev */
3387 eip = dis_mov_G_E(cb, sz, eip);
3388 break;
3389
3390 case 0x8A: /* MOV Eb,Gb */
3391 eip = dis_mov_E_G(cb, 1, eip);
3392 break;
3393
3394 case 0x8B: /* MOV Ev,Gv */
3395 eip = dis_mov_E_G(cb, sz, eip);
3396 break;
3397
3398 case 0x8D: /* LEA M,Gv */
3399 modrm = getUChar(eip);
3400 if (epartIsReg(modrm))
3401 VG_(panic)("LEA M,Gv: modRM refers to register");
3402 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
3403 eip += HI8(pair);
3404 t1 = LOW24(pair);
3405 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, gregOfRM(modrm));
3406 if (dis)
3407 VG_(printf)("lea%c %s, %s\n", nameISize(sz), dis_buf,
3408 nameIReg(sz,gregOfRM(modrm)));
3409 break;
3410
3411 case 0xA0: /* MOV Ob,AL */
3412 sz = 1;
3413 /* Fall through ... */
3414 case 0xA1: /* MOV Ov,eAX */
3415 d32 = getUDisp32(eip); eip += 4;
3416 t1 = newTemp(cb); t2 = newTemp(cb);
3417 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
3418 uLiteral(cb, d32);
3419 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3420 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EAX);
3421 if (dis) VG_(printf)("mov%c 0x%x,%s\n", nameISize(sz),
3422 d32, nameIReg(sz,R_EAX));
3423 break;
3424
3425 case 0xA2: /* MOV AL,Ob */
3426 sz = 1;
3427 /* Fall through ... */
3428 case 0xA3: /* MOV eAX,Ov */
3429 d32 = getUDisp32(eip); eip += 4;
3430 t1 = newTemp(cb); t2 = newTemp(cb);
3431 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
3432 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
3433 uLiteral(cb, d32);
3434 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3435 SMC_IF_SOME(cb);
3436 if (dis) VG_(printf)("mov%c %s,0x%x\n", nameISize(sz),
3437 nameIReg(sz,R_EAX), d32);
3438 break;
3439
3440 case 0xB0: /* MOV imm,AL */
3441 case 0xB1: /* MOV imm,CL */
3442 case 0xB2: /* MOV imm,DL */
3443 case 0xB3: /* MOV imm,BL */
3444 case 0xB4: /* MOV imm,AH */
3445 case 0xB5: /* MOV imm,CH */
3446 case 0xB6: /* MOV imm,DH */
3447 case 0xB7: /* MOV imm,BH */
3448 d32 = getUChar(eip); eip += 1;
3449 t1 = newTemp(cb);
3450 uInstr2(cb, MOV, 1, Literal, 0, TempReg, t1);
3451 uLiteral(cb, d32);
3452 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, opc-0xB0);
3453 if (dis) VG_(printf)("movb $0x%x,%s\n", d32,
3454 nameIReg(1,opc-0xB0));
3455 break;
3456
3457 case 0xB8: /* MOV imm,eAX */
3458 case 0xB9: /* MOV imm,eCX */
3459 case 0xBA: /* MOV imm,eDX */
3460 case 0xBB: /* MOV imm,eBX */
3461 case 0xBD: /* MOV imm,eBP */
3462 case 0xBE: /* MOV imm,eSI */
3463 case 0xBF: /* MOV imm,eDI */
3464 d32 = getUDisp(sz,eip); eip += sz;
3465 t1 = newTemp(cb);
3466 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t1);
3467 uLiteral(cb, d32);
3468 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, opc-0xB8);
3469 if (dis) VG_(printf)("mov%c $0x%x,%s\n", nameISize(sz), d32,
3470 nameIReg(sz,opc-0xB8));
3471 break;
3472
3473 case 0xC6: /* MOV Ib,Eb */
3474 sz = 1;
3475 goto do_Mov_I_E;
3476 case 0xC7: /* MOV Iv,Ev */
3477 goto do_Mov_I_E;
3478
3479 do_Mov_I_E:
3480 modrm = getUChar(eip);
3481 if (epartIsReg(modrm)) {
3482 d32 = getUDisp(sz,eip); eip += sz;
3483 t1 = newTemp(cb);
3484 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t1);
3485 uLiteral(cb, d32);
3486 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
3487 if (dis) VG_(printf)("mov%c $0x%x, %s\n", nameISize(sz), d32,
3488 nameIReg(sz,eregOfRM(modrm)));
3489 } else {
3490 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
3491 eip += HI8(pair);
3492 d32 = getUDisp(sz,eip); eip += sz;
3493 t1 = newTemp(cb);
3494 t2 = LOW24(pair);
3495 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t1);
3496 uLiteral(cb, d32);
3497 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3498 SMC_IF_SOME(cb);
3499 if (dis) VG_(printf)("mov%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
3500 }
3501 break;
3502
3503 /* ------------------------ opl imm, A ----------------- */
3504
3505 case 0x04: /* ADD Ib, AL */
3506 eip = dis_op_imm_A(cb, 1, ADD, True, eip, "add" );
3507 break;
3508 case 0x05: /* ADD Iv, eAX */
3509 eip = dis_op_imm_A(cb, sz, ADD, True, eip, "add" );
3510 break;
3511
3512 case 0x0C: /* OR Ib, AL */
3513 eip = dis_op_imm_A(cb, 1, OR, True, eip, "or" );
3514 break;
3515 case 0x0D: /* OR Iv, eAX */
3516 eip = dis_op_imm_A(cb, sz, OR, True, eip, "or" );
3517 break;
3518
3519 case 0x24: /* AND Ib, AL */
3520 eip = dis_op_imm_A(cb, 1, AND, True, eip, "and" );
3521 break;
3522 case 0x25: /* AND Iv, eAX */
3523 eip = dis_op_imm_A(cb, sz, AND, True, eip, "and" );
3524 break;
3525
3526 case 0x2C: /* SUB Ib, AL */
3527 eip = dis_op_imm_A(cb, 1, SUB, True, eip, "sub" );
3528 break;
3529 case 0x2D: /* SUB Iv, eAX */
3530 eip = dis_op_imm_A(cb, sz, SUB, True, eip, "sub" );
3531 break;
3532
3533 case 0x34: /* XOR Ib, AL */
3534 eip = dis_op_imm_A(cb, 1, XOR, True, eip, "xor" );
3535 break;
3536 case 0x35: /* XOR Iv, eAX */
3537 eip = dis_op_imm_A(cb, sz, XOR, True, eip, "xor" );
3538 break;
3539
3540 case 0x3C: /* CMP Ib, AL */
3541 eip = dis_op_imm_A(cb, 1, SUB, False, eip, "cmp" );
3542 break;
3543 case 0x3D: /* CMP Iv, eAX */
3544 eip = dis_op_imm_A(cb, sz, SUB, False, eip, "cmp" );
3545 break;
3546
3547 case 0xA8: /* TEST Ib, AL */
3548 eip = dis_op_imm_A(cb, 1, AND, False, eip, "test" );
3549 break;
3550 case 0xA9: /* TEST Iv, eAX */
3551 eip = dis_op_imm_A(cb, sz, AND, False, eip, "test" );
3552 break;
3553
3554 /* ------------------------ opl Ev, Gv ----------------- */
3555
3556 case 0x02: /* ADD Eb,Gb */
3557 eip = dis_op2_E_G ( cb, ADD, True, 1, eip, "add" );
3558 break;
3559 case 0x03: /* ADD Ev,Gv */
3560 eip = dis_op2_E_G ( cb, ADD, True, sz, eip, "add" );
3561 break;
3562
3563 case 0x0A: /* OR Eb,Gb */
3564 eip = dis_op2_E_G ( cb, OR, True, 1, eip, "or" );
3565 break;
3566 case 0x0B: /* OR Ev,Gv */
3567 eip = dis_op2_E_G ( cb, OR, True, sz, eip, "or" );
3568 break;
3569
3570 case 0x13: /* ADC Ev,Gv */
3571 eip = dis_op2_E_G ( cb, ADC, True, sz, eip, "adc" );
3572 break;
3573
3574 case 0x1B: /* SBB Ev,Gv */
3575 eip = dis_op2_E_G ( cb, SBB, True, sz, eip, "sbb" );
3576 break;
3577
3578 case 0x22: /* AND Eb,Gb */
3579 eip = dis_op2_E_G ( cb, AND, True, 1, eip, "and" );
3580 break;
3581 case 0x23: /* AND Ev,Gv */
3582 eip = dis_op2_E_G ( cb, AND, True, sz, eip, "and" );
3583 break;
3584
3585 case 0x2A: /* SUB Eb,Gb */
3586 eip = dis_op2_E_G ( cb, SUB, True, 1, eip, "sub" );
3587 break;
3588 case 0x2B: /* SUB Ev,Gv */
3589 eip = dis_op2_E_G ( cb, SUB, True, sz, eip, "sub" );
3590 break;
3591
3592 case 0x32: /* XOR Eb,Gb */
3593 eip = dis_op2_E_G ( cb, XOR, True, 1, eip, "xor" );
3594 break;
3595 case 0x33: /* XOR Ev,Gv */
3596 eip = dis_op2_E_G ( cb, XOR, True, sz, eip, "xor" );
3597 break;
3598
3599 case 0x3A: /* CMP Eb,Gb */
3600 eip = dis_op2_E_G ( cb, SUB, False, 1, eip, "cmp" );
3601 break;
3602 case 0x3B: /* CMP Ev,Gv */
3603 eip = dis_op2_E_G ( cb, SUB, False, sz, eip, "cmp" );
3604 break;
3605
3606 case 0x84: /* TEST Eb,Gb */
3607 eip = dis_op2_E_G ( cb, AND, False, 1, eip, "test" );
3608 break;
3609 case 0x85: /* TEST Ev,Gv */
3610 eip = dis_op2_E_G ( cb, AND, False, sz, eip, "test" );
3611 break;
3612
3613 /* ------------------------ opl Gv, Ev ----------------- */
3614
3615 case 0x00: /* ADD Gb,Eb */
3616 eip = dis_op2_G_E ( cb, ADD, True, 1, eip, "add" );
3617 break;
3618 case 0x01: /* ADD Gv,Ev */
3619 eip = dis_op2_G_E ( cb, ADD, True, sz, eip, "add" );
3620 break;
3621
3622 case 0x08: /* OR Gb,Eb */
3623 eip = dis_op2_G_E ( cb, OR, True, 1, eip, "or" );
3624 break;
3625 case 0x09: /* OR Gv,Ev */
3626 eip = dis_op2_G_E ( cb, OR, True, sz, eip, "or" );
3627 break;
3628
3629 case 0x11: /* ADC Gv,Ev */
3630 eip = dis_op2_G_E ( cb, ADC, True, sz, eip, "adc" );
3631 break;
3632
3633 case 0x19: /* SBB Gv,Ev */
3634 eip = dis_op2_G_E ( cb, SBB, True, sz, eip, "sbb" );
3635 break;
3636
3637 case 0x20: /* AND Gb,Eb */
3638 eip = dis_op2_G_E ( cb, AND, True, 1, eip, "and" );
3639 break;
3640 case 0x21: /* AND Gv,Ev */
3641 eip = dis_op2_G_E ( cb, AND, True, sz, eip, "and" );
3642 break;
3643
3644 case 0x28: /* SUB Gb,Eb */
3645 eip = dis_op2_G_E ( cb, SUB, True, 1, eip, "sub" );
3646 break;
3647 case 0x29: /* SUB Gv,Ev */
3648 eip = dis_op2_G_E ( cb, SUB, True, sz, eip, "sub" );
3649 break;
3650
3651 case 0x30: /* XOR Gb,Eb */
3652 eip = dis_op2_G_E ( cb, XOR, True, 1, eip, "xor" );
3653 break;
3654 case 0x31: /* XOR Gv,Ev */
3655 eip = dis_op2_G_E ( cb, XOR, True, sz, eip, "xor" );
3656 break;
3657
3658 case 0x38: /* CMP Gb,Eb */
3659 eip = dis_op2_G_E ( cb, SUB, False, 1, eip, "cmp" );
3660 break;
3661 case 0x39: /* CMP Gv,Ev */
3662 eip = dis_op2_G_E ( cb, SUB, False, sz, eip, "cmp" );
3663 break;
3664
3665 /* ------------------------ POP ------------------------ */
3666
3667 case 0x58: /* POP eAX */
3668 case 0x59: /* POP eCX */
3669 case 0x5A: /* POP eDX */
3670 case 0x5B: /* POP eBX */
3671 case 0x5C: /* POP eSP */
3672 case 0x5D: /* POP eBP */
3673 case 0x5E: /* POP eSI */
3674 case 0x5F: /* POP eDI */
3675 t1 = newTemp(cb); t2 = newTemp(cb);
3676 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
3677 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3678 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3679 uLiteral(cb, sz);
3680 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
3681 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, opc-0x58);
3682 if (dis)
3683 VG_(printf)("pop%c %s\n", nameISize(sz), nameIReg(sz,opc-0x58));
3684 break;
3685
3686 case 0x9D: /* POPF */
3687 vg_assert(sz == 2 || sz == 4);
3688 t1 = newTemp(cb); t2 = newTemp(cb);
3689 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
3690 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3691 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3692 uLiteral(cb, sz);
3693 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
3694 uInstr1(cb, PUTF, sz, TempReg, t1);
3695 /* PUTF writes all the flags we are interested in */
3696 uFlagsRWU(cb, FlagsEmpty, FlagsALL, FlagsEmpty);
3697 if (dis)
3698 VG_(printf)("popf%c\n", nameISize(sz));
3699 break;
3700
3701 case 0x61: /* POPA */
3702 { Int reg;
3703 /* Just to keep things sane, we assert for a size 4. It's
3704 probably OK for size 2 as well, but I'd like to find a test
3705 case; ie, have the assertion fail, before committing to it.
3706 If it fails for you, uncomment the sz == 2 bit, try again,
3707 and let me know whether or not it works. (jseward@acm.org). */
3708 vg_assert(sz == 4 /* || sz == 2 */);
3709
3710 /* Eight values are popped, one per register, but the value of
3711 %esp on the stack is ignored and instead incremented (in one
3712 hit at the end) for each of the values. */
3713 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3714 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
3715 uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t3);
3716
3717 /* Do %edi, %esi, %ebp */
3718 for (reg = 7; reg >= 5; reg--) {
3719 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3720 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3721 uLiteral(cb, sz);
3722 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
3723 }
3724 /* Ignore (skip) value of %esp on stack. */
3725 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3726 uLiteral(cb, sz);
3727 /* Do %ebx, %edx, %ecx, %eax */
3728 for (reg = 3; reg >= 0; reg--) {
3729 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3730 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3731 uLiteral(cb, sz);
3732 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
3733 }
3734 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t3);
3735 uLiteral(cb, sz * 8); /* One 'sz' per register */
3736 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
3737 if (dis)
3738 VG_(printf)("popa%c\n", nameISize(sz));
3739 break;
3740 }
3741
3742 /* ------------------------ PUSH ----------------------- */
3743
3744 case 0x50: /* PUSH eAX */
3745 case 0x51: /* PUSH eCX */
3746 case 0x52: /* PUSH eDX */
3747 case 0x54: /* PUSH eSP */
3748 case 0x53: /* PUSH eBX */
3749 case 0x55: /* PUSH eBP */
3750 case 0x56: /* PUSH eSI */
3751 case 0x57: /* PUSH eDI */
3752 /* This is the Right Way, in that the value to be pushed is
3753 established before %esp is changed, so that pushl %esp
3754 correctly pushes the old value. */
3755 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3756 uInstr2(cb, GET, sz, ArchReg, opc-0x50, TempReg, t1);
3757 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
3758 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
3759 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3760 uLiteral(cb, sz);
3761 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
3762 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3763 SMC_IF_ALL(cb);
3764 if (dis)
3765 VG_(printf)("push%c %s\n", nameISize(sz), nameIReg(sz,opc-0x50));
3766 break;
3767
3768 case 0x68: /* PUSH Iv */
3769 d32 = getUDisp(sz,eip); eip += sz;
3770 goto do_push_I;
3771 case 0x6A: /* PUSH Ib, sign-extended to sz */
3772 d32 = getSDisp8(eip); eip += 1;
3773 goto do_push_I;
3774 do_push_I:
3775 t1 = newTemp(cb); t2 = newTemp(cb);
3776 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
3777 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t1);
3778 uLiteral(cb, sz);
3779 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3780 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t2);
3781 uLiteral(cb, d32);
3782 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
3783 SMC_IF_ALL(cb);
3784 if (dis)
3785 VG_(printf)("push%c $0x%x\n", nameISize(sz), d32);
3786 break;
3787
3788 case 0x9C: /* PUSHF */
3789 vg_assert(sz == 2 || sz == 4);
3790 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3791 uInstr1(cb, GETF, sz, TempReg, t1);
3792 /* GETF reads all the flags we are interested in */
3793 uFlagsRWU(cb, FlagsALL, FlagsEmpty, FlagsEmpty);
3794 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
3795 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
3796 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3797 uLiteral(cb, sz);
3798 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
3799 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3800 SMC_IF_ALL(cb);
3801 if (dis)
3802 VG_(printf)("pushf%c\n", nameISize(sz));
3803 break;
3804
3805 case 0x60: /* PUSHA */
3806 { Int reg;
3807 /* Just to keep things sane, we assert for a size 4. It's
3808 probably OK for size 2 as well, but I'd like to find a test
3809 case; ie, have the assertion fail, before committing to it.
3810 If it fails for you, uncomment the sz == 2 bit, try again,
3811 and let me know whether or not it works. (jseward@acm.org). */
3812 vg_assert(sz == 4 /* || sz == 2 */);
3813
3814 /* This is the Right Way, in that the value to be pushed is
3815 established before %esp is changed, so that pusha
3816 correctly pushes the old %esp value. New value of %esp is
3817 pushed at start. */
3818 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3819 t4 = newTemp(cb);
3820 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
3821 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
3822 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t4);
3823 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t4);
3824 uLiteral(cb, sz * 8); /* One 'sz' per register. */
3825 uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_ESP);
3826 /* Do %eax, %ecx, %edx, %ebx */
3827 for (reg = 0; reg <= 3; reg++) {
3828 uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
3829 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3830 uLiteral(cb, sz);
3831 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3832 SMC_IF_ALL(cb);
3833 }
3834 /* Push old value of %esp */
3835 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3836 uLiteral(cb, sz);
3837 uInstr2(cb, STORE, sz, TempReg, t3, TempReg, t2);
3838 SMC_IF_ALL(cb);
3839 /* Do %ebp, %esi, %edi */
3840 for (reg = 5; reg <= 7; reg++) {
3841 uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
3842 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3843 uLiteral(cb, sz);
3844 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3845 SMC_IF_ALL(cb);
3846 }
3847 if (dis)
3848 VG_(printf)("pusha%c\n", nameISize(sz));
3849 break;
3850 }
3851
3852 /* ------------------------ SCAS et al ----------------- */
3853
3854 case 0xA4: /* MOVSb, no REP prefix */
3855 codegen_MOVS ( cb, 1 );
3856 if (dis) VG_(printf)("movsb\n");
3857 break;
3858 case 0xA5: /* MOVSv, no REP prefix */
3859 codegen_MOVS ( cb, sz );
3860 if (dis) VG_(printf)("movs%c\n", nameISize(sz));
3861 break;
3862
3863 case 0xA6: /* CMPSb, no REP prefix */
3864 codegen_CMPS ( cb, 1 );
3865 if (dis) VG_(printf)("cmpsb\n");
3866 break;
3867
3868 case 0xAA: /* STOSb, no REP prefix */
3869 codegen_STOS ( cb, 1 );
3870 if (dis) VG_(printf)("stosb\n");
3871 break;
3872 case 0xAB: /* STOSv, no REP prefix */
3873 codegen_STOS ( cb, sz );
3874 if (dis) VG_(printf)("stos%c\n", nameISize(sz));
3875 break;
3876
3877 case 0xAC: /* LODSb, no REP prefix */
3878 codegen_LODS ( cb, 1 );
3879 if (dis) VG_(printf)("lodsb\n");
3880 break;
3881
3882 case 0xAE: /* SCASb, no REP prefix */
3883 codegen_SCAS ( cb, 1 );
3884 if (dis) VG_(printf)("scasb\n");
3885 break;
3886
3887 case 0xFC: /* CLD */
3888 uInstr0(cb, CALLM_S, 0);
3889 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CLD));
3890 uFlagsRWU(cb, FlagsEmpty, FlagD, FlagsEmpty);
3891 uInstr0(cb, CALLM_E, 0);
3892 if (dis) VG_(printf)("cld\n");
3893 break;
3894
3895 case 0xFD: /* STD */
3896 uInstr0(cb, CALLM_S, 0);
3897 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_STD));
3898 uFlagsRWU(cb, FlagsEmpty, FlagD, FlagsEmpty);
3899 uInstr0(cb, CALLM_E, 0);
3900 if (dis) VG_(printf)("std\n");
3901 break;
3902
3903 case 0xF2: { /* REPNE prefix insn */
3904 Addr eip_orig = eip - 1;
3905 abyte = getUChar(eip); eip++;
3906 if (abyte == 0x66) { sz = 2; abyte = getUChar(eip); eip++; }
3907
3908 if (abyte == 0xAE || 0xAF) { /* REPNE SCAS<sz> */
3909 if (abyte == 0xAE) sz = 1;
3910 codegen_REPNE_SCAS ( cb, sz, eip_orig, eip );
3911 *isEnd = True;
3912 if (dis) VG_(printf)("repne scas%c\n", nameISize(sz));
3913 }
3914 else {
3915 VG_(printf)("REPNE then 0x%x\n", (UInt)abyte);
3916 VG_(panic)("Unhandled REPNE case");
3917 }
3918 break;
3919 }
3920
3921 case 0xF3: { /* REPE prefix insn */
3922 Addr eip_orig = eip - 1;
3923 abyte = getUChar(eip); eip++;
3924 if (abyte == 0x66) { sz = 2; abyte = getUChar(eip); eip++; }
3925
3926 if (abyte == 0xA4 || abyte == 0xA5) { /* REPE MOV<sz> */
3927 if (abyte == 0xA4) sz = 1;
3928 codegen_REPE_MOVS ( cb, sz, eip_orig, eip );
3929 *isEnd = True;
3930 if (dis) VG_(printf)("repe mov%c\n", nameISize(sz));
3931 }
3932 else
3933 if (abyte == 0xA6 || abyte == 0xA7) { /* REPE CMP<sz> */
3934 if (abyte == 0xA6) sz = 1;
3935 codegen_REPE_CMPS ( cb, sz, eip_orig, eip );
3936 *isEnd = True;
3937 if (dis) VG_(printf)("repe cmps%c\n", nameISize(sz));
3938 }
3939 else
3940 if (abyte == 0xAA || abyte == 0xAB) { /* REPE STOS<sz> */
3941 if (abyte == 0xAA) sz = 1;
3942 codegen_REPE_STOS ( cb, sz, eip_orig, eip );
3943 *isEnd = True;
3944 if (dis) VG_(printf)("repe stos%c\n", nameISize(sz));
3945 } else {
3946 VG_(printf)("REPE then 0x%x\n", (UInt)abyte);
3947 VG_(panic)("Unhandled REPE case");
3948 }
3949 break;
3950 }
3951
3952 /* ------------------------ XCHG ----------------------- */
3953
3954 case 0x86: /* XCHG Gb,Eb */
3955 sz = 1;
3956 /* Fall through ... */
3957 case 0x87: /* XCHG Gv,Ev */
3958 modrm = getUChar(eip);
3959 t1 = newTemp(cb); t2 = newTemp(cb);
3960 if (epartIsReg(modrm)) {
3961 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
3962 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t2);
3963 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, gregOfRM(modrm));
3964 uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, eregOfRM(modrm));
3965 eip++;
3966 if (dis)
3967 VG_(printf)("xchg%c %s, %s\n", nameISize(sz),
3968 nameIReg(sz,gregOfRM(modrm)),
3969 nameIReg(sz,eregOfRM(modrm)));
3970 } else {
3971 pair = disAMode ( cb, eip, dis?dis_buf:NULL);
3972 t3 = LOW24(pair);
3973 uInstr2(cb, LOAD, sz, TempReg, t3, TempReg, t1);
3974 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t2);
3975 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t3);
3976 SMC_IF_SOME(cb);
3977 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, gregOfRM(modrm));
3978 eip += HI8(pair);
3979 if (dis)
3980 VG_(printf)("xchg%c %s, %s\n", nameISize(sz),
3981 nameIReg(sz,gregOfRM(modrm)),
3982 dis_buf);
3983 }
3984 break;
3985
3986 case 0x90: /* XCHG eAX,eAX */
3987 if (dis) VG_(printf)("nop\n");
3988 break;
3989 case 0x91: /* XCHG eCX,eSI */
3990 case 0x96: /* XCHG eAX,eSI */
3991 case 0x97: /* XCHG eAX,eDI */
3992 codegen_xchg_eAX_Reg ( cb, sz, opc - 0x90 );
3993 break;
3994
3995 /* ------------------------ (Grp1 extensions) ---------- */
3996
3997 case 0x80: /* Grp1 Ib,Eb */
3998 modrm = getUChar(eip);
3999 am_sz = lengthAMode(eip);
4000 sz = 1;
4001 d_sz = 1;
4002 d32 = getSDisp8(eip + am_sz);
4003 eip = dis_Grp1 ( cb, eip, modrm, am_sz, d_sz, sz, d32 );
4004 break;
4005
4006 case 0x81: /* Grp1 Iv,Ev */
4007 modrm = getUChar(eip);
4008 am_sz = lengthAMode(eip);
4009 d_sz = sz;
4010 d32 = getUDisp(d_sz, eip + am_sz);
4011 eip = dis_Grp1 ( cb, eip, modrm, am_sz, d_sz, sz, d32 );
4012 break;
4013
4014 case 0x83: /* Grp1 Ib,Ev */
4015 modrm = getUChar(eip);
4016 am_sz = lengthAMode(eip);
4017 d_sz = 1;
4018 d32 = getSDisp8(eip + am_sz);
4019 eip = dis_Grp1 ( cb, eip, modrm, am_sz, d_sz, sz, d32 );
4020 break;
4021
4022 /* ------------------------ (Grp2 extensions) ---------- */
4023
4024 case 0xC0: /* Grp2 Ib,Eb */
4025 modrm = getUChar(eip);
4026 am_sz = lengthAMode(eip);
4027 d_sz = 1;
4028 d32 = getSDisp8(eip + am_sz);
4029 sz = 1;
4030 eip = dis_Grp2 ( cb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
4031 break;
4032
4033 case 0xC1: /* Grp2 Ib,Ev */
4034 modrm = getUChar(eip);
4035 am_sz = lengthAMode(eip);
4036 d_sz = 1;
4037 d32 = getSDisp8(eip + am_sz);
4038 eip = dis_Grp2 ( cb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
4039 break;
4040
4041 case 0xD0: /* Grp2 1,Eb */
4042 modrm = getUChar(eip);
4043 am_sz = lengthAMode(eip);
4044 d_sz = 0;
4045 d32 = 1;
4046 sz = 1;
4047 eip = dis_Grp2 ( cb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
4048 break;
4049
4050 case 0xD1: /* Grp2 1,Ev */
4051 modrm = getUChar(eip);
4052 am_sz = lengthAMode(eip);
4053 d_sz = 0;
4054 d32 = 1;
4055 eip = dis_Grp2 ( cb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
4056 break;
4057
4058 case 0xD3: /* Grp2 CL,Ev */
4059 modrm = getUChar(eip);
4060 am_sz = lengthAMode(eip);
4061 d_sz = 0;
4062 eip = dis_Grp2 ( cb, eip, modrm, am_sz, d_sz, sz, ArchReg, R_ECX );
4063 break;
4064
4065 /* ------------------------ (Grp3 extensions) ---------- */
4066
4067 case 0xF6: /* Grp3 Eb */
4068 eip = dis_Grp3 ( cb, 1, eip );
4069 break;
4070 case 0xF7: /* Grp3 Ev */
4071 eip = dis_Grp3 ( cb, sz, eip );
4072 break;
4073
4074 /* ------------------------ (Grp4 extensions) ---------- */
4075
4076 case 0xFE: /* Grp4 Eb */
4077 eip = dis_Grp4 ( cb, eip );
4078 break;
4079
4080 /* ------------------------ (Grp5 extensions) ---------- */
4081
4082 case 0xFF: /* Grp5 Ev */
4083 eip = dis_Grp5 ( cb, sz, eip, isEnd );
4084 break;
4085
4086 /* ------------------------ Escapes to 2-byte opcodes -- */
4087
4088 case 0x0F: {
4089 opc = getUChar(eip); eip++;
4090 switch (opc) {
4091
4092 /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
4093
4094 case 0xBA: /* Grp8 Ib,Ev */
4095 modrm = getUChar(eip);
4096 am_sz = lengthAMode(eip);
4097 d32 = getSDisp8(eip + am_sz);
sewardj0ece28b2002-04-16 00:42:12 +00004098 eip = dis_Grp8_BT ( cb, eip, modrm, am_sz, sz, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00004099 break;
sewardj0ece28b2002-04-16 00:42:12 +00004100
sewardjde4a1d02002-03-22 01:27:54 +00004101 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
4102
4103 case 0xBC: /* BSF Gv,Ev */
4104 eip = dis_bs_E_G ( cb, sz, eip, True );
4105 break;
4106 case 0xBD: /* BSR Gv,Ev */
4107 eip = dis_bs_E_G ( cb, sz, eip, False );
4108 break;
4109
4110 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
4111
4112 case 0xC8: /* BSWAP %eax */
4113 case 0xC9:
4114 case 0xCA:
4115 case 0xCB:
4116 case 0xCC:
4117 case 0xCD:
4118 case 0xCE:
4119 case 0xCF: /* BSWAP %edi */
4120 /* AFAICS from the Intel docs, this only exists at size 4. */
4121 vg_assert(sz == 4);
4122 t1 = newTemp(cb);
4123 uInstr2(cb, GET, 4, ArchReg, opc-0xC8, TempReg, t1);
4124 uInstr1(cb, BSWAP, 4, TempReg, t1);
4125 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, opc-0xC8);
4126 if (dis) VG_(printf)("bswapl %s\n", nameIReg(4, opc-0xC8));
4127 break;
4128
4129 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
4130
4131 case 0xA3: /* BT Gv,Ev */
4132 eip = dis_bt_G_E ( cb, sz, eip, BtOpNone );
4133 break;
4134 case 0xB3: /* BTR Gv,Ev */
4135 eip = dis_bt_G_E ( cb, sz, eip, BtOpReset );
4136 break;
4137 case 0xAB: /* BTS Gv,Ev */
4138 eip = dis_bt_G_E ( cb, sz, eip, BtOpSet );
4139 break;
4140 case 0xBB: /* BTC Gv,Ev */
4141 eip = dis_bt_G_E ( cb, sz, eip, BtOpComp );
4142 break;
4143
4144 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
4145
4146 case 0x40:
4147 case 0x41:
4148 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
4149 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
4150 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
4151 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
4152 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
4153 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
4154 case 0x48: /* CMOVSb (cmov negative) */
4155 case 0x49: /* CMOVSb (cmov not negative) */
4156 case 0x4A: /* CMOVP (cmov parity even) */
4157 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
4158 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
4159 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
4160 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
4161 eip = dis_cmov_E_G(cb, sz, (Condcode)(opc - 0x40), eip);
4162 break;
4163
4164 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
4165
4166 case 0xB1: /* CMPXCHG Gv,Ev */
4167 eip = dis_cmpxchg_G_E ( cb, sz, eip );
4168 break;
4169
4170 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
4171
4172 case 0xA2: /* CPUID */
4173 t1 = newTemp(cb);
4174 t2 = newTemp(cb);
4175 t3 = newTemp(cb);
4176 t4 = newTemp(cb);
4177 uInstr0(cb, CALLM_S, 0);
4178
4179 uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t1);
4180 uInstr1(cb, PUSH, 4, TempReg, t1);
4181
4182 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
4183 uLiteral(cb, 0);
4184 uInstr1(cb, PUSH, 4, TempReg, t2);
4185
4186 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t3);
4187 uLiteral(cb, 0);
4188 uInstr1(cb, PUSH, 4, TempReg, t3);
4189
4190 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
4191 uLiteral(cb, 0);
4192 uInstr1(cb, PUSH, 4, TempReg, t4);
4193
4194 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CPUID));
4195 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
4196
4197 uInstr1(cb, POP, 4, TempReg, t4);
4198 uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_EDX);
4199
4200 uInstr1(cb, POP, 4, TempReg, t3);
4201 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ECX);
4202
4203 uInstr1(cb, POP, 4, TempReg, t2);
4204 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBX);
4205
4206 uInstr1(cb, POP, 4, TempReg, t1);
4207 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
4208
4209 uInstr0(cb, CALLM_E, 0);
4210 if (dis) VG_(printf)("cpuid\n");
4211 break;
4212
4213 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
4214
4215 case 0xB6: /* MOVZXb Eb,Gv */
4216 eip = dis_movx_E_G ( cb, eip, 1, 4, False );
4217 break;
4218 case 0xB7: /* MOVZXw Ew,Gv */
4219 eip = dis_movx_E_G ( cb, eip, 2, 4, False );
4220 break;
4221
4222 case 0xBE: /* MOVSXb Eb,Gv */
4223 eip = dis_movx_E_G ( cb, eip, 1, 4, True );
4224 break;
4225 case 0xBF: /* MOVSXw Ew,Gv */
4226 eip = dis_movx_E_G ( cb, eip, 2, 4, True );
4227 break;
4228
4229 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
4230
4231 case 0xAF: /* IMUL Ev, Gv */
4232 eip = dis_mul_E_G ( cb, sz, eip, True );
4233 break;
4234
4235 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
4236 case 0x80:
4237 case 0x81:
4238 case 0x82: /* JBb/JNAEb (jump below) */
4239 case 0x83: /* JNBb/JAEb (jump not below) */
4240 case 0x84: /* JZb/JEb (jump zero) */
4241 case 0x85: /* JNZb/JNEb (jump not zero) */
4242 case 0x86: /* JBEb/JNAb (jump below or equal) */
4243 case 0x87: /* JNBEb/JAb (jump not below or equal) */
4244 case 0x88: /* JSb (jump negative) */
4245 case 0x89: /* JSb (jump not negative) */
4246 case 0x8A: /* JP (jump parity even) */
4247 case 0x8C: /* JLb/JNGEb (jump less) */
4248 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
4249 case 0x8E: /* JLEb/JNGb (jump less or equal) */
4250 case 0x8F: /* JGb/JNLEb (jump greater) */
4251 d32 = (eip+4) + getUDisp32(eip); eip += 4;
4252 uInstr1(cb, JMP, 0, Literal, 0);
4253 uLiteral(cb, d32);
4254 uCond(cb, (Condcode)(opc - 0x80));
4255 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
4256 uInstr1(cb, JMP, 0, Literal, 0);
4257 uLiteral(cb, eip);
4258 uCond(cb, CondAlways);
4259 *isEnd = True;
4260 if (dis)
4261 VG_(printf)("j%s-32 0x%x\n",
4262 VG_(nameCondcode)(opc - 0x80), d32);
4263 break;
4264
4265 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
4266
4267 case 0x31: /* RDTSC */
4268 t1 = newTemp(cb);
4269 t2 = newTemp(cb);
4270 t3 = newTemp(cb);
4271 uInstr0(cb, CALLM_S, 0);
4272 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
4273 uLiteral(cb, 0);
4274 uInstr1(cb, PUSH, 4, TempReg, t1);
4275 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
4276 uLiteral(cb, 0);
4277 uInstr1(cb, PUSH, 4, TempReg, t2);
4278 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_RDTSC));
4279 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
4280 uInstr1(cb, POP, 4, TempReg, t3);
4281 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EDX);
4282 uInstr1(cb, POP, 4, TempReg, t3);
4283 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EAX);
4284 uInstr0(cb, CALLM_E, 0);
4285 if (dis) VG_(printf)("rdtsc\n");
4286 break;
4287
4288 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
4289 case 0x90:
4290 case 0x91:
4291 case 0x92: /* set-Bb/set-NAEb (jump below) */
4292 case 0x93: /* set-NBb/set-AEb (jump not below) */
4293 case 0x94: /* set-Zb/set-Eb (jump zero) */
4294 case 0x95: /* set-NZb/set-NEb (jump not zero) */
4295 case 0x96: /* set-BEb/set-NAb (jump below or equal) */
4296 case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
4297 case 0x98: /* set-Sb (jump negative) */
4298 case 0x99: /* set-Sb (jump not negative) */
4299 case 0x9A: /* set-P (jump parity even) */
4300 case 0x9B: /* set-NP (jump parity odd) */
4301 case 0x9C: /* set-Lb/set-NGEb (jump less) */
4302 case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
4303 case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
4304 case 0x9F: /* set-Gb/set-NLEb (jump greater) */
4305 modrm = getUChar(eip);
4306 t1 = newTemp(cb);
4307 if (epartIsReg(modrm)) {
4308 eip++;
4309 uInstr1(cb, CC2VAL, 1, TempReg, t1);
4310 uCond(cb, (Condcode)(opc-0x90));
4311 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
4312 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, eregOfRM(modrm));
4313 if (dis) VG_(printf)("set%s %s\n",
4314 VG_(nameCondcode)(opc-0x90),
4315 nameIReg(1,eregOfRM(modrm)));
4316 } else {
4317 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
4318 t2 = LOW24(pair);
4319 eip += HI8(pair);
4320 uInstr1(cb, CC2VAL, 1, TempReg, t1);
4321 uCond(cb, (Condcode)(opc-0x90));
4322 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
4323 uInstr2(cb, STORE, 1, TempReg, t1, TempReg, t2);
4324 SMC_IF_ALL(cb);
4325 if (dis) VG_(printf)("set%s %s\n",
4326 VG_(nameCondcode)(opc-0x90),
4327 dis_buf);
4328 }
4329 break;
4330
4331 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
4332
4333 case 0xA4: /* SHLDv imm8,Gv,Ev */
4334 modrm = getUChar(eip);
4335 eip = dis_SHLRD_Gv_Ev (
4336 cb, eip, modrm, sz,
4337 Literal, getUChar(eip + lengthAMode(eip)),
4338 True );
4339 break;
4340 case 0xA5: /* SHLDv %cl,Gv,Ev */
4341 modrm = getUChar(eip);
4342 eip = dis_SHLRD_Gv_Ev (
4343 cb, eip, modrm, sz, ArchReg, R_CL, True );
4344 break;
4345
4346 case 0xAC: /* SHRDv imm8,Gv,Ev */
4347 modrm = getUChar(eip);
4348 eip = dis_SHLRD_Gv_Ev (
4349 cb, eip, modrm, sz,
4350 Literal, getUChar(eip + lengthAMode(eip)),
4351 False );
4352 break;
4353 case 0xAD: /* SHRDv %cl,Gv,Ev */
4354 modrm = getUChar(eip);
4355 eip = dis_SHLRD_Gv_Ev (
4356 cb, eip, modrm, sz, ArchReg, R_CL, False );
4357 break;
4358
4359 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
4360
4361 case 0xC1: /* XADD Gv,Ev */
4362 eip = dis_xadd_G_E ( cb, sz, eip );
4363 break;
4364
4365 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
4366
4367 default:
4368 VG_(printf)("disInstr: unhandled 2-byte opcode 0x%x\n",
4369 (UInt)opc);
4370 VG_(unimplemented)("unhandled x86 0x0F 2-byte opcode");
4371 }
4372
4373 break;
4374 }
4375
4376 /* ------------------------ ??? ------------------------ */
4377
4378 default:
4379 VG_(printf)("disInstr: unhandled opcode 0x%x then 0x%x\n",
4380 (UInt)opc, (UInt)getUChar(eip));
4381 VG_(panic)("unhandled x86 opcode");
4382 }
4383
4384 if (dis)
4385 VG_(printf)("\n");
4386 for (; first_uinstr < cb->used; first_uinstr++) {
4387 Bool sane = VG_(saneUInstr)(True, &cb->instrs[first_uinstr]);
4388 if (dis || !sane)
4389 VG_(ppUInstr)(sane ? first_uinstr : -1,
4390 &cb->instrs[first_uinstr]);
4391 vg_assert(sane);
4392 }
4393
4394 return eip;
4395}
4396
4397
4398/* Disassemble a complete basic block, starting at eip, and dumping
4399 the ucode into cb. Returns the size, in bytes, of the basic
4400 block. */
4401
4402Int VG_(disBB) ( UCodeBlock* cb, Addr eip0 )
4403{
4404 Addr eip = eip0;
4405 Bool isEnd = False;
4406 Bool block_sane;
4407 if (dis) VG_(printf)("\n");
4408
4409 if (VG_(clo_single_step)) {
4410 eip = disInstr ( cb, eip, &isEnd );
4411 uInstr1(cb, JMP, 0, Literal, 0);
4412 uLiteral(cb, eip);
4413 uCond(cb, CondAlways);
4414 if (dis) VG_(ppUInstr)(cb->used-1, &cb->instrs[cb->used-1]);
4415 } else {
4416 Int delta = 0;
4417 Addr eip2;
4418 while (True) {
4419 if (isEnd) break;
4420 eip2 = disInstr ( cb, eip, &isEnd );
4421 delta += (eip2 - eip);
4422 eip = eip2;
4423 if (delta > 4 && !isEnd) {
4424 uInstr1(cb, INCEIP, 0, Lit16, delta);
4425 if (dis) VG_(ppUInstr)(cb->used-1, &cb->instrs[cb->used-1]);
4426 delta = 0;
4427 }
4428 /* Split up giant basic blocks into pieces, so the
4429 translations fall within 64k. */
4430 if (eip - eip0 > 2000) {
4431 if (VG_(clo_verbosity) > 0)
4432 VG_(message)(Vg_DebugMsg,
4433 "Warning: splitting giant basic block into pieces");
4434 uInstr1(cb, JMP, 0, Literal, 0);
4435 uLiteral(cb, eip);
4436 uCond(cb, CondAlways);
4437 if (dis) VG_(ppUInstr)(cb->used-1, &cb->instrs[cb->used-1]);
4438 if (dis) VG_(printf)("\n");
4439 break;
4440 }
4441 if (dis) VG_(printf)("\n");
4442 }
4443 }
4444
4445 block_sane = VG_(saneUCodeBlock)(cb);
4446 if (!block_sane) {
4447 VG_(ppUCodeBlock)(cb, "block failing sanity check");
4448 vg_assert(block_sane);
4449 }
4450
4451 return eip - eip0;
4452}
4453
4454
4455/*--------------------------------------------------------------------*/
4456/*--- end vg_to_ucode.c ---*/
4457/*--------------------------------------------------------------------*/