2 ===================================================================
3 RCS file: /cvsroot/qemu/qemu/dyngen-exec.h,v
4 retrieving revision 1.25
5 diff -u -p -r1.25 dyngen-exec.h
6 --- dyngen-exec.h 24 Apr 2005 18:01:56 -0000 1.25
7 +++ dyngen-exec.h 11 May 2005 20:38:33 -0000
8 @@ -155,7 +155,12 @@ extern int printf(const char *, ...);
11 /* force GCC to generate only one epilog at the end of the function */
12 +#if defined(__i386__) || defined(__x86_64__)
13 +/* Also add 4 bytes of padding so that we can replace the ret with a jmp. */
14 +#define FORCE_RET() asm volatile ("nop;nop;nop;nop");
16 #define FORCE_RET() asm volatile ("");
21 @@ -205,12 +210,19 @@ extern int __op_jmp0, __op_jmp1, __op_jm
25 -#define EXIT_TB() asm volatile ("ret")
26 -#define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n)
27 +/* Dyngen will replace hlt instructions with a ret instruction. Inserting a
28 + ret directly would confuse dyngen. */
29 +#define EXIT_TB() asm volatile ("hlt")
30 +/* Dyngen will replace cli with 0x9e (jmp).
31 + We generate the offset manually. */
32 +#define GOTO_LABEL_PARAM(n) \
33 + asm volatile ("cli;.long " ASM_NAME(__op_gen_label) #n " - 1f;1:")
36 -#define EXIT_TB() asm volatile ("ret")
37 -#define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n)
38 +/* The same as i386. */
39 +#define EXIT_TB() asm volatile ("hlt")
40 +#define GOTO_LABEL_PARAM(n) \
41 + asm volatile ("cli;.long " ASM_NAME(__op_gen_label) #n " - 1f;1:")
44 #define EXIT_TB() asm volatile ("blr")
46 ===================================================================
47 RCS file: /cvsroot/qemu/qemu/dyngen.c,v
48 retrieving revision 1.40
49 diff -u -p -r1.40 dyngen.c
50 --- dyngen.c 27 Apr 2005 19:55:58 -0000 1.40
51 +++ dyngen.c 11 May 2005 20:38:33 -0000
54 #include "config-host.h"
58 /* NOTE: we test CONFIG_WIN32 instead of _WIN32 to enabled cross
60 #if defined(CONFIG_WIN32)
61 @@ -1343,6 +1345,639 @@ int arm_emit_ldr_info(const char *name,
65 +#if defined(HOST_I386) || defined(HOST_X86_64)
67 +/* This byte is the first byte of an instruction. */
68 +#define FLAG_INSN (1 << 0)
69 +/* This byte has been processed as part of an instruction. */
70 +#define FLAG_SCANNED (1 << 1)
71 +/* This instruction is a return instruction. Gcc cometimes generates prefix
72 + bytes, so may be more than one byte long. */
73 +#define FLAG_RET (1 << 2)
74 +/* This is either the target of a jump, or the preceeding instruction uses
75 + a pc-relative offset. */
76 +#define FLAG_TARGET (1 << 3)
77 +/* This is a magic instruction that needs fixing up. */
78 +#define FLAG_EXIT (1 << 4)
82 +bad_opcode(const char *name, uint32_t op)
84 + error("Unsupported opcode %0*x in %s", (op > 0xff) ? 4 : 2, op, name);
87 +/* Mark len bytes as scanned, Returns insn_size + len. Reports an error
88 + if these bytes have already been scanned. */
90 +eat_bytes(const char *name, char *flags, int insn, int insn_size, int len)
93 + /* This should never occur in sane code. */
94 + if (flags[insn + insn_size] & FLAG_SCANNED)
95 + error ("Overlapping instructions in %s", name);
96 + flags[insn + insn_size] |= FLAG_SCANNED;
104 +trace_i386_insn (const char *name, uint8_t *start_p, char *flags, int insn,
123 + ptr = start_p + insn;
124 + /* nonzero if this insn has a ModR/M byte. */
126 + /* The size of the immediate value in this instruction. */
128 + /* The operand size. */
130 + /* The address size */
132 + /* The total length of this instruction. */
142 + while (is_prefix) {
143 + op = ptr[insn_size];
144 + insn_size = eat_bytes(name, flags, insn, insn_size, 1);
152 + /* two-byte opcode. */
153 + op = ptr[insn_size];
154 + insn_size = eat_bytes(name, flags, insn, insn_size, 1);
157 + if ((op & 0xf) > 3)
160 + case 1: /* vector move or prefetch */
161 + case 2: /* various moves and vector compares. */
163 + case 5: /* vector instructions */
170 + if (op & 0x77) /* emms */
173 + case 3: /* wrmsr, rdtsc, rdmsr, rdpmc, sysenter, sysexit */
176 + case 8: /* long conditional jump */
181 + case 9: /* setcc */
184 + switch (op & 0x7) {
185 + case 0: /* push fs/gs */
186 + case 1: /* pop fs/gs */
187 + case 2: /* cpuid/rsm */
190 + case 4: /* shld/shrd immediate */
193 + default: /* Normal instructions with a ModR/M byte. */
198 + switch (op & 0xf) {
199 + case 10: /* bt, bts, btr, btc */
203 + /* cmpxchg, lss, btr, lfs, lgs, movzx, btc, bsf, bsr
204 + undefined, and movsx */
213 + switch (op & 0x7) {
226 + } else if ((op & 0x07) <= 0x3) {
227 + /* General arithmentic ax. */
228 + } else if ((op & 0x07) <= 0x5) {
229 + /* General arithmetic ax, immediate. */
235 + } else if ((op & 0x23) == 0x22) {
236 + /* Segment prefix. */
239 + /* Segment register push/pop or DAA/AAA/DAS/AAS. */
244 +#if defined(HOST_X86_64)
245 + case 4: /* rex prefix. */
247 + /* The address/operand size is actually 64-bit, but the immediate
248 + values in the instruction are still 32-bit. */
255 + case 4: /* inc/dec register. */
257 + case 5: /* push/pop general register. */
262 + switch (op & 0x0f) {
263 + case 0: /* pusha */
267 + case 2: /* bound */
274 + case 6: /* opcode size prefix. */
278 + case 7: /* Address size prefix. */
282 + case 8: /* push immediate */
283 + case 10: /* pop immediate */
287 + case 9: /* imul immediate */
288 + case 11: /* imul immediate */
291 + case 12: /* insb */
292 + case 13: /* insw */
293 + case 14: /* outsb */
294 + case 15: /* outsw */
300 + case 7: /* Short conditional jump. */
307 + if ((op & 0xf) <= 3) {
308 + /* arithmetic immediate. */
314 + /* else test, xchg, mov, lea or pop general. */
318 + /* Various single-byte opcodes with no modrm byte. */
327 + switch ((op & 0xe) >> 1) {
328 + case 0: /* mov absoliute immediate. */
335 + case 4: /* test immediate. */
341 + default: /* Various string ops. */
347 + case 11: /* move immediate to register */
360 + switch (op & 0xf) {
361 + case 0: /* shift immediate */
365 + case 2: /* ret immediate */
368 + bad_opcode(name, op);
376 + case 6: /* mov immediate byte */
379 + case 7: /* mov immediate */
382 + case 8: /* enter */
383 + /* TODO: Is this right? */
387 + case 10: /* retf immediate */
390 + bad_opcode(name, op);
396 + case 11: /* retf */
397 + case 15: /* iret */
399 + bad_opcode(name, op);
401 + default: /* leave, int3 or into */
408 + if ((op & 0xf) >= 8) {
409 + /* Coprocessor escape. For our purposes this is just a normal
410 + instruction with a ModR/M byte. */
411 + } else if ((op & 0xf) >= 4) {
412 + /* AAM, AAD or XLAT */
415 + /* else shift instruction */
419 + switch ((op & 0xc) >> 2) {
420 + case 0: /* loop or jcxz */
424 + case 1: /* in/out immed */
427 + case 2: /* call or jmp */
432 + case 1: /* long jump */
436 + case 2: /* far jmp */
437 + bad_opcode(name, op);
439 + case 3: /* short jmp */
445 + case 3: /* in/out register */
452 + switch ((op & 0xe) >> 1) {
462 + /* Some privileged insns are used as markers. */
464 + case 0xf4: /* hlt: Exit translation block. */
467 + case 0xfa: /* cli: Jump to label. */
471 + case 0xfb: /* sti: TB patch jump. */
472 + /* Mark the insn for patching, but continue sscanning. */
473 + flags[insn] |= FLAG_EXIT;
478 + case 3: /* unary grp3 */
479 + if ((ptr[insn_size] & 0x38) == 0) {
483 + immed = 1; /* test immediate */
486 + case 7: /* inc/dec grp4/5 */
487 + /* TODO: This includes indirect jumps. We should fail if we
488 + encounter one of these. */
496 + if (addr_size != 4)
497 + error("16-bit addressing mode used in %s", name);
500 + modrm = ptr[insn_size];
501 + insn_size = eat_bytes(name, flags, insn, insn_size, 1);
503 + switch ((modrm & 0xc0) >> 6) {
515 + if ((modrm & 0xc0) != 0xc0 && (modrm & 0x7) == 4) {
517 + if (modrm == 4 && (ptr[insn_size] & 0x7) == 5) {
521 + insn_size = eat_bytes(name, flags, insn, insn_size, 1);
523 + insn_size = eat_bytes(name, flags, insn, insn_size, disp);
525 + insn_size = eat_bytes(name, flags, insn, insn_size, immed);
526 + if (is_condjmp || is_jmp) {
528 + disp = (int8_t)*(ptr + insn_size - 1);
530 + disp = (((int32_t)*(ptr + insn_size - 1)) << 24)
531 + | (((int32_t)*(ptr + insn_size - 2)) << 16)
532 + | (((int32_t)*(ptr + insn_size - 3)) << 8)
533 + | *(ptr + insn_size - 4);
536 + /* Jumps to external symbols point to the address of the offset
537 + before relocation. */
538 + /* ??? These are probably a tailcall. We could fix them up by
539 + replacing them with jmp to EOB + call, but it's easier to just
540 + prevent the compiler generating them. */
542 + error("Unconditional jump (sibcall?) in %s", name);
544 + if (disp < 0 || disp > len)
545 + error("Jump outside instruction in %s", name);
547 + if ((flags[disp] & (FLAG_INSN | FLAG_SCANNED)) == FLAG_SCANNED)
548 + error("Overlapping instructions in %s", name);
550 + flags[disp] |= (FLAG_INSN | FLAG_TARGET);
554 + /* Mark the following insn as a jump target. This will stop
555 + this instruction being moved. */
556 + flags[insn + insn_size] |= FLAG_TARGET;
559 + flags[insn] |= FLAG_RET;
562 + flags[insn] |= FLAG_EXIT;
564 + if (!(is_jmp || is_ret || is_exit))
565 + flags[insn + insn_size] |= FLAG_INSN;
568 +/* Scan a function body. Returns the position of the return sequence.
569 + Sets *patch_bytes to the number of bytes that need to be copied from that
570 + location. If no patching is required (ie. the return is the last insn)
571 + *patch_bytes will be set to -1. *plen is the number of code bytes to copy.
573 +static int trace_i386_op(const char * name, uint8_t *start_p, int *plen,
574 + int *patch_bytes, int *exit_addrs)
586 + flags = malloc(len + 1);
587 + memset(flags, 0, len + 1);
588 + flags[0] |= FLAG_INSN;
592 + for (insn = 0; insn < len; insn++) {
593 + if ((flags[insn] & (FLAG_INSN | FLAG_SCANNED)) == FLAG_INSN) {
594 + trace_i386_insn(name, start_p, flags, insn, len);
600 + /* Strip any unused code at the end of the function. */
601 + while (len > 0 && flags[len - 1] == 0)
607 + for (insn = 0; insn < len; insn++) {
608 + if (flags[insn] & FLAG_RET) {
609 + /* ??? In theory it should be possible to handle multiple return
610 + points. In practice it's not worth the effort. */
612 + error("Multiple return instructions in %s", name);
615 + if (flags[insn] & FLAG_EXIT) {
616 + if (num_exits == MAX_EXITS)
617 + error("Too many block exits in %s", name);
618 + exit_addrs[num_exits] = insn;
621 + if (flags[insn] & FLAG_INSN)
625 + exit_addrs[num_exits] = -1;
626 + if (retpos == -1) {
627 + if (num_exits == 0) {
628 + error ("No return instruction found in %s", name);
635 + /* If the return instruction is the last instruction we can just
637 + if (retpos == last_insn)
642 + /* Back up over any nop instructions. */
644 + && (flags[retpos] & FLAG_TARGET) == 0
645 + && (flags[retpos - 1] & FLAG_INSN) != 0
646 + && start_p[retpos - 1] == 0x90) {
650 + if (*patch_bytes == -1) {
657 + /* The ret is in the middle of the function. Find four more bytes that
658 + so the ret can be replaced by a jmp. */
659 + /* ??? Use a short jump where possible. */
662 + /* We can clobber everything up to the next jump target. */
663 + while (insn < len && bytes > 0 && (flags[insn] & FLAG_TARGET) == 0) {
668 + /* ???: Strip out nop blocks. */
669 + /* We can't do the replacement without clobbering anything important.
670 + Copy preceeding instructions(s) to give us some space. */
671 + while (retpos > 0) {
672 + /* If this byte is the target of a jmp we can't move it. */
673 + if (flags[retpos] & FLAG_TARGET)
680 + /* Break out of the loop if we have enough space and this is either
681 + the first byte of an instruction or a pad byte. */
682 + if ((flags[retpos] & (FLAG_INSN | FLAG_SCANNED)) != FLAG_SCANNED
690 + error("Unable to replace ret with jmp in %s\n", name);
700 /* generate op code */
701 @@ -1356,6 +1991,11 @@ void gen_code(const char *name, host_ulo
702 uint8_t args_present[MAX_ARGS];
703 const char *sym_name, *p;
705 +#if defined(HOST_I386) || defined(HOST_X86_64)
708 + int exit_addrs[MAX_EXITS];
711 /* Compute exact size excluding prologue and epilogue instructions.
712 * Increment start_offset to skip epilogue instructions, then compute
713 @@ -1366,33 +2006,12 @@ void gen_code(const char *name, host_ulo
714 p_end = p_start + size;
715 start_offset = offset;
716 #if defined(HOST_I386) || defined(HOST_X86_64)
717 -#ifdef CONFIG_FORMAT_COFF
722 - error("empty code for %s", name);
723 - while (*p != 0xc3) {
726 - error("ret or jmp expected at the end of %s", name);
728 - copy_size = p - p_start;
733 len = p_end - p_start;
735 - error("empty code for %s", name);
736 - if (p_end[-1] == 0xc3) {
739 - error("ret or jmp expected at the end of %s", name);
741 + retpos = trace_i386_op(name, p_start, &len, &patch_bytes, exit_addrs);
745 #elif defined(HOST_PPC)
748 @@ -1559,6 +2178,13 @@ void gen_code(const char *name, host_ulo
751 if (gen_switch == 2) {
752 +#if defined(HOST_I386) || defined(HOST_X86_64)
753 + if (patch_bytes != -1)
754 + copy_size += patch_bytes;
759 fprintf(outfile, "DEF(%s, %d, %d)\n", name + 3, nb_args, copy_size);
760 } else if (gen_switch == 1) {
762 @@ -1761,7 +2387,43 @@ void gen_code(const char *name, host_ulo
763 #error unsupport object format
767 + /* Replace the marker instructions with the actual opcodes. */
768 + for (i = 0; exit_addrs[i] != -1; i++) {
770 + switch (p_start[exit_addrs[i]])
772 + case 0xf4: op = 0xc3; break; /* hlt -> ret */
773 + case 0xfa: op = 0xe9; break; /* cli -> jmp */
774 + case 0xfb: op = 0xe9; break; /* sti -> jmp */
775 + default: error("Internal error");
778 + " *(uint8_t *)(gen_code_ptr + %d) = 0x%x;\n",
779 + exit_addrs[i], op);
781 + /* Fix up the return instruction. */
782 + if (patch_bytes != -1) {
784 + fprintf(outfile, " memcpy(gen_code_ptr + %d,"
785 + "gen_code_ptr + %d, %d);\n",
786 + copy_size, retpos, patch_bytes);
789 + " *(uint8_t *)(gen_code_ptr + %d) = 0xe9;\n",
792 + " *(uint32_t *)(gen_code_ptr + %d) = 0x%x;\n",
793 + retpos + 1, copy_size - (retpos + 5));
795 + copy_size += patch_bytes;
799 + " *(uint16_t *)(gen_code_ptr + %d) = 0x9090;\n",
804 #elif defined(HOST_X86_64)
806 @@ -1793,6 +2455,42 @@ void gen_code(const char *name, host_ulo
810 + /* Replace the marker instructions with the actual opcodes. */
811 + for (i = 0; exit_addrs[i] != -1; i++) {
813 + switch (p_start[exit_addrs[i]])
815 + case 0xf4: op = 0xc3; break; /* hlt -> ret */
816 + case 0xfa: op = 0xe9; break; /* cli -> jmp */
817 + case 0xfb: op = 0xe9; break; /* sti -> jmp */
818 + default: error("Internal error");
821 + " *(uint8_t *)(gen_code_ptr + %d) = 0x%x;\n",
822 + exit_addrs[i], op);
824 + /* Fix up the return instruction. */
825 + if (patch_bytes != -1) {
827 + fprintf(outfile, " memcpy(gen_code_ptr + %d,"
828 + "gen_code_ptr + %d, %d);\n",
829 + copy_size, retpos, patch_bytes);
832 + " *(uint8_t *)(gen_code_ptr + %d) = 0xe9;\n",
835 + " *(uint32_t *)(gen_code_ptr + %d) = 0x%x;\n",
836 + retpos + 1, copy_size - (retpos + 5));
838 + copy_size += patch_bytes;
842 + " *(uint16_t *)(gen_code_ptr + %d) = 0x9090;\n",
847 #elif defined(HOST_PPC)
850 ===================================================================
851 RCS file: /cvsroot/qemu/qemu/exec-all.h,v
852 retrieving revision 1.31
853 diff -u -p -r1.31 exec-all.h
854 --- exec-all.h 2005-09-04 19:11:31.000000000 +0200
855 +++ exec-all.h 2005-09-06 03:16:54.000000000 +0200
856 @@ -338,14 +338,15 @@
858 #elif defined(__i386__) && defined(USE_DIRECT_JUMP)
860 -/* we patch the jump instruction directly */
861 +/* we patch the jump instruction directly. Use sti in place of the actual
862 + jmp instruction so that dyngen can patch in the correct result. */
863 #define GOTO_TB(opname, tbparam, n)\
865 asm volatile (".section .data\n"\
866 ASM_OP_LABEL_NAME(n, opname) ":\n"\
868 ASM_PREVIOUS_SECTION \
869 - "jmp " ASM_NAME(__op_jmp) #n "\n"\
870 + "sti;.long " ASM_NAME(__op_jmp) #n " - 1f\n"\
874 Index: target-ppc/exec.h
875 ===================================================================
876 RCS file: /cvsroot/qemu/qemu/target-ppc/exec.h,v
877 retrieving revision 1.10
878 diff -u -p -r1.10 exec.h
879 --- target-ppc/exec.h 13 Mar 2005 17:01:22 -0000 1.10
880 +++ target-ppc/exec.h 11 May 2005 20:38:35 -0000
881 @@ -33,11 +33,7 @@ register uint32_t T2 asm(AREG3);
882 #define FT1 (env->ft1)
883 #define FT2 (env->ft2)
885 -#if defined (DEBUG_OP)
886 -#define RETURN() __asm__ __volatile__("nop");
888 -#define RETURN() __asm__ __volatile__("");
890 +#define RETURN() FORCE_RET()
893 #include "exec-all.h"