blob: 26f16139bf381b6c6d635fb03727989617d0df66 [file] [log] [blame]
sewardjde4a1d02002-03-22 01:27:54 +00001
2/*--------------------------------------------------------------------*/
3/*--- The JITter: translate ucode back to x86 code. ---*/
4/*--- vg_from_ucode.c ---*/
5/*--------------------------------------------------------------------*/
6/*
7 This file is part of Valgrind, an x86 protected-mode emulator
8 designed for debugging and profiling binaries on x86-Unixes.
9
10 Copyright (C) 2000-2002 Julian Seward
11 jseward@acm.org
sewardjde4a1d02002-03-22 01:27:54 +000012
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
27
28 The GNU General Public License is contained in the file LICENSE.
29*/
30
31#include "vg_include.h"
32
33
34/*------------------------------------------------------------*/
35/*--- Renamings of frequently-used global functions. ---*/
36/*------------------------------------------------------------*/
37
38#define dis VG_(disassemble)
39#define nameIReg VG_(nameOfIntReg)
40#define nameISize VG_(nameOfIntSize)
41
42
43/*------------------------------------------------------------*/
44/*--- Instruction emission -- turning final uinstrs back ---*/
45/*--- into x86 code. ---*/
46/*------------------------------------------------------------*/
47
48/* [2001-07-08 This comment is now somewhat out of date.]
49
50 This is straightforward but for one thing: to facilitate generating
51 code in a single pass, we generate position-independent code. To
52 do this, calls and jmps to fixed addresses must specify the address
53 by first loading it into a register, and jump to/call that
54 register. Fortunately, the only jump to a literal is the jump back
55 to vg_dispatch, and only %eax is live then, conveniently. Ucode
56 call insns may only have a register as target anyway, so there's no
57 need to do anything fancy for them.
58
59 The emit_* routines constitute the lowest level of instruction
60 emission. They simply emit the sequence of bytes corresponding to
61 the relevant instruction, with no further ado. In particular there
62 is no checking about whether uses of byte registers makes sense,
63 nor whether shift insns have their first operand in %cl, etc.
64
65 These issues are taken care of by the level above, the synth_*
66 routines. These detect impossible operand combinations and turn
67 them into sequences of legal instructions. Finally, emitUInstr is
68 phrased in terms of the synth_* abstraction layer. */
69
70static UChar* emitted_code;
71static Int emitted_code_used;
72static Int emitted_code_size;
73
74static void expandEmittedCode ( void )
75{
76 Int i;
77 UChar* tmp = VG_(jitmalloc)(2 * emitted_code_size);
78 /* VG_(printf)("expand to %d\n", 2 * emitted_code_size); */
79 for (i = 0; i < emitted_code_size; i++)
80 tmp[i] = emitted_code[i];
81 VG_(jitfree)(emitted_code);
82 emitted_code = tmp;
83 emitted_code_size *= 2;
84}
85
86static __inline__ void emitB ( UInt b )
87{
88 if (dis) {
89 if (b < 16) VG_(printf)("0%x ", b); else VG_(printf)("%2x ", b);
90 }
91 if (emitted_code_used == emitted_code_size)
92 expandEmittedCode();
93
94 emitted_code[emitted_code_used] = (UChar)b;
95 emitted_code_used++;
96}
97
98static __inline__ void emitW ( UInt l )
99{
100 emitB ( (l) & 0x000000FF );
101 emitB ( (l >> 8) & 0x000000FF );
102}
103
104static __inline__ void emitL ( UInt l )
105{
106 emitB ( (l) & 0x000000FF );
107 emitB ( (l >> 8) & 0x000000FF );
108 emitB ( (l >> 16) & 0x000000FF );
109 emitB ( (l >> 24) & 0x000000FF );
110}
111
112static __inline__ void newEmit ( void )
113{
114 if (dis)
115 VG_(printf)("\t %4d: ", emitted_code_used );
116}
117
118/* Is this a callee-save register, in the normal C calling convention? */
119#define VG_CALLEE_SAVED(reg) (reg == R_EBX || reg == R_ESI || reg == R_EDI)
120
121
122/*----------------------------------------------------*/
123/*--- Addressing modes ---*/
124/*----------------------------------------------------*/
125
126static __inline__ UChar mkModRegRM ( UChar mod, UChar reg, UChar regmem )
127{
128 return ((mod & 3) << 6) | ((reg & 7) << 3) | (regmem & 7);
129}
130
131static __inline__ UChar mkSIB ( Int scale, Int regindex, Int regbase )
132{
133 Int shift;
134 switch (scale) {
135 case 1: shift = 0; break;
136 case 2: shift = 1; break;
137 case 4: shift = 2; break;
138 case 8: shift = 3; break;
139 default: VG_(panic)( "mkSIB" );
140 }
141 return ((shift & 3) << 6) | ((regindex & 7) << 3) | (regbase & 7);
142}
143
144static __inline__ void emit_amode_litmem_reg ( Addr addr, Int reg )
145{
146 /* ($ADDR), reg */
147 emitB ( mkModRegRM(0, reg, 5) );
148 emitL ( addr );
149}
150
151static __inline__ void emit_amode_regmem_reg ( Int regmem, Int reg )
152{
153 /* (regmem), reg */
154 if (regmem == R_ESP)
155 VG_(panic)("emit_amode_regmem_reg");
156 if (regmem == R_EBP) {
157 emitB ( mkModRegRM(1, reg, 5) );
158 emitB ( 0x00 );
159 } else {
160 emitB( mkModRegRM(0, reg, regmem) );
161 }
162}
163
164static __inline__ void emit_amode_offregmem_reg ( Int off, Int regmem, Int reg )
165{
166 if (regmem == R_ESP)
167 VG_(panic)("emit_amode_offregmem_reg(ESP)");
168 if (off < -128 || off > 127) {
169 /* Use a large offset */
170 /* d32(regmem), reg */
171 emitB ( mkModRegRM(2, reg, regmem) );
172 emitL ( off );
173 } else {
174 /* d8(regmem), reg */
175 emitB ( mkModRegRM(1, reg, regmem) );
176 emitB ( off & 0xFF );
177 }
178}
179
180static __inline__ void emit_amode_sib_reg ( Int off, Int scale, Int regbase,
181 Int regindex, Int reg )
182{
183 if (regindex == R_ESP)
184 VG_(panic)("emit_amode_sib_reg(ESP)");
185 if (off < -128 || off > 127) {
186 /* Use a 32-bit offset */
187 emitB ( mkModRegRM(2, reg, 4) ); /* SIB with 32-bit displacement */
188 emitB ( mkSIB( scale, regindex, regbase ) );
189 emitL ( off );
190 } else {
191 /* Use an 8-bit offset */
192 emitB ( mkModRegRM(1, reg, 4) ); /* SIB with 8-bit displacement */
193 emitB ( mkSIB( scale, regindex, regbase ) );
194 emitB ( off & 0xFF );
195 }
196}
197
198static __inline__ void emit_amode_ereg_greg ( Int e_reg, Int g_reg )
199{
200 /* other_reg, reg */
201 emitB ( mkModRegRM(3, g_reg, e_reg) );
202}
203
204static __inline__ void emit_amode_greg_ereg ( Int g_reg, Int e_reg )
205{
206 /* other_reg, reg */
207 emitB ( mkModRegRM(3, g_reg, e_reg) );
208}
209
210
211/*----------------------------------------------------*/
212/*--- Opcode translation ---*/
213/*----------------------------------------------------*/
214
215static __inline__ Int mkGrp1opcode ( Opcode opc )
216{
217 switch (opc) {
218 case ADD: return 0;
219 case OR: return 1;
220 case ADC: return 2;
221 case SBB: return 3;
222 case AND: return 4;
223 case SUB: return 5;
224 case XOR: return 6;
225 default: VG_(panic)("mkGrp1opcode");
226 }
227}
228
229static __inline__ Int mkGrp2opcode ( Opcode opc )
230{
231 switch (opc) {
232 case ROL: return 0;
233 case ROR: return 1;
234 case RCL: return 2;
235 case RCR: return 3;
236 case SHL: return 4;
237 case SHR: return 5;
238 case SAR: return 7;
239 default: VG_(panic)("mkGrp2opcode");
240 }
241}
242
243static __inline__ Int mkGrp3opcode ( Opcode opc )
244{
245 switch (opc) {
246 case NOT: return 2;
247 case NEG: return 3;
248 default: VG_(panic)("mkGrp3opcode");
249 }
250}
251
252static __inline__ Int mkGrp4opcode ( Opcode opc )
253{
254 switch (opc) {
255 case INC: return 0;
256 case DEC: return 1;
257 default: VG_(panic)("mkGrp4opcode");
258 }
259}
260
261static __inline__ Int mkGrp5opcode ( Opcode opc )
262{
263 switch (opc) {
264 case CALLM: return 2;
265 case JMP: return 4;
266 default: VG_(panic)("mkGrp5opcode");
267 }
268}
269
270static __inline__ UChar mkPrimaryOpcode ( Opcode opc )
271{
272 switch (opc) {
273 case ADD: return 0x00;
274 case ADC: return 0x10;
275 case AND: return 0x20;
276 case XOR: return 0x30;
277 case OR: return 0x08;
278 case SBB: return 0x18;
279 case SUB: return 0x28;
280 default: VG_(panic)("mkPrimaryOpcode");
281 }
282}
283
284/*----------------------------------------------------*/
285/*--- v-size (4, or 2 with OSO) insn emitters ---*/
286/*----------------------------------------------------*/
287
288static void emit_movv_offregmem_reg ( Int sz, Int off, Int areg, Int reg )
289{
290 newEmit();
291 if (sz == 2) emitB ( 0x66 );
292 emitB ( 0x8B ); /* MOV Ev, Gv */
293 emit_amode_offregmem_reg ( off, areg, reg );
294 if (dis)
295 VG_(printf)( "\n\t\tmov%c\t0x%x(%s), %s\n",
296 nameISize(sz), off, nameIReg(4,areg), nameIReg(sz,reg));
297}
298
299static void emit_movv_reg_offregmem ( Int sz, Int reg, Int off, Int areg )
300{
301 newEmit();
302 if (sz == 2) emitB ( 0x66 );
303 emitB ( 0x89 ); /* MOV Gv, Ev */
304 emit_amode_offregmem_reg ( off, areg, reg );
305 if (dis)
306 VG_(printf)( "\n\t\tmov%c\t%s, 0x%x(%s)\n",
307 nameISize(sz), nameIReg(sz,reg), off, nameIReg(4,areg));
308}
309
310static void emit_movv_regmem_reg ( Int sz, Int reg1, Int reg2 )
311{
312 newEmit();
313 if (sz == 2) emitB ( 0x66 );
314 emitB ( 0x8B ); /* MOV Ev, Gv */
315 emit_amode_regmem_reg ( reg1, reg2 );
316 if (dis)
317 VG_(printf)( "\n\t\tmov%c\t(%s), %s\n",
318 nameISize(sz), nameIReg(4,reg1), nameIReg(sz,reg2));
319}
320
321static void emit_movv_reg_regmem ( Int sz, Int reg1, Int reg2 )
322{
323 newEmit();
324 if (sz == 2) emitB ( 0x66 );
325 emitB ( 0x89 ); /* MOV Gv, Ev */
326 emit_amode_regmem_reg ( reg2, reg1 );
327 if (dis)
328 VG_(printf)( "\n\t\tmov%c\t%s, (%s)\n",
329 nameISize(sz), nameIReg(sz,reg1), nameIReg(4,reg2));
330}
331
332static void emit_movv_reg_reg ( Int sz, Int reg1, Int reg2 )
333{
334 newEmit();
335 if (sz == 2) emitB ( 0x66 );
336 emitB ( 0x89 ); /* MOV Gv, Ev */
337 emit_amode_ereg_greg ( reg2, reg1 );
338 if (dis)
339 VG_(printf)( "\n\t\tmov%c\t%s, %s\n",
340 nameISize(sz), nameIReg(sz,reg1), nameIReg(sz,reg2));
341}
342
343static void emit_nonshiftopv_lit_reg ( Int sz, Opcode opc,
344 UInt lit, Int reg )
345{
346 newEmit();
347 if (sz == 2) emitB ( 0x66 );
348 if (lit == VG_(extend_s_8to32)(lit & 0x000000FF)) {
349 /* short form OK */
350 emitB ( 0x83 ); /* Grp1 Ib,Ev */
351 emit_amode_ereg_greg ( reg, mkGrp1opcode(opc) );
352 emitB ( lit & 0x000000FF );
353 } else {
354 emitB ( 0x81 ); /* Grp1 Iv,Ev */
355 emit_amode_ereg_greg ( reg, mkGrp1opcode(opc) );
356 if (sz == 2) emitW ( lit ); else emitL ( lit );
357 }
358 if (dis)
359 VG_(printf)( "\n\t\t%s%c\t$0x%x, %s\n",
360 VG_(nameUOpcode)(False,opc), nameISize(sz),
361 lit, nameIReg(sz,reg));
362}
363
364static void emit_shiftopv_lit_reg ( Int sz, Opcode opc, UInt lit, Int reg )
365{
366 newEmit();
367 if (sz == 2) emitB ( 0x66 );
368 emitB ( 0xC1 ); /* Grp2 Ib,Ev */
369 emit_amode_ereg_greg ( reg, mkGrp2opcode(opc) );
370 emitB ( lit );
371 if (dis)
372 VG_(printf)( "\n\t\t%s%c\t$%d, %s\n",
373 VG_(nameUOpcode)(False,opc), nameISize(sz),
374 lit, nameIReg(sz,reg));
375}
376
377static void emit_shiftopv_cl_stack0 ( Int sz, Opcode opc )
378{
379 newEmit();
380 if (sz == 2) emitB ( 0x66 );
381 emitB ( 0xD3 ); /* Grp2 CL,Ev */
382 emitB ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
383 emitB ( 0x24 ); /* a SIB, I think `d8(%esp)' */
384 emitB ( 0x00 ); /* the d8 displacement */
385 if (dis)
386 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
387 VG_(nameUOpcode)(False,opc), nameISize(sz) );
388}
389
390static void emit_shiftopb_cl_stack0 ( Opcode opc )
391{
392 newEmit();
393 emitB ( 0xD2 ); /* Grp2 CL,Eb */
394 emitB ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
395 emitB ( 0x24 ); /* a SIB, I think `d8(%esp)' */
396 emitB ( 0x00 ); /* the d8 displacement */
397 if (dis)
398 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
399 VG_(nameUOpcode)(False,opc), nameISize(1) );
400}
401
402static void emit_nonshiftopv_offregmem_reg ( Int sz, Opcode opc,
403 Int off, Int areg, Int reg )
404{
405 newEmit();
406 if (sz == 2) emitB ( 0x66 );
407 emitB ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
408 emit_amode_offregmem_reg ( off, areg, reg );
409 if (dis)
410 VG_(printf)( "\n\t\t%s%c\t0x%x(%s), %s\n",
411 VG_(nameUOpcode)(False,opc), nameISize(sz),
412 off, nameIReg(4,areg), nameIReg(sz,reg));
413}
414
415static void emit_nonshiftopv_reg_reg ( Int sz, Opcode opc,
416 Int reg1, Int reg2 )
417{
418 newEmit();
419 if (sz == 2) emitB ( 0x66 );
420# if 0
421 /* Perfectly correct, but the GNU assembler uses the other form.
422 Therefore we too use the other form, to aid verification. */
423 emitB ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
424 emit_amode_ereg_greg ( reg1, reg2 );
425# else
426 emitB ( 1 + mkPrimaryOpcode(opc) ); /* op Gv, Ev */
427 emit_amode_greg_ereg ( reg1, reg2 );
428# endif
429 if (dis)
430 VG_(printf)( "\n\t\t%s%c\t%s, %s\n",
431 VG_(nameUOpcode)(False,opc), nameISize(sz),
432 nameIReg(sz,reg1), nameIReg(sz,reg2));
433}
434
435static void emit_movv_lit_reg ( Int sz, UInt lit, Int reg )
436{
437 if (lit == 0) {
438 emit_nonshiftopv_reg_reg ( sz, XOR, reg, reg );
439 return;
440 }
441 newEmit();
442 if (sz == 2) emitB ( 0x66 );
443 emitB ( 0xB8+reg ); /* MOV imm, Gv */
444 if (sz == 2) emitW ( lit ); else emitL ( lit );
445 if (dis)
446 VG_(printf)( "\n\t\tmov%c\t$0x%x, %s\n",
447 nameISize(sz), lit, nameIReg(sz,reg));
448}
449
450static void emit_unaryopv_reg ( Int sz, Opcode opc, Int reg )
451{
452 newEmit();
453 if (sz == 2) emitB ( 0x66 );
454 switch (opc) {
455 case NEG:
456 emitB ( 0xF7 );
457 emit_amode_ereg_greg ( reg, mkGrp3opcode(NEG) );
458 if (dis)
459 VG_(printf)( "\n\t\tneg%c\t%s\n",
460 nameISize(sz), nameIReg(sz,reg));
461 break;
462 case NOT:
463 emitB ( 0xF7 );
464 emit_amode_ereg_greg ( reg, mkGrp3opcode(NOT) );
465 if (dis)
466 VG_(printf)( "\n\t\tnot%c\t%s\n",
467 nameISize(sz), nameIReg(sz,reg));
468 break;
469 case DEC:
470 emitB ( 0x48 + reg );
471 if (dis)
472 VG_(printf)( "\n\t\tdec%c\t%s\n",
473 nameISize(sz), nameIReg(sz,reg));
474 break;
475 case INC:
476 emitB ( 0x40 + reg );
477 if (dis)
478 VG_(printf)( "\n\t\tinc%c\t%s\n",
479 nameISize(sz), nameIReg(sz,reg));
480 break;
481 default:
482 VG_(panic)("emit_unaryopv_reg");
483 }
484}
485
486static void emit_pushv_reg ( Int sz, Int reg )
487{
488 newEmit();
489 if (sz == 2) {
490 emitB ( 0x66 );
491 } else {
492 vg_assert(sz == 4);
493 }
494 emitB ( 0x50 + reg );
495 if (dis)
496 VG_(printf)("\n\t\tpush%c %s\n", nameISize(sz), nameIReg(sz,reg));
497}
498
499static void emit_popv_reg ( Int sz, Int reg )
500{
501 newEmit();
502 if (sz == 2) {
503 emitB ( 0x66 );
504 } else {
505 vg_assert(sz == 4);
506 }
507 emitB ( 0x58 + reg );
508 if (dis)
509 VG_(printf)("\n\t\tpop%c %s\n", nameISize(sz), nameIReg(sz,reg));
510}
511
512static void emit_pushl_lit8 ( Int lit8 )
513{
514 vg_assert(lit8 >= -128 && lit8 < 128);
515 newEmit();
516 emitB ( 0x6A );
517 emitB ( (UChar)((UInt)lit8) );
518 if (dis)
519 VG_(printf)("\n\t\tpushl $%d\n", lit8 );
520}
521
522static void emit_pushl_lit32 ( UInt int32 )
523{
524 newEmit();
525 emitB ( 0x68 );
526 emitL ( int32 );
527 if (dis)
528 VG_(printf)("\n\t\tpushl $0x%x\n", int32 );
529}
530
531static void emit_cmpl_zero_reg ( Int reg )
532{
533 newEmit();
534 emitB ( 0x83 );
535 emit_amode_ereg_greg ( reg, 7 /* Grp 3 opcode for CMP */ );
536 emitB ( 0x00 );
537 if (dis)
538 VG_(printf)("\n\t\tcmpl $0, %s\n", nameIReg(4,reg));
539}
540
541static void emit_swapl_reg_ECX ( Int reg )
542{
543 newEmit();
544 emitB ( 0x87 ); /* XCHG Gv,Ev */
545 emit_amode_ereg_greg ( reg, R_ECX );
546 if (dis)
547 VG_(printf)("\n\t\txchgl %%ecx, %s\n", nameIReg(4,reg));
548}
549
550static void emit_swapl_reg_EAX ( Int reg )
551{
552 newEmit();
553 emitB ( 0x90 + reg ); /* XCHG Gv,eAX */
554 if (dis)
555 VG_(printf)("\n\t\txchgl %%eax, %s\n", nameIReg(4,reg));
556}
557
558static void emit_swapl_reg_reg ( Int reg1, Int reg2 )
559{
560 newEmit();
561 emitB ( 0x87 ); /* XCHG Gv,Ev */
562 emit_amode_ereg_greg ( reg1, reg2 );
563 if (dis)
564 VG_(printf)("\n\t\txchgl %s, %s\n", nameIReg(4,reg1),
565 nameIReg(4,reg2));
566}
567
568static void emit_bswapl_reg ( Int reg )
569{
570 newEmit();
571 emitB ( 0x0F );
572 emitB ( 0xC8 + reg ); /* BSWAP r32 */
573 if (dis)
574 VG_(printf)("\n\t\tbswapl %s\n", nameIReg(4,reg));
575}
576
577static void emit_movl_reg_reg ( Int regs, Int regd )
578{
579 newEmit();
580 emitB ( 0x89 ); /* MOV Gv,Ev */
581 emit_amode_ereg_greg ( regd, regs );
582 if (dis)
583 VG_(printf)("\n\t\tmovl %s, %s\n", nameIReg(4,regs), nameIReg(4,regd));
584}
585
586static void emit_testv_lit_reg ( Int sz, UInt lit, Int reg )
587{
588 newEmit();
589 if (sz == 2) {
590 emitB ( 0x66 );
591 } else {
592 vg_assert(sz == 4);
593 }
594 emitB ( 0xF7 ); /* Grp3 Ev */
595 emit_amode_ereg_greg ( reg, 0 /* Grp3 subopcode for TEST */ );
596 if (sz == 2) emitW ( lit ); else emitL ( lit );
597 if (dis)
598 VG_(printf)("\n\t\ttest%c $0x%x, %s\n", nameISize(sz),
599 lit, nameIReg(sz,reg));
600}
601
602static void emit_testv_lit_offregmem ( Int sz, UInt lit, Int off, Int reg )
603{
604 newEmit();
605 if (sz == 2) {
606 emitB ( 0x66 );
607 } else {
608 vg_assert(sz == 4);
609 }
610 emitB ( 0xF7 ); /* Grp3 Ev */
611 emit_amode_offregmem_reg ( off, reg, 0 /* Grp3 subopcode for TEST */ );
612 if (sz == 2) emitW ( lit ); else emitL ( lit );
613 if (dis)
614 VG_(printf)("\n\t\ttest%c $%d, 0x%x(%s)\n",
615 nameISize(sz), lit, off, nameIReg(4,reg) );
616}
617
618static void emit_movv_lit_offregmem ( Int sz, UInt lit, Int off, Int memreg )
619{
620 newEmit();
621 if (sz == 2) {
622 emitB ( 0x66 );
623 } else {
624 vg_assert(sz == 4);
625 }
626 emitB ( 0xC7 ); /* Grp11 Ev */
627 emit_amode_offregmem_reg ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
628 if (sz == 2) emitW ( lit ); else emitL ( lit );
629 if (dis)
630 VG_(printf)( "\n\t\tmov%c\t$0x%x, 0x%x(%s)\n",
631 nameISize(sz), lit, off, nameIReg(4,memreg) );
632}
633
634
635/*----------------------------------------------------*/
636/*--- b-size (1 byte) instruction emitters ---*/
637/*----------------------------------------------------*/
638
639/* There is some doubt as to whether C6 (Grp 11) is in the
640 486 insn set. ToDo: investigate. */
641static void emit_movb_lit_offregmem ( UInt lit, Int off, Int memreg )
642{
643 newEmit();
644 emitB ( 0xC6 ); /* Grp11 Eb */
645 emit_amode_offregmem_reg ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
646 emitB ( lit );
647 if (dis)
648 VG_(printf)( "\n\t\tmovb\t$0x%x, 0x%x(%s)\n",
649 lit, off, nameIReg(4,memreg) );
650}
651
652static void emit_nonshiftopb_offregmem_reg ( Opcode opc,
653 Int off, Int areg, Int reg )
654{
655 newEmit();
656 emitB ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
657 emit_amode_offregmem_reg ( off, areg, reg );
658 if (dis)
659 VG_(printf)( "\n\t\t%sb\t0x%x(%s), %s\n",
660 VG_(nameUOpcode)(False,opc), off, nameIReg(4,areg),
661 nameIReg(1,reg));
662}
663
664static void emit_movb_reg_offregmem ( Int reg, Int off, Int areg )
665{
666 /* Could do better when reg == %al. */
667 newEmit();
668 emitB ( 0x88 ); /* MOV G1, E1 */
669 emit_amode_offregmem_reg ( off, areg, reg );
670 if (dis)
671 VG_(printf)( "\n\t\tmovb\t%s, 0x%x(%s)\n",
672 nameIReg(1,reg), off, nameIReg(4,areg));
673}
674
675static void emit_nonshiftopb_reg_reg ( Opcode opc, Int reg1, Int reg2 )
676{
677 newEmit();
678 emitB ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
679 emit_amode_ereg_greg ( reg1, reg2 );
680 if (dis)
681 VG_(printf)( "\n\t\t%sb\t%s, %s\n",
682 VG_(nameUOpcode)(False,opc),
683 nameIReg(1,reg1), nameIReg(1,reg2));
684}
685
686static void emit_movb_reg_regmem ( Int reg1, Int reg2 )
687{
688 newEmit();
689 emitB ( 0x88 ); /* MOV G1, E1 */
690 emit_amode_regmem_reg ( reg2, reg1 );
691 if (dis)
692 VG_(printf)( "\n\t\tmovb\t%s, (%s)\n", nameIReg(1,reg1),
693 nameIReg(4,reg2));
694}
695
696static void emit_nonshiftopb_lit_reg ( Opcode opc, UInt lit, Int reg )
697{
698 newEmit();
699 emitB ( 0x80 ); /* Grp1 Ib,Eb */
700 emit_amode_ereg_greg ( reg, mkGrp1opcode(opc) );
701 emitB ( lit & 0x000000FF );
702 if (dis)
703 VG_(printf)( "\n\t\t%sb\t$0x%x, %s\n", VG_(nameUOpcode)(False,opc),
704 lit, nameIReg(1,reg));
705}
706
707static void emit_shiftopb_lit_reg ( Opcode opc, UInt lit, Int reg )
708{
709 newEmit();
710 emitB ( 0xC0 ); /* Grp2 Ib,Eb */
711 emit_amode_ereg_greg ( reg, mkGrp2opcode(opc) );
712 emitB ( lit );
713 if (dis)
714 VG_(printf)( "\n\t\t%sb\t$%d, %s\n",
715 VG_(nameUOpcode)(False,opc),
716 lit, nameIReg(1,reg));
717}
718
719static void emit_unaryopb_reg ( Opcode opc, Int reg )
720{
721 newEmit();
722 switch (opc) {
723 case INC:
724 emitB ( 0xFE );
725 emit_amode_ereg_greg ( reg, mkGrp4opcode(INC) );
726 if (dis)
727 VG_(printf)( "\n\t\tincb\t%s\n", nameIReg(1,reg));
728 break;
729 case DEC:
730 emitB ( 0xFE );
731 emit_amode_ereg_greg ( reg, mkGrp4opcode(DEC) );
732 if (dis)
733 VG_(printf)( "\n\t\tdecb\t%s\n", nameIReg(1,reg));
734 break;
735 case NOT:
736 emitB ( 0xF6 );
737 emit_amode_ereg_greg ( reg, mkGrp3opcode(NOT) );
738 if (dis)
739 VG_(printf)( "\n\t\tnotb\t%s\n", nameIReg(1,reg));
740 break;
741 case NEG:
742 emitB ( 0xF6 );
743 emit_amode_ereg_greg ( reg, mkGrp3opcode(NEG) );
744 if (dis)
745 VG_(printf)( "\n\t\tnegb\t%s\n", nameIReg(1,reg));
746 break;
747 default:
748 VG_(panic)("emit_unaryopb_reg");
749 }
750}
751
752static void emit_testb_lit_reg ( UInt lit, Int reg )
753{
754 newEmit();
755 emitB ( 0xF6 ); /* Grp3 Eb */
756 emit_amode_ereg_greg ( reg, 0 /* Grp3 subopcode for TEST */ );
757 emitB ( lit );
758 if (dis)
759 VG_(printf)("\n\t\ttestb $0x%x, %s\n", lit, nameIReg(1,reg));
760}
761
762
763/*----------------------------------------------------*/
764/*--- zero-extended load emitters ---*/
765/*----------------------------------------------------*/
766
767static void emit_movzbl_offregmem_reg ( Int off, Int regmem, Int reg )
768{
769 newEmit();
770 emitB ( 0x0F ); emitB ( 0xB6 ); /* MOVZBL */
771 emit_amode_offregmem_reg ( off, regmem, reg );
772 if (dis)
773 VG_(printf)( "\n\t\tmovzbl\t0x%x(%s), %s\n",
774 off, nameIReg(4,regmem), nameIReg(4,reg));
775}
776
777static void emit_movzbl_regmem_reg ( Int reg1, Int reg2 )
778{
779 newEmit();
780 emitB ( 0x0F ); emitB ( 0xB6 ); /* MOVZBL */
781 emit_amode_regmem_reg ( reg1, reg2 );
782 if (dis)
783 VG_(printf)( "\n\t\tmovzbl\t(%s), %s\n", nameIReg(4,reg1),
784 nameIReg(4,reg2));
785}
786
787static void emit_movzwl_offregmem_reg ( Int off, Int areg, Int reg )
788{
789 newEmit();
790 emitB ( 0x0F ); emitB ( 0xB7 ); /* MOVZWL */
791 emit_amode_offregmem_reg ( off, areg, reg );
792 if (dis)
793 VG_(printf)( "\n\t\tmovzwl\t0x%x(%s), %s\n",
794 off, nameIReg(4,areg), nameIReg(4,reg));
795}
796
797static void emit_movzwl_regmem_reg ( Int reg1, Int reg2 )
798{
799 newEmit();
800 emitB ( 0x0F ); emitB ( 0xB7 ); /* MOVZWL */
801 emit_amode_regmem_reg ( reg1, reg2 );
802 if (dis)
803 VG_(printf)( "\n\t\tmovzwl\t(%s), %s\n", nameIReg(4,reg1),
804 nameIReg(4,reg2));
805}
806
807/*----------------------------------------------------*/
808/*--- FPU instruction emitters ---*/
809/*----------------------------------------------------*/
810
811static void emit_get_fpu_state ( void )
812{
813 Int off = 4 * VGOFF_(m_fpustate);
814 newEmit();
815 emitB ( 0xDD ); emitB ( 0xA5 ); /* frstor d32(%ebp) */
816 emitL ( off );
817 if (dis)
818 VG_(printf)("\n\t\tfrstor\t%d(%%ebp)\n", off );
819}
820
821static void emit_put_fpu_state ( void )
822{
823 Int off = 4 * VGOFF_(m_fpustate);
824 newEmit();
825 emitB ( 0xDD ); emitB ( 0xB5 ); /* fnsave d32(%ebp) */
826 emitL ( off );
827 if (dis)
828 VG_(printf)("\n\t\tfnsave\t%d(%%ebp)\n", off );
829}
830
831static void emit_fpu_no_mem ( UChar first_byte,
832 UChar second_byte )
833{
834 newEmit();
835 emitB ( first_byte );
836 emitB ( second_byte );
837 if (dis)
838 VG_(printf)("\n\t\tfpu-0x%x:0x%x\n",
839 (UInt)first_byte, (UInt)second_byte );
840}
841
842static void emit_fpu_regmem ( UChar first_byte,
843 UChar second_byte_masked,
844 Int reg )
845{
846 newEmit();
847 emitB ( first_byte );
848 emit_amode_regmem_reg ( reg, second_byte_masked >> 3 );
849 if (dis)
850 VG_(printf)("\n\t\tfpu-0x%x:0x%x-(%s)\n",
851 (UInt)first_byte, (UInt)second_byte_masked,
852 nameIReg(4,reg) );
853}
854
855
856/*----------------------------------------------------*/
857/*--- misc instruction emitters ---*/
858/*----------------------------------------------------*/
859
860static void emit_call_reg ( Int reg )
861{
862 newEmit();
863 emitB ( 0xFF ); /* Grp5 */
864 emit_amode_ereg_greg ( reg, mkGrp5opcode(CALLM) );
865 if (dis)
866 VG_(printf)( "\n\t\tcall\t*%s\n", nameIReg(4,reg) );
867}
868
869
870static void emit_call_star_EBP_off ( Int byte_off )
871{
872 newEmit();
873 if (byte_off < -128 || byte_off > 127) {
874 emitB ( 0xFF );
875 emitB ( 0x95 );
876 emitL ( byte_off );
877 } else {
878 emitB ( 0xFF );
879 emitB ( 0x55 );
880 emitB ( byte_off );
881 }
882 if (dis)
883 VG_(printf)( "\n\t\tcall * %d(%%ebp)\n", byte_off );
884}
885
886
887static void emit_addlit8_offregmem ( Int lit8, Int regmem, Int off )
888{
889 vg_assert(lit8 >= -128 && lit8 < 128);
890 newEmit();
891 emitB ( 0x83 ); /* Grp1 Ib,Ev */
892 emit_amode_offregmem_reg ( off, regmem,
893 0 /* Grp1 subopcode for ADD */ );
894 emitB ( lit8 & 0xFF );
895 if (dis)
896 VG_(printf)( "\n\t\taddl $%d, %d(%s)\n", lit8, off,
897 nameIReg(4,regmem));
898}
899
900
901static void emit_add_lit_to_esp ( Int lit )
902{
903 if (lit < -128 || lit > 127) VG_(panic)("emit_add_lit_to_esp");
904 newEmit();
905 emitB ( 0x83 );
906 emitB ( 0xC4 );
907 emitB ( lit & 0xFF );
908 if (dis)
909 VG_(printf)( "\n\t\taddl $%d, %%esp\n", lit );
910}
911
912
913static void emit_movb_AL_zeroESPmem ( void )
914{
915 /* movb %al, 0(%esp) */
916 /* 88442400 movb %al, 0(%esp) */
917 newEmit();
918 emitB ( 0x88 );
919 emitB ( 0x44 );
920 emitB ( 0x24 );
921 emitB ( 0x00 );
922 if (dis)
923 VG_(printf)( "\n\t\tmovb %%al, 0(%%esp)\n" );
924}
925
926static void emit_movb_zeroESPmem_AL ( void )
927{
928 /* movb 0(%esp), %al */
929 /* 8A442400 movb 0(%esp), %al */
930 newEmit();
931 emitB ( 0x8A );
932 emitB ( 0x44 );
933 emitB ( 0x24 );
934 emitB ( 0x00 );
935 if (dis)
936 VG_(printf)( "\n\t\tmovb 0(%%esp), %%al\n" );
937}
938
939
940/* Emit a jump short with an 8-bit signed offset. Note that the
941 offset is that which should be added to %eip once %eip has been
942 advanced over this insn. */
943static void emit_jcondshort_delta ( Condcode cond, Int delta )
944{
945 vg_assert(delta >= -128 && delta <= 127);
946 newEmit();
947 emitB ( 0x70 + (UInt)cond );
948 emitB ( (UChar)delta );
949 if (dis)
950 VG_(printf)( "\n\t\tj%s-8\t%%eip+%d\n",
951 VG_(nameCondcode)(cond), delta );
952}
953
954static void emit_get_eflags ( void )
955{
956 Int off = 4 * VGOFF_(m_eflags);
957 vg_assert(off >= 0 && off < 128);
958 newEmit();
959 emitB ( 0xFF ); /* PUSHL off(%ebp) */
960 emitB ( 0x75 );
961 emitB ( off );
962 emitB ( 0x9D ); /* POPFL */
963 if (dis)
964 VG_(printf)( "\n\t\tpushl %d(%%ebp) ; popfl\n", off );
965}
966
967static void emit_put_eflags ( void )
968{
969 Int off = 4 * VGOFF_(m_eflags);
970 vg_assert(off >= 0 && off < 128);
971 newEmit();
972 emitB ( 0x9C ); /* PUSHFL */
973 emitB ( 0x8F ); /* POPL vg_m_state.m_eflags */
974 emitB ( 0x45 );
975 emitB ( off );
976 if (dis)
977 VG_(printf)( "\n\t\tpushfl ; popl %d(%%ebp)\n", off );
978}
979
980static void emit_setb_reg ( Int reg, Condcode cond )
981{
982 newEmit();
983 emitB ( 0x0F ); emitB ( 0x90 + (UChar)cond );
984 emit_amode_ereg_greg ( reg, 0 );
985 if (dis)
986 VG_(printf)("\n\t\tset%s %s\n",
987 VG_(nameCondcode)(cond), nameIReg(1,reg));
988}
989
990static void emit_ret ( void )
991{
992 newEmit();
993 emitB ( 0xC3 ); /* RET */
994 if (dis)
995 VG_(printf)("\n\t\tret\n");
996}
997
998static void emit_pushal ( void )
999{
1000 newEmit();
1001 emitB ( 0x60 ); /* PUSHAL */
1002 if (dis)
1003 VG_(printf)("\n\t\tpushal\n");
1004}
1005
1006static void emit_popal ( void )
1007{
1008 newEmit();
1009 emitB ( 0x61 ); /* POPAL */
1010 if (dis)
1011 VG_(printf)("\n\t\tpopal\n");
1012}
1013
1014static void emit_lea_litreg_reg ( UInt lit, Int regmem, Int reg )
1015{
1016 newEmit();
1017 emitB ( 0x8D ); /* LEA M,Gv */
1018 emit_amode_offregmem_reg ( (Int)lit, regmem, reg );
1019 if (dis)
1020 VG_(printf)("\n\t\tleal 0x%x(%s), %s\n",
1021 lit, nameIReg(4,regmem), nameIReg(4,reg) );
1022}
1023
1024static void emit_lea_sib_reg ( UInt lit, Int scale,
1025 Int regbase, Int regindex, Int reg )
1026{
1027 newEmit();
1028 emitB ( 0x8D ); /* LEA M,Gv */
1029 emit_amode_sib_reg ( (Int)lit, scale, regbase, regindex, reg );
1030 if (dis)
1031 VG_(printf)("\n\t\tleal 0x%x(%s,%s,%d), %s\n",
1032 lit, nameIReg(4,regbase),
1033 nameIReg(4,regindex), scale,
1034 nameIReg(4,reg) );
1035}
1036
1037static void emit_AMD_prefetch_reg ( Int reg )
1038{
1039 newEmit();
1040 emitB ( 0x0F );
1041 emitB ( 0x0D );
1042 emit_amode_regmem_reg ( reg, 1 /* 0 is prefetch; 1 is prefetchw */ );
1043 if (dis)
1044 VG_(printf)("\n\t\tamd-prefetch (%s)\n", nameIReg(4,reg) );
1045}
1046
1047/*----------------------------------------------------*/
1048/*--- Instruction synthesisers ---*/
1049/*----------------------------------------------------*/
1050
1051static Condcode invertCondition ( Condcode cond )
1052{
1053 return (Condcode)(1 ^ (UInt)cond);
1054}
1055
1056
1057/* Synthesise a call to *baseBlock[offset], ie,
1058 call * (4 x offset)(%ebp).
1059*/
1060static void synth_call_baseBlock_method ( Bool ensure_shortform,
1061 Int word_offset )
1062{
1063 vg_assert(word_offset >= 0);
1064 vg_assert(word_offset < VG_BASEBLOCK_WORDS);
1065 if (ensure_shortform)
1066 vg_assert(word_offset < 32);
1067 emit_call_star_EBP_off ( 4 * word_offset );
1068}
1069
njn6431be72002-07-28 09:53:34 +00001070static void synth_ccall_saveRegs ( void )
1071{
1072 emit_pushv_reg ( 4, R_EAX );
1073 emit_pushv_reg ( 4, R_ECX );
1074 emit_pushv_reg ( 4, R_EDX );
1075}
1076
1077static void synth_ccall_pushOneArg ( Int r1 )
1078{
1079 emit_pushv_reg ( 4, r1 );
1080}
1081
1082static void synth_ccall_pushTwoArgs ( Int r1, Int r2 )
1083{
1084 /* must push in reverse order */
1085 emit_pushv_reg ( 4, r2 );
1086 emit_pushv_reg ( 4, r1 );
1087}
1088
1089/* Synthesise a call to *baseBlock[offset], ie,
1090 call * (4 x offset)(%ebp) with arguments
1091*/
1092static void synth_ccall_call_clearStack_restoreRegs ( Int word_offset,
1093 UInt n_args_bytes )
1094{
1095 vg_assert(word_offset >= 0);
1096 vg_assert(word_offset < VG_BASEBLOCK_WORDS);
1097 vg_assert(n_args_bytes <= 12); /* Max 3 word-sized args */
1098 vg_assert(0 == (n_args_bytes & 0x3)); /* Divisible by four */
1099
1100 emit_call_star_EBP_off ( 4 * word_offset );
1101 if ( 0 != n_args_bytes )
1102 emit_add_lit_to_esp ( n_args_bytes );
1103 emit_popv_reg ( 4, R_EDX );
1104 emit_popv_reg ( 4, R_ECX );
1105 emit_popv_reg ( 4, R_EAX );
1106}
sewardjde4a1d02002-03-22 01:27:54 +00001107
sewardj2e93c502002-04-12 11:12:52 +00001108static void load_ebp_from_JmpKind ( JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00001109{
sewardj2e93c502002-04-12 11:12:52 +00001110 switch (jmpkind) {
1111 case JmpBoring:
1112 break;
1113 case JmpCall:
1114 case JmpRet:
sewardj54cacf02002-04-12 23:24:59 +00001115 emit_movv_lit_reg ( 4, VG_TRC_EBP_JMP_STKADJ, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00001116 break;
1117 case JmpSyscall:
1118 emit_movv_lit_reg ( 4, VG_TRC_EBP_JMP_SYSCALL, R_EBP );
1119 break;
1120 case JmpClientReq:
1121 emit_movv_lit_reg ( 4, VG_TRC_EBP_JMP_CLIENTREQ, R_EBP );
1122 break;
1123 default:
1124 VG_(panic)("load_ebp_from_JmpKind");
1125 }
1126}
1127
1128/* Jump to the next translation, by loading its original addr into
1129 %eax and returning to the scheduler. Signal special requirements
1130 by loading a special value into %ebp first.
1131*/
1132static void synth_jmp_reg ( Int reg, JmpKind jmpkind )
1133{
1134 load_ebp_from_JmpKind ( jmpkind );
sewardjde4a1d02002-03-22 01:27:54 +00001135 if (reg != R_EAX)
1136 emit_movv_reg_reg ( 4, reg, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00001137 emit_ret();
1138}
1139
1140
1141/* Same deal as synth_jmp_reg. */
sewardj2e93c502002-04-12 11:12:52 +00001142static void synth_jmp_lit ( Addr addr, JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00001143{
sewardj2e93c502002-04-12 11:12:52 +00001144 load_ebp_from_JmpKind ( jmpkind );
sewardjde4a1d02002-03-22 01:27:54 +00001145 emit_movv_lit_reg ( 4, addr, R_EAX );
1146 emit_ret();
1147}
1148
1149
sewardjde4a1d02002-03-22 01:27:54 +00001150static void synth_jcond_lit ( Condcode cond, Addr addr )
1151{
1152 /* Do the following:
1153 get eflags
1154 jmp short if not cond to xyxyxy
1155 addr -> eax
1156 ret
1157 xyxyxy
1158
1159 2 0000 750C jnz xyxyxy
1160 3 0002 B877665544 movl $0x44556677, %eax
1161 4 0007 C3 ret
1162 5 0008 FFE3 jmp *%ebx
1163 6 xyxyxy:
1164 */
1165 emit_get_eflags();
1166 emit_jcondshort_delta ( invertCondition(cond), 5+1 );
sewardj2e93c502002-04-12 11:12:52 +00001167 synth_jmp_lit ( addr, JmpBoring );
sewardjde4a1d02002-03-22 01:27:54 +00001168}
1169
1170
1171static void synth_jmp_ifzero_reg_lit ( Int reg, Addr addr )
1172{
1173 /* 0000 83FF00 cmpl $0, %edi
1174 0003 750A jnz next
1175 0005 B844332211 movl $0x11223344, %eax
1176 000a C3 ret
1177 next:
1178 */
1179 emit_cmpl_zero_reg ( reg );
1180 emit_jcondshort_delta ( CondNZ, 5+1 );
sewardj2e93c502002-04-12 11:12:52 +00001181 synth_jmp_lit ( addr, JmpBoring );
sewardjde4a1d02002-03-22 01:27:54 +00001182}
1183
1184
1185static void synth_mov_lit_reg ( Int size, UInt lit, Int reg )
1186{
1187 /* Load the zero-extended literal into reg, at size l,
1188 regardless of the request size. */
1189 emit_movv_lit_reg ( 4, lit, reg );
1190}
1191
1192
1193static void synth_mov_regmem_reg ( Int size, Int reg1, Int reg2 )
1194{
1195 switch (size) {
1196 case 4: emit_movv_regmem_reg ( 4, reg1, reg2 ); break;
1197 case 2: emit_movzwl_regmem_reg ( reg1, reg2 ); break;
1198 case 1: emit_movzbl_regmem_reg ( reg1, reg2 ); break;
1199 default: VG_(panic)("synth_mov_regmem_reg");
1200 }
1201}
1202
1203
1204static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg )
1205{
1206 switch (size) {
1207 case 4: emit_movv_offregmem_reg ( 4, off, areg, reg ); break;
1208 case 2: emit_movzwl_offregmem_reg ( off, areg, reg ); break;
1209 case 1: emit_movzbl_offregmem_reg ( off, areg, reg ); break;
1210 default: VG_(panic)("synth_mov_offregmem_reg");
1211 }
1212}
1213
1214
1215static void synth_mov_reg_offregmem ( Int size, Int reg,
1216 Int off, Int areg )
1217{
1218 switch (size) {
1219 case 4: emit_movv_reg_offregmem ( 4, reg, off, areg ); break;
1220 case 2: emit_movv_reg_offregmem ( 2, reg, off, areg ); break;
1221 case 1: if (reg < 4) {
1222 emit_movb_reg_offregmem ( reg, off, areg );
1223 }
1224 else {
1225 emit_swapl_reg_EAX ( reg );
1226 emit_movb_reg_offregmem ( R_AL, off, areg );
1227 emit_swapl_reg_EAX ( reg );
1228 }
1229 break;
1230 default: VG_(panic)("synth_mov_reg_offregmem");
1231 }
1232}
1233
1234
1235static void synth_mov_reg_memreg ( Int size, Int reg1, Int reg2 )
1236{
1237 Int s1;
1238 switch (size) {
1239 case 4: emit_movv_reg_regmem ( 4, reg1, reg2 ); break;
1240 case 2: emit_movv_reg_regmem ( 2, reg1, reg2 ); break;
1241 case 1: if (reg1 < 4) {
1242 emit_movb_reg_regmem ( reg1, reg2 );
1243 }
1244 else {
1245 /* Choose a swap reg which is < 4 and not reg1 or reg2. */
1246 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
1247 emit_swapl_reg_reg ( s1, reg1 );
1248 emit_movb_reg_regmem ( s1, reg2 );
1249 emit_swapl_reg_reg ( s1, reg1 );
1250 }
1251 break;
1252 default: VG_(panic)("synth_mov_reg_litmem");
1253 }
1254}
1255
1256
njn5a74eb82002-08-06 20:56:40 +00001257static void synth_unaryop_reg ( Bool wr_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001258 Opcode opcode, Int size,
1259 Int reg )
1260{
1261 /* NB! opcode is a uinstr opcode, not an x86 one! */
1262 switch (size) {
njn5a74eb82002-08-06 20:56:40 +00001263 case 4: //if (rd_cc) emit_get_eflags(); (never needed --njn)
sewardjde4a1d02002-03-22 01:27:54 +00001264 emit_unaryopv_reg ( 4, opcode, reg );
njn5a74eb82002-08-06 20:56:40 +00001265 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001266 break;
njn5a74eb82002-08-06 20:56:40 +00001267 case 2: //if (rd_cc) emit_get_eflags(); (never needed --njn)
sewardjde4a1d02002-03-22 01:27:54 +00001268 emit_unaryopv_reg ( 2, opcode, reg );
njn5a74eb82002-08-06 20:56:40 +00001269 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001270 break;
1271 case 1: if (reg < 4) {
njn5a74eb82002-08-06 20:56:40 +00001272 //if (rd_cc) emit_get_eflags(); (never needed --njn)
sewardjde4a1d02002-03-22 01:27:54 +00001273 emit_unaryopb_reg ( opcode, reg );
njn5a74eb82002-08-06 20:56:40 +00001274 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001275 } else {
1276 emit_swapl_reg_EAX ( reg );
njn5a74eb82002-08-06 20:56:40 +00001277 //if (rd_cc) emit_get_eflags(); (never needed --njn)
sewardjde4a1d02002-03-22 01:27:54 +00001278 emit_unaryopb_reg ( opcode, R_AL );
njn5a74eb82002-08-06 20:56:40 +00001279 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001280 emit_swapl_reg_EAX ( reg );
1281 }
1282 break;
1283 default: VG_(panic)("synth_unaryop_reg");
1284 }
1285}
1286
1287
1288
njn5a74eb82002-08-06 20:56:40 +00001289static void synth_nonshiftop_reg_reg ( Bool rd_cc, Bool wr_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001290 Opcode opcode, Int size,
1291 Int reg1, Int reg2 )
1292{
1293 /* NB! opcode is a uinstr opcode, not an x86 one! */
1294 switch (size) {
njn5a74eb82002-08-06 20:56:40 +00001295 case 4: if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001296 emit_nonshiftopv_reg_reg ( 4, opcode, reg1, reg2 );
njn5a74eb82002-08-06 20:56:40 +00001297 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001298 break;
njn5a74eb82002-08-06 20:56:40 +00001299 case 2: if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001300 emit_nonshiftopv_reg_reg ( 2, opcode, reg1, reg2 );
njn5a74eb82002-08-06 20:56:40 +00001301 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001302 break;
1303 case 1: { /* Horrible ... */
1304 Int s1, s2;
1305 /* Choose s1 and s2 to be x86 regs which we can talk about the
1306 lowest 8 bits, ie either %eax, %ebx, %ecx or %edx. Make
1307 sure s1 != s2 and that neither of them equal either reg1 or
1308 reg2. Then use them as temporaries to make things work. */
1309 if (reg1 < 4 && reg2 < 4) {
njn5a74eb82002-08-06 20:56:40 +00001310 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001311 emit_nonshiftopb_reg_reg(opcode, reg1, reg2);
njn5a74eb82002-08-06 20:56:40 +00001312 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001313 break;
1314 }
1315 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
1316 if (reg1 >= 4 && reg2 < 4) {
1317 emit_swapl_reg_reg ( reg1, s1 );
njn5a74eb82002-08-06 20:56:40 +00001318 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001319 emit_nonshiftopb_reg_reg(opcode, s1, reg2);
njn5a74eb82002-08-06 20:56:40 +00001320 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001321 emit_swapl_reg_reg ( reg1, s1 );
1322 break;
1323 }
1324 for (s2 = 0; s2 == reg1 || s2 == reg2 || s2 == s1; s2++) ;
1325 if (reg1 < 4 && reg2 >= 4) {
1326 emit_swapl_reg_reg ( reg2, s2 );
njn5a74eb82002-08-06 20:56:40 +00001327 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001328 emit_nonshiftopb_reg_reg(opcode, reg1, s2);
njn5a74eb82002-08-06 20:56:40 +00001329 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001330 emit_swapl_reg_reg ( reg2, s2 );
1331 break;
1332 }
1333 if (reg1 >= 4 && reg2 >= 4 && reg1 != reg2) {
1334 emit_swapl_reg_reg ( reg1, s1 );
1335 emit_swapl_reg_reg ( reg2, s2 );
njn5a74eb82002-08-06 20:56:40 +00001336 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001337 emit_nonshiftopb_reg_reg(opcode, s1, s2);
njn5a74eb82002-08-06 20:56:40 +00001338 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001339 emit_swapl_reg_reg ( reg1, s1 );
1340 emit_swapl_reg_reg ( reg2, s2 );
1341 break;
1342 }
1343 if (reg1 >= 4 && reg2 >= 4 && reg1 == reg2) {
1344 emit_swapl_reg_reg ( reg1, s1 );
njn5a74eb82002-08-06 20:56:40 +00001345 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001346 emit_nonshiftopb_reg_reg(opcode, s1, s1);
njn5a74eb82002-08-06 20:56:40 +00001347 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001348 emit_swapl_reg_reg ( reg1, s1 );
1349 break;
1350 }
1351 VG_(panic)("synth_nonshiftopb_reg_reg");
1352 }
1353 default: VG_(panic)("synth_nonshiftop_reg_reg");
1354 }
1355}
1356
1357
1358static void synth_nonshiftop_offregmem_reg (
njn5a74eb82002-08-06 20:56:40 +00001359 Bool rd_cc, Bool wr_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001360 Opcode opcode, Int size,
1361 Int off, Int areg, Int reg )
1362{
1363 switch (size) {
1364 case 4:
njn5a74eb82002-08-06 20:56:40 +00001365 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001366 emit_nonshiftopv_offregmem_reg ( 4, opcode, off, areg, reg );
njn5a74eb82002-08-06 20:56:40 +00001367 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001368 break;
1369 case 2:
njn5a74eb82002-08-06 20:56:40 +00001370 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001371 emit_nonshiftopv_offregmem_reg ( 2, opcode, off, areg, reg );
njn5a74eb82002-08-06 20:56:40 +00001372 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001373 break;
1374 case 1:
1375 if (reg < 4) {
njn5a74eb82002-08-06 20:56:40 +00001376 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001377 emit_nonshiftopb_offregmem_reg ( opcode, off, areg, reg );
njn5a74eb82002-08-06 20:56:40 +00001378 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001379 } else {
1380 emit_swapl_reg_EAX ( reg );
njn5a74eb82002-08-06 20:56:40 +00001381 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001382 emit_nonshiftopb_offregmem_reg ( opcode, off, areg, R_AL );
njn5a74eb82002-08-06 20:56:40 +00001383 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001384 emit_swapl_reg_EAX ( reg );
1385 }
1386 break;
1387 default:
njn5a74eb82002-08-06 20:56:40 +00001388 VG_(panic)("synth_nonshiftop_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001389 }
1390}
1391
1392
njn5a74eb82002-08-06 20:56:40 +00001393static void synth_nonshiftop_lit_reg ( Bool rd_cc, Bool wr_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001394 Opcode opcode, Int size,
1395 UInt lit, Int reg )
1396{
1397 switch (size) {
njn5a74eb82002-08-06 20:56:40 +00001398 case 4: if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001399 emit_nonshiftopv_lit_reg ( 4, opcode, lit, reg );
njn5a74eb82002-08-06 20:56:40 +00001400 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001401 break;
njn5a74eb82002-08-06 20:56:40 +00001402 case 2: if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001403 emit_nonshiftopv_lit_reg ( 2, opcode, lit, reg );
njn5a74eb82002-08-06 20:56:40 +00001404 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001405 break;
1406 case 1: if (reg < 4) {
njn5a74eb82002-08-06 20:56:40 +00001407 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001408 emit_nonshiftopb_lit_reg ( opcode, lit, reg );
njn5a74eb82002-08-06 20:56:40 +00001409 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001410 } else {
1411 emit_swapl_reg_EAX ( reg );
njn5a74eb82002-08-06 20:56:40 +00001412 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001413 emit_nonshiftopb_lit_reg ( opcode, lit, R_AL );
njn5a74eb82002-08-06 20:56:40 +00001414 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001415 emit_swapl_reg_EAX ( reg );
1416 }
1417 break;
1418 default: VG_(panic)("synth_nonshiftop_lit_reg");
1419 }
1420}
1421
1422
1423static void synth_push_reg ( Int size, Int reg )
1424{
1425 switch (size) {
1426 case 4:
1427 emit_pushv_reg ( 4, reg );
1428 break;
1429 case 2:
1430 emit_pushv_reg ( 2, reg );
1431 break;
1432 /* Pray that we don't have to generate this really cruddy bit of
1433 code very often. Could do better, but can I be bothered? */
1434 case 1:
1435 vg_assert(reg != R_ESP); /* duh */
1436 emit_add_lit_to_esp(-1);
1437 if (reg != R_EAX) emit_swapl_reg_EAX ( reg );
1438 emit_movb_AL_zeroESPmem();
1439 if (reg != R_EAX) emit_swapl_reg_EAX ( reg );
1440 break;
1441 default:
1442 VG_(panic)("synth_push_reg");
1443 }
1444}
1445
1446
1447static void synth_pop_reg ( Int size, Int reg )
1448{
1449 switch (size) {
1450 case 4:
1451 emit_popv_reg ( 4, reg );
1452 break;
1453 case 2:
1454 emit_popv_reg ( 2, reg );
1455 break;
1456 case 1:
1457 /* Same comment as above applies. */
1458 vg_assert(reg != R_ESP); /* duh */
1459 if (reg != R_EAX) emit_swapl_reg_EAX ( reg );
1460 emit_movb_zeroESPmem_AL();
1461 if (reg != R_EAX) emit_swapl_reg_EAX ( reg );
1462 emit_add_lit_to_esp(1);
1463 break;
1464 default: VG_(panic)("synth_pop_reg");
1465 }
1466}
1467
1468
njn5a74eb82002-08-06 20:56:40 +00001469static void synth_shiftop_reg_reg ( Bool rd_cc, Bool wr_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001470 Opcode opcode, Int size,
1471 Int regs, Int regd )
1472{
1473 synth_push_reg ( size, regd );
1474 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
njn5a74eb82002-08-06 20:56:40 +00001475 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001476 switch (size) {
1477 case 4: emit_shiftopv_cl_stack0 ( 4, opcode ); break;
1478 case 2: emit_shiftopv_cl_stack0 ( 2, opcode ); break;
1479 case 1: emit_shiftopb_cl_stack0 ( opcode ); break;
1480 default: VG_(panic)("synth_shiftop_reg_reg");
1481 }
njn5a74eb82002-08-06 20:56:40 +00001482 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001483 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
1484 synth_pop_reg ( size, regd );
1485}
1486
1487
njn5a74eb82002-08-06 20:56:40 +00001488static void synth_shiftop_lit_reg ( Bool rd_cc, Bool wr_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001489 Opcode opcode, Int size,
1490 UInt lit, Int reg )
1491{
1492 switch (size) {
njn5a74eb82002-08-06 20:56:40 +00001493 case 4: if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001494 emit_shiftopv_lit_reg ( 4, opcode, lit, reg );
njn5a74eb82002-08-06 20:56:40 +00001495 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001496 break;
njn5a74eb82002-08-06 20:56:40 +00001497 case 2: if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001498 emit_shiftopv_lit_reg ( 2, opcode, lit, reg );
njn5a74eb82002-08-06 20:56:40 +00001499 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001500 break;
1501 case 1: if (reg < 4) {
njn5a74eb82002-08-06 20:56:40 +00001502 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001503 emit_shiftopb_lit_reg ( opcode, lit, reg );
njn5a74eb82002-08-06 20:56:40 +00001504 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001505 } else {
1506 emit_swapl_reg_EAX ( reg );
njn5a74eb82002-08-06 20:56:40 +00001507 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001508 emit_shiftopb_lit_reg ( opcode, lit, R_AL );
njn5a74eb82002-08-06 20:56:40 +00001509 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001510 emit_swapl_reg_EAX ( reg );
1511 }
1512 break;
njn5a74eb82002-08-06 20:56:40 +00001513 default: VG_(panic)("synth_shiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001514 }
1515}
1516
1517
1518static void synth_setb_reg ( Int reg, Condcode cond )
1519{
1520 emit_get_eflags();
1521 if (reg < 4) {
1522 emit_setb_reg ( reg, cond );
1523 } else {
1524 emit_swapl_reg_EAX ( reg );
1525 emit_setb_reg ( R_AL, cond );
1526 emit_swapl_reg_EAX ( reg );
1527 }
1528}
1529
1530
1531static void synth_fpu_regmem ( UChar first_byte,
1532 UChar second_byte_masked,
1533 Int reg )
1534{
1535 emit_get_fpu_state();
1536 emit_fpu_regmem ( first_byte, second_byte_masked, reg );
1537 emit_put_fpu_state();
1538}
1539
1540
1541static void synth_fpu_no_mem ( UChar first_byte,
1542 UChar second_byte )
1543{
1544 emit_get_fpu_state();
1545 emit_fpu_no_mem ( first_byte, second_byte );
1546 emit_put_fpu_state();
1547}
1548
1549
1550static void synth_movl_reg_reg ( Int src, Int dst )
1551{
1552 emit_movl_reg_reg ( src, dst );
1553}
1554
1555static void synth_cmovl_reg_reg ( Condcode cond, Int src, Int dst )
1556{
1557 emit_get_eflags();
1558 emit_jcondshort_delta ( invertCondition(cond),
1559 2 /* length of the next insn */ );
1560 emit_movl_reg_reg ( src, dst );
1561}
1562
1563
sewardjde4a1d02002-03-22 01:27:54 +00001564/* Synthesise a minimal test (and which discards result) of reg32
1565 against lit. It's always safe do simply
1566 emit_testv_lit_reg ( 4, lit, reg32 )
1567 but we try to do better when possible.
1568*/
1569static void synth_minimal_test_lit_reg ( UInt lit, Int reg32 )
1570{
1571 if ((lit & 0xFFFFFF00) == 0 && reg32 < 4) {
1572 /* We can get away with a byte insn. */
1573 emit_testb_lit_reg ( lit, reg32 );
1574 }
1575 else
1576 if ((lit & 0xFFFF0000) == 0) {
1577 /* Literal fits in 16 bits; do a word insn. */
1578 emit_testv_lit_reg ( 2, lit, reg32 );
1579 }
1580 else {
1581 /* Totally general ... */
1582 emit_testv_lit_reg ( 4, lit, reg32 );
1583 }
1584}
1585
1586
1587/*----------------------------------------------------*/
1588/*--- Top level of the uinstr -> x86 translation. ---*/
1589/*----------------------------------------------------*/
1590
1591/* Return the byte offset from %ebp (ie, into baseBlock)
1592 for the specified ArchReg or SpillNo. */
1593
1594static Int spillOrArchOffset ( Int size, Tag tag, UInt value )
1595{
1596 if (tag == SpillNo) {
1597 vg_assert(size == 4);
1598 vg_assert(value >= 0 && value < VG_MAX_SPILLSLOTS);
1599 return 4 * (value + VGOFF_(spillslots));
1600 }
1601 if (tag == ArchReg) {
1602 switch (value) {
1603 case R_EAX: return 4 * VGOFF_(m_eax);
1604 case R_ECX: return 4 * VGOFF_(m_ecx);
1605 case R_EDX: return 4 * VGOFF_(m_edx);
1606 case R_EBX: return 4 * VGOFF_(m_ebx);
1607 case R_ESP:
1608 if (size == 1) return 4 * VGOFF_(m_eax) + 1;
1609 else return 4 * VGOFF_(m_esp);
1610 case R_EBP:
1611 if (size == 1) return 4 * VGOFF_(m_ecx) + 1;
1612 else return 4 * VGOFF_(m_ebp);
1613 case R_ESI:
1614 if (size == 1) return 4 * VGOFF_(m_edx) + 1;
1615 else return 4 * VGOFF_(m_esi);
1616 case R_EDI:
1617 if (size == 1) return 4 * VGOFF_(m_ebx) + 1;
1618 else return 4 * VGOFF_(m_edi);
1619 }
1620 }
1621 VG_(panic)("spillOrArchOffset");
1622}
1623
1624
1625static Int eflagsOffset ( void )
1626{
1627 return 4 * VGOFF_(m_eflags);
1628}
1629
1630
1631static Int shadowOffset ( Int arch )
1632{
1633 switch (arch) {
1634 case R_EAX: return 4 * VGOFF_(sh_eax);
1635 case R_ECX: return 4 * VGOFF_(sh_ecx);
1636 case R_EDX: return 4 * VGOFF_(sh_edx);
1637 case R_EBX: return 4 * VGOFF_(sh_ebx);
1638 case R_ESP: return 4 * VGOFF_(sh_esp);
1639 case R_EBP: return 4 * VGOFF_(sh_ebp);
1640 case R_ESI: return 4 * VGOFF_(sh_esi);
1641 case R_EDI: return 4 * VGOFF_(sh_edi);
1642 default: VG_(panic)( "shadowOffset");
1643 }
1644}
1645
1646
1647static Int shadowFlagsOffset ( void )
1648{
1649 return 4 * VGOFF_(sh_eflags);
1650}
1651
1652
1653static void synth_LOADV ( Int sz, Int a_reg, Int tv_reg )
1654{
1655 Int i, j, helper_offw;
1656 Int pushed[VG_MAX_REALREGS+2];
1657 Int n_pushed;
1658 switch (sz) {
1659 case 4: helper_offw = VGOFF_(helperc_LOADV4); break;
1660 case 2: helper_offw = VGOFF_(helperc_LOADV2); break;
1661 case 1: helper_offw = VGOFF_(helperc_LOADV1); break;
1662 default: VG_(panic)("synth_LOADV");
1663 }
1664 n_pushed = 0;
1665 for (i = 0; i < VG_MAX_REALREGS; i++) {
1666 j = VG_(rankToRealRegNo) ( i );
1667 if (VG_CALLEE_SAVED(j)) continue;
1668 if (j == tv_reg || j == a_reg) continue;
1669 emit_pushv_reg ( 4, j );
1670 pushed[n_pushed++] = j;
1671 }
1672 emit_pushv_reg ( 4, a_reg );
1673 pushed[n_pushed++] = a_reg;
1674 vg_assert(n_pushed <= VG_MAX_REALREGS+1);
1675
1676 synth_call_baseBlock_method ( False, helper_offw );
1677 /* Result is in %eax; we need to get it to tv_reg. */
1678 if (tv_reg != R_EAX)
1679 emit_movv_reg_reg ( 4, R_EAX, tv_reg );
1680
1681 while (n_pushed > 0) {
1682 n_pushed--;
1683 if (pushed[n_pushed] == tv_reg) {
1684 emit_add_lit_to_esp ( 4 );
1685 } else {
1686 emit_popv_reg ( 4, pushed[n_pushed] );
1687 }
1688 }
1689}
1690
1691
1692static void synth_STOREV ( Int sz,
1693 Int tv_tag, Int tv_val,
1694 Int a_reg )
1695{
1696 Int i, j, helper_offw;
1697 vg_assert(tv_tag == RealReg || tv_tag == Literal);
1698 switch (sz) {
1699 case 4: helper_offw = VGOFF_(helperc_STOREV4); break;
1700 case 2: helper_offw = VGOFF_(helperc_STOREV2); break;
1701 case 1: helper_offw = VGOFF_(helperc_STOREV1); break;
1702 default: VG_(panic)("synth_STOREV");
1703 }
1704 for (i = 0; i < VG_MAX_REALREGS; i++) {
1705 j = VG_(rankToRealRegNo) ( i );
1706 if (VG_CALLEE_SAVED(j)) continue;
1707 if ((tv_tag == RealReg && j == tv_val) || j == a_reg) continue;
1708 emit_pushv_reg ( 4, j );
1709 }
1710 if (tv_tag == RealReg) {
1711 emit_pushv_reg ( 4, tv_val );
1712 } else {
1713 if (tv_val == VG_(extend_s_8to32)(tv_val))
1714 emit_pushl_lit8 ( VG_(extend_s_8to32)(tv_val) );
1715 else
1716 emit_pushl_lit32(tv_val);
1717 }
1718 emit_pushv_reg ( 4, a_reg );
1719 synth_call_baseBlock_method ( False, helper_offw );
1720 emit_popv_reg ( 4, a_reg );
1721 if (tv_tag == RealReg) {
1722 emit_popv_reg ( 4, tv_val );
1723 } else {
1724 emit_add_lit_to_esp ( 4 );
1725 }
1726 for (i = VG_MAX_REALREGS-1; i >= 0; i--) {
1727 j = VG_(rankToRealRegNo) ( i );
1728 if (VG_CALLEE_SAVED(j)) continue;
1729 if ((tv_tag == RealReg && j == tv_val) || j == a_reg) continue;
1730 emit_popv_reg ( 4, j );
1731 }
1732}
1733
1734
1735static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
1736{
1737 if (sz_src == 1 && sz_dst == 4) {
1738 emit_shiftopv_lit_reg ( 4, SHL, 24, reg );
1739 emit_shiftopv_lit_reg ( 4, SAR, 24, reg );
1740 }
1741 else if (sz_src == 2 && sz_dst == 4) {
1742 emit_shiftopv_lit_reg ( 4, SHL, 16, reg );
1743 emit_shiftopv_lit_reg ( 4, SAR, 16, reg );
1744 }
1745 else if (sz_src == 1 && sz_dst == 2) {
1746 emit_shiftopv_lit_reg ( 2, SHL, 8, reg );
1747 emit_shiftopv_lit_reg ( 2, SAR, 8, reg );
1748 }
1749 else
1750 VG_(panic)("synth_WIDEN");
1751}
1752
1753
1754static void synth_SETV ( Int sz, Int reg )
1755{
1756 UInt val;
1757 switch (sz) {
1758 case 4: val = 0x00000000; break;
1759 case 2: val = 0xFFFF0000; break;
1760 case 1: val = 0xFFFFFF00; break;
1761 case 0: val = 0xFFFFFFFE; break;
1762 default: VG_(panic)("synth_SETV");
1763 }
1764 emit_movv_lit_reg ( 4, val, reg );
1765}
1766
1767
1768static void synth_TESTV ( Int sz, Int tag, Int val )
1769{
1770 vg_assert(tag == ArchReg || tag == RealReg);
1771 if (tag == ArchReg) {
1772 switch (sz) {
1773 case 4:
1774 emit_testv_lit_offregmem (
1775 4, 0xFFFFFFFF, shadowOffset(val), R_EBP );
1776 break;
1777 case 2:
1778 emit_testv_lit_offregmem (
1779 4, 0x0000FFFF, shadowOffset(val), R_EBP );
1780 break;
1781 case 1:
1782 if (val < 4) {
1783 emit_testv_lit_offregmem (
1784 4, 0x000000FF, shadowOffset(val), R_EBP );
1785 } else {
1786 emit_testv_lit_offregmem (
1787 4, 0x0000FF00, shadowOffset(val-4), R_EBP );
1788 }
1789 break;
1790 case 0:
1791 /* should never happen */
1792 default:
1793 VG_(panic)("synth_TESTV(ArchReg)");
1794 }
1795 } else {
1796 switch (sz) {
1797 case 4:
1798 /* Works, but holds the entire 32-bit literal, hence
1799 generating a 6-byte insn. We want to know if any bits
1800 in the reg are set, but since this is for the full reg,
1801 we might as well compare it against zero, which can be
1802 done with a shorter insn. */
1803 /* synth_minimal_test_lit_reg ( 0xFFFFFFFF, val ); */
1804 emit_cmpl_zero_reg ( val );
1805 break;
1806 case 2:
1807 synth_minimal_test_lit_reg ( 0x0000FFFF, val );
1808 break;
1809 case 1:
1810 synth_minimal_test_lit_reg ( 0x000000FF, val );
1811 break;
1812 case 0:
1813 synth_minimal_test_lit_reg ( 0x00000001, val );
1814 break;
1815 default:
1816 VG_(panic)("synth_TESTV(RealReg)");
1817 }
1818 }
1819 emit_jcondshort_delta ( CondZ, 3 );
1820 synth_call_baseBlock_method (
1821 True, /* needed to guarantee that this insn is indeed 3 bytes long */
1822 (sz==4 ? VGOFF_(helper_value_check4_fail)
1823 : (sz==2 ? VGOFF_(helper_value_check2_fail)
1824 : sz == 1 ? VGOFF_(helper_value_check1_fail)
1825 : VGOFF_(helper_value_check0_fail)))
1826 );
1827}
1828
1829
1830static void synth_GETV ( Int sz, Int arch, Int reg )
1831{
1832 /* VG_(printf)("synth_GETV %d of Arch %s\n", sz, nameIReg(sz, arch)); */
1833 switch (sz) {
1834 case 4:
1835 emit_movv_offregmem_reg ( 4, shadowOffset(arch), R_EBP, reg );
1836 break;
1837 case 2:
1838 emit_movzwl_offregmem_reg ( shadowOffset(arch), R_EBP, reg );
1839 emit_nonshiftopv_lit_reg ( 4, OR, 0xFFFF0000, reg );
1840 break;
1841 case 1:
1842 if (arch < 4) {
1843 emit_movzbl_offregmem_reg ( shadowOffset(arch), R_EBP, reg );
1844 } else {
1845 emit_movzbl_offregmem_reg ( shadowOffset(arch-4)+1, R_EBP, reg );
1846 }
1847 emit_nonshiftopv_lit_reg ( 4, OR, 0xFFFFFF00, reg );
1848 break;
1849 default:
1850 VG_(panic)("synth_GETV");
1851 }
1852}
1853
1854
1855static void synth_PUTV ( Int sz, Int srcTag, UInt lit_or_reg, Int arch )
1856{
1857 if (srcTag == Literal) {
1858 /* PUTV with a Literal is only ever used to set the corresponding
1859 ArchReg to `all valid'. Should really be a kind of SETV. */
1860 UInt lit = lit_or_reg;
1861 switch (sz) {
1862 case 4:
1863 vg_assert(lit == 0x00000000);
1864 emit_movv_lit_offregmem ( 4, 0x00000000,
1865 shadowOffset(arch), R_EBP );
1866 break;
1867 case 2:
1868 vg_assert(lit == 0xFFFF0000);
1869 emit_movv_lit_offregmem ( 2, 0x0000,
1870 shadowOffset(arch), R_EBP );
1871 break;
1872 case 1:
1873 vg_assert(lit == 0xFFFFFF00);
1874 if (arch < 4) {
1875 emit_movb_lit_offregmem ( 0x00,
1876 shadowOffset(arch), R_EBP );
1877 } else {
1878 emit_movb_lit_offregmem ( 0x00,
1879 shadowOffset(arch-4)+1, R_EBP );
1880 }
1881 break;
1882 default:
1883 VG_(panic)("synth_PUTV(lit)");
1884 }
1885
1886 } else {
1887
1888 UInt reg;
1889 vg_assert(srcTag == RealReg);
1890
1891 if (sz == 1 && lit_or_reg >= 4) {
1892 emit_swapl_reg_EAX ( lit_or_reg );
1893 reg = R_EAX;
1894 } else {
1895 reg = lit_or_reg;
1896 }
1897
1898 if (sz == 1) vg_assert(reg < 4);
1899
1900 switch (sz) {
1901 case 4:
1902 emit_movv_reg_offregmem ( 4, reg,
1903 shadowOffset(arch), R_EBP );
1904 break;
1905 case 2:
1906 emit_movv_reg_offregmem ( 2, reg,
1907 shadowOffset(arch), R_EBP );
1908 break;
1909 case 1:
1910 if (arch < 4) {
1911 emit_movb_reg_offregmem ( reg,
1912 shadowOffset(arch), R_EBP );
1913 } else {
1914 emit_movb_reg_offregmem ( reg,
1915 shadowOffset(arch-4)+1, R_EBP );
1916 }
1917 break;
1918 default:
1919 VG_(panic)("synth_PUTV(reg)");
1920 }
1921
1922 if (sz == 1 && lit_or_reg >= 4) {
1923 emit_swapl_reg_EAX ( lit_or_reg );
1924 }
1925 }
1926}
1927
1928
1929static void synth_GETVF ( Int reg )
1930{
1931 emit_movv_offregmem_reg ( 4, shadowFlagsOffset(), R_EBP, reg );
1932 /* paranoia only; should be unnecessary ... */
1933 /* emit_nonshiftopv_lit_reg ( 4, OR, 0xFFFFFFFE, reg ); */
1934}
1935
1936
1937static void synth_PUTVF ( UInt reg )
1938{
1939 emit_movv_reg_offregmem ( 4, reg, shadowFlagsOffset(), R_EBP );
1940}
1941
1942
1943static void synth_handle_esp_assignment ( Int reg )
1944{
1945 emit_pushal();
1946 emit_pushv_reg ( 4, reg );
1947 synth_call_baseBlock_method ( False, VGOFF_(handle_esp_assignment) );
1948 emit_add_lit_to_esp ( 4 );
1949 emit_popal();
1950}
1951
1952
1953static void synth_fpu_mem_check_actions ( Bool isWrite,
1954 Int size, Int a_reg )
1955{
1956 Int helper_offw
1957 = isWrite ? VGOFF_(fpu_write_check)
1958 : VGOFF_(fpu_read_check);
1959 emit_pushal();
1960 emit_pushl_lit8 ( size );
1961 emit_pushv_reg ( 4, a_reg );
1962 synth_call_baseBlock_method ( False, helper_offw );
1963 emit_add_lit_to_esp ( 8 );
1964 emit_popal();
1965}
1966
1967
1968#if 0
1969/* FixMe. Useful for debugging. */
1970void VG_(oink) ( Int n )
1971{
1972 VG_(printf)("OiNk(%d): ", n );
1973 VG_(show_reg_tags)( &VG_(m_shadow) );
1974}
1975
1976static void synth_OINK ( Int n )
1977{
1978 emit_pushal();
1979 emit_movv_lit_reg ( 4, n, R_EBP );
1980 emit_pushl_reg ( R_EBP );
1981 emit_movv_lit_reg ( 4, (Addr)&VG_(oink), R_EBP );
1982 emit_call_reg ( R_EBP );
1983 emit_add_lit_to_esp ( 4 );
1984 emit_popal();
1985}
1986#endif
1987
1988static void synth_TAG1_op ( VgTagOp op, Int reg )
1989{
1990 switch (op) {
1991
1992 /* Scheme is
1993 neg<sz> %reg -- CF = %reg==0 ? 0 : 1
1994 sbbl %reg, %reg -- %reg = -CF
1995 or 0xFFFFFFFE, %reg -- invalidate all bits except lowest
1996 */
1997 case VgT_PCast40:
1998 emit_unaryopv_reg(4, NEG, reg);
1999 emit_nonshiftopv_reg_reg(4, SBB, reg, reg);
2000 emit_nonshiftopv_lit_reg(4, OR, 0xFFFFFFFE, reg);
2001 break;
2002 case VgT_PCast20:
2003 emit_unaryopv_reg(2, NEG, reg);
2004 emit_nonshiftopv_reg_reg(4, SBB, reg, reg);
2005 emit_nonshiftopv_lit_reg(4, OR, 0xFFFFFFFE, reg);
2006 break;
2007 case VgT_PCast10:
2008 if (reg >= 4) {
2009 emit_swapl_reg_EAX(reg);
2010 emit_unaryopb_reg(NEG, R_EAX);
2011 emit_swapl_reg_EAX(reg);
2012 } else {
2013 emit_unaryopb_reg(NEG, reg);
2014 }
2015 emit_nonshiftopv_reg_reg(4, SBB, reg, reg);
2016 emit_nonshiftopv_lit_reg(4, OR, 0xFFFFFFFE, reg);
2017 break;
2018
2019 /* Scheme is
2020 andl $1, %reg -- %reg is 0 or 1
2021 negl %reg -- %reg is 0 or 0xFFFFFFFF
2022 and possibly an OR to invalidate unused bits.
2023 */
2024 case VgT_PCast04:
2025 emit_nonshiftopv_lit_reg(4, AND, 0x00000001, reg);
2026 emit_unaryopv_reg(4, NEG, reg);
2027 break;
2028 case VgT_PCast02:
2029 emit_nonshiftopv_lit_reg(4, AND, 0x00000001, reg);
2030 emit_unaryopv_reg(4, NEG, reg);
2031 emit_nonshiftopv_lit_reg(4, OR, 0xFFFF0000, reg);
2032 break;
2033 case VgT_PCast01:
2034 emit_nonshiftopv_lit_reg(4, AND, 0x00000001, reg);
2035 emit_unaryopv_reg(4, NEG, reg);
2036 emit_nonshiftopv_lit_reg(4, OR, 0xFFFFFF00, reg);
2037 break;
2038
2039 /* Scheme is
2040 shl $24, %reg -- make irrelevant bits disappear
2041 negl %reg -- CF = %reg==0 ? 0 : 1
2042 sbbl %reg, %reg -- %reg = -CF
2043 and possibly an OR to invalidate unused bits.
2044 */
2045 case VgT_PCast14:
2046 emit_shiftopv_lit_reg(4, SHL, 24, reg);
2047 emit_unaryopv_reg(4, NEG, reg);
2048 emit_nonshiftopv_reg_reg(4, SBB, reg, reg);
2049 break;
2050 case VgT_PCast12:
2051 emit_shiftopv_lit_reg(4, SHL, 24, reg);
2052 emit_unaryopv_reg(4, NEG, reg);
2053 emit_nonshiftopv_reg_reg(4, SBB, reg, reg);
2054 emit_nonshiftopv_lit_reg(4, OR, 0xFFFF0000, reg);
2055 break;
2056 case VgT_PCast11:
2057 emit_shiftopv_lit_reg(4, SHL, 24, reg);
2058 emit_unaryopv_reg(4, NEG, reg);
2059 emit_nonshiftopv_reg_reg(4, SBB, reg, reg);
2060 emit_nonshiftopv_lit_reg(4, OR, 0xFFFFFF00, reg);
2061 break;
2062
2063 /* We steal %ebp (a non-allocable reg) as a temporary:
2064 pushl %ebp
2065 movl %reg, %ebp
2066 negl %ebp
2067 orl %ebp, %reg
2068 popl %ebp
2069 This sequence turns out to be correct regardless of the
2070 operation width.
2071 */
2072 case VgT_Left4:
2073 case VgT_Left2:
2074 case VgT_Left1:
2075 vg_assert(reg != R_EDI);
2076 emit_movv_reg_reg(4, reg, R_EDI);
2077 emit_unaryopv_reg(4, NEG, R_EDI);
2078 emit_nonshiftopv_reg_reg(4, OR, R_EDI, reg);
2079 break;
2080
2081 /* These are all fairly obvious; do the op and then, if
2082 necessary, invalidate unused bits. */
2083 case VgT_SWiden14:
2084 emit_shiftopv_lit_reg(4, SHL, 24, reg);
2085 emit_shiftopv_lit_reg(4, SAR, 24, reg);
2086 break;
2087 case VgT_SWiden24:
2088 emit_shiftopv_lit_reg(4, SHL, 16, reg);
2089 emit_shiftopv_lit_reg(4, SAR, 16, reg);
2090 break;
2091 case VgT_SWiden12:
2092 emit_shiftopv_lit_reg(4, SHL, 24, reg);
2093 emit_shiftopv_lit_reg(4, SAR, 24, reg);
2094 emit_nonshiftopv_lit_reg(4, OR, 0xFFFF0000, reg);
2095 break;
2096 case VgT_ZWiden14:
2097 emit_nonshiftopv_lit_reg(4, AND, 0x000000FF, reg);
2098 break;
2099 case VgT_ZWiden24:
2100 emit_nonshiftopv_lit_reg(4, AND, 0x0000FFFF, reg);
2101 break;
2102 case VgT_ZWiden12:
2103 emit_nonshiftopv_lit_reg(4, AND, 0x000000FF, reg);
2104 emit_nonshiftopv_lit_reg(4, OR, 0xFFFF0000, reg);
2105 break;
2106
2107 default:
2108 VG_(panic)("synth_TAG1_op");
2109 }
2110}
2111
2112
2113static void synth_TAG2_op ( VgTagOp op, Int regs, Int regd )
2114{
2115 switch (op) {
2116
2117 /* UifU is implemented by OR, since 1 means Undefined. */
2118 case VgT_UifU4:
2119 case VgT_UifU2:
2120 case VgT_UifU1:
2121 case VgT_UifU0:
2122 emit_nonshiftopv_reg_reg(4, OR, regs, regd);
2123 break;
2124
2125 /* DifD is implemented by AND, since 0 means Defined. */
2126 case VgT_DifD4:
2127 case VgT_DifD2:
2128 case VgT_DifD1:
2129 emit_nonshiftopv_reg_reg(4, AND, regs, regd);
2130 break;
2131
2132 /* ImproveAND(value, tags) = value OR tags.
2133 Defined (0) value 0s give defined (0); all other -> undefined (1).
2134 value is in regs; tags is in regd.
2135 Be paranoid and invalidate unused bits; I don't know whether
2136 or not this is actually necessary. */
2137 case VgT_ImproveAND4_TQ:
2138 emit_nonshiftopv_reg_reg(4, OR, regs, regd);
2139 break;
2140 case VgT_ImproveAND2_TQ:
2141 emit_nonshiftopv_reg_reg(4, OR, regs, regd);
2142 emit_nonshiftopv_lit_reg(4, OR, 0xFFFF0000, regd);
2143 break;
2144 case VgT_ImproveAND1_TQ:
2145 emit_nonshiftopv_reg_reg(4, OR, regs, regd);
2146 emit_nonshiftopv_lit_reg(4, OR, 0xFFFFFF00, regd);
2147 break;
2148
2149 /* ImproveOR(value, tags) = (not value) OR tags.
2150 Defined (0) value 1s give defined (0); all other -> undefined (1).
2151 value is in regs; tags is in regd.
2152 To avoid trashing value, this is implemented (re de Morgan) as
2153 not (value AND (not tags))
2154 Be paranoid and invalidate unused bits; I don't know whether
2155 or not this is actually necessary. */
2156 case VgT_ImproveOR4_TQ:
2157 emit_unaryopv_reg(4, NOT, regd);
2158 emit_nonshiftopv_reg_reg(4, AND, regs, regd);
2159 emit_unaryopv_reg(4, NOT, regd);
2160 break;
2161 case VgT_ImproveOR2_TQ:
2162 emit_unaryopv_reg(4, NOT, regd);
2163 emit_nonshiftopv_reg_reg(4, AND, regs, regd);
2164 emit_unaryopv_reg(4, NOT, regd);
2165 emit_nonshiftopv_lit_reg(4, OR, 0xFFFF0000, regd);
2166 break;
2167 case VgT_ImproveOR1_TQ:
2168 emit_unaryopv_reg(4, NOT, regd);
2169 emit_nonshiftopv_reg_reg(4, AND, regs, regd);
2170 emit_unaryopv_reg(4, NOT, regd);
2171 emit_nonshiftopv_lit_reg(4, OR, 0xFFFFFF00, regd);
2172 break;
2173
2174 default:
2175 VG_(panic)("synth_TAG2_op");
2176 }
2177}
2178
2179/*----------------------------------------------------*/
2180/*--- Generate code for a single UInstr. ---*/
2181/*----------------------------------------------------*/
2182
njn5a74eb82002-08-06 20:56:40 +00002183static Bool readFlagUse ( UInstr* u )
2184{
2185 return (u->flags_r != FlagsEmpty);
2186}
2187
2188static Bool writeFlagUse ( UInstr* u )
2189{
2190 return (u->flags_w != FlagsEmpty);
2191}
2192
sewardjde4a1d02002-03-22 01:27:54 +00002193static void emitUInstr ( Int i, UInstr* u )
2194{
2195 if (dis)
2196 VG_(ppUInstr)(i, u);
2197
2198# if 0
2199 if (0&& VG_(translations_done) >= 600) {
2200 Bool old_dis = dis;
2201 dis = False;
2202 synth_OINK(i);
2203 dis = old_dis;
2204 }
2205# endif
2206
2207 switch (u->opcode) {
2208
2209 case NOP: case CALLM_S: case CALLM_E: break;
2210
2211 case INCEIP: {
2212 vg_assert(u->tag1 == Lit16);
2213 emit_addlit8_offregmem ( u->val1, R_EBP, 4 * VGOFF_(m_eip) );
2214 break;
2215 }
2216
2217 case LEA1: {
2218 vg_assert(u->tag1 == RealReg);
2219 vg_assert(u->tag2 == RealReg);
2220 emit_lea_litreg_reg ( u->lit32, u->val1, u->val2 );
2221 break;
2222 }
2223
2224 case LEA2: {
2225 vg_assert(u->tag1 == RealReg);
2226 vg_assert(u->tag2 == RealReg);
2227 vg_assert(u->tag3 == RealReg);
2228 emit_lea_sib_reg ( u->lit32, u->extra4b,
2229 u->val1, u->val2, u->val3 );
2230 break;
2231 }
2232
2233 case WIDEN: {
2234 vg_assert(u->tag1 == RealReg);
2235 if (u->signed_widen) {
2236 synth_WIDEN_signed ( u->extra4b, u->size, u->val1 );
2237 } else {
2238 /* no need to generate any code. */
2239 }
2240 break;
2241 }
2242
2243 case SETV: {
2244 vg_assert(VG_(clo_instrument));
2245 vg_assert(u->tag1 == RealReg);
2246 synth_SETV ( u->size, u->val1 );
2247 break;
2248 }
2249
2250 case STOREV: {
2251 vg_assert(VG_(clo_instrument));
2252 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
2253 vg_assert(u->tag2 == RealReg);
2254 synth_STOREV ( u->size, u->tag1,
2255 u->tag1==Literal ? u->lit32 : u->val1,
2256 u->val2 );
2257 break;
2258 }
2259
2260 case STORE: {
2261 vg_assert(u->tag1 == RealReg);
2262 vg_assert(u->tag2 == RealReg);
2263 synth_mov_reg_memreg ( u->size, u->val1, u->val2 );
sewardj18d75132002-05-16 11:06:21 +00002264 /* No longer possible, but retained for illustrative purposes.
sewardjde4a1d02002-03-22 01:27:54 +00002265 if (u->smc_check)
2266 synth_orig_code_write_check ( u->size, u->val2 );
sewardj18d75132002-05-16 11:06:21 +00002267 */
sewardjde4a1d02002-03-22 01:27:54 +00002268 break;
2269 }
2270
2271 case LOADV: {
2272 vg_assert(VG_(clo_instrument));
2273 vg_assert(u->tag1 == RealReg);
2274 vg_assert(u->tag2 == RealReg);
2275 if (0 && VG_(clo_instrument))
2276 emit_AMD_prefetch_reg ( u->val1 );
2277 synth_LOADV ( u->size, u->val1, u->val2 );
2278 break;
2279 }
2280
2281 case LOAD: {
2282 vg_assert(u->tag1 == RealReg);
2283 vg_assert(u->tag2 == RealReg);
2284 synth_mov_regmem_reg ( u->size, u->val1, u->val2 );
2285 break;
2286 }
2287
2288 case TESTV: {
2289 vg_assert(VG_(clo_instrument));
2290 vg_assert(u->tag1 == RealReg || u->tag1 == ArchReg);
2291 synth_TESTV(u->size, u->tag1, u->val1);
2292 break;
2293 }
2294
2295 case GETV: {
2296 vg_assert(VG_(clo_instrument));
2297 vg_assert(u->tag1 == ArchReg);
2298 vg_assert(u->tag2 == RealReg);
2299 synth_GETV(u->size, u->val1, u->val2);
2300 break;
2301 }
2302
2303 case GETVF: {
2304 vg_assert(VG_(clo_instrument));
2305 vg_assert(u->tag1 == RealReg);
2306 vg_assert(u->size == 0);
2307 synth_GETVF(u->val1);
2308 break;
2309 }
2310
2311 case PUTV: {
2312 vg_assert(VG_(clo_instrument));
2313 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
2314 vg_assert(u->tag2 == ArchReg);
2315 synth_PUTV(u->size, u->tag1,
2316 u->tag1==Literal ? u->lit32 : u->val1,
2317 u->val2 );
2318 break;
2319 }
2320
2321 case PUTVF: {
2322 vg_assert(VG_(clo_instrument));
2323 vg_assert(u->tag1 == RealReg);
2324 vg_assert(u->size == 0);
2325 synth_PUTVF(u->val1);
2326 break;
2327 }
2328
2329 case GET: {
2330 vg_assert(u->tag1 == ArchReg || u->tag1 == SpillNo);
2331 vg_assert(u->tag2 == RealReg);
2332 synth_mov_offregmem_reg (
2333 u->size,
2334 spillOrArchOffset( u->size, u->tag1, u->val1 ),
2335 R_EBP,
2336 u->val2
2337 );
2338 break;
2339 }
2340
2341 case PUT: {
2342 vg_assert(u->tag2 == ArchReg || u->tag2 == SpillNo);
2343 vg_assert(u->tag1 == RealReg);
2344 if (u->tag2 == ArchReg
2345 && u->val2 == R_ESP
2346 && u->size == 4
2347 && VG_(clo_instrument)) {
2348 synth_handle_esp_assignment ( u->val1 );
2349 }
2350 synth_mov_reg_offregmem (
2351 u->size,
2352 u->val1,
2353 spillOrArchOffset( u->size, u->tag2, u->val2 ),
2354 R_EBP
2355 );
2356 break;
2357 }
2358
2359 case GETF: {
2360 vg_assert(u->size == 2 || u->size == 4);
2361 vg_assert(u->tag1 == RealReg);
2362 synth_mov_offregmem_reg (
2363 u->size,
2364 eflagsOffset(),
2365 R_EBP,
2366 u->val1
2367 );
2368 break;
2369 }
2370
2371 case PUTF: {
2372 vg_assert(u->size == 2 || u->size == 4);
2373 vg_assert(u->tag1 == RealReg);
2374 synth_mov_reg_offregmem (
2375 u->size,
2376 u->val1,
2377 eflagsOffset(),
2378 R_EBP
2379 );
2380 break;
2381 }
2382
2383 case MOV: {
2384 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
2385 vg_assert(u->tag2 == RealReg);
2386 switch (u->tag1) {
2387 case RealReg: vg_assert(u->size == 4);
2388 if (u->val1 != u->val2)
2389 synth_movl_reg_reg ( u->val1, u->val2 );
2390 break;
2391 case Literal: synth_mov_lit_reg ( u->size, u->lit32, u->val2 );
2392 break;
2393 default: VG_(panic)("emitUInstr:mov");
2394 }
2395 break;
2396 }
2397
sewardjde4a1d02002-03-22 01:27:54 +00002398 case XOR:
2399 case OR:
2400 case AND:
2401 case SUB:
njn5a74eb82002-08-06 20:56:40 +00002402 case ADD:
2403 vg_assert(! readFlagUse ( u ));
2404 /* fall thru */
2405 case SBB:
2406 case ADC: {
sewardjde4a1d02002-03-22 01:27:54 +00002407 vg_assert(u->tag2 == RealReg);
2408 switch (u->tag1) {
2409 case Literal: synth_nonshiftop_lit_reg (
njn5a74eb82002-08-06 20:56:40 +00002410 readFlagUse(u), writeFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002411 u->opcode, u->size, u->lit32, u->val2 );
2412 break;
2413 case RealReg: synth_nonshiftop_reg_reg (
njn5a74eb82002-08-06 20:56:40 +00002414 readFlagUse(u), writeFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002415 u->opcode, u->size, u->val1, u->val2 );
2416 break;
2417 case ArchReg: synth_nonshiftop_offregmem_reg (
njn5a74eb82002-08-06 20:56:40 +00002418 readFlagUse(u), writeFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002419 u->opcode, u->size,
2420 spillOrArchOffset( u->size, u->tag1, u->val1 ),
2421 R_EBP,
2422 u->val2 );
2423 break;
2424 default: VG_(panic)("emitUInstr:non-shift-op");
2425 }
2426 break;
2427 }
2428
sewardjde4a1d02002-03-22 01:27:54 +00002429 case ROR:
2430 case ROL:
2431 case SAR:
2432 case SHR:
2433 case SHL: {
njn5a74eb82002-08-06 20:56:40 +00002434 vg_assert(! readFlagUse ( u ));
2435 /* fall thru */
2436 case RCR:
2437 case RCL:
sewardjde4a1d02002-03-22 01:27:54 +00002438 vg_assert(u->tag2 == RealReg);
njn5a74eb82002-08-06 20:56:40 +00002439 vg_assert(! readFlagUse ( u ));
sewardjde4a1d02002-03-22 01:27:54 +00002440 switch (u->tag1) {
2441 case Literal: synth_shiftop_lit_reg (
njn5a74eb82002-08-06 20:56:40 +00002442 readFlagUse(u), writeFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002443 u->opcode, u->size, u->lit32, u->val2 );
2444 break;
2445 case RealReg: synth_shiftop_reg_reg (
njn5a74eb82002-08-06 20:56:40 +00002446 readFlagUse(u), writeFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002447 u->opcode, u->size, u->val1, u->val2 );
2448 break;
2449 default: VG_(panic)("emitUInstr:non-shift-op");
2450 }
2451 break;
2452 }
2453
2454 case INC:
2455 case DEC:
2456 case NEG:
2457 case NOT:
2458 vg_assert(u->tag1 == RealReg);
njn5a74eb82002-08-06 20:56:40 +00002459 vg_assert(! readFlagUse ( u ));
sewardjde4a1d02002-03-22 01:27:54 +00002460 synth_unaryop_reg (
njn5a74eb82002-08-06 20:56:40 +00002461 writeFlagUse(u), u->opcode, u->size, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002462 break;
2463
2464 case BSWAP:
2465 vg_assert(u->tag1 == RealReg);
2466 vg_assert(u->size == 4);
2467 vg_assert(!VG_(anyFlagUse)(u));
2468 emit_bswapl_reg ( u->val1 );
2469 break;
2470
2471 case CMOV:
2472 vg_assert(u->tag1 == RealReg);
2473 vg_assert(u->tag2 == RealReg);
2474 vg_assert(u->cond != CondAlways);
2475 vg_assert(u->size == 4);
2476 synth_cmovl_reg_reg ( u->cond, u->val1, u->val2 );
2477 break;
2478
2479 case JMP: {
2480 vg_assert(u->tag2 == NoValue);
2481 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
2482 if (u->cond == CondAlways) {
sewardj2e93c502002-04-12 11:12:52 +00002483 switch (u->tag1) {
2484 case RealReg:
2485 synth_jmp_reg ( u->val1, u->jmpkind );
2486 break;
2487 case Literal:
2488 synth_jmp_lit ( u->lit32, u->jmpkind );
2489 break;
2490 default:
2491 VG_(panic)("emitUInstr(JMP, unconditional, default)");
2492 break;
sewardjde4a1d02002-03-22 01:27:54 +00002493 }
2494 } else {
sewardj2e93c502002-04-12 11:12:52 +00002495 switch (u->tag1) {
2496 case RealReg:
2497 VG_(panic)("emitUInstr(JMP, conditional, RealReg)");
2498 break;
2499 case Literal:
2500 vg_assert(u->jmpkind == JmpBoring);
2501 synth_jcond_lit ( u->cond, u->lit32 );
2502 break;
2503 default:
2504 VG_(panic)("emitUInstr(JMP, conditional, default)");
2505 break;
sewardjde4a1d02002-03-22 01:27:54 +00002506 }
2507 }
2508 break;
2509 }
2510
2511 case JIFZ:
2512 vg_assert(u->tag1 == RealReg);
2513 vg_assert(u->tag2 == Literal);
2514 vg_assert(u->size == 4);
2515 synth_jmp_ifzero_reg_lit ( u->val1, u->lit32 );
2516 break;
2517
2518 case TAG1:
2519 synth_TAG1_op ( u->val3, u->val1 );
2520 break;
2521
2522 case TAG2:
2523 if (u->val3 != VgT_DebugFn) {
2524 synth_TAG2_op ( u->val3, u->val1, u->val2 );
2525 } else {
2526 /* Assume a call to VgT_DebugFn passing both args
2527 and placing the result back in the second. */
2528 Int j, k;
2529 /* u->val2 is the reg into which the result is written. So
2530 don't save/restore it. And it can be used at a temp for
2531 the call target, too. Since %eax is used for the return
2532 value from the C procedure, it is preserved only by
2533 virtue of not being mentioned as a VG_CALLEE_SAVED reg. */
2534 for (k = 0; k < VG_MAX_REALREGS; k++) {
2535 j = VG_(rankToRealRegNo) ( k );
2536 if (VG_CALLEE_SAVED(j)) continue;
2537 if (j == u->val2) continue;
2538 emit_pushv_reg ( 4, j );
2539 }
2540 emit_pushv_reg(4, u->val2);
2541 emit_pushv_reg(4, u->val1);
2542 emit_movv_lit_reg ( 4, (UInt)(&VG_(DebugFn)), u->val2 );
2543 emit_call_reg ( u->val2 );
2544 if (u->val2 != R_EAX)
2545 emit_movv_reg_reg ( 4, R_EAX, u->val2 );
2546 /* nuke args */
2547 emit_add_lit_to_esp(8);
2548 for (k = VG_MAX_REALREGS-1; k >= 0; k--) {
2549 j = VG_(rankToRealRegNo) ( k );
2550 if (VG_CALLEE_SAVED(j)) continue;
2551 if (j == u->val2) continue;
2552 emit_popv_reg ( 4, j );
2553 }
2554 }
2555 break;
2556
2557 case PUSH:
2558 vg_assert(u->tag1 == RealReg);
2559 vg_assert(u->tag2 == NoValue);
2560 emit_pushv_reg ( 4, u->val1 );
2561 break;
2562
2563 case POP:
2564 vg_assert(u->tag1 == RealReg);
2565 vg_assert(u->tag2 == NoValue);
2566 emit_popv_reg ( 4, u->val1 );
2567 break;
2568
2569 case CALLM:
2570 vg_assert(u->tag1 == Lit16);
2571 vg_assert(u->tag2 == NoValue);
2572 vg_assert(u->size == 0);
njn5a74eb82002-08-06 20:56:40 +00002573 if (readFlagUse ( u ))
sewardjde4a1d02002-03-22 01:27:54 +00002574 emit_get_eflags();
2575 synth_call_baseBlock_method ( False, u->val1 );
njn5a74eb82002-08-06 20:56:40 +00002576 if (writeFlagUse ( u ))
sewardjde4a1d02002-03-22 01:27:54 +00002577 emit_put_eflags();
2578 break;
2579
njn6431be72002-07-28 09:53:34 +00002580 case CCALL_1_0:
2581 vg_assert(u->tag1 == RealReg);
2582 vg_assert(u->tag2 == NoValue);
2583 vg_assert(u->size == 0);
2584
2585 synth_ccall_saveRegs();
2586 synth_ccall_pushOneArg ( u->val1 );
2587 synth_ccall_call_clearStack_restoreRegs ( u->lit32, 4 );
2588 break;
2589
2590 case CCALL_2_0:
2591 vg_assert(u->tag1 == RealReg);
2592 vg_assert(u->tag2 == RealReg);
2593 vg_assert(u->size == 0);
2594
2595 synth_ccall_saveRegs();
2596 synth_ccall_pushTwoArgs ( u->val1, u->val2 );
2597 synth_ccall_call_clearStack_restoreRegs ( u->lit32, 8 );
2598 break;
2599
sewardjde4a1d02002-03-22 01:27:54 +00002600 case CLEAR:
2601 vg_assert(u->tag1 == Lit16);
2602 vg_assert(u->tag2 == NoValue);
2603 emit_add_lit_to_esp ( u->val1 );
2604 break;
2605
2606 case CC2VAL:
2607 vg_assert(u->tag1 == RealReg);
2608 vg_assert(u->tag2 == NoValue);
2609 vg_assert(VG_(anyFlagUse)(u));
2610 synth_setb_reg ( u->val1, u->cond );
2611 break;
2612
2613 /* We assume that writes to memory done by FPU_Ws are not going
2614 to be used to create new code, so there's no orig-code-write
2615 checks done by default. */
2616 case FPU_R:
2617 case FPU_W:
2618 vg_assert(u->tag1 == Lit16);
2619 vg_assert(u->tag2 == RealReg);
2620 if (VG_(clo_instrument))
2621 synth_fpu_mem_check_actions (
2622 u->opcode==FPU_W, u->size, u->val2 );
2623 synth_fpu_regmem ( (u->val1 >> 8) & 0xFF,
2624 u->val1 & 0xFF,
2625 u->val2 );
sewardj18d75132002-05-16 11:06:21 +00002626 /* No longer possible, but retained for illustrative purposes.
sewardjde4a1d02002-03-22 01:27:54 +00002627 if (u->opcode == FPU_W && u->smc_check)
2628 synth_orig_code_write_check ( u->size, u->val2 );
sewardj18d75132002-05-16 11:06:21 +00002629 */
sewardjde4a1d02002-03-22 01:27:54 +00002630 break;
2631
2632 case FPU:
2633 vg_assert(u->tag1 == Lit16);
2634 vg_assert(u->tag2 == NoValue);
njn5a74eb82002-08-06 20:56:40 +00002635 if (readFlagUse ( u ))
sewardj4a7456e2002-03-24 13:52:19 +00002636 emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00002637 synth_fpu_no_mem ( (u->val1 >> 8) & 0xFF,
2638 u->val1 & 0xFF );
njn5a74eb82002-08-06 20:56:40 +00002639 if (writeFlagUse ( u ))
sewardj4a7456e2002-03-24 13:52:19 +00002640 emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00002641 break;
2642
2643 default:
2644 VG_(printf)("emitUInstr: unhandled insn:\n");
2645 VG_(ppUInstr)(0,u);
2646 VG_(panic)("emitUInstr: unimplemented opcode");
2647 }
2648
2649}
2650
2651
2652/* Emit x86 for the ucode in cb, returning the address of the
2653 generated code and setting *nbytes to its size. */
2654UChar* VG_(emit_code) ( UCodeBlock* cb, Int* nbytes )
2655{
2656 Int i;
2657 emitted_code_used = 0;
2658 emitted_code_size = 500; /* reasonable initial size */
2659 emitted_code = VG_(jitmalloc)(emitted_code_size);
2660
2661 if (dis) VG_(printf)("Generated code:\n");
2662
2663 for (i = 0; i < cb->used; i++) {
2664 if (cb->instrs[i].opcode != NOP) {
2665 UInstr* u = &cb->instrs[i];
2666# if 1
2667 /* Check on the sanity of this insn. */
2668 Bool sane = VG_(saneUInstr)( False, u );
2669 if (!sane) {
2670 VG_(printf)("\ninsane instruction\n");
2671 VG_(ppUInstr)( i, u );
2672 }
2673 vg_assert(sane);
2674# endif
2675# if 0
2676 /* Pass args to TAG1/TAG2 to vg_DebugFn for sanity checking.
2677 Requires a suitable definition of vg_DebugFn. */
2678 if (u->opcode == TAG1) {
2679 UInstr t1;
2680 vg_assert(u->tag1 == RealReg);
2681 VG_(emptyUInstr)( &t1 );
2682 t1.opcode = TAG2;
2683 t1.tag1 = t1.tag2 = RealReg;
2684 t1.val1 = t1.val2 = u->val1;
2685 t1.tag3 = Lit16;
2686 t1.val3 = VgT_DebugFn;
2687 emitUInstr( i, &t1 );
2688 }
2689 if (u->opcode == TAG2) {
2690 UInstr t1;
2691 vg_assert(u->tag1 == RealReg);
2692 vg_assert(u->tag2 == RealReg);
2693 VG_(emptyUInstr)( &t1 );
2694 t1.opcode = TAG2;
2695 t1.tag1 = t1.tag2 = RealReg;
2696 t1.val1 = t1.val2 = u->val1;
2697 t1.tag3 = Lit16;
2698 t1.val3 = VgT_DebugFn;
2699 if (u->val3 == VgT_UifU1 || u->val3 == VgT_UifU2
2700 || u->val3 == VgT_UifU4 || u->val3 == VgT_DifD1
2701 || u->val3 == VgT_DifD2 || u->val3 == VgT_DifD4)
2702 emitUInstr( i, &t1 );
2703 t1.val1 = t1.val2 = u->val2;
2704 emitUInstr( i, &t1 );
2705 }
2706# endif
2707 emitUInstr( i, u );
2708 }
2709 }
2710
2711 /* Returns a pointer to the emitted code. This will have to be
2712 copied by the caller into the translation cache, and then freed
2713 using VG_(jitfree). */
2714 *nbytes = emitted_code_used;
2715 return emitted_code;
2716}
2717
2718/*--------------------------------------------------------------------*/
2719/*--- end vg_from_ucode.c ---*/
2720/*--------------------------------------------------------------------*/