#define _GNU_SOURCE
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include "debug.h"
#include "box64stack.h"
#include "x64emu.h"
#include "x64run.h"
#include "x64emu_private.h"
#include "x64run_private.h"
#include "x64primop.h"
#include "x64trace.h"
#include "x87emu_private.h"
#include "box64context.h"
#include "bridge.h"
#ifdef DYNAREC
#include "../dynarec/native_lock.h"
#endif
#include "modrm.h"
#ifdef TEST_INTERPRETER
uintptr_t Test66(x64test_t *test, rex_t rex, int rep, uintptr_t addr)
#else
uintptr_t Run66(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr)
#endif
{
uint8_t opcode;
uint8_t nextop;
int8_t tmp8s;
uint8_t tmp8u, tmp8u2;
int16_t tmp16s;
uint16_t tmp16u, tmp16u2;
int32_t tmp32s;
int64_t tmp64s;
uint64_t tmp64u, tmp64u2, tmp64u3;
reg64_t *oped, *opgd;
#ifdef TEST_INTERPRETER
x64emu_t* emu = test->emu;
#endif
opcode = F8;
while((opcode==0x2E) || (opcode==0x36) || (opcode==0x26) || (opcode==0x66)) // ignoring CS:, SS:, ES: or multiple 0x66
opcode = F8;
while((opcode==0xF2) || (opcode==0xF3)) {
rep = opcode-0xF1;
opcode = F8;
}
rex.rex = 0;
if(!rex.is32bits)
while(opcode>=0x40 && opcode<=0x4f) {
rex.rex = opcode;
opcode = F8;
}
switch(opcode) {
#define GO(B, OP) \
case B+0: \
nextop = F8; \
GETEB(0); \
GETGB; \
EB->byte[0] = OP##8(emu, EB->byte[0], GB); \
break; \
case B+1: \
nextop = F8; \
GETEW(0); \
GETGW; \
if(rex.w) \
EW->q[0] = OP##64(emu, EW->q[0], GW->q[0]); \
else \
EW->word[0] = OP##16(emu, EW->word[0], GW->word[0]); \
break; \
case B+2: \
nextop = F8; \
GETEB(0); \
GETGB; \
GB = OP##8(emu, GB, EB->byte[0]); \
break; \
case B+3: \
nextop = F8; \
GETEW(0); \
GETGW; \
if(rex.w) \
GW->q[0] = OP##64(emu, GW->q[0], EW->q[0]); \
else \
GW->word[0] = OP##16(emu, GW->word[0], EW->word[0]); \
break; \
case B+4: \
R_AL = OP##8(emu, R_AL, F8); \
break; \
case B+5: \
if(rex.w) \
R_RAX = OP##64(emu, R_RAX, F32S64); \
else \
R_AX = OP##16(emu, R_AX, F16); \
break;
GO(0x00, add) /* ADD 0x01 ~> 0x05 */
GO(0x08, or) /* OR 0x09 ~> 0x0D */
GO(0x10, adc) /* ADC 0x11 ~> 0x15 */
GO(0x18, sbb) /* SBB 0x19 ~> 0x1D */
GO(0x20, and) /* AND 0x21 ~> 0x25 */
GO(0x28, sub) /* SUB 0x29 ~> 0x2D */
GO(0x30, xor) /* XOR 0x31 ~> 0x35 */
case 0x06: /* PUSH ES */
if(!rex.is32bits) {
return 0;
}
Push16(emu, emu->segs[_ES]);
break;
case 0x07: /* POP ES */
if(!rex.is32bits) {
return 0;
}
emu->segs[_ES] = Pop16(emu);
emu->segs_serial[_ES] = 0;
break;
case 0x0F: /* more opcdes */
switch(rep) {
case 0:
#ifdef TEST_INTERPRETER
return Test660F(test, rex, addr);
#else
return Run660F(emu, rex, addr);
#endif
case 1:
#ifdef TEST_INTERPRETER
return Test66F20F(test, rex, addr);
#else
return Run66F20F(emu, rex, addr);
#endif
case 2:
#ifdef TEST_INTERPRETER
return Test66F30F(test, rex, addr);
#else
return Run66F30F(emu, rex, addr);
#endif
}
return 0; // unreachable
case 0x1E: /* PUSH DS */
if(!rex.is32bits) {
return 0;
}
Push16(emu, emu->segs[_DS]);
break;
case 0x1F: /* POP DS */
if(!rex.is32bits) {
return 0;
}
emu->segs[_DS] = Pop16(emu); // no check, no use....
emu->segs_serial[_DS] = 0;
break;
case 0x39:
nextop = F8;
GETEW(0);
GETGW;
if(rex.w)
cmp64(emu, EW->q[0], GW->q[0]);
else
cmp16(emu, EW->word[0], GW->word[0]);
break;
case 0x3B:
nextop = F8;
GETEW(0);
GETGW;
if(rex.w)
cmp64(emu, GW->q[0], EW->dword[0]);
else
cmp16(emu, GW->word[0], EW->word[0]);
break;
case 0x3D:
if(rex.w)
cmp64(emu, R_RAX, F32S64);
else
cmp16(emu, R_AX, F16);
break;
case 0x40:
case 0x41:
case 0x42:
case 0x43:
case 0x44:
case 0x45:
case 0x46:
case 0x47: /* INC Reg (32bits only) */
tmp8u = opcode&7;
emu->regs[tmp8u].word[0] = inc16(emu, emu->regs[tmp8u].word[0]);
break;
case 0x48:
case 0x49:
case 0x4A:
case 0x4B:
case 0x4C:
case 0x4D:
case 0x4E:
case 0x4F: /* DEC Reg (32bits only) */
tmp8u = opcode&7;
emu->regs[tmp8u].word[0] = dec16(emu, emu->regs[tmp8u].word[0]);
break;
case 0x50:
case 0x51:
case 0x52:
case 0x53:
case 0x54:
case 0x55:
case 0x56:
case 0x57: /* PUSH Reg */
tmp16u = emu->regs[opcode&7].word[0];
Push16(emu, tmp16u);
break;
case 0x58:
case 0x59:
case 0x5A:
case 0x5B:
case 0x5C: /* POP ESP */
case 0x5D:
case 0x5E:
case 0x5F: /* POP Reg */
tmp8u = opcode&7;
emu->regs[tmp8u].word[0] = Pop16(emu);
break;
case 0x60: /* PUSHA */
if(rex.is32bits) {
tmp16u = R_SP;
Push16(emu, R_AX);
Push16(emu, R_CX);
Push16(emu, R_DX);
Push16(emu, R_BX);
Push16(emu, tmp16u);
Push16(emu, R_BP);
Push16(emu, R_SI);
Push16(emu, R_DI);
} else {
return 0;
}
break;
case 0x61: /* POPA */
if(rex.is32bits) {
R_DI = Pop16(emu);
R_SI = Pop16(emu);
R_BP = Pop16(emu);
R_ESP+=2; // POP ESP
R_BX = Pop16(emu);
R_DX = Pop16(emu);
R_CX = Pop16(emu);
R_AX = Pop16(emu);
} else {
return 0;
}
break;
case 0x64: /* FS: */
#ifdef TEST_INTERPRETER
return Test6664(test, rex, _FS, addr);
#else
return Run6664(emu, rex, _FS, addr);
#endif
case 0x65: /* GS: */
#ifdef TEST_INTERPRETER
return Test6664(test, rex, _GS, addr);
#else
return Run6664(emu, rex, _GS, addr);
#endif
case 0x68: /* PUSH u16 */
tmp16u = F16;
Push16(emu, tmp16u);
break;
case 0x69: /* IMUL Gw,Ew,Iw */
nextop = F8;
GETEW(rex.w?4:2);
GETGW;
if(rex.w) {
tmp64u = F32S64;
GW->q[0] = imul64(emu, EW->q[0], tmp64u);
} else {
tmp16u = F16;
GW->word[0] = imul16(emu, EW->word[0], tmp16u);
}
break;
case 0x6B: /* IMUL Gw,Ew,Ib */
nextop = F8;
GETEW(1);
GETGW;
if(rex.w) {
tmp64s = F8S;
GW->q[0] = imul64(emu, EW->q[0], (uint64_t)tmp64s);
} else {
tmp16s = F8S;
GW->word[0] = imul16(emu, EW->word[0], (uint16_t)tmp16s);
}
break;
case 0x70:
case 0x71:
case 0x72:
case 0x73:
case 0x74:
case 0x75:
case 0x76:
case 0x77:
case 0x78:
case 0x79:
case 0x7a:
case 0x7b:
case 0x7c:
case 0x7d:
case 0x7e:
case 0x7f:
// just ignore the 66 (and maybe other) prefix and use regular conditional jump
addr--;
return addr;
case 0x81: /* GRP3 Ew,Iw */
case 0x83: /* GRP3 Ew,Ib */
nextop = F8;
GETEW((opcode==0x81)?2:1);
GETGW;
if(opcode==0x81)
tmp16u = F16;
else {
tmp16s = F8S;
tmp16u = (uint16_t)tmp16s;
}
switch((nextop>>3)&7) {
case 0: EW->word[0] = add16(emu, EW->word[0], tmp16u); break;
case 1: EW->word[0] = or16(emu, EW->word[0], tmp16u); break;
case 2: EW->word[0] = adc16(emu, EW->word[0], tmp16u); break;
case 3: EW->word[0] = sbb16(emu, EW->word[0], tmp16u); break;
case 4: EW->word[0] = and16(emu, EW->word[0], tmp16u); break;
case 5: EW->word[0] = sub16(emu, EW->word[0], tmp16u); break;
case 6: EW->word[0] = xor16(emu, EW->word[0], tmp16u); break;
case 7: cmp16(emu, EW->word[0], tmp16u); break;
}
break;
case 0x85: /* TEST Ew,Gw */
nextop = F8;
GETEW(0);
GETGW;
test16(emu, EW->word[0], GW->word[0]);
break;
case 0x87: /* XCHG Ew,Gw */
nextop = F8;
GETEW(0);
GETGW;
if(rex.w) {
tmp64u = GW->q[0];
GW->q[0] = EW->q[0];
EW->q[0] = tmp64u;
} else {
tmp16u = GW->word[0];
GW->word[0] = EW->word[0];
EW->word[0] = tmp16u;
}
break;
case 0x89: /* MOV Ew,Gw */
nextop = F8;
GETEW(0);
GETGW;
if(rex.w)
EW->q[0] = GW->q[0];
else
EW->word[0] = GW->word[0];
break;
case 0x8B: /* MOV Gw,Ew */
nextop = F8;
GETEW(0);
GETGW;
if(rex.w)
GW->q[0] = EW->q[0];
else
GW->word[0] = EW->word[0];
break;
case 0x8C: /* MOV Ed, Seg */
nextop = F8;
GETEW(0);
if(rex.w)
EW->q[0] = emu->segs[((nextop&0x38)>>3)];
else
EW->word[0] = emu->segs[((nextop&0x38)>>3)];
break;
case 0x8D: /* LEA Gw,M */
nextop = F8;
GETGW;
tmp64u = GETEA(0);
if(rex.w)
GW->q[0] = tmp64u;
else
GW->word[0] = (uint16_t)tmp64u;
break;
case 0x8E: /* MOV Seg,Ew */
nextop = F8;
GETEW(0);
emu->segs[((nextop&0x38)>>3)] = EW->word[0];
emu->segs_serial[((nextop&0x38)>>3)] = 0;
break;
case 0x8F: /* POP Ew */
nextop = F8;
GETEW(0);
EW->word[0] = Pop16(emu);
break;
case 0x90: /* NOP or XCHG R8d, AX*/
case 0x91:
case 0x92:
case 0x93:
case 0x94:
case 0x95:
case 0x96:
case 0x97: /* XCHG reg,AX */
tmp8u = _AX+(opcode&7)+(rex.b<<3);
if(tmp8u!=_AX) {
if(rex.w) {
tmp64u = R_RAX;
R_RAX = emu->regs[tmp8u].q[0];
emu->regs[tmp8u].q[0] = tmp64u;
} else {
tmp16u = R_AX;
R_AX = emu->regs[tmp8u].word[0];
emu->regs[tmp8u].word[0] = tmp16u;
}
}
break;
case 0x98: /* CBW */
emu->regs[_AX].sword[0] = emu->regs[_AX].sbyte[0];
break;
case 0x99: /* CWD */
R_DX=((R_AX & 0x8000)?0xFFFF:0x0000);
break;
case 0x9C: /* PUSHFW */
CHECK_FLAGS(emu);
Push16(emu, (uint16_t)emu->eflags.x64);
break;
case 0x9D: /* POPFW */
CHECK_FLAGS(emu);
emu->eflags.x64 &=0xffff0000;
emu->eflags.x64 |= (Pop16(emu) & 0x3F7FD7) | 0x2;
break;
case 0xA1: /* MOV EAX,Od */
if(rex.is32bits) {
R_AX = *(uint16_t*)(uintptr_t)F32;
} else {
if(rex.w)
R_RAX = *(uint64_t*)F64;
else
R_AX = *(uint16_t*)F64;
}
break;
case 0xA3: /* MOV Od,EAX */
if(rex.is32bits) {
*(uint16_t*)(uintptr_t)F32 = R_AX;
} else {
if(rex.w)
*(uint64_t*)F64 = R_RAX;
else
*(uint16_t*)F64 = R_AX;
}
break;
case 0xA4: /* (REP) MOVSB */
tmp8s = ACCESS_FLAG(F_DF)?-1:+1;
tmp64u = (rep)?R_RCX:1L;
while(tmp64u) {
#ifndef TEST_INTERPRETER
*(uint8_t*)R_RDI = *(uint8_t*)R_RSI;
#endif
R_RDI += tmp8s;
R_RSI += tmp8s;
--tmp64u;
}
if(rep)
R_RCX = tmp64u;
break;
case 0xA5: /* (REP) MOVSW */
tmp8s = ACCESS_FLAG(F_DF)?-1:+1;
tmp64u = (rep)?R_RCX:1L;
if(rex.w) {
tmp8s *= 8;
while(tmp64u) {
--tmp64u;
*(uint64_t*)R_RDI = *(uint64_t*)R_RSI;
R_RDI += tmp8s;
R_RSI += tmp8s;
}
} else {
tmp8s *= 2;
while(tmp64u) {
--tmp64u;
*(uint16_t*)R_RDI = *(uint16_t*)R_RSI;
R_RDI += tmp8s;
R_RSI += tmp8s;
}
}
if(rep)
R_RCX = tmp64u;
break;
case 0xA7: /* (REPZ/REPNE) CMPSW */
if(rex.w)
tmp8s = ACCESS_FLAG(F_DF)?-8:+8;
else
tmp8s = ACCESS_FLAG(F_DF)?-2:+2;
switch(rep) {
case 1:
if(R_RCX) {
if(rex.w) {
while(R_RCX) {
--R_RCX;
tmp64u3 = *(uint64_t*)R_RDI;
tmp64u2 = *(uint64_t*)R_RSI;
R_RDI += tmp8s;
R_RSI += tmp8s;
if(tmp64u3==tmp64u2)
break;
}
cmp64(emu, tmp64u2, tmp64u3);
} else {
while(R_RCX) {
--R_RCX;
tmp16u = *(uint16_t*)R_RDI;
tmp16u2 = *(uint16_t*)R_RSI;
R_RDI += tmp8s;
R_RSI += tmp8s;
if(tmp16u==tmp16u2)
break;
}
cmp16(emu, tmp16u2, tmp16u);
}
}
break;
case 2:
if(R_RCX) {
if(rex.w) {
while(R_RCX) {
--R_RCX;
tmp64u3 = *(uint64_t*)R_RDI;
tmp64u2 = *(uint64_t*)R_RSI;
R_RDI += tmp8s;
R_RSI += tmp8s;
if(tmp64u3!=tmp64u2)
break;
}
cmp64(emu, tmp64u2, tmp64u3);
} else {
while(R_RCX) {
--R_RCX;
tmp16u = *(uint16_t*)R_RDI;
tmp16u2 = *(uint16_t*)R_RSI;
R_RDI += tmp8s;
R_RSI += tmp8s;
if(tmp16u!=tmp16u2)
break;
}
cmp16(emu, tmp16u2, tmp16u);
}
}
break;
default:
if(rex.w) {
tmp64u = *(uint64_t*)R_RDI;
tmp64u2 = *(uint64_t*)R_RSI;
R_RDI += tmp8s;
R_RSI += tmp8s;
cmp64(emu, tmp64u2, tmp64u);
} else {
tmp16u = *(uint16_t*)R_RDI;
tmp16u2 = *(uint16_t*)R_RSI;
R_RDI += tmp8s;
R_RSI += tmp8s;
cmp16(emu, tmp16u2, tmp16u);
}
}
break;
case 0xA9: /* TEST AX,Iw */
if(rex.w)
test64(emu, R_RAX, F32S64);
else
test16(emu, R_AX, F16);
break;
case 0xAB: /* (REP) STOSW */
if(rex.w)
tmp8s = ACCESS_FLAG(F_DF)?-8:+8;
else
tmp8s = ACCESS_FLAG(F_DF)?-2:+2;
tmp64u = (rep)?R_RCX:1L;
if((rex.w))
while(tmp64u) {
#ifndef TEST_INTERPRETER
*(uint64_t*)R_RDI = R_RAX;
#endif
R_RDI += tmp8s;
--tmp64u;
}
else
while(tmp64u) {
#ifndef TEST_INTERPRETER
*(uint16_t*)R_RDI = R_AX;
#endif
R_RDI += tmp8s;
--tmp64u;
}
if(rep)
R_RCX = tmp64u;
break;
case 0xAD: /* (REP) LODSW */
if(rex.w)
tmp8s = ACCESS_FLAG(F_DF)?-8:+8;
else
tmp8s = ACCESS_FLAG(F_DF)?-2:+2;
tmp64u = (rep)?R_RCX:1L;
if((rex.w))
while(tmp64u) {
R_RAX = *(uint64_t*)R_RSI;
R_RSI += tmp8s;
--tmp64u;
}
else
while(tmp64u) {
R_AX = *(uint16_t*)R_RSI;
R_RSI += tmp8s;
--tmp64u;
}
if(rep)
R_RCX = tmp64u;
break;
case 0xAF: /* (REPZ/REPNE) SCASW */
if(rex.w)
tmp8s = ACCESS_FLAG(F_DF)?-8:+8;
else
tmp8s = ACCESS_FLAG(F_DF)?-2:+2;
switch(rep) {
case 1:
if(R_RCX) {
if(rex.w) {
while(R_RCX) {
--R_RCX;
tmp64u2 = *(uint64_t*)R_RDI;
R_RDI += tmp8s;
if(R_RAX==tmp64u2)
break;
}
cmp64(emu, R_RAX, tmp64u2);
} else {
while(R_RCX) {
--R_RCX;
tmp16u = *(uint16_t*)R_RDI;
R_RDI += tmp8s;
if(R_AX==tmp16u)
break;
}
cmp16(emu, R_AX, tmp16u);
}
}
break;
case 2:
if(R_RCX) {
if(rex.w) {
while(R_RCX) {
--R_RCX;
tmp64u2 = *(uint64_t*)R_RDI;
R_RDI += tmp8s;
if(R_RAX!=tmp64u2)
break;
}
cmp64(emu, R_RAX, tmp64u2);
} else {
while(R_RCX) {
--R_RCX;
tmp16u = *(uint16_t*)R_RDI;
R_RDI += tmp8s;
if(R_AX!=tmp16u)
break;
}
cmp16(emu, R_AX, tmp16u);
}
}
break;
default:
if(rex.w)
cmp64(emu, R_RAX, *(uint64_t*)R_RDI);
else
cmp16(emu, R_AX, *(uint16_t*)R_RDI);
R_RDI += tmp8s;
}
break;
case 0xB8: /* MOV AX,Iw */
case 0xB9: /* MOV CX,Iw */
case 0xBA: /* MOV DX,Iw */
case 0xBB: /* MOV BX,Iw */
case 0xBC: /* ... */
case 0xBD:
case 0xBE:
case 0xBF:
if(rex.w)
emu->regs[(opcode&7)+(rex.b<<3)].q[0] = F64;
else
emu->regs[(opcode&7)+(rex.b<<3)].word[0] = F16;
break;
case 0xC1: /* GRP2 Ew,Ib */
nextop = F8;
GETEW(1);
tmp8u = F8 /*& 0x1f*/;
switch((nextop>>3)&7) {
case 0: EW->word[0] = rol16(emu, EW->word[0], tmp8u); break;
case 1: EW->word[0] = ror16(emu, EW->word[0], tmp8u); break;
case 2: EW->word[0] = rcl16(emu, EW->word[0], tmp8u); break;
case 3: EW->word[0] = rcr16(emu, EW->word[0], tmp8u); break;
case 4:
case 6: EW->word[0] = shl16(emu, EW->word[0], tmp8u); break;
case 5: EW->word[0] = shr16(emu, EW->word[0], tmp8u); break;
case 7: EW->word[0] = sar16(emu, EW->word[0], tmp8u); break;
}
break;
case 0xC7: /* MOV Ew,Iw */
nextop = F8;
GETEW(2);
EW->word[0] = F16;
break;
case 0xC8: /* ENTER Iw,Ib */
tmp16u = F16;
tmp8u = (F8) & 0x1f;
tmp64u = R_RBP;
Push16(emu, R_BP);
R_RBP = R_RSP;
if (tmp8u) {
for (tmp8u2 = 1; tmp8u2 < tmp8u; tmp8u2++) {
tmp64u -= 2;
Push16(emu, *((uint16_t*)tmp64u));
}
Push16(emu, R_BP);
}
R_RSP -= tmp16u;
break;
case 0xC9: /* LEAVE */
R_RSP = R_RBP;
R_BP = Pop16(emu);
break;
case 0xD1: /* GRP2 Ew,1 */
case 0xD3: /* GRP2 Ew,CL */
nextop = F8;
GETEW(0);
tmp8u=(opcode==0xD3)?R_CL:1;
if(rex.w) {
switch((nextop>>3)&7) {
case 0: EW->q[0] = rol64(emu, EW->q[0], tmp8u); break;
case 1: EW->q[0] = ror64(emu, EW->q[0], tmp8u); break;
case 2: EW->q[0] = rcl64(emu, EW->q[0], tmp8u); break;
case 3: EW->q[0] = rcr64(emu, EW->q[0], tmp8u); break;
case 4:
case 6: EW->q[0] = shl64(emu, EW->q[0], tmp8u); break;
case 5: EW->q[0] = shr64(emu, EW->q[0], tmp8u); break;
case 7: EW->q[0] = sar64(emu, EW->q[0], tmp8u); break;
}
} else {
switch((nextop>>3)&7) {
case 0: EW->word[0] = rol16(emu, EW->word[0], tmp8u); break;
case 1: EW->word[0] = ror16(emu, EW->word[0], tmp8u); break;
case 2: EW->word[0] = rcl16(emu, EW->word[0], tmp8u); break;
case 3: EW->word[0] = rcr16(emu, EW->word[0], tmp8u); break;
case 4:
case 6: EW->word[0] = shl16(emu, EW->word[0], tmp8u); break;
case 5: EW->word[0] = shr16(emu, EW->word[0], tmp8u); break;
case 7: EW->word[0] = sar16(emu, EW->word[0], tmp8u); break;
}
}
break;
case 0xD9: /* x87 opcdes */
#ifdef TEST_INTERPRETER
return Test66D9(test, rex, addr);
#else
return Run66D9(emu, rex, addr);
#endif
case 0xDD: /* x87 opcdes */
#ifdef TEST_INTERPRETER
return Test66DD(test, rex, addr);
#else
return Run66DD(emu, rex, addr);
#endif
case 0xE8: /* CALL Id */
tmp32s = F32S; // call is relative
if(rex.is32bits)
Push32(emu, addr);
else
Push64(emu, addr);
addr += tmp32s;
break;
case 0xF0: /* LOCK: */
#ifdef TEST_INTERPRETER
return Test66F0(test, rex, addr);
#else
return Run66F0(emu, rex, addr);
#endif
case 0xF7: /* GRP3 Ew(,Iw) */
nextop = F8;
tmp8u = (nextop>>3)&7;
if(rex.w) {
GETED((tmp8u<2)?4:0);
switch(tmp8u) {
case 0:
case 1: /* TEST Ed,Id */
tmp64u = F32S64;
test64(emu, ED->q[0], tmp64u);
break;
case 2: /* NOT Ed */
ED->q[0] = not64(emu, ED->q[0]);
break;
case 3: /* NEG Ed */
ED->q[0] = neg64(emu, ED->q[0]);
break;
case 4: /* MUL RAX,Ed */
mul64_rax(emu, ED->q[0]);
break;
case 5: /* IMUL RAX,Ed */
imul64_rax(emu, ED->q[0]);
break;
case 6: /* DIV Ed */
div64(emu, ED->q[0]);
break;
case 7: /* IDIV Ed */
idiv64(emu, ED->q[0]);
#ifdef TEST_INTERPRETER
test->notest = 1;
#endif
break;
}
} else {
switch(tmp8u) {
case 0:
case 1: /* TEST Ew,Iw */
GETEW(2);
test16(emu, EW->word[0], F16);
break;
case 2: /* NOT Ew */
GETEW(0);
EW->word[0] = not16(emu, EW->word[0]);
break;
case 3: /* NEG Ew */
GETEW(0);
EW->word[0] = neg16(emu, EW->word[0]);
break;
case 4: /* MUL AX,Ew */
GETEW(0);
mul16(emu, EW->word[0]);
break;
case 5: /* IMUL AX,Ew */
GETEW(0);
imul16_eax(emu, EW->word[0]);
break;
case 6: /* DIV Ew */
GETEW(0);
div16(emu, EW->word[0]);
break;
case 7: /* IDIV Ew */
GETEW(0);
idiv16(emu, EW->word[0]);
break;
}
}
break;
case 0xF8: /* CLC */
CHECK_FLAGS(emu);
CLEAR_FLAG(F_CF);
break;
case 0xF9: /* STC */
CHECK_FLAGS(emu);
SET_FLAG(F_CF);
break;
case 0xFF: /* GRP 5 Ew */
nextop = F8;
GETEW(0);
switch((nextop>>3)&7) {
case 0: /* INC Ed */
EW->word[0] = inc16(emu, EW->word[0]);
break;
case 1: /* DEC Ed */
EW->word[0] = dec16(emu, EW->word[0]);
break;
case 2: /* CALL NEAR Ed */
if(rex.is32bits) {
tmp64u = (uintptr_t)getAlternate((void*)(uintptr_t)ED->dword[0]);
Push32(emu, addr);
} else {
tmp64u = (uintptr_t)getAlternate((void*)ED->q[0]);
Push64(emu, addr);
}
addr = tmp64u;
break;
case 6: /* Push Ew */
Push16(emu, EW->word[0]);
break;
default:
printf_log(LOG_NONE, "Illegal Opcode %p: 66 %02X %02X %02X %02X %02X %02X\n",(void*)R_RIP, opcode, nextop, PK(2), PK(3), PK(4), PK(5));
emu->quit=1;
emu->error |= ERR_ILLEGAL;
return 0;
}
break;
default:
return 0;
}
return addr;
}