cosmopolitan/tool/build/lib/machine.c

2246 lines
56 KiB
C
Raw Normal View History

/*-*- 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
2020-12-28 01:18:44 +00:00
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
2020-12-28 01:18:44 +00:00
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/log/check.h"
#include "libc/macros.internal.h"
#include "libc/rand/rand.h"
#include "libc/runtime/runtime.h"
Make major improvements to redbean and libraries The most exciting improvement is dynamic pages will soon be able to use the executable itself as an object store. it required a heroic technique for overcoming ETXTBSY restrictions which lets us open the executable in read/write mode, which means (1) wa can restore the APE header, and (2) we can potentially containerize redbean extension code so that modules you download for your redbean online will only impact your redbean. Here's a list of breaking changes to redbean: - Remove /tool/net/ prefix from magic ZIP paths - GetHeader() now returns NIL if header is absent Here's a list of fixes and enhancements to redbean: - Support 64-bit ZIP archives - Record User-Agent header in logs - Add twelve error handlers to accept() - Display octal st_mode on listing page - Show ZIP file comments on listing page - Restore APE MZ header on redbean startup - Track request count on redbean index page - Report server uptime on redbean index page - Don't bind server socket using SO_REUSEPORT - Fix #151 where Lua LoadAsset() could free twice - Report rusage accounting when workers exit w/ -vv - Use ZIP iattr field as text/plain vs. binary hint - Add ParseUrl() API for parsing things like a.href - Add ParseParams() API for parsing HTTP POST bodies - Add IsAcceptablePath() API for checking dots, etc. - Add IsValidHttpToken() API for validating sane ASCII - Add IsAcceptableHostPort() for validating HOST[:PORT] - Send 400 response to HTTP/1.1 requests without a Host - Send 403 response if ZIP or file isn't other readable - Add virtual hosting that tries prepending Host to path - Route requests based on Host in Request-URI if present - Host routing will attempt to remove or add the www. prefix - Sign-extend UNIX timestamps and don't adjust FileTime zone Here's some of the improvements made to Cosmopolitan Libc: - Fix ape.S indentation - Improve consts.sh magnums - Write pretty good URL parser - Improve rusage accounting apis - Bring mremap() closer to working - Added ZIP APIs which will change - Check for overflow in reallocarray() - Remove overly fancy linkage in strerror() - Fix GDB attach on crash w/ OpenBSD msyscall() - Make sigqueue() portable to most UNIX distros - Make integer serialization macros more elegant - Bring back 34x tprecode8to16() performance boost - Make malloc() more resilient to absurdly large sizes
2021-04-18 18:34:59 +00:00
#include "libc/str/str.h"
#include "tool/build/lib/abp.h"
#include "tool/build/lib/address.h"
#include "tool/build/lib/alu.h"
#include "tool/build/lib/bcd.h"
#include "tool/build/lib/bitscan.h"
#include "tool/build/lib/case.h"
Productionize new APE loader and more The APE_NO_MODIFY_SELF loader payload has been moved out of the examples folder and improved so that it works on BSD systems, and permits general elf program headers. This brings its quality up enough that it should be acceptable to use by default for many programs, e.g. Python, Lua, SQLite and Python. It's the responsibility of the user to define an appropriate TMPDIR if /tmp is considered an adversarial environment. Mac OS shall be supported by APE_NO_MODIFY_SELF soon. Fixes and improvements have been made to program_executable_name as it's now the one true way to get the absolute path of the executing image. This change fixes a memory leak in linenoise history loading, introduced by performance optimizations in 51904e2687c04d7ae20410cd94c2148972d6bae6 This change fixes a longstanding regression with Mach system calls, that 23ae9dfceb6f657862f00e674a8e4dc357a9d24d back in February which impacted our sched_yield() implementation, which is why no one noticed until now. The Blinkenlights PC emulator has been improved. We now fix rendering on XNU and BSD by not making the assumption that the kernel terminal driver understands UTF8 since that seems to break its internal modeling of \r\n which is now being addressed by using \e[𝑦H instead. The paneling is now more compact in real mode so you won't need to make your font as tiny if you're only emulating an 8086 program. The CLMUL ISA is now emulated too This change also makes improvement to time. CLOCK_MONOTONIC now does the right thing on Windows NT. The nanosecond time module functions added in Python 3.7 have been backported. This change doubles the performance of Argon2 password stretching simply by not using its copy_block and xor_block helper functions, as they were trivial to inline thus resulting in us needing to iterate over each 1024 byte block four fewer times. This change makes code size improvements. _PyUnicode_ToNumeric() was 64k in size and now it's 10k. The CJK codec lookup tables now use lazy delta zigzag deflate (δzd) encoding which reduces their size from 600k to 200k plus the code bloat caused by macro abuse in _decimal.c is now addressed so our fully-loaded statically-linked hermetically-sealed Python virtual interpreter container is now 9.4 megs in the default build mode and 5.5m in MODE=tiny which leaves plenty of room for chibicc. The pydoc web server now accommodates the use case of people who work by SSH'ing into a different machine w/ python.com -m pydoc -p8080 -h0.0.0.0 Finally Python Capsulae delenda est and won't be supported in the future
2021-10-02 15:17:04 +00:00
#include "tool/build/lib/clmul.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"
2020-10-27 10:39:46 +00:00
#include "tool/build/lib/op101.h"
#include "tool/build/lib/sse.h"
#include "tool/build/lib/ssefloat.h"
#include "tool/build/lib/ssemov.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"
#include "tool/build/lib/time.h"
#define OpLfence OpNoop
#define OpMfence OpNoop
#define OpSfence OpNoop
#define OpClflush OpNoop
#define OpHintNopEv OpNoop
typedef void (*nexgen32e_f)(struct Machine *, uint32_t);
static uint64_t ReadMemory(uint32_t rde, uint8_t p[8]) {
if (Rexw(rde)) {
return Read64(p);
} else if (!Osz(rde)) {
return Read32(p);
} else {
return Read16(p);
}
}
static int64_t ReadMemorySigned(uint32_t rde, uint8_t p[8]) {
if (Rexw(rde)) {
return (int64_t)Read64(p);
} else if (!Osz(rde)) {
return (int32_t)Read32(p);
} else {
return (int16_t)Read16(p);
}
}
static void WriteRegister(uint32_t rde, uint8_t p[8], uint64_t x) {
if (Rexw(rde)) {
Write64(p, x);
} else if (!Osz(rde)) {
Write64(p, x & 0xffffffff);
} else {
Write16(p, x);
}
}
static void WriteMemory(uint32_t rde, uint8_t p[8], uint64_t x) {
if (Rexw(rde)) {
Write64(p, x);
} else if (!Osz(rde)) {
Write32(p, x);
} else {
Write16(p, x);
}
}
static void WriteRegisterOrMemory(uint32_t rde, uint8_t p[8], uint64_t x) {
if (IsModrmRegister(rde)) {
WriteRegister(rde, p, x);
} else {
WriteMemory(rde, p, x);
}
}
static bool IsParity(struct Machine *m) {
return GetFlag(m->flags, FLAGS_PF);
}
static bool IsBelowOrEqual(struct Machine *m) {
return GetFlag(m->flags, FLAGS_CF) | GetFlag(m->flags, FLAGS_ZF);
}
static bool IsAbove(struct Machine *m) {
return !GetFlag(m->flags, FLAGS_CF) && !GetFlag(m->flags, FLAGS_ZF);
}
static bool IsLess(struct Machine *m) {
return GetFlag(m->flags, FLAGS_SF) != GetFlag(m->flags, FLAGS_OF);
}
static bool IsGreaterOrEqual(struct Machine *m) {
return GetFlag(m->flags, FLAGS_SF) == GetFlag(m->flags, FLAGS_OF);
}
static bool IsLessOrEqual(struct Machine *m) {
return GetFlag(m->flags, FLAGS_ZF) |
(GetFlag(m->flags, FLAGS_SF) != GetFlag(m->flags, FLAGS_OF));
}
static bool IsGreater(struct Machine *m) {
return !GetFlag(m->flags, FLAGS_ZF) &
(GetFlag(m->flags, FLAGS_SF) == GetFlag(m->flags, FLAGS_OF));
}
static void OpNoop(struct Machine *m, uint32_t rde) {
}
static void OpCmc(struct Machine *m, uint32_t rde) {
m->flags = SetFlag(m->flags, FLAGS_CF, !GetFlag(m->flags, FLAGS_CF));
}
static void OpClc(struct Machine *m, uint32_t rde) {
m->flags = SetFlag(m->flags, FLAGS_CF, false);
}
static void OpStc(struct Machine *m, uint32_t rde) {
m->flags = SetFlag(m->flags, FLAGS_CF, true);
}
static void OpCli(struct Machine *m, uint32_t rde) {
m->flags = SetFlag(m->flags, FLAGS_IF, false);
}
static void OpSti(struct Machine *m, uint32_t rde) {
m->flags = SetFlag(m->flags, FLAGS_IF, true);
}
static void OpCld(struct Machine *m, uint32_t rde) {
m->flags = SetFlag(m->flags, FLAGS_DF, false);
}
static void OpStd(struct Machine *m, uint32_t rde) {
m->flags = SetFlag(m->flags, FLAGS_DF, true);
}
static void OpPushf(struct Machine *m, uint32_t rde) {
Push(m, rde, ExportFlags(m->flags) & 0xFCFFFF);
}
static void OpPopf(struct Machine *m, uint32_t rde) {
if (!Osz(rde)) {
ImportFlags(m, Pop(m, rde, 0));
} else {
ImportFlags(m, (m->flags & ~0xffff) | Pop(m, rde, 0));
}
}
static void OpLahf(struct Machine *m, uint32_t rde) {
Write8(m->ax + 1, ExportFlags(m->flags));
}
static void OpSahf(struct Machine *m, uint32_t rde) {
ImportFlags(m, (m->flags & ~0xff) | m->ax[1]);
}
static void OpLeaGvqpM(struct Machine *m, uint32_t rde) {
WriteRegister(rde, RegRexrReg(m, rde), LoadEffectiveAddress(m, rde).addr);
}
static relegated void OpPushSeg(struct Machine *m, uint32_t rde) {
uint8_t seg = (m->xedd->op.opcode & 070) >> 3;
Push(m, rde, Read64(GetSegment(m, rde, seg)) >> 4);
}
static relegated void OpPopSeg(struct Machine *m, uint32_t rde) {
uint8_t seg = (m->xedd->op.opcode & 070) >> 3;
Write64(GetSegment(m, rde, seg), Pop(m, rde, 0) << 4);
}
static relegated void OpMovEvqpSw(struct Machine *m, uint32_t rde) {
WriteRegisterOrMemory(rde, GetModrmRegisterWordPointerWriteOszRexw(m, rde),
Read64(GetSegment(m, rde, ModrmReg(rde))) >> 4);
}
static relegated int GetDescriptor(struct Machine *m, int selector,
uint64_t *out_descriptor) {
uint8_t buf[8];
DCHECK(m->gdt_base + m->gdt_limit <= m->real.n);
selector &= -8;
if (8 <= selector && selector + 8 <= m->gdt_limit) {
SetReadAddr(m, m->gdt_base + selector, 8);
*out_descriptor = Read64(m->real.p + m->gdt_base + selector);
return 0;
} else {
return -1;
}
}
static uint64_t GetDescriptorBase(uint64_t d) {
return (d & 0xff00000000000000) >> 32 | (d & 0x000000ffffff0000) >> 16;
}
static uint64_t GetDescriptorLimit(uint64_t d) {
return (d & 0x000f000000000000) >> 32 | d & 0xffff;
}
static int GetDescriptorMode(uint64_t d) {
uint8_t kMode[] = {
XED_MACHINE_MODE_REAL,
XED_MACHINE_MODE_LONG_64,
XED_MACHINE_MODE_LEGACY_32,
XED_MACHINE_MODE_LONG_64,
};
return kMode[(d & 0x0060000000000000) >> 53];
}
static bool IsProtectedMode(struct Machine *m) {
return m->cr0 & 1;
}
static relegated void OpMovSwEvqp(struct Machine *m, uint32_t rde) {
uint64_t x, d;
x = ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde));
if (!IsProtectedMode(m)) {
x <<= 4;
} else if (GetDescriptor(m, x, &d) != -1) {
x = GetDescriptorBase(d);
} else {
ThrowProtectionFault(m);
}
Write64(GetSegment(m, rde, ModrmReg(rde)), x);
}
static void OpLsl(struct Machine *m, uint32_t rde) {
uint64_t descriptor;
if (GetDescriptor(m, Read16(GetModrmRegisterWordPointerRead2(m, rde)),
&descriptor) != -1) {
WriteRegister(rde, RegRexrReg(m, rde), GetDescriptorLimit(descriptor));
SetFlag(m->flags, FLAGS_ZF, true);
} else {
SetFlag(m->flags, FLAGS_ZF, false);
}
}
static void ChangeMachineMode(struct Machine *m, int mode) {
if (mode == m->mode) return;
ResetInstructionCache(m);
m->mode = mode;
}
static void OpJmpf(struct Machine *m, uint32_t rde) {
uint64_t descriptor;
if (!IsProtectedMode(m)) {
Write64(m->cs, m->xedd->op.uimm0 << 4);
m->ip = m->xedd->op.disp;
} else if (GetDescriptor(m, m->xedd->op.uimm0, &descriptor) != -1) {
Write64(m->cs, GetDescriptorBase(descriptor));
m->ip = m->xedd->op.disp;
ChangeMachineMode(m, GetDescriptorMode(descriptor));
} else {
ThrowProtectionFault(m);
}
if (m->onlongbranch) {
m->onlongbranch(m);
}
}
static void OpInto(struct Machine *m, uint32_t rde) {
if (GetFlag(m->flags, FLAGS_OF)) {
HaltMachine(m, kMachineOverflow);
}
}
static relegated void OpXlatAlBbb(struct Machine *m, uint32_t rde) {
uint64_t v;
v = MaskAddress(Eamode(rde), Read64(m->bx) + Read8(m->ax));
v = DataSegment(m, rde, v);
SetReadAddr(m, v, 1);
Write8(m->ax, Read8(ResolveAddress(m, v)));
}
static void WriteEaxAx(struct Machine *m, uint32_t rde, uint32_t x) {
if (!Osz(rde)) {
Write64(m->ax, x);
} else {
Write16(m->ax, x);
}
}
static uint32_t ReadEaxAx(struct Machine *m, uint32_t rde) {
if (!Osz(rde)) {
return Read32(m->ax);
} else {
return Read16(m->ax);
}
}
static void OpInAlImm(struct Machine *m, uint32_t rde) {
Write8(m->ax, OpIn(m, m->xedd->op.uimm0));
}
static void OpInAxImm(struct Machine *m, uint32_t rde) {
WriteEaxAx(m, rde, OpIn(m, m->xedd->op.uimm0));
}
static void OpInAlDx(struct Machine *m, uint32_t rde) {
Write8(m->ax, OpIn(m, Read16(m->dx)));
}
static void OpInAxDx(struct Machine *m, uint32_t rde) {
WriteEaxAx(m, rde, OpIn(m, Read16(m->dx)));
}
static void OpOutImmAl(struct Machine *m, uint32_t rde) {
OpOut(m, m->xedd->op.uimm0, Read8(m->ax));
}
static void OpOutImmAx(struct Machine *m, uint32_t rde) {
OpOut(m, m->xedd->op.uimm0, ReadEaxAx(m, rde));
}
static void OpOutDxAl(struct Machine *m, uint32_t rde) {
OpOut(m, Read16(m->dx), Read8(m->ax));
}
static void OpOutDxAx(struct Machine *m, uint32_t rde) {
OpOut(m, Read16(m->dx), ReadEaxAx(m, rde));
}
static void AluEb(struct Machine *m, uint32_t rde, aluop_f op) {
uint8_t *p;
p = GetModrmRegisterBytePointerWrite(m, rde);
Write8(p, op(Read8(p), 0, &m->flags));
}
static void AluEvqp(struct Machine *m, uint32_t rde, aluop_f ops[4]) {
uint8_t *p;
p = GetModrmRegisterWordPointerWriteOszRexw(m, rde);
WriteRegisterOrMemory(rde, p,
ops[RegLog2(rde)](ReadMemory(rde, p), 0, &m->flags));
}
static void OpXchgZvqp(struct Machine *m, uint32_t rde) {
uint64_t x, y;
x = Read64(m->ax);
y = Read64(RegRexbSrm(m, rde));
WriteRegister(rde, m->ax, y);
WriteRegister(rde, RegRexbSrm(m, rde), x);
}
static void OpXchgGbEb(struct Machine *m, uint32_t rde) {
uint8_t *p;
uint8_t x, y;
p = GetModrmRegisterBytePointerWrite(m, rde);
x = Read8(ByteRexrReg(m, rde));
y = Read8(p);
Write8(ByteRexrReg(m, rde), y);
Write8(p, x);
}
static void OpXchgGvqpEvqp(struct Machine *m, uint32_t rde) {
uint8_t *p;
uint64_t x, y;
p = GetModrmRegisterWordPointerWriteOszRexw(m, rde);
x = ReadMemory(rde, RegRexrReg(m, rde));
y = ReadMemory(rde, p);
WriteRegister(rde, RegRexrReg(m, rde), y);
WriteRegisterOrMemory(rde, p, x);
}
static void OpCmpxchgEbAlGb(struct Machine *m, uint32_t rde) {
uint8_t *p;
uint8_t x, y, z;
p = GetModrmRegisterBytePointerWrite(m, rde);
x = Read8(m->ax);
y = Read8(p);
z = Read8(ByteRexrReg(m, rde));
Sub8(x, y, &m->flags);
if (GetFlag(m->flags, FLAGS_ZF)) {
Write8(p, z);
} else {
Write8(m->ax, y);
}
}
static void OpCmpxchgEvqpRaxGvqp(struct Machine *m, uint32_t rde) {
uint8_t *p;
uint64_t x, y, z;
p = GetModrmRegisterWordPointerWriteOszRexw(m, rde);
x = ReadMemory(rde, m->ax);
y = ReadMemory(rde, p);
z = ReadMemory(rde, RegRexrReg(m, rde));
kAlu[ALU_SUB][RegLog2(rde)](x, y, &m->flags);
if (GetFlag(m->flags, FLAGS_ZF)) {
WriteRegisterOrMemory(rde, p, z);
} else {
WriteRegister(rde, m->ax, y);
}
}
static void OpCmpxchg8b(struct Machine *m, uint32_t rde) {
uint8_t *p;
uint32_t d, a;
p = GetModrmRegisterXmmPointerRead8(m, rde);
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, uint32_t rde) {
uint8_t *p;
uint64_t d, a;
p = GetModrmRegisterXmmPointerRead16(m, rde);
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 OpRdrand(struct Machine *m, uint32_t rde) {
WriteRegister(rde, RegRexbRm(m, rde), rdrand());
m->flags = SetFlag(m->flags, FLAGS_CF, true);
}
static void OpRdseed(struct Machine *m, uint32_t rde) {
OpRdrand(m, rde);
}
static void Op1c7(struct Machine *m, uint32_t rde) {
bool ismem;
ismem = !IsModrmRegister(rde);
switch (ModrmReg(rde)) {
case 1:
if (ismem) {
if (Rexw(rde)) {
OpCmpxchg16b(m, rde);
} else {
OpCmpxchg8b(m, rde);
}
} else {
OpUd(m, rde);
}
break;
case 6:
if (!ismem) {
OpRdrand(m, rde);
} else {
OpUd(m, rde);
}
break;
case 7:
if (!ismem) {
if (Rep(rde) == 3) {
OpRdpid(m, rde);
} else {
OpRdseed(m, rde);
}
} else {
OpUd(m, rde);
}
break;
default:
OpUd(m, rde);
}
}
static void OpXaddEbGb(struct Machine *m, uint32_t rde) {
uint8_t *p;
uint8_t x, y, z;
p = GetModrmRegisterWordPointerWriteOszRexw(m, rde);
x = Read8(p);
y = Read8(RegRexrReg(m, rde));
z = Add8(x, y, &m->flags);
Write8(p, z);
Write8(RegRexrReg(m, rde), x);
}
static void OpXaddEvqpGvqp(struct Machine *m, uint32_t rde) {
uint8_t *p;
uint64_t x, y, z;
p = GetModrmRegisterWordPointerWriteOszRexw(m, rde);
x = ReadMemory(rde, p);
y = ReadMemory(rde, RegRexrReg(m, rde));
z = kAlu[ALU_ADD][RegLog2(rde)](x, y, &m->flags);
WriteRegisterOrMemory(rde, p, z);
WriteRegister(rde, RegRexrReg(m, rde), x);
}
static uint64_t Bts(uint64_t x, uint64_t y) {
return x | y;
}
static uint64_t Btr(uint64_t x, uint64_t y) {
return x & ~y;
}
static uint64_t Btc(uint64_t x, uint64_t y) {
return (x & ~y) | (~x & y);
}
static void OpBit(struct Machine *m, uint32_t rde) {
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(rde)][Rexw(rde)];
if (m->xedd->op.opcode == 0xBA) {
op = ModrmReg(rde);
bit = m->xedd->op.uimm0 & ((8 << w) - 1);
disp = 0;
} else {
op = (m->xedd->op.opcode & 070) >> 3;
disp = ReadMemorySigned(rde, RegRexrReg(m, rde));
bit = disp & ((8 << w) - 1);
disp &= -(8 << w);
disp >>= 3;
}
if (IsModrmRegister(rde)) {
p = RegRexbRm(m, rde);
} else {
v = MaskAddress(Eamode(rde), ComputeAddress(m, rde) + disp);
p = ReserveAddress(m, v, 1 << w);
if (op == 4) {
SetReadAddr(m, v, 1 << w);
} else {
SetWriteAddr(m, v, 1 << w);
}
}
y = 1;
y <<= bit;
x = ReadMemory(rde, p);
m->flags = SetFlag(m->flags, FLAGS_CF, !!(y & x));
switch (op) {
case 4:
return;
case 5:
z = Bts(x, y);
break;
case 6:
z = Btr(x, y);
break;
case 7:
z = Btc(x, y);
break;
default:
OpUd(m, rde);
}
WriteRegisterOrMemory(rde, p, z);
}
static void OpSax(struct Machine *m, uint32_t rde) {
if (Rexw(rde)) {
Write64(m->ax, (int32_t)Read32(m->ax));
} else if (!Osz(rde)) {
Write64(m->ax, (uint32_t)(int16_t)Read16(m->ax));
} else {
Write16(m->ax, (int8_t)Read8(m->ax));
}
}
static void OpConvert(struct Machine *m, uint32_t rde) {
if (Rexw(rde)) {
Write64(m->dx, Read64(m->ax) & 0x8000000000000000 ? 0xffffffffffffffff : 0);
} else if (!Osz(rde)) {
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, uint32_t rde) {
uint64_t x;
x = Read64(RegRexbSrm(m, rde));
if (Rexw(rde)) {
Write64(
RegRexbSrm(m, rde),
((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(rde)) {
Write64(RegRexbSrm(m, rde),
((x & 0xff000000) >> 030 | (x & 0x000000ff) << 030 |
(x & 0x00ff0000) >> 010 | (x & 0x0000ff00) << 010));
} else {
Write16(RegRexbSrm(m, rde), (x & 0x00ff) << 010 | (x & 0xff00) << 010);
}
}
static void OpMovEbIb(struct Machine *m, uint32_t rde) {
Write8(GetModrmRegisterBytePointerWrite(m, rde), m->xedd->op.uimm0);
}
static void OpMovAlOb(struct Machine *m, uint32_t rde) {
int64_t addr;
addr = AddressOb(m, rde);
SetWriteAddr(m, addr, 1);
Write8(m->ax, Read8(ResolveAddress(m, addr)));
}
static void OpMovObAl(struct Machine *m, uint32_t rde) {
int64_t addr;
addr = AddressOb(m, rde);
SetReadAddr(m, addr, 1);
Write8(ResolveAddress(m, addr), Read8(m->ax));
}
static void OpMovRaxOvqp(struct Machine *m, uint32_t rde) {
uint64_t v;
v = DataSegment(m, rde, m->xedd->op.disp);
SetReadAddr(m, v, 1 << RegLog2(rde));
WriteRegister(rde, m->ax, ReadMemory(rde, ResolveAddress(m, v)));
}
static void OpMovOvqpRax(struct Machine *m, uint32_t rde) {
uint64_t v;
v = DataSegment(m, rde, m->xedd->op.disp);
SetWriteAddr(m, v, 1 << RegLog2(rde));
WriteMemory(rde, ResolveAddress(m, v), Read64(m->ax));
}
static void OpMovEbGb(struct Machine *m, uint32_t rde) {
memcpy(GetModrmRegisterBytePointerWrite(m, rde), ByteRexrReg(m, rde), 1);
}
static void OpMovGbEb(struct Machine *m, uint32_t rde) {
memcpy(ByteRexrReg(m, rde), GetModrmRegisterBytePointerRead(m, rde), 1);
}
static void OpMovZbIb(struct Machine *m, uint32_t rde) {
Write8(ByteRexbSrm(m, rde), m->xedd->op.uimm0);
}
static void OpMovZvqpIvqp(struct Machine *m, uint32_t rde) {
WriteRegister(rde, RegRexbSrm(m, rde), m->xedd->op.uimm0);
}
static relegated void OpIncZv(struct Machine *m, uint32_t rde) {
if (!Osz(rde)) {
Write32(RegSrm(m, rde), Inc32(Read32(RegSrm(m, rde)), 0, &m->flags));
} else {
Write16(RegSrm(m, rde), Inc16(Read16(RegSrm(m, rde)), 0, &m->flags));
}
}
static relegated void OpDecZv(struct Machine *m, uint32_t rde) {
if (!Osz(rde)) {
Write32(RegSrm(m, rde), Dec32(Read32(RegSrm(m, rde)), 0, &m->flags));
} else {
Write16(RegSrm(m, rde), Dec16(Read16(RegSrm(m, rde)), 0, &m->flags));
}
}
static void OpMovEvqpIvds(struct Machine *m, uint32_t rde) {
WriteRegisterOrMemory(rde, GetModrmRegisterWordPointerWriteOszRexw(m, rde),
m->xedd->op.uimm0);
}
static void OpMovEvqpGvqp(struct Machine *m, uint32_t rde) {
WriteRegisterOrMemory(rde, GetModrmRegisterWordPointerWriteOszRexw(m, rde),
ReadMemory(rde, RegRexrReg(m, rde)));
}
static void OpMovzbGvqpEb(struct Machine *m, uint32_t rde) {
WriteRegister(rde, RegRexrReg(m, rde),
Read8(GetModrmRegisterBytePointerRead(m, rde)));
}
static void OpMovzwGvqpEw(struct Machine *m, uint32_t rde) {
WriteRegister(rde, RegRexrReg(m, rde),
Read16(GetModrmRegisterWordPointerRead2(m, rde)));
}
static void OpMovsbGvqpEb(struct Machine *m, uint32_t rde) {
WriteRegister(rde, RegRexrReg(m, rde),
(int8_t)Read8(GetModrmRegisterBytePointerRead(m, rde)));
}
static void OpMovswGvqpEw(struct Machine *m, uint32_t rde) {
WriteRegister(rde, RegRexrReg(m, rde),
(int16_t)Read16(GetModrmRegisterWordPointerRead2(m, rde)));
}
static void OpMovsxdGdqpEd(struct Machine *m, uint32_t rde) {
Write64(RegRexrReg(m, rde),
(int32_t)Read32(GetModrmRegisterWordPointerRead4(m, rde)));
}
static void Alub(struct Machine *m, uint32_t rde, aluop_f op) {
uint8_t *a = GetModrmRegisterBytePointerWrite(m, rde);
Write8(a, op(Read8(a), Read8(ByteRexrReg(m, rde)), &m->flags));
}
static void OpAlubAdd(struct Machine *m, uint32_t rde) {
Alub(m, rde, Add8);
}
static void OpAlubOr(struct Machine *m, uint32_t rde) {
Alub(m, rde, Or8);
}
static void OpAlubAdc(struct Machine *m, uint32_t rde) {
Alub(m, rde, Adc8);
}
static void OpAlubSbb(struct Machine *m, uint32_t rde) {
Alub(m, rde, Sbb8);
}
static void OpAlubAnd(struct Machine *m, uint32_t rde) {
Alub(m, rde, And8);
}
static void OpAlubSub(struct Machine *m, uint32_t rde) {
Alub(m, rde, Sub8);
}
static void OpAlubXor(struct Machine *m, uint32_t rde) {
Alub(m, rde, Xor8);
}
static void AlubRo(struct Machine *m, uint32_t rde, aluop_f op) {
op(Read8(GetModrmRegisterBytePointerRead(m, rde)), Read8(ByteRexrReg(m, rde)),
&m->flags);
}
static void OpAlubCmp(struct Machine *m, uint32_t rde) {
AlubRo(m, rde, Sub8);
}
static void OpAlubTest(struct Machine *m, uint32_t rde) {
AlubRo(m, rde, And8);
}
static void AlubFlip(struct Machine *m, uint32_t rde, aluop_f op) {
Write8(ByteRexrReg(m, rde),
op(Read8(ByteRexrReg(m, rde)),
Read8(GetModrmRegisterBytePointerRead(m, rde)), &m->flags));
}
static void OpAlubFlipAdd(struct Machine *m, uint32_t rde) {
AlubFlip(m, rde, Add8);
}
static void OpAlubFlipOr(struct Machine *m, uint32_t rde) {
AlubFlip(m, rde, Or8);
}
static void OpAlubFlipAdc(struct Machine *m, uint32_t rde) {
AlubFlip(m, rde, Adc8);
}
static void OpAlubFlipSbb(struct Machine *m, uint32_t rde) {
AlubFlip(m, rde, Sbb8);
}
static void OpAlubFlipAnd(struct Machine *m, uint32_t rde) {
AlubFlip(m, rde, And8);
}
static void OpAlubFlipSub(struct Machine *m, uint32_t rde) {
AlubFlip(m, rde, Sub8);
}
static void OpAlubFlipXor(struct Machine *m, uint32_t rde) {
AlubFlip(m, rde, Xor8);
}
static void AlubFlipRo(struct Machine *m, uint32_t rde, aluop_f op) {
op(Read8(ByteRexrReg(m, rde)), Read8(GetModrmRegisterBytePointerRead(m, rde)),
&m->flags);
}
static void OpAlubFlipCmp(struct Machine *m, uint32_t rde) {
AlubFlipRo(m, rde, Sub8);
}
static void OpAlubFlipTest(struct Machine *m, uint32_t rde) {
AlubFlipRo(m, rde, And8);
}
static void Alubi(struct Machine *m, uint32_t rde, aluop_f op) {
uint8_t *a = GetModrmRegisterBytePointerWrite(m, rde);
Write8(a, op(Read8(a), m->xedd->op.uimm0, &m->flags));
}
static void AlubiRo(struct Machine *m, uint32_t rde, aluop_f op) {
op(Read8(GetModrmRegisterBytePointerRead(m, rde)), m->xedd->op.uimm0,
&m->flags);
}
static void OpAlubiTest(struct Machine *m, uint32_t rde) {
AlubiRo(m, rde, And8);
}
static void OpAlubiReg(struct Machine *m, uint32_t rde) {
if (ModrmReg(rde) == ALU_CMP) {
AlubiRo(m, rde, kAlu[ModrmReg(rde)][0]);
} else {
Alubi(m, rde, kAlu[ModrmReg(rde)][0]);
}
}
static void OpAluw(struct Machine *m, uint32_t rde) {
uint8_t *a;
a = GetModrmRegisterWordPointerWriteOszRexw(m, rde);
WriteRegisterOrMemory(
rde, a,
kAlu[(m->xedd->op.opcode & 070) >> 3][RegLog2(rde)](
ReadMemory(rde, a), Read64(RegRexrReg(m, rde)), &m->flags));
}
static void AluwRo(struct Machine *m, uint32_t rde, aluop_f ops[4]) {
ops[RegLog2(rde)](
ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde)),
Read64(RegRexrReg(m, rde)), &m->flags);
}
static void OpAluwCmp(struct Machine *m, uint32_t rde) {
AluwRo(m, rde, kAlu[ALU_SUB]);
}
static void OpAluwTest(struct Machine *m, uint32_t rde) {
AluwRo(m, rde, kAlu[ALU_AND]);
}
static void OpAluwFlip(struct Machine *m, uint32_t rde) {
WriteRegister(
rde, RegRexrReg(m, rde),
kAlu[(m->xedd->op.opcode & 070) >> 3][RegLog2(rde)](
Read64(RegRexrReg(m, rde)),
ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde)),
&m->flags));
}
static void AluwFlipRo(struct Machine *m, uint32_t rde, aluop_f ops[4]) {
ops[RegLog2(rde)](
Read64(RegRexrReg(m, rde)),
ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde)),
&m->flags);
}
static void OpAluwFlipCmp(struct Machine *m, uint32_t rde) {
AluwFlipRo(m, rde, kAlu[ALU_SUB]);
}
static void OpAluwFlipTest(struct Machine *m, uint32_t rde) {
AluwFlipRo(m, rde, kAlu[ALU_AND]);
}
static void Aluwi(struct Machine *m, uint32_t rde, aluop_f ops[4]) {
uint8_t *a;
a = GetModrmRegisterWordPointerWriteOszRexw(m, rde);
WriteRegisterOrMemory(
rde, a,
ops[RegLog2(rde)](ReadMemory(rde, a), m->xedd->op.uimm0, &m->flags));
}
static void AluwiRo(struct Machine *m, uint32_t rde, aluop_f ops[4]) {
ops[RegLog2(rde)](
ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde)),
m->xedd->op.uimm0, &m->flags);
}
static void OpAluwiReg(struct Machine *m, uint32_t rde) {
if (ModrmReg(rde) == ALU_CMP) {
AluwiRo(m, rde, kAlu[ModrmReg(rde)]);
} else {
Aluwi(m, rde, kAlu[ModrmReg(rde)]);
}
}
static void AluAlIb(struct Machine *m, aluop_f op) {
Write8(m->ax, op(Read8(m->ax), m->xedd->op.uimm0, &m->flags));
}
static void OpAluAlIbAdd(struct Machine *m, uint32_t rde) {
AluAlIb(m, Add8);
}
static void OpAluAlIbOr(struct Machine *m, uint32_t rde) {
AluAlIb(m, Or8);
}
static void OpAluAlIbAdc(struct Machine *m, uint32_t rde) {
AluAlIb(m, Adc8);
}
static void OpAluAlIbSbb(struct Machine *m, uint32_t rde) {
AluAlIb(m, Sbb8);
}
static void OpAluAlIbAnd(struct Machine *m, uint32_t rde) {
AluAlIb(m, And8);
}
static void OpAluAlIbSub(struct Machine *m, uint32_t rde) {
AluAlIb(m, Sub8);
}
static void OpAluAlIbXor(struct Machine *m, uint32_t rde) {
AluAlIb(m, Xor8);
}
static void OpAluRaxIvds(struct Machine *m, uint32_t rde) {
WriteRegister(rde, m->ax,
kAlu[(m->xedd->op.opcode & 070) >> 3][RegLog2(rde)](
ReadMemory(rde, m->ax), m->xedd->op.uimm0, &m->flags));
}
static void OpCmpAlIb(struct Machine *m, uint32_t rde) {
Sub8(Read8(m->ax), m->xedd->op.uimm0, &m->flags);
}
static void OpCmpRaxIvds(struct Machine *m, uint32_t rde) {
kAlu[ALU_SUB][RegLog2(rde)](ReadMemory(rde, m->ax), m->xedd->op.uimm0,
&m->flags);
}
static void OpTestAlIb(struct Machine *m, uint32_t rde) {
And8(Read8(m->ax), m->xedd->op.uimm0, &m->flags);
}
static void OpTestRaxIvds(struct Machine *m, uint32_t rde) {
kAlu[ALU_AND][RegLog2(rde)](ReadMemory(rde, m->ax), m->xedd->op.uimm0,
&m->flags);
}
static void Bsuwi(struct Machine *m, uint32_t rde, uint64_t y) {
uint8_t *p;
p = GetModrmRegisterWordPointerWriteOszRexw(m, rde);
WriteRegisterOrMemory(
rde, p,
kBsu[ModrmReg(rde)][RegLog2(rde)](ReadMemory(rde, p), y, &m->flags));
}
static void OpBsuwi1(struct Machine *m, uint32_t rde) {
Bsuwi(m, rde, 1);
}
static void OpBsuwiCl(struct Machine *m, uint32_t rde) {
Bsuwi(m, rde, Read8(m->cx));
}
static void OpBsuwiImm(struct Machine *m, uint32_t rde) {
Bsuwi(m, rde, m->xedd->op.uimm0);
}
static void Bsubi(struct Machine *m, uint32_t rde, uint64_t y) {
uint8_t *a = GetModrmRegisterBytePointerWrite(m, rde);
Write8(a, kBsu[ModrmReg(rde)][RegLog2(rde)](Read8(a), y, &m->flags));
}
static void OpBsubi1(struct Machine *m, uint32_t rde) {
Bsubi(m, rde, 1);
}
static void OpBsubiCl(struct Machine *m, uint32_t rde) {
Bsubi(m, rde, Read8(m->cx));
}
static void OpBsubiImm(struct Machine *m, uint32_t rde) {
Bsubi(m, rde, m->xedd->op.uimm0);
}
static void OpPushImm(struct Machine *m, uint32_t rde) {
Push(m, rde, m->xedd->op.uimm0);
}
static void Interrupt(struct Machine *m, uint32_t rde, int i) {
HaltMachine(m, i);
}
static void OpInterruptImm(struct Machine *m, uint32_t rde) {
Interrupt(m, rde, m->xedd->op.uimm0);
}
static void OpInterrupt1(struct Machine *m, uint32_t rde) {
Interrupt(m, rde, 1);
}
static void OpInterrupt3(struct Machine *m, uint32_t rde) {
Interrupt(m, rde, 3);
}
static void OpJmp(struct Machine *m, uint32_t rde) {
m->ip += m->xedd->op.disp;
}
static void OpJe(struct Machine *m, uint32_t rde) {
if (GetFlag(m->flags, FLAGS_ZF)) {
OpJmp(m, rde);
}
}
static void OpJne(struct Machine *m, uint32_t rde) {
if (!GetFlag(m->flags, FLAGS_ZF)) {
OpJmp(m, rde);
}
}
static void OpJb(struct Machine *m, uint32_t rde) {
if (GetFlag(m->flags, FLAGS_CF)) {
OpJmp(m, rde);
}
}
static void OpJbe(struct Machine *m, uint32_t rde) {
if (IsBelowOrEqual(m)) {
OpJmp(m, rde);
}
}
static void OpJo(struct Machine *m, uint32_t rde) {
if (GetFlag(m->flags, FLAGS_OF)) {
OpJmp(m, rde);
}
}
static void OpJno(struct Machine *m, uint32_t rde) {
if (!GetFlag(m->flags, FLAGS_OF)) {
OpJmp(m, rde);
}
}
static void OpJae(struct Machine *m, uint32_t rde) {
if (!GetFlag(m->flags, FLAGS_CF)) {
OpJmp(m, rde);
}
}
static void OpJa(struct Machine *m, uint32_t rde) {
if (IsAbove(m)) {
OpJmp(m, rde);
}
}
static void OpJs(struct Machine *m, uint32_t rde) {
if (GetFlag(m->flags, FLAGS_SF)) {
OpJmp(m, rde);
}
}
static void OpJns(struct Machine *m, uint32_t rde) {
if (!GetFlag(m->flags, FLAGS_SF)) {
OpJmp(m, rde);
}
}
static void OpJp(struct Machine *m, uint32_t rde) {
if (IsParity(m)) {
OpJmp(m, rde);
}
}
static void OpJnp(struct Machine *m, uint32_t rde) {
if (!IsParity(m)) {
OpJmp(m, rde);
}
}
static void OpJl(struct Machine *m, uint32_t rde) {
if (IsLess(m)) {
OpJmp(m, rde);
}
}
static void OpJge(struct Machine *m, uint32_t rde) {
if (IsGreaterOrEqual(m)) {
OpJmp(m, rde);
}
}
static void OpJle(struct Machine *m, uint32_t rde) {
if (IsLessOrEqual(m)) {
OpJmp(m, rde);
}
}
static void OpJg(struct Machine *m, uint32_t rde) {
if (IsGreater(m)) {
OpJmp(m, rde);
}
}
static void OpMovGvqpEvqp(struct Machine *m, uint32_t rde) {
WriteRegister(
rde, RegRexrReg(m, rde),
ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde)));
}
static void OpCmovo(struct Machine *m, uint32_t rde) {
if (GetFlag(m->flags, FLAGS_OF)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmovno(struct Machine *m, uint32_t rde) {
if (!GetFlag(m->flags, FLAGS_OF)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmovb(struct Machine *m, uint32_t rde) {
if (GetFlag(m->flags, FLAGS_CF)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmovae(struct Machine *m, uint32_t rde) {
if (!GetFlag(m->flags, FLAGS_CF)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmove(struct Machine *m, uint32_t rde) {
if (GetFlag(m->flags, FLAGS_ZF)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmovne(struct Machine *m, uint32_t rde) {
if (!GetFlag(m->flags, FLAGS_ZF)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmovbe(struct Machine *m, uint32_t rde) {
if (IsBelowOrEqual(m)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmova(struct Machine *m, uint32_t rde) {
if (IsAbove(m)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmovs(struct Machine *m, uint32_t rde) {
if (GetFlag(m->flags, FLAGS_SF)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmovns(struct Machine *m, uint32_t rde) {
if (!GetFlag(m->flags, FLAGS_SF)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmovp(struct Machine *m, uint32_t rde) {
if (IsParity(m)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmovnp(struct Machine *m, uint32_t rde) {
if (!IsParity(m)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmovl(struct Machine *m, uint32_t rde) {
if (IsLess(m)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmovge(struct Machine *m, uint32_t rde) {
if (IsGreaterOrEqual(m)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmovle(struct Machine *m, uint32_t rde) {
if (IsLessOrEqual(m)) {
OpMovGvqpEvqp(m, rde);
}
}
static void OpCmovg(struct Machine *m, uint32_t rde) {
if (IsGreater(m)) {
OpMovGvqpEvqp(m, rde);
}
}
static void SetEb(struct Machine *m, uint32_t rde, bool x) {
Write8(GetModrmRegisterBytePointerWrite(m, rde), x);
}
static void OpSeto(struct Machine *m, uint32_t rde) {
SetEb(m, rde, GetFlag(m->flags, FLAGS_OF));
}
static void OpSetno(struct Machine *m, uint32_t rde) {
SetEb(m, rde, !GetFlag(m->flags, FLAGS_OF));
}
static void OpSetb(struct Machine *m, uint32_t rde) {
SetEb(m, rde, GetFlag(m->flags, FLAGS_CF));
}
static void OpSetae(struct Machine *m, uint32_t rde) {
SetEb(m, rde, !GetFlag(m->flags, FLAGS_CF));
}
static void OpSete(struct Machine *m, uint32_t rde) {
SetEb(m, rde, GetFlag(m->flags, FLAGS_ZF));
}
static void OpSetne(struct Machine *m, uint32_t rde) {
SetEb(m, rde, !GetFlag(m->flags, FLAGS_ZF));
}
static void OpSetbe(struct Machine *m, uint32_t rde) {
SetEb(m, rde, IsBelowOrEqual(m));
}
static void OpSeta(struct Machine *m, uint32_t rde) {
SetEb(m, rde, IsAbove(m));
}
static void OpSets(struct Machine *m, uint32_t rde) {
SetEb(m, rde, GetFlag(m->flags, FLAGS_SF));
}
static void OpSetns(struct Machine *m, uint32_t rde) {
SetEb(m, rde, !GetFlag(m->flags, FLAGS_SF));
}
static void OpSetp(struct Machine *m, uint32_t rde) {
SetEb(m, rde, IsParity(m));
}
static void OpSetnp(struct Machine *m, uint32_t rde) {
SetEb(m, rde, !IsParity(m));
}
static void OpSetl(struct Machine *m, uint32_t rde) {
SetEb(m, rde, IsLess(m));
}
static void OpSetge(struct Machine *m, uint32_t rde) {
SetEb(m, rde, IsGreaterOrEqual(m));
}
static void OpSetle(struct Machine *m, uint32_t rde) {
SetEb(m, rde, IsLessOrEqual(m));
}
static void OpSetg(struct Machine *m, uint32_t rde) {
SetEb(m, rde, IsGreater(m));
}
static void OpJcxz(struct Machine *m, uint32_t rde) {
if (!MaskAddress(Eamode(rde), Read64(m->cx))) {
OpJmp(m, rde);
}
}
static void Bitscan(struct Machine *m, uint32_t rde, bitscan_f op) {
WriteRegister(
rde, RegRexrReg(m, rde),
op(m, rde,
ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde))));
}
static void OpBsf(struct Machine *m, uint32_t rde) {
Bitscan(m, rde, AluBsf);
}
static void OpBsr(struct Machine *m, uint32_t rde) {
Bitscan(m, rde, AluBsr);
}
static void Op1b8(struct Machine *m, uint32_t rde) {
if (Rep(rde) == 3) {
Bitscan(m, rde, AluPopcnt);
} else {
OpUd(m, rde);
}
}
static void OpNotEb(struct Machine *m, uint32_t rde) {
AluEb(m, rde, Not8);
}
static void OpNegEb(struct Machine *m, uint32_t rde) {
AluEb(m, rde, Neg8);
}
static relegated void LoadFarPointer(struct Machine *m, uint32_t rde,
uint8_t seg[8]) {
uint32_t fp;
fp = Read32(ComputeReserveAddressRead4(m, rde));
Write64(seg, (fp & 0x0000ffff) << 4);
Write16(RegRexrReg(m, rde), fp >> 16);
}
static relegated void OpLes(struct Machine *m, uint32_t rde) {
LoadFarPointer(m, rde, m->es);
}
static relegated void OpLds(struct Machine *m, uint32_t rde) {
LoadFarPointer(m, rde, m->ds);
}
static relegated void Loop(struct Machine *m, uint32_t rde, bool cond) {
uint64_t cx;
cx = Read64(m->cx) - 1;
if (Eamode(rde) != XED_MODE_REAL) {
if (Eamode(rde) == XED_MODE_LEGACY) {
cx &= 0xffffffff;
}
Write64(m->cx, cx);
} else {
cx &= 0xffff;
Write16(m->cx, cx);
}
if (cx && cond) {
OpJmp(m, rde);
}
}
static relegated void OpLoope(struct Machine *m, uint32_t rde) {
Loop(m, rde, GetFlag(m->flags, FLAGS_ZF));
}
static relegated void OpLoopne(struct Machine *m, uint32_t rde) {
Loop(m, rde, !GetFlag(m->flags, FLAGS_ZF));
}
static relegated void OpLoop1(struct Machine *m, uint32_t rde) {
Loop(m, rde, true);
}
static const nexgen32e_f kOp0f6[] = {
OpAlubiTest,
OpAlubiTest,
OpNotEb,
OpNegEb,
OpMulAxAlEbUnsigned,
OpMulAxAlEbSigned,
OpDivAlAhAxEbUnsigned,
OpDivAlAhAxEbSigned,
};
static void Op0f6(struct Machine *m, uint32_t rde) {
kOp0f6[ModrmReg(rde)](m, rde);
}
static void OpTestEvqpIvds(struct Machine *m, uint32_t rde) {
AluwiRo(m, rde, kAlu[ALU_AND]);
}
static void OpNotEvqp(struct Machine *m, uint32_t rde) {
AluEvqp(m, rde, kAlu[ALU_NOT]);
}
static void OpNegEvqp(struct Machine *m, uint32_t rde) {
AluEvqp(m, rde, kAlu[ALU_NEG]);
}
static const nexgen32e_f kOp0f7[] = {
OpTestEvqpIvds,
OpTestEvqpIvds,
OpNotEvqp,
OpNegEvqp,
OpMulRdxRaxEvqpUnsigned,
OpMulRdxRaxEvqpSigned,
OpDivRdxRaxEvqpUnsigned,
OpDivRdxRaxEvqpSigned,
};
static void Op0f7(struct Machine *m, uint32_t rde) {
kOp0f7[ModrmReg(rde)](m, rde);
}
static void Op0fe(struct Machine *m, uint32_t rde) {
switch (ModrmReg(rde)) {
case 0:
AluEb(m, rde, Inc8);
break;
case 1:
AluEb(m, rde, Dec8);
break;
default:
OpUd(m, rde);
}
}
static void OpIncEvqp(struct Machine *m, uint32_t rde) {
AluEvqp(m, rde, kAlu[ALU_INC]);
}
static void OpDecEvqp(struct Machine *m, uint32_t rde) {
AluEvqp(m, rde, kAlu[ALU_DEC]);
}
static const nexgen32e_f kOp0ff[] = {OpIncEvqp, OpDecEvqp, OpCallEq, OpUd,
OpJmpEq, OpUd, OpPushEvq, OpUd};
static void Op0ff(struct Machine *m, uint32_t rde) {
kOp0ff[ModrmReg(rde)](m, rde);
}
static void OpDoubleShift(struct Machine *m, uint32_t rde) {
uint8_t *p;
2020-09-03 12:44:37 +00:00
uint64_t x;
uint8_t W[2][2] = {{2, 3}, {1, 3}};
p = GetModrmRegisterWordPointerWriteOszRexw(m, rde);
WriteRegisterOrMemory(
rde, p,
BsuDoubleShift(W[Osz(rde)][Rexw(rde)], ReadMemory(rde, p),
ReadMemory(rde, RegRexrReg(m, rde)),
m->xedd->op.opcode & 1 ? Read8(m->cx) : m->xedd->op.uimm0,
m->xedd->op.opcode & 8, &m->flags));
}
static void OpFxsave(struct Machine *m, uint32_t rde) {
int64_t v;
uint8_t buf[32];
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
bzero(buf, 32);
Write16(buf + 0, m->fpu.cw);
Write16(buf + 2, m->fpu.sw);
Write8(buf + 4, m->fpu.tw);
Write16(buf + 6, m->fpu.op);
Write32(buf + 8, m->fpu.ip);
Write32(buf + 24, m->sse.mxcsr);
v = ComputeAddress(m, rde);
VirtualRecv(m, v + 0, buf, 32);
VirtualRecv(m, v + 32, m->fpu.st, 128);
VirtualRecv(m, v + 160, m->xmm, 256);
SetWriteAddr(m, v, 416);
}
static void OpFxrstor(struct Machine *m, uint32_t rde) {
int64_t v;
uint8_t buf[32];
v = ComputeAddress(m, rde);
SetReadAddr(m, v, 416);
VirtualSend(m, buf, v + 0, 32);
VirtualSend(m, m->fpu.st, v + 32, 128);
VirtualSend(m, m->xmm, v + 160, 256);
m->fpu.cw = Read16(buf + 0);
m->fpu.sw = Read16(buf + 2);
m->fpu.tw = Read8(buf + 4);
m->fpu.op = Read16(buf + 6);
m->fpu.ip = Read32(buf + 8);
m->sse.mxcsr = Read32(buf + 24);
}
static void OpXsave(struct Machine *m, uint32_t rde) {
}
static void OpLdmxcsr(struct Machine *m, uint32_t rde) {
m->sse.mxcsr = Read32(ComputeReserveAddressRead4(m, rde));
}
static void OpStmxcsr(struct Machine *m, uint32_t rde) {
Write32(ComputeReserveAddressWrite4(m, rde), m->sse.mxcsr);
}
static void OpRdfsbase(struct Machine *m, uint32_t rde) {
WriteRegister(rde, RegRexbRm(m, rde), Read64(m->fs));
}
static void OpRdgsbase(struct Machine *m, uint32_t rde) {
WriteRegister(rde, RegRexbRm(m, rde), Read64(m->gs));
}
static void OpWrfsbase(struct Machine *m, uint32_t rde) {
Write64(m->fs, ReadMemory(rde, RegRexbRm(m, rde)));
}
static void OpWrgsbase(struct Machine *m, uint32_t rde) {
Write64(m->gs, ReadMemory(rde, RegRexbRm(m, rde)));
}
static void Op1ae(struct Machine *m, uint32_t rde) {
bool ismem;
ismem = !IsModrmRegister(rde);
switch (ModrmReg(rde)) {
case 0:
if (ismem) {
OpFxsave(m, rde);
} else {
OpRdfsbase(m, rde);
}
break;
case 1:
if (ismem) {
OpFxrstor(m, rde);
} else {
OpRdgsbase(m, rde);
}
break;
case 2:
if (ismem) {
OpLdmxcsr(m, rde);
} else {
OpWrfsbase(m, rde);
}
break;
case 3:
if (ismem) {
OpStmxcsr(m, rde);
} else {
OpWrgsbase(m, rde);
}
break;
case 4:
if (ismem) {
OpXsave(m, rde);
} else {
OpUd(m, rde);
}
break;
case 5:
OpLfence(m, rde);
break;
case 6:
OpMfence(m, rde);
break;
case 7:
if (ismem) {
OpClflush(m, rde);
} else {
OpSfence(m, rde);
}
break;
default:
OpUd(m, rde);
}
}
static void OpSalc(struct Machine *m, uint32_t rde) {
Make major improvements to redbean and libraries The most exciting improvement is dynamic pages will soon be able to use the executable itself as an object store. it required a heroic technique for overcoming ETXTBSY restrictions which lets us open the executable in read/write mode, which means (1) wa can restore the APE header, and (2) we can potentially containerize redbean extension code so that modules you download for your redbean online will only impact your redbean. Here's a list of breaking changes to redbean: - Remove /tool/net/ prefix from magic ZIP paths - GetHeader() now returns NIL if header is absent Here's a list of fixes and enhancements to redbean: - Support 64-bit ZIP archives - Record User-Agent header in logs - Add twelve error handlers to accept() - Display octal st_mode on listing page - Show ZIP file comments on listing page - Restore APE MZ header on redbean startup - Track request count on redbean index page - Report server uptime on redbean index page - Don't bind server socket using SO_REUSEPORT - Fix #151 where Lua LoadAsset() could free twice - Report rusage accounting when workers exit w/ -vv - Use ZIP iattr field as text/plain vs. binary hint - Add ParseUrl() API for parsing things like a.href - Add ParseParams() API for parsing HTTP POST bodies - Add IsAcceptablePath() API for checking dots, etc. - Add IsValidHttpToken() API for validating sane ASCII - Add IsAcceptableHostPort() for validating HOST[:PORT] - Send 400 response to HTTP/1.1 requests without a Host - Send 403 response if ZIP or file isn't other readable - Add virtual hosting that tries prepending Host to path - Route requests based on Host in Request-URI if present - Host routing will attempt to remove or add the www. prefix - Sign-extend UNIX timestamps and don't adjust FileTime zone Here's some of the improvements made to Cosmopolitan Libc: - Fix ape.S indentation - Improve consts.sh magnums - Write pretty good URL parser - Improve rusage accounting apis - Bring mremap() closer to working - Added ZIP APIs which will change - Check for overflow in reallocarray() - Remove overly fancy linkage in strerror() - Fix GDB attach on crash w/ OpenBSD msyscall() - Make sigqueue() portable to most UNIX distros - Make integer serialization macros more elegant - Bring back 34x tprecode8to16() performance boost - Make malloc() more resilient to absurdly large sizes
2021-04-18 18:34:59 +00:00
if (GetFlag(m->flags, FLAGS_CF)) {
m->ax[0] = 255;
} else {
m->ax[0] = 0;
}
}
static void OpBofram(struct Machine *m, uint32_t rde) {
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 OpBinbase(struct Machine *m, uint32_t rde) {
if (m->onbinbase) {
m->onbinbase(m);
}
}
static void OpNopEv(struct Machine *m, uint32_t rde) {
switch (ModrmMod(rde) << 6 | ModrmReg(rde) << 3 | ModrmRm(rde)) {
case 0105:
OpBofram(m, rde);
break;
case 0106:
OpBofram(m, rde);
break;
case 0007:
case 0107:
case 0207:
OpBinbase(m, rde);
break;
default:
OpNoop(m, rde);
}
}
static void OpNop(struct Machine *m, uint32_t rde) {
if (Rexb(rde)) {
OpXchgZvqp(m, rde);
} else if (Rep(rde) == 3) {
OpPause(m, rde);
} else {
OpNoop(m, rde);
}
}
2020-10-27 10:39:46 +00:00
static void OpMovRqCq(struct Machine *m, uint32_t rde) {
switch (ModrmReg(rde)) {
case 0:
Write64(RegRexbRm(m, rde), m->cr0);
break;
case 2:
Write64(RegRexbRm(m, rde), m->cr2);
break;
case 3:
Write64(RegRexbRm(m, rde), m->cr3);
break;
case 4:
Write64(RegRexbRm(m, rde), m->cr4);
break;
default:
OpUd(m, rde);
}
}
static void OpMovCqRq(struct Machine *m, uint32_t rde) {
int64_t cr3;
2020-10-27 10:39:46 +00:00
switch (ModrmReg(rde)) {
case 0:
m->cr0 = Read64(RegRexbRm(m, rde));
break;
case 2:
m->cr2 = Read64(RegRexbRm(m, rde));
break;
case 3:
cr3 = Read64(RegRexbRm(m, rde));
if (0 <= cr3 && cr3 + 512 * 8 <= m->real.n) {
m->cr3 = cr3;
} else {
ThrowProtectionFault(m);
}
2020-10-27 10:39:46 +00:00
break;
case 4:
m->cr4 = Read64(RegRexbRm(m, rde));
break;
default:
OpUd(m, rde);
}
}
static void OpWrmsr(struct Machine *m, uint32_t rde) {
}
static void OpRdmsr(struct Machine *m, uint32_t rde) {
Write32(m->dx, 0);
Write32(m->ax, 0);
}
static void OpVzeroupper(struct Machine *m, uint32_t rde) {
}
static void OpEmms(struct Machine *m, uint32_t rde) {
if (m->xedd->op.vexvalid) {
OpVzeroupper(m, rde);
} else {
m->fpu.tw = -1;
}
}
static const nexgen32e_f kNexgen32e[] = {
[0x000] = OpAlubAdd,
[0x001] = OpAluw,
[0x002] = OpAlubFlipAdd,
[0x003] = OpAluwFlip,
[0x004] = OpAluAlIbAdd,
[0x005] = OpAluRaxIvds,
[0x006] = OpPushSeg,
[0x007] = OpPopSeg,
[0x008] = OpAlubOr,
[0x009] = OpAluw,
[0x00A] = OpAlubFlipOr,
[0x00B] = OpAluwFlip,
[0x00C] = OpAluAlIbOr,
[0x00D] = OpAluRaxIvds,
[0x00E] = OpPushSeg,
[0x00F] = OpPopSeg,
[0x010] = OpAlubAdc,
[0x011] = OpAluw,
[0x012] = OpAlubFlipAdc,
[0x013] = OpAluwFlip,
[0x014] = OpAluAlIbAdc,
[0x015] = OpAluRaxIvds,
[0x016] = OpPushSeg,
[0x017] = OpPopSeg,
[0x018] = OpAlubSbb,
[0x019] = OpAluw,
[0x01A] = OpAlubFlipSbb,
[0x01B] = OpAluwFlip,
[0x01C] = OpAluAlIbSbb,
[0x01D] = OpAluRaxIvds,
[0x01E] = OpPushSeg,
[0x01F] = OpPopSeg,
[0x020] = OpAlubAnd,
[0x021] = OpAluw,
[0x022] = OpAlubFlipAnd,
[0x023] = OpAluwFlip,
[0x024] = OpAluAlIbAnd,
[0x025] = OpAluRaxIvds,
[0x026] = OpPushSeg,
[0x027] = OpPopSeg,
[0x028] = OpAlubSub,
[0x029] = OpAluw,
[0x02A] = OpAlubFlipSub,
[0x02B] = OpAluwFlip,
[0x02C] = OpAluAlIbSub,
[0x02D] = OpAluRaxIvds,
[0x02E] = OpUd,
[0x02F] = OpDas,
[0x030] = OpAlubXor,
[0x031] = OpAluw,
[0x032] = OpAlubFlipXor,
[0x033] = OpAluwFlip,
[0x034] = OpAluAlIbXor,
[0x035] = OpAluRaxIvds,
[0x036] = OpUd,
[0x037] = OpAaa,
[0x038] = OpAlubCmp,
[0x039] = OpAluwCmp,
[0x03A] = OpAlubFlipCmp,
[0x03B] = OpAluwFlipCmp,
[0x03C] = OpCmpAlIb,
[0x03D] = OpCmpRaxIvds,
[0x03E] = OpUd,
[0x03F] = OpAas,
[0x040] = OpIncZv,
[0x041] = OpIncZv,
[0x042] = OpIncZv,
[0x043] = OpIncZv,
[0x044] = OpIncZv,
[0x045] = OpIncZv,
[0x046] = OpIncZv,
[0x047] = OpIncZv,
[0x048] = OpDecZv,
[0x049] = OpDecZv,
[0x04A] = OpDecZv,
[0x04B] = OpDecZv,
[0x04C] = OpDecZv,
[0x04D] = OpDecZv,
[0x04E] = OpDecZv,
[0x04F] = OpDecZv,
[0x050] = OpPushZvq,
[0x051] = OpPushZvq,
[0x052] = OpPushZvq,
[0x053] = OpPushZvq,
[0x054] = OpPushZvq,
[0x055] = OpPushZvq,
[0x056] = OpPushZvq,
[0x057] = OpPushZvq,
[0x058] = OpPopZvq,
[0x059] = OpPopZvq,
[0x05A] = OpPopZvq,
[0x05B] = OpPopZvq,
[0x05C] = OpPopZvq,
[0x05D] = OpPopZvq,
[0x05E] = OpPopZvq,
[0x05F] = OpPopZvq,
[0x060] = OpPusha,
[0x061] = OpPopa,
[0x062] = OpUd,
[0x063] = OpMovsxdGdqpEd,
[0x064] = OpUd,
[0x065] = OpUd,
[0x066] = OpUd,
[0x067] = OpUd,
[0x068] = OpPushImm,
[0x069] = OpImulGvqpEvqpImm,
[0x06A] = OpPushImm,
[0x06B] = OpImulGvqpEvqpImm,
[0x06C] = OpIns,
[0x06D] = OpIns,
[0x06E] = OpOuts,
[0x06F] = OpOuts,
[0x070] = OpJo,
[0x071] = OpJno,
[0x072] = OpJb,
[0x073] = OpJae,
[0x074] = OpJe,
[0x075] = OpJne,
[0x076] = OpJbe,
[0x077] = OpJa,
[0x078] = OpJs,
[0x079] = OpJns,
[0x07A] = OpJp,
[0x07B] = OpJnp,
[0x07C] = OpJl,
[0x07D] = OpJge,
[0x07E] = OpJle,
[0x07F] = OpJg,
[0x080] = OpAlubiReg,
[0x081] = OpAluwiReg,
[0x082] = OpAlubiReg,
[0x083] = OpAluwiReg,
[0x084] = OpAlubTest,
[0x085] = OpAluwTest,
[0x086] = OpXchgGbEb,
[0x087] = OpXchgGvqpEvqp,
[0x088] = OpMovEbGb,
[0x089] = OpMovEvqpGvqp,
[0x08A] = OpMovGbEb,
[0x08B] = OpMovGvqpEvqp,
[0x08C] = OpMovEvqpSw,
[0x08D] = OpLeaGvqpM,
[0x08E] = OpMovSwEvqp,
[0x08F] = OpPopEvq,
[0x090] = OpNop,
[0x091] = OpXchgZvqp,
[0x092] = OpXchgZvqp,
[0x093] = OpXchgZvqp,
[0x094] = OpXchgZvqp,
[0x095] = OpXchgZvqp,
[0x096] = OpXchgZvqp,
[0x097] = OpXchgZvqp,
[0x098] = OpSax,
[0x099] = OpConvert,
[0x09A] = OpCallf,
[0x09B] = OpFwait,
[0x09C] = OpPushf,
[0x09D] = OpPopf,
[0x09E] = OpSahf,
[0x09F] = OpLahf,
[0x0A0] = OpMovAlOb,
[0x0A1] = OpMovRaxOvqp,
[0x0A2] = OpMovObAl,
[0x0A3] = OpMovOvqpRax,
[0x0A4] = OpMovsb,
[0x0A5] = OpMovs,
[0x0A6] = OpCmps,
[0x0A7] = OpCmps,
[0x0A8] = OpTestAlIb,
[0x0A9] = OpTestRaxIvds,
[0x0AA] = OpStosb,
[0x0AB] = OpStos,
[0x0AC] = OpLods,
[0x0AD] = OpLods,
[0x0AE] = OpScas,
[0x0AF] = OpScas,
[0x0B0] = OpMovZbIb,
[0x0B1] = OpMovZbIb,
[0x0B2] = OpMovZbIb,
[0x0B3] = OpMovZbIb,
[0x0B4] = OpMovZbIb,
[0x0B5] = OpMovZbIb,
[0x0B6] = OpMovZbIb,
[0x0B7] = OpMovZbIb,
[0x0B8] = OpMovZvqpIvqp,
[0x0B9] = OpMovZvqpIvqp,
[0x0BA] = OpMovZvqpIvqp,
[0x0BB] = OpMovZvqpIvqp,
[0x0BC] = OpMovZvqpIvqp,
[0x0BD] = OpMovZvqpIvqp,
[0x0BE] = OpMovZvqpIvqp,
[0x0BF] = OpMovZvqpIvqp,
[0x0C0] = OpBsubiImm,
[0x0C1] = OpBsuwiImm,
[0x0C2] = OpRet,
[0x0C3] = OpRet,
[0x0C4] = OpLes,
[0x0C5] = OpLds,
[0x0C6] = OpMovEbIb,
[0x0C7] = OpMovEvqpIvds,
[0x0C8] = OpUd,
[0x0C9] = OpLeave,
[0x0CA] = OpRetf,
[0x0CB] = OpRetf,
[0x0CC] = OpInterrupt3,
[0x0CD] = OpInterruptImm,
[0x0CE] = OpInto,
[0x0CF] = OpUd,
[0x0D0] = OpBsubi1,
[0x0D1] = OpBsuwi1,
[0x0D2] = OpBsubiCl,
[0x0D3] = OpBsuwiCl,
[0x0D4] = OpAam,
[0x0D5] = OpAad,
[0x0D6] = OpSalc,
[0x0D7] = OpXlatAlBbb,
[0x0D8] = OpFpu,
[0x0D9] = OpFpu,
[0x0DA] = OpFpu,
[0x0DB] = OpFpu,
[0x0DC] = OpFpu,
[0x0DD] = OpFpu,
[0x0DE] = OpFpu,
[0x0DF] = OpFpu,
[0x0E0] = OpLoopne,
[0x0E1] = OpLoope,
[0x0E2] = OpLoop1,
[0x0E3] = OpJcxz,
[0x0E4] = OpInAlImm,
[0x0E5] = OpInAxImm,
[0x0E6] = OpOutImmAl,
[0x0E7] = OpOutImmAx,
[0x0E8] = OpCallJvds,
[0x0E9] = OpJmp,
[0x0EA] = OpJmpf,
[0x0EB] = OpJmp,
[0x0EC] = OpInAlDx,
[0x0ED] = OpInAxDx,
[0x0EE] = OpOutDxAl,
[0x0EF] = OpOutDxAx,
[0x0F0] = OpUd,
[0x0F1] = OpInterrupt1,
[0x0F2] = OpUd,
[0x0F3] = OpUd,
[0x0F4] = OpHlt,
[0x0F5] = OpCmc,
[0x0F6] = Op0f6,
[0x0F7] = Op0f7,
[0x0F8] = OpClc,
[0x0F9] = OpStc,
[0x0FA] = OpCli,
[0x0FB] = OpSti,
[0x0FC] = OpCld,
[0x0FD] = OpStd,
[0x0FE] = Op0fe,
[0x0FF] = Op0ff,
[0x100] = OpUd,
[0x101] = Op101,
[0x102] = OpUd,
[0x103] = OpLsl,
[0x104] = OpUd,
[0x105] = OpSyscall,
[0x106] = OpUd,
[0x107] = OpUd,
[0x108] = OpUd,
[0x109] = OpUd,
[0x10A] = OpUd,
[0x10B] = OpUd,
[0x10C] = OpUd,
[0x10D] = OpHintNopEv,
[0x10E] = OpUd,
[0x10F] = OpUd,
[0x110] = OpMov0f10,
[0x111] = OpMovWpsVps,
[0x112] = OpMov0f12,
[0x113] = OpMov0f13,
[0x114] = OpUnpcklpsd,
[0x115] = OpUnpckhpsd,
[0x116] = OpMov0f16,
[0x117] = OpMov0f17,
[0x118] = OpHintNopEv,
[0x119] = OpHintNopEv,
[0x11A] = OpHintNopEv,
[0x11B] = OpHintNopEv,
[0x11C] = OpHintNopEv,
[0x11D] = OpHintNopEv,
[0x11E] = OpHintNopEv,
[0x11F] = OpNopEv,
2020-10-27 10:39:46 +00:00
[0x120] = OpMovRqCq,
[0x121] = OpUd,
2020-10-27 10:39:46 +00:00
[0x122] = OpMovCqRq,
[0x123] = OpUd,
[0x124] = OpUd,
[0x125] = OpUd,
[0x126] = OpUd,
[0x127] = OpUd,
[0x128] = OpMov0f28,
[0x129] = OpMovWpsVps,
[0x12A] = OpCvt0f2a,
[0x12B] = OpMov0f2b,
[0x12C] = OpCvtt0f2c,
[0x12D] = OpCvt0f2d,
[0x12E] = OpComissVsWs,
[0x12F] = OpComissVsWs,
[0x130] = OpWrmsr,
[0x131] = OpRdtsc,
[0x132] = OpRdmsr,
[0x133] = OpUd,
[0x134] = OpUd,
[0x135] = OpUd,
[0x136] = OpUd,
[0x137] = OpUd,
[0x138] = OpUd,
[0x139] = OpUd,
[0x13A] = OpUd,
[0x13B] = OpUd,
[0x13C] = OpUd,
[0x13D] = OpUd,
[0x13E] = OpUd,
[0x13F] = OpUd,
[0x140] = OpCmovo,
[0x141] = OpCmovno,
[0x142] = OpCmovb,
[0x143] = OpCmovae,
[0x144] = OpCmove,
[0x145] = OpCmovne,
[0x146] = OpCmovbe,
[0x147] = OpCmova,
[0x148] = OpCmovs,
[0x149] = OpCmovns,
[0x14A] = OpCmovp,
[0x14B] = OpCmovnp,
[0x14C] = OpCmovl,
[0x14D] = OpCmovge,
[0x14E] = OpCmovle,
[0x14F] = OpCmovg,
[0x150] = OpUd,
[0x151] = OpSqrtpsd,
[0x152] = OpRsqrtps,
[0x153] = OpRcpps,
[0x154] = OpAndpsd,
[0x155] = OpAndnpsd,
[0x156] = OpOrpsd,
[0x157] = OpXorpsd,
[0x158] = OpAddpsd,
[0x159] = OpMulpsd,
[0x15A] = OpCvt0f5a,
[0x15B] = OpCvt0f5b,
[0x15C] = OpSubpsd,
[0x15D] = OpMinpsd,
[0x15E] = OpDivpsd,
[0x15F] = OpMaxpsd,
[0x160] = OpSsePunpcklbw,
[0x161] = OpSsePunpcklwd,
[0x162] = OpSsePunpckldq,
[0x163] = OpSsePacksswb,
[0x164] = OpSsePcmpgtb,
[0x165] = OpSsePcmpgtw,
[0x166] = OpSsePcmpgtd,
[0x167] = OpSsePackuswb,
[0x168] = OpSsePunpckhbw,
[0x169] = OpSsePunpckhwd,
[0x16A] = OpSsePunpckhdq,
[0x16B] = OpSsePackssdw,
[0x16C] = OpSsePunpcklqdq,
[0x16D] = OpSsePunpckhqdq,
[0x16E] = OpMov0f6e,
[0x16F] = OpMov0f6f,
[0x170] = OpShuffle,
[0x171] = Op171,
[0x172] = Op172,
[0x173] = Op173,
[0x174] = OpSsePcmpeqb,
[0x175] = OpSsePcmpeqw,
[0x176] = OpSsePcmpeqd,
[0x177] = OpEmms,
[0x178] = OpUd,
[0x179] = OpUd,
[0x17A] = OpUd,
[0x17B] = OpUd,
[0x17C] = OpHaddpsd,
[0x17D] = OpHsubpsd,
[0x17E] = OpMov0f7e,
[0x17F] = OpMov0f7f,
[0x180] = OpJo,
[0x181] = OpJno,
[0x182] = OpJb,
[0x183] = OpJae,
[0x184] = OpJe,
[0x185] = OpJne,
[0x186] = OpJbe,
[0x187] = OpJa,
[0x188] = OpJs,
[0x189] = OpJns,
[0x18A] = OpJp,
[0x18B] = OpJnp,
[0x18C] = OpJl,
[0x18D] = OpJge,
[0x18E] = OpJle,
[0x18F] = OpJg,
[0x190] = OpSeto,
[0x191] = OpSetno,
[0x192] = OpSetb,
[0x193] = OpSetae,
[0x194] = OpSete,
[0x195] = OpSetne,
[0x196] = OpSetbe,
[0x197] = OpSeta,
[0x198] = OpSets,
[0x199] = OpSetns,
[0x19A] = OpSetp,
[0x19B] = OpSetnp,
[0x19C] = OpSetl,
[0x19D] = OpSetge,
[0x19E] = OpSetle,
[0x19F] = OpSetg,
[0x1A0] = OpPushSeg,
[0x1A1] = OpPopSeg,
[0x1A2] = OpCpuid,
[0x1A3] = OpBit,
[0x1A4] = OpDoubleShift,
[0x1A5] = OpDoubleShift,
[0x1A6] = OpUd,
[0x1A7] = OpUd,
[0x1A8] = OpPushSeg,
[0x1A9] = OpPopSeg,
[0x1AA] = OpUd,
[0x1AB] = OpBit,
[0x1AC] = OpDoubleShift,
[0x1AD] = OpDoubleShift,
[0x1AE] = Op1ae,
[0x1AF] = OpImulGvqpEvqp,
[0x1B0] = OpCmpxchgEbAlGb,
[0x1B1] = OpCmpxchgEvqpRaxGvqp,
[0x1B2] = OpUd,
[0x1B3] = OpBit,
[0x1B4] = OpUd,
[0x1B5] = OpUd,
[0x1B6] = OpMovzbGvqpEb,
[0x1B7] = OpMovzwGvqpEw,
[0x1B8] = Op1b8,
[0x1B9] = OpUd,
[0x1BA] = OpBit,
[0x1BB] = OpBit,
[0x1BC] = OpBsf,
[0x1BD] = OpBsr,
[0x1BE] = OpMovsbGvqpEb,
[0x1BF] = OpMovswGvqpEw,
[0x1C0] = OpXaddEbGb,
[0x1C1] = OpXaddEvqpGvqp,
[0x1C2] = OpCmppsd,
[0x1C3] = OpMovntiMdqpGdqp,
[0x1C4] = OpPinsrwVdqEwIb,
[0x1C5] = OpPextrwGdqpUdqIb,
[0x1C6] = OpShufpsd,
[0x1C7] = Op1c7,
[0x1C8] = OpBswapZvqp,
[0x1C9] = OpBswapZvqp,
[0x1CA] = OpBswapZvqp,
[0x1CB] = OpBswapZvqp,
[0x1CC] = OpBswapZvqp,
[0x1CD] = OpBswapZvqp,
[0x1CE] = OpBswapZvqp,
[0x1CF] = OpBswapZvqp,
[0x1D0] = OpAddsubpsd,
[0x1D1] = OpSsePsrlwv,
[0x1D2] = OpSsePsrldv,
[0x1D3] = OpSsePsrlqv,
[0x1D4] = OpSsePaddq,
[0x1D5] = OpSsePmullw,
[0x1D6] = OpMov0fD6,
[0x1D7] = OpPmovmskbGdqpNqUdq,
[0x1D8] = OpSsePsubusb,
[0x1D9] = OpSsePsubusw,
[0x1DA] = OpSsePminub,
[0x1DB] = OpSsePand,
[0x1DC] = OpSsePaddusb,
[0x1DD] = OpSsePaddusw,
[0x1DE] = OpSsePmaxub,
[0x1DF] = OpSsePandn,
[0x1E0] = OpSsePavgb,
[0x1E1] = OpSsePsrawv,
[0x1E2] = OpSsePsradv,
[0x1E3] = OpSsePavgw,
[0x1E4] = OpSsePmulhuw,
[0x1E5] = OpSsePmulhw,
[0x1E6] = OpCvt0fE6,
[0x1E7] = OpMov0fE7,
[0x1E8] = OpSsePsubsb,
[0x1E9] = OpSsePsubsw,
[0x1EA] = OpSsePminsw,
[0x1EB] = OpSsePor,
[0x1EC] = OpSsePaddsb,
[0x1ED] = OpSsePaddsw,
[0x1EE] = OpSsePmaxsw,
[0x1EF] = OpSsePxor,
[0x1F0] = OpLddquVdqMdq,
[0x1F1] = OpSsePsllwv,
[0x1F2] = OpSsePslldv,
[0x1F3] = OpSsePsllqv,
[0x1F4] = OpSsePmuludq,
[0x1F5] = OpSsePmaddwd,
[0x1F6] = OpSsePsadbw,
[0x1F7] = OpMaskMovDiXmmRegXmmRm,
[0x1F8] = OpSsePsubb,
[0x1F9] = OpSsePsubw,
[0x1FA] = OpSsePsubd,
[0x1FB] = OpSsePsubq,
[0x1FC] = OpSsePaddb,
[0x1FD] = OpSsePaddw,
[0x1FE] = OpSsePaddd,
[0x1FF] = OpUd,
[0x200] = OpSsePshufb,
[0x201] = OpSsePhaddw,
[0x202] = OpSsePhaddd,
[0x203] = OpSsePhaddsw,
[0x204] = OpSsePmaddubsw,
[0x205] = OpSsePhsubw,
[0x206] = OpSsePhsubd,
[0x207] = OpSsePhsubsw,
[0x208] = OpSsePsignb,
[0x209] = OpSsePsignw,
[0x20A] = OpSsePsignd,
[0x20B] = OpSsePmulhrsw,
};
void ExecuteSparseInstruction(struct Machine *m, uint32_t rde, uint32_t d) {
switch (d) {
CASE(0x21c, OpSsePabsb(m, rde));
CASE(0x21d, OpSsePabsw(m, rde));
CASE(0x21e, OpSsePabsd(m, rde));
CASE(0x22a, OpMovntdqaVdqMdq(m, rde));
CASE(0x240, OpSsePmulld(m, rde));
CASE(0x30f, OpSsePalignr(m, rde));
Productionize new APE loader and more The APE_NO_MODIFY_SELF loader payload has been moved out of the examples folder and improved so that it works on BSD systems, and permits general elf program headers. This brings its quality up enough that it should be acceptable to use by default for many programs, e.g. Python, Lua, SQLite and Python. It's the responsibility of the user to define an appropriate TMPDIR if /tmp is considered an adversarial environment. Mac OS shall be supported by APE_NO_MODIFY_SELF soon. Fixes and improvements have been made to program_executable_name as it's now the one true way to get the absolute path of the executing image. This change fixes a memory leak in linenoise history loading, introduced by performance optimizations in 51904e2687c04d7ae20410cd94c2148972d6bae6 This change fixes a longstanding regression with Mach system calls, that 23ae9dfceb6f657862f00e674a8e4dc357a9d24d back in February which impacted our sched_yield() implementation, which is why no one noticed until now. The Blinkenlights PC emulator has been improved. We now fix rendering on XNU and BSD by not making the assumption that the kernel terminal driver understands UTF8 since that seems to break its internal modeling of \r\n which is now being addressed by using \e[𝑦H instead. The paneling is now more compact in real mode so you won't need to make your font as tiny if you're only emulating an 8086 program. The CLMUL ISA is now emulated too This change also makes improvement to time. CLOCK_MONOTONIC now does the right thing on Windows NT. The nanosecond time module functions added in Python 3.7 have been backported. This change doubles the performance of Argon2 password stretching simply by not using its copy_block and xor_block helper functions, as they were trivial to inline thus resulting in us needing to iterate over each 1024 byte block four fewer times. This change makes code size improvements. _PyUnicode_ToNumeric() was 64k in size and now it's 10k. The CJK codec lookup tables now use lazy delta zigzag deflate (δzd) encoding which reduces their size from 600k to 200k plus the code bloat caused by macro abuse in _decimal.c is now addressed so our fully-loaded statically-linked hermetically-sealed Python virtual interpreter container is now 9.4 megs in the default build mode and 5.5m in MODE=tiny which leaves plenty of room for chibicc. The pydoc web server now accommodates the use case of people who work by SSH'ing into a different machine w/ python.com -m pydoc -p8080 -h0.0.0.0 Finally Python Capsulae delenda est and won't be supported in the future
2021-10-02 15:17:04 +00:00
CASE(0x344, OpSsePclmulqdq(m, rde));
default:
OpUd(m, rde);
}
}
void ExecuteInstruction(struct Machine *m) {
m->ip += m->xedd->length;
if (m->xedd->op.dispatch < ARRAYLEN(kNexgen32e)) {
kNexgen32e[m->xedd->op.dispatch](m, m->xedd->op.rde);
} else {
ExecuteSparseInstruction(m, m->xedd->op.rde, m->xedd->op.dispatch);
}
if (m->stashaddr) {
VirtualRecv(m, m->stashaddr, m->stash, m->stashsize);
m->stashaddr = 0;
}
}