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