]> git.ipfire.org Git - thirdparty/qemu.git/commitdiff
better 16 bit code support
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sat, 22 Mar 2003 15:23:14 +0000 (15:23 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sat, 22 Mar 2003 15:23:14 +0000 (15:23 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@38 c046a42c-6fe2-441c-8c8c-71466251a162

TODO
cpu-i386.h
exec-i386.c
exec-i386.h
linux-user/main.c
linux-user/syscall.c
linux-user/syscall_defs.h
op-i386.c
opc-i386.h
ops_template.h
translate-i386.c

diff --git a/TODO b/TODO
index ad3c765938d1bfa72203fcf9ad48642bfad78466..36efe4e9e45970e1dfbdcbf1827b94967b62cdb2 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,3 +1,4 @@
+- overrides/16bit for string ops
 - optimize translated cache chaining (DLL PLT-like system)
 - 64 bit syscalls
 - signals
index 550e18387f77b2c3c3d170f8b354349caea8806b..9125ecadc53b24f3d2bbbf9d251a6bc8dfaff3c4 100644 (file)
@@ -141,7 +141,7 @@ typedef struct SegmentDescriptorTable {
 typedef struct CPUX86State {
     /* standard registers */
     uint32_t regs[8];
-    uint32_t pc; /* cs_case + eip value */
+    uint32_t eip;
     uint32_t eflags;
 
     /* emulator internal eflags handling */
@@ -392,10 +392,12 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector);
 
 #define GEN_FLAG_CODE32_SHIFT 0
 #define GEN_FLAG_ADDSEG_SHIFT 1
-#define GEN_FLAG_ST_SHIFT     2
+#define GEN_FLAG_SS32_SHIFT   2
+#define GEN_FLAG_ST_SHIFT     3
+
 int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, 
-                     int *gen_code_size_ptr, uint8_t *pc_start, 
-                     int flags);
+                     int *gen_code_size_ptr,
+                     uint8_t *pc_start,  uint8_t *cs_base, int flags);
 void cpu_x86_tblocks_init(void);
 
 #endif /* CPU_I386_H */
index 0dbaccc8300c28772e9ef609cb3452c218f7db6d..e83d220369c2a8a20939fe960dedc6d028cc3909 100644 (file)
@@ -38,7 +38,8 @@
 #define CODE_GEN_HASH_SIZE     (1 << CODE_GEN_HASH_BITS)
 
 typedef struct TranslationBlock {
-    unsigned long pc;   /* simulated PC corresponding to this block */
+    unsigned long pc;   /* simulated PC corresponding to this block (EIP + CS base) */
+    unsigned long cs_base; /* CS base for this block */
     unsigned int flags; /* flags defining in which context the code was generated */
     uint8_t *tc_ptr;    /* pointer to the translated code */
     struct TranslationBlock *hash_next; /* next matching block */
@@ -140,6 +141,7 @@ static void tb_flush(void)
 /* find a translation block in the translation cache. If not found,
    allocate a new one */
 static inline TranslationBlock *tb_find_and_alloc(unsigned long pc, 
+                                                  unsigned long cs_base,
                                                   unsigned int flags)
 {
     TranslationBlock **ptb, *tb;
@@ -151,7 +153,7 @@ static inline TranslationBlock *tb_find_and_alloc(unsigned long pc,
         tb = *ptb;
         if (!tb)
             break;
-        if (tb->pc == pc && tb->flags == flags)
+        if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
             return tb;
         ptb = &tb->hash_next;
     }
@@ -161,6 +163,7 @@ static inline TranslationBlock *tb_find_and_alloc(unsigned long pc,
     tb = &tbs[nb_tbs++];
     *ptb = tb;
     tb->pc = pc;
+    tb->cs_base = cs_base;
     tb->flags = flags;
     tb->tc_ptr = NULL;
     tb->hash_next = NULL;
@@ -198,7 +201,7 @@ int cpu_x86_exec(CPUX86State *env1)
     int code_gen_size, ret;
     void (*gen_func)(void);
     TranslationBlock *tb;
-    uint8_t *tc_ptr;
+    uint8_t *tc_ptr, *cs_base, *pc;
     unsigned int flags;
 
     /* first we save global registers */
@@ -251,17 +254,21 @@ int cpu_x86_exec(CPUX86State *env1)
             /* we compute the CPU state. We assume it will not
                change during the whole generated block. */
             flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT;
+            flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT;
             flags |= (((unsigned long)env->seg_cache[R_DS].base | 
                        (unsigned long)env->seg_cache[R_ES].base |
                        (unsigned long)env->seg_cache[R_SS].base) != 0) << 
                 GEN_FLAG_ADDSEG_SHIFT;
-            tb = tb_find_and_alloc((unsigned long)env->pc, flags);
+            cs_base = env->seg_cache[R_CS].base;
+            pc = cs_base + env->eip;
+            tb = tb_find_and_alloc((unsigned long)pc, (unsigned long)cs_base, 
+                                   flags);
             tc_ptr = tb->tc_ptr;
             if (!tb->tc_ptr) {
                 /* if no translated code available, then translate it now */
                 tc_ptr = code_gen_ptr;
                 cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, 
-                                 &code_gen_size, (uint8_t *)env->pc, flags);
+                                 &code_gen_size, pc, cs_base, flags);
                 tb->tc_ptr = tc_ptr;
                 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
             }
index 0384d0bf22c5a16760282c08b58dd67c6decc700..f2e1386b5758c5eeb06e6c2af36472ae7e2ac01d 100644 (file)
@@ -111,7 +111,7 @@ register struct CPUX86State *env asm("l3");
 #ifndef reg_EDI
 #define EDI (env->regs[R_EDI])
 #endif
-#define PC  (env->pc)
+#define EIP  (env->eip)
 #define DF  (env->df)
 
 #define CC_SRC (env->cc_src)
index 45e81b207c0e63b499ebcf9752430c2100a6fb9c..3222629b27badf2568a73309fe56129f9b71d566 100644 (file)
@@ -179,7 +179,7 @@ int main(int argc, char **argv)
     env->regs[R_EDI] = regs->edi;
     env->regs[R_EBP] = regs->ebp;
     env->regs[R_ESP] = regs->esp;
-    env->pc = regs->eip;
+    env->eip = regs->eip;
 
     /* linux segment setup */
     env->gdt.base = (void *)gdt_table;
@@ -198,12 +198,12 @@ int main(int argc, char **argv)
         uint8_t *pc;
         
         err = cpu_x86_exec(env);
+        pc = env->seg_cache[R_CS].base + env->eip;
         switch(err) {
         case EXCP0D_GPF:
-            pc = (uint8_t *)env->pc;
             if (pc[0] == 0xcd && pc[1] == 0x80) {
                 /* syscall */
-                env->pc += 2;
+                env->eip += 2;
                 env->regs[R_EAX] = do_syscall(env, 
                                               env->regs[R_EAX], 
                                               env->regs[R_EBX],
@@ -219,7 +219,7 @@ int main(int argc, char **argv)
         default:
         trap_error:
             fprintf(stderr, "0x%08lx: Unknown exception %d, aborting\n", 
-                    (long)env->pc, err);
+                    (long)pc, err);
             abort();
         }
     }
index c0bee47f766ae9bbc3a0b25264e3a4973639ca5c..afdf1896763c5fdbd877a13d2c9c7b218baafa98 100644 (file)
@@ -53,6 +53,7 @@
 #include <linux/cdrom.h>
 #include <linux/hdreg.h>
 #include <linux/soundcard.h>
+#include <linux/dirent.h>
 
 #include "gemu.h"
 
 #define PAGE_MASK ~(PAGE_SIZE - 1)
 #endif
 
-struct dirent {
-        long            d_ino;
-        long            d_off;
-        unsigned short  d_reclen;
-        char            d_name[256]; /* We must not include limits.h! */
-};
-
 //#include <linux/msdos_fs.h>
 #define        VFAT_IOCTL_READDIR_BOTH         _IOR('r', 1, struct dirent [2])
 #define        VFAT_IOCTL_READDIR_SHORT        _IOR('r', 2, struct dirent [2])
@@ -86,6 +80,7 @@ struct dirent {
 #define __NR_sys_statfs __NR_statfs
 #define __NR_sys_fstatfs __NR_fstatfs
 #define __NR_sys_getdents __NR_getdents
+#define __NR_sys_getdents64 __NR_getdents64
 
 #ifdef __NR_gettid
 _syscall0(int, gettid)
@@ -97,6 +92,7 @@ static int gettid(void) {
 _syscall1(int,sys_uname,struct new_utsname *,buf)
 _syscall2(int,sys_getcwd1,char *,buf,size_t,size)
 _syscall3(int, sys_getdents, uint, fd, struct dirent *, dirp, uint, count);
+_syscall3(int, sys_getdents64, uint, fd, struct dirent64 *, dirp, uint, count);
 _syscall5(int, _llseek,  uint,  fd, ulong, hi, ulong, lo,
           loff_t *, res, uint, wh);
 _syscall2(int,sys_statfs,const char *,path,struct kernel_statfs *,buf)
@@ -1005,7 +1001,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
         ret = get_errno(setsid());
         break;
     case TARGET_NR_sigaction:
-#if 0
+#if 1
         {
             ret = 0;
         }
@@ -1336,6 +1332,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
         {
             struct dirent *dirp = (void *)arg2;
             long count = arg3;
+
             ret = get_errno(sys_getdents(arg1, dirp, count));
             if (!is_error(ret)) {
                 struct dirent *de;
@@ -1355,6 +1352,29 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
             }
         }
         break;
+    case TARGET_NR_getdents64:
+        {
+            struct dirent64 *dirp = (void *)arg2;
+            long count = arg3;
+            ret = get_errno(sys_getdents64(arg1, dirp, count));
+            if (!is_error(ret)) {
+                struct dirent64 *de;
+                int len = ret;
+                int reclen;
+                de = dirp;
+                while (len > 0) {
+                    reclen = tswap16(de->d_reclen);
+                    if (reclen > len)
+                        break;
+                    de->d_reclen = reclen;
+                    tswap64s(&de->d_ino);
+                    tswap64s(&de->d_off);
+                    de = (struct dirent64 *)((char *)de + reclen);
+                    len -= reclen;
+                }
+            }
+        }
+        break;
     case TARGET_NR__newselect:
         ret = do_select(arg1, (void *)arg2, (void *)arg3, (void *)arg4, 
                         (void *)arg5);
@@ -1519,7 +1539,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
     case TARGET_NR_pivot_root:
     case TARGET_NR_mincore:
     case TARGET_NR_madvise:
-    case TARGET_NR_getdents64:
         goto unimplemented;
 #if TARGET_LONG_BITS == 32
     case TARGET_NR_fcntl64:
index dc44272dbba5a990882da0a585ddc443e34c96ba..8b2d6bd75635cdb70705f21fcb55787748f67b1b 100644 (file)
@@ -75,6 +75,22 @@ struct kernel_statfs {
        int f_spare[6];
 };
 
+struct target_dirent {
+       target_long     d_ino;
+       target_long     d_off;
+       unsigned short  d_reclen;
+       char            d_name[256]; /* We must not include limits.h! */
+};
+
+struct target_dirent64 {
+       uint64_t        d_ino;
+       int64_t         d_off;
+       unsigned short  d_reclen;
+       unsigned char   d_type;
+       char            d_name[256];
+};
+
+
 /* mostly generic signal stuff */
 #define TARGET_SIG_DFL ((target_long)0)        /* default signal handling */
 #define TARGET_SIG_IGN ((target_long)1)        /* ignore signal */
index 70b1d7449004d1bf6895fdef213753232d6f9c61..a9583ecf394073ca544e003ae9a1643f2ed86f17 100644 (file)
--- a/op-i386.c
+++ b/op-i386.c
@@ -464,18 +464,43 @@ void OPPROTO op_idivl_EAX_T0(void)
     EDX = r;
 }
 
-/* constant load */
+/* constant load & misc op */
 
 void OPPROTO op_movl_T0_im(void)
 {
     T0 = PARAM1;
 }
 
+void OPPROTO op_addl_T0_im(void)
+{
+    T0 += PARAM1;
+}
+
+void OPPROTO op_andl_T0_ffff(void)
+{
+    T0 = T0 & 0xffff;
+}
+
+void OPPROTO op_movl_T0_T1(void)
+{
+    T0 = T1;
+}
+
 void OPPROTO op_movl_T1_im(void)
 {
     T1 = PARAM1;
 }
 
+void OPPROTO op_addl_T1_im(void)
+{
+    T1 += PARAM1;
+}
+
+void OPPROTO op_movl_T1_A0(void)
+{
+    T1 = A0;
+}
+
 void OPPROTO op_movl_A0_im(void)
 {
     A0 = PARAM1;
@@ -574,23 +599,23 @@ void OPPROTO op_add_bitl_A0_T1(void)
 
 void OPPROTO op_jmp_T0(void)
 {
-    PC = T0;
+    EIP = T0;
 }
 
 void OPPROTO op_jmp_im(void)
 {
-    PC = PARAM1;
+    EIP = PARAM1;
 }
 
 void OPPROTO op_int_im(void)
 {
-    PC = PARAM1;
+    EIP = PARAM1;
     raise_exception(EXCP0D_GPF);
 }
 
 void OPPROTO op_int3(void)
 {
-    PC = PARAM1;
+    EIP = PARAM1;
     raise_exception(EXCP03_INT3);
 }
 
@@ -599,10 +624,10 @@ void OPPROTO op_into(void)
     int eflags;
     eflags = cc_table[CC_OP].compute_all();
     if (eflags & CC_O) {
-        PC = PARAM1;
+        EIP = PARAM1;
         raise_exception(EXCP04_INTO);
     } else {
-        PC = PARAM2;
+        EIP = PARAM2;
     }
 }
 
@@ -665,7 +690,6 @@ void OPPROTO op_movswl_DX_AX(void)
 }
 
 /* push/pop */
-/* XXX: add 16 bit operand/16 bit seg variants */
 
 void op_pushl_T0(void)
 {
@@ -676,107 +700,110 @@ void op_pushl_T0(void)
     ESP = offset;
 }
 
-void op_pushl_T1(void)
+void op_pushw_T0(void)
+{
+    uint32_t offset;
+    offset = ESP - 2;
+    stw((void *)offset, T0);
+    /* modify ESP after to handle exceptions correctly */
+    ESP = offset;
+}
+
+void op_pushl_ss32_T0(void)
 {
     uint32_t offset;
     offset = ESP - 4;
-    stl((void *)offset, T1);
+    stl(env->seg_cache[R_SS].base + offset, T0);
     /* modify ESP after to handle exceptions correctly */
     ESP = offset;
 }
 
+void op_pushw_ss32_T0(void)
+{
+    uint32_t offset;
+    offset = ESP - 2;
+    stw(env->seg_cache[R_SS].base + offset, T0);
+    /* modify ESP after to handle exceptions correctly */
+    ESP = offset;
+}
+
+void op_pushl_ss16_T0(void)
+{
+    uint32_t offset;
+    offset = (ESP - 4) & 0xffff;
+    stl(env->seg_cache[R_SS].base + offset, T0);
+    /* modify ESP after to handle exceptions correctly */
+    ESP = (ESP & ~0xffff) | offset;
+}
+
+void op_pushw_ss16_T0(void)
+{
+    uint32_t offset;
+    offset = (ESP - 2) & 0xffff;
+    stw(env->seg_cache[R_SS].base + offset, T0);
+    /* modify ESP after to handle exceptions correctly */
+    ESP = (ESP & ~0xffff) | offset;
+}
+
+/* NOTE: ESP update is done after */
 void op_popl_T0(void)
 {
     T0 = ldl((void *)ESP);
+}
+
+void op_popw_T0(void)
+{
+    T0 = lduw((void *)ESP);
+}
+
+void op_popl_ss32_T0(void)
+{
+    T0 = ldl(env->seg_cache[R_SS].base + ESP);
+}
+
+void op_popw_ss32_T0(void)
+{
+    T0 = lduw(env->seg_cache[R_SS].base + ESP);
+}
+
+void op_popl_ss16_T0(void)
+{
+    T0 = ldl(env->seg_cache[R_SS].base + (ESP & 0xffff));
+}
+
+void op_popw_ss16_T0(void)
+{
+    T0 = lduw(env->seg_cache[R_SS].base + (ESP & 0xffff));
+}
+
+void op_addl_ESP_4(void)
+{
     ESP += 4;
 }
 
+void op_addl_ESP_2(void)
+{
+    ESP += 2;
+}
+
+void op_addw_ESP_4(void)
+{
+    ESP = (ESP & ~0xffff) | ((ESP + 4) & 0xffff);
+}
+
+void op_addw_ESP_2(void)
+{
+    ESP = (ESP & ~0xffff) | ((ESP + 2) & 0xffff);
+}
+
 void op_addl_ESP_im(void)
 {
     ESP += PARAM1;
 }
 
-void op_pushal(void)
-{
-    uint8_t *sp;
-    sp = (void *)(ESP - 32);
-    stl(sp, EDI);
-    stl(sp + 4, ESI);
-    stl(sp + 8, EBP);
-    stl(sp + 12, ESP);
-    stl(sp + 16, EBX);
-    stl(sp + 20, EDX);
-    stl(sp + 24, ECX);
-    stl(sp + 28, EAX);
-    ESP = (unsigned long)sp;
-}
-
-void op_pushaw(void)
-{
-    uint8_t *sp;
-    sp = (void *)(ESP - 16);
-    stw(sp, EDI);
-    stw(sp + 2, ESI);
-    stw(sp + 4, EBP);
-    stw(sp + 6, ESP);
-    stw(sp + 8, EBX);
-    stw(sp + 10, EDX);
-    stw(sp + 12, ECX);
-    stw(sp + 14, EAX);
-    ESP = (unsigned long)sp;
-}
-
-void op_popal(void)
-{
-    uint8_t *sp;
-    sp = (void *)ESP;
-    EDI = ldl(sp);
-    ESI = ldl(sp + 4);
-    EBP = ldl(sp + 8);
-    EBX = ldl(sp + 16);
-    EDX = ldl(sp + 20);
-    ECX = ldl(sp + 24);
-    EAX = ldl(sp + 28);
-    ESP = (unsigned long)sp + 32;
-}
-
-void op_popaw(void)
-{
-    uint8_t *sp;
-    sp = (void *)ESP;
-    EDI = ldl(sp);
-    ESI = ldl(sp + 2);
-    EBP = ldl(sp + 4);
-    EBX = ldl(sp + 8);
-    EDX = ldl(sp + 10);
-    ECX = ldl(sp + 12);
-    EAX = ldl(sp + 14);
-    ESP = (unsigned long)sp + 16;
-}
-
-void op_enterl(void)
-{
-    unsigned int bp, frame_temp, level;
-    uint8_t *sp;
-
-    sp = (void *)ESP;
-    bp = EBP;
-    sp -= 4;
-    stl(sp, bp);
-    frame_temp = (unsigned int)sp;
-    level = PARAM2;
-    if (level) {
-        while (level--) {
-            bp -= 4; 
-            sp -= 4;
-            stl(sp, bp);
-        }
-        sp -= 4;
-        stl(sp, frame_temp);
-    }
-    EBP = frame_temp;
-    sp -= PARAM1;
-    ESP = (int)sp;
+void op_addw_ESP_im(void)
+{
+    ESP = (ESP & ~0xffff) | ((ESP + PARAM1) & 0xffff);
 }
 
 /* rdtsc */
@@ -988,18 +1015,18 @@ void OPPROTO op_jo_cc(void)
     int eflags;
     eflags = cc_table[CC_OP].compute_all();
     if (eflags & CC_O)
-        PC = PARAM1;
+        EIP = PARAM1;
     else
-        PC = PARAM2;
+        EIP = PARAM2;
     FORCE_RET();
 }
 
 void OPPROTO op_jb_cc(void)
 {
     if (cc_table[CC_OP].compute_c())
-        PC = PARAM1;
+        EIP = PARAM1;
     else
-        PC = PARAM2;
+        EIP = PARAM2;
     FORCE_RET();
 }
 
@@ -1008,9 +1035,9 @@ void OPPROTO op_jz_cc(void)
     int eflags;
     eflags = cc_table[CC_OP].compute_all();
     if (eflags & CC_Z)
-        PC = PARAM1;
+        EIP = PARAM1;
     else
-        PC = PARAM2;
+        EIP = PARAM2;
     FORCE_RET();
 }
 
@@ -1019,9 +1046,9 @@ void OPPROTO op_jbe_cc(void)
     int eflags;
     eflags = cc_table[CC_OP].compute_all();
     if (eflags & (CC_Z | CC_C))
-        PC = PARAM1;
+        EIP = PARAM1;
     else
-        PC = PARAM2;
+        EIP = PARAM2;
     FORCE_RET();
 }
 
@@ -1030,9 +1057,9 @@ void OPPROTO op_js_cc(void)
     int eflags;
     eflags = cc_table[CC_OP].compute_all();
     if (eflags & CC_S)
-        PC = PARAM1;
+        EIP = PARAM1;
     else
-        PC = PARAM2;
+        EIP = PARAM2;
     FORCE_RET();
 }
 
@@ -1041,9 +1068,9 @@ void OPPROTO op_jp_cc(void)
     int eflags;
     eflags = cc_table[CC_OP].compute_all();
     if (eflags & CC_P)
-        PC = PARAM1;
+        EIP = PARAM1;
     else
-        PC = PARAM2;
+        EIP = PARAM2;
     FORCE_RET();
 }
 
@@ -1052,9 +1079,9 @@ void OPPROTO op_jl_cc(void)
     int eflags;
     eflags = cc_table[CC_OP].compute_all();
     if ((eflags ^ (eflags >> 4)) & 0x80)
-        PC = PARAM1;
+        EIP = PARAM1;
     else
-        PC = PARAM2;
+        EIP = PARAM2;
     FORCE_RET();
 }
 
@@ -1063,9 +1090,9 @@ void OPPROTO op_jle_cc(void)
     int eflags;
     eflags = cc_table[CC_OP].compute_all();
     if (((eflags ^ (eflags >> 4)) & 0x80) || (eflags & CC_Z))
-        PC = PARAM1;
+        EIP = PARAM1;
     else
-        PC = PARAM2;
+        EIP = PARAM2;
     FORCE_RET();
 }
 
index aae289419c9bcc2d27df854a06e58dfbae851b2e..09290446864f5d4467e856816202f8a19cc99d06 100644 (file)
@@ -202,7 +202,12 @@ DEF(idivw_AX_T0)
 DEF(divl_EAX_T0)
 DEF(idivl_EAX_T0)
 DEF(movl_T0_im)
+DEF(addl_T0_im)
+DEF(andl_T0_ffff)
+DEF(movl_T0_T1)
 DEF(movl_T1_im)
+DEF(addl_T1_im)
+DEF(movl_T1_A0)
 DEF(movl_A0_im)
 DEF(addl_A0_im)
 DEF(andl_A0_ffff)
@@ -398,14 +403,23 @@ DEF(movsbw_AX_AL)
 DEF(movslq_EDX_EAX)
 DEF(movswl_DX_AX)
 DEF(pushl_T0)
-DEF(pushl_T1)
+DEF(pushw_T0)
+DEF(pushl_ss32_T0)
+DEF(pushw_ss32_T0)
+DEF(pushl_ss16_T0)
+DEF(pushw_ss16_T0)
 DEF(popl_T0)
+DEF(popw_T0)
+DEF(popl_ss32_T0)
+DEF(popw_ss32_T0)
+DEF(popl_ss16_T0)
+DEF(popw_ss16_T0)
+DEF(addl_ESP_4)
+DEF(addl_ESP_2)
+DEF(addw_ESP_4)
+DEF(addw_ESP_2)
 DEF(addl_ESP_im)
-DEF(pushal)
-DEF(pushaw)
-DEF(popal)
-DEF(popaw)
-DEF(enterl)
+DEF(addw_ESP_im)
 DEF(rdtsc)
 DEF(aam)
 DEF(aad)
index bc96f651a29e50578a8688993b4e2af654fec930..70ee9f355cefc3322a2b00937a613246604f661b 100644 (file)
@@ -214,18 +214,18 @@ void OPPROTO glue(op_jb_sub, SUFFIX)(void)
     src2 = CC_SRC - CC_DST;
 
     if ((DATA_TYPE)src1 < (DATA_TYPE)src2)
-        PC = PARAM1;
+        EIP = PARAM1;
     else
-        PC = PARAM2;
+        EIP = PARAM2;
     FORCE_RET();
 }
 
 void OPPROTO glue(op_jz_sub, SUFFIX)(void)
 {
     if ((DATA_TYPE)CC_DST == 0)
-        PC = PARAM1;
+        EIP = PARAM1;
     else
-        PC = PARAM2;
+        EIP = PARAM2;
     FORCE_RET();
 }
 
@@ -236,18 +236,18 @@ void OPPROTO glue(op_jbe_sub, SUFFIX)(void)
     src2 = CC_SRC - CC_DST;
 
     if ((DATA_TYPE)src1 <= (DATA_TYPE)src2)
-        PC = PARAM1;
+        EIP = PARAM1;
     else
-        PC = PARAM2;
+        EIP = PARAM2;
     FORCE_RET();
 }
 
 void OPPROTO glue(op_js_sub, SUFFIX)(void)
 {
     if (CC_DST & SIGN_MASK)
-        PC = PARAM1;
+        EIP = PARAM1;
     else
-        PC = PARAM2;
+        EIP = PARAM2;
     FORCE_RET();
 }
 
@@ -258,9 +258,9 @@ void OPPROTO glue(op_jl_sub, SUFFIX)(void)
     src2 = CC_SRC - CC_DST;
 
     if ((DATA_STYPE)src1 < (DATA_STYPE)src2)
-        PC = PARAM1;
+        EIP = PARAM1;
     else
-        PC = PARAM2;
+        EIP = PARAM2;
     FORCE_RET();
 }
 
@@ -271,9 +271,9 @@ void OPPROTO glue(op_jle_sub, SUFFIX)(void)
     src2 = CC_SRC - CC_DST;
 
     if ((DATA_STYPE)src1 <= (DATA_STYPE)src2)
-        PC = PARAM1;
+        EIP = PARAM1;
     else
-        PC = PARAM2;
+        EIP = PARAM2;
     FORCE_RET();
 }
 
@@ -289,9 +289,9 @@ void OPPROTO glue(op_loopnz, SUFFIX)(void)
     tmp = (ECX - 1) & DATA_MASK;
     ECX = (ECX & ~DATA_MASK) | tmp;
     if (tmp != 0 && !(eflags & CC_Z))
-        PC = PARAM1;
+        EIP = PARAM1;
     else
-        PC = PARAM2;
+        EIP = PARAM2;
     FORCE_RET();
 }
 
@@ -303,9 +303,9 @@ void OPPROTO glue(op_loopz, SUFFIX)(void)
     tmp = (ECX - 1) & DATA_MASK;
     ECX = (ECX & ~DATA_MASK) | tmp;
     if (tmp != 0 && (eflags & CC_Z))
-        PC = PARAM1;
+        EIP = PARAM1;
     else
-        PC = PARAM2;
+        EIP = PARAM2;
     FORCE_RET();
 }
 
@@ -315,18 +315,18 @@ void OPPROTO glue(op_loop, SUFFIX)(void)
     tmp = (ECX - 1) & DATA_MASK;
     ECX = (ECX & ~DATA_MASK) | tmp;
     if (tmp != 0)
-        PC = PARAM1;
+        EIP = PARAM1;
     else
-        PC = PARAM2;
+        EIP = PARAM2;
     FORCE_RET();
 }
 
 void OPPROTO glue(op_jecxz, SUFFIX)(void)
 {
     if ((DATA_TYPE)ECX == 0)
-        PC = PARAM1;
+        EIP = PARAM1;
     else
-        PC = PARAM2;
+        EIP = PARAM2;
     FORCE_RET();
 }
 
index 4c052a4e47ed4b402fd985713fa431d72d354ebd..5cbaa813cef55b18a5ab8eaaf773711ba74d333e 100644 (file)
@@ -92,11 +92,13 @@ typedef struct DisasContext {
     /* current insn context */
     int prefix;
     int aflag, dflag;
-    uint8_t *pc; /* current pc */
+    uint8_t *pc; /* pc = eip + cs_base */
     int is_jmp; /* 1 = means jump (stop translation), 2 means CPU
                    static state change (stop translation) */
     /* current block context */
+    uint8_t *cs_base; /* base of CS segment */
     int code32; /* 32 bit code segment */
+    int ss32;   /* 32 bit stack segment */
     int cc_op;  /* current CC operation */
     int addseg; /* non zero if either DS/ES/SS have a non zero base */
     int f_st;   /* currently unused */
@@ -1051,7 +1053,7 @@ static inline uint32_t insn_get(DisasContext *s, int ot)
     return ret;
 }
 
-static void gen_jcc(DisasContext *s, int b, int val)
+static inline void gen_jcc(DisasContext *s, int b, int val, int next_eip)
 {
     int inv, jcc_op;
     GenOpFunc2 *func;
@@ -1112,9 +1114,9 @@ static void gen_jcc(DisasContext *s, int b, int val)
         break;
     }
     if (!inv) {
-        func(val, (long)s->pc);
+        func(val, next_eip);
     } else {
-        func((long)s->pc, val);
+        func(next_eip, val);
     }
 }
 
@@ -1176,7 +1178,7 @@ static void gen_setcc(DisasContext *s, int b)
 }
 
 /* move T0 to seg_reg and compute if the CPU state may change */
-void gen_movl_seg_T0(DisasContext *s, int seg_reg)
+static void gen_movl_seg_T0(DisasContext *s, int seg_reg)
 {
     gen_op_movl_seg_T0(seg_reg);
     if (!s->addseg && seg_reg < R_FS)
@@ -1184,6 +1186,148 @@ void gen_movl_seg_T0(DisasContext *s, int seg_reg)
                           have a non zero base */
 }
 
+/* generate a push. It depends on ss32, addseg and dflag */
+static void gen_push_T0(DisasContext *s)
+{
+    if (s->ss32) {
+        if (!s->addseg) {
+            if (s->dflag)
+                gen_op_pushl_T0();
+            else
+                gen_op_pushw_T0();
+        } else {
+            if (s->dflag)
+                gen_op_pushl_ss32_T0();
+            else
+                gen_op_pushw_ss32_T0();
+        }
+    } else {
+        if (s->dflag)
+            gen_op_pushl_ss16_T0();
+        else
+            gen_op_pushw_ss16_T0();
+    }
+}
+
+/* two step pop is necessary for precise exceptions */
+static void gen_pop_T0(DisasContext *s)
+{
+    if (s->ss32) {
+        if (!s->addseg) {
+            if (s->dflag)
+                gen_op_popl_T0();
+            else
+                gen_op_popw_T0();
+        } else {
+            if (s->dflag)
+                gen_op_popl_ss32_T0();
+            else
+                gen_op_popw_ss32_T0();
+        }
+    } else {
+        if (s->dflag)
+            gen_op_popl_ss16_T0();
+        else
+            gen_op_popw_ss16_T0();
+    }
+}
+
+static void gen_pop_update(DisasContext *s)
+{
+    if (s->ss32) {
+        if (s->dflag)
+            gen_op_addl_ESP_4();
+        else
+            gen_op_addl_ESP_2();
+    } else {
+        if (s->dflag)
+            gen_op_addw_ESP_4();
+        else
+            gen_op_addw_ESP_2();
+    }
+}
+
+/* NOTE: wrap around in 16 bit not fully handled */
+static void gen_pusha(DisasContext *s)
+{
+    int i;
+    gen_op_movl_A0_ESP();
+    gen_op_addl_A0_im(-16 <<  s->dflag);
+    if (!s->ss32)
+        gen_op_andl_A0_ffff();
+    gen_op_movl_T1_A0();
+    if (s->addseg)
+        gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base));
+    for(i = 0;i < 8; i++) {
+        gen_op_mov_TN_reg[OT_LONG][0][7 - i]();
+        gen_op_st_T0_A0[OT_WORD + s->dflag]();
+        gen_op_addl_A0_im(2 <<  s->dflag);
+    }
+    gen_op_mov_reg_T1[OT_WORD + s->dflag][R_ESP]();
+}
+
+/* NOTE: wrap around in 16 bit not fully handled */
+static void gen_popa(DisasContext *s)
+{
+    int i;
+    gen_op_movl_A0_ESP();
+    if (!s->ss32)
+        gen_op_andl_A0_ffff();
+    gen_op_movl_T1_A0();
+    gen_op_addl_T1_im(16 <<  s->dflag);
+    if (s->addseg)
+        gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base));
+    for(i = 0;i < 8; i++) {
+        /* ESP is not reloaded */
+        if (i != 3) {
+            gen_op_ld_T0_A0[OT_WORD + s->dflag]();
+            gen_op_mov_reg_T0[OT_WORD + s->dflag][7 - i]();
+        }
+        gen_op_addl_A0_im(2 <<  s->dflag);
+    }
+    gen_op_mov_reg_T1[OT_WORD + s->dflag][R_ESP]();
+}
+
+/* NOTE: wrap around in 16 bit not fully handled */
+/* XXX: check this */
+static void gen_enter(DisasContext *s, int esp_addend, int level)
+{
+    int ot, level1, addend, opsize;
+
+    ot = s->dflag + OT_WORD;
+    level &= 0x1f;
+    level1 = level;
+    opsize = 2 << s->dflag;
+
+    gen_op_movl_A0_ESP();
+    gen_op_addl_A0_im(-opsize);
+    if (!s->ss32)
+        gen_op_andl_A0_ffff();
+    gen_op_movl_T1_A0();
+    if (s->addseg)
+        gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base));
+    /* push bp */
+    gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
+    gen_op_st_T0_A0[ot]();
+    if (level) {
+        while (level--) {
+            gen_op_addl_A0_im(-opsize);
+            gen_op_addl_T0_im(-opsize);
+            gen_op_st_T0_A0[ot]();
+        }
+        gen_op_addl_A0_im(-opsize);
+        /* XXX: add st_T1_A0 ? */
+        gen_op_movl_T0_T1();
+        gen_op_st_T0_A0[ot]();
+    }
+    gen_op_mov_reg_T1[ot][R_EBP]();
+    addend = -esp_addend;
+    if (level1)
+        addend -= opsize * (level1 + 1);
+    gen_op_addl_T1_im(addend);
+    gen_op_mov_reg_T1[ot][R_ESP]();
+}
+
 /* return the next pc address. Return -1 if no insn found. *is_jmp_ptr
    is set to true if the instruction sets the PC (last instruction of
    a basic block) */
@@ -1192,6 +1336,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
     int b, prefixes, aflag, dflag;
     int shift, ot;
     int modrm, reg, rm, mod, reg_addr, op, opreg, offset_addr, val;
+    unsigned int next_eip;
 
     s->pc = pc_start;
     prefixes = 0;
@@ -1492,7 +1637,8 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
         }
         if (mod != 3) {
             gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
-            gen_op_ld_T0_A0[ot]();
+            if (op != 3 && op != 5)
+                gen_op_ld_T0_A0[ot]();
         } else {
             gen_op_mov_TN_reg[ot][0][rm]();
         }
@@ -1513,17 +1659,48 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
                 gen_op_mov_reg_T0[ot][rm]();
             break;
         case 2: /* call Ev */
-            gen_op_movl_T1_im((long)s->pc);
-            gen_op_pushl_T1();
+            /* XXX: optimize if memory (no and is necessary) */
+            if (s->dflag == 0)
+                gen_op_andl_T0_ffff();
+            gen_op_jmp_T0();
+            next_eip = s->pc - s->cs_base;
+            gen_op_movl_T0_im(next_eip);
+            gen_push_T0(s);
+            s->is_jmp = 1;
+            break;
+        case 3: /* lcall Ev */
+            /* push return segment + offset */
+            gen_op_movl_T0_seg(R_CS);
+            gen_push_T0(s);
+            next_eip = s->pc - s->cs_base;
+            gen_op_movl_T0_im(next_eip);
+            gen_push_T0(s);
+
+            gen_op_ld_T1_A0[ot]();
+            gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));
+            gen_op_lduw_T0_A0();
+            gen_movl_seg_T0(s, R_CS);
+            gen_op_movl_T0_T1();
             gen_op_jmp_T0();
             s->is_jmp = 1;
             break;
         case 4: /* jmp Ev */
+            if (s->dflag == 0)
+                gen_op_andl_T0_ffff();
+            gen_op_jmp_T0();
+            s->is_jmp = 1;
+            break;
+        case 5: /* ljmp Ev */
+            gen_op_ld_T1_A0[ot]();
+            gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));
+            gen_op_lduw_T0_A0();
+            gen_movl_seg_T0(s, R_CS);
+            gen_op_movl_T0_T1();
             gen_op_jmp_T0();
             s->is_jmp = 1;
             break;
         case 6: /* push Ev */
-            gen_op_pushl_T0();
+            gen_push_T0(s);
             break;
         default:
             goto illegal_op;
@@ -1653,23 +1830,19 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
         /* push/pop */
     case 0x50 ... 0x57: /* push */
         gen_op_mov_TN_reg[OT_LONG][0][b & 7]();
-        gen_op_pushl_T0();
+        gen_push_T0(s);
         break;
     case 0x58 ... 0x5f: /* pop */
-        gen_op_popl_T0();
-        gen_op_mov_reg_T0[OT_LONG][b & 7]();
+        ot = dflag ? OT_LONG : OT_WORD;
+        gen_pop_T0(s);
+        gen_op_mov_reg_T0[ot][b & 7]();
+        gen_pop_update(s);
         break;
     case 0x60: /* pusha */
-        if (s->dflag)
-            gen_op_pushal();
-        else
-            gen_op_pushaw();
+        gen_pusha(s);
         break;
     case 0x61: /* popa */
-        if (s->dflag)
-            gen_op_popal();
-        else
-            gen_op_popaw();
+        gen_popa(s);
         break;
     case 0x68: /* push Iv */
     case 0x6a:
@@ -1679,13 +1852,14 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
         else
             val = (int8_t)insn_get(s, OT_BYTE);
         gen_op_movl_T0_im(val);
-        gen_op_pushl_T0();
+        gen_push_T0(s);
         break;
     case 0x8f: /* pop Ev */
         ot = dflag ? OT_LONG : OT_WORD;
         modrm = ldub(s->pc++);
-        gen_op_popl_T0();
+        gen_pop_T0(s);
         gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
+        gen_pop_update(s);
         break;
     case 0xc8: /* enter */
         {
@@ -1693,38 +1867,47 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
             val = lduw(s->pc);
             s->pc += 2;
             level = ldub(s->pc++);
-            level &= 0x1f;
-            gen_op_enterl(val, level);
+            gen_enter(s, val, level);
         }
         break;
     case 0xc9: /* leave */
-        gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
-        gen_op_mov_reg_T0[OT_LONG][R_ESP]();
-        gen_op_popl_T0();
-        gen_op_mov_reg_T0[OT_LONG][R_EBP]();
+        /* XXX: exception not precise (ESP is update before potential exception) */
+        if (s->ss32) {
+            gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
+            gen_op_mov_reg_T0[OT_LONG][R_ESP]();
+        } else {
+            gen_op_mov_TN_reg[OT_WORD][0][R_EBP]();
+            gen_op_mov_reg_T0[OT_WORD][R_ESP]();
+        }
+        gen_pop_T0(s);
+        ot = dflag ? OT_LONG : OT_WORD;
+        gen_op_mov_reg_T0[ot][R_EBP]();
+        gen_pop_update(s);
         break;
     case 0x06: /* push es */
     case 0x0e: /* push cs */
     case 0x16: /* push ss */
     case 0x1e: /* push ds */
         gen_op_movl_T0_seg(b >> 3);
-        gen_op_pushl_T0();
+        gen_push_T0(s);
         break;
     case 0x1a0: /* push fs */
     case 0x1a8: /* push gs */
         gen_op_movl_T0_seg(((b >> 3) & 7) + R_FS);
-        gen_op_pushl_T0();
+        gen_push_T0(s);
         break;
     case 0x07: /* pop es */
     case 0x17: /* pop ss */
     case 0x1f: /* pop ds */
-        gen_op_popl_T0();
+        gen_pop_T0(s);
         gen_movl_seg_T0(s, b >> 3);
+        gen_pop_update(s);
         break;
     case 0x1a1: /* pop fs */
     case 0x1a9: /* pop gs */
-        gen_op_popl_T0();
+        gen_pop_T0(s);
         gen_movl_seg_T0(s, ((b >> 3) & 7) + R_FS);
+        gen_pop_update(s);
         break;
 
         /**************************/
@@ -1775,7 +1958,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
         modrm = ldub(s->pc++);
         reg = (modrm >> 3) & 7;
         gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
-        if (reg >= 6)
+        if (reg >= 6 || reg == R_CS)
             goto illegal_op;
         gen_movl_seg_T0(s, reg);
         break;
@@ -2585,42 +2768,130 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
         /************************/
         /* control */
     case 0xc2: /* ret im */
-        /* XXX: handle stack pop ? */
         val = ldsw(s->pc);
         s->pc += 2;
-        gen_op_popl_T0();
-        gen_op_addl_ESP_im(val);
+        gen_pop_T0(s);
+        if (s->ss32)
+            gen_op_addl_ESP_im(val + (2 << s->dflag));
+        else
+            gen_op_addw_ESP_im(val + (2 << s->dflag));
+        if (s->dflag == 0)
+            gen_op_andl_T0_ffff();
         gen_op_jmp_T0();
         s->is_jmp = 1;
         break;
     case 0xc3: /* ret */
-        gen_op_popl_T0();
+        gen_pop_T0(s);
+        gen_pop_update(s);
+        if (s->dflag == 0)
+            gen_op_andl_T0_ffff();
         gen_op_jmp_T0();
         s->is_jmp = 1;
         break;
-    case 0xe8: /* call */
-        val = insn_get(s, OT_LONG);
-        val += (long)s->pc;
-        gen_op_movl_T1_im((long)s->pc);
-        gen_op_pushl_T1();
-        gen_op_jmp_im(val);
+    case 0xca: /* lret im */
+        val = ldsw(s->pc);
+        s->pc += 2;
+        /* pop offset */
+        gen_pop_T0(s);
+        if (s->dflag == 0)
+            gen_op_andl_T0_ffff();
+        gen_op_jmp_T0();
+        gen_pop_update(s);
+        /* pop selector */
+        gen_pop_T0(s);
+        gen_movl_seg_T0(s, R_CS);
+        gen_pop_update(s);
+        /* add stack offset */
+        if (s->ss32)
+            gen_op_addl_ESP_im(val + (2 << s->dflag));
+        else
+            gen_op_addw_ESP_im(val + (2 << s->dflag));
+        s->is_jmp = 1;
+        break;
+    case 0xcb: /* lret */
+        /* pop offset */
+        gen_pop_T0(s);
+        if (s->dflag == 0)
+            gen_op_andl_T0_ffff();
+        gen_op_jmp_T0();
+        gen_pop_update(s);
+        /* pop selector */
+        gen_pop_T0(s);
+        gen_movl_seg_T0(s, R_CS);
+        gen_pop_update(s);
         s->is_jmp = 1;
         break;
+    case 0xe8: /* call im */
+        {
+            unsigned int next_eip;
+            ot = dflag ? OT_LONG : OT_WORD;
+            val = insn_get(s, ot);
+            next_eip = s->pc - s->cs_base;
+            val += next_eip;
+            if (s->dflag == 0)
+                val &= 0xffff;
+            gen_op_movl_T0_im(next_eip);
+            gen_push_T0(s);
+            gen_op_jmp_im(val);
+            s->is_jmp = 1;
+        }
+        break;
+    case 0x9a: /* lcall im */
+        {
+            unsigned int selector, offset;
+
+            ot = dflag ? OT_LONG : OT_WORD;
+            offset = insn_get(s, ot);
+            selector = insn_get(s, OT_WORD);
+            
+            /* push return segment + offset */
+            gen_op_movl_T0_seg(R_CS);
+            gen_push_T0(s);
+            next_eip = s->pc - s->cs_base;
+            gen_op_movl_T0_im(next_eip);
+            gen_push_T0(s);
+
+            /* change cs and pc */
+            gen_op_movl_T0_im(selector);
+            gen_movl_seg_T0(s, R_CS);
+            gen_op_jmp_im((unsigned long)offset);
+            s->is_jmp = 1;
+        }
+        break;
     case 0xe9: /* jmp */
-        val = insn_get(s, OT_LONG);
-        val += (long)s->pc;
+        ot = dflag ? OT_LONG : OT_WORD;
+        val = insn_get(s, ot);
+        val += s->pc - s->cs_base;
+        if (s->dflag == 0)
+            val = val & 0xffff;
         gen_op_jmp_im(val);
         s->is_jmp = 1;
         break;
+    case 0xea: /* ljmp im */
+        {
+            unsigned int selector, offset;
+
+            ot = dflag ? OT_LONG : OT_WORD;
+            offset = insn_get(s, ot);
+            selector = insn_get(s, OT_WORD);
+            
+            /* change cs and pc */
+            gen_op_movl_T0_im(selector);
+            gen_movl_seg_T0(s, R_CS);
+            gen_op_jmp_im((unsigned long)offset);
+            s->is_jmp = 1;
+        }
+        break;
     case 0xeb: /* jmp Jb */
         val = (int8_t)insn_get(s, OT_BYTE);
-        val += (long)s->pc;
+        val += s->pc - s->cs_base;
+        if (s->dflag == 0)
+            val = val & 0xffff;
         gen_op_jmp_im(val);
         s->is_jmp = 1;
         break;
     case 0x70 ... 0x7f: /* jcc Jb */
         val = (int8_t)insn_get(s, OT_BYTE);
-        val += (long)s->pc;
         goto do_jcc;
     case 0x180 ... 0x18f: /* jcc Jv */
         if (dflag) {
@@ -2628,9 +2899,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
         } else {
             val = (int16_t)insn_get(s, OT_WORD); 
         }
-        val += (long)s->pc; /* XXX: fix 16 bit wrap */
     do_jcc:
-        gen_jcc(s, b, val);
+        next_eip = s->pc - s->cs_base;
+        val += next_eip;
+        if (s->dflag == 0)
+            val &= 0xffff;
+        gen_jcc(s, b, val, next_eip);
         s->is_jmp = 1;
         break;
 
@@ -2661,11 +2935,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
         if (s->cc_op != CC_OP_DYNAMIC)
             gen_op_set_cc_op(s->cc_op);
         gen_op_movl_T0_eflags();
-        gen_op_pushl_T0();
+        gen_push_T0(s);
         break;
     case 0x9d: /* popf */
-        gen_op_popl_T0();
+        gen_pop_T0(s);
         gen_op_movl_eflags_T0();
+        gen_pop_update(s);
         s->cc_op = CC_OP_EFLAGS;
         break;
     case 0x9e: /* sahf */
@@ -2860,8 +3135,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
     case 0xe2: /* loop */
     case 0xe3: /* jecxz */
         val = (int8_t)insn_get(s, OT_BYTE);
-        val += (long)s->pc;
-        gen_op_loop[s->aflag][b & 3](val, (long)s->pc);
+        next_eip = s->pc - s->cs_base;
+        val += next_eip;
+        if (s->dflag == 0)
+            val &= 0xffff;
+        gen_op_loop[s->aflag][b & 3](val, next_eip);
         s->is_jmp = 1;
         break;
     case 0x131: /* rdtsc */
@@ -3203,8 +3481,8 @@ static uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
 
 /* return the next pc */
 int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, 
-                     int *gen_code_size_ptr, uint8_t *pc_start, 
-                     int flags)
+                     int *gen_code_size_ptr,
+                     uint8_t *pc_start,  uint8_t *cs_base, int flags)
 {
     DisasContext dc1, *dc = &dc1;
     uint8_t *pc_ptr;
@@ -3218,9 +3496,11 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
     /* generate intermediate code */
 
     dc->code32 = (flags >> GEN_FLAG_CODE32_SHIFT) & 1;
+    dc->ss32 = (flags >> GEN_FLAG_SS32_SHIFT) & 1;
     dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1;
     dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7;
     dc->cc_op = CC_OP_DYNAMIC;
+    dc->cs_base = cs_base;
 
     gen_opc_ptr = gen_opc_buf;
     gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
@@ -3242,7 +3522,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
         gen_op_set_cc_op(dc->cc_op);
     if (dc->is_jmp != 1) {
         /* we add an additionnal jmp to update the simulated PC */
-        gen_op_jmp_im(ret);
+        gen_op_jmp_im(ret - (unsigned long)dc->cs_base);
     }
     *gen_opc_ptr = INDEX_op_end;
 
@@ -3258,11 +3538,11 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
         disasm_info.arch = bfd_get_arch (abfd);
         disasm_info.mach = bfd_get_mach (abfd);
 #endif
-#ifdef WORDS_BIGENDIAN
-        disasm_info.endian = BFD_ENDIAN_BIG;
-#else
         disasm_info.endian = BFD_ENDIAN_LITTLE;
-#endif        
+        if (dc->code32)
+            disasm_info.mach = bfd_mach_i386_i386;
+        else
+            disasm_info.mach = bfd_mach_i386_i8086;
         fprintf(logfile, "----------------\n");
         fprintf(logfile, "IN:\n");
         disasm_info.buffer = pc_start;
@@ -3304,6 +3584,19 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
         uint8_t *pc;
         int count;
 
+        INIT_DISASSEMBLE_INFO(disasm_info, logfile, fprintf);
+#if 0        
+        disasm_info.flavour = bfd_get_flavour (abfd);
+        disasm_info.arch = bfd_get_arch (abfd);
+        disasm_info.mach = bfd_get_mach (abfd);
+#endif
+#ifdef WORDS_BIGENDIAN
+        disasm_info.endian = BFD_ENDIAN_BIG;
+#else
+        disasm_info.endian = BFD_ENDIAN_LITTLE;
+#endif        
+        disasm_info.mach = bfd_mach_i386_i386;
+
         pc = gen_code_buf;
         disasm_info.buffer = pc;
         disasm_info.buffer_vma = (unsigned long)pc;