blob: da2871c3f184b9eff3d1c1ef0d5c436f7533533f [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
sewardja4b87f62002-05-29 23:38:23 +00003610 case 0x12: /* ADC Eb,Gb */
3611 eip = dis_op2_E_G ( cb, ADC, True, 1, eip, "adc" );
3612 break;
sewardjde4a1d02002-03-22 01:27:54 +00003613 case 0x13: /* ADC Ev,Gv */
3614 eip = dis_op2_E_G ( cb, ADC, True, sz, eip, "adc" );
3615 break;
3616
3617 case 0x1B: /* SBB Ev,Gv */
3618 eip = dis_op2_E_G ( cb, SBB, True, sz, eip, "sbb" );
3619 break;
3620
3621 case 0x22: /* AND Eb,Gb */
3622 eip = dis_op2_E_G ( cb, AND, True, 1, eip, "and" );
3623 break;
3624 case 0x23: /* AND Ev,Gv */
3625 eip = dis_op2_E_G ( cb, AND, True, sz, eip, "and" );
3626 break;
3627
3628 case 0x2A: /* SUB Eb,Gb */
3629 eip = dis_op2_E_G ( cb, SUB, True, 1, eip, "sub" );
3630 break;
3631 case 0x2B: /* SUB Ev,Gv */
3632 eip = dis_op2_E_G ( cb, SUB, True, sz, eip, "sub" );
3633 break;
3634
3635 case 0x32: /* XOR Eb,Gb */
3636 eip = dis_op2_E_G ( cb, XOR, True, 1, eip, "xor" );
3637 break;
3638 case 0x33: /* XOR Ev,Gv */
3639 eip = dis_op2_E_G ( cb, XOR, True, sz, eip, "xor" );
3640 break;
3641
3642 case 0x3A: /* CMP Eb,Gb */
3643 eip = dis_op2_E_G ( cb, SUB, False, 1, eip, "cmp" );
3644 break;
3645 case 0x3B: /* CMP Ev,Gv */
3646 eip = dis_op2_E_G ( cb, SUB, False, sz, eip, "cmp" );
3647 break;
3648
3649 case 0x84: /* TEST Eb,Gb */
3650 eip = dis_op2_E_G ( cb, AND, False, 1, eip, "test" );
3651 break;
3652 case 0x85: /* TEST Ev,Gv */
3653 eip = dis_op2_E_G ( cb, AND, False, sz, eip, "test" );
3654 break;
3655
3656 /* ------------------------ opl Gv, Ev ----------------- */
3657
3658 case 0x00: /* ADD Gb,Eb */
3659 eip = dis_op2_G_E ( cb, ADD, True, 1, eip, "add" );
3660 break;
3661 case 0x01: /* ADD Gv,Ev */
3662 eip = dis_op2_G_E ( cb, ADD, True, sz, eip, "add" );
3663 break;
3664
3665 case 0x08: /* OR Gb,Eb */
3666 eip = dis_op2_G_E ( cb, OR, True, 1, eip, "or" );
3667 break;
3668 case 0x09: /* OR Gv,Ev */
3669 eip = dis_op2_G_E ( cb, OR, True, sz, eip, "or" );
3670 break;
3671
3672 case 0x11: /* ADC Gv,Ev */
3673 eip = dis_op2_G_E ( cb, ADC, True, sz, eip, "adc" );
3674 break;
3675
3676 case 0x19: /* SBB Gv,Ev */
3677 eip = dis_op2_G_E ( cb, SBB, True, sz, eip, "sbb" );
3678 break;
3679
3680 case 0x20: /* AND Gb,Eb */
3681 eip = dis_op2_G_E ( cb, AND, True, 1, eip, "and" );
3682 break;
3683 case 0x21: /* AND Gv,Ev */
3684 eip = dis_op2_G_E ( cb, AND, True, sz, eip, "and" );
3685 break;
3686
3687 case 0x28: /* SUB Gb,Eb */
3688 eip = dis_op2_G_E ( cb, SUB, True, 1, eip, "sub" );
3689 break;
3690 case 0x29: /* SUB Gv,Ev */
3691 eip = dis_op2_G_E ( cb, SUB, True, sz, eip, "sub" );
3692 break;
3693
3694 case 0x30: /* XOR Gb,Eb */
3695 eip = dis_op2_G_E ( cb, XOR, True, 1, eip, "xor" );
3696 break;
3697 case 0x31: /* XOR Gv,Ev */
3698 eip = dis_op2_G_E ( cb, XOR, True, sz, eip, "xor" );
3699 break;
3700
3701 case 0x38: /* CMP Gb,Eb */
3702 eip = dis_op2_G_E ( cb, SUB, False, 1, eip, "cmp" );
3703 break;
3704 case 0x39: /* CMP Gv,Ev */
3705 eip = dis_op2_G_E ( cb, SUB, False, sz, eip, "cmp" );
3706 break;
3707
3708 /* ------------------------ POP ------------------------ */
3709
3710 case 0x58: /* POP eAX */
3711 case 0x59: /* POP eCX */
3712 case 0x5A: /* POP eDX */
3713 case 0x5B: /* POP eBX */
sewardjde4a1d02002-03-22 01:27:54 +00003714 case 0x5D: /* POP eBP */
3715 case 0x5E: /* POP eSI */
3716 case 0x5F: /* POP eDI */
sewardj4f51f9a2002-05-07 23:38:30 +00003717 { Int n_pops;
3718 Addr eipS, eipE;
3719 UChar ch;
sewardj95621db2002-05-08 21:26:01 +00003720 if (sz != 4) goto normal_pop_case;
3721 if (VG_(clo_cachesim)) goto normal_pop_case;
sewardj4f51f9a2002-05-07 23:38:30 +00003722 /* eip points at first pop insn + 1. Make eipS and eipE
3723 bracket the sequence. */
3724 eipE = eipS = eip - 1;
3725 while (True) {
3726 ch = getUChar(eipE+1);
3727 if (ch < 0x58 || ch > 0x5F || ch == 0x5C) break;
3728 eipE++;
3729 }
3730 n_pops = eipE - eipS + 1;
3731 if (0 && n_pops > 1) VG_(printf)("%d pops\n", n_pops);
3732 t1 = newTemp(cb); t3 = newTemp(cb);
3733 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
3734 for (; eipS <= eipE; eipS++) {
3735 ch = getUChar(eipS);
3736 uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t3);
3737 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, ch-0x58);
3738 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1);
3739 uLiteral(cb, 4);
3740 SMC_IF_ALL(cb);
3741 if (dis)
3742 VG_(printf)("popl %s\n", nameIReg(4,ch-0x58));
3743 }
3744 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3745 eip = eipE + 1;
3746 break;
3747 }
3748
3749 case 0x5C: /* POP eSP */
3750 normal_pop_case:
sewardjde4a1d02002-03-22 01:27:54 +00003751 t1 = newTemp(cb); t2 = newTemp(cb);
3752 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
3753 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3754 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3755 uLiteral(cb, sz);
3756 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
3757 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, opc-0x58);
3758 if (dis)
3759 VG_(printf)("pop%c %s\n", nameISize(sz), nameIReg(sz,opc-0x58));
3760 break;
3761
3762 case 0x9D: /* POPF */
3763 vg_assert(sz == 2 || sz == 4);
3764 t1 = newTemp(cb); t2 = newTemp(cb);
3765 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
3766 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3767 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3768 uLiteral(cb, sz);
3769 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
3770 uInstr1(cb, PUTF, sz, TempReg, t1);
3771 /* PUTF writes all the flags we are interested in */
3772 uFlagsRWU(cb, FlagsEmpty, FlagsALL, FlagsEmpty);
3773 if (dis)
3774 VG_(printf)("popf%c\n", nameISize(sz));
3775 break;
3776
3777 case 0x61: /* POPA */
3778 { Int reg;
3779 /* Just to keep things sane, we assert for a size 4. It's
3780 probably OK for size 2 as well, but I'd like to find a test
3781 case; ie, have the assertion fail, before committing to it.
3782 If it fails for you, uncomment the sz == 2 bit, try again,
3783 and let me know whether or not it works. (jseward@acm.org). */
3784 vg_assert(sz == 4 /* || sz == 2 */);
3785
3786 /* Eight values are popped, one per register, but the value of
3787 %esp on the stack is ignored and instead incremented (in one
3788 hit at the end) for each of the values. */
3789 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3790 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t2);
3791 uInstr2(cb, MOV, 4, TempReg, t2, TempReg, t3);
3792
3793 /* Do %edi, %esi, %ebp */
3794 for (reg = 7; reg >= 5; reg--) {
3795 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3796 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3797 uLiteral(cb, sz);
3798 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
3799 }
3800 /* Ignore (skip) value of %esp on stack. */
3801 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3802 uLiteral(cb, sz);
3803 /* Do %ebx, %edx, %ecx, %eax */
3804 for (reg = 3; reg >= 0; reg--) {
3805 uInstr2(cb, LOAD, sz, TempReg, t2, TempReg, t1);
3806 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t2);
3807 uLiteral(cb, sz);
3808 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, reg);
3809 }
3810 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t3);
3811 uLiteral(cb, sz * 8); /* One 'sz' per register */
3812 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ESP);
3813 if (dis)
3814 VG_(printf)("popa%c\n", nameISize(sz));
3815 break;
3816 }
3817
sewardj363e6062002-05-22 11:55:35 +00003818 case 0x8F: /* POPL/POPW m32 */
3819 { UInt pair1;
3820 Int tmpa;
3821 UChar rm = getUChar(eip);
3822
3823 /* make sure this instruction is correct POP */
3824 vg_assert(!epartIsReg(rm) && (gregOfRM(rm) == 0));
3825 /* and has correct size */
3826 vg_assert(sz == 4);
3827
3828 t1 = newTemp(cb); t3 = newTemp(cb);
3829 /* set t1 to ESP: t1 = ESP */
3830 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
3831 /* load M[ESP] to virtual register t3: t3 = M[t1] */
3832 uInstr2(cb, LOAD, 4, TempReg, t1, TempReg, t3);
3833 /* resolve MODR/M */
3834 pair1 = disAMode ( cb, eip, dis?dis_buf:NULL);
3835
3836 tmpa = LOW24(pair1);
3837 /* uInstr2(cb, LOAD, sz, TempReg, tmpa, TempReg, tmpa); */
3838 /* store value from stack in memory, M[m32] = t3 */
3839 uInstr2(cb, STORE, 4, TempReg, t3, TempReg, tmpa);
3840
3841 /* increase ESP */
3842 uInstr2(cb, ADD, 4, Literal, 0, TempReg, t1);
3843 uLiteral(cb, sz);
3844 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3845
3846 if (dis)
3847 VG_(printf)("popl %s\n", dis_buf);
3848
3849 eip += HI8(pair1);
3850 break;
3851 }
3852
sewardjde4a1d02002-03-22 01:27:54 +00003853 /* ------------------------ PUSH ----------------------- */
3854
3855 case 0x50: /* PUSH eAX */
3856 case 0x51: /* PUSH eCX */
3857 case 0x52: /* PUSH eDX */
sewardjde4a1d02002-03-22 01:27:54 +00003858 case 0x53: /* PUSH eBX */
3859 case 0x55: /* PUSH eBP */
3860 case 0x56: /* PUSH eSI */
3861 case 0x57: /* PUSH eDI */
sewardj4f51f9a2002-05-07 23:38:30 +00003862 { Int n_pushes;
3863 Addr eipS, eipE;
3864 UChar ch;
sewardj95621db2002-05-08 21:26:01 +00003865 if (sz != 4) goto normal_push_case;
3866 if (VG_(clo_cachesim)) goto normal_push_case;
sewardj4f51f9a2002-05-07 23:38:30 +00003867 /* eip points at first push insn + 1. Make eipS and eipE
3868 bracket the sequence. */
3869 eipE = eipS = eip - 1;
3870 while (True) {
3871 ch = getUChar(eipE+1);
3872 if (ch < 0x50 || ch > 0x57 || ch == 0x54) break;
3873 eipE++;
3874 }
3875 n_pushes = eipE - eipS + 1;
3876 if (0 && n_pushes > 1) VG_(printf)("%d pushes\n", n_pushes);
3877 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3878 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
3879 uInstr2(cb, MOV, 4, TempReg, t1, TempReg, t2);
3880 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3881 uLiteral(cb, 4 * n_pushes);
3882 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
3883 for (; eipS <= eipE; eipS++) {
3884 ch = getUChar(eipS);
3885 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t1);
3886 uLiteral(cb, 4);
3887 uInstr2(cb, GET, 4, ArchReg, ch-0x50, TempReg, t3);
3888 uInstr2(cb, STORE, 4, TempReg, t3, TempReg, t1);
3889 SMC_IF_ALL(cb);
3890 if (dis)
3891 VG_(printf)("pushl %s\n", nameIReg(4,ch-0x50));
3892 }
3893 eip = eipE + 1;
3894 break;
3895 }
3896
3897 case 0x54: /* PUSH eSP */
3898 normal_push_case:
sewardjde4a1d02002-03-22 01:27:54 +00003899 /* This is the Right Way, in that the value to be pushed is
3900 established before %esp is changed, so that pushl %esp
3901 correctly pushes the old value. */
3902 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3903 uInstr2(cb, GET, sz, ArchReg, opc-0x50, TempReg, t1);
3904 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
3905 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
3906 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3907 uLiteral(cb, sz);
3908 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
3909 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3910 SMC_IF_ALL(cb);
3911 if (dis)
3912 VG_(printf)("push%c %s\n", nameISize(sz), nameIReg(sz,opc-0x50));
3913 break;
3914
3915 case 0x68: /* PUSH Iv */
3916 d32 = getUDisp(sz,eip); eip += sz;
3917 goto do_push_I;
3918 case 0x6A: /* PUSH Ib, sign-extended to sz */
3919 d32 = getSDisp8(eip); eip += 1;
3920 goto do_push_I;
3921 do_push_I:
3922 t1 = newTemp(cb); t2 = newTemp(cb);
3923 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t1);
3924 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t1);
3925 uLiteral(cb, sz);
3926 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_ESP);
3927 uInstr2(cb, MOV, sz, Literal, 0, TempReg, t2);
3928 uLiteral(cb, d32);
3929 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t1);
3930 SMC_IF_ALL(cb);
3931 if (dis)
3932 VG_(printf)("push%c $0x%x\n", nameISize(sz), d32);
3933 break;
3934
3935 case 0x9C: /* PUSHF */
3936 vg_assert(sz == 2 || sz == 4);
3937 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3938 uInstr1(cb, GETF, sz, TempReg, t1);
3939 /* GETF reads all the flags we are interested in */
3940 uFlagsRWU(cb, FlagsALL, FlagsEmpty, FlagsEmpty);
3941 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
3942 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
3943 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3944 uLiteral(cb, sz);
3945 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_ESP);
3946 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3947 SMC_IF_ALL(cb);
3948 if (dis)
3949 VG_(printf)("pushf%c\n", nameISize(sz));
3950 break;
3951
3952 case 0x60: /* PUSHA */
3953 { Int reg;
3954 /* Just to keep things sane, we assert for a size 4. It's
3955 probably OK for size 2 as well, but I'd like to find a test
3956 case; ie, have the assertion fail, before committing to it.
3957 If it fails for you, uncomment the sz == 2 bit, try again,
3958 and let me know whether or not it works. (jseward@acm.org). */
3959 vg_assert(sz == 4 /* || sz == 2 */);
3960
3961 /* This is the Right Way, in that the value to be pushed is
3962 established before %esp is changed, so that pusha
3963 correctly pushes the old %esp value. New value of %esp is
3964 pushed at start. */
3965 t1 = newTemp(cb); t2 = newTemp(cb); t3 = newTemp(cb);
3966 t4 = newTemp(cb);
3967 uInstr2(cb, GET, 4, ArchReg, R_ESP, TempReg, t3);
3968 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t2);
3969 uInstr2(cb, MOV, 4, TempReg, t3, TempReg, t4);
3970 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t4);
3971 uLiteral(cb, sz * 8); /* One 'sz' per register. */
3972 uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_ESP);
3973 /* Do %eax, %ecx, %edx, %ebx */
3974 for (reg = 0; reg <= 3; reg++) {
3975 uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
3976 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3977 uLiteral(cb, sz);
3978 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3979 SMC_IF_ALL(cb);
3980 }
3981 /* Push old value of %esp */
3982 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3983 uLiteral(cb, sz);
3984 uInstr2(cb, STORE, sz, TempReg, t3, TempReg, t2);
3985 SMC_IF_ALL(cb);
3986 /* Do %ebp, %esi, %edi */
3987 for (reg = 5; reg <= 7; reg++) {
3988 uInstr2(cb, GET, sz, ArchReg, reg, TempReg, t1);
3989 uInstr2(cb, SUB, 4, Literal, 0, TempReg, t2);
3990 uLiteral(cb, sz);
3991 uInstr2(cb, STORE, sz, TempReg, t1, TempReg, t2);
3992 SMC_IF_ALL(cb);
3993 }
3994 if (dis)
3995 VG_(printf)("pusha%c\n", nameISize(sz));
3996 break;
3997 }
3998
3999 /* ------------------------ SCAS et al ----------------- */
4000
4001 case 0xA4: /* MOVSb, no REP prefix */
4002 codegen_MOVS ( cb, 1 );
4003 if (dis) VG_(printf)("movsb\n");
4004 break;
4005 case 0xA5: /* MOVSv, no REP prefix */
4006 codegen_MOVS ( cb, sz );
4007 if (dis) VG_(printf)("movs%c\n", nameISize(sz));
4008 break;
4009
4010 case 0xA6: /* CMPSb, no REP prefix */
4011 codegen_CMPS ( cb, 1 );
4012 if (dis) VG_(printf)("cmpsb\n");
4013 break;
4014
4015 case 0xAA: /* STOSb, no REP prefix */
4016 codegen_STOS ( cb, 1 );
4017 if (dis) VG_(printf)("stosb\n");
4018 break;
4019 case 0xAB: /* STOSv, no REP prefix */
4020 codegen_STOS ( cb, sz );
4021 if (dis) VG_(printf)("stos%c\n", nameISize(sz));
4022 break;
4023
4024 case 0xAC: /* LODSb, no REP prefix */
4025 codegen_LODS ( cb, 1 );
4026 if (dis) VG_(printf)("lodsb\n");
4027 break;
sewardj64a8cc42002-05-08 01:38:43 +00004028 case 0xAD: /* LODSv, no REP prefix */
4029 codegen_LODS ( cb, sz );
4030 if (dis) VG_(printf)("lods%c\n", nameISize(sz));
4031 break;
sewardjde4a1d02002-03-22 01:27:54 +00004032
4033 case 0xAE: /* SCASb, no REP prefix */
4034 codegen_SCAS ( cb, 1 );
4035 if (dis) VG_(printf)("scasb\n");
4036 break;
4037
4038 case 0xFC: /* CLD */
4039 uInstr0(cb, CALLM_S, 0);
4040 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CLD));
4041 uFlagsRWU(cb, FlagsEmpty, FlagD, FlagsEmpty);
4042 uInstr0(cb, CALLM_E, 0);
4043 if (dis) VG_(printf)("cld\n");
4044 break;
4045
4046 case 0xFD: /* STD */
4047 uInstr0(cb, CALLM_S, 0);
4048 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_STD));
4049 uFlagsRWU(cb, FlagsEmpty, FlagD, FlagsEmpty);
4050 uInstr0(cb, CALLM_E, 0);
4051 if (dis) VG_(printf)("std\n");
4052 break;
4053
4054 case 0xF2: { /* REPNE prefix insn */
4055 Addr eip_orig = eip - 1;
4056 abyte = getUChar(eip); eip++;
4057 if (abyte == 0x66) { sz = 2; abyte = getUChar(eip); eip++; }
4058
4059 if (abyte == 0xAE || 0xAF) { /* REPNE SCAS<sz> */
4060 if (abyte == 0xAE) sz = 1;
4061 codegen_REPNE_SCAS ( cb, sz, eip_orig, eip );
4062 *isEnd = True;
4063 if (dis) VG_(printf)("repne scas%c\n", nameISize(sz));
4064 }
4065 else {
4066 VG_(printf)("REPNE then 0x%x\n", (UInt)abyte);
4067 VG_(panic)("Unhandled REPNE case");
4068 }
4069 break;
4070 }
4071
4072 case 0xF3: { /* REPE prefix insn */
4073 Addr eip_orig = eip - 1;
4074 abyte = getUChar(eip); eip++;
4075 if (abyte == 0x66) { sz = 2; abyte = getUChar(eip); eip++; }
4076
4077 if (abyte == 0xA4 || abyte == 0xA5) { /* REPE MOV<sz> */
4078 if (abyte == 0xA4) sz = 1;
4079 codegen_REPE_MOVS ( cb, sz, eip_orig, eip );
4080 *isEnd = True;
4081 if (dis) VG_(printf)("repe mov%c\n", nameISize(sz));
4082 }
4083 else
4084 if (abyte == 0xA6 || abyte == 0xA7) { /* REPE CMP<sz> */
4085 if (abyte == 0xA6) sz = 1;
4086 codegen_REPE_CMPS ( cb, sz, eip_orig, eip );
4087 *isEnd = True;
4088 if (dis) VG_(printf)("repe cmps%c\n", nameISize(sz));
4089 }
4090 else
4091 if (abyte == 0xAA || abyte == 0xAB) { /* REPE STOS<sz> */
4092 if (abyte == 0xAA) sz = 1;
4093 codegen_REPE_STOS ( cb, sz, eip_orig, eip );
4094 *isEnd = True;
4095 if (dis) VG_(printf)("repe stos%c\n", nameISize(sz));
4096 } else {
4097 VG_(printf)("REPE then 0x%x\n", (UInt)abyte);
4098 VG_(panic)("Unhandled REPE case");
4099 }
4100 break;
4101 }
4102
4103 /* ------------------------ XCHG ----------------------- */
4104
4105 case 0x86: /* XCHG Gb,Eb */
4106 sz = 1;
4107 /* Fall through ... */
4108 case 0x87: /* XCHG Gv,Ev */
4109 modrm = getUChar(eip);
4110 t1 = newTemp(cb); t2 = newTemp(cb);
4111 if (epartIsReg(modrm)) {
4112 uInstr2(cb, GET, sz, ArchReg, eregOfRM(modrm), TempReg, t1);
4113 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t2);
4114 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, gregOfRM(modrm));
4115 uInstr2(cb, PUT, sz, TempReg, t2, ArchReg, eregOfRM(modrm));
4116 eip++;
4117 if (dis)
4118 VG_(printf)("xchg%c %s, %s\n", nameISize(sz),
4119 nameIReg(sz,gregOfRM(modrm)),
4120 nameIReg(sz,eregOfRM(modrm)));
4121 } else {
4122 pair = disAMode ( cb, eip, dis?dis_buf:NULL);
4123 t3 = LOW24(pair);
4124 uInstr2(cb, LOAD, sz, TempReg, t3, TempReg, t1);
4125 uInstr2(cb, GET, sz, ArchReg, gregOfRM(modrm), TempReg, t2);
4126 uInstr2(cb, STORE, sz, TempReg, t2, TempReg, t3);
4127 SMC_IF_SOME(cb);
4128 uInstr2(cb, PUT, sz, TempReg, t1, ArchReg, gregOfRM(modrm));
4129 eip += HI8(pair);
4130 if (dis)
4131 VG_(printf)("xchg%c %s, %s\n", nameISize(sz),
4132 nameIReg(sz,gregOfRM(modrm)),
4133 dis_buf);
4134 }
4135 break;
4136
4137 case 0x90: /* XCHG eAX,eAX */
4138 if (dis) VG_(printf)("nop\n");
4139 break;
4140 case 0x91: /* XCHG eCX,eSI */
4141 case 0x96: /* XCHG eAX,eSI */
4142 case 0x97: /* XCHG eAX,eDI */
4143 codegen_xchg_eAX_Reg ( cb, sz, opc - 0x90 );
4144 break;
4145
4146 /* ------------------------ (Grp1 extensions) ---------- */
4147
4148 case 0x80: /* Grp1 Ib,Eb */
4149 modrm = getUChar(eip);
4150 am_sz = lengthAMode(eip);
4151 sz = 1;
4152 d_sz = 1;
4153 d32 = getSDisp8(eip + am_sz);
4154 eip = dis_Grp1 ( cb, eip, modrm, am_sz, d_sz, sz, d32 );
4155 break;
4156
4157 case 0x81: /* Grp1 Iv,Ev */
4158 modrm = getUChar(eip);
4159 am_sz = lengthAMode(eip);
4160 d_sz = sz;
4161 d32 = getUDisp(d_sz, eip + am_sz);
4162 eip = dis_Grp1 ( cb, eip, modrm, am_sz, d_sz, sz, d32 );
4163 break;
4164
4165 case 0x83: /* Grp1 Ib,Ev */
4166 modrm = getUChar(eip);
4167 am_sz = lengthAMode(eip);
4168 d_sz = 1;
4169 d32 = getSDisp8(eip + am_sz);
4170 eip = dis_Grp1 ( cb, eip, modrm, am_sz, d_sz, sz, d32 );
4171 break;
4172
4173 /* ------------------------ (Grp2 extensions) ---------- */
4174
4175 case 0xC0: /* Grp2 Ib,Eb */
4176 modrm = getUChar(eip);
4177 am_sz = lengthAMode(eip);
4178 d_sz = 1;
4179 d32 = getSDisp8(eip + am_sz);
4180 sz = 1;
4181 eip = dis_Grp2 ( cb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
4182 break;
4183
4184 case 0xC1: /* Grp2 Ib,Ev */
4185 modrm = getUChar(eip);
4186 am_sz = lengthAMode(eip);
4187 d_sz = 1;
4188 d32 = getSDisp8(eip + am_sz);
4189 eip = dis_Grp2 ( cb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
4190 break;
4191
4192 case 0xD0: /* Grp2 1,Eb */
4193 modrm = getUChar(eip);
4194 am_sz = lengthAMode(eip);
4195 d_sz = 0;
4196 d32 = 1;
4197 sz = 1;
4198 eip = dis_Grp2 ( cb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
4199 break;
4200
4201 case 0xD1: /* Grp2 1,Ev */
4202 modrm = getUChar(eip);
4203 am_sz = lengthAMode(eip);
4204 d_sz = 0;
4205 d32 = 1;
4206 eip = dis_Grp2 ( cb, eip, modrm, am_sz, d_sz, sz, Literal, d32 );
4207 break;
4208
4209 case 0xD3: /* Grp2 CL,Ev */
4210 modrm = getUChar(eip);
4211 am_sz = lengthAMode(eip);
4212 d_sz = 0;
4213 eip = dis_Grp2 ( cb, eip, modrm, am_sz, d_sz, sz, ArchReg, R_ECX );
4214 break;
4215
4216 /* ------------------------ (Grp3 extensions) ---------- */
4217
4218 case 0xF6: /* Grp3 Eb */
4219 eip = dis_Grp3 ( cb, 1, eip );
4220 break;
4221 case 0xF7: /* Grp3 Ev */
4222 eip = dis_Grp3 ( cb, sz, eip );
4223 break;
4224
4225 /* ------------------------ (Grp4 extensions) ---------- */
4226
4227 case 0xFE: /* Grp4 Eb */
4228 eip = dis_Grp4 ( cb, eip );
4229 break;
4230
4231 /* ------------------------ (Grp5 extensions) ---------- */
4232
4233 case 0xFF: /* Grp5 Ev */
4234 eip = dis_Grp5 ( cb, sz, eip, isEnd );
4235 break;
4236
4237 /* ------------------------ Escapes to 2-byte opcodes -- */
4238
4239 case 0x0F: {
4240 opc = getUChar(eip); eip++;
4241 switch (opc) {
4242
4243 /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
4244
4245 case 0xBA: /* Grp8 Ib,Ev */
4246 modrm = getUChar(eip);
4247 am_sz = lengthAMode(eip);
4248 d32 = getSDisp8(eip + am_sz);
sewardj0ece28b2002-04-16 00:42:12 +00004249 eip = dis_Grp8_BT ( cb, eip, modrm, am_sz, sz, d32 );
sewardjde4a1d02002-03-22 01:27:54 +00004250 break;
sewardj0ece28b2002-04-16 00:42:12 +00004251
sewardjde4a1d02002-03-22 01:27:54 +00004252 /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
4253
4254 case 0xBC: /* BSF Gv,Ev */
4255 eip = dis_bs_E_G ( cb, sz, eip, True );
4256 break;
4257 case 0xBD: /* BSR Gv,Ev */
4258 eip = dis_bs_E_G ( cb, sz, eip, False );
4259 break;
4260
4261 /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
4262
4263 case 0xC8: /* BSWAP %eax */
4264 case 0xC9:
4265 case 0xCA:
4266 case 0xCB:
4267 case 0xCC:
4268 case 0xCD:
4269 case 0xCE:
4270 case 0xCF: /* BSWAP %edi */
4271 /* AFAICS from the Intel docs, this only exists at size 4. */
4272 vg_assert(sz == 4);
4273 t1 = newTemp(cb);
4274 uInstr2(cb, GET, 4, ArchReg, opc-0xC8, TempReg, t1);
4275 uInstr1(cb, BSWAP, 4, TempReg, t1);
4276 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, opc-0xC8);
4277 if (dis) VG_(printf)("bswapl %s\n", nameIReg(4, opc-0xC8));
4278 break;
4279
4280 /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
4281
4282 case 0xA3: /* BT Gv,Ev */
4283 eip = dis_bt_G_E ( cb, sz, eip, BtOpNone );
4284 break;
4285 case 0xB3: /* BTR Gv,Ev */
4286 eip = dis_bt_G_E ( cb, sz, eip, BtOpReset );
4287 break;
4288 case 0xAB: /* BTS Gv,Ev */
4289 eip = dis_bt_G_E ( cb, sz, eip, BtOpSet );
4290 break;
4291 case 0xBB: /* BTC Gv,Ev */
4292 eip = dis_bt_G_E ( cb, sz, eip, BtOpComp );
4293 break;
4294
4295 /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
4296
4297 case 0x40:
4298 case 0x41:
4299 case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
4300 case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
4301 case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
4302 case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
4303 case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
4304 case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
4305 case 0x48: /* CMOVSb (cmov negative) */
4306 case 0x49: /* CMOVSb (cmov not negative) */
4307 case 0x4A: /* CMOVP (cmov parity even) */
sewardj969129d2002-04-21 11:43:11 +00004308 case 0x4B: /* CMOVNP (cmov parity odd) */
sewardjde4a1d02002-03-22 01:27:54 +00004309 case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
4310 case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
4311 case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
4312 case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
4313 eip = dis_cmov_E_G(cb, sz, (Condcode)(opc - 0x40), eip);
4314 break;
4315
4316 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
4317
4318 case 0xB1: /* CMPXCHG Gv,Ev */
4319 eip = dis_cmpxchg_G_E ( cb, sz, eip );
4320 break;
4321
4322 /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
4323
4324 case 0xA2: /* CPUID */
4325 t1 = newTemp(cb);
4326 t2 = newTemp(cb);
4327 t3 = newTemp(cb);
4328 t4 = newTemp(cb);
4329 uInstr0(cb, CALLM_S, 0);
4330
4331 uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t1);
4332 uInstr1(cb, PUSH, 4, TempReg, t1);
4333
4334 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
4335 uLiteral(cb, 0);
4336 uInstr1(cb, PUSH, 4, TempReg, t2);
4337
4338 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t3);
4339 uLiteral(cb, 0);
4340 uInstr1(cb, PUSH, 4, TempReg, t3);
4341
4342 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t4);
4343 uLiteral(cb, 0);
4344 uInstr1(cb, PUSH, 4, TempReg, t4);
4345
4346 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_CPUID));
4347 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
4348
4349 uInstr1(cb, POP, 4, TempReg, t4);
4350 uInstr2(cb, PUT, 4, TempReg, t4, ArchReg, R_EDX);
4351
4352 uInstr1(cb, POP, 4, TempReg, t3);
4353 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_ECX);
4354
4355 uInstr1(cb, POP, 4, TempReg, t2);
4356 uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EBX);
4357
4358 uInstr1(cb, POP, 4, TempReg, t1);
4359 uInstr2(cb, PUT, 4, TempReg, t1, ArchReg, R_EAX);
4360
4361 uInstr0(cb, CALLM_E, 0);
4362 if (dis) VG_(printf)("cpuid\n");
4363 break;
4364
4365 /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
4366
4367 case 0xB6: /* MOVZXb Eb,Gv */
4368 eip = dis_movx_E_G ( cb, eip, 1, 4, False );
4369 break;
4370 case 0xB7: /* MOVZXw Ew,Gv */
4371 eip = dis_movx_E_G ( cb, eip, 2, 4, False );
4372 break;
4373
4374 case 0xBE: /* MOVSXb Eb,Gv */
4375 eip = dis_movx_E_G ( cb, eip, 1, 4, True );
4376 break;
4377 case 0xBF: /* MOVSXw Ew,Gv */
4378 eip = dis_movx_E_G ( cb, eip, 2, 4, True );
4379 break;
4380
4381 /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
4382
4383 case 0xAF: /* IMUL Ev, Gv */
4384 eip = dis_mul_E_G ( cb, sz, eip, True );
4385 break;
4386
4387 /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
4388 case 0x80:
4389 case 0x81:
4390 case 0x82: /* JBb/JNAEb (jump below) */
4391 case 0x83: /* JNBb/JAEb (jump not below) */
4392 case 0x84: /* JZb/JEb (jump zero) */
4393 case 0x85: /* JNZb/JNEb (jump not zero) */
4394 case 0x86: /* JBEb/JNAb (jump below or equal) */
4395 case 0x87: /* JNBEb/JAb (jump not below or equal) */
4396 case 0x88: /* JSb (jump negative) */
4397 case 0x89: /* JSb (jump not negative) */
4398 case 0x8A: /* JP (jump parity even) */
sewardj969129d2002-04-21 11:43:11 +00004399 case 0x8B: /* JNP/JPO (jump parity odd) */
sewardjde4a1d02002-03-22 01:27:54 +00004400 case 0x8C: /* JLb/JNGEb (jump less) */
4401 case 0x8D: /* JGEb/JNLb (jump greater or equal) */
4402 case 0x8E: /* JLEb/JNGb (jump less or equal) */
4403 case 0x8F: /* JGb/JNLEb (jump greater) */
4404 d32 = (eip+4) + getUDisp32(eip); eip += 4;
4405 uInstr1(cb, JMP, 0, Literal, 0);
4406 uLiteral(cb, d32);
4407 uCond(cb, (Condcode)(opc - 0x80));
4408 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
4409 uInstr1(cb, JMP, 0, Literal, 0);
4410 uLiteral(cb, eip);
4411 uCond(cb, CondAlways);
4412 *isEnd = True;
4413 if (dis)
4414 VG_(printf)("j%s-32 0x%x\n",
4415 VG_(nameCondcode)(opc - 0x80), d32);
4416 break;
4417
4418 /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
4419
4420 case 0x31: /* RDTSC */
4421 t1 = newTemp(cb);
4422 t2 = newTemp(cb);
4423 t3 = newTemp(cb);
4424 uInstr0(cb, CALLM_S, 0);
4425 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1);
4426 uLiteral(cb, 0);
4427 uInstr1(cb, PUSH, 4, TempReg, t1);
4428 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2);
4429 uLiteral(cb, 0);
4430 uInstr1(cb, PUSH, 4, TempReg, t2);
4431 uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_RDTSC));
4432 uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty);
4433 uInstr1(cb, POP, 4, TempReg, t3);
4434 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EDX);
4435 uInstr1(cb, POP, 4, TempReg, t3);
4436 uInstr2(cb, PUT, 4, TempReg, t3, ArchReg, R_EAX);
4437 uInstr0(cb, CALLM_E, 0);
4438 if (dis) VG_(printf)("rdtsc\n");
4439 break;
4440
4441 /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
4442 case 0x90:
4443 case 0x91:
4444 case 0x92: /* set-Bb/set-NAEb (jump below) */
4445 case 0x93: /* set-NBb/set-AEb (jump not below) */
4446 case 0x94: /* set-Zb/set-Eb (jump zero) */
4447 case 0x95: /* set-NZb/set-NEb (jump not zero) */
4448 case 0x96: /* set-BEb/set-NAb (jump below or equal) */
4449 case 0x97: /* set-NBEb/set-Ab (jump not below or equal) */
4450 case 0x98: /* set-Sb (jump negative) */
4451 case 0x99: /* set-Sb (jump not negative) */
4452 case 0x9A: /* set-P (jump parity even) */
4453 case 0x9B: /* set-NP (jump parity odd) */
4454 case 0x9C: /* set-Lb/set-NGEb (jump less) */
4455 case 0x9D: /* set-GEb/set-NLb (jump greater or equal) */
4456 case 0x9E: /* set-LEb/set-NGb (jump less or equal) */
4457 case 0x9F: /* set-Gb/set-NLEb (jump greater) */
4458 modrm = getUChar(eip);
4459 t1 = newTemp(cb);
4460 if (epartIsReg(modrm)) {
4461 eip++;
4462 uInstr1(cb, CC2VAL, 1, TempReg, t1);
4463 uCond(cb, (Condcode)(opc-0x90));
4464 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
4465 uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, eregOfRM(modrm));
4466 if (dis) VG_(printf)("set%s %s\n",
4467 VG_(nameCondcode)(opc-0x90),
4468 nameIReg(1,eregOfRM(modrm)));
4469 } else {
4470 pair = disAMode ( cb, eip, dis?dis_buf:NULL );
4471 t2 = LOW24(pair);
4472 eip += HI8(pair);
4473 uInstr1(cb, CC2VAL, 1, TempReg, t1);
4474 uCond(cb, (Condcode)(opc-0x90));
4475 uFlagsRWU(cb, FlagsOSZACP, FlagsEmpty, FlagsEmpty);
4476 uInstr2(cb, STORE, 1, TempReg, t1, TempReg, t2);
4477 SMC_IF_ALL(cb);
4478 if (dis) VG_(printf)("set%s %s\n",
4479 VG_(nameCondcode)(opc-0x90),
4480 dis_buf);
4481 }
4482 break;
4483
4484 /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
4485
4486 case 0xA4: /* SHLDv imm8,Gv,Ev */
4487 modrm = getUChar(eip);
4488 eip = dis_SHLRD_Gv_Ev (
4489 cb, eip, modrm, sz,
4490 Literal, getUChar(eip + lengthAMode(eip)),
4491 True );
4492 break;
4493 case 0xA5: /* SHLDv %cl,Gv,Ev */
4494 modrm = getUChar(eip);
4495 eip = dis_SHLRD_Gv_Ev (
4496 cb, eip, modrm, sz, ArchReg, R_CL, True );
4497 break;
4498
4499 case 0xAC: /* SHRDv imm8,Gv,Ev */
4500 modrm = getUChar(eip);
4501 eip = dis_SHLRD_Gv_Ev (
4502 cb, eip, modrm, sz,
4503 Literal, getUChar(eip + lengthAMode(eip)),
4504 False );
4505 break;
4506 case 0xAD: /* SHRDv %cl,Gv,Ev */
4507 modrm = getUChar(eip);
4508 eip = dis_SHLRD_Gv_Ev (
4509 cb, eip, modrm, sz, ArchReg, R_CL, False );
4510 break;
4511
4512 /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
4513
4514 case 0xC1: /* XADD Gv,Ev */
4515 eip = dis_xadd_G_E ( cb, sz, eip );
4516 break;
4517
4518 /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
4519
4520 default:
4521 VG_(printf)("disInstr: unhandled 2-byte opcode 0x%x\n",
4522 (UInt)opc);
4523 VG_(unimplemented)("unhandled x86 0x0F 2-byte opcode");
4524 }
4525
4526 break;
4527 }
4528
4529 /* ------------------------ ??? ------------------------ */
4530
4531 default:
4532 VG_(printf)("disInstr: unhandled opcode 0x%x then 0x%x\n",
4533 (UInt)opc, (UInt)getUChar(eip));
sewardjcfc39b22002-05-08 01:58:18 +00004534 if (opc == 0x8C)
4535 VG_(nvidia_moan)();
sewardjde4a1d02002-03-22 01:27:54 +00004536 VG_(panic)("unhandled x86 opcode");
4537 }
4538
4539 if (dis)
4540 VG_(printf)("\n");
4541 for (; first_uinstr < cb->used; first_uinstr++) {
4542 Bool sane = VG_(saneUInstr)(True, &cb->instrs[first_uinstr]);
4543 if (dis || !sane)
4544 VG_(ppUInstr)(sane ? first_uinstr : -1,
4545 &cb->instrs[first_uinstr]);
4546 vg_assert(sane);
4547 }
4548
4549 return eip;
4550}
4551
4552
4553/* Disassemble a complete basic block, starting at eip, and dumping
4554 the ucode into cb. Returns the size, in bytes, of the basic
4555 block. */
4556
4557Int VG_(disBB) ( UCodeBlock* cb, Addr eip0 )
4558{
4559 Addr eip = eip0;
4560 Bool isEnd = False;
4561 Bool block_sane;
njn4f9c9342002-04-29 16:03:24 +00004562 Int INCEIP_allowed_lag = 4;
4563 Int delta = 0;
4564
sewardjde4a1d02002-03-22 01:27:54 +00004565 if (dis) VG_(printf)("\n");
4566
njn4f9c9342002-04-29 16:03:24 +00004567 /* When cache simulating, to ensure cache misses are attributed to the
4568 * correct line we ensure EIP is always correct. This is done by:
4569 *
4570 * a) Using eager INCEIP updating to cope with all instructions except those
4571 * at the end of a basic block.
4572 *
4573 * b) Patching in the size of the original x86 instr in the `extra4b' field
4574 * of JMPs at the end of a basic block. Two cases:
4575 * - Jcond followed by Juncond: patch the Jcond
4576 * - Juncond alone: patch the Juncond
4577 *
4578 * See vg_cachesim_instrument() for how this is used.
4579 */
4580 if (VG_(clo_cachesim)) {
4581 INCEIP_allowed_lag = 0;
4582 }
4583
sewardjde4a1d02002-03-22 01:27:54 +00004584 if (VG_(clo_single_step)) {
4585 eip = disInstr ( cb, eip, &isEnd );
njn4f9c9342002-04-29 16:03:24 +00004586
4587 /* Add a JMP to the next (single x86 instruction) BB if it doesn't
4588 * already end with a JMP instr. We also need to check for no UCode,
4589 * which occurs if the x86 instr was a nop */
4590 if (cb->used == 0 || LAST_UINSTR(cb).opcode != JMP) {
4591 uInstr1(cb, JMP, 0, Literal, 0);
4592 uLiteral(cb, eip);
4593 uCond(cb, CondAlways);
4594 if (dis) VG_(ppUInstr)(cb->used-1, &cb->instrs[cb->used-1]);
4595 }
4596 delta = eip - eip0;
4597
sewardjde4a1d02002-03-22 01:27:54 +00004598 } else {
sewardjde4a1d02002-03-22 01:27:54 +00004599 Addr eip2;
njn4f9c9342002-04-29 16:03:24 +00004600 while (!isEnd) {
sewardjde4a1d02002-03-22 01:27:54 +00004601 eip2 = disInstr ( cb, eip, &isEnd );
4602 delta += (eip2 - eip);
4603 eip = eip2;
sewardjde4a1d02002-03-22 01:27:54 +00004604 /* Split up giant basic blocks into pieces, so the
4605 translations fall within 64k. */
njn4f9c9342002-04-29 16:03:24 +00004606 if (eip - eip0 > 2000 && !isEnd) {
sewardja0f921a2002-05-08 00:42:25 +00004607 if (VG_(clo_verbosity) > 2)
njn4f9c9342002-04-29 16:03:24 +00004608 VG_(message)(Vg_DebugMsg,
sewardjde4a1d02002-03-22 01:27:54 +00004609 "Warning: splitting giant basic block into pieces");
4610 uInstr1(cb, JMP, 0, Literal, 0);
4611 uLiteral(cb, eip);
4612 uCond(cb, CondAlways);
4613 if (dis) VG_(ppUInstr)(cb->used-1, &cb->instrs[cb->used-1]);
njn4f9c9342002-04-29 16:03:24 +00004614 isEnd = True;
4615
4616 } else if (delta > INCEIP_allowed_lag && !isEnd) {
4617 uInstr1(cb, INCEIP, 0, Lit16, delta);
4618 if (dis) VG_(ppUInstr)(cb->used-1, &cb->instrs[cb->used-1]);
4619 delta = 0;
sewardjde4a1d02002-03-22 01:27:54 +00004620 }
4621 if (dis) VG_(printf)("\n");
4622 }
4623 }
njn4f9c9342002-04-29 16:03:24 +00004624 if (VG_(clo_cachesim)) {
4625 /* Patch instruction size into earliest JMP. */
4626 if (cb->used >= 2 && JMP == cb->instrs[cb->used - 2].opcode) {
4627 cb->instrs[cb->used - 2].extra4b = delta;
4628 } else {
4629 LAST_UINSTR(cb).extra4b = delta;
4630 }
4631 }
sewardjde4a1d02002-03-22 01:27:54 +00004632
4633 block_sane = VG_(saneUCodeBlock)(cb);
4634 if (!block_sane) {
4635 VG_(ppUCodeBlock)(cb, "block failing sanity check");
4636 vg_assert(block_sane);
4637 }
4638
4639 return eip - eip0;
4640}
4641
4642
4643/*--------------------------------------------------------------------*/
4644/*--- end vg_to_ucode.c ---*/
4645/*--------------------------------------------------------------------*/