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