blob: d6b03bc3e50e70ca7f1d22ee07fba26f719d175e [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{
sewardj9316cba2002-05-03 20:52:53 +00002761 Int t, t1, ta, helper;
sewardjde4a1d02002-03-22 01:27:54 +00002762 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);
sewardj9316cba2002-05-03 20:52:53 +00002771 t1 = newTemp(cb);
sewardjde4a1d02002-03-22 01:27:54 +00002772 t = newTemp(cb);
2773
sewardj9316cba2002-05-03 20:52:53 +00002774 uInstr0(cb, CALLM_S, 0);
2775 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t1);
2776 uInstr1(cb, PUSH, sz, TempReg, t1);
2777
sewardjde4a1d02002-03-22 01:27:54 +00002778 if (epartIsReg(modrm)) {
2779 eip++;
2780 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t);
2781 if (dis)
2782 VG_(printf)("bs%c%c %s, %s\n",
2783 fwds ? 'f' : 'r',
2784 nameISize(sz), nameIReg(sz, eregOfRM(modrm)),
2785 nameIReg(sz, gregOfRM(modrm)));
2786 } else {
2787 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
2788 ta = LOW24(pair);
2789 eip += HI8(pair);
2790 uInstr2(cb, LOAD, sz, TempReg, ta, TempReg, t);
2791 if (dis)
2792 VG_(printf)("bs%c%c %s, %s\n",
2793 fwds ? 'f' : 'r',
2794 nameISize(sz), dis_buf,
2795 nameIReg(sz, gregOfRM(modrm)));
2796 }
2797
sewardjde4a1d02002-03-22 01:27:54 +00002798 uInstr1(cb, PUSH, sz, TempReg, t);
2799 uInstr1(cb, CALLM, 0, Lit16, helper);
2800 uFlagsRWU(cb, FlagsEmpty, FlagZ, FlagsOSACP);
2801 uInstr1(cb, POP, sz, TempReg, t);
sewardj9316cba2002-05-03 20:52:53 +00002802 uInstr1(cb, POP, sz, TempReg, t);
sewardjde4a1d02002-03-22 01:27:54 +00002803 uInstr2(cb, PUT, sz, TempReg, t, ArchReg, gregOfRM(modrm));
2804 uInstr0(cb, CALLM_E, 0);
2805
2806 return eip;
2807}
2808
2809
2810static
2811void codegen_xchg_eAX_Reg ( UCodeBlock* cb, Int sz, Int reg )
2812{
2813 Int t1, t2;
2814 vg_assert(sz == 2 || sz == 4);
2815 t1 = newTemp(cb);
2816 t2 = newTemp(cb);
2817 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
2818 uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t2);
2819 uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, R_EAX);
2820 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
2821 if (dis)
2822 VG_(printf)("xchg%c %s, %s\n", nameISize(sz),
2823 nameIReg(sz, R_EAX), nameIReg(sz, reg));
2824}
2825
2826
2827static
2828void codegen_SAHF ( UCodeBlock* cb )
2829{
sewardj3a72df02002-03-24 10:03:17 +00002830 Int t = newTemp(cb);
2831 Int t2 = newTemp(cb);
sewardjde4a1d02002-03-22 01:27:54 +00002832 uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t);
sewardj3a72df02002-03-24 10:03:17 +00002833
2834 /* Mask out parts of t not corresponding to %AH. This stops the
2835 instrumenter complaining if they are undefined. Otherwise, the
2836 instrumenter would check all 32 bits of t at the PUSH, which
2837 could be the cause of incorrect warnings. Discovered by Daniel
2838 Veillard <veillard@redhat.com>.
2839 */
2840 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
2841 uLiteral(cb, 0x0000FF00);
2842 uInstr2(cb, AND, 4, TempReg, t2, TempReg, t);
2843 /* We deliberately don't set the condition codes here, since this
2844 AND is purely internal to Valgrind and nothing to do with the
2845 client's state. */
2846
sewardjde4a1d02002-03-22 01:27:54 +00002847 uInstr0(cb, CALLM_S, 0);
2848 uInstr1(cb, PUSH, 4, TempReg, t);
2849 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_SAHF));
2850 uFlagsRWU(cb, FlagsEmpty, FlagsSZACP, FlagsEmpty);
2851 uInstr1(cb, CLEAR, 0, Lit16, 4);
2852 uInstr0(cb, CALLM_E, 0);
2853}
2854
2855
2856static
2857Addr dis_cmpxchg_G_E ( UCodeBlock* cb,
2858 Int size,
2859 Addr eip0 )
2860{
2861 Int ta, junk, dest, src, acc;
2862 UChar dis_buf[50];
2863 UChar rm;
2864
2865 rm = getUChar(eip0);
2866 acc = newTemp(cb);
2867 src = newTemp(cb);
2868 dest = newTemp(cb);
2869 junk = newTemp(cb);
2870 /* Only needed to get gcc's dataflow analyser off my back. */
2871 ta = INVALID_TEMPREG;
2872
2873 if (epartIsReg(rm)) {
2874 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, dest);
2875 eip0++;
2876 if (dis) VG_(printf)("cmpxchg%c %s,%s\n",
2877 nameISize(size),
2878 nameIReg(size,gregOfRM(rm)),
2879 nameIReg(size,eregOfRM(rm)) );
2880 nameIReg(size,eregOfRM(rm));
2881 } else {
2882 UInt pair = disAMode ( cb, eip0, dis?dis_buf:NULL );
2883 ta = LOW24(pair);
2884 uInstr2(cb, LOAD, size, TempReg, ta, TempReg, dest);
2885 eip0 += HI8(pair);
2886 if (dis) VG_(printf)("cmpxchg%c %s,%s\n", nameISize(size),
2887 nameIReg(size,gregOfRM(rm)), dis_buf);
2888 }
2889
2890 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, src);
2891 uInstr2(cb, GET, size, ArchReg, R_EAX, TempReg, acc);
2892 uInstr2(cb, MOV, size, TempReg, acc, TempReg, junk);
2893 uInstr2(cb, SUB, size, TempReg, dest, TempReg, junk);
2894 setFlagsFromUOpcode(cb, SUB);
2895
2896 uInstr2(cb, CMOV, 4, TempReg, src, TempReg, dest);
2897 uCond(cb, CondZ);
2898 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
2899 uInstr2(cb, CMOV, 4, TempReg, dest, TempReg, acc);
2900 uCond(cb, CondNZ);
2901 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
2902
2903 uInstr2(cb, PUT, size, TempReg, acc, ArchReg, R_EAX);
2904 if (epartIsReg(rm)) {
2905 uInstr2(cb, PUT, size, TempReg, dest, ArchReg, eregOfRM(rm));
2906 } else {
2907 uInstr2(cb, STORE, size, TempReg, dest, TempReg, ta);
2908 }
2909
2910 return eip0;
2911}
2912
2913
2914/* Handle conditional move instructions of the form
2915 cmovcc E(reg-or-mem), G(reg)
2916
2917 E(src) is reg-or-mem
2918 G(dst) is reg.
2919
2920 If E is reg, --> GET %E, tmps
2921 GET %G, tmpd
2922 CMOVcc tmps, tmpd
2923 PUT tmpd, %G
2924
2925 If E is mem --> (getAddr E) -> tmpa
2926 LD (tmpa), tmps
2927 GET %G, tmpd
2928 CMOVcc tmps, tmpd
2929 PUT tmpd, %G
2930*/
2931static
2932Addr dis_cmov_E_G ( UCodeBlock* cb,
2933 Int size,
2934 Condcode cond,
2935 Addr eip0 )
2936{
2937 UChar rm = getUChar(eip0);
2938 UChar dis_buf[50];
2939
2940 Int tmps = newTemp(cb);
2941 Int tmpd = newTemp(cb);
2942
2943 if (epartIsReg(rm)) {
2944 uInstr2(cb, GET, size, ArchReg, eregOfRM(rm), TempReg, tmps);
2945 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmpd);
2946 uInstr2(cb, CMOV, 4, TempReg, tmps, TempReg, tmpd);
2947 uCond(cb, cond);
2948 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
2949 uInstr2(cb, PUT, size, TempReg, tmpd, ArchReg, gregOfRM(rm));
2950 if (dis) VG_(printf)("cmov%c%s %s,%s\n",
2951 nameISize(size),
2952 VG_(nameCondcode)(cond),
2953 nameIReg(size,eregOfRM(rm)),
2954 nameIReg(size,gregOfRM(rm)));
2955 return 1+eip0;
2956 }
2957
2958 /* E refers to memory */
2959 {
2960 UInt pair = disAMode ( cb, eip0, dis?dis_buf:NULL);
2961 Int tmpa = LOW24(pair);
2962 uInstr2(cb, LOAD, size, TempReg, tmpa, TempReg, tmps);
2963 uInstr2(cb, GET, size, ArchReg, gregOfRM(rm), TempReg, tmpd);
2964 uInstr2(cb, CMOV, 4, TempReg, tmps, TempReg, tmpd);
2965 uCond(cb, cond);
2966 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
2967 uInstr2(cb, PUT, size, TempReg, tmpd, ArchReg, gregOfRM(rm));
2968 if (dis) VG_(printf)("cmov%c%s %s,%s\n",
2969 nameISize(size),
2970 VG_(nameCondcode)(cond),
2971 dis_buf,
2972 nameIReg(size,gregOfRM(rm)));
2973 return HI8(pair)+eip0;
2974 }
2975}
2976
2977
2978static
2979Addr dis_xadd_G_E ( UCodeBlock* cb,
2980 Int sz,
2981 Addr eip0 )
2982{
2983 UChar rm = getUChar(eip0);
2984 UChar dis_buf[50];
2985
2986 Int tmpd = newTemp(cb);
2987 Int tmpt = newTemp(cb);
2988
2989 if (epartIsReg(rm)) {
2990 uInstr2(cb, GET, sz, ArchReg, eregOfRM(rm), TempReg, tmpd);
2991 uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
2992 uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
2993 setFlagsFromUOpcode(cb, ADD);
2994 uInstr2(cb, PUT, sz, TempReg, tmpt, ArchReg, eregOfRM(rm));
2995 uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
2996 if (dis)
2997 VG_(printf)("xadd%c %s, %s\n", nameISize(sz),
2998 nameIReg(sz,gregOfRM(rm)),
2999 nameIReg(sz,eregOfRM(rm)));
3000 return 1+eip0;
3001 } else {
3002 UInt pair = disAMode ( cb, eip0, dis?dis_buf:NULL);
3003 Int tmpa = LOW24(pair);
3004 uInstr2(cb, LOAD, sz, TempReg, tmpa, TempReg, tmpd);
3005 uInstr2(cb, GET, sz, ArchReg, gregOfRM(rm), TempReg, tmpt);
3006 uInstr2(cb, ADD, sz, TempReg, tmpd, TempReg, tmpt);
3007 setFlagsFromUOpcode(cb, ADD);
3008 uInstr2(cb, STORE, sz, TempReg, tmpt, TempReg, tmpa);
3009 SMC_IF_SOME(cb);
3010 uInstr2(cb, PUT, sz, TempReg, tmpd, ArchReg, gregOfRM(rm));
3011 if (dis)
3012 VG_(printf)("xadd%c %s, %s\n", nameISize(sz),
3013 nameIReg(sz,gregOfRM(rm)),
3014 dis_buf);
3015 return HI8(pair)+eip0;
3016 }
3017}
3018
3019
sewardjde4a1d02002-03-22 01:27:54 +00003020/*------------------------------------------------------------*/
3021/*--- Disassembling entire basic blocks ---*/
3022/*------------------------------------------------------------*/
3023
3024/* Disassemble a single instruction into ucode, returning the update
3025 eip, and setting *isEnd to True if this is the last insn in a basic
3026 block. Also do debug printing if (dis). */
3027
3028static Addr disInstr ( UCodeBlock* cb, Addr eip, Bool* isEnd )
3029{
3030 UChar opc, modrm, abyte;
3031 UInt d32, pair;
3032 Int t1, t2, t3, t4;
3033 UChar dis_buf[50];
3034 Int am_sz, d_sz;
3035
3036 Int sz = 4;
3037 Int first_uinstr = cb->used;
3038 *isEnd = False;
3039 t1 = t2 = t3 = t4 = INVALID_TEMPREG;
3040
3041 if (dis) VG_(printf)("\t0x%x: ", eip);
3042
sewardjc7529c32002-04-16 01:55:18 +00003043 /* Spot the client-request magic sequence. */
3044 {
sewardjde4a1d02002-03-22 01:27:54 +00003045 UChar* myeip = (UChar*)eip;
3046 /* Spot this:
3047 C1C01D roll $29, %eax
3048 C1C003 roll $3, %eax
sewardj2e93c502002-04-12 11:12:52 +00003049 C1C81B rorl $27, %eax
3050 C1C805 rorl $5, %eax
3051 C1C00D roll $13, %eax
3052 C1C013 roll $19, %eax
sewardjde4a1d02002-03-22 01:27:54 +00003053 */
sewardj2e93c502002-04-12 11:12:52 +00003054 if (myeip[ 0] == 0xC1 && myeip[ 1] == 0xC0 && myeip[ 2] == 0x1D &&
3055 myeip[ 3] == 0xC1 && myeip[ 4] == 0xC0 && myeip[ 5] == 0x03 &&
3056 myeip[ 6] == 0xC1 && myeip[ 7] == 0xC8 && myeip[ 8] == 0x1B &&
3057 myeip[ 9] == 0xC1 && myeip[10] == 0xC8 && myeip[11] == 0x05 &&
3058 myeip[12] == 0xC1 && myeip[13] == 0xC0 && myeip[14] == 0x0D &&
3059 myeip[15] == 0xC1 && myeip[16] == 0xC0 && myeip[17] == 0x13
3060 ) {
3061 eip += 18;
3062 uInstr1(cb, JMP, 0, Literal, 0);
3063 uLiteral(cb, eip);
3064 uCond(cb, CondAlways);
3065 LAST_UINSTR(cb).jmpkind = JmpClientReq;
3066 *isEnd = True;
3067 if (dis)
3068 VG_(printf)("%%edx = client_request ( %%eax )\n");
sewardjde4a1d02002-03-22 01:27:54 +00003069 return eip;
3070 }
3071 }
3072
3073 /* Skip a LOCK prefix. */
sewardj5716dbb2002-04-26 03:28:18 +00003074 if (getUChar(eip) == 0xF0) {
3075 /* VG_(printf)("LOCK LOCK LOCK LOCK LOCK \n"); */
3076 eip++;
3077 }
sewardjde4a1d02002-03-22 01:27:54 +00003078
3079 /* Crap out if we see a segment override prefix. */
3080 if (getUChar(eip) == 0x65) {
3081 VG_(message)(Vg_DebugMsg, "");
3082 VG_(message)(Vg_DebugMsg, "Possible workaround for the following abort: do not use special");
3083 VG_(message)(Vg_DebugMsg, "PII/PIII-specific pthreads library (possibly in /lib/i686/*.so).");
3084 VG_(message)(Vg_DebugMsg, "You might be able to kludge around this by renaming /lib/i686 to");
3085 VG_(message)(Vg_DebugMsg, "/lib/i686-HIDDEN. On RedHat 7.2 this causes ld.so to fall back");
3086 VG_(message)(Vg_DebugMsg, "to using the less specialised versions in /lib instead, which");
3087 VG_(message)(Vg_DebugMsg, "valgrind might be able to better deal with.");
3088 VG_(message)(Vg_DebugMsg, "");
3089 VG_(message)(Vg_DebugMsg, "WARNING. WARNING. WARNING. WARNING. WARNING. WARNING. WARNING.");
3090 VG_(message)(Vg_DebugMsg, "WARNING: The suggested kludge may also render your system unbootable");
3091 VG_(message)(Vg_DebugMsg, "WARNING: or otherwise totally screw it up. Only try this if you");
3092 VG_(message)(Vg_DebugMsg, "WARNING: know what you are doing, and are prepared to take risks.");
3093 VG_(message)(Vg_DebugMsg, "YOU HAVE BEEN WARNED. YOU HAVE BEEN WARNED. YOU HAVE BEEN WARNED.");
3094 VG_(message)(Vg_DebugMsg, "");
3095 VG_(message)(Vg_DebugMsg, "Another consideration is that this may well mean your application");
3096 VG_(message)(Vg_DebugMsg, "uses threads, which valgrind doesn't currently support, so even if");
3097 VG_(message)(Vg_DebugMsg, "you work around this problem, valgrind may abort later if it sees");
3098 VG_(message)(Vg_DebugMsg, "a clone() system call.");
3099 VG_(unimplemented)("x86 segment override (SEG=GS) prefix; see above for details");
3100 }
3101
3102 /* Detect operand-size overrides. */
3103 if (getUChar(eip) == 0x66) { sz = 2; eip++; };
3104
3105 opc = getUChar(eip); eip++;
3106
3107 switch (opc) {
3108
3109 /* ------------------------ Control flow --------------- */
3110
3111 case 0xC2: /* RET imm16 */
3112 d32 = getUDisp16(eip); eip += 2;
3113 goto do_Ret;
3114 case 0xC3: /* RET */
3115 d32 = 0;
3116 goto do_Ret;
3117 do_Ret:
3118 t1 = newTemp(cb); t2 = newTemp(cb);
3119 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
3120 uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t2);
3121 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1);
3122 uLiteral(cb, 4+d32);
3123 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3124 uInstr1(cb, JMP, 0, TempReg, t2);
3125 uCond(cb, CondAlways);
sewardj2e93c502002-04-12 11:12:52 +00003126 LAST_UINSTR(cb).jmpkind = JmpRet;
sewardjde4a1d02002-03-22 01:27:54 +00003127
3128 *isEnd = True;
3129 if (dis) {
3130 if (d32 == 0) VG_(printf)("ret\n");
3131 else VG_(printf)("ret %d\n", d32);
3132 }
3133 break;
3134
3135 case 0xE8: /* CALL J4 */
3136 d32 = getUDisp32(eip); eip += 4;
3137 d32 += eip; /* eip now holds return-to addr, d32 is call-to addr */
sewardjde4a1d02002-03-22 01:27:54 +00003138 if (d32 == eip && getUChar(eip) >= 0x58
3139 && getUChar(eip) <= 0x5F) {
3140 /* Specially treat the position-independent-code idiom
3141 call X
3142 X: popl %reg
3143 as
3144 movl %eip, %reg.
3145 since this generates better code, but for no other reason. */
3146 Int archReg = getUChar(eip) - 0x58;
3147 /* VG_(printf)("-- fPIC thingy\n"); */
3148 t1 = newTemp(cb);
3149 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
3150 uLiteral(cb, eip);
3151 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, archReg);
3152 eip++; /* Step over the POP */
3153 if (dis)
3154 VG_(printf)("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
3155 } else {
3156 /* The normal sequence for a call. */
3157 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3158 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
3159 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t1);
3160 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t1);
3161 uLiteral(cb, 4);
3162 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3163 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
3164 uLiteral(cb, eip);
3165 uInstr2(cb, STORE, 4, TempReg, t2, TempReg, t1);
3166 SMC_IF_ALL(cb);
3167 uInstr1(cb, JMP, 0, Literal, 0);
3168 uLiteral(cb, d32);
3169 uCond(cb, CondAlways);
sewardj2e93c502002-04-12 11:12:52 +00003170 LAST_UINSTR(cb).jmpkind = JmpCall;
sewardjde4a1d02002-03-22 01:27:54 +00003171 *isEnd = True;
3172 if (dis) VG_(printf)("call 0x%x\n",d32);
3173 }
3174 break;
3175
3176 case 0xC9: /* LEAVE */
3177 t1 = newTemp(cb); t2 = newTemp(cb);
3178 uInstr2(cb, GET, 4, ArchReg, R_EBP, TempReg, t1);
3179 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3180 uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t2);
3181 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBP);
3182 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1);
3183 uLiteral(cb, 4);
3184 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3185 if (dis) VG_(printf)("leave");
3186 break;
3187
sewardj4d0ab1f2002-03-24 10:00:09 +00003188 /* ---------------- Misc wierd-ass insns --------------- */
3189
sewardjfe8a1662002-03-24 11:54:07 +00003190 case 0x27: /* DAA */
sewardj4d0ab1f2002-03-24 10:00:09 +00003191 case 0x2F: /* DAS */
3192 t1 = newTemp(cb);
3193 uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
3194 /* Widen %AL to 32 bits, so it's all defined when we push it. */
3195 uInstr1(cb, WIDEN, 4, TempReg, t1);
3196 LAST_UINSTR(cb).extra4b = 1;
3197 LAST_UINSTR(cb).signed_widen = False;
3198 uInstr0(cb, CALLM_S, 0);
3199 uInstr1(cb, PUSH, 4, TempReg, t1);
sewardjfe8a1662002-03-24 11:54:07 +00003200 uInstr1(cb, CALLM, 0, Lit16,
3201 opc == 0x27 ? VGOFF_(helper_DAA) : VGOFF_(helper_DAS) );
sewardj4d0ab1f2002-03-24 10:00:09 +00003202 uFlagsRWU(cb, FlagsAC, FlagsOSZACP, FlagsEmpty);
3203 uInstr1(cb, POP, 4, TempReg, t1);
3204 uInstr0(cb, CALLM_E, 0);
3205 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
sewardjfe8a1662002-03-24 11:54:07 +00003206 if (dis) VG_(printf)(opc == 0x27 ? "daa\n" : "das\n");
3207 break;
sewardj4d0ab1f2002-03-24 10:00:09 +00003208
sewardjde4a1d02002-03-22 01:27:54 +00003209 /* ------------------------ CWD/CDQ -------------------- */
3210
3211 case 0x98: /* CBW */
3212 t1 = newTemp(cb);
3213 if (sz == 4) {
3214 uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
3215 uInstr1(cb, WIDEN, 4, TempReg, t1); /* 4 == dst size */
3216 LAST_UINSTR(cb).extra4b = 2; /* the source size */
3217 LAST_UINSTR(cb).signed_widen = True;
3218 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
3219 if (dis) VG_(printf)("cwd\n");
3220 } else {
3221 vg_assert(sz == 2);
3222 uInstr2(cb, GET, 1, ArchReg, R_EAX, TempReg, t1);
3223 uInstr1(cb, WIDEN, 2, TempReg, t1); /* 2 == dst size */
3224 LAST_UINSTR(cb).extra4b = 1; /* the source size */
3225 LAST_UINSTR(cb).signed_widen = True;
3226 uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
3227 if (dis) VG_(printf)("cbw\n");
3228 }
3229 break;
3230
3231 case 0x99: /* CWD/CDQ */
3232 t1 = newTemp(cb);
3233 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
3234 uInstr2(cb, SAR, sz, Literal, 0, TempReg, t1);
3235 uLiteral(cb, sz == 2 ? 15 : 31);
3236 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EDX);
3237 if (dis) VG_(printf)(sz == 2 ? "cwdq\n" : "cdqq\n");
3238 break;
3239
3240 /* ------------------------ FPU ops -------------------- */
3241
3242 case 0x9E: /* SAHF */
3243 codegen_SAHF ( cb );
3244 if (dis) VG_(printf)("sahf\n");
3245 break;
3246
3247 case 0x9B: /* FWAIT */
3248 /* ignore? */
3249 if (dis) VG_(printf)("fwait\n");
3250 break;
3251
3252 case 0xD8:
3253 case 0xD9:
3254 case 0xDA:
3255 case 0xDB:
3256 case 0xDC:
3257 case 0xDD:
3258 case 0xDE:
3259 case 0xDF:
3260 eip = dis_fpu ( cb, opc, eip );
3261 break;
3262
3263 /* ------------------------ INC & DEC ------------------ */
3264
3265 case 0x40: /* INC eAX */
3266 case 0x41: /* INC eCX */
3267 case 0x42: /* INC eDX */
3268 case 0x43: /* INC eBX */
3269 case 0x45: /* INC eBP */
3270 case 0x46: /* INC eSI */
3271 case 0x47: /* INC eDI */
3272 t1 = newTemp(cb);
3273 uInstr2(cb, GET, sz, ArchReg, (UInt)(opc - 0x40),
3274 TempReg, t1);
3275 uInstr1(cb, INC, sz, TempReg, t1);
3276 setFlagsFromUOpcode(cb, INC);
3277 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg,
3278 (UInt)(opc - 0x40));
3279 if (dis)
3280 VG_(printf)("inc%c %s\n", nameISize(sz), nameIReg(sz,opc-0x40));
3281 break;
3282
3283 case 0x48: /* DEC eAX */
3284 case 0x49: /* DEC eCX */
3285 case 0x4A: /* DEC eDX */
3286 case 0x4B: /* DEC eBX */
3287 case 0x4D: /* DEC eBP */
3288 case 0x4E: /* DEC eSI */
3289 case 0x4F: /* DEC eDI */
3290 t1 = newTemp(cb);
3291 uInstr2(cb, GET, sz, ArchReg, (UInt)(opc - 0x48),
3292 TempReg, t1);
3293 uInstr1(cb, DEC, sz, TempReg, t1);
3294 setFlagsFromUOpcode(cb, DEC);
3295 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg,
3296 (UInt)(opc - 0x48));
3297 if (dis)
3298 VG_(printf)("dec%c %s\n", nameISize(sz), nameIReg(sz,opc-0x48));
3299 break;
3300
3301 /* ------------------------ INT ------------------------ */
3302
3303 case 0xCD: /* INT imm8 */
3304 d32 = getUChar(eip); eip++;
3305 if (d32 != 0x80) VG_(panic)("disInstr: INT but not 0x80 !");
3306 /* It's important that all ArchRegs carry their up-to-date value
3307 at this point. So we declare an end-of-block here, which
3308 forces any TempRegs caching ArchRegs to be flushed. */
sewardjde4a1d02002-03-22 01:27:54 +00003309 uInstr1(cb, JMP, 0, Literal, 0);
3310 uLiteral(cb, eip);
3311 uCond(cb, CondAlways);
sewardj2e93c502002-04-12 11:12:52 +00003312 LAST_UINSTR(cb).jmpkind = JmpSyscall;
sewardjde4a1d02002-03-22 01:27:54 +00003313 *isEnd = True;
3314 if (dis) VG_(printf)("int $0x80\n");
3315 break;
3316
3317 /* ------------------------ Jcond, byte offset --------- */
3318
3319 case 0xEB: /* Jb (jump, byte offset) */
3320 d32 = (eip+1) + getSDisp8(eip); eip++;
3321 uInstr1(cb, JMP, 0, Literal, 0);
3322 uLiteral(cb, d32);
3323 uCond(cb, CondAlways);
3324 *isEnd = True;
3325 if (dis)
3326 VG_(printf)("jmp-8 0x%x\n", d32);
3327 break;
3328
3329 case 0xE9: /* Jv (jump, 16/32 offset) */
3330 d32 = (eip+sz) + getSDisp(sz,eip); eip += sz;
3331 uInstr1(cb, JMP, 0, Literal, 0);
3332 uLiteral(cb, d32);
3333 uCond(cb, CondAlways);
3334 *isEnd = True;
3335 if (dis)
3336 VG_(printf)("jmp 0x%x\n", d32);
3337 break;
3338
3339 case 0x70:
3340 case 0x71:
3341 case 0x72: /* JBb/JNAEb (jump below) */
3342 case 0x73: /* JNBb/JAEb (jump not below) */
3343 case 0x74: /* JZb/JEb (jump zero) */
3344 case 0x75: /* JNZb/JNEb (jump not zero) */
3345 case 0x76: /* JBEb/JNAb (jump below or equal) */
3346 case 0x77: /* JNBEb/JAb (jump not below or equal) */
3347 case 0x78: /* JSb (jump negative) */
3348 case 0x79: /* JSb (jump not negative) */
3349 case 0x7A: /* JP (jump parity even) */
3350 case 0x7B: /* JNP/JPO (jump parity odd) */
3351 case 0x7C: /* JLb/JNGEb (jump less) */
3352 case 0x7D: /* JGEb/JNLb (jump greater or equal) */
3353 case 0x7E: /* JLEb/JNGb (jump less or equal) */
3354 case 0x7F: /* JGb/JNLEb (jump greater) */
3355 d32 = (eip+1) + getSDisp8(eip); eip++;
3356 uInstr1(cb, JMP, 0, Literal, 0);
3357 uLiteral(cb, d32);
3358 uCond(cb, (Condcode)(opc - 0x70));
3359 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
3360 /* It's actually acceptable not to end this basic block at a
3361 control transfer, reducing the number of jumps through
3362 vg_dispatch, at the expense of possibly translating the insns
3363 following this jump twice. This does give faster code, but
3364 on the whole I don't think the effort is worth it. */
3365 uInstr1(cb, JMP, 0, Literal, 0);
3366 uLiteral(cb, eip);
3367 uCond(cb, CondAlways);
3368 *isEnd = True;
3369 /* The above 3 lines would be removed if the bb was not to end
3370 here. */
3371 if (dis)
3372 VG_(printf)("j%s-8 0x%x\n", VG_(nameCondcode)(opc - 0x70), d32);
3373 break;
3374
3375 case 0xE3: /* JECXZ or perhaps JCXZ, depending on OSO ? Intel
3376 manual says it depends on address size override,
3377 which doesn't sound right to me. */
3378 d32 = (eip+1) + getSDisp8(eip); eip++;
3379 t1 = newTemp(cb);
3380 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
3381 uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
3382 uLiteral(cb, d32);
3383 if (dis)
3384 VG_(printf)("j%sz 0x%x\n", nameIReg(sz, R_ECX), d32);
3385 break;
3386
3387 case 0xE2: /* LOOP disp8 */
3388 /* Again, the docs say this uses ECX/CX as a count depending on
3389 the address size override, not the operand one. Since we
3390 don't handle address size overrides, I guess that means
3391 ECX. */
3392 d32 = (eip+1) + getSDisp8(eip); eip++;
3393 t1 = newTemp(cb);
3394 uInstr2(cb, GET, 4, ArchReg, R_ECX, TempReg, t1);
3395 uInstr1(cb, DEC, 4, TempReg, t1);
3396 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ECX);
3397 uInstr2(cb, JIFZ, 4, TempReg, t1, Literal, 0);
3398 uLiteral(cb, eip);
3399 uInstr1(cb, JMP, 0, Literal, 0);
3400 uLiteral(cb, d32);
3401 uCond(cb, CondAlways);
3402 *isEnd = True;
3403 if (dis)
3404 VG_(printf)("loop 0x%x\n", d32);
3405 break;
3406
3407 /* ------------------------ IMUL ----------------------- */
3408
3409 case 0x69: /* IMUL Iv, Ev, Gv */
3410 eip = dis_imul_I_E_G ( cb, sz, eip, sz );
3411 break;
3412 case 0x6B: /* IMUL Ib, Ev, Gv */
3413 eip = dis_imul_I_E_G ( cb, sz, eip, 1 );
3414 break;
3415
3416 /* ------------------------ MOV ------------------------ */
3417
3418 case 0x88: /* MOV Gb,Eb */
3419 eip = dis_mov_G_E(cb, 1, eip);
3420 break;
3421
3422 case 0x89: /* MOV Gv,Ev */
3423 eip = dis_mov_G_E(cb, sz, eip);
3424 break;
3425
3426 case 0x8A: /* MOV Eb,Gb */
3427 eip = dis_mov_E_G(cb, 1, eip);
3428 break;
3429
3430 case 0x8B: /* MOV Ev,Gv */
3431 eip = dis_mov_E_G(cb, sz, eip);
3432 break;
3433
3434 case 0x8D: /* LEA M,Gv */
3435 modrm = getUChar(eip);
3436 if (epartIsReg(modrm))
3437 VG_(panic)("LEA M,Gv: modRM refers to register");
3438 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
3439 eip += HI8(pair);
3440 t1 = LOW24(pair);
3441 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, gregOfRM(modrm));
3442 if (dis)
3443 VG_(printf)("lea%c %s, %s\n", nameISize(sz), dis_buf,
3444 nameIReg(sz,gregOfRM(modrm)));
3445 break;
3446
3447 case 0xA0: /* MOV Ob,AL */
3448 sz = 1;
3449 /* Fall through ... */
3450 case 0xA1: /* MOV Ov,eAX */
3451 d32 = getUDisp32(eip); eip += 4;
3452 t1 = newTemp(cb); t2 = newTemp(cb);
3453 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
3454 uLiteral(cb, d32);
3455 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3456 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, R_EAX);
3457 if (dis) VG_(printf)("mov%c 0x%x,%s\n", nameISize(sz),
3458 d32, nameIReg(sz,R_EAX));
3459 break;
3460
3461 case 0xA2: /* MOV AL,Ob */
3462 sz = 1;
3463 /* Fall through ... */
3464 case 0xA3: /* MOV eAX,Ov */
3465 d32 = getUDisp32(eip); eip += 4;
3466 t1 = newTemp(cb); t2 = newTemp(cb);
3467 uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, t1);
3468 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
3469 uLiteral(cb, d32);
3470 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3471 SMC_IF_SOME(cb);
3472 if (dis) VG_(printf)("mov%c %s,0x%x\n", nameISize(sz),
3473 nameIReg(sz,R_EAX), d32);
3474 break;
3475
3476 case 0xB0: /* MOV imm,AL */
3477 case 0xB1: /* MOV imm,CL */
3478 case 0xB2: /* MOV imm,DL */
3479 case 0xB3: /* MOV imm,BL */
3480 case 0xB4: /* MOV imm,AH */
3481 case 0xB5: /* MOV imm,CH */
3482 case 0xB6: /* MOV imm,DH */
3483 case 0xB7: /* MOV imm,BH */
3484 d32 = getUChar(eip); eip += 1;
3485 t1 = newTemp(cb);
3486 uInstr2(cb, MOV, 1, Literal, 0, TempReg, t1);
3487 uLiteral(cb, d32);
3488 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, opc-0xB0);
3489 if (dis) VG_(printf)("movb $0x%x,%s\n", d32,
3490 nameIReg(1,opc-0xB0));
3491 break;
3492
3493 case 0xB8: /* MOV imm,eAX */
3494 case 0xB9: /* MOV imm,eCX */
3495 case 0xBA: /* MOV imm,eDX */
3496 case 0xBB: /* MOV imm,eBX */
3497 case 0xBD: /* MOV imm,eBP */
3498 case 0xBE: /* MOV imm,eSI */
3499 case 0xBF: /* MOV imm,eDI */
3500 d32 = getUDisp(sz,eip); eip += sz;
3501 t1 = newTemp(cb);
3502 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t1);
3503 uLiteral(cb, d32);
3504 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, opc-0xB8);
3505 if (dis) VG_(printf)("mov%c $0x%x,%s\n", nameISize(sz), d32,
3506 nameIReg(sz,opc-0xB8));
3507 break;
3508
3509 case 0xC6: /* MOV Ib,Eb */
3510 sz = 1;
3511 goto do_Mov_I_E;
3512 case 0xC7: /* MOV Iv,Ev */
3513 goto do_Mov_I_E;
3514
3515 do_Mov_I_E:
3516 modrm = getUChar(eip);
3517 if (epartIsReg(modrm)) {
3518 d32 = getUDisp(sz,eip); eip += sz;
3519 t1 = newTemp(cb);
3520 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t1);
3521 uLiteral(cb, d32);
3522 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, eregOfRM(modrm));
3523 if (dis) VG_(printf)("mov%c $0x%x, %s\n", nameISize(sz), d32,
3524 nameIReg(sz,eregOfRM(modrm)));
3525 } else {
3526 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
3527 eip += HI8(pair);
3528 d32 = getUDisp(sz,eip); eip += sz;
3529 t1 = newTemp(cb);
3530 t2 = LOW24(pair);
3531 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t1);
3532 uLiteral(cb, d32);
3533 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3534 SMC_IF_SOME(cb);
3535 if (dis) VG_(printf)("mov%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
3536 }
3537 break;
3538
3539 /* ------------------------ opl imm, A ----------------- */
3540
3541 case 0x04: /* ADD Ib, AL */
3542 eip = dis_op_imm_A(cb, 1, ADD, True, eip, "add" );
3543 break;
3544 case 0x05: /* ADD Iv, eAX */
3545 eip = dis_op_imm_A(cb, sz, ADD, True, eip, "add" );
3546 break;
3547
3548 case 0x0C: /* OR Ib, AL */
3549 eip = dis_op_imm_A(cb, 1, OR, True, eip, "or" );
3550 break;
3551 case 0x0D: /* OR Iv, eAX */
3552 eip = dis_op_imm_A(cb, sz, OR, True, eip, "or" );
3553 break;
3554
sewardje9c06f12002-05-08 01:44:03 +00003555 case 0x1C: /* SBB Ib, AL */
3556 eip = dis_op_imm_A(cb, 1, SBB, True, eip, "sbb" );
3557 break;
3558
sewardjde4a1d02002-03-22 01:27:54 +00003559 case 0x24: /* AND Ib, AL */
3560 eip = dis_op_imm_A(cb, 1, AND, True, eip, "and" );
3561 break;
3562 case 0x25: /* AND Iv, eAX */
3563 eip = dis_op_imm_A(cb, sz, AND, True, eip, "and" );
3564 break;
3565
3566 case 0x2C: /* SUB Ib, AL */
3567 eip = dis_op_imm_A(cb, 1, SUB, True, eip, "sub" );
3568 break;
3569 case 0x2D: /* SUB Iv, eAX */
3570 eip = dis_op_imm_A(cb, sz, SUB, True, eip, "sub" );
3571 break;
3572
3573 case 0x34: /* XOR Ib, AL */
3574 eip = dis_op_imm_A(cb, 1, XOR, True, eip, "xor" );
3575 break;
3576 case 0x35: /* XOR Iv, eAX */
3577 eip = dis_op_imm_A(cb, sz, XOR, True, eip, "xor" );
3578 break;
3579
3580 case 0x3C: /* CMP Ib, AL */
3581 eip = dis_op_imm_A(cb, 1, SUB, False, eip, "cmp" );
3582 break;
3583 case 0x3D: /* CMP Iv, eAX */
3584 eip = dis_op_imm_A(cb, sz, SUB, False, eip, "cmp" );
3585 break;
3586
3587 case 0xA8: /* TEST Ib, AL */
3588 eip = dis_op_imm_A(cb, 1, AND, False, eip, "test" );
3589 break;
3590 case 0xA9: /* TEST Iv, eAX */
3591 eip = dis_op_imm_A(cb, sz, AND, False, eip, "test" );
3592 break;
3593
3594 /* ------------------------ opl Ev, Gv ----------------- */
3595
3596 case 0x02: /* ADD Eb,Gb */
3597 eip = dis_op2_E_G ( cb, ADD, True, 1, eip, "add" );
3598 break;
3599 case 0x03: /* ADD Ev,Gv */
3600 eip = dis_op2_E_G ( cb, ADD, True, sz, eip, "add" );
3601 break;
3602
3603 case 0x0A: /* OR Eb,Gb */
3604 eip = dis_op2_E_G ( cb, OR, True, 1, eip, "or" );
3605 break;
3606 case 0x0B: /* OR Ev,Gv */
3607 eip = dis_op2_E_G ( cb, OR, True, sz, eip, "or" );
3608 break;
3609
3610 case 0x13: /* ADC Ev,Gv */
3611 eip = dis_op2_E_G ( cb, ADC, True, sz, eip, "adc" );
3612 break;
3613
3614 case 0x1B: /* SBB Ev,Gv */
3615 eip = dis_op2_E_G ( cb, SBB, True, sz, eip, "sbb" );
3616 break;
3617
3618 case 0x22: /* AND Eb,Gb */
3619 eip = dis_op2_E_G ( cb, AND, True, 1, eip, "and" );
3620 break;
3621 case 0x23: /* AND Ev,Gv */
3622 eip = dis_op2_E_G ( cb, AND, True, sz, eip, "and" );
3623 break;
3624
3625 case 0x2A: /* SUB Eb,Gb */
3626 eip = dis_op2_E_G ( cb, SUB, True, 1, eip, "sub" );
3627 break;
3628 case 0x2B: /* SUB Ev,Gv */
3629 eip = dis_op2_E_G ( cb, SUB, True, sz, eip, "sub" );
3630 break;
3631
3632 case 0x32: /* XOR Eb,Gb */
3633 eip = dis_op2_E_G ( cb, XOR, True, 1, eip, "xor" );
3634 break;
3635 case 0x33: /* XOR Ev,Gv */
3636 eip = dis_op2_E_G ( cb, XOR, True, sz, eip, "xor" );
3637 break;
3638
3639 case 0x3A: /* CMP Eb,Gb */
3640 eip = dis_op2_E_G ( cb, SUB, False, 1, eip, "cmp" );
3641 break;
3642 case 0x3B: /* CMP Ev,Gv */
3643 eip = dis_op2_E_G ( cb, SUB, False, sz, eip, "cmp" );
3644 break;
3645
3646 case 0x84: /* TEST Eb,Gb */
3647 eip = dis_op2_E_G ( cb, AND, False, 1, eip, "test" );
3648 break;
3649 case 0x85: /* TEST Ev,Gv */
3650 eip = dis_op2_E_G ( cb, AND, False, sz, eip, "test" );
3651 break;
3652
3653 /* ------------------------ opl Gv, Ev ----------------- */
3654
3655 case 0x00: /* ADD Gb,Eb */
3656 eip = dis_op2_G_E ( cb, ADD, True, 1, eip, "add" );
3657 break;
3658 case 0x01: /* ADD Gv,Ev */
3659 eip = dis_op2_G_E ( cb, ADD, True, sz, eip, "add" );
3660 break;
3661
3662 case 0x08: /* OR Gb,Eb */
3663 eip = dis_op2_G_E ( cb, OR, True, 1, eip, "or" );
3664 break;
3665 case 0x09: /* OR Gv,Ev */
3666 eip = dis_op2_G_E ( cb, OR, True, sz, eip, "or" );
3667 break;
3668
3669 case 0x11: /* ADC Gv,Ev */
3670 eip = dis_op2_G_E ( cb, ADC, True, sz, eip, "adc" );
3671 break;
3672
3673 case 0x19: /* SBB Gv,Ev */
3674 eip = dis_op2_G_E ( cb, SBB, True, sz, eip, "sbb" );
3675 break;
3676
3677 case 0x20: /* AND Gb,Eb */
3678 eip = dis_op2_G_E ( cb, AND, True, 1, eip, "and" );
3679 break;
3680 case 0x21: /* AND Gv,Ev */
3681 eip = dis_op2_G_E ( cb, AND, True, sz, eip, "and" );
3682 break;
3683
3684 case 0x28: /* SUB Gb,Eb */
3685 eip = dis_op2_G_E ( cb, SUB, True, 1, eip, "sub" );
3686 break;
3687 case 0x29: /* SUB Gv,Ev */
3688 eip = dis_op2_G_E ( cb, SUB, True, sz, eip, "sub" );
3689 break;
3690
3691 case 0x30: /* XOR Gb,Eb */
3692 eip = dis_op2_G_E ( cb, XOR, True, 1, eip, "xor" );
3693 break;
3694 case 0x31: /* XOR Gv,Ev */
3695 eip = dis_op2_G_E ( cb, XOR, True, sz, eip, "xor" );
3696 break;
3697
3698 case 0x38: /* CMP Gb,Eb */
3699 eip = dis_op2_G_E ( cb, SUB, False, 1, eip, "cmp" );
3700 break;
3701 case 0x39: /* CMP Gv,Ev */
3702 eip = dis_op2_G_E ( cb, SUB, False, sz, eip, "cmp" );
3703 break;
3704
3705 /* ------------------------ POP ------------------------ */
3706
3707 case 0x58: /* POP eAX */
3708 case 0x59: /* POP eCX */
3709 case 0x5A: /* POP eDX */
3710 case 0x5B: /* POP eBX */
sewardjde4a1d02002-03-22 01:27:54 +00003711 case 0x5D: /* POP eBP */
3712 case 0x5E: /* POP eSI */
3713 case 0x5F: /* POP eDI */
sewardj4f51f9a2002-05-07 23:38:30 +00003714 { Int n_pops;
3715 Addr eipS, eipE;
3716 UChar ch;
sewardj95621db2002-05-08 21:26:01 +00003717 if (sz != 4) goto normal_pop_case;
3718 if (VG_(clo_cachesim)) goto normal_pop_case;
sewardj4f51f9a2002-05-07 23:38:30 +00003719 /* eip points at first pop insn + 1. Make eipS and eipE
3720 bracket the sequence. */
3721 eipE = eipS = eip - 1;
3722 while (True) {
3723 ch = getUChar(eipE+1);
3724 if (ch < 0x58 || ch > 0x5F || ch == 0x5C) break;
3725 eipE++;
3726 }
3727 n_pops = eipE - eipS + 1;
3728 if (0 && n_pops > 1) VG_(printf)("%d pops\n", n_pops);
3729 t1 = newTemp(cb); t3 = newTemp(cb);
3730 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
3731 for (; eipS <= eipE; eipS++) {
3732 ch = getUChar(eipS);
3733 uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t3);
3734 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, ch-0x58);
3735 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1);
3736 uLiteral(cb, 4);
3737 SMC_IF_ALL(cb);
3738 if (dis)
3739 VG_(printf)("popl %s\n", nameIReg(4,ch-0x58));
3740 }
3741 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3742 eip = eipE + 1;
3743 break;
3744 }
3745
3746 case 0x5C: /* POP eSP */
3747 normal_pop_case:
sewardjde4a1d02002-03-22 01:27:54 +00003748 t1 = newTemp(cb); t2 = newTemp(cb);
3749 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
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, 4, TempReg, t2, ArchReg, R_ESP);
3754 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, opc-0x58);
3755 if (dis)
3756 VG_(printf)("pop%c %s\n", nameISize(sz), nameIReg(sz,opc-0x58));
3757 break;
3758
3759 case 0x9D: /* POPF */
3760 vg_assert(sz == 2 || sz == 4);
3761 t1 = newTemp(cb); t2 = newTemp(cb);
3762 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
3763 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3764 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3765 uLiteral(cb, sz);
3766 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
3767 uInstr1(cb, PUTF, sz, TempReg, t1);
3768 /* PUTF writes all the flags we are interested in */
3769 uFlagsRWU(cb, FlagsEmpty, FlagsALL, FlagsEmpty);
3770 if (dis)
3771 VG_(printf)("popf%c\n", nameISize(sz));
3772 break;
3773
3774 case 0x61: /* POPA */
3775 { Int reg;
3776 /* Just to keep things sane, we assert for a size 4. It's
3777 probably OK for size 2 as well, but I'd like to find a test
3778 case; ie, have the assertion fail, before committing to it.
3779 If it fails for you, uncomment the sz == 2 bit, try again,
3780 and let me know whether or not it works. (jseward@acm.org). */
3781 vg_assert(sz == 4 /* || sz == 2 */);
3782
3783 /* Eight values are popped, one per register, but the value of
3784 %esp on the stack is ignored and instead incremented (in one
3785 hit at the end) for each of the values. */
3786 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3787 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
3788 uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t3);
3789
3790 /* Do %edi, %esi, %ebp */
3791 for (reg = 7; reg >= 5; reg--) {
3792 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3793 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3794 uLiteral(cb, sz);
3795 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
3796 }
3797 /* Ignore (skip) value of %esp on stack. */
3798 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3799 uLiteral(cb, sz);
3800 /* Do %ebx, %edx, %ecx, %eax */
3801 for (reg = 3; reg >= 0; reg--) {
3802 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3803 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3804 uLiteral(cb, sz);
3805 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
3806 }
3807 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t3);
3808 uLiteral(cb, sz * 8); /* One 'sz' per register */
3809 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
3810 if (dis)
3811 VG_(printf)("popa%c\n", nameISize(sz));
3812 break;
3813 }
3814
sewardj363e6062002-05-22 11:55:35 +00003815 case 0x8F: /* POPL/POPW m32 */
3816 { UInt pair1;
3817 Int tmpa;
3818 UChar rm = getUChar(eip);
3819
3820 /* make sure this instruction is correct POP */
3821 vg_assert(!epartIsReg(rm) && (gregOfRM(rm) == 0));
3822 /* and has correct size */
3823 vg_assert(sz == 4);
3824
3825 t1 = newTemp(cb); t3 = newTemp(cb);
3826 /* set t1 to ESP: t1 = ESP */
3827 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
3828 /* load M[ESP] to virtual register t3: t3 = M[t1] */
3829 uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t3);
3830 /* resolve MODR/M */
3831 pair1 = disAMode ( cb, eip, dis?dis_buf:NULL);
3832
3833 tmpa = LOW24(pair1);
3834 /* uInstr2(cb, LOAD, sz, TempReg, tmpa, TempReg, tmpa); */
3835 /* store value from stack in memory, M[m32] = t3 */
3836 uInstr2(cb, STORE, 4, TempReg, t3, TempReg, tmpa);
3837
3838 /* increase ESP */
3839 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1);
3840 uLiteral(cb, sz);
3841 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3842
3843 if (dis)
3844 VG_(printf)("popl %s\n", dis_buf);
3845
3846 eip += HI8(pair1);
3847 break;
3848 }
3849
sewardjde4a1d02002-03-22 01:27:54 +00003850 /* ------------------------ PUSH ----------------------- */
3851
3852 case 0x50: /* PUSH eAX */
3853 case 0x51: /* PUSH eCX */
3854 case 0x52: /* PUSH eDX */
sewardjde4a1d02002-03-22 01:27:54 +00003855 case 0x53: /* PUSH eBX */
3856 case 0x55: /* PUSH eBP */
3857 case 0x56: /* PUSH eSI */
3858 case 0x57: /* PUSH eDI */
sewardj4f51f9a2002-05-07 23:38:30 +00003859 { Int n_pushes;
3860 Addr eipS, eipE;
3861 UChar ch;
sewardj95621db2002-05-08 21:26:01 +00003862 if (sz != 4) goto normal_push_case;
3863 if (VG_(clo_cachesim)) goto normal_push_case;
sewardj4f51f9a2002-05-07 23:38:30 +00003864 /* eip points at first push insn + 1. Make eipS and eipE
3865 bracket the sequence. */
3866 eipE = eipS = eip - 1;
3867 while (True) {
3868 ch = getUChar(eipE+1);
3869 if (ch < 0x50 || ch > 0x57 || ch == 0x54) break;
3870 eipE++;
3871 }
3872 n_pushes = eipE - eipS + 1;
3873 if (0 && n_pushes > 1) VG_(printf)("%d pushes\n", n_pushes);
3874 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3875 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
3876 uInstr2(cb, MOV, 4, TempReg, t1, TempReg, t2);
3877 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3878 uLiteral(cb, 4 * n_pushes);
3879 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
3880 for (; eipS <= eipE; eipS++) {
3881 ch = getUChar(eipS);
3882 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t1);
3883 uLiteral(cb, 4);
3884 uInstr2(cb, GET, 4, ArchReg, ch-0x50, TempReg, t3);
3885 uInstr2(cb, STORE, 4, TempReg, t3, TempReg, t1);
3886 SMC_IF_ALL(cb);
3887 if (dis)
3888 VG_(printf)("pushl %s\n", nameIReg(4,ch-0x50));
3889 }
3890 eip = eipE + 1;
3891 break;
3892 }
3893
3894 case 0x54: /* PUSH eSP */
3895 normal_push_case:
sewardjde4a1d02002-03-22 01:27:54 +00003896 /* This is the Right Way, in that the value to be pushed is
3897 established before %esp is changed, so that pushl %esp
3898 correctly pushes the old value. */
3899 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3900 uInstr2(cb, GET, sz, ArchReg, opc-0x50, TempReg, t1);
3901 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
3902 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
3903 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3904 uLiteral(cb, sz);
3905 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
3906 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3907 SMC_IF_ALL(cb);
3908 if (dis)
3909 VG_(printf)("push%c %s\n", nameISize(sz), nameIReg(sz,opc-0x50));
3910 break;
3911
3912 case 0x68: /* PUSH Iv */
3913 d32 = getUDisp(sz,eip); eip += sz;
3914 goto do_push_I;
3915 case 0x6A: /* PUSH Ib, sign-extended to sz */
3916 d32 = getSDisp8(eip); eip += 1;
3917 goto do_push_I;
3918 do_push_I:
3919 t1 = newTemp(cb); t2 = newTemp(cb);
3920 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
3921 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t1);
3922 uLiteral(cb, sz);
3923 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3924 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t2);
3925 uLiteral(cb, d32);
3926 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
3927 SMC_IF_ALL(cb);
3928 if (dis)
3929 VG_(printf)("push%c $0x%x\n", nameISize(sz), d32);
3930 break;
3931
3932 case 0x9C: /* PUSHF */
3933 vg_assert(sz == 2 || sz == 4);
3934 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3935 uInstr1(cb, GETF, sz, TempReg, t1);
3936 /* GETF reads all the flags we are interested in */
3937 uFlagsRWU(cb, FlagsALL, FlagsEmpty, FlagsEmpty);
3938 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
3939 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
3940 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3941 uLiteral(cb, sz);
3942 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
3943 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3944 SMC_IF_ALL(cb);
3945 if (dis)
3946 VG_(printf)("pushf%c\n", nameISize(sz));
3947 break;
3948
3949 case 0x60: /* PUSHA */
3950 { Int reg;
3951 /* Just to keep things sane, we assert for a size 4. It's
3952 probably OK for size 2 as well, but I'd like to find a test
3953 case; ie, have the assertion fail, before committing to it.
3954 If it fails for you, uncomment the sz == 2 bit, try again,
3955 and let me know whether or not it works. (jseward@acm.org). */
3956 vg_assert(sz == 4 /* || sz == 2 */);
3957
3958 /* This is the Right Way, in that the value to be pushed is
3959 established before %esp is changed, so that pusha
3960 correctly pushes the old %esp value. New value of %esp is
3961 pushed at start. */
3962 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3963 t4 = newTemp(cb);
3964 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
3965 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
3966 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t4);
3967 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t4);
3968 uLiteral(cb, sz * 8); /* One 'sz' per register. */
3969 uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_ESP);
3970 /* Do %eax, %ecx, %edx, %ebx */
3971 for (reg = 0; reg <= 3; reg++) {
3972 uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
3973 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3974 uLiteral(cb, sz);
3975 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3976 SMC_IF_ALL(cb);
3977 }
3978 /* Push old value of %esp */
3979 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3980 uLiteral(cb, sz);
3981 uInstr2(cb, STORE, sz, TempReg, t3, TempReg, t2);
3982 SMC_IF_ALL(cb);
3983 /* Do %ebp, %esi, %edi */
3984 for (reg = 5; reg <= 7; reg++) {
3985 uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
3986 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3987 uLiteral(cb, sz);
3988 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3989 SMC_IF_ALL(cb);
3990 }
3991 if (dis)
3992 VG_(printf)("pusha%c\n", nameISize(sz));
3993 break;
3994 }
3995
3996 /* ------------------------ SCAS et al ----------------- */
3997
3998 case 0xA4: /* MOVSb, no REP prefix */
3999 codegen_MOVS ( cb, 1 );
4000 if (dis) VG_(printf)("movsb\n");
4001 break;
4002 case 0xA5: /* MOVSv, no REP prefix */
4003 codegen_MOVS ( cb, sz );
4004 if (dis) VG_(printf)("movs%c\n", nameISize(sz));
4005 break;
4006
4007 case 0xA6: /* CMPSb, no REP prefix */
4008 codegen_CMPS ( cb, 1 );
4009 if (dis) VG_(printf)("cmpsb\n");
4010 break;
4011
4012 case 0xAA: /* STOSb, no REP prefix */
4013 codegen_STOS ( cb, 1 );
4014 if (dis) VG_(printf)("stosb\n");
4015 break;
4016 case 0xAB: /* STOSv, no REP prefix */
4017 codegen_STOS ( cb, sz );
4018 if (dis) VG_(printf)("stos%c\n", nameISize(sz));
4019 break;
4020
4021 case 0xAC: /* LODSb, no REP prefix */
4022 codegen_LODS ( cb, 1 );
4023 if (dis) VG_(printf)("lodsb\n");
4024 break;
sewardj64a8cc42002-05-08 01:38:43 +00004025 case 0xAD: /* LODSv, no REP prefix */
4026 codegen_LODS ( cb, sz );
4027 if (dis) VG_(printf)("lods%c\n", nameISize(sz));
4028 break;
sewardjde4a1d02002-03-22 01:27:54 +00004029
4030 case 0xAE: /* SCASb, no REP prefix */
4031 codegen_SCAS ( cb, 1 );
4032 if (dis) VG_(printf)("scasb\n");
4033 break;
4034
4035 case 0xFC: /* CLD */
4036 uInstr0(cb, CALLM_S, 0);
4037 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CLD));
4038 uFlagsRWU(cb, FlagsEmpty, FlagD, FlagsEmpty);
4039 uInstr0(cb, CALLM_E, 0);
4040 if (dis) VG_(printf)("cld\n");
4041 break;
4042
4043 case 0xFD: /* STD */
4044 uInstr0(cb, CALLM_S, 0);
4045 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_STD));
4046 uFlagsRWU(cb, FlagsEmpty, FlagD, FlagsEmpty);
4047 uInstr0(cb, CALLM_E, 0);
4048 if (dis) VG_(printf)("std\n");
4049 break;
4050
4051 case 0xF2: { /* REPNE prefix insn */
4052 Addr eip_orig = eip - 1;
4053 abyte = getUChar(eip); eip++;
4054 if (abyte == 0x66) { sz = 2; abyte = getUChar(eip); eip++; }
4055
4056 if (abyte == 0xAE || 0xAF) { /* REPNE SCAS<sz> */
4057 if (abyte == 0xAE) sz = 1;
4058 codegen_REPNE_SCAS ( cb, sz, eip_orig, eip );
4059 *isEnd = True;
4060 if (dis) VG_(printf)("repne scas%c\n", nameISize(sz));
4061 }
4062 else {
4063 VG_(printf)("REPNE then 0x%x\n", (UInt)abyte);
4064 VG_(panic)("Unhandled REPNE case");
4065 }
4066 break;
4067 }
4068
4069 case 0xF3: { /* REPE prefix insn */
4070 Addr eip_orig = eip - 1;
4071 abyte = getUChar(eip); eip++;
4072 if (abyte == 0x66) { sz = 2; abyte = getUChar(eip); eip++; }
4073
4074 if (abyte == 0xA4 || abyte == 0xA5) { /* REPE MOV<sz> */
4075 if (abyte == 0xA4) sz = 1;
4076 codegen_REPE_MOVS ( cb, sz, eip_orig, eip );
4077 *isEnd = True;
4078 if (dis) VG_(printf)("repe mov%c\n", nameISize(sz));
4079 }
4080 else
4081 if (abyte == 0xA6 || abyte == 0xA7) { /* REPE CMP<sz> */
4082 if (abyte == 0xA6) sz = 1;
4083 codegen_REPE_CMPS ( cb, sz, eip_orig, eip );
4084 *isEnd = True;
4085 if (dis) VG_(printf)("repe cmps%c\n", nameISize(sz));
4086 }
4087 else
4088 if (abyte == 0xAA || abyte == 0xAB) { /* REPE STOS<sz> */
4089 if (abyte == 0xAA) sz = 1;
4090 codegen_REPE_STOS ( cb, sz, eip_orig, eip );
4091 *isEnd = True;
4092 if (dis) VG_(printf)("repe stos%c\n", nameISize(sz));
4093 } else {
4094 VG_(printf)("REPE then 0x%x\n", (UInt)abyte);
4095 VG_(panic)("Unhandled REPE case");
4096 }
4097 break;
4098 }
4099
4100 /* ------------------------ XCHG ----------------------- */
4101
4102 case 0x86: /* XCHG Gb,Eb */
4103 sz = 1;
4104 /* Fall through ... */
4105 case 0x87: /* XCHG Gv,Ev */
4106 modrm = getUChar(eip);
4107 t1 = newTemp(cb); t2 = newTemp(cb);
4108 if (epartIsReg(modrm)) {
4109 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
4110 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t2);
4111 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, gregOfRM(modrm));
4112 uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, eregOfRM(modrm));
4113 eip++;
4114 if (dis)
4115 VG_(printf)("xchg%c %s, %s\n", nameISize(sz),
4116 nameIReg(sz,gregOfRM(modrm)),
4117 nameIReg(sz,eregOfRM(modrm)));
4118 } else {
4119 pair = disAMode ( cb, eip, dis?dis_buf:NULL);
4120 t3 = LOW24(pair);
4121 uInstr2(cb, LOAD, sz, TempReg, t3, TempReg, t1);
4122 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t2);
4123 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t3);
4124 SMC_IF_SOME(cb);
4125 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, gregOfRM(modrm));
4126 eip += HI8(pair);
4127 if (dis)
4128 VG_(printf)("xchg%c %s, %s\n", nameISize(sz),
4129 nameIReg(sz,gregOfRM(modrm)),
4130 dis_buf);
4131 }
4132 break;
4133
4134 case 0x90: /* XCHG eAX,eAX */
4135 if (dis) VG_(printf)("nop\n");
4136 break;
4137 case 0x91: /* XCHG eCX,eSI */
4138 case 0x96: /* XCHG eAX,eSI */
4139 case 0x97: /* XCHG eAX,eDI */
4140 codegen_xchg_eAX_Reg ( cb, sz, opc - 0x90 );
4141 break;
4142
4143 /* ------------------------ (Grp1 extensions) ---------- */
4144
4145 case 0x80: /* Grp1 Ib,Eb */
4146 modrm = getUChar(eip);
4147 am_sz = lengthAMode(eip);
4148 sz = 1;
4149 d_sz = 1;
4150 d32 = getSDisp8(eip + am_sz);
4151 eip = dis_Grp1 ( cb, eip, modrm, am_sz, d_sz, sz, d32 );
4152 break;
4153
4154 case 0x81: /* Grp1 Iv,Ev */
4155 modrm = getUChar(eip);
4156 am_sz = lengthAMode(eip);
4157 d_sz = sz;
4158 d32 = getUDisp(d_sz, eip + am_sz);
4159 eip = dis_Grp1 ( cb, eip, modrm, am_sz, d_sz, sz, d32 );
4160 break;
4161
4162 case 0x83: /* Grp1 Ib,Ev */
4163 modrm = getUChar(eip);
4164 am_sz = lengthAMode(eip);
4165 d_sz = 1;
4166 d32 = getSDisp8(eip + am_sz);
4167 eip = dis_Grp1 ( cb, eip, modrm, am_sz, d_sz, sz, d32 );
4168 break;
4169
4170 /* ------------------------ (Grp2 extensions) ---------- */
4171
4172 case 0xC0: /* Grp2 Ib,Eb */
4173 modrm = getUChar(eip);
4174 am_sz = lengthAMode(eip);
4175 d_sz = 1;
4176 d32 = getSDisp8(eip + am_sz);
4177 sz = 1;
4178 eip = dis_Grp2 ( cb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
4179 break;
4180
4181 case 0xC1: /* Grp2 Ib,Ev */
4182 modrm = getUChar(eip);
4183 am_sz = lengthAMode(eip);
4184 d_sz = 1;
4185 d32 = getSDisp8(eip + am_sz);
4186 eip = dis_Grp2 ( cb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
4187 break;
4188
4189 case 0xD0: /* Grp2 1,Eb */
4190 modrm = getUChar(eip);
4191 am_sz = lengthAMode(eip);
4192 d_sz = 0;
4193 d32 = 1;
4194 sz = 1;
4195 eip = dis_Grp2 ( cb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
4196 break;
4197
4198 case 0xD1: /* Grp2 1,Ev */
4199 modrm = getUChar(eip);
4200 am_sz = lengthAMode(eip);
4201 d_sz = 0;
4202 d32 = 1;
4203 eip = dis_Grp2 ( cb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
4204 break;
4205
4206 case 0xD3: /* Grp2 CL,Ev */
4207 modrm = getUChar(eip);
4208 am_sz = lengthAMode(eip);
4209 d_sz = 0;
4210 eip = dis_Grp2 ( cb, eip, modrm, am_sz, d_sz, sz, ArchReg, R_ECX );
4211 break;
4212
4213 /* ------------------------ (Grp3 extensions) ---------- */
4214
4215 case 0xF6: /* Grp3 Eb */
4216 eip = dis_Grp3 ( cb, 1, eip );
4217 break;
4218 case 0xF7: /* Grp3 Ev */
4219 eip = dis_Grp3 ( cb, sz, eip );
4220 break;
4221
4222 /* ------------------------ (Grp4 extensions) ---------- */
4223
4224 case 0xFE: /* Grp4 Eb */
4225 eip = dis_Grp4 ( cb, eip );
4226 break;
4227
4228 /* ------------------------ (Grp5 extensions) ---------- */
4229
4230 case 0xFF: /* Grp5 Ev */
4231 eip = dis_Grp5 ( cb, sz, eip, isEnd );
4232 break;
4233
4234 /* ------------------------ Escapes to 2-byte opcodes -- */
4235
4236 case 0x0F: {
4237 opc = getUChar(eip); eip++;
4238 switch (opc) {
4239
4240 /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
4241
4242 case 0xBA: /* Grp8 Ib,Ev */
4243 modrm = getUChar(eip);
4244 am_sz = lengthAMode(eip);
4245 d32 = getSDisp8(eip + am_sz);
sewardj0ece28b2002-04-16 00:42:12 +00004246 eip = dis_Grp8_BT ( cb, eip, modrm, am_sz, sz, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00004247 break;
sewardj0ece28b2002-04-16 00:42:12 +00004248
sewardjde4a1d02002-03-22 01:27:54 +00004249 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
4250
4251 case 0xBC: /* BSF Gv,Ev */
4252 eip = dis_bs_E_G ( cb, sz, eip, True );
4253 break;
4254 case 0xBD: /* BSR Gv,Ev */
4255 eip = dis_bs_E_G ( cb, sz, eip, False );
4256 break;
4257
4258 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
4259
4260 case 0xC8: /* BSWAP %eax */
4261 case 0xC9:
4262 case 0xCA:
4263 case 0xCB:
4264 case 0xCC:
4265 case 0xCD:
4266 case 0xCE:
4267 case 0xCF: /* BSWAP %edi */
4268 /* AFAICS from the Intel docs, this only exists at size 4. */
4269 vg_assert(sz == 4);
4270 t1 = newTemp(cb);
4271 uInstr2(cb, GET, 4, ArchReg, opc-0xC8, TempReg, t1);
4272 uInstr1(cb, BSWAP, 4, TempReg, t1);
4273 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, opc-0xC8);
4274 if (dis) VG_(printf)("bswapl %s\n", nameIReg(4, opc-0xC8));
4275 break;
4276
4277 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
4278
4279 case 0xA3: /* BT Gv,Ev */
4280 eip = dis_bt_G_E ( cb, sz, eip, BtOpNone );
4281 break;
4282 case 0xB3: /* BTR Gv,Ev */
4283 eip = dis_bt_G_E ( cb, sz, eip, BtOpReset );
4284 break;
4285 case 0xAB: /* BTS Gv,Ev */
4286 eip = dis_bt_G_E ( cb, sz, eip, BtOpSet );
4287 break;
4288 case 0xBB: /* BTC Gv,Ev */
4289 eip = dis_bt_G_E ( cb, sz, eip, BtOpComp );
4290 break;
4291
4292 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
4293
4294 case 0x40:
4295 case 0x41:
4296 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
4297 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
4298 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
4299 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
4300 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
4301 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
4302 case 0x48: /* CMOVSb (cmov negative) */
4303 case 0x49: /* CMOVSb (cmov not negative) */
4304 case 0x4A: /* CMOVP (cmov parity even) */
sewardj969129d2002-04-21 11:43:11 +00004305 case 0x4B: /* CMOVNP (cmov parity odd) */
sewardjde4a1d02002-03-22 01:27:54 +00004306 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
4307 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
4308 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
4309 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
4310 eip = dis_cmov_E_G(cb, sz, (Condcode)(opc - 0x40), eip);
4311 break;
4312
4313 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
4314
4315 case 0xB1: /* CMPXCHG Gv,Ev */
4316 eip = dis_cmpxchg_G_E ( cb, sz, eip );
4317 break;
4318
4319 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
4320
4321 case 0xA2: /* CPUID */
4322 t1 = newTemp(cb);
4323 t2 = newTemp(cb);
4324 t3 = newTemp(cb);
4325 t4 = newTemp(cb);
4326 uInstr0(cb, CALLM_S, 0);
4327
4328 uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t1);
4329 uInstr1(cb, PUSH, 4, TempReg, t1);
4330
4331 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
4332 uLiteral(cb, 0);
4333 uInstr1(cb, PUSH, 4, TempReg, t2);
4334
4335 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t3);
4336 uLiteral(cb, 0);
4337 uInstr1(cb, PUSH, 4, TempReg, t3);
4338
4339 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
4340 uLiteral(cb, 0);
4341 uInstr1(cb, PUSH, 4, TempReg, t4);
4342
4343 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CPUID));
4344 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
4345
4346 uInstr1(cb, POP, 4, TempReg, t4);
4347 uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_EDX);
4348
4349 uInstr1(cb, POP, 4, TempReg, t3);
4350 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ECX);
4351
4352 uInstr1(cb, POP, 4, TempReg, t2);
4353 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBX);
4354
4355 uInstr1(cb, POP, 4, TempReg, t1);
4356 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
4357
4358 uInstr0(cb, CALLM_E, 0);
4359 if (dis) VG_(printf)("cpuid\n");
4360 break;
4361
4362 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
4363
4364 case 0xB6: /* MOVZXb Eb,Gv */
4365 eip = dis_movx_E_G ( cb, eip, 1, 4, False );
4366 break;
4367 case 0xB7: /* MOVZXw Ew,Gv */
4368 eip = dis_movx_E_G ( cb, eip, 2, 4, False );
4369 break;
4370
4371 case 0xBE: /* MOVSXb Eb,Gv */
4372 eip = dis_movx_E_G ( cb, eip, 1, 4, True );
4373 break;
4374 case 0xBF: /* MOVSXw Ew,Gv */
4375 eip = dis_movx_E_G ( cb, eip, 2, 4, True );
4376 break;
4377
4378 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
4379
4380 case 0xAF: /* IMUL Ev, Gv */
4381 eip = dis_mul_E_G ( cb, sz, eip, True );
4382 break;
4383
4384 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
4385 case 0x80:
4386 case 0x81:
4387 case 0x82: /* JBb/JNAEb (jump below) */
4388 case 0x83: /* JNBb/JAEb (jump not below) */
4389 case 0x84: /* JZb/JEb (jump zero) */
4390 case 0x85: /* JNZb/JNEb (jump not zero) */
4391 case 0x86: /* JBEb/JNAb (jump below or equal) */
4392 case 0x87: /* JNBEb/JAb (jump not below or equal) */
4393 case 0x88: /* JSb (jump negative) */
4394 case 0x89: /* JSb (jump not negative) */
4395 case 0x8A: /* JP (jump parity even) */
sewardj969129d2002-04-21 11:43:11 +00004396 case 0x8B: /* JNP/JPO (jump parity odd) */
sewardjde4a1d02002-03-22 01:27:54 +00004397 case 0x8C: /* JLb/JNGEb (jump less) */
4398 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
4399 case 0x8E: /* JLEb/JNGb (jump less or equal) */
4400 case 0x8F: /* JGb/JNLEb (jump greater) */
4401 d32 = (eip+4) + getUDisp32(eip); eip += 4;
4402 uInstr1(cb, JMP, 0, Literal, 0);
4403 uLiteral(cb, d32);
4404 uCond(cb, (Condcode)(opc - 0x80));
4405 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
4406 uInstr1(cb, JMP, 0, Literal, 0);
4407 uLiteral(cb, eip);
4408 uCond(cb, CondAlways);
4409 *isEnd = True;
4410 if (dis)
4411 VG_(printf)("j%s-32 0x%x\n",
4412 VG_(nameCondcode)(opc - 0x80), d32);
4413 break;
4414
4415 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
4416
4417 case 0x31: /* RDTSC */
4418 t1 = newTemp(cb);
4419 t2 = newTemp(cb);
4420 t3 = newTemp(cb);
4421 uInstr0(cb, CALLM_S, 0);
4422 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
4423 uLiteral(cb, 0);
4424 uInstr1(cb, PUSH, 4, TempReg, t1);
4425 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
4426 uLiteral(cb, 0);
4427 uInstr1(cb, PUSH, 4, TempReg, t2);
4428 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_RDTSC));
4429 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
4430 uInstr1(cb, POP, 4, TempReg, t3);
4431 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EDX);
4432 uInstr1(cb, POP, 4, TempReg, t3);
4433 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EAX);
4434 uInstr0(cb, CALLM_E, 0);
4435 if (dis) VG_(printf)("rdtsc\n");
4436 break;
4437
4438 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
4439 case 0x90:
4440 case 0x91:
4441 case 0x92: /* set-Bb/set-NAEb (jump below) */
4442 case 0x93: /* set-NBb/set-AEb (jump not below) */
4443 case 0x94: /* set-Zb/set-Eb (jump zero) */
4444 case 0x95: /* set-NZb/set-NEb (jump not zero) */
4445 case 0x96: /* set-BEb/set-NAb (jump below or equal) */
4446 case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
4447 case 0x98: /* set-Sb (jump negative) */
4448 case 0x99: /* set-Sb (jump not negative) */
4449 case 0x9A: /* set-P (jump parity even) */
4450 case 0x9B: /* set-NP (jump parity odd) */
4451 case 0x9C: /* set-Lb/set-NGEb (jump less) */
4452 case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
4453 case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
4454 case 0x9F: /* set-Gb/set-NLEb (jump greater) */
4455 modrm = getUChar(eip);
4456 t1 = newTemp(cb);
4457 if (epartIsReg(modrm)) {
4458 eip++;
4459 uInstr1(cb, CC2VAL, 1, TempReg, t1);
4460 uCond(cb, (Condcode)(opc-0x90));
4461 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
4462 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, eregOfRM(modrm));
4463 if (dis) VG_(printf)("set%s %s\n",
4464 VG_(nameCondcode)(opc-0x90),
4465 nameIReg(1,eregOfRM(modrm)));
4466 } else {
4467 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
4468 t2 = LOW24(pair);
4469 eip += HI8(pair);
4470 uInstr1(cb, CC2VAL, 1, TempReg, t1);
4471 uCond(cb, (Condcode)(opc-0x90));
4472 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
4473 uInstr2(cb, STORE, 1, TempReg, t1, TempReg, t2);
4474 SMC_IF_ALL(cb);
4475 if (dis) VG_(printf)("set%s %s\n",
4476 VG_(nameCondcode)(opc-0x90),
4477 dis_buf);
4478 }
4479 break;
4480
4481 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
4482
4483 case 0xA4: /* SHLDv imm8,Gv,Ev */
4484 modrm = getUChar(eip);
4485 eip = dis_SHLRD_Gv_Ev (
4486 cb, eip, modrm, sz,
4487 Literal, getUChar(eip + lengthAMode(eip)),
4488 True );
4489 break;
4490 case 0xA5: /* SHLDv %cl,Gv,Ev */
4491 modrm = getUChar(eip);
4492 eip = dis_SHLRD_Gv_Ev (
4493 cb, eip, modrm, sz, ArchReg, R_CL, True );
4494 break;
4495
4496 case 0xAC: /* SHRDv imm8,Gv,Ev */
4497 modrm = getUChar(eip);
4498 eip = dis_SHLRD_Gv_Ev (
4499 cb, eip, modrm, sz,
4500 Literal, getUChar(eip + lengthAMode(eip)),
4501 False );
4502 break;
4503 case 0xAD: /* SHRDv %cl,Gv,Ev */
4504 modrm = getUChar(eip);
4505 eip = dis_SHLRD_Gv_Ev (
4506 cb, eip, modrm, sz, ArchReg, R_CL, False );
4507 break;
4508
4509 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
4510
4511 case 0xC1: /* XADD Gv,Ev */
4512 eip = dis_xadd_G_E ( cb, sz, eip );
4513 break;
4514
4515 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
4516
4517 default:
4518 VG_(printf)("disInstr: unhandled 2-byte opcode 0x%x\n",
4519 (UInt)opc);
4520 VG_(unimplemented)("unhandled x86 0x0F 2-byte opcode");
4521 }
4522
4523 break;
4524 }
4525
4526 /* ------------------------ ??? ------------------------ */
4527
4528 default:
4529 VG_(printf)("disInstr: unhandled opcode 0x%x then 0x%x\n",
4530 (UInt)opc, (UInt)getUChar(eip));
sewardjcfc39b22002-05-08 01:58:18 +00004531 if (opc == 0x8C)
4532 VG_(nvidia_moan)();
sewardjde4a1d02002-03-22 01:27:54 +00004533 VG_(panic)("unhandled x86 opcode");
4534 }
4535
4536 if (dis)
4537 VG_(printf)("\n");
4538 for (; first_uinstr < cb->used; first_uinstr++) {
4539 Bool sane = VG_(saneUInstr)(True, &cb->instrs[first_uinstr]);
4540 if (dis || !sane)
4541 VG_(ppUInstr)(sane ? first_uinstr : -1,
4542 &cb->instrs[first_uinstr]);
4543 vg_assert(sane);
4544 }
4545
4546 return eip;
4547}
4548
4549
4550/* Disassemble a complete basic block, starting at eip, and dumping
4551 the ucode into cb. Returns the size, in bytes, of the basic
4552 block. */
4553
4554Int VG_(disBB) ( UCodeBlock* cb, Addr eip0 )
4555{
4556 Addr eip = eip0;
4557 Bool isEnd = False;
4558 Bool block_sane;
njn4f9c9342002-04-29 16:03:24 +00004559 Int INCEIP_allowed_lag = 4;
4560 Int delta = 0;
4561
sewardjde4a1d02002-03-22 01:27:54 +00004562 if (dis) VG_(printf)("\n");
4563
njn4f9c9342002-04-29 16:03:24 +00004564 /* When cache simulating, to ensure cache misses are attributed to the
4565 * correct line we ensure EIP is always correct. This is done by:
4566 *
4567 * a) Using eager INCEIP updating to cope with all instructions except those
4568 * at the end of a basic block.
4569 *
4570 * b) Patching in the size of the original x86 instr in the `extra4b' field
4571 * of JMPs at the end of a basic block. Two cases:
4572 * - Jcond followed by Juncond: patch the Jcond
4573 * - Juncond alone: patch the Juncond
4574 *
4575 * See vg_cachesim_instrument() for how this is used.
4576 */
4577 if (VG_(clo_cachesim)) {
4578 INCEIP_allowed_lag = 0;
4579 }
4580
sewardjde4a1d02002-03-22 01:27:54 +00004581 if (VG_(clo_single_step)) {
4582 eip = disInstr ( cb, eip, &isEnd );
njn4f9c9342002-04-29 16:03:24 +00004583
4584 /* Add a JMP to the next (single x86 instruction) BB if it doesn't
4585 * already end with a JMP instr. We also need to check for no UCode,
4586 * which occurs if the x86 instr was a nop */
4587 if (cb->used == 0 || LAST_UINSTR(cb).opcode != JMP) {
4588 uInstr1(cb, JMP, 0, Literal, 0);
4589 uLiteral(cb, eip);
4590 uCond(cb, CondAlways);
4591 if (dis) VG_(ppUInstr)(cb->used-1, &cb->instrs[cb->used-1]);
4592 }
4593 delta = eip - eip0;
4594
sewardjde4a1d02002-03-22 01:27:54 +00004595 } else {
sewardjde4a1d02002-03-22 01:27:54 +00004596 Addr eip2;
njn4f9c9342002-04-29 16:03:24 +00004597 while (!isEnd) {
sewardjde4a1d02002-03-22 01:27:54 +00004598 eip2 = disInstr ( cb, eip, &isEnd );
4599 delta += (eip2 - eip);
4600 eip = eip2;
sewardjde4a1d02002-03-22 01:27:54 +00004601 /* Split up giant basic blocks into pieces, so the
4602 translations fall within 64k. */
njn4f9c9342002-04-29 16:03:24 +00004603 if (eip - eip0 > 2000 && !isEnd) {
sewardja0f921a2002-05-08 00:42:25 +00004604 if (VG_(clo_verbosity) > 2)
njn4f9c9342002-04-29 16:03:24 +00004605 VG_(message)(Vg_DebugMsg,
sewardjde4a1d02002-03-22 01:27:54 +00004606 "Warning: splitting giant basic block into pieces");
4607 uInstr1(cb, JMP, 0, Literal, 0);
4608 uLiteral(cb, eip);
4609 uCond(cb, CondAlways);
4610 if (dis) VG_(ppUInstr)(cb->used-1, &cb->instrs[cb->used-1]);
njn4f9c9342002-04-29 16:03:24 +00004611 isEnd = True;
4612
4613 } else if (delta > INCEIP_allowed_lag && !isEnd) {
4614 uInstr1(cb, INCEIP, 0, Lit16, delta);
4615 if (dis) VG_(ppUInstr)(cb->used-1, &cb->instrs[cb->used-1]);
4616 delta = 0;
sewardjde4a1d02002-03-22 01:27:54 +00004617 }
4618 if (dis) VG_(printf)("\n");
4619 }
4620 }
njn4f9c9342002-04-29 16:03:24 +00004621 if (VG_(clo_cachesim)) {
4622 /* Patch instruction size into earliest JMP. */
4623 if (cb->used >= 2 && JMP == cb->instrs[cb->used - 2].opcode) {
4624 cb->instrs[cb->used - 2].extra4b = delta;
4625 } else {
4626 LAST_UINSTR(cb).extra4b = delta;
4627 }
4628 }
sewardjde4a1d02002-03-22 01:27:54 +00004629
4630 block_sane = VG_(saneUCodeBlock)(cb);
4631 if (!block_sane) {
4632 VG_(ppUCodeBlock)(cb, "block failing sanity check");
4633 vg_assert(block_sane);
4634 }
4635
4636 return eip - eip0;
4637}
4638
4639
4640/*--------------------------------------------------------------------*/
4641/*--- end vg_to_ucode.c ---*/
4642/*--------------------------------------------------------------------*/