diff options
-rw-r--r-- | TODO | 1 | ||||
-rw-r--r-- | cpu-i386.h | 10 | ||||
-rw-r--r-- | exec-i386.c | 17 | ||||
-rw-r--r-- | exec-i386.h | 2 | ||||
-rw-r--r-- | linux-user/main.c | 8 | ||||
-rw-r--r-- | linux-user/syscall.c | 37 | ||||
-rw-r--r-- | linux-user/syscall_defs.h | 16 | ||||
-rw-r--r-- | op-i386.c | 241 | ||||
-rw-r--r-- | opc-i386.h | 26 | ||||
-rw-r--r-- | ops_template.h | 40 | ||||
-rw-r--r-- | translate-i386.c | 413 |
11 files changed, 595 insertions, 216 deletions
@@ -1,3 +1,4 @@ +- overrides/16bit for string ops - optimize translated cache chaining (DLL PLT-like system) - 64 bit syscalls - signals diff --git a/cpu-i386.h b/cpu-i386.h index 550e18387f..9125ecadc5 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -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 */ diff --git a/exec-i386.c b/exec-i386.c index 0dbaccc830..e83d220369 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -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)); } diff --git a/exec-i386.h b/exec-i386.h index 0384d0bf22..f2e1386b57 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -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) diff --git a/linux-user/main.c b/linux-user/main.c index 45e81b207c..3222629b27 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -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(); } } diff --git a/linux-user/syscall.c b/linux-user/syscall.c index c0bee47f76..afdf189676 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -53,6 +53,7 @@ #include <linux/cdrom.h> #include <linux/hdreg.h> #include <linux/soundcard.h> +#include <linux/dirent.h> #include "gemu.h" @@ -63,13 +64,6 @@ #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: diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index dc44272dbb..8b2d6bd756 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -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 */ @@ -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(); } diff --git a/opc-i386.h b/opc-i386.h index aae289419c..0929044686 100644 --- a/opc-i386.h +++ b/opc-i386.h @@ -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) diff --git a/ops_template.h b/ops_template.h index bc96f651a2..70ee9f355c 100644 --- a/ops_template.h +++ b/ops_template.h @@ -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(); } diff --git a/translate-i386.c b/translate-i386.c index 4c052a4e47..5cbaa813ce 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -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, ®_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; |