render / rpms / qemu

Forked from rpms/qemu 7 months ago
Clone
David Woodhouse 66db2b
Index: dyngen-exec.h
David Woodhouse 66db2b
===================================================================
David Woodhouse 66db2b
RCS file: /cvsroot/qemu/qemu/dyngen-exec.h,v
David Woodhouse 66db2b
retrieving revision 1.25
David Woodhouse 66db2b
diff -u -p -r1.25 dyngen-exec.h
David Woodhouse 66db2b
--- dyngen-exec.h	24 Apr 2005 18:01:56 -0000	1.25
David Woodhouse 66db2b
+++ dyngen-exec.h	11 May 2005 20:38:33 -0000
David Woodhouse 66db2b
@@ -155,7 +155,12 @@ extern int printf(const char *, ...);
David Woodhouse 66db2b
 #endif
David Woodhouse 66db2b
 
David Woodhouse 66db2b
 /* force GCC to generate only one epilog at the end of the function */
David Woodhouse 66db2b
+#if defined(__i386__) || defined(__x86_64__)
David Woodhouse 66db2b
+/* Also add 4 bytes of padding so that we can replace the ret with a jmp.  */
David Woodhouse 66db2b
+#define FORCE_RET() asm volatile ("nop;nop;nop;nop");
David Woodhouse 66db2b
+#else
David Woodhouse 66db2b
 #define FORCE_RET() asm volatile ("");
David Woodhouse 66db2b
+#endif
David Woodhouse 66db2b
 
David Woodhouse 66db2b
 #ifndef OPPROTO
David Woodhouse 66db2b
 #define OPPROTO
David Woodhouse 66db2b
@@ -205,12 +210,19 @@ extern int __op_jmp0, __op_jmp1, __op_jm
David Woodhouse 66db2b
 #endif
David Woodhouse 66db2b
 
David Woodhouse 66db2b
 #ifdef __i386__
David Woodhouse 66db2b
-#define EXIT_TB() asm volatile ("ret")
David Woodhouse 66db2b
-#define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n)
David Woodhouse 66db2b
+/* Dyngen will replace hlt instructions with a ret instruction.  Inserting a
David Woodhouse 66db2b
+   ret directly would confuse dyngen.  */
David Woodhouse 66db2b
+#define EXIT_TB() asm volatile ("hlt")
David Woodhouse 66db2b
+/* Dyngen will replace cli with 0x9e (jmp). 
David Woodhouse 66db2b
+   We generate the offset manually.  */
David Woodhouse 66db2b
+#define GOTO_LABEL_PARAM(n) \
David Woodhouse 66db2b
+  asm volatile ("cli;.long " ASM_NAME(__op_gen_label) #n " - 1f;1:")
David Woodhouse 66db2b
 #endif
David Woodhouse 66db2b
 #ifdef __x86_64__
David Woodhouse 66db2b
-#define EXIT_TB() asm volatile ("ret")
David Woodhouse 66db2b
-#define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n)
David Woodhouse 66db2b
+/* The same as i386.  */
David Woodhouse 66db2b
+#define EXIT_TB() asm volatile ("hlt")
David Woodhouse 66db2b
+#define GOTO_LABEL_PARAM(n) \
David Woodhouse 66db2b
+  asm volatile ("cli;.long " ASM_NAME(__op_gen_label) #n " - 1f;1:")
David Woodhouse 66db2b
 #endif
David Woodhouse 66db2b
 #ifdef __powerpc__
David Woodhouse 66db2b
 #define EXIT_TB() asm volatile ("blr")
David Woodhouse 66db2b
Index: dyngen.c
David Woodhouse 66db2b
===================================================================
David Woodhouse 66db2b
RCS file: /cvsroot/qemu/qemu/dyngen.c,v
David Woodhouse 66db2b
retrieving revision 1.40
David Woodhouse 66db2b
diff -u -p -r1.40 dyngen.c
David Woodhouse 66db2b
--- dyngen.c	27 Apr 2005 19:55:58 -0000	1.40
David Woodhouse 66db2b
+++ dyngen.c	11 May 2005 20:38:33 -0000
David Woodhouse 66db2b
@@ -32,6 +32,8 @@
David Woodhouse 66db2b
 
David Woodhouse 66db2b
 #include "config-host.h"
David Woodhouse 66db2b
 
David Woodhouse 66db2b
+//#define DEBUG_OP
David Woodhouse 66db2b
+
David Woodhouse 66db2b
 /* NOTE: we test CONFIG_WIN32 instead of _WIN32 to enabled cross
David Woodhouse 66db2b
    compilation */
David Woodhouse 66db2b
 #if defined(CONFIG_WIN32)
David Woodhouse 66db2b
@@ -1343,6 +1345,639 @@ int arm_emit_ldr_info(const char *name, 
David Woodhouse 66db2b
 #endif
David Woodhouse 66db2b
 
David Woodhouse 66db2b
 
David Woodhouse 66db2b
+#if defined(HOST_I386) || defined(HOST_X86_64)
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+/* This byte is the first byte of an instruction.  */
David Woodhouse 66db2b
+#define FLAG_INSN     (1 << 0)
David Woodhouse 66db2b
+/* This byte has been processed as part of an instruction.  */
David Woodhouse 66db2b
+#define FLAG_SCANNED  (1 << 1)
David Woodhouse 66db2b
+/* This instruction is a return instruction.  Gcc cometimes generates prefix
David Woodhouse 66db2b
+   bytes, so may be more than one byte long.  */
David Woodhouse 66db2b
+#define FLAG_RET      (1 << 2)
David Woodhouse 66db2b
+/* This is either the target of a jump, or the preceeding instruction uses
David Woodhouse 66db2b
+   a pc-relative offset.  */
David Woodhouse 66db2b
+#define FLAG_TARGET   (1 << 3)
David Woodhouse 66db2b
+/* This is a magic instruction that needs fixing up.  */
David Woodhouse 66db2b
+#define FLAG_EXIT     (1 << 4)
David Woodhouse 66db2b
+#define MAX_EXITS     5
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+static void
David Woodhouse 66db2b
+bad_opcode(const char *name, uint32_t op)
David Woodhouse 66db2b
+{
David Woodhouse 66db2b
+    error("Unsupported opcode %0*x in %s", (op > 0xff) ? 4 : 2, op, name);
David Woodhouse 66db2b
+}
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+/* Mark len bytes as scanned,  Returns insn_size + len.  Reports an error
David Woodhouse 66db2b
+   if these bytes have already been scanned.  */
David Woodhouse 66db2b
+static int
David Woodhouse 66db2b
+eat_bytes(const char *name, char *flags, int insn, int insn_size, int len)
David Woodhouse 66db2b
+{
David Woodhouse 66db2b
+    while (len > 0) {
David Woodhouse 66db2b
+        /* This should never occur in sane code.  */
David Woodhouse 66db2b
+        if (flags[insn + insn_size] & FLAG_SCANNED)
David Woodhouse 66db2b
+            error ("Overlapping instructions in %s", name);
David Woodhouse 66db2b
+        flags[insn + insn_size] |= FLAG_SCANNED;
David Woodhouse 66db2b
+        insn_size++;
David Woodhouse 66db2b
+        len--;
David Woodhouse 66db2b
+    }
David Woodhouse 66db2b
+    return insn_size;
David Woodhouse 66db2b
+}
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+static void
David Woodhouse 66db2b
+trace_i386_insn (const char *name, uint8_t *start_p, char *flags, int insn,
David Woodhouse 66db2b
+                 int len)
David Woodhouse 66db2b
+{
David Woodhouse 66db2b
+    uint8_t *ptr;
David Woodhouse 66db2b
+    uint8_t op;
David Woodhouse 66db2b
+    int modrm;
David Woodhouse 66db2b
+    int is_prefix;
David Woodhouse 66db2b
+    int op_size;
David Woodhouse 66db2b
+    int addr_size;
David Woodhouse 66db2b
+    int insn_size;
David Woodhouse 66db2b
+    int is_ret;
David Woodhouse 66db2b
+    int is_condjmp;
David Woodhouse 66db2b
+    int is_jmp;
David Woodhouse 66db2b
+    int is_exit;
David Woodhouse 66db2b
+    int is_pcrel;
David Woodhouse 66db2b
+    int immed;
David Woodhouse 66db2b
+    int seen_rexw;
David Woodhouse 66db2b
+    int32_t disp;
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+    ptr = start_p + insn;
David Woodhouse 66db2b
+    /* nonzero if this insn has a ModR/M byte.  */
David Woodhouse 66db2b
+    modrm = 1;
David Woodhouse 66db2b
+    /* The size of the immediate value in this instruction.  */
David Woodhouse 66db2b
+    immed = 0;
David Woodhouse 66db2b
+    /* The operand size.  */
David Woodhouse 66db2b
+    op_size = 4;
David Woodhouse 66db2b
+    /* The address size */
David Woodhouse 66db2b
+    addr_size = 4;
David Woodhouse 66db2b
+    /* The total length of this instruction.  */
David Woodhouse 66db2b
+    insn_size = 0;
David Woodhouse 66db2b
+    is_prefix = 1;
David Woodhouse 66db2b
+    is_ret = 0;
David Woodhouse 66db2b
+    is_condjmp = 0;
David Woodhouse 66db2b
+    is_jmp = 0;
David Woodhouse 66db2b
+    is_exit = 0;
David Woodhouse 66db2b
+    seen_rexw = 0;
David Woodhouse 66db2b
+    is_pcrel = 0;
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+    while (is_prefix) {
David Woodhouse 66db2b
+        op = ptr[insn_size];
David Woodhouse 66db2b
+        insn_size = eat_bytes(name, flags, insn, insn_size, 1);
David Woodhouse 66db2b
+        is_prefix = 0;
David Woodhouse 66db2b
+        switch (op >> 4) {
David Woodhouse 66db2b
+        case 0:
David Woodhouse 66db2b
+        case 1:
David Woodhouse 66db2b
+        case 2:
David Woodhouse 66db2b
+        case 3:
David Woodhouse 66db2b
+            if (op == 0x0f) {
David Woodhouse 66db2b
+                /* two-byte opcode.  */
David Woodhouse 66db2b
+                op = ptr[insn_size];
David Woodhouse 66db2b
+                insn_size = eat_bytes(name, flags, insn, insn_size, 1);
David Woodhouse 66db2b
+                switch (op >> 4) {
David Woodhouse 66db2b
+                case 0:
David Woodhouse 66db2b
+                    if ((op & 0xf) > 3)
David Woodhouse 66db2b
+                      modrm = 0;
David Woodhouse 66db2b
+                    break;
David Woodhouse 66db2b
+                case 1: /* vector move or prefetch */
David Woodhouse 66db2b
+                case 2: /* various moves and vector compares.  */
David Woodhouse 66db2b
+                case 4: /* cmov */
David Woodhouse 66db2b
+                case 5: /* vector instructions */
David Woodhouse 66db2b
+                case 6:
David Woodhouse 66db2b
+                case 13:
David Woodhouse 66db2b
+                case 14:
David Woodhouse 66db2b
+                case 15:
David Woodhouse 66db2b
+                    break;
David Woodhouse 66db2b
+                case 7: /* mmx */
David Woodhouse 66db2b
+                    if (op & 0x77) /* emms */
David Woodhouse 66db2b
+                      modrm = 0;
David Woodhouse 66db2b
+                    break;
David Woodhouse 66db2b
+                case 3: /* wrmsr, rdtsc, rdmsr, rdpmc, sysenter, sysexit */
David Woodhouse 66db2b
+                    modrm = 0;
David Woodhouse 66db2b
+                    break;
David Woodhouse 66db2b
+                case 8: /* long conditional jump */
David Woodhouse 66db2b
+                    is_condjmp = 1;
David Woodhouse 66db2b
+                    immed = op_size;
David Woodhouse 66db2b
+                    modrm = 0;
David Woodhouse 66db2b
+                    break;
David Woodhouse 66db2b
+                case 9: /* setcc */
David Woodhouse 66db2b
+                    break;
David Woodhouse 66db2b
+                case 10:
David Woodhouse 66db2b
+                    switch (op & 0x7) {
David Woodhouse 66db2b
+                    case 0: /* push fs/gs */
David Woodhouse 66db2b
+                    case 1: /* pop fs/gs */
David Woodhouse 66db2b
+                    case 2: /* cpuid/rsm */
David Woodhouse 66db2b
+                        modrm = 0;
David Woodhouse 66db2b
+                        break;
David Woodhouse 66db2b
+                    case 4: /* shld/shrd immediate */
David Woodhouse 66db2b
+                        immed = 1;
David Woodhouse 66db2b
+                        break;
David Woodhouse 66db2b
+                    default: /* Normal instructions with a ModR/M byte.  */
David Woodhouse 66db2b
+                        break;
David Woodhouse 66db2b
+                    }
David Woodhouse 66db2b
+                    break;
David Woodhouse 66db2b
+                case 11:
David Woodhouse 66db2b
+                    switch (op & 0xf) {
David Woodhouse 66db2b
+                    case 10: /* bt, bts, btr, btc */
David Woodhouse 66db2b
+                        immed = 1;
David Woodhouse 66db2b
+                        break;
David Woodhouse 66db2b
+                    default:
David Woodhouse 66db2b
+                        /* cmpxchg, lss, btr, lfs, lgs, movzx, btc, bsf, bsr
David Woodhouse 66db2b
+                           undefined, and movsx */
David Woodhouse 66db2b
+                        break;
David Woodhouse 66db2b
+                    }
David Woodhouse 66db2b
+                    break;
David Woodhouse 66db2b
+                case 12:
David Woodhouse 66db2b
+                    if (op & 8) {
David Woodhouse 66db2b
+                        /* bswap */
David Woodhouse 66db2b
+                        modrm = 0;
David Woodhouse 66db2b
+                    } else {
David Woodhouse 66db2b
+                        switch (op & 0x7) {
David Woodhouse 66db2b
+                        case 2:
David Woodhouse 66db2b
+                        case 4:
David Woodhouse 66db2b
+                        case 5:
David Woodhouse 66db2b
+                        case 6:
David Woodhouse 66db2b
+                            immed = 1;
David Woodhouse 66db2b
+                            break;
David Woodhouse 66db2b
+                        default:
David Woodhouse 66db2b
+                            break;
David Woodhouse 66db2b
+                        }
David Woodhouse 66db2b
+                    }
David Woodhouse 66db2b
+                    break;
David Woodhouse 66db2b
+                }
David Woodhouse 66db2b
+            } else if ((op & 0x07) <= 0x3) {
David Woodhouse 66db2b
+                /* General arithmentic ax.  */
David Woodhouse 66db2b
+            } else if ((op & 0x07) <= 0x5) {
David Woodhouse 66db2b
+                /* General arithmetic ax, immediate.  */
David Woodhouse 66db2b
+                if (op & 0x01)
David Woodhouse 66db2b
+                    immed = op_size;
David Woodhouse 66db2b
+                else
David Woodhouse 66db2b
+                    immed = 1;
David Woodhouse 66db2b
+                modrm = 0;
David Woodhouse 66db2b
+            } else if ((op & 0x23) == 0x22) {
David Woodhouse 66db2b
+                /* Segment prefix.  */
David Woodhouse 66db2b
+                is_prefix = 1;
David Woodhouse 66db2b
+            } else {
David Woodhouse 66db2b
+                /* Segment register push/pop or DAA/AAA/DAS/AAS.  */
David Woodhouse 66db2b
+                modrm = 0;
David Woodhouse 66db2b
+            }
David Woodhouse 66db2b
+            break;
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+#if defined(HOST_X86_64)
David Woodhouse 66db2b
+        case 4: /* rex prefix.  */
David Woodhouse 66db2b
+            is_prefix = 1;
David Woodhouse 66db2b
+            /* The address/operand size is actually 64-bit, but the immediate
David Woodhouse 66db2b
+               values in the instruction are still 32-bit.  */
David Woodhouse 66db2b
+            op_size = 4;
David Woodhouse 66db2b
+            addr_size = 4;
David Woodhouse 66db2b
+            if (op & 8)
David Woodhouse 66db2b
+                seen_rexw = 1;
David Woodhouse 66db2b
+            break;
David Woodhouse 66db2b
+#else
David Woodhouse 66db2b
+        case 4: /* inc/dec register.  */
David Woodhouse 66db2b
+#endif
David Woodhouse 66db2b
+        case 5: /* push/pop general register.  */
David Woodhouse 66db2b
+            modrm = 0;
David Woodhouse 66db2b
+            break;
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+        case 6:
David Woodhouse 66db2b
+            switch (op & 0x0f) {
David Woodhouse 66db2b
+            case 0: /* pusha */
David Woodhouse 66db2b
+            case 1: /* popa */
David Woodhouse 66db2b
+                modrm = 0;
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            case 2: /* bound */
David Woodhouse 66db2b
+            case 3: /* arpl */
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            case 4: /* FS */
David Woodhouse 66db2b
+            case 5: /* GS */
David Woodhouse 66db2b
+                is_prefix = 1;
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            case 6: /* opcode size prefix.  */
David Woodhouse 66db2b
+                op_size = 2;
David Woodhouse 66db2b
+                is_prefix = 1;
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            case 7: /* Address size prefix.  */
David Woodhouse 66db2b
+                addr_size = 2;
David Woodhouse 66db2b
+                is_prefix = 1;
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            case 8: /* push immediate */
David Woodhouse 66db2b
+            case 10: /* pop immediate */
David Woodhouse 66db2b
+                immed = op_size;
David Woodhouse 66db2b
+                modrm = 0;
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            case 9: /* imul immediate */
David Woodhouse 66db2b
+            case 11: /* imul immediate */
David Woodhouse 66db2b
+                immed = op_size;
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            case 12: /* insb */
David Woodhouse 66db2b
+            case 13: /* insw */
David Woodhouse 66db2b
+            case 14: /* outsb */
David Woodhouse 66db2b
+            case 15: /* outsw */
David Woodhouse 66db2b
+                modrm = 0;
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            }
David Woodhouse 66db2b
+            break;
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+        case 7: /* Short conditional jump.  */
David Woodhouse 66db2b
+            is_condjmp = 1;
David Woodhouse 66db2b
+            immed = 1;
David Woodhouse 66db2b
+            modrm = 0;
David Woodhouse 66db2b
+            break;
David Woodhouse 66db2b
+          
David Woodhouse 66db2b
+        case 8:
David Woodhouse 66db2b
+            if ((op & 0xf) <= 3) {
David Woodhouse 66db2b
+                /* arithmetic immediate.  */
David Woodhouse 66db2b
+                if ((op & 3) == 1)
David Woodhouse 66db2b
+                    immed = op_size;
David Woodhouse 66db2b
+                else
David Woodhouse 66db2b
+                    immed = 1;
David Woodhouse 66db2b
+            }
David Woodhouse 66db2b
+            /* else test, xchg, mov, lea or pop general.  */
David Woodhouse 66db2b
+            break;
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+        case 9:
David Woodhouse 66db2b
+            /* Various single-byte opcodes with no modrm byte.  */
David Woodhouse 66db2b
+            modrm = 0;
David Woodhouse 66db2b
+            if (op == 10) {
David Woodhouse 66db2b
+                /* Call */
David Woodhouse 66db2b
+                immed = 4;
David Woodhouse 66db2b
+            }
David Woodhouse 66db2b
+            break;
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+        case 10:
David Woodhouse 66db2b
+            switch ((op & 0xe) >> 1) {
David Woodhouse 66db2b
+            case 0: /* mov absoliute immediate.  */
David Woodhouse 66db2b
+            case 1:
David Woodhouse 66db2b
+                if (seen_rexw)
David Woodhouse 66db2b
+                    immed = 8;
David Woodhouse 66db2b
+                else
David Woodhouse 66db2b
+                    immed = addr_size;
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            case 4: /* test immediate.  */
David Woodhouse 66db2b
+                if (op & 1)
David Woodhouse 66db2b
+                    immed = op_size;
David Woodhouse 66db2b
+                else
David Woodhouse 66db2b
+                    immed = 1;
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            default: /* Various string ops.  */
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            }
David Woodhouse 66db2b
+            modrm = 0;
David Woodhouse 66db2b
+            break;
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+        case 11: /* move immediate to register */
David Woodhouse 66db2b
+            if (op & 8) {
David Woodhouse 66db2b
+                if (seen_rexw)
David Woodhouse 66db2b
+                    immed = 8;
David Woodhouse 66db2b
+                else
David Woodhouse 66db2b
+                    immed = op_size;
David Woodhouse 66db2b
+            } else {
David Woodhouse 66db2b
+                immed = 1;
David Woodhouse 66db2b
+            }
David Woodhouse 66db2b
+            modrm = 0;
David Woodhouse 66db2b
+            break;
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+          case 12:
David Woodhouse 66db2b
+            switch (op & 0xf) {
David Woodhouse 66db2b
+            case 0: /* shift immediate */
David Woodhouse 66db2b
+            case 1:
David Woodhouse 66db2b
+                immed = 1;
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            case 2: /* ret immediate */
David Woodhouse 66db2b
+                immed = 2;
David Woodhouse 66db2b
+                modrm = 0;
David Woodhouse 66db2b
+                bad_opcode(name, op);
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            case 3: /* ret */
David Woodhouse 66db2b
+                modrm = 0;
David Woodhouse 66db2b
+                is_ret = 1;
David Woodhouse 66db2b
+            case 4: /* les */
David Woodhouse 66db2b
+            case 5: /* lds */
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            case 6: /* mov immediate byte */
David Woodhouse 66db2b
+                immed = 1;
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            case 7: /* mov immediate */
David Woodhouse 66db2b
+                immed = op_size;
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            case 8: /* enter */
David Woodhouse 66db2b
+                /* TODO: Is this right?  */
David Woodhouse 66db2b
+                immed = 3;
David Woodhouse 66db2b
+                modrm = 0;
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            case 10: /* retf immediate */
David Woodhouse 66db2b
+                immed = 2;
David Woodhouse 66db2b
+                modrm = 0;
David Woodhouse 66db2b
+                bad_opcode(name, op);
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            case 13: /* int */
David Woodhouse 66db2b
+                immed = 1;
David Woodhouse 66db2b
+                modrm = 0;
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            case 11: /* retf */
David Woodhouse 66db2b
+            case 15: /* iret */
David Woodhouse 66db2b
+                modrm = 0;
David Woodhouse 66db2b
+                bad_opcode(name, op);
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            default: /* leave, int3 or into */
David Woodhouse 66db2b
+                modrm = 0;
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            }
David Woodhouse 66db2b
+            break;
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+        case 13:
David Woodhouse 66db2b
+            if ((op & 0xf) >= 8) {
David Woodhouse 66db2b
+                /* Coprocessor escape.  For our purposes this is just a normal
David Woodhouse 66db2b
+                   instruction with a ModR/M byte.  */
David Woodhouse 66db2b
+            } else if ((op & 0xf) >= 4) {
David Woodhouse 66db2b
+                /* AAM, AAD or XLAT */
David Woodhouse 66db2b
+                modrm = 0;
David Woodhouse 66db2b
+            }
David Woodhouse 66db2b
+            /* else shift instruction */
David Woodhouse 66db2b
+            break;
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+        case 14:
David Woodhouse 66db2b
+            switch ((op & 0xc) >> 2) {
David Woodhouse 66db2b
+            case 0: /* loop or jcxz */
David Woodhouse 66db2b
+                is_condjmp = 1;
David Woodhouse 66db2b
+                immed = 1;
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            case 1: /* in/out immed */
David Woodhouse 66db2b
+                immed = 1;
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            case 2: /* call or jmp */
David Woodhouse 66db2b
+                switch (op & 3) {
David Woodhouse 66db2b
+                case 0: /* call */
David Woodhouse 66db2b
+                    immed = op_size;
David Woodhouse 66db2b
+                    break;
David Woodhouse 66db2b
+                case 1: /* long jump */
David Woodhouse 66db2b
+                    immed = 4;
David Woodhouse 66db2b
+                    is_jmp = 1;
David Woodhouse 66db2b
+                    break;
David Woodhouse 66db2b
+                case 2: /* far jmp */
David Woodhouse 66db2b
+                    bad_opcode(name, op);
David Woodhouse 66db2b
+                    break;
David Woodhouse 66db2b
+                case 3: /* short jmp */
David Woodhouse 66db2b
+                    immed = 1;
David Woodhouse 66db2b
+                    is_jmp = 1;
David Woodhouse 66db2b
+                    break;
David Woodhouse 66db2b
+                }
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            case 3: /* in/out register */
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            }
David Woodhouse 66db2b
+            modrm = 0;
David Woodhouse 66db2b
+            break;
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+        case 15:
David Woodhouse 66db2b
+            switch ((op & 0xe) >> 1) {
David Woodhouse 66db2b
+            case 0:
David Woodhouse 66db2b
+            case 1:
David Woodhouse 66db2b
+                is_prefix = 1;
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            case 2:
David Woodhouse 66db2b
+            case 4:
David Woodhouse 66db2b
+            case 5:
David Woodhouse 66db2b
+            case 6:
David Woodhouse 66db2b
+                modrm = 0;
David Woodhouse 66db2b
+                /* Some privileged insns are used as markers.  */
David Woodhouse 66db2b
+                switch (op) {
David Woodhouse 66db2b
+                case 0xf4: /* hlt: Exit translation block.  */
David Woodhouse 66db2b
+                    is_exit = 1;
David Woodhouse 66db2b
+                    break;
David Woodhouse 66db2b
+                case 0xfa: /* cli: Jump to label.  */
David Woodhouse 66db2b
+                    is_exit = 1;
David Woodhouse 66db2b
+                    immed = 4;
David Woodhouse 66db2b
+                    break;
David Woodhouse 66db2b
+                case 0xfb: /* sti: TB patch jump.  */
David Woodhouse 66db2b
+                    /* Mark the insn for patching, but continue sscanning.  */
David Woodhouse 66db2b
+                    flags[insn] |= FLAG_EXIT;
David Woodhouse 66db2b
+                    immed = 4;
David Woodhouse 66db2b
+                    break;
David Woodhouse 66db2b
+                }
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            case 3: /* unary grp3 */
David Woodhouse 66db2b
+                if ((ptr[insn_size] & 0x38) == 0) {
David Woodhouse 66db2b
+                    if (op == 0xf7)
David Woodhouse 66db2b
+                        immed = op_size;
David Woodhouse 66db2b
+                    else
David Woodhouse 66db2b
+                        immed = 1; /* test immediate */
David Woodhouse 66db2b
+                }
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            case 7: /* inc/dec grp4/5 */
David Woodhouse 66db2b
+                /* TODO: This includes indirect jumps.  We should fail if we
David Woodhouse 66db2b
+                   encounter one of these. */
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            }
David Woodhouse 66db2b
+            break;
David Woodhouse 66db2b
+        }
David Woodhouse 66db2b
+    }
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+    if (modrm) {
David Woodhouse 66db2b
+        if (addr_size != 4)
David Woodhouse 66db2b
+            error("16-bit addressing mode used in %s", name);
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+        disp = 0;
David Woodhouse 66db2b
+        modrm = ptr[insn_size];
David Woodhouse 66db2b
+        insn_size = eat_bytes(name, flags, insn, insn_size, 1);
David Woodhouse 66db2b
+        modrm &= 0xc7;
David Woodhouse 66db2b
+        switch ((modrm & 0xc0) >> 6) {
David Woodhouse 66db2b
+        case 0:
David Woodhouse 66db2b
+            if (modrm == 5)
David Woodhouse 66db2b
+              disp = 4;
David Woodhouse 66db2b
+            break;
David Woodhouse 66db2b
+        case 1:
David Woodhouse 66db2b
+            disp = 1;
David Woodhouse 66db2b
+            break;
David Woodhouse 66db2b
+        case 2:
David Woodhouse 66db2b
+            disp = 4;
David Woodhouse 66db2b
+            break;
David Woodhouse 66db2b
+        }
David Woodhouse 66db2b
+        if ((modrm & 0xc0) != 0xc0 && (modrm & 0x7) == 4) {
David Woodhouse 66db2b
+            /* SIB byte */
David Woodhouse 66db2b
+            if (modrm == 4 && (ptr[insn_size] & 0x7) == 5) {
David Woodhouse 66db2b
+                disp = 4;
David Woodhouse 66db2b
+                is_pcrel = 1;
David Woodhouse 66db2b
+            }
David Woodhouse 66db2b
+            insn_size = eat_bytes(name, flags, insn, insn_size, 1);
David Woodhouse 66db2b
+        }
David Woodhouse 66db2b
+        insn_size = eat_bytes(name, flags, insn, insn_size, disp);
David Woodhouse 66db2b
+    }
David Woodhouse 66db2b
+    insn_size = eat_bytes(name, flags, insn, insn_size, immed);
David Woodhouse 66db2b
+    if (is_condjmp || is_jmp) {
David Woodhouse 66db2b
+        if (immed == 1) {
David Woodhouse 66db2b
+            disp = (int8_t)*(ptr + insn_size - 1);
David Woodhouse 66db2b
+        } else {
David Woodhouse 66db2b
+            disp = (((int32_t)*(ptr + insn_size - 1)) << 24)
David Woodhouse 66db2b
+                   | (((int32_t)*(ptr + insn_size - 2)) << 16)
David Woodhouse 66db2b
+                   | (((int32_t)*(ptr + insn_size - 3)) << 8)
David Woodhouse 66db2b
+                   | *(ptr + insn_size - 4);
David Woodhouse 66db2b
+        }
David Woodhouse 66db2b
+        disp += insn_size;
David Woodhouse 66db2b
+        /* Jumps to external symbols point to the address of the offset
David Woodhouse 66db2b
+           before relocation.  */
David Woodhouse 66db2b
+        /* ??? These are probably a tailcall.  We could fix them up by
David Woodhouse 66db2b
+           replacing them with jmp to EOB + call, but it's easier to just
David Woodhouse 66db2b
+           prevent the compiler generating them.  */
David Woodhouse 66db2b
+        if (disp == 1)
David Woodhouse 66db2b
+            error("Unconditional jump (sibcall?) in %s", name);
David Woodhouse 66db2b
+        disp += insn;
David Woodhouse 66db2b
+        if (disp < 0 || disp > len)
David Woodhouse 66db2b
+            error("Jump outside instruction in %s", name);
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+        if ((flags[disp] & (FLAG_INSN | FLAG_SCANNED)) == FLAG_SCANNED)
David Woodhouse 66db2b
+            error("Overlapping instructions in %s", name);
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+        flags[disp] |= (FLAG_INSN | FLAG_TARGET);
David Woodhouse 66db2b
+        is_pcrel = 1; 
David Woodhouse 66db2b
+    }
David Woodhouse 66db2b
+    if (is_pcrel) {
David Woodhouse 66db2b
+        /* Mark the following insn as a jump target.  This will stop
David Woodhouse 66db2b
+           this instruction being moved.  */
David Woodhouse 66db2b
+        flags[insn + insn_size] |= FLAG_TARGET;
David Woodhouse 66db2b
+    }
David Woodhouse 66db2b
+    if (is_ret)
David Woodhouse 66db2b
+      flags[insn] |= FLAG_RET;
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+    if (is_exit)
David Woodhouse 66db2b
+      flags[insn] |= FLAG_EXIT;
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+    if (!(is_jmp || is_ret || is_exit))
David Woodhouse 66db2b
+      flags[insn + insn_size] |= FLAG_INSN;
David Woodhouse 66db2b
+}
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+/* Scan a function body.  Returns the position of the return sequence.
David Woodhouse 66db2b
+   Sets *patch_bytes to the number of bytes that need to be copied from that
David Woodhouse 66db2b
+   location.  If no patching is required (ie. the return is the last insn)
David Woodhouse 66db2b
+   *patch_bytes will be set to -1.  *plen is the number of code bytes to copy.
David Woodhouse 66db2b
+ */
David Woodhouse 66db2b
+static int trace_i386_op(const char * name, uint8_t *start_p, int *plen,
David Woodhouse 66db2b
+                         int *patch_bytes, int *exit_addrs)
David Woodhouse 66db2b
+{
David Woodhouse 66db2b
+    char *flags;
David Woodhouse 66db2b
+    int more;
David Woodhouse 66db2b
+    int insn;
David Woodhouse 66db2b
+    int retpos;
David Woodhouse 66db2b
+    int bytes;
David Woodhouse 66db2b
+    int num_exits;
David Woodhouse 66db2b
+    int len;
David Woodhouse 66db2b
+    int last_insn;
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+    len = *plen;
David Woodhouse 66db2b
+    flags = malloc(len + 1);
David Woodhouse 66db2b
+    memset(flags, 0, len + 1);
David Woodhouse 66db2b
+    flags[0] |= FLAG_INSN;
David Woodhouse 66db2b
+    more = 1;
David Woodhouse 66db2b
+    while (more) {
David Woodhouse 66db2b
+        more = 0;
David Woodhouse 66db2b
+        for (insn = 0; insn < len; insn++) {
David Woodhouse 66db2b
+            if ((flags[insn] & (FLAG_INSN | FLAG_SCANNED)) == FLAG_INSN) {
David Woodhouse 66db2b
+                trace_i386_insn(name, start_p, flags, insn, len);
David Woodhouse 66db2b
+                more = 1;
David Woodhouse 66db2b
+            }
David Woodhouse 66db2b
+        }
David Woodhouse 66db2b
+    }
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+    /* Strip any unused code at the end of the function.  */
David Woodhouse 66db2b
+    while (len > 0 && flags[len - 1] == 0)
David Woodhouse 66db2b
+      len--;
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+    retpos = -1;
David Woodhouse 66db2b
+    num_exits = 0;
David Woodhouse 66db2b
+    last_insn = 0;
David Woodhouse 66db2b
+    for (insn = 0; insn < len; insn++) {
David Woodhouse 66db2b
+        if (flags[insn] & FLAG_RET) {
David Woodhouse 66db2b
+            /* ??? In theory it should be possible to handle multiple return
David Woodhouse 66db2b
+               points.  In practice it's not worth the effort.  */
David Woodhouse 66db2b
+            if (retpos != -1)
David Woodhouse 66db2b
+                error("Multiple return instructions in %s", name);
David Woodhouse 66db2b
+            retpos = insn;
David Woodhouse 66db2b
+        }
David Woodhouse 66db2b
+        if (flags[insn] & FLAG_EXIT) {
David Woodhouse 66db2b
+            if (num_exits == MAX_EXITS)
David Woodhouse 66db2b
+                error("Too many block exits in %s", name);
David Woodhouse 66db2b
+            exit_addrs[num_exits] = insn;
David Woodhouse 66db2b
+            num_exits++;
David Woodhouse 66db2b
+        }
David Woodhouse 66db2b
+        if (flags[insn] & FLAG_INSN)
David Woodhouse 66db2b
+            last_insn = insn;
David Woodhouse 66db2b
+    }
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+    exit_addrs[num_exits] = -1;
David Woodhouse 66db2b
+    if (retpos == -1) {
David Woodhouse 66db2b
+        if (num_exits == 0) {
David Woodhouse 66db2b
+            error ("No return instruction found in %s", name);
David Woodhouse 66db2b
+        } else {
David Woodhouse 66db2b
+            retpos = len;
David Woodhouse 66db2b
+            last_insn = len;
David Woodhouse 66db2b
+        }
David Woodhouse 66db2b
+    }
David Woodhouse 66db2b
+    
David Woodhouse 66db2b
+    /* If the return instruction is the last instruction we can just 
David Woodhouse 66db2b
+       remove it.  */
David Woodhouse 66db2b
+    if (retpos == last_insn)
David Woodhouse 66db2b
+        *patch_bytes = -1;
David Woodhouse 66db2b
+    else
David Woodhouse 66db2b
+        *patch_bytes = 0;
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+    /* Back up over any nop instructions.  */
David Woodhouse 66db2b
+    while (retpos > 0
David Woodhouse 66db2b
+           && (flags[retpos] & FLAG_TARGET) == 0
David Woodhouse 66db2b
+           && (flags[retpos - 1] & FLAG_INSN) != 0
David Woodhouse 66db2b
+           && start_p[retpos - 1] == 0x90) {
David Woodhouse 66db2b
+        retpos--;
David Woodhouse 66db2b
+    }
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+    if (*patch_bytes == -1) {
David Woodhouse 66db2b
+        *plen = retpos;
David Woodhouse 66db2b
+        free (flags);
David Woodhouse 66db2b
+        return retpos;
David Woodhouse 66db2b
+    }
David Woodhouse 66db2b
+    *plen = len;
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+    /* The ret is in the middle of the function.  Find four more bytes that
David Woodhouse 66db2b
+       so the ret can be replaced by a jmp. */
David Woodhouse 66db2b
+    /* ??? Use a short jump where possible. */
David Woodhouse 66db2b
+    bytes = 4;
David Woodhouse 66db2b
+    insn = retpos + 1;
David Woodhouse 66db2b
+    /* We can clobber everything up to the next jump target.  */
David Woodhouse 66db2b
+    while (insn < len && bytes > 0 && (flags[insn] & FLAG_TARGET) == 0) {
David Woodhouse 66db2b
+        insn++;
David Woodhouse 66db2b
+        bytes--;
David Woodhouse 66db2b
+    }
David Woodhouse 66db2b
+    if (bytes > 0) {
David Woodhouse 66db2b
+        /* ???: Strip out nop blocks.  */
David Woodhouse 66db2b
+        /* We can't do the replacement without clobbering anything important.
David Woodhouse 66db2b
+           Copy preceeding instructions(s) to give us some space.  */
David Woodhouse 66db2b
+        while (retpos > 0) {
David Woodhouse 66db2b
+            /* If this byte is the target of a jmp we can't move it.  */
David Woodhouse 66db2b
+            if (flags[retpos] & FLAG_TARGET)
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+            (*patch_bytes)++;
David Woodhouse 66db2b
+            bytes--;
David Woodhouse 66db2b
+            retpos--;
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+            /* Break out of the loop if we have enough space and this is either 
David Woodhouse 66db2b
+               the first byte of an instruction or a pad byte.  */
David Woodhouse 66db2b
+            if ((flags[retpos] & (FLAG_INSN | FLAG_SCANNED)) != FLAG_SCANNED
David Woodhouse 66db2b
+                && bytes <= 0) {
David Woodhouse 66db2b
+                break;
David Woodhouse 66db2b
+            }
David Woodhouse 66db2b
+        }
David Woodhouse 66db2b
+    }
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+    if (bytes > 0)
David Woodhouse 66db2b
+        error("Unable to replace ret with jmp in %s\n", name);
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+    free(flags);
David Woodhouse 66db2b
+    return retpos;
David Woodhouse 66db2b
+}
David Woodhouse 66db2b
+
David Woodhouse 66db2b
+#endif
David Woodhouse 66db2b
+
David Woodhouse 66db2b
 #define MAX_ARGS 3
David Woodhouse 66db2b
 
David Woodhouse 66db2b
 /* generate op code */
David Woodhouse 66db2b
@@ -1356,6 +1991,11 @@ void gen_code(const char *name, host_ulo
David Woodhouse 66db2b
     uint8_t args_present[MAX_ARGS];
David Woodhouse 66db2b
     const char *sym_name, *p;
David Woodhouse 66db2b
     EXE_RELOC *rel;
David Woodhouse 66db2b
+#if defined(HOST_I386) || defined(HOST_X86_64)
David Woodhouse 66db2b
+    int patch_bytes;
David Woodhouse 66db2b
+    int retpos;
David Woodhouse 66db2b
+    int exit_addrs[MAX_EXITS];
David Woodhouse 66db2b
+#endif
David Woodhouse 66db2b
 
David Woodhouse 66db2b
     /* Compute exact size excluding prologue and epilogue instructions.
David Woodhouse 66db2b
      * Increment start_offset to skip epilogue instructions, then compute
David Woodhouse 66db2b
@@ -1366,33 +2006,12 @@ void gen_code(const char *name, host_ulo
David Woodhouse 66db2b
     p_end = p_start + size;
David Woodhouse 66db2b
     start_offset = offset;
David Woodhouse 66db2b
 #if defined(HOST_I386) || defined(HOST_X86_64)
David Woodhouse 66db2b
-#ifdef CONFIG_FORMAT_COFF
David Woodhouse 66db2b
-    {
David Woodhouse 66db2b
-        uint8_t *p;
David Woodhouse 66db2b
-        p = p_end - 1;
David Woodhouse 66db2b
-        if (p == p_start)
David Woodhouse 66db2b
-            error("empty code for %s", name);
David Woodhouse 66db2b
-        while (*p != 0xc3) {
David Woodhouse 66db2b
-            p--;
David Woodhouse 66db2b
-            if (p <= p_start)
David Woodhouse 66db2b
-                error("ret or jmp expected at the end of %s", name);
David Woodhouse 66db2b
-        }
David Woodhouse 66db2b
-        copy_size = p - p_start;
David Woodhouse 66db2b
-    }
David Woodhouse 66db2b
-#else
David Woodhouse 66db2b
     {
David Woodhouse 66db2b
         int len;
David Woodhouse 66db2b
         len = p_end - p_start;
David Woodhouse 66db2b
-        if (len == 0)
David Woodhouse 66db2b
-            error("empty code for %s", name);
David Woodhouse 66db2b
-        if (p_end[-1] == 0xc3) {
David Woodhouse 66db2b
-            len--;
David Woodhouse 66db2b
-        } else {
David Woodhouse 66db2b
-            error("ret or jmp expected at the end of %s", name);
David Woodhouse 66db2b
-        }
David Woodhouse 66db2b
+        retpos = trace_i386_op(name, p_start, &len, &patch_bytes, exit_addrs);
David Woodhouse 66db2b
         copy_size = len;
David Woodhouse 66db2b
     }
David Woodhouse 66db2b
-#endif    
David Woodhouse 66db2b
 #elif defined(HOST_PPC)
David Woodhouse 66db2b
     {
David Woodhouse 66db2b
         uint8_t *p;
David Woodhouse 66db2b
@@ -1559,6 +2178,13 @@ void gen_code(const char *name, host_ulo
David Woodhouse 66db2b
     }
David Woodhouse 66db2b
 
David Woodhouse 66db2b
     if (gen_switch == 2) {
David Woodhouse 66db2b
+#if defined(HOST_I386) || defined(HOST_X86_64)
David Woodhouse 66db2b
+        if (patch_bytes != -1)
David Woodhouse 66db2b
+            copy_size += patch_bytes;
David Woodhouse 66db2b
+#ifdef DEBUG_OP
David Woodhouse 66db2b
+        copy_size += 2;
David Woodhouse 66db2b
+#endif
David Woodhouse 66db2b
+#endif
David Woodhouse 66db2b
         fprintf(outfile, "DEF(%s, %d, %d)\n", name + 3, nb_args, copy_size);
David Woodhouse 66db2b
     } else if (gen_switch == 1) {
David Woodhouse 66db2b
 
David Woodhouse 66db2b
@@ -1761,7 +2387,43 @@ void gen_code(const char *name, host_ulo
David Woodhouse 66db2b
 #error unsupport object format
David Woodhouse 66db2b
 #endif
David Woodhouse 66db2b
                 }
David Woodhouse 66db2b
+		}
David Woodhouse 66db2b
+                /* Replace the marker instructions with the actual opcodes.  */
David Woodhouse 66db2b
+                for (i = 0; exit_addrs[i] != -1; i++) {
David Woodhouse 66db2b
+                    int op;
David Woodhouse 66db2b
+                    switch (p_start[exit_addrs[i]])
David Woodhouse 66db2b
+                      {
David Woodhouse 66db2b
+                      case 0xf4: op = 0xc3; break; /* hlt -> ret */
David Woodhouse 66db2b
+                      case 0xfa: op = 0xe9; break; /* cli -> jmp */
David Woodhouse 66db2b
+                      case 0xfb: op = 0xe9; break; /* sti -> jmp */
David Woodhouse 66db2b
+                      default: error("Internal error");
David Woodhouse 66db2b
+                      }
David Woodhouse 66db2b
+                    fprintf(outfile, 
David Woodhouse 66db2b
+                            "    *(uint8_t *)(gen_code_ptr + %d) = 0x%x;\n",
David Woodhouse 66db2b
+                            exit_addrs[i], op);
David Woodhouse 66db2b
+                }
David Woodhouse 66db2b
+                /* Fix up the return instruction.  */
David Woodhouse 66db2b
+                if (patch_bytes != -1) {
David Woodhouse 66db2b
+                    if (patch_bytes) {
David Woodhouse 66db2b
+                        fprintf(outfile, "    memcpy(gen_code_ptr + %d,"
David Woodhouse 66db2b
+                                "gen_code_ptr + %d, %d);\n",
David Woodhouse 66db2b
+                                copy_size, retpos, patch_bytes);
David Woodhouse 66db2b
+                    }
David Woodhouse 66db2b
+                    fprintf(outfile,
David Woodhouse 66db2b
+                            "    *(uint8_t *)(gen_code_ptr + %d) = 0xe9;\n",
David Woodhouse 66db2b
+                            retpos);
David Woodhouse 66db2b
+                    fprintf(outfile,
David Woodhouse 66db2b
+                            "    *(uint32_t *)(gen_code_ptr + %d) = 0x%x;\n",
David Woodhouse 66db2b
+                            retpos + 1, copy_size - (retpos + 5));
David Woodhouse 66db2b
+                    
David Woodhouse 66db2b
+                    copy_size += patch_bytes;
David Woodhouse 66db2b
                 }
David Woodhouse 66db2b
+#ifdef DEBUG_OP
David Woodhouse 66db2b
+                fprintf(outfile,
David Woodhouse 66db2b
+                        "    *(uint16_t *)(gen_code_ptr + %d) = 0x9090;\n",
David Woodhouse 66db2b
+                        copy_size);
David Woodhouse 66db2b
+                copy_size += 2;
David Woodhouse 66db2b
+#endif
David Woodhouse 66db2b
             }
David Woodhouse 66db2b
 #elif defined(HOST_X86_64)
David Woodhouse 66db2b
             {
David Woodhouse 66db2b
@@ -1793,6 +2455,42 @@ void gen_code(const char *name, host_ulo
David Woodhouse 66db2b
                     }
David Woodhouse 66db2b
                 }
David Woodhouse 66db2b
                 }
David Woodhouse 66db2b
+                /* Replace the marker instructions with the actual opcodes.  */
David Woodhouse 66db2b
+                for (i = 0; exit_addrs[i] != -1; i++) {
David Woodhouse 66db2b
+                    int op;
David Woodhouse 66db2b
+                    switch (p_start[exit_addrs[i]])
David Woodhouse 66db2b
+                      {
David Woodhouse 66db2b
+                      case 0xf4: op = 0xc3; break; /* hlt -> ret */
David Woodhouse 66db2b
+                      case 0xfa: op = 0xe9; break; /* cli -> jmp */
David Woodhouse 66db2b
+                      case 0xfb: op = 0xe9; break; /* sti -> jmp */
David Woodhouse 66db2b
+                      default: error("Internal error");
David Woodhouse 66db2b
+                      }
David Woodhouse 66db2b
+                    fprintf(outfile, 
David Woodhouse 66db2b
+                            "    *(uint8_t *)(gen_code_ptr + %d) = 0x%x;\n",
David Woodhouse 66db2b
+                            exit_addrs[i], op);
David Woodhouse 66db2b
+                }
David Woodhouse 66db2b
+                /* Fix up the return instruction.  */
David Woodhouse 66db2b
+                if (patch_bytes != -1) {
David Woodhouse 66db2b
+                    if (patch_bytes) {
David Woodhouse 66db2b
+                        fprintf(outfile, "    memcpy(gen_code_ptr + %d,"
David Woodhouse 66db2b
+                                "gen_code_ptr + %d, %d);\n",
David Woodhouse 66db2b
+                                copy_size, retpos, patch_bytes);
David Woodhouse 66db2b
+                    }
David Woodhouse 66db2b
+                    fprintf(outfile,
David Woodhouse 66db2b
+                            "    *(uint8_t *)(gen_code_ptr + %d) = 0xe9;\n",
David Woodhouse 66db2b
+                            retpos);
David Woodhouse 66db2b
+                    fprintf(outfile,
David Woodhouse 66db2b
+                            "    *(uint32_t *)(gen_code_ptr + %d) = 0x%x;\n",
David Woodhouse 66db2b
+                            retpos + 1, copy_size - (retpos + 5));
David Woodhouse 66db2b
+                    
David Woodhouse 66db2b
+                    copy_size += patch_bytes;
David Woodhouse 66db2b
+                }
David Woodhouse 66db2b
+#ifdef DEBUG_OP
David Woodhouse 66db2b
+                fprintf(outfile,
David Woodhouse 66db2b
+                        "    *(uint16_t *)(gen_code_ptr + %d) = 0x9090;\n",
David Woodhouse 66db2b
+                        copy_size);
David Woodhouse 66db2b
+                copy_size += 2;
David Woodhouse 66db2b
+#endif
David Woodhouse 66db2b
             }
David Woodhouse 66db2b
 #elif defined(HOST_PPC)
David Woodhouse 66db2b
             {
David Woodhouse 66db2b
Index: exec-all.h
David Woodhouse 66db2b
===================================================================
David Woodhouse 66db2b
RCS file: /cvsroot/qemu/qemu/exec-all.h,v
David Woodhouse 66db2b
retrieving revision 1.31
David Woodhouse 66db2b
diff -u -p -r1.31 exec-all.h
David Woodhouse 66db2b
--- exec-all.h	17 Apr 2005 18:32:14 -0000	1.31
David Woodhouse 66db2b
+++ exec-all.h	11 May 2005 20:38:33 -0000
David Woodhouse 66db2b
@@ -335,14 +335,15 @@ do {\
David Woodhouse 66db2b
 
David Woodhouse 66db2b
 #elif defined(__i386__) && defined(USE_DIRECT_JUMP)
David Woodhouse 66db2b
 
David Woodhouse 66db2b
-/* we patch the jump instruction directly */
David Woodhouse 66db2b
+/* we patch the jump instruction directly.  Use sti in place of the actual
David Woodhouse 66db2b
+   jmp instruction so that dyngen can patch in the correct result.  */
David Woodhouse 66db2b
 #define GOTO_TB(opname, tbparam, n)\
David Woodhouse 66db2b
 do {\
David Woodhouse 66db2b
     asm volatile (".section .data\n"\
David Woodhouse 66db2b
 		  ASM_NAME(__op_label) #n "." ASM_NAME(opname) ":\n"\
David Woodhouse 66db2b
 		  ".long 1f\n"\
David Woodhouse 66db2b
 		  ASM_PREVIOUS_SECTION \
David Woodhouse 66db2b
-                  "jmp " ASM_NAME(__op_jmp) #n "\n"\
David Woodhouse 66db2b
+                  "sti;.long " ASM_NAME(__op_jmp) #n " - 1f\n"\
David Woodhouse 66db2b
 		  "1:\n");\
David Woodhouse 66db2b
 } while (0)
David Woodhouse 66db2b
 
David Woodhouse 66db2b
Index: target-ppc/exec.h
David Woodhouse 66db2b
===================================================================
David Woodhouse 66db2b
RCS file: /cvsroot/qemu/qemu/target-ppc/exec.h,v
David Woodhouse 66db2b
retrieving revision 1.10
David Woodhouse 66db2b
diff -u -p -r1.10 exec.h
David Woodhouse 66db2b
--- target-ppc/exec.h	13 Mar 2005 17:01:22 -0000	1.10
David Woodhouse 66db2b
+++ target-ppc/exec.h	11 May 2005 20:38:35 -0000
David Woodhouse 66db2b
@@ -33,11 +33,7 @@ register uint32_t T2 asm(AREG3);
David Woodhouse 66db2b
 #define FT1 (env->ft1)
David Woodhouse 66db2b
 #define FT2 (env->ft2)
David Woodhouse 66db2b
 
David Woodhouse 66db2b
-#if defined (DEBUG_OP)
David Woodhouse 66db2b
-#define RETURN() __asm__ __volatile__("nop");
David Woodhouse 66db2b
-#else
David Woodhouse 66db2b
-#define RETURN() __asm__ __volatile__("");
David Woodhouse 66db2b
-#endif
David Woodhouse 66db2b
+#define RETURN() FORCE_RET()
David Woodhouse 66db2b
 
David Woodhouse 66db2b
 #include "cpu.h"
David Woodhouse 66db2b
 #include "exec-all.h"