#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])
#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)
_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)
ret = get_errno(setsid());
break;
case TARGET_NR_sigaction:
-#if 0
+#if 1
{
ret = 0;
}
{
struct dirent *dirp = (void *)arg2;
long count = arg3;
+
ret = get_errno(sys_getdents(arg1, dirp, count));
if (!is_error(ret)) {
struct dirent *de;
}
}
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);
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:
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;
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);
}
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;
}
}
}
/* push/pop */
-/* XXX: add 16 bit operand/16 bit seg variants */
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 */
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();
}
int eflags;
eflags = cc_table[CC_OP].compute_all();
if (eflags & CC_Z)
- PC = PARAM1;
+ EIP = PARAM1;
else
- PC = PARAM2;
+ EIP = PARAM2;
FORCE_RET();
}
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();
}
int eflags;
eflags = cc_table[CC_OP].compute_all();
if (eflags & CC_S)
- PC = PARAM1;
+ EIP = PARAM1;
else
- PC = PARAM2;
+ EIP = PARAM2;
FORCE_RET();
}
int eflags;
eflags = cc_table[CC_OP].compute_all();
if (eflags & CC_P)
- PC = PARAM1;
+ EIP = PARAM1;
else
- PC = PARAM2;
+ EIP = PARAM2;
FORCE_RET();
}
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();
}
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();
}
/* 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 */
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;
break;
}
if (!inv) {
- func(val, (long)s->pc);
+ func(val, next_eip);
} else {
- func((long)s->pc, val);
+ func(next_eip, val);
}
}
}
/* 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)
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) */
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;
}
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]();
}
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;
/* 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:
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 */
{
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;
/**************************/
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;
/************************/
/* 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) {
} 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;
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 */
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 */
/* 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;
/* 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;
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;
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;
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;