You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							893 lines
						
					
					
						
							28 KiB
						
					
					
				
			
		
		
	
	
							893 lines
						
					
					
						
							28 KiB
						
					
					
				| # --- SDE-COPYRIGHT-NOTE-BEGIN --- | |
| # This copyright note is auto-generated by ./scripts/Create-CopyPatch. | |
| # | |
| # Filename: package/.../qemu/qemu-0.9.0-gcc4.patch | |
| # Copyright (C) 2007 The OpenSDE Project | |
| # | |
| # More information can be found in the files COPYING and README. | |
| # | |
| # This patch file is dual-licensed. It is available under the license the | |
| # patched project is licensed under, as long as it is an OpenSource license | |
| # as defined at http://www.opensource.org/ (e.g. BSD, X11) or under the terms | |
| # of the GNU General Public License as published by the Free Software | |
| # Foundation; either version 2 of the License, or (at your option) any later | |
| # version. | |
| # --- SDE-COPYRIGHT-NOTE-END --- | |
|  | |
| 2007-04-12  rediffed for qemu 0.9.0 | |
|  | |
| 2005-06-02  Gwenole Beauchesne  <[email protected]> | |
|  | |
|         * dyngen.c (trace_i386_insn): Fix push/imul case with 8-bit | |
|         immediate. | |
|  | |
| 2005-05-11  Paul Brook  <[email protected]> | |
|  | |
|         * gcc4 host support. | |
|  | |
| diff -ruN qemu-0.9.0/dyngen-exec.h qemu-0.9.0-gcc4/dyngen-exec.h | |
| --- qemu-0.9.0/dyngen-exec.h	2007-02-06 00:01:54.000000000 +0100 | |
| +++ qemu-0.9.0-gcc4/dyngen-exec.h	2007-04-12 17:24:57.000000000 +0200 | |
| @@ -191,7 +191,12 @@ | |
|  #endif | |
|   | |
|  /* force GCC to generate only one epilog at the end of the function */ | |
| +#if defined(__i386__) || defined(__x86_64__) | |
| +/* Also add 4 bytes of padding so that we can replace the ret with a jmp.  */ | |
| +#define FORCE_RET() __asm__ __volatile__("nop;nop;nop;nop" : : : "memory"); | |
| +#else | |
|  #define FORCE_RET() __asm__ __volatile__("" : : : "memory"); | |
| +#endif | |
|   | |
|  #ifndef OPPROTO | |
|  #define OPPROTO | |
| @@ -241,12 +246,19 @@ | |
|  #endif | |
|   | |
|  #ifdef __i386__ | |
| -#define EXIT_TB() asm volatile ("ret") | |
| -#define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n) | |
| +/* Dyngen will replace hlt instructions with a ret instruction.  Inserting a | |
| +   ret directly would confuse dyngen.  */ | |
| +#define EXIT_TB() asm volatile ("hlt") | |
| +/* Dyngen will replace cli with 0x9e (jmp).  | |
| +   We generate the offset manually.  */ | |
| +#define GOTO_LABEL_PARAM(n) \ | |
| +  asm volatile ("cli;.long " ASM_NAME(__op_gen_label) #n " - 1f;1:") | |
|  #endif | |
|  #ifdef __x86_64__ | |
| -#define EXIT_TB() asm volatile ("ret") | |
| -#define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n) | |
| +/* The same as i386.  */ | |
| +#define EXIT_TB() asm volatile ("hlt") | |
| +#define GOTO_LABEL_PARAM(n) \ | |
| +  asm volatile ("cli;.long " ASM_NAME(__op_gen_label) #n " - 1f;1:") | |
|  #endif | |
|  #ifdef __powerpc__ | |
|  #define EXIT_TB() asm volatile ("blr") | |
| diff -ruN qemu-0.9.0/dyngen.c qemu-0.9.0-gcc4/dyngen.c | |
| --- qemu-0.9.0/dyngen.c	2007-02-06 00:01:54.000000000 +0100 | |
| +++ qemu-0.9.0-gcc4/dyngen.c	2007-04-12 17:24:57.000000000 +0200 | |
| @@ -32,6 +32,8 @@ | |
|   | |
|  #include "config-host.h" | |
|   | |
| +//#define DEBUG_OP | |
| + | |
|  /* NOTE: we test CONFIG_WIN32 instead of _WIN32 to enabled cross | |
|     compilation */ | |
|  #if defined(CONFIG_WIN32) | |
| @@ -1414,6 +1416,644 @@ | |
|  #endif | |
|   | |
|   | |
| +#if defined(HOST_I386) || defined(HOST_X86_64) | |
| + | |
| +/* This byte is the first byte of an instruction.  */ | |
| +#define FLAG_INSN     (1 << 0) | |
| +/* This byte has been processed as part of an instruction.  */ | |
| +#define FLAG_SCANNED  (1 << 1) | |
| +/* This instruction is a return instruction.  Gcc cometimes generates prefix | |
| +   bytes, so may be more than one byte long.  */ | |
| +#define FLAG_RET      (1 << 2) | |
| +/* This is either the target of a jump, or the preceeding instruction uses | |
| +   a pc-relative offset.  */ | |
| +#define FLAG_TARGET   (1 << 3) | |
| +/* This is a magic instruction that needs fixing up.  */ | |
| +#define FLAG_EXIT     (1 << 4) | |
| +#define MAX_EXITS     5 | |
| + | |
| +static void | |
| +bad_opcode(const char *name, uint32_t op) | |
| +{ | |
| +    error("Unsupported opcode %0*x in %s", (op > 0xff) ? 4 : 2, op, name); | |
| +} | |
| + | |
| +/* Mark len bytes as scanned,  Returns insn_size + len.  Reports an error | |
| +   if these bytes have already been scanned.  */ | |
| +static int | |
| +eat_bytes(const char *name, char *flags, int insn, int insn_size, int len) | |
| +{ | |
| +    while (len > 0) { | |
| +        /* This should never occur in sane code.  */ | |
| +        if (flags[insn + insn_size] & FLAG_SCANNED) | |
| +            error ("Overlapping instructions in %s", name); | |
| +        flags[insn + insn_size] |= FLAG_SCANNED; | |
| +        insn_size++; | |
| +        len--; | |
| +    } | |
| +    return insn_size; | |
| +} | |
| + | |
| +static void | |
| +trace_i386_insn (const char *name, uint8_t *start_p, char *flags, int insn, | |
| +                 int len) | |
| +{ | |
| +    uint8_t *ptr; | |
| +    uint8_t op; | |
| +    int modrm; | |
| +    int is_prefix; | |
| +    int op_size; | |
| +    int addr_size; | |
| +    int insn_size; | |
| +    int is_ret; | |
| +    int is_condjmp; | |
| +    int is_jmp; | |
| +    int is_exit; | |
| +    int is_pcrel; | |
| +    int immed; | |
| +    int seen_rexw; | |
| +    int32_t disp; | |
| + | |
| +    ptr = start_p + insn; | |
| +    /* nonzero if this insn has a ModR/M byte.  */ | |
| +    modrm = 1; | |
| +    /* The size of the immediate value in this instruction.  */ | |
| +    immed = 0; | |
| +    /* The operand size.  */ | |
| +    op_size = 4; | |
| +    /* The address size */ | |
| +    addr_size = 4; | |
| +    /* The total length of this instruction.  */ | |
| +    insn_size = 0; | |
| +    is_prefix = 1; | |
| +    is_ret = 0; | |
| +    is_condjmp = 0; | |
| +    is_jmp = 0; | |
| +    is_exit = 0; | |
| +    seen_rexw = 0; | |
| +    is_pcrel = 0; | |
| + | |
| +    while (is_prefix) { | |
| +        op = ptr[insn_size]; | |
| +        insn_size = eat_bytes(name, flags, insn, insn_size, 1); | |
| +        is_prefix = 0; | |
| +        switch (op >> 4) { | |
| +        case 0: | |
| +        case 1: | |
| +        case 2: | |
| +        case 3: | |
| +            if (op == 0x0f) { | |
| +                /* two-byte opcode.  */ | |
| +                op = ptr[insn_size]; | |
| +                insn_size = eat_bytes(name, flags, insn, insn_size, 1); | |
| +                switch (op >> 4) { | |
| +                case 0: | |
| +                    if ((op & 0xf) > 3) | |
| +                      modrm = 0; | |
| +                    break; | |
| +                case 1: /* vector move or prefetch */ | |
| +                case 2: /* various moves and vector compares.  */ | |
| +                case 4: /* cmov */ | |
| +                case 5: /* vector instructions */ | |
| +                case 6: | |
| +                case 13: | |
| +                case 14: | |
| +                case 15: | |
| +                    break; | |
| +                case 7: /* mmx */ | |
| +                    if (op & 0x77) /* emms */ | |
| +                      modrm = 0; | |
| +                    break; | |
| +                case 3: /* wrmsr, rdtsc, rdmsr, rdpmc, sysenter, sysexit */ | |
| +                    modrm = 0; | |
| +                    break; | |
| +                case 8: /* long conditional jump */ | |
| +                    is_condjmp = 1; | |
| +                    immed = op_size; | |
| +                    modrm = 0; | |
| +                    break; | |
| +                case 9: /* setcc */ | |
| +                    break; | |
| +                case 10: | |
| +                    switch (op & 0x7) { | |
| +                    case 0: /* push fs/gs */ | |
| +                    case 1: /* pop fs/gs */ | |
| +                    case 2: /* cpuid/rsm */ | |
| +                        modrm = 0; | |
| +                        break; | |
| +                    case 4: /* shld/shrd immediate */ | |
| +                        immed = 1; | |
| +                        break; | |
| +                    default: /* Normal instructions with a ModR/M byte.  */ | |
| +                        break; | |
| +                    } | |
| +                    break; | |
| +                case 11: | |
| +                    switch (op & 0xf) { | |
| +                    case 10: /* bt, bts, btr, btc */ | |
| +                        immed = 1; | |
| +                        break; | |
| +                    default: | |
| +                        /* cmpxchg, lss, btr, lfs, lgs, movzx, btc, bsf, bsr | |
| +                           undefined, and movsx */ | |
| +                        break; | |
| +                    } | |
| +                    break; | |
| +                case 12: | |
| +                    if (op & 8) { | |
| +                        /* bswap */ | |
| +                        modrm = 0; | |
| +                    } else { | |
| +                        switch (op & 0x7) { | |
| +                        case 2: | |
| +                        case 4: | |
| +                        case 5: | |
| +                        case 6: | |
| +                            immed = 1; | |
| +                            break; | |
| +                        default: | |
| +                            break; | |
| +                        } | |
| +                    } | |
| +                    break; | |
| +                } | |
| +            } else if ((op & 0x07) <= 0x3) { | |
| +                /* General arithmentic ax.  */ | |
| +            } else if ((op & 0x07) <= 0x5) { | |
| +                /* General arithmetic ax, immediate.  */ | |
| +                if (op & 0x01) | |
| +                    immed = op_size; | |
| +                else | |
| +                    immed = 1; | |
| +                modrm = 0; | |
| +            } else if ((op & 0x23) == 0x22) { | |
| +                /* Segment prefix.  */ | |
| +                is_prefix = 1; | |
| +            } else { | |
| +                /* Segment register push/pop or DAA/AAA/DAS/AAS.  */ | |
| +                modrm = 0; | |
| +            } | |
| +            break; | |
| + | |
| +#if defined(HOST_X86_64) | |
| +        case 4: /* rex prefix.  */ | |
| +            is_prefix = 1; | |
| +            /* The address/operand size is actually 64-bit, but the immediate | |
| +               values in the instruction are still 32-bit.  */ | |
| +            op_size = 4; | |
| +            addr_size = 4; | |
| +            if (op & 8) | |
| +                seen_rexw = 1; | |
| +            break; | |
| +#else | |
| +        case 4: /* inc/dec register.  */ | |
| +#endif | |
| +        case 5: /* push/pop general register.  */ | |
| +            modrm = 0; | |
| +            break; | |
| + | |
| +        case 6: | |
| +            switch (op & 0x0f) { | |
| +            case 0: /* pusha */ | |
| +            case 1: /* popa */ | |
| +                modrm = 0; | |
| +                break; | |
| +            case 2: /* bound */ | |
| +            case 3: /* arpl */ | |
| +                break; | |
| +            case 4: /* FS */ | |
| +            case 5: /* GS */ | |
| +                is_prefix = 1; | |
| +                break; | |
| +            case 6: /* opcode size prefix.  */ | |
| +                op_size = 2; | |
| +                is_prefix = 1; | |
| +                break; | |
| +            case 7: /* Address size prefix.  */ | |
| +                addr_size = 2; | |
| +                is_prefix = 1; | |
| +                break; | |
| +            case 8: /* push immediate */ | |
| +                immed = op_size; | |
| +                modrm = 0; | |
| +                break; | |
| +            case 10: /* push 8-bit immediate */ | |
| +                immed = 1; | |
| +                modrm = 0; | |
| +                break; | |
| +            case 9: /* imul immediate */ | |
| +                immed = op_size; | |
| +                break; | |
| +            case 11: /* imul 8-bit immediate */ | |
| +                immed = 1; | |
| +                break; | |
| +            case 12: /* insb */ | |
| +            case 13: /* insw */ | |
| +            case 14: /* outsb */ | |
| +            case 15: /* outsw */ | |
| +                modrm = 0; | |
| +                break; | |
| +            } | |
| +            break; | |
| + | |
| +        case 7: /* Short conditional jump.  */ | |
| +            is_condjmp = 1; | |
| +            immed = 1; | |
| +            modrm = 0; | |
| +            break; | |
| +           | |
| +        case 8: | |
| +            if ((op & 0xf) <= 3) { | |
| +                /* arithmetic immediate.  */ | |
| +                if ((op & 3) == 1) | |
| +                    immed = op_size; | |
| +                else | |
| +                    immed = 1; | |
| +            } | |
| +            /* else test, xchg, mov, lea or pop general.  */ | |
| +            break; | |
| + | |
| +        case 9: | |
| +            /* Various single-byte opcodes with no modrm byte.  */ | |
| +            modrm = 0; | |
| +            if (op == 10) { | |
| +                /* Call */ | |
| +                immed = 4; | |
| +            } | |
| +            break; | |
| + | |
| +        case 10: | |
| +            switch ((op & 0xe) >> 1) { | |
| +            case 0: /* mov absoliute immediate.  */ | |
| +            case 1: | |
| +                if (seen_rexw) | |
| +                    immed = 8; | |
| +                else | |
| +                    immed = addr_size; | |
| +                break; | |
| +            case 4: /* test immediate.  */ | |
| +                if (op & 1) | |
| +                    immed = op_size; | |
| +                else | |
| +                    immed = 1; | |
| +                break; | |
| +            default: /* Various string ops.  */ | |
| +                break; | |
| +            } | |
| +            modrm = 0; | |
| +            break; | |
| + | |
| +        case 11: /* move immediate to register */ | |
| +            if (op & 8) { | |
| +                if (seen_rexw) | |
| +                    immed = 8; | |
| +                else | |
| +                    immed = op_size; | |
| +            } else { | |
| +                immed = 1; | |
| +            } | |
| +            modrm = 0; | |
| +            break; | |
| + | |
| +          case 12: | |
| +            switch (op & 0xf) { | |
| +            case 0: /* shift immediate */ | |
| +            case 1: | |
| +                immed = 1; | |
| +                break; | |
| +            case 2: /* ret immediate */ | |
| +                immed = 2; | |
| +                modrm = 0; | |
| +                bad_opcode(name, op); | |
| +                break; | |
| +            case 3: /* ret */ | |
| +                modrm = 0; | |
| +                is_ret = 1; | |
| +            case 4: /* les */ | |
| +            case 5: /* lds */ | |
| +                break; | |
| +            case 6: /* mov immediate byte */ | |
| +                immed = 1; | |
| +                break; | |
| +            case 7: /* mov immediate */ | |
| +                immed = op_size; | |
| +                break; | |
| +            case 8: /* enter */ | |
| +                /* TODO: Is this right?  */ | |
| +                immed = 3; | |
| +                modrm = 0; | |
| +                break; | |
| +            case 10: /* retf immediate */ | |
| +                immed = 2; | |
| +                modrm = 0; | |
| +                bad_opcode(name, op); | |
| +                break; | |
| +            case 13: /* int */ | |
| +                immed = 1; | |
| +                modrm = 0; | |
| +                break; | |
| +            case 11: /* retf */ | |
| +            case 15: /* iret */ | |
| +                modrm = 0; | |
| +                bad_opcode(name, op); | |
| +                break; | |
| +            default: /* leave, int3 or into */ | |
| +                modrm = 0; | |
| +                break; | |
| +            } | |
| +            break; | |
| + | |
| +        case 13: | |
| +            if ((op & 0xf) >= 8) { | |
| +                /* Coprocessor escape.  For our purposes this is just a normal | |
| +                   instruction with a ModR/M byte.  */ | |
| +            } else if ((op & 0xf) >= 4) { | |
| +                /* AAM, AAD or XLAT */ | |
| +                modrm = 0; | |
| +            } | |
| +            /* else shift instruction */ | |
| +            break; | |
| + | |
| +        case 14: | |
| +            switch ((op & 0xc) >> 2) { | |
| +            case 0: /* loop or jcxz */ | |
| +                is_condjmp = 1; | |
| +                immed = 1; | |
| +                break; | |
| +            case 1: /* in/out immed */ | |
| +                immed = 1; | |
| +                break; | |
| +            case 2: /* call or jmp */ | |
| +                switch (op & 3) { | |
| +                case 0: /* call */ | |
| +                    immed = op_size; | |
| +                    break; | |
| +                case 1: /* long jump */ | |
| +                    immed = 4; | |
| +                    is_jmp = 1; | |
| +                    break; | |
| +                case 2: /* far jmp */ | |
| +                    bad_opcode(name, op); | |
| +                    break; | |
| +                case 3: /* short jmp */ | |
| +                    immed = 1; | |
| +                    is_jmp = 1; | |
| +                    break; | |
| +                } | |
| +                break; | |
| +            case 3: /* in/out register */ | |
| +                break; | |
| +            } | |
| +            modrm = 0; | |
| +            break; | |
| + | |
| +        case 15: | |
| +            switch ((op & 0xe) >> 1) { | |
| +            case 0: | |
| +            case 1: | |
| +                is_prefix = 1; | |
| +                break; | |
| +            case 2: | |
| +            case 4: | |
| +            case 5: | |
| +            case 6: | |
| +                modrm = 0; | |
| +                /* Some privileged insns are used as markers.  */ | |
| +                switch (op) { | |
| +                case 0xf4: /* hlt: Exit translation block.  */ | |
| +                    is_exit = 1; | |
| +                    break; | |
| +                case 0xfa: /* cli: Jump to label.  */ | |
| +                    is_exit = 1; | |
| +                    immed = 4; | |
| +                    break; | |
| +                case 0xfb: /* sti: TB patch jump.  */ | |
| +                    /* Mark the insn for patching, but continue sscanning.  */ | |
| +                    flags[insn] |= FLAG_EXIT; | |
| +                    immed = 4; | |
| +                    break; | |
| +                } | |
| +                break; | |
| +            case 3: /* unary grp3 */ | |
| +                if ((ptr[insn_size] & 0x38) == 0) { | |
| +                    if (op == 0xf7) | |
| +                        immed = op_size; | |
| +                    else | |
| +                        immed = 1; /* test immediate */ | |
| +                } | |
| +                break; | |
| +            case 7: /* inc/dec grp4/5 */ | |
| +                /* TODO: This includes indirect jumps.  We should fail if we | |
| +                   encounter one of these. */ | |
| +                break; | |
| +            } | |
| +            break; | |
| +        } | |
| +    } | |
| + | |
| +    if (modrm) { | |
| +        if (addr_size != 4) | |
| +            error("16-bit addressing mode used in %s", name); | |
| + | |
| +        disp = 0; | |
| +        modrm = ptr[insn_size]; | |
| +        insn_size = eat_bytes(name, flags, insn, insn_size, 1); | |
| +        modrm &= 0xc7; | |
| +        switch ((modrm & 0xc0) >> 6) { | |
| +        case 0: | |
| +            if (modrm == 5) | |
| +              disp = 4; | |
| +            break; | |
| +        case 1: | |
| +            disp = 1; | |
| +            break; | |
| +        case 2: | |
| +            disp = 4; | |
| +            break; | |
| +        } | |
| +        if ((modrm & 0xc0) != 0xc0 && (modrm & 0x7) == 4) { | |
| +            /* SIB byte */ | |
| +            if (modrm == 4 && (ptr[insn_size] & 0x7) == 5) { | |
| +                disp = 4; | |
| +                is_pcrel = 1; | |
| +            } | |
| +            insn_size = eat_bytes(name, flags, insn, insn_size, 1); | |
| +        } | |
| +        insn_size = eat_bytes(name, flags, insn, insn_size, disp); | |
| +    } | |
| +    insn_size = eat_bytes(name, flags, insn, insn_size, immed); | |
| +    if (is_condjmp || is_jmp) { | |
| +        if (immed == 1) { | |
| +            disp = (int8_t)*(ptr + insn_size - 1); | |
| +        } else { | |
| +            disp = (((int32_t)*(ptr + insn_size - 1)) << 24) | |
| +                   | (((int32_t)*(ptr + insn_size - 2)) << 16) | |
| +                   | (((int32_t)*(ptr + insn_size - 3)) << 8) | |
| +                   | *(ptr + insn_size - 4); | |
| +        } | |
| +        disp += insn_size; | |
| +        /* Jumps to external symbols point to the address of the offset | |
| +           before relocation.  */ | |
| +        /* ??? These are probably a tailcall.  We could fix them up by | |
| +           replacing them with jmp to EOB + call, but it's easier to just | |
| +           prevent the compiler generating them.  */ | |
| +        if (disp == 1) | |
| +            error("Unconditional jump (sibcall?) in %s", name); | |
| +        disp += insn; | |
| +        if (disp < 0 || disp > len) | |
| +            error("Jump outside instruction in %s", name); | |
| + | |
| +        if ((flags[disp] & (FLAG_INSN | FLAG_SCANNED)) == FLAG_SCANNED) | |
| +            error("Overlapping instructions in %s", name); | |
| + | |
| +        flags[disp] |= (FLAG_INSN | FLAG_TARGET); | |
| +        is_pcrel = 1;  | |
| +    } | |
| +    if (is_pcrel) { | |
| +        /* Mark the following insn as a jump target.  This will stop | |
| +           this instruction being moved.  */ | |
| +        flags[insn + insn_size] |= FLAG_TARGET; | |
| +    } | |
| +    if (is_ret) | |
| +      flags[insn] |= FLAG_RET; | |
| + | |
| +    if (is_exit) | |
| +      flags[insn] |= FLAG_EXIT; | |
| + | |
| +    if (!(is_jmp || is_ret || is_exit)) | |
| +      flags[insn + insn_size] |= FLAG_INSN; | |
| +} | |
| + | |
| +/* Scan a function body.  Returns the position of the return sequence. | |
| +   Sets *patch_bytes to the number of bytes that need to be copied from that | |
| +   location.  If no patching is required (ie. the return is the last insn) | |
| +   *patch_bytes will be set to -1.  *plen is the number of code bytes to copy. | |
| + */ | |
| +static int trace_i386_op(const char * name, uint8_t *start_p, int *plen, | |
| +                         int *patch_bytes, int *exit_addrs) | |
| +{ | |
| +    char *flags; | |
| +    int more; | |
| +    int insn; | |
| +    int retpos; | |
| +    int bytes; | |
| +    int num_exits; | |
| +    int len; | |
| +    int last_insn; | |
| + | |
| +    len = *plen; | |
| +    flags = malloc(len + 1); | |
| +    memset(flags, 0, len + 1); | |
| +    flags[0] |= FLAG_INSN; | |
| +    more = 1; | |
| +    while (more) { | |
| +        more = 0; | |
| +        for (insn = 0; insn < len; insn++) { | |
| +            if ((flags[insn] & (FLAG_INSN | FLAG_SCANNED)) == FLAG_INSN) { | |
| +                trace_i386_insn(name, start_p, flags, insn, len); | |
| +                more = 1; | |
| +            } | |
| +        } | |
| +    } | |
| + | |
| +    /* Strip any unused code at the end of the function.  */ | |
| +    while (len > 0 && flags[len - 1] == 0) | |
| +      len--; | |
| + | |
| +    retpos = -1; | |
| +    num_exits = 0; | |
| +    last_insn = 0; | |
| +    for (insn = 0; insn < len; insn++) { | |
| +        if (flags[insn] & FLAG_RET) { | |
| +            /* ??? In theory it should be possible to handle multiple return | |
| +               points.  In practice it's not worth the effort.  */ | |
| +            if (retpos != -1) | |
| +                error("Multiple return instructions in %s", name); | |
| +            retpos = insn; | |
| +        } | |
| +        if (flags[insn] & FLAG_EXIT) { | |
| +            if (num_exits == MAX_EXITS) | |
| +                error("Too many block exits in %s", name); | |
| +            exit_addrs[num_exits] = insn; | |
| +            num_exits++; | |
| +        } | |
| +        if (flags[insn] & FLAG_INSN) | |
| +            last_insn = insn; | |
| +    } | |
| + | |
| +    exit_addrs[num_exits] = -1; | |
| +    if (retpos == -1) { | |
| +        if (num_exits == 0) { | |
| +            error ("No return instruction found in %s", name); | |
| +        } else { | |
| +            retpos = len; | |
| +            last_insn = len; | |
| +        } | |
| +    } | |
| +     | |
| +    /* If the return instruction is the last instruction we can just  | |
| +       remove it.  */ | |
| +    if (retpos == last_insn) | |
| +        *patch_bytes = -1; | |
| +    else | |
| +        *patch_bytes = 0; | |
| + | |
| +    /* Back up over any nop instructions.  */ | |
| +    while (retpos > 0 | |
| +           && (flags[retpos] & FLAG_TARGET) == 0 | |
| +           && (flags[retpos - 1] & FLAG_INSN) != 0 | |
| +           && start_p[retpos - 1] == 0x90) { | |
| +        retpos--; | |
| +    } | |
| + | |
| +    if (*patch_bytes == -1) { | |
| +        *plen = retpos; | |
| +        free (flags); | |
| +        return retpos; | |
| +    } | |
| +    *plen = len; | |
| + | |
| +    /* The ret is in the middle of the function.  Find four more bytes that | |
| +       so the ret can be replaced by a jmp. */ | |
| +    /* ??? Use a short jump where possible. */ | |
| +    bytes = 4; | |
| +    insn = retpos + 1; | |
| +    /* We can clobber everything up to the next jump target.  */ | |
| +    while (insn < len && bytes > 0 && (flags[insn] & FLAG_TARGET) == 0) { | |
| +        insn++; | |
| +        bytes--; | |
| +    } | |
| +    if (bytes > 0) { | |
| +        /* ???: Strip out nop blocks.  */ | |
| +        /* We can't do the replacement without clobbering anything important. | |
| +           Copy preceeding instructions(s) to give us some space.  */ | |
| +        while (retpos > 0) { | |
| +            /* If this byte is the target of a jmp we can't move it.  */ | |
| +            if (flags[retpos] & FLAG_TARGET) | |
| +                break; | |
| + | |
| +            (*patch_bytes)++; | |
| +            bytes--; | |
| +            retpos--; | |
| + | |
| +            /* Break out of the loop if we have enough space and this is either  | |
| +               the first byte of an instruction or a pad byte.  */ | |
| +            if ((flags[retpos] & (FLAG_INSN | FLAG_SCANNED)) != FLAG_SCANNED | |
| +                && bytes <= 0) { | |
| +                break; | |
| +            } | |
| +        } | |
| +    } | |
| + | |
| +    if (bytes > 0) | |
| +        error("Unable to replace ret with jmp in %s\n", name); | |
| + | |
| +    free(flags); | |
| +    return retpos; | |
| +} | |
| + | |
| +#endif | |
| + | |
|  #define MAX_ARGS 3 | |
|   | |
|  /* generate op code */ | |
| @@ -1427,6 +2067,11 @@ | |
|      uint8_t args_present[MAX_ARGS]; | |
|      const char *sym_name, *p; | |
|      EXE_RELOC *rel; | |
| +#if defined(HOST_I386) || defined(HOST_X86_64) | |
| +    int patch_bytes; | |
| +    int retpos; | |
| +    int exit_addrs[MAX_EXITS]; | |
| +#endif | |
|   | |
|      /* Compute exact size excluding prologue and epilogue instructions. | |
|       * Increment start_offset to skip epilogue instructions, then compute | |
| @@ -1437,33 +2082,12 @@ | |
|      p_end = p_start + size; | |
|      start_offset = offset; | |
|  #if defined(HOST_I386) || defined(HOST_X86_64) | |
| -#ifdef CONFIG_FORMAT_COFF | |
| -    { | |
| -        uint8_t *p; | |
| -        p = p_end - 1; | |
| -        if (p == p_start) | |
| -            error("empty code for %s", name); | |
| -        while (*p != 0xc3) { | |
| -            p--; | |
| -            if (p <= p_start) | |
| -                error("ret or jmp expected at the end of %s", name); | |
| -        } | |
| -        copy_size = p - p_start; | |
| -    } | |
| -#else | |
|      { | |
|          int len; | |
|          len = p_end - p_start; | |
| -        if (len == 0) | |
| -            error("empty code for %s", name); | |
| -        if (p_end[-1] == 0xc3) { | |
| -            len--; | |
| -        } else { | |
| -            error("ret or jmp expected at the end of %s", name); | |
| -        } | |
| +        retpos = trace_i386_op(name, p_start, &len, &patch_bytes, exit_addrs); | |
|          copy_size = len; | |
|      } | |
| -#endif     | |
|  #elif defined(HOST_PPC) | |
|      { | |
|          uint8_t *p; | |
| @@ -1675,6 +2299,13 @@ | |
|      } | |
|   | |
|      if (gen_switch == 2) { | |
| +#if defined(HOST_I386) || defined(HOST_X86_64) | |
| +        if (patch_bytes != -1) | |
| +            copy_size += patch_bytes; | |
| +#ifdef DEBUG_OP | |
| +        copy_size += 2; | |
| +#endif | |
| +#endif | |
|          fprintf(outfile, "DEF(%s, %d, %d)\n", name + 3, nb_args, copy_size); | |
|      } else if (gen_switch == 1) { | |
|   | |
| @@ -1879,7 +2510,43 @@ | |
|  #error unsupport object format | |
|  #endif | |
|                  } | |
| +               } | |
| +                /* Replace the marker instructions with the actual opcodes.  */ | |
| +                for (i = 0; exit_addrs[i] != -1; i++) { | |
| +                    int op; | |
| +                    switch (p_start[exit_addrs[i]]) | |
| +                      { | |
| +                      case 0xf4: op = 0xc3; break; /* hlt -> ret */ | |
| +                      case 0xfa: op = 0xe9; break; /* cli -> jmp */ | |
| +                      case 0xfb: op = 0xe9; break; /* sti -> jmp */ | |
| +                      default: error("Internal error"); | |
| +                      } | |
| +                    fprintf(outfile,  | |
| +                            "    *(uint8_t *)(gen_code_ptr + %d) = 0x%x;\n", | |
| +                            exit_addrs[i], op); | |
|                  } | |
| +                /* Fix up the return instruction.  */ | |
| +                if (patch_bytes != -1) { | |
| +                    if (patch_bytes) { | |
| +                        fprintf(outfile, "    memcpy(gen_code_ptr + %d," | |
| +                                "gen_code_ptr + %d, %d);\n", | |
| +                                copy_size, retpos, patch_bytes); | |
| +                    } | |
| +                    fprintf(outfile, | |
| +                            "    *(uint8_t *)(gen_code_ptr + %d) = 0xe9;\n", | |
| +                            retpos); | |
| +                    fprintf(outfile, | |
| +                            "    *(uint32_t *)(gen_code_ptr + %d) = 0x%x;\n", | |
| +                            retpos + 1, copy_size - (retpos + 5)); | |
| +                     | |
| +                    copy_size += patch_bytes; | |
| +                } | |
| +#ifdef DEBUG_OP | |
| +                fprintf(outfile, | |
| +                        "    *(uint16_t *)(gen_code_ptr + %d) = 0x9090;\n", | |
| +                        copy_size); | |
| +                copy_size += 2; | |
| +#endif | |
|              } | |
|  #elif defined(HOST_X86_64) | |
|              { | |
| @@ -1913,6 +2580,42 @@ | |
|                      } | |
|                  } | |
|                  } | |
| +                /* Replace the marker instructions with the actual opcodes.  */ | |
| +                for (i = 0; exit_addrs[i] != -1; i++) { | |
| +                    int op; | |
| +                    switch (p_start[exit_addrs[i]]) | |
| +                      { | |
| +                      case 0xf4: op = 0xc3; break; /* hlt -> ret */ | |
| +                      case 0xfa: op = 0xe9; break; /* cli -> jmp */ | |
| +                      case 0xfb: op = 0xe9; break; /* sti -> jmp */ | |
| +                      default: error("Internal error"); | |
| +                      } | |
| +                    fprintf(outfile,  | |
| +                            "    *(uint8_t *)(gen_code_ptr + %d) = 0x%x;\n", | |
| +                            exit_addrs[i], op); | |
| +                } | |
| +                /* Fix up the return instruction.  */ | |
| +                if (patch_bytes != -1) { | |
| +                    if (patch_bytes) { | |
| +                        fprintf(outfile, "    memcpy(gen_code_ptr + %d," | |
| +                                "gen_code_ptr + %d, %d);\n", | |
| +                                copy_size, retpos, patch_bytes); | |
| +                    } | |
| +                    fprintf(outfile, | |
| +                            "    *(uint8_t *)(gen_code_ptr + %d) = 0xe9;\n", | |
| +                            retpos); | |
| +                    fprintf(outfile, | |
| +                            "    *(uint32_t *)(gen_code_ptr + %d) = 0x%x;\n", | |
| +                            retpos + 1, copy_size - (retpos + 5)); | |
| +                     | |
| +                    copy_size += patch_bytes; | |
| +                } | |
| +#ifdef DEBUG_OP | |
| +                fprintf(outfile, | |
| +                        "    *(uint16_t *)(gen_code_ptr + %d) = 0x9090;\n", | |
| +                        copy_size); | |
| +                copy_size += 2; | |
| +#endif | |
|              } | |
|  #elif defined(HOST_PPC) | |
|              { | |
| diff -ruN qemu-0.9.0/exec-all.h qemu-0.9.0-gcc4/exec-all.h | |
| --- qemu-0.9.0/exec-all.h	2007-02-06 00:01:54.000000000 +0100 | |
| +++ qemu-0.9.0-gcc4/exec-all.h	2007-04-12 17:24:57.000000000 +0200 | |
| @@ -326,14 +326,15 @@ | |
|   | |
|  #elif defined(__i386__) && defined(USE_DIRECT_JUMP) | |
|   | |
| -/* we patch the jump instruction directly */ | |
| +/* we patch the jump instruction directly.  Use sti in place of the actual | |
| +   jmp instruction so that dyngen can patch in the correct result.  */ | |
|  #define GOTO_TB(opname, tbparam, n)\ | |
|  do {\ | |
|      asm volatile (".section .data\n"\ | |
|  		  ASM_OP_LABEL_NAME(n, opname) ":\n"\ | |
|  		  ".long 1f\n"\ | |
|  		  ASM_PREVIOUS_SECTION \ | |
| -                  "jmp " ASM_NAME(__op_jmp) #n "\n"\ | |
| +                  "sti;.long " ASM_NAME(__op_jmp) #n " - 1f\n"\ | |
|  		  "1:\n");\ | |
|  } while (0) | |
|  
 | |
| 
 |