blob: c03f5817d2f4368554e97e8ec983e7c51759e980 [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
1222
1223/* Group 8 extended opcodes. */
1224static
1225Addr dis_Grp8 ( UCodeBlock* cb, Addr eip, UChar modrm,
1226 Int am_sz, Int sz, UInt src_val )
1227{
1228 /* src_val denotes a d8.
1229 And eip on entry points at the modrm byte. */
1230 Int t1, t2, helper;
1231 UInt pair;
1232 UChar dis_buf[50];
1233
1234 switch (gregOfRM(modrm)) {
1235 case 4: helper = VGOFF_(helper_bt); break;
1236 case 5: helper = VGOFF_(helper_bts); break;
1237 case 6: helper = VGOFF_(helper_btr); break;
1238 case 7: helper = VGOFF_(helper_btc); break;
1239 /* If this needs to be extended, be careful to do the flag
1240 setting in the parts below correctly. */
1241 default: VG_(panic)("dis_Grp8");
1242 }
1243
1244 t1 = newTemp(cb);
1245 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
1246 uLiteral(cb, src_val);
1247 uInstr0(cb, CALLM_S, 0);
1248 uInstr1(cb, PUSH, 4, TempReg, t1);
1249
1250 if (epartIsReg(modrm)) {
1251 vg_assert(am_sz == 1);
1252 t2 = newTemp(cb);
1253 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t2);
1254 uInstr1(cb, PUSH, sz, TempReg, t2);
1255 uInstr1(cb, CALLM, 0, Lit16, helper);
1256 uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
1257 uInstr1(cb, POP, sz, TempReg, t2);
1258 uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, eregOfRM(modrm));
1259 uInstr1(cb, CLEAR, 0, Lit16, 4);
1260 eip += (am_sz + 1);
1261 if (dis)
1262 VG_(printf)("%s%c $0x%x, %s\n",
1263 nameGrp8(gregOfRM(modrm)), nameISize(sz),
1264 src_val,
1265 nameIReg(sz,eregOfRM(modrm)));
1266 } else {
1267 pair = disAMode ( cb, eip, dis?dis_buf:NULL);
1268 t1 = LOW24(pair);
1269 t2 = newTemp(cb);
1270 eip += HI8(pair);
1271 eip += 1;
1272 uInstr2(cb, LOAD, sz, TempReg, t1, TempReg, t2);
1273 uInstr1(cb, PUSH, sz, TempReg, t2);
1274 uInstr1(cb, CALLM, 0, Lit16, helper);
1275 uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
1276 uInstr1(cb, POP, sz, TempReg, t2);
1277 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
1278 SMC_IF_ALL(cb);
1279 uInstr1(cb, CLEAR, 0, Lit16, 4);
1280 if (dis)
1281 VG_(printf)("%s%c $0x%x, %s\n",
1282 nameGrp8(gregOfRM(modrm)), nameISize(sz), src_val,
1283 dis_buf);
1284 }
1285 uInstr0(cb, CALLM_E, 0);
1286 return eip;
1287}
1288
1289
1290
1291
1292/* Generate ucode to multiply the value in EAX/AX/AL by the register
1293 specified by the ereg of modrm, and park the result in
1294 EDX:EAX/DX:AX/AX. */
1295static void codegen_mul_A_D_Reg ( UCodeBlock* cb, Int sz,
1296 UChar modrm, Bool signed_multiply )
1297{
1298 Int helper = signed_multiply
1299 ?
1300 (sz==1 ? VGOFF_(helper_imul_8_16)
1301 : (sz==2 ? VGOFF_(helper_imul_16_32)
1302 : VGOFF_(helper_imul_32_64)))
1303 :
1304 (sz==1 ? VGOFF_(helper_mul_8_16)
1305 : (sz==2 ? VGOFF_(helper_mul_16_32)
1306 : VGOFF_(helper_mul_32_64)));
1307 Int t1 = newTemp(cb);
1308 Int ta = newTemp(cb);
1309 uInstr0(cb, CALLM_S, 0);
1310 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1311 uInstr1(cb, PUSH, sz, TempReg, t1);
1312 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
1313 uInstr1(cb, PUSH, sz, TempReg, ta);
1314 uInstr1(cb, CALLM, 0, Lit16, helper);
1315 uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP);
1316 if (sz > 1) {
1317 uInstr1(cb, POP, sz, TempReg, t1);
1318 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EDX);
1319 uInstr1(cb, POP, sz, TempReg, t1);
1320 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EAX);
1321 } else {
1322 uInstr1(cb, CLEAR, 0, Lit16, 4);
1323 uInstr1(cb, POP, 2, TempReg, t1);
1324 uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
1325 }
1326 uInstr0(cb, CALLM_E, 0);
1327 if (dis) VG_(printf)("%s%c %s\n", signed_multiply ? "imul" : "mul",
1328 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
1329
1330}
1331
1332
1333/* Generate ucode to multiply the value in EAX/AX/AL by the value in
1334 TempReg temp, and park the result in EDX:EAX/DX:AX/AX. */
1335static void codegen_mul_A_D_Temp ( UCodeBlock* cb, Int sz,
1336 Int temp, Bool signed_multiply,
1337 UChar* dis_buf )
1338{
1339 Int helper = signed_multiply
1340 ?
1341 (sz==1 ? VGOFF_(helper_imul_8_16)
1342 : (sz==2 ? VGOFF_(helper_imul_16_32)
1343 : VGOFF_(helper_imul_32_64)))
1344 :
1345 (sz==1 ? VGOFF_(helper_mul_8_16)
1346 : (sz==2 ? VGOFF_(helper_mul_16_32)
1347 : VGOFF_(helper_mul_32_64)));
1348 Int t1 = newTemp(cb);
1349 uInstr0(cb, CALLM_S, 0);
1350 uInstr1(cb, PUSH, sz, TempReg, temp);
1351 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
1352 uInstr1(cb, PUSH, sz, TempReg, t1);
1353 uInstr1(cb, CALLM, 0, Lit16, helper);
1354 uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP);
1355 if (sz > 1) {
1356 uInstr1(cb, POP, sz, TempReg, t1);
1357 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EDX);
1358 uInstr1(cb, POP, sz, TempReg, t1);
1359 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EAX);
1360 } else {
1361 uInstr1(cb, CLEAR, 0, Lit16, 4);
1362 uInstr1(cb, POP, 2, TempReg, t1);
1363 uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
1364 }
1365 uInstr0(cb, CALLM_E, 0);
1366 if (dis) VG_(printf)("%s%c %s\n", signed_multiply ? "imul" : "mul",
1367 nameISize(sz), dis_buf);
1368}
1369
1370
1371/* Group 3 extended opcodes. */
1372static
1373Addr dis_Grp3 ( UCodeBlock* cb, Int sz, Addr eip )
1374{
1375 Int t1, t2;
1376 UInt pair, d32;
1377 UChar modrm;
1378 UChar dis_buf[50];
1379 t1 = t2 = INVALID_TEMPREG;
1380 modrm = getUChar(eip);
1381 if (epartIsReg(modrm)) {
1382 t1 = newTemp(cb);
1383 switch (gregOfRM(modrm)) {
1384 case 0: { /* TEST */
1385 Int tao = newTemp(cb);
1386 eip++; d32 = getUDisp(sz, eip); eip += sz;
1387 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1388 uInstr2(cb, MOV, sz, Literal, 0, TempReg, tao);
1389 uLiteral(cb, d32);
1390 uInstr2(cb, AND, sz, TempReg, tao, TempReg, t1);
1391 setFlagsFromUOpcode(cb, AND);
1392 if (dis)
1393 VG_(printf)("test%c $0x%x, %s\n",
1394 nameISize(sz), d32, nameIReg(sz, eregOfRM(modrm)));
1395 break;
1396 }
1397 case 2: /* NOT */
1398 eip++;
1399 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1400 uInstr1(cb, NOT, sz, TempReg, t1);
1401 setFlagsFromUOpcode(cb, NOT);
1402 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
1403 if (dis)
1404 VG_(printf)("not%c %s\n",
1405 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
1406 break;
1407 case 3: /* NEG */
1408 eip++;
1409 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1410 uInstr1(cb, NEG, sz, TempReg, t1);
1411 setFlagsFromUOpcode(cb, NEG);
1412 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
1413 if (dis)
1414 VG_(printf)("neg%c %s\n",
1415 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
1416 break;
1417 case 4: /* MUL */
1418 eip++;
1419 codegen_mul_A_D_Reg ( cb, sz, modrm, False );
1420 break;
1421 case 5: /* IMUL */
1422 eip++;
1423 codegen_mul_A_D_Reg ( cb, sz, modrm, True );
1424 break;
1425 case 6: /* DIV */
1426 eip++;
1427 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1428 codegen_div ( cb, sz, t1, False );
1429 if (dis)
1430 VG_(printf)("div%c %s\n", nameISize(sz),
1431 nameIReg(sz, eregOfRM(modrm)));
1432 break;
1433 case 7: /* IDIV */
1434 eip++;
1435 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1436 codegen_div ( cb, sz, t1, True );
1437 if (dis)
1438 VG_(printf)("idiv%c %s\n", nameISize(sz),
1439 nameIReg(sz, eregOfRM(modrm)));
1440 break;
1441 default:
1442 VG_(printf)(
1443 "unhandled Grp3(R) case %d\n", (UInt)gregOfRM(modrm));
1444 VG_(panic)("Grp3");
1445 }
1446 } else {
1447 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
1448 t2 = LOW24(pair);
1449 t1 = newTemp(cb);
1450 eip += HI8(pair);
1451 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
1452 switch (gregOfRM(modrm)) {
1453 case 0: { /* TEST */
1454 Int tao = newTemp(cb);
1455 d32 = getUDisp(sz, eip); eip += sz;
1456 uInstr2(cb, MOV, sz, Literal, 0, TempReg, tao);
1457 uLiteral(cb, d32);
1458 uInstr2(cb, AND, sz, TempReg, tao, TempReg, t1);
1459 setFlagsFromUOpcode(cb, AND);
1460 if (dis)
1461 VG_(printf)("test%c $0x%x, %s\n",
1462 nameISize(sz), d32, dis_buf);
1463 break;
1464 }
1465 case 2: /* NOT */
1466 uInstr1(cb, NOT, sz, TempReg, t1);
1467 setFlagsFromUOpcode(cb, NOT);
1468 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
1469 SMC_IF_ALL(cb);
1470 if (dis)
1471 VG_(printf)("not%c %s\n", nameISize(sz), dis_buf);
1472 break;
1473 case 3: /* NEG */
1474 uInstr1(cb, NEG, sz, TempReg, t1);
1475 setFlagsFromUOpcode(cb, NEG);
1476 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
1477 SMC_IF_ALL(cb);
1478 if (dis)
1479 VG_(printf)("neg%c %s\n", nameISize(sz), dis_buf);
1480 break;
1481 case 4: /* MUL */
1482 codegen_mul_A_D_Temp ( cb, sz, t1, False,
1483 dis?dis_buf:NULL );
1484 break;
1485 case 5: /* IMUL */
1486 codegen_mul_A_D_Temp ( cb, sz, t1, True, dis?dis_buf:NULL );
1487 break;
1488 case 6: /* DIV */
1489 codegen_div ( cb, sz, t1, False );
1490 if (dis)
1491 VG_(printf)("div%c %s\n", nameISize(sz), dis_buf);
1492 break;
1493 case 7: /* IDIV */
1494 codegen_div ( cb, sz, t1, True );
1495 if (dis)
1496 VG_(printf)("idiv%c %s\n", nameISize(sz), dis_buf);
1497 break;
1498 default:
1499 VG_(printf)(
1500 "unhandled Grp3(M) case %d\n", (UInt)gregOfRM(modrm));
1501 VG_(panic)("Grp3");
1502 }
1503 }
1504 return eip;
1505}
1506
1507
1508/* Group 4 extended opcodes. */
1509static
1510Addr dis_Grp4 ( UCodeBlock* cb, Addr eip )
1511{
1512 Int t1, t2;
1513 UInt pair;
1514 UChar modrm;
1515 UChar dis_buf[50];
1516 t1 = t2 = INVALID_TEMPREG;
1517
1518 modrm = getUChar(eip);
1519 if (epartIsReg(modrm)) {
1520 t1 = newTemp(cb);
1521 uInstr2(cb, GET, 1, ArchReg, eregOfRM(modrm), TempReg, t1);
1522 switch (gregOfRM(modrm)) {
1523 case 0: /* INC */
1524 uInstr1(cb, INC, 1, TempReg, t1);
1525 setFlagsFromUOpcode(cb, INC);
1526 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, eregOfRM(modrm));
1527 break;
1528 case 1: /* DEC */
1529 uInstr1(cb, DEC, 1, TempReg, t1);
1530 setFlagsFromUOpcode(cb, DEC);
1531 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, eregOfRM(modrm));
1532 break;
1533 default:
1534 VG_(printf)(
1535 "unhandled Grp4(R) case %d\n", (UInt)gregOfRM(modrm));
1536 VG_(panic)("Grp4");
1537 }
1538 eip++;
1539 if (dis)
1540 VG_(printf)("%sb %s\n", nameGrp4(gregOfRM(modrm)),
1541 nameIReg(1, eregOfRM(modrm)));
1542 } else {
1543 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
1544 t2 = LOW24(pair);
1545 t1 = newTemp(cb);
1546 uInstr2(cb, LOAD, 1, TempReg, t2, TempReg, t1);
1547 switch (gregOfRM(modrm)) {
1548 case 0: /* INC */
1549 uInstr1(cb, INC, 1, TempReg, t1);
1550 setFlagsFromUOpcode(cb, INC);
1551 uInstr2(cb, STORE, 1, TempReg, t1, TempReg, t2);
1552 SMC_IF_ALL(cb);
1553 break;
1554 case 1: /* DEC */
1555 uInstr1(cb, DEC, 1, TempReg, t1);
1556 setFlagsFromUOpcode(cb, DEC);
1557 uInstr2(cb, STORE, 1, TempReg, t1, TempReg, t2);
1558 SMC_IF_ALL(cb);
1559 break;
1560 default:
1561 VG_(printf)(
1562 "unhandled Grp4(M) case %d\n", (UInt)gregOfRM(modrm));
1563 VG_(panic)("Grp4");
1564 }
1565 eip += HI8(pair);
1566 if (dis)
1567 VG_(printf)("%sb %s\n", nameGrp4(gregOfRM(modrm)), dis_buf);
1568 }
1569 return eip;
1570}
1571
1572
1573/* Group 5 extended opcodes. */
1574static
1575Addr dis_Grp5 ( UCodeBlock* cb, Int sz, Addr eip, Bool* isEnd )
1576{
1577 Int t1, t2, t3, t4;
1578 UInt pair;
1579 UChar modrm;
1580 UChar dis_buf[50];
1581 t1 = t2 = t3 = t4 = INVALID_TEMPREG;
1582
1583 modrm = getUChar(eip);
1584 if (epartIsReg(modrm)) {
1585 t1 = newTemp(cb);
1586 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
1587 switch (gregOfRM(modrm)) {
1588 case 0: /* INC */
1589 uInstr1(cb, INC, sz, TempReg, t1);
1590 setFlagsFromUOpcode(cb, INC);
1591 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
1592 break;
1593 case 1: /* DEC */
1594 uInstr1(cb, DEC, sz, TempReg, t1);
1595 setFlagsFromUOpcode(cb, DEC);
1596 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
1597 break;
1598 case 2: /* call Ev */
1599 t3 = newTemp(cb); t4 = newTemp(cb);
1600 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
1601 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t3);
1602 uLiteral(cb, 4);
1603 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
1604 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
1605 uLiteral(cb, eip+1);
1606 uInstr2(cb, STORE, 4, TempReg, t4, TempReg, t3);
1607 SMC_IF_ALL(cb);
1608 uInstr1(cb, JMP, 0, TempReg, t1);
1609 uCond(cb, CondAlways);
1610 LAST_UINSTR(cb).call_dispatch = True;
1611 *isEnd = True;
1612 break;
1613 case 4: /* jmp Ev */
1614 uInstr1(cb, JMP, 0, TempReg, t1);
1615 uCond(cb, CondAlways);
1616 *isEnd = True;
1617 break;
1618 default:
1619 VG_(printf)(
1620 "unhandled Grp5(R) case %d\n", (UInt)gregOfRM(modrm));
1621 VG_(panic)("Grp5");
1622 }
1623 eip++;
1624 if (dis)
1625 VG_(printf)("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
1626 nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
1627 } else {
1628 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
1629 t2 = LOW24(pair);
1630 t1 = newTemp(cb);
1631 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
1632 switch (gregOfRM(modrm)) {
1633 case 0: /* INC */
1634 uInstr1(cb, INC, sz, TempReg, t1);
1635 setFlagsFromUOpcode(cb, INC);
1636 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
1637 SMC_IF_ALL(cb);
1638 break;
1639 case 1: /* DEC */
1640 uInstr1(cb, DEC, sz, TempReg, t1);
1641 setFlagsFromUOpcode(cb, DEC);
1642 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
1643 SMC_IF_ALL(cb);
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+HI8(pair));
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);
1657 LAST_UINSTR(cb).call_dispatch = True;
1658 *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 case 6: /* PUSH Ev */
1666 t3 = newTemp(cb);
1667 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
1668 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t3);
1669 uLiteral(cb, sz);
1670 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
1671 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t3);
1672 SMC_IF_ALL(cb);
1673 break;
1674 default:
1675 VG_(printf)(
1676 "unhandled Grp5(M) case %d\n", (UInt)gregOfRM(modrm));
1677 VG_(panic)("Grp5");
1678 }
1679 eip += HI8(pair);
1680 if (dis)
1681 VG_(printf)("%s%c %s\n", nameGrp5(gregOfRM(modrm)),
1682 nameISize(sz), dis_buf);
1683 }
1684 return eip;
1685}
1686
1687
1688/* Template for REPE CMPS<sz>. Assumes this insn is the last one in
1689 the basic block, and so emits a jump to the next insn. */
1690static
1691void codegen_REPE_CMPS ( UCodeBlock* cb, Int sz, Addr eip, Addr eip_next )
1692{
1693 Int tc, /* ECX */
1694 td, /* EDI */ ts, /* ESI */
1695 tdv, /* (EDI) */ tsv /* (ESI) */;
1696
1697 tdv = newTemp(cb);
1698 tsv = newTemp(cb);
1699 td = newTemp(cb);
1700 ts = newTemp(cb);
1701 tc = newTemp(cb);
1702
1703 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, tc);
1704 uInstr2(cb, JIFZ, 4, TempReg, tc, Literal, 0);
1705 uLiteral(cb, eip_next);
1706 uInstr1(cb, DEC, 4, TempReg, tc);
1707 uInstr2(cb, PUT, 4, TempReg, tc, ArchReg, R_ECX);
1708
1709 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
1710 uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
1711
1712 uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tdv);
1713 uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tsv);
1714
1715 uInstr2(cb, SUB, sz, TempReg, tdv, TempReg, tsv);
1716 setFlagsFromUOpcode(cb, SUB);
1717
1718 uInstr0(cb, CALLM_S, 0);
1719 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tdv);
1720 uLiteral(cb, 0);
1721 uInstr1(cb, PUSH, 4, TempReg, tdv);
1722
1723 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
1724 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
1725
1726 uInstr1(cb, POP, 4, TempReg, tdv);
1727 uInstr0(cb, CALLM_E, 0);
1728 if (sz == 4 || sz == 2) {
1729 uInstr2(cb, SHL, 4, Literal, 0, TempReg, tdv);
1730 uLiteral(cb, sz/2);
1731 }
1732 uInstr2(cb, ADD, 4, TempReg, tdv, TempReg, td);
1733 uInstr2(cb, ADD, 4, TempReg, tdv, TempReg, ts);
1734
1735 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
1736 uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
1737
1738 uInstr1(cb, JMP, 0, Literal, 0);
1739 uLiteral(cb, eip);
1740 uCond(cb, CondZ);
1741 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
1742 uInstr1(cb, JMP, 0, Literal, 0);
1743 uLiteral(cb, eip_next);
1744 uCond(cb, CondAlways);
1745}
1746
1747
1748/* Template for REPNE SCAS<sz>. Assumes this insn is the last one in
1749 the basic block, and so emits a jump to the next insn. */
1750static
1751void codegen_REPNE_SCAS ( UCodeBlock* cb, Int sz, Addr eip, Addr eip_next )
1752{
1753 Int ta /* EAX */, tc /* ECX */, td /* EDI */, tv;
1754 ta = newTemp(cb);
1755 tc = newTemp(cb);
1756 tv = newTemp(cb);
1757 td = newTemp(cb);
1758
1759 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, tc);
1760 uInstr2(cb, JIFZ, 4, TempReg, tc, Literal, 0);
1761 uLiteral(cb, eip_next);
1762 uInstr1(cb, DEC, 4, TempReg, tc);
1763 uInstr2(cb, PUT, 4, TempReg, tc, ArchReg, R_ECX);
1764
1765 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
1766 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
1767 uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tv);
1768 /* next uinstr kills ta, but that's ok -- don't need it again */
1769 uInstr2(cb, SUB, sz, TempReg, tv, TempReg, ta);
1770 setFlagsFromUOpcode(cb, SUB);
1771
1772 uInstr0(cb, CALLM_S, 0);
1773 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tv);
1774 uLiteral(cb, 0);
1775 uInstr1(cb, PUSH, 4, TempReg, tv);
1776
1777 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
1778 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
1779
1780 uInstr1(cb, POP, 4, TempReg, tv);
1781 uInstr0(cb, CALLM_E, 0);
1782
1783 if (sz == 4 || sz == 2) {
1784 uInstr2(cb, SHL, 4, Literal, 0, TempReg, tv);
1785 uLiteral(cb, sz/2);
1786 }
1787 uInstr2(cb, ADD, 4, TempReg, tv, TempReg, td);
1788 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
1789 uInstr1(cb, JMP, 0, Literal, 0);
1790 uLiteral(cb, eip);
1791 uCond(cb, CondNZ);
1792 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
1793 uInstr1(cb, JMP, 0, Literal, 0);
1794 uLiteral(cb, eip_next);
1795 uCond(cb, CondAlways);
1796}
1797
1798
1799/* Template for REPE MOVS<sz>. Assumes this insn is the last one in
1800 the basic block, and so emits a jump to the next insn. */
1801static
1802void codegen_REPE_MOVS ( UCodeBlock* cb, Int sz, Addr eip, Addr eip_next )
1803{
1804 Int ts /* ESI */, tc /* ECX */, td /* EDI */, tv;
1805 tc = newTemp(cb);
1806 td = newTemp(cb);
1807 ts = newTemp(cb);
1808 tv = newTemp(cb);
1809
1810 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, tc);
1811 uInstr2(cb, JIFZ, 4, TempReg, tc, Literal, 0);
1812 uLiteral(cb, eip_next);
1813 uInstr1(cb, DEC, 4, TempReg, tc);
1814 uInstr2(cb, PUT, 4, TempReg, tc, ArchReg, R_ECX);
1815
1816 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
1817 uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
1818
1819 uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tv);
1820 uInstr2(cb, STORE, sz, TempReg, tv, TempReg, td);
1821 SMC_IF_SOME(cb);
1822
1823 uInstr0(cb, CALLM_S, 0);
1824 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tv);
1825 uLiteral(cb, 0);
1826 uInstr1(cb, PUSH, 4, TempReg, tv);
1827
1828 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
1829 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
1830
1831 uInstr1(cb, POP, 4, TempReg, tv);
1832 uInstr0(cb, CALLM_E, 0);
1833
1834 if (sz == 4 || sz == 2) {
1835 uInstr2(cb, SHL, 4, Literal, 0, TempReg, tv);
1836 uLiteral(cb, sz/2);
1837 }
1838 uInstr2(cb, ADD, 4, TempReg, tv, TempReg, td);
1839 uInstr2(cb, ADD, 4, TempReg, tv, TempReg, ts);
1840
1841 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
1842 uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
1843
1844 uInstr1(cb, JMP, 0, Literal, 0);
1845 uLiteral(cb, eip);
1846 uCond(cb, CondAlways);
1847}
1848
1849
1850/* Template for REPE STOS<sz>. Assumes this insn is the last one in
1851 the basic block, and so emits a jump to the next insn. */
1852static
1853void codegen_REPE_STOS ( UCodeBlock* cb, Int sz, Addr eip, Addr eip_next )
1854{
1855 Int ta /* EAX */, tc /* ECX */, td /* EDI */;
1856 ta = newTemp(cb);
1857 tc = newTemp(cb);
1858 td = newTemp(cb);
1859
1860 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, tc);
1861 uInstr2(cb, JIFZ, 4, TempReg, tc, Literal, 0);
1862 uLiteral(cb, eip_next);
1863 uInstr1(cb, DEC, 4, TempReg, tc);
1864 uInstr2(cb, PUT, 4, TempReg, tc, ArchReg, R_ECX);
1865
1866 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
1867 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
1868 uInstr2(cb, STORE, sz, TempReg, ta, TempReg, td);
1869 SMC_IF_SOME(cb);
1870
1871 uInstr0(cb, CALLM_S, 0);
1872 uInstr2(cb, MOV, 4, Literal, 0, TempReg, ta);
1873 uLiteral(cb, 0);
1874 uInstr1(cb, PUSH, 4, TempReg, ta);
1875
1876 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
1877 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
1878
1879 uInstr1(cb, POP, 4, TempReg, ta);
1880 uInstr0(cb, CALLM_E, 0);
1881
1882 if (sz == 4 || sz == 2) {
1883 uInstr2(cb, SHL, 4, Literal, 0, TempReg, ta);
1884 uLiteral(cb, sz/2);
1885 }
1886 uInstr2(cb, ADD, 4, TempReg, ta, TempReg, td);
1887 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
1888
1889 uInstr1(cb, JMP, 0, Literal, 0);
1890 uLiteral(cb, eip);
1891 uCond(cb, CondAlways);
1892}
1893
1894
1895/* Template for CMPS<sz>, _not_ preceded by a REP prefix. */
1896static
1897void codegen_CMPS ( UCodeBlock* cb, Int sz )
1898{
1899 Int td, /* EDI */ ts, /* ESI */
1900 tdv, /* (EDI) */ tsv /* (ESI) */;
1901 tdv = newTemp(cb);
1902 tsv = newTemp(cb);
1903 td = newTemp(cb);
1904 ts = newTemp(cb);
1905
1906 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
1907 uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
1908
1909 uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tdv);
1910 uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tsv);
1911
1912 uInstr2(cb, SUB, sz, TempReg, tdv, TempReg, tsv);
1913 setFlagsFromUOpcode(cb, SUB);
1914
1915 uInstr0(cb, CALLM_S, 0);
1916 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tdv);
1917 uLiteral(cb, 0);
1918 uInstr1(cb, PUSH, 4, TempReg, tdv);
1919
1920 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
1921 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
1922
1923 uInstr1(cb, POP, 4, TempReg, tdv);
1924 uInstr0(cb, CALLM_E, 0);
1925
1926 if (sz == 4 || sz == 2) {
1927 uInstr2(cb, SHL, 4, Literal, 0, TempReg, tdv);
1928 uLiteral(cb, sz/2);
1929 }
1930 uInstr2(cb, ADD, 4, TempReg, tdv, TempReg, td);
1931 uInstr2(cb, ADD, 4, TempReg, tdv, TempReg, ts);
1932
1933 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
1934 uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
1935}
1936
1937
1938/* Template for MOVS<sz>, _not_ preceded by a REP prefix. */
1939static
1940void codegen_MOVS ( UCodeBlock* cb, Int sz )
1941{
1942 Int tv, /* the value being copied */
1943 td, /* EDI */ ts /* ESI */;
1944 tv = newTemp(cb);
1945 td = newTemp(cb);
1946 ts = newTemp(cb);
1947
1948 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
1949 uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
1950
1951 uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, tv);
1952 uInstr2(cb, STORE, sz, TempReg, tv, TempReg, td);
1953 SMC_IF_SOME(cb);
1954
1955 uInstr0(cb, CALLM_S, 0);
1956 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tv);
1957 uLiteral(cb, 0);
1958 uInstr1(cb, PUSH, 4, TempReg, tv);
1959
1960 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
1961 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
1962
1963 uInstr1(cb, POP, 4, TempReg, tv);
1964 uInstr0(cb, CALLM_E, 0);
1965
1966 if (sz == 4 || sz == 2) {
1967 uInstr2(cb, SHL, 4, Literal, 0, TempReg, tv);
1968 uLiteral(cb, sz/2);
1969 }
1970 uInstr2(cb, ADD, 4, TempReg, tv, TempReg, td);
1971 uInstr2(cb, ADD, 4, TempReg, tv, TempReg, ts);
1972
1973 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
1974 uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
1975}
1976
1977
1978/* Template for STOS<sz>, _not_ preceded by a REP prefix. */
1979static
1980void codegen_STOS ( UCodeBlock* cb, Int sz )
1981{
1982 Int ta /* EAX */, td /* EDI */;
1983 ta = newTemp(cb);
1984 td = newTemp(cb);
1985
1986 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
1987 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
1988 uInstr2(cb, STORE, sz, TempReg, ta, TempReg, td);
1989 SMC_IF_SOME(cb);
1990
1991 uInstr0(cb, CALLM_S, 0);
1992 uInstr2(cb, MOV, 4, Literal, 0, TempReg, ta);
1993 uLiteral(cb, 0);
1994 uInstr1(cb, PUSH, 4, TempReg, ta);
1995
1996 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
1997 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
1998
1999 uInstr1(cb, POP, 4, TempReg, ta);
2000 uInstr0(cb, CALLM_E, 0);
2001
2002 if (sz == 4 || sz == 2) {
2003 uInstr2(cb, SHL, 4, Literal, 0, TempReg, ta);
2004 uLiteral(cb, sz/2);
2005 }
2006 uInstr2(cb, ADD, 4, TempReg, ta, TempReg, td);
2007 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2008}
2009
2010
2011/* Template for LODS<sz>, _not_ preceded by a REP prefix. */
2012static
2013void codegen_LODS ( UCodeBlock* cb, Int sz )
2014{
2015 Int ta /* EAX */, ts /* ESI */;
2016 ta = newTemp(cb);
2017 ts = newTemp(cb);
2018
2019 uInstr2(cb, GET, 4, ArchReg, R_ESI, TempReg, ts);
2020 uInstr2(cb, LOAD, sz, TempReg, ts, TempReg, ta);
2021 uInstr2(cb, PUT, sz, TempReg, ta, ArchReg, R_EAX);
2022
2023 uInstr0(cb, CALLM_S, 0);
2024 uInstr2(cb, MOV, 4, Literal, 0, TempReg, ta);
2025 uLiteral(cb, 0);
2026 uInstr1(cb, PUSH, 4, TempReg, ta);
2027
2028 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
2029 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
2030
2031 uInstr1(cb, POP, 4, TempReg, ta);
2032 uInstr0(cb, CALLM_E, 0);
2033
2034 if (sz == 4 || sz == 2) {
2035 uInstr2(cb, SHL, 4, Literal, 0, TempReg, ta);
2036 uLiteral(cb, sz/2);
2037 }
2038 uInstr2(cb, ADD, 4, TempReg, ta, TempReg, ts);
2039 uInstr2(cb, PUT, 4, TempReg, ts, ArchReg, R_ESI);
2040}
2041
2042
2043/* Template for REPNE SCAS<sz>, _not_ preceded by a REP prefix. */
2044static
2045void codegen_SCAS ( UCodeBlock* cb, Int sz )
2046{
2047 Int ta /* EAX */, td /* EDI */, tv;
2048 ta = newTemp(cb);
2049 tv = newTemp(cb);
2050 td = newTemp(cb);
2051
2052 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
2053 uInstr2(cb, GET, 4, ArchReg, R_EDI, TempReg, td);
2054 uInstr2(cb, LOAD, sz, TempReg, td, TempReg, tv);
2055 /* next uinstr kills ta, but that's ok -- don't need it again */
2056 uInstr2(cb, SUB, sz, TempReg, tv, TempReg, ta);
2057 setFlagsFromUOpcode(cb, SUB);
2058
2059 uInstr0(cb, CALLM_S, 0);
2060 uInstr2(cb, MOV, 4, Literal, 0, TempReg, tv);
2061 uLiteral(cb, 0);
2062 uInstr1(cb, PUSH, 4, TempReg, tv);
2063
2064 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_get_dirflag));
2065 uFlagsRWU(cb, FlagD, FlagsEmpty, FlagsEmpty);
2066
2067 uInstr1(cb, POP, 4, TempReg, tv);
2068 uInstr0(cb, CALLM_E, 0);
2069
2070 if (sz == 4 || sz == 2) {
2071 uInstr2(cb, SHL, 4, Literal, 0, TempReg, tv);
2072 uLiteral(cb, sz/2);
2073 }
2074 uInstr2(cb, ADD, 4, TempReg, tv, TempReg, td);
2075 uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
2076}
2077
2078
2079/* (I)MUL E, G. Supplied eip points to the modR/M byte. */
2080static
2081Addr dis_mul_E_G ( UCodeBlock* cb,
2082 Int size,
2083 Addr eip0,
2084 Bool signed_multiply )
2085{
2086 Int ta, tg, te, helper;
2087 UChar dis_buf[50];
2088 UChar rm = getUChar(eip0);
2089 ta = INVALID_TEMPREG;
2090 te = newTemp(cb);
2091 tg = newTemp(cb);
2092
2093 switch (size) {
2094 case 4: helper = signed_multiply ? VGOFF_(helper_imul_32_64)
2095 : VGOFF_(helper_mul_32_64);
2096 break;
2097 case 2: helper = signed_multiply ? VGOFF_(helper_imul_16_32)
2098 : VGOFF_(helper_mul_16_32);
2099 break;
2100 case 1: helper = signed_multiply ? VGOFF_(helper_imul_8_16)
2101 : VGOFF_(helper_mul_8_16);
2102 break;
2103 default: VG_(panic)("dis_mul_E_G");
2104 }
2105
2106 uInstr0(cb, CALLM_S, 0);
2107 if (epartIsReg(rm)) {
2108 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, te);
2109 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tg);
2110 uInstr1(cb, PUSH, size, TempReg, te);
2111 uInstr1(cb, PUSH, size, TempReg, tg);
2112 uInstr1(cb, CALLM, 0, Lit16, helper);
2113 uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP);
2114 uInstr1(cb, CLEAR, 0, Lit16, 4);
2115 uInstr1(cb, POP, size, TempReg, tg);
2116 uInstr2(cb, PUT, size, TempReg, tg, ArchReg, gregOfRM(rm));
2117 uInstr0(cb, CALLM_E, 0);
2118 if (dis) VG_(printf)("%smul%c %s, %s\n",
2119 signed_multiply ? "i" : "",
2120 nameISize(size),
2121 nameIReg(size,eregOfRM(rm)),
2122 nameIReg(size,gregOfRM(rm)));
2123 return 1+eip0;
2124 } else {
2125 UInt pair = disAMode ( cb, eip0, dis?dis_buf:NULL);
2126 ta = LOW24(pair);
2127 uInstr2(cb, LOAD, size, TempReg, ta, TempReg, te);
2128 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tg);
2129 uInstr1(cb, PUSH, size, TempReg, te);
2130 uInstr1(cb, PUSH, size, TempReg, tg);
2131 uInstr1(cb, CALLM, 0, Lit16, helper);
2132 uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP);
2133 uInstr1(cb, CLEAR, 0, Lit16, 4);
2134 uInstr1(cb, POP, size, TempReg, tg);
2135 uInstr2(cb, PUT, size, TempReg, tg, ArchReg, gregOfRM(rm));
2136 uInstr0(cb, CALLM_E, 0);
2137 if (dis) VG_(printf)("%smul%c %s, %s\n",
2138 signed_multiply ? "i" : "",
2139 nameISize(size),
2140 dis_buf,nameIReg(size,gregOfRM(rm)));
2141 return HI8(pair)+eip0;
2142 }
2143}
2144
2145
2146/* IMUL I * E -> G. Supplied eip points to the modR/M byte. */
2147static
2148Addr dis_imul_I_E_G ( UCodeBlock* cb,
2149 Int size,
2150 Addr eip,
2151 Int litsize )
2152{
2153 Int ta, te, tl, helper, d32;
2154 UChar dis_buf[50];
2155 UChar rm = getUChar(eip);
2156 ta = INVALID_TEMPREG;
2157 te = newTemp(cb);
2158 tl = newTemp(cb);
2159
2160 switch (size) {
2161 case 4: helper = VGOFF_(helper_imul_32_64); break;
2162 case 2: helper = VGOFF_(helper_imul_16_32); break;
2163 case 1: helper = VGOFF_(helper_imul_8_16); break;
2164 default: VG_(panic)("dis_imul_I_E_G");
2165 }
2166
2167 uInstr0(cb, CALLM_S, 0);
2168 if (epartIsReg(rm)) {
2169 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, te);
2170 uInstr1(cb, PUSH, size, TempReg, te);
2171 eip++;
2172 } else {
2173 UInt pair = disAMode ( cb, eip, dis?dis_buf:NULL);
2174 ta = LOW24(pair);
2175 uInstr2(cb, LOAD, size, TempReg, ta, TempReg, te);
2176 uInstr1(cb, PUSH, size, TempReg, te);
2177 eip += HI8(pair);
2178 }
2179
2180 d32 = getSDisp(litsize,eip);
2181 eip += litsize;
2182
2183 uInstr2(cb, MOV, size, Literal, 0, TempReg, tl);
2184 uLiteral(cb, d32);
2185 uInstr1(cb, PUSH, size, TempReg, tl);
2186 uInstr1(cb, CALLM, 0, Lit16, helper);
2187 uFlagsRWU(cb, FlagsEmpty, FlagsOC, FlagsSZAP);
2188 uInstr1(cb, CLEAR, 0, Lit16, 4);
2189 uInstr1(cb, POP, size, TempReg, te);
2190 uInstr2(cb, PUT, size, TempReg, te, ArchReg, gregOfRM(rm));
2191 uInstr0(cb, CALLM_E, 0);
2192
2193 if (dis) {
2194 if (epartIsReg(rm)) {
2195 VG_(printf)("imul %d, %s, %s\n", d32, nameIReg(size,eregOfRM(rm)),
2196 nameIReg(size,gregOfRM(rm)));
2197 } else {
2198 VG_(printf)("imul %d, %s, %s\n", d32, dis_buf,
2199 nameIReg(size,gregOfRM(rm)));
2200 }
2201 }
2202
2203 return eip;
2204}
2205
2206
2207/* Handle FPU insns which read/write memory. On entry, eip points to
2208 the second byte of the insn (the one following D8 .. DF). */
2209static
2210Addr dis_fpu_mem ( UCodeBlock* cb, Int size, Bool is_write,
2211 Addr eip, UChar first_byte )
2212{
2213 Int ta;
2214 UInt pair;
2215 UChar dis_buf[50];
2216 UChar second_byte = getUChar(eip);
2217 vg_assert(second_byte < 0xC0);
2218 second_byte &= 0x38;
2219 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
2220 ta = LOW24(pair);
2221 eip += HI8(pair);
2222 uInstr2(cb, is_write ? FPU_W : FPU_R, size,
2223 Lit16,
2224 (((UShort)first_byte) << 8) | ((UShort)second_byte),
2225 TempReg, ta);
2226 if (is_write) SMC_IF_ALL(cb);
2227 if (dis) {
2228 if (is_write)
2229 VG_(printf)("fpu_w_%d 0x%x:0x%x, %s\n",
2230 size, (UInt)first_byte,
2231 (UInt)second_byte, dis_buf );
2232 else
2233 VG_(printf)("fpu_r_%d %s, 0x%x:0x%x\n",
2234 size, dis_buf,
2235 (UInt)first_byte,
2236 (UInt)second_byte );
2237 }
2238 return eip;
2239}
2240
2241
2242/* Handle FPU insns which don't reference memory. On entry, eip points to
2243 the second byte of the insn (the one following D8 .. DF). */
2244static
2245Addr dis_fpu_no_mem ( UCodeBlock* cb, Addr eip, UChar first_byte )
2246{
2247 UChar second_byte = getUChar(eip); eip++;
2248 vg_assert(second_byte >= 0xC0);
2249 uInstr1(cb, FPU, 0,
2250 Lit16,
2251 (((UShort)first_byte) << 8) | ((UShort)second_byte)
2252 );
2253 if (dis) VG_(printf)("fpu 0x%x:0x%x\n",
2254 (UInt)first_byte, (UInt)second_byte );
2255 return eip;
2256}
2257
2258
2259/* Top-level handler for all FPU insns. On entry, eip points to the
2260 second byte of the insn. */
2261static
2262Addr dis_fpu ( UCodeBlock* cb, UChar first_byte, Addr eip )
2263{
2264 const Bool rd = False;
2265 const Bool wr = True;
2266 UChar second_byte = getUChar(eip);
2267
2268 /* Handle FSTSW %ax specially. */
2269 if (first_byte == 0xDF && second_byte == 0xE0) {
2270 Int t1 = newTemp(cb);
2271 uInstr0(cb, CALLM_S, 0);
2272 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
2273 uLiteral(cb, 0);
2274 uInstr1(cb, PUSH, 4, TempReg, t1);
2275 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_fstsw_AX) );
2276 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
2277 uInstr1(cb, POP, 2, TempReg, t1);
2278 uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
2279 uInstr0(cb, CALLM_E, 0);
2280 if (dis) VG_(printf)("fstsw %%ax\n");
2281 eip++;
2282 return eip;
2283 }
2284
2285 /* Handle all non-memory FPU ops simply. */
2286 if (second_byte >= 0xC0)
2287 return dis_fpu_no_mem ( cb, eip, first_byte );
2288
2289 /* The insn references memory; need to determine
2290 whether it reads or writes, and at what size. */
2291 switch (first_byte) {
2292
2293 case 0xD8:
2294 switch ((second_byte >> 3) & 7) {
2295 case 0: /* FADDs */
2296 case 1: /* FMULs */
2297 case 2: /* FCOMs */
2298 case 3: /* FCOMPs */
2299 case 4: /* FSUBs */
2300 case 5: /* FSUBRs */
2301 case 6: /* FDIVs */
2302 case 7: /* FDIVRs */
2303 return dis_fpu_mem(cb, 4, rd, eip, first_byte);
2304 default:
2305 goto unhandled;
2306 }
2307 break;
2308
2309 case 0xD9:
2310 switch ((second_byte >> 3) & 7) {
2311 case 0: /* FLDs */
2312 return dis_fpu_mem(cb, 4, rd, eip, first_byte);
2313 case 2: /* FSTs */
2314 case 3: /* FSTPs */
2315 return dis_fpu_mem(cb, 4, wr, eip, first_byte);
2316 case 5: /* FLDCW */
2317 return dis_fpu_mem(cb, 2, rd, eip, first_byte);
2318 case 7: /* FSTCW */
2319 /* HACK! FSTCW actually writes 2 bytes, not 4. glibc
2320 gets lots of moaning in __floor() if we do the right
2321 thing here. */
2322 /* Later ... hack disabled .. we do do the Right Thing. */
2323 return dis_fpu_mem(cb, /*4*/ 2, wr, eip, first_byte);
2324 default:
2325 goto unhandled;
2326 }
2327 break;
2328
2329 case 0xDA:
2330 switch ((second_byte >> 3) & 7) {
2331 case 0: /* FIADD */
2332 case 1: /* FIMUL */
2333 case 2: /* FICOM */
2334 case 3: /* FICOMP */
2335 case 4: /* FISUB */
2336 case 5: /* FISUBR */
2337 case 6: /* FIDIV */
2338 case 7: /* FIDIVR */
2339 return dis_fpu_mem(cb, 4, rd, eip, first_byte);
2340 default:
2341 goto unhandled;
2342 }
2343 break;
2344
2345 case 0xDB:
2346 switch ((second_byte >> 3) & 7) {
2347 case 0: /* FILD dword-integer */
2348 return dis_fpu_mem(cb, 4, rd, eip, first_byte);
2349 case 2: /* FIST dword-integer */
2350 return dis_fpu_mem(cb, 4, wr, eip, first_byte);
2351 case 3: /* FISTPl */
2352 return dis_fpu_mem(cb, 4, wr, eip, first_byte);
2353 case 5: /* FLD extended-real */
2354 return dis_fpu_mem(cb, 10, rd, eip, first_byte);
2355 case 7: /* FSTP extended-real */
2356 return dis_fpu_mem(cb, 10, wr, eip, first_byte);
2357 default:
2358 goto unhandled;
2359 }
2360 break;
2361
2362 case 0xDC:
2363 switch ((second_byte >> 3) & 7) {
2364 case 0: /* FADD double-real */
2365 case 1: /* FMUL double-real */
2366 case 2: /* FCOM double-real */
2367 case 3: /* FCOMP double-real */
2368 case 4: /* FSUB double-real */
2369 case 5: /* FSUBR double-real */
2370 case 6: /* FDIV double-real */
2371 case 7: /* FDIVR double-real */
2372 return dis_fpu_mem(cb, 8, rd, eip, first_byte);
2373 default:
2374 goto unhandled;
2375 }
2376 break;
2377
2378 case 0xDD:
2379 switch ((second_byte >> 3) & 7) {
2380 case 0: /* FLD double-real */
2381 return dis_fpu_mem(cb, 8, rd, eip, first_byte);
2382 case 2: /* FST double-real */
2383 case 3: /* FSTP double-real */
2384 return dis_fpu_mem(cb, 8, wr, eip, first_byte);
2385 default:
2386 goto unhandled;
2387 }
2388 break;
2389
2390 case 0xDF:
2391 switch ((second_byte >> 3) & 7) {
2392 case 0: /* FILD word-integer */
2393 return dis_fpu_mem(cb, 2, rd, eip, first_byte);
2394 case 2: /* FIST word-integer */
2395 return dis_fpu_mem(cb, 2, wr, eip, first_byte);
2396 case 3: /* FISTP word-integer */
2397 return dis_fpu_mem(cb, 2, wr, eip, first_byte);
2398 case 5: /* FILD qword-integer */
2399 return dis_fpu_mem(cb, 8, rd, eip, first_byte);
2400 case 7: /* FISTP qword-integer */
2401 return dis_fpu_mem(cb, 8, wr, eip, first_byte);
2402 default:
2403 goto unhandled;
2404 }
2405 break;
2406
2407 default: goto unhandled;
2408 }
2409
2410 unhandled:
2411 VG_(printf)("dis_fpu: unhandled memory case 0x%2x:0x%2x(%d)\n",
2412 (UInt)first_byte, (UInt)second_byte,
2413 (UInt)((second_byte >> 3) & 7) );
2414 VG_(panic)("dis_fpu: unhandled opcodes");
2415}
2416
2417
2418/* Double length left shifts. Apparently only required in v-size (no
2419 b- variant). */
2420static
2421Addr dis_SHLRD_Gv_Ev ( UCodeBlock* cb, Addr eip, UChar modrm,
2422 Int sz,
2423 Tag amt_tag, UInt amt_val,
2424 Bool left_shift )
2425{
2426 /* amt_tag and amt_val denote either ArchReg(%CL) or a Literal.
2427 And eip on entry points at the modrm byte. */
2428 Int t, t1, t2, ta, helper;
2429 UInt pair;
2430 UChar dis_buf[50];
2431
2432 vg_assert(sz == 2 || sz == 4);
2433
2434 helper = left_shift
2435 ? (sz==4 ? VGOFF_(helper_shldl)
2436 : VGOFF_(helper_shldw))
2437 : (sz==4 ? VGOFF_(helper_shrdl)
2438 : VGOFF_(helper_shrdw));
2439
2440 /* Get the amount to be shifted by onto the stack. */
2441 t = newTemp(cb);
2442 t1 = newTemp(cb);
2443 t2 = newTemp(cb);
2444 if (amt_tag == ArchReg) {
2445 vg_assert(amt_val == R_CL);
2446 uInstr2(cb, GET, 1, ArchReg, amt_val, TempReg, t);
2447 } else {
2448 uInstr2(cb, MOV, 1, Literal, 0, TempReg, t);
2449 uLiteral(cb, amt_val);
2450 }
2451
2452 uInstr0(cb, CALLM_S, 0);
2453 uInstr1(cb, PUSH, 1, TempReg, t);
2454
2455 /* The E-part is the destination; this is shifted. The G-part
2456 supplies bits to be shifted into the E-part, but is not
2457 changed. */
2458
2459 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t1);
2460 uInstr1(cb, PUSH, sz, TempReg, t1);
2461
2462 if (epartIsReg(modrm)) {
2463 eip++;
2464 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t2);
2465 uInstr1(cb, PUSH, sz, TempReg, t2);
2466 uInstr1(cb, CALLM, 0, Lit16, helper);
2467 uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
2468 uInstr1(cb, POP, sz, TempReg, t);
2469 uInstr2(cb, PUT, sz, TempReg, t, ArchReg, eregOfRM(modrm));
2470 if (dis)
2471 VG_(printf)("shld%c %%cl, %s, %s\n",
2472 nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
2473 nameIReg(sz, eregOfRM(modrm)));
2474 } else {
2475 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
2476 ta = LOW24(pair);
2477 eip += HI8(pair);
2478 uInstr2(cb, LOAD, sz, TempReg, ta, TempReg, t2);
2479 uInstr1(cb, PUSH, sz, TempReg, t2);
2480 uInstr1(cb, CALLM, 0, Lit16, helper);
2481 uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
2482 uInstr1(cb, POP, sz, TempReg, t);
2483 uInstr2(cb, STORE, sz, TempReg, t, TempReg, ta);
2484 SMC_IF_ALL(cb);
2485 if (dis)
2486 VG_(printf)("shld%c %%cl, %s, %s\n",
2487 nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
2488 dis_buf);
2489 }
2490
2491 if (amt_tag == Literal) eip++;
2492 uInstr1(cb, CLEAR, 0, Lit16, 8);
2493
2494 uInstr0(cb, CALLM_E, 0);
2495 return eip;
2496}
2497
2498
2499/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
2500 required. */
2501
2502typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
2503
2504static Char* nameBtOp ( BtOp op )
2505{
2506 switch (op) {
2507 case BtOpNone: return "";
2508 case BtOpSet: return "s";
2509 case BtOpReset: return "r";
2510 case BtOpComp: return "c";
2511 default: VG_(panic)("nameBtOp");
2512 }
2513}
2514
2515static
2516Addr dis_bt_G_E ( UCodeBlock* cb, Int sz, Addr eip, BtOp op )
2517{
2518 Int t, t2, ta, helper;
2519 UInt pair;
2520 UChar dis_buf[50];
2521 UChar modrm;
2522
2523 vg_assert(sz == 2 || sz == 4);
2524 vg_assert(sz == 4);
2525 switch (op) {
2526 case BtOpNone: helper = VGOFF_(helper_bt); break;
2527 case BtOpSet: helper = VGOFF_(helper_bts); break;
2528 case BtOpReset: helper = VGOFF_(helper_btr); break;
2529 case BtOpComp: helper = VGOFF_(helper_btc); break;
2530 default: VG_(panic)("dis_bt_G_E");
2531 }
2532
2533 modrm = getUChar(eip);
2534
2535 t = newTemp(cb);
2536 t2 = newTemp(cb);
2537 uInstr0(cb, CALLM_S, 0);
2538 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t);
2539 uInstr1(cb, PUSH, sz, TempReg, t);
2540
2541 if (epartIsReg(modrm)) {
2542 eip++;
2543 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t2);
2544 uInstr1(cb, PUSH, sz, TempReg, t2);
2545 uInstr1(cb, CALLM, 0, Lit16, helper);
2546 uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
2547 uInstr1(cb, POP, sz, TempReg, t);
2548 uInstr2(cb, PUT, sz, TempReg, t, ArchReg, eregOfRM(modrm));
2549 if (dis)
2550 VG_(printf)("bt%s%c %s, %s\n",
2551 nameBtOp(op),
2552 nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
2553 nameIReg(sz, eregOfRM(modrm)));
2554 } else {
2555 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
2556 ta = LOW24(pair);
2557 eip += HI8(pair);
2558 uInstr2(cb, LOAD, sz, TempReg, ta, TempReg, t2);
2559 uInstr1(cb, PUSH, sz, TempReg, t2);
2560 uInstr1(cb, CALLM, 0, Lit16, helper);
2561 uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
2562 uInstr1(cb, POP, sz, TempReg, t);
2563 uInstr2(cb, STORE, sz, TempReg, t, TempReg, ta);
2564 SMC_IF_ALL(cb);
2565 if (dis)
2566 VG_(printf)("bt%s%c %s, %s\n",
2567 nameBtOp(op),
2568 nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
2569 dis_buf);
2570 }
2571
2572 uInstr1(cb, CLEAR, 0, Lit16, 4);
2573 uInstr0(cb, CALLM_E, 0);
2574
2575 return eip;
2576}
2577
2578
2579/* Handle BSF/BSR. Only v-size seems necessary. */
2580static
2581Addr dis_bs_E_G ( UCodeBlock* cb, Int sz, Addr eip, Bool fwds )
2582{
2583 Int t, ta, helper;
2584 UInt pair;
2585 UChar dis_buf[50];
2586 UChar modrm;
2587
2588 vg_assert(sz == 2 || sz == 4);
2589 vg_assert(sz==4);
2590
2591 helper = fwds ? VGOFF_(helper_bsf) : VGOFF_(helper_bsr);
2592 modrm = getUChar(eip);
2593 t = newTemp(cb);
2594
2595 if (epartIsReg(modrm)) {
2596 eip++;
2597 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t);
2598 if (dis)
2599 VG_(printf)("bs%c%c %s, %s\n",
2600 fwds ? 'f' : 'r',
2601 nameISize(sz), nameIReg(sz, eregOfRM(modrm)),
2602 nameIReg(sz, gregOfRM(modrm)));
2603 } else {
2604 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
2605 ta = LOW24(pair);
2606 eip += HI8(pair);
2607 uInstr2(cb, LOAD, sz, TempReg, ta, TempReg, t);
2608 if (dis)
2609 VG_(printf)("bs%c%c %s, %s\n",
2610 fwds ? 'f' : 'r',
2611 nameISize(sz), dis_buf,
2612 nameIReg(sz, gregOfRM(modrm)));
2613 }
2614
2615 uInstr0(cb, CALLM_S, 0);
2616 uInstr1(cb, PUSH, sz, TempReg, t);
2617 uInstr1(cb, CALLM, 0, Lit16, helper);
2618 uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsOSACP);
2619 uInstr1(cb, POP, sz, TempReg, t);
2620 uInstr2(cb, PUT, sz, TempReg, t, ArchReg, gregOfRM(modrm));
2621 uInstr0(cb, CALLM_E, 0);
2622
2623 return eip;
2624}
2625
2626
2627static
2628void codegen_xchg_eAX_Reg ( UCodeBlock* cb, Int sz, Int reg )
2629{
2630 Int t1, t2;
2631 vg_assert(sz == 2 || sz == 4);
2632 t1 = newTemp(cb);
2633 t2 = newTemp(cb);
2634 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
2635 uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t2);
2636 uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, R_EAX);
2637 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
2638 if (dis)
2639 VG_(printf)("xchg%c %s, %s\n", nameISize(sz),
2640 nameIReg(sz, R_EAX), nameIReg(sz, reg));
2641}
2642
2643
2644static
2645void codegen_SAHF ( UCodeBlock* cb )
2646{
sewardj3a72df02002-03-24 10:03:17 +00002647 Int t = newTemp(cb);
2648 Int t2 = newTemp(cb);
sewardjde4a1d02002-03-22 01:27:54 +00002649 uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t);
sewardj3a72df02002-03-24 10:03:17 +00002650
2651 /* Mask out parts of t not corresponding to %AH. This stops the
2652 instrumenter complaining if they are undefined. Otherwise, the
2653 instrumenter would check all 32 bits of t at the PUSH, which
2654 could be the cause of incorrect warnings. Discovered by Daniel
2655 Veillard <veillard@redhat.com>.
2656 */
2657 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
2658 uLiteral(cb, 0x0000FF00);
2659 uInstr2(cb, AND, 4, TempReg, t2, TempReg, t);
2660 /* We deliberately don't set the condition codes here, since this
2661 AND is purely internal to Valgrind and nothing to do with the
2662 client's state. */
2663
sewardjde4a1d02002-03-22 01:27:54 +00002664 uInstr0(cb, CALLM_S, 0);
2665 uInstr1(cb, PUSH, 4, TempReg, t);
2666 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_SAHF));
2667 uFlagsRWU(cb, FlagsEmpty, FlagsSZACP, FlagsEmpty);
2668 uInstr1(cb, CLEAR, 0, Lit16, 4);
2669 uInstr0(cb, CALLM_E, 0);
2670}
2671
2672
2673static
2674Addr dis_cmpxchg_G_E ( UCodeBlock* cb,
2675 Int size,
2676 Addr eip0 )
2677{
2678 Int ta, junk, dest, src, acc;
2679 UChar dis_buf[50];
2680 UChar rm;
2681
2682 rm = getUChar(eip0);
2683 acc = newTemp(cb);
2684 src = newTemp(cb);
2685 dest = newTemp(cb);
2686 junk = newTemp(cb);
2687 /* Only needed to get gcc's dataflow analyser off my back. */
2688 ta = INVALID_TEMPREG;
2689
2690 if (epartIsReg(rm)) {
2691 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, dest);
2692 eip0++;
2693 if (dis) VG_(printf)("cmpxchg%c %s,%s\n",
2694 nameISize(size),
2695 nameIReg(size,gregOfRM(rm)),
2696 nameIReg(size,eregOfRM(rm)) );
2697 nameIReg(size,eregOfRM(rm));
2698 } else {
2699 UInt pair = disAMode ( cb, eip0, dis?dis_buf:NULL );
2700 ta = LOW24(pair);
2701 uInstr2(cb, LOAD, size, TempReg, ta, TempReg, dest);
2702 eip0 += HI8(pair);
2703 if (dis) VG_(printf)("cmpxchg%c %s,%s\n", nameISize(size),
2704 nameIReg(size,gregOfRM(rm)), dis_buf);
2705 }
2706
2707 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, src);
2708 uInstr2(cb, GET, size, ArchReg, R_EAX, TempReg, acc);
2709 uInstr2(cb, MOV, size, TempReg, acc, TempReg, junk);
2710 uInstr2(cb, SUB, size, TempReg, dest, TempReg, junk);
2711 setFlagsFromUOpcode(cb, SUB);
2712
2713 uInstr2(cb, CMOV, 4, TempReg, src, TempReg, dest);
2714 uCond(cb, CondZ);
2715 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
2716 uInstr2(cb, CMOV, 4, TempReg, dest, TempReg, acc);
2717 uCond(cb, CondNZ);
2718 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
2719
2720 uInstr2(cb, PUT, size, TempReg, acc, ArchReg, R_EAX);
2721 if (epartIsReg(rm)) {
2722 uInstr2(cb, PUT, size, TempReg, dest, ArchReg, eregOfRM(rm));
2723 } else {
2724 uInstr2(cb, STORE, size, TempReg, dest, TempReg, ta);
2725 }
2726
2727 return eip0;
2728}
2729
2730
2731/* Handle conditional move instructions of the form
2732 cmovcc E(reg-or-mem), G(reg)
2733
2734 E(src) is reg-or-mem
2735 G(dst) is reg.
2736
2737 If E is reg, --> GET %E, tmps
2738 GET %G, tmpd
2739 CMOVcc tmps, tmpd
2740 PUT tmpd, %G
2741
2742 If E is mem --> (getAddr E) -> tmpa
2743 LD (tmpa), tmps
2744 GET %G, tmpd
2745 CMOVcc tmps, tmpd
2746 PUT tmpd, %G
2747*/
2748static
2749Addr dis_cmov_E_G ( UCodeBlock* cb,
2750 Int size,
2751 Condcode cond,
2752 Addr eip0 )
2753{
2754 UChar rm = getUChar(eip0);
2755 UChar dis_buf[50];
2756
2757 Int tmps = newTemp(cb);
2758 Int tmpd = newTemp(cb);
2759
2760 if (epartIsReg(rm)) {
2761 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, tmps);
2762 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmpd);
2763 uInstr2(cb, CMOV, 4, TempReg, tmps, TempReg, tmpd);
2764 uCond(cb, cond);
2765 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
2766 uInstr2(cb, PUT, size, TempReg, tmpd, ArchReg, gregOfRM(rm));
2767 if (dis) VG_(printf)("cmov%c%s %s,%s\n",
2768 nameISize(size),
2769 VG_(nameCondcode)(cond),
2770 nameIReg(size,eregOfRM(rm)),
2771 nameIReg(size,gregOfRM(rm)));
2772 return 1+eip0;
2773 }
2774
2775 /* E refers to memory */
2776 {
2777 UInt pair = disAMode ( cb, eip0, dis?dis_buf:NULL);
2778 Int tmpa = LOW24(pair);
2779 uInstr2(cb, LOAD, size, TempReg, tmpa, TempReg, tmps);
2780 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmpd);
2781 uInstr2(cb, CMOV, 4, TempReg, tmps, TempReg, tmpd);
2782 uCond(cb, cond);
2783 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
2784 uInstr2(cb, PUT, size, TempReg, tmpd, ArchReg, gregOfRM(rm));
2785 if (dis) VG_(printf)("cmov%c%s %s,%s\n",
2786 nameISize(size),
2787 VG_(nameCondcode)(cond),
2788 dis_buf,
2789 nameIReg(size,gregOfRM(rm)));
2790 return HI8(pair)+eip0;
2791 }
2792}
2793
2794
2795static
2796Addr dis_xadd_G_E ( UCodeBlock* cb,
2797 Int sz,
2798 Addr eip0 )
2799{
2800 UChar rm = getUChar(eip0);
2801 UChar dis_buf[50];
2802
2803 Int tmpd = newTemp(cb);
2804 Int tmpt = newTemp(cb);
2805
2806 if (epartIsReg(rm)) {
2807 uInstr2(cb, GET, sz, ArchReg, eregOfRM(rm), TempReg, tmpd);
2808 uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
2809 uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
2810 setFlagsFromUOpcode(cb, ADD);
2811 uInstr2(cb, PUT, sz, TempReg, tmpt, ArchReg, eregOfRM(rm));
2812 uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
2813 if (dis)
2814 VG_(printf)("xadd%c %s, %s\n", nameISize(sz),
2815 nameIReg(sz,gregOfRM(rm)),
2816 nameIReg(sz,eregOfRM(rm)));
2817 return 1+eip0;
2818 } else {
2819 UInt pair = disAMode ( cb, eip0, dis?dis_buf:NULL);
2820 Int tmpa = LOW24(pair);
2821 uInstr2(cb, LOAD, sz, TempReg, tmpa, TempReg, tmpd);
2822 uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
2823 uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
2824 setFlagsFromUOpcode(cb, ADD);
2825 uInstr2(cb, STORE, sz, TempReg, tmpt, TempReg, tmpa);
2826 SMC_IF_SOME(cb);
2827 uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
2828 if (dis)
2829 VG_(printf)("xadd%c %s, %s\n", nameISize(sz),
2830 nameIReg(sz,gregOfRM(rm)),
2831 dis_buf);
2832 return HI8(pair)+eip0;
2833 }
2834}
2835
2836
2837/* Push %ECX, %EBX and %EAX, call helper_do_client_request, and put
2838 the resulting %EAX value back. */
2839static
2840void dis_ClientRequest ( UCodeBlock* cb )
2841{
2842 Int tmpc = newTemp(cb);
2843 Int tmpb = newTemp(cb);
2844 Int tmpa = newTemp(cb);
2845 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, tmpc);
2846 uInstr2(cb, GET, 4, ArchReg, R_EBX, TempReg, tmpb);
2847 uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, tmpa);
2848 uInstr0(cb, CALLM_S, 0);
2849 uInstr1(cb, PUSH, 4, TempReg, tmpc);
2850 uInstr1(cb, PUSH, 4, TempReg, tmpb);
2851 uInstr1(cb, PUSH, 4, TempReg, tmpa);
2852 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_do_client_request));
2853 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
2854 uInstr1(cb, POP, 4, TempReg, tmpa);
2855 uInstr1(cb, CLEAR, 0, Lit16, 8);
2856 uInstr0(cb, CALLM_E, 0);
2857 uInstr2(cb, PUT, 4, TempReg, tmpa, ArchReg, R_EAX);
2858 if (dis)
2859 VG_(printf)("%%eax = client_request ( %%eax, %%ebx, %%ecx )\n");
2860}
2861
2862
2863/*------------------------------------------------------------*/
2864/*--- Disassembling entire basic blocks ---*/
2865/*------------------------------------------------------------*/
2866
2867/* Disassemble a single instruction into ucode, returning the update
2868 eip, and setting *isEnd to True if this is the last insn in a basic
2869 block. Also do debug printing if (dis). */
2870
2871static Addr disInstr ( UCodeBlock* cb, Addr eip, Bool* isEnd )
2872{
2873 UChar opc, modrm, abyte;
2874 UInt d32, pair;
2875 Int t1, t2, t3, t4;
2876 UChar dis_buf[50];
2877 Int am_sz, d_sz;
2878
2879 Int sz = 4;
2880 Int first_uinstr = cb->used;
2881 *isEnd = False;
2882 t1 = t2 = t3 = t4 = INVALID_TEMPREG;
2883
2884 if (dis) VG_(printf)("\t0x%x: ", eip);
2885
2886 /* Spot the client-request magic sequence, if required. */
2887 if (VG_(clo_client_perms)) {
2888 UChar* myeip = (UChar*)eip;
2889 /* Spot this:
2890 C1C01D roll $29, %eax
2891 C1C003 roll $3, %eax
2892 C1C01B roll $27, %eax
2893 C1C005 roll $5, %eax
2894 */
2895 if (myeip[0] == 0xC1 && myeip[1] == 0xC0 && myeip[2] == 0x1D &&
2896 myeip[3] == 0xC1 && myeip[4] == 0xC0 && myeip[5] == 0x03 &&
2897 myeip[6] == 0xC1 && myeip[7] == 0xC0 && myeip[8] == 0x1B &&
2898 myeip[9] == 0xC1 && myeip[10] == 0xC0 && myeip[11] == 0x05) {
2899 vg_assert(VG_(clo_instrument));
2900 dis_ClientRequest(cb);
2901 eip += 12;
2902 return eip;
2903 }
2904 }
2905
2906 /* Skip a LOCK prefix. */
2907 if (getUChar(eip) == 0xF0) eip++;
2908
2909 /* Crap out if we see a segment override prefix. */
2910 if (getUChar(eip) == 0x65) {
2911 VG_(message)(Vg_DebugMsg, "");
2912 VG_(message)(Vg_DebugMsg, "Possible workaround for the following abort: do not use special");
2913 VG_(message)(Vg_DebugMsg, "PII/PIII-specific pthreads library (possibly in /lib/i686/*.so).");
2914 VG_(message)(Vg_DebugMsg, "You might be able to kludge around this by renaming /lib/i686 to");
2915 VG_(message)(Vg_DebugMsg, "/lib/i686-HIDDEN. On RedHat 7.2 this causes ld.so to fall back");
2916 VG_(message)(Vg_DebugMsg, "to using the less specialised versions in /lib instead, which");
2917 VG_(message)(Vg_DebugMsg, "valgrind might be able to better deal with.");
2918 VG_(message)(Vg_DebugMsg, "");
2919 VG_(message)(Vg_DebugMsg, "WARNING. WARNING. WARNING. WARNING. WARNING. WARNING. WARNING.");
2920 VG_(message)(Vg_DebugMsg, "WARNING: The suggested kludge may also render your system unbootable");
2921 VG_(message)(Vg_DebugMsg, "WARNING: or otherwise totally screw it up. Only try this if you");
2922 VG_(message)(Vg_DebugMsg, "WARNING: know what you are doing, and are prepared to take risks.");
2923 VG_(message)(Vg_DebugMsg, "YOU HAVE BEEN WARNED. YOU HAVE BEEN WARNED. YOU HAVE BEEN WARNED.");
2924 VG_(message)(Vg_DebugMsg, "");
2925 VG_(message)(Vg_DebugMsg, "Another consideration is that this may well mean your application");
2926 VG_(message)(Vg_DebugMsg, "uses threads, which valgrind doesn't currently support, so even if");
2927 VG_(message)(Vg_DebugMsg, "you work around this problem, valgrind may abort later if it sees");
2928 VG_(message)(Vg_DebugMsg, "a clone() system call.");
2929 VG_(unimplemented)("x86 segment override (SEG=GS) prefix; see above for details");
2930 }
2931
2932 /* Detect operand-size overrides. */
2933 if (getUChar(eip) == 0x66) { sz = 2; eip++; };
2934
2935 opc = getUChar(eip); eip++;
2936
2937 switch (opc) {
2938
2939 /* ------------------------ Control flow --------------- */
2940
2941 case 0xC2: /* RET imm16 */
2942 d32 = getUDisp16(eip); eip += 2;
2943 goto do_Ret;
2944 case 0xC3: /* RET */
2945 d32 = 0;
2946 goto do_Ret;
2947 do_Ret:
2948 t1 = newTemp(cb); t2 = newTemp(cb);
2949 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
2950 uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t2);
2951 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1);
2952 uLiteral(cb, 4+d32);
2953 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
2954 uInstr1(cb, JMP, 0, TempReg, t2);
2955 uCond(cb, CondAlways);
2956
2957 if (d32 == 0)
2958 LAST_UINSTR(cb).ret_dispatch = True;
2959
2960 *isEnd = True;
2961 if (dis) {
2962 if (d32 == 0) VG_(printf)("ret\n");
2963 else VG_(printf)("ret %d\n", d32);
2964 }
2965 break;
2966
2967 case 0xE8: /* CALL J4 */
2968 d32 = getUDisp32(eip); eip += 4;
2969 d32 += eip; /* eip now holds return-to addr, d32 is call-to addr */
2970 if (d32 == (Addr)&VG_(shutdown)) {
2971 /* Set vg_dispatch_ctr to 1, vg_interrupt_reason to VG_Y_EXIT,
2972 and get back to the dispatch loop. We ask for a jump to this
2973 CALL insn because vg_dispatch will ultimately transfer control
2974 to the real CPU, and we want this call to be the first insn
2975 it does. */
2976 uInstr0(cb, CALLM_S, 0);
2977 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_request_normal_exit));
2978 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
2979 uInstr0(cb, CALLM_E, 0);
2980 uInstr1(cb, JMP, 0, Literal, 0);
2981 uLiteral(cb, eip-5);
2982 uCond(cb, CondAlways);
2983 *isEnd = True;
2984 if (dis) VG_(printf)("call 0x%x\n",d32);
2985 } else
2986 if (d32 == eip && getUChar(eip) >= 0x58
2987 && getUChar(eip) <= 0x5F) {
2988 /* Specially treat the position-independent-code idiom
2989 call X
2990 X: popl %reg
2991 as
2992 movl %eip, %reg.
2993 since this generates better code, but for no other reason. */
2994 Int archReg = getUChar(eip) - 0x58;
2995 /* VG_(printf)("-- fPIC thingy\n"); */
2996 t1 = newTemp(cb);
2997 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
2998 uLiteral(cb, eip);
2999 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, archReg);
3000 eip++; /* Step over the POP */
3001 if (dis)
3002 VG_(printf)("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
3003 } else {
3004 /* The normal sequence for a call. */
3005 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3006 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
3007 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t1);
3008 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t1);
3009 uLiteral(cb, 4);
3010 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3011 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
3012 uLiteral(cb, eip);
3013 uInstr2(cb, STORE, 4, TempReg, t2, TempReg, t1);
3014 SMC_IF_ALL(cb);
3015 uInstr1(cb, JMP, 0, Literal, 0);
3016 uLiteral(cb, d32);
3017 uCond(cb, CondAlways);
3018 LAST_UINSTR(cb).call_dispatch = True;
3019 *isEnd = True;
3020 if (dis) VG_(printf)("call 0x%x\n",d32);
3021 }
3022 break;
3023
3024 case 0xC9: /* LEAVE */
3025 t1 = newTemp(cb); t2 = newTemp(cb);
3026 uInstr2(cb, GET, 4, ArchReg, R_EBP, TempReg, t1);
3027 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3028 uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t2);
3029 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
3030 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1);
3031 uLiteral(cb, 4);
3032 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3033 if (dis) VG_(printf)("leave");
3034 break;
3035
sewardj4d0ab1f2002-03-24 10:00:09 +00003036 /* ---------------- Misc wierd-ass insns --------------- */
3037
3038 case 0x2F: /* DAS */
3039 t1 = newTemp(cb);
3040 uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
3041 /* Widen %AL to 32 bits, so it's all defined when we push it. */
3042 uInstr1(cb, WIDEN, 4, TempReg, t1);
3043 LAST_UINSTR(cb).extra4b = 1;
3044 LAST_UINSTR(cb).signed_widen = False;
3045 uInstr0(cb, CALLM_S, 0);
3046 uInstr1(cb, PUSH, 4, TempReg, t1);
3047 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_DAS) );
3048 uFlagsRWU(cb, FlagsAC, FlagsOSZACP, FlagsEmpty);
3049 uInstr1(cb, POP, 4, TempReg, t1);
3050 uInstr0(cb, CALLM_E, 0);
3051 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
3052 if (dis) VG_(printf)("das\n");
3053
sewardjde4a1d02002-03-22 01:27:54 +00003054 /* ------------------------ CWD/CDQ -------------------- */
3055
3056 case 0x98: /* CBW */
3057 t1 = newTemp(cb);
3058 if (sz == 4) {
3059 uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
3060 uInstr1(cb, WIDEN, 4, TempReg, t1); /* 4 == dst size */
3061 LAST_UINSTR(cb).extra4b = 2; /* the source size */
3062 LAST_UINSTR(cb).signed_widen = True;
3063 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
3064 if (dis) VG_(printf)("cwd\n");
3065 } else {
3066 vg_assert(sz == 2);
3067 uInstr2(cb, GET, 1, ArchReg, R_EAX, TempReg, t1);
3068 uInstr1(cb, WIDEN, 2, TempReg, t1); /* 2 == dst size */
3069 LAST_UINSTR(cb).extra4b = 1; /* the source size */
3070 LAST_UINSTR(cb).signed_widen = True;
3071 uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
3072 if (dis) VG_(printf)("cbw\n");
3073 }
3074 break;
3075
3076 case 0x99: /* CWD/CDQ */
3077 t1 = newTemp(cb);
3078 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
3079 uInstr2(cb, SAR, sz, Literal, 0, TempReg, t1);
3080 uLiteral(cb, sz == 2 ? 15 : 31);
3081 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EDX);
3082 if (dis) VG_(printf)(sz == 2 ? "cwdq\n" : "cdqq\n");
3083 break;
3084
3085 /* ------------------------ FPU ops -------------------- */
3086
3087 case 0x9E: /* SAHF */
3088 codegen_SAHF ( cb );
3089 if (dis) VG_(printf)("sahf\n");
3090 break;
3091
3092 case 0x9B: /* FWAIT */
3093 /* ignore? */
3094 if (dis) VG_(printf)("fwait\n");
3095 break;
3096
3097 case 0xD8:
3098 case 0xD9:
3099 case 0xDA:
3100 case 0xDB:
3101 case 0xDC:
3102 case 0xDD:
3103 case 0xDE:
3104 case 0xDF:
3105 eip = dis_fpu ( cb, opc, eip );
3106 break;
3107
3108 /* ------------------------ INC & DEC ------------------ */
3109
3110 case 0x40: /* INC eAX */
3111 case 0x41: /* INC eCX */
3112 case 0x42: /* INC eDX */
3113 case 0x43: /* INC eBX */
3114 case 0x45: /* INC eBP */
3115 case 0x46: /* INC eSI */
3116 case 0x47: /* INC eDI */
3117 t1 = newTemp(cb);
3118 uInstr2(cb, GET, sz, ArchReg, (UInt)(opc - 0x40),
3119 TempReg, t1);
3120 uInstr1(cb, INC, sz, TempReg, t1);
3121 setFlagsFromUOpcode(cb, INC);
3122 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg,
3123 (UInt)(opc - 0x40));
3124 if (dis)
3125 VG_(printf)("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
3126 break;
3127
3128 case 0x48: /* DEC eAX */
3129 case 0x49: /* DEC eCX */
3130 case 0x4A: /* DEC eDX */
3131 case 0x4B: /* DEC eBX */
3132 case 0x4D: /* DEC eBP */
3133 case 0x4E: /* DEC eSI */
3134 case 0x4F: /* DEC eDI */
3135 t1 = newTemp(cb);
3136 uInstr2(cb, GET, sz, ArchReg, (UInt)(opc - 0x48),
3137 TempReg, t1);
3138 uInstr1(cb, DEC, sz, TempReg, t1);
3139 setFlagsFromUOpcode(cb, DEC);
3140 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg,
3141 (UInt)(opc - 0x48));
3142 if (dis)
3143 VG_(printf)("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
3144 break;
3145
3146 /* ------------------------ INT ------------------------ */
3147
3148 case 0xCD: /* INT imm8 */
3149 d32 = getUChar(eip); eip++;
3150 if (d32 != 0x80) VG_(panic)("disInstr: INT but not 0x80 !");
3151 /* It's important that all ArchRegs carry their up-to-date value
3152 at this point. So we declare an end-of-block here, which
3153 forces any TempRegs caching ArchRegs to be flushed. */
3154 t1 = newTemp(cb);
3155 uInstr0(cb, CALLM_S, 0);
3156 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_do_syscall) );
3157 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
3158 uInstr0(cb, CALLM_E, 0);
3159 uInstr1(cb, JMP, 0, Literal, 0);
3160 uLiteral(cb, eip);
3161 uCond(cb, CondAlways);
3162 *isEnd = True;
3163 if (dis) VG_(printf)("int $0x80\n");
3164 break;
3165
3166 /* ------------------------ Jcond, byte offset --------- */
3167
3168 case 0xEB: /* Jb (jump, byte offset) */
3169 d32 = (eip+1) + getSDisp8(eip); eip++;
3170 uInstr1(cb, JMP, 0, Literal, 0);
3171 uLiteral(cb, d32);
3172 uCond(cb, CondAlways);
3173 *isEnd = True;
3174 if (dis)
3175 VG_(printf)("jmp-8 0x%x\n", d32);
3176 break;
3177
3178 case 0xE9: /* Jv (jump, 16/32 offset) */
3179 d32 = (eip+sz) + getSDisp(sz,eip); eip += sz;
3180 uInstr1(cb, JMP, 0, Literal, 0);
3181 uLiteral(cb, d32);
3182 uCond(cb, CondAlways);
3183 *isEnd = True;
3184 if (dis)
3185 VG_(printf)("jmp 0x%x\n", d32);
3186 break;
3187
3188 case 0x70:
3189 case 0x71:
3190 case 0x72: /* JBb/JNAEb (jump below) */
3191 case 0x73: /* JNBb/JAEb (jump not below) */
3192 case 0x74: /* JZb/JEb (jump zero) */
3193 case 0x75: /* JNZb/JNEb (jump not zero) */
3194 case 0x76: /* JBEb/JNAb (jump below or equal) */
3195 case 0x77: /* JNBEb/JAb (jump not below or equal) */
3196 case 0x78: /* JSb (jump negative) */
3197 case 0x79: /* JSb (jump not negative) */
3198 case 0x7A: /* JP (jump parity even) */
3199 case 0x7B: /* JNP/JPO (jump parity odd) */
3200 case 0x7C: /* JLb/JNGEb (jump less) */
3201 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
3202 case 0x7E: /* JLEb/JNGb (jump less or equal) */
3203 case 0x7F: /* JGb/JNLEb (jump greater) */
3204 d32 = (eip+1) + getSDisp8(eip); eip++;
3205 uInstr1(cb, JMP, 0, Literal, 0);
3206 uLiteral(cb, d32);
3207 uCond(cb, (Condcode)(opc - 0x70));
3208 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
3209 /* It's actually acceptable not to end this basic block at a
3210 control transfer, reducing the number of jumps through
3211 vg_dispatch, at the expense of possibly translating the insns
3212 following this jump twice. This does give faster code, but
3213 on the whole I don't think the effort is worth it. */
3214 uInstr1(cb, JMP, 0, Literal, 0);
3215 uLiteral(cb, eip);
3216 uCond(cb, CondAlways);
3217 *isEnd = True;
3218 /* The above 3 lines would be removed if the bb was not to end
3219 here. */
3220 if (dis)
3221 VG_(printf)("j%s-8 0x%x\n", VG_(nameCondcode)(opc - 0x70), d32);
3222 break;
3223
3224 case 0xE3: /* JECXZ or perhaps JCXZ, depending on OSO ? Intel
3225 manual says it depends on address size override,
3226 which doesn't sound right to me. */
3227 d32 = (eip+1) + getSDisp8(eip); eip++;
3228 t1 = newTemp(cb);
3229 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
3230 uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
3231 uLiteral(cb, d32);
3232 if (dis)
3233 VG_(printf)("j%sz 0x%x\n", nameIReg(sz, R_ECX), d32);
3234 break;
3235
3236 case 0xE2: /* LOOP disp8 */
3237 /* Again, the docs say this uses ECX/CX as a count depending on
3238 the address size override, not the operand one. Since we
3239 don't handle address size overrides, I guess that means
3240 ECX. */
3241 d32 = (eip+1) + getSDisp8(eip); eip++;
3242 t1 = newTemp(cb);
3243 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
3244 uInstr1(cb, DEC, 4, TempReg, t1);
3245 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ECX);
3246 uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
3247 uLiteral(cb, eip);
3248 uInstr1(cb, JMP, 0, Literal, 0);
3249 uLiteral(cb, d32);
3250 uCond(cb, CondAlways);
3251 *isEnd = True;
3252 if (dis)
3253 VG_(printf)("loop 0x%x\n", d32);
3254 break;
3255
3256 /* ------------------------ IMUL ----------------------- */
3257
3258 case 0x69: /* IMUL Iv, Ev, Gv */
3259 eip = dis_imul_I_E_G ( cb, sz, eip, sz );
3260 break;
3261 case 0x6B: /* IMUL Ib, Ev, Gv */
3262 eip = dis_imul_I_E_G ( cb, sz, eip, 1 );
3263 break;
3264
3265 /* ------------------------ MOV ------------------------ */
3266
3267 case 0x88: /* MOV Gb,Eb */
3268 eip = dis_mov_G_E(cb, 1, eip);
3269 break;
3270
3271 case 0x89: /* MOV Gv,Ev */
3272 eip = dis_mov_G_E(cb, sz, eip);
3273 break;
3274
3275 case 0x8A: /* MOV Eb,Gb */
3276 eip = dis_mov_E_G(cb, 1, eip);
3277 break;
3278
3279 case 0x8B: /* MOV Ev,Gv */
3280 eip = dis_mov_E_G(cb, sz, eip);
3281 break;
3282
3283 case 0x8D: /* LEA M,Gv */
3284 modrm = getUChar(eip);
3285 if (epartIsReg(modrm))
3286 VG_(panic)("LEA M,Gv: modRM refers to register");
3287 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
3288 eip += HI8(pair);
3289 t1 = LOW24(pair);
3290 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, gregOfRM(modrm));
3291 if (dis)
3292 VG_(printf)("lea%c %s, %s\n", nameISize(sz), dis_buf,
3293 nameIReg(sz,gregOfRM(modrm)));
3294 break;
3295
3296 case 0xA0: /* MOV Ob,AL */
3297 sz = 1;
3298 /* Fall through ... */
3299 case 0xA1: /* MOV Ov,eAX */
3300 d32 = getUDisp32(eip); eip += 4;
3301 t1 = newTemp(cb); t2 = newTemp(cb);
3302 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
3303 uLiteral(cb, d32);
3304 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3305 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EAX);
3306 if (dis) VG_(printf)("mov%c 0x%x,%s\n", nameISize(sz),
3307 d32, nameIReg(sz,R_EAX));
3308 break;
3309
3310 case 0xA2: /* MOV AL,Ob */
3311 sz = 1;
3312 /* Fall through ... */
3313 case 0xA3: /* MOV eAX,Ov */
3314 d32 = getUDisp32(eip); eip += 4;
3315 t1 = newTemp(cb); t2 = newTemp(cb);
3316 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
3317 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
3318 uLiteral(cb, d32);
3319 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3320 SMC_IF_SOME(cb);
3321 if (dis) VG_(printf)("mov%c %s,0x%x\n", nameISize(sz),
3322 nameIReg(sz,R_EAX), d32);
3323 break;
3324
3325 case 0xB0: /* MOV imm,AL */
3326 case 0xB1: /* MOV imm,CL */
3327 case 0xB2: /* MOV imm,DL */
3328 case 0xB3: /* MOV imm,BL */
3329 case 0xB4: /* MOV imm,AH */
3330 case 0xB5: /* MOV imm,CH */
3331 case 0xB6: /* MOV imm,DH */
3332 case 0xB7: /* MOV imm,BH */
3333 d32 = getUChar(eip); eip += 1;
3334 t1 = newTemp(cb);
3335 uInstr2(cb, MOV, 1, Literal, 0, TempReg, t1);
3336 uLiteral(cb, d32);
3337 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, opc-0xB0);
3338 if (dis) VG_(printf)("movb $0x%x,%s\n", d32,
3339 nameIReg(1,opc-0xB0));
3340 break;
3341
3342 case 0xB8: /* MOV imm,eAX */
3343 case 0xB9: /* MOV imm,eCX */
3344 case 0xBA: /* MOV imm,eDX */
3345 case 0xBB: /* MOV imm,eBX */
3346 case 0xBD: /* MOV imm,eBP */
3347 case 0xBE: /* MOV imm,eSI */
3348 case 0xBF: /* MOV imm,eDI */
3349 d32 = getUDisp(sz,eip); eip += sz;
3350 t1 = newTemp(cb);
3351 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t1);
3352 uLiteral(cb, d32);
3353 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, opc-0xB8);
3354 if (dis) VG_(printf)("mov%c $0x%x,%s\n", nameISize(sz), d32,
3355 nameIReg(sz,opc-0xB8));
3356 break;
3357
3358 case 0xC6: /* MOV Ib,Eb */
3359 sz = 1;
3360 goto do_Mov_I_E;
3361 case 0xC7: /* MOV Iv,Ev */
3362 goto do_Mov_I_E;
3363
3364 do_Mov_I_E:
3365 modrm = getUChar(eip);
3366 if (epartIsReg(modrm)) {
3367 d32 = getUDisp(sz,eip); eip += sz;
3368 t1 = newTemp(cb);
3369 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t1);
3370 uLiteral(cb, d32);
3371 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
3372 if (dis) VG_(printf)("mov%c $0x%x, %s\n", nameISize(sz), d32,
3373 nameIReg(sz,eregOfRM(modrm)));
3374 } else {
3375 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
3376 eip += HI8(pair);
3377 d32 = getUDisp(sz,eip); eip += sz;
3378 t1 = newTemp(cb);
3379 t2 = LOW24(pair);
3380 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t1);
3381 uLiteral(cb, d32);
3382 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3383 SMC_IF_SOME(cb);
3384 if (dis) VG_(printf)("mov%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
3385 }
3386 break;
3387
3388 /* ------------------------ opl imm, A ----------------- */
3389
3390 case 0x04: /* ADD Ib, AL */
3391 eip = dis_op_imm_A(cb, 1, ADD, True, eip, "add" );
3392 break;
3393 case 0x05: /* ADD Iv, eAX */
3394 eip = dis_op_imm_A(cb, sz, ADD, True, eip, "add" );
3395 break;
3396
3397 case 0x0C: /* OR Ib, AL */
3398 eip = dis_op_imm_A(cb, 1, OR, True, eip, "or" );
3399 break;
3400 case 0x0D: /* OR Iv, eAX */
3401 eip = dis_op_imm_A(cb, sz, OR, True, eip, "or" );
3402 break;
3403
3404 case 0x24: /* AND Ib, AL */
3405 eip = dis_op_imm_A(cb, 1, AND, True, eip, "and" );
3406 break;
3407 case 0x25: /* AND Iv, eAX */
3408 eip = dis_op_imm_A(cb, sz, AND, True, eip, "and" );
3409 break;
3410
3411 case 0x2C: /* SUB Ib, AL */
3412 eip = dis_op_imm_A(cb, 1, SUB, True, eip, "sub" );
3413 break;
3414 case 0x2D: /* SUB Iv, eAX */
3415 eip = dis_op_imm_A(cb, sz, SUB, True, eip, "sub" );
3416 break;
3417
3418 case 0x34: /* XOR Ib, AL */
3419 eip = dis_op_imm_A(cb, 1, XOR, True, eip, "xor" );
3420 break;
3421 case 0x35: /* XOR Iv, eAX */
3422 eip = dis_op_imm_A(cb, sz, XOR, True, eip, "xor" );
3423 break;
3424
3425 case 0x3C: /* CMP Ib, AL */
3426 eip = dis_op_imm_A(cb, 1, SUB, False, eip, "cmp" );
3427 break;
3428 case 0x3D: /* CMP Iv, eAX */
3429 eip = dis_op_imm_A(cb, sz, SUB, False, eip, "cmp" );
3430 break;
3431
3432 case 0xA8: /* TEST Ib, AL */
3433 eip = dis_op_imm_A(cb, 1, AND, False, eip, "test" );
3434 break;
3435 case 0xA9: /* TEST Iv, eAX */
3436 eip = dis_op_imm_A(cb, sz, AND, False, eip, "test" );
3437 break;
3438
3439 /* ------------------------ opl Ev, Gv ----------------- */
3440
3441 case 0x02: /* ADD Eb,Gb */
3442 eip = dis_op2_E_G ( cb, ADD, True, 1, eip, "add" );
3443 break;
3444 case 0x03: /* ADD Ev,Gv */
3445 eip = dis_op2_E_G ( cb, ADD, True, sz, eip, "add" );
3446 break;
3447
3448 case 0x0A: /* OR Eb,Gb */
3449 eip = dis_op2_E_G ( cb, OR, True, 1, eip, "or" );
3450 break;
3451 case 0x0B: /* OR Ev,Gv */
3452 eip = dis_op2_E_G ( cb, OR, True, sz, eip, "or" );
3453 break;
3454
3455 case 0x13: /* ADC Ev,Gv */
3456 eip = dis_op2_E_G ( cb, ADC, True, sz, eip, "adc" );
3457 break;
3458
3459 case 0x1B: /* SBB Ev,Gv */
3460 eip = dis_op2_E_G ( cb, SBB, True, sz, eip, "sbb" );
3461 break;
3462
3463 case 0x22: /* AND Eb,Gb */
3464 eip = dis_op2_E_G ( cb, AND, True, 1, eip, "and" );
3465 break;
3466 case 0x23: /* AND Ev,Gv */
3467 eip = dis_op2_E_G ( cb, AND, True, sz, eip, "and" );
3468 break;
3469
3470 case 0x2A: /* SUB Eb,Gb */
3471 eip = dis_op2_E_G ( cb, SUB, True, 1, eip, "sub" );
3472 break;
3473 case 0x2B: /* SUB Ev,Gv */
3474 eip = dis_op2_E_G ( cb, SUB, True, sz, eip, "sub" );
3475 break;
3476
3477 case 0x32: /* XOR Eb,Gb */
3478 eip = dis_op2_E_G ( cb, XOR, True, 1, eip, "xor" );
3479 break;
3480 case 0x33: /* XOR Ev,Gv */
3481 eip = dis_op2_E_G ( cb, XOR, True, sz, eip, "xor" );
3482 break;
3483
3484 case 0x3A: /* CMP Eb,Gb */
3485 eip = dis_op2_E_G ( cb, SUB, False, 1, eip, "cmp" );
3486 break;
3487 case 0x3B: /* CMP Ev,Gv */
3488 eip = dis_op2_E_G ( cb, SUB, False, sz, eip, "cmp" );
3489 break;
3490
3491 case 0x84: /* TEST Eb,Gb */
3492 eip = dis_op2_E_G ( cb, AND, False, 1, eip, "test" );
3493 break;
3494 case 0x85: /* TEST Ev,Gv */
3495 eip = dis_op2_E_G ( cb, AND, False, sz, eip, "test" );
3496 break;
3497
3498 /* ------------------------ opl Gv, Ev ----------------- */
3499
3500 case 0x00: /* ADD Gb,Eb */
3501 eip = dis_op2_G_E ( cb, ADD, True, 1, eip, "add" );
3502 break;
3503 case 0x01: /* ADD Gv,Ev */
3504 eip = dis_op2_G_E ( cb, ADD, True, sz, eip, "add" );
3505 break;
3506
3507 case 0x08: /* OR Gb,Eb */
3508 eip = dis_op2_G_E ( cb, OR, True, 1, eip, "or" );
3509 break;
3510 case 0x09: /* OR Gv,Ev */
3511 eip = dis_op2_G_E ( cb, OR, True, sz, eip, "or" );
3512 break;
3513
3514 case 0x11: /* ADC Gv,Ev */
3515 eip = dis_op2_G_E ( cb, ADC, True, sz, eip, "adc" );
3516 break;
3517
3518 case 0x19: /* SBB Gv,Ev */
3519 eip = dis_op2_G_E ( cb, SBB, True, sz, eip, "sbb" );
3520 break;
3521
3522 case 0x20: /* AND Gb,Eb */
3523 eip = dis_op2_G_E ( cb, AND, True, 1, eip, "and" );
3524 break;
3525 case 0x21: /* AND Gv,Ev */
3526 eip = dis_op2_G_E ( cb, AND, True, sz, eip, "and" );
3527 break;
3528
3529 case 0x28: /* SUB Gb,Eb */
3530 eip = dis_op2_G_E ( cb, SUB, True, 1, eip, "sub" );
3531 break;
3532 case 0x29: /* SUB Gv,Ev */
3533 eip = dis_op2_G_E ( cb, SUB, True, sz, eip, "sub" );
3534 break;
3535
3536 case 0x30: /* XOR Gb,Eb */
3537 eip = dis_op2_G_E ( cb, XOR, True, 1, eip, "xor" );
3538 break;
3539 case 0x31: /* XOR Gv,Ev */
3540 eip = dis_op2_G_E ( cb, XOR, True, sz, eip, "xor" );
3541 break;
3542
3543 case 0x38: /* CMP Gb,Eb */
3544 eip = dis_op2_G_E ( cb, SUB, False, 1, eip, "cmp" );
3545 break;
3546 case 0x39: /* CMP Gv,Ev */
3547 eip = dis_op2_G_E ( cb, SUB, False, sz, eip, "cmp" );
3548 break;
3549
3550 /* ------------------------ POP ------------------------ */
3551
3552 case 0x58: /* POP eAX */
3553 case 0x59: /* POP eCX */
3554 case 0x5A: /* POP eDX */
3555 case 0x5B: /* POP eBX */
3556 case 0x5C: /* POP eSP */
3557 case 0x5D: /* POP eBP */
3558 case 0x5E: /* POP eSI */
3559 case 0x5F: /* POP eDI */
3560 t1 = newTemp(cb); t2 = newTemp(cb);
3561 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
3562 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3563 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3564 uLiteral(cb, sz);
3565 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
3566 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, opc-0x58);
3567 if (dis)
3568 VG_(printf)("pop%c %s\n", nameISize(sz), nameIReg(sz,opc-0x58));
3569 break;
3570
3571 case 0x9D: /* POPF */
3572 vg_assert(sz == 2 || sz == 4);
3573 t1 = newTemp(cb); t2 = newTemp(cb);
3574 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
3575 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3576 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3577 uLiteral(cb, sz);
3578 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
3579 uInstr1(cb, PUTF, sz, TempReg, t1);
3580 /* PUTF writes all the flags we are interested in */
3581 uFlagsRWU(cb, FlagsEmpty, FlagsALL, FlagsEmpty);
3582 if (dis)
3583 VG_(printf)("popf%c\n", nameISize(sz));
3584 break;
3585
3586 case 0x61: /* POPA */
3587 { Int reg;
3588 /* Just to keep things sane, we assert for a size 4. It's
3589 probably OK for size 2 as well, but I'd like to find a test
3590 case; ie, have the assertion fail, before committing to it.
3591 If it fails for you, uncomment the sz == 2 bit, try again,
3592 and let me know whether or not it works. (jseward@acm.org). */
3593 vg_assert(sz == 4 /* || sz == 2 */);
3594
3595 /* Eight values are popped, one per register, but the value of
3596 %esp on the stack is ignored and instead incremented (in one
3597 hit at the end) for each of the values. */
3598 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3599 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
3600 uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t3);
3601
3602 /* Do %edi, %esi, %ebp */
3603 for (reg = 7; reg >= 5; reg--) {
3604 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3605 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3606 uLiteral(cb, sz);
3607 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
3608 }
3609 /* Ignore (skip) value of %esp on stack. */
3610 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3611 uLiteral(cb, sz);
3612 /* Do %ebx, %edx, %ecx, %eax */
3613 for (reg = 3; reg >= 0; reg--) {
3614 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3615 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3616 uLiteral(cb, sz);
3617 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
3618 }
3619 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t3);
3620 uLiteral(cb, sz * 8); /* One 'sz' per register */
3621 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
3622 if (dis)
3623 VG_(printf)("popa%c\n", nameISize(sz));
3624 break;
3625 }
3626
3627 /* ------------------------ PUSH ----------------------- */
3628
3629 case 0x50: /* PUSH eAX */
3630 case 0x51: /* PUSH eCX */
3631 case 0x52: /* PUSH eDX */
3632 case 0x54: /* PUSH eSP */
3633 case 0x53: /* PUSH eBX */
3634 case 0x55: /* PUSH eBP */
3635 case 0x56: /* PUSH eSI */
3636 case 0x57: /* PUSH eDI */
3637 /* This is the Right Way, in that the value to be pushed is
3638 established before %esp is changed, so that pushl %esp
3639 correctly pushes the old value. */
3640 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3641 uInstr2(cb, GET, sz, ArchReg, opc-0x50, TempReg, t1);
3642 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
3643 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
3644 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3645 uLiteral(cb, sz);
3646 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
3647 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3648 SMC_IF_ALL(cb);
3649 if (dis)
3650 VG_(printf)("push%c %s\n", nameISize(sz), nameIReg(sz,opc-0x50));
3651 break;
3652
3653 case 0x68: /* PUSH Iv */
3654 d32 = getUDisp(sz,eip); eip += sz;
3655 goto do_push_I;
3656 case 0x6A: /* PUSH Ib, sign-extended to sz */
3657 d32 = getSDisp8(eip); eip += 1;
3658 goto do_push_I;
3659 do_push_I:
3660 t1 = newTemp(cb); t2 = newTemp(cb);
3661 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
3662 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t1);
3663 uLiteral(cb, sz);
3664 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3665 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t2);
3666 uLiteral(cb, d32);
3667 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
3668 SMC_IF_ALL(cb);
3669 if (dis)
3670 VG_(printf)("push%c $0x%x\n", nameISize(sz), d32);
3671 break;
3672
3673 case 0x9C: /* PUSHF */
3674 vg_assert(sz == 2 || sz == 4);
3675 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3676 uInstr1(cb, GETF, sz, TempReg, t1);
3677 /* GETF reads all the flags we are interested in */
3678 uFlagsRWU(cb, FlagsALL, FlagsEmpty, FlagsEmpty);
3679 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
3680 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
3681 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3682 uLiteral(cb, sz);
3683 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
3684 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3685 SMC_IF_ALL(cb);
3686 if (dis)
3687 VG_(printf)("pushf%c\n", nameISize(sz));
3688 break;
3689
3690 case 0x60: /* PUSHA */
3691 { Int reg;
3692 /* Just to keep things sane, we assert for a size 4. It's
3693 probably OK for size 2 as well, but I'd like to find a test
3694 case; ie, have the assertion fail, before committing to it.
3695 If it fails for you, uncomment the sz == 2 bit, try again,
3696 and let me know whether or not it works. (jseward@acm.org). */
3697 vg_assert(sz == 4 /* || sz == 2 */);
3698
3699 /* This is the Right Way, in that the value to be pushed is
3700 established before %esp is changed, so that pusha
3701 correctly pushes the old %esp value. New value of %esp is
3702 pushed at start. */
3703 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3704 t4 = newTemp(cb);
3705 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
3706 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
3707 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t4);
3708 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t4);
3709 uLiteral(cb, sz * 8); /* One 'sz' per register. */
3710 uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_ESP);
3711 /* Do %eax, %ecx, %edx, %ebx */
3712 for (reg = 0; reg <= 3; reg++) {
3713 uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
3714 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3715 uLiteral(cb, sz);
3716 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3717 SMC_IF_ALL(cb);
3718 }
3719 /* Push old value of %esp */
3720 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3721 uLiteral(cb, sz);
3722 uInstr2(cb, STORE, sz, TempReg, t3, TempReg, t2);
3723 SMC_IF_ALL(cb);
3724 /* Do %ebp, %esi, %edi */
3725 for (reg = 5; reg <= 7; reg++) {
3726 uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
3727 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3728 uLiteral(cb, sz);
3729 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3730 SMC_IF_ALL(cb);
3731 }
3732 if (dis)
3733 VG_(printf)("pusha%c\n", nameISize(sz));
3734 break;
3735 }
3736
3737 /* ------------------------ SCAS et al ----------------- */
3738
3739 case 0xA4: /* MOVSb, no REP prefix */
3740 codegen_MOVS ( cb, 1 );
3741 if (dis) VG_(printf)("movsb\n");
3742 break;
3743 case 0xA5: /* MOVSv, no REP prefix */
3744 codegen_MOVS ( cb, sz );
3745 if (dis) VG_(printf)("movs%c\n", nameISize(sz));
3746 break;
3747
3748 case 0xA6: /* CMPSb, no REP prefix */
3749 codegen_CMPS ( cb, 1 );
3750 if (dis) VG_(printf)("cmpsb\n");
3751 break;
3752
3753 case 0xAA: /* STOSb, no REP prefix */
3754 codegen_STOS ( cb, 1 );
3755 if (dis) VG_(printf)("stosb\n");
3756 break;
3757 case 0xAB: /* STOSv, no REP prefix */
3758 codegen_STOS ( cb, sz );
3759 if (dis) VG_(printf)("stos%c\n", nameISize(sz));
3760 break;
3761
3762 case 0xAC: /* LODSb, no REP prefix */
3763 codegen_LODS ( cb, 1 );
3764 if (dis) VG_(printf)("lodsb\n");
3765 break;
3766
3767 case 0xAE: /* SCASb, no REP prefix */
3768 codegen_SCAS ( cb, 1 );
3769 if (dis) VG_(printf)("scasb\n");
3770 break;
3771
3772 case 0xFC: /* CLD */
3773 uInstr0(cb, CALLM_S, 0);
3774 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CLD));
3775 uFlagsRWU(cb, FlagsEmpty, FlagD, FlagsEmpty);
3776 uInstr0(cb, CALLM_E, 0);
3777 if (dis) VG_(printf)("cld\n");
3778 break;
3779
3780 case 0xFD: /* STD */
3781 uInstr0(cb, CALLM_S, 0);
3782 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_STD));
3783 uFlagsRWU(cb, FlagsEmpty, FlagD, FlagsEmpty);
3784 uInstr0(cb, CALLM_E, 0);
3785 if (dis) VG_(printf)("std\n");
3786 break;
3787
3788 case 0xF2: { /* REPNE prefix insn */
3789 Addr eip_orig = eip - 1;
3790 abyte = getUChar(eip); eip++;
3791 if (abyte == 0x66) { sz = 2; abyte = getUChar(eip); eip++; }
3792
3793 if (abyte == 0xAE || 0xAF) { /* REPNE SCAS<sz> */
3794 if (abyte == 0xAE) sz = 1;
3795 codegen_REPNE_SCAS ( cb, sz, eip_orig, eip );
3796 *isEnd = True;
3797 if (dis) VG_(printf)("repne scas%c\n", nameISize(sz));
3798 }
3799 else {
3800 VG_(printf)("REPNE then 0x%x\n", (UInt)abyte);
3801 VG_(panic)("Unhandled REPNE case");
3802 }
3803 break;
3804 }
3805
3806 case 0xF3: { /* REPE prefix insn */
3807 Addr eip_orig = eip - 1;
3808 abyte = getUChar(eip); eip++;
3809 if (abyte == 0x66) { sz = 2; abyte = getUChar(eip); eip++; }
3810
3811 if (abyte == 0xA4 || abyte == 0xA5) { /* REPE MOV<sz> */
3812 if (abyte == 0xA4) sz = 1;
3813 codegen_REPE_MOVS ( cb, sz, eip_orig, eip );
3814 *isEnd = True;
3815 if (dis) VG_(printf)("repe mov%c\n", nameISize(sz));
3816 }
3817 else
3818 if (abyte == 0xA6 || abyte == 0xA7) { /* REPE CMP<sz> */
3819 if (abyte == 0xA6) sz = 1;
3820 codegen_REPE_CMPS ( cb, sz, eip_orig, eip );
3821 *isEnd = True;
3822 if (dis) VG_(printf)("repe cmps%c\n", nameISize(sz));
3823 }
3824 else
3825 if (abyte == 0xAA || abyte == 0xAB) { /* REPE STOS<sz> */
3826 if (abyte == 0xAA) sz = 1;
3827 codegen_REPE_STOS ( cb, sz, eip_orig, eip );
3828 *isEnd = True;
3829 if (dis) VG_(printf)("repe stos%c\n", nameISize(sz));
3830 } else {
3831 VG_(printf)("REPE then 0x%x\n", (UInt)abyte);
3832 VG_(panic)("Unhandled REPE case");
3833 }
3834 break;
3835 }
3836
3837 /* ------------------------ XCHG ----------------------- */
3838
3839 case 0x86: /* XCHG Gb,Eb */
3840 sz = 1;
3841 /* Fall through ... */
3842 case 0x87: /* XCHG Gv,Ev */
3843 modrm = getUChar(eip);
3844 t1 = newTemp(cb); t2 = newTemp(cb);
3845 if (epartIsReg(modrm)) {
3846 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
3847 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t2);
3848 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, gregOfRM(modrm));
3849 uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, eregOfRM(modrm));
3850 eip++;
3851 if (dis)
3852 VG_(printf)("xchg%c %s, %s\n", nameISize(sz),
3853 nameIReg(sz,gregOfRM(modrm)),
3854 nameIReg(sz,eregOfRM(modrm)));
3855 } else {
3856 pair = disAMode ( cb, eip, dis?dis_buf:NULL);
3857 t3 = LOW24(pair);
3858 uInstr2(cb, LOAD, sz, TempReg, t3, TempReg, t1);
3859 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t2);
3860 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t3);
3861 SMC_IF_SOME(cb);
3862 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, gregOfRM(modrm));
3863 eip += HI8(pair);
3864 if (dis)
3865 VG_(printf)("xchg%c %s, %s\n", nameISize(sz),
3866 nameIReg(sz,gregOfRM(modrm)),
3867 dis_buf);
3868 }
3869 break;
3870
3871 case 0x90: /* XCHG eAX,eAX */
3872 if (dis) VG_(printf)("nop\n");
3873 break;
3874 case 0x91: /* XCHG eCX,eSI */
3875 case 0x96: /* XCHG eAX,eSI */
3876 case 0x97: /* XCHG eAX,eDI */
3877 codegen_xchg_eAX_Reg ( cb, sz, opc - 0x90 );
3878 break;
3879
3880 /* ------------------------ (Grp1 extensions) ---------- */
3881
3882 case 0x80: /* Grp1 Ib,Eb */
3883 modrm = getUChar(eip);
3884 am_sz = lengthAMode(eip);
3885 sz = 1;
3886 d_sz = 1;
3887 d32 = getSDisp8(eip + am_sz);
3888 eip = dis_Grp1 ( cb, eip, modrm, am_sz, d_sz, sz, d32 );
3889 break;
3890
3891 case 0x81: /* Grp1 Iv,Ev */
3892 modrm = getUChar(eip);
3893 am_sz = lengthAMode(eip);
3894 d_sz = sz;
3895 d32 = getUDisp(d_sz, eip + am_sz);
3896 eip = dis_Grp1 ( cb, eip, modrm, am_sz, d_sz, sz, d32 );
3897 break;
3898
3899 case 0x83: /* Grp1 Ib,Ev */
3900 modrm = getUChar(eip);
3901 am_sz = lengthAMode(eip);
3902 d_sz = 1;
3903 d32 = getSDisp8(eip + am_sz);
3904 eip = dis_Grp1 ( cb, eip, modrm, am_sz, d_sz, sz, d32 );
3905 break;
3906
3907 /* ------------------------ (Grp2 extensions) ---------- */
3908
3909 case 0xC0: /* Grp2 Ib,Eb */
3910 modrm = getUChar(eip);
3911 am_sz = lengthAMode(eip);
3912 d_sz = 1;
3913 d32 = getSDisp8(eip + am_sz);
3914 sz = 1;
3915 eip = dis_Grp2 ( cb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
3916 break;
3917
3918 case 0xC1: /* Grp2 Ib,Ev */
3919 modrm = getUChar(eip);
3920 am_sz = lengthAMode(eip);
3921 d_sz = 1;
3922 d32 = getSDisp8(eip + am_sz);
3923 eip = dis_Grp2 ( cb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
3924 break;
3925
3926 case 0xD0: /* Grp2 1,Eb */
3927 modrm = getUChar(eip);
3928 am_sz = lengthAMode(eip);
3929 d_sz = 0;
3930 d32 = 1;
3931 sz = 1;
3932 eip = dis_Grp2 ( cb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
3933 break;
3934
3935 case 0xD1: /* Grp2 1,Ev */
3936 modrm = getUChar(eip);
3937 am_sz = lengthAMode(eip);
3938 d_sz = 0;
3939 d32 = 1;
3940 eip = dis_Grp2 ( cb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
3941 break;
3942
3943 case 0xD3: /* Grp2 CL,Ev */
3944 modrm = getUChar(eip);
3945 am_sz = lengthAMode(eip);
3946 d_sz = 0;
3947 eip = dis_Grp2 ( cb, eip, modrm, am_sz, d_sz, sz, ArchReg, R_ECX );
3948 break;
3949
3950 /* ------------------------ (Grp3 extensions) ---------- */
3951
3952 case 0xF6: /* Grp3 Eb */
3953 eip = dis_Grp3 ( cb, 1, eip );
3954 break;
3955 case 0xF7: /* Grp3 Ev */
3956 eip = dis_Grp3 ( cb, sz, eip );
3957 break;
3958
3959 /* ------------------------ (Grp4 extensions) ---------- */
3960
3961 case 0xFE: /* Grp4 Eb */
3962 eip = dis_Grp4 ( cb, eip );
3963 break;
3964
3965 /* ------------------------ (Grp5 extensions) ---------- */
3966
3967 case 0xFF: /* Grp5 Ev */
3968 eip = dis_Grp5 ( cb, sz, eip, isEnd );
3969 break;
3970
3971 /* ------------------------ Escapes to 2-byte opcodes -- */
3972
3973 case 0x0F: {
3974 opc = getUChar(eip); eip++;
3975 switch (opc) {
3976
3977 /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
3978
3979 case 0xBA: /* Grp8 Ib,Ev */
3980 modrm = getUChar(eip);
3981 am_sz = lengthAMode(eip);
3982 d32 = getSDisp8(eip + am_sz);
3983 eip = dis_Grp8 ( cb, eip, modrm, am_sz, sz, d32 );
3984 break;
3985
3986 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
3987
3988 case 0xBC: /* BSF Gv,Ev */
3989 eip = dis_bs_E_G ( cb, sz, eip, True );
3990 break;
3991 case 0xBD: /* BSR Gv,Ev */
3992 eip = dis_bs_E_G ( cb, sz, eip, False );
3993 break;
3994
3995 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
3996
3997 case 0xC8: /* BSWAP %eax */
3998 case 0xC9:
3999 case 0xCA:
4000 case 0xCB:
4001 case 0xCC:
4002 case 0xCD:
4003 case 0xCE:
4004 case 0xCF: /* BSWAP %edi */
4005 /* AFAICS from the Intel docs, this only exists at size 4. */
4006 vg_assert(sz == 4);
4007 t1 = newTemp(cb);
4008 uInstr2(cb, GET, 4, ArchReg, opc-0xC8, TempReg, t1);
4009 uInstr1(cb, BSWAP, 4, TempReg, t1);
4010 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, opc-0xC8);
4011 if (dis) VG_(printf)("bswapl %s\n", nameIReg(4, opc-0xC8));
4012 break;
4013
4014 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
4015
4016 case 0xA3: /* BT Gv,Ev */
4017 eip = dis_bt_G_E ( cb, sz, eip, BtOpNone );
4018 break;
4019 case 0xB3: /* BTR Gv,Ev */
4020 eip = dis_bt_G_E ( cb, sz, eip, BtOpReset );
4021 break;
4022 case 0xAB: /* BTS Gv,Ev */
4023 eip = dis_bt_G_E ( cb, sz, eip, BtOpSet );
4024 break;
4025 case 0xBB: /* BTC Gv,Ev */
4026 eip = dis_bt_G_E ( cb, sz, eip, BtOpComp );
4027 break;
4028
4029 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
4030
4031 case 0x40:
4032 case 0x41:
4033 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
4034 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
4035 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
4036 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
4037 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
4038 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
4039 case 0x48: /* CMOVSb (cmov negative) */
4040 case 0x49: /* CMOVSb (cmov not negative) */
4041 case 0x4A: /* CMOVP (cmov parity even) */
4042 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
4043 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
4044 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
4045 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
4046 eip = dis_cmov_E_G(cb, sz, (Condcode)(opc - 0x40), eip);
4047 break;
4048
4049 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
4050
4051 case 0xB1: /* CMPXCHG Gv,Ev */
4052 eip = dis_cmpxchg_G_E ( cb, sz, eip );
4053 break;
4054
4055 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
4056
4057 case 0xA2: /* CPUID */
4058 t1 = newTemp(cb);
4059 t2 = newTemp(cb);
4060 t3 = newTemp(cb);
4061 t4 = newTemp(cb);
4062 uInstr0(cb, CALLM_S, 0);
4063
4064 uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t1);
4065 uInstr1(cb, PUSH, 4, TempReg, t1);
4066
4067 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
4068 uLiteral(cb, 0);
4069 uInstr1(cb, PUSH, 4, TempReg, t2);
4070
4071 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t3);
4072 uLiteral(cb, 0);
4073 uInstr1(cb, PUSH, 4, TempReg, t3);
4074
4075 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
4076 uLiteral(cb, 0);
4077 uInstr1(cb, PUSH, 4, TempReg, t4);
4078
4079 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CPUID));
4080 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
4081
4082 uInstr1(cb, POP, 4, TempReg, t4);
4083 uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_EDX);
4084
4085 uInstr1(cb, POP, 4, TempReg, t3);
4086 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ECX);
4087
4088 uInstr1(cb, POP, 4, TempReg, t2);
4089 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBX);
4090
4091 uInstr1(cb, POP, 4, TempReg, t1);
4092 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
4093
4094 uInstr0(cb, CALLM_E, 0);
4095 if (dis) VG_(printf)("cpuid\n");
4096 break;
4097
4098 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
4099
4100 case 0xB6: /* MOVZXb Eb,Gv */
4101 eip = dis_movx_E_G ( cb, eip, 1, 4, False );
4102 break;
4103 case 0xB7: /* MOVZXw Ew,Gv */
4104 eip = dis_movx_E_G ( cb, eip, 2, 4, False );
4105 break;
4106
4107 case 0xBE: /* MOVSXb Eb,Gv */
4108 eip = dis_movx_E_G ( cb, eip, 1, 4, True );
4109 break;
4110 case 0xBF: /* MOVSXw Ew,Gv */
4111 eip = dis_movx_E_G ( cb, eip, 2, 4, True );
4112 break;
4113
4114 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
4115
4116 case 0xAF: /* IMUL Ev, Gv */
4117 eip = dis_mul_E_G ( cb, sz, eip, True );
4118 break;
4119
4120 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
4121 case 0x80:
4122 case 0x81:
4123 case 0x82: /* JBb/JNAEb (jump below) */
4124 case 0x83: /* JNBb/JAEb (jump not below) */
4125 case 0x84: /* JZb/JEb (jump zero) */
4126 case 0x85: /* JNZb/JNEb (jump not zero) */
4127 case 0x86: /* JBEb/JNAb (jump below or equal) */
4128 case 0x87: /* JNBEb/JAb (jump not below or equal) */
4129 case 0x88: /* JSb (jump negative) */
4130 case 0x89: /* JSb (jump not negative) */
4131 case 0x8A: /* JP (jump parity even) */
4132 case 0x8C: /* JLb/JNGEb (jump less) */
4133 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
4134 case 0x8E: /* JLEb/JNGb (jump less or equal) */
4135 case 0x8F: /* JGb/JNLEb (jump greater) */
4136 d32 = (eip+4) + getUDisp32(eip); eip += 4;
4137 uInstr1(cb, JMP, 0, Literal, 0);
4138 uLiteral(cb, d32);
4139 uCond(cb, (Condcode)(opc - 0x80));
4140 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
4141 uInstr1(cb, JMP, 0, Literal, 0);
4142 uLiteral(cb, eip);
4143 uCond(cb, CondAlways);
4144 *isEnd = True;
4145 if (dis)
4146 VG_(printf)("j%s-32 0x%x\n",
4147 VG_(nameCondcode)(opc - 0x80), d32);
4148 break;
4149
4150 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
4151
4152 case 0x31: /* RDTSC */
4153 t1 = newTemp(cb);
4154 t2 = newTemp(cb);
4155 t3 = newTemp(cb);
4156 uInstr0(cb, CALLM_S, 0);
4157 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
4158 uLiteral(cb, 0);
4159 uInstr1(cb, PUSH, 4, TempReg, t1);
4160 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
4161 uLiteral(cb, 0);
4162 uInstr1(cb, PUSH, 4, TempReg, t2);
4163 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_RDTSC));
4164 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
4165 uInstr1(cb, POP, 4, TempReg, t3);
4166 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EDX);
4167 uInstr1(cb, POP, 4, TempReg, t3);
4168 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EAX);
4169 uInstr0(cb, CALLM_E, 0);
4170 if (dis) VG_(printf)("rdtsc\n");
4171 break;
4172
4173 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
4174 case 0x90:
4175 case 0x91:
4176 case 0x92: /* set-Bb/set-NAEb (jump below) */
4177 case 0x93: /* set-NBb/set-AEb (jump not below) */
4178 case 0x94: /* set-Zb/set-Eb (jump zero) */
4179 case 0x95: /* set-NZb/set-NEb (jump not zero) */
4180 case 0x96: /* set-BEb/set-NAb (jump below or equal) */
4181 case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
4182 case 0x98: /* set-Sb (jump negative) */
4183 case 0x99: /* set-Sb (jump not negative) */
4184 case 0x9A: /* set-P (jump parity even) */
4185 case 0x9B: /* set-NP (jump parity odd) */
4186 case 0x9C: /* set-Lb/set-NGEb (jump less) */
4187 case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
4188 case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
4189 case 0x9F: /* set-Gb/set-NLEb (jump greater) */
4190 modrm = getUChar(eip);
4191 t1 = newTemp(cb);
4192 if (epartIsReg(modrm)) {
4193 eip++;
4194 uInstr1(cb, CC2VAL, 1, TempReg, t1);
4195 uCond(cb, (Condcode)(opc-0x90));
4196 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
4197 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, eregOfRM(modrm));
4198 if (dis) VG_(printf)("set%s %s\n",
4199 VG_(nameCondcode)(opc-0x90),
4200 nameIReg(1,eregOfRM(modrm)));
4201 } else {
4202 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
4203 t2 = LOW24(pair);
4204 eip += HI8(pair);
4205 uInstr1(cb, CC2VAL, 1, TempReg, t1);
4206 uCond(cb, (Condcode)(opc-0x90));
4207 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
4208 uInstr2(cb, STORE, 1, TempReg, t1, TempReg, t2);
4209 SMC_IF_ALL(cb);
4210 if (dis) VG_(printf)("set%s %s\n",
4211 VG_(nameCondcode)(opc-0x90),
4212 dis_buf);
4213 }
4214 break;
4215
4216 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
4217
4218 case 0xA4: /* SHLDv imm8,Gv,Ev */
4219 modrm = getUChar(eip);
4220 eip = dis_SHLRD_Gv_Ev (
4221 cb, eip, modrm, sz,
4222 Literal, getUChar(eip + lengthAMode(eip)),
4223 True );
4224 break;
4225 case 0xA5: /* SHLDv %cl,Gv,Ev */
4226 modrm = getUChar(eip);
4227 eip = dis_SHLRD_Gv_Ev (
4228 cb, eip, modrm, sz, ArchReg, R_CL, True );
4229 break;
4230
4231 case 0xAC: /* SHRDv imm8,Gv,Ev */
4232 modrm = getUChar(eip);
4233 eip = dis_SHLRD_Gv_Ev (
4234 cb, eip, modrm, sz,
4235 Literal, getUChar(eip + lengthAMode(eip)),
4236 False );
4237 break;
4238 case 0xAD: /* SHRDv %cl,Gv,Ev */
4239 modrm = getUChar(eip);
4240 eip = dis_SHLRD_Gv_Ev (
4241 cb, eip, modrm, sz, ArchReg, R_CL, False );
4242 break;
4243
4244 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
4245
4246 case 0xC1: /* XADD Gv,Ev */
4247 eip = dis_xadd_G_E ( cb, sz, eip );
4248 break;
4249
4250 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
4251
4252 default:
4253 VG_(printf)("disInstr: unhandled 2-byte opcode 0x%x\n",
4254 (UInt)opc);
4255 VG_(unimplemented)("unhandled x86 0x0F 2-byte opcode");
4256 }
4257
4258 break;
4259 }
4260
4261 /* ------------------------ ??? ------------------------ */
4262
4263 default:
4264 VG_(printf)("disInstr: unhandled opcode 0x%x then 0x%x\n",
4265 (UInt)opc, (UInt)getUChar(eip));
4266 VG_(panic)("unhandled x86 opcode");
4267 }
4268
4269 if (dis)
4270 VG_(printf)("\n");
4271 for (; first_uinstr < cb->used; first_uinstr++) {
4272 Bool sane = VG_(saneUInstr)(True, &cb->instrs[first_uinstr]);
4273 if (dis || !sane)
4274 VG_(ppUInstr)(sane ? first_uinstr : -1,
4275 &cb->instrs[first_uinstr]);
4276 vg_assert(sane);
4277 }
4278
4279 return eip;
4280}
4281
4282
4283/* Disassemble a complete basic block, starting at eip, and dumping
4284 the ucode into cb. Returns the size, in bytes, of the basic
4285 block. */
4286
4287Int VG_(disBB) ( UCodeBlock* cb, Addr eip0 )
4288{
4289 Addr eip = eip0;
4290 Bool isEnd = False;
4291 Bool block_sane;
4292 if (dis) VG_(printf)("\n");
4293
4294 if (VG_(clo_single_step)) {
4295 eip = disInstr ( cb, eip, &isEnd );
4296 uInstr1(cb, JMP, 0, Literal, 0);
4297 uLiteral(cb, eip);
4298 uCond(cb, CondAlways);
4299 if (dis) VG_(ppUInstr)(cb->used-1, &cb->instrs[cb->used-1]);
4300 } else {
4301 Int delta = 0;
4302 Addr eip2;
4303 while (True) {
4304 if (isEnd) break;
4305 eip2 = disInstr ( cb, eip, &isEnd );
4306 delta += (eip2 - eip);
4307 eip = eip2;
4308 if (delta > 4 && !isEnd) {
4309 uInstr1(cb, INCEIP, 0, Lit16, delta);
4310 if (dis) VG_(ppUInstr)(cb->used-1, &cb->instrs[cb->used-1]);
4311 delta = 0;
4312 }
4313 /* Split up giant basic blocks into pieces, so the
4314 translations fall within 64k. */
4315 if (eip - eip0 > 2000) {
4316 if (VG_(clo_verbosity) > 0)
4317 VG_(message)(Vg_DebugMsg,
4318 "Warning: splitting giant basic block into pieces");
4319 uInstr1(cb, JMP, 0, Literal, 0);
4320 uLiteral(cb, eip);
4321 uCond(cb, CondAlways);
4322 if (dis) VG_(ppUInstr)(cb->used-1, &cb->instrs[cb->used-1]);
4323 if (dis) VG_(printf)("\n");
4324 break;
4325 }
4326 if (dis) VG_(printf)("\n");
4327 }
4328 }
4329
4330 block_sane = VG_(saneUCodeBlock)(cb);
4331 if (!block_sane) {
4332 VG_(ppUCodeBlock)(cb, "block failing sanity check");
4333 vg_assert(block_sane);
4334 }
4335
4336 return eip - eip0;
4337}
4338
4339
4340/*--------------------------------------------------------------------*/
4341/*--- end vg_to_ucode.c ---*/
4342/*--------------------------------------------------------------------*/