blob: 382de0ceeeb43dd1d9c834deabc0d995999533e0 [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);
sewardj2e93c502002-04-12 11:12:52 +00001610 LAST_UINSTR(cb).jmpkind = JmpCall;
sewardjde4a1d02002-03-22 01:27:54 +00001611 *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);
sewardj2e93c502002-04-12 11:12:52 +00001657 LAST_UINSTR(cb).jmpkind = JmpCall;
sewardjde4a1d02002-03-22 01:27:54 +00001658 *isEnd = True;
1659 break;
1660 case 4: /* JMP Ev */
1661 uInstr1(cb, JMP, 0, TempReg, t1);
1662 uCond(cb, CondAlways);
1663 *isEnd = True;
1664 break;
1665 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{
sewardj4a7456e2002-03-24 13:52:19 +00002247 Bool sets_ZCP = False;
sewardjde4a1d02002-03-22 01:27:54 +00002248 UChar second_byte = getUChar(eip); eip++;
2249 vg_assert(second_byte >= 0xC0);
sewardj4a7456e2002-03-24 13:52:19 +00002250
2251 if (first_byte == 0xDB && second_byte >= 0xF0 && second_byte <= 0xF7) {
2252 /* FCOMI */
2253 sets_ZCP = True;
2254 } else
2255 if (first_byte == 0xDF && second_byte >= 0xF0 && second_byte <= 0xF7) {
2256 /* FCOMIP */
2257 sets_ZCP = True;
2258 } else
2259 if (first_byte == 0xDB && second_byte >= 0xE8 && second_byte <= 0xEF) {
2260 /* FUCOMI */
2261 sets_ZCP = True;
2262 } else
2263 if (first_byte == 0xDF && second_byte >= 0xE8 && second_byte <= 0xEF) {
2264 /* FUCOMIP */
2265 sets_ZCP = True;
2266 }
2267
sewardjde4a1d02002-03-22 01:27:54 +00002268 uInstr1(cb, FPU, 0,
2269 Lit16,
2270 (((UShort)first_byte) << 8) | ((UShort)second_byte)
2271 );
sewardj4a7456e2002-03-24 13:52:19 +00002272 if (sets_ZCP) {
2273 /* VG_(printf)("!!! --- FPU insn which writes %EFLAGS\n"); */
2274 uFlagsRWU(cb, FlagsEmpty, FlagsZCP, FlagsEmpty);
2275 }
2276
2277 if (dis) VG_(printf)("fpu 0x%x:0x%x%s\n",
2278 (UInt)first_byte, (UInt)second_byte,
2279 sets_ZCP ? " -wZCP" : "" );
sewardjde4a1d02002-03-22 01:27:54 +00002280 return eip;
2281}
2282
2283
2284/* Top-level handler for all FPU insns. On entry, eip points to the
2285 second byte of the insn. */
2286static
2287Addr dis_fpu ( UCodeBlock* cb, UChar first_byte, Addr eip )
2288{
2289 const Bool rd = False;
2290 const Bool wr = True;
2291 UChar second_byte = getUChar(eip);
2292
2293 /* Handle FSTSW %ax specially. */
2294 if (first_byte == 0xDF && second_byte == 0xE0) {
2295 Int t1 = newTemp(cb);
2296 uInstr0(cb, CALLM_S, 0);
2297 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
2298 uLiteral(cb, 0);
2299 uInstr1(cb, PUSH, 4, TempReg, t1);
2300 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_fstsw_AX) );
2301 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
2302 uInstr1(cb, POP, 2, TempReg, t1);
2303 uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
2304 uInstr0(cb, CALLM_E, 0);
2305 if (dis) VG_(printf)("fstsw %%ax\n");
2306 eip++;
2307 return eip;
2308 }
2309
2310 /* Handle all non-memory FPU ops simply. */
2311 if (second_byte >= 0xC0)
2312 return dis_fpu_no_mem ( cb, eip, first_byte );
2313
2314 /* The insn references memory; need to determine
2315 whether it reads or writes, and at what size. */
2316 switch (first_byte) {
2317
2318 case 0xD8:
2319 switch ((second_byte >> 3) & 7) {
2320 case 0: /* FADDs */
2321 case 1: /* FMULs */
2322 case 2: /* FCOMs */
2323 case 3: /* FCOMPs */
2324 case 4: /* FSUBs */
2325 case 5: /* FSUBRs */
2326 case 6: /* FDIVs */
2327 case 7: /* FDIVRs */
2328 return dis_fpu_mem(cb, 4, rd, eip, first_byte);
2329 default:
2330 goto unhandled;
2331 }
2332 break;
2333
2334 case 0xD9:
2335 switch ((second_byte >> 3) & 7) {
2336 case 0: /* FLDs */
2337 return dis_fpu_mem(cb, 4, rd, eip, first_byte);
2338 case 2: /* FSTs */
2339 case 3: /* FSTPs */
2340 return dis_fpu_mem(cb, 4, wr, eip, first_byte);
2341 case 5: /* FLDCW */
2342 return dis_fpu_mem(cb, 2, rd, eip, first_byte);
2343 case 7: /* FSTCW */
2344 /* HACK! FSTCW actually writes 2 bytes, not 4. glibc
2345 gets lots of moaning in __floor() if we do the right
2346 thing here. */
2347 /* Later ... hack disabled .. we do do the Right Thing. */
2348 return dis_fpu_mem(cb, /*4*/ 2, wr, eip, first_byte);
2349 default:
2350 goto unhandled;
2351 }
2352 break;
2353
2354 case 0xDA:
2355 switch ((second_byte >> 3) & 7) {
2356 case 0: /* FIADD */
2357 case 1: /* FIMUL */
2358 case 2: /* FICOM */
2359 case 3: /* FICOMP */
2360 case 4: /* FISUB */
2361 case 5: /* FISUBR */
2362 case 6: /* FIDIV */
2363 case 7: /* FIDIVR */
2364 return dis_fpu_mem(cb, 4, rd, eip, first_byte);
2365 default:
2366 goto unhandled;
2367 }
2368 break;
2369
2370 case 0xDB:
2371 switch ((second_byte >> 3) & 7) {
2372 case 0: /* FILD dword-integer */
2373 return dis_fpu_mem(cb, 4, rd, eip, first_byte);
2374 case 2: /* FIST dword-integer */
2375 return dis_fpu_mem(cb, 4, wr, eip, first_byte);
2376 case 3: /* FISTPl */
2377 return dis_fpu_mem(cb, 4, wr, eip, first_byte);
2378 case 5: /* FLD extended-real */
2379 return dis_fpu_mem(cb, 10, rd, eip, first_byte);
2380 case 7: /* FSTP extended-real */
2381 return dis_fpu_mem(cb, 10, wr, eip, first_byte);
2382 default:
2383 goto unhandled;
2384 }
2385 break;
2386
2387 case 0xDC:
2388 switch ((second_byte >> 3) & 7) {
2389 case 0: /* FADD double-real */
2390 case 1: /* FMUL double-real */
2391 case 2: /* FCOM double-real */
2392 case 3: /* FCOMP double-real */
2393 case 4: /* FSUB double-real */
2394 case 5: /* FSUBR double-real */
2395 case 6: /* FDIV double-real */
2396 case 7: /* FDIVR double-real */
2397 return dis_fpu_mem(cb, 8, rd, eip, first_byte);
2398 default:
2399 goto unhandled;
2400 }
2401 break;
2402
2403 case 0xDD:
2404 switch ((second_byte >> 3) & 7) {
2405 case 0: /* FLD double-real */
2406 return dis_fpu_mem(cb, 8, rd, eip, first_byte);
2407 case 2: /* FST double-real */
2408 case 3: /* FSTP double-real */
2409 return dis_fpu_mem(cb, 8, wr, eip, first_byte);
2410 default:
2411 goto unhandled;
2412 }
2413 break;
2414
2415 case 0xDF:
2416 switch ((second_byte >> 3) & 7) {
2417 case 0: /* FILD word-integer */
2418 return dis_fpu_mem(cb, 2, rd, eip, first_byte);
2419 case 2: /* FIST word-integer */
2420 return dis_fpu_mem(cb, 2, wr, eip, first_byte);
2421 case 3: /* FISTP word-integer */
2422 return dis_fpu_mem(cb, 2, wr, eip, first_byte);
2423 case 5: /* FILD qword-integer */
2424 return dis_fpu_mem(cb, 8, rd, eip, first_byte);
2425 case 7: /* FISTP qword-integer */
2426 return dis_fpu_mem(cb, 8, wr, eip, first_byte);
2427 default:
2428 goto unhandled;
2429 }
2430 break;
2431
2432 default: goto unhandled;
2433 }
2434
2435 unhandled:
2436 VG_(printf)("dis_fpu: unhandled memory case 0x%2x:0x%2x(%d)\n",
2437 (UInt)first_byte, (UInt)second_byte,
2438 (UInt)((second_byte >> 3) & 7) );
2439 VG_(panic)("dis_fpu: unhandled opcodes");
2440}
2441
2442
2443/* Double length left shifts. Apparently only required in v-size (no
2444 b- variant). */
2445static
2446Addr dis_SHLRD_Gv_Ev ( UCodeBlock* cb, Addr eip, UChar modrm,
2447 Int sz,
2448 Tag amt_tag, UInt amt_val,
2449 Bool left_shift )
2450{
2451 /* amt_tag and amt_val denote either ArchReg(%CL) or a Literal.
2452 And eip on entry points at the modrm byte. */
2453 Int t, t1, t2, ta, helper;
2454 UInt pair;
2455 UChar dis_buf[50];
2456
2457 vg_assert(sz == 2 || sz == 4);
2458
2459 helper = left_shift
2460 ? (sz==4 ? VGOFF_(helper_shldl)
2461 : VGOFF_(helper_shldw))
2462 : (sz==4 ? VGOFF_(helper_shrdl)
2463 : VGOFF_(helper_shrdw));
2464
2465 /* Get the amount to be shifted by onto the stack. */
2466 t = newTemp(cb);
2467 t1 = newTemp(cb);
2468 t2 = newTemp(cb);
2469 if (amt_tag == ArchReg) {
2470 vg_assert(amt_val == R_CL);
2471 uInstr2(cb, GET, 1, ArchReg, amt_val, TempReg, t);
2472 } else {
2473 uInstr2(cb, MOV, 1, Literal, 0, TempReg, t);
2474 uLiteral(cb, amt_val);
2475 }
2476
2477 uInstr0(cb, CALLM_S, 0);
2478 uInstr1(cb, PUSH, 1, TempReg, t);
2479
2480 /* The E-part is the destination; this is shifted. The G-part
2481 supplies bits to be shifted into the E-part, but is not
2482 changed. */
2483
2484 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t1);
2485 uInstr1(cb, PUSH, sz, TempReg, t1);
2486
2487 if (epartIsReg(modrm)) {
2488 eip++;
2489 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t2);
2490 uInstr1(cb, PUSH, sz, TempReg, t2);
2491 uInstr1(cb, CALLM, 0, Lit16, helper);
2492 uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
2493 uInstr1(cb, POP, sz, TempReg, t);
2494 uInstr2(cb, PUT, sz, TempReg, t, ArchReg, eregOfRM(modrm));
2495 if (dis)
2496 VG_(printf)("shld%c %%cl, %s, %s\n",
2497 nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
2498 nameIReg(sz, eregOfRM(modrm)));
2499 } else {
2500 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
2501 ta = LOW24(pair);
2502 eip += HI8(pair);
2503 uInstr2(cb, LOAD, sz, TempReg, ta, TempReg, t2);
2504 uInstr1(cb, PUSH, sz, TempReg, t2);
2505 uInstr1(cb, CALLM, 0, Lit16, helper);
2506 uFlagsRWU(cb, FlagsEmpty, FlagsOSZACP, FlagsEmpty);
2507 uInstr1(cb, POP, sz, TempReg, t);
2508 uInstr2(cb, STORE, sz, TempReg, t, TempReg, ta);
2509 SMC_IF_ALL(cb);
2510 if (dis)
2511 VG_(printf)("shld%c %%cl, %s, %s\n",
2512 nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
2513 dis_buf);
2514 }
2515
2516 if (amt_tag == Literal) eip++;
2517 uInstr1(cb, CLEAR, 0, Lit16, 8);
2518
2519 uInstr0(cb, CALLM_E, 0);
2520 return eip;
2521}
2522
2523
2524/* Handle BT/BTS/BTR/BTC Gv, Ev. Apparently b-size is not
2525 required. */
2526
2527typedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
2528
2529static Char* nameBtOp ( BtOp op )
2530{
2531 switch (op) {
2532 case BtOpNone: return "";
2533 case BtOpSet: return "s";
2534 case BtOpReset: return "r";
2535 case BtOpComp: return "c";
2536 default: VG_(panic)("nameBtOp");
2537 }
2538}
2539
sewardj7f2a8bf2002-04-15 14:35:28 +00002540#if 0
sewardjde4a1d02002-03-22 01:27:54 +00002541static
2542Addr dis_bt_G_E ( UCodeBlock* cb, Int sz, Addr eip, BtOp op )
2543{
2544 Int t, t2, ta, helper;
2545 UInt pair;
2546 UChar dis_buf[50];
2547 UChar modrm;
2548
2549 vg_assert(sz == 2 || sz == 4);
2550 vg_assert(sz == 4);
2551 switch (op) {
2552 case BtOpNone: helper = VGOFF_(helper_bt); break;
2553 case BtOpSet: helper = VGOFF_(helper_bts); break;
2554 case BtOpReset: helper = VGOFF_(helper_btr); break;
2555 case BtOpComp: helper = VGOFF_(helper_btc); break;
2556 default: VG_(panic)("dis_bt_G_E");
2557 }
2558
2559 modrm = getUChar(eip);
2560
2561 t = newTemp(cb);
2562 t2 = newTemp(cb);
2563 uInstr0(cb, CALLM_S, 0);
2564 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t);
2565 uInstr1(cb, PUSH, sz, TempReg, t);
2566
2567 if (epartIsReg(modrm)) {
2568 eip++;
2569 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t2);
2570 uInstr1(cb, PUSH, sz, TempReg, t2);
2571 uInstr1(cb, CALLM, 0, Lit16, helper);
2572 uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
2573 uInstr1(cb, POP, sz, TempReg, t);
2574 uInstr2(cb, PUT, sz, TempReg, t, ArchReg, eregOfRM(modrm));
2575 if (dis)
2576 VG_(printf)("bt%s%c %s, %s\n",
2577 nameBtOp(op),
2578 nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
2579 nameIReg(sz, eregOfRM(modrm)));
2580 } else {
2581 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
2582 ta = LOW24(pair);
2583 eip += HI8(pair);
2584 uInstr2(cb, LOAD, sz, TempReg, ta, TempReg, t2);
2585 uInstr1(cb, PUSH, sz, TempReg, t2);
2586 uInstr1(cb, CALLM, 0, Lit16, helper);
2587 uFlagsRWU(cb, FlagsEmpty, FlagC, FlagsOSZAP);
2588 uInstr1(cb, POP, sz, TempReg, t);
2589 uInstr2(cb, STORE, sz, TempReg, t, TempReg, ta);
2590 SMC_IF_ALL(cb);
2591 if (dis)
2592 VG_(printf)("bt%s%c %s, %s\n",
2593 nameBtOp(op),
2594 nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
2595 dis_buf);
2596 }
2597
2598 uInstr1(cb, CLEAR, 0, Lit16, 4);
2599 uInstr0(cb, CALLM_E, 0);
2600
2601 return eip;
2602}
sewardj7f2a8bf2002-04-15 14:35:28 +00002603#endif
2604
2605
2606static
2607Addr dis_bt_G_E ( UCodeBlock* cb, Int sz, Addr eip, BtOp op )
2608{
2609 UInt pair;
2610 UChar dis_buf[50];
2611 UChar modrm;
2612
2613 Int t_addr, t_bitno, t_mask, t_fetched, t_esp, temp, lit;
2614
2615 /* 2 and 4 are actually possible. */
2616 vg_assert(sz == 2 || sz == 4);
2617 /* We only handle 4. */
2618 vg_assert(sz == 4);
2619
2620 t_addr = t_bitno = t_mask
2621 = t_fetched = t_esp = temp = INVALID_TEMPREG;
2622
2623 t_fetched = newTemp(cb);
2624 t_bitno = newTemp(cb);
2625 temp = newTemp(cb);
2626 lit = newTemp(cb);
2627
2628 modrm = getUChar(eip);
2629
2630 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t_bitno);
2631
2632 if (epartIsReg(modrm)) {
2633 eip++;
2634 /* Get it onto the client's stack. */
2635 t_esp = newTemp(cb);
2636 t_addr = newTemp(cb);
2637 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t_esp);
2638 uInstr2(cb, SUB, sz, Literal, 0, TempReg, t_esp);
2639 uLiteral(cb, sz);
2640 uInstr2(cb, PUT, 4, TempReg, t_esp, ArchReg, R_ESP);
2641 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, temp);
2642 uInstr2(cb, STORE, sz, TempReg, temp, TempReg, t_esp);
2643 /* Make ta point at it. */
2644 uInstr2(cb, MOV, 4, TempReg, t_esp, TempReg, t_addr);
2645 /* Mask out upper bits of the shift amount, since we're doing a
2646 reg. */
2647 uInstr2(cb, MOV, 4, Literal, 0, TempReg, lit);
2648 uLiteral(cb, sz == 4 ? 31 : 15);
2649 uInstr2(cb, AND, 4, TempReg, lit, TempReg, t_bitno);
2650 } else {
2651 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
2652 t_addr = LOW24(pair);
2653 eip += HI8(pair);
2654 }
2655
2656 /* At this point: ta points to the address being operated on. If
2657 it was a reg, we will have pushed it onto the client's stack.
2658 t_bitno is the bit number, suitable masked in the case of a reg. */
2659
2660 /* Now the main sequence. */
2661
2662 uInstr2(cb, MOV, 4, TempReg, t_bitno, TempReg, temp);
2663 uInstr2(cb, SAR, 4, Literal, 0, TempReg, temp);
2664 uLiteral(cb, 3);
2665 uInstr2(cb, ADD, 4, TempReg, temp, TempReg, t_addr);
2666 /* ta now holds effective address */
2667
2668 uInstr2(cb, MOV, 4, Literal, 0, TempReg, lit);
2669 uLiteral(cb, 7);
2670 uInstr2(cb, AND, 4, TempReg, lit, TempReg, t_bitno);
2671 /* bitno contains offset of bit within byte */
2672
2673 if (op != BtOpNone) {
2674 t_mask = newTemp(cb);
2675 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_mask);
2676 uLiteral(cb, 1);
2677 uInstr2(cb, SHL, 4, TempReg, t_bitno, TempReg, t_mask);
2678 }
2679 /* mask is now a suitable byte mask */
2680
2681 uInstr2(cb, LOAD, 1, TempReg, t_addr, TempReg, t_fetched);
2682 if (op != BtOpNone) {
2683 uInstr2(cb, MOV, 4, TempReg, t_fetched, TempReg, temp);
2684 switch (op) {
2685 case BtOpSet:
2686 uInstr2(cb, OR, 4, TempReg, t_mask, TempReg, temp);
2687 break;
2688 case BtOpComp:
2689 uInstr2(cb, XOR, 4, TempReg, t_mask, TempReg, temp);
2690 break;
2691 case BtOpReset:
2692 uInstr1(cb, NOT, 4, TempReg, t_mask);
2693 uInstr2(cb, AND, 4, TempReg, t_mask, TempReg, temp);
2694 break;
2695 default:
2696 VG_(panic)("dis_bt_G_E");
2697 }
2698 uInstr2(cb, STORE, 1, TempReg, temp, TempReg, t_addr);
2699 }
2700
2701 /* Side effect done; now get selected bit into Carry flag */
2702
2703 uInstr2(cb, SHR, 4, TempReg, t_bitno, TempReg, t_fetched);
2704 /* at bit 0 of fetched */
2705
2706 uInstr2(cb, MOV, 4, Literal, 0, TempReg, lit);
2707 uLiteral(cb, 1);
2708 uInstr2(cb, AND, 4, TempReg, lit, TempReg, t_fetched);
2709 /* fetched is now 1 or 0 */
2710
2711 /* NEG is a handy way to convert zero/nonzero into the carry
2712 flag. */
2713 uInstr1(cb, NEG, 4, TempReg, t_fetched);
2714 setFlagsFromUOpcode(cb, NEG);
2715 /* fetched is now in carry flag */
2716
2717 /* Move reg operand from stack back to reg */
2718 if (epartIsReg(modrm)) {
2719 /* t_esp still points at it. */
2720 uInstr2(cb, LOAD, sz, TempReg, t_esp, TempReg, temp);
2721 uInstr2(cb, PUT, sz, TempReg, temp, ArchReg, eregOfRM(modrm));
2722 uInstr2(cb, ADD, sz, Literal, 0, TempReg, t_esp);
2723 uLiteral(cb, sz);
2724 uInstr2(cb, PUT, 4, TempReg, t_esp, ArchReg, R_ESP);
2725 }
2726
2727 if (epartIsReg(modrm)) {
2728 if (dis)
2729 VG_(printf)("bt%s%c %s, %s\n",
2730 nameBtOp(op),
2731 nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
2732 nameIReg(sz, eregOfRM(modrm)));
2733 } else {
2734 if (dis)
2735 VG_(printf)("bt%s%c %s, %s\n",
2736 nameBtOp(op),
2737 nameISize(sz), nameIReg(sz, gregOfRM(modrm)),
2738 dis_buf);
2739 }
2740
2741 return eip;
2742}
2743
2744
sewardjde4a1d02002-03-22 01:27:54 +00002745
2746
2747/* Handle BSF/BSR. Only v-size seems necessary. */
2748static
2749Addr dis_bs_E_G ( UCodeBlock* cb, Int sz, Addr eip, Bool fwds )
2750{
2751 Int t, ta, helper;
2752 UInt pair;
2753 UChar dis_buf[50];
2754 UChar modrm;
2755
2756 vg_assert(sz == 2 || sz == 4);
2757 vg_assert(sz==4);
2758
2759 helper = fwds ? VGOFF_(helper_bsf) : VGOFF_(helper_bsr);
2760 modrm = getUChar(eip);
2761 t = newTemp(cb);
2762
2763 if (epartIsReg(modrm)) {
2764 eip++;
2765 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t);
2766 if (dis)
2767 VG_(printf)("bs%c%c %s, %s\n",
2768 fwds ? 'f' : 'r',
2769 nameISize(sz), nameIReg(sz, eregOfRM(modrm)),
2770 nameIReg(sz, gregOfRM(modrm)));
2771 } else {
2772 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
2773 ta = LOW24(pair);
2774 eip += HI8(pair);
2775 uInstr2(cb, LOAD, sz, TempReg, ta, TempReg, t);
2776 if (dis)
2777 VG_(printf)("bs%c%c %s, %s\n",
2778 fwds ? 'f' : 'r',
2779 nameISize(sz), dis_buf,
2780 nameIReg(sz, gregOfRM(modrm)));
2781 }
2782
2783 uInstr0(cb, CALLM_S, 0);
2784 uInstr1(cb, PUSH, sz, TempReg, t);
2785 uInstr1(cb, CALLM, 0, Lit16, helper);
2786 uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsOSACP);
2787 uInstr1(cb, POP, sz, TempReg, t);
2788 uInstr2(cb, PUT, sz, TempReg, t, ArchReg, gregOfRM(modrm));
2789 uInstr0(cb, CALLM_E, 0);
2790
2791 return eip;
2792}
2793
2794
2795static
2796void codegen_xchg_eAX_Reg ( UCodeBlock* cb, Int sz, Int reg )
2797{
2798 Int t1, t2;
2799 vg_assert(sz == 2 || sz == 4);
2800 t1 = newTemp(cb);
2801 t2 = newTemp(cb);
2802 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
2803 uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t2);
2804 uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, R_EAX);
2805 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
2806 if (dis)
2807 VG_(printf)("xchg%c %s, %s\n", nameISize(sz),
2808 nameIReg(sz, R_EAX), nameIReg(sz, reg));
2809}
2810
2811
2812static
2813void codegen_SAHF ( UCodeBlock* cb )
2814{
sewardj3a72df02002-03-24 10:03:17 +00002815 Int t = newTemp(cb);
2816 Int t2 = newTemp(cb);
sewardjde4a1d02002-03-22 01:27:54 +00002817 uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t);
sewardj3a72df02002-03-24 10:03:17 +00002818
2819 /* Mask out parts of t not corresponding to %AH. This stops the
2820 instrumenter complaining if they are undefined. Otherwise, the
2821 instrumenter would check all 32 bits of t at the PUSH, which
2822 could be the cause of incorrect warnings. Discovered by Daniel
2823 Veillard <veillard@redhat.com>.
2824 */
2825 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
2826 uLiteral(cb, 0x0000FF00);
2827 uInstr2(cb, AND, 4, TempReg, t2, TempReg, t);
2828 /* We deliberately don't set the condition codes here, since this
2829 AND is purely internal to Valgrind and nothing to do with the
2830 client's state. */
2831
sewardjde4a1d02002-03-22 01:27:54 +00002832 uInstr0(cb, CALLM_S, 0);
2833 uInstr1(cb, PUSH, 4, TempReg, t);
2834 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_SAHF));
2835 uFlagsRWU(cb, FlagsEmpty, FlagsSZACP, FlagsEmpty);
2836 uInstr1(cb, CLEAR, 0, Lit16, 4);
2837 uInstr0(cb, CALLM_E, 0);
2838}
2839
2840
2841static
2842Addr dis_cmpxchg_G_E ( UCodeBlock* cb,
2843 Int size,
2844 Addr eip0 )
2845{
2846 Int ta, junk, dest, src, acc;
2847 UChar dis_buf[50];
2848 UChar rm;
2849
2850 rm = getUChar(eip0);
2851 acc = newTemp(cb);
2852 src = newTemp(cb);
2853 dest = newTemp(cb);
2854 junk = newTemp(cb);
2855 /* Only needed to get gcc's dataflow analyser off my back. */
2856 ta = INVALID_TEMPREG;
2857
2858 if (epartIsReg(rm)) {
2859 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, dest);
2860 eip0++;
2861 if (dis) VG_(printf)("cmpxchg%c %s,%s\n",
2862 nameISize(size),
2863 nameIReg(size,gregOfRM(rm)),
2864 nameIReg(size,eregOfRM(rm)) );
2865 nameIReg(size,eregOfRM(rm));
2866 } else {
2867 UInt pair = disAMode ( cb, eip0, dis?dis_buf:NULL );
2868 ta = LOW24(pair);
2869 uInstr2(cb, LOAD, size, TempReg, ta, TempReg, dest);
2870 eip0 += HI8(pair);
2871 if (dis) VG_(printf)("cmpxchg%c %s,%s\n", nameISize(size),
2872 nameIReg(size,gregOfRM(rm)), dis_buf);
2873 }
2874
2875 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, src);
2876 uInstr2(cb, GET, size, ArchReg, R_EAX, TempReg, acc);
2877 uInstr2(cb, MOV, size, TempReg, acc, TempReg, junk);
2878 uInstr2(cb, SUB, size, TempReg, dest, TempReg, junk);
2879 setFlagsFromUOpcode(cb, SUB);
2880
2881 uInstr2(cb, CMOV, 4, TempReg, src, TempReg, dest);
2882 uCond(cb, CondZ);
2883 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
2884 uInstr2(cb, CMOV, 4, TempReg, dest, TempReg, acc);
2885 uCond(cb, CondNZ);
2886 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
2887
2888 uInstr2(cb, PUT, size, TempReg, acc, ArchReg, R_EAX);
2889 if (epartIsReg(rm)) {
2890 uInstr2(cb, PUT, size, TempReg, dest, ArchReg, eregOfRM(rm));
2891 } else {
2892 uInstr2(cb, STORE, size, TempReg, dest, TempReg, ta);
2893 }
2894
2895 return eip0;
2896}
2897
2898
2899/* Handle conditional move instructions of the form
2900 cmovcc E(reg-or-mem), G(reg)
2901
2902 E(src) is reg-or-mem
2903 G(dst) is reg.
2904
2905 If E is reg, --> GET %E, tmps
2906 GET %G, tmpd
2907 CMOVcc tmps, tmpd
2908 PUT tmpd, %G
2909
2910 If E is mem --> (getAddr E) -> tmpa
2911 LD (tmpa), tmps
2912 GET %G, tmpd
2913 CMOVcc tmps, tmpd
2914 PUT tmpd, %G
2915*/
2916static
2917Addr dis_cmov_E_G ( UCodeBlock* cb,
2918 Int size,
2919 Condcode cond,
2920 Addr eip0 )
2921{
2922 UChar rm = getUChar(eip0);
2923 UChar dis_buf[50];
2924
2925 Int tmps = newTemp(cb);
2926 Int tmpd = newTemp(cb);
2927
2928 if (epartIsReg(rm)) {
2929 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, tmps);
2930 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmpd);
2931 uInstr2(cb, CMOV, 4, TempReg, tmps, TempReg, tmpd);
2932 uCond(cb, cond);
2933 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
2934 uInstr2(cb, PUT, size, TempReg, tmpd, ArchReg, gregOfRM(rm));
2935 if (dis) VG_(printf)("cmov%c%s %s,%s\n",
2936 nameISize(size),
2937 VG_(nameCondcode)(cond),
2938 nameIReg(size,eregOfRM(rm)),
2939 nameIReg(size,gregOfRM(rm)));
2940 return 1+eip0;
2941 }
2942
2943 /* E refers to memory */
2944 {
2945 UInt pair = disAMode ( cb, eip0, dis?dis_buf:NULL);
2946 Int tmpa = LOW24(pair);
2947 uInstr2(cb, LOAD, size, TempReg, tmpa, TempReg, tmps);
2948 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmpd);
2949 uInstr2(cb, CMOV, 4, TempReg, tmps, TempReg, tmpd);
2950 uCond(cb, cond);
2951 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
2952 uInstr2(cb, PUT, size, TempReg, tmpd, ArchReg, gregOfRM(rm));
2953 if (dis) VG_(printf)("cmov%c%s %s,%s\n",
2954 nameISize(size),
2955 VG_(nameCondcode)(cond),
2956 dis_buf,
2957 nameIReg(size,gregOfRM(rm)));
2958 return HI8(pair)+eip0;
2959 }
2960}
2961
2962
2963static
2964Addr dis_xadd_G_E ( UCodeBlock* cb,
2965 Int sz,
2966 Addr eip0 )
2967{
2968 UChar rm = getUChar(eip0);
2969 UChar dis_buf[50];
2970
2971 Int tmpd = newTemp(cb);
2972 Int tmpt = newTemp(cb);
2973
2974 if (epartIsReg(rm)) {
2975 uInstr2(cb, GET, sz, ArchReg, eregOfRM(rm), TempReg, tmpd);
2976 uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
2977 uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
2978 setFlagsFromUOpcode(cb, ADD);
2979 uInstr2(cb, PUT, sz, TempReg, tmpt, ArchReg, eregOfRM(rm));
2980 uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
2981 if (dis)
2982 VG_(printf)("xadd%c %s, %s\n", nameISize(sz),
2983 nameIReg(sz,gregOfRM(rm)),
2984 nameIReg(sz,eregOfRM(rm)));
2985 return 1+eip0;
2986 } else {
2987 UInt pair = disAMode ( cb, eip0, dis?dis_buf:NULL);
2988 Int tmpa = LOW24(pair);
2989 uInstr2(cb, LOAD, sz, TempReg, tmpa, TempReg, tmpd);
2990 uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
2991 uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
2992 setFlagsFromUOpcode(cb, ADD);
2993 uInstr2(cb, STORE, sz, TempReg, tmpt, TempReg, tmpa);
2994 SMC_IF_SOME(cb);
2995 uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
2996 if (dis)
2997 VG_(printf)("xadd%c %s, %s\n", nameISize(sz),
2998 nameIReg(sz,gregOfRM(rm)),
2999 dis_buf);
3000 return HI8(pair)+eip0;
3001 }
3002}
3003
3004
sewardjde4a1d02002-03-22 01:27:54 +00003005/*------------------------------------------------------------*/
3006/*--- Disassembling entire basic blocks ---*/
3007/*------------------------------------------------------------*/
3008
3009/* Disassemble a single instruction into ucode, returning the update
3010 eip, and setting *isEnd to True if this is the last insn in a basic
3011 block. Also do debug printing if (dis). */
3012
3013static Addr disInstr ( UCodeBlock* cb, Addr eip, Bool* isEnd )
3014{
3015 UChar opc, modrm, abyte;
3016 UInt d32, pair;
3017 Int t1, t2, t3, t4;
3018 UChar dis_buf[50];
3019 Int am_sz, d_sz;
3020
3021 Int sz = 4;
3022 Int first_uinstr = cb->used;
3023 *isEnd = False;
3024 t1 = t2 = t3 = t4 = INVALID_TEMPREG;
3025
3026 if (dis) VG_(printf)("\t0x%x: ", eip);
3027
3028 /* Spot the client-request magic sequence, if required. */
sewardj2e93c502002-04-12 11:12:52 +00003029 if (1 /*VG_(clo_client_perms)*/) {
sewardjde4a1d02002-03-22 01:27:54 +00003030 UChar* myeip = (UChar*)eip;
3031 /* Spot this:
3032 C1C01D roll $29, %eax
3033 C1C003 roll $3, %eax
sewardj2e93c502002-04-12 11:12:52 +00003034 C1C81B rorl $27, %eax
3035 C1C805 rorl $5, %eax
3036 C1C00D roll $13, %eax
3037 C1C013 roll $19, %eax
sewardjde4a1d02002-03-22 01:27:54 +00003038 */
sewardj2e93c502002-04-12 11:12:52 +00003039 if (myeip[ 0] == 0xC1 && myeip[ 1] == 0xC0 && myeip[ 2] == 0x1D &&
3040 myeip[ 3] == 0xC1 && myeip[ 4] == 0xC0 && myeip[ 5] == 0x03 &&
3041 myeip[ 6] == 0xC1 && myeip[ 7] == 0xC8 && myeip[ 8] == 0x1B &&
3042 myeip[ 9] == 0xC1 && myeip[10] == 0xC8 && myeip[11] == 0x05 &&
3043 myeip[12] == 0xC1 && myeip[13] == 0xC0 && myeip[14] == 0x0D &&
3044 myeip[15] == 0xC1 && myeip[16] == 0xC0 && myeip[17] == 0x13
3045 ) {
3046 eip += 18;
3047 uInstr1(cb, JMP, 0, Literal, 0);
3048 uLiteral(cb, eip);
3049 uCond(cb, CondAlways);
3050 LAST_UINSTR(cb).jmpkind = JmpClientReq;
3051 *isEnd = True;
3052 if (dis)
3053 VG_(printf)("%%edx = client_request ( %%eax )\n");
sewardjde4a1d02002-03-22 01:27:54 +00003054 return eip;
3055 }
3056 }
3057
3058 /* Skip a LOCK prefix. */
3059 if (getUChar(eip) == 0xF0) eip++;
3060
3061 /* Crap out if we see a segment override prefix. */
3062 if (getUChar(eip) == 0x65) {
3063 VG_(message)(Vg_DebugMsg, "");
3064 VG_(message)(Vg_DebugMsg, "Possible workaround for the following abort: do not use special");
3065 VG_(message)(Vg_DebugMsg, "PII/PIII-specific pthreads library (possibly in /lib/i686/*.so).");
3066 VG_(message)(Vg_DebugMsg, "You might be able to kludge around this by renaming /lib/i686 to");
3067 VG_(message)(Vg_DebugMsg, "/lib/i686-HIDDEN. On RedHat 7.2 this causes ld.so to fall back");
3068 VG_(message)(Vg_DebugMsg, "to using the less specialised versions in /lib instead, which");
3069 VG_(message)(Vg_DebugMsg, "valgrind might be able to better deal with.");
3070 VG_(message)(Vg_DebugMsg, "");
3071 VG_(message)(Vg_DebugMsg, "WARNING. WARNING. WARNING. WARNING. WARNING. WARNING. WARNING.");
3072 VG_(message)(Vg_DebugMsg, "WARNING: The suggested kludge may also render your system unbootable");
3073 VG_(message)(Vg_DebugMsg, "WARNING: or otherwise totally screw it up. Only try this if you");
3074 VG_(message)(Vg_DebugMsg, "WARNING: know what you are doing, and are prepared to take risks.");
3075 VG_(message)(Vg_DebugMsg, "YOU HAVE BEEN WARNED. YOU HAVE BEEN WARNED. YOU HAVE BEEN WARNED.");
3076 VG_(message)(Vg_DebugMsg, "");
3077 VG_(message)(Vg_DebugMsg, "Another consideration is that this may well mean your application");
3078 VG_(message)(Vg_DebugMsg, "uses threads, which valgrind doesn't currently support, so even if");
3079 VG_(message)(Vg_DebugMsg, "you work around this problem, valgrind may abort later if it sees");
3080 VG_(message)(Vg_DebugMsg, "a clone() system call.");
3081 VG_(unimplemented)("x86 segment override (SEG=GS) prefix; see above for details");
3082 }
3083
3084 /* Detect operand-size overrides. */
3085 if (getUChar(eip) == 0x66) { sz = 2; eip++; };
3086
3087 opc = getUChar(eip); eip++;
3088
3089 switch (opc) {
3090
3091 /* ------------------------ Control flow --------------- */
3092
3093 case 0xC2: /* RET imm16 */
3094 d32 = getUDisp16(eip); eip += 2;
3095 goto do_Ret;
3096 case 0xC3: /* RET */
3097 d32 = 0;
3098 goto do_Ret;
3099 do_Ret:
3100 t1 = newTemp(cb); t2 = newTemp(cb);
3101 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
3102 uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t2);
3103 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1);
3104 uLiteral(cb, 4+d32);
3105 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3106 uInstr1(cb, JMP, 0, TempReg, t2);
3107 uCond(cb, CondAlways);
sewardj2e93c502002-04-12 11:12:52 +00003108 LAST_UINSTR(cb).jmpkind = JmpRet;
sewardjde4a1d02002-03-22 01:27:54 +00003109
3110 *isEnd = True;
3111 if (dis) {
3112 if (d32 == 0) VG_(printf)("ret\n");
3113 else VG_(printf)("ret %d\n", d32);
3114 }
3115 break;
3116
3117 case 0xE8: /* CALL J4 */
3118 d32 = getUDisp32(eip); eip += 4;
3119 d32 += eip; /* eip now holds return-to addr, d32 is call-to addr */
sewardjde4a1d02002-03-22 01:27:54 +00003120 if (d32 == eip && getUChar(eip) >= 0x58
3121 && getUChar(eip) <= 0x5F) {
3122 /* Specially treat the position-independent-code idiom
3123 call X
3124 X: popl %reg
3125 as
3126 movl %eip, %reg.
3127 since this generates better code, but for no other reason. */
3128 Int archReg = getUChar(eip) - 0x58;
3129 /* VG_(printf)("-- fPIC thingy\n"); */
3130 t1 = newTemp(cb);
3131 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
3132 uLiteral(cb, eip);
3133 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, archReg);
3134 eip++; /* Step over the POP */
3135 if (dis)
3136 VG_(printf)("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
3137 } else {
3138 /* The normal sequence for a call. */
3139 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3140 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
3141 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t1);
3142 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t1);
3143 uLiteral(cb, 4);
3144 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3145 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
3146 uLiteral(cb, eip);
3147 uInstr2(cb, STORE, 4, TempReg, t2, TempReg, t1);
3148 SMC_IF_ALL(cb);
3149 uInstr1(cb, JMP, 0, Literal, 0);
3150 uLiteral(cb, d32);
3151 uCond(cb, CondAlways);
sewardj2e93c502002-04-12 11:12:52 +00003152 LAST_UINSTR(cb).jmpkind = JmpCall;
sewardjde4a1d02002-03-22 01:27:54 +00003153 *isEnd = True;
3154 if (dis) VG_(printf)("call 0x%x\n",d32);
3155 }
3156 break;
3157
3158 case 0xC9: /* LEAVE */
3159 t1 = newTemp(cb); t2 = newTemp(cb);
3160 uInstr2(cb, GET, 4, ArchReg, R_EBP, TempReg, t1);
3161 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3162 uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t2);
3163 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
3164 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1);
3165 uLiteral(cb, 4);
3166 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3167 if (dis) VG_(printf)("leave");
3168 break;
3169
sewardj4d0ab1f2002-03-24 10:00:09 +00003170 /* ---------------- Misc wierd-ass insns --------------- */
3171
sewardjfe8a1662002-03-24 11:54:07 +00003172 case 0x27: /* DAA */
sewardj4d0ab1f2002-03-24 10:00:09 +00003173 case 0x2F: /* DAS */
3174 t1 = newTemp(cb);
3175 uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
3176 /* Widen %AL to 32 bits, so it's all defined when we push it. */
3177 uInstr1(cb, WIDEN, 4, TempReg, t1);
3178 LAST_UINSTR(cb).extra4b = 1;
3179 LAST_UINSTR(cb).signed_widen = False;
3180 uInstr0(cb, CALLM_S, 0);
3181 uInstr1(cb, PUSH, 4, TempReg, t1);
sewardjfe8a1662002-03-24 11:54:07 +00003182 uInstr1(cb, CALLM, 0, Lit16,
3183 opc == 0x27 ? VGOFF_(helper_DAA) : VGOFF_(helper_DAS) );
sewardj4d0ab1f2002-03-24 10:00:09 +00003184 uFlagsRWU(cb, FlagsAC, FlagsOSZACP, FlagsEmpty);
3185 uInstr1(cb, POP, 4, TempReg, t1);
3186 uInstr0(cb, CALLM_E, 0);
3187 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
sewardjfe8a1662002-03-24 11:54:07 +00003188 if (dis) VG_(printf)(opc == 0x27 ? "daa\n" : "das\n");
3189 break;
sewardj4d0ab1f2002-03-24 10:00:09 +00003190
sewardjde4a1d02002-03-22 01:27:54 +00003191 /* ------------------------ CWD/CDQ -------------------- */
3192
3193 case 0x98: /* CBW */
3194 t1 = newTemp(cb);
3195 if (sz == 4) {
3196 uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
3197 uInstr1(cb, WIDEN, 4, TempReg, t1); /* 4 == dst size */
3198 LAST_UINSTR(cb).extra4b = 2; /* the source size */
3199 LAST_UINSTR(cb).signed_widen = True;
3200 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
3201 if (dis) VG_(printf)("cwd\n");
3202 } else {
3203 vg_assert(sz == 2);
3204 uInstr2(cb, GET, 1, ArchReg, R_EAX, TempReg, t1);
3205 uInstr1(cb, WIDEN, 2, TempReg, t1); /* 2 == dst size */
3206 LAST_UINSTR(cb).extra4b = 1; /* the source size */
3207 LAST_UINSTR(cb).signed_widen = True;
3208 uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
3209 if (dis) VG_(printf)("cbw\n");
3210 }
3211 break;
3212
3213 case 0x99: /* CWD/CDQ */
3214 t1 = newTemp(cb);
3215 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
3216 uInstr2(cb, SAR, sz, Literal, 0, TempReg, t1);
3217 uLiteral(cb, sz == 2 ? 15 : 31);
3218 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EDX);
3219 if (dis) VG_(printf)(sz == 2 ? "cwdq\n" : "cdqq\n");
3220 break;
3221
3222 /* ------------------------ FPU ops -------------------- */
3223
3224 case 0x9E: /* SAHF */
3225 codegen_SAHF ( cb );
3226 if (dis) VG_(printf)("sahf\n");
3227 break;
3228
3229 case 0x9B: /* FWAIT */
3230 /* ignore? */
3231 if (dis) VG_(printf)("fwait\n");
3232 break;
3233
3234 case 0xD8:
3235 case 0xD9:
3236 case 0xDA:
3237 case 0xDB:
3238 case 0xDC:
3239 case 0xDD:
3240 case 0xDE:
3241 case 0xDF:
3242 eip = dis_fpu ( cb, opc, eip );
3243 break;
3244
3245 /* ------------------------ INC & DEC ------------------ */
3246
3247 case 0x40: /* INC eAX */
3248 case 0x41: /* INC eCX */
3249 case 0x42: /* INC eDX */
3250 case 0x43: /* INC eBX */
3251 case 0x45: /* INC eBP */
3252 case 0x46: /* INC eSI */
3253 case 0x47: /* INC eDI */
3254 t1 = newTemp(cb);
3255 uInstr2(cb, GET, sz, ArchReg, (UInt)(opc - 0x40),
3256 TempReg, t1);
3257 uInstr1(cb, INC, sz, TempReg, t1);
3258 setFlagsFromUOpcode(cb, INC);
3259 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg,
3260 (UInt)(opc - 0x40));
3261 if (dis)
3262 VG_(printf)("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
3263 break;
3264
3265 case 0x48: /* DEC eAX */
3266 case 0x49: /* DEC eCX */
3267 case 0x4A: /* DEC eDX */
3268 case 0x4B: /* DEC eBX */
3269 case 0x4D: /* DEC eBP */
3270 case 0x4E: /* DEC eSI */
3271 case 0x4F: /* DEC eDI */
3272 t1 = newTemp(cb);
3273 uInstr2(cb, GET, sz, ArchReg, (UInt)(opc - 0x48),
3274 TempReg, t1);
3275 uInstr1(cb, DEC, sz, TempReg, t1);
3276 setFlagsFromUOpcode(cb, DEC);
3277 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg,
3278 (UInt)(opc - 0x48));
3279 if (dis)
3280 VG_(printf)("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
3281 break;
3282
3283 /* ------------------------ INT ------------------------ */
3284
3285 case 0xCD: /* INT imm8 */
3286 d32 = getUChar(eip); eip++;
3287 if (d32 != 0x80) VG_(panic)("disInstr: INT but not 0x80 !");
3288 /* It's important that all ArchRegs carry their up-to-date value
3289 at this point. So we declare an end-of-block here, which
3290 forces any TempRegs caching ArchRegs to be flushed. */
sewardjde4a1d02002-03-22 01:27:54 +00003291 uInstr1(cb, JMP, 0, Literal, 0);
3292 uLiteral(cb, eip);
3293 uCond(cb, CondAlways);
sewardj2e93c502002-04-12 11:12:52 +00003294 LAST_UINSTR(cb).jmpkind = JmpSyscall;
sewardjde4a1d02002-03-22 01:27:54 +00003295 *isEnd = True;
3296 if (dis) VG_(printf)("int $0x80\n");
3297 break;
3298
3299 /* ------------------------ Jcond, byte offset --------- */
3300
3301 case 0xEB: /* Jb (jump, byte offset) */
3302 d32 = (eip+1) + getSDisp8(eip); eip++;
3303 uInstr1(cb, JMP, 0, Literal, 0);
3304 uLiteral(cb, d32);
3305 uCond(cb, CondAlways);
3306 *isEnd = True;
3307 if (dis)
3308 VG_(printf)("jmp-8 0x%x\n", d32);
3309 break;
3310
3311 case 0xE9: /* Jv (jump, 16/32 offset) */
3312 d32 = (eip+sz) + getSDisp(sz,eip); eip += sz;
3313 uInstr1(cb, JMP, 0, Literal, 0);
3314 uLiteral(cb, d32);
3315 uCond(cb, CondAlways);
3316 *isEnd = True;
3317 if (dis)
3318 VG_(printf)("jmp 0x%x\n", d32);
3319 break;
3320
3321 case 0x70:
3322 case 0x71:
3323 case 0x72: /* JBb/JNAEb (jump below) */
3324 case 0x73: /* JNBb/JAEb (jump not below) */
3325 case 0x74: /* JZb/JEb (jump zero) */
3326 case 0x75: /* JNZb/JNEb (jump not zero) */
3327 case 0x76: /* JBEb/JNAb (jump below or equal) */
3328 case 0x77: /* JNBEb/JAb (jump not below or equal) */
3329 case 0x78: /* JSb (jump negative) */
3330 case 0x79: /* JSb (jump not negative) */
3331 case 0x7A: /* JP (jump parity even) */
3332 case 0x7B: /* JNP/JPO (jump parity odd) */
3333 case 0x7C: /* JLb/JNGEb (jump less) */
3334 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
3335 case 0x7E: /* JLEb/JNGb (jump less or equal) */
3336 case 0x7F: /* JGb/JNLEb (jump greater) */
3337 d32 = (eip+1) + getSDisp8(eip); eip++;
3338 uInstr1(cb, JMP, 0, Literal, 0);
3339 uLiteral(cb, d32);
3340 uCond(cb, (Condcode)(opc - 0x70));
3341 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
3342 /* It's actually acceptable not to end this basic block at a
3343 control transfer, reducing the number of jumps through
3344 vg_dispatch, at the expense of possibly translating the insns
3345 following this jump twice. This does give faster code, but
3346 on the whole I don't think the effort is worth it. */
3347 uInstr1(cb, JMP, 0, Literal, 0);
3348 uLiteral(cb, eip);
3349 uCond(cb, CondAlways);
3350 *isEnd = True;
3351 /* The above 3 lines would be removed if the bb was not to end
3352 here. */
3353 if (dis)
3354 VG_(printf)("j%s-8 0x%x\n", VG_(nameCondcode)(opc - 0x70), d32);
3355 break;
3356
3357 case 0xE3: /* JECXZ or perhaps JCXZ, depending on OSO ? Intel
3358 manual says it depends on address size override,
3359 which doesn't sound right to me. */
3360 d32 = (eip+1) + getSDisp8(eip); eip++;
3361 t1 = newTemp(cb);
3362 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
3363 uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
3364 uLiteral(cb, d32);
3365 if (dis)
3366 VG_(printf)("j%sz 0x%x\n", nameIReg(sz, R_ECX), d32);
3367 break;
3368
3369 case 0xE2: /* LOOP disp8 */
3370 /* Again, the docs say this uses ECX/CX as a count depending on
3371 the address size override, not the operand one. Since we
3372 don't handle address size overrides, I guess that means
3373 ECX. */
3374 d32 = (eip+1) + getSDisp8(eip); eip++;
3375 t1 = newTemp(cb);
3376 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
3377 uInstr1(cb, DEC, 4, TempReg, t1);
3378 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ECX);
3379 uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
3380 uLiteral(cb, eip);
3381 uInstr1(cb, JMP, 0, Literal, 0);
3382 uLiteral(cb, d32);
3383 uCond(cb, CondAlways);
3384 *isEnd = True;
3385 if (dis)
3386 VG_(printf)("loop 0x%x\n", d32);
3387 break;
3388
3389 /* ------------------------ IMUL ----------------------- */
3390
3391 case 0x69: /* IMUL Iv, Ev, Gv */
3392 eip = dis_imul_I_E_G ( cb, sz, eip, sz );
3393 break;
3394 case 0x6B: /* IMUL Ib, Ev, Gv */
3395 eip = dis_imul_I_E_G ( cb, sz, eip, 1 );
3396 break;
3397
3398 /* ------------------------ MOV ------------------------ */
3399
3400 case 0x88: /* MOV Gb,Eb */
3401 eip = dis_mov_G_E(cb, 1, eip);
3402 break;
3403
3404 case 0x89: /* MOV Gv,Ev */
3405 eip = dis_mov_G_E(cb, sz, eip);
3406 break;
3407
3408 case 0x8A: /* MOV Eb,Gb */
3409 eip = dis_mov_E_G(cb, 1, eip);
3410 break;
3411
3412 case 0x8B: /* MOV Ev,Gv */
3413 eip = dis_mov_E_G(cb, sz, eip);
3414 break;
3415
3416 case 0x8D: /* LEA M,Gv */
3417 modrm = getUChar(eip);
3418 if (epartIsReg(modrm))
3419 VG_(panic)("LEA M,Gv: modRM refers to register");
3420 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
3421 eip += HI8(pair);
3422 t1 = LOW24(pair);
3423 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, gregOfRM(modrm));
3424 if (dis)
3425 VG_(printf)("lea%c %s, %s\n", nameISize(sz), dis_buf,
3426 nameIReg(sz,gregOfRM(modrm)));
3427 break;
3428
3429 case 0xA0: /* MOV Ob,AL */
3430 sz = 1;
3431 /* Fall through ... */
3432 case 0xA1: /* MOV Ov,eAX */
3433 d32 = getUDisp32(eip); eip += 4;
3434 t1 = newTemp(cb); t2 = newTemp(cb);
3435 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
3436 uLiteral(cb, d32);
3437 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3438 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EAX);
3439 if (dis) VG_(printf)("mov%c 0x%x,%s\n", nameISize(sz),
3440 d32, nameIReg(sz,R_EAX));
3441 break;
3442
3443 case 0xA2: /* MOV AL,Ob */
3444 sz = 1;
3445 /* Fall through ... */
3446 case 0xA3: /* MOV eAX,Ov */
3447 d32 = getUDisp32(eip); eip += 4;
3448 t1 = newTemp(cb); t2 = newTemp(cb);
3449 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
3450 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
3451 uLiteral(cb, d32);
3452 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3453 SMC_IF_SOME(cb);
3454 if (dis) VG_(printf)("mov%c %s,0x%x\n", nameISize(sz),
3455 nameIReg(sz,R_EAX), d32);
3456 break;
3457
3458 case 0xB0: /* MOV imm,AL */
3459 case 0xB1: /* MOV imm,CL */
3460 case 0xB2: /* MOV imm,DL */
3461 case 0xB3: /* MOV imm,BL */
3462 case 0xB4: /* MOV imm,AH */
3463 case 0xB5: /* MOV imm,CH */
3464 case 0xB6: /* MOV imm,DH */
3465 case 0xB7: /* MOV imm,BH */
3466 d32 = getUChar(eip); eip += 1;
3467 t1 = newTemp(cb);
3468 uInstr2(cb, MOV, 1, Literal, 0, TempReg, t1);
3469 uLiteral(cb, d32);
3470 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, opc-0xB0);
3471 if (dis) VG_(printf)("movb $0x%x,%s\n", d32,
3472 nameIReg(1,opc-0xB0));
3473 break;
3474
3475 case 0xB8: /* MOV imm,eAX */
3476 case 0xB9: /* MOV imm,eCX */
3477 case 0xBA: /* MOV imm,eDX */
3478 case 0xBB: /* MOV imm,eBX */
3479 case 0xBD: /* MOV imm,eBP */
3480 case 0xBE: /* MOV imm,eSI */
3481 case 0xBF: /* MOV imm,eDI */
3482 d32 = getUDisp(sz,eip); eip += sz;
3483 t1 = newTemp(cb);
3484 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t1);
3485 uLiteral(cb, d32);
3486 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, opc-0xB8);
3487 if (dis) VG_(printf)("mov%c $0x%x,%s\n", nameISize(sz), d32,
3488 nameIReg(sz,opc-0xB8));
3489 break;
3490
3491 case 0xC6: /* MOV Ib,Eb */
3492 sz = 1;
3493 goto do_Mov_I_E;
3494 case 0xC7: /* MOV Iv,Ev */
3495 goto do_Mov_I_E;
3496
3497 do_Mov_I_E:
3498 modrm = getUChar(eip);
3499 if (epartIsReg(modrm)) {
3500 d32 = getUDisp(sz,eip); eip += sz;
3501 t1 = newTemp(cb);
3502 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t1);
3503 uLiteral(cb, d32);
3504 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
3505 if (dis) VG_(printf)("mov%c $0x%x, %s\n", nameISize(sz), d32,
3506 nameIReg(sz,eregOfRM(modrm)));
3507 } else {
3508 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
3509 eip += HI8(pair);
3510 d32 = getUDisp(sz,eip); eip += sz;
3511 t1 = newTemp(cb);
3512 t2 = LOW24(pair);
3513 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t1);
3514 uLiteral(cb, d32);
3515 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3516 SMC_IF_SOME(cb);
3517 if (dis) VG_(printf)("mov%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
3518 }
3519 break;
3520
3521 /* ------------------------ opl imm, A ----------------- */
3522
3523 case 0x04: /* ADD Ib, AL */
3524 eip = dis_op_imm_A(cb, 1, ADD, True, eip, "add" );
3525 break;
3526 case 0x05: /* ADD Iv, eAX */
3527 eip = dis_op_imm_A(cb, sz, ADD, True, eip, "add" );
3528 break;
3529
3530 case 0x0C: /* OR Ib, AL */
3531 eip = dis_op_imm_A(cb, 1, OR, True, eip, "or" );
3532 break;
3533 case 0x0D: /* OR Iv, eAX */
3534 eip = dis_op_imm_A(cb, sz, OR, True, eip, "or" );
3535 break;
3536
3537 case 0x24: /* AND Ib, AL */
3538 eip = dis_op_imm_A(cb, 1, AND, True, eip, "and" );
3539 break;
3540 case 0x25: /* AND Iv, eAX */
3541 eip = dis_op_imm_A(cb, sz, AND, True, eip, "and" );
3542 break;
3543
3544 case 0x2C: /* SUB Ib, AL */
3545 eip = dis_op_imm_A(cb, 1, SUB, True, eip, "sub" );
3546 break;
3547 case 0x2D: /* SUB Iv, eAX */
3548 eip = dis_op_imm_A(cb, sz, SUB, True, eip, "sub" );
3549 break;
3550
3551 case 0x34: /* XOR Ib, AL */
3552 eip = dis_op_imm_A(cb, 1, XOR, True, eip, "xor" );
3553 break;
3554 case 0x35: /* XOR Iv, eAX */
3555 eip = dis_op_imm_A(cb, sz, XOR, True, eip, "xor" );
3556 break;
3557
3558 case 0x3C: /* CMP Ib, AL */
3559 eip = dis_op_imm_A(cb, 1, SUB, False, eip, "cmp" );
3560 break;
3561 case 0x3D: /* CMP Iv, eAX */
3562 eip = dis_op_imm_A(cb, sz, SUB, False, eip, "cmp" );
3563 break;
3564
3565 case 0xA8: /* TEST Ib, AL */
3566 eip = dis_op_imm_A(cb, 1, AND, False, eip, "test" );
3567 break;
3568 case 0xA9: /* TEST Iv, eAX */
3569 eip = dis_op_imm_A(cb, sz, AND, False, eip, "test" );
3570 break;
3571
3572 /* ------------------------ opl Ev, Gv ----------------- */
3573
3574 case 0x02: /* ADD Eb,Gb */
3575 eip = dis_op2_E_G ( cb, ADD, True, 1, eip, "add" );
3576 break;
3577 case 0x03: /* ADD Ev,Gv */
3578 eip = dis_op2_E_G ( cb, ADD, True, sz, eip, "add" );
3579 break;
3580
3581 case 0x0A: /* OR Eb,Gb */
3582 eip = dis_op2_E_G ( cb, OR, True, 1, eip, "or" );
3583 break;
3584 case 0x0B: /* OR Ev,Gv */
3585 eip = dis_op2_E_G ( cb, OR, True, sz, eip, "or" );
3586 break;
3587
3588 case 0x13: /* ADC Ev,Gv */
3589 eip = dis_op2_E_G ( cb, ADC, True, sz, eip, "adc" );
3590 break;
3591
3592 case 0x1B: /* SBB Ev,Gv */
3593 eip = dis_op2_E_G ( cb, SBB, True, sz, eip, "sbb" );
3594 break;
3595
3596 case 0x22: /* AND Eb,Gb */
3597 eip = dis_op2_E_G ( cb, AND, True, 1, eip, "and" );
3598 break;
3599 case 0x23: /* AND Ev,Gv */
3600 eip = dis_op2_E_G ( cb, AND, True, sz, eip, "and" );
3601 break;
3602
3603 case 0x2A: /* SUB Eb,Gb */
3604 eip = dis_op2_E_G ( cb, SUB, True, 1, eip, "sub" );
3605 break;
3606 case 0x2B: /* SUB Ev,Gv */
3607 eip = dis_op2_E_G ( cb, SUB, True, sz, eip, "sub" );
3608 break;
3609
3610 case 0x32: /* XOR Eb,Gb */
3611 eip = dis_op2_E_G ( cb, XOR, True, 1, eip, "xor" );
3612 break;
3613 case 0x33: /* XOR Ev,Gv */
3614 eip = dis_op2_E_G ( cb, XOR, True, sz, eip, "xor" );
3615 break;
3616
3617 case 0x3A: /* CMP Eb,Gb */
3618 eip = dis_op2_E_G ( cb, SUB, False, 1, eip, "cmp" );
3619 break;
3620 case 0x3B: /* CMP Ev,Gv */
3621 eip = dis_op2_E_G ( cb, SUB, False, sz, eip, "cmp" );
3622 break;
3623
3624 case 0x84: /* TEST Eb,Gb */
3625 eip = dis_op2_E_G ( cb, AND, False, 1, eip, "test" );
3626 break;
3627 case 0x85: /* TEST Ev,Gv */
3628 eip = dis_op2_E_G ( cb, AND, False, sz, eip, "test" );
3629 break;
3630
3631 /* ------------------------ opl Gv, Ev ----------------- */
3632
3633 case 0x00: /* ADD Gb,Eb */
3634 eip = dis_op2_G_E ( cb, ADD, True, 1, eip, "add" );
3635 break;
3636 case 0x01: /* ADD Gv,Ev */
3637 eip = dis_op2_G_E ( cb, ADD, True, sz, eip, "add" );
3638 break;
3639
3640 case 0x08: /* OR Gb,Eb */
3641 eip = dis_op2_G_E ( cb, OR, True, 1, eip, "or" );
3642 break;
3643 case 0x09: /* OR Gv,Ev */
3644 eip = dis_op2_G_E ( cb, OR, True, sz, eip, "or" );
3645 break;
3646
3647 case 0x11: /* ADC Gv,Ev */
3648 eip = dis_op2_G_E ( cb, ADC, True, sz, eip, "adc" );
3649 break;
3650
3651 case 0x19: /* SBB Gv,Ev */
3652 eip = dis_op2_G_E ( cb, SBB, True, sz, eip, "sbb" );
3653 break;
3654
3655 case 0x20: /* AND Gb,Eb */
3656 eip = dis_op2_G_E ( cb, AND, True, 1, eip, "and" );
3657 break;
3658 case 0x21: /* AND Gv,Ev */
3659 eip = dis_op2_G_E ( cb, AND, True, sz, eip, "and" );
3660 break;
3661
3662 case 0x28: /* SUB Gb,Eb */
3663 eip = dis_op2_G_E ( cb, SUB, True, 1, eip, "sub" );
3664 break;
3665 case 0x29: /* SUB Gv,Ev */
3666 eip = dis_op2_G_E ( cb, SUB, True, sz, eip, "sub" );
3667 break;
3668
3669 case 0x30: /* XOR Gb,Eb */
3670 eip = dis_op2_G_E ( cb, XOR, True, 1, eip, "xor" );
3671 break;
3672 case 0x31: /* XOR Gv,Ev */
3673 eip = dis_op2_G_E ( cb, XOR, True, sz, eip, "xor" );
3674 break;
3675
3676 case 0x38: /* CMP Gb,Eb */
3677 eip = dis_op2_G_E ( cb, SUB, False, 1, eip, "cmp" );
3678 break;
3679 case 0x39: /* CMP Gv,Ev */
3680 eip = dis_op2_G_E ( cb, SUB, False, sz, eip, "cmp" );
3681 break;
3682
3683 /* ------------------------ POP ------------------------ */
3684
3685 case 0x58: /* POP eAX */
3686 case 0x59: /* POP eCX */
3687 case 0x5A: /* POP eDX */
3688 case 0x5B: /* POP eBX */
3689 case 0x5C: /* POP eSP */
3690 case 0x5D: /* POP eBP */
3691 case 0x5E: /* POP eSI */
3692 case 0x5F: /* POP eDI */
3693 t1 = newTemp(cb); t2 = newTemp(cb);
3694 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
3695 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3696 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3697 uLiteral(cb, sz);
3698 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
3699 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, opc-0x58);
3700 if (dis)
3701 VG_(printf)("pop%c %s\n", nameISize(sz), nameIReg(sz,opc-0x58));
3702 break;
3703
3704 case 0x9D: /* POPF */
3705 vg_assert(sz == 2 || sz == 4);
3706 t1 = newTemp(cb); t2 = newTemp(cb);
3707 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
3708 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3709 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3710 uLiteral(cb, sz);
3711 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
3712 uInstr1(cb, PUTF, sz, TempReg, t1);
3713 /* PUTF writes all the flags we are interested in */
3714 uFlagsRWU(cb, FlagsEmpty, FlagsALL, FlagsEmpty);
3715 if (dis)
3716 VG_(printf)("popf%c\n", nameISize(sz));
3717 break;
3718
3719 case 0x61: /* POPA */
3720 { Int reg;
3721 /* Just to keep things sane, we assert for a size 4. It's
3722 probably OK for size 2 as well, but I'd like to find a test
3723 case; ie, have the assertion fail, before committing to it.
3724 If it fails for you, uncomment the sz == 2 bit, try again,
3725 and let me know whether or not it works. (jseward@acm.org). */
3726 vg_assert(sz == 4 /* || sz == 2 */);
3727
3728 /* Eight values are popped, one per register, but the value of
3729 %esp on the stack is ignored and instead incremented (in one
3730 hit at the end) for each of the values. */
3731 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3732 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
3733 uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t3);
3734
3735 /* Do %edi, %esi, %ebp */
3736 for (reg = 7; reg >= 5; reg--) {
3737 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3738 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3739 uLiteral(cb, sz);
3740 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
3741 }
3742 /* Ignore (skip) value of %esp on stack. */
3743 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3744 uLiteral(cb, sz);
3745 /* Do %ebx, %edx, %ecx, %eax */
3746 for (reg = 3; reg >= 0; reg--) {
3747 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3748 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3749 uLiteral(cb, sz);
3750 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
3751 }
3752 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t3);
3753 uLiteral(cb, sz * 8); /* One 'sz' per register */
3754 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
3755 if (dis)
3756 VG_(printf)("popa%c\n", nameISize(sz));
3757 break;
3758 }
3759
3760 /* ------------------------ PUSH ----------------------- */
3761
3762 case 0x50: /* PUSH eAX */
3763 case 0x51: /* PUSH eCX */
3764 case 0x52: /* PUSH eDX */
3765 case 0x54: /* PUSH eSP */
3766 case 0x53: /* PUSH eBX */
3767 case 0x55: /* PUSH eBP */
3768 case 0x56: /* PUSH eSI */
3769 case 0x57: /* PUSH eDI */
3770 /* This is the Right Way, in that the value to be pushed is
3771 established before %esp is changed, so that pushl %esp
3772 correctly pushes the old value. */
3773 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3774 uInstr2(cb, GET, sz, ArchReg, opc-0x50, TempReg, t1);
3775 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
3776 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
3777 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3778 uLiteral(cb, sz);
3779 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
3780 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3781 SMC_IF_ALL(cb);
3782 if (dis)
3783 VG_(printf)("push%c %s\n", nameISize(sz), nameIReg(sz,opc-0x50));
3784 break;
3785
3786 case 0x68: /* PUSH Iv */
3787 d32 = getUDisp(sz,eip); eip += sz;
3788 goto do_push_I;
3789 case 0x6A: /* PUSH Ib, sign-extended to sz */
3790 d32 = getSDisp8(eip); eip += 1;
3791 goto do_push_I;
3792 do_push_I:
3793 t1 = newTemp(cb); t2 = newTemp(cb);
3794 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
3795 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t1);
3796 uLiteral(cb, sz);
3797 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3798 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t2);
3799 uLiteral(cb, d32);
3800 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
3801 SMC_IF_ALL(cb);
3802 if (dis)
3803 VG_(printf)("push%c $0x%x\n", nameISize(sz), d32);
3804 break;
3805
3806 case 0x9C: /* PUSHF */
3807 vg_assert(sz == 2 || sz == 4);
3808 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3809 uInstr1(cb, GETF, sz, TempReg, t1);
3810 /* GETF reads all the flags we are interested in */
3811 uFlagsRWU(cb, FlagsALL, FlagsEmpty, FlagsEmpty);
3812 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
3813 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
3814 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3815 uLiteral(cb, sz);
3816 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
3817 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3818 SMC_IF_ALL(cb);
3819 if (dis)
3820 VG_(printf)("pushf%c\n", nameISize(sz));
3821 break;
3822
3823 case 0x60: /* PUSHA */
3824 { Int reg;
3825 /* Just to keep things sane, we assert for a size 4. It's
3826 probably OK for size 2 as well, but I'd like to find a test
3827 case; ie, have the assertion fail, before committing to it.
3828 If it fails for you, uncomment the sz == 2 bit, try again,
3829 and let me know whether or not it works. (jseward@acm.org). */
3830 vg_assert(sz == 4 /* || sz == 2 */);
3831
3832 /* This is the Right Way, in that the value to be pushed is
3833 established before %esp is changed, so that pusha
3834 correctly pushes the old %esp value. New value of %esp is
3835 pushed at start. */
3836 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3837 t4 = newTemp(cb);
3838 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
3839 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
3840 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t4);
3841 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t4);
3842 uLiteral(cb, sz * 8); /* One 'sz' per register. */
3843 uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_ESP);
3844 /* Do %eax, %ecx, %edx, %ebx */
3845 for (reg = 0; reg <= 3; reg++) {
3846 uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
3847 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3848 uLiteral(cb, sz);
3849 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3850 SMC_IF_ALL(cb);
3851 }
3852 /* Push old value of %esp */
3853 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3854 uLiteral(cb, sz);
3855 uInstr2(cb, STORE, sz, TempReg, t3, TempReg, t2);
3856 SMC_IF_ALL(cb);
3857 /* Do %ebp, %esi, %edi */
3858 for (reg = 5; reg <= 7; reg++) {
3859 uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
3860 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3861 uLiteral(cb, sz);
3862 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3863 SMC_IF_ALL(cb);
3864 }
3865 if (dis)
3866 VG_(printf)("pusha%c\n", nameISize(sz));
3867 break;
3868 }
3869
3870 /* ------------------------ SCAS et al ----------------- */
3871
3872 case 0xA4: /* MOVSb, no REP prefix */
3873 codegen_MOVS ( cb, 1 );
3874 if (dis) VG_(printf)("movsb\n");
3875 break;
3876 case 0xA5: /* MOVSv, no REP prefix */
3877 codegen_MOVS ( cb, sz );
3878 if (dis) VG_(printf)("movs%c\n", nameISize(sz));
3879 break;
3880
3881 case 0xA6: /* CMPSb, no REP prefix */
3882 codegen_CMPS ( cb, 1 );
3883 if (dis) VG_(printf)("cmpsb\n");
3884 break;
3885
3886 case 0xAA: /* STOSb, no REP prefix */
3887 codegen_STOS ( cb, 1 );
3888 if (dis) VG_(printf)("stosb\n");
3889 break;
3890 case 0xAB: /* STOSv, no REP prefix */
3891 codegen_STOS ( cb, sz );
3892 if (dis) VG_(printf)("stos%c\n", nameISize(sz));
3893 break;
3894
3895 case 0xAC: /* LODSb, no REP prefix */
3896 codegen_LODS ( cb, 1 );
3897 if (dis) VG_(printf)("lodsb\n");
3898 break;
3899
3900 case 0xAE: /* SCASb, no REP prefix */
3901 codegen_SCAS ( cb, 1 );
3902 if (dis) VG_(printf)("scasb\n");
3903 break;
3904
3905 case 0xFC: /* CLD */
3906 uInstr0(cb, CALLM_S, 0);
3907 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CLD));
3908 uFlagsRWU(cb, FlagsEmpty, FlagD, FlagsEmpty);
3909 uInstr0(cb, CALLM_E, 0);
3910 if (dis) VG_(printf)("cld\n");
3911 break;
3912
3913 case 0xFD: /* STD */
3914 uInstr0(cb, CALLM_S, 0);
3915 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_STD));
3916 uFlagsRWU(cb, FlagsEmpty, FlagD, FlagsEmpty);
3917 uInstr0(cb, CALLM_E, 0);
3918 if (dis) VG_(printf)("std\n");
3919 break;
3920
3921 case 0xF2: { /* REPNE prefix insn */
3922 Addr eip_orig = eip - 1;
3923 abyte = getUChar(eip); eip++;
3924 if (abyte == 0x66) { sz = 2; abyte = getUChar(eip); eip++; }
3925
3926 if (abyte == 0xAE || 0xAF) { /* REPNE SCAS<sz> */
3927 if (abyte == 0xAE) sz = 1;
3928 codegen_REPNE_SCAS ( cb, sz, eip_orig, eip );
3929 *isEnd = True;
3930 if (dis) VG_(printf)("repne scas%c\n", nameISize(sz));
3931 }
3932 else {
3933 VG_(printf)("REPNE then 0x%x\n", (UInt)abyte);
3934 VG_(panic)("Unhandled REPNE case");
3935 }
3936 break;
3937 }
3938
3939 case 0xF3: { /* REPE prefix insn */
3940 Addr eip_orig = eip - 1;
3941 abyte = getUChar(eip); eip++;
3942 if (abyte == 0x66) { sz = 2; abyte = getUChar(eip); eip++; }
3943
3944 if (abyte == 0xA4 || abyte == 0xA5) { /* REPE MOV<sz> */
3945 if (abyte == 0xA4) sz = 1;
3946 codegen_REPE_MOVS ( cb, sz, eip_orig, eip );
3947 *isEnd = True;
3948 if (dis) VG_(printf)("repe mov%c\n", nameISize(sz));
3949 }
3950 else
3951 if (abyte == 0xA6 || abyte == 0xA7) { /* REPE CMP<sz> */
3952 if (abyte == 0xA6) sz = 1;
3953 codegen_REPE_CMPS ( cb, sz, eip_orig, eip );
3954 *isEnd = True;
3955 if (dis) VG_(printf)("repe cmps%c\n", nameISize(sz));
3956 }
3957 else
3958 if (abyte == 0xAA || abyte == 0xAB) { /* REPE STOS<sz> */
3959 if (abyte == 0xAA) sz = 1;
3960 codegen_REPE_STOS ( cb, sz, eip_orig, eip );
3961 *isEnd = True;
3962 if (dis) VG_(printf)("repe stos%c\n", nameISize(sz));
3963 } else {
3964 VG_(printf)("REPE then 0x%x\n", (UInt)abyte);
3965 VG_(panic)("Unhandled REPE case");
3966 }
3967 break;
3968 }
3969
3970 /* ------------------------ XCHG ----------------------- */
3971
3972 case 0x86: /* XCHG Gb,Eb */
3973 sz = 1;
3974 /* Fall through ... */
3975 case 0x87: /* XCHG Gv,Ev */
3976 modrm = getUChar(eip);
3977 t1 = newTemp(cb); t2 = newTemp(cb);
3978 if (epartIsReg(modrm)) {
3979 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
3980 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t2);
3981 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, gregOfRM(modrm));
3982 uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, eregOfRM(modrm));
3983 eip++;
3984 if (dis)
3985 VG_(printf)("xchg%c %s, %s\n", nameISize(sz),
3986 nameIReg(sz,gregOfRM(modrm)),
3987 nameIReg(sz,eregOfRM(modrm)));
3988 } else {
3989 pair = disAMode ( cb, eip, dis?dis_buf:NULL);
3990 t3 = LOW24(pair);
3991 uInstr2(cb, LOAD, sz, TempReg, t3, TempReg, t1);
3992 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t2);
3993 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t3);
3994 SMC_IF_SOME(cb);
3995 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, gregOfRM(modrm));
3996 eip += HI8(pair);
3997 if (dis)
3998 VG_(printf)("xchg%c %s, %s\n", nameISize(sz),
3999 nameIReg(sz,gregOfRM(modrm)),
4000 dis_buf);
4001 }
4002 break;
4003
4004 case 0x90: /* XCHG eAX,eAX */
4005 if (dis) VG_(printf)("nop\n");
4006 break;
4007 case 0x91: /* XCHG eCX,eSI */
4008 case 0x96: /* XCHG eAX,eSI */
4009 case 0x97: /* XCHG eAX,eDI */
4010 codegen_xchg_eAX_Reg ( cb, sz, opc - 0x90 );
4011 break;
4012
4013 /* ------------------------ (Grp1 extensions) ---------- */
4014
4015 case 0x80: /* Grp1 Ib,Eb */
4016 modrm = getUChar(eip);
4017 am_sz = lengthAMode(eip);
4018 sz = 1;
4019 d_sz = 1;
4020 d32 = getSDisp8(eip + am_sz);
4021 eip = dis_Grp1 ( cb, eip, modrm, am_sz, d_sz, sz, d32 );
4022 break;
4023
4024 case 0x81: /* Grp1 Iv,Ev */
4025 modrm = getUChar(eip);
4026 am_sz = lengthAMode(eip);
4027 d_sz = sz;
4028 d32 = getUDisp(d_sz, eip + am_sz);
4029 eip = dis_Grp1 ( cb, eip, modrm, am_sz, d_sz, sz, d32 );
4030 break;
4031
4032 case 0x83: /* Grp1 Ib,Ev */
4033 modrm = getUChar(eip);
4034 am_sz = lengthAMode(eip);
4035 d_sz = 1;
4036 d32 = getSDisp8(eip + am_sz);
4037 eip = dis_Grp1 ( cb, eip, modrm, am_sz, d_sz, sz, d32 );
4038 break;
4039
4040 /* ------------------------ (Grp2 extensions) ---------- */
4041
4042 case 0xC0: /* Grp2 Ib,Eb */
4043 modrm = getUChar(eip);
4044 am_sz = lengthAMode(eip);
4045 d_sz = 1;
4046 d32 = getSDisp8(eip + am_sz);
4047 sz = 1;
4048 eip = dis_Grp2 ( cb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
4049 break;
4050
4051 case 0xC1: /* Grp2 Ib,Ev */
4052 modrm = getUChar(eip);
4053 am_sz = lengthAMode(eip);
4054 d_sz = 1;
4055 d32 = getSDisp8(eip + am_sz);
4056 eip = dis_Grp2 ( cb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
4057 break;
4058
4059 case 0xD0: /* Grp2 1,Eb */
4060 modrm = getUChar(eip);
4061 am_sz = lengthAMode(eip);
4062 d_sz = 0;
4063 d32 = 1;
4064 sz = 1;
4065 eip = dis_Grp2 ( cb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
4066 break;
4067
4068 case 0xD1: /* Grp2 1,Ev */
4069 modrm = getUChar(eip);
4070 am_sz = lengthAMode(eip);
4071 d_sz = 0;
4072 d32 = 1;
4073 eip = dis_Grp2 ( cb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
4074 break;
4075
4076 case 0xD3: /* Grp2 CL,Ev */
4077 modrm = getUChar(eip);
4078 am_sz = lengthAMode(eip);
4079 d_sz = 0;
4080 eip = dis_Grp2 ( cb, eip, modrm, am_sz, d_sz, sz, ArchReg, R_ECX );
4081 break;
4082
4083 /* ------------------------ (Grp3 extensions) ---------- */
4084
4085 case 0xF6: /* Grp3 Eb */
4086 eip = dis_Grp3 ( cb, 1, eip );
4087 break;
4088 case 0xF7: /* Grp3 Ev */
4089 eip = dis_Grp3 ( cb, sz, eip );
4090 break;
4091
4092 /* ------------------------ (Grp4 extensions) ---------- */
4093
4094 case 0xFE: /* Grp4 Eb */
4095 eip = dis_Grp4 ( cb, eip );
4096 break;
4097
4098 /* ------------------------ (Grp5 extensions) ---------- */
4099
4100 case 0xFF: /* Grp5 Ev */
4101 eip = dis_Grp5 ( cb, sz, eip, isEnd );
4102 break;
4103
4104 /* ------------------------ Escapes to 2-byte opcodes -- */
4105
4106 case 0x0F: {
4107 opc = getUChar(eip); eip++;
4108 switch (opc) {
4109
4110 /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
4111
4112 case 0xBA: /* Grp8 Ib,Ev */
4113 modrm = getUChar(eip);
4114 am_sz = lengthAMode(eip);
4115 d32 = getSDisp8(eip + am_sz);
4116 eip = dis_Grp8 ( cb, eip, modrm, am_sz, sz, d32 );
4117 break;
4118
4119 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
4120
4121 case 0xBC: /* BSF Gv,Ev */
4122 eip = dis_bs_E_G ( cb, sz, eip, True );
4123 break;
4124 case 0xBD: /* BSR Gv,Ev */
4125 eip = dis_bs_E_G ( cb, sz, eip, False );
4126 break;
4127
4128 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
4129
4130 case 0xC8: /* BSWAP %eax */
4131 case 0xC9:
4132 case 0xCA:
4133 case 0xCB:
4134 case 0xCC:
4135 case 0xCD:
4136 case 0xCE:
4137 case 0xCF: /* BSWAP %edi */
4138 /* AFAICS from the Intel docs, this only exists at size 4. */
4139 vg_assert(sz == 4);
4140 t1 = newTemp(cb);
4141 uInstr2(cb, GET, 4, ArchReg, opc-0xC8, TempReg, t1);
4142 uInstr1(cb, BSWAP, 4, TempReg, t1);
4143 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, opc-0xC8);
4144 if (dis) VG_(printf)("bswapl %s\n", nameIReg(4, opc-0xC8));
4145 break;
4146
4147 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
4148
4149 case 0xA3: /* BT Gv,Ev */
4150 eip = dis_bt_G_E ( cb, sz, eip, BtOpNone );
4151 break;
4152 case 0xB3: /* BTR Gv,Ev */
4153 eip = dis_bt_G_E ( cb, sz, eip, BtOpReset );
4154 break;
4155 case 0xAB: /* BTS Gv,Ev */
4156 eip = dis_bt_G_E ( cb, sz, eip, BtOpSet );
4157 break;
4158 case 0xBB: /* BTC Gv,Ev */
4159 eip = dis_bt_G_E ( cb, sz, eip, BtOpComp );
4160 break;
4161
4162 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
4163
4164 case 0x40:
4165 case 0x41:
4166 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
4167 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
4168 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
4169 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
4170 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
4171 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
4172 case 0x48: /* CMOVSb (cmov negative) */
4173 case 0x49: /* CMOVSb (cmov not negative) */
4174 case 0x4A: /* CMOVP (cmov parity even) */
4175 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
4176 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
4177 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
4178 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
4179 eip = dis_cmov_E_G(cb, sz, (Condcode)(opc - 0x40), eip);
4180 break;
4181
4182 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
4183
4184 case 0xB1: /* CMPXCHG Gv,Ev */
4185 eip = dis_cmpxchg_G_E ( cb, sz, eip );
4186 break;
4187
4188 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
4189
4190 case 0xA2: /* CPUID */
4191 t1 = newTemp(cb);
4192 t2 = newTemp(cb);
4193 t3 = newTemp(cb);
4194 t4 = newTemp(cb);
4195 uInstr0(cb, CALLM_S, 0);
4196
4197 uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t1);
4198 uInstr1(cb, PUSH, 4, TempReg, t1);
4199
4200 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
4201 uLiteral(cb, 0);
4202 uInstr1(cb, PUSH, 4, TempReg, t2);
4203
4204 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t3);
4205 uLiteral(cb, 0);
4206 uInstr1(cb, PUSH, 4, TempReg, t3);
4207
4208 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
4209 uLiteral(cb, 0);
4210 uInstr1(cb, PUSH, 4, TempReg, t4);
4211
4212 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CPUID));
4213 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
4214
4215 uInstr1(cb, POP, 4, TempReg, t4);
4216 uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_EDX);
4217
4218 uInstr1(cb, POP, 4, TempReg, t3);
4219 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ECX);
4220
4221 uInstr1(cb, POP, 4, TempReg, t2);
4222 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBX);
4223
4224 uInstr1(cb, POP, 4, TempReg, t1);
4225 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
4226
4227 uInstr0(cb, CALLM_E, 0);
4228 if (dis) VG_(printf)("cpuid\n");
4229 break;
4230
4231 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
4232
4233 case 0xB6: /* MOVZXb Eb,Gv */
4234 eip = dis_movx_E_G ( cb, eip, 1, 4, False );
4235 break;
4236 case 0xB7: /* MOVZXw Ew,Gv */
4237 eip = dis_movx_E_G ( cb, eip, 2, 4, False );
4238 break;
4239
4240 case 0xBE: /* MOVSXb Eb,Gv */
4241 eip = dis_movx_E_G ( cb, eip, 1, 4, True );
4242 break;
4243 case 0xBF: /* MOVSXw Ew,Gv */
4244 eip = dis_movx_E_G ( cb, eip, 2, 4, True );
4245 break;
4246
4247 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
4248
4249 case 0xAF: /* IMUL Ev, Gv */
4250 eip = dis_mul_E_G ( cb, sz, eip, True );
4251 break;
4252
4253 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
4254 case 0x80:
4255 case 0x81:
4256 case 0x82: /* JBb/JNAEb (jump below) */
4257 case 0x83: /* JNBb/JAEb (jump not below) */
4258 case 0x84: /* JZb/JEb (jump zero) */
4259 case 0x85: /* JNZb/JNEb (jump not zero) */
4260 case 0x86: /* JBEb/JNAb (jump below or equal) */
4261 case 0x87: /* JNBEb/JAb (jump not below or equal) */
4262 case 0x88: /* JSb (jump negative) */
4263 case 0x89: /* JSb (jump not negative) */
4264 case 0x8A: /* JP (jump parity even) */
4265 case 0x8C: /* JLb/JNGEb (jump less) */
4266 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
4267 case 0x8E: /* JLEb/JNGb (jump less or equal) */
4268 case 0x8F: /* JGb/JNLEb (jump greater) */
4269 d32 = (eip+4) + getUDisp32(eip); eip += 4;
4270 uInstr1(cb, JMP, 0, Literal, 0);
4271 uLiteral(cb, d32);
4272 uCond(cb, (Condcode)(opc - 0x80));
4273 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
4274 uInstr1(cb, JMP, 0, Literal, 0);
4275 uLiteral(cb, eip);
4276 uCond(cb, CondAlways);
4277 *isEnd = True;
4278 if (dis)
4279 VG_(printf)("j%s-32 0x%x\n",
4280 VG_(nameCondcode)(opc - 0x80), d32);
4281 break;
4282
4283 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
4284
4285 case 0x31: /* RDTSC */
4286 t1 = newTemp(cb);
4287 t2 = newTemp(cb);
4288 t3 = newTemp(cb);
4289 uInstr0(cb, CALLM_S, 0);
4290 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
4291 uLiteral(cb, 0);
4292 uInstr1(cb, PUSH, 4, TempReg, t1);
4293 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
4294 uLiteral(cb, 0);
4295 uInstr1(cb, PUSH, 4, TempReg, t2);
4296 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_RDTSC));
4297 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
4298 uInstr1(cb, POP, 4, TempReg, t3);
4299 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EDX);
4300 uInstr1(cb, POP, 4, TempReg, t3);
4301 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EAX);
4302 uInstr0(cb, CALLM_E, 0);
4303 if (dis) VG_(printf)("rdtsc\n");
4304 break;
4305
4306 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
4307 case 0x90:
4308 case 0x91:
4309 case 0x92: /* set-Bb/set-NAEb (jump below) */
4310 case 0x93: /* set-NBb/set-AEb (jump not below) */
4311 case 0x94: /* set-Zb/set-Eb (jump zero) */
4312 case 0x95: /* set-NZb/set-NEb (jump not zero) */
4313 case 0x96: /* set-BEb/set-NAb (jump below or equal) */
4314 case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
4315 case 0x98: /* set-Sb (jump negative) */
4316 case 0x99: /* set-Sb (jump not negative) */
4317 case 0x9A: /* set-P (jump parity even) */
4318 case 0x9B: /* set-NP (jump parity odd) */
4319 case 0x9C: /* set-Lb/set-NGEb (jump less) */
4320 case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
4321 case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
4322 case 0x9F: /* set-Gb/set-NLEb (jump greater) */
4323 modrm = getUChar(eip);
4324 t1 = newTemp(cb);
4325 if (epartIsReg(modrm)) {
4326 eip++;
4327 uInstr1(cb, CC2VAL, 1, TempReg, t1);
4328 uCond(cb, (Condcode)(opc-0x90));
4329 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
4330 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, eregOfRM(modrm));
4331 if (dis) VG_(printf)("set%s %s\n",
4332 VG_(nameCondcode)(opc-0x90),
4333 nameIReg(1,eregOfRM(modrm)));
4334 } else {
4335 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
4336 t2 = LOW24(pair);
4337 eip += HI8(pair);
4338 uInstr1(cb, CC2VAL, 1, TempReg, t1);
4339 uCond(cb, (Condcode)(opc-0x90));
4340 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
4341 uInstr2(cb, STORE, 1, TempReg, t1, TempReg, t2);
4342 SMC_IF_ALL(cb);
4343 if (dis) VG_(printf)("set%s %s\n",
4344 VG_(nameCondcode)(opc-0x90),
4345 dis_buf);
4346 }
4347 break;
4348
4349 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
4350
4351 case 0xA4: /* SHLDv imm8,Gv,Ev */
4352 modrm = getUChar(eip);
4353 eip = dis_SHLRD_Gv_Ev (
4354 cb, eip, modrm, sz,
4355 Literal, getUChar(eip + lengthAMode(eip)),
4356 True );
4357 break;
4358 case 0xA5: /* SHLDv %cl,Gv,Ev */
4359 modrm = getUChar(eip);
4360 eip = dis_SHLRD_Gv_Ev (
4361 cb, eip, modrm, sz, ArchReg, R_CL, True );
4362 break;
4363
4364 case 0xAC: /* SHRDv imm8,Gv,Ev */
4365 modrm = getUChar(eip);
4366 eip = dis_SHLRD_Gv_Ev (
4367 cb, eip, modrm, sz,
4368 Literal, getUChar(eip + lengthAMode(eip)),
4369 False );
4370 break;
4371 case 0xAD: /* SHRDv %cl,Gv,Ev */
4372 modrm = getUChar(eip);
4373 eip = dis_SHLRD_Gv_Ev (
4374 cb, eip, modrm, sz, ArchReg, R_CL, False );
4375 break;
4376
4377 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
4378
4379 case 0xC1: /* XADD Gv,Ev */
4380 eip = dis_xadd_G_E ( cb, sz, eip );
4381 break;
4382
4383 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
4384
4385 default:
4386 VG_(printf)("disInstr: unhandled 2-byte opcode 0x%x\n",
4387 (UInt)opc);
4388 VG_(unimplemented)("unhandled x86 0x0F 2-byte opcode");
4389 }
4390
4391 break;
4392 }
4393
4394 /* ------------------------ ??? ------------------------ */
4395
4396 default:
4397 VG_(printf)("disInstr: unhandled opcode 0x%x then 0x%x\n",
4398 (UInt)opc, (UInt)getUChar(eip));
4399 VG_(panic)("unhandled x86 opcode");
4400 }
4401
4402 if (dis)
4403 VG_(printf)("\n");
4404 for (; first_uinstr < cb->used; first_uinstr++) {
4405 Bool sane = VG_(saneUInstr)(True, &cb->instrs[first_uinstr]);
4406 if (dis || !sane)
4407 VG_(ppUInstr)(sane ? first_uinstr : -1,
4408 &cb->instrs[first_uinstr]);
4409 vg_assert(sane);
4410 }
4411
4412 return eip;
4413}
4414
4415
4416/* Disassemble a complete basic block, starting at eip, and dumping
4417 the ucode into cb. Returns the size, in bytes, of the basic
4418 block. */
4419
4420Int VG_(disBB) ( UCodeBlock* cb, Addr eip0 )
4421{
4422 Addr eip = eip0;
4423 Bool isEnd = False;
4424 Bool block_sane;
4425 if (dis) VG_(printf)("\n");
4426
4427 if (VG_(clo_single_step)) {
4428 eip = disInstr ( cb, eip, &isEnd );
4429 uInstr1(cb, JMP, 0, Literal, 0);
4430 uLiteral(cb, eip);
4431 uCond(cb, CondAlways);
4432 if (dis) VG_(ppUInstr)(cb->used-1, &cb->instrs[cb->used-1]);
4433 } else {
4434 Int delta = 0;
4435 Addr eip2;
4436 while (True) {
4437 if (isEnd) break;
4438 eip2 = disInstr ( cb, eip, &isEnd );
4439 delta += (eip2 - eip);
4440 eip = eip2;
4441 if (delta > 4 && !isEnd) {
4442 uInstr1(cb, INCEIP, 0, Lit16, delta);
4443 if (dis) VG_(ppUInstr)(cb->used-1, &cb->instrs[cb->used-1]);
4444 delta = 0;
4445 }
4446 /* Split up giant basic blocks into pieces, so the
4447 translations fall within 64k. */
4448 if (eip - eip0 > 2000) {
4449 if (VG_(clo_verbosity) > 0)
4450 VG_(message)(Vg_DebugMsg,
4451 "Warning: splitting giant basic block into pieces");
4452 uInstr1(cb, JMP, 0, Literal, 0);
4453 uLiteral(cb, eip);
4454 uCond(cb, CondAlways);
4455 if (dis) VG_(ppUInstr)(cb->used-1, &cb->instrs[cb->used-1]);
4456 if (dis) VG_(printf)("\n");
4457 break;
4458 }
4459 if (dis) VG_(printf)("\n");
4460 }
4461 }
4462
4463 block_sane = VG_(saneUCodeBlock)(cb);
4464 if (!block_sane) {
4465 VG_(ppUCodeBlock)(cb, "block failing sanity check");
4466 vg_assert(block_sane);
4467 }
4468
4469 return eip - eip0;
4470}
4471
4472
4473/*--------------------------------------------------------------------*/
4474/*--- end vg_to_ucode.c ---*/
4475/*--------------------------------------------------------------------*/