mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 23:13:34 +00:00
- Emulator can now test the αcτµαlly pδrταblε εxεcµταblε bootloader - Whipped up a webserver named redbean. It services 150k requests per second on a single core. Bundling assets inside zip enables extremely fast serving for two reasons. The first is that zip central directory lookups go faster than stat() system calls. The second is that both zip and gzip content-encoding use DEFLATE, therefore, compressed responses can be served via the sendfile() system call which does an in-kernel copy directly from the zip executable structure. Also note that red bean zip executables can be deployed easily to all platforms, since these native executables work on Linux, Mac, BSD, and Windows. - Address sanitizer now works very well
522 lines
14 KiB
C
522 lines
14 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/str/str.h"
|
|
#include "tool/build/lib/address.h"
|
|
#include "tool/build/lib/endian.h"
|
|
#include "tool/build/lib/memory.h"
|
|
#include "tool/build/lib/modrm.h"
|
|
#include "tool/build/lib/ssemov.h"
|
|
#include "tool/build/lib/throw.h"
|
|
|
|
static void MovdquVdqWdq(struct Machine *m, uint32_t rde) {
|
|
memcpy(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead16(m, rde), 16);
|
|
}
|
|
|
|
static void MovdquWdqVdq(struct Machine *m, uint32_t rde) {
|
|
memcpy(GetModrmRegisterXmmPointerWrite16(m, rde), XmmRexrReg(m, rde), 16);
|
|
}
|
|
|
|
static void MovupsVpsWps(struct Machine *m, uint32_t rde) {
|
|
MovdquVdqWdq(m, rde);
|
|
}
|
|
|
|
static void MovupsWpsVps(struct Machine *m, uint32_t rde) {
|
|
MovdquWdqVdq(m, rde);
|
|
}
|
|
|
|
static void MovupdVpsWps(struct Machine *m, uint32_t rde) {
|
|
MovdquVdqWdq(m, rde);
|
|
}
|
|
|
|
static void MovupdWpsVps(struct Machine *m, uint32_t rde) {
|
|
MovdquWdqVdq(m, rde);
|
|
}
|
|
|
|
void OpLddquVdqMdq(struct Machine *m, uint32_t rde) {
|
|
MovdquVdqWdq(m, rde);
|
|
}
|
|
|
|
void OpMovntiMdqpGdqp(struct Machine *m, uint32_t rde) {
|
|
if (Rexw(rde)) {
|
|
memcpy(ComputeReserveAddressWrite8(m, rde), XmmRexrReg(m, rde), 8);
|
|
} else {
|
|
memcpy(ComputeReserveAddressWrite4(m, rde), XmmRexrReg(m, rde), 4);
|
|
}
|
|
}
|
|
|
|
static void MovdqaVdqMdq(struct Machine *m, uint32_t rde) {
|
|
int64_t v;
|
|
uint8_t *p;
|
|
v = ComputeAddress(m, rde);
|
|
SetReadAddr(m, v, 16);
|
|
if ((v & 15) || !(p = FindReal(m, v))) ThrowSegmentationFault(m, v);
|
|
memcpy(XmmRexrReg(m, rde), Abp16(p), 16);
|
|
}
|
|
|
|
static void MovdqaMdqVdq(struct Machine *m, uint32_t rde) {
|
|
int64_t v;
|
|
uint8_t *p;
|
|
v = ComputeAddress(m, rde);
|
|
SetWriteAddr(m, v, 16);
|
|
if ((v & 15) || !(p = FindReal(m, v))) ThrowSegmentationFault(m, v);
|
|
memcpy(Abp16(p), XmmRexrReg(m, rde), 16);
|
|
}
|
|
|
|
static void MovdqaVdqWdq(struct Machine *m, uint32_t rde) {
|
|
if (IsModrmRegister(rde)) {
|
|
memcpy(XmmRexrReg(m, rde), XmmRexbRm(m, rde), 16);
|
|
} else {
|
|
MovdqaVdqMdq(m, rde);
|
|
}
|
|
}
|
|
|
|
static void MovdqaWdqVdq(struct Machine *m, uint32_t rde) {
|
|
if (IsModrmRegister(rde)) {
|
|
memcpy(XmmRexbRm(m, rde), XmmRexrReg(m, rde), 16);
|
|
} else {
|
|
MovdqaMdqVdq(m, rde);
|
|
}
|
|
}
|
|
|
|
static void MovntdqMdqVdq(struct Machine *m, uint32_t rde) {
|
|
MovdqaMdqVdq(m, rde);
|
|
}
|
|
|
|
static void MovntpsMpsVps(struct Machine *m, uint32_t rde) {
|
|
MovdqaMdqVdq(m, rde);
|
|
}
|
|
|
|
static void MovntpdMpdVpd(struct Machine *m, uint32_t rde) {
|
|
MovdqaMdqVdq(m, rde);
|
|
}
|
|
|
|
void OpMovntdqaVdqMdq(struct Machine *m, uint32_t rde) {
|
|
MovdqaVdqMdq(m, rde);
|
|
}
|
|
|
|
static void MovqPqQq(struct Machine *m, uint32_t rde) {
|
|
memcpy(MmReg(m, rde), GetModrmRegisterMmPointerRead8(m, rde), 8);
|
|
}
|
|
|
|
static void MovqQqPq(struct Machine *m, uint32_t rde) {
|
|
memcpy(GetModrmRegisterMmPointerWrite8(m, rde), MmReg(m, rde), 8);
|
|
}
|
|
|
|
static void MovqVdqEqp(struct Machine *m, uint32_t rde) {
|
|
memcpy(XmmRexrReg(m, rde), GetModrmRegisterWordPointerRead8(m, rde), 8);
|
|
memset(XmmRexrReg(m, rde) + 8, 0, 8);
|
|
}
|
|
|
|
static void MovdVdqEd(struct Machine *m, uint32_t rde) {
|
|
memset(XmmRexrReg(m, rde), 0, 16);
|
|
memcpy(XmmRexrReg(m, rde), GetModrmRegisterWordPointerRead4(m, rde), 4);
|
|
}
|
|
|
|
static void MovqPqEqp(struct Machine *m, uint32_t rde) {
|
|
memcpy(MmReg(m, rde), GetModrmRegisterWordPointerRead8(m, rde), 8);
|
|
}
|
|
|
|
static void MovdPqEd(struct Machine *m, uint32_t rde) {
|
|
memcpy(MmReg(m, rde), GetModrmRegisterWordPointerRead4(m, rde), 4);
|
|
memset(MmReg(m, rde) + 4, 0, 4);
|
|
}
|
|
|
|
static void MovdEdVdq(struct Machine *m, uint32_t rde) {
|
|
if (IsModrmRegister(rde)) {
|
|
Write64(RegRexbRm(m, rde), Read32(XmmRexrReg(m, rde)));
|
|
} else {
|
|
memcpy(ComputeReserveAddressWrite4(m, rde), XmmRexrReg(m, rde), 4);
|
|
}
|
|
}
|
|
|
|
static void MovqEqpVdq(struct Machine *m, uint32_t rde) {
|
|
memcpy(GetModrmRegisterWordPointerWrite8(m, rde), XmmRexrReg(m, rde), 8);
|
|
}
|
|
|
|
static void MovdEdPq(struct Machine *m, uint32_t rde) {
|
|
if (IsModrmRegister(rde)) {
|
|
Write64(RegRexbRm(m, rde), Read32(MmReg(m, rde)));
|
|
} else {
|
|
memcpy(ComputeReserveAddressWrite4(m, rde), MmReg(m, rde), 4);
|
|
}
|
|
}
|
|
|
|
static void MovqEqpPq(struct Machine *m, uint32_t rde) {
|
|
memcpy(GetModrmRegisterWordPointerWrite(m, rde, 8), MmReg(m, rde), 8);
|
|
}
|
|
|
|
static void MovntqMqPq(struct Machine *m, uint32_t rde) {
|
|
memcpy(ComputeReserveAddressWrite8(m, rde), MmReg(m, rde), 8);
|
|
}
|
|
|
|
static void MovqVqWq(struct Machine *m, uint32_t rde) {
|
|
memcpy(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead8(m, rde), 8);
|
|
memset(XmmRexrReg(m, rde) + 8, 0, 8);
|
|
}
|
|
|
|
static void MovssVpsWps(struct Machine *m, uint32_t rde) {
|
|
memcpy(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead4(m, rde), 4);
|
|
}
|
|
|
|
static void MovssWpsVps(struct Machine *m, uint32_t rde) {
|
|
memcpy(GetModrmRegisterXmmPointerWrite4(m, rde), XmmRexrReg(m, rde), 4);
|
|
}
|
|
|
|
static void MovsdVpsWps(struct Machine *m, uint32_t rde) {
|
|
memcpy(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead16(m, rde), 8);
|
|
}
|
|
|
|
static void MovsdWpsVps(struct Machine *m, uint32_t rde) {
|
|
memcpy(GetModrmRegisterXmmPointerWrite16(m, rde), XmmRexrReg(m, rde), 8);
|
|
}
|
|
|
|
static void MovhlpsVqUq(struct Machine *m, uint32_t rde) {
|
|
memcpy(XmmRexrReg(m, rde), XmmRexbRm(m, rde) + 8, 8);
|
|
}
|
|
|
|
static void MovlpsVqMq(struct Machine *m, uint32_t rde) {
|
|
memcpy(XmmRexrReg(m, rde), ComputeReserveAddressRead8(m, rde), 8);
|
|
}
|
|
|
|
static void MovlpdVqMq(struct Machine *m, uint32_t rde) {
|
|
memcpy(XmmRexrReg(m, rde), ComputeReserveAddressRead8(m, rde), 8);
|
|
}
|
|
|
|
static void MovddupVqWq(struct Machine *m, uint32_t rde) {
|
|
uint8_t *src;
|
|
src = GetModrmRegisterXmmPointerRead8(m, rde);
|
|
memcpy(XmmRexrReg(m, rde) + 0, src, 8);
|
|
memcpy(XmmRexrReg(m, rde) + 8, src, 8);
|
|
}
|
|
|
|
static void MovsldupVqWq(struct Machine *m, uint32_t rde) {
|
|
uint8_t *dst, *src;
|
|
dst = XmmRexrReg(m, rde);
|
|
src = GetModrmRegisterXmmPointerRead16(m, rde);
|
|
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 MovlpsMqVq(struct Machine *m, uint32_t rde) {
|
|
memcpy(ComputeReserveAddressWrite8(m, rde), XmmRexrReg(m, rde), 8);
|
|
}
|
|
|
|
static void MovlpdMqVq(struct Machine *m, uint32_t rde) {
|
|
memcpy(ComputeReserveAddressWrite8(m, rde), XmmRexrReg(m, rde), 8);
|
|
}
|
|
|
|
static void MovlhpsVqUq(struct Machine *m, uint32_t rde) {
|
|
memcpy(XmmRexrReg(m, rde) + 8, XmmRexbRm(m, rde), 8);
|
|
}
|
|
|
|
static void MovhpsVqMq(struct Machine *m, uint32_t rde) {
|
|
memcpy(XmmRexrReg(m, rde) + 8, ComputeReserveAddressRead8(m, rde), 8);
|
|
}
|
|
|
|
static void MovhpdVqMq(struct Machine *m, uint32_t rde) {
|
|
memcpy(XmmRexrReg(m, rde) + 8, ComputeReserveAddressRead8(m, rde), 8);
|
|
}
|
|
|
|
static void MovshdupVqWq(struct Machine *m, uint32_t rde) {
|
|
uint8_t *dst, *src;
|
|
dst = XmmRexrReg(m, rde);
|
|
src = GetModrmRegisterXmmPointerRead16(m, rde);
|
|
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 MovhpsMqVq(struct Machine *m, uint32_t rde) {
|
|
memcpy(ComputeReserveAddressWrite8(m, rde), XmmRexrReg(m, rde) + 8, 8);
|
|
}
|
|
|
|
static void MovhpdMqVq(struct Machine *m, uint32_t rde) {
|
|
memcpy(ComputeReserveAddressWrite8(m, rde), XmmRexrReg(m, rde) + 8, 8);
|
|
}
|
|
|
|
static void MovqWqVq(struct Machine *m, uint32_t rde) {
|
|
if (IsModrmRegister(rde)) {
|
|
memcpy(XmmRexbRm(m, rde), XmmRexrReg(m, rde), 8);
|
|
memset(XmmRexbRm(m, rde) + 8, 0, 8);
|
|
} else {
|
|
memcpy(ComputeReserveAddressWrite8(m, rde), XmmRexrReg(m, rde), 8);
|
|
}
|
|
}
|
|
|
|
static void Movq2dqVdqNq(struct Machine *m, uint32_t rde) {
|
|
memcpy(XmmRexrReg(m, rde), MmRm(m, rde), 8);
|
|
memset(XmmRexrReg(m, rde) + 8, 0, 8);
|
|
}
|
|
|
|
static void Movdq2qPqUq(struct Machine *m, uint32_t rde) {
|
|
memcpy(MmReg(m, rde), XmmRexbRm(m, rde), 8);
|
|
}
|
|
|
|
static void MovapsVpsWps(struct Machine *m, uint32_t rde) {
|
|
MovdqaVdqWdq(m, rde);
|
|
}
|
|
|
|
static void MovapdVpdWpd(struct Machine *m, uint32_t rde) {
|
|
MovdqaVdqWdq(m, rde);
|
|
}
|
|
|
|
static void MovapsWpsVps(struct Machine *m, uint32_t rde) {
|
|
MovdqaWdqVdq(m, rde);
|
|
}
|
|
|
|
static void MovapdWpdVpd(struct Machine *m, uint32_t rde) {
|
|
MovdqaWdqVdq(m, rde);
|
|
}
|
|
|
|
void OpMovWpsVps(struct Machine *m, uint32_t rde) {
|
|
uint8_t *p, *r;
|
|
switch (Rep(rde) | Osz(rde)) {
|
|
case 0:
|
|
MovupsWpsVps(m, rde);
|
|
break;
|
|
case 1:
|
|
MovupdWpsVps(m, rde);
|
|
break;
|
|
case 2:
|
|
MovsdWpsVps(m, rde);
|
|
break;
|
|
case 3:
|
|
MovssWpsVps(m, rde);
|
|
break;
|
|
default:
|
|
unreachable;
|
|
}
|
|
}
|
|
|
|
void OpMov0f28(struct Machine *m, uint32_t rde) {
|
|
if (!Osz(rde)) {
|
|
MovapsVpsWps(m, rde);
|
|
} else {
|
|
MovapdVpdWpd(m, rde);
|
|
}
|
|
}
|
|
|
|
void OpMov0f6e(struct Machine *m, uint32_t rde) {
|
|
if (Osz(rde)) {
|
|
if (Rexw(rde)) {
|
|
MovqVdqEqp(m, rde);
|
|
} else {
|
|
MovdVdqEd(m, rde);
|
|
}
|
|
} else {
|
|
if (Rexw(rde)) {
|
|
MovqPqEqp(m, rde);
|
|
} else {
|
|
MovdPqEd(m, rde);
|
|
}
|
|
}
|
|
}
|
|
|
|
void OpMov0f6f(struct Machine *m, uint32_t rde) {
|
|
if (Osz(rde)) {
|
|
MovdqaVdqWdq(m, rde);
|
|
} else if (Rep(rde) == 3) {
|
|
MovdquVdqWdq(m, rde);
|
|
} else {
|
|
MovqPqQq(m, rde);
|
|
}
|
|
}
|
|
|
|
void OpMov0fE7(struct Machine *m, uint32_t rde) {
|
|
if (!Osz(rde)) {
|
|
MovntqMqPq(m, rde);
|
|
} else {
|
|
MovntdqMdqVdq(m, rde);
|
|
}
|
|
}
|
|
|
|
void OpMov0f7e(struct Machine *m, uint32_t rde) {
|
|
if (Rep(rde) == 3) {
|
|
MovqVqWq(m, rde);
|
|
} else if (Osz(rde)) {
|
|
if (Rexw(rde)) {
|
|
MovqEqpVdq(m, rde);
|
|
} else {
|
|
MovdEdVdq(m, rde);
|
|
}
|
|
} else {
|
|
if (Rexw(rde)) {
|
|
MovqEqpPq(m, rde);
|
|
} else {
|
|
MovdEdPq(m, rde);
|
|
}
|
|
}
|
|
}
|
|
|
|
void OpMov0f7f(struct Machine *m, uint32_t rde) {
|
|
if (Rep(rde) == 3) {
|
|
MovdquWdqVdq(m, rde);
|
|
} else if (Osz(rde)) {
|
|
MovdqaWdqVdq(m, rde);
|
|
} else {
|
|
MovqQqPq(m, rde);
|
|
}
|
|
}
|
|
|
|
void OpMov0f10(struct Machine *m, uint32_t rde) {
|
|
uint8_t *p, *r;
|
|
switch (Rep(rde) | Osz(rde)) {
|
|
case 0:
|
|
MovupsVpsWps(m, rde);
|
|
break;
|
|
case 1:
|
|
MovupdVpsWps(m, rde);
|
|
break;
|
|
case 2:
|
|
MovsdVpsWps(m, rde);
|
|
break;
|
|
case 3:
|
|
MovssVpsWps(m, rde);
|
|
break;
|
|
default:
|
|
unreachable;
|
|
}
|
|
}
|
|
|
|
void OpMov0f29(struct Machine *m, uint32_t rde) {
|
|
if (!Osz(rde)) {
|
|
MovapsWpsVps(m, rde);
|
|
} else {
|
|
MovapdWpdVpd(m, rde);
|
|
}
|
|
}
|
|
|
|
void OpMov0f2b(struct Machine *m, uint32_t rde) {
|
|
if (!Osz(rde)) {
|
|
MovntpsMpsVps(m, rde);
|
|
} else {
|
|
MovntpdMpdVpd(m, rde);
|
|
}
|
|
}
|
|
|
|
void OpMov0f12(struct Machine *m, uint32_t rde) {
|
|
switch (Rep(rde) | Osz(rde)) {
|
|
case 0:
|
|
if (IsModrmRegister(rde)) {
|
|
MovhlpsVqUq(m, rde);
|
|
} else {
|
|
MovlpsVqMq(m, rde);
|
|
}
|
|
break;
|
|
case 1:
|
|
MovlpdVqMq(m, rde);
|
|
break;
|
|
case 2:
|
|
MovddupVqWq(m, rde);
|
|
break;
|
|
case 3:
|
|
MovsldupVqWq(m, rde);
|
|
break;
|
|
default:
|
|
unreachable;
|
|
}
|
|
}
|
|
|
|
void OpMov0f13(struct Machine *m, uint32_t rde) {
|
|
if (Osz(rde)) {
|
|
MovlpdMqVq(m, rde);
|
|
} else {
|
|
MovlpsMqVq(m, rde);
|
|
}
|
|
}
|
|
|
|
void OpMov0f16(struct Machine *m, uint32_t rde) {
|
|
switch (Rep(rde) | Osz(rde)) {
|
|
case 0:
|
|
if (IsModrmRegister(rde)) {
|
|
MovlhpsVqUq(m, rde);
|
|
} else {
|
|
MovhpsVqMq(m, rde);
|
|
}
|
|
break;
|
|
case 1:
|
|
MovhpdVqMq(m, rde);
|
|
break;
|
|
case 3:
|
|
MovshdupVqWq(m, rde);
|
|
break;
|
|
default:
|
|
OpUd(m, rde);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void OpMov0f17(struct Machine *m, uint32_t rde) {
|
|
if (Osz(rde)) {
|
|
MovhpdMqVq(m, rde);
|
|
} else {
|
|
MovhpsMqVq(m, rde);
|
|
}
|
|
}
|
|
|
|
void OpMov0fD6(struct Machine *m, uint32_t rde) {
|
|
if (Rep(rde) == 3) {
|
|
Movq2dqVdqNq(m, rde);
|
|
} else if (Rep(rde) == 2) {
|
|
Movdq2qPqUq(m, rde);
|
|
} else if (Osz(rde)) {
|
|
MovqWqVq(m, rde);
|
|
} else {
|
|
OpUd(m, rde);
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
void OpPmovmskbGdqpNqUdq(struct Machine *m, uint32_t rde) {
|
|
uint64_t bitmask;
|
|
if (Osz(rde)) {
|
|
bitmask = pmovmskb(Read64(XmmRexbRm(m, rde) + 8)) << 8 |
|
|
pmovmskb(Read64(XmmRexbRm(m, rde)));
|
|
} else {
|
|
bitmask = pmovmskb(Read64(MmRm(m, rde) + 8)) << 8 |
|
|
pmovmskb(Read64(MmRm(m, rde)));
|
|
}
|
|
Write64(RegRexrReg(m, rde), bitmask);
|
|
}
|
|
|
|
void OpMaskMovDiXmmRegXmmRm(struct Machine *m, uint32_t rde) {
|
|
void *p[2];
|
|
uint64_t v;
|
|
unsigned i, n;
|
|
uint8_t *mem, b[16];
|
|
v = AddressDi(m, rde);
|
|
n = Osz(rde) ? 16 : 8;
|
|
mem = BeginStore(m, v, n, p, b);
|
|
for (i = 0; i < n; ++i) {
|
|
if (XmmRexbRm(m, rde)[i] & 0x80) {
|
|
mem[i] = XmmRexrReg(m, rde)[i];
|
|
}
|
|
}
|
|
EndStore(m, v, n, p, b);
|
|
}
|