提交 dab2ed99 编写于 作者: B bellard

better 16 bit code support


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@38 c046a42c-6fe2-441c-8c8c-71466251a162
上级 e5918247
- overrides/16bit for string ops
- optimize translated cache chaining (DLL PLT-like system) - optimize translated cache chaining (DLL PLT-like system)
- 64 bit syscalls - 64 bit syscalls
- signals - signals
......
...@@ -141,7 +141,7 @@ typedef struct SegmentDescriptorTable { ...@@ -141,7 +141,7 @@ typedef struct SegmentDescriptorTable {
typedef struct CPUX86State { typedef struct CPUX86State {
/* standard registers */ /* standard registers */
uint32_t regs[8]; uint32_t regs[8];
uint32_t pc; /* cs_case + eip value */ uint32_t eip;
uint32_t eflags; uint32_t eflags;
/* emulator internal eflags handling */ /* emulator internal eflags handling */
...@@ -392,10 +392,12 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector); ...@@ -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_CODE32_SHIFT 0
#define GEN_FLAG_ADDSEG_SHIFT 1 #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 cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
int *gen_code_size_ptr, uint8_t *pc_start, int *gen_code_size_ptr,
int flags); uint8_t *pc_start, uint8_t *cs_base, int flags);
void cpu_x86_tblocks_init(void); void cpu_x86_tblocks_init(void);
#endif /* CPU_I386_H */ #endif /* CPU_I386_H */
...@@ -38,7 +38,8 @@ ...@@ -38,7 +38,8 @@
#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS) #define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS)
typedef struct TranslationBlock { 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 */ unsigned int flags; /* flags defining in which context the code was generated */
uint8_t *tc_ptr; /* pointer to the translated code */ uint8_t *tc_ptr; /* pointer to the translated code */
struct TranslationBlock *hash_next; /* next matching block */ struct TranslationBlock *hash_next; /* next matching block */
...@@ -140,6 +141,7 @@ static void tb_flush(void) ...@@ -140,6 +141,7 @@ static void tb_flush(void)
/* find a translation block in the translation cache. If not found, /* find a translation block in the translation cache. If not found,
allocate a new one */ allocate a new one */
static inline TranslationBlock *tb_find_and_alloc(unsigned long pc, static inline TranslationBlock *tb_find_and_alloc(unsigned long pc,
unsigned long cs_base,
unsigned int flags) unsigned int flags)
{ {
TranslationBlock **ptb, *tb; TranslationBlock **ptb, *tb;
...@@ -151,7 +153,7 @@ static inline TranslationBlock *tb_find_and_alloc(unsigned long pc, ...@@ -151,7 +153,7 @@ static inline TranslationBlock *tb_find_and_alloc(unsigned long pc,
tb = *ptb; tb = *ptb;
if (!tb) if (!tb)
break; break;
if (tb->pc == pc && tb->flags == flags) if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
return tb; return tb;
ptb = &tb->hash_next; ptb = &tb->hash_next;
} }
...@@ -161,6 +163,7 @@ static inline TranslationBlock *tb_find_and_alloc(unsigned long pc, ...@@ -161,6 +163,7 @@ static inline TranslationBlock *tb_find_and_alloc(unsigned long pc,
tb = &tbs[nb_tbs++]; tb = &tbs[nb_tbs++];
*ptb = tb; *ptb = tb;
tb->pc = pc; tb->pc = pc;
tb->cs_base = cs_base;
tb->flags = flags; tb->flags = flags;
tb->tc_ptr = NULL; tb->tc_ptr = NULL;
tb->hash_next = NULL; tb->hash_next = NULL;
...@@ -198,7 +201,7 @@ int cpu_x86_exec(CPUX86State *env1) ...@@ -198,7 +201,7 @@ int cpu_x86_exec(CPUX86State *env1)
int code_gen_size, ret; int code_gen_size, ret;
void (*gen_func)(void); void (*gen_func)(void);
TranslationBlock *tb; TranslationBlock *tb;
uint8_t *tc_ptr; uint8_t *tc_ptr, *cs_base, *pc;
unsigned int flags; unsigned int flags;
/* first we save global registers */ /* first we save global registers */
...@@ -251,17 +254,21 @@ int cpu_x86_exec(CPUX86State *env1) ...@@ -251,17 +254,21 @@ int cpu_x86_exec(CPUX86State *env1)
/* we compute the CPU state. We assume it will not /* we compute the CPU state. We assume it will not
change during the whole generated block. */ change during the whole generated block. */
flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT; 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 | flags |= (((unsigned long)env->seg_cache[R_DS].base |
(unsigned long)env->seg_cache[R_ES].base | (unsigned long)env->seg_cache[R_ES].base |
(unsigned long)env->seg_cache[R_SS].base) != 0) << (unsigned long)env->seg_cache[R_SS].base) != 0) <<
GEN_FLAG_ADDSEG_SHIFT; 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; tc_ptr = tb->tc_ptr;
if (!tb->tc_ptr) { if (!tb->tc_ptr) {
/* if no translated code available, then translate it now */ /* if no translated code available, then translate it now */
tc_ptr = code_gen_ptr; tc_ptr = code_gen_ptr;
cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, 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; 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)); code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
} }
......
...@@ -111,7 +111,7 @@ register struct CPUX86State *env asm("l3"); ...@@ -111,7 +111,7 @@ register struct CPUX86State *env asm("l3");
#ifndef reg_EDI #ifndef reg_EDI
#define EDI (env->regs[R_EDI]) #define EDI (env->regs[R_EDI])
#endif #endif
#define PC (env->pc) #define EIP (env->eip)
#define DF (env->df) #define DF (env->df)
#define CC_SRC (env->cc_src) #define CC_SRC (env->cc_src)
......
...@@ -179,7 +179,7 @@ int main(int argc, char **argv) ...@@ -179,7 +179,7 @@ int main(int argc, char **argv)
env->regs[R_EDI] = regs->edi; env->regs[R_EDI] = regs->edi;
env->regs[R_EBP] = regs->ebp; env->regs[R_EBP] = regs->ebp;
env->regs[R_ESP] = regs->esp; env->regs[R_ESP] = regs->esp;
env->pc = regs->eip; env->eip = regs->eip;
/* linux segment setup */ /* linux segment setup */
env->gdt.base = (void *)gdt_table; env->gdt.base = (void *)gdt_table;
...@@ -198,12 +198,12 @@ int main(int argc, char **argv) ...@@ -198,12 +198,12 @@ int main(int argc, char **argv)
uint8_t *pc; uint8_t *pc;
err = cpu_x86_exec(env); err = cpu_x86_exec(env);
pc = env->seg_cache[R_CS].base + env->eip;
switch(err) { switch(err) {
case EXCP0D_GPF: case EXCP0D_GPF:
pc = (uint8_t *)env->pc;
if (pc[0] == 0xcd && pc[1] == 0x80) { if (pc[0] == 0xcd && pc[1] == 0x80) {
/* syscall */ /* syscall */
env->pc += 2; env->eip += 2;
env->regs[R_EAX] = do_syscall(env, env->regs[R_EAX] = do_syscall(env,
env->regs[R_EAX], env->regs[R_EAX],
env->regs[R_EBX], env->regs[R_EBX],
...@@ -219,7 +219,7 @@ int main(int argc, char **argv) ...@@ -219,7 +219,7 @@ int main(int argc, char **argv)
default: default:
trap_error: trap_error:
fprintf(stderr, "0x%08lx: Unknown exception %d, aborting\n", fprintf(stderr, "0x%08lx: Unknown exception %d, aborting\n",
(long)env->pc, err); (long)pc, err);
abort(); abort();
} }
} }
......
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
#include <linux/cdrom.h> #include <linux/cdrom.h>
#include <linux/hdreg.h> #include <linux/hdreg.h>
#include <linux/soundcard.h> #include <linux/soundcard.h>
#include <linux/dirent.h>
#include "gemu.h" #include "gemu.h"
...@@ -63,13 +64,6 @@ ...@@ -63,13 +64,6 @@
#define PAGE_MASK ~(PAGE_SIZE - 1) #define PAGE_MASK ~(PAGE_SIZE - 1)
#endif #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> //#include <linux/msdos_fs.h>
#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2]) #define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2])
#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2]) #define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2])
...@@ -86,6 +80,7 @@ struct dirent { ...@@ -86,6 +80,7 @@ struct dirent {
#define __NR_sys_statfs __NR_statfs #define __NR_sys_statfs __NR_statfs
#define __NR_sys_fstatfs __NR_fstatfs #define __NR_sys_fstatfs __NR_fstatfs
#define __NR_sys_getdents __NR_getdents #define __NR_sys_getdents __NR_getdents
#define __NR_sys_getdents64 __NR_getdents64
#ifdef __NR_gettid #ifdef __NR_gettid
_syscall0(int, gettid) _syscall0(int, gettid)
...@@ -97,6 +92,7 @@ static int gettid(void) { ...@@ -97,6 +92,7 @@ static int gettid(void) {
_syscall1(int,sys_uname,struct new_utsname *,buf) _syscall1(int,sys_uname,struct new_utsname *,buf)
_syscall2(int,sys_getcwd1,char *,buf,size_t,size) _syscall2(int,sys_getcwd1,char *,buf,size_t,size)
_syscall3(int, sys_getdents, uint, fd, struct dirent *, dirp, uint, count); _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, _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
loff_t *, res, uint, wh); loff_t *, res, uint, wh);
_syscall2(int,sys_statfs,const char *,path,struct kernel_statfs *,buf) _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, ...@@ -1005,7 +1001,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
ret = get_errno(setsid()); ret = get_errno(setsid());
break; break;
case TARGET_NR_sigaction: case TARGET_NR_sigaction:
#if 0 #if 1
{ {
ret = 0; ret = 0;
} }
...@@ -1336,6 +1332,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ...@@ -1336,6 +1332,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
{ {
struct dirent *dirp = (void *)arg2; struct dirent *dirp = (void *)arg2;
long count = arg3; long count = arg3;
ret = get_errno(sys_getdents(arg1, dirp, count)); ret = get_errno(sys_getdents(arg1, dirp, count));
if (!is_error(ret)) { if (!is_error(ret)) {
struct dirent *de; struct dirent *de;
...@@ -1355,6 +1352,29 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ...@@ -1355,6 +1352,29 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
} }
} }
break; 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: case TARGET_NR__newselect:
ret = do_select(arg1, (void *)arg2, (void *)arg3, (void *)arg4, ret = do_select(arg1, (void *)arg2, (void *)arg3, (void *)arg4,
(void *)arg5); (void *)arg5);
...@@ -1519,7 +1539,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ...@@ -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_pivot_root:
case TARGET_NR_mincore: case TARGET_NR_mincore:
case TARGET_NR_madvise: case TARGET_NR_madvise:
case TARGET_NR_getdents64:
goto unimplemented; goto unimplemented;
#if TARGET_LONG_BITS == 32 #if TARGET_LONG_BITS == 32
case TARGET_NR_fcntl64: case TARGET_NR_fcntl64:
......
...@@ -75,6 +75,22 @@ struct kernel_statfs { ...@@ -75,6 +75,22 @@ struct kernel_statfs {
int f_spare[6]; 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 */ /* mostly generic signal stuff */
#define TARGET_SIG_DFL ((target_long)0) /* default signal handling */ #define TARGET_SIG_DFL ((target_long)0) /* default signal handling */
#define TARGET_SIG_IGN ((target_long)1) /* ignore signal */ #define TARGET_SIG_IGN ((target_long)1) /* ignore signal */
......
...@@ -464,18 +464,43 @@ void OPPROTO op_idivl_EAX_T0(void) ...@@ -464,18 +464,43 @@ void OPPROTO op_idivl_EAX_T0(void)
EDX = r; EDX = r;
} }
/* constant load */ /* constant load & misc op */
void OPPROTO op_movl_T0_im(void) void OPPROTO op_movl_T0_im(void)
{ {
T0 = PARAM1; 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) void OPPROTO op_movl_T1_im(void)
{ {
T1 = PARAM1; 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) void OPPROTO op_movl_A0_im(void)
{ {
A0 = PARAM1; A0 = PARAM1;
...@@ -574,23 +599,23 @@ void OPPROTO op_add_bitl_A0_T1(void) ...@@ -574,23 +599,23 @@ void OPPROTO op_add_bitl_A0_T1(void)
void OPPROTO op_jmp_T0(void) void OPPROTO op_jmp_T0(void)
{ {
PC = T0; EIP = T0;
} }
void OPPROTO op_jmp_im(void) void OPPROTO op_jmp_im(void)
{ {
PC = PARAM1; EIP = PARAM1;
} }
void OPPROTO op_int_im(void) void OPPROTO op_int_im(void)
{ {
PC = PARAM1; EIP = PARAM1;
raise_exception(EXCP0D_GPF); raise_exception(EXCP0D_GPF);
} }
void OPPROTO op_int3(void) void OPPROTO op_int3(void)
{ {
PC = PARAM1; EIP = PARAM1;
raise_exception(EXCP03_INT3); raise_exception(EXCP03_INT3);
} }
...@@ -599,10 +624,10 @@ void OPPROTO op_into(void) ...@@ -599,10 +624,10 @@ void OPPROTO op_into(void)
int eflags; int eflags;
eflags = cc_table[CC_OP].compute_all(); eflags = cc_table[CC_OP].compute_all();
if (eflags & CC_O) { if (eflags & CC_O) {
PC = PARAM1; EIP = PARAM1;
raise_exception(EXCP04_INTO); raise_exception(EXCP04_INTO);
} else { } else {
PC = PARAM2; EIP = PARAM2;
} }
} }
...@@ -665,7 +690,6 @@ void OPPROTO op_movswl_DX_AX(void) ...@@ -665,7 +690,6 @@ void OPPROTO op_movswl_DX_AX(void)
} }
/* push/pop */ /* push/pop */
/* XXX: add 16 bit operand/16 bit seg variants */
void op_pushl_T0(void) void op_pushl_T0(void)
{ {
...@@ -676,107 +700,110 @@ void op_pushl_T0(void) ...@@ -676,107 +700,110 @@ void op_pushl_T0(void)
ESP = offset; 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; uint32_t offset;
offset = ESP - 4; offset = ESP - 4;
stl((void *)offset, T1); stl(env->seg_cache[R_SS].base + offset, T0);
/* modify ESP after to handle exceptions correctly */ /* modify ESP after to handle exceptions correctly */
ESP = offset; 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) void op_popl_T0(void)
{ {
T0 = ldl((void *)ESP); 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; 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) void op_addl_ESP_im(void)
{ {
ESP += PARAM1; ESP += PARAM1;
} }
void op_pushal(void) void op_addw_ESP_im(void)
{ {
uint8_t *sp; ESP = (ESP & ~0xffff) | ((ESP + PARAM1) & 0xffff);
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;
} }
/* rdtsc */ /* rdtsc */
...@@ -988,18 +1015,18 @@ void OPPROTO op_jo_cc(void) ...@@ -988,18 +1015,18 @@ void OPPROTO op_jo_cc(void)
int eflags; int eflags;
eflags = cc_table[CC_OP].compute_all(); eflags = cc_table[CC_OP].compute_all();
if (eflags & CC_O) if (eflags & CC_O)
PC = PARAM1; EIP = PARAM1;
else else
PC = PARAM2; EIP = PARAM2;
FORCE_RET(); FORCE_RET();
} }
void OPPROTO op_jb_cc(void) void OPPROTO op_jb_cc(void)
{ {
if (cc_table[CC_OP].compute_c()) if (cc_table[CC_OP].compute_c())
PC = PARAM1; EIP = PARAM1;
else else
PC = PARAM2; EIP = PARAM2;
FORCE_RET(); FORCE_RET();
} }
...@@ -1008,9 +1035,9 @@ void OPPROTO op_jz_cc(void) ...@@ -1008,9 +1035,9 @@ void OPPROTO op_jz_cc(void)
int eflags; int eflags;
eflags = cc_table[CC_OP].compute_all(); eflags = cc_table[CC_OP].compute_all();
if (eflags & CC_Z) if (eflags & CC_Z)
PC = PARAM1; EIP = PARAM1;
else else
PC = PARAM2; EIP = PARAM2;
FORCE_RET(); FORCE_RET();
} }
...@@ -1019,9 +1046,9 @@ void OPPROTO op_jbe_cc(void) ...@@ -1019,9 +1046,9 @@ void OPPROTO op_jbe_cc(void)
int eflags; int eflags;
eflags = cc_table[CC_OP].compute_all(); eflags = cc_table[CC_OP].compute_all();
if (eflags & (CC_Z | CC_C)) if (eflags & (CC_Z | CC_C))
PC = PARAM1; EIP = PARAM1;
else else
PC = PARAM2; EIP = PARAM2;
FORCE_RET(); FORCE_RET();
} }
...@@ -1030,9 +1057,9 @@ void OPPROTO op_js_cc(void) ...@@ -1030,9 +1057,9 @@ void OPPROTO op_js_cc(void)
int eflags; int eflags;
eflags = cc_table[CC_OP].compute_all(); eflags = cc_table[CC_OP].compute_all();
if (eflags & CC_S) if (eflags & CC_S)
PC = PARAM1; EIP = PARAM1;
else else
PC = PARAM2; EIP = PARAM2;
FORCE_RET(); FORCE_RET();
} }
...@@ -1041,9 +1068,9 @@ void OPPROTO op_jp_cc(void) ...@@ -1041,9 +1068,9 @@ void OPPROTO op_jp_cc(void)
int eflags; int eflags;
eflags = cc_table[CC_OP].compute_all(); eflags = cc_table[CC_OP].compute_all();
if (eflags & CC_P) if (eflags & CC_P)
PC = PARAM1; EIP = PARAM1;
else else
PC = PARAM2; EIP = PARAM2;
FORCE_RET(); FORCE_RET();
} }
...@@ -1052,9 +1079,9 @@ void OPPROTO op_jl_cc(void) ...@@ -1052,9 +1079,9 @@ void OPPROTO op_jl_cc(void)
int eflags; int eflags;
eflags = cc_table[CC_OP].compute_all(); eflags = cc_table[CC_OP].compute_all();
if ((eflags ^ (eflags >> 4)) & 0x80) if ((eflags ^ (eflags >> 4)) & 0x80)
PC = PARAM1; EIP = PARAM1;
else else
PC = PARAM2; EIP = PARAM2;
FORCE_RET(); FORCE_RET();
} }
...@@ -1063,9 +1090,9 @@ void OPPROTO op_jle_cc(void) ...@@ -1063,9 +1090,9 @@ void OPPROTO op_jle_cc(void)
int eflags; int eflags;
eflags = cc_table[CC_OP].compute_all(); eflags = cc_table[CC_OP].compute_all();
if (((eflags ^ (eflags >> 4)) & 0x80) || (eflags & CC_Z)) if (((eflags ^ (eflags >> 4)) & 0x80) || (eflags & CC_Z))
PC = PARAM1; EIP = PARAM1;
else else
PC = PARAM2; EIP = PARAM2;
FORCE_RET(); FORCE_RET();
} }
......
...@@ -202,7 +202,12 @@ DEF(idivw_AX_T0) ...@@ -202,7 +202,12 @@ DEF(idivw_AX_T0)
DEF(divl_EAX_T0) DEF(divl_EAX_T0)
DEF(idivl_EAX_T0) DEF(idivl_EAX_T0)
DEF(movl_T0_im) DEF(movl_T0_im)
DEF(addl_T0_im)
DEF(andl_T0_ffff)
DEF(movl_T0_T1)
DEF(movl_T1_im) DEF(movl_T1_im)
DEF(addl_T1_im)
DEF(movl_T1_A0)
DEF(movl_A0_im) DEF(movl_A0_im)
DEF(addl_A0_im) DEF(addl_A0_im)
DEF(andl_A0_ffff) DEF(andl_A0_ffff)
...@@ -398,14 +403,23 @@ DEF(movsbw_AX_AL) ...@@ -398,14 +403,23 @@ DEF(movsbw_AX_AL)
DEF(movslq_EDX_EAX) DEF(movslq_EDX_EAX)
DEF(movswl_DX_AX) DEF(movswl_DX_AX)
DEF(pushl_T0) 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(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(addl_ESP_im)
DEF(pushal) DEF(addw_ESP_im)
DEF(pushaw)
DEF(popal)
DEF(popaw)
DEF(enterl)
DEF(rdtsc) DEF(rdtsc)
DEF(aam) DEF(aam)
DEF(aad) DEF(aad)
......
...@@ -214,18 +214,18 @@ void OPPROTO glue(op_jb_sub, SUFFIX)(void) ...@@ -214,18 +214,18 @@ void OPPROTO glue(op_jb_sub, SUFFIX)(void)
src2 = CC_SRC - CC_DST; src2 = CC_SRC - CC_DST;
if ((DATA_TYPE)src1 < (DATA_TYPE)src2) if ((DATA_TYPE)src1 < (DATA_TYPE)src2)
PC = PARAM1; EIP = PARAM1;
else else
PC = PARAM2; EIP = PARAM2;
FORCE_RET(); FORCE_RET();
} }
void OPPROTO glue(op_jz_sub, SUFFIX)(void) void OPPROTO glue(op_jz_sub, SUFFIX)(void)
{ {
if ((DATA_TYPE)CC_DST == 0) if ((DATA_TYPE)CC_DST == 0)
PC = PARAM1; EIP = PARAM1;
else else
PC = PARAM2; EIP = PARAM2;
FORCE_RET(); FORCE_RET();
} }
...@@ -236,18 +236,18 @@ void OPPROTO glue(op_jbe_sub, SUFFIX)(void) ...@@ -236,18 +236,18 @@ void OPPROTO glue(op_jbe_sub, SUFFIX)(void)
src2 = CC_SRC - CC_DST; src2 = CC_SRC - CC_DST;
if ((DATA_TYPE)src1 <= (DATA_TYPE)src2) if ((DATA_TYPE)src1 <= (DATA_TYPE)src2)
PC = PARAM1; EIP = PARAM1;
else else
PC = PARAM2; EIP = PARAM2;
FORCE_RET(); FORCE_RET();
} }
void OPPROTO glue(op_js_sub, SUFFIX)(void) void OPPROTO glue(op_js_sub, SUFFIX)(void)
{ {
if (CC_DST & SIGN_MASK) if (CC_DST & SIGN_MASK)
PC = PARAM1; EIP = PARAM1;
else else
PC = PARAM2; EIP = PARAM2;
FORCE_RET(); FORCE_RET();
} }
...@@ -258,9 +258,9 @@ void OPPROTO glue(op_jl_sub, SUFFIX)(void) ...@@ -258,9 +258,9 @@ void OPPROTO glue(op_jl_sub, SUFFIX)(void)
src2 = CC_SRC - CC_DST; src2 = CC_SRC - CC_DST;
if ((DATA_STYPE)src1 < (DATA_STYPE)src2) if ((DATA_STYPE)src1 < (DATA_STYPE)src2)
PC = PARAM1; EIP = PARAM1;
else else
PC = PARAM2; EIP = PARAM2;
FORCE_RET(); FORCE_RET();
} }
...@@ -271,9 +271,9 @@ void OPPROTO glue(op_jle_sub, SUFFIX)(void) ...@@ -271,9 +271,9 @@ void OPPROTO glue(op_jle_sub, SUFFIX)(void)
src2 = CC_SRC - CC_DST; src2 = CC_SRC - CC_DST;
if ((DATA_STYPE)src1 <= (DATA_STYPE)src2) if ((DATA_STYPE)src1 <= (DATA_STYPE)src2)
PC = PARAM1; EIP = PARAM1;
else else
PC = PARAM2; EIP = PARAM2;
FORCE_RET(); FORCE_RET();
} }
...@@ -289,9 +289,9 @@ void OPPROTO glue(op_loopnz, SUFFIX)(void) ...@@ -289,9 +289,9 @@ void OPPROTO glue(op_loopnz, SUFFIX)(void)
tmp = (ECX - 1) & DATA_MASK; tmp = (ECX - 1) & DATA_MASK;
ECX = (ECX & ~DATA_MASK) | tmp; ECX = (ECX & ~DATA_MASK) | tmp;
if (tmp != 0 && !(eflags & CC_Z)) if (tmp != 0 && !(eflags & CC_Z))
PC = PARAM1; EIP = PARAM1;
else else
PC = PARAM2; EIP = PARAM2;
FORCE_RET(); FORCE_RET();
} }
...@@ -303,9 +303,9 @@ void OPPROTO glue(op_loopz, SUFFIX)(void) ...@@ -303,9 +303,9 @@ void OPPROTO glue(op_loopz, SUFFIX)(void)
tmp = (ECX - 1) & DATA_MASK; tmp = (ECX - 1) & DATA_MASK;
ECX = (ECX & ~DATA_MASK) | tmp; ECX = (ECX & ~DATA_MASK) | tmp;
if (tmp != 0 && (eflags & CC_Z)) if (tmp != 0 && (eflags & CC_Z))
PC = PARAM1; EIP = PARAM1;
else else
PC = PARAM2; EIP = PARAM2;
FORCE_RET(); FORCE_RET();
} }
...@@ -315,18 +315,18 @@ void OPPROTO glue(op_loop, SUFFIX)(void) ...@@ -315,18 +315,18 @@ void OPPROTO glue(op_loop, SUFFIX)(void)
tmp = (ECX - 1) & DATA_MASK; tmp = (ECX - 1) & DATA_MASK;
ECX = (ECX & ~DATA_MASK) | tmp; ECX = (ECX & ~DATA_MASK) | tmp;
if (tmp != 0) if (tmp != 0)
PC = PARAM1; EIP = PARAM1;
else else
PC = PARAM2; EIP = PARAM2;
FORCE_RET(); FORCE_RET();
} }
void OPPROTO glue(op_jecxz, SUFFIX)(void) void OPPROTO glue(op_jecxz, SUFFIX)(void)
{ {
if ((DATA_TYPE)ECX == 0) if ((DATA_TYPE)ECX == 0)
PC = PARAM1; EIP = PARAM1;
else else
PC = PARAM2; EIP = PARAM2;
FORCE_RET(); FORCE_RET();
} }
......
...@@ -92,11 +92,13 @@ typedef struct DisasContext { ...@@ -92,11 +92,13 @@ typedef struct DisasContext {
/* current insn context */ /* current insn context */
int prefix; int prefix;
int aflag, dflag; 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 int is_jmp; /* 1 = means jump (stop translation), 2 means CPU
static state change (stop translation) */ static state change (stop translation) */
/* current block context */ /* current block context */
uint8_t *cs_base; /* base of CS segment */
int code32; /* 32 bit code segment */ int code32; /* 32 bit code segment */
int ss32; /* 32 bit stack segment */
int cc_op; /* current CC operation */ int cc_op; /* current CC operation */
int addseg; /* non zero if either DS/ES/SS have a non zero base */ int addseg; /* non zero if either DS/ES/SS have a non zero base */
int f_st; /* currently unused */ int f_st; /* currently unused */
...@@ -1051,7 +1053,7 @@ static inline uint32_t insn_get(DisasContext *s, int ot) ...@@ -1051,7 +1053,7 @@ static inline uint32_t insn_get(DisasContext *s, int ot)
return ret; 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; int inv, jcc_op;
GenOpFunc2 *func; GenOpFunc2 *func;
...@@ -1112,9 +1114,9 @@ static void gen_jcc(DisasContext *s, int b, int val) ...@@ -1112,9 +1114,9 @@ static void gen_jcc(DisasContext *s, int b, int val)
break; break;
} }
if (!inv) { if (!inv) {
func(val, (long)s->pc); func(val, next_eip);
} else { } else {
func((long)s->pc, val); func(next_eip, val);
} }
} }
...@@ -1176,7 +1178,7 @@ static void gen_setcc(DisasContext *s, int b) ...@@ -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 */ /* 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); gen_op_movl_seg_T0(seg_reg);
if (!s->addseg && seg_reg < R_FS) if (!s->addseg && seg_reg < R_FS)
...@@ -1184,6 +1186,148 @@ void gen_movl_seg_T0(DisasContext *s, int seg_reg) ...@@ -1184,6 +1186,148 @@ void gen_movl_seg_T0(DisasContext *s, int seg_reg)
have a non zero base */ 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 /* 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 is set to true if the instruction sets the PC (last instruction of
a basic block) */ a basic block) */
...@@ -1192,6 +1336,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) ...@@ -1192,6 +1336,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
int b, prefixes, aflag, dflag; int b, prefixes, aflag, dflag;
int shift, ot; int shift, ot;
int modrm, reg, rm, mod, reg_addr, op, opreg, offset_addr, val; int modrm, reg, rm, mod, reg_addr, op, opreg, offset_addr, val;
unsigned int next_eip;
s->pc = pc_start; s->pc = pc_start;
prefixes = 0; prefixes = 0;
...@@ -1492,7 +1637,8 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) ...@@ -1492,7 +1637,8 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
} }
if (mod != 3) { if (mod != 3) {
gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); 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 { } else {
gen_op_mov_TN_reg[ot][0][rm](); gen_op_mov_TN_reg[ot][0][rm]();
} }
...@@ -1513,17 +1659,48 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) ...@@ -1513,17 +1659,48 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
gen_op_mov_reg_T0[ot][rm](); gen_op_mov_reg_T0[ot][rm]();
break; break;
case 2: /* call Ev */ case 2: /* call Ev */
gen_op_movl_T1_im((long)s->pc); /* XXX: optimize if memory (no and is necessary) */
gen_op_pushl_T1(); 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(); gen_op_jmp_T0();
s->is_jmp = 1; s->is_jmp = 1;
break; break;
case 4: /* jmp Ev */ 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(); gen_op_jmp_T0();
s->is_jmp = 1; s->is_jmp = 1;
break; break;
case 6: /* push Ev */ case 6: /* push Ev */
gen_op_pushl_T0(); gen_push_T0(s);
break; break;
default: default:
goto illegal_op; goto illegal_op;
...@@ -1653,23 +1830,19 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) ...@@ -1653,23 +1830,19 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
/* push/pop */ /* push/pop */
case 0x50 ... 0x57: /* push */ case 0x50 ... 0x57: /* push */
gen_op_mov_TN_reg[OT_LONG][0][b & 7](); gen_op_mov_TN_reg[OT_LONG][0][b & 7]();
gen_op_pushl_T0(); gen_push_T0(s);
break; break;
case 0x58 ... 0x5f: /* pop */ case 0x58 ... 0x5f: /* pop */
gen_op_popl_T0(); ot = dflag ? OT_LONG : OT_WORD;
gen_op_mov_reg_T0[OT_LONG][b & 7](); gen_pop_T0(s);
gen_op_mov_reg_T0[ot][b & 7]();
gen_pop_update(s);
break; break;
case 0x60: /* pusha */ case 0x60: /* pusha */
if (s->dflag) gen_pusha(s);
gen_op_pushal();
else
gen_op_pushaw();
break; break;
case 0x61: /* popa */ case 0x61: /* popa */
if (s->dflag) gen_popa(s);
gen_op_popal();
else
gen_op_popaw();
break; break;
case 0x68: /* push Iv */ case 0x68: /* push Iv */
case 0x6a: case 0x6a:
...@@ -1679,13 +1852,14 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) ...@@ -1679,13 +1852,14 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
else else
val = (int8_t)insn_get(s, OT_BYTE); val = (int8_t)insn_get(s, OT_BYTE);
gen_op_movl_T0_im(val); gen_op_movl_T0_im(val);
gen_op_pushl_T0(); gen_push_T0(s);
break; break;
case 0x8f: /* pop Ev */ case 0x8f: /* pop Ev */
ot = dflag ? OT_LONG : OT_WORD; ot = dflag ? OT_LONG : OT_WORD;
modrm = ldub(s->pc++); modrm = ldub(s->pc++);
gen_op_popl_T0(); gen_pop_T0(s);
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
gen_pop_update(s);
break; break;
case 0xc8: /* enter */ case 0xc8: /* enter */
{ {
...@@ -1693,38 +1867,47 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) ...@@ -1693,38 +1867,47 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
val = lduw(s->pc); val = lduw(s->pc);
s->pc += 2; s->pc += 2;
level = ldub(s->pc++); level = ldub(s->pc++);
level &= 0x1f; gen_enter(s, val, level);
gen_op_enterl(val, level);
} }
break; break;
case 0xc9: /* leave */ case 0xc9: /* leave */
gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); /* XXX: exception not precise (ESP is update before potential exception) */
gen_op_mov_reg_T0[OT_LONG][R_ESP](); if (s->ss32) {
gen_op_popl_T0(); gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
gen_op_mov_reg_T0[OT_LONG][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; break;
case 0x06: /* push es */ case 0x06: /* push es */
case 0x0e: /* push cs */ case 0x0e: /* push cs */
case 0x16: /* push ss */ case 0x16: /* push ss */
case 0x1e: /* push ds */ case 0x1e: /* push ds */
gen_op_movl_T0_seg(b >> 3); gen_op_movl_T0_seg(b >> 3);
gen_op_pushl_T0(); gen_push_T0(s);
break; break;
case 0x1a0: /* push fs */ case 0x1a0: /* push fs */
case 0x1a8: /* push gs */ case 0x1a8: /* push gs */
gen_op_movl_T0_seg(((b >> 3) & 7) + R_FS); gen_op_movl_T0_seg(((b >> 3) & 7) + R_FS);
gen_op_pushl_T0(); gen_push_T0(s);
break; break;
case 0x07: /* pop es */ case 0x07: /* pop es */
case 0x17: /* pop ss */ case 0x17: /* pop ss */
case 0x1f: /* pop ds */ case 0x1f: /* pop ds */
gen_op_popl_T0(); gen_pop_T0(s);
gen_movl_seg_T0(s, b >> 3); gen_movl_seg_T0(s, b >> 3);
gen_pop_update(s);
break; break;
case 0x1a1: /* pop fs */ case 0x1a1: /* pop fs */
case 0x1a9: /* pop gs */ case 0x1a9: /* pop gs */
gen_op_popl_T0(); gen_pop_T0(s);
gen_movl_seg_T0(s, ((b >> 3) & 7) + R_FS); gen_movl_seg_T0(s, ((b >> 3) & 7) + R_FS);
gen_pop_update(s);
break; break;
/**************************/ /**************************/
...@@ -1775,7 +1958,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) ...@@ -1775,7 +1958,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
modrm = ldub(s->pc++); modrm = ldub(s->pc++);
reg = (modrm >> 3) & 7; reg = (modrm >> 3) & 7;
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
if (reg >= 6) if (reg >= 6 || reg == R_CS)
goto illegal_op; goto illegal_op;
gen_movl_seg_T0(s, reg); gen_movl_seg_T0(s, reg);
break; break;
...@@ -2585,42 +2768,130 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) ...@@ -2585,42 +2768,130 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
/************************/ /************************/
/* control */ /* control */
case 0xc2: /* ret im */ case 0xc2: /* ret im */
/* XXX: handle stack pop ? */
val = ldsw(s->pc); val = ldsw(s->pc);
s->pc += 2; s->pc += 2;
gen_op_popl_T0(); gen_pop_T0(s);
gen_op_addl_ESP_im(val); 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(); gen_op_jmp_T0();
s->is_jmp = 1; s->is_jmp = 1;
break; break;
case 0xc3: /* ret */ 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(); gen_op_jmp_T0();
s->is_jmp = 1; s->is_jmp = 1;
break; break;
case 0xe8: /* call */ case 0xca: /* lret im */
val = insn_get(s, OT_LONG); val = ldsw(s->pc);
val += (long)s->pc; s->pc += 2;
gen_op_movl_T1_im((long)s->pc); /* pop offset */
gen_op_pushl_T1(); gen_pop_T0(s);
gen_op_jmp_im(val); 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; s->is_jmp = 1;
break; 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 */ case 0xe9: /* jmp */
val = insn_get(s, OT_LONG); ot = dflag ? OT_LONG : OT_WORD;
val += (long)s->pc; val = insn_get(s, ot);
val += s->pc - s->cs_base;
if (s->dflag == 0)
val = val & 0xffff;
gen_op_jmp_im(val); gen_op_jmp_im(val);
s->is_jmp = 1; s->is_jmp = 1;
break; 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 */ case 0xeb: /* jmp Jb */
val = (int8_t)insn_get(s, OT_BYTE); 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); gen_op_jmp_im(val);
s->is_jmp = 1; s->is_jmp = 1;
break; break;
case 0x70 ... 0x7f: /* jcc Jb */ case 0x70 ... 0x7f: /* jcc Jb */
val = (int8_t)insn_get(s, OT_BYTE); val = (int8_t)insn_get(s, OT_BYTE);
val += (long)s->pc;
goto do_jcc; goto do_jcc;
case 0x180 ... 0x18f: /* jcc Jv */ case 0x180 ... 0x18f: /* jcc Jv */
if (dflag) { if (dflag) {
...@@ -2628,9 +2899,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) ...@@ -2628,9 +2899,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
} else { } else {
val = (int16_t)insn_get(s, OT_WORD); val = (int16_t)insn_get(s, OT_WORD);
} }
val += (long)s->pc; /* XXX: fix 16 bit wrap */
do_jcc: 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; s->is_jmp = 1;
break; break;
...@@ -2661,11 +2935,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) ...@@ -2661,11 +2935,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
if (s->cc_op != CC_OP_DYNAMIC) if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op); gen_op_set_cc_op(s->cc_op);
gen_op_movl_T0_eflags(); gen_op_movl_T0_eflags();
gen_op_pushl_T0(); gen_push_T0(s);
break; break;
case 0x9d: /* popf */ case 0x9d: /* popf */
gen_op_popl_T0(); gen_pop_T0(s);
gen_op_movl_eflags_T0(); gen_op_movl_eflags_T0();
gen_pop_update(s);
s->cc_op = CC_OP_EFLAGS; s->cc_op = CC_OP_EFLAGS;
break; break;
case 0x9e: /* sahf */ case 0x9e: /* sahf */
...@@ -2860,8 +3135,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) ...@@ -2860,8 +3135,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
case 0xe2: /* loop */ case 0xe2: /* loop */
case 0xe3: /* jecxz */ case 0xe3: /* jecxz */
val = (int8_t)insn_get(s, OT_BYTE); val = (int8_t)insn_get(s, OT_BYTE);
val += (long)s->pc; next_eip = s->pc - s->cs_base;
gen_op_loop[s->aflag][b & 3](val, (long)s->pc); val += next_eip;
if (s->dflag == 0)
val &= 0xffff;
gen_op_loop[s->aflag][b & 3](val, next_eip);
s->is_jmp = 1; s->is_jmp = 1;
break; break;
case 0x131: /* rdtsc */ case 0x131: /* rdtsc */
...@@ -3203,8 +3481,8 @@ static uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE]; ...@@ -3203,8 +3481,8 @@ static uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
/* return the next pc */ /* return the next pc */
int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
int *gen_code_size_ptr, uint8_t *pc_start, int *gen_code_size_ptr,
int flags) uint8_t *pc_start, uint8_t *cs_base, int flags)
{ {
DisasContext dc1, *dc = &dc1; DisasContext dc1, *dc = &dc1;
uint8_t *pc_ptr; uint8_t *pc_ptr;
...@@ -3218,9 +3496,11 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, ...@@ -3218,9 +3496,11 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
/* generate intermediate code */ /* generate intermediate code */
dc->code32 = (flags >> GEN_FLAG_CODE32_SHIFT) & 1; 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->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1;
dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7; dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7;
dc->cc_op = CC_OP_DYNAMIC; dc->cc_op = CC_OP_DYNAMIC;
dc->cs_base = cs_base;
gen_opc_ptr = gen_opc_buf; gen_opc_ptr = gen_opc_buf;
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; 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, ...@@ -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); gen_op_set_cc_op(dc->cc_op);
if (dc->is_jmp != 1) { if (dc->is_jmp != 1) {
/* we add an additionnal jmp to update the simulated PC */ /* 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; *gen_opc_ptr = INDEX_op_end;
...@@ -3258,11 +3538,11 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, ...@@ -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.arch = bfd_get_arch (abfd);
disasm_info.mach = bfd_get_mach (abfd); disasm_info.mach = bfd_get_mach (abfd);
#endif #endif
#ifdef WORDS_BIGENDIAN
disasm_info.endian = BFD_ENDIAN_BIG;
#else
disasm_info.endian = BFD_ENDIAN_LITTLE; 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, "----------------\n");
fprintf(logfile, "IN:\n"); fprintf(logfile, "IN:\n");
disasm_info.buffer = pc_start; disasm_info.buffer = pc_start;
...@@ -3304,6 +3584,19 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, ...@@ -3304,6 +3584,19 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
uint8_t *pc; uint8_t *pc;
int count; 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; pc = gen_code_buf;
disasm_info.buffer = pc; disasm_info.buffer = pc;
disasm_info.buffer_vma = (unsigned long)pc; disasm_info.buffer_vma = (unsigned long)pc;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册