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