520 lines
14 KiB
C
520 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/intrin/pmovmskb.h"
|
|
#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) {
|
|
if (IsModrmRegister(rde)) {
|
|
memcpy(XmmRexrReg(m, rde), XmmRexbRm(m, rde), 4);
|
|
} else {
|
|
memcpy(XmmRexrReg(m, rde), ComputeReserveAddressRead4(m, rde), 4);
|
|
memset(XmmRexrReg(m, rde) + 4, 0, 12);
|
|
}
|
|
}
|
|
|
|
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) {
|
|
if (IsModrmRegister(rde)) {
|
|
memcpy(XmmRexrReg(m, rde), XmmRexbRm(m, rde), 8);
|
|
} else {
|
|
memcpy(XmmRexrReg(m, rde), ComputeReserveAddressRead8(m, rde), 8);
|
|
memset(XmmRexrReg(m, rde) + 8, 0, 8);
|
|
}
|
|
}
|
|
|
|
static void MovsdWpsVps(struct Machine *m, uint32_t rde) {
|
|
memcpy(GetModrmRegisterXmmPointerWrite8(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);
|
|
}
|
|
}
|
|
|
|
void OpPmovmskbGdqpNqUdq(struct Machine *m, uint32_t rde) {
|
|
Write64(RegRexrReg(m, rde),
|
|
pmovmskb(XmmRexbRm(m, rde)) & (Osz(rde) ? 0xffff : 0xff));
|
|
}
|
|
|
|
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);
|
|
}
|