mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-03-04 07:58:21 +00:00
I wanted a tiny scriptable meltdown proof way to run userspace programs and visualize how program execution impacts memory. It helps to explain how things like Actually Portable Executable works. It can show you how the GCC generated code is going about manipulating matrices and more. I didn't feel fully comfortable with Qemu and Bochs because I'm not smart enough to understand them. I wanted something like gVisor but with much stronger levels of assurances. I wanted a single binary that'll run, on all major operating systems with an embedded GPL barrier ZIP filesystem that is tiny enough to transpile to JavaScript and run in browsers too. https://justine.storage.googleapis.com/emulator625.mp4
2381 lines
69 KiB
C
2381 lines
69 KiB
C
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
|
│ │
|
|
│ This program is free software; you can redistribute it and/or modify │
|
|
│ it under the terms of the GNU General Public License as published by │
|
|
│ the Free Software Foundation; version 2 of the License. │
|
|
│ │
|
|
│ This program is distributed in the hope that it will be useful, but │
|
|
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
|
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
|
│ General Public License for more details. │
|
|
│ │
|
|
│ You should have received a copy of the GNU General Public License │
|
|
│ along with this program; if not, write to the Free Software │
|
|
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
|
│ 02110-1301 USA │
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
|
#include "libc/assert.h"
|
|
#include "libc/bits/popcnt.h"
|
|
#include "libc/calls/calls.h"
|
|
#include "libc/conv/conv.h"
|
|
#include "libc/dce.h"
|
|
#include "libc/intrin/pshufd.h"
|
|
#include "libc/intrin/pshufhw.h"
|
|
#include "libc/intrin/pshuflw.h"
|
|
#include "libc/intrin/pshufw.h"
|
|
#include "libc/intrin/shufpd.h"
|
|
#include "libc/intrin/shufps.h"
|
|
#include "libc/log/check.h"
|
|
#include "libc/log/log.h"
|
|
#include "libc/macros.h"
|
|
#include "libc/math.h"
|
|
#include "libc/nexgen32e/rdtsc.h"
|
|
#include "libc/runtime/runtime.h"
|
|
#include "libc/sysv/consts/clock.h"
|
|
#include "libc/time/time.h"
|
|
#include "tool/build/lib/abp.h"
|
|
#include "tool/build/lib/alu.h"
|
|
#include "tool/build/lib/bitscan.h"
|
|
#include "tool/build/lib/case.h"
|
|
#include "tool/build/lib/cond.h"
|
|
#include "tool/build/lib/cpuid.h"
|
|
#include "tool/build/lib/cvt.h"
|
|
#include "tool/build/lib/divmul.h"
|
|
#include "tool/build/lib/endian.h"
|
|
#include "tool/build/lib/flags.h"
|
|
#include "tool/build/lib/fpu.h"
|
|
#include "tool/build/lib/ioports.h"
|
|
#include "tool/build/lib/machine.h"
|
|
#include "tool/build/lib/memory.h"
|
|
#include "tool/build/lib/modrm.h"
|
|
#include "tool/build/lib/sse.h"
|
|
#include "tool/build/lib/stack.h"
|
|
#include "tool/build/lib/stats.h"
|
|
#include "tool/build/lib/string.h"
|
|
#include "tool/build/lib/syscall.h"
|
|
#include "tool/build/lib/throw.h"
|
|
|
|
#define MUTATING true
|
|
#define READONLY false
|
|
#define UNCONDITIONAL true
|
|
#define REG ModrmReg(m->xedd)
|
|
#define UIMM0 m->xedd->op.uimm0
|
|
#define BITS (8 << RegLog2(m->xedd))
|
|
#define SIGN (1ull << (BITS - 1))
|
|
#define MASK (SIGN | (SIGN - 1))
|
|
#define SHIFTMASK (BITS - 1)
|
|
|
|
typedef int int_v _Vector_size(16) aligned(16);
|
|
typedef long long_v _Vector_size(16) aligned(16);
|
|
typedef float float_v _Vector_size(16) aligned(16);
|
|
typedef double double_v _Vector_size(16) aligned(16);
|
|
typedef void (*machine_f)(struct Machine *);
|
|
typedef void (*machine_u8p_u8p_f)(struct Machine *, uint8_t *, uint8_t *);
|
|
typedef void (*alu_f)(struct Machine *, aluop2_f, bool);
|
|
|
|
static uint64_t AluNot(struct Machine *m, uint64_t x) {
|
|
return ~x & MASK;
|
|
}
|
|
|
|
static uint64_t AluNeg(struct Machine *m, uint64_t x) {
|
|
m->flags = SetFlag(m->flags, FLAGS_CF, !!(x & MASK));
|
|
m->flags = SetFlag(m->flags, FLAGS_OF, (x & MASK) == SIGN);
|
|
x = ~x + 1;
|
|
m->flags = SetFlag(m->flags, FLAGS_ZF, !(x & MASK));
|
|
m->flags = SetFlag(m->flags, FLAGS_SF, !!(x & SIGN));
|
|
m->flags = SetLazyParityByte(m->flags, x);
|
|
return x & MASK;
|
|
}
|
|
|
|
static uint64_t AluInc(struct Machine *m, uint64_t a) {
|
|
uint64_t c;
|
|
uint128_t x, z;
|
|
a &= MASK;
|
|
x = a;
|
|
z = x + 1;
|
|
c = z;
|
|
m->flags = SetFlag(m->flags, FLAGS_ZF, !(c & MASK));
|
|
m->flags = SetFlag(m->flags, FLAGS_SF, !!(c & SIGN));
|
|
m->flags = SetFlag(m->flags, FLAGS_OF, !!((c ^ a) & (c ^ 1) & SIGN));
|
|
m->flags = SetLazyParityByte(m->flags, x);
|
|
return c & MASK;
|
|
}
|
|
|
|
static uint64_t AluDec(struct Machine *m, uint64_t a) {
|
|
uint64_t c;
|
|
uint128_t x, z;
|
|
a &= MASK;
|
|
x = a;
|
|
z = x - 1;
|
|
c = z;
|
|
m->flags = SetFlag(m->flags, FLAGS_ZF, !(c & MASK));
|
|
m->flags = SetFlag(m->flags, FLAGS_SF, !!(c & SIGN));
|
|
m->flags = SetFlag(m->flags, FLAGS_OF, !!((c ^ a) & (a ^ 1) & SIGN));
|
|
m->flags = SetLazyParityByte(m->flags, x);
|
|
return c & MASK;
|
|
}
|
|
|
|
static void ImportFlags(struct Machine *m, uint64_t flags) {
|
|
uint64_t old, mask = 0;
|
|
mask |= 1u << FLAGS_CF;
|
|
mask |= 1u << FLAGS_PF;
|
|
mask |= 1u << FLAGS_AF;
|
|
mask |= 1u << FLAGS_ZF;
|
|
mask |= 1u << FLAGS_SF;
|
|
mask |= 1u << FLAGS_TF;
|
|
mask |= 1u << FLAGS_IF;
|
|
mask |= 1u << FLAGS_DF;
|
|
mask |= 1u << FLAGS_OF;
|
|
mask |= 1u << FLAGS_NT;
|
|
mask |= 1u << FLAGS_AC;
|
|
mask |= 1u << FLAGS_ID;
|
|
m->flags = (flags & mask) | (m->flags & ~mask);
|
|
m->flags = SetFlag(m->flags, FLAGS_RF, false);
|
|
m->flags = SetLazyParityByte(m->flags, !((m->flags >> FLAGS_PF) & 1));
|
|
}
|
|
|
|
static uint64_t ReadMemory(struct Machine *m, uint8_t p[8]) {
|
|
if (Rexw(m->xedd)) {
|
|
return Read64(p);
|
|
} else if (!Osz(m->xedd)) {
|
|
return Read32(p);
|
|
} else {
|
|
return Read16(p);
|
|
}
|
|
}
|
|
|
|
static int64_t ReadMemorySigned(struct Machine *m, uint8_t p[8]) {
|
|
if (Rexw(m->xedd)) {
|
|
return (int64_t)Read64(p);
|
|
} else if (!Osz(m->xedd)) {
|
|
return (int32_t)Read32(p);
|
|
} else {
|
|
return (int16_t)Read16(p);
|
|
}
|
|
}
|
|
|
|
static void WriteRegister(struct Machine *m, uint8_t p[8], uint64_t x) {
|
|
if (Rexw(m->xedd)) {
|
|
Write64(p, x);
|
|
} else if (!Osz(m->xedd)) {
|
|
Write64(p, x & 0xffffffff);
|
|
} else {
|
|
Write16(p, x);
|
|
}
|
|
}
|
|
|
|
static void WriteMemory(struct Machine *m, uint8_t p[8], uint64_t x) {
|
|
if (Rexw(m->xedd)) {
|
|
Write64(p, x);
|
|
} else if (!Osz(m->xedd)) {
|
|
Write32(p, x);
|
|
} else {
|
|
Write16(p, x);
|
|
}
|
|
}
|
|
|
|
static void WriteRegisterOrMemory(struct Machine *m, uint8_t p[8], uint64_t x) {
|
|
if (IsModrmRegister(m->xedd)) {
|
|
WriteRegister(m, p, x);
|
|
} else {
|
|
WriteMemory(m, p, x);
|
|
}
|
|
}
|
|
|
|
static void OpLfence(struct Machine *m) {
|
|
}
|
|
|
|
static void OpMfence(struct Machine *m) {
|
|
}
|
|
|
|
static void OpSfence(struct Machine *m) {
|
|
}
|
|
|
|
static void OpClflush(struct Machine *m) {
|
|
}
|
|
|
|
static void OpWutNopEv(struct Machine *m) {
|
|
}
|
|
|
|
static void OpCmc(struct Machine *m) {
|
|
m->flags = SetFlag(m->flags, FLAGS_CF, !GetFlag(m->flags, FLAGS_CF));
|
|
}
|
|
|
|
static void OpClc(struct Machine *m) {
|
|
m->flags = SetFlag(m->flags, FLAGS_CF, false);
|
|
}
|
|
|
|
static void OpStc(struct Machine *m) {
|
|
m->flags = SetFlag(m->flags, FLAGS_CF, true);
|
|
}
|
|
|
|
static void OpCli(struct Machine *m) {
|
|
m->flags = SetFlag(m->flags, FLAGS_IF, false);
|
|
}
|
|
|
|
static void OpSti(struct Machine *m) {
|
|
m->flags = SetFlag(m->flags, FLAGS_IF, true);
|
|
}
|
|
|
|
static void OpCld(struct Machine *m) {
|
|
m->flags = SetFlag(m->flags, FLAGS_DF, false);
|
|
}
|
|
|
|
static void OpStd(struct Machine *m) {
|
|
m->flags = SetFlag(m->flags, FLAGS_DF, true);
|
|
}
|
|
|
|
static void OpPushf(struct Machine *m) {
|
|
PushOsz(m, ExportFlags(m->flags) & 0xFCFFFF);
|
|
}
|
|
|
|
static void OpPopf(struct Machine *m) {
|
|
if (!Osz(m->xedd)) {
|
|
ImportFlags(m, Pop64(m, 0));
|
|
} else {
|
|
ImportFlags(m, (m->flags & ~0xFFFFull) | Pop16(m, 0));
|
|
}
|
|
}
|
|
|
|
static void OpLahf(struct Machine *m) {
|
|
Write8(m->ax + 1, ExportFlags(m->flags));
|
|
}
|
|
|
|
static void OpPushFs(struct Machine *m) {
|
|
ThrowSegmentationFault(m, m->ip);
|
|
}
|
|
|
|
static void OpPopFs(struct Machine *m) {
|
|
ThrowSegmentationFault(m, m->ip);
|
|
}
|
|
|
|
static void OpPushGs(struct Machine *m) {
|
|
ThrowSegmentationFault(m, m->ip);
|
|
}
|
|
|
|
static void OpPopGs(struct Machine *m) {
|
|
ThrowSegmentationFault(m, m->ip);
|
|
}
|
|
|
|
static void OpSahf(struct Machine *m) {
|
|
ImportFlags(m, (m->flags & ~0xFFull) | m->ax[1]);
|
|
}
|
|
|
|
static void OpEbSetCc(struct Machine *m, bool x) {
|
|
Write8(GetModrmRegisterBytePointerWrite(m), x);
|
|
}
|
|
|
|
static void OpLeaGvqpM(struct Machine *m) {
|
|
Write64(RegRexrReg(m), ComputeAddress(m));
|
|
}
|
|
|
|
static void PushVq(struct Machine *m, uint8_t *p) {
|
|
if (!Osz(m->xedd)) {
|
|
Push64(m, Read64(p));
|
|
} else {
|
|
Push16(m, Read16(p));
|
|
}
|
|
}
|
|
|
|
static void PopVq(struct Machine *m, uint8_t *p) {
|
|
if (!Osz(m->xedd)) {
|
|
Write64(p, Pop64(m, 0));
|
|
} else {
|
|
Write16(p, Pop16(m, 0));
|
|
}
|
|
}
|
|
|
|
static void OpPushEvq(struct Machine *m) {
|
|
PushVq(m, GetModrmRegisterWordPointerReadOsz(m));
|
|
}
|
|
|
|
static void OpPushZvq(struct Machine *m) {
|
|
PushVq(m, RegRexbSrm(m));
|
|
}
|
|
|
|
static void OpPopZvq(struct Machine *m) {
|
|
PopVq(m, RegRexbSrm(m));
|
|
}
|
|
|
|
static void OpPopEvq(struct Machine *m) {
|
|
PopVq(m, GetModrmRegisterWordPointerWriteOsz(m));
|
|
}
|
|
|
|
static void OpJmp(struct Machine *m) {
|
|
m->ip += m->xedd->op.disp;
|
|
}
|
|
|
|
static void OpJmpEq(struct Machine *m) {
|
|
m->ip = Read64(GetModrmRegisterWordPointerRead8(m));
|
|
}
|
|
|
|
static void OpJcxz(struct Machine *m) {
|
|
uint64_t count;
|
|
count = Read64(m->cx);
|
|
if (Asz(m->xedd)) count &= 0xffffffff;
|
|
if (!count) OpJmp(m);
|
|
}
|
|
|
|
static void OpLoop(struct Machine *m, bool cond) {
|
|
uint64_t count;
|
|
count = Read64(m->cx) - 1;
|
|
if (Asz(m->xedd)) count &= 0xffffffff;
|
|
Write64(m->cx, count);
|
|
if (count && cond) m->ip += m->xedd->op.disp;
|
|
}
|
|
|
|
static void OpXlat(struct Machine *m) {
|
|
int64_t v;
|
|
uint8_t al, *p;
|
|
v = Read64(m->bx) + Read8(m->ax);
|
|
if (Asz(m->xedd)) v &= 0xffffffff;
|
|
SetReadAddr(m, v, 1);
|
|
Write8(m->ax, Read8(ResolveAddress(m, v)));
|
|
}
|
|
|
|
static void OpEb(struct Machine *m, aluop1_f op) {
|
|
uint8_t *p;
|
|
p = GetModrmRegisterBytePointerWrite(m);
|
|
Write8(p, op(m, Read8(p)));
|
|
}
|
|
|
|
static void OpEvqp(struct Machine *m, aluop1_f op) {
|
|
uint8_t *p;
|
|
p = GetModrmRegisterWordPointerWriteOszRexw(m);
|
|
WriteRegisterOrMemory(m, p, op(m, ReadMemory(m, p)));
|
|
}
|
|
|
|
static void OpGvqpEvqp(struct Machine *m, aluop2_f op, bool write) {
|
|
uint64_t x;
|
|
x = op(m, ReadMemory(m, RegRexrReg(m)),
|
|
ReadMemory(m, GetModrmRegisterWordPointerReadOszRexw(m)));
|
|
if (write) WriteRegister(m, RegRexrReg(m), x);
|
|
}
|
|
|
|
static void OpEvqpGvqp(struct Machine *m, aluop2_f op, bool write) {
|
|
uint8_t *p;
|
|
uint64_t x, y;
|
|
p = GetModrmRegisterWordPointerWriteOszRexw(m);
|
|
x = ReadMemory(m, p);
|
|
y = ReadMemory(m, RegRexrReg(m));
|
|
x = op(m, x, y);
|
|
if (write) WriteRegisterOrMemory(m, p, x);
|
|
}
|
|
|
|
static void OpXchgZvqp(struct Machine *m) {
|
|
uint64_t x, y;
|
|
x = Read64(m->ax);
|
|
y = Read64(RegRexbSrm(m));
|
|
WriteRegister(m, m->ax, y);
|
|
WriteRegister(m, RegRexbSrm(m), x);
|
|
}
|
|
|
|
static void OpBofram(struct Machine *m) {
|
|
if (m->xedd->op.disp) {
|
|
m->bofram[0] = m->ip;
|
|
m->bofram[1] = m->ip + (m->xedd->op.disp & 0xff);
|
|
} else {
|
|
m->bofram[0] = 0;
|
|
m->bofram[1] = 0;
|
|
}
|
|
}
|
|
|
|
static void OpNopEv(struct Machine *m) {
|
|
if (m->xedd->op.modrm == 0x45) {
|
|
OpBofram(m);
|
|
}
|
|
}
|
|
|
|
static void OpPause(struct Machine *m) {
|
|
sched_yield();
|
|
}
|
|
|
|
static void OpNop(struct Machine *m) {
|
|
if (m->xedd->op.rexb) {
|
|
OpXchgZvqp(m);
|
|
} else if (m->xedd->op.ild_f3) {
|
|
OpPause(m);
|
|
}
|
|
}
|
|
|
|
static void OpXchgGbEb(struct Machine *m) {
|
|
uint8_t *b;
|
|
uint8_t x, y;
|
|
b = GetModrmRegisterBytePointerWrite(m);
|
|
x = Read8(ByteRexrReg(m));
|
|
y = Read8(b);
|
|
Write8(ByteRexrReg(m), y);
|
|
Write8(b, x);
|
|
}
|
|
|
|
static void OpXchgGvqpEvqp(struct Machine *m) {
|
|
uint8_t *p;
|
|
uint64_t x, y;
|
|
p = GetModrmRegisterWordPointerWriteOszRexw(m);
|
|
x = ReadMemory(m, RegRexrReg(m));
|
|
y = ReadMemory(m, p);
|
|
WriteRegister(m, RegRexrReg(m), y);
|
|
WriteRegisterOrMemory(m, p, x);
|
|
}
|
|
|
|
static void OpCmpxchgEbAlGb(struct Machine *m) {
|
|
uint8_t *p;
|
|
uint8_t x, y, z;
|
|
p = GetModrmRegisterBytePointerWrite(m);
|
|
x = Read8(m->ax);
|
|
y = Read8(p);
|
|
z = Read8(ByteRexrReg(m));
|
|
Alu(0, ALU_SUB, x, y, &m->flags);
|
|
if (GetFlag(m->flags, FLAGS_ZF)) {
|
|
Write8(p, z);
|
|
} else {
|
|
Write8(m->ax, y);
|
|
}
|
|
}
|
|
|
|
static void OpCmpxchgEvqpRaxGvqp(struct Machine *m) {
|
|
uint8_t *p;
|
|
uint64_t x, y, z;
|
|
p = GetModrmRegisterWordPointerWriteOszRexw(m);
|
|
x = ReadMemory(m, m->ax);
|
|
y = ReadMemory(m, p);
|
|
z = ReadMemory(m, RegRexrReg(m));
|
|
Alu(RegLog2(m->xedd), ALU_SUB, x, y, &m->flags);
|
|
if (GetFlag(m->flags, FLAGS_ZF)) {
|
|
WriteRegisterOrMemory(m, p, z);
|
|
} else {
|
|
WriteRegister(m, m->ax, y);
|
|
}
|
|
}
|
|
|
|
static void OpCmpxchg8b(struct Machine *m) {
|
|
uint8_t *p;
|
|
uint32_t d, a;
|
|
p = GetModrmRegisterXmmPointerRead8(m);
|
|
a = Read32(p + 0);
|
|
d = Read32(p + 4);
|
|
if (a == Read32(m->ax) && d == Read32(m->dx)) {
|
|
SetFlag(m->flags, FLAGS_ZF, true);
|
|
memcpy(p + 0, m->bx, 4);
|
|
memcpy(p + 4, m->cx, 4);
|
|
} else {
|
|
SetFlag(m->flags, FLAGS_ZF, false);
|
|
Write32(m->ax, a);
|
|
Write32(m->dx, d);
|
|
}
|
|
}
|
|
|
|
static void OpCmpxchg16b(struct Machine *m) {
|
|
uint8_t *p;
|
|
uint64_t d, a;
|
|
p = GetModrmRegisterXmmPointerRead16(m);
|
|
a = Read64(p + 0);
|
|
d = Read64(p + 8);
|
|
if (a == Read64(m->ax) && d == Read64(m->dx)) {
|
|
SetFlag(m->flags, FLAGS_ZF, true);
|
|
memcpy(p + 0, m->bx, 8);
|
|
memcpy(p + 8, m->cx, 8);
|
|
} else {
|
|
SetFlag(m->flags, FLAGS_ZF, false);
|
|
Write64(m->ax, a);
|
|
Write64(m->dx, d);
|
|
}
|
|
}
|
|
|
|
static void OpCmpxchgDxAx(struct Machine *m) {
|
|
if (Rexw(m->xedd)) {
|
|
OpCmpxchg16b(m);
|
|
} else {
|
|
OpCmpxchg8b(m);
|
|
}
|
|
}
|
|
|
|
static uint64_t OpDoubleShift(struct Machine *m, uint64_t x, uint64_t y) {
|
|
uint8_t b, w, W[2][2] = {{2, 3}, {1, 3}};
|
|
return BsuDoubleShift(
|
|
W[Osz(m->xedd)][Rexw(m->xedd)], x, y,
|
|
m->xedd->op.opcode & 1 ? Read8(m->cx) : m->xedd->op.uimm0,
|
|
m->xedd->op.opcode & 8, &m->flags);
|
|
}
|
|
|
|
static uint64_t OpBts(uint64_t x, uint64_t y) {
|
|
return x | y;
|
|
}
|
|
|
|
static uint64_t OpBtr(uint64_t x, uint64_t y) {
|
|
return x & ~y;
|
|
}
|
|
|
|
static uint64_t OpBtc(uint64_t x, uint64_t y) {
|
|
return (x & ~y) | (~x & y);
|
|
}
|
|
|
|
static void OpBit(struct Machine *m) {
|
|
int op;
|
|
uint8_t *p;
|
|
unsigned bit;
|
|
int64_t disp;
|
|
uint64_t v, x, y, z;
|
|
uint8_t w, W[2][2] = {{2, 3}, {1, 3}};
|
|
w = W[Osz(m->xedd)][Rexw(m->xedd)];
|
|
if (m->xedd->op.opcode == 0xBA) {
|
|
op = ModrmReg(m->xedd);
|
|
bit = m->xedd->op.uimm0 & ((8 << w) - 1);
|
|
disp = 0;
|
|
} else {
|
|
op = (m->xedd->op.opcode & 070) >> 3;
|
|
disp = ReadMemorySigned(m, RegRexrReg(m));
|
|
bit = disp & ((8 << w) - 1);
|
|
disp &= -(8 << w);
|
|
disp >>= 3;
|
|
}
|
|
if (IsModrmRegister(m->xedd)) {
|
|
p = RegRexbRm(m);
|
|
} else {
|
|
v = ComputeAddress(m) + disp;
|
|
if (Asz(m->xedd)) v &= 0xffffffff;
|
|
p = ReserveAddress(m, v, 1 << w);
|
|
if (op == 4) {
|
|
SetReadAddr(m, v, 1 << w);
|
|
} else {
|
|
SetWriteAddr(m, v, 1 << w);
|
|
}
|
|
}
|
|
y = 1ull << bit;
|
|
x = ReadMemory(m, p);
|
|
m->flags = SetFlag(m->flags, FLAGS_CF, !!(y & x));
|
|
switch (op) {
|
|
case 4:
|
|
return;
|
|
case 5:
|
|
z = OpBts(x, y);
|
|
break;
|
|
case 6:
|
|
z = OpBtr(x, y);
|
|
break;
|
|
case 7:
|
|
z = OpBtc(x, y);
|
|
break;
|
|
default:
|
|
OpUd(m);
|
|
}
|
|
WriteRegisterOrMemory(m, p, z);
|
|
}
|
|
|
|
static void OpConvert1(struct Machine *m) {
|
|
if (Rexw(m->xedd)) {
|
|
Write64(m->ax, Read32(m->ax) |
|
|
(Read32(m->ax) & 0x80000000 ? 0xffffffff00000000 : 0));
|
|
} else if (!Osz(m->xedd)) {
|
|
Write64(m->ax, Read16(m->ax) | (Read16(m->ax) & 0x8000 ? 0xffff0000 : 0));
|
|
} else {
|
|
Write16(m->ax, Read8(m->ax) | (Read8(m->ax) & 0x0080 ? 0xff00 : 0));
|
|
}
|
|
}
|
|
|
|
static void OpConvert2(struct Machine *m) {
|
|
if (Rexw(m->xedd)) {
|
|
Write64(m->dx, Read64(m->ax) & 0x8000000000000000 ? 0xffffffffffffffff : 0);
|
|
} else if (!Osz(m->xedd)) {
|
|
Write64(m->dx, Read32(m->ax) & 0x80000000 ? 0xffffffff : 0);
|
|
} else {
|
|
Write16(m->dx, Read16(m->ax) & 0x8000 ? 0xffff : 0);
|
|
}
|
|
}
|
|
|
|
static void OpBswapZvqp(struct Machine *m) {
|
|
uint64_t x;
|
|
x = Read64(RegRexbSrm(m));
|
|
if (Rexw(m->xedd)) {
|
|
Write64(
|
|
RegRexbSrm(m),
|
|
((x & 0xff00000000000000) >> 070 | (x & 0x00000000000000ff) << 070 |
|
|
(x & 0x00ff000000000000) >> 050 | (x & 0x000000000000ff00) << 050 |
|
|
(x & 0x0000ff0000000000) >> 030 | (x & 0x0000000000ff0000) << 030 |
|
|
(x & 0x000000ff00000000) >> 010 | (x & 0x00000000ff000000) << 010));
|
|
} else if (!Osz(m->xedd)) {
|
|
Write64(RegRexbSrm(m), ((x & 0xff000000) >> 030 | (x & 0x000000ff) << 030 |
|
|
(x & 0x00ff0000) >> 010 | (x & 0x0000ff00) << 010));
|
|
} else {
|
|
Write16(RegRexbSrm(m), (x & 0x00ff) << 010 | (x & 0xff00) << 010);
|
|
}
|
|
}
|
|
|
|
static uint8_t pmovmskb(uint64_t x) {
|
|
return (x & 0x0000000000000080) >> 007 | (x & 0x0000000000008000) >> 016 |
|
|
(x & 0x0000000000800000) >> 025 | (x & 0x0000000080000000) >> 034 |
|
|
(x & 0x0000008000000000) >> 043 | (x & 0x0000800000000000) >> 052 |
|
|
(x & 0x0080000000000000) >> 061 | (x & 0x8000000000000000) >> 070;
|
|
}
|
|
|
|
static void OpPmovmskbGdqpNqUdq(struct Machine *m) {
|
|
uint64_t bitmask;
|
|
if (Prefix66(m->xedd)) {
|
|
bitmask = pmovmskb(Read64(XmmRexbRm(m) + 8)) << 8 |
|
|
pmovmskb(Read64(XmmRexbRm(m)));
|
|
} else {
|
|
bitmask = pmovmskb(Read64(MmRm(m) + 8)) << 8 | pmovmskb(Read64(MmRm(m)));
|
|
}
|
|
Write64(RegRexrReg(m), bitmask);
|
|
}
|
|
|
|
static void OpRdtsc(struct Machine *m) {
|
|
uint64_t c;
|
|
#ifdef __x86_64__
|
|
c = rdtsc();
|
|
#else
|
|
struct timespec ts;
|
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
c = ts.tv_sec * 1000000000 + ts.tv_nsec;
|
|
#endif
|
|
Write64(m->ax, c & 0xffffffff);
|
|
c >>= 32;
|
|
Write64(m->dx, c & 0xffffffff);
|
|
}
|
|
|
|
static void OpMovEvqpSw(struct Machine *m) {
|
|
ThrowSegmentationFault(m, m->ip);
|
|
}
|
|
|
|
static void OpMovSwEvqp(struct Machine *m) {
|
|
ThrowSegmentationFault(m, m->ip);
|
|
}
|
|
|
|
static void OpMovEbIb(struct Machine *m) {
|
|
Write8(GetModrmRegisterBytePointerWrite(m), m->xedd->op.uimm0);
|
|
}
|
|
|
|
static void OpMovAlOb(struct Machine *m) {
|
|
memcpy(ResolveAddress(m, m->xedd->op.uimm0), m->ax, 1);
|
|
}
|
|
|
|
static void OpMovObAl(struct Machine *m) {
|
|
memcpy(m->ax, ResolveAddress(m, m->xedd->op.uimm0), 1);
|
|
}
|
|
|
|
static void OpMovRaxOvqp(struct Machine *m) {
|
|
WriteRegister(m, m->ax, ReadMemory(m, ResolveAddress(m, m->xedd->op.uimm0)));
|
|
}
|
|
|
|
static void OpMovOvqpRax(struct Machine *m) {
|
|
WriteMemory(m, ResolveAddress(m, m->xedd->op.uimm0), Read64(m->ax));
|
|
}
|
|
|
|
static void OpMovEbGb(struct Machine *m) {
|
|
memcpy(GetModrmRegisterBytePointerWrite(m), ByteRexrReg(m), 1);
|
|
}
|
|
|
|
static void OpMovGbEb(struct Machine *m) {
|
|
memcpy(ByteRexrReg(m), GetModrmRegisterBytePointerRead(m), 1);
|
|
}
|
|
|
|
static void OpMovZbIb(struct Machine *m) {
|
|
Write8(ByteRexbSrm(m), m->xedd->op.uimm0);
|
|
}
|
|
|
|
static void OpMovZvqpIvqp(struct Machine *m) {
|
|
WriteRegister(m, RegRexbSrm(m), m->xedd->op.uimm0);
|
|
}
|
|
|
|
static void OpMovEvqpIvds(struct Machine *m) {
|
|
WriteRegisterOrMemory(m, GetModrmRegisterWordPointerWriteOszRexw(m),
|
|
m->xedd->op.uimm0);
|
|
}
|
|
|
|
static void OpMovEvqpGvqp(struct Machine *m) {
|
|
WriteRegisterOrMemory(m, GetModrmRegisterWordPointerWriteOszRexw(m),
|
|
ReadMemory(m, RegRexrReg(m)));
|
|
}
|
|
|
|
static void OpMovGvqpEvqp(struct Machine *m) {
|
|
WriteRegister(m, RegRexrReg(m),
|
|
ReadMemory(m, GetModrmRegisterWordPointerReadOszRexw(m)));
|
|
}
|
|
|
|
static void OpMovzbGvqpEb(struct Machine *m) {
|
|
WriteRegister(m, RegRexrReg(m), Read8(GetModrmRegisterBytePointerRead(m)));
|
|
}
|
|
|
|
static void OpMovzwGvqpEw(struct Machine *m) {
|
|
WriteRegister(m, RegRexrReg(m), Read16(GetModrmRegisterWordPointerRead2(m)));
|
|
}
|
|
|
|
static void OpMovsbGvqpEb(struct Machine *m) {
|
|
WriteRegister(m, RegRexrReg(m),
|
|
(int8_t)Read8(GetModrmRegisterBytePointerRead(m)));
|
|
}
|
|
|
|
static void OpMovswGvqpEw(struct Machine *m) {
|
|
WriteRegister(m, RegRexrReg(m),
|
|
(int16_t)Read16(GetModrmRegisterWordPointerRead2(m)));
|
|
}
|
|
|
|
static void OpMovsxdGdqpEd(struct Machine *m) {
|
|
uint64_t x;
|
|
uint8_t *p;
|
|
x = (int32_t)Read32(GetModrmRegisterWordPointerRead4(m));
|
|
if (!Rexw(m->xedd)) x &= 0xffffffff; /* wut */
|
|
Write64(RegRexrReg(m), x);
|
|
}
|
|
|
|
static void OpMovdquVdqWdq(struct Machine *m) {
|
|
memcpy(XmmRexrReg(m), GetModrmRegisterXmmPointerRead16(m), 16);
|
|
}
|
|
|
|
static void OpMovdquWdqVdq(struct Machine *m) {
|
|
memcpy(GetModrmRegisterXmmPointerWrite16(m), XmmRexrReg(m), 16);
|
|
}
|
|
|
|
static void OpMovupsVpsWps(struct Machine *m) {
|
|
OpMovdquVdqWdq(m);
|
|
}
|
|
|
|
static void OpMovupsWpsVps(struct Machine *m) {
|
|
OpMovdquWdqVdq(m);
|
|
}
|
|
|
|
static void OpMovupdVpsWps(struct Machine *m) {
|
|
OpMovdquVdqWdq(m);
|
|
}
|
|
|
|
static void OpMovupdWpsVps(struct Machine *m) {
|
|
OpMovdquWdqVdq(m);
|
|
}
|
|
|
|
static void OpLddquVdqMdq(struct Machine *m) {
|
|
OpMovdquVdqWdq(m);
|
|
}
|
|
|
|
static void OpMovdqaVdqMdq(struct Machine *m) {
|
|
int64_t v;
|
|
uint8_t *p;
|
|
v = ComputeAddress(m);
|
|
SetReadAddr(m, v, 16);
|
|
if ((v & 15) || !(p = FindReal(m, v))) ThrowSegmentationFault(m, v);
|
|
memcpy(XmmRexrReg(m), Abp16(p), 16);
|
|
}
|
|
|
|
static void OpMovdqaMdqVdq(struct Machine *m) {
|
|
int64_t v;
|
|
uint8_t *p;
|
|
v = ComputeAddress(m);
|
|
SetWriteAddr(m, v, 16);
|
|
if ((v & 15) || !(p = FindReal(m, v))) ThrowSegmentationFault(m, v);
|
|
memcpy(Abp16(p), XmmRexrReg(m), 16);
|
|
}
|
|
|
|
static void OpMovdqaVdqWdq(struct Machine *m) {
|
|
if (IsModrmRegister(m->xedd)) {
|
|
memcpy(XmmRexrReg(m), XmmRexbRm(m), 16);
|
|
} else {
|
|
OpMovdqaVdqMdq(m);
|
|
}
|
|
}
|
|
|
|
static void OpMovdqaWdqVdq(struct Machine *m) {
|
|
if (IsModrmRegister(m->xedd)) {
|
|
memcpy(XmmRexbRm(m), XmmRexrReg(m), 16);
|
|
} else {
|
|
OpMovdqaMdqVdq(m);
|
|
}
|
|
}
|
|
|
|
static void OpMovntiMdqpGdqp(struct Machine *m) {
|
|
int64_t v;
|
|
uint8_t *a;
|
|
void *p[2];
|
|
uint8_t n, b[8];
|
|
v = ComputeAddress(m);
|
|
n = Rexw(m->xedd) ? 8 : 4;
|
|
a = BeginStore(m, v, n, p, b);
|
|
SetWriteAddr(m, v, n);
|
|
memcpy(p, XmmRexrReg(m), n);
|
|
EndStore(m, v, n, p, b);
|
|
}
|
|
|
|
static void OpMovntdqMdqVdq(struct Machine *m) {
|
|
OpMovdqaMdqVdq(m);
|
|
}
|
|
|
|
static void OpMovntpsMpsVps(struct Machine *m) {
|
|
OpMovdqaMdqVdq(m);
|
|
}
|
|
|
|
static void OpMovntpdMpdVpd(struct Machine *m) {
|
|
OpMovdqaMdqVdq(m);
|
|
}
|
|
|
|
static void OpMovntdqaVdqMdq(struct Machine *m) {
|
|
OpMovdqaVdqMdq(m);
|
|
}
|
|
|
|
static void OpMovqPqQq(struct Machine *m) {
|
|
memcpy(MmReg(m), GetModrmRegisterMmPointerRead8(m), 8);
|
|
}
|
|
|
|
static void OpMovqQqPq(struct Machine *m) {
|
|
memcpy(GetModrmRegisterMmPointerWrite8(m), MmReg(m), 8);
|
|
}
|
|
|
|
static void OpMovqVdqEqp(struct Machine *m) {
|
|
memcpy(XmmRexrReg(m), GetModrmRegisterWordPointerRead8(m), 8);
|
|
memset(XmmRexrReg(m) + 8, 0, 8);
|
|
}
|
|
|
|
static void OpMovdVdqEd(struct Machine *m) {
|
|
memset(XmmRexrReg(m), 0, 16);
|
|
memcpy(XmmRexrReg(m), GetModrmRegisterWordPointerRead4(m), 4);
|
|
}
|
|
|
|
static void OpMovqPqEqp(struct Machine *m) {
|
|
memcpy(MmReg(m), GetModrmRegisterWordPointerRead8(m), 8);
|
|
}
|
|
|
|
static void OpMovdPqEd(struct Machine *m) {
|
|
memcpy(MmReg(m), GetModrmRegisterWordPointerRead4(m), 4);
|
|
memset(MmReg(m) + 4, 0, 4);
|
|
}
|
|
|
|
static void OpMovdEdVdq(struct Machine *m) {
|
|
if (IsModrmRegister(m->xedd)) {
|
|
memset(RegRexbRm(m), 0, 16);
|
|
memcpy(RegRexbRm(m), XmmRexrReg(m), 4);
|
|
} else {
|
|
memcpy(ComputeReserveAddressWrite4(m), XmmRexrReg(m), 4);
|
|
}
|
|
}
|
|
|
|
static void OpMovqEqpVdq(struct Machine *m) {
|
|
memcpy(GetModrmRegisterWordPointerWrite8(m), XmmRexrReg(m), 8);
|
|
}
|
|
|
|
static void OpMovdEdPq(struct Machine *m) {
|
|
if (IsModrmRegister(m->xedd)) {
|
|
memcpy(RegRexbRm(m), MmReg(m), 4);
|
|
memset(RegRexbRm(m) + 4, 0, 4);
|
|
} else {
|
|
memcpy(ComputeReserveAddressWrite4(m), MmReg(m), 4);
|
|
}
|
|
}
|
|
|
|
static void OpMovqEqpPq(struct Machine *m) {
|
|
memcpy(GetModrmRegisterWordPointerWrite(m, 8), MmReg(m), 8);
|
|
}
|
|
|
|
static void OpMovntqMqPq(struct Machine *m) {
|
|
memcpy(ComputeReserveAddressWrite8(m), MmReg(m), 8);
|
|
}
|
|
|
|
static void OpMovqVqWq(struct Machine *m) {
|
|
memcpy(XmmRexrReg(m), GetModrmRegisterXmmPointerRead8(m), 8);
|
|
memset(XmmRexrReg(m) + 8, 0, 8);
|
|
}
|
|
|
|
static void OpMovssVpsWps(struct Machine *m) {
|
|
memcpy(XmmRexrReg(m), GetModrmRegisterXmmPointerRead4(m), 4);
|
|
}
|
|
|
|
static void OpMovssWpsVps(struct Machine *m) {
|
|
memcpy(GetModrmRegisterXmmPointerWrite4(m), XmmRexrReg(m), 4);
|
|
}
|
|
|
|
static void OpMovsdVpsWps(struct Machine *m) {
|
|
memcpy(XmmRexrReg(m), GetModrmRegisterXmmPointerRead16(m), 8);
|
|
}
|
|
|
|
static void OpMovsdWpsVps(struct Machine *m) {
|
|
memcpy(GetModrmRegisterXmmPointerWrite16(m), XmmRexrReg(m), 8);
|
|
}
|
|
|
|
static void OpMaskMovDiXmmRegXmmRm(struct Machine *m) {
|
|
void *p[2];
|
|
uint64_t v;
|
|
unsigned i, n;
|
|
uint8_t *mem, b[16];
|
|
n = Prefix66(m->xedd) ? 16 : 8;
|
|
v = GetSegment() + Read64(m->di);
|
|
if (Asz(m->xedd)) v &= 0xffffffff;
|
|
mem = BeginStore(m, v, n, p, b);
|
|
for (i = 0; i < n; ++i) {
|
|
if (XmmRexbRm(m)[i] & 0x80) {
|
|
mem[i] = XmmRexrReg(m)[i];
|
|
}
|
|
}
|
|
EndStore(m, v, n, p, b);
|
|
}
|
|
|
|
static void OpMovhlpsVqUq(struct Machine *m) {
|
|
memcpy(XmmRexrReg(m), XmmRexbRm(m) + 8, 8);
|
|
}
|
|
|
|
static void OpMovlpsVqMq(struct Machine *m) {
|
|
memcpy(XmmRexrReg(m), ComputeReserveAddressRead8(m), 8);
|
|
}
|
|
|
|
static void OpMovlpdVqMq(struct Machine *m) {
|
|
memcpy(XmmRexrReg(m), ComputeReserveAddressRead8(m), 8);
|
|
}
|
|
|
|
static void OpMovddupVqWq(struct Machine *m) {
|
|
uint8_t *dst, *src;
|
|
dst = XmmRexrReg(m);
|
|
src = GetModrmRegisterXmmPointerRead8(m);
|
|
memcpy(dst + 0, src, 8);
|
|
memcpy(dst + 8, src, 8);
|
|
}
|
|
|
|
static void OpMovsldupVqWq(struct Machine *m) {
|
|
uint8_t *dst, *src;
|
|
dst = XmmRexrReg(m);
|
|
src = GetModrmRegisterXmmPointerRead16(m);
|
|
memcpy(dst + 0 + 0, src + 0, 4);
|
|
memcpy(dst + 0 + 4, src + 0, 4);
|
|
memcpy(dst + 8 + 0, src + 8, 4);
|
|
memcpy(dst + 8 + 4, src + 8, 4);
|
|
}
|
|
|
|
static void OpMovlpsMqVq(struct Machine *m) {
|
|
memcpy(ComputeReserveAddressWrite8(m), XmmRexrReg(m), 8);
|
|
}
|
|
|
|
static void OpMovlpdMqVq(struct Machine *m) {
|
|
memcpy(ComputeReserveAddressWrite8(m), XmmRexrReg(m), 8);
|
|
}
|
|
|
|
static void OpMovlhpsVqUq(struct Machine *m) {
|
|
memcpy(XmmRexrReg(m) + 8, XmmRexbRm(m), 8);
|
|
}
|
|
|
|
static void OpMovhpsVqMq(struct Machine *m) {
|
|
memcpy(XmmRexrReg(m) + 8, ComputeReserveAddressRead8(m), 8);
|
|
}
|
|
|
|
static void OpMovhpdVqMq(struct Machine *m) {
|
|
memcpy(XmmRexrReg(m) + 8, ComputeReserveAddressRead8(m), 8);
|
|
}
|
|
|
|
static void OpMovshdupVqWq(struct Machine *m) {
|
|
uint8_t *dst, *src;
|
|
dst = XmmRexrReg(m);
|
|
src = GetModrmRegisterXmmPointerRead16(m);
|
|
memcpy(dst + 0 + 0, src + 04, 4);
|
|
memcpy(dst + 0 + 4, src + 04, 4);
|
|
memcpy(dst + 8 + 0, src + 12, 4);
|
|
memcpy(dst + 8 + 4, src + 12, 4);
|
|
}
|
|
|
|
static void OpMovhpsMqVq(struct Machine *m) {
|
|
memcpy(ComputeReserveAddressRead8(m), XmmRexrReg(m) + 8, 8);
|
|
}
|
|
|
|
static void OpMovhpdMqVq(struct Machine *m) {
|
|
memcpy(ComputeReserveAddressRead8(m), XmmRexrReg(m) + 8, 8);
|
|
}
|
|
|
|
static void OpMovqWqVq(struct Machine *m) {
|
|
if (IsModrmRegister(m->xedd)) {
|
|
memcpy(XmmRexbRm(m), XmmRexrReg(m), 8);
|
|
memset(XmmRexbRm(m) + 8, 0, 8);
|
|
} else {
|
|
memcpy(ComputeReserveAddressWrite8(m), XmmRexrReg(m), 8);
|
|
}
|
|
}
|
|
|
|
static void OpMovq2dqVdqNq(struct Machine *m) {
|
|
memcpy(XmmRexrReg(m), MmRm(m), 8);
|
|
memset(XmmRexrReg(m) + 8, 0, 8);
|
|
}
|
|
|
|
static void OpMovdq2qPqUq(struct Machine *m) {
|
|
memcpy(MmReg(m), XmmRexbRm(m), 8);
|
|
}
|
|
|
|
static void OpMovapsVpsWps(struct Machine *m) {
|
|
OpMovdqaVdqWdq(m);
|
|
}
|
|
|
|
static void OpMovapdVpdWpd(struct Machine *m) {
|
|
OpMovdqaVdqWdq(m);
|
|
}
|
|
|
|
static void OpMovapsWpsVps(struct Machine *m) {
|
|
OpMovdqaWdqVdq(m);
|
|
}
|
|
|
|
static void OpMovapdWpdVpd(struct Machine *m) {
|
|
OpMovdqaWdqVdq(m);
|
|
}
|
|
|
|
static void OpMovWpsVps(struct Machine *m) {
|
|
uint8_t *p, *r;
|
|
switch (m->xedd->op.rep | Prefix66(m->xedd)) {
|
|
case 0:
|
|
OpMovupsWpsVps(m);
|
|
break;
|
|
case 1:
|
|
OpMovupdWpsVps(m);
|
|
break;
|
|
case 2:
|
|
OpMovsdWpsVps(m);
|
|
break;
|
|
case 3:
|
|
OpMovssWpsVps(m);
|
|
break;
|
|
default:
|
|
unreachable;
|
|
}
|
|
}
|
|
|
|
static void OpMov0f28(struct Machine *m) {
|
|
if (!Prefix66(m->xedd)) {
|
|
OpMovapsVpsWps(m);
|
|
} else {
|
|
OpMovapdVpdWpd(m);
|
|
}
|
|
}
|
|
|
|
static void OpMov0f6e(struct Machine *m) {
|
|
if (Prefix66(m->xedd)) {
|
|
if (Rexw(m->xedd)) {
|
|
OpMovqVdqEqp(m);
|
|
} else {
|
|
OpMovdVdqEd(m);
|
|
}
|
|
} else {
|
|
if (Rexw(m->xedd)) {
|
|
OpMovqPqEqp(m);
|
|
} else {
|
|
OpMovdPqEd(m);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void OpMov0f6f(struct Machine *m) {
|
|
if (Prefix66(m->xedd)) {
|
|
OpMovdqaVdqWdq(m);
|
|
} else if (m->xedd->op.ild_f3) {
|
|
OpMovdquVdqWdq(m);
|
|
} else {
|
|
OpMovqPqQq(m);
|
|
}
|
|
}
|
|
|
|
static void OpMov0fE7(struct Machine *m) {
|
|
if (!Prefix66(m->xedd)) {
|
|
OpMovntqMqPq(m);
|
|
} else {
|
|
OpMovntdqMdqVdq(m);
|
|
}
|
|
}
|
|
|
|
static void OpMov0f7e(struct Machine *m) {
|
|
if (m->xedd->op.ild_f3) {
|
|
OpMovqVqWq(m);
|
|
} else if (Prefix66(m->xedd)) {
|
|
if (Rexw(m->xedd)) {
|
|
OpMovqEqpVdq(m);
|
|
} else {
|
|
OpMovdEdVdq(m);
|
|
}
|
|
} else {
|
|
if (Rexw(m->xedd)) {
|
|
OpMovqEqpPq(m);
|
|
} else {
|
|
OpMovdEdPq(m);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void OpMov0f7f(struct Machine *m) {
|
|
if (m->xedd->op.ild_f3) {
|
|
OpMovdquWdqVdq(m);
|
|
} else if (Prefix66(m->xedd)) {
|
|
OpMovdqaWdqVdq(m);
|
|
} else {
|
|
OpMovqQqPq(m);
|
|
}
|
|
}
|
|
|
|
static void OpMov0f10(struct Machine *m) {
|
|
uint8_t *p, *r;
|
|
switch (m->xedd->op.rep | Prefix66(m->xedd)) {
|
|
case 0:
|
|
OpMovupsVpsWps(m);
|
|
break;
|
|
case 1:
|
|
OpMovupdVpsWps(m);
|
|
break;
|
|
case 2:
|
|
OpMovsdVpsWps(m);
|
|
break;
|
|
case 3:
|
|
OpMovssVpsWps(m);
|
|
break;
|
|
default:
|
|
unreachable;
|
|
}
|
|
}
|
|
|
|
static void OpMov0f29(struct Machine *m) {
|
|
if (!Prefix66(m->xedd)) {
|
|
OpMovapsWpsVps(m);
|
|
} else {
|
|
OpMovapdWpdVpd(m);
|
|
}
|
|
}
|
|
|
|
static void OpMov0f2b(struct Machine *m) {
|
|
if (!Prefix66(m->xedd)) {
|
|
OpMovntpsMpsVps(m);
|
|
} else {
|
|
OpMovntpdMpdVpd(m);
|
|
}
|
|
}
|
|
|
|
static void OpMov0f12(struct Machine *m) {
|
|
switch (m->xedd->op.rep | Prefix66(m->xedd)) {
|
|
case 0:
|
|
if (IsModrmRegister(m->xedd)) {
|
|
OpMovhlpsVqUq(m);
|
|
} else {
|
|
OpMovlpsVqMq(m);
|
|
}
|
|
break;
|
|
case 1:
|
|
OpMovlpdVqMq(m);
|
|
break;
|
|
case 2:
|
|
OpMovddupVqWq(m);
|
|
break;
|
|
case 3:
|
|
OpMovsldupVqWq(m);
|
|
break;
|
|
default:
|
|
unreachable;
|
|
}
|
|
}
|
|
|
|
static void OpMov0f13(struct Machine *m) {
|
|
if (Prefix66(m->xedd)) {
|
|
OpMovlpdMqVq(m);
|
|
} else {
|
|
OpMovlpsMqVq(m);
|
|
}
|
|
}
|
|
|
|
static void OpMov0f16(struct Machine *m) {
|
|
switch (m->xedd->op.rep | Prefix66(m->xedd)) {
|
|
case 0:
|
|
if (IsModrmRegister(m->xedd)) {
|
|
OpMovlhpsVqUq(m);
|
|
} else {
|
|
OpMovhpsVqMq(m);
|
|
}
|
|
break;
|
|
case 1:
|
|
OpMovhpdVqMq(m);
|
|
break;
|
|
case 3:
|
|
OpMovshdupVqWq(m);
|
|
break;
|
|
default:
|
|
OpUd(m);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void OpMov0f17(struct Machine *m) {
|
|
if (Prefix66(m->xedd)) {
|
|
OpMovhpdMqVq(m);
|
|
} else {
|
|
OpMovhpsMqVq(m);
|
|
}
|
|
}
|
|
|
|
static void OpMov0fD6(struct Machine *m) {
|
|
if (m->xedd->op.ild_f3) {
|
|
OpMovq2dqVdqNq(m);
|
|
} else if (m->xedd->op.ild_f2) {
|
|
OpMovdq2qPqUq(m);
|
|
} else if (Prefix66(m->xedd)) {
|
|
OpMovqWqVq(m);
|
|
} else {
|
|
OpUd(m);
|
|
}
|
|
}
|
|
|
|
static void OpUnpcklpsd(struct Machine *m) {
|
|
uint8_t *a, *b;
|
|
a = XmmRexrReg(m);
|
|
b = GetModrmRegisterXmmPointerRead8(m);
|
|
if (Prefix66(m->xedd)) {
|
|
memcpy(a + 8, b, 8);
|
|
} else {
|
|
memcpy(a + 4 * 3, b + 4, 4);
|
|
memcpy(a + 4 * 2, a + 4, 4);
|
|
memcpy(a + 4 * 1, b + 0, 4);
|
|
}
|
|
}
|
|
|
|
static void OpUnpckhpsd(struct Machine *m) {
|
|
uint8_t *a, *b;
|
|
a = XmmRexrReg(m);
|
|
b = GetModrmRegisterXmmPointerRead16(m);
|
|
if (Prefix66(m->xedd)) {
|
|
memcpy(a + 0, b + 8, 8);
|
|
memcpy(a + 8, b + 8, 8);
|
|
} else {
|
|
memcpy(a + 4 * 0, a + 4 * 2, 4);
|
|
memcpy(a + 4 * 1, b + 4 * 2, 4);
|
|
memcpy(a + 4 * 2, a + 4 * 3, 4);
|
|
memcpy(a + 4 * 3, b + 4 * 3, 4);
|
|
}
|
|
}
|
|
|
|
static void OpPextrwGdqpUdqIb(struct Machine *m) {
|
|
uint8_t i;
|
|
i = m->xedd->op.uimm0;
|
|
i &= Prefix66(m->xedd) ? 7 : 3;
|
|
Write16(RegRexrReg(m), Read16(XmmRexbRm(m) + i * 2));
|
|
}
|
|
|
|
static void OpPinsrwVdqEwIb(struct Machine *m) {
|
|
uint8_t i;
|
|
i = m->xedd->op.uimm0;
|
|
i &= Prefix66(m->xedd) ? 7 : 3;
|
|
Write16(XmmRexrReg(m) + i * 2, Read16(GetModrmRegisterWordPointerRead2(m)));
|
|
}
|
|
|
|
static void OpShuffle(struct Machine *m) {
|
|
int16_t q16[4];
|
|
int16_t x16[8];
|
|
int32_t x32[4];
|
|
switch (m->xedd->op.rep | Prefix66(m->xedd)) {
|
|
case 0:
|
|
memcpy(q16, GetModrmRegisterXmmPointerRead8(m), 8);
|
|
(pshufw)(q16, q16, m->xedd->op.uimm0);
|
|
memcpy(XmmRexrReg(m), q16, 8);
|
|
break;
|
|
case 1:
|
|
memcpy(x32, GetModrmRegisterXmmPointerRead16(m), 16);
|
|
(pshufd)(x32, x32, m->xedd->op.uimm0);
|
|
memcpy(XmmRexrReg(m), x32, 16);
|
|
break;
|
|
case 2:
|
|
memcpy(x16, GetModrmRegisterXmmPointerRead16(m), 16);
|
|
(pshuflw)(x16, x16, m->xedd->op.uimm0);
|
|
memcpy(XmmRexrReg(m), x16, 16);
|
|
break;
|
|
case 3:
|
|
memcpy(x16, GetModrmRegisterXmmPointerRead16(m), 16);
|
|
(pshufhw)(x16, x16, m->xedd->op.uimm0);
|
|
memcpy(XmmRexrReg(m), x16, 16);
|
|
break;
|
|
default:
|
|
unreachable;
|
|
}
|
|
}
|
|
|
|
static void OpShufpsd(struct Machine *m) {
|
|
float s[4];
|
|
double d[2];
|
|
if (Prefix66(m->xedd)) {
|
|
memcpy(d, GetModrmRegisterXmmPointerRead16(m), 16);
|
|
(shufpd)(d, d, m->xedd->op.uimm0);
|
|
memcpy(XmmRexrReg(m), d, 16);
|
|
} else {
|
|
memcpy(s, GetModrmRegisterXmmPointerRead16(m), 16);
|
|
(shufps)(s, s, m->xedd->op.uimm0);
|
|
memcpy(XmmRexrReg(m), s, 16);
|
|
}
|
|
}
|
|
|
|
static void OpSqrtpsd(struct Machine *m) {
|
|
long i;
|
|
float_v xf;
|
|
double_v xd;
|
|
switch (m->xedd->op.rep | Prefix66(m->xedd)) {
|
|
case 0:
|
|
memcpy(&xf, GetModrmRegisterXmmPointerRead16(m), 16);
|
|
for (i = 0; i < 4; ++i) xf[i] = sqrtf(xf[i]);
|
|
memcpy(XmmRexrReg(m), &xf, 16);
|
|
break;
|
|
case 1:
|
|
memcpy(&xd, GetModrmRegisterXmmPointerRead16(m), 16);
|
|
for (i = 0; i < 2; ++i) xd[i] = sqrt(xd[i]);
|
|
memcpy(XmmRexrReg(m), &xd, 16);
|
|
break;
|
|
case 2:
|
|
memcpy(&xd, GetModrmRegisterXmmPointerRead8(m), 8);
|
|
xd[0] = sqrt(xd[0]);
|
|
memcpy(XmmRexrReg(m), &xd, 8);
|
|
break;
|
|
case 3:
|
|
memcpy(&xf, GetModrmRegisterXmmPointerRead4(m), 4);
|
|
xf[0] = sqrtf(xf[0]);
|
|
memcpy(XmmRexrReg(m), &xf, 4);
|
|
break;
|
|
default:
|
|
unreachable;
|
|
}
|
|
}
|
|
|
|
static void OpRsqrtps(struct Machine *m) {
|
|
unsigned i;
|
|
float_v x;
|
|
if (!m->xedd->op.ild_f3) {
|
|
memcpy(&x, GetModrmRegisterXmmPointerRead16(m), 16);
|
|
for (i = 0; i < 4; ++i) x[i] = 1.f / sqrtf(x[i]);
|
|
memcpy(XmmRexrReg(m), &x, 16);
|
|
} else {
|
|
memcpy(&x, GetModrmRegisterXmmPointerRead4(m), 4);
|
|
x[0] = 1.f / sqrtf(x[0]);
|
|
memcpy(XmmRexrReg(m), &x, 4);
|
|
}
|
|
}
|
|
|
|
static void OpRcpps(struct Machine *m) {
|
|
int i;
|
|
float_v x;
|
|
if (!m->xedd->op.ild_f3) {
|
|
memcpy(&x, GetModrmRegisterXmmPointerRead16(m), 16);
|
|
for (i = 0; i < 4; ++i) x[i] = 1.f / x[i];
|
|
memcpy(XmmRexrReg(m), &x, 16);
|
|
} else {
|
|
memcpy(&x, GetModrmRegisterXmmPointerRead4(m), 4);
|
|
x[0] = 1.f / x[0];
|
|
memcpy(XmmRexrReg(m), &x, 4);
|
|
}
|
|
}
|
|
|
|
static void OpVpsdWpsd(struct Machine *m,
|
|
float_v opf(struct Machine *, float_v, float_v),
|
|
double_v opd(struct Machine *, double_v, double_v),
|
|
bool isfloat, bool isdouble) {
|
|
float_v xf, yf;
|
|
double_v xd, yd;
|
|
if (isfloat) {
|
|
memcpy(&xf, XmmRexrReg(m), 16);
|
|
memcpy(&yf, GetModrmRegisterXmmPointerRead16(m), 16);
|
|
xf = opf(m, xf, yf);
|
|
memcpy(XmmRexrReg(m), &xf, 16);
|
|
} else if (isdouble) {
|
|
memcpy(&xd, XmmRexrReg(m), 16);
|
|
memcpy(&yd, GetModrmRegisterXmmPointerRead16(m), 16);
|
|
xd = opd(m, xd, yd);
|
|
memcpy(XmmRexrReg(m), &xd, 16);
|
|
} else {
|
|
OpUd(m);
|
|
}
|
|
}
|
|
|
|
static void OpVpsdWpsd66(struct Machine *m,
|
|
float_v opf(struct Machine *, float_v, float_v),
|
|
double_v opd(struct Machine *, double_v, double_v)) {
|
|
OpVpsdWpsd(m, opf, opd, !Prefix66(m->xedd), Prefix66(m->xedd));
|
|
}
|
|
|
|
static void OpVpsdWpsd66f2(struct Machine *m,
|
|
float_v opf(struct Machine *, float_v, float_v),
|
|
double_v opd(struct Machine *, double_v, double_v)) {
|
|
OpVpsdWpsd(m, opf, opd, m->xedd->op.ild_f2, Prefix66(m->xedd));
|
|
}
|
|
|
|
static void OpVspsdWspsd(struct Machine *m,
|
|
float_v opf(struct Machine *, float_v, float_v),
|
|
double_v opd(struct Machine *, double_v, double_v)) {
|
|
float_v xf, yf;
|
|
double_v xd, yd;
|
|
switch (m->xedd->op.rep | Prefix66(m->xedd)) {
|
|
case 0:
|
|
memcpy(&yf, GetModrmRegisterXmmPointerRead16(m), 16);
|
|
memcpy(&xf, XmmRexrReg(m), 16);
|
|
xf = opf(m, xf, yf);
|
|
memcpy(XmmRexrReg(m), &xf, 16);
|
|
break;
|
|
case 1:
|
|
memcpy(&yd, GetModrmRegisterXmmPointerRead16(m), 16);
|
|
memcpy(&xd, XmmRexrReg(m), 16);
|
|
xd = opd(m, xd, yd);
|
|
memcpy(XmmRexrReg(m), &xd, 16);
|
|
break;
|
|
case 2:
|
|
memcpy(&yd, GetModrmRegisterXmmPointerRead8(m), 8);
|
|
memcpy(&xd, XmmRexrReg(m), 8);
|
|
xd = opd(m, xd, yd);
|
|
memcpy(XmmRexrReg(m), &xd, 8);
|
|
break;
|
|
case 3:
|
|
memcpy(&yf, GetModrmRegisterXmmPointerRead4(m), 4);
|
|
memcpy(&xf, XmmRexrReg(m), 4);
|
|
xf = opf(m, xf, yf);
|
|
memcpy(XmmRexrReg(m), &xf, 4);
|
|
break;
|
|
default:
|
|
unreachable;
|
|
}
|
|
}
|
|
|
|
static void OpComissVsWs(struct Machine *m) {
|
|
float xf, yf;
|
|
double xd, yd;
|
|
uint8_t zf, cf, pf, ie;
|
|
if (!Prefix66(m->xedd)) {
|
|
memcpy(&xf, XmmRexrReg(m), 4);
|
|
memcpy(&yf, GetModrmRegisterXmmPointerRead4(m), 4);
|
|
if (!isnan(xf) && !isnan(yf)) {
|
|
zf = xf == yf;
|
|
cf = xf < yf;
|
|
pf = false;
|
|
ie = false;
|
|
} else {
|
|
zf = cf = pf = ie = true;
|
|
}
|
|
} else {
|
|
memcpy(&xd, XmmRexrReg(m), 8);
|
|
memcpy(&yd, GetModrmRegisterXmmPointerRead8(m), 8);
|
|
if (!isnan(xd) && !isnan(yd)) {
|
|
zf = xd == yd;
|
|
cf = xd < yd;
|
|
pf = false;
|
|
ie = false;
|
|
} else {
|
|
zf = cf = pf = ie = true;
|
|
}
|
|
}
|
|
m->flags = SetFlag(m->flags, FLAGS_ZF, zf);
|
|
m->flags = SetFlag(m->flags, FLAGS_PF, pf);
|
|
m->flags = SetFlag(m->flags, FLAGS_CF, cf);
|
|
m->flags = SetFlag(m->flags, FLAGS_SF, false);
|
|
m->flags = SetFlag(m->flags, FLAGS_OF, false);
|
|
if ((m->xedd->op.opcode & 1) && (m->sse.ie = ie) && !m->sse.im) {
|
|
HaltMachine(m, kMachineSimdException);
|
|
}
|
|
}
|
|
|
|
static float_v OpAddps(struct Machine *m, float_v x, float_v y) {
|
|
return x + y;
|
|
}
|
|
|
|
static double_v OpAddpd(struct Machine *m, double_v x, double_v y) {
|
|
return x + y;
|
|
}
|
|
|
|
static float_v OpMulps(struct Machine *m, float_v x, float_v y) {
|
|
return x * y;
|
|
}
|
|
|
|
static double_v OpMulpd(struct Machine *m, double_v x, double_v y) {
|
|
return x * y;
|
|
}
|
|
|
|
static float_v OpSubps(struct Machine *m, float_v x, float_v y) {
|
|
return x - y;
|
|
}
|
|
|
|
static double_v OpSubpd(struct Machine *m, double_v x, double_v y) {
|
|
return x - y;
|
|
}
|
|
|
|
static float_v OpDivps(struct Machine *m, float_v x, float_v y) {
|
|
return x / y;
|
|
}
|
|
|
|
static double_v OpDivpd(struct Machine *m, double_v x, double_v y) {
|
|
return x / y;
|
|
}
|
|
|
|
static float_v OpAndps(struct Machine *m, float_v x, float_v y) {
|
|
return (float_v)((int_v)x & (int_v)y);
|
|
}
|
|
|
|
static double_v OpAndpd(struct Machine *m, double_v x, double_v y) {
|
|
return (double_v)((long_v)x & (long_v)y);
|
|
}
|
|
|
|
static float_v OpAndnps(struct Machine *m, float_v x, float_v y) {
|
|
return (float_v)(~(int_v)x & (int_v)y);
|
|
}
|
|
|
|
static double_v OpAndnpd(struct Machine *m, double_v x, double_v y) {
|
|
return (double_v)(~(long_v)x & (long_v)y);
|
|
}
|
|
|
|
static float_v OpOrps(struct Machine *m, float_v x, float_v y) {
|
|
return (float_v)((int_v)x | (int_v)y);
|
|
}
|
|
|
|
static double_v OpOrpd(struct Machine *m, double_v x, double_v y) {
|
|
return (double_v)((long_v)x | (long_v)y);
|
|
}
|
|
|
|
static float_v OpXorps(struct Machine *m, float_v x, float_v y) {
|
|
return (float_v)((int_v)x ^ (int_v)y);
|
|
}
|
|
|
|
static double_v OpXorpd(struct Machine *m, double_v x, double_v y) {
|
|
return (double_v)((long_v)x ^ (long_v)y);
|
|
}
|
|
|
|
static double_v OpHaddpd(struct Machine *m, double_v x, double_v y) {
|
|
return (double_v){x[0] + x[1], y[0] + y[1]};
|
|
}
|
|
|
|
static float_v OpHaddps(struct Machine *m, float_v x, float_v y) {
|
|
return (float_v){x[0] + x[1], x[2] + x[3], y[0] + y[1], y[2] + y[3]};
|
|
}
|
|
|
|
static double_v OpHsubpd(struct Machine *m, double_v x, double_v y) {
|
|
return (double_v){x[0] - x[1], y[0] - y[1]};
|
|
}
|
|
|
|
static float_v OpHsubps(struct Machine *m, float_v x, float_v y) {
|
|
return (float_v){x[0] - x[1], x[2] - x[3], y[0] - y[1], y[2] - y[3]};
|
|
}
|
|
|
|
static double_v OpAddsubpd(struct Machine *m, double_v x, double_v y) {
|
|
return (double_v){x[0] - y[0], x[1] + y[1]};
|
|
}
|
|
|
|
static float_v OpAddsubps(struct Machine *m, float_v x, float_v y) {
|
|
return (float_v){x[0] - y[0], x[1] + y[1], x[2] - y[2], x[3] + y[3]};
|
|
}
|
|
|
|
static float_v OpMinps(struct Machine *m, float_v x, float_v y) {
|
|
int i;
|
|
for (i = 0; i < 4; ++i) {
|
|
x[i] = MIN(x[i], y[i]);
|
|
}
|
|
return x;
|
|
}
|
|
|
|
static double_v OpMinpd(struct Machine *m, double_v x, double_v y) {
|
|
int i;
|
|
for (i = 0; i < 4; ++i) {
|
|
x[i] = MIN(x[i], y[i]);
|
|
}
|
|
return x;
|
|
}
|
|
|
|
static float_v OpMaxps(struct Machine *m, float_v x, float_v y) {
|
|
int i;
|
|
for (i = 0; i < 4; ++i) {
|
|
x[i] = MAX(x[i], y[i]);
|
|
}
|
|
return x;
|
|
}
|
|
|
|
static double_v OpMaxpd(struct Machine *m, double_v x, double_v y) {
|
|
int i;
|
|
for (i = 0; i < 4; ++i) {
|
|
x[i] = MAX(x[i], y[i]);
|
|
}
|
|
return x;
|
|
}
|
|
|
|
static float_v OpCmpps(struct Machine *m, float_v x, float_v y) {
|
|
long i;
|
|
switch (m->xedd->op.uimm0) {
|
|
case 0:
|
|
return x == y;
|
|
case 1:
|
|
return x < y;
|
|
case 2:
|
|
return x <= y;
|
|
case 3:
|
|
for (i = 0; i < 4; ++i) {
|
|
x[i] = isnan(x[i]) || isnan(y[i]);
|
|
}
|
|
return x;
|
|
case 4:
|
|
return x != y;
|
|
case 5:
|
|
return x >= y;
|
|
case 6:
|
|
return x > y;
|
|
case 7:
|
|
for (i = 0; i < 4; ++i) {
|
|
x[i] = !(isnan(x[i]) || isnan(y[i]));
|
|
}
|
|
return x;
|
|
default:
|
|
OpUd(m);
|
|
}
|
|
}
|
|
|
|
static double_v OpCmppd(struct Machine *m, double_v x, double_v y) {
|
|
long i;
|
|
switch (m->xedd->op.uimm0) {
|
|
case 0:
|
|
return x == y;
|
|
case 1:
|
|
return x < y;
|
|
case 2:
|
|
return x <= y;
|
|
case 3:
|
|
for (i = 0; i < 2; ++i) {
|
|
x[i] = isnan(x[i]) || isnan(y[i]);
|
|
}
|
|
return x;
|
|
case 4:
|
|
return x != y;
|
|
case 5:
|
|
return x >= y;
|
|
case 6:
|
|
return x > y;
|
|
case 7:
|
|
for (i = 0; i < 2; ++i) {
|
|
x[i] = !(isnan(x[i]) || isnan(y[i]));
|
|
}
|
|
return x;
|
|
default:
|
|
OpUd(m);
|
|
}
|
|
}
|
|
|
|
static void OpAddpsd(struct Machine *m) {
|
|
OpVspsdWspsd(m, OpAddps, OpAddpd);
|
|
}
|
|
|
|
static void OpMulpsd(struct Machine *m) {
|
|
OpVspsdWspsd(m, OpMulps, OpMulpd);
|
|
}
|
|
|
|
static void OpSubpsd(struct Machine *m) {
|
|
OpVspsdWspsd(m, OpSubps, OpSubpd);
|
|
}
|
|
|
|
static void OpDivpsd(struct Machine *m) {
|
|
OpVspsdWspsd(m, OpDivps, OpDivpd);
|
|
}
|
|
|
|
static void OpMinpsd(struct Machine *m) {
|
|
OpVspsdWspsd(m, OpMinps, OpMinpd);
|
|
}
|
|
|
|
static void OpMaxpsd(struct Machine *m) {
|
|
OpVspsdWspsd(m, OpMaxps, OpMaxpd);
|
|
}
|
|
|
|
static void OpCmppsd(struct Machine *m) {
|
|
OpVspsdWspsd(m, OpCmpps, OpCmppd);
|
|
}
|
|
|
|
static void OpAndpsd(struct Machine *m) {
|
|
OpVpsdWpsd66(m, OpAndps, OpAndpd);
|
|
}
|
|
|
|
static void OpAndnpsd(struct Machine *m) {
|
|
OpVpsdWpsd66(m, OpAndnps, OpAndnpd);
|
|
}
|
|
|
|
static void OpOrpsd(struct Machine *m) {
|
|
OpVpsdWpsd66(m, OpOrps, OpOrpd);
|
|
}
|
|
|
|
static void OpXorpsd(struct Machine *m) {
|
|
OpVpsdWpsd66(m, OpXorps, OpXorpd);
|
|
}
|
|
|
|
static void OpHaddpsd(struct Machine *m) {
|
|
OpVpsdWpsd66f2(m, OpHaddps, OpHaddpd);
|
|
}
|
|
|
|
static void OpHsubpsd(struct Machine *m) {
|
|
OpVpsdWpsd66f2(m, OpHsubps, OpHsubpd);
|
|
}
|
|
|
|
static void OpAddsubpsd(struct Machine *m) {
|
|
OpVpsdWpsd66f2(m, OpAddsubps, OpAddsubpd);
|
|
}
|
|
|
|
static void OpAluw(struct Machine *m,
|
|
int64_t f(int, int, uint64_t, uint64_t, uint32_t *), int h) {
|
|
int64_t v;
|
|
void *p[2];
|
|
uint64_t x, y, z;
|
|
uint8_t w, *a, *b, *c, split[8];
|
|
w = RegLog2(m->xedd);
|
|
if (ModrmMod(m->xedd) != 0b11) {
|
|
v = ComputeAddress(m);
|
|
if (h & ALU_FLIP) {
|
|
a = Load(m, v, 1 << w, split);
|
|
} else {
|
|
a = BeginLoadStore(m, v, 1 << w, p, split);
|
|
}
|
|
} else {
|
|
v = 0;
|
|
a = RegRexbRm(m);
|
|
}
|
|
b = RegRexrReg(m);
|
|
if (h & ALU_FLIP) {
|
|
c = b;
|
|
b = a;
|
|
a = c;
|
|
}
|
|
y = Read64(b);
|
|
x = Read64(a);
|
|
z = f(w, h, x, y, &m->flags);
|
|
switch (w) {
|
|
case 0:
|
|
Write8(a, z);
|
|
break;
|
|
case 1:
|
|
Write16(a, z);
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
Write64(a, z);
|
|
break;
|
|
default:
|
|
unreachable;
|
|
}
|
|
EndStore(m, v, 1 << w, p, split);
|
|
if (h & ALU_XCHG) {
|
|
switch (w) {
|
|
case 0:
|
|
Write8(b, x);
|
|
break;
|
|
case 1:
|
|
Write16(b, x);
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
Write64(b, x);
|
|
break;
|
|
default:
|
|
unreachable;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void OpAlub(struct Machine *m,
|
|
int64_t f(int, int, uint64_t, uint64_t, uint32_t *), int h) {
|
|
int64_t v;
|
|
uint64_t x, y, z;
|
|
uint8_t *a, *b, *c;
|
|
if (!m->xedd->op.has_modrm || IsModrmRegister(m->xedd)) {
|
|
a = ByteRexbRm(m);
|
|
} else {
|
|
v = ComputeAddress(m);
|
|
a = ResolveAddress(m, v);
|
|
if (h & ALU_FLIP) {
|
|
SetReadAddr(m, v, 1);
|
|
} else {
|
|
SetWriteAddr(m, v, 1);
|
|
}
|
|
}
|
|
b = ByteRexrReg(m);
|
|
if (h & ALU_FLIP) {
|
|
c = b;
|
|
b = a;
|
|
a = c;
|
|
}
|
|
y = Read8(b);
|
|
x = Read8(a);
|
|
z = f(0, h, x, y, &m->flags);
|
|
Write8(a, z);
|
|
if (h & ALU_XCHG) Write8(b, x);
|
|
}
|
|
|
|
static void OpAluwi(struct Machine *m,
|
|
int64_t f(int, int, uint64_t, uint64_t, uint32_t *), int h,
|
|
uint64_t yimm) {
|
|
int64_t v;
|
|
void *p[2];
|
|
uint64_t x, y, z;
|
|
uint8_t w, *a, *c, split[8];
|
|
w = RegLog2(m->xedd);
|
|
if (m->xedd->op.has_modrm && ModrmMod(m->xedd) != 0b11) {
|
|
v = ComputeAddress(m);
|
|
a = BeginLoadStore(m, v, 1 << w, p, split);
|
|
} else {
|
|
v = 0;
|
|
a = RegRexbRm(m);
|
|
}
|
|
y = yimm;
|
|
x = Read64(a);
|
|
z = f(w, h, x, y, &m->flags);
|
|
switch (w) {
|
|
case 0:
|
|
Write8(a, z);
|
|
break;
|
|
case 1:
|
|
Write16(a, z);
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
Write64(a, z);
|
|
break;
|
|
default:
|
|
unreachable;
|
|
}
|
|
EndStore(m, v, 1 << w, p, split);
|
|
}
|
|
|
|
static void OpAlubi(struct Machine *m,
|
|
int64_t f(int, int, uint64_t, uint64_t, uint32_t *), int h,
|
|
uint64_t yimm) {
|
|
int64_t v;
|
|
uint64_t x, y, z;
|
|
uint8_t *a, *b, *c;
|
|
if (!m->xedd->op.has_modrm || IsModrmRegister(m->xedd)) {
|
|
a = ByteRexbRm(m);
|
|
} else {
|
|
v = ComputeAddress(m);
|
|
a = ResolveAddress(m, v);
|
|
SetWriteAddr(m, v, 1);
|
|
}
|
|
y = yimm;
|
|
b = NULL;
|
|
x = Read8(a);
|
|
z = f(0, h, x, y, &m->flags);
|
|
Write8(a, z);
|
|
}
|
|
|
|
static void ExecuteInstructionMap0(struct Machine *m) {
|
|
switch (m->xedd->op.opcode) {
|
|
CASE(/*0120 0x50*/ 0b01010000 ... 0x57, OpPushZvq(m));
|
|
CASE(/*0130 0x58*/ 0b01011000 ... 0x5f, OpPopZvq(m));
|
|
CASE(/*0143 0x63*/ 0b01100011, OpMovsxdGdqpEd(m));
|
|
CASE(/*0150 0x68*/ 0b01101000, PushOsz(m, m->xedd->op.uimm0));
|
|
CASE(/*0151 0x69*/ 0b01101001, OpImulGvqpEvqpImm(m));
|
|
CASE(/*0152 0x6A*/ 0b01101010, PushOsz(m, m->xedd->op.uimm0));
|
|
CASE(/*0153 0x6B*/ 0b01101011, OpImulGvqpEvqpImm(m));
|
|
CASE(/*0154 0x6C*/ 0b01101100, OpString(m, STRING_INS));
|
|
CASE(/*0155 0x6D*/ 0b01101101, OpString(m, STRING_INS));
|
|
CASE(/*0156 0x6E*/ 0b01101110, OpString(m, STRING_OUTS));
|
|
CASE(/*0157 0x6F*/ 0b01101111, OpString(m, STRING_OUTS));
|
|
CASE(/*0160 0x70*/ 0b01110000, if (GetCond(m, 0x0)) OpJmp(m));
|
|
CASE(/*0161 0x71*/ 0b01110001, if (GetCond(m, 0x1)) OpJmp(m));
|
|
CASE(/*0162 0x72*/ 0b01110010, if (GetCond(m, 0x2)) OpJmp(m));
|
|
CASE(/*0163 0x73*/ 0b01110011, if (GetCond(m, 0x3)) OpJmp(m));
|
|
CASE(/*0164 0x74*/ 0b01110100, if (GetCond(m, 0x4)) OpJmp(m));
|
|
CASE(/*0165 0x75*/ 0b01110101, if (GetCond(m, 0x5)) OpJmp(m));
|
|
CASE(/*0166 0x76*/ 0b01110110, if (GetCond(m, 0x6)) OpJmp(m));
|
|
CASE(/*0167 0x77*/ 0b01110111, if (GetCond(m, 0x7)) OpJmp(m));
|
|
CASE(/*0170 0x78*/ 0b01111000, if (GetCond(m, 0x8)) OpJmp(m));
|
|
CASE(/*0171 0x79*/ 0b01111001, if (GetCond(m, 0x9)) OpJmp(m));
|
|
CASE(/*0172 0x7A*/ 0b01111010, if (GetCond(m, 0xa)) OpJmp(m));
|
|
CASE(/*0173 0x7B*/ 0b01111011, if (GetCond(m, 0xb)) OpJmp(m));
|
|
CASE(/*0174 0x7C*/ 0b01111100, if (GetCond(m, 0xc)) OpJmp(m));
|
|
CASE(/*0175 0x7D*/ 0b01111101, if (GetCond(m, 0xd)) OpJmp(m));
|
|
CASE(/*0176 0x7E*/ 0b01111110, if (GetCond(m, 0xe)) OpJmp(m));
|
|
CASE(/*0177 0x7F*/ 0b01111111, if (GetCond(m, 0xf)) OpJmp(m));
|
|
CASE(/*0200 0x80*/ 0b10000000, OpAlubi(m, Alu, ModrmReg(m->xedd), UIMM0));
|
|
CASE(/*0201 0x81*/ 0b10000001, OpAluwi(m, Alu, ModrmReg(m->xedd), UIMM0));
|
|
CASE(/*0202 0x82*/ 0b10000010, OpAlubi(m, Alu, ModrmReg(m->xedd), UIMM0));
|
|
CASE(/*0203 0x83*/ 0b10000011, OpAluwi(m, Alu, ModrmReg(m->xedd), UIMM0));
|
|
CASE(/*0204 0x84*/ 0b10000100, OpAlub(m, Alu, ALU_TEST | ALU_AND));
|
|
CASE(/*0205 0x85*/ 0b10000101, OpAluw(m, Alu, ALU_TEST | ALU_AND));
|
|
CASE(/*0206 0x86*/ 0b10000110, OpXchgGbEb(m));
|
|
CASE(/*0207 0x87*/ 0b10000111, OpXchgGvqpEvqp(m));
|
|
CASE(/*0210 0x88*/ 0b10001000, OpMovEbGb(m));
|
|
CASE(/*0211 0x89*/ 0b10001001, OpMovEvqpGvqp(m));
|
|
CASE(/*0212 0x8A*/ 0b10001010, OpMovGbEb(m));
|
|
CASE(/*0213 0x8B*/ 0b10001011, OpMovGvqpEvqp(m));
|
|
CASE(/*0214 0x8C*/ 0b10001100, OpMovEvqpSw(m));
|
|
CASE(/*0215 0x8D*/ 0b10001101, OpLeaGvqpM(m));
|
|
CASE(/*0216 0x8E*/ 0b10001110, OpMovSwEvqp(m));
|
|
CASE(/*0217 0x8F*/ 0b10001111, OpPopEvq(m));
|
|
CASE(/*0220 0x90*/ 0b10010000, OpNop(m));
|
|
CASE(/*0221 0x91*/ 0b10010001 ... 0x97, OpXchgZvqp(m));
|
|
CASE(/*0230 0x98*/ 0b10011000, OpConvert1(m));
|
|
CASE(/*0231 0x99*/ 0b10011001, OpConvert2(m));
|
|
CASE(/*0234 0x9C*/ 0b10011100, OpPushf(m));
|
|
CASE(/*0235 0x9D*/ 0b10011101, OpPopf(m));
|
|
CASE(/*0236 0x9E*/ 0b10011110, OpSahf(m));
|
|
CASE(/*0237 0x9F*/ 0b10011111, OpLahf(m));
|
|
CASE(/*0233 0x9b*/ 0b10011011, OpFwait(m));
|
|
CASE(/*0240 0xA0*/ 0b10100000, OpMovAlOb(m));
|
|
CASE(/*0241 0xA1*/ 0b10100001, OpMovRaxOvqp(m));
|
|
CASE(/*0242 0xA2*/ 0b10100010, OpMovObAl(m));
|
|
CASE(/*0243 0xA3*/ 0b10100011, OpMovOvqpRax(m));
|
|
CASE(/*0244 0xA4*/ 0b10100100, OpMovsb(m));
|
|
CASE(/*0245 0xA5*/ 0b10100101, OpString(m, STRING_MOVS));
|
|
CASE(/*0246 0xA6*/ 0b10100110, OpString(m, STRING_CMPS));
|
|
CASE(/*0247 0xA7*/ 0b10100111, OpString(m, STRING_CMPS));
|
|
CASE(/*0250 0xA8*/ 0b10101000, OpAlubi(m, Alu, ALU_TEST | ALU_AND, UIMM0));
|
|
CASE(/*0251 0xA9*/ 0b10101001, OpAluwi(m, Alu, ALU_TEST | ALU_AND, UIMM0));
|
|
CASE(/*0252 0xAA*/ 0b10101010, OpStosb(m));
|
|
CASE(/*0253 0xAB*/ 0b10101011, OpString(m, STRING_STOS));
|
|
CASE(/*0254 0xAC*/ 0b10101100, OpString(m, STRING_LODS));
|
|
CASE(/*0255 0xAD*/ 0b10101101, OpString(m, STRING_LODS));
|
|
CASE(/*0256 0xAE*/ 0b10101110, OpString(m, STRING_SCAS));
|
|
CASE(/*0257 0xAF*/ 0b10101111, OpString(m, STRING_SCAS));
|
|
CASE(/*0260 0xB0*/ 0b10110000 ... 0b10110111, OpMovZbIb(m));
|
|
CASE(/*0270 0xB8*/ 0b10111000 ... 0b10111111, OpMovZvqpIvqp(m));
|
|
CASE(/*0300 0xC0*/ 0b11000000, OpAlubi(m, Bsu, ModrmReg(m->xedd), UIMM0));
|
|
CASE(/*0301 0xC1*/ 0b11000001, OpAluwi(m, Bsu, ModrmReg(m->xedd), UIMM0));
|
|
CASE(/*0302 0xC2*/ 0b11000010, OpRet(m, m->xedd->op.uimm0));
|
|
CASE(/*0303 0xC3*/ 0b11000011, OpRet(m, 0));
|
|
CASE(/*0306 0xC6*/ 0b11000110, OpMovEbIb(m));
|
|
CASE(/*0307 0xC7*/ 0b11000111, OpMovEvqpIvds(m));
|
|
CASE(/*0311 0xC9*/ 0b11001001, OpLeave(m));
|
|
CASE(/*0314 0xCC*/ 0b11001100, OpInterrupt(m, 3));
|
|
CASE(/*0315 0xCD*/ 0b11001101, OpInterrupt(m, m->xedd->op.uimm0));
|
|
CASE(/*0320 0xD0*/ 0b11010000, OpAlubi(m, Bsu, ModrmReg(m->xedd), 1));
|
|
CASE(/*0321 0xD1*/ 0b11010001, OpAluwi(m, Bsu, ModrmReg(m->xedd), 1));
|
|
CASE(/*0322 0xD2*/ 0b11010010, OpAlubi(m, Bsu, REG, m->cx[0]));
|
|
CASE(/*0323 0xD3*/ 0b11010011, OpAluwi(m, Bsu, REG, m->cx[0]));
|
|
CASE(/*0327 0xD7*/ 0b11010111, OpXlat(m));
|
|
CASE(/*0340 0xE0*/ 0b11100000, OpLoop(m, !GetFlag(m->flags, FLAGS_ZF)));
|
|
CASE(/*0341 0xE1*/ 0b11100001, OpLoop(m, GetFlag(m->flags, FLAGS_ZF)));
|
|
CASE(/*0342 0xE2*/ 0b11100010, OpLoop(m, 1));
|
|
CASE(/*0343 0xE3*/ 0b11100011, OpJcxz(m));
|
|
CASE(/*0344 0xE4*/ 0b11100100, Write8(m->ax, OpIn(m, UIMM0)));
|
|
CASE(/*0345 0xE5*/ 0b11100101, Write32(m->ax, OpIn(m, UIMM0)));
|
|
CASE(/*0346 0xE6*/ 0b11100110, OpOut(m, UIMM0, Read8(m->ax)));
|
|
CASE(/*0347 0xE7*/ 0b11100111, OpOut(m, UIMM0, Read32(m->ax)));
|
|
CASE(/*0350 0xE8*/ 0b11101000, OpCallJvds(m));
|
|
CASE(/*0351 0xE9*/ 0b11101001, OpJmp(m));
|
|
CASE(/*0353 0xEB*/ 0b11101011, OpJmp(m));
|
|
CASE(/*0354 0xEC*/ 0b11101100, Write8(m->ax, OpIn(m, Read16(m->dx))));
|
|
CASE(/*0355 0xED*/ 0b11101101, Write32(m->ax, OpIn(m, Read16(m->dx))));
|
|
CASE(/*0356 0xEE*/ 0b11101110, OpOut(m, Read16(m->dx), Read8(m->ax)));
|
|
CASE(/*0357 0xEF*/ 0b11101111, OpOut(m, Read16(m->dx), Read32(m->ax)));
|
|
CASE(/*0361 0xF1*/ 0b11110001, OpInterrupt(m, 1));
|
|
CASE(/*0364 0xF4*/ 0b11110100, OpHlt(m));
|
|
CASE(/*0365 0xF5*/ 0b11110101, OpCmc(m));
|
|
CASE(/*0370 0xF8*/ 0b11111000, OpClc(m));
|
|
CASE(/*0371 0xF9*/ 0b11111001, OpStc(m));
|
|
CASE(/*0372 0xFA*/ 0b11111010, OpCli(m));
|
|
CASE(/*0373 0xFB*/ 0b11111011, OpSti(m));
|
|
CASE(/*0374 0xFC*/ 0b11111100, OpCld(m));
|
|
CASE(/*0375 0xFD*/ 0b11111101, OpStd(m));
|
|
case /*0004 0x04*/ 0b00000100:
|
|
case /*0014 0x0C*/ 0b00001100:
|
|
case /*0024 0x14*/ 0b00010100:
|
|
case /*0034 0x1C*/ 0b00011100:
|
|
case /*0044 0x24*/ 0b00100100:
|
|
case /*0054 0x2C*/ 0b00101100:
|
|
case /*0064 0x34*/ 0b00110100:
|
|
case /*0074 0x3C*/ 0b00111100:
|
|
OpAlubi(m, Alu, (m->xedd->op.opcode & 070) >> 3, m->xedd->op.uimm0);
|
|
break;
|
|
case /*0005 0x05*/ 0b00000101:
|
|
case /*0015 0x0D*/ 0b00001101:
|
|
case /*0025 0x15*/ 0b00010101:
|
|
case /*0035 0x1D*/ 0b00011101:
|
|
case /*0045 0x25*/ 0b00100101:
|
|
case /*0055 0x2D*/ 0b00101101:
|
|
case /*0065 0x35*/ 0b00110101:
|
|
case /*0075 0x3D*/ 0b00111101:
|
|
OpAluwi(m, Alu, (m->xedd->op.opcode & 070) >> 3, m->xedd->op.uimm0);
|
|
break;
|
|
case /*0000 0x00*/ 0b00000000:
|
|
case /*0002 0x02*/ 0b00000010:
|
|
case /*0010 0x08*/ 0b00001000:
|
|
case /*0012 0x0A*/ 0b00001010:
|
|
case /*0020 0x10*/ 0b00010000:
|
|
case /*0022 0x12*/ 0b00010010:
|
|
case /*0030 0x18*/ 0b00011000:
|
|
case /*0032 0x1A*/ 0b00011010:
|
|
case /*0040 0x20*/ 0b00100000:
|
|
case /*0042 0x22*/ 0b00100010:
|
|
case /*0050 0x28*/ 0b00101000:
|
|
case /*0052 0x2A*/ 0b00101010:
|
|
case /*0060 0x30*/ 0b00110000:
|
|
case /*0062 0x32*/ 0b00110010:
|
|
case /*0070 0x38*/ 0b00111000:
|
|
case /*0072 0x3A*/ 0b00111010:
|
|
OpAlub(m, Alu,
|
|
((m->xedd->op.opcode & 070) >> 3 |
|
|
(m->xedd->op.opcode & 0b010 ? ALU_FLIP : 0)));
|
|
break;
|
|
case /*0001 0x01*/ 0b00000001:
|
|
case /*0003 0x03*/ 0b00000011:
|
|
case /*0011 0x09*/ 0b00001001:
|
|
case /*0013 0x0B*/ 0b00001011:
|
|
case /*0021 0x11*/ 0b00010001:
|
|
case /*0023 0x13*/ 0b00010011:
|
|
case /*0031 0x19*/ 0b00011001:
|
|
case /*0033 0x1B*/ 0b00011011:
|
|
case /*0041 0x21*/ 0b00100001:
|
|
case /*0043 0x23*/ 0b00100011:
|
|
case /*0051 0x29*/ 0b00101001:
|
|
case /*0053 0x2B*/ 0b00101011:
|
|
case /*0061 0x31*/ 0b00110001:
|
|
case /*0063 0x33*/ 0b00110011:
|
|
case /*0071 0x39*/ 0b00111001:
|
|
case /*0073 0x3B*/ 0b00111011:
|
|
OpAluw(m, Alu,
|
|
((m->xedd->op.opcode & 070) >> 3 |
|
|
(m->xedd->op.opcode & 0b010 ? ALU_FLIP : 0)));
|
|
break;
|
|
case /*0330 0xD8*/ 0b11011000:
|
|
case /*0331 0xD9*/ 0b11011001:
|
|
case /*0332 0xDA*/ 0b11011010:
|
|
case /*0333 0xDB*/ 0b11011011:
|
|
case /*0334 0xDC*/ 0b11011100:
|
|
case /*0335 0xDD*/ 0b11011101:
|
|
case /*0336 0xDE*/ 0b11011110:
|
|
case /*0337 0xDF*/ 0b11011111:
|
|
OpFpu(m);
|
|
break;
|
|
case /*0366 0xF6*/ 0b11110110:
|
|
switch (ModrmReg(m->xedd)) {
|
|
CASE(0, OpAlubi(m, Alu, ALU_TEST | ALU_AND, UIMM0));
|
|
CASE(1, OpAlubi(m, Alu, ALU_TEST | ALU_AND, UIMM0));
|
|
CASE(2, OpEb(m, AluNot));
|
|
CASE(3, OpEb(m, AluNeg));
|
|
CASE(4, OpMulAxAlEbUnsigned(m));
|
|
CASE(5, OpMulAxAlEbSigned(m));
|
|
CASE(6, OpDivAlAhAxEbUnsigned(m));
|
|
CASE(7, OpDivAlAhAxEbSigned(m));
|
|
default:
|
|
unreachable;
|
|
}
|
|
break;
|
|
case /*0367 0xF7*/ 0b11110111:
|
|
switch (ModrmReg(m->xedd)) {
|
|
CASE(0, OpAluwi(m, Alu, ALU_TEST | ALU_AND, UIMM0));
|
|
CASE(1, OpAluwi(m, Alu, ALU_TEST | ALU_AND, UIMM0));
|
|
CASE(2, OpEvqp(m, AluNot));
|
|
CASE(3, OpEvqp(m, AluNeg));
|
|
CASE(4, OpMulRdxRaxEvqpUnsigned(m));
|
|
CASE(5, OpMulRdxRaxEvqpSigned(m));
|
|
CASE(6, OpDivRdxRaxEvqpUnsigned(m));
|
|
CASE(7, OpDivRdxRaxEvqpSigned(m));
|
|
default:
|
|
unreachable;
|
|
}
|
|
break;
|
|
case /*0376 0xFE*/ 0b11111110:
|
|
switch (ModrmReg(m->xedd)) {
|
|
CASE(0b000, OpEb(m, AluInc));
|
|
CASE(0b001, OpEb(m, AluDec));
|
|
default:
|
|
OpUd(m);
|
|
}
|
|
break;
|
|
case /*0377 0xFF*/ 0b11111111:
|
|
switch (ModrmReg(m->xedd)) {
|
|
CASE(0, OpEvqp(m, AluInc));
|
|
CASE(1, OpEvqp(m, AluDec));
|
|
CASE(2, OpCallEq(m));
|
|
CASE(4, OpJmpEq(m));
|
|
CASE(6, OpPushEvq(m));
|
|
default:
|
|
OpUd(m);
|
|
}
|
|
break;
|
|
default:
|
|
OpUd(m);
|
|
}
|
|
}
|
|
|
|
static void ExecuteInstructionMap1(struct Machine *m) {
|
|
switch (m->xedd->op.opcode) {
|
|
CASE(/*0005 0x05*/ 0b00000101, OpSyscall(m));
|
|
CASE(/*0020 0x10*/ 0b00010000, OpMov0f10(m));
|
|
CASE(/*0021 0x11*/ 0b00010001, OpMovWpsVps(m));
|
|
CASE(/*0022 0x12*/ 0b00010010, OpMov0f12(m));
|
|
CASE(/*0023 0x13*/ 0b00010011, OpMov0f13(m));
|
|
CASE(/*0024 0x14*/ 0b00010100, OpUnpcklpsd(m));
|
|
CASE(/*0025 0x15*/ 0b00010101, OpUnpckhpsd(m));
|
|
CASE(/*0026 0x16*/ 0b00010110, OpMov0f16(m));
|
|
CASE(/*0027 0x17*/ 0b00010111, OpMov0f17(m));
|
|
CASE(/*0050 0x28*/ 0b00101000, OpMov0f28(m));
|
|
CASE(/*0051 0x29*/ 0b00101001, OpMovWpsVps(m));
|
|
CASE(/*0052 0x2A*/ 0b00101010, OpCvt(m, kOpCvt0f2a));
|
|
CASE(/*0053 0x2B*/ 0b00101011, OpMov0f2b(m));
|
|
CASE(/*0054 0x2C*/ 0b00101100, OpCvt(m, kOpCvtt0f2c));
|
|
CASE(/*0055 0x2D*/ 0b00101101, OpCvt(m, kOpCvt0f2d));
|
|
CASE(/*0056 0x2E*/ 0b00101110, OpComissVsWs(m));
|
|
CASE(/*0057 0x2F*/ 0b00101111, OpComissVsWs(m));
|
|
CASE(/*0061 0x31*/ 0b00110001, OpRdtsc(m));
|
|
CASE(/*0100 0x40*/ 0b01000000, if (GetCond(m, 0x0)) OpMovGvqpEvqp(m));
|
|
CASE(/*0101 0x41*/ 0b01000001, if (GetCond(m, 0x1)) OpMovGvqpEvqp(m));
|
|
CASE(/*0102 0x42*/ 0b01000010, if (GetCond(m, 0x2)) OpMovGvqpEvqp(m));
|
|
CASE(/*0103 0x43*/ 0b01000011, if (GetCond(m, 0x3)) OpMovGvqpEvqp(m));
|
|
CASE(/*0104 0x44*/ 0b01000100, if (GetCond(m, 0x4)) OpMovGvqpEvqp(m));
|
|
CASE(/*0105 0x45*/ 0b01000101, if (GetCond(m, 0x5)) OpMovGvqpEvqp(m));
|
|
CASE(/*0106 0x46*/ 0b01000110, if (GetCond(m, 0x6)) OpMovGvqpEvqp(m));
|
|
CASE(/*0107 0x47*/ 0b01000111, if (GetCond(m, 0x7)) OpMovGvqpEvqp(m));
|
|
CASE(/*0110 0x48*/ 0b01001000, if (GetCond(m, 0x8)) OpMovGvqpEvqp(m));
|
|
CASE(/*0111 0x49*/ 0b01001001, if (GetCond(m, 0x9)) OpMovGvqpEvqp(m));
|
|
CASE(/*0112 0x4a*/ 0b01001010, if (GetCond(m, 0xa)) OpMovGvqpEvqp(m));
|
|
CASE(/*0113 0x4b*/ 0b01001011, if (GetCond(m, 0xb)) OpMovGvqpEvqp(m));
|
|
CASE(/*0114 0x4c*/ 0b01001100, if (GetCond(m, 0xc)) OpMovGvqpEvqp(m));
|
|
CASE(/*0115 0x4d*/ 0b01001101, if (GetCond(m, 0xd)) OpMovGvqpEvqp(m));
|
|
CASE(/*0116 0x4e*/ 0b01001110, if (GetCond(m, 0xe)) OpMovGvqpEvqp(m));
|
|
CASE(/*0117 0x4f*/ 0b01001111, if (GetCond(m, 0xf)) OpMovGvqpEvqp(m));
|
|
CASE(/*0121 0x51*/ 0b01010001, OpSqrtpsd(m));
|
|
CASE(/*0122 0x52*/ 0b01010010, OpRsqrtps(m));
|
|
CASE(/*0123 0x53*/ 0b01010011, OpRcpps(m));
|
|
CASE(/*0124 0x54*/ 0b01010100, OpAndpsd(m));
|
|
CASE(/*0125 0x55*/ 0b01010101, OpAndnpsd(m));
|
|
CASE(/*0126 0x56*/ 0b01010110, OpOrpsd(m));
|
|
CASE(/*0127 0x57*/ 0b01010111, OpXorpsd(m));
|
|
CASE(/*0130 0x58*/ 0b01011000, OpAddpsd(m));
|
|
CASE(/*0131 0x59*/ 0b01011001, OpMulpsd(m));
|
|
CASE(/*0132 0x5A*/ 0b01011010, OpCvt(m, kOpCvt0f5a));
|
|
CASE(/*0133 0x5B*/ 0b01011011, OpCvt(m, kOpCvt0f5b));
|
|
CASE(/*0134 0x5C*/ 0b01011100, OpSubpsd(m));
|
|
CASE(/*0135 0x5D*/ 0b01011101, OpMinpsd(m));
|
|
CASE(/*0136 0x5E*/ 0b01011110, OpDivpsd(m));
|
|
CASE(/*0137 0x5F*/ 0b01011111, OpMaxpsd(m));
|
|
CASE(/*0140 0x60*/ 0b01100000, OpSse(m, kOpSsePunpcklbw));
|
|
CASE(/*0141 0x61*/ 0b01100001, OpSse(m, kOpSsePunpcklwd));
|
|
CASE(/*0142 0x62*/ 0b01100010, OpSse(m, kOpSsePunpckldq));
|
|
CASE(/*0143 0x63*/ 0b01100011, OpSse(m, kOpSsePacksswb));
|
|
CASE(/*0144 0x64*/ 0b01100100, OpSse(m, kOpSsePcmpgtb));
|
|
CASE(/*0145 0x65*/ 0b01100101, OpSse(m, kOpSsePcmpgtw));
|
|
CASE(/*0146 0x66*/ 0b01100110, OpSse(m, kOpSsePcmpgtd));
|
|
CASE(/*0147 0x67*/ 0b01100111, OpSse(m, kOpSsePackuswb));
|
|
CASE(/*0150 0x68*/ 0b01101000, OpSse(m, kOpSsePunpckhbw));
|
|
CASE(/*0151 0x69*/ 0b01101001, OpSse(m, kOpSsePunpckhwd));
|
|
CASE(/*0152 0x6A*/ 0b01101010, OpSse(m, kOpSsePunpckhdq));
|
|
CASE(/*0153 0x6B*/ 0b01101011, OpSse(m, kOpSsePackssdw));
|
|
CASE(/*0154 0x6C*/ 0b01101100, OpSse(m, kOpSsePunpcklqdq));
|
|
CASE(/*0155 0x6D*/ 0b01101101, OpSse(m, kOpSsePunpckhqdq));
|
|
CASE(/*0156 0x6E*/ 0b01101110, OpMov0f6e(m));
|
|
CASE(/*0157 0x6F*/ 0b01101111, OpMov0f6f(m));
|
|
CASE(/*0160 0x70*/ 0b01110000, OpShuffle(m));
|
|
CASE(/*0164 0x74*/ 0b01110100, OpSse(m, kOpSsePcmpeqb));
|
|
CASE(/*0165 0x75*/ 0b01110101, OpSse(m, kOpSsePcmpeqw));
|
|
CASE(/*0166 0x76*/ 0b01110110, OpSse(m, kOpSsePcmpeqd));
|
|
CASE(/*0174 0x7C*/ 0b01111100, OpHaddpsd(m));
|
|
CASE(/*0175 0x7D*/ 0b01111101, OpHsubpsd(m));
|
|
CASE(/*0176 0x7E*/ 0b01111110, OpMov0f7e(m));
|
|
CASE(/*0177 0x7F*/ 0b01111111, OpMov0f7f(m));
|
|
CASE(/*0200 0x80*/ 0b10000000, if (GetCond(m, 0x0)) OpJmp(m));
|
|
CASE(/*0201 0x81*/ 0b10000001, if (GetCond(m, 0x1)) OpJmp(m));
|
|
CASE(/*0202 0x82*/ 0b10000010, if (GetCond(m, 0x2)) OpJmp(m));
|
|
CASE(/*0203 0x83*/ 0b10000011, if (GetCond(m, 0x3)) OpJmp(m));
|
|
CASE(/*0204 0x84*/ 0b10000100, if (GetCond(m, 0x4)) OpJmp(m));
|
|
CASE(/*0205 0x85*/ 0b10000101, if (GetCond(m, 0x5)) OpJmp(m));
|
|
CASE(/*0206 0x86*/ 0b10000110, if (GetCond(m, 0x6)) OpJmp(m));
|
|
CASE(/*0207 0x87*/ 0b10000111, if (GetCond(m, 0x7)) OpJmp(m));
|
|
CASE(/*0210 0x88*/ 0b10001000, if (GetCond(m, 0x8)) OpJmp(m));
|
|
CASE(/*0211 0x89*/ 0b10001001, if (GetCond(m, 0x9)) OpJmp(m));
|
|
CASE(/*0212 0x8a*/ 0b10001010, if (GetCond(m, 0xa)) OpJmp(m));
|
|
CASE(/*0213 0x8b*/ 0b10001011, if (GetCond(m, 0xb)) OpJmp(m));
|
|
CASE(/*0214 0x8c*/ 0b10001100, if (GetCond(m, 0xc)) OpJmp(m));
|
|
CASE(/*0215 0x8d*/ 0b10001101, if (GetCond(m, 0xd)) OpJmp(m));
|
|
CASE(/*0216 0x8e*/ 0b10001110, if (GetCond(m, 0xe)) OpJmp(m));
|
|
CASE(/*0217 0x8f*/ 0b10001111, if (GetCond(m, 0xf)) OpJmp(m));
|
|
CASE(/*0220 0x90*/ 0b10010000, OpEbSetCc(m, GetCond(m, 0x0)));
|
|
CASE(/*0221 0x91*/ 0b10010001, OpEbSetCc(m, GetCond(m, 0x1)));
|
|
CASE(/*0222 0x92*/ 0b10010010, OpEbSetCc(m, GetCond(m, 0x2)));
|
|
CASE(/*0223 0x93*/ 0b10010011, OpEbSetCc(m, GetCond(m, 0x3)));
|
|
CASE(/*0224 0x94*/ 0b10010100, OpEbSetCc(m, GetCond(m, 0x4)));
|
|
CASE(/*0225 0x95*/ 0b10010101, OpEbSetCc(m, GetCond(m, 0x5)));
|
|
CASE(/*0226 0x96*/ 0b10010110, OpEbSetCc(m, GetCond(m, 0x6)));
|
|
CASE(/*0227 0x97*/ 0b10010111, OpEbSetCc(m, GetCond(m, 0x7)));
|
|
CASE(/*0230 0x98*/ 0b10011000, OpEbSetCc(m, GetCond(m, 0x8)));
|
|
CASE(/*0231 0x99*/ 0b10011001, OpEbSetCc(m, GetCond(m, 0x9)));
|
|
CASE(/*0232 0x9A*/ 0b10011010, OpEbSetCc(m, GetCond(m, 0xa)));
|
|
CASE(/*0233 0x9B*/ 0b10011011, OpEbSetCc(m, GetCond(m, 0xb)));
|
|
CASE(/*0234 0x9C*/ 0b10011100, OpEbSetCc(m, GetCond(m, 0xc)));
|
|
CASE(/*0235 0x9D*/ 0b10011101, OpEbSetCc(m, GetCond(m, 0xd)));
|
|
CASE(/*0236 0x9E*/ 0b10011110, OpEbSetCc(m, GetCond(m, 0xe)));
|
|
CASE(/*0237 0x9F*/ 0b10011111, OpEbSetCc(m, GetCond(m, 0xf)));
|
|
CASE(/*0240 0xA0*/ 0b10100000, OpPushFs(m));
|
|
CASE(/*0241 0xA1*/ 0b10100001, OpPopFs(m));
|
|
CASE(/*0242 0xA2*/ 0b10100010, OpCpuid(m));
|
|
CASE(/*0243 0xA3*/ 0b10100011, OpBit(m));
|
|
CASE(/*0250 0xA8*/ 0b10101000, OpPushGs(m));
|
|
CASE(/*0251 0xA9*/ 0b10101001, OpPopGs(m));
|
|
CASE(/*0253 0xAB*/ 0b10101011, OpBit(m));
|
|
CASE(/*0257 0xAF*/ 0b10101111, OpImulGvqpEvqp(m));
|
|
CASE(/*0260 0xB0*/ 0b10110000, OpCmpxchgEbAlGb(m));
|
|
CASE(/*0261 0xB1*/ 0b10110001, OpCmpxchgEvqpRaxGvqp(m));
|
|
CASE(/*0263 0xB3*/ 0b10110011, OpBit(m));
|
|
CASE(/*0266 0xB6*/ 0b10110110, OpMovzbGvqpEb(m));
|
|
CASE(/*0267 0xB7*/ 0b10110111, OpMovzwGvqpEw(m));
|
|
CASE(/*0272 0xBA*/ 0b10111010, OpBit(m));
|
|
CASE(/*0273 0xBB*/ 0b10111011, OpBit(m));
|
|
CASE(/*0274 0xBC*/ 0b10111100, OpGvqpEvqp(m, AluBsf, MUTATING));
|
|
CASE(/*0275 0xBD*/ 0b10111101, OpGvqpEvqp(m, AluBsr, MUTATING));
|
|
CASE(/*0276 0xBE*/ 0b10111110, OpMovsbGvqpEb(m));
|
|
CASE(/*0277 0xBF*/ 0b10111111, OpMovswGvqpEw(m));
|
|
CASE(/*0300 0xC0*/ 0b11000000, OpAlub(m, Alu, ALU_XCHG | ALU_ADD));
|
|
CASE(/*0301 0xC1*/ 0b11000001, OpAluw(m, Alu, ALU_XCHG | ALU_ADD));
|
|
CASE(/*0302 0xC2*/ 0b11000010, OpCmppsd(m));
|
|
CASE(/*0303 0xC3*/ 0b11000011, OpMovntiMdqpGdqp(m));
|
|
CASE(/*0304 0xC4*/ 0b11000100, OpPinsrwVdqEwIb(m));
|
|
CASE(/*0305 0xC5*/ 0b11000101, OpPextrwGdqpUdqIb(m));
|
|
CASE(/*0306 0xC6*/ 0b11000110, OpShufpsd(m));
|
|
CASE(/*0307 0xC7*/ 0b11000111, OpCmpxchgDxAx(m));
|
|
CASE(/*0310 0xC8*/ 0b11001000 ... 0b11001111, OpBswapZvqp(m));
|
|
CASE(/*0320 0xD0*/ 0b11010000, OpAddsubpsd(m));
|
|
CASE(/*0321 0xD1*/ 0b11010001, OpSse(m, kOpSsePsrlwv));
|
|
CASE(/*0322 0xD2*/ 0b11010010, OpSse(m, kOpSsePsrldv));
|
|
CASE(/*0323 0xD3*/ 0b11010011, OpSse(m, kOpSsePsrlqv));
|
|
CASE(/*0324 0xD4*/ 0b11010100, OpSse(m, kOpSsePaddq));
|
|
CASE(/*0325 0xD5*/ 0b11010101, OpSse(m, kOpSsePmullw));
|
|
CASE(/*0326 0xD6*/ 0b11010110, OpMov0fD6(m));
|
|
CASE(/*0327 0xD7*/ 0b11010111, OpPmovmskbGdqpNqUdq(m));
|
|
CASE(/*0330 0xD8*/ 0b11011000, OpSse(m, kOpSsePsubusb));
|
|
CASE(/*0331 0xD9*/ 0b11011001, OpSse(m, kOpSsePsubusw));
|
|
CASE(/*0332 0xDA*/ 0b11011010, OpSse(m, kOpSsePminub));
|
|
CASE(/*0333 0xDB*/ 0b11011011, OpSse(m, kOpSsePand));
|
|
CASE(/*0334 0xDC*/ 0b11011100, OpSse(m, kOpSsePaddusb));
|
|
CASE(/*0335 0xDD*/ 0b11011101, OpSse(m, kOpSsePaddusw));
|
|
CASE(/*0336 0xDE*/ 0b11011110, OpSse(m, kOpSsePmaxub));
|
|
CASE(/*0337 0xDF*/ 0b11011111, OpSse(m, kOpSsePandn));
|
|
CASE(/*0340 0xE0*/ 0b11100000, OpSse(m, kOpSsePavgb));
|
|
CASE(/*0341 0xE1*/ 0b11100001, OpSse(m, kOpSsePsrawv));
|
|
CASE(/*0342 0xE2*/ 0b11100010, OpSse(m, kOpSsePsradv));
|
|
CASE(/*0343 0xE3*/ 0b11100011, OpSse(m, kOpSsePavgw));
|
|
CASE(/*0344 0xE4*/ 0b11100100, OpSse(m, kOpSsePmulhuw));
|
|
CASE(/*0345 0xE5*/ 0b11100101, OpSse(m, kOpSsePmulhw));
|
|
CASE(/*0346 0xE6*/ 0b11100110, OpCvt(m, kOpCvt0fE6));
|
|
CASE(/*0347 0xE7*/ 0b11100111, OpMov0fE7(m));
|
|
CASE(/*0350 0xE8*/ 0b11101000, OpSse(m, kOpSsePsubsb));
|
|
CASE(/*0351 0xE9*/ 0b11101001, OpSse(m, kOpSsePsubsw));
|
|
CASE(/*0352 0xEA*/ 0b11101010, OpSse(m, kOpSsePminsw));
|
|
CASE(/*0353 0xEB*/ 0b11101011, OpSse(m, kOpSsePor));
|
|
CASE(/*0354 0xEC*/ 0b11101100, OpSse(m, kOpSsePaddsb));
|
|
CASE(/*0355 0xED*/ 0b11101101, OpSse(m, kOpSsePaddsw));
|
|
CASE(/*0356 0xEE*/ 0b11101110, OpSse(m, kOpSsePmaxsw));
|
|
CASE(/*0357 0xEF*/ 0b11101111, OpSse(m, kOpSsePxor));
|
|
CASE(/*0360 0xF0*/ 0b11110000, OpLddquVdqMdq(m));
|
|
CASE(/*0361 0xF1*/ 0b11110001, OpSse(m, kOpSsePsllwv));
|
|
CASE(/*0362 0xF2*/ 0b11110010, OpSse(m, kOpSsePslldv));
|
|
CASE(/*0363 0xF3*/ 0b11110011, OpSse(m, kOpSsePsllqv));
|
|
CASE(/*0364 0xF4*/ 0b11110100, OpSse(m, kOpSsePmuludq));
|
|
CASE(/*0365 0xF5*/ 0b11110101, OpSse(m, kOpSsePmaddwd));
|
|
CASE(/*0366 0xF6*/ 0b11110110, OpSse(m, kOpSsePsadbw));
|
|
CASE(/*0367 0xF7*/ 0b11110111, OpMaskMovDiXmmRegXmmRm(m));
|
|
CASE(/*0370 0xF8*/ 0b11111000, OpSse(m, kOpSsePsubb));
|
|
CASE(/*0371 0xF9*/ 0b11111001, OpSse(m, kOpSsePsubw));
|
|
CASE(/*0372 0xFA*/ 0b11111010, OpSse(m, kOpSsePsubd));
|
|
CASE(/*0373 0xFB*/ 0b11111011, OpSse(m, kOpSsePsubq));
|
|
CASE(/*0374 0xFC*/ 0b11111100, OpSse(m, kOpSsePaddb));
|
|
CASE(/*0375 0xFD*/ 0b11111101, OpSse(m, kOpSsePaddw));
|
|
CASE(/*0376 0xFE*/ 0b11111110, OpSse(m, kOpSsePaddd));
|
|
case /*0013 0x0B*/ 0b00001011:
|
|
case /*0271 0xB9*/ 0b10111001:
|
|
case /*0377 0xFF*/ 0b11111111:
|
|
OpUd(m);
|
|
break;
|
|
case /*0015 0x0D*/ 0b00001101:
|
|
case /*0030 0x18*/ 0b00011000:
|
|
case /*0031 0x19*/ 0b00011001:
|
|
case /*0032 0x1A*/ 0b00011010:
|
|
case /*0033 0x1B*/ 0b00011011:
|
|
case /*0034 0x1C*/ 0b00011100:
|
|
case /*0035 0x1D*/ 0b00011101:
|
|
OpWutNopEv(m);
|
|
break;
|
|
case /*0037 0x1F*/ 0b00011111:
|
|
OpNopEv(m);
|
|
break;
|
|
case /*0161 0x71*/ 0b01110001:
|
|
switch (ModrmReg(m->xedd)) {
|
|
CASE(2, OpSseUdqIb(m, kOpSseUdqIbPsrlw));
|
|
CASE(4, OpSseUdqIb(m, kOpSseUdqIbPsraw));
|
|
CASE(6, OpSseUdqIb(m, kOpSseUdqIbPsllw));
|
|
default:
|
|
OpUd(m);
|
|
}
|
|
break;
|
|
case /*0162 0x72*/ 0b01110010:
|
|
switch (ModrmReg(m->xedd)) {
|
|
CASE(2, OpSseUdqIb(m, kOpSseUdqIbPsrld));
|
|
CASE(4, OpSseUdqIb(m, kOpSseUdqIbPsrad));
|
|
CASE(6, OpSseUdqIb(m, kOpSseUdqIbPslld));
|
|
default:
|
|
OpUd(m);
|
|
}
|
|
break;
|
|
case /*0163 0x73*/ 0b01110011:
|
|
switch (ModrmReg(m->xedd)) {
|
|
CASE(2, OpSseUdqIb(m, kOpSseUdqIbPsrlq));
|
|
CASE(3, OpSseUdqIb(m, kOpSseUdqIbPsrldq));
|
|
CASE(6, OpSseUdqIb(m, kOpSseUdqIbPsllq));
|
|
CASE(7, OpSseUdqIb(m, kOpSseUdqIbPslldq));
|
|
default:
|
|
OpUd(m);
|
|
}
|
|
break;
|
|
case /*0244 0xA4*/ 0b10100100:
|
|
case /*0245 0xA5*/ 0b10100101:
|
|
case /*0254 0xAC*/ 0b10101100:
|
|
case /*0255 0xAD*/ 0b10101101:
|
|
OpEvqpGvqp(m, OpDoubleShift, MUTATING);
|
|
break;
|
|
case /*0256 0xAE*/ 0b10101110:
|
|
switch (ModrmReg(m->xedd)) {
|
|
CASE(5, OpLfence(m));
|
|
CASE(6, OpMfence(m));
|
|
case 7:
|
|
if (0xf8 <= m->xedd->op.modrm && m->xedd->op.modrm <= 0xff) {
|
|
OpSfence(m);
|
|
} else {
|
|
OpClflush(m);
|
|
}
|
|
break;
|
|
default:
|
|
OpUd(m);
|
|
}
|
|
break;
|
|
case 0xB8:
|
|
if (m->xedd->op.ild_f3) {
|
|
OpGvqpEvqp(m, AluPopcnt, MUTATING);
|
|
} else {
|
|
OpUd(m);
|
|
}
|
|
break;
|
|
default:
|
|
OpUd(m);
|
|
}
|
|
}
|
|
|
|
static void ExecuteInstructionMap2(struct Machine *m) {
|
|
switch (m->xedd->op.opcode) {
|
|
CASE(0x00, OpSse(m, kOpSsePshufb));
|
|
CASE(0x01, OpSse(m, kOpSsePhaddw));
|
|
CASE(0x02, OpSse(m, kOpSsePhaddd));
|
|
CASE(0x03, OpSse(m, kOpSsePhaddsw));
|
|
CASE(0x04, OpSse(m, kOpSsePmaddubsw));
|
|
CASE(0x05, OpSse(m, kOpSsePhsubw));
|
|
CASE(0x06, OpSse(m, kOpSsePhsubd));
|
|
CASE(0x07, OpSse(m, kOpSsePhsubsw));
|
|
CASE(0x08, OpSse(m, kOpSsePsignb));
|
|
CASE(0x09, OpSse(m, kOpSsePsignw));
|
|
CASE(0x0A, OpSse(m, kOpSsePsignd));
|
|
CASE(0x0B, OpSse(m, kOpSsePmulhrsw));
|
|
CASE(0x1C, OpSse(m, kOpSsePabsb));
|
|
CASE(0x1D, OpSse(m, kOpSsePabsw));
|
|
CASE(0x1E, OpSse(m, kOpSsePabsd));
|
|
CASE(0x2A, OpMovntdqaVdqMdq(m));
|
|
CASE(0x40, OpSse(m, kOpSsePmulld));
|
|
default:
|
|
OpUd(m);
|
|
}
|
|
}
|
|
|
|
static void ExecuteInstructionMap3(struct Machine *m) {
|
|
switch (m->xedd->op.opcode) {
|
|
CASE(0x0F, OpSsePalignr(m));
|
|
default:
|
|
OpUd(m);
|
|
}
|
|
}
|
|
|
|
static void SaveStash(struct Machine *m) {
|
|
VirtualRecv(m, m->stashaddr, m->stash, m->stashsize);
|
|
m->stashaddr = 0;
|
|
}
|
|
|
|
void ExecuteInstruction(struct Machine *m) {
|
|
m->ip += m->xedd->length;
|
|
switch (m->xedd->op.map) {
|
|
CASE(XED_ILD_MAP0, ExecuteInstructionMap0(m));
|
|
CASE(XED_ILD_MAP1, ExecuteInstructionMap1(m));
|
|
CASE(XED_ILD_MAP2, ExecuteInstructionMap2(m));
|
|
CASE(XED_ILD_MAP3, ExecuteInstructionMap3(m));
|
|
default:
|
|
OpUd(m);
|
|
}
|
|
if (m->stashaddr) {
|
|
SaveStash(m);
|
|
}
|
|
}
|