mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
parent
50d8d953ce
commit
06b749ae03
130 changed files with 2 additions and 26665 deletions
|
@ -1,139 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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 "tool/build/lib/alu.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "test/tool/build/lib/optest.h"
|
||||
#include "tool/build/lib/case.h"
|
||||
#include "tool/build/lib/flags.h"
|
||||
#ifdef __x86_64__
|
||||
|
||||
#define ALU_TEST 8
|
||||
|
||||
#define NATIVE_ALU2(MODE, INSTRUCTION) \
|
||||
do { \
|
||||
intptr_t flags; \
|
||||
asm("pushf\n\t" \
|
||||
"andl\t%3,(%%rsp)\n\t" \
|
||||
"orl\t%4,(%%rsp)\n\t" \
|
||||
"popf\n\t" INSTRUCTION "\t%" MODE "2,%" MODE "0\n\t" \
|
||||
"pushf\n\t" \
|
||||
"pop\t%q1" \
|
||||
: "+r"(x), "=rm"(flags) \
|
||||
: "r"(y), "i"(~FMASK), "r"(*f & FMASK) \
|
||||
: "cc"); \
|
||||
*f = flags; \
|
||||
} while (0)
|
||||
|
||||
#define NATIVE_ALU2_ANYBITS(INSTRUCTION, MUTATING) \
|
||||
switch (w) { \
|
||||
case 0: \
|
||||
NATIVE_ALU2("b", INSTRUCTION); \
|
||||
if (MUTATING) x &= 0xff; \
|
||||
return x; \
|
||||
case 1: \
|
||||
NATIVE_ALU2("w", INSTRUCTION); \
|
||||
if (MUTATING) x &= 0xffff; \
|
||||
return x; \
|
||||
case 2: \
|
||||
NATIVE_ALU2("k", INSTRUCTION); \
|
||||
return x; \
|
||||
case 3: \
|
||||
NATIVE_ALU2("q", INSTRUCTION); \
|
||||
return x; \
|
||||
default: \
|
||||
abort(); \
|
||||
}
|
||||
|
||||
int64_t RunGolden(char w, int h, uint64_t x, uint64_t y, uint32_t *f) {
|
||||
bool rw;
|
||||
rw = !(h & ALU_TEST);
|
||||
switch (h & 7) {
|
||||
case ALU_OR:
|
||||
NATIVE_ALU2_ANYBITS("or", rw);
|
||||
case ALU_AND:
|
||||
if (rw) {
|
||||
NATIVE_ALU2_ANYBITS("and", rw);
|
||||
} else {
|
||||
NATIVE_ALU2_ANYBITS("test", rw);
|
||||
}
|
||||
case ALU_XOR:
|
||||
NATIVE_ALU2_ANYBITS("xor", rw);
|
||||
case ALU_SBB:
|
||||
NATIVE_ALU2_ANYBITS("sbb", rw);
|
||||
case ALU_CMP:
|
||||
rw = false;
|
||||
NATIVE_ALU2_ANYBITS("cmp", rw);
|
||||
case ALU_SUB:
|
||||
NATIVE_ALU2_ANYBITS("sub", rw);
|
||||
case ALU_ADC:
|
||||
NATIVE_ALU2_ANYBITS("adc", rw);
|
||||
case ALU_ADD:
|
||||
NATIVE_ALU2_ANYBITS("add", rw);
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t kAluOps[] = {
|
||||
ALU_ADD, //
|
||||
ALU_OR, //
|
||||
ALU_ADC, //
|
||||
ALU_SBB, //
|
||||
ALU_AND, //
|
||||
ALU_SUB, //
|
||||
ALU_XOR, //
|
||||
ALU_CMP, //
|
||||
ALU_AND | ALU_TEST, //
|
||||
};
|
||||
|
||||
const char *const kAluNames[] = {
|
||||
[ALU_ADD] = "add", //
|
||||
[ALU_OR] = "or", //
|
||||
[ALU_ADC] = "adc", //
|
||||
[ALU_SBB] = "sbb", //
|
||||
[ALU_AND] = "and", //
|
||||
[ALU_SUB] = "sub", //
|
||||
[ALU_XOR] = "xor", //
|
||||
[ALU_CMP] = "cmp", //
|
||||
[ALU_AND | ALU_TEST] = "test", //
|
||||
};
|
||||
|
||||
int64_t Alu(int w, int h, uint64_t x, uint64_t y, uint32_t *flags) {
|
||||
if (h < ALU_CMP) {
|
||||
return kAlu[h][w](x, y, flags);
|
||||
} else {
|
||||
kAlu[h & 7][w](x, y, flags);
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t RunOpTest(char w, int h, uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return Alu(w, h, x, y, f);
|
||||
}
|
||||
|
||||
TEST(alu, test) {
|
||||
RunOpTests(kAluOps, ARRAYLEN(kAluOps), kAluNames);
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
|
@ -1,108 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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 "tool/build/lib/bitscan.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "test/tool/build/lib/numbers.h"
|
||||
#include "tool/build/lib/flags.h"
|
||||
#ifdef __x86_64__
|
||||
|
||||
#define OSZ 00000000040
|
||||
#define REXW 00000000100
|
||||
|
||||
struct Machine m[1];
|
||||
struct XedDecodedInst xedd[1];
|
||||
|
||||
void SetUp(void) {
|
||||
m->xedd = xedd;
|
||||
}
|
||||
|
||||
TEST(bsr64, test) {
|
||||
bool zf;
|
||||
uint64_t i, w, x, a, b;
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
x = kNumbers[i];
|
||||
a = AluBsr(m, REXW, x);
|
||||
asm("bsrq\t%2,%0" : "=r"(b), "=@ccz"(zf) : "r"(x));
|
||||
ASSERT_EQ(zf, GetFlag(m->flags, FLAGS_ZF));
|
||||
if (!zf) ASSERT_EQ(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(bsr32, test) {
|
||||
bool zf;
|
||||
uint32_t i, w, x, a, b;
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
x = kNumbers[i];
|
||||
a = AluBsr(m, 0, x);
|
||||
asm("bsrl\t%2,%0" : "=r"(b), "=@ccz"(zf) : "r"(x));
|
||||
ASSERT_EQ(zf, GetFlag(m->flags, FLAGS_ZF));
|
||||
if (!zf) ASSERT_EQ(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(bsr16, test) {
|
||||
bool zf;
|
||||
uint16_t i, w, x, a, b;
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
x = kNumbers[i];
|
||||
a = AluBsr(m, OSZ, x);
|
||||
asm("bsrw\t%2,%0" : "=r"(b), "=@ccz"(zf) : "r"(x));
|
||||
ASSERT_EQ(zf, GetFlag(m->flags, FLAGS_ZF));
|
||||
if (!zf) ASSERT_EQ(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(bsf64, test) {
|
||||
bool zf;
|
||||
uint64_t i, w, x, a, b;
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
x = kNumbers[i];
|
||||
a = AluBsf(m, REXW, x);
|
||||
asm("bsfq\t%2,%0" : "=r"(b), "=@ccz"(zf) : "r"(x));
|
||||
ASSERT_EQ(zf, GetFlag(m->flags, FLAGS_ZF));
|
||||
if (!zf) ASSERT_EQ(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(bsf32, test) {
|
||||
bool zf;
|
||||
uint32_t i, w, x, a, b;
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
x = kNumbers[i];
|
||||
a = AluBsf(m, 0, x);
|
||||
asm("bsfl\t%2,%0" : "=r"(b), "=@ccz"(zf) : "r"(x));
|
||||
ASSERT_EQ(zf, GetFlag(m->flags, FLAGS_ZF));
|
||||
if (!zf) ASSERT_EQ(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(bsf16, test) {
|
||||
bool zf;
|
||||
uint16_t i, w, x, a, b;
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
x = kNumbers[i];
|
||||
a = AluBsf(m, OSZ, x);
|
||||
asm("bsfw\t%2,%0" : "=r"(b), "=@ccz"(zf) : "r"(x));
|
||||
ASSERT_EQ(zf, GetFlag(m->flags, FLAGS_ZF));
|
||||
if (!zf) ASSERT_EQ(a, b, "%#lx", x);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
|
@ -1,329 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "test/tool/build/lib/numbers.h"
|
||||
#include "test/tool/build/lib/optest.h"
|
||||
#include "tool/build/lib/alu.h"
|
||||
#include "tool/build/lib/flags.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#ifdef __x86_64__
|
||||
|
||||
#define NATIVE_ALU2(MODE, INSTRUCTION) \
|
||||
asm("pushf\n\t" \
|
||||
"andl\t%3,(%%rsp)\n\t" \
|
||||
"orl\t%4,(%%rsp)\n\t" \
|
||||
"popf\n\t" INSTRUCTION "\t%b2,%" MODE "0\n\t" \
|
||||
"pushf\n\t" \
|
||||
"pop\t%q1" \
|
||||
: "+r"(x), "=r"(*f) \
|
||||
: "c"(y), "i"(~FMASK), "r"(*f & FMASK) \
|
||||
: "cc")
|
||||
|
||||
#define NATIVE_ALU2_ANYBITS(INSTRUCTION, MUTATING) \
|
||||
switch (w) { \
|
||||
case 0: \
|
||||
NATIVE_ALU2("b", INSTRUCTION); \
|
||||
if (MUTATING) x &= 0xff; \
|
||||
return x; \
|
||||
case 1: \
|
||||
NATIVE_ALU2("w", INSTRUCTION); \
|
||||
if (MUTATING) x &= 0xffff; \
|
||||
return x; \
|
||||
case 2: \
|
||||
NATIVE_ALU2("k", INSTRUCTION); \
|
||||
return x; \
|
||||
case 3: \
|
||||
NATIVE_ALU2("q", INSTRUCTION); \
|
||||
return x; \
|
||||
default: \
|
||||
abort(); \
|
||||
}
|
||||
|
||||
int64_t Bsu(int w, int h, uint64_t x, uint64_t y, uint32_t *f) {
|
||||
switch (h & 7) {
|
||||
case BSU_SHR:
|
||||
switch (w) {
|
||||
case 0:
|
||||
return Shr8(x, y, f);
|
||||
case 1:
|
||||
return Shr16(x, y, f);
|
||||
case 2:
|
||||
return Shr32(x, y, f);
|
||||
case 3:
|
||||
return Shr64(x, y, f);
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
case BSU_SAL:
|
||||
case BSU_SHL:
|
||||
switch (w) {
|
||||
case 0:
|
||||
return Shl8(x, y, f);
|
||||
case 1:
|
||||
return Shl16(x, y, f);
|
||||
case 2:
|
||||
return Shl32(x, y, f);
|
||||
case 3:
|
||||
return Shl64(x, y, f);
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
case BSU_SAR:
|
||||
switch (w) {
|
||||
case 0:
|
||||
return Sar8(x, y, f);
|
||||
case 1:
|
||||
return Sar16(x, y, f);
|
||||
case 2:
|
||||
return Sar32(x, y, f);
|
||||
case 3:
|
||||
return Sar64(x, y, f);
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
case BSU_ROL:
|
||||
switch (w) {
|
||||
case 0:
|
||||
return Rol8(x, y, f);
|
||||
case 1:
|
||||
return Rol16(x, y, f);
|
||||
case 2:
|
||||
return Rol32(x, y, f);
|
||||
case 3:
|
||||
return Rol64(x, y, f);
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
case BSU_ROR:
|
||||
switch (w) {
|
||||
case 0:
|
||||
return Ror8(x, y, f);
|
||||
case 1:
|
||||
return Ror16(x, y, f);
|
||||
case 2:
|
||||
return Ror32(x, y, f);
|
||||
case 3:
|
||||
return Ror64(x, y, f);
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
case BSU_RCR:
|
||||
switch (w) {
|
||||
case 0:
|
||||
return Rcr8(x, y, f);
|
||||
case 1:
|
||||
return Rcr16(x, y, f);
|
||||
case 2:
|
||||
return Rcr32(x, y, f);
|
||||
case 3:
|
||||
return Rcr64(x, y, f);
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
case BSU_RCL:
|
||||
switch (w) {
|
||||
case 0:
|
||||
return Rcl8(x, y, f);
|
||||
case 1:
|
||||
return Rcl16(x, y, f);
|
||||
case 2:
|
||||
return Rcl32(x, y, f);
|
||||
case 3:
|
||||
return Rcl64(x, y, f);
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
int64_t RunGolden(char w, int h, uint64_t x, uint64_t y, uint32_t *f) {
|
||||
switch (h & 7) {
|
||||
case BSU_ROR:
|
||||
NATIVE_ALU2_ANYBITS("ror", true);
|
||||
case BSU_SHL:
|
||||
NATIVE_ALU2_ANYBITS("shl", true);
|
||||
case BSU_SAL:
|
||||
NATIVE_ALU2_ANYBITS("sal", true);
|
||||
case BSU_RCR:
|
||||
NATIVE_ALU2_ANYBITS("rcr", true);
|
||||
case BSU_SAR:
|
||||
NATIVE_ALU2_ANYBITS("sar", true);
|
||||
case BSU_SHR:
|
||||
NATIVE_ALU2_ANYBITS("shr", true);
|
||||
case BSU_RCL:
|
||||
NATIVE_ALU2_ANYBITS("rcl", true);
|
||||
case BSU_ROL:
|
||||
NATIVE_ALU2_ANYBITS("rol", true);
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t kBsuOps[] = {
|
||||
BSU_SHR, BSU_SHL, BSU_ROL, BSU_ROR, BSU_RCL,
|
||||
BSU_RCR, BSU_SHL, BSU_SAL, BSU_SAR,
|
||||
};
|
||||
|
||||
const char *const kBsuNames[] = {
|
||||
[BSU_ROL] = "rol", [BSU_ROR] = "ror", [BSU_RCL] = "rcl", [BSU_RCR] = "rcr",
|
||||
[BSU_SHL] = "shl", [BSU_SHR] = "shr", [BSU_SAL] = "sal", [BSU_SAR] = "sar",
|
||||
};
|
||||
|
||||
int64_t RunOpTest(char w, int h, uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return Bsu(w, h, x, y, f);
|
||||
}
|
||||
|
||||
void FixupUndefOpTestFlags(char w, int h, uint64_t x, uint64_t y,
|
||||
uint32_t goldenflags, uint32_t *flags) {
|
||||
y &= w == 3 ? 0x3F : 0x1F;
|
||||
if (y != 0 && y != 1) {
|
||||
*flags = SetFlag(*flags, FLAGS_OF, GetFlag(goldenflags, FLAGS_OF));
|
||||
}
|
||||
if (y >= w) {
|
||||
*flags = SetFlag(*flags, FLAGS_CF, GetFlag(goldenflags, FLAGS_CF));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(bsu, test) {
|
||||
RunOpTests(kBsuOps, ARRAYLEN(kBsuOps), kBsuNames);
|
||||
}
|
||||
|
||||
TEST(shrd32, smoke) {
|
||||
int i, j, k;
|
||||
uint8_t b, cf, of;
|
||||
uint32_t x, y, z1, f, z2, unflag;
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
x = kNumbers[i];
|
||||
for (j = 0; j < ARRAYLEN(kNumbers); ++j) {
|
||||
y = kNumbers[j];
|
||||
for (k = 0; k < ARRAYLEN(kNumbers); ++k) {
|
||||
f = 0;
|
||||
cf = 0;
|
||||
of = 0;
|
||||
b = kNumbers[k];
|
||||
z1 = BsuDoubleShift(2, x, y, b, true, &f);
|
||||
z2 = x;
|
||||
asm("xor\t%1,%1\n\t"
|
||||
"shrd\t%5,%4,%0"
|
||||
: "+rm"(z2), "=&r"(unflag), "=@ccc"(cf), "=@cco"(of)
|
||||
: "r"(y), "c"(b)
|
||||
: "cc");
|
||||
ASSERT_EQ(z2, z1);
|
||||
ASSERT_EQ(cf, GetFlag(f, FLAGS_CF));
|
||||
if (b <= 1) ASSERT_EQ(of, GetFlag(f, FLAGS_OF));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(shld16, smoke) {
|
||||
uint32_t f;
|
||||
int i, j, k;
|
||||
uint8_t b, cf, of;
|
||||
uint16_t x, y, z1, z2, unflag;
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
x = kNumbers[i];
|
||||
for (j = 0; j < ARRAYLEN(kNumbers); ++j) {
|
||||
y = kNumbers[j];
|
||||
for (k = 0; k < ARRAYLEN(kNumbers); ++k) {
|
||||
f = 0;
|
||||
cf = 0;
|
||||
of = 0;
|
||||
b = kNumbers[k];
|
||||
if (b > 16) continue;
|
||||
z1 = BsuDoubleShift(1, x, y, b, false, &f);
|
||||
z2 = x;
|
||||
asm("xor\t%1,%1\n\t"
|
||||
"shldw\t%5,%4,%0"
|
||||
: "+rm"(z2), "=&r"(unflag), "=@ccc"(cf), "=@cco"(of)
|
||||
: "r"(y), "c"(b)
|
||||
: "cc");
|
||||
ASSERT_EQ(z2, z1);
|
||||
ASSERT_EQ(cf, GetFlag(f, FLAGS_CF));
|
||||
if (b <= 1) ASSERT_EQ(of, GetFlag(f, FLAGS_OF));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(shld32, smoke) {
|
||||
int i, j, k;
|
||||
uint8_t b, cf, of;
|
||||
uint32_t x, y, z1, f, z2, unflag;
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
x = kNumbers[i];
|
||||
for (j = 0; j < ARRAYLEN(kNumbers); ++j) {
|
||||
y = kNumbers[j];
|
||||
for (k = 0; k < ARRAYLEN(kNumbers); ++k) {
|
||||
f = 0;
|
||||
cf = 0;
|
||||
of = 0;
|
||||
b = kNumbers[k];
|
||||
if (b > 32) continue;
|
||||
z1 = BsuDoubleShift(2, x, y, b, false, &f);
|
||||
z2 = x;
|
||||
asm("xor\t%1,%1\n\t"
|
||||
"shld\t%5,%4,%0"
|
||||
: "+rm"(z2), "=&r"(unflag), "=@ccc"(cf), "=@cco"(of)
|
||||
: "r"(y), "c"(b)
|
||||
: "cc");
|
||||
ASSERT_EQ(z2, z1);
|
||||
ASSERT_EQ(cf, GetFlag(f, FLAGS_CF));
|
||||
if (b <= 1) ASSERT_EQ(of, GetFlag(f, FLAGS_OF));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(shld64, smoke) {
|
||||
uint32_t f;
|
||||
int i, j, k;
|
||||
uint8_t b, cf, of;
|
||||
uint64_t x, y, z1, z2, unflag;
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
x = kNumbers[i];
|
||||
for (j = 0; j < ARRAYLEN(kNumbers); ++j) {
|
||||
y = kNumbers[j];
|
||||
for (k = 0; k < ARRAYLEN(kNumbers); ++k) {
|
||||
f = 0;
|
||||
cf = 0;
|
||||
of = 0;
|
||||
b = kNumbers[k];
|
||||
if (b > 64) continue;
|
||||
z1 = BsuDoubleShift(3, x, y, b, false, &f);
|
||||
z2 = x;
|
||||
asm("xor\t%1,%1\n\t"
|
||||
"shldq\t%5,%4,%0"
|
||||
: "+rm"(z2), "=&r"(unflag), "=@ccc"(cf), "=@cco"(of)
|
||||
: "r"(y), "c"(b)
|
||||
: "cc");
|
||||
ASSERT_EQ(z2, z1);
|
||||
ASSERT_EQ(cf, GetFlag(f, FLAGS_CF));
|
||||
if (b <= 1) ASSERT_EQ(of, GetFlag(f, FLAGS_OF));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
|
@ -1,263 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/stdio/lcg.internal.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "tool/build/lib/dis.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
|
||||
char b1[64];
|
||||
char b2[64];
|
||||
struct Dis d[1];
|
||||
|
||||
#define ILD(OP, MODE) \
|
||||
do { \
|
||||
xed_decoded_inst_zero_set_mode(d->xedd, MODE); \
|
||||
ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, OP, sizeof(OP))); \
|
||||
d->xedd->op.rde = EncodeRde(d->xedd); \
|
||||
} while (0)
|
||||
|
||||
TEST(DisInst, testInt3) {
|
||||
uint8_t op[] = {0xcc};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("int3 ", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testImmMem_needsSuffix) {
|
||||
uint8_t op[] = {0x80, 0x3c, 0x07, 0x00};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("cmpb $0,(%rdi,%rax)", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testImmReg_doesntNeedSuffix) {
|
||||
uint8_t op[] = {0xb8, 0x08, 0x70, 0x40, 0x00};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("mov $0x407008,%eax", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testPuttingOnTheRiz) {
|
||||
static uint8_t ops[][15] = {
|
||||
{0x8d, 0b00110100, 0b00100110},
|
||||
{0x67, 0x8d, 0b00110100, 0b11100110},
|
||||
{0x67, 0x8d, 0b10110100, 0b11100101, 0, 0, 0, 0},
|
||||
{0x8d, 0b00110100, 0b11100101, 0x37, 0x13, 0x03, 0},
|
||||
{0x8d, 0b10110100, 0b11100101, 0, 0, 0, 0},
|
||||
};
|
||||
ILD(ops[0], XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("lea (%rsi),%esi", b1);
|
||||
ILD(ops[1], XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("lea (%esi,%eiz,8),%esi", b1);
|
||||
ILD(ops[2], XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("lea 0(%ebp,%eiz,8),%esi", b1);
|
||||
ILD(ops[3], XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("lea 0x31337,%esi", b1);
|
||||
ILD(ops[4], XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("lea 0(%rbp,%riz,8),%esi", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testSibIndexOnly) {
|
||||
uint8_t op[] = {76, 141, 4, 141, 0, 0, 0, 0};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("lea 0(,%rcx,4),%r8", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testRealMode) {
|
||||
uint8_t op[] = {0x89, 0xe5};
|
||||
ILD(op, XED_MACHINE_MODE_REAL);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("mov %sp,%bp", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testNop) {
|
||||
uint8_t op[] = {0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("nopw %cs:0(%rax,%rax)", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testPush) {
|
||||
uint8_t op[] = {0x41, 0x5c};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
EXPECT_EQ(4, ModrmSrm(d->xedd->op.rde));
|
||||
EXPECT_EQ(1, Rexb(d->xedd->op.rde));
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("pop %r12", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testMovb) {
|
||||
uint8_t op[] = {0x8a, 0x1e, 0x0c, 0x32};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("mov (%rsi),%bl", b1);
|
||||
ILD(op, XED_MACHINE_MODE_REAL);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("mov 0x320c,%bl", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testLes) {
|
||||
uint8_t op[] = {0xc4, 0x3e, 0x16, 0x32};
|
||||
ILD(op, XED_MACHINE_MODE_REAL);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("les 0x3216,%di", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testStosbLong) {
|
||||
uint8_t op[] = {0xAA};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("stosb %al,(%rdi)", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testStosbReal) {
|
||||
uint8_t op[] = {0xAA};
|
||||
ILD(op, XED_MACHINE_MODE_REAL);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("stosb %al,(%di)", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testStosbLegacy) {
|
||||
uint8_t op[] = {0xAA};
|
||||
ILD(op, XED_MACHINE_MODE_LEGACY_32);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("stosb %al,(%edi)", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testStosbLongAsz) {
|
||||
uint8_t op[] = {0x67, 0xAA};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("stosb %al,(%edi)", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testAddLong) {
|
||||
uint8_t op[] = {0x01, 0xff};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("add %edi,%edi", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testAddLegacy) {
|
||||
uint8_t op[] = {0x01, 0xff};
|
||||
ILD(op, XED_MACHINE_MODE_LEGACY_32);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("add %edi,%edi", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testAddReal) {
|
||||
uint8_t op[] = {0x01, 0xff};
|
||||
ILD(op, XED_MACHINE_MODE_REAL);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("add %di,%di", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testAddLongOsz) {
|
||||
uint8_t op[] = {0x66, 0x01, 0xff};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("add %di,%di", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testAddLegacyOsz) {
|
||||
uint8_t op[] = {0x66, 0x01, 0xff};
|
||||
ILD(op, XED_MACHINE_MODE_LEGACY_32);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("add %di,%di", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testAddRealOsz) {
|
||||
uint8_t op[] = {0x66, 0x01, 0xff};
|
||||
ILD(op, XED_MACHINE_MODE_REAL);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("add %edi,%edi", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testFxam) {
|
||||
uint8_t op[] = {0xd9, 0xe5};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
ASSERT_EQ(4, ModrmReg(d->xedd->op.rde));
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("fxam ", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testOrImmCode16gcc) {
|
||||
uint8_t op[] = {0x67, 0x81, 0x4c, 0x24, 0x0c, 0x00, 0x0c};
|
||||
ILD(op, XED_MACHINE_MODE_REAL);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("orw $0xc00,12(%esp)", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testPause) {
|
||||
uint8_t op[] = {0xf3, 0x90};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("pause ", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testJmpEw) {
|
||||
uint8_t op[] = {0xff, 0xe0};
|
||||
ILD(op, XED_MACHINE_MODE_REAL);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("jmp %ax", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testJmpEv16) {
|
||||
uint8_t op[] = {0x66, 0xff, 0xe0};
|
||||
ILD(op, XED_MACHINE_MODE_REAL);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("jmp %eax", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testJmpEv32) {
|
||||
uint8_t op[] = {0xff, 0xe0};
|
||||
ILD(op, XED_MACHINE_MODE_LEGACY_32);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("jmp %eax", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testJmpEq) {
|
||||
uint8_t op[] = {0x66, 0xff, 0xe0};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("jmp %rax", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testMovswSs) {
|
||||
uint8_t op[] = {0x36, 0xA5};
|
||||
ILD(op, XED_MACHINE_MODE_REAL);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("movs %ss:(%si),(%di)", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testRealModrm_sibOverlap_showsNoDisplacement) {
|
||||
uint8_t op[] = {0x8b, 0b00100101};
|
||||
ILD(op, XED_MACHINE_MODE_REAL);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("mov (%di),%sp", b1);
|
||||
}
|
|
@ -1,556 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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 "tool/build/lib/divmul.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/xsigaction.h"
|
||||
#include "third_party/xed/x86.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/flags.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#ifdef __x86_64__
|
||||
|
||||
#define CX 1
|
||||
#define OSZ 00000000040
|
||||
#define REXW 00000000100
|
||||
#define RM(x) (0000001600 & ((x) << 007))
|
||||
#define MOD(x) (0060000000 & ((x) << 026))
|
||||
|
||||
jmp_buf sigfpejmp;
|
||||
struct Machine m[1];
|
||||
struct sigaction oldsigfpe[1];
|
||||
struct XedDecodedInst xedd[1];
|
||||
|
||||
void OnSigFpe(void) {
|
||||
/* ProTip: gdb -ex 'handle SIGFPE nostop noprint pass' */
|
||||
longjmp(sigfpejmp, 1);
|
||||
}
|
||||
|
||||
void SetUp(void) {
|
||||
m->xedd = xedd;
|
||||
ASSERT_NE(-1, xsigaction(SIGFPE, OnSigFpe, SA_NODEFER, 0, oldsigfpe));
|
||||
}
|
||||
|
||||
void TearDown(void) {
|
||||
m->xedd = xedd;
|
||||
ASSERT_NE(-1, sigaction(SIGFPE, oldsigfpe, NULL));
|
||||
}
|
||||
|
||||
TEST(imul8, test) {
|
||||
static const uint8_t A[] = {0x00, 0x01, 0x80, 0x7F, 0x81, 0x7E, 0xFF, 0xBF};
|
||||
int i, j;
|
||||
int16_t ax;
|
||||
bool cf, of;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
Write8(m->ax, A[i]);
|
||||
Write8(m->cx, A[j]);
|
||||
OpMulAxAlEbSigned(m, MOD(3) | RM(CX));
|
||||
asm volatile("imulb\t%3"
|
||||
: "=a"(ax), "=@ccc"(cf), "=@cco"(of)
|
||||
: "q"(A[j]), "0"(A[i])
|
||||
: "cc");
|
||||
EXPECT_EQ(ax, (int16_t)Read16(m->ax));
|
||||
EXPECT_EQ(cf, GetFlag(m->flags, FLAGS_CF));
|
||||
EXPECT_EQ(of, GetFlag(m->flags, FLAGS_OF));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(imul16, test) {
|
||||
static const uint16_t A[] = {0x0000, 0x0001, 0x8000, 0x7FFF, 0x8001, 0x7FFE,
|
||||
0xFFFF, 0xBeef, 0x00b5, 0x00b6, 0xb504, 0xb505};
|
||||
int i, j;
|
||||
bool cf, of;
|
||||
uint16_t dx, ax;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
Write16(m->ax, A[i]);
|
||||
Write16(m->cx, A[j]);
|
||||
OpMulRdxRaxEvqpSigned(m, OSZ | MOD(3) | RM(CX));
|
||||
asm("imulw\t%4"
|
||||
: "=d"(dx), "=a"(ax), "=@ccc"(cf), "=@cco"(of)
|
||||
: "r"(A[j]), "1"(A[i])
|
||||
: "cc");
|
||||
EXPECT_EQ((int32_t)((uint32_t)dx << 16 | ax),
|
||||
(int32_t)((uint32_t)Read16(m->dx) << 16 | Read16(m->ax)));
|
||||
EXPECT_EQ(cf, GetFlag(m->flags, FLAGS_CF));
|
||||
EXPECT_EQ(of, GetFlag(m->flags, FLAGS_OF));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(imul32, test) {
|
||||
static const uint32_t A[] = {0x00000000, 0x00000001, 0x80000000, 0x7FFFFFFF,
|
||||
0x80000001, 0x7FFFFFFE, 0xFFFFFFFF, 0xDeadBeef,
|
||||
0x000000b6, 0x0000b504, 0x0000b505, 0xb504f334};
|
||||
int i, j;
|
||||
bool cf, of;
|
||||
uint32_t dx, ax;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
Write32(m->ax, A[i]);
|
||||
Write32(m->cx, A[j]);
|
||||
OpMulRdxRaxEvqpSigned(m, MOD(3) | RM(CX));
|
||||
asm("imull\t%4"
|
||||
: "=d"(dx), "=a"(ax), "=@ccc"(cf), "=@cco"(of)
|
||||
: "r"(A[j]), "1"(A[i])
|
||||
: "cc");
|
||||
EXPECT_EQ((int64_t)((uint64_t)dx << 32 | ax),
|
||||
(int64_t)((uint64_t)Read32(m->dx) << 32 | Read32(m->ax)));
|
||||
EXPECT_EQ(cf, GetFlag(m->flags, FLAGS_CF));
|
||||
EXPECT_EQ(of, GetFlag(m->flags, FLAGS_OF));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(imul64, test) {
|
||||
static const uint64_t A[] = {0x00000000, 0x00000001, 0x80000000, 0x7FFFFFFF,
|
||||
0x80000001, 0x7FFFFFFE, 0xFFFFFFFF, 0xDeadBeef,
|
||||
0x000000b6, 0x0000b504, 0x0000b505, 0xb504f334};
|
||||
int i, j;
|
||||
bool cf, of;
|
||||
uint64_t dx, ax;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
Write64(m->ax, A[i]);
|
||||
Write64(m->cx, A[j]);
|
||||
OpMulRdxRaxEvqpSigned(m, REXW | MOD(3) | RM(CX));
|
||||
asm("imulq\t%4"
|
||||
: "=d"(dx), "=a"(ax), "=@ccc"(cf), "=@cco"(of)
|
||||
: "r"(A[j]), "1"(A[i])
|
||||
: "cc");
|
||||
EXPECT_EQ((int128_t)((uint128_t)dx << 64 | ax),
|
||||
(int128_t)((uint128_t)Read64(m->dx) << 64 | Read64(m->ax)));
|
||||
EXPECT_EQ(cf, GetFlag(m->flags, FLAGS_CF));
|
||||
EXPECT_EQ(of, GetFlag(m->flags, FLAGS_OF));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(mul8, test) {
|
||||
static const uint8_t A[] = {0x00, 0x01, 0x80, 0x7F, 0x81, 0x7E, 0xFF, 0xb6};
|
||||
int i, j;
|
||||
uint16_t ax;
|
||||
bool cf, of;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
Write8(m->ax, A[i]);
|
||||
Write8(m->cx, A[j]);
|
||||
OpMulAxAlEbUnsigned(m, MOD(3) | RM(CX));
|
||||
asm volatile("mulb\t%3"
|
||||
: "=a"(ax), "=@ccc"(cf), "=@cco"(of)
|
||||
: "q"(A[j]), "0"(A[i])
|
||||
: "cc");
|
||||
EXPECT_EQ(ax, Read16(m->ax));
|
||||
EXPECT_EQ(cf, GetFlag(m->flags, FLAGS_CF));
|
||||
EXPECT_EQ(of, GetFlag(m->flags, FLAGS_OF));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(mul16, test) {
|
||||
static const uint16_t A[] = {0x0000, 0x0001, 0x8000, 0x7FFF,
|
||||
0x8001, 0x7FFE, 0xFFFF, 0x00b6};
|
||||
int i, j;
|
||||
bool cf, of;
|
||||
uint16_t dx, ax;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
Write16(m->ax, A[i]);
|
||||
Write16(m->cx, A[j]);
|
||||
OpMulRdxRaxEvqpUnsigned(m, OSZ | MOD(3) | RM(CX));
|
||||
asm("mulw\t%4"
|
||||
: "=d"(dx), "=a"(ax), "=@ccc"(cf), "=@cco"(of)
|
||||
: "r"(A[j]), "1"(A[i])
|
||||
: "cc");
|
||||
EXPECT_EQ((uint32_t)((uint32_t)dx << 16 | ax),
|
||||
(uint32_t)((uint32_t)Read16(m->dx) << 16 | Read16(m->ax)));
|
||||
EXPECT_EQ(cf, GetFlag(m->flags, FLAGS_CF));
|
||||
EXPECT_EQ(of, GetFlag(m->flags, FLAGS_OF));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(mul32, test) {
|
||||
static const uint32_t A[] = {0x00000000, 0x00000001, 0x80000000, 0x7FFFFFFF,
|
||||
0x80000001, 0x7FFFFFFE, 0xFFFFFFFF, 0x000000b5,
|
||||
0x000000b6, 0x0000b504, 0x0000b505, 0xb504f334};
|
||||
int i, j;
|
||||
bool cf, of;
|
||||
uint32_t dx, ax;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
Write32(m->ax, A[i]);
|
||||
Write32(m->cx, A[j]);
|
||||
OpMulRdxRaxEvqpUnsigned(m, MOD(3) | RM(CX));
|
||||
asm("mull\t%4"
|
||||
: "=d"(dx), "=a"(ax), "=@ccc"(cf), "=@cco"(of)
|
||||
: "r"(A[j]), "1"(A[i])
|
||||
: "cc");
|
||||
EXPECT_EQ((uint64_t)((uint64_t)dx << 32 | ax),
|
||||
(uint64_t)((uint64_t)Read32(m->dx) << 32 | Read32(m->ax)));
|
||||
EXPECT_EQ(cf, GetFlag(m->flags, FLAGS_CF));
|
||||
EXPECT_EQ(of, GetFlag(m->flags, FLAGS_OF));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(mul64, test) {
|
||||
static const uint64_t A[] = {0x00000000, 0x00000001, 0x80000000, 0x7FFFFFFF,
|
||||
0x80000001, 0x7FFFFFFE, 0xFFFFFFFF, 0x000000b6,
|
||||
0x0000b504, 0x0000b505, 0xb504f333, 0xb504f334};
|
||||
int i, j;
|
||||
bool cf, of;
|
||||
uint64_t dx, ax;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
Write64(m->ax, A[i]);
|
||||
Write64(m->cx, A[j]);
|
||||
OpMulRdxRaxEvqpUnsigned(m, REXW | MOD(3) | RM(CX));
|
||||
asm("mulq\t%4"
|
||||
: "=d"(dx), "=a"(ax), "=@ccc"(cf), "=@cco"(of)
|
||||
: "r"(A[j]), "1"(A[i])
|
||||
: "cc");
|
||||
EXPECT_EQ((uint128_t)((uint128_t)dx << 64 | ax),
|
||||
(uint128_t)((uint128_t)Read64(m->dx) << 64 | Read64(m->ax)));
|
||||
EXPECT_EQ(cf, GetFlag(m->flags, FLAGS_CF));
|
||||
EXPECT_EQ(of, GetFlag(m->flags, FLAGS_OF));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(idiv8, test) {
|
||||
if (IsWindows()) return; /* TODO */
|
||||
static const uint8_t A[] = {0x00, 0x01, 0x80, 0x7F, 0x81, 0x7E, 0xFF, 0xBF};
|
||||
uint16_t remquo;
|
||||
bool gotthrow, gotsigfpe;
|
||||
int8_t i, j, k, w, x, a, b;
|
||||
int8_t quotient, remainder;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
for (k = 0; k < ARRAYLEN(A); ++k) {
|
||||
m->ax[1] = A[i];
|
||||
m->ax[0] = A[j];
|
||||
m->cx[0] = A[k];
|
||||
gotthrow = false;
|
||||
gotsigfpe = false;
|
||||
if (!setjmp(m->onhalt)) {
|
||||
OpDivAlAhAxEbSigned(m, MOD(3) | RM(CX));
|
||||
} else {
|
||||
gotthrow = true;
|
||||
}
|
||||
if (!setjmp(sigfpejmp)) {
|
||||
asm("idivb\t%1"
|
||||
: "=a"(remquo)
|
||||
: "q"(A[k]), "0"((int16_t)(A[i] << 8 | A[j]))
|
||||
: "cc");
|
||||
} else {
|
||||
gotsigfpe = true;
|
||||
}
|
||||
EXPECT_EQ(gotsigfpe, gotthrow);
|
||||
if (!gotsigfpe && !gotthrow) {
|
||||
quotient = (int8_t)remquo;
|
||||
remainder = (int8_t)(remquo >> 8);
|
||||
EXPECT_EQ(quotient, (int8_t)m->ax[0]);
|
||||
EXPECT_EQ(remainder, (int8_t)m->ax[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(idiv16, test) {
|
||||
if (IsWindows()) return; /* TODO */
|
||||
static const uint16_t A[] = {0x0000, 0x0001, 0x8000, 0x7FFF,
|
||||
0x8001, 0x7FFE, 0xFFFF, 0xBeef};
|
||||
bool gotthrow, gotsigfpe;
|
||||
int16_t i, j, k, w, x, a, b;
|
||||
int16_t quotient, remainder;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
for (k = 0; k < ARRAYLEN(A); ++k) {
|
||||
memcpy(m->dx, &A[i], 2);
|
||||
memcpy(m->ax, &A[j], 2);
|
||||
memcpy(m->cx, &A[k], 2);
|
||||
if (!setjmp(m->onhalt)) {
|
||||
gotthrow = false;
|
||||
OpDivRdxRaxEvqpSigned(m, OSZ | MOD(3) | RM(CX));
|
||||
} else {
|
||||
gotthrow = true;
|
||||
}
|
||||
if (!setjmp(sigfpejmp)) {
|
||||
gotsigfpe = false;
|
||||
asm("idivw\t%2"
|
||||
: "=d"(remainder), "=a"(quotient)
|
||||
: "r"(A[k]), "0"(A[i]), "1"(A[j])
|
||||
: "cc");
|
||||
} else {
|
||||
gotsigfpe = true;
|
||||
}
|
||||
EXPECT_EQ(gotsigfpe, gotthrow);
|
||||
if (!gotsigfpe && !gotthrow) {
|
||||
EXPECT_EQ(quotient, (int16_t)Read16(m->ax));
|
||||
EXPECT_EQ(remainder, (int16_t)Read16(m->dx));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(idiv32, test) {
|
||||
if (IsWindows()) return; /* TODO */
|
||||
static const uint32_t A[] = {0x00000000, 0x00000001, 0x80000000, 0x7FFFFFFF,
|
||||
0x80000001, 0x7FFFFFFE, 0xFFFFFFFF, 0xDeadBeef};
|
||||
bool gotthrow, gotsigfpe;
|
||||
int32_t i, j, k, w, x, a, b;
|
||||
int32_t quotient, remainder;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
for (k = 0; k < ARRAYLEN(A); ++k) {
|
||||
memcpy(m->dx, &A[i], 4);
|
||||
memcpy(m->ax, &A[j], 4);
|
||||
memcpy(m->cx, &A[k], 4);
|
||||
if (!setjmp(m->onhalt)) {
|
||||
gotthrow = false;
|
||||
OpDivRdxRaxEvqpSigned(m, MOD(3) | RM(CX));
|
||||
} else {
|
||||
gotthrow = true;
|
||||
}
|
||||
if (!setjmp(sigfpejmp)) {
|
||||
gotsigfpe = false;
|
||||
asm("idivl\t%2"
|
||||
: "=d"(remainder), "=a"(quotient)
|
||||
: "r"(A[k]), "0"(A[i]), "1"(A[j])
|
||||
: "cc");
|
||||
} else {
|
||||
gotsigfpe = true;
|
||||
}
|
||||
EXPECT_EQ(gotsigfpe, gotthrow);
|
||||
if (!gotsigfpe && !gotthrow) {
|
||||
EXPECT_EQ(quotient, (int32_t)Read32(m->ax));
|
||||
EXPECT_EQ(remainder, (int32_t)Read32(m->dx));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(idiv64, test) {
|
||||
if (IsWindows()) return; /* TODO */
|
||||
static const uint64_t A[] = {0x0000000000000000, 0x0000000000000001,
|
||||
0x8000000000000000, 0x7FFFFFFFFFFFFFFF,
|
||||
0x8000000000000001, 0x7FFFFFFFFFFFFFFE,
|
||||
0xFFFFFFFFFFFFFFFF, 0x00DeadBeefCafe00};
|
||||
bool gotthrow, gotsigfpe;
|
||||
int64_t i, j, k, w, x, a, b;
|
||||
int64_t quotient, remainder;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
for (k = 0; k < ARRAYLEN(A); ++k) {
|
||||
memcpy(m->dx, &A[i], 8);
|
||||
memcpy(m->ax, &A[j], 8);
|
||||
memcpy(m->cx, &A[k], 8);
|
||||
if (!setjmp(m->onhalt)) {
|
||||
gotthrow = false;
|
||||
OpDivRdxRaxEvqpSigned(m, REXW | MOD(3) | RM(CX));
|
||||
} else {
|
||||
gotthrow = true;
|
||||
}
|
||||
if (!setjmp(sigfpejmp)) {
|
||||
gotsigfpe = false;
|
||||
asm("idivq\t%2"
|
||||
: "=d"(remainder), "=a"(quotient)
|
||||
: "r"(A[k]), "0"(A[i]), "1"(A[j])
|
||||
: "cc");
|
||||
} else {
|
||||
gotsigfpe = true;
|
||||
}
|
||||
EXPECT_EQ(gotsigfpe, gotthrow);
|
||||
if (!gotsigfpe && !gotthrow) {
|
||||
EXPECT_EQ(quotient, (int64_t)Read64(m->ax));
|
||||
EXPECT_EQ(remainder, (int64_t)Read64(m->dx));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(div, test) {
|
||||
if (IsWindows()) return; /* TODO */
|
||||
static const uint8_t A[] = {0x00, 0x01, 0x80, 0x7F, 0x81, 0x7E, 0xFF, 0xBF};
|
||||
uint16_t remquo;
|
||||
bool gotthrow, gotsigfpe;
|
||||
uint8_t i, j, k, w, x, a, b;
|
||||
uint8_t quotient, remainder;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
for (k = 0; k < ARRAYLEN(A); ++k) {
|
||||
m->ax[1] = A[i];
|
||||
m->ax[0] = A[j];
|
||||
m->cx[0] = A[k];
|
||||
gotthrow = false;
|
||||
gotsigfpe = false;
|
||||
if (!setjmp(m->onhalt)) {
|
||||
OpDivAlAhAxEbUnsigned(m, MOD(3) | RM(CX));
|
||||
} else {
|
||||
gotthrow = true;
|
||||
}
|
||||
if (!setjmp(sigfpejmp)) {
|
||||
asm("divb\t%1"
|
||||
: "=a"(remquo)
|
||||
: "q"(A[k]), "0"((uint16_t)(A[i] << 8 | A[j]))
|
||||
: "cc");
|
||||
} else {
|
||||
gotsigfpe = true;
|
||||
}
|
||||
EXPECT_EQ(gotsigfpe, gotthrow);
|
||||
if (!gotsigfpe && !gotthrow) {
|
||||
quotient = (uint8_t)remquo;
|
||||
remainder = (uint8_t)(remquo >> 8);
|
||||
EXPECT_EQ(quotient, (uint8_t)m->ax[0]);
|
||||
EXPECT_EQ(remainder, (uint8_t)m->ax[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(div16, test) {
|
||||
if (IsWindows()) return; /* TODO */
|
||||
static const uint16_t A[] = {0x0000, 0x0001, 0x8000, 0x7FFF,
|
||||
0x8001, 0x7FFE, 0xFFFF, 0xBeef};
|
||||
bool gotthrow, gotsigfpe;
|
||||
uint16_t i, j, k, w, x, a, b;
|
||||
uint16_t quotient, remainder;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
for (k = 0; k < ARRAYLEN(A); ++k) {
|
||||
memcpy(m->dx, &A[i], 2);
|
||||
memcpy(m->ax, &A[j], 2);
|
||||
memcpy(m->cx, &A[k], 2);
|
||||
if (!setjmp(m->onhalt)) {
|
||||
gotthrow = false;
|
||||
OpDivRdxRaxEvqpUnsigned(m, OSZ | MOD(3) | RM(CX));
|
||||
} else {
|
||||
gotthrow = true;
|
||||
}
|
||||
if (!setjmp(sigfpejmp)) {
|
||||
gotsigfpe = false;
|
||||
asm("divw\t%2"
|
||||
: "=d"(remainder), "=a"(quotient)
|
||||
: "r"(A[k]), "0"(A[i]), "1"(A[j])
|
||||
: "cc");
|
||||
} else {
|
||||
gotsigfpe = true;
|
||||
}
|
||||
EXPECT_EQ(gotsigfpe, gotthrow);
|
||||
if (!gotsigfpe && !gotthrow) {
|
||||
EXPECT_EQ(quotient, (uint16_t)Read16(m->ax));
|
||||
EXPECT_EQ(remainder, (uint16_t)Read16(m->dx));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(div32, test) {
|
||||
if (IsWindows()) return; /* TODO */
|
||||
static const uint32_t A[] = {0x00000000, 0x00000001, 0x80000000, 0x7FFFFFFF,
|
||||
0x80000001, 0x7FFFFFFE, 0xFFFFFFFF, 0xDeadBeef};
|
||||
bool gotthrow, gotsigfpe;
|
||||
uint32_t i, j, k, w, x, a, b;
|
||||
uint32_t quotient, remainder;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
for (k = 0; k < ARRAYLEN(A); ++k) {
|
||||
memcpy(m->dx, &A[i], 4);
|
||||
memcpy(m->ax, &A[j], 4);
|
||||
memcpy(m->cx, &A[k], 4);
|
||||
if (!setjmp(m->onhalt)) {
|
||||
gotthrow = false;
|
||||
OpDivRdxRaxEvqpUnsigned(m, MOD(3) | RM(CX));
|
||||
} else {
|
||||
gotthrow = true;
|
||||
}
|
||||
if (!setjmp(sigfpejmp)) {
|
||||
gotsigfpe = false;
|
||||
asm("divl\t%2"
|
||||
: "=d"(remainder), "=a"(quotient)
|
||||
: "r"(A[k]), "0"(A[i]), "1"(A[j])
|
||||
: "cc");
|
||||
} else {
|
||||
gotsigfpe = true;
|
||||
}
|
||||
EXPECT_EQ(gotsigfpe, gotthrow);
|
||||
if (!gotsigfpe && !gotthrow) {
|
||||
EXPECT_EQ(quotient, (uint32_t)Read32(m->ax));
|
||||
EXPECT_EQ(remainder, (uint32_t)Read32(m->dx));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(div64, test) {
|
||||
if (IsWindows()) return; /* TODO */
|
||||
static const uint64_t A[] = {0x0000000000000000, 0x0000000000000001,
|
||||
0x8000000000000000, 0x7FFFFFFFFFFFFFFF,
|
||||
0x8000000000000001, 0x7FFFFFFFFFFFFFFE,
|
||||
0xFFFFFFFFFFFFFFFF, 0x00DeadBeefCafe00};
|
||||
bool gotthrow, gotsigfpe;
|
||||
uint64_t i, j, k, w, x, a, b;
|
||||
uint64_t quotient, remainder;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
for (k = 0; k < ARRAYLEN(A); ++k) {
|
||||
memcpy(m->dx, &A[i], 8);
|
||||
memcpy(m->ax, &A[j], 8);
|
||||
memcpy(m->cx, &A[k], 8);
|
||||
if (!setjmp(m->onhalt)) {
|
||||
gotthrow = false;
|
||||
OpDivRdxRaxEvqpUnsigned(m, REXW | MOD(3) | RM(CX));
|
||||
} else {
|
||||
gotthrow = true;
|
||||
}
|
||||
if (!setjmp(sigfpejmp)) {
|
||||
gotsigfpe = false;
|
||||
asm("divq\t%2"
|
||||
: "=d"(remainder), "=a"(quotient)
|
||||
: "r"(A[k]), "0"(A[i]), "1"(A[j])
|
||||
: "cc");
|
||||
} else {
|
||||
gotsigfpe = true;
|
||||
}
|
||||
EXPECT_EQ(gotsigfpe, gotthrow);
|
||||
if (!gotsigfpe && !gotthrow) {
|
||||
EXPECT_EQ(quotient, (uint64_t)Read64(m->ax));
|
||||
EXPECT_EQ(remainder, (uint64_t)Read64(m->dx));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
|
@ -1,84 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/testlib/testlib.h"
|
||||
#include "tool/build/lib/iovs.h"
|
||||
|
||||
TEST(iovs, testEmpty) {
|
||||
struct Iovs iv;
|
||||
InitIovs(&iv);
|
||||
EXPECT_EQ(0, iv.i);
|
||||
EXPECT_GE(iv.n, iv.i);
|
||||
FreeIovs(&iv);
|
||||
}
|
||||
|
||||
TEST(iovs, testAppendEmptyString_wontCreateEmptyEntries) {
|
||||
struct Iovs iv;
|
||||
InitIovs(&iv);
|
||||
EXPECT_NE(-1, AppendIovs(&iv, "", 0));
|
||||
EXPECT_NE(-1, AppendIovs(&iv, NULL, 0));
|
||||
EXPECT_EQ(0, iv.i);
|
||||
EXPECT_GE(iv.n, iv.i);
|
||||
FreeIovs(&iv);
|
||||
}
|
||||
|
||||
TEST(iovs, testAppendContiguousVectors_coalescesAdjacentEntries) {
|
||||
struct Iovs iv;
|
||||
char buf[8], *b = buf;
|
||||
InitIovs(&iv);
|
||||
EXPECT_NE(-1, AppendIovs(&iv, b + 0, 4));
|
||||
EXPECT_NE(-1, AppendIovs(&iv, b + 4, 4));
|
||||
EXPECT_EQ(1, iv.i);
|
||||
EXPECT_GE(iv.n, iv.i);
|
||||
EXPECT_EQ(8, iv.p[0].iov_len);
|
||||
EXPECT_EQ(b, iv.p[0].iov_base);
|
||||
FreeIovs(&iv);
|
||||
}
|
||||
|
||||
TEST(iovs, testAppendNoncontiguousVectors_growsMemoryAndPreservesOrdering) {
|
||||
struct Iovs iv;
|
||||
char buf[8], *b = buf;
|
||||
InitIovs(&iv);
|
||||
EXPECT_NE(-1, AppendIovs(&iv, b + 0, 1));
|
||||
EXPECT_NE(-1, AppendIovs(&iv, b + 2, 1));
|
||||
EXPECT_NE(-1, AppendIovs(&iv, b + 4, 1));
|
||||
EXPECT_NE(-1, AppendIovs(&iv, b + 6, 1));
|
||||
EXPECT_NE(-1, AppendIovs(&iv, b + 1, 1));
|
||||
EXPECT_NE(-1, AppendIovs(&iv, b + 3, 1));
|
||||
EXPECT_NE(-1, AppendIovs(&iv, b + 5, 1));
|
||||
EXPECT_NE(-1, AppendIovs(&iv, b + 7, 1));
|
||||
EXPECT_EQ(8, iv.i);
|
||||
EXPECT_GE(iv.n, iv.i);
|
||||
EXPECT_EQ(b + 0, iv.p[0].iov_base);
|
||||
EXPECT_EQ(1, iv.p[0].iov_len);
|
||||
EXPECT_EQ(b + 2, iv.p[1].iov_base);
|
||||
EXPECT_EQ(1, iv.p[1].iov_len);
|
||||
EXPECT_EQ(b + 4, iv.p[2].iov_base);
|
||||
EXPECT_EQ(1, iv.p[2].iov_len);
|
||||
EXPECT_EQ(b + 6, iv.p[3].iov_base);
|
||||
EXPECT_EQ(1, iv.p[3].iov_len);
|
||||
EXPECT_EQ(b + 1, iv.p[4].iov_base);
|
||||
EXPECT_EQ(1, iv.p[4].iov_len);
|
||||
EXPECT_EQ(b + 3, iv.p[5].iov_base);
|
||||
EXPECT_EQ(1, iv.p[5].iov_len);
|
||||
EXPECT_EQ(b + 5, iv.p[6].iov_base);
|
||||
EXPECT_EQ(1, iv.p[6].iov_len);
|
||||
EXPECT_EQ(b + 7, iv.p[7].iov_base);
|
||||
EXPECT_EQ(1, iv.p[7].iov_len);
|
||||
FreeIovs(&iv);
|
||||
}
|
|
@ -1,348 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/fmt/bing.internal.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/fpu.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#include "tool/build/lib/memory.h"
|
||||
|
||||
const uint8_t kPi80[] = {
|
||||
0xd9, 0xe8, // fld1
|
||||
0xb8, 0x0a, 0x00, 0x00, 0x00, // mov $0xa,%eax
|
||||
0x31, 0xd2, // xor %edx,%edx
|
||||
0xd9, 0xee, // fldz
|
||||
0x48, 0x98, // cltq
|
||||
0x48, 0x39, 0xc2, // cmp %rax,%rdx
|
||||
0xd9, 0x05, 0x1a, 0x00, 0x00, 0x00, // flds 0x1a(%rip)
|
||||
0x7d, 0x13, // jge 2b <pi80+0x2b>
|
||||
0xde, 0xc1, // faddp
|
||||
0x48, 0xff, 0xc2, // inc %rdx
|
||||
0xd9, 0xfa, // fsqrt
|
||||
0xd9, 0x05, 0x0f, 0x00, 0x00, 0x00, // flds 15(%rip)
|
||||
0xd8, 0xc9, // fmul %st(1),%st
|
||||
0xde, 0xca, // fmulp %st,%st(2)
|
||||
0xeb, 0xe2, // jmp d <pi80+0xd>
|
||||
0xdd, 0xd9, // fstp %st(1)
|
||||
0xde, 0xf1, // fdivp
|
||||
0xf4, // hlt
|
||||
0x00, 0x00, 0x00, 0x40, // .float 2.0
|
||||
0x00, 0x00, 0x00, 0x3f, // .float 0.5
|
||||
};
|
||||
|
||||
const uint8_t kTenthprime[] = {
|
||||
0x31, 0xd2, // xor %edx,%edx
|
||||
0x45, 0x31, 0xc0, // xor %r8d,%r8d
|
||||
0x31, 0xc9, // xor %ecx,%ecx
|
||||
0xbe, 0x03, 0x00, 0x00, 0x00, // mov $0x3,%esi
|
||||
0x41, 0xff, 0xc0, // inc %r8d
|
||||
0x44, 0x89, 0xc0, // mov %r8d,%eax
|
||||
0x83, 0xf9, 0x0a, // cmp $0xa,%ecx
|
||||
0x74, 0x0b, // je 20
|
||||
0x99, // cltd
|
||||
0xf7, 0xfe, // idiv %esi
|
||||
0x83, 0xfa, 0x01, // cmp $0x1,%edx
|
||||
0x83, 0xd9, 0xff, // sbb $-1,%ecx
|
||||
0xeb, 0xea, // jmp a
|
||||
0xf4, // hlt
|
||||
};
|
||||
|
||||
const uint8_t kTenthprime2[] = {
|
||||
0xE8, 0x11, 0x00, 0x00, 0x00, //
|
||||
0xF4, //
|
||||
0x89, 0xF8, //
|
||||
0xB9, 0x03, 0x00, 0x00, 0x00, //
|
||||
0x99, //
|
||||
0xF7, 0xF9, //
|
||||
0x85, 0xD2, //
|
||||
0x0F, 0x95, 0xC0, //
|
||||
0xC3, //
|
||||
0x55, //
|
||||
0x48, 0x89, 0xE5, //
|
||||
0x31, 0xF6, //
|
||||
0x45, 0x31, 0xC0, //
|
||||
0x44, 0x89, 0xC7, //
|
||||
0xE8, 0xDF, 0xFF, 0xFF, 0xFF, //
|
||||
0x0F, 0xB6, 0xC0, //
|
||||
0x66, 0x83, 0xF8, 0x01, //
|
||||
0x83, 0xDE, 0xFF, //
|
||||
0x41, 0xFF, 0xC0, //
|
||||
0x83, 0xFE, 0x0A, //
|
||||
0x75, 0xE6, //
|
||||
0x44, 0x89, 0xC0, //
|
||||
0x5D, //
|
||||
0xC3, //
|
||||
};
|
||||
|
||||
struct Machine *m;
|
||||
|
||||
void SetUp(void) {
|
||||
m = NewMachine();
|
||||
m->mode = XED_MACHINE_MODE_LONG_64;
|
||||
m->cr3 = AllocateLinearPage(m);
|
||||
ReserveVirtual(m, 0, 4096, 0x0207);
|
||||
ASSERT_EQ(0x1007, Read64(m->real.p + 0x0000)); // PML4T
|
||||
ASSERT_EQ(0x2007, Read64(m->real.p + 0x1000)); // PDPT
|
||||
ASSERT_EQ(0x3007, Read64(m->real.p + 0x2000)); // PDE
|
||||
ASSERT_EQ(0x0207, Read64(m->real.p + 0x3000)); // PT
|
||||
ASSERT_EQ(0x4000, m->real.i);
|
||||
ASSERT_EQ(1, m->memstat.reserved);
|
||||
ASSERT_EQ(4, m->memstat.committed);
|
||||
ASSERT_EQ(4, m->memstat.allocated);
|
||||
ASSERT_EQ(3, m->memstat.pagetables);
|
||||
Write64(m->sp, 4096);
|
||||
}
|
||||
|
||||
void TearDown(void) {
|
||||
FreeVirtual(m, 0, 4096);
|
||||
ASSERT_EQ(0x1007, Read64(m->real.p + 0x0000)); // PML4T
|
||||
ASSERT_EQ(0x2007, Read64(m->real.p + 0x1000)); // PDPT
|
||||
ASSERT_EQ(0x3007, Read64(m->real.p + 0x2000)); // PDE
|
||||
ASSERT_EQ(0x0000, Read64(m->real.p + 0x3000)); // PT
|
||||
FreeMachine(m);
|
||||
}
|
||||
|
||||
int ExecuteUntilHalt(struct Machine *m) {
|
||||
int rc;
|
||||
if (!(rc = setjmp(m->onhalt))) {
|
||||
for (;;) {
|
||||
LoadInstruction(m);
|
||||
ExecuteInstruction(m);
|
||||
}
|
||||
} else {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(machine, test) {
|
||||
VirtualRecv(m, 0, kTenthprime, sizeof(kTenthprime));
|
||||
ASSERT_EQ(kMachineHalt, ExecuteUntilHalt(m));
|
||||
ASSERT_EQ(15, Read32(m->ax));
|
||||
}
|
||||
|
||||
TEST(machine, testFpu) {
|
||||
VirtualRecv(m, 0, kPi80, sizeof(kPi80));
|
||||
ASSERT_EQ(kMachineHalt, ExecuteUntilHalt(m));
|
||||
ASSERT_TRUE(fabsl(3.14159 - FpuPop(m)) < 0.0001);
|
||||
m->ip = 0;
|
||||
ASSERT_EQ(kMachineHalt, ExecuteUntilHalt(m));
|
||||
ASSERT_TRUE(fabsl(3.14159 - FpuPop(m)) < 0.0001);
|
||||
}
|
||||
|
||||
BENCH(machine, benchPrimeNumberPrograms) {
|
||||
VirtualRecv(m, 0, kTenthprime2, sizeof(kTenthprime2));
|
||||
EZBENCH2("tenthprime2", m->ip = 0, ExecuteUntilHalt(m));
|
||||
ASSERT_EQ(15, Read32(m->ax));
|
||||
VirtualRecv(m, 0, kTenthprime, sizeof(kTenthprime));
|
||||
EZBENCH2("tenthprime", m->ip = 0, ExecuteUntilHalt(m));
|
||||
ASSERT_EQ(15, Read32(m->ax));
|
||||
}
|
||||
|
||||
static void machine_benchFpu_fn(void) {
|
||||
ExecuteUntilHalt(m);
|
||||
FpuPop(m);
|
||||
}
|
||||
|
||||
BENCH(machine, benchFpu) {
|
||||
VirtualRecv(m, 0, kPi80, sizeof(kPi80));
|
||||
EZBENCH2("pi80", m->ip = 0, machine_benchFpu_fn());
|
||||
}
|
||||
|
||||
BENCH(machine, benchLoadExec2) {
|
||||
uint8_t kMovCode[] = {0xbe, 0x03, 0x00, 0x00, 0x00};
|
||||
VirtualRecv(m, 0, kMovCode, sizeof(kMovCode));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("mov", m->ip = 0, ExecuteInstruction(m));
|
||||
}
|
||||
|
||||
BENCH(machine, benchLoadExec3) {
|
||||
uint8_t kMovdCode[] = {0x66, 0x0f, 0x6e, 0xc0};
|
||||
Write64(m->ax, 0);
|
||||
VirtualRecv(m, 0, kMovdCode, sizeof(kMovdCode));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("movd", m->ip = 0, ExecuteInstruction(m));
|
||||
}
|
||||
|
||||
BENCH(machine, benchLoadExec4) {
|
||||
uint8_t kAddpsRegregCode[] = {0x0f, 0x58, 0xC0};
|
||||
uint8_t kAddpsMemregCode[] = {0x0f, 0x58, 0x00};
|
||||
Write64(m->ax, 0);
|
||||
VirtualRecv(m, 0, kAddpsRegregCode, sizeof(kAddpsRegregCode));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("addps reg reg", m->ip = 0, ExecuteInstruction(m));
|
||||
VirtualRecv(m, 0, kAddpsMemregCode, sizeof(kAddpsMemregCode));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("addps mem reg", m->ip = 0, ExecuteInstruction(m));
|
||||
}
|
||||
|
||||
BENCH(machine, benchLoadExec5) {
|
||||
uint8_t kPaddwRegregCode[] = {0x66, 0x0F, 0xFD, 0xC0};
|
||||
uint8_t kPaddwMemregCode[] = {0x66, 0x0F, 0xFD, 0x00};
|
||||
Write64(m->ax, 0);
|
||||
VirtualRecv(m, 0, kPaddwRegregCode, sizeof(kPaddwRegregCode));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("paddw", m->ip = 0, ExecuteInstruction(m));
|
||||
VirtualRecv(m, 0, kPaddwMemregCode, sizeof(kPaddwMemregCode));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("paddw mem", m->ip = 0, ExecuteInstruction(m));
|
||||
}
|
||||
|
||||
BENCH(machine, benchLoadExec6) {
|
||||
uint8_t kPsubqRegregCode[] = {0x66, 0x0F, 0xFB, 0xC0};
|
||||
uint8_t kPsubqMemregCode[] = {0x66, 0x0F, 0xFB, 0x00};
|
||||
Write64(m->ax, 0);
|
||||
VirtualRecv(m, 0, kPsubqRegregCode, sizeof(kPsubqRegregCode));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("psubq", m->ip = 0, ExecuteInstruction(m));
|
||||
VirtualRecv(m, 0, kPsubqMemregCode, sizeof(kPsubqMemregCode));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("psubq mem", m->ip = 0, ExecuteInstruction(m));
|
||||
}
|
||||
|
||||
BENCH(machine, benchAddqMem) {
|
||||
uint8_t kAddMemregCode[] = {0x48, 0x03, 0x08};
|
||||
Write64(m->ax, 0);
|
||||
VirtualRecv(m, 0, kAddMemregCode, sizeof(kAddMemregCode));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("addq mem", m->ip = 0, ExecuteInstruction(m));
|
||||
}
|
||||
|
||||
BENCH(machine, benchAddlMem) {
|
||||
uint8_t kAddMemregCode[] = {0x03, 0x08};
|
||||
Write64(m->ax, 0);
|
||||
VirtualRecv(m, 0, kAddMemregCode, sizeof(kAddMemregCode));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("addl mem", m->ip = 0, ExecuteInstruction(m));
|
||||
}
|
||||
|
||||
BENCH(machine, benchAddq) {
|
||||
uint8_t kAddqCode[] = {0x48, 0x01, 0xd8};
|
||||
Write64(m->ax, 0);
|
||||
VirtualRecv(m, 0, kAddqCode, sizeof(kAddqCode));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("addq", m->ip = 0, ExecuteInstruction(m));
|
||||
}
|
||||
|
||||
BENCH(machine, benchAddb) {
|
||||
uint8_t kAddbCode[] = {0x00, 0xd8};
|
||||
Write64(m->ax, 0);
|
||||
VirtualRecv(m, 0, kAddbCode, sizeof(kAddbCode));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("addb", m->ip = 0, ExecuteInstruction(m));
|
||||
}
|
||||
|
||||
BENCH(machine, benchXorReg) {
|
||||
VirtualRecv(m, 0, kTenthprime, sizeof(kTenthprime));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("xor", m->ip = 0, ExecuteInstruction(m));
|
||||
}
|
||||
|
||||
BENCH(machine, benchLoadExec8) {
|
||||
uint8_t kFchsCode[] = {0xd9, 0xe0};
|
||||
Write64(m->ax, 0);
|
||||
OpFinit(m);
|
||||
*FpuSt(m, 0) = M_PI;
|
||||
FpuSetTag(m, 0, kFpuTagValid);
|
||||
VirtualRecv(m, 0, kFchsCode, sizeof(kFchsCode));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("fchs", m->ip = 0, ExecuteInstruction(m));
|
||||
}
|
||||
|
||||
static void machine_benchPushpop_fn(void) {
|
||||
LoadInstruction(m);
|
||||
ExecuteInstruction(m);
|
||||
LoadInstruction(m);
|
||||
ExecuteInstruction(m);
|
||||
}
|
||||
|
||||
BENCH(machine, benchPushpop) {
|
||||
uint8_t kPushpop[] = {0x50, 0x58};
|
||||
Write64(m->ax, 0);
|
||||
VirtualRecv(m, 0, kPushpop, sizeof(kPushpop));
|
||||
EZBENCH2("pushpop", m->ip = 0, machine_benchPushpop_fn());
|
||||
}
|
||||
|
||||
BENCH(machine, benchPause) {
|
||||
uint8_t kPause[] = {0xf3, 0x90};
|
||||
Write64(m->ax, 0);
|
||||
VirtualRecv(m, 0, kPause, sizeof(kPause));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("pause", m->ip = 0, ExecuteInstruction(m));
|
||||
}
|
||||
|
||||
BENCH(machine, benchClc) {
|
||||
uint8_t kClc[] = {0xf8};
|
||||
Write64(m->ax, 0);
|
||||
VirtualRecv(m, 0, kClc, sizeof(kClc));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("clc", m->ip = 0, ExecuteInstruction(m));
|
||||
}
|
||||
|
||||
static void machine_benchNop_fn(void) {
|
||||
LoadInstruction(m);
|
||||
ExecuteInstruction(m);
|
||||
}
|
||||
|
||||
BENCH(machine, benchNop) {
|
||||
uint8_t kNop[] = {0x90};
|
||||
Write64(m->ax, 0);
|
||||
VirtualRecv(m, 0, kNop, sizeof(kNop));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("nop", m->ip = 0, ExecuteInstruction(m));
|
||||
EZBENCH2("nop w/ load", m->ip = 0, machine_benchNop_fn());
|
||||
}
|
||||
|
||||
TEST(x87, fprem1) {
|
||||
// 1 rem -1.5
|
||||
const uint8_t prog[] = {
|
||||
0xd9, 0x05, 0x05, 0x00, 0x00, 0x00, // flds
|
||||
0xd9, 0xe8, // fld1
|
||||
0xd9, 0xf8, // fprem
|
||||
0xf4, // hlt
|
||||
0x00, 0x00, 0xc0, 0xbf, // .float -1.5
|
||||
};
|
||||
VirtualRecv(m, 0, prog, sizeof(prog));
|
||||
ASSERT_EQ(kMachineHalt, ExecuteUntilHalt(m));
|
||||
ASSERT_LDBL_EQ(1, FpuPop(m));
|
||||
}
|
||||
|
||||
TEST(x87, fprem2) {
|
||||
// 12300000000000000. rem .0000000000000123
|
||||
const uint8_t prog[] = {
|
||||
0xdd, 0x05, 0x11, 0x00, 0x00, 0x00, // fldl
|
||||
0xdd, 0x05, 0x03, 0x00, 0x00, 0x00, // fldl
|
||||
0xd9, 0xf8, // fprem
|
||||
0xf4, // hlt
|
||||
0x00, 0x60, 0x5e, 0x75, 0x64, 0xd9, 0x45, 0x43, //
|
||||
0x5b, 0x14, 0xea, 0x9d, 0x77, 0xb2, 0x0b, 0x3d, //
|
||||
};
|
||||
VirtualRecv(m, 0, prog, sizeof(prog));
|
||||
ASSERT_EQ(kMachineHalt, ExecuteUntilHalt(m));
|
||||
ASSERT_LDBL_EQ(1.1766221079117338e-14, FpuPop(m));
|
||||
}
|
||||
|
||||
TEST(machine, sizeIsReasonable) {
|
||||
ASSERT_LE(sizeof(struct Machine), 65536 * 3);
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/mem/mem.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "third_party/xed/x86.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
|
||||
#define ILD(XEDD, OP, MODE) \
|
||||
do { \
|
||||
xed_decoded_inst_zero_set_mode(XEDD, MODE); \
|
||||
ASSERT_EQ(0, xed_instruction_length_decode(XEDD, OP, sizeof(OP))); \
|
||||
XEDD->op.rde = EncodeRde(XEDD); \
|
||||
} while (0)
|
||||
|
||||
TEST(modrm, testAddressSizeOverride_isNotPresent_keepsWholeExpression) {
|
||||
struct Machine *m = gc(NewMachine());
|
||||
struct XedDecodedInst *xedd = gc(calloc(1, sizeof(struct XedDecodedInst)));
|
||||
uint8_t op[] = {0x8d, 0x04, 0x03}; /* lea (%rbx,%rax,1),%eax */
|
||||
m->xedd = xedd;
|
||||
Write64(m->bx, 0x2);
|
||||
Write64(m->ax, 0xffffffff);
|
||||
ILD(xedd, op, XED_MACHINE_MODE_LONG_64);
|
||||
EXPECT_EQ(0x100000001, ComputeAddress(m, m->xedd->op.rde));
|
||||
}
|
||||
|
||||
TEST(modrm, testAddressSizeOverride_isPresent_modulesWholeExpression) {
|
||||
struct Machine *m = gc(NewMachine());
|
||||
struct XedDecodedInst *xedd = gc(calloc(1, sizeof(struct XedDecodedInst)));
|
||||
uint8_t op[] = {0x67, 0x8d, 0x04, 0x03}; /* lea (%ebx,%eax,1),%eax */
|
||||
m->xedd = xedd;
|
||||
Write64(m->bx, 0x2);
|
||||
Write64(m->ax, 0xffffffff);
|
||||
ILD(xedd, op, XED_MACHINE_MODE_LONG_64);
|
||||
EXPECT_EQ(0x000000001, ComputeAddress(m, m->xedd->op.rde));
|
||||
}
|
||||
|
||||
TEST(modrm, testOverflow_doesntTriggerTooling) {
|
||||
struct Machine *m = gc(NewMachine());
|
||||
struct XedDecodedInst *xedd = gc(calloc(1, sizeof(struct XedDecodedInst)));
|
||||
uint8_t op[] = {0x8d, 0x04, 0x03}; /* lea (%rbx,%rax,1),%eax */
|
||||
m->xedd = xedd;
|
||||
Write64(m->bx, 0x0000000000000001);
|
||||
Write64(m->ax, 0x7fffffffffffffff);
|
||||
ILD(xedd, op, XED_MACHINE_MODE_LONG_64);
|
||||
EXPECT_EQ(0x8000000000000000ull,
|
||||
(uint64_t)ComputeAddress(m, m->xedd->op.rde));
|
||||
}
|
||||
|
||||
TEST(modrm, testPuttingOnTheRiz) {
|
||||
struct Machine *m = gc(NewMachine());
|
||||
static uint8_t ops[][15] = {
|
||||
{0x8d, 0b00110100, 0b00100110}, // lea (%rsi),%esi
|
||||
{0x67, 0x8d, 0b00110100, 0b11100110}, // lea (%esi,%eiz,8),%esi
|
||||
{103, 141, 180, 229, 55, 19, 3, 0}, // lea 0x31337(%ebp,%eiz,8),%esi
|
||||
{141, 52, 229, 55, 19, 3, 0}, // lea 0x31337,%esi
|
||||
};
|
||||
m->xedd = gc(calloc(1, sizeof(struct XedDecodedInst)));
|
||||
Write64(m->si, 0x100000001);
|
||||
Write64(m->bp, 0x200000002);
|
||||
ILD(m->xedd, ops[0], XED_MACHINE_MODE_LONG_64);
|
||||
EXPECT_EQ(0x100000001, ComputeAddress(m, m->xedd->op.rde));
|
||||
ILD(m->xedd, ops[1], XED_MACHINE_MODE_LONG_64);
|
||||
EXPECT_EQ(0x000000001, ComputeAddress(m, m->xedd->op.rde));
|
||||
ILD(m->xedd, ops[2], XED_MACHINE_MODE_LONG_64);
|
||||
EXPECT_EQ(0x31339, ComputeAddress(m, m->xedd->op.rde));
|
||||
ILD(m->xedd, ops[3], XED_MACHINE_MODE_LONG_64);
|
||||
EXPECT_EQ(0x31337, ComputeAddress(m, m->xedd->op.rde));
|
||||
}
|
||||
|
||||
TEST(modrm, testSibIndexOnly) {
|
||||
// lea 0x0(,%rcx,4),%r8
|
||||
// mod = 0b00 (0)
|
||||
// reg = 0b000 (0)
|
||||
// rm = 0b100 (4)
|
||||
// scale = 0b10 (2)
|
||||
// index = 0b001 (1)
|
||||
// base = 0b101 (5)
|
||||
struct Machine *m = gc(NewMachine());
|
||||
struct XedDecodedInst *xedd = gc(calloc(1, sizeof(struct XedDecodedInst)));
|
||||
uint8_t op[] = {0x4c, 0x8d, 0x04, 0x8d, 0, 0, 0, 0};
|
||||
m->xedd = xedd;
|
||||
Write64(m->bp, 0x123);
|
||||
Write64(m->cx, 0x123);
|
||||
ILD(xedd, op, XED_MACHINE_MODE_LONG_64);
|
||||
EXPECT_TRUE(Rexw(m->xedd->op.rde));
|
||||
EXPECT_TRUE(Rexr(m->xedd->op.rde));
|
||||
EXPECT_FALSE(Rexb(m->xedd->op.rde));
|
||||
EXPECT_EQ(0b000, ModrmReg(m->xedd->op.rde));
|
||||
EXPECT_EQ(0b100, ModrmRm(m->xedd->op.rde));
|
||||
EXPECT_EQ(0x123 * 4, (uint64_t)ComputeAddress(m, m->xedd->op.rde));
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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 "test/tool/build/lib/numbers.h"
|
||||
|
||||
const uint64_t kNumbers[102] = {
|
||||
0x0000000000000000, 0x0000000080000000, 0x0000000000008000,
|
||||
0x0000000000000001, 0x0000000000000002, 0x0000000000000003,
|
||||
0x0000000000000004, 0x0000000000000005, 0x0000000000000006,
|
||||
0x0000000000000007, 0x0000000000000008, 0x0000000000000009,
|
||||
0x000000000000000a, 0x000000000000000b, 0x000000000000000c,
|
||||
0x000000000000000d, 0x000000000000000e, 0x000000000000000f,
|
||||
0x0000000000000010, 0x0000000000000011, 0x0000000000000012,
|
||||
0x0000000000000013, 0x0000000000000014, 0x0000000000000015,
|
||||
0x0000000000000016, 0x0000000000000017, 0x0000000000000018,
|
||||
0x0000000000000019, 0x000000000000001a, 0x000000000000001b,
|
||||
0x000000000000001c, 0x000000000000001d, 0x000000000000001e,
|
||||
0x000000000000001f, 0x0000000000000020, 0x0000000000000040,
|
||||
0x8000000000000000, 0x0000000000000080, 0x0000000000000002,
|
||||
0x0000000000000001, 0x0000000000000004, 0x00000000C0000000,
|
||||
0xC000000000000000, 0x000000000000C000, 0x00000000000000C0,
|
||||
0x0000000000000003, 0x000000000000E000, 0x00000000E0000000,
|
||||
0xE000000000000000, 0x00000000000000E0, 0x000000000000001F,
|
||||
0x00000000000000FC, 0x000000000000003F, 0x000000000000007F,
|
||||
0x00000000000000FB, 0x00000000000000FD, 0x00000000000000FE,
|
||||
0x00000000000000FF, 0x000000000000FF1F, 0x0000000000001FFF,
|
||||
0x000000000000FFFC, 0x0000000000003FFF, 0x000000000000FF3F,
|
||||
0x000000000000FFFD, 0x000000000000FFFE, 0x000000000000FFFB,
|
||||
0x000000000000FF7F, 0x0000000000007FFF, 0x000000000000FFFF,
|
||||
0x00000000FFFF1FFF, 0x00000000FFFFFF1F, 0x000000001FFFFFFF,
|
||||
0x00000000FFFFFF3F, 0x00000000FFFF3FFF, 0x00000000FFFFFFFC,
|
||||
0x000000003FFFFFFF, 0x00000000FFFFFF7F, 0x00000000FFFFFFFD,
|
||||
0x00000000FFFFFFFE, 0x00000000FFFFFFFB, 0x000000007FFFFFFF,
|
||||
0x00000000FFFF7FFF, 0x00000000FFFFFFFF, 0xFFFFFFFF1FFFFFFF,
|
||||
0x1FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFF1FFF, 0xFFFFFFFFFFFFFF1F,
|
||||
0xFFFFFFFFFFFFFFFC, 0xFFFFFFFFFFFF3FFF, 0xFFFFFFFF3FFFFFFF,
|
||||
0xFFFFFFFFFFFFFF3F, 0x3FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFD,
|
||||
0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFB, 0xFFFFFFFF7FFFFFFF,
|
||||
0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFF7F, 0xFFFFFFFFFFFF7FFF,
|
||||
0xFFFFFFFFFFFFFFFF, 0x00DeadBeefCafe00, 0x0000031337000000,
|
||||
};
|
|
@ -1,10 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TEST_TOOL_BUILD_LIB_NUMBERS_H_
|
||||
#define COSMOPOLITAN_TEST_TOOL_BUILD_LIB_NUMBERS_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern const uint64_t kNumbers[102];
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TEST_TOOL_BUILD_LIB_NUMBERS_H_ */
|
|
@ -1,96 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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 "test/tool/build/lib/optest.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "test/tool/build/lib/numbers.h"
|
||||
#include "tool/build/lib/flags.h"
|
||||
#ifdef __x86_64__
|
||||
|
||||
const char kOpSuffix[] = {'b', 'w', 'l', 'q'};
|
||||
|
||||
void(RunOpTests)(const uint8_t *ops, size_t n, const char *const *opnames,
|
||||
const char *file, int line, const char *func) {
|
||||
uint64_t x, y;
|
||||
uint64_t xn, xp;
|
||||
uint32_t f0, f1, f2;
|
||||
long failed, succeeded;
|
||||
int w, h, i, j, c, z, s, o, p;
|
||||
failed = 0;
|
||||
succeeded = 0;
|
||||
for (w = 0; w < 4; ++w) {
|
||||
for (h = 0; h < n; ++h) {
|
||||
for (z = 0; z < 2; ++z) {
|
||||
for (o = 0; o < 2; ++o) {
|
||||
for (s = 0; s < 2; ++s) {
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(kNumbers); ++j) {
|
||||
for (c = 0; c < 2; ++c) {
|
||||
x = kNumbers[i];
|
||||
y = kNumbers[j];
|
||||
f2 = f1 = f0 = c << FLAGS_CF | z << FLAGS_ZF | s << FLAGS_SF |
|
||||
o << FLAGS_OF;
|
||||
xn = RunGolden(w, ops[h], x, y, &f1);
|
||||
xp = RunOpTest(w, ops[h], x, y, &f2);
|
||||
if (_weaken(FixupUndefOpTestFlags)) {
|
||||
FixupUndefOpTestFlags(w, ops[h], x, y, f1, &f2);
|
||||
}
|
||||
if (xn == xp && (f1 & FMASK) == (f2 & FMASK)) {
|
||||
succeeded++;
|
||||
} else if (failed++ < 10) {
|
||||
fprintf(stderr,
|
||||
"%s:%d:%s: %s%c failed\n\t"
|
||||
"𝑥 %016x\n\t"
|
||||
"𝑦 %016x %c%c%c%c 0NPlODITSZKA1PVC\n\t"
|
||||
"𝑥ₙ %016x %c%c%c%c %016b\n\t"
|
||||
"𝑥ₚ %016x %c%c%c%c %016b\n",
|
||||
file, line, func, opnames[ops[h]], kOpSuffix[w], x,
|
||||
y, ".C"[c], ".Z"[z], ".S"[s], ".O"[o], xn,
|
||||
".C"[!!(f1 & (1 << FLAGS_CF))],
|
||||
".Z"[!!(f1 & (1 << FLAGS_ZF))],
|
||||
".S"[!!(f1 & (1 << FLAGS_SF))],
|
||||
".O"[!!(f1 & (1 << FLAGS_OF))], f1, xp,
|
||||
".C"[!!(f2 & (1 << FLAGS_CF))],
|
||||
".Z"[!!(f2 & (1 << FLAGS_ZF))],
|
||||
".S"[!!(f2 & (1 << FLAGS_SF))],
|
||||
".O"[!!(f2 & (1 << FLAGS_OF))], f2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (failed) {
|
||||
fprintf(stderr,
|
||||
"\n"
|
||||
"passing: %d%%\n"
|
||||
"succeeded: %,ld\n"
|
||||
"failed: %,ld\n"
|
||||
"\n",
|
||||
(int)((1 - (double)failed / succeeded) * 100), succeeded, failed);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
|
@ -1,21 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TEST_TOOL_BUILD_LIB_OPTEST_H_
|
||||
#define COSMOPOLITAN_TEST_TOOL_BUILD_LIB_OPTEST_H_
|
||||
#include "tool/build/lib/flags.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define FMASK (1 << FLAGS_CF | 1 << FLAGS_ZF | 1 << FLAGS_SF | 1 << FLAGS_OF)
|
||||
|
||||
void RunOpTests(const uint8_t *, size_t, const char *const *, const char *, int,
|
||||
const char *);
|
||||
|
||||
int64_t RunGolden(char, int, uint64_t, uint64_t, uint32_t *);
|
||||
int64_t RunOpTest(char, int, uint64_t, uint64_t, uint32_t *);
|
||||
void FixupUndefOpTestFlags(char, int, uint64_t, uint64_t, uint32_t, uint32_t *);
|
||||
|
||||
#define RunOpTests(ops, n, names) \
|
||||
RunOpTests(ops, n, names, __FILE__, __LINE__, __func__)
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TEST_TOOL_BUILD_LIB_OPTEST_H_ */
|
|
@ -1,235 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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 "tool/build/lib/pty.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/unicode.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
char *render(struct Pty *pty) {
|
||||
static struct Buffer b;
|
||||
int y;
|
||||
b.i = 0;
|
||||
for (y = 0; y < pty->yn; ++y) {
|
||||
PtyAppendLine(pty, &b, y);
|
||||
}
|
||||
b.p[b.i] = 0;
|
||||
return b.p;
|
||||
}
|
||||
|
||||
const char widelatin[] forcealign(16) = "\
|
||||
A-BCDEFGHIJKLMNOPQRSTUVWXYZ\r\n\
|
||||
ab-cdefghijklmnopqrstuvwxyz\r\n\
|
||||
012-3456789\r\n\
|
||||
ABCD-EFGHIJKLMNOPQRSTUVWXYZ\r\n\
|
||||
abcde-fghijklmnopqrstuvwxyz\r\n\
|
||||
012345-6789\r\n\
|
||||
ABCDEFG-HIJKLMNOPQRSTUVWXYZ\r\n\
|
||||
abcdefgh-ijklmnopqrstuvwxyz\r\n\
|
||||
012345678-9";
|
||||
|
||||
static const char widelatin_golden[] = "\
|
||||
A-BCDEFGHIJKLMNOPQRSTUVWXYZ \
|
||||
ab-cdefghijklmnopqrstuvwxyz \
|
||||
012-3456789 \
|
||||
ABCD-EFGHIJKLMNOPQRSTUVWXYZ \
|
||||
abcde-fghijklmnopqrstuvwxyz \
|
||||
012345-6789 \
|
||||
ABCDEFG-HIJKLMNOPQRSTUVWXYZ \
|
||||
abcdefgh-ijklmnopqrstuvwxyz \
|
||||
012345678-9▂ \
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
";
|
||||
|
||||
TEST(pty, testFunWidth) {
|
||||
struct Pty *pty = NewPty();
|
||||
PtyWrite(pty, widelatin, ARRAYLEN(widelatin) - 1);
|
||||
EXPECT_STREQ(widelatin_golden, gc(render(pty)));
|
||||
FreePty(pty);
|
||||
}
|
||||
|
||||
const char hyperion[] forcealign(16) = "\
|
||||
Fanatics have their dreams, wherewith they weave \
|
||||
A paradise for a sect; the savage too \
|
||||
From forth the loftiest fashion of his sleep \
|
||||
Guesses at Heaven; pity these have not \
|
||||
Trac'd upon vellum or wild Indian leaf \
|
||||
The shadows of melodious utterance. \
|
||||
But bare of laurel they live, dream, and die; \
|
||||
For Poesy alone can tell her dreams, \
|
||||
With the fine spell of words alone can save \
|
||||
Imagination from the sable charm \
|
||||
And dumb enchantment. Who alive can say, \
|
||||
'Thou art no Poet may'st not tell thy dreams?' \
|
||||
Since every man whose soul is not a clod \
|
||||
Hath visions, and would speak, if he had loved \
|
||||
And been well nurtured in his mother tongue. \
|
||||
Whether the dream now purpos'd to rehearse \
|
||||
Be poet's or fanatic's will be known \
|
||||
When this warm scribe my hand is in the grave.";
|
||||
|
||||
static const wchar_t hyperion_golden[] = L"\
|
||||
Fanatics have their dreams, wherewith they weave A paradise for a sect; the sava\
|
||||
ge too From forth the loftiest fashion of his sleep Guesses at Heaven; pity thes\
|
||||
e have not Trac'd upon vellum or wild Indian leaf The shadows of melodious utter\
|
||||
ance. But bare of laurel they live, dream, and die; For Poesy alone can tell her\
|
||||
dreams, With the fine spell of words alone can save Imagination from the sable \
|
||||
charm And dumb enchantment. Who alive can say, 'Thou art no Poet may'st not tell\
|
||||
thy dreams?' Since every man whose soul is not a clod Hath visions, and would s\
|
||||
peak, if he had loved And been well nurtured in his mother tongue. Whether the d\
|
||||
ream now purpos'd to rehearse Be poet's or fanatic's will be known When this war\
|
||||
m scribe my hand is in the grave. \
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
";
|
||||
|
||||
TEST(pty, testPureAscii_benefitsFromVectorization) {
|
||||
struct Pty *pty = NewPty();
|
||||
PtyWrite(pty, hyperion, ARRAYLEN(hyperion) - 1);
|
||||
EXPECT_STREQN(pty->wcs, hyperion_golden, ARRAYLEN(hyperion_golden) - 1);
|
||||
FreePty(pty);
|
||||
}
|
||||
|
||||
static const char kKiloAnsi[] = "\
|
||||
\e[?25l\e[H\
|
||||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐\e[39m\e[0K\r\n\
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi─────────\e[39m\e[0K\r\n\
|
||||
#\e[39m\e[0K\r\n\
|
||||
# SYNOPSIS\e[39m\e[0K\r\n\
|
||||
#\e[39m\e[0K\r\n\
|
||||
# Freestanding Hermetically-Sealed Monolithic Repository\e[39m\e[0K\r\n\
|
||||
#\e[39m\e[0K\r\n\
|
||||
# REQUIREMENTS\e[39m\e[0K\r\n\
|
||||
#\e[39m\e[0K\r\n\
|
||||
# You can run your programs on any operating system, but you have\e[39m\e[0K\r\n\
|
||||
# to build them on Linux 2.6+ (or WSL) using GNU Make. A modern C\e[39m\e[0K\r\n\
|
||||
# compiler that\'s statically-linked comes included as a courtesy.\e[39m\e[0K\r\n\
|
||||
#\e[39m\e[0K\r\n\
|
||||
# EXAMPLES\e[39m\e[0K\r\n\
|
||||
#\e[39m\e[0K\r\n\
|
||||
# # build and run everything\e[39m\e[0K\r\n\
|
||||
# make -j8 -O\e[39m\e[0K\r\n\
|
||||
# make -j8 -O MODE=dbg\e[39m\e[0K\r\n\
|
||||
# make -j8 -O MODE=opt\e[39m\e[0K\r\n\
|
||||
# make -j8 -O MODE=rel\e[39m\e[0K\r\n\
|
||||
# make -j8 -O MODE=tiny\e[39m\e[0K\r\n\
|
||||
#\e[39m\e[0K\r\n\
|
||||
# # build individual target\e[39m\e[0K\r\n\
|
||||
\e[0K\e[7mMakefile - 340 lines 1/340\e[0m\r\n\
|
||||
\e[0KHELP: Ctrl-S = save | Ctrl-Q = quit | Ctrl-F = find\e[1;1H\e[?25h";
|
||||
|
||||
static const wchar_t kKiloGolden[] = L"\
|
||||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ \
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────── \
|
||||
# \
|
||||
# SYNOPSIS \
|
||||
# \
|
||||
# Freestanding Hermetically-Sealed Monolithic Repository \
|
||||
# \
|
||||
# REQUIREMENTS \
|
||||
# \
|
||||
# You can run your programs on any operating system, but you have \
|
||||
# to build them on Linux 2.6+ (or WSL) using GNU Make. A modern C \
|
||||
# compiler that's statically-linked comes included as a courtesy. \
|
||||
# \
|
||||
# EXAMPLES \
|
||||
# \
|
||||
# # build and run everything \
|
||||
# make -j8 -O \
|
||||
# make -j8 -O MODE=dbg \
|
||||
# make -j8 -O MODE=opt \
|
||||
# make -j8 -O MODE=rel \
|
||||
# make -j8 -O MODE=tiny \
|
||||
# \
|
||||
# # build individual target \
|
||||
Makefile - 340 lines 1/340\
|
||||
HELP: Ctrl-S = save | Ctrl-Q = quit | Ctrl-F = find \
|
||||
";
|
||||
|
||||
TEST(pty, testLongestPossibleCharacter) {
|
||||
EXPECT_EQ(60, strlen("\e[21;22;27;24;25;29;38;2;255;255;255;48;2;255;255;"
|
||||
"255m\377\277\277\277\277\277"));
|
||||
struct Buffer b = {0};
|
||||
struct Pty *pty = NewPty();
|
||||
const char *s = "\e[1;2;3;4;5;6;7;9m"
|
||||
"h"
|
||||
"\e[0;"
|
||||
"38;2;255;255;255;"
|
||||
"48;2;255;255;255m"
|
||||
"\377\277\277\277\277\277"
|
||||
"\e[0m";
|
||||
PtyWrite(pty, s, strlen(s));
|
||||
PtyAppendLine(pty, &b, 0);
|
||||
AppendChar(&b, '\0');
|
||||
EXPECT_STREQ("\e[1;2;4;7;5;9m"
|
||||
"𝒉"
|
||||
"\e[22;24;27;25;29;38;2;255;255;255;48;2;255;255;255m"
|
||||
" "
|
||||
"\e[0m▂ "
|
||||
" ",
|
||||
b.p);
|
||||
FreePty(pty);
|
||||
free(b.p);
|
||||
}
|
||||
|
||||
TEST(pty, test) {
|
||||
struct Pty *pty = NewPty();
|
||||
PtyWrite(pty, kKiloAnsi, strlen(kKiloAnsi));
|
||||
EXPECT_STREQN(kKiloGolden, pty->wcs, wcslen(kKiloGolden));
|
||||
FreePty(pty);
|
||||
}
|
||||
|
||||
BENCH(pty, bench) {
|
||||
struct Pty *pty = NewPty();
|
||||
EZBENCH2("pty write ascii", donothing,
|
||||
PtyWrite(pty, hyperion, sizeof(hyperion) - 1));
|
||||
EZBENCH2("pty write kilo", donothing,
|
||||
PtyWrite(pty, kKiloAnsi, sizeof(kKiloAnsi) - 1));
|
||||
FreePty(pty);
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/errno.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "tool/build/lib/xlat.h"
|
||||
|
||||
TEST(xlaterrno, test) {
|
||||
EXPECT_EQ(95, XlatErrno(EOPNOTSUPP));
|
||||
EXPECT_EQ(90, XlatErrno(EMSGSIZE));
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -95,19 +95,6 @@ o/$(MODE)/tool/build/%.com.dbg: \
|
|||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/tool/build/blinkenlights.com: \
|
||||
o/$(MODE)/tool/build/blinkenlights.com.dbg \
|
||||
o/$(MODE)/third_party/zip/zip.com \
|
||||
o/$(MODE)/tool/build/symtab.com \
|
||||
$(VM)
|
||||
@$(MAKE_OBJCOPY)
|
||||
@$(MAKE_SYMTAB_CREATE)
|
||||
@$(MAKE_SYMTAB_ZIP)
|
||||
|
||||
o/$(MODE)/tool/build/emulator.o: private \
|
||||
COPTS += \
|
||||
-fno-sanitize=pointer-overflow
|
||||
|
||||
o/$(MODE)/tool/build/dso/sandbox.so.zip.o \
|
||||
o/$(MODE)/tool/build/mkdir.zip.o \
|
||||
o/$(MODE)/tool/build/chmod.zip.o \
|
||||
|
@ -165,8 +152,6 @@ o/$(MODE)/tool/build/pledge.com.dbg: \
|
|||
|
||||
.PHONY: o/$(MODE)/tool/build
|
||||
o/$(MODE)/tool/build: \
|
||||
o/$(MODE)/tool/build/emucrt \
|
||||
o/$(MODE)/tool/build/emubin \
|
||||
o/$(MODE)/tool/build/lib \
|
||||
$(TOOL_BUILD_BINS) \
|
||||
$(TOOL_BUILD_CHECKS)
|
||||
|
|
318
tool/build/dis.c
318
tool/build/dis.c
|
@ -1,318 +0,0 @@
|
|||
/*-*- 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 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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 "tool/build/lib/dis.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/elf/def.h"
|
||||
#include "libc/elf/elf.h"
|
||||
#include "libc/elf/struct/ehdr.h"
|
||||
#include "libc/elf/struct/shdr.h"
|
||||
#include "libc/elf/struct/sym.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/struct/importobjectheader.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "third_party/xed/x86.h"
|
||||
#include "tool/build/lib/high.h"
|
||||
#include "tool/build/lib/loader.h"
|
||||
|
||||
#define HEXWIDTH 8
|
||||
|
||||
const char *const kRealSymbols[] = {
|
||||
"a20", "ape.mbrpad", "ape.str",
|
||||
"ape_disk", "ape_grub", "ape_mz",
|
||||
"apesh", "dsknfo", "e820",
|
||||
"gdt", "golong", "hiload",
|
||||
"lcheck", "longmodeloader", "pc",
|
||||
"pcread", "pinit", "realmodeloader",
|
||||
"rldie", "rvputs", "sconf",
|
||||
"sinit", "sinit4", "str.cpuid",
|
||||
"str.crlf", "str.dsknfo", "str.e820",
|
||||
"str.error", "str.long", "str.memory",
|
||||
"str.oldskool", "stub", "unreal",
|
||||
};
|
||||
|
||||
const char *const kLegacySymbols[] = {
|
||||
"ape_grub_entry",
|
||||
};
|
||||
|
||||
bool boop;
|
||||
long cursym;
|
||||
Elf64_Ehdr *elf;
|
||||
Elf64_Shdr *sec;
|
||||
struct Dis dis[1];
|
||||
struct Machine m[1];
|
||||
struct Elf diself[1];
|
||||
char codebuf[256];
|
||||
char optspecbuf[128];
|
||||
const Elf64_Sym *syms;
|
||||
char *symstrs, *secstrs;
|
||||
size_t i, j, k, l, size, skip, symcount;
|
||||
|
||||
bool IsRealSymbol(const char *s) {
|
||||
int m, l, r, x;
|
||||
l = 0;
|
||||
r = ARRAYLEN(kRealSymbols) - 1;
|
||||
while (l <= r) {
|
||||
m = (l + r) >> 1;
|
||||
x = strcmp(s, kRealSymbols[m]);
|
||||
if (x < 0) {
|
||||
r = m - 1;
|
||||
} else if (x > 0) {
|
||||
l = m + 1;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsLegacySymbol(const char *s) {
|
||||
int m, l, r, x;
|
||||
l = 0;
|
||||
r = ARRAYLEN(kLegacySymbols) - 1;
|
||||
while (l <= r) {
|
||||
m = (l + r) >> 1;
|
||||
x = strcmp(s, kLegacySymbols[m]);
|
||||
if (x < 0) {
|
||||
r = m - 1;
|
||||
} else if (x > 0) {
|
||||
l = m + 1;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SetSymbol(bool printit) {
|
||||
if (!boop) {
|
||||
printf("\n");
|
||||
boop = true;
|
||||
}
|
||||
if (printit) {
|
||||
printf("\e[38;5;%dm%s\e[0m:\n", g_high.label, symstrs + syms[k].st_name);
|
||||
}
|
||||
if (IsRealSymbol(symstrs + syms[k].st_name)) {
|
||||
if (m->mode != XED_MACHINE_MODE_REAL) {
|
||||
printf("\t\e[38;5;%dm.code16\e[0m\n", g_high.keyword);
|
||||
}
|
||||
m->mode = XED_MACHINE_MODE_REAL;
|
||||
} else if (IsLegacySymbol(symstrs + syms[k].st_name)) {
|
||||
if (m->mode != XED_MACHINE_MODE_LEGACY_32) {
|
||||
printf("\t\e[38;5;%dm.code32\e[0m\n", g_high.keyword);
|
||||
}
|
||||
m->mode = XED_MACHINE_MODE_LEGACY_32;
|
||||
} else {
|
||||
if (m->mode != XED_MACHINE_MODE_LONG_64) {
|
||||
printf("\t\e[38;5;%dm.code64\e[0m\n", g_high.keyword);
|
||||
}
|
||||
m->mode = XED_MACHINE_MODE_LONG_64;
|
||||
}
|
||||
cursym = k;
|
||||
if (syms[k].st_size) {
|
||||
skip = syms[k].st_size;
|
||||
} else {
|
||||
skip = -1;
|
||||
for (l = 0; l < symcount; ++l) {
|
||||
if (syms[l].st_shndx == i && syms[l].st_name &&
|
||||
syms[l].st_value > syms[cursym].st_value) {
|
||||
skip = MIN(skip, syms[l].st_value - syms[cursym].st_value);
|
||||
}
|
||||
}
|
||||
if (skip == -1) {
|
||||
skip = sec->sh_addr + sec->sh_size - syms[cursym].st_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PrintSymbolName(void) {
|
||||
bool done;
|
||||
done = false;
|
||||
boop = false;
|
||||
for (k = 0; k < symcount; ++k) {
|
||||
if (syms[k].st_value == sec->sh_addr + j && syms[k].st_name) {
|
||||
if (!done && syms[k].st_size) {
|
||||
SetSymbol(true);
|
||||
done = true;
|
||||
} else {
|
||||
if (!boop) {
|
||||
printf("\n");
|
||||
boop = true;
|
||||
}
|
||||
printf("\e[38;5;%dm%s\e[0m:\n", g_high.label,
|
||||
symstrs + syms[k].st_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (done) {
|
||||
return;
|
||||
}
|
||||
for (k = 0; k < symcount; ++k) {
|
||||
if (ELF64_ST_TYPE(syms[k].st_info) && syms[k].st_name &&
|
||||
syms[k].st_value == sec->sh_addr + j) {
|
||||
SetSymbol(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (k = 0; k < symcount; ++k) {
|
||||
if (syms[k].st_name && syms[k].st_value == sec->sh_addr + j) {
|
||||
SetSymbol(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (cursym != -1 && syms[cursym].st_size &&
|
||||
sec->sh_addr + j >= syms[cursym].st_value + syms[cursym].st_size) {
|
||||
cursym = -1;
|
||||
skip = 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool Ild(void) {
|
||||
int remain;
|
||||
remain = 15;
|
||||
if (cursym != -1 && syms[cursym].st_size) {
|
||||
remain =
|
||||
(syms[cursym].st_value + syms[cursym].st_size) - (sec->sh_addr + j);
|
||||
}
|
||||
xed_decoded_inst_zero_set_mode(dis->xedd, m->mode);
|
||||
xed_instruction_length_decode(dis->xedd, (char *)elf + sec->sh_offset + j,
|
||||
remain);
|
||||
skip = dis->xedd->op.error ? 1 : MAX(1, dis->xedd->length);
|
||||
return !dis->xedd->op.error;
|
||||
}
|
||||
|
||||
bool IsCode(void) {
|
||||
if (!(sec->sh_flags & SHF_EXECINSTR)) return false;
|
||||
if (cursym != -1 && ELF64_ST_TYPE(syms[cursym].st_info) == STT_OBJECT) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsBss(void) {
|
||||
return sec->sh_type == SHT_NOBITS;
|
||||
}
|
||||
|
||||
void Disassemble(void) {
|
||||
int c;
|
||||
bool istext;
|
||||
cursym = -1;
|
||||
secstrs = GetElfSectionNameStringTable(elf, size);
|
||||
symstrs = GetElfStringTable(elf, size);
|
||||
syms = GetElfSymbolTable(elf, size, &symcount);
|
||||
for (i = 0; i < elf->e_shnum; ++i) {
|
||||
sec = GetElfSectionHeaderAddress(elf, size, i);
|
||||
if (!sec->sh_size) continue;
|
||||
if (!(sec->sh_flags & SHF_ALLOC)) continue;
|
||||
printf("\n\t\e[38;5;%dm.section\e[0m %s\n", g_high.keyword,
|
||||
secstrs + sec->sh_name);
|
||||
for (j = 0; j < sec->sh_size; j += MAX(1, skip)) {
|
||||
PrintSymbolName();
|
||||
if (cursym == -1) continue;
|
||||
if (sec->sh_type == SHT_NOBITS) {
|
||||
printf("\t\e[38;5;%dm.zero\e[0m\t%ld\n", g_high.keyword, skip);
|
||||
} else if (IsCode()) {
|
||||
if (Ild()) {
|
||||
dis->addr = sec->sh_addr + j;
|
||||
DisInst(dis, codebuf, DisSpec(dis->xedd, optspecbuf));
|
||||
printf("\t%s\n", codebuf);
|
||||
} else {
|
||||
printf("\t.wut\t%ld\n", dis->xedd->op.error);
|
||||
}
|
||||
} else {
|
||||
for (k = 0; k < skip; ++k) {
|
||||
if (!(k & (HEXWIDTH - 1))) {
|
||||
if (k) {
|
||||
printf(" \e[38;5;%dm# %#.*s\e[0m\n", g_high.comment, HEXWIDTH,
|
||||
(unsigned char *)elf + sec->sh_offset + j + k - HEXWIDTH);
|
||||
}
|
||||
printf("\t\e[38;5;%dm.byte\e[0m\t", g_high.keyword);
|
||||
} else if (k) {
|
||||
printf(",");
|
||||
}
|
||||
printf("0x%02x", ((unsigned char *)elf)[sec->sh_offset + j + k]);
|
||||
}
|
||||
if (k) {
|
||||
if (!(k & (HEXWIDTH - 1))) {
|
||||
printf(" \e[38;5;%dm# %#.*s\e[0m\n", g_high.comment, HEXWIDTH,
|
||||
(unsigned char *)elf + sec->sh_offset + j + skip - HEXWIDTH);
|
||||
} else {
|
||||
for (l = 0; l < HEXWIDTH - (k & (HEXWIDTH - 1)); ++l) {
|
||||
printf(" ");
|
||||
}
|
||||
printf(" \e[38;5;%dm# %#.*s\e[0m\n", g_high.comment,
|
||||
skip - ROUNDDOWN(skip, HEXWIDTH),
|
||||
(unsigned char *)elf + sec->sh_offset + j +
|
||||
ROUNDDOWN(skip, HEXWIDTH));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
ShowCrashReports();
|
||||
int fd;
|
||||
void *map;
|
||||
struct stat st;
|
||||
const char *path;
|
||||
if (argc == 1) {
|
||||
fprintf(stderr, "USAGE: %s ELF\n", program_invocation_name);
|
||||
exit(1);
|
||||
} else {
|
||||
path = argv[1];
|
||||
}
|
||||
if ((fd = open(path, O_RDONLY)) == -1) {
|
||||
fprintf(stderr, "ERROR: NOT FOUND: %`'s\n", path);
|
||||
exit(1);
|
||||
}
|
||||
CHECK_NE(-1, fstat(fd, &st));
|
||||
CHECK_NE(0, st.st_size);
|
||||
CHECK_NE(MAP_FAILED,
|
||||
(map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)));
|
||||
if (memcmp(map, ELFMAG, 4)) {
|
||||
fprintf(stderr, "ERROR: NOT AN ELF: %`'s\n", path);
|
||||
exit(1);
|
||||
}
|
||||
m->mode = XED_MACHINE_MODE_LONG_64;
|
||||
g_high.keyword = 155;
|
||||
g_high.reg = 215;
|
||||
g_high.literal = 182;
|
||||
g_high.label = 221;
|
||||
g_high.comment = 112;
|
||||
g_high.quote = 180;
|
||||
dis->m = m;
|
||||
diself->prog = path;
|
||||
LoadDebugSymbols(diself);
|
||||
DisLoadElf(dis, diself);
|
||||
LOGIFNEG1(close(fd));
|
||||
elf = map;
|
||||
size = st.st_size;
|
||||
Disassemble();
|
||||
LOGIFNEG1(munmap(map, st.st_size));
|
||||
return 0;
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
|
||||
PKGS += TOOL_BUILD_EMUBIN
|
||||
|
||||
TOOL_BUILD_EMUBIN_BINS = \
|
||||
o/$(MODE)/tool/build/emubin/sha256.bin \
|
||||
o/$(MODE)/tool/build/emubin/sha256.bin.dbg \
|
||||
o/$(MODE)/tool/build/emubin/mips.bin \
|
||||
o/$(MODE)/tool/build/emubin/mips.bin.dbg \
|
||||
o/$(MODE)/tool/build/emubin/prime.bin \
|
||||
o/$(MODE)/tool/build/emubin/prime.bin.dbg \
|
||||
o/$(MODE)/tool/build/emubin/pi.bin \
|
||||
o/$(MODE)/tool/build/emubin/pi.bin.dbg
|
||||
|
||||
TOOL_BUILD_EMUBIN_A = o/$(MODE)/tool/build/emubin/emubin.a
|
||||
TOOL_BUILD_EMUBIN_FILES := $(wildcard tool/build/emubin/*)
|
||||
TOOL_BUILD_EMUBIN_SRCS = $(filter %.c,$(TOOL_BUILD_EMUBIN_FILES))
|
||||
TOOL_BUILD_EMUBIN_HDRS = $(filter %.h,$(TOOL_BUILD_EMUBIN_FILES))
|
||||
|
||||
TOOL_BUILD_EMUBIN_OBJS = \
|
||||
$(TOOL_BUILD_EMUBIN_SRCS:%.c=o/$(MODE)/%.o)
|
||||
|
||||
TOOL_BUILD_EMUBIN_CHECKS = \
|
||||
$(TOOL_BUILD_EMUBIN_HDRS:%=o/$(MODE)/%.ok)
|
||||
|
||||
TOOL_BUILD_EMUBIN_DIRECTDEPS = \
|
||||
LIBC_INTRIN \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_STUBS \
|
||||
LIBC_TINYMATH
|
||||
|
||||
TOOL_BUILD_EMUBIN_DEPS := \
|
||||
$(call uniq,$(foreach x,$(TOOL_BUILD_EMUBIN_DIRECTDEPS),$($(x))))
|
||||
|
||||
$(TOOL_BUILD_EMUBIN_A): \
|
||||
tool/build/emubin/ \
|
||||
$(TOOL_BUILD_EMUBIN_A).pkg \
|
||||
$(TOOL_BUILD_EMUBIN_OBJS)
|
||||
|
||||
$(TOOL_BUILD_EMUBIN_A).pkg: \
|
||||
$(TOOL_BUILD_EMUBIN_OBJS) \
|
||||
$(foreach x,$(TOOL_BUILD_EMUBIN_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/tool/build/emubin/%.bin.dbg: \
|
||||
$(TOOL_BUILD_EMUCRT) \
|
||||
$(TOOL_BUILD_EMUBIN_DEPS) \
|
||||
$(TOOL_BUILD_EMUBIN_A) \
|
||||
o/$(MODE)/tool/build/emubin/%.o \
|
||||
$(TOOL_BUILD_EMUBIN_A).pkg
|
||||
@$(ELFLINK) -e emucrt -z common-page-size=0x10 -z max-page-size=0x10
|
||||
|
||||
o/tiny/tool/build/emubin/spiral.bin.dbg: \
|
||||
$(TOOL_BUILD_EMUBIN_DEPS) \
|
||||
o/tiny/tool/build/emubin/spiral.real.o
|
||||
@$(ELFLINK) -z common-page-size=0x10 -z max-page-size=0x10 -T tool/build/emucrt/real.lds
|
||||
|
||||
o/tiny/tool/build/emubin/mdatest.bin.dbg: \
|
||||
$(TOOL_BUILD_EMUBIN_DEPS) \
|
||||
o/tiny/tool/build/emubin/mdatest.real.o
|
||||
@$(ELFLINK) -z common-page-size=0x10 -z max-page-size=0x10 -T tool/build/emucrt/real.lds
|
||||
|
||||
$(TOOL_BUILD_EMUBIN_OBJS): private \
|
||||
CFLAGS += \
|
||||
$(NO_MAGIC)
|
||||
|
||||
.PHONY: o/$(MODE)/tool/build/emubin
|
||||
o/$(MODE)/tool/build/emubin:
|
|
@ -1,31 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/linux/exit.h"
|
||||
#include "libc/linux/fstat.h"
|
||||
#include "libc/linux/mmap.h"
|
||||
#include "libc/linux/open.h"
|
||||
|
||||
struct stat st;
|
||||
|
||||
void _start(void) {
|
||||
long fd = LinuxOpen("/etc/passwd", 0, 0);
|
||||
LinuxFstat(fd, &st);
|
||||
LinuxMmap((void *)0x000000000000, st.st_size, 1, 2, fd, 0);
|
||||
LinuxExit(0);
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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 "tool/build/emubin/poke.h"
|
||||
#include "tool/build/emubin/real.h"
|
||||
#include "tool/build/emubin/realstart.inc"
|
||||
|
||||
/*
|
||||
m=tiny; make -j12 MODE=$m o/$m/tool/build/{tinyemu,emulator}.com \
|
||||
o/$m/tool/build/emubin/mdatest.bin && o/$m/tool/build/emulator.com \
|
||||
-rt o/$m/tool/build/emubin/mdatest.bin
|
||||
*/
|
||||
|
||||
static void MdaTest(uint16_t p[25][80]) {
|
||||
int i, y, x;
|
||||
for (i = 0; i < 256; ++i) {
|
||||
y = i / 16;
|
||||
x = i % 16 * 3;
|
||||
POKE(p[y][x + 0], i << 8 | "0123456789abcdef"[(i & 0xf0) >> 4]);
|
||||
POKE(p[y][x + 1], i << 8 | "0123456789abcdef"[(i & 0x0f) >> 0]);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
SetVideoMode(7);
|
||||
SetEs(0xb0000 >> 4);
|
||||
MdaTest((void *)0);
|
||||
for (;;) __builtin_ia32_pause();
|
||||
}
|
|
@ -1,154 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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 "tool/build/emubin/metalsha256.h"
|
||||
#include "libc/intrin/repstosb.h"
|
||||
|
||||
#define ROTR(a, b) (((a) >> (b)) | ((a) << (32 - (b))))
|
||||
#define CH(x, y, z) (((x) & (y)) ^ (~(x) & (z)))
|
||||
#define MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
|
||||
#define EP0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
|
||||
#define EP1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
|
||||
#define SIG0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ ((x) >> 3))
|
||||
#define SIG1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ ((x) >> 10))
|
||||
|
||||
const uint32_t kMetalSha256Tab[64] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
|
||||
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
|
||||
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
|
||||
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
|
||||
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
|
||||
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
|
||||
};
|
||||
|
||||
void MetalSha256Cleanup(struct MetalSha256Ctx *ctx) {
|
||||
repstosb(ctx, 0, sizeof(*ctx));
|
||||
asm("pxor\t%xmm0,%xmm0\n\t"
|
||||
"pxor\t%xmm1,%xmm1\n\t"
|
||||
"pxor\t%xmm2,%xmm2\n\t"
|
||||
"pxor\t%xmm3,%xmm3\n\t"
|
||||
"pxor\t%xmm4,%xmm4\n\t"
|
||||
"pxor\t%xmm5,%xmm5\n\t"
|
||||
"pxor\t%xmm6,%xmm6\n\t"
|
||||
"pxor\t%xmm7,%xmm7");
|
||||
}
|
||||
|
||||
void MetalSha256Transform(uint32_t state[8], const uint8_t data[64]) {
|
||||
unsigned i;
|
||||
uint32_t a, b, c, d, e, f, g, h, t1, t2, m[64];
|
||||
for (i = 0; i < 16; ++i, data += 4) {
|
||||
m[i] = (uint32_t)data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
|
||||
}
|
||||
for (; i < 64; ++i) {
|
||||
m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
|
||||
}
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
f = state[5];
|
||||
g = state[6];
|
||||
h = state[7];
|
||||
for (i = 0; i < 64; ++i) {
|
||||
t1 = h + EP1(e) + CH(e, f, g) + kMetalSha256Tab[i] + m[i];
|
||||
t2 = EP0(a) + MAJ(a, b, c);
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + t1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = t1 + t2;
|
||||
}
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
state[5] += f;
|
||||
state[6] += g;
|
||||
state[7] += h;
|
||||
}
|
||||
|
||||
void MetalSha256Init(struct MetalSha256Ctx *ctx) {
|
||||
ctx->datalen = 0;
|
||||
ctx->bitlen = 0;
|
||||
ctx->state[0] = 0x6a09e667;
|
||||
ctx->state[1] = 0xbb67ae85;
|
||||
ctx->state[2] = 0x3c6ef372;
|
||||
ctx->state[3] = 0xa54ff53a;
|
||||
ctx->state[4] = 0x510e527f;
|
||||
ctx->state[5] = 0x9b05688c;
|
||||
ctx->state[6] = 0x1f83d9ab;
|
||||
ctx->state[7] = 0x5be0cd19;
|
||||
}
|
||||
|
||||
void MetalSha256Update(struct MetalSha256Ctx *ctx, const uint8_t *data,
|
||||
long size) {
|
||||
long i;
|
||||
for (i = 0; i < size; ++i) {
|
||||
ctx->data[ctx->datalen] = data[i];
|
||||
ctx->datalen++;
|
||||
if (ctx->datalen == 64) {
|
||||
MetalSha256Transform(ctx->state, ctx->data);
|
||||
ctx->bitlen += 512;
|
||||
ctx->datalen = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MetalSha256Final(struct MetalSha256Ctx *ctx, uint8_t *hash) {
|
||||
long i;
|
||||
i = ctx->datalen;
|
||||
ctx->data[i++] = 0x80;
|
||||
if (ctx->datalen < 56) {
|
||||
repstosb(ctx->data + i, 0, 56 - i);
|
||||
} else {
|
||||
repstosb(ctx->data + i, 0, 64 - i);
|
||||
MetalSha256Transform(ctx->state, ctx->data);
|
||||
repstosb(ctx->data, 0, 56);
|
||||
}
|
||||
ctx->bitlen += ctx->datalen * 8;
|
||||
ctx->data[63] = ctx->bitlen;
|
||||
ctx->data[62] = ctx->bitlen >> 8;
|
||||
ctx->data[61] = ctx->bitlen >> 16;
|
||||
ctx->data[60] = ctx->bitlen >> 24;
|
||||
ctx->data[59] = ctx->bitlen >> 32;
|
||||
ctx->data[58] = ctx->bitlen >> 40;
|
||||
ctx->data[57] = ctx->bitlen >> 48;
|
||||
ctx->data[56] = ctx->bitlen >> 56;
|
||||
MetalSha256Transform(ctx->state, ctx->data);
|
||||
for (i = 0; i < 4; ++i) {
|
||||
hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0xff;
|
||||
hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0xff;
|
||||
hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0xff;
|
||||
hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0xff;
|
||||
hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0xff;
|
||||
hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0xff;
|
||||
hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0xff;
|
||||
hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0xff;
|
||||
}
|
||||
MetalSha256Cleanup(ctx);
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_EMUBIN_METALSHA256_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_EMUBIN_METALSHA256_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct MetalSha256Ctx {
|
||||
uint8_t data[64];
|
||||
uint32_t datalen;
|
||||
uint64_t bitlen;
|
||||
uint32_t state[8];
|
||||
};
|
||||
|
||||
void MetalSha256Init(struct MetalSha256Ctx *);
|
||||
void MetalSha256Update(struct MetalSha256Ctx *, const uint8_t *, long);
|
||||
void MetalSha256Final(struct MetalSha256Ctx *, uint8_t *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_EMUBIN_METALSHA256_H_ */
|
|
@ -1,49 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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 "tool/build/emubin/metalsha256.h"
|
||||
|
||||
//#define DISINGENUOUS /* 100 million NOPs is still 100 MIPS lool */
|
||||
|
||||
static void Print(uint8_t c) {
|
||||
asm volatile("out\t%0,$0xE9" : /* no outputs */ : "a"(c) : "memory");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
#ifdef DISINGENUOUS
|
||||
for (i = 0; i < 150 * 1000 * 1000 / 3; ++i) asm("nop");
|
||||
#else
|
||||
size_t size;
|
||||
struct MetalSha256Ctx ctx;
|
||||
unsigned char hash[32], *data;
|
||||
data = (void *)0x7fffffff0000;
|
||||
size = 0x10000;
|
||||
MetalSha256Init(&ctx);
|
||||
for (i = 0; i < 10; ++i) {
|
||||
MetalSha256Update(&ctx, data, size);
|
||||
}
|
||||
MetalSha256Final(&ctx, hash);
|
||||
for (i = 0; i < sizeof(hash); ++i) {
|
||||
Print("0123456789abcdef"[(hash[i] >> 4) & 15]);
|
||||
Print("0123456789abcdef"[(hash[i] >> 0) & 15]);
|
||||
}
|
||||
Print('\n');
|
||||
#endif
|
||||
return 0;
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/math.h"
|
||||
|
||||
#if 1
|
||||
#define FLOAT long double
|
||||
#define SQRT sqrtl
|
||||
#else
|
||||
#define FLOAT float
|
||||
#define SQRT sqrt
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Computes π w/ François Viète method.
|
||||
*
|
||||
* make -j8 MODE=tiny
|
||||
* o/tiny/tool/build/emulator.com.dbg -t o/tiny/tool/build/pi.bin
|
||||
*
|
||||
*/
|
||||
FLOAT Main(void) {
|
||||
long i, n;
|
||||
FLOAT pi, q, t;
|
||||
n = VEIL("r", 10);
|
||||
q = 0;
|
||||
t = 1;
|
||||
for (i = 0; i < n; ++i) {
|
||||
q += 2;
|
||||
q = SQRT(q);
|
||||
t *= q / 2;
|
||||
}
|
||||
return 2 / t;
|
||||
}
|
||||
|
||||
volatile FLOAT st0;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
st0 = Main();
|
||||
return 0;
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_EMUBIN_POKE_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_EMUBIN_POKE_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define POKE(MEM, VAL) \
|
||||
asm volatile("mov%z0\t%1,%%es:%0" : "=m"(MEM) : "Qi"((typeof(MEM))(VAL)))
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_EMUBIN_POKE_H_ */
|
|
@ -1,41 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
|
||||
dontinline bool IsPrime(int i) {
|
||||
int j, n;
|
||||
for (j = 3, n = VEIL("r", 3); j <= n; j += 2) {
|
||||
if (VEIL("r", i) % VEIL("r", j) == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Places 10th prime number in RAX.
|
||||
*/
|
||||
int main(int argc, char *argv[]) {
|
||||
int i, c;
|
||||
for (c = i = 0; c < VEIL("r", 10); ++i) {
|
||||
if (IsPrime(i)) {
|
||||
++c;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_EMUBIN_REAL_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_EMUBIN_REAL_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
forceinline void SetEs(int base) {
|
||||
asm volatile("mov%z0\t%0,%%es" : /* no outputs */ : "r"(base));
|
||||
}
|
||||
|
||||
forceinline void SetVideoMode(int mode) {
|
||||
asm volatile("int\t$0x10"
|
||||
: /* no outputs */
|
||||
: "a"(mode));
|
||||
}
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_EMUBIN_REAL_H_ */
|
|
@ -1,7 +0,0 @@
|
|||
asm(".section .start,\"ax\",@progbits\n\t"
|
||||
".globl\t_start\n"
|
||||
"_start:\n\t"
|
||||
"jmp\t1f\n1:\t"
|
||||
"call\tmain\n\t"
|
||||
"nop\n\t"
|
||||
".previous");
|
|
@ -1,52 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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 "tool/build/emubin/metalsha256.h"
|
||||
|
||||
#define SHA256_BLOCK_SIZE 32
|
||||
|
||||
#define OUTB(PORT, BYTE) asm volatile("outb\t%b1,%0" : : "N"(PORT), "a"(BYTE))
|
||||
#define INW(PORT) \
|
||||
({ \
|
||||
int Word; \
|
||||
asm volatile("in\t%1,%0" : "=a"(Word) : "N"(PORT)); \
|
||||
Word; \
|
||||
})
|
||||
|
||||
static void PrintHexBytes(int n, const uint8_t p[n]) {
|
||||
int i;
|
||||
for (i = 0; i < n; ++i) {
|
||||
OUTB(0xE9, "0123456789abcdef"[(p[i] >> 4) & 15]);
|
||||
OUTB(0xE9, "0123456789abcdef"[(p[i] >> 0) & 15]);
|
||||
}
|
||||
OUTB(0xE9, '\n');
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int rc;
|
||||
uint8_t hash[32], buf[1];
|
||||
struct MetalSha256Ctx ctx;
|
||||
MetalSha256Init(&ctx);
|
||||
while ((rc = INW(0xE9)) != -1) {
|
||||
buf[0] = rc;
|
||||
MetalSha256Update(&ctx, buf, sizeof(buf));
|
||||
}
|
||||
MetalSha256Final(&ctx, hash);
|
||||
PrintHexBytes(sizeof(hash), hash);
|
||||
return 0;
|
||||
}
|
|
@ -1,138 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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 "tool/build/emubin/poke.h"
|
||||
#include "tool/build/emubin/real.h"
|
||||
#include "tool/build/emubin/realstart.inc"
|
||||
|
||||
#define signbit(x) __builtin_signbit(x)
|
||||
|
||||
static const unsigned char kBlocks[] = {
|
||||
[0b1111] = 0xdb, // █
|
||||
[0b0110] = 0xdb, // █
|
||||
[0b1001] = 0xdb, // █
|
||||
[0b0111] = 0xdb, // █
|
||||
[0b1011] = 0xdb, // █
|
||||
[0b1110] = 0xdb, // █
|
||||
[0b1101] = 0xdb, // █
|
||||
[0b1100] = 0xdc, // ▄
|
||||
[0b0100] = 0xdc, // ▄
|
||||
[0b1000] = 0xdc, // ▄
|
||||
[0b0101] = 0xdd, // ▌
|
||||
[0b1010] = 0xde, // ▐
|
||||
[0b0011] = 0xdf, // ▀
|
||||
[0b0010] = 0xdf, // ▀
|
||||
[0b0001] = 0xdf, // ▀
|
||||
};
|
||||
|
||||
forceinline void *SetMemory(void *di, int al, unsigned long cx) {
|
||||
asm("rep stosb"
|
||||
: "=D"(di), "=c"(cx), "=m"(*(char(*)[cx])di)
|
||||
: "0"(di), "1"(cx), "a"(al));
|
||||
return di;
|
||||
}
|
||||
|
||||
forceinline long double pi(void) {
|
||||
long double x;
|
||||
asm("fldpi" : "=t"(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
forceinline long double tau(void) {
|
||||
return pi() * 2;
|
||||
}
|
||||
|
||||
forceinline void sincosl_(long double x, long double *sin, long double *cos) {
|
||||
asm("fsincos" : "=t"(*sin), "=u"(*cos) : "0"(x));
|
||||
}
|
||||
|
||||
forceinline long double atan2l_(long double x, long double y) {
|
||||
asm("fpatan" : "+t"(x) : "u"(y) : "st(1)");
|
||||
return x;
|
||||
}
|
||||
|
||||
forceinline long lrintl_(long double x) {
|
||||
long i;
|
||||
asm("fistp%z0\t%0" : "=m"(i) : "t"(x) : "st");
|
||||
return i;
|
||||
}
|
||||
|
||||
forceinline long double truncl_(long double x) {
|
||||
asm("frndint" : "+t"(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
forceinline long double fabsl_(long double x) {
|
||||
asm("fabs" : "+t"(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
forceinline long lroundl_(long double x) {
|
||||
int s = signbit(x);
|
||||
x = truncl_(fabsl_(x) + .5);
|
||||
if (s) x = -x;
|
||||
return lrintl_(x);
|
||||
}
|
||||
|
||||
static unsigned short GetFpuControlWord(void) {
|
||||
unsigned short cw;
|
||||
asm("fnstcw\t%0" : "=m"(cw));
|
||||
return cw;
|
||||
}
|
||||
|
||||
static void SetFpuControlWord(unsigned short cw) {
|
||||
asm volatile("fldcw\t%0" : /* no outputs */ : "m"(cw));
|
||||
}
|
||||
|
||||
static void InitializeFpu(void) {
|
||||
asm("fninit");
|
||||
}
|
||||
|
||||
static void SetTruncationRounding(void) {
|
||||
SetFpuControlWord(GetFpuControlWord() | 0x0c00);
|
||||
}
|
||||
|
||||
static void spiral(unsigned char p[25][80][2], unsigned char B[25][80], int g) {
|
||||
int i, x, y;
|
||||
long double a, b, u, v, h;
|
||||
for (a = b = i = 0; i < 1000; ++i) {
|
||||
sincosl_(a, &u, &v);
|
||||
h = atan2l_(u, v) - .333L * g;
|
||||
x = lroundl_(80 + u * b);
|
||||
y = lroundl_(25 + v * b * (1. / ((266 / 64.) * (900 / 1600.))));
|
||||
B[y >> 1][x >> 1] |= 1 << ((y & 1) << 1 | (x & 1));
|
||||
POKE(p[y >> 1][x >> 1][0], kBlocks[B[y >> 1][x >> 1]]);
|
||||
POKE(p[y >> 1][x >> 1][1], (lrintl_((h + tau()) * (8 / tau())) & 7) + 8);
|
||||
a += .05;
|
||||
b += .05;
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
int g;
|
||||
InitializeFpu();
|
||||
SetTruncationRounding();
|
||||
SetVideoMode(3);
|
||||
for (g = 0;; ++g) {
|
||||
SetEs(0);
|
||||
SetMemory((void *)(0x7c00 + 512), 0, 25 * 80);
|
||||
SetEs(0xb8000 >> 4);
|
||||
/* SetMemory((void *)0, 0, 25 * 80 * 2); */
|
||||
spiral((void *)0, (void *)(0x7c00 + 512), g);
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/macros.internal.h"
|
||||
|
||||
.section .start,"ax",@progbits
|
||||
emucrt: bofram 9f
|
||||
movslq (%rsp),%rdi # argc
|
||||
lea 8(%rsp),%rsi # argv
|
||||
lea 24(%rsp,%rdi,8),%rdx # envp
|
||||
.weak main
|
||||
call main
|
||||
movzbl %al,%edi
|
||||
mov $0xE7,%eax
|
||||
syscall
|
||||
9: .endfn emucrt,globl
|
|
@ -1,80 +0,0 @@
|
|||
/*-*- mode: ld-script; indent-tabs-mode: nil; tab-width: 2; coding: utf-8 -*-│
|
||||
│vi: set et sts=2 tw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS {
|
||||
|
||||
.text IMAGE_BASE_VIRTUAL : {
|
||||
*(.start)
|
||||
KEEP(*(.initprologue))
|
||||
KEEP(*(SORT_BY_NAME(.init.*)))
|
||||
KEEP(*(SORT_NONE(.init)))
|
||||
KEEP(*(.initepilogue))
|
||||
*(.text .text.*)
|
||||
*(.privileged)
|
||||
*(.rodata .rodata.*)
|
||||
KEEP(*(.initroprologue))
|
||||
KEEP(*(SORT_BY_NAME(.initro.*)))
|
||||
KEEP(*(.initroepilogue))
|
||||
*(.ubsan.types)
|
||||
*(.ubsan.data)
|
||||
*(.data .data.*)
|
||||
*(.bss .bss.*)
|
||||
*(COMMON)
|
||||
}
|
||||
|
||||
.gnu_debuglink 0 : { *(.gnu_debuglink) }
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
.debug_pubtypes 0 : { *(.debug_pubtypes) }
|
||||
.debug_ranges 0 : { *(.debug_ranges) }
|
||||
.debug_macro 0 : { *(.debug_macro) }
|
||||
.debug_addr 0 : { *(.debug_addr) }
|
||||
.gnu.attributes 0 : { KEEP(*(.gnu.attributes)) }
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.GCC.command.line)
|
||||
*(.comment)
|
||||
*(.discard)
|
||||
*(.yoink)
|
||||
*(.*)
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
|
||||
PKGS += TOOL_BUILD_EMUCRT
|
||||
|
||||
TOOL_BUILD_EMUCRT = \
|
||||
o/$(MODE)/tool/build/emucrt/emucrt.o \
|
||||
o/$(MODE)/tool/build/emucrt/emucrt.lds
|
||||
|
||||
o/$(MODE)/tool/build/emucrt/emucrt.o: \
|
||||
tool/build/emucrt/emucrt.S \
|
||||
libc/macros.internal.h \
|
||||
libc/intrin/asancodes.h \
|
||||
ape/relocations.h
|
||||
|
||||
.PHONY: o/$(MODE)/tool/build/emucrt
|
||||
o/$(MODE)/tool/build/emucrt: \
|
||||
$(TOOL_BUILD_EMUCRT)
|
|
@ -1,38 +0,0 @@
|
|||
/*-*- mode: ld-script; indent-tabs-mode: nil; tab-width: 2; coding: utf-8 -*-│
|
||||
│vi: set et sts=2 tw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS {
|
||||
|
||||
.text 0x7c00 : {
|
||||
*(.start)
|
||||
*(.text .text.*)
|
||||
*(.rodata .rodata.*)
|
||||
*(.data .data.*)
|
||||
. = 0x1fe;
|
||||
SHORT(0xaa55);
|
||||
*(.bss .bss.*)
|
||||
*(COMMON)
|
||||
}
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.*)
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_ABP_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_ABP_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
#define Abp8(x) ((uint8_t *)__builtin_assume_aligned(x, 8))
|
||||
#define Abp16(x) ((uint8_t *)__builtin_assume_aligned(x, 16))
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_ABP_H_ */
|
|
@ -1,88 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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 "tool/build/lib/address.h"
|
||||
#include "third_party/xed/x86.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
#include "tool/build/lib/throw.h"
|
||||
|
||||
uint64_t AddressOb(struct Machine *m, uint32_t rde) {
|
||||
return AddSegment(m, rde, m->xedd->op.disp, m->ds);
|
||||
}
|
||||
|
||||
uint8_t *GetSegment(struct Machine *m, uint32_t rde, int s) {
|
||||
switch (s & 7) {
|
||||
case 0:
|
||||
return m->es;
|
||||
case 1:
|
||||
return m->cs;
|
||||
case 2:
|
||||
return m->ss;
|
||||
case 3:
|
||||
return m->ds;
|
||||
case 4:
|
||||
return m->fs;
|
||||
case 5:
|
||||
return m->gs;
|
||||
case 6:
|
||||
case 7:
|
||||
OpUd(m, rde);
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t AddSegment(struct Machine *m, uint32_t rde, uint64_t i, uint8_t s[8]) {
|
||||
if (!Sego(rde)) {
|
||||
return i + Read64(s);
|
||||
} else {
|
||||
return i + Read64(GetSegment(m, rde, Sego(rde) - 1));
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t DataSegment(struct Machine *m, uint32_t rde, uint64_t i) {
|
||||
return AddSegment(m, rde, i, m->ds);
|
||||
}
|
||||
|
||||
uint64_t AddressSi(struct Machine *m, uint32_t rde) {
|
||||
switch (Eamode(rde)) {
|
||||
case XED_MODE_LONG:
|
||||
return DataSegment(m, rde, Read64(m->si));
|
||||
case XED_MODE_REAL:
|
||||
return DataSegment(m, rde, Read16(m->si));
|
||||
case XED_MODE_LEGACY:
|
||||
return DataSegment(m, rde, Read32(m->si));
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t AddressDi(struct Machine *m, uint32_t rde) {
|
||||
uint64_t i = Read64(m->es);
|
||||
switch (Eamode(rde)) {
|
||||
case XED_MODE_LONG:
|
||||
return i + Read64(m->di);
|
||||
case XED_MODE_REAL:
|
||||
return i + Read16(m->di);
|
||||
case XED_MODE_LEGACY:
|
||||
return i + Read32(m->di);
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_ADDRESS_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_ADDRESS_H_
|
||||
#include "libc/assert.h"
|
||||
#include "third_party/xed/x86.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
uint64_t AddressOb(struct Machine *, uint32_t);
|
||||
uint64_t AddressDi(struct Machine *, uint32_t);
|
||||
uint64_t AddressSi(struct Machine *, uint32_t);
|
||||
uint64_t DataSegment(struct Machine *, uint32_t, uint64_t);
|
||||
uint64_t AddSegment(struct Machine *, uint32_t, uint64_t, uint8_t[8]);
|
||||
uint8_t *GetSegment(struct Machine *, uint32_t, int) nosideeffect;
|
||||
|
||||
forceinline uint64_t MaskAddress(uint32_t mode, uint64_t x) {
|
||||
if (mode != XED_MODE_LONG) {
|
||||
if (mode == XED_MODE_REAL) {
|
||||
x &= 0xffff;
|
||||
} else {
|
||||
x &= 0xffffffff;
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_ADDRESS_H_ */
|
|
@ -1,763 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/assert.h"
|
||||
#include "tool/build/lib/alu.h"
|
||||
#include "tool/build/lib/flags.h"
|
||||
|
||||
const aluop_f kAlu[12][4] = {
|
||||
{Add8, Add16, Add32, Add64}, {Or8, Or16, Or32, Or64},
|
||||
{Adc8, Adc16, Adc32, Adc64}, {Sbb8, Sbb16, Sbb32, Sbb64},
|
||||
{And8, And16, And32, And64}, {Sub8, Sub16, Sub32, Sub64},
|
||||
{Xor8, Xor16, Xor32, Xor64}, {Sub8, Sub16, Sub32, Sub64},
|
||||
{Not8, Not16, Not32, Not64}, {Neg8, Neg16, Neg32, Neg64},
|
||||
{Inc8, Inc16, Inc32, Inc64}, {Dec8, Dec16, Dec32, Dec64},
|
||||
};
|
||||
|
||||
const aluop_f kBsu[8][4] = {
|
||||
{Rol8, Rol16, Rol32, Rol64}, {Ror8, Ror16, Ror32, Ror64},
|
||||
{Rcl8, Rcl16, Rcl32, Rcl64}, {Rcr8, Rcr16, Rcr32, Rcr64},
|
||||
{Shl8, Shl16, Shl32, Shl64}, {Shr8, Shr16, Shr32, Shr64},
|
||||
{Shl8, Shl16, Shl32, Shl64}, {Sar8, Sar16, Sar32, Sar64},
|
||||
};
|
||||
|
||||
int64_t AluFlags8(uint8_t z, uint32_t af, uint32_t *f, uint32_t of,
|
||||
uint32_t cf) {
|
||||
return AluFlags(z, af, f, of, cf, z >> 7);
|
||||
}
|
||||
|
||||
int64_t AluFlags32(uint32_t z, uint32_t af, uint32_t *f, uint32_t of,
|
||||
uint32_t cf) {
|
||||
return AluFlags(z, af, f, of, cf, z >> 31);
|
||||
}
|
||||
|
||||
int64_t Xor32(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return AluFlags32(x ^ y, 0, f, 0, 0);
|
||||
}
|
||||
|
||||
int64_t Sub32(uint64_t x64, uint64_t y64, uint32_t *f) {
|
||||
bool cf, of, af;
|
||||
uint32_t x, y, z;
|
||||
x = x64;
|
||||
y = y64;
|
||||
z = x - y;
|
||||
cf = x < z;
|
||||
af = (x & 15) < (z & 15);
|
||||
of = ((z ^ x) & (x ^ y)) >> 31;
|
||||
return AluFlags32(z, af, f, of, cf);
|
||||
}
|
||||
|
||||
int64_t AluFlags64(uint64_t z, uint32_t af, uint32_t *f, uint32_t of,
|
||||
uint32_t cf) {
|
||||
return AluFlags(z, af, f, of, cf, z >> 63);
|
||||
}
|
||||
|
||||
int64_t Sub64(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
uint64_t z;
|
||||
bool cf, of, af;
|
||||
z = x - y;
|
||||
cf = x < z;
|
||||
af = (x & 15) < (z & 15);
|
||||
of = ((z ^ x) & (x ^ y)) >> 63;
|
||||
return AluFlags64(z, af, f, of, cf);
|
||||
}
|
||||
|
||||
int64_t Xor8(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return AluFlags8(x ^ y, 0, f, 0, 0);
|
||||
}
|
||||
|
||||
int64_t Xor64(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return AluFlags64(x ^ y, 0, f, 0, 0);
|
||||
}
|
||||
|
||||
int64_t Or8(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return AluFlags8(x | y, 0, f, 0, 0);
|
||||
}
|
||||
|
||||
int64_t Or32(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return AluFlags32(x | y, 0, f, 0, 0);
|
||||
}
|
||||
|
||||
int64_t Or64(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return AluFlags64(x | y, 0, f, 0, 0);
|
||||
}
|
||||
|
||||
int64_t And8(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return AluFlags8(x & y, 0, f, 0, 0);
|
||||
}
|
||||
|
||||
int64_t And32(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return AluFlags32(x & y, 0, f, 0, 0);
|
||||
}
|
||||
|
||||
int64_t And64(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return AluFlags64(x & y, 0, f, 0, 0);
|
||||
}
|
||||
|
||||
int64_t Sub8(uint64_t x64, uint64_t y64, uint32_t *f) {
|
||||
bool cf, of, af;
|
||||
uint8_t x, y, z;
|
||||
x = x64;
|
||||
y = y64;
|
||||
z = x - y;
|
||||
cf = x < z;
|
||||
af = (x & 15) < (z & 15);
|
||||
of = ((z ^ x) & (x ^ y)) >> 7;
|
||||
return AluFlags8(z, af, f, of, cf);
|
||||
}
|
||||
|
||||
int64_t Add8(uint64_t x64, uint64_t y64, uint32_t *f) {
|
||||
bool cf, of, af;
|
||||
uint8_t x, y, z;
|
||||
x = x64;
|
||||
y = y64;
|
||||
z = x + y;
|
||||
cf = z < y;
|
||||
af = (z & 15) < (y & 15);
|
||||
of = ((z ^ x) & (z ^ y)) >> 7;
|
||||
return AluFlags8(z, af, f, of, cf);
|
||||
}
|
||||
|
||||
int64_t Add32(uint64_t x64, uint64_t y64, uint32_t *f) {
|
||||
bool cf, of, af;
|
||||
uint32_t x, y, z;
|
||||
x = x64;
|
||||
y = y64;
|
||||
z = x + y;
|
||||
cf = z < y;
|
||||
af = (z & 15) < (y & 15);
|
||||
of = ((z ^ x) & (z ^ y)) >> 31;
|
||||
return AluFlags32(z, af, f, of, cf);
|
||||
}
|
||||
|
||||
int64_t Add64(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
uint64_t z;
|
||||
bool cf, of, af;
|
||||
z = x + y;
|
||||
cf = z < y;
|
||||
af = (z & 15) < (y & 15);
|
||||
of = ((z ^ x) & (z ^ y)) >> 63;
|
||||
return AluFlags64(z, af, f, of, cf);
|
||||
}
|
||||
|
||||
int64_t Adc8(uint64_t x64, uint64_t y64, uint32_t *f) {
|
||||
bool cf, of, af;
|
||||
uint8_t x, y, z, t;
|
||||
x = x64;
|
||||
y = y64;
|
||||
t = x + GetFlag(*f, FLAGS_CF);
|
||||
z = t + y;
|
||||
cf = (t < x) | (z < y);
|
||||
of = ((z ^ x) & (z ^ y)) >> 7;
|
||||
af = ((t & 15) < (x & 15)) | ((z & 15) < (y & 15));
|
||||
return AluFlags8(z, af, f, of, cf);
|
||||
}
|
||||
|
||||
int64_t Adc32(uint64_t x64, uint64_t y64, uint32_t *f) {
|
||||
bool cf, of, af;
|
||||
uint32_t x, y, z, t;
|
||||
x = x64;
|
||||
y = y64;
|
||||
t = x + GetFlag(*f, FLAGS_CF);
|
||||
z = t + y;
|
||||
cf = (t < x) | (z < y);
|
||||
of = ((z ^ x) & (z ^ y)) >> 31;
|
||||
af = ((t & 15) < (x & 15)) | ((z & 15) < (y & 15));
|
||||
return AluFlags32(z, af, f, of, cf);
|
||||
}
|
||||
|
||||
int64_t Adc64(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
uint64_t z, t;
|
||||
bool cf, of, af;
|
||||
t = x + GetFlag(*f, FLAGS_CF);
|
||||
z = t + y;
|
||||
cf = (t < x) | (z < y);
|
||||
of = ((z ^ x) & (z ^ y)) >> 63;
|
||||
af = ((t & 15) < (x & 15)) | ((z & 15) < (y & 15));
|
||||
return AluFlags64(z, af, f, of, cf);
|
||||
}
|
||||
|
||||
int64_t Sbb8(uint64_t x64, uint64_t y64, uint32_t *f) {
|
||||
bool cf, of, af;
|
||||
uint8_t x, y, z, t;
|
||||
x = x64;
|
||||
y = y64;
|
||||
t = x - GetFlag(*f, FLAGS_CF);
|
||||
z = t - y;
|
||||
cf = (x < t) | (t < z);
|
||||
of = ((z ^ x) & (x ^ y)) >> 7;
|
||||
af = ((x & 15) < (t & 15)) | ((t & 15) < (z & 15));
|
||||
return AluFlags8(z, af, f, of, cf);
|
||||
}
|
||||
|
||||
int64_t Sbb32(uint64_t x64, uint64_t y64, uint32_t *f) {
|
||||
bool cf, of, af;
|
||||
uint32_t x, y, z, t;
|
||||
x = x64;
|
||||
y = y64;
|
||||
t = x - GetFlag(*f, FLAGS_CF);
|
||||
z = t - y;
|
||||
cf = (x < t) | (t < z);
|
||||
of = ((z ^ x) & (x ^ y)) >> 31;
|
||||
af = ((x & 15) < (t & 15)) | ((t & 15) < (z & 15));
|
||||
return AluFlags32(z, af, f, of, cf);
|
||||
}
|
||||
|
||||
int64_t Sbb64(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
uint64_t z, t;
|
||||
bool cf, of, af;
|
||||
t = x - GetFlag(*f, FLAGS_CF);
|
||||
z = t - y;
|
||||
cf = (x < t) | (t < z);
|
||||
of = ((z ^ x) & (x ^ y)) >> 63;
|
||||
af = ((x & 15) < (t & 15)) | ((t & 15) < (z & 15));
|
||||
return AluFlags64(z, af, f, of, cf);
|
||||
}
|
||||
|
||||
int64_t Not8(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return ~x & 0xFF;
|
||||
}
|
||||
|
||||
int64_t Not32(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return ~x & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
int64_t Not64(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return ~x & 0xFFFFFFFFFFFFFFFF;
|
||||
}
|
||||
|
||||
int64_t Neg8(uint64_t x64, uint64_t y, uint32_t *f) {
|
||||
uint8_t x;
|
||||
bool cf, of, af;
|
||||
x = x64;
|
||||
af = cf = !!x;
|
||||
of = x == 0x80;
|
||||
x = ~x + 1;
|
||||
return AluFlags8(x, af, f, of, cf);
|
||||
}
|
||||
|
||||
int64_t Neg32(uint64_t x64, uint64_t y, uint32_t *f) {
|
||||
uint32_t x;
|
||||
bool cf, of, af;
|
||||
x = x64;
|
||||
af = cf = !!x;
|
||||
of = x == 0x80000000;
|
||||
x = ~x + 1;
|
||||
return AluFlags32(x, af, f, of, cf);
|
||||
}
|
||||
|
||||
int64_t Neg64(uint64_t x64, uint64_t y, uint32_t *f) {
|
||||
uint64_t x;
|
||||
bool cf, of, af;
|
||||
x = x64;
|
||||
af = cf = !!x;
|
||||
of = x == 0x8000000000000000;
|
||||
x = ~x + 1;
|
||||
return AluFlags64(x, af, f, of, cf);
|
||||
}
|
||||
|
||||
static int64_t BumpFlags(uint64_t x, uint32_t af, uint32_t *f, uint32_t of,
|
||||
uint32_t sf) {
|
||||
return AluFlags(x, af, f, of, GetFlag(*f, FLAGS_CF), sf);
|
||||
}
|
||||
|
||||
int64_t Dec32(uint64_t x64, uint64_t y, uint32_t *f) {
|
||||
uint32_t x, z, of, sf, af;
|
||||
x = x64;
|
||||
z = x - 1;
|
||||
sf = z >> 31;
|
||||
af = (x & 15) < (z & 15);
|
||||
of = ((z ^ x) & (x ^ 1)) >> 31;
|
||||
return BumpFlags(z, af, f, of, sf);
|
||||
}
|
||||
|
||||
int64_t Inc32(uint64_t x64, uint64_t y, uint32_t *f) {
|
||||
uint32_t x, z, of, sf, af;
|
||||
x = x64;
|
||||
z = x + 1;
|
||||
sf = z >> 31;
|
||||
af = (z & 15) < (y & 15);
|
||||
of = ((z ^ x) & (z ^ 1)) >> 31;
|
||||
return BumpFlags(z, af, f, of, sf);
|
||||
}
|
||||
|
||||
int64_t Inc64(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
uint64_t z;
|
||||
uint32_t of, sf, af;
|
||||
z = x + 1;
|
||||
sf = z >> 63;
|
||||
af = (z & 15) < (y & 15);
|
||||
of = ((z ^ x) & (z ^ 1)) >> 63;
|
||||
return BumpFlags(z, af, f, of, sf);
|
||||
}
|
||||
|
||||
int64_t Dec64(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
uint64_t z;
|
||||
uint32_t of, sf, af;
|
||||
z = x - 1;
|
||||
sf = z >> 63;
|
||||
af = (x & 15) < (z & 15);
|
||||
of = ((z ^ x) & (x ^ 1)) >> 63;
|
||||
return BumpFlags(z, af, f, of, sf);
|
||||
}
|
||||
|
||||
int64_t Inc8(uint64_t x64, uint64_t y, uint32_t *f) {
|
||||
uint8_t x, z;
|
||||
uint32_t of, sf, af;
|
||||
x = x64;
|
||||
z = x + 1;
|
||||
sf = z >> 7;
|
||||
af = (z & 15) < (y & 15);
|
||||
of = ((z ^ x) & (z ^ 1)) >> 7;
|
||||
return BumpFlags(z, af, f, of, sf);
|
||||
}
|
||||
|
||||
int64_t Dec8(uint64_t x64, uint64_t y, uint32_t *f) {
|
||||
uint8_t x, z;
|
||||
uint32_t of, sf, af;
|
||||
x = x64;
|
||||
z = x - 1;
|
||||
sf = z >> 7;
|
||||
af = (x & 15) < (z & 15);
|
||||
of = ((z ^ x) & (x ^ 1)) >> 7;
|
||||
return BumpFlags(z, af, f, of, sf);
|
||||
}
|
||||
|
||||
int64_t Shr8(uint64_t x64, uint64_t y, uint32_t *f) {
|
||||
uint32_t x, cf;
|
||||
x = x64 & 0xff;
|
||||
if ((y &= 31)) {
|
||||
cf = (x >> (y - 1)) & 1;
|
||||
x >>= y;
|
||||
return AluFlags8(x, 0, f, ((x << 1) ^ x) >> 7, cf);
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t Shr32(uint64_t x64, uint64_t y, uint32_t *f) {
|
||||
uint32_t cf, x = x64;
|
||||
if ((y &= 31)) {
|
||||
cf = (x >> (y - 1)) & 1;
|
||||
x >>= y;
|
||||
return AluFlags32(x, 0, f, ((x << 1) ^ x) >> 31, cf);
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t Shr64(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
uint32_t cf;
|
||||
if ((y &= 63)) {
|
||||
cf = (x >> (y - 1)) & 1;
|
||||
x >>= y;
|
||||
return AluFlags64(x, 0, f, ((x << 1) ^ x) >> 63, cf);
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t Shl8(uint64_t x64, uint64_t y, uint32_t *f) {
|
||||
uint32_t x, cf;
|
||||
x = x64 & 0xff;
|
||||
if ((y &= 31)) {
|
||||
cf = (x >> ((8 - y) & 31)) & 1;
|
||||
x = (x << y) & 0xff;
|
||||
return AluFlags8(x, 0, f, (x >> 7) ^ cf, cf);
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t Shl32(uint64_t x64, uint64_t y, uint32_t *f) {
|
||||
uint32_t cf, x = x64;
|
||||
if ((y &= 31)) {
|
||||
cf = (x >> (32 - y)) & 1;
|
||||
x <<= y;
|
||||
return AluFlags32(x, 0, f, (x >> 31) ^ cf, cf);
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t Shl64(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
uint32_t cf;
|
||||
if ((y &= 63)) {
|
||||
cf = (x >> (64 - y)) & 1;
|
||||
x <<= y;
|
||||
return AluFlags64(x, 0, f, (x >> 63) ^ cf, cf);
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t Sar8(uint64_t x64, uint64_t y, uint32_t *f) {
|
||||
uint32_t x, cf;
|
||||
x = x64 & 0xff;
|
||||
if ((y &= 31)) {
|
||||
cf = ((int32_t)(int8_t)x >> (y - 1)) & 1;
|
||||
x = ((int32_t)(int8_t)x >> y) & 0xff;
|
||||
return AluFlags8(x, 0, f, 0, cf);
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t Sar32(uint64_t x64, uint64_t y, uint32_t *f) {
|
||||
uint32_t cf, x = x64;
|
||||
if ((y &= 31)) {
|
||||
cf = ((int32_t)x >> (y - 1)) & 1;
|
||||
x = (int32_t)x >> y;
|
||||
return AluFlags32(x, 0, f, 0, cf);
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t Sar64(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
uint32_t cf;
|
||||
if ((y &= 63)) {
|
||||
cf = ((int64_t)x >> (y - 1)) & 1;
|
||||
x = (int64_t)x >> y;
|
||||
return AluFlags64(x, 0, f, 0, cf);
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
static int64_t RotateFlags(uint64_t x, uint32_t cf, uint32_t *f, uint32_t of) {
|
||||
*f &= ~(1u << FLAGS_CF | 1u << FLAGS_OF);
|
||||
*f |= cf << FLAGS_CF | of << FLAGS_OF;
|
||||
return x;
|
||||
}
|
||||
|
||||
int64_t Rol32(uint64_t x64, uint64_t y, uint32_t *f) {
|
||||
uint32_t x = x64;
|
||||
if ((y &= 31)) {
|
||||
x = x << y | x >> (32 - y);
|
||||
return RotateFlags(x, x & 1, f, ((x >> 31) ^ x) & 1);
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t Rol64(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
if ((y &= 63)) {
|
||||
x = x << y | x >> (64 - y);
|
||||
return RotateFlags(x, x & 1, f, ((x >> 63) ^ x) & 1);
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t Ror32(uint64_t x64, uint64_t y, uint32_t *f) {
|
||||
uint32_t x = x64;
|
||||
if ((y &= 31)) {
|
||||
x = x >> y | x << (32 - y);
|
||||
return RotateFlags(x, x >> 31, f, ((x >> 31) ^ (x >> 30)) & 1);
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t Ror64(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
if ((y &= 63)) {
|
||||
x = x >> y | x << (64 - y);
|
||||
return RotateFlags(x, x >> 63, f, ((x >> 63) ^ (x >> 62)) & 1);
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t Rol8(uint64_t x64, uint64_t y, uint32_t *f) {
|
||||
uint8_t x = x64;
|
||||
if (y & 31) {
|
||||
if ((y &= 7)) x = x << y | x >> (8 - y);
|
||||
return RotateFlags(x, x & 1, f, ((x >> 7) ^ x) & 1);
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t Ror8(uint64_t x64, uint64_t y, uint32_t *f) {
|
||||
uint8_t x = x64;
|
||||
if (y & 31) {
|
||||
if ((y &= 7)) x = x >> y | x << (8 - y);
|
||||
return RotateFlags(x, x >> 7, f, ((x >> 7) ^ (x >> 6)) & 1);
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
static int64_t Rcr(uint64_t x, uint64_t y, uint32_t *f, uint64_t xm,
|
||||
uint64_t k) {
|
||||
uint64_t cf;
|
||||
uint32_t ct;
|
||||
x &= xm;
|
||||
if (y) {
|
||||
cf = GetFlag(*f, FLAGS_CF);
|
||||
ct = (x >> (y - 1)) & 1;
|
||||
if (y == 1) {
|
||||
x = (x >> 1 | cf << (k - 1)) & xm;
|
||||
} else {
|
||||
x = (x >> y | cf << (k - y) | x << (k + 1 - y)) & xm;
|
||||
}
|
||||
return RotateFlags(x, ct, f, (((x << 1) ^ x) >> (k - 1)) & 1);
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t Rcr8(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return Rcr(x, (y & 31) % 9, f, 0xff, 8);
|
||||
}
|
||||
|
||||
int64_t Rcr16(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return Rcr(x, (y & 31) % 17, f, 0xffff, 16);
|
||||
}
|
||||
|
||||
int64_t Rcr32(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return Rcr(x, y & 31, f, 0xffffffff, 32);
|
||||
}
|
||||
|
||||
int64_t Rcr64(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return Rcr(x, y & 63, f, 0xffffffffffffffff, 64);
|
||||
}
|
||||
|
||||
static int64_t Rcl(uint64_t x, uint64_t y, uint32_t *f, uint64_t xm,
|
||||
uint64_t k) {
|
||||
uint64_t cf;
|
||||
uint32_t ct;
|
||||
x &= xm;
|
||||
if (y) {
|
||||
cf = GetFlag(*f, FLAGS_CF);
|
||||
ct = (x >> (k - y)) & 1;
|
||||
if (y == 1) {
|
||||
x = (x << 1 | cf) & xm;
|
||||
} else {
|
||||
x = (x << y | cf << (y - 1) | x >> (k + 1 - y)) & xm;
|
||||
}
|
||||
return RotateFlags(x, ct, f, ct ^ ((x >> (k - 1)) & 1));
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t Rcl8(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return Rcl(x, (y & 31) % 9, f, 0xff, 8);
|
||||
}
|
||||
|
||||
int64_t Rcl16(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return Rcl(x, (y & 31) % 17, f, 0xffff, 16);
|
||||
}
|
||||
|
||||
int64_t Rcl32(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return Rcl(x, y & 31, f, 0xffffffff, 32);
|
||||
}
|
||||
|
||||
int64_t Rcl64(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return Rcl(x, y & 63, f, 0xffffffffffffffff, 64);
|
||||
}
|
||||
|
||||
uint64_t BsuDoubleShift(int w, uint64_t x, uint64_t y, uint8_t b, bool isright,
|
||||
uint32_t *f) {
|
||||
bool cf, of;
|
||||
uint64_t s, k, m, z;
|
||||
k = 8;
|
||||
k <<= w;
|
||||
s = 1;
|
||||
s <<= k - 1;
|
||||
m = s | s - 1;
|
||||
b &= w == 3 ? 63 : 31;
|
||||
x &= m;
|
||||
if (b) {
|
||||
if (isright) {
|
||||
z = x >> b | y << (k - b);
|
||||
cf = (x >> (b - 1)) & 1;
|
||||
of = b == 1 && (z & s) != (x & s);
|
||||
} else {
|
||||
z = x << b | y >> (k - b);
|
||||
cf = (x >> (k - b)) & 1;
|
||||
of = b == 1 && (z & s) != (x & s);
|
||||
}
|
||||
x = z;
|
||||
x &= m;
|
||||
return AluFlags(x, 0, f, of, cf, !!(x & s));
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t AluFlags16(uint16_t z, uint32_t af, uint32_t *f, uint32_t of,
|
||||
uint32_t cf) {
|
||||
return AluFlags(z, af, f, of, cf, z >> 15);
|
||||
}
|
||||
|
||||
int64_t Xor16(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return AluFlags16(x ^ y, 0, f, 0, 0);
|
||||
}
|
||||
|
||||
int64_t Or16(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return AluFlags16(x | y, 0, f, 0, 0);
|
||||
}
|
||||
|
||||
int64_t And16(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return AluFlags16(x & y, 0, f, 0, 0);
|
||||
}
|
||||
|
||||
int64_t Sub16(uint64_t x64, uint64_t y64, uint32_t *f) {
|
||||
bool cf, of, af;
|
||||
uint16_t x, y, z;
|
||||
x = x64;
|
||||
y = y64;
|
||||
z = x - y;
|
||||
cf = x < z;
|
||||
af = (x & 15) < (z & 15);
|
||||
of = ((z ^ x) & (x ^ y)) >> 15;
|
||||
return AluFlags16(z, af, f, of, cf);
|
||||
}
|
||||
|
||||
int64_t Add16(uint64_t x64, uint64_t y64, uint32_t *f) {
|
||||
bool cf, of, af;
|
||||
uint16_t x, y, z;
|
||||
x = x64;
|
||||
y = y64;
|
||||
z = x + y;
|
||||
cf = z < y;
|
||||
af = (z & 15) < (y & 15);
|
||||
of = ((z ^ x) & (z ^ y)) >> 15;
|
||||
return AluFlags16(z, af, f, of, cf);
|
||||
}
|
||||
|
||||
int64_t Adc16(uint64_t x64, uint64_t y64, uint32_t *f) {
|
||||
bool cf, of, af;
|
||||
uint16_t x, y, z, t;
|
||||
x = x64;
|
||||
y = y64;
|
||||
t = x + GetFlag(*f, FLAGS_CF);
|
||||
z = t + y;
|
||||
cf = (t < x) | (z < y);
|
||||
of = ((z ^ x) & (z ^ y)) >> 15;
|
||||
af = ((t & 15) < (x & 15)) | ((z & 15) < (y & 15));
|
||||
return AluFlags16(z, af, f, of, cf);
|
||||
}
|
||||
|
||||
int64_t Sbb16(uint64_t x64, uint64_t y64, uint32_t *f) {
|
||||
bool cf, of, af;
|
||||
uint16_t x, y, z, t;
|
||||
x = x64;
|
||||
y = y64;
|
||||
t = x - GetFlag(*f, FLAGS_CF);
|
||||
z = t - y;
|
||||
cf = (x < t) | (t < z);
|
||||
of = ((z ^ x) & (x ^ y)) >> 15;
|
||||
af = ((x & 15) < (t & 15)) | ((t & 15) < (z & 15));
|
||||
return AluFlags16(z, af, f, of, cf);
|
||||
}
|
||||
|
||||
int64_t Not16(uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return ~x & 0xFFFF;
|
||||
}
|
||||
|
||||
int64_t Neg16(uint64_t x64, uint64_t y, uint32_t *f) {
|
||||
uint16_t x;
|
||||
bool cf, of, af;
|
||||
x = x64;
|
||||
af = cf = !!x;
|
||||
of = x == 0x8000;
|
||||
x = ~x + 1;
|
||||
return AluFlags16(x, af, f, of, cf);
|
||||
}
|
||||
|
||||
int64_t Inc16(uint64_t x64, uint64_t y, uint32_t *f) {
|
||||
uint16_t x, z;
|
||||
uint32_t of, sf, af;
|
||||
x = x64;
|
||||
z = x + 1;
|
||||
sf = z >> 15;
|
||||
af = (z & 15) < (y & 15);
|
||||
of = ((z ^ x) & (z ^ 1)) >> 15;
|
||||
return BumpFlags(z, af, f, of, sf);
|
||||
}
|
||||
|
||||
int64_t Dec16(uint64_t x64, uint64_t y, uint32_t *f) {
|
||||
uint16_t x, z;
|
||||
uint32_t of, sf, af;
|
||||
x = x64;
|
||||
z = x - 1;
|
||||
sf = z >> 15;
|
||||
af = (x & 15) < (z & 15);
|
||||
of = ((z ^ x) & (x ^ 1)) >> 15;
|
||||
return BumpFlags(z, af, f, of, sf);
|
||||
}
|
||||
|
||||
int64_t Shr16(uint64_t x64, uint64_t y, uint32_t *f) {
|
||||
uint32_t x, cf;
|
||||
x = x64 & 0xffff;
|
||||
if ((y &= 31)) {
|
||||
cf = (x >> (y - 1)) & 1;
|
||||
x >>= y;
|
||||
return AluFlags16(x, 0, f, ((x << 1) ^ x) >> 15, cf);
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t Shl16(uint64_t x64, uint64_t y, uint32_t *f) {
|
||||
uint32_t x, cf;
|
||||
x = x64 & 0xffff;
|
||||
if ((y &= 31)) {
|
||||
cf = (x >> ((16 - y) & 31)) & 1;
|
||||
x = (x << y) & 0xffff;
|
||||
return AluFlags16(x, 0, f, (x >> 15) ^ cf, cf);
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t Sar16(uint64_t x64, uint64_t y, uint32_t *f) {
|
||||
uint32_t x, cf;
|
||||
x = x64 & 0xffff;
|
||||
if ((y &= 31)) {
|
||||
cf = ((int32_t)(int16_t)x >> (y - 1)) & 1;
|
||||
x = ((int32_t)(int16_t)x >> y) & 0xffff;
|
||||
return AluFlags16(x, 0, f, 0, cf);
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t Rol16(uint64_t x64, uint64_t y, uint32_t *f) {
|
||||
uint16_t x = x64;
|
||||
if (y & 31) {
|
||||
if ((y &= 15)) x = x << y | x >> (16 - y);
|
||||
return RotateFlags(x, x & 1, f, ((x >> 15) ^ x) & 1);
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t Ror16(uint64_t x64, uint64_t y, uint32_t *f) {
|
||||
uint16_t x = x64;
|
||||
if (y & 31) {
|
||||
if ((y &= 15)) x = x >> y | x << (16 - y);
|
||||
return RotateFlags(x, x >> 15, f, ((x >> 15) ^ (x >> 14)) & 1);
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
|
@ -1,118 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_ALU_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_ALU_H_
|
||||
#include "tool/build/lib/machine.h"
|
||||
|
||||
#define ALU_ADD 0
|
||||
#define ALU_OR 1
|
||||
#define ALU_ADC 2
|
||||
#define ALU_SBB 3
|
||||
#define ALU_AND 4
|
||||
#define ALU_SUB 5
|
||||
#define ALU_XOR 6
|
||||
#define ALU_CMP 7
|
||||
#define ALU_NOT 8
|
||||
#define ALU_NEG 9
|
||||
#define ALU_INC 10
|
||||
#define ALU_DEC 11
|
||||
|
||||
#define BSU_ROL 0
|
||||
#define BSU_ROR 1
|
||||
#define BSU_RCL 2
|
||||
#define BSU_RCR 3
|
||||
#define BSU_SHL 4
|
||||
#define BSU_SHR 5
|
||||
#define BSU_SAL 6
|
||||
#define BSU_SAR 7
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
typedef int64_t (*aluop_f)(uint64_t, uint64_t, uint32_t *);
|
||||
|
||||
extern const aluop_f kAlu[12][4];
|
||||
extern const aluop_f kBsu[8][4];
|
||||
|
||||
int64_t Xor8(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Xor16(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Xor32(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Xor64(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Or8(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Or16(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Or32(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Or64(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t And8(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t And16(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t And32(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t And64(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Sub8(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Sbb8(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Sub16(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Sbb16(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Sub32(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Sbb32(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Sub64(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Sbb64(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Add8(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Adc8(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Add16(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Adc16(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Add32(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Adc32(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Add64(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Adc64(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Not8(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Not16(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Not32(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Not64(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Neg8(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Neg16(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Neg32(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Neg64(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Inc8(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Inc16(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Inc32(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Inc64(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Dec8(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Dec16(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Dec32(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Dec64(uint64_t, uint64_t, uint32_t *);
|
||||
|
||||
int64_t Shr8(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Shr16(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Shr32(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Shr64(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Shl8(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Shl16(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Shl32(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Shl64(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Sar8(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Sar16(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Sar32(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Sar64(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Rol8(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Rol16(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Rol32(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Rol64(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Ror8(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Ror16(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Ror32(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Ror64(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Rcr8(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Rcr16(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Rcr32(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Rcr64(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Rcl8(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Rcl16(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Rcl32(uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Rcl64(uint64_t, uint64_t, uint32_t *);
|
||||
|
||||
uint64_t BsuDoubleShift(int, uint64_t, uint64_t, uint8_t, bool, uint32_t *);
|
||||
|
||||
int64_t AluFlags8(uint8_t, uint32_t, uint32_t *, uint32_t, uint32_t);
|
||||
int64_t AluFlags16(uint16_t, uint32_t, uint32_t *, uint32_t, uint32_t);
|
||||
int64_t AluFlags32(uint32_t, uint32_t, uint32_t *, uint32_t, uint32_t);
|
||||
int64_t AluFlags64(uint64_t, uint32_t, uint32_t *, uint32_t, uint32_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_ALU_H_ */
|
|
@ -1,75 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/mem/mem.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#include "tool/build/lib/memory.h"
|
||||
|
||||
#define STACKALIGN 16
|
||||
#define LINUX_AT_EXECFN 31
|
||||
|
||||
static size_t GetArgListLen(char **p) {
|
||||
size_t n;
|
||||
for (n = 0; *p; ++p) ++n;
|
||||
return n;
|
||||
}
|
||||
|
||||
static int64_t PushString(struct Machine *m, const char *s) {
|
||||
size_t n;
|
||||
int64_t sp;
|
||||
n = strlen(s) + 1;
|
||||
sp = Read64(m->sp);
|
||||
sp -= n;
|
||||
Write64(m->sp, sp);
|
||||
VirtualRecv(m, sp, s, n);
|
||||
return sp;
|
||||
}
|
||||
|
||||
void LoadArgv(struct Machine *m, const char *prog, char **args, char **vars) {
|
||||
int64_t i, n, sp, *p, *bloc;
|
||||
size_t narg, nenv, naux, nall;
|
||||
DCHECK_NOTNULL(prog);
|
||||
DCHECK_NOTNULL(args);
|
||||
DCHECK_NOTNULL(vars);
|
||||
naux = 1;
|
||||
nenv = GetArgListLen(vars);
|
||||
narg = GetArgListLen(args);
|
||||
nall = 1 + 1 + narg + 1 + nenv + 1 + (naux + 1) * 2;
|
||||
bloc = gc(malloc(sizeof(int64_t) * nall));
|
||||
p = bloc + nall;
|
||||
*--p = 0;
|
||||
*--p = 0;
|
||||
*--p = PushString(m, prog);
|
||||
*--p = LINUX_AT_EXECFN;
|
||||
for (*--p = 0, i = nenv; i--;) *--p = PushString(m, vars[i]);
|
||||
for (*--p = 0, i = narg; i--;) *--p = PushString(m, args[i]);
|
||||
*--p = PushString(m, prog);
|
||||
*--p = 1 + narg;
|
||||
DCHECK_EQ(bloc, p);
|
||||
sp = Read64(m->sp);
|
||||
while ((sp - nall * sizeof(int64_t)) & (STACKALIGN - 1)) --sp;
|
||||
sp -= nall * sizeof(int64_t);
|
||||
DCHECK_EQ(0, sp % STACKALIGN);
|
||||
Write64(m->sp, sp);
|
||||
Write64(m->di, 0); /* or ape detects freebsd */
|
||||
VirtualRecv(m, sp, bloc, sizeof(int64_t) * nall);
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_ARGV_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_ARGV_H_
|
||||
#include "tool/build/lib/machine.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void LoadArgv(struct Machine *, const char *, char **, char **);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_ARGV_H_ */
|
|
@ -1,77 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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 "tool/build/lib/alu.h"
|
||||
#include "tool/build/lib/bcd.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/flags.h"
|
||||
#include "tool/build/lib/throw.h"
|
||||
|
||||
relegated void OpDas(struct Machine *m, uint32_t rde) {
|
||||
uint8_t al, af, cf;
|
||||
af = cf = 0;
|
||||
al = m->ax[0];
|
||||
if ((al & 0x0f) > 9 || GetFlag(m->flags, FLAGS_AF)) {
|
||||
cf = m->ax[0] < 6 || GetFlag(m->flags, FLAGS_CF);
|
||||
m->ax[0] -= 0x06;
|
||||
af = 1;
|
||||
}
|
||||
if (al > 0x99 || GetFlag(m->flags, FLAGS_CF)) {
|
||||
m->ax[0] -= 0x60;
|
||||
cf = 1;
|
||||
}
|
||||
AluFlags8(m->ax[0], af, &m->flags, 0, cf);
|
||||
}
|
||||
|
||||
relegated void OpAaa(struct Machine *m, uint32_t rde) {
|
||||
uint8_t af, cf;
|
||||
af = cf = 0;
|
||||
if ((m->ax[0] & 0x0f) > 9 || GetFlag(m->flags, FLAGS_AF)) {
|
||||
cf = m->ax[0] < 6 || GetFlag(m->flags, FLAGS_CF);
|
||||
Write16(m->ax, Read16(m->ax) + 0x106);
|
||||
af = cf = 1;
|
||||
}
|
||||
m->ax[0] &= 0x0f;
|
||||
AluFlags8(m->ax[0], af, &m->flags, 0, cf);
|
||||
}
|
||||
|
||||
relegated void OpAas(struct Machine *m, uint32_t rde) {
|
||||
uint8_t af, cf;
|
||||
af = cf = 0;
|
||||
if ((m->ax[0] & 0x0f) > 9 || GetFlag(m->flags, FLAGS_AF)) {
|
||||
cf = m->ax[0] < 6 || GetFlag(m->flags, FLAGS_CF);
|
||||
Write16(m->ax, Read16(m->ax) - 0x106);
|
||||
af = cf = 1;
|
||||
}
|
||||
m->ax[0] &= 0x0f;
|
||||
AluFlags8(m->ax[0], af, &m->flags, 0, cf);
|
||||
}
|
||||
|
||||
relegated void OpAam(struct Machine *m, uint32_t rde) {
|
||||
uint8_t i = m->xedd->op.uimm0;
|
||||
if (!i) ThrowDivideError(m);
|
||||
m->ax[1] = m->ax[0] / i;
|
||||
m->ax[0] = m->ax[0] % i;
|
||||
AluFlags8(m->ax[0], 0, &m->flags, 0, 0);
|
||||
}
|
||||
|
||||
relegated void OpAad(struct Machine *m, uint32_t rde) {
|
||||
uint8_t i = m->xedd->op.uimm0;
|
||||
Write16(m->ax, (m->ax[1] * i + m->ax[0]) & 0xff);
|
||||
AluFlags8(m->ax[0], 0, &m->flags, 0, 0);
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_BCD_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_BCD_H_
|
||||
#include "tool/build/lib/machine.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void OpDas(struct Machine *, uint32_t);
|
||||
void OpAaa(struct Machine *, uint32_t);
|
||||
void OpAas(struct Machine *, uint32_t);
|
||||
void OpAam(struct Machine *, uint32_t);
|
||||
void OpAad(struct Machine *, uint32_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_BCD_H_ */
|
|
@ -1,145 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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 "tool/build/lib/bitscan.h"
|
||||
#include "tool/build/lib/flags.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
|
||||
uint64_t AluPopcnt(struct Machine *m, uint32_t rde, uint64_t x) {
|
||||
m->flags = SetFlag(m->flags, FLAGS_ZF, !x);
|
||||
m->flags = SetFlag(m->flags, FLAGS_CF, false);
|
||||
m->flags = SetFlag(m->flags, FLAGS_SF, false);
|
||||
m->flags = SetFlag(m->flags, FLAGS_OF, false);
|
||||
m->flags = SetFlag(m->flags, FLAGS_PF, false);
|
||||
x = x - ((x >> 1) & 0x5555555555555555);
|
||||
x = ((x >> 2) & 0x3333333333333333) + (x & 0x3333333333333333);
|
||||
x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f;
|
||||
x = (x + (x >> 32)) & 0xffffffff;
|
||||
x = x + (x >> 16);
|
||||
x = (x + (x >> 8)) & 0x7f;
|
||||
return x;
|
||||
}
|
||||
|
||||
uint64_t AluBsr(struct Machine *m, uint32_t rde, uint64_t x) {
|
||||
unsigned i;
|
||||
if (Rexw(rde)) {
|
||||
x &= 0xffffffffffffffff;
|
||||
if (Rep(rde) == 3) {
|
||||
if (!x) {
|
||||
m->flags = SetFlag(m->flags, FLAGS_CF, true);
|
||||
m->flags = SetFlag(m->flags, FLAGS_ZF, false);
|
||||
return 64;
|
||||
} else {
|
||||
m->flags = SetFlag(m->flags, FLAGS_CF, false);
|
||||
m->flags = SetFlag(m->flags, FLAGS_ZF, x == 1);
|
||||
}
|
||||
} else {
|
||||
m->flags = SetFlag(m->flags, FLAGS_ZF, !x);
|
||||
if (!x) return 0;
|
||||
}
|
||||
return 63 ^ __builtin_clzll(x);
|
||||
} else if (!Osz(rde)) {
|
||||
x &= 0xffffffff;
|
||||
if (Rep(rde) == 3) {
|
||||
if (!x) {
|
||||
m->flags = SetFlag(m->flags, FLAGS_CF, true);
|
||||
m->flags = SetFlag(m->flags, FLAGS_ZF, false);
|
||||
return 32;
|
||||
} else {
|
||||
m->flags = SetFlag(m->flags, FLAGS_CF, false);
|
||||
m->flags = SetFlag(m->flags, FLAGS_ZF, x == 1);
|
||||
}
|
||||
} else {
|
||||
m->flags = SetFlag(m->flags, FLAGS_ZF, !x);
|
||||
if (!x) return 0;
|
||||
}
|
||||
return 31 ^ __builtin_clz(x);
|
||||
} else {
|
||||
x &= 0xffff;
|
||||
if (Rep(rde) == 3) {
|
||||
if (!x) {
|
||||
m->flags = SetFlag(m->flags, FLAGS_CF, true);
|
||||
m->flags = SetFlag(m->flags, FLAGS_ZF, false);
|
||||
return 16;
|
||||
} else {
|
||||
m->flags = SetFlag(m->flags, FLAGS_CF, false);
|
||||
m->flags = SetFlag(m->flags, FLAGS_ZF, x == 1);
|
||||
}
|
||||
} else {
|
||||
m->flags = SetFlag(m->flags, FLAGS_ZF, !x);
|
||||
if (!x) return 0;
|
||||
}
|
||||
for (i = 15; !(x & 0x8000); --i) x <<= 1;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t AluBsf(struct Machine *m, uint32_t rde, uint64_t x) {
|
||||
unsigned i;
|
||||
if (Rexw(rde)) {
|
||||
x &= 0xffffffffffffffff;
|
||||
if (Rep(rde) == 3) {
|
||||
if (!x) {
|
||||
m->flags = SetFlag(m->flags, FLAGS_CF, true);
|
||||
m->flags = SetFlag(m->flags, FLAGS_ZF, false);
|
||||
return 64;
|
||||
} else {
|
||||
m->flags = SetFlag(m->flags, FLAGS_CF, false);
|
||||
m->flags = SetFlag(m->flags, FLAGS_ZF, x & 1);
|
||||
}
|
||||
} else {
|
||||
m->flags = SetFlag(m->flags, FLAGS_ZF, !x);
|
||||
if (!x) return 0;
|
||||
}
|
||||
return __builtin_ctzll(x);
|
||||
} else if (!Osz(rde)) {
|
||||
x &= 0xffffffff;
|
||||
if (Rep(rde) == 3) {
|
||||
if (!x) {
|
||||
m->flags = SetFlag(m->flags, FLAGS_CF, true);
|
||||
m->flags = SetFlag(m->flags, FLAGS_ZF, false);
|
||||
return 32;
|
||||
} else {
|
||||
m->flags = SetFlag(m->flags, FLAGS_CF, false);
|
||||
m->flags = SetFlag(m->flags, FLAGS_ZF, x & 1);
|
||||
}
|
||||
} else {
|
||||
m->flags = SetFlag(m->flags, FLAGS_ZF, !x);
|
||||
if (!x) return 0;
|
||||
}
|
||||
return __builtin_ctz(x);
|
||||
} else {
|
||||
x &= 0xffff;
|
||||
if (Rep(rde) == 3) {
|
||||
if (!x) {
|
||||
m->flags = SetFlag(m->flags, FLAGS_CF, true);
|
||||
m->flags = SetFlag(m->flags, FLAGS_ZF, false);
|
||||
return 16;
|
||||
} else {
|
||||
m->flags = SetFlag(m->flags, FLAGS_CF, false);
|
||||
m->flags = SetFlag(m->flags, FLAGS_ZF, x & 1);
|
||||
}
|
||||
} else {
|
||||
m->flags = SetFlag(m->flags, FLAGS_ZF, !x);
|
||||
if (!x) return 0;
|
||||
}
|
||||
for (i = 0; !(x & 1); ++i) x >>= 1;
|
||||
return i;
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_BITSCAN_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_BITSCAN_H_
|
||||
#include "tool/build/lib/machine.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
typedef uint64_t (*bitscan_f)(struct Machine *, uint32_t, uint64_t);
|
||||
|
||||
uint64_t AluBsr(struct Machine *, uint32_t, uint64_t);
|
||||
uint64_t AluBsf(struct Machine *, uint32_t, uint64_t);
|
||||
uint64_t AluPopcnt(struct Machine *, uint32_t, uint64_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_BITSCAN_H_ */
|
|
@ -1,56 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/mem/arraylist2.internal.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "tool/build/lib/breakpoint.h"
|
||||
|
||||
void PopBreakpoint(struct Breakpoints *bps) {
|
||||
if (bps->i) {
|
||||
--bps->i;
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t PushBreakpoint(struct Breakpoints *bps, struct Breakpoint *b) {
|
||||
int i;
|
||||
for (i = 0; i < bps->i; ++i) {
|
||||
if (bps->p[i].disable) {
|
||||
memcpy(&bps->p[i], b, sizeof(*b));
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return APPEND(&bps->p, &bps->i, &bps->n, b);
|
||||
}
|
||||
|
||||
ssize_t IsAtBreakpoint(struct Breakpoints *bps, int64_t addr) {
|
||||
size_t i;
|
||||
for (i = bps->i; i--;) {
|
||||
if (bps->p[i].disable) continue;
|
||||
if (bps->p[i].addr == addr) {
|
||||
if (bps->p[i].oneshot) {
|
||||
bps->p[i].disable = true;
|
||||
if (i == bps->i - 1) {
|
||||
--bps->i;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_BREAKPOINT_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_BREAKPOINT_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct Breakpoints {
|
||||
size_t i, n;
|
||||
struct Breakpoint {
|
||||
int64_t addr;
|
||||
const char *symbol;
|
||||
bool disable;
|
||||
bool oneshot;
|
||||
} * p;
|
||||
};
|
||||
|
||||
ssize_t IsAtBreakpoint(struct Breakpoints *, int64_t);
|
||||
ssize_t PushBreakpoint(struct Breakpoints *, struct Breakpoint *);
|
||||
void PopBreakpoint(struct Breakpoints *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_BREAKPOINT_H_ */
|
|
@ -1,36 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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 "tool/build/lib/modrm.h"
|
||||
|
||||
/**
|
||||
* Byte register offsets.
|
||||
*
|
||||
* for (i = 0; i < 2; ++i) { // rex
|
||||
* for (j = 0; j < 2; ++j) { // rexb, or rexr
|
||||
* for (k = 0; k < 8; ++k) { // reg, rm, or srm
|
||||
* kByteReg[i << 4 | j << 3 | k] =
|
||||
* i ? (j << 3 | k) * 8 : (k & 0b11) * 8 + ((k & 0b100) >> 2);
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
const uint8_t kByteReg[32] = {0x00, 0x08, 0x10, 0x18, 0x01, 0x09, 0x11, 0x19,
|
||||
0x00, 0x08, 0x10, 0x18, 0x01, 0x09, 0x11, 0x19,
|
||||
0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38,
|
||||
0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78};
|
|
@ -1,56 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/fmt/itoa.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/tab.internal.h"
|
||||
#include "tool/build/lib/buffer.h"
|
||||
#include "tool/build/lib/cga.h"
|
||||
|
||||
/* blk blu grn cyn red mag yel wht */
|
||||
static const uint8_t kCgaToAnsi[16] = {30, 34, 32, 36, 31, 35, 33, 37,
|
||||
90, 94, 92, 96, 91, 95, 93, 97};
|
||||
|
||||
size_t FormatCga(uint8_t bgfg, char buf[hasatleast 11]) {
|
||||
char *p = buf;
|
||||
*p++ = '\e';
|
||||
*p++ = '[';
|
||||
p = FormatUint32(p, kCgaToAnsi[(bgfg & 0xF0) >> 4] + 10);
|
||||
*p++ = ';';
|
||||
p = FormatUint32(p, kCgaToAnsi[bgfg & 0x0F]);
|
||||
*p++ = 'm';
|
||||
*p = '\0';
|
||||
return p - buf;
|
||||
}
|
||||
|
||||
void DrawCga(struct Panel *p, uint8_t v[25][80][2]) {
|
||||
char buf[11];
|
||||
unsigned y, x, n, a;
|
||||
n = MIN(25, p->bottom - p->top);
|
||||
for (y = 0; y < n; ++y) {
|
||||
a = -1;
|
||||
for (x = 0; x < 80; ++x) {
|
||||
if (v[y][x][1] != a) {
|
||||
AppendData(&p->lines[y], buf, FormatCga((a = v[y][x][1]), buf));
|
||||
}
|
||||
AppendWide(&p->lines[y], kCp437[v[y][x][0]]);
|
||||
}
|
||||
AppendStr(&p->lines[y], "\e[0m");
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_CGA_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_CGA_H_
|
||||
#include "tool/build/lib/panel.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void DrawCga(struct Panel *, uint8_t[25][80][2]);
|
||||
size_t FormatCga(uint8_t, char[hasatleast 11]);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_CGA_H_ */
|
|
@ -1,52 +0,0 @@
|
|||
/*-*- 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 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/intrin/bsr.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "tool/build/lib/clmul.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Carryless Multiplication ISA
|
||||
*/
|
||||
|
||||
struct clmul {
|
||||
uint64_t x, y;
|
||||
};
|
||||
|
||||
static struct clmul clmul(uint64_t a, uint64_t b) {
|
||||
uint64_t t, x = 0, y = 0;
|
||||
if (a && b) {
|
||||
if (_bsrl(a) < _bsrl(b)) t = a, a = b, b = t;
|
||||
for (t = 0; b; a <<= 1, b >>= 1) {
|
||||
if (b & 1) x ^= a, y ^= t;
|
||||
t = t << 1 | a >> 63;
|
||||
}
|
||||
}
|
||||
return (struct clmul){x, y};
|
||||
}
|
||||
|
||||
void OpSsePclmulqdq(struct Machine *m, uint32_t rde) {
|
||||
struct clmul res;
|
||||
res = clmul(Read64(XmmRexrReg(m, rde) + ((m->xedd->op.uimm0 & 0x01) << 3)),
|
||||
Read64(GetModrmRegisterXmmPointerRead16(m, rde) +
|
||||
((m->xedd->op.uimm0 & 0x10) >> 1)));
|
||||
Write64(XmmRexrReg(m, rde) + 0, res.x);
|
||||
Write64(XmmRexrReg(m, rde) + 8, res.y);
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_CLMUL_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_CLMUL_H_
|
||||
#include "tool/build/lib/machine.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void OpSsePclmulqdq(struct Machine *, uint32_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_CLMUL_H_ */
|
|
@ -1,88 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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 "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
|
||||
void OpCpuid(struct Machine *m, uint32_t rde) {
|
||||
uint32_t ax, bx, cx, dx;
|
||||
ax = 0;
|
||||
bx = 0;
|
||||
cx = 0;
|
||||
dx = 0;
|
||||
switch (Read32(m->ax)) {
|
||||
case 0:
|
||||
case 0x80000000:
|
||||
ax = 7;
|
||||
bx = 'G' | 'e' << 8 | 'n' << 16 | 'u' << 24;
|
||||
dx = 'i' | 'n' << 8 | 'e' << 16 | 'C' << 24;
|
||||
cx = 'o' | 's' << 8 | 'm' << 16 | 'o' << 24;
|
||||
break;
|
||||
case 1:
|
||||
cx |= 1 << 0; // sse3
|
||||
cx |= 1 << 1; // pclmulqdq
|
||||
cx |= 1 << 9; // ssse3
|
||||
cx |= 1 << 23; // popcnt
|
||||
cx |= 1 << 30; // rdrnd
|
||||
cx |= 0 << 25; // aes
|
||||
cx |= 1 << 13; // cmpxchg16b
|
||||
dx |= 1 << 0; // fpu
|
||||
dx |= 1 << 4; // tsc
|
||||
dx |= 1 << 6; // pae
|
||||
dx |= 1 << 8; // cmpxchg8b
|
||||
dx |= 1 << 15; // cmov
|
||||
dx |= 1 << 19; // clflush
|
||||
dx |= 1 << 23; // mmx
|
||||
dx |= 1 << 24; // fxsave
|
||||
dx |= 1 << 25; // sse
|
||||
dx |= 1 << 26; // sse2
|
||||
break;
|
||||
case 7:
|
||||
switch (Read32(m->cx)) {
|
||||
case 0:
|
||||
bx |= 1 << 0; // fsgsbase
|
||||
bx |= 1 << 9; // erms
|
||||
bx |= 0 << 18; // rdseed
|
||||
cx |= 1 << 22; // rdpid
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x80000001:
|
||||
cx |= 1 << 0; // lahf
|
||||
dx |= 1 << 0; // fpu
|
||||
dx |= 1 << 8; // cmpxchg8b
|
||||
dx |= 1 << 11; // syscall
|
||||
dx |= 1 << 15; // cmov
|
||||
dx |= 1 << 23; // mmx
|
||||
dx |= 1 << 24; // fxsave
|
||||
dx |= 1 << 27; // rdtscp
|
||||
dx |= 1 << 29; // long
|
||||
break;
|
||||
case 0x80000007:
|
||||
dx |= 1 << 8; // invtsc
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Write64(m->ax, ax);
|
||||
Write64(m->bx, bx);
|
||||
Write64(m->cx, cx);
|
||||
Write64(m->dx, dx);
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_CPUID_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_CPUID_H_
|
||||
#include "tool/build/lib/machine.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void OpCpuid(struct Machine *, uint32_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_CPUID_H_ */
|
|
@ -1,458 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/macros.internal.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/build/lib/cvt.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/fpu.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#include "tool/build/lib/memory.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
#include "tool/build/lib/pun.h"
|
||||
#include "tool/build/lib/throw.h"
|
||||
|
||||
#define kOpCvt0f2a 0
|
||||
#define kOpCvtt0f2c 4
|
||||
#define kOpCvt0f2d 8
|
||||
#define kOpCvt0f5a 12
|
||||
#define kOpCvt0f5b 16
|
||||
#define kOpCvt0fE6 20
|
||||
|
||||
static double SseRoundDouble(struct Machine *m, double x) {
|
||||
switch ((m->mxcsr & kMxcsrRc) >> 13) {
|
||||
case 0:
|
||||
return rint(x);
|
||||
case 1:
|
||||
return floor(x);
|
||||
case 2:
|
||||
return ceil(x);
|
||||
case 3:
|
||||
return trunc(x);
|
||||
default:
|
||||
for (;;) (void)0;
|
||||
}
|
||||
}
|
||||
|
||||
static void OpGdqpWssCvttss2si(struct Machine *m, uint32_t rde) {
|
||||
int64_t n;
|
||||
union FloatPun f;
|
||||
f.i = Read32(GetModrmRegisterXmmPointerRead4(m, rde));
|
||||
n = f.f;
|
||||
if (!Rexw(rde)) n &= 0xffffffff;
|
||||
Write64(RegRexrReg(m, rde), n);
|
||||
}
|
||||
|
||||
static void OpGdqpWsdCvttsd2si(struct Machine *m, uint32_t rde) {
|
||||
int64_t n;
|
||||
union DoublePun d;
|
||||
d.i = Read64(GetModrmRegisterXmmPointerRead8(m, rde));
|
||||
n = d.f;
|
||||
if (!Rexw(rde)) n &= 0xffffffff;
|
||||
Write64(RegRexrReg(m, rde), n);
|
||||
}
|
||||
|
||||
static void OpGdqpWssCvtss2si(struct Machine *m, uint32_t rde) {
|
||||
int64_t n;
|
||||
union FloatPun f;
|
||||
f.i = Read32(GetModrmRegisterXmmPointerRead4(m, rde));
|
||||
n = rintf(f.f);
|
||||
if (!Rexw(rde)) n &= 0xffffffff;
|
||||
Write64(RegRexrReg(m, rde), n);
|
||||
}
|
||||
|
||||
static void OpGdqpWsdCvtsd2si(struct Machine *m, uint32_t rde) {
|
||||
int64_t n;
|
||||
union DoublePun d;
|
||||
d.i = Read64(GetModrmRegisterXmmPointerRead8(m, rde));
|
||||
n = SseRoundDouble(m, d.f);
|
||||
if (!Rexw(rde)) n &= 0xffffffff;
|
||||
Write64(RegRexrReg(m, rde), n);
|
||||
}
|
||||
|
||||
static void OpVssEdqpCvtsi2ss(struct Machine *m, uint32_t rde) {
|
||||
union FloatPun f;
|
||||
if (Rexw(rde)) {
|
||||
int64_t n;
|
||||
n = Read64(GetModrmRegisterWordPointerRead8(m, rde));
|
||||
f.f = n;
|
||||
Write32(XmmRexrReg(m, rde), f.i);
|
||||
} else {
|
||||
int32_t n;
|
||||
n = Read32(GetModrmRegisterWordPointerRead4(m, rde));
|
||||
f.f = n;
|
||||
Write32(XmmRexrReg(m, rde), f.i);
|
||||
}
|
||||
}
|
||||
|
||||
static void OpVsdEdqpCvtsi2sd(struct Machine *m, uint32_t rde) {
|
||||
union DoublePun d;
|
||||
if (Rexw(rde)) {
|
||||
int64_t n;
|
||||
n = Read64(GetModrmRegisterWordPointerRead8(m, rde));
|
||||
d.f = n;
|
||||
Write64(XmmRexrReg(m, rde), d.i);
|
||||
} else {
|
||||
int32_t n;
|
||||
n = Read32(GetModrmRegisterWordPointerRead4(m, rde));
|
||||
d.f = n;
|
||||
Write64(XmmRexrReg(m, rde), d.i);
|
||||
}
|
||||
}
|
||||
|
||||
static void OpVpsQpiCvtpi2ps(struct Machine *m, uint32_t rde) {
|
||||
uint8_t *p;
|
||||
int32_t i[2];
|
||||
union FloatPun f[2];
|
||||
p = GetModrmRegisterMmPointerRead8(m, rde);
|
||||
i[0] = Read32(p + 0);
|
||||
i[1] = Read32(p + 4);
|
||||
f[0].f = i[0];
|
||||
f[1].f = i[1];
|
||||
Write32(XmmRexrReg(m, rde) + 0, f[0].i);
|
||||
Write32(XmmRexrReg(m, rde) + 4, f[1].i);
|
||||
}
|
||||
|
||||
static void OpVpdQpiCvtpi2pd(struct Machine *m, uint32_t rde) {
|
||||
uint8_t *p;
|
||||
int32_t n[2];
|
||||
union DoublePun f[2];
|
||||
p = GetModrmRegisterMmPointerRead8(m, rde);
|
||||
n[0] = Read32(p + 0);
|
||||
n[1] = Read32(p + 4);
|
||||
f[0].f = n[0];
|
||||
f[1].f = n[1];
|
||||
Write64(XmmRexrReg(m, rde) + 0, f[0].i);
|
||||
Write64(XmmRexrReg(m, rde) + 8, f[1].i);
|
||||
}
|
||||
|
||||
static void OpPpiWpsqCvtps2pi(struct Machine *m, uint32_t rde) {
|
||||
uint8_t *p;
|
||||
unsigned i;
|
||||
int32_t n[2];
|
||||
union FloatPun f[2];
|
||||
p = GetModrmRegisterXmmPointerRead8(m, rde);
|
||||
f[0].i = Read32(p + 0 * 4);
|
||||
f[1].i = Read32(p + 1 * 4);
|
||||
switch ((m->mxcsr & kMxcsrRc) >> 13) {
|
||||
case 0:
|
||||
for (i = 0; i < 2; ++i) n[i] = rintf(f[i].f);
|
||||
break;
|
||||
case 1:
|
||||
for (i = 0; i < 2; ++i) n[i] = floorf(f[i].f);
|
||||
break;
|
||||
case 2:
|
||||
for (i = 0; i < 2; ++i) n[i] = ceilf(f[i].f);
|
||||
break;
|
||||
case 3:
|
||||
for (i = 0; i < 2; ++i) n[i] = truncf(f[i].f);
|
||||
break;
|
||||
default:
|
||||
for (;;) (void)0;
|
||||
}
|
||||
Write32(MmReg(m, rde) + 0, n[0]);
|
||||
Write32(MmReg(m, rde) + 4, n[1]);
|
||||
}
|
||||
|
||||
static void OpPpiWpsqCvttps2pi(struct Machine *m, uint32_t rde) {
|
||||
uint8_t *p;
|
||||
int32_t n[2];
|
||||
union FloatPun f[2];
|
||||
p = GetModrmRegisterXmmPointerRead8(m, rde);
|
||||
f[0].i = Read32(p + 0);
|
||||
f[1].i = Read32(p + 4);
|
||||
n[0] = f[0].f;
|
||||
n[1] = f[1].f;
|
||||
Write32(MmReg(m, rde) + 0, n[0]);
|
||||
Write32(MmReg(m, rde) + 4, n[1]);
|
||||
}
|
||||
|
||||
static void OpPpiWpdCvtpd2pi(struct Machine *m, uint32_t rde) {
|
||||
uint8_t *p;
|
||||
unsigned i;
|
||||
int32_t n[2];
|
||||
union DoublePun d[2];
|
||||
p = GetModrmRegisterXmmPointerRead16(m, rde);
|
||||
d[0].i = Read64(p + 0);
|
||||
d[1].i = Read64(p + 8);
|
||||
for (i = 0; i < 2; ++i) n[i] = SseRoundDouble(m, d[i].f);
|
||||
Write32(MmReg(m, rde) + 0, n[0]);
|
||||
Write32(MmReg(m, rde) + 4, n[1]);
|
||||
}
|
||||
|
||||
static void OpPpiWpdCvttpd2pi(struct Machine *m, uint32_t rde) {
|
||||
uint8_t *p;
|
||||
int32_t n[2];
|
||||
union DoublePun d[2];
|
||||
p = GetModrmRegisterXmmPointerRead16(m, rde);
|
||||
d[0].i = Read64(p + 0);
|
||||
d[1].i = Read64(p + 8);
|
||||
n[0] = d[0].f;
|
||||
n[1] = d[1].f;
|
||||
Write32(MmReg(m, rde) + 0, n[0]);
|
||||
Write32(MmReg(m, rde) + 4, n[1]);
|
||||
}
|
||||
|
||||
static void OpVpdWpsCvtps2pd(struct Machine *m, uint32_t rde) {
|
||||
uint8_t *p;
|
||||
union FloatPun f[2];
|
||||
union DoublePun d[2];
|
||||
p = GetModrmRegisterXmmPointerRead8(m, rde);
|
||||
f[0].i = Read32(p + 0);
|
||||
f[1].i = Read32(p + 4);
|
||||
d[0].f = f[0].f;
|
||||
d[1].f = f[1].f;
|
||||
Write64(XmmRexrReg(m, rde) + 0, d[0].i);
|
||||
Write64(XmmRexrReg(m, rde) + 8, d[1].i);
|
||||
}
|
||||
|
||||
static void OpVpsWpdCvtpd2ps(struct Machine *m, uint32_t rde) {
|
||||
uint8_t *p;
|
||||
union FloatPun f[2];
|
||||
union DoublePun d[2];
|
||||
p = GetModrmRegisterXmmPointerRead16(m, rde);
|
||||
d[0].i = Read64(p + 0);
|
||||
d[1].i = Read64(p + 8);
|
||||
f[0].f = d[0].f;
|
||||
f[1].f = d[1].f;
|
||||
Write32(XmmRexrReg(m, rde) + 0, f[0].i);
|
||||
Write32(XmmRexrReg(m, rde) + 4, f[1].i);
|
||||
}
|
||||
|
||||
static void OpVssWsdCvtsd2ss(struct Machine *m, uint32_t rde) {
|
||||
union FloatPun f;
|
||||
union DoublePun d;
|
||||
d.i = Read64(GetModrmRegisterXmmPointerRead8(m, rde));
|
||||
f.f = d.f;
|
||||
Write32(XmmRexrReg(m, rde), f.i);
|
||||
}
|
||||
|
||||
static void OpVsdWssCvtss2sd(struct Machine *m, uint32_t rde) {
|
||||
union FloatPun f;
|
||||
union DoublePun d;
|
||||
f.i = Read32(GetModrmRegisterXmmPointerRead4(m, rde));
|
||||
d.f = f.f;
|
||||
Write64(XmmRexrReg(m, rde), d.i);
|
||||
}
|
||||
|
||||
static void OpVpsWdqCvtdq2ps(struct Machine *m, uint32_t rde) {
|
||||
uint8_t *p;
|
||||
int32_t n[4];
|
||||
union FloatPun f[4];
|
||||
p = GetModrmRegisterXmmPointerRead16(m, rde);
|
||||
n[0] = Read32(p + 0 * 4);
|
||||
n[1] = Read32(p + 1 * 4);
|
||||
n[2] = Read32(p + 2 * 4);
|
||||
n[3] = Read32(p + 3 * 4);
|
||||
f[0].f = n[0];
|
||||
f[1].f = n[1];
|
||||
f[2].f = n[2];
|
||||
f[3].f = n[3];
|
||||
Write32(XmmRexrReg(m, rde) + 0 * 4, f[0].i);
|
||||
Write32(XmmRexrReg(m, rde) + 1 * 4, f[1].i);
|
||||
Write32(XmmRexrReg(m, rde) + 2 * 4, f[2].i);
|
||||
Write32(XmmRexrReg(m, rde) + 3 * 4, f[3].i);
|
||||
}
|
||||
|
||||
static void OpVpdWdqCvtdq2pd(struct Machine *m, uint32_t rde) {
|
||||
uint8_t *p;
|
||||
int32_t n[2];
|
||||
union DoublePun d[2];
|
||||
p = GetModrmRegisterXmmPointerRead8(m, rde);
|
||||
n[0] = Read32(p + 0 * 4);
|
||||
n[1] = Read32(p + 1 * 4);
|
||||
d[0].f = n[0];
|
||||
d[1].f = n[1];
|
||||
Write64(XmmRexrReg(m, rde) + 0, d[0].i);
|
||||
Write64(XmmRexrReg(m, rde) + 8, d[1].i);
|
||||
}
|
||||
|
||||
static void OpVdqWpsCvttps2dq(struct Machine *m, uint32_t rde) {
|
||||
uint8_t *p;
|
||||
int32_t n[4];
|
||||
union FloatPun f[4];
|
||||
p = GetModrmRegisterXmmPointerRead16(m, rde);
|
||||
f[0].i = Read32(p + 0 * 4);
|
||||
f[1].i = Read32(p + 1 * 4);
|
||||
f[2].i = Read32(p + 2 * 4);
|
||||
f[3].i = Read32(p + 3 * 4);
|
||||
n[0] = f[0].f;
|
||||
n[1] = f[1].f;
|
||||
n[2] = f[2].f;
|
||||
n[3] = f[3].f;
|
||||
Write32(XmmRexrReg(m, rde) + 0 * 4, n[0]);
|
||||
Write32(XmmRexrReg(m, rde) + 1 * 4, n[1]);
|
||||
Write32(XmmRexrReg(m, rde) + 2 * 4, n[2]);
|
||||
Write32(XmmRexrReg(m, rde) + 3 * 4, n[3]);
|
||||
}
|
||||
|
||||
static void OpVdqWpsCvtps2dq(struct Machine *m, uint32_t rde) {
|
||||
uint8_t *p;
|
||||
unsigned i;
|
||||
int32_t n[4];
|
||||
union FloatPun f[4];
|
||||
p = GetModrmRegisterXmmPointerRead16(m, rde);
|
||||
f[0].i = Read32(p + 0 * 4);
|
||||
f[1].i = Read32(p + 1 * 4);
|
||||
f[2].i = Read32(p + 2 * 4);
|
||||
f[3].i = Read32(p + 3 * 4);
|
||||
switch ((m->mxcsr & kMxcsrRc) >> 13) {
|
||||
case 0:
|
||||
for (i = 0; i < 4; ++i) n[i] = rintf(f[i].f);
|
||||
break;
|
||||
case 1:
|
||||
for (i = 0; i < 4; ++i) n[i] = floorf(f[i].f);
|
||||
break;
|
||||
case 2:
|
||||
for (i = 0; i < 4; ++i) n[i] = ceilf(f[i].f);
|
||||
break;
|
||||
case 3:
|
||||
for (i = 0; i < 4; ++i) n[i] = truncf(f[i].f);
|
||||
break;
|
||||
default:
|
||||
for (;;) (void)0;
|
||||
}
|
||||
Write32(XmmRexrReg(m, rde) + 0 * 4, n[0]);
|
||||
Write32(XmmRexrReg(m, rde) + 1 * 4, n[1]);
|
||||
Write32(XmmRexrReg(m, rde) + 2 * 4, n[2]);
|
||||
Write32(XmmRexrReg(m, rde) + 3 * 4, n[3]);
|
||||
}
|
||||
|
||||
static void OpVdqWpdCvttpd2dq(struct Machine *m, uint32_t rde) {
|
||||
uint8_t *p;
|
||||
int32_t n[2];
|
||||
union DoublePun d[2];
|
||||
p = GetModrmRegisterXmmPointerRead16(m, rde);
|
||||
d[0].i = Read64(p + 0);
|
||||
d[1].i = Read64(p + 8);
|
||||
n[0] = d[0].f;
|
||||
n[1] = d[1].f;
|
||||
Write32(XmmRexrReg(m, rde) + 0, n[0]);
|
||||
Write32(XmmRexrReg(m, rde) + 4, n[1]);
|
||||
}
|
||||
|
||||
static void OpVdqWpdCvtpd2dq(struct Machine *m, uint32_t rde) {
|
||||
uint8_t *p;
|
||||
unsigned i;
|
||||
int32_t n[2];
|
||||
union DoublePun d[2];
|
||||
p = GetModrmRegisterXmmPointerRead16(m, rde);
|
||||
d[0].i = Read64(p + 0);
|
||||
d[1].i = Read64(p + 8);
|
||||
for (i = 0; i < 2; ++i) n[i] = SseRoundDouble(m, d[i].f);
|
||||
Write32(XmmRexrReg(m, rde) + 0, n[0]);
|
||||
Write32(XmmRexrReg(m, rde) + 4, n[1]);
|
||||
}
|
||||
|
||||
static void OpCvt(struct Machine *m, uint32_t rde, unsigned long op) {
|
||||
switch (op | Rep(rde) | Osz(rde)) {
|
||||
case kOpCvt0f2a + 0:
|
||||
OpVpsQpiCvtpi2ps(m, rde);
|
||||
break;
|
||||
case kOpCvt0f2a + 1:
|
||||
OpVpdQpiCvtpi2pd(m, rde);
|
||||
break;
|
||||
case kOpCvt0f2a + 2:
|
||||
OpVsdEdqpCvtsi2sd(m, rde);
|
||||
break;
|
||||
case kOpCvt0f2a + 3:
|
||||
OpVssEdqpCvtsi2ss(m, rde);
|
||||
break;
|
||||
case kOpCvtt0f2c + 0:
|
||||
OpPpiWpsqCvttps2pi(m, rde);
|
||||
break;
|
||||
case kOpCvtt0f2c + 1:
|
||||
OpPpiWpdCvttpd2pi(m, rde);
|
||||
break;
|
||||
case kOpCvtt0f2c + 2:
|
||||
OpGdqpWsdCvttsd2si(m, rde);
|
||||
break;
|
||||
case kOpCvtt0f2c + 3:
|
||||
OpGdqpWssCvttss2si(m, rde);
|
||||
break;
|
||||
case kOpCvt0f2d + 0:
|
||||
OpPpiWpsqCvtps2pi(m, rde);
|
||||
break;
|
||||
case kOpCvt0f2d + 1:
|
||||
OpPpiWpdCvtpd2pi(m, rde);
|
||||
break;
|
||||
case kOpCvt0f2d + 2:
|
||||
OpGdqpWsdCvtsd2si(m, rde);
|
||||
break;
|
||||
case kOpCvt0f2d + 3:
|
||||
OpGdqpWssCvtss2si(m, rde);
|
||||
break;
|
||||
case kOpCvt0f5a + 0:
|
||||
OpVpdWpsCvtps2pd(m, rde);
|
||||
break;
|
||||
case kOpCvt0f5a + 1:
|
||||
OpVpsWpdCvtpd2ps(m, rde);
|
||||
break;
|
||||
case kOpCvt0f5a + 2:
|
||||
OpVssWsdCvtsd2ss(m, rde);
|
||||
break;
|
||||
case kOpCvt0f5a + 3:
|
||||
OpVsdWssCvtss2sd(m, rde);
|
||||
break;
|
||||
case kOpCvt0f5b + 0:
|
||||
OpVpsWdqCvtdq2ps(m, rde);
|
||||
break;
|
||||
case kOpCvt0f5b + 1:
|
||||
OpVdqWpsCvtps2dq(m, rde);
|
||||
break;
|
||||
case kOpCvt0f5b + 3:
|
||||
OpVdqWpsCvttps2dq(m, rde);
|
||||
break;
|
||||
case kOpCvt0fE6 + 1:
|
||||
OpVdqWpdCvtpd2dq(m, rde);
|
||||
break;
|
||||
case kOpCvt0fE6 + 2:
|
||||
OpVdqWpdCvttpd2dq(m, rde);
|
||||
break;
|
||||
case kOpCvt0fE6 + 3:
|
||||
OpVpdWdqCvtdq2pd(m, rde);
|
||||
break;
|
||||
default:
|
||||
OpUd(m, rde);
|
||||
}
|
||||
}
|
||||
|
||||
void OpCvt0f2a(struct Machine *m, uint32_t rde) {
|
||||
OpCvt(m, rde, kOpCvt0f2a);
|
||||
}
|
||||
|
||||
void OpCvtt0f2c(struct Machine *m, uint32_t rde) {
|
||||
OpCvt(m, rde, kOpCvtt0f2c);
|
||||
}
|
||||
|
||||
void OpCvt0f2d(struct Machine *m, uint32_t rde) {
|
||||
OpCvt(m, rde, kOpCvt0f2d);
|
||||
}
|
||||
|
||||
void OpCvt0f5a(struct Machine *m, uint32_t rde) {
|
||||
OpCvt(m, rde, kOpCvt0f5a);
|
||||
}
|
||||
|
||||
void OpCvt0f5b(struct Machine *m, uint32_t rde) {
|
||||
OpCvt(m, rde, kOpCvt0f5b);
|
||||
}
|
||||
|
||||
void OpCvt0fE6(struct Machine *m, uint32_t rde) {
|
||||
OpCvt(m, rde, kOpCvt0fE6);
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_CVT_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_CVT_H_
|
||||
#include "tool/build/lib/machine.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void OpCvt0f2a(struct Machine *, uint32_t);
|
||||
void OpCvtt0f2c(struct Machine *, uint32_t);
|
||||
void OpCvt0f2d(struct Machine *, uint32_t);
|
||||
void OpCvt0f5a(struct Machine *, uint32_t);
|
||||
void OpCvt0f5b(struct Machine *, uint32_t);
|
||||
void OpCvt0fE6(struct Machine *, uint32_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_CVT_H_ */
|
|
@ -1,47 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/elf/elf.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "tool/build/lib/loader.h"
|
||||
|
||||
void LoadDebugSymbols(struct Elf *elf) {
|
||||
int fd;
|
||||
size_t n;
|
||||
void *elfmap;
|
||||
struct stat st;
|
||||
const char *path;
|
||||
if (elf->ehdr && GetElfSymbolTable(elf->ehdr, elf->size, &n) && n) return;
|
||||
DCHECK_NOTNULL(elf->prog);
|
||||
if ((fd = open(xstrcat(elf->prog, ".dbg"), O_RDONLY)) != -1) {
|
||||
if (fstat(fd, &st) != -1 &&
|
||||
(elfmap = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) !=
|
||||
MAP_FAILED) {
|
||||
elf->ehdr = elfmap;
|
||||
elf->size = st.st_size;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
}
|
|
@ -1,296 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/fmt/bing.internal.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/tpenc.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/mem/arraylist2.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/xed/x86.h"
|
||||
#include "tool/build/lib/demangle.h"
|
||||
#include "tool/build/lib/dis.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/high.h"
|
||||
#include "tool/build/lib/memory.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
|
||||
#define ADDRLEN 8
|
||||
#define BYTELEN 11
|
||||
#define PFIXLEN 4
|
||||
#define NAMELEN 8
|
||||
#define CODELEN 40
|
||||
#define CODELIM 15
|
||||
#define DATALIM 8
|
||||
#define PIVOTOP pos_opcode
|
||||
|
||||
static char *DisColumn(char *p2, char *p1, long need) {
|
||||
char *p;
|
||||
unsigned long have;
|
||||
DCHECK_GE(p2, p1);
|
||||
have = p2 - p1;
|
||||
p = p2;
|
||||
do {
|
||||
*p++ = ' ';
|
||||
} while (++have < need);
|
||||
*p = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisOctets(char *p, const uint8_t *d, size_t n) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (i) *p++ = ',';
|
||||
*p++ = '0';
|
||||
*p++ = 'x';
|
||||
*p++ = "0123456789abcdef"[(d[i] & 0xf0) >> 4];
|
||||
*p++ = "0123456789abcdef"[(d[i] & 0x0f) >> 0];
|
||||
}
|
||||
*p = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisByte(char *p, const uint8_t *d, size_t n) {
|
||||
p = HighStart(p, g_high.keyword);
|
||||
p = DisColumn(stpcpy(p, ".byte"), p, NAMELEN);
|
||||
p = HighEnd(p);
|
||||
p = DisOctets(p, d, n);
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisError(struct Dis *d, char *p) {
|
||||
p = DisColumn(DisByte(p, d->xedd->bytes, MIN(15, d->xedd->length)), p,
|
||||
CODELEN);
|
||||
p = HighStart(p, g_high.comment);
|
||||
*p++ = '#';
|
||||
*p++ = ' ';
|
||||
p = stpcpy(p, IndexDoubleNulString(kXedErrorNames, d->xedd->op.error));
|
||||
p = HighEnd(p);
|
||||
*p = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisAddr(struct Dis *d, char *p) {
|
||||
int64_t x = d->addr;
|
||||
if (0 <= x && x < 0x10fff0) {
|
||||
return p + uint64toarray_fixed16(x, p, 24);
|
||||
} else if (INT_MIN <= x && x <= INT_MAX) {
|
||||
return p + uint64toarray_fixed16(x, p, 32);
|
||||
} else {
|
||||
return p + uint64toarray_fixed16(x, p, 48);
|
||||
}
|
||||
}
|
||||
|
||||
static char *DisRaw(struct Dis *d, char *p) {
|
||||
long i;
|
||||
int plen;
|
||||
if (0 <= d->addr && d->addr < 0x10fff0) {
|
||||
plen = 2;
|
||||
} else {
|
||||
plen = PFIXLEN;
|
||||
}
|
||||
for (i = 0; i < plen - MIN(plen, d->xedd->op.PIVOTOP); ++i) {
|
||||
*p++ = ' ';
|
||||
*p++ = ' ';
|
||||
}
|
||||
for (i = 0; i < MIN(15, d->xedd->length); ++i) {
|
||||
if (i == d->xedd->op.PIVOTOP) *p++ = ' ';
|
||||
*p++ = "0123456789abcdef"[(d->xedd->bytes[i] & 0xf0) >> 4];
|
||||
*p++ = "0123456789abcdef"[(d->xedd->bytes[i] & 0x0f) >> 0];
|
||||
}
|
||||
*p = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisCode(struct Dis *d, char *p) {
|
||||
char optspecbuf[128];
|
||||
if (!d->xedd->op.error) {
|
||||
return DisInst(d, p, DisSpec(d->xedd, optspecbuf));
|
||||
} else {
|
||||
return DisError(d, p);
|
||||
}
|
||||
}
|
||||
|
||||
static char *DisLineCode(struct Dis *d, char *p) {
|
||||
int blen, plen;
|
||||
if (0 <= d->addr && d->addr < 0x10fff0) {
|
||||
plen = 2;
|
||||
blen = 6;
|
||||
} else {
|
||||
blen = BYTELEN;
|
||||
plen = PFIXLEN;
|
||||
}
|
||||
p = DisColumn(DisAddr(d, p), p, ADDRLEN);
|
||||
p = DisColumn(DisRaw(d, p), p, plen * 2 + 1 + blen * 2);
|
||||
p = DisCode(d, p);
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisLineData(struct Dis *d, char *p, const uint8_t *b, size_t n) {
|
||||
size_t i;
|
||||
uint64_t w;
|
||||
p = DisColumn(DisAddr(d, p), p, ADDRLEN);
|
||||
p = DisColumn(DisByte(p, b, n), p, 64);
|
||||
p = HighStart(p, g_high.comment);
|
||||
*p++ = '#';
|
||||
*p++ = ' ';
|
||||
for (i = 0; i < n; ++i) {
|
||||
w = _tpenc(bing(b[i], 0));
|
||||
do {
|
||||
*p++ = w;
|
||||
} while ((w >>= 8));
|
||||
}
|
||||
p = HighEnd(p);
|
||||
*p = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisLabel(struct Dis *d, char *p, const char *name) {
|
||||
p = DisColumn(DisAddr(d, p), p, ADDRLEN);
|
||||
p = HighStart(p, g_high.label);
|
||||
p = Demangle(p, name, DIS_MAX_SYMBOL_LENGTH);
|
||||
p = HighEnd(p);
|
||||
*p++ = ':';
|
||||
*p = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
long DisFind(struct Dis *d, int64_t addr) {
|
||||
int l, r, m, i;
|
||||
l = 0;
|
||||
r = d->ops.i - 1;
|
||||
while (l <= r) {
|
||||
m = (l + r) >> 1;
|
||||
if (d->ops.p[m].addr < addr) {
|
||||
l = m + 1;
|
||||
} else if (d->ops.p[m].addr > addr) {
|
||||
r = m - 1;
|
||||
} else {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static long DisAppendOpLines(struct Dis *d, struct Machine *m, int64_t addr) {
|
||||
void *r;
|
||||
int64_t ip;
|
||||
unsigned k;
|
||||
struct DisOp op;
|
||||
long i, n, symbol;
|
||||
uint8_t *p, b[15];
|
||||
n = 15;
|
||||
ip = addr - Read64(m->cs);
|
||||
if ((symbol = DisFindSym(d, ip)) != -1) {
|
||||
if (d->syms.p[symbol].addr <= ip &&
|
||||
ip < d->syms.p[symbol].addr + d->syms.p[symbol].size) {
|
||||
n = d->syms.p[symbol].size - (ip - d->syms.p[symbol].addr);
|
||||
}
|
||||
if (ip == d->syms.p[symbol].addr && d->syms.p[symbol].name) {
|
||||
op.addr = addr;
|
||||
op.size = 0;
|
||||
op.active = true;
|
||||
d->addr = addr;
|
||||
DisLabel(d, d->buf, d->syms.stab + d->syms.p[symbol].name);
|
||||
if (!(op.s = strdup(d->buf))) return -1;
|
||||
APPEND(&d->ops.p, &d->ops.i, &d->ops.n, &op);
|
||||
}
|
||||
}
|
||||
n = MAX(1, MIN(15, n));
|
||||
if (!(r = FindReal(m, addr))) return -1;
|
||||
k = 0x1000 - (addr & 0xfff);
|
||||
if (n <= k) {
|
||||
p = r;
|
||||
} else {
|
||||
p = b;
|
||||
memcpy(b, r, k);
|
||||
if ((r = FindReal(m, addr + k))) {
|
||||
memcpy(b + k, r, n - k);
|
||||
} else {
|
||||
n = k;
|
||||
}
|
||||
}
|
||||
xed_decoded_inst_zero_set_mode(d->xedd, m->mode);
|
||||
xed_instruction_length_decode(d->xedd, p, n);
|
||||
d->xedd->op.rde = EncodeRde(d->xedd);
|
||||
n = d->xedd->op.error ? 1 : d->xedd->length;
|
||||
op.addr = addr;
|
||||
op.size = n;
|
||||
op.active = true;
|
||||
op.s = NULL;
|
||||
APPEND(&d->ops.p, &d->ops.i, &d->ops.n, &op);
|
||||
return n;
|
||||
}
|
||||
|
||||
long Dis(struct Dis *d, struct Machine *m, uint64_t addr, uint64_t ip,
|
||||
int lines) {
|
||||
int64_t i, j, symbol;
|
||||
DisFreeOps(&d->ops);
|
||||
if ((symbol = DisFindSym(d, addr)) != -1 &&
|
||||
(d->syms.p[symbol].addr < addr &&
|
||||
addr < d->syms.p[symbol].addr + d->syms.p[symbol].size)) {
|
||||
for (i = d->syms.p[symbol].addr; i < addr; i += j) {
|
||||
if ((j = DisAppendOpLines(d, m, i)) == -1) return -1;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < lines; ++i, addr += j) {
|
||||
if ((j = DisAppendOpLines(d, m, addr)) == -1) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *DisGetLine(struct Dis *d, struct Machine *m, size_t i) {
|
||||
void *r[2];
|
||||
uint8_t b[15];
|
||||
if (i >= d->ops.i) return "";
|
||||
if (d->ops.p[i].s) return d->ops.p[i].s;
|
||||
DCHECK_LE(d->ops.p[i].size, 15);
|
||||
xed_decoded_inst_zero_set_mode(d->xedd, m->mode);
|
||||
xed_instruction_length_decode(
|
||||
d->xedd, AccessRam(m, d->ops.p[i].addr, d->ops.p[i].size, r, b, true),
|
||||
d->ops.p[i].size);
|
||||
d->xedd->op.rde = EncodeRde(d->xedd);
|
||||
d->m = m;
|
||||
d->addr = d->ops.p[i].addr;
|
||||
CHECK_LT(DisLineCode(d, d->buf) - d->buf, sizeof(d->buf));
|
||||
return d->buf;
|
||||
}
|
||||
|
||||
void DisFreeOp(struct DisOp *o) {
|
||||
free(o->s);
|
||||
}
|
||||
|
||||
void DisFreeOps(struct DisOps *ops) {
|
||||
long i;
|
||||
for (i = 0; i < ops->i; ++i) {
|
||||
DisFreeOp(&ops->p[i]);
|
||||
}
|
||||
free(ops->p);
|
||||
bzero(ops, sizeof(*ops));
|
||||
}
|
||||
|
||||
void DisFree(struct Dis *d) {
|
||||
long i;
|
||||
DisFreeOps(&d->ops);
|
||||
free(d->edges.p);
|
||||
free(d->loads.p);
|
||||
free(d->syms.p);
|
||||
bzero(d, sizeof(*d));
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_DIS_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_DIS_H_
|
||||
#include "third_party/xed/x86.h"
|
||||
#include "tool/build/lib/loader.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define DIS_MAX_SYMBOL_LENGTH 32
|
||||
|
||||
struct Dis {
|
||||
struct DisOps {
|
||||
size_t i, n;
|
||||
struct DisOp {
|
||||
int64_t addr;
|
||||
uint8_t size;
|
||||
bool active;
|
||||
char *s;
|
||||
} * p;
|
||||
} ops;
|
||||
struct DisLoads {
|
||||
size_t i, n;
|
||||
struct DisLoad {
|
||||
int64_t addr;
|
||||
uint64_t size;
|
||||
bool istext;
|
||||
} * p;
|
||||
} loads;
|
||||
struct DisSyms {
|
||||
size_t i, n;
|
||||
struct DisSym {
|
||||
int64_t addr;
|
||||
int unique;
|
||||
int size;
|
||||
int name;
|
||||
char rank;
|
||||
bool iscode;
|
||||
bool isabs;
|
||||
} * p;
|
||||
const char *stab;
|
||||
} syms;
|
||||
struct DisEdges {
|
||||
size_t i, n;
|
||||
struct DisEdge {
|
||||
int64_t src;
|
||||
int64_t dst;
|
||||
} * p;
|
||||
} edges;
|
||||
struct XedDecodedInst xedd[1];
|
||||
struct Machine *m; /* for the segment registers */
|
||||
uint64_t addr; /* current effective address */
|
||||
char buf[512];
|
||||
};
|
||||
|
||||
extern bool g_disisprog_disable;
|
||||
|
||||
long Dis(struct Dis *, struct Machine *, uint64_t, uint64_t, int);
|
||||
long DisFind(struct Dis *, int64_t);
|
||||
void DisFree(struct Dis *);
|
||||
void DisFreeOp(struct DisOp *);
|
||||
void DisFreeOps(struct DisOps *);
|
||||
void DisLoadElf(struct Dis *, struct Elf *);
|
||||
long DisFindSym(struct Dis *, int64_t);
|
||||
long DisFindSymByName(struct Dis *, const char *);
|
||||
bool DisIsText(struct Dis *, int64_t);
|
||||
bool DisIsProg(struct Dis *, int64_t);
|
||||
char *DisInst(struct Dis *, char *, const char *);
|
||||
char *DisArg(struct Dis *, char *, const char *);
|
||||
const char *DisSpec(struct XedDecodedInst *, char *);
|
||||
const char *DisGetLine(struct Dis *, struct Machine *, size_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_DIS_H_ */
|
|
@ -1,747 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/fmt/itoa.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/build/lib/demangle.h"
|
||||
#include "tool/build/lib/dis.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/high.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
|
||||
static const char kRiz[2][4] = {"eiz", "riz"};
|
||||
static const char kRip[2][4] = {"eip", "rip"};
|
||||
static const char kSka[4][4] = {"", ",2", ",4", ",8"};
|
||||
static const char kSeg[8][3] = {"es", "cs", "ss", "ds", "fs", "gs"};
|
||||
static const char kCtl[8][4] = {"cr0", "wut", "cr2", "cr3",
|
||||
"cr4", "wut", "wut", "wut"};
|
||||
|
||||
static const char kBreg[2][2][8][5] = {
|
||||
{{"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"},
|
||||
{"al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil"}},
|
||||
{{"wut", "wut", "wut", "wut", "wut", "wut", "wut", "wut"},
|
||||
{"r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b"}},
|
||||
};
|
||||
|
||||
static const char kGreg[2][2][2][8][5] = {
|
||||
{{{"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"},
|
||||
{"r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d"}},
|
||||
{{"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi"},
|
||||
{"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}}},
|
||||
{{{"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"},
|
||||
{"r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w"}},
|
||||
{{"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi"},
|
||||
{"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}}},
|
||||
};
|
||||
|
||||
static int64_t RipRelative(struct Dis *d, int64_t i) {
|
||||
return d->addr + d->xedd->length + i;
|
||||
}
|
||||
|
||||
static int64_t ZeroExtend(uint32_t rde, int64_t i) {
|
||||
switch (Mode(rde)) {
|
||||
case XED_MODE_REAL:
|
||||
return i & 0xffff;
|
||||
case XED_MODE_LEGACY:
|
||||
return i & 0xffffffff;
|
||||
default:
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
static int64_t Unrelative(uint32_t rde, int64_t i) {
|
||||
switch (Eamode(rde)) {
|
||||
case XED_MODE_REAL:
|
||||
return i & 0xffff;
|
||||
case XED_MODE_LEGACY:
|
||||
return i & 0xffffffff;
|
||||
default:
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
static int64_t GetSeg(struct Dis *d, uint32_t rde, unsigned char *s) {
|
||||
switch (Sego(rde) ? Sego(rde) : d->xedd->op.hint) {
|
||||
default:
|
||||
return Read64(s);
|
||||
case 1:
|
||||
return Read64(d->m->es);
|
||||
case 2:
|
||||
return Read64(d->m->cs);
|
||||
case 3:
|
||||
return Read64(d->m->ss);
|
||||
case 4:
|
||||
return Read64(d->m->ds);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *GetAddrReg(struct Dis *d, uint32_t rde, uint8_t x,
|
||||
uint8_t r) {
|
||||
return kGreg[Eamode(rde) == XED_MODE_REAL][Eamode(rde) == XED_MODE_LONG]
|
||||
[x & 1][r & 7];
|
||||
}
|
||||
|
||||
static char *DisRegister(char *p, const char *s) {
|
||||
p = HighStart(p, g_high.reg);
|
||||
*p++ = '%';
|
||||
p = stpcpy(p, s);
|
||||
p = HighEnd(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisComment(char *p, const char *s) {
|
||||
p = HighStart(p, g_high.comment);
|
||||
p = stpcpy(p, s);
|
||||
p = HighEnd(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisRegisterByte(struct Dis *d, uint32_t rde, char *p, bool g,
|
||||
int r) {
|
||||
return DisRegister(p, kBreg[g][Rex(rde)][r]);
|
||||
}
|
||||
|
||||
static char *DisRegisterWord(struct Dis *d, uint32_t rde, char *p, bool g,
|
||||
int r) {
|
||||
return DisRegister(p, kGreg[Osz(rde)][Rexw(rde)][g][r]);
|
||||
}
|
||||
|
||||
static char *DisInt(char *p, int64_t x) {
|
||||
if (-15 <= x && x <= 15) {
|
||||
p = FormatInt64(p, x);
|
||||
} else if (x == INT64_MIN) {
|
||||
p = stpcpy(p, "-0x");
|
||||
p += uint64toarray_radix16(INT64_MIN, p);
|
||||
} else if (x < 0 && -x < 0xFFFFFFFF) {
|
||||
p = stpcpy(p, "-0x");
|
||||
p += uint64toarray_radix16(-x, p);
|
||||
} else {
|
||||
p = stpcpy(p, "0x");
|
||||
p += uint64toarray_radix16(x, p);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisSymImpl(struct Dis *d, char *p, int64_t x, long sym) {
|
||||
int64_t addend;
|
||||
const char *name;
|
||||
addend = x - d->syms.p[sym].addr;
|
||||
name = d->syms.stab + d->syms.p[sym].name;
|
||||
p = Demangle(p, name, DIS_MAX_SYMBOL_LENGTH);
|
||||
if (addend) {
|
||||
*p++ = '+';
|
||||
p = DisInt(p, addend);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisSym(struct Dis *d, char *p, int64_t value, int64_t addr) {
|
||||
long sym;
|
||||
if ((sym = DisFindSym(d, addr)) != -1 && d->syms.p[sym].name) {
|
||||
return DisSymImpl(d, p, addr, sym);
|
||||
} else {
|
||||
return DisInt(p, value);
|
||||
}
|
||||
}
|
||||
|
||||
static char *DisSymLiteral(struct Dis *d, uint32_t rde, char *p, uint64_t addr,
|
||||
uint64_t ip) {
|
||||
*p++ = '$';
|
||||
p = HighStart(p, g_high.literal);
|
||||
p = DisSym(d, p, addr, addr);
|
||||
p = HighEnd(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisGvqp(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegisterWord(d, rde, p, Rexr(rde), ModrmReg(rde));
|
||||
}
|
||||
|
||||
static char *DisGdqp(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegister(p, kGreg[0][Rexw(rde)][Rexr(rde)][ModrmReg(rde)]);
|
||||
}
|
||||
|
||||
static char *DisGb(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegisterByte(d, rde, p, Rexr(rde), ModrmReg(rde));
|
||||
}
|
||||
|
||||
static char *DisSego(struct Dis *d, uint32_t rde, char *p) {
|
||||
int seg;
|
||||
seg = Sego(rde) ? Sego(rde) : d->xedd->op.hint;
|
||||
if (seg) {
|
||||
p = DisRegister(p, kSeg[seg - 1]);
|
||||
*p++ = ':';
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static bool IsRealModrmAbsolute(uint32_t rde) {
|
||||
return Eamode(rde) == XED_MODE_REAL && ModrmRm(rde) == 6 && !ModrmMod(rde);
|
||||
}
|
||||
|
||||
static char *DisDisp(struct Dis *d, uint32_t rde, char *p) {
|
||||
bool rela;
|
||||
int64_t disp;
|
||||
if (ModrmMod(rde) == 0b01 || ModrmMod(rde) == 0b10 || IsRipRelative(rde) ||
|
||||
IsRealModrmAbsolute(rde) ||
|
||||
(Eamode(rde) != XED_MODE_REAL && ModrmMod(rde) == 0b00 &&
|
||||
ModrmRm(rde) == 0b100 && SibBase(d->xedd) == 0b101)) {
|
||||
disp = d->xedd->op.disp;
|
||||
if (IsRipRelative(rde)) {
|
||||
if (Mode(rde) == XED_MODE_LONG) {
|
||||
disp = RipRelative(d, disp);
|
||||
rela = true;
|
||||
} else {
|
||||
disp = Unrelative(rde, disp);
|
||||
rela = false;
|
||||
}
|
||||
} else if (IsRealModrmAbsolute(rde)) {
|
||||
disp = Unrelative(rde, disp);
|
||||
rela = false;
|
||||
} else {
|
||||
rela = true;
|
||||
}
|
||||
p = DisSym(d, p, disp, disp);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisBis(struct Dis *d, uint32_t rde, char *p) {
|
||||
const char *base, *index, *scale;
|
||||
base = index = scale = NULL;
|
||||
if (Eamode(rde) != XED_MODE_REAL) {
|
||||
if (!SibExists(rde)) {
|
||||
DCHECK(!d->xedd->op.has_sib);
|
||||
if (IsRipRelative(rde)) {
|
||||
if (Mode(rde) == XED_MODE_LONG) {
|
||||
base = kRip[Eamode(rde) == XED_MODE_LONG];
|
||||
}
|
||||
} else {
|
||||
base = GetAddrReg(d, rde, Rexb(rde), ModrmRm(rde));
|
||||
}
|
||||
} else if (!SibIsAbsolute(d->xedd, rde)) {
|
||||
if (SibHasBase(d->xedd, rde)) {
|
||||
base = GetAddrReg(d, rde, Rexb(rde), SibBase(d->xedd));
|
||||
}
|
||||
if (SibHasIndex(d->xedd)) {
|
||||
index = GetAddrReg(d, rde, Rexx(d->xedd), SibIndex(d->xedd));
|
||||
} else if (d->xedd->op.scale) {
|
||||
index = kRiz[Eamode(rde) == XED_MODE_LONG];
|
||||
}
|
||||
scale = kSka[d->xedd->op.scale];
|
||||
}
|
||||
} else {
|
||||
switch (ModrmRm(rde)) {
|
||||
case 0:
|
||||
base = "bx";
|
||||
index = "si";
|
||||
break;
|
||||
case 1:
|
||||
base = "bx";
|
||||
index = "di";
|
||||
break;
|
||||
case 2:
|
||||
base = "bp";
|
||||
index = "si";
|
||||
break;
|
||||
case 3:
|
||||
base = "bp";
|
||||
index = "di";
|
||||
break;
|
||||
case 4:
|
||||
base = "si";
|
||||
break;
|
||||
case 5:
|
||||
base = "di";
|
||||
break;
|
||||
case 6:
|
||||
if (ModrmMod(rde)) base = "bp";
|
||||
break;
|
||||
case 7:
|
||||
base = "bx";
|
||||
break;
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
if (base || index) {
|
||||
*p++ = '(';
|
||||
if (base) {
|
||||
p = DisRegister(p, base);
|
||||
}
|
||||
if (index) {
|
||||
*p++ = ',';
|
||||
p = DisRegister(p, index);
|
||||
if (scale) {
|
||||
p = stpcpy(p, scale);
|
||||
}
|
||||
}
|
||||
*p++ = ')';
|
||||
}
|
||||
*p = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisM(struct Dis *d, uint32_t rde, char *p) {
|
||||
p = DisSego(d, rde, p);
|
||||
p = DisDisp(d, rde, p);
|
||||
p = DisBis(d, rde, p);
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisRegMem(struct Dis *d, uint32_t rde, char *p,
|
||||
char *f(struct Dis *, uint32_t, char *)) {
|
||||
if (IsModrmRegister(rde)) {
|
||||
return f(d, rde, p);
|
||||
} else {
|
||||
return DisM(d, rde, p);
|
||||
}
|
||||
}
|
||||
|
||||
static dontinline char *DisE(struct Dis *d, uint32_t rde, char *p,
|
||||
char *f(struct Dis *, uint32_t, char *, bool,
|
||||
int)) {
|
||||
if (IsModrmRegister(rde)) {
|
||||
return f(d, rde, p, Rexb(rde), ModrmRm(rde));
|
||||
} else {
|
||||
return DisM(d, rde, p);
|
||||
}
|
||||
}
|
||||
|
||||
static char *DisEb(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisE(d, rde, p, DisRegisterByte);
|
||||
}
|
||||
|
||||
static char *DisEvqp(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisE(d, rde, p, DisRegisterWord);
|
||||
}
|
||||
|
||||
static char *DisRv(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegister(p, kGreg[Osz(rde)][0][Rexb(rde)][ModrmRm(rde)]);
|
||||
}
|
||||
|
||||
static char *DisRvqp(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegister(p, kGreg[Osz(rde)][Rexw(rde)][Rexb(rde)][ModrmRm(rde)]);
|
||||
}
|
||||
|
||||
static char *DisRdqp(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegister(p, kGreg[0][Rexw(rde)][Rexb(rde)][ModrmRm(rde)]);
|
||||
}
|
||||
|
||||
static char *DisEdqp(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegMem(d, rde, p, DisRdqp);
|
||||
}
|
||||
|
||||
static char *DisEv(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegMem(d, rde, p, DisRv);
|
||||
}
|
||||
|
||||
static char *DisGvq(struct Dis *d, uint32_t rde, char *p, int r) {
|
||||
const char *s;
|
||||
if (Mode(rde) == XED_MODE_LONG) {
|
||||
s = kGreg[Osz(rde)][!Osz(rde)][Rexb(rde)][r];
|
||||
} else {
|
||||
s = kGreg[Osz(rde)][0][Rexb(rde)][r];
|
||||
}
|
||||
return DisRegister(p, s);
|
||||
}
|
||||
|
||||
static char *DisZvq(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisGvq(d, rde, p, ModrmSrm(rde));
|
||||
}
|
||||
|
||||
static char *DisEvqReg(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisGvq(d, rde, p, ModrmRm(rde));
|
||||
}
|
||||
|
||||
static char *DisEvq(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegMem(d, rde, p, DisEvqReg);
|
||||
}
|
||||
|
||||
static char *DisEdReg(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegister(p, kGreg[0][0][Rexb(rde)][ModrmRm(rde)]);
|
||||
}
|
||||
|
||||
static char *DisEd(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegMem(d, rde, p, DisEdReg);
|
||||
}
|
||||
|
||||
static char *DisEqReg(struct Dis *d, uint32_t rde, char *p) {
|
||||
const char *r;
|
||||
if (Mode(rde) == XED_MODE_LONG) {
|
||||
r = kGreg[0][1][Rexb(rde)][ModrmRm(rde)];
|
||||
} else {
|
||||
r = kGreg[Osz(rde)][0][Rexb(rde)][ModrmRm(rde)];
|
||||
}
|
||||
return DisRegister(p, r);
|
||||
}
|
||||
|
||||
static char *DisEq(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegMem(d, rde, p, DisEqReg);
|
||||
}
|
||||
|
||||
static char *DisZvqp(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegisterWord(d, rde, p, Rexb(rde), ModrmSrm(rde));
|
||||
}
|
||||
|
||||
static char *DisZb(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegisterByte(d, rde, p, Rexb(rde), ModrmSrm(rde));
|
||||
}
|
||||
|
||||
static char *DisEax(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegister(p, kGreg[Osz(rde)][0][0][0]);
|
||||
}
|
||||
|
||||
static char *DisRax(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegister(p, kGreg[Osz(rde)][Rexw(rde)][0][0]);
|
||||
}
|
||||
|
||||
static char *DisRdx(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegister(p, kGreg[Osz(rde)][Rexw(rde)][0][2]);
|
||||
}
|
||||
|
||||
static char *DisPort(struct Dis *d, uint32_t rde, char *p) {
|
||||
*p++ = '(';
|
||||
p = DisRegister(p, kGreg[1][0][0][2]);
|
||||
*p++ = ')';
|
||||
*p = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisCd(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegister(p, kCtl[ModrmReg(rde)]);
|
||||
}
|
||||
|
||||
static char *DisHd(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegister(p, kGreg[0][Mode(rde) == XED_MODE_LONG][0][ModrmRm(rde)]);
|
||||
}
|
||||
|
||||
static char *DisImm(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisSymLiteral(d, rde, p, d->xedd->op.uimm0,
|
||||
ZeroExtend(rde, d->xedd->op.uimm0));
|
||||
}
|
||||
|
||||
static char *DisRvds(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisSymLiteral(d, rde, p, d->xedd->op.disp, d->xedd->op.disp);
|
||||
}
|
||||
|
||||
static char *DisKpvds(struct Dis *d, uint32_t rde, char *p, uint64_t x) {
|
||||
*p++ = '$';
|
||||
p = HighStart(p, g_high.literal);
|
||||
p = DisInt(p, x);
|
||||
p = HighEnd(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisKvds(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisKpvds(d, rde, p, d->xedd->op.uimm0);
|
||||
}
|
||||
|
||||
static char *DisPvds(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisKpvds(d, rde, p,
|
||||
d->xedd->op.disp & (Osz(rde) ? 0xffff : 0xffffffff));
|
||||
}
|
||||
|
||||
static char *DisOne(struct Dis *d, uint32_t rde, char *p) {
|
||||
*p++ = '$';
|
||||
p = HighStart(p, g_high.literal);
|
||||
p = stpcpy(p, "1");
|
||||
p = HighEnd(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisJbs(struct Dis *d, uint32_t rde, char *p) {
|
||||
if (d->xedd->op.disp > 0) *p++ = '+';
|
||||
p = FormatInt64(p, d->xedd->op.disp);
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisJb(struct Dis *d, uint32_t rde, char *p) {
|
||||
if (d->xedd->op.disp > 0) *p++ = '+';
|
||||
p = FormatUint32(p, d->xedd->op.disp & 0xff);
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisJvds(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisSym(d, p, RipRelative(d, d->xedd->op.disp),
|
||||
RipRelative(d, d->xedd->op.disp) - Read64(d->m->cs));
|
||||
}
|
||||
|
||||
static char *DisAbs(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisSym(d, p, d->xedd->op.disp, d->xedd->op.disp);
|
||||
}
|
||||
|
||||
static char *DisSw(struct Dis *d, uint32_t rde, char *p) {
|
||||
if (kSeg[ModrmReg(rde)][0]) p = DisRegister(p, kSeg[ModrmReg(rde)]);
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisSpecialAddr(struct Dis *d, uint32_t rde, char *p, int r) {
|
||||
*p++ = '(';
|
||||
p = DisRegister(p, GetAddrReg(d, rde, 0, r));
|
||||
*p++ = ')';
|
||||
*p = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisY(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisSpecialAddr(d, rde, p, 7); // es:di
|
||||
}
|
||||
|
||||
static char *DisX(struct Dis *d, uint32_t rde, char *p) {
|
||||
p = DisSego(d, rde, p);
|
||||
return DisSpecialAddr(d, rde, p, 6); // ds:si
|
||||
}
|
||||
|
||||
static char *DisBBb(struct Dis *d, uint32_t rde, char *p) {
|
||||
p = DisSego(d, rde, p);
|
||||
return DisSpecialAddr(d, rde, p, 3); // ds:bx
|
||||
}
|
||||
|
||||
static char *DisXmm(struct Dis *d, uint32_t rde, char *p, const char *s,
|
||||
int reg) {
|
||||
p = HighStart(p, g_high.reg);
|
||||
*p++ = '%';
|
||||
p = stpcpy(p, s);
|
||||
p = FormatUint32(p, reg);
|
||||
p = HighEnd(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisNq(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisXmm(d, rde, p, "mm", ModrmRm(rde));
|
||||
}
|
||||
|
||||
static char *DisPq(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisXmm(d, rde, p, "mm", ModrmReg(rde));
|
||||
}
|
||||
|
||||
static char *DisUq(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisXmm(d, rde, p, "xmm", RexbRm(rde));
|
||||
}
|
||||
|
||||
static char *DisUdq(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisXmm(d, rde, p, "xmm", RexbRm(rde));
|
||||
}
|
||||
|
||||
static char *DisVdq(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisXmm(d, rde, p, "xmm", RexrReg(rde));
|
||||
}
|
||||
|
||||
static char *DisQq(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegMem(d, rde, p, DisNq);
|
||||
}
|
||||
|
||||
static char *DisEst(struct Dis *d, uint32_t rde, char *p) {
|
||||
p = DisRegister(p, "st");
|
||||
if (ModrmRm(rde) != 0) {
|
||||
*p++ = '(';
|
||||
*p++ = '0' + ModrmRm(rde);
|
||||
*p++ = ')';
|
||||
*p = '\0';
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisEst1(struct Dis *d, uint32_t rde, char *p) {
|
||||
if (ModrmRm(rde) != 1) {
|
||||
p = DisEst(d, rde, p);
|
||||
} else {
|
||||
*p = '\0';
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisEssr(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegMem(d, rde, p, DisEst);
|
||||
}
|
||||
|
||||
static char *DisWps(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegMem(d, rde, p, DisUdq);
|
||||
}
|
||||
|
||||
#define DisEdr DisM
|
||||
#define DisEqp DisEq
|
||||
#define DisEsr DisM
|
||||
#define DisGv DisGvqp
|
||||
#define DisIb DisImm
|
||||
#define DisIbs DisImm
|
||||
#define DisIbss DisImm
|
||||
#define DisIvds DisImm
|
||||
#define DisIvqp DisImm
|
||||
#define DisIvs DisImm
|
||||
#define DisIw DisImm
|
||||
#define DisMdi DisM
|
||||
#define DisMdq DisM
|
||||
#define DisMdqp DisM
|
||||
#define DisMdr DisM
|
||||
#define DisMe DisM
|
||||
#define DisMer DisM
|
||||
#define DisMp DisM
|
||||
#define DisMps DisM
|
||||
#define DisMq DisM
|
||||
#define DisMqi DisM
|
||||
#define DisMs DisM
|
||||
#define DisMsr DisEssr
|
||||
#define DisMw DisM
|
||||
#define DisMwi DisM
|
||||
#define DisOb DisAbs
|
||||
#define DisOvqp DisAbs
|
||||
#define DisPpi DisPq
|
||||
#define DisQpi DisQq
|
||||
#define DisVpd DisVdq
|
||||
#define DisVps DisVdq
|
||||
#define DisVq DisVdq
|
||||
#define DisVsd DisVdq
|
||||
#define DisVss DisVdq
|
||||
#define DisWdq DisWps
|
||||
#define DisWpd DisWps
|
||||
#define DisWpsq DisWps
|
||||
#define DisWq DisWps
|
||||
#define DisWsd DisWps
|
||||
#define DisWss DisWps
|
||||
#define DisXb DisX
|
||||
#define DisXv DisX
|
||||
#define DisXvqp DisX
|
||||
#define DisYb DisY
|
||||
#define DisYv DisY
|
||||
#define DisYvqp DisY
|
||||
#define DisZv DisZvqp
|
||||
|
||||
static const struct DisArg {
|
||||
char s[8];
|
||||
char *(*f)(struct Dis *, uint32_t, char *);
|
||||
} kDisArgs[] = /* <sorted> */ {
|
||||
{"$1", DisOne}, //
|
||||
{"%Cd", DisCd}, //
|
||||
{"%Gb", DisGb}, //
|
||||
{"%Gdqp", DisGdqp}, //
|
||||
{"%Gv", DisGv}, //
|
||||
{"%Gvqp", DisGvqp}, //
|
||||
{"%Hd", DisHd}, //
|
||||
{"%Nq", DisNq}, //
|
||||
{"%Ppi", DisPpi}, //
|
||||
{"%Pq", DisPq}, //
|
||||
{"%Rdqp", DisRdqp}, //
|
||||
{"%Rvqp", DisRvqp}, //
|
||||
{"%Sw", DisSw}, //
|
||||
{"%Udq", DisUdq}, //
|
||||
{"%Uq", DisUq}, //
|
||||
{"%Vdq", DisVdq}, //
|
||||
{"%Vpd", DisVpd}, //
|
||||
{"%Vps", DisVps}, //
|
||||
{"%Vq", DisVq}, //
|
||||
{"%Vsd", DisVsd}, //
|
||||
{"%Vss", DisVss}, //
|
||||
{"%Zb", DisZb}, //
|
||||
{"%Zv", DisZv}, //
|
||||
{"%Zvq", DisZvq}, //
|
||||
{"%Zvqp", DisZvqp}, //
|
||||
{"%eAX", DisEax}, //
|
||||
{"%rAX", DisRax}, //
|
||||
{"%rDX", DisRdx}, //
|
||||
{"BBb", DisBBb}, //
|
||||
{"DX", DisPort}, //
|
||||
{"EST", DisEst}, //
|
||||
{"EST1", DisEst1}, //
|
||||
{"ESsr", DisEssr}, //
|
||||
{"Eb", DisEb}, //
|
||||
{"Ed", DisEd}, //
|
||||
{"Edqp", DisEdqp}, //
|
||||
{"Edr", DisEdr}, //
|
||||
{"Eq", DisEq}, //
|
||||
{"Eqp", DisEqp}, //
|
||||
{"Esr", DisEsr}, //
|
||||
{"Ev", DisEv}, //
|
||||
{"Evq", DisEvq}, //
|
||||
{"Evqp", DisEvqp}, //
|
||||
{"Ew", DisEvqp}, //
|
||||
{"Ib", DisIb}, //
|
||||
{"Ibs", DisIbs}, //
|
||||
{"Ibss", DisIbss}, //
|
||||
{"Ivds", DisIvds}, //
|
||||
{"Ivqp", DisIvqp}, //
|
||||
{"Ivs", DisIvs}, //
|
||||
{"Iw", DisIw}, //
|
||||
{"Jb", DisJb}, //
|
||||
{"Jbs", DisJbs}, //
|
||||
{"Jvds", DisJvds}, //
|
||||
{"Kvds", DisKvds}, //
|
||||
{"M", DisM}, //
|
||||
{"Mdi", DisMdi}, //
|
||||
{"Mdq", DisMdq}, //
|
||||
{"Mdqp", DisMdqp}, //
|
||||
{"Mdr", DisMdr}, //
|
||||
{"Me", DisMe}, //
|
||||
{"Mer", DisMer}, //
|
||||
{"Mp", DisMp}, //
|
||||
{"Mps", DisMps}, //
|
||||
{"Mq", DisMq}, //
|
||||
{"Mqi", DisMqi}, //
|
||||
{"Ms", DisMs}, //
|
||||
{"Msr", DisMsr}, //
|
||||
{"Mw", DisMw}, //
|
||||
{"Mwi", DisMwi}, //
|
||||
{"Ob", DisOb}, //
|
||||
{"Ovqp", DisOvqp}, //
|
||||
{"Pvds", DisPvds}, //
|
||||
{"Qpi", DisQpi}, //
|
||||
{"Qq", DisQq}, //
|
||||
{"Rvds", DisRvds}, //
|
||||
{"Wdq", DisWdq}, //
|
||||
{"Wpd", DisWpd}, //
|
||||
{"Wps", DisWps}, //
|
||||
{"Wpsq", DisWpsq}, //
|
||||
{"Wq", DisWq}, //
|
||||
{"Wsd", DisWsd}, //
|
||||
{"Wss", DisWss}, //
|
||||
{"Xb", DisXb}, //
|
||||
{"Xv", DisXv}, //
|
||||
{"Xvqp", DisXvqp}, //
|
||||
{"Yb", DisYb}, //
|
||||
{"Yv", DisYv}, //
|
||||
{"Yvqp", DisYvqp}, //
|
||||
};
|
||||
|
||||
char *DisArg(struct Dis *d, char *p, const char *s) {
|
||||
char k[8];
|
||||
int m, l, r;
|
||||
l = 0;
|
||||
r = ARRAYLEN(kDisArgs) - 1;
|
||||
strncpy(k, s, 8);
|
||||
while (l <= r) {
|
||||
m = (l + r) >> 1;
|
||||
if (READ64BE(kDisArgs[m].s) < READ64BE(k)) {
|
||||
l = m + 1;
|
||||
} else if (READ64BE(kDisArgs[m].s) > READ64BE(k)) {
|
||||
r = m - 1;
|
||||
} else {
|
||||
return kDisArgs[m].f(d, d->xedd->op.rde, p);
|
||||
}
|
||||
}
|
||||
if (*s == '%') {
|
||||
p = DisRegister(p, s + 1);
|
||||
} else {
|
||||
p = stpcpy(p, s);
|
||||
}
|
||||
return p;
|
||||
}
|
|
@ -1,220 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/elf/elf.h"
|
||||
#include "libc/elf/struct/sym.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/alg.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/build/lib/dis.h"
|
||||
|
||||
bool g_disisprog_disable;
|
||||
|
||||
static int DisSymCompare(const struct DisSym *a, const struct DisSym *b) {
|
||||
if (a->addr != b->addr) {
|
||||
if (a->addr < b->addr) return -1;
|
||||
if (a->addr > b->addr) return +1;
|
||||
}
|
||||
if (a->rank != b->rank) {
|
||||
if (a->rank > b->rank) return -1;
|
||||
if (a->rank < b->rank) return +1;
|
||||
}
|
||||
if (a->unique != b->unique) {
|
||||
if (a->unique < b->unique) return -1;
|
||||
if (a->unique > b->unique) return +1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void DisLoadElfLoads(struct Dis *d, struct Elf *elf) {
|
||||
long i, j, n;
|
||||
int64_t addr;
|
||||
uint64_t size;
|
||||
Elf64_Phdr *phdr;
|
||||
j = 0;
|
||||
n = elf->ehdr->e_phnum;
|
||||
if (d->loads.n < n) {
|
||||
d->loads.n = n;
|
||||
d->loads.p = realloc(d->loads.p, d->loads.n * sizeof(*d->loads.p));
|
||||
CHECK_NOTNULL(d->loads.p);
|
||||
}
|
||||
for (i = 0; i < n; ++i) {
|
||||
phdr = GetElfSegmentHeaderAddress(elf->ehdr, elf->size, i);
|
||||
if (phdr->p_type != PT_LOAD) continue;
|
||||
d->loads.p[j].addr = phdr->p_vaddr;
|
||||
d->loads.p[j].size = phdr->p_memsz;
|
||||
d->loads.p[j].istext = (phdr->p_flags & PF_X) == PF_X;
|
||||
++j;
|
||||
}
|
||||
d->loads.i = j;
|
||||
}
|
||||
|
||||
static void DisLoadElfSyms(struct Dis *d, struct Elf *elf) {
|
||||
size_t i, j, n;
|
||||
int64_t stablen;
|
||||
const Elf64_Sym *st, *sym;
|
||||
bool isabs, iscode, isweak, islocal, ishidden, isprotected, isfunc, isobject;
|
||||
j = 0;
|
||||
if ((d->syms.stab = GetElfStringTable(elf->ehdr, elf->size)) &&
|
||||
(st = GetElfSymbolTable(elf->ehdr, elf->size, &n))) {
|
||||
stablen = (intptr_t)elf->ehdr + elf->size - (intptr_t)d->syms.stab;
|
||||
if (d->syms.n < n) {
|
||||
d->syms.n = n;
|
||||
d->syms.p = realloc(d->syms.p, d->syms.n * sizeof(*d->syms.p));
|
||||
CHECK_NOTNULL(d->syms.p);
|
||||
}
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (ELF64_ST_TYPE(st[i].st_info) == STT_SECTION ||
|
||||
ELF64_ST_TYPE(st[i].st_info) == STT_FILE || !st[i].st_name ||
|
||||
_startswith(d->syms.stab + st[i].st_name, "v_") ||
|
||||
!(0 <= st[i].st_name && st[i].st_name < stablen) || !st[i].st_value ||
|
||||
!IsLegalPointer(st[i].st_value)) {
|
||||
continue;
|
||||
}
|
||||
isabs = st[i].st_shndx == SHN_ABS;
|
||||
isweak = ELF64_ST_BIND(st[i].st_info) == STB_WEAK;
|
||||
islocal = ELF64_ST_BIND(st[i].st_info) == STB_LOCAL;
|
||||
ishidden = st[i].st_other == STV_HIDDEN;
|
||||
isprotected = st[i].st_other == STV_PROTECTED;
|
||||
isfunc = ELF64_ST_TYPE(st[i].st_info) == STT_FUNC;
|
||||
isobject = ELF64_ST_TYPE(st[i].st_info) == STT_OBJECT;
|
||||
d->syms.p[j].unique = i;
|
||||
d->syms.p[j].size = st[i].st_size;
|
||||
d->syms.p[j].name = st[i].st_name;
|
||||
CHECK_GE(st[i].st_value, 0);
|
||||
d->syms.p[j].addr = st[i].st_value;
|
||||
d->syms.p[j].rank =
|
||||
-islocal + -isweak + -isabs + isprotected + isobject + isfunc;
|
||||
d->syms.p[j].iscode = DisIsText(d, st[i].st_value) ? !isobject : isfunc;
|
||||
d->syms.p[j].isabs = isabs;
|
||||
++j;
|
||||
}
|
||||
}
|
||||
d->syms.i = j;
|
||||
}
|
||||
|
||||
static void DisSortSyms(struct Dis *d) {
|
||||
size_t i, j;
|
||||
qsort(d->syms.p, d->syms.i, sizeof(struct DisSym), (void *)DisSymCompare);
|
||||
for (i = 0; i < d->syms.i; ++i) {
|
||||
if (!strcmp("_end", d->syms.stab + d->syms.p[i].name)) {
|
||||
d->syms.i = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void DisCanonizeSyms(struct Dis *d) {
|
||||
int64_t i, j, a;
|
||||
if (d->syms.i) {
|
||||
i = 1;
|
||||
j = 1;
|
||||
a = d->syms.p[0].addr;
|
||||
do {
|
||||
if (d->syms.p[j].addr > a) {
|
||||
a = d->syms.p[j].addr;
|
||||
if (j > i) {
|
||||
d->syms.p[i] = d->syms.p[j];
|
||||
}
|
||||
++i;
|
||||
}
|
||||
++j;
|
||||
} while (j < d->syms.i);
|
||||
d->syms.p = realloc(d->syms.p, sizeof(*d->syms.p) * i);
|
||||
d->syms.i = i;
|
||||
d->syms.n = i;
|
||||
}
|
||||
for (i = 0; i < d->syms.i; ++i) {
|
||||
DEBUGF("%012lx-%012lx %s", d->syms.p[i].addr,
|
||||
d->syms.p[i].addr + (d->syms.p[i].size ? d->syms.p[i].size - 1 : 0),
|
||||
d->syms.stab + d->syms.p[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
bool DisIsProg(struct Dis *d, int64_t addr) {
|
||||
long i;
|
||||
if (g_disisprog_disable) return true;
|
||||
for (i = 0; i < d->loads.i; ++i) {
|
||||
if (addr >= d->loads.p[i].addr &&
|
||||
addr < d->loads.p[i].addr + d->loads.p[i].size) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DisIsText(struct Dis *d, int64_t addr) {
|
||||
long i;
|
||||
for (i = 0; i < d->loads.i; ++i) {
|
||||
if (addr >= d->loads.p[i].addr &&
|
||||
addr < d->loads.p[i].addr + d->loads.p[i].size) {
|
||||
return d->loads.p[i].istext;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
long DisFindSym(struct Dis *d, int64_t addr) {
|
||||
long l, r, m, n;
|
||||
if (DisIsProg(d, addr)) {
|
||||
l = 0;
|
||||
r = d->syms.i;
|
||||
while (l < r) {
|
||||
m = (l + r) >> 1;
|
||||
if (d->syms.p[m].addr > addr) {
|
||||
r = m;
|
||||
} else {
|
||||
l = m + 1;
|
||||
}
|
||||
}
|
||||
// TODO(jart): This was <256 but that broke SectorLISP debugging
|
||||
// Why did the Cosmo binbase bootloader need this?
|
||||
if (r && d->syms.p[r - 1].addr < 32) {
|
||||
return -1;
|
||||
}
|
||||
if (r && (addr == d->syms.p[r - 1].addr ||
|
||||
(addr > d->syms.p[r - 1].addr &&
|
||||
(addr <= d->syms.p[r - 1].addr + d->syms.p[r - 1].size ||
|
||||
!d->syms.p[r - 1].size)))) {
|
||||
return r - 1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
long DisFindSymByName(struct Dis *d, const char *s) {
|
||||
long i;
|
||||
for (i = 0; i < d->syms.i; ++i) {
|
||||
if (strcmp(s, d->syms.stab + d->syms.p[i].name) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void DisLoadElf(struct Dis *d, struct Elf *elf) {
|
||||
if (!elf || !elf->ehdr) return;
|
||||
DisLoadElfLoads(d, elf);
|
||||
DisLoadElfSyms(d, elf);
|
||||
DisSortSyms(d);
|
||||
/* DisCanonizeSyms(d); */
|
||||
}
|
|
@ -1,215 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/str/str.h"
|
||||
#include "tool/build/lib/dis.h"
|
||||
#include "tool/build/lib/high.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
|
||||
static const char kJcxz[3][6] = {"jcxz", "jecxz", "jrcxz"};
|
||||
static const char kAluOp[8][4] = {"add", "or", "adc", "sbb",
|
||||
"and", "sub", "xor", "cmp"};
|
||||
static const char kBitOp[8][4] = {"rol", "ror", "rcl", "rcr",
|
||||
"shl", "shr", "sal", "sar"};
|
||||
static const char kCc[16][3] = {"o", "no", "b", "ae", "e", "ne", "be", "a",
|
||||
"s", "ns", "p", "np", "l", "ge", "le", "g"};
|
||||
|
||||
static bool IsProbablyByteOp(struct XedDecodedInst *x) {
|
||||
return !(x->op.opcode & 1);
|
||||
}
|
||||
|
||||
static int IsRepOpcode(struct Dis *d) {
|
||||
switch (d->xedd->op.opcode & ~1) {
|
||||
case 0x6C: // INS
|
||||
return 1;
|
||||
case 0x6E: // OUTS
|
||||
return 1;
|
||||
case 0xA4: // MOVS
|
||||
return 1;
|
||||
case 0xAA: // STOS
|
||||
return 1;
|
||||
case 0xAC: // LODS
|
||||
return 1;
|
||||
case 0xA6: // CMPS
|
||||
return 2;
|
||||
case 0xAE: // SCAS
|
||||
return 2;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static char *DisRepPrefix(struct Dis *d, char *p) {
|
||||
const char *s;
|
||||
if (Rep(d->xedd->op.rde) && d->xedd->op.map == XED_ILD_MAP0) {
|
||||
switch (IsRepOpcode(d)) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
p = stpcpy(p, "rep ");
|
||||
break;
|
||||
case 2:
|
||||
p = stpcpy(p, Rep(d->xedd->op.rde) == 2 ? "repnz " : "repz ");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisBranchTaken(struct Dis *d, char *p) {
|
||||
switch (d->xedd->op.hint) {
|
||||
case XED_HINT_NTAKEN:
|
||||
return stpcpy(p, ",pn");
|
||||
case XED_HINT_TAKEN:
|
||||
return stpcpy(p, ",pt");
|
||||
default:
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
static char *DisName(struct Dis *d, char *bp, const char *name,
|
||||
bool ambiguous) {
|
||||
char *p, *np;
|
||||
uint32_t rde;
|
||||
bool notbyte, notlong, wantsuffix, wantsuffixsd;
|
||||
p = bp;
|
||||
rde = d->xedd->op.rde;
|
||||
if (d->xedd->op.lock) p = stpcpy(p, "lock ");
|
||||
p = DisRepPrefix(d, p);
|
||||
if (strcmp(name, "BIT") == 0) {
|
||||
p = stpcpy(p, kBitOp[ModrmReg(rde)]);
|
||||
} else if (strcmp(name, "nop") == 0 && d->xedd->op.rep) {
|
||||
p = stpcpy(p, "pause");
|
||||
} else if (strcmp(name, "CALL") == 0) {
|
||||
p = stpcpy(p, "call");
|
||||
} else if (strcmp(name, "JMP") == 0) {
|
||||
p = stpcpy(p, "jmp");
|
||||
} else if (strcmp(name, "jcxz") == 0) {
|
||||
p = stpcpy(p, kJcxz[Eamode(rde)]);
|
||||
p = DisBranchTaken(d, p);
|
||||
} else if (strcmp(name, "loop") == 0 || strcmp(name, "loope") == 0 ||
|
||||
strcmp(name, "loopne") == 0) {
|
||||
p = stpcpy(p, name);
|
||||
if (Eamode(rde) != Mode(rde)) {
|
||||
*p++ = "wl"[Eamode(rde)];
|
||||
*p = '\0';
|
||||
}
|
||||
p = DisBranchTaken(d, p);
|
||||
} else if (strcmp(name, "cwtl") == 0) {
|
||||
if (Osz(rde)) name = "cbtw";
|
||||
if (Rexw(rde)) name = "cltq";
|
||||
p = stpcpy(p, name);
|
||||
} else if (strcmp(name, "cltd") == 0) {
|
||||
if (Osz(rde)) name = "cwtd";
|
||||
if (Rexw(rde)) name = "cqto";
|
||||
p = stpcpy(p, name);
|
||||
} else {
|
||||
notbyte = false;
|
||||
notlong = false;
|
||||
wantsuffix = false;
|
||||
wantsuffixsd = false;
|
||||
for (np = name; *np && (islower(*np) || isdigit(*np)); ++np) {
|
||||
*p++ = *np;
|
||||
}
|
||||
if (strcmp(name, "ALU") == 0) {
|
||||
p = stpcpy(p, kAluOp[(d->xedd->op.opcode & 070) >> 3]);
|
||||
} else if (strcmp(name, "ALU2") == 0) {
|
||||
p = stpcpy(p, kAluOp[ModrmReg(rde)]);
|
||||
} else if (strcmp(np, "WLQ") == 0) {
|
||||
notbyte = true;
|
||||
wantsuffix = true;
|
||||
} else if (strcmp(np, "CC") == 0) {
|
||||
p = stpcpy(p, kCc[d->xedd->op.opcode & 15]);
|
||||
p = DisBranchTaken(d, p);
|
||||
} else if (strcmp(np, "WQ") == 0) {
|
||||
notbyte = true;
|
||||
notlong = Eamode(rde) != XED_MODE_REAL;
|
||||
wantsuffix = true;
|
||||
} else if (strcmp(np, "LQ") == 0 || strcmp(np, "WL") == 0) {
|
||||
notbyte = true;
|
||||
wantsuffix = true;
|
||||
} else if (strcmp(np, "SD") == 0) {
|
||||
notbyte = true;
|
||||
wantsuffixsd = true;
|
||||
} else if (strcmp(np, "ABS") == 0) {
|
||||
if (Rexw(rde)) p = stpcpy(p, "abs");
|
||||
}
|
||||
if (wantsuffixsd) {
|
||||
if (Osz(rde)) {
|
||||
*p++ = 'd';
|
||||
} else {
|
||||
*p++ = 's';
|
||||
}
|
||||
} else if (wantsuffix || (ambiguous && !_startswith(name, "f") &&
|
||||
!_startswith(name, "set"))) {
|
||||
if (Osz(rde)) {
|
||||
if (ambiguous || Mode(rde) != XED_MODE_REAL) {
|
||||
*p++ = 'w';
|
||||
}
|
||||
} else if (Rexw(rde)) {
|
||||
*p++ = 'q';
|
||||
} else if (ambiguous && !notbyte && IsProbablyByteOp(d->xedd)) {
|
||||
*p++ = 'b';
|
||||
} else if (!notlong) {
|
||||
*p++ = 'l';
|
||||
}
|
||||
}
|
||||
}
|
||||
*p++ = ' ';
|
||||
while (p - bp < 8) *p++ = ' ';
|
||||
*p = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disassembles instruction based on string spec.
|
||||
* @see DisSpec()
|
||||
*/
|
||||
char *DisInst(struct Dis *d, char *p, const char *spec) {
|
||||
long i, n;
|
||||
char sbuf[64];
|
||||
char args[4][256];
|
||||
char *s, *name, *state;
|
||||
bool hasarg, hasmodrm, hasregister, hasmemory;
|
||||
CHECK_EQ(0, (int)d->xedd->op.error);
|
||||
DCHECK_LT(strlen(spec), 128);
|
||||
hasarg = false;
|
||||
hasmodrm = d->xedd->op.has_modrm;
|
||||
hasmemory = hasmodrm && !IsModrmRegister(d->xedd->op.rde);
|
||||
hasregister = hasmodrm && IsModrmRegister(d->xedd->op.rde);
|
||||
name = strtok_r(strcpy(sbuf, spec), " ", &state);
|
||||
for (n = 0; (s = strtok_r(NULL, " ", &state)); ++n) {
|
||||
hasarg = true;
|
||||
hasregister |= *s == '%';
|
||||
hasmemory |= *s == 'O';
|
||||
CHECK_LT(DisArg(d, args[n], s) - args[n], sizeof(args[n]));
|
||||
}
|
||||
p = HighStart(p, g_high.keyword);
|
||||
p = DisName(d, p, name, hasarg && !hasregister && hasmemory);
|
||||
p = HighEnd(p);
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (i && args[n - i][0]) {
|
||||
*p++ = ',';
|
||||
}
|
||||
p = stpcpy(p, args[n - i - 1]);
|
||||
}
|
||||
return p;
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,369 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/limits.h"
|
||||
#include "tool/build/lib/divmul.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/flags.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
#include "tool/build/lib/throw.h"
|
||||
|
||||
struct Dubble {
|
||||
uint64_t lo;
|
||||
uint64_t hi;
|
||||
};
|
||||
|
||||
static inline struct Dubble DubbleNeg(struct Dubble x) {
|
||||
struct Dubble d;
|
||||
d.lo = -x.lo;
|
||||
d.hi = ~(x.hi - (x.lo - 1 > x.lo));
|
||||
return d;
|
||||
}
|
||||
|
||||
static inline struct Dubble DubbleShl(struct Dubble x) {
|
||||
struct Dubble d;
|
||||
d.lo = x.lo << 1;
|
||||
d.hi = x.hi << 1 | x.lo >> 63;
|
||||
return d;
|
||||
}
|
||||
|
||||
static inline struct Dubble DubbleShr(struct Dubble x) {
|
||||
struct Dubble d;
|
||||
d.lo = x.lo >> 1 | x.hi << 63;
|
||||
d.hi = x.hi >> 1;
|
||||
return d;
|
||||
}
|
||||
|
||||
static inline unsigned DubbleLte(struct Dubble a, struct Dubble b) {
|
||||
return a.hi == b.hi ? a.lo <= b.lo : a.hi <= b.hi;
|
||||
}
|
||||
|
||||
static struct Dubble DubbleMul(uint64_t a, uint64_t b) {
|
||||
struct Dubble d;
|
||||
uint64_t x, y, t;
|
||||
x = (a & 0xffffffff) * (b & 0xffffffff);
|
||||
t = x >> 32;
|
||||
x &= 0xffffffff;
|
||||
t += (a >> 32) * (b & 0xffffffff);
|
||||
x += (t & 0xffffffff) << 32;
|
||||
y = t >> 32;
|
||||
t = x >> 32;
|
||||
x &= 0xffffffff;
|
||||
t += (b >> 32) * (a & 0xffffffff);
|
||||
x += (t & 0xffffffff) << 32;
|
||||
y += t >> 32;
|
||||
y += (a >> 32) * (b >> 32);
|
||||
d.lo = x;
|
||||
d.hi = y;
|
||||
return d;
|
||||
}
|
||||
|
||||
static struct Dubble DubbleImul(uint64_t a, uint64_t b) {
|
||||
unsigned s, t;
|
||||
struct Dubble p;
|
||||
if ((s = a >> 63)) a = -a;
|
||||
if ((t = b >> 63)) b = -b;
|
||||
p = DubbleMul(a, b);
|
||||
return s ^ t ? DubbleNeg(p) : p;
|
||||
}
|
||||
|
||||
static struct Dubble DubbleDiv(struct Dubble a, uint64_t b, uint64_t *r) {
|
||||
int n, c;
|
||||
uint64_t s;
|
||||
struct Dubble d, q, t;
|
||||
d.lo = b, d.hi = 0;
|
||||
q.lo = 0, q.hi = 0;
|
||||
for (n = 0; DubbleLte(d, a) && n < 128; ++n) {
|
||||
d = DubbleShl(d);
|
||||
}
|
||||
for (; n > 0; --n) {
|
||||
t = a;
|
||||
d = DubbleShr(d);
|
||||
q = DubbleShl(q);
|
||||
s = a.lo, a.lo -= d.lo + 0, c = a.lo > s;
|
||||
s = a.hi, a.hi -= d.hi + c, c = a.hi > s;
|
||||
if (c) {
|
||||
a = t;
|
||||
} else {
|
||||
q.lo++;
|
||||
}
|
||||
}
|
||||
*r = a.lo;
|
||||
return q;
|
||||
}
|
||||
|
||||
static struct Dubble DubbleIdiv(struct Dubble a, uint64_t b, uint64_t *r) {
|
||||
unsigned s, t;
|
||||
struct Dubble q;
|
||||
if ((s = a.hi >> 63)) a = DubbleNeg(a);
|
||||
if ((t = b >> 63)) b = -b;
|
||||
q = DubbleDiv(a, b, r);
|
||||
if (s ^ t) q = DubbleNeg(q);
|
||||
if (s) *r = -*r;
|
||||
return q;
|
||||
}
|
||||
|
||||
void OpDivAlAhAxEbSigned(struct Machine *m, uint32_t rde) {
|
||||
int8_t y, r;
|
||||
int16_t x, q;
|
||||
x = Read16(m->ax);
|
||||
y = Read8(GetModrmRegisterBytePointerRead(m, rde));
|
||||
if (!y) ThrowDivideError(m);
|
||||
if (x == INT16_MIN) ThrowDivideError(m);
|
||||
q = x / y;
|
||||
r = x % y;
|
||||
if (q != (int8_t)q) ThrowDivideError(m);
|
||||
m->ax[0] = q & 0xff;
|
||||
m->ax[1] = r & 0xff;
|
||||
}
|
||||
|
||||
void OpDivAlAhAxEbUnsigned(struct Machine *m, uint32_t rde) {
|
||||
uint8_t y, r;
|
||||
uint16_t x, q;
|
||||
x = Read16(m->ax);
|
||||
y = Read8(GetModrmRegisterBytePointerRead(m, rde));
|
||||
if (!y) ThrowDivideError(m);
|
||||
q = x / y;
|
||||
r = x % y;
|
||||
if (q > 255) ThrowDivideError(m);
|
||||
m->ax[0] = q & 0xff;
|
||||
m->ax[1] = r & 0xff;
|
||||
}
|
||||
|
||||
static void OpDivRdxRaxEvqpSigned64(struct Machine *m, uint32_t rde,
|
||||
uint8_t *p) {
|
||||
uint64_t d, r;
|
||||
struct Dubble q;
|
||||
q.lo = Read64(m->ax);
|
||||
q.hi = Read64(m->dx);
|
||||
d = Read64(p);
|
||||
if (!d) ThrowDivideError(m);
|
||||
if (!q.lo && q.hi == 0x8000000000000000) ThrowDivideError(m);
|
||||
q = DubbleIdiv(q, d, &r);
|
||||
if ((int64_t)q.lo < 0 && (int64_t)q.hi != -1) ThrowDivideError(m);
|
||||
if ((int64_t)q.lo >= 0 && q.hi) ThrowDivideError(m);
|
||||
Write64(m->ax, q.lo);
|
||||
Write64(m->dx, r);
|
||||
}
|
||||
|
||||
static void OpDivRdxRaxEvqpSigned32(struct Machine *m, uint32_t rde,
|
||||
uint8_t *p) {
|
||||
int32_t y, r;
|
||||
int64_t x, q;
|
||||
x = (uint64_t)Read32(m->dx) << 32 | Read32(m->ax);
|
||||
y = Read32(p);
|
||||
if (!y) ThrowDivideError(m);
|
||||
if (x == INT64_MIN) ThrowDivideError(m);
|
||||
q = x / y;
|
||||
r = x % y;
|
||||
if (q != (int32_t)q) ThrowDivideError(m);
|
||||
Write64(m->ax, q & 0xffffffff);
|
||||
Write64(m->dx, r & 0xffffffff);
|
||||
}
|
||||
|
||||
static void OpDivRdxRaxEvqpSigned16(struct Machine *m, uint32_t rde,
|
||||
uint8_t *p) {
|
||||
int16_t y, r;
|
||||
int32_t x, q;
|
||||
x = (uint32_t)Read16(m->dx) << 16 | Read16(m->ax);
|
||||
y = Read16(p);
|
||||
if (!y) ThrowDivideError(m);
|
||||
if (x == INT32_MIN) ThrowDivideError(m);
|
||||
q = x / y;
|
||||
r = x % y;
|
||||
if (q != (int16_t)q) ThrowDivideError(m);
|
||||
Write16(m->ax, q);
|
||||
Write16(m->dx, r);
|
||||
}
|
||||
|
||||
static void OpDivRdxRaxEvqpUnsigned16(struct Machine *m, uint32_t rde,
|
||||
uint8_t *p) {
|
||||
uint16_t y, r;
|
||||
uint32_t x, q;
|
||||
x = (uint32_t)Read16(m->dx) << 16 | Read16(m->ax);
|
||||
y = Read16(p);
|
||||
if (!y) ThrowDivideError(m);
|
||||
q = x / y;
|
||||
r = x % y;
|
||||
if (q > 65535) ThrowDivideError(m);
|
||||
Write16(m->ax, q);
|
||||
Write16(m->dx, r);
|
||||
}
|
||||
|
||||
static void OpDivRdxRaxEvqpUnsigned32(struct Machine *m, uint32_t rde,
|
||||
uint8_t *p) {
|
||||
uint32_t y, r;
|
||||
uint64_t x, q;
|
||||
x = (uint64_t)Read32(m->dx) << 32 | Read32(m->ax);
|
||||
y = Read32(p);
|
||||
if (!y) ThrowDivideError(m);
|
||||
q = x / y;
|
||||
r = x % y;
|
||||
if (q > 4294967295) ThrowDivideError(m);
|
||||
Write64(m->ax, q & 0xffffffff);
|
||||
Write64(m->dx, r & 0xffffffff);
|
||||
}
|
||||
|
||||
static void OpDivRdxRaxEvqpUnsigned64(struct Machine *m, uint32_t rde,
|
||||
uint8_t *p) {
|
||||
uint64_t d, r;
|
||||
struct Dubble q;
|
||||
q.lo = Read64(m->ax);
|
||||
q.hi = Read64(m->dx);
|
||||
d = Read64(p);
|
||||
if (!d) ThrowDivideError(m);
|
||||
q = DubbleDiv(q, d, &r);
|
||||
if (q.hi) ThrowDivideError(m);
|
||||
Write64(m->ax, q.lo);
|
||||
Write64(m->dx, r);
|
||||
}
|
||||
|
||||
void OpDivRdxRaxEvqpSigned(struct Machine *m, uint32_t rde) {
|
||||
uint8_t *p;
|
||||
p = GetModrmRegisterWordPointerReadOszRexw(m, rde);
|
||||
if (Rexw(rde)) {
|
||||
OpDivRdxRaxEvqpSigned64(m, rde, p);
|
||||
} else if (!Osz(rde)) {
|
||||
OpDivRdxRaxEvqpSigned32(m, rde, p);
|
||||
} else {
|
||||
OpDivRdxRaxEvqpSigned16(m, rde, p);
|
||||
}
|
||||
}
|
||||
|
||||
void OpDivRdxRaxEvqpUnsigned(struct Machine *m, uint32_t rde) {
|
||||
uint8_t *p;
|
||||
p = GetModrmRegisterWordPointerReadOszRexw(m, rde);
|
||||
if (Rexw(rde)) {
|
||||
OpDivRdxRaxEvqpUnsigned64(m, rde, p);
|
||||
} else if (!Osz(rde)) {
|
||||
OpDivRdxRaxEvqpUnsigned32(m, rde, p);
|
||||
} else {
|
||||
OpDivRdxRaxEvqpUnsigned16(m, rde, p);
|
||||
}
|
||||
}
|
||||
|
||||
void OpMulAxAlEbSigned(struct Machine *m, uint32_t rde) {
|
||||
int16_t ax;
|
||||
uint8_t *p;
|
||||
unsigned of;
|
||||
p = GetModrmRegisterBytePointerRead(m, rde);
|
||||
ax = (int8_t)Read8(m->ax) * (int8_t)Read8(p);
|
||||
of = ax != (int8_t)ax;
|
||||
m->flags = SetFlag(m->flags, FLAGS_CF, of);
|
||||
m->flags = SetFlag(m->flags, FLAGS_OF, of);
|
||||
Write16(m->ax, ax);
|
||||
}
|
||||
|
||||
void OpMulAxAlEbUnsigned(struct Machine *m, uint32_t rde) {
|
||||
int ax;
|
||||
uint8_t *p;
|
||||
unsigned of;
|
||||
p = GetModrmRegisterBytePointerRead(m, rde);
|
||||
ax = Read8(m->ax) * Read8(p);
|
||||
of = ax != (uint8_t)ax;
|
||||
m->flags = SetFlag(m->flags, FLAGS_CF, of);
|
||||
m->flags = SetFlag(m->flags, FLAGS_OF, of);
|
||||
Write16(m->ax, ax);
|
||||
}
|
||||
|
||||
void OpMulRdxRaxEvqpSigned(struct Machine *m, uint32_t rde) {
|
||||
uint8_t *p;
|
||||
unsigned of;
|
||||
int32_t dxax;
|
||||
int64_t edxeax;
|
||||
struct Dubble rdxrax;
|
||||
p = GetModrmRegisterWordPointerReadOszRexw(m, rde);
|
||||
if (Rexw(rde)) {
|
||||
rdxrax = DubbleImul(Read64(m->ax), Read64(p));
|
||||
of = !!(rdxrax.hi + (rdxrax.lo >> 63));
|
||||
Write64(m->ax, rdxrax.lo);
|
||||
Write64(m->dx, rdxrax.hi);
|
||||
} else if (!Osz(rde)) {
|
||||
edxeax = (int64_t)(int32_t)Read32(m->ax) * (int32_t)Read32(p);
|
||||
of = edxeax != (int32_t)edxeax;
|
||||
Write64(m->ax, edxeax);
|
||||
Write64(m->dx, edxeax >> 32);
|
||||
} else {
|
||||
dxax = (int32_t)(int16_t)Read16(m->ax) * (int16_t)Read16(p);
|
||||
of = dxax != (int16_t)dxax;
|
||||
Write16(m->ax, dxax);
|
||||
Write16(m->dx, dxax >> 16);
|
||||
}
|
||||
m->flags = SetFlag(m->flags, FLAGS_CF, of);
|
||||
m->flags = SetFlag(m->flags, FLAGS_OF, of);
|
||||
}
|
||||
|
||||
void OpMulRdxRaxEvqpUnsigned(struct Machine *m, uint32_t rde) {
|
||||
uint8_t *p;
|
||||
unsigned of;
|
||||
uint32_t dxax;
|
||||
uint64_t edxeax;
|
||||
struct Dubble rdxrax;
|
||||
p = GetModrmRegisterWordPointerReadOszRexw(m, rde);
|
||||
if (Rexw(rde)) {
|
||||
rdxrax = DubbleMul(Read64(m->ax), Read64(p));
|
||||
of = !!rdxrax.hi;
|
||||
Write64(m->ax, rdxrax.lo);
|
||||
Write64(m->dx, rdxrax.hi);
|
||||
} else if (!Osz(rde)) {
|
||||
edxeax = (uint64_t)Read32(m->ax) * Read32(p);
|
||||
of = (uint32_t)edxeax != edxeax;
|
||||
Write64(m->ax, edxeax);
|
||||
Write64(m->dx, edxeax >> 32);
|
||||
} else {
|
||||
dxax = (uint32_t)(uint16_t)Read16(m->ax) * (uint16_t)Read16(p);
|
||||
of = (uint16_t)dxax != dxax;
|
||||
Write16(m->ax, dxax);
|
||||
Write16(m->dx, dxax >> 16);
|
||||
}
|
||||
m->flags = SetFlag(m->flags, FLAGS_CF, of);
|
||||
m->flags = SetFlag(m->flags, FLAGS_OF, of);
|
||||
}
|
||||
|
||||
static void AluImul(struct Machine *m, uint32_t rde, uint8_t *a, uint8_t *b) {
|
||||
unsigned of;
|
||||
if (Rexw(rde)) {
|
||||
struct Dubble p;
|
||||
p = DubbleImul(Read64(a), Read64(b));
|
||||
of = !!(p.hi + (p.lo >> 63));
|
||||
Write64(RegRexrReg(m, rde), p.lo);
|
||||
} else if (!Osz(rde)) {
|
||||
int64_t z;
|
||||
z = (int64_t)(int32_t)Read32(a) * (int32_t)Read32(b);
|
||||
of = z != (int32_t)z;
|
||||
Write64(RegRexrReg(m, rde), z & 0xffffffff);
|
||||
} else {
|
||||
int32_t z;
|
||||
z = (int32_t)(int16_t)Read16(a) * (int16_t)Read16(b);
|
||||
of = z != (int16_t)z;
|
||||
Write16(RegRexrReg(m, rde), z);
|
||||
}
|
||||
m->flags = SetFlag(m->flags, FLAGS_CF, of);
|
||||
m->flags = SetFlag(m->flags, FLAGS_OF, of);
|
||||
}
|
||||
|
||||
void OpImulGvqpEvqp(struct Machine *m, uint32_t rde) {
|
||||
AluImul(m, rde, RegRexrReg(m, rde),
|
||||
GetModrmRegisterWordPointerReadOszRexw(m, rde));
|
||||
}
|
||||
|
||||
void OpImulGvqpEvqpImm(struct Machine *m, uint32_t rde) {
|
||||
uint8_t b[8];
|
||||
Write64(b, m->xedd->op.uimm0);
|
||||
AluImul(m, rde, GetModrmRegisterWordPointerReadOszRexw(m, rde), b);
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_DIVMUL_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_DIVMUL_H_
|
||||
#include "tool/build/lib/machine.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void OpDivAlAhAxEbSigned(struct Machine *, uint32_t);
|
||||
void OpDivAlAhAxEbUnsigned(struct Machine *, uint32_t);
|
||||
void OpDivRdxRaxEvqpSigned(struct Machine *, uint32_t);
|
||||
void OpDivRdxRaxEvqpUnsigned(struct Machine *, uint32_t);
|
||||
void OpImulGvqpEvqp(struct Machine *, uint32_t);
|
||||
void OpImulGvqpEvqpImm(struct Machine *, uint32_t);
|
||||
void OpMulAxAlEbSigned(struct Machine *, uint32_t);
|
||||
void OpMulAxAlEbUnsigned(struct Machine *, uint32_t);
|
||||
void OpMulRdxRaxEvqpSigned(struct Machine *, uint32_t);
|
||||
void OpMulRdxRaxEvqpUnsigned(struct Machine *, uint32_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_DIVMUL_H_ */
|
|
@ -1,48 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/mem/mem.h"
|
||||
#include "tool/build/lib/fds.h"
|
||||
|
||||
int MachineFdAdd(struct MachineFds *mf) {
|
||||
int fd;
|
||||
struct MachineFdClosed *closed;
|
||||
if ((closed = mf->closed)) {
|
||||
fd = closed->fd;
|
||||
mf->closed = closed->next;
|
||||
free(closed);
|
||||
} else {
|
||||
fd = mf->i;
|
||||
if (mf->i++ == mf->n) {
|
||||
mf->n = mf->i + (mf->i >> 1);
|
||||
mf->p = realloc(mf->p, mf->n * sizeof(*mf->p));
|
||||
}
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
void MachineFdRemove(struct MachineFds *mf, int fd) {
|
||||
struct MachineFdClosed *closed;
|
||||
mf->p[fd].cb = NULL;
|
||||
if ((closed = malloc(sizeof(struct MachineFdClosed)))) {
|
||||
closed->fd = fd;
|
||||
closed->next = mf->closed;
|
||||
mf->closed = closed;
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_FDS_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_FDS_H_
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/sock/struct/pollfd.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct MachineFdClosed {
|
||||
unsigned fd;
|
||||
struct MachineFdClosed *next;
|
||||
};
|
||||
|
||||
struct MachineFdCb {
|
||||
int (*close)(int);
|
||||
ssize_t (*readv)(int, const struct iovec *, int);
|
||||
ssize_t (*writev)(int, const struct iovec *, int);
|
||||
int (*ioctl)(int, int, ...);
|
||||
int (*poll)(struct pollfd *, uint64_t, int32_t);
|
||||
};
|
||||
|
||||
struct MachineFd {
|
||||
int fd;
|
||||
struct MachineFdCb *cb;
|
||||
};
|
||||
|
||||
struct MachineFds {
|
||||
size_t i, n;
|
||||
struct MachineFd *p;
|
||||
struct MachineFdClosed *closed;
|
||||
};
|
||||
|
||||
int MachineFdAdd(struct MachineFds *);
|
||||
void MachineFdRemove(struct MachineFds *, int);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_FDS_H_ */
|
|
@ -1,63 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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 "tool/build/lib/flags.h"
|
||||
|
||||
bool GetParity(uint8_t b) {
|
||||
b ^= b >> 4;
|
||||
b ^= b >> 2;
|
||||
b ^= b >> 1;
|
||||
return ~b & 1;
|
||||
}
|
||||
|
||||
void ImportFlags(struct Machine *m, uint64_t flags) {
|
||||
uint64_t old, mask = 0;
|
||||
mask |= 1u << FLAGS_CF;
|
||||
mask |= 1u << FLAGS_PF;
|
||||
mask |= 1u << FLAGS_AF;
|
||||
mask |= 1u << FLAGS_ZF;
|
||||
mask |= 1u << FLAGS_SF;
|
||||
mask |= 1u << FLAGS_TF;
|
||||
mask |= 1u << FLAGS_IF;
|
||||
mask |= 1u << FLAGS_DF;
|
||||
mask |= 1u << FLAGS_OF;
|
||||
mask |= 1u << FLAGS_NT;
|
||||
mask |= 1u << FLAGS_AC;
|
||||
mask |= 1u << FLAGS_ID;
|
||||
m->flags = (flags & mask) | (m->flags & ~mask);
|
||||
m->flags = SetFlag(m->flags, FLAGS_RF, false);
|
||||
m->flags = SetLazyParityByte(m->flags, !((m->flags >> FLAGS_PF) & 1));
|
||||
}
|
||||
|
||||
uint64_t ExportFlags(uint64_t flags) {
|
||||
flags = SetFlag(flags, FLAGS_IOPL, 3);
|
||||
flags = SetFlag(flags, FLAGS_F1, true);
|
||||
flags = SetFlag(flags, FLAGS_F0, false);
|
||||
flags = flags & ~(1ull << FLAGS_PF);
|
||||
flags |= GetLazyParityBool(flags) << FLAGS_PF;
|
||||
return flags;
|
||||
}
|
||||
|
||||
int64_t AluFlags(uint64_t x, uint32_t af, uint32_t *f, uint32_t of, uint32_t cf,
|
||||
uint32_t sf) {
|
||||
*f &= ~(1u << FLAGS_CF | 1u << FLAGS_ZF | 1u << FLAGS_SF | 1u << FLAGS_OF |
|
||||
1u << FLAGS_AF | 0xFF000000u);
|
||||
*f |= sf << FLAGS_SF | cf << FLAGS_CF | !x << FLAGS_ZF | of << FLAGS_OF |
|
||||
af << FLAGS_AF | (x & 0xFF) << 24;
|
||||
return x;
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_FLAGS_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_FLAGS_H_
|
||||
#include "tool/build/lib/machine.h"
|
||||
|
||||
#define FLAGS_CF 0
|
||||
#define FLAGS_VF 1
|
||||
#define FLAGS_PF 2
|
||||
#define FLAGS_F1 3
|
||||
#define FLAGS_AF 4
|
||||
#define FLAGS_KF 5
|
||||
#define FLAGS_ZF 6
|
||||
#define FLAGS_SF 7
|
||||
#define FLAGS_TF 8
|
||||
#define FLAGS_IF 9
|
||||
#define FLAGS_DF 10
|
||||
#define FLAGS_OF 11
|
||||
#define FLAGS_IOPL 12
|
||||
#define FLAGS_NT 14
|
||||
#define FLAGS_F0 15
|
||||
#define FLAGS_RF 16
|
||||
#define FLAGS_VM 17
|
||||
#define FLAGS_AC 18
|
||||
#define FLAGS_VIF 19
|
||||
#define FLAGS_VIP 20
|
||||
#define FLAGS_ID 21
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define GetLazyParityBool(f) GetParity((f) >> 24)
|
||||
#define SetLazyParityByte(f, x) (((f) & ~0xFF000000u) | ((x)&0xFFu) << 24)
|
||||
|
||||
#define GetFlag(FLAGS, BIT) \
|
||||
({ \
|
||||
autotype(FLAGS) Flags = (FLAGS); \
|
||||
typeof(Flags) IsSet; \
|
||||
switch (BIT) { \
|
||||
case FLAGS_PF: \
|
||||
IsSet = GetLazyParityBool(Flags); \
|
||||
break; \
|
||||
default: \
|
||||
IsSet = (Flags >> (BIT)) & 1; \
|
||||
break; \
|
||||
} \
|
||||
IsSet; \
|
||||
})
|
||||
|
||||
#define SetFlag(FLAGS, BIT, VAL) \
|
||||
({ \
|
||||
autotype(FLAGS) Flags = (FLAGS); \
|
||||
typeof(Flags) Val = (VAL); \
|
||||
typeof(Flags) One = 1; \
|
||||
switch (BIT) { \
|
||||
case FLAGS_PF: \
|
||||
Flags = SetLazyParityByte(Flags, !Val); \
|
||||
break; \
|
||||
default: \
|
||||
Flags = (Flags & ~(One << (BIT))) | Val << (BIT); \
|
||||
break; \
|
||||
} \
|
||||
Flags; \
|
||||
})
|
||||
|
||||
bool GetParity(uint8_t);
|
||||
uint64_t ExportFlags(uint64_t);
|
||||
void ImportFlags(struct Machine *, uint64_t);
|
||||
int64_t AluFlags(uint64_t, uint32_t, uint32_t *, uint32_t, uint32_t, uint32_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_FLAGS_H_ */
|
1190
tool/build/lib/fpu.c
1190
tool/build/lib/fpu.c
File diff suppressed because it is too large
Load diff
|
@ -1,65 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_FPU_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_FPU_H_
|
||||
#include "tool/build/lib/machine.h"
|
||||
|
||||
#define kFpuTagValid 0b00
|
||||
#define kFpuTagZero 0b01
|
||||
#define kFpuTagSpecial 0b10
|
||||
#define kFpuTagEmpty 0b11
|
||||
|
||||
#define kFpuCwIm 0x0001 /* invalid operation mask */
|
||||
#define kFpuCwDm 0x0002 /* denormal operand mask */
|
||||
#define kFpuCwZm 0x0004 /* zero divide mask */
|
||||
#define kFpuCwOm 0x0008 /* overflow mask */
|
||||
#define kFpuCwUm 0x0010 /* underflow mask */
|
||||
#define kFpuCwPm 0x0020 /* precision mask */
|
||||
#define kFpuCwPc 0x0300 /* precision: 32,∅,64,80 */
|
||||
#define kFpuCwRc 0x0c00 /* rounding: even,→-∞,→+∞,→0 */
|
||||
|
||||
#define kFpuSwIe 0x0001 /* invalid operation */
|
||||
#define kFpuSwDe 0x0002 /* denormalized operand */
|
||||
#define kFpuSwZe 0x0004 /* zero divide */
|
||||
#define kFpuSwOe 0x0008 /* overflow */
|
||||
#define kFpuSwUe 0x0010 /* underflow */
|
||||
#define kFpuSwPe 0x0020 /* precision */
|
||||
#define kFpuSwSf 0x0040 /* stack fault */
|
||||
#define kFpuSwEs 0x0080 /* exception summary status */
|
||||
#define kFpuSwC0 0x0100 /* condition 0 */
|
||||
#define kFpuSwC1 0x0200 /* condition 1 */
|
||||
#define kFpuSwC2 0x0400 /* condition 2 */
|
||||
#define kFpuSwSp 0x3800 /* top stack */
|
||||
#define kFpuSwC3 0x4000 /* condition 3 */
|
||||
#define kFpuSwBf 0x8000 /* busy flag */
|
||||
|
||||
#define kMxcsrIe 0x0001 /* invalid operation flag */
|
||||
#define kMxcsrDe 0x0002 /* denormal flag */
|
||||
#define kMxcsrZe 0x0004 /* divide by zero flag */
|
||||
#define kMxcsrOe 0x0008 /* overflow flag */
|
||||
#define kMxcsrUe 0x0010 /* underflow flag */
|
||||
#define kMxcsrPe 0x0020 /* precision flag */
|
||||
#define kMxcsrDaz 0x0040 /* denormals are zeros */
|
||||
#define kMxcsrIm 0x0080 /* invalid operation mask */
|
||||
#define kMxcsrDm 0x0100 /* denormal mask */
|
||||
#define kMxcsrZm 0x0200 /* divide by zero mask */
|
||||
#define kMxcsrOm 0x0400 /* overflow mask */
|
||||
#define kMxcsrUm 0x0800 /* underflow mask */
|
||||
#define kMxcsrPm 0x1000 /* precision mask */
|
||||
#define kMxcsrRc 0x6000 /* rounding control */
|
||||
#define kMxcsrFtz 0x8000 /* flush to zero */
|
||||
|
||||
#define FpuSt(m, i) ((m)->fpu.st + (((i) + ((m->fpu.sw & kFpuSwSp) >> 11)) & 7))
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
double FpuPop(struct Machine *);
|
||||
int FpuGetTag(struct Machine *, unsigned);
|
||||
void FpuPush(struct Machine *, double);
|
||||
void FpuSetTag(struct Machine *, unsigned, unsigned);
|
||||
void OpFinit(struct Machine *);
|
||||
void OpFpu(struct Machine *, uint32_t);
|
||||
void OpFwait(struct Machine *, uint32_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_FPU_H_ */
|
|
@ -1,41 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/fmt/itoa.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/build/lib/high.h"
|
||||
|
||||
struct High g_high;
|
||||
|
||||
char *HighStart(char *p, int h) {
|
||||
if (h) {
|
||||
p = stpcpy(p, "\e[38;5;");
|
||||
p = FormatUint32(p, h);
|
||||
p = stpcpy(p, "m");
|
||||
g_high.active = true;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
char *HighEnd(char *p) {
|
||||
if (g_high.active) {
|
||||
p = stpcpy(p, "\e[39m");
|
||||
g_high.active = false;
|
||||
}
|
||||
return p;
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_HIGH_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_HIGH_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct High {
|
||||
bool active;
|
||||
uint8_t keyword;
|
||||
uint8_t reg;
|
||||
uint8_t literal;
|
||||
uint8_t label;
|
||||
uint8_t comment;
|
||||
uint8_t quote;
|
||||
};
|
||||
|
||||
extern struct High g_high;
|
||||
|
||||
char *HighStart(char *, int);
|
||||
char *HighEnd(char *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_HIGH_H_ */
|
|
@ -1,92 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/intrin/bsf.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/xed/x86.h"
|
||||
#include "tool/build/lib/address.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#include "tool/build/lib/memory.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
#include "tool/build/lib/stats.h"
|
||||
#include "tool/build/lib/throw.h"
|
||||
|
||||
static bool IsOpcodeEqual(struct XedDecodedInst *xedd, uint8_t *a) {
|
||||
uint64_t w;
|
||||
if (xedd->length) {
|
||||
if (xedd->length <= 7) {
|
||||
w = Read64(a) ^ Read64(xedd->bytes);
|
||||
return !w || _bsfl(w) >= (xedd->length << 3);
|
||||
} else {
|
||||
return memcmp(a, xedd->bytes, xedd->length) == 0;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void DecodeInstruction(struct Machine *m, uint8_t *p, unsigned n) {
|
||||
struct XedDecodedInst xedd[1];
|
||||
xed_decoded_inst_zero_set_mode(xedd, m->mode);
|
||||
if (!xed_instruction_length_decode(xedd, p, n)) {
|
||||
xedd->op.rde = EncodeRde(xedd);
|
||||
memcpy(m->xedd, xedd, sizeof(m->icache[0]));
|
||||
} else {
|
||||
HaltMachine(m, kMachineDecodeError);
|
||||
}
|
||||
}
|
||||
|
||||
static dontinline void LoadInstructionSlow(struct Machine *m, uint64_t ip) {
|
||||
unsigned i;
|
||||
uint8_t *addr;
|
||||
uint8_t copy[15], *toil;
|
||||
i = 0x1000 - (ip & 0xfff);
|
||||
addr = ResolveAddress(m, ip);
|
||||
if ((toil = FindReal(m, ip + i))) {
|
||||
memcpy(copy, addr, i);
|
||||
memcpy(copy + i, toil, 15 - i);
|
||||
DecodeInstruction(m, copy, 15);
|
||||
} else {
|
||||
DecodeInstruction(m, addr, i);
|
||||
}
|
||||
}
|
||||
|
||||
void LoadInstruction(struct Machine *m) {
|
||||
uint64_t ip;
|
||||
unsigned key;
|
||||
uint8_t *addr;
|
||||
ip = Read64(m->cs) + MaskAddress(m->mode & 3, m->ip);
|
||||
key = ip & (ARRAYLEN(m->icache) - 1);
|
||||
m->xedd = (struct XedDecodedInst *)m->icache[key];
|
||||
if ((ip & 0xfff) < 0x1000 - 15) {
|
||||
if (ip - (ip & 0xfff) == m->codevirt && m->codehost) {
|
||||
addr = m->codehost + (ip & 0xfff);
|
||||
} else {
|
||||
m->codevirt = ip - (ip & 0xfff);
|
||||
m->codehost = ResolveAddress(m, m->codevirt);
|
||||
addr = m->codehost + (ip & 0xfff);
|
||||
}
|
||||
if (!IsOpcodeEqual(m->xedd, addr)) {
|
||||
DecodeInstruction(m, addr, 15);
|
||||
}
|
||||
} else {
|
||||
LoadInstructionSlow(m, ip);
|
||||
}
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/nexgen32e/uart.internal.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/poll.h"
|
||||
#include "tool/build/lib/ioports.h"
|
||||
|
||||
static int OpE9Read(struct Machine *m) {
|
||||
int fd;
|
||||
uint8_t b;
|
||||
fd = STDIN_FILENO;
|
||||
if (fd >= m->fds.i) return -1;
|
||||
if (!m->fds.p[fd].cb) return -1;
|
||||
if (m->fds.p[fd].cb->readv(m->fds.p[fd].fd, &(struct iovec){&b, 1}, 1) == 1) {
|
||||
return b;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void OpE9Write(struct Machine *m, uint8_t b) {
|
||||
int fd;
|
||||
fd = STDOUT_FILENO;
|
||||
if (fd >= m->fds.i) return;
|
||||
if (!m->fds.p[fd].cb) return;
|
||||
m->fds.p[fd].cb->writev(m->fds.p[fd].fd, &(struct iovec){&b, 1}, 1);
|
||||
}
|
||||
|
||||
static int OpE9Poll(struct Machine *m) {
|
||||
int fd, rc;
|
||||
struct pollfd pf;
|
||||
fd = STDIN_FILENO;
|
||||
if (fd >= m->fds.i) return -1;
|
||||
if (!m->fds.p[fd].cb) return -1;
|
||||
pf.fd = m->fds.p[fd].fd;
|
||||
pf.events = POLLIN | POLLOUT;
|
||||
rc = m->fds.p[fd].cb->poll(&pf, 1, 20);
|
||||
if (rc <= 0) return rc;
|
||||
return pf.revents;
|
||||
}
|
||||
|
||||
static int OpSerialIn(struct Machine *m, int r) {
|
||||
int p, s;
|
||||
switch (r) {
|
||||
case UART_DLL:
|
||||
if (!m->dlab) {
|
||||
return OpE9Read(m);
|
||||
} else {
|
||||
return 0x01;
|
||||
}
|
||||
case UART_LSR:
|
||||
if ((p = OpE9Poll(m)) == -1) return -1;
|
||||
s = UART_TTYIDL;
|
||||
if (p & POLLIN) s |= UART_TTYDA;
|
||||
if (p & POLLOUT) s |= UART_TTYTXR;
|
||||
return s;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void OpSerialOut(struct Machine *m, int r, uint32_t x) {
|
||||
switch (r) {
|
||||
case UART_DLL:
|
||||
if (!m->dlab) {
|
||||
return OpE9Write(m, x);
|
||||
}
|
||||
break;
|
||||
case UART_LCR:
|
||||
m->dlab = !!(x & UART_DLAB);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t OpIn(struct Machine *m, uint16_t p) {
|
||||
switch (p) {
|
||||
case 0xE9:
|
||||
return OpE9Read(m);
|
||||
case 0x3F8 ... 0x3FF:
|
||||
return OpSerialIn(m, p - 0x3F8);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void OpOut(struct Machine *m, uint16_t p, uint32_t x) {
|
||||
switch (p) {
|
||||
case 0xE9:
|
||||
OpE9Write(m, x);
|
||||
break;
|
||||
case 0x3F8 ... 0x3FF:
|
||||
OpSerialOut(m, p - 0x3F8, x);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_IOPORTS_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_IOPORTS_H_
|
||||
#include "tool/build/lib/machine.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
uint64_t OpIn(struct Machine *, uint16_t);
|
||||
void OpOut(struct Machine *, uint16_t, uint32_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_IOPORTS_H_ */
|
|
@ -1,66 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/build/lib/iovs.h"
|
||||
|
||||
void InitIovs(struct Iovs *ib) {
|
||||
ib->p = ib->init;
|
||||
ib->i = 0;
|
||||
ib->n = ARRAYLEN(ib->init);
|
||||
}
|
||||
|
||||
void FreeIovs(struct Iovs *ib) {
|
||||
if (ib->p != ib->init) {
|
||||
free(ib->p);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends memory region to i/o vector builder.
|
||||
*/
|
||||
int AppendIovs(struct Iovs *ib, void *base, size_t len) {
|
||||
unsigned i, n;
|
||||
struct iovec *p;
|
||||
if (len) {
|
||||
p = ib->p;
|
||||
i = ib->i;
|
||||
n = ib->n;
|
||||
if (i && (intptr_t)base == (intptr_t)p[i - 1].iov_base + p[i - 1].iov_len) {
|
||||
p[i - 1].iov_len += len;
|
||||
} else {
|
||||
if (__builtin_expect(i == n, 0)) {
|
||||
n += n >> 1;
|
||||
if (p == ib->init) {
|
||||
if (!(p = malloc(sizeof(struct iovec) * n))) return -1;
|
||||
memcpy(p, ib->init, sizeof(ib->init));
|
||||
} else {
|
||||
if (!(p = realloc(p, sizeof(struct iovec) * n))) return -1;
|
||||
}
|
||||
ib->p = p;
|
||||
ib->n = n;
|
||||
}
|
||||
p[i].iov_base = base;
|
||||
p[i].iov_len = len;
|
||||
++ib->i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_IOVS_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_IOVS_H_
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct Iovs {
|
||||
struct iovec *p;
|
||||
unsigned i, n;
|
||||
struct iovec init[2];
|
||||
};
|
||||
|
||||
void InitIovs(struct Iovs *);
|
||||
void FreeIovs(struct Iovs *);
|
||||
int AppendIovs(struct Iovs *, void *, size_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_IOVS_H_ */
|
|
@ -1,49 +0,0 @@
|
|||
/*-*- 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 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/macros.internal.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/ldbl.h"
|
||||
#include "tool/build/lib/pun.h"
|
||||
|
||||
uint8_t *SerializeLdbl(uint8_t b[10], double f) {
|
||||
int e;
|
||||
union DoublePun u = {f};
|
||||
e = (u.i >> 52) & 0x7ff;
|
||||
if (!e) {
|
||||
e = 0;
|
||||
} else if (e == 0x7ff) {
|
||||
e = 0x7fff;
|
||||
} else {
|
||||
e -= 0x3ff;
|
||||
e += 0x3fff;
|
||||
}
|
||||
Write16(b + 8, e | u.i >> 63 << 15);
|
||||
Write64(b, (u.i & 0x000fffffffffffff) << 11 | (uint64_t) !!u.f << 63);
|
||||
return b;
|
||||
}
|
||||
|
||||
double DeserializeLdbl(const uint8_t b[10]) {
|
||||
union DoublePun u;
|
||||
u.i = (uint64_t)(MAX(-1023, MIN(1024, ((Read16(b + 8) & 0x7fff) - 0x3fff))) +
|
||||
1023)
|
||||
<< 52 |
|
||||
((Read64(b) & 0x7fffffffffffffff) + (1 << (11 - 1))) >> 11 |
|
||||
(uint64_t)(b[9] >> 7) << 63;
|
||||
return u.f;
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_LDBL_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_LDBL_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
double DeserializeLdbl(const uint8_t[10]);
|
||||
uint8_t *SerializeLdbl(uint8_t[10], double);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_LDBL_H_ */
|
|
@ -1,227 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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 "tool/build/lib/loader.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/elf/elf.h"
|
||||
#include "libc/elf/struct/phdr.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/popcnt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/pc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "third_party/xed/x86.h"
|
||||
#include "tool/build/lib/argv.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#include "tool/build/lib/memory.h"
|
||||
|
||||
static void LoadElfLoadSegment(struct Machine *m, void *code, size_t codesize,
|
||||
Elf64_Phdr *phdr) {
|
||||
void *rbss;
|
||||
int64_t align, bsssize;
|
||||
int64_t felf, fstart, fend, vstart, vbss, vend;
|
||||
align = MAX(phdr->p_align, PAGESIZE);
|
||||
if (popcnt(align) != 1) align = 8;
|
||||
CHECK_EQ(0, (phdr->p_vaddr - phdr->p_offset) % align);
|
||||
felf = (int64_t)(intptr_t)code;
|
||||
vstart = ROUNDDOWN(phdr->p_vaddr, align);
|
||||
vbss = ROUNDUP(phdr->p_vaddr + phdr->p_filesz, align);
|
||||
vend = ROUNDUP(phdr->p_vaddr + phdr->p_memsz, align);
|
||||
fstart = felf + ROUNDDOWN(phdr->p_offset, align);
|
||||
fend = felf + phdr->p_offset + phdr->p_filesz;
|
||||
bsssize = vend - vbss;
|
||||
VERBOSEF("LOADELFLOADSEGMENT"
|
||||
" VSTART %#lx VBSS %#lx VEND %#lx"
|
||||
" FSTART %#lx FEND %#lx BSSSIZE %#lx",
|
||||
vstart, vbss, vend, fstart, fend, bsssize);
|
||||
m->brk = MAX(m->brk, vend);
|
||||
CHECK_GE(vend, vstart);
|
||||
CHECK_GE(fend, fstart);
|
||||
CHECK_LE(felf, fstart);
|
||||
CHECK_GE(vstart, -0x800000000000);
|
||||
CHECK_LE(vend, 0x800000000000);
|
||||
CHECK_GE(vend - vstart, fstart - fend);
|
||||
CHECK_LE(phdr->p_filesz, phdr->p_memsz);
|
||||
CHECK_EQ(felf + phdr->p_offset - fstart, phdr->p_vaddr - vstart);
|
||||
CHECK_NE(-1, ReserveVirtual(m, vstart, fend - fstart,
|
||||
PAGE_V | PAGE_RW | PAGE_U | PAGE_RSRV));
|
||||
VirtualRecv(m, vstart, (void *)fstart, fend - fstart);
|
||||
if (bsssize)
|
||||
CHECK_NE(-1, ReserveVirtual(m, vbss, bsssize,
|
||||
PAGE_V | PAGE_RW | PAGE_U | PAGE_RSRV));
|
||||
if (phdr->p_memsz - phdr->p_filesz > bsssize) {
|
||||
VirtualSet(m, phdr->p_vaddr + phdr->p_filesz, 0,
|
||||
phdr->p_memsz - phdr->p_filesz - bsssize);
|
||||
}
|
||||
}
|
||||
|
||||
static void LoadElf(struct Machine *m, struct Elf *elf) {
|
||||
unsigned i;
|
||||
Elf64_Phdr *phdr;
|
||||
m->ip = elf->base = 0x400000 /* elf->ehdr->e_entry */;
|
||||
VERBOSEF("LOADELF ENTRY %012lx", m->ip);
|
||||
for (i = 0; i < elf->ehdr->e_phnum; ++i) {
|
||||
phdr = GetElfSegmentHeaderAddress(elf->ehdr, elf->size, i);
|
||||
switch (phdr->p_type) {
|
||||
case PT_LOAD:
|
||||
elf->base = MIN(elf->base, phdr->p_vaddr);
|
||||
LoadElfLoadSegment(m, elf->ehdr, elf->size, phdr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void LoadBin(struct Machine *m, intptr_t base, const char *prog,
|
||||
void *code, size_t codesize) {
|
||||
Elf64_Phdr phdr = {
|
||||
.p_type = PT_LOAD,
|
||||
.p_flags = PF_X | PF_R | PF_W,
|
||||
.p_offset = 0,
|
||||
.p_vaddr = base,
|
||||
.p_paddr = base,
|
||||
.p_filesz = codesize,
|
||||
.p_memsz = ROUNDUP(codesize + FRAMESIZE, 0x200000),
|
||||
.p_align = PAGESIZE,
|
||||
};
|
||||
LoadElfLoadSegment(m, code, codesize, &phdr);
|
||||
m->ip = base;
|
||||
}
|
||||
|
||||
static void BootProgram(struct Machine *m, struct Elf *elf, size_t codesize) {
|
||||
m->ip = 0x7c00;
|
||||
elf->base = 0x7c00;
|
||||
CHECK_NE(-1, ReserveReal(m, 0x00f00000));
|
||||
bzero(m->real.p, 0x00f00000);
|
||||
Write16(m->real.p + 0x400, 0x3F8);
|
||||
Write16(m->real.p + 0x40E, 0xb0000 >> 4);
|
||||
Write16(m->real.p + 0x413, 0xb0000 / 1024);
|
||||
Write16(m->real.p + 0x44A, 80);
|
||||
Write64(m->cs, 0);
|
||||
Write64(m->dx, 0);
|
||||
memcpy(m->real.p + 0x7c00, elf->map, 512);
|
||||
if (memcmp(elf->map, "\177ELF", 4) == 0) {
|
||||
elf->ehdr = (void *)elf->map;
|
||||
elf->size = codesize;
|
||||
elf->base = elf->ehdr->e_entry;
|
||||
} else {
|
||||
elf->base = 0x7c00;
|
||||
elf->ehdr = NULL;
|
||||
elf->size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int GetElfHeader(char ehdr[hasatleast 64], const char *prog,
|
||||
const char *image) {
|
||||
char *p;
|
||||
int c, i;
|
||||
for (p = image; p < image + 4096; ++p) {
|
||||
if (READ64LE(p) != READ64LE("printf '")) continue;
|
||||
for (i = 0, p += 8; p + 3 < image + 4096 && (c = *p++) != '\'';) {
|
||||
if (c == '\\') {
|
||||
if ('0' <= *p && *p <= '7') {
|
||||
c = *p++ - '0';
|
||||
if ('0' <= *p && *p <= '7') {
|
||||
c *= 8;
|
||||
c += *p++ - '0';
|
||||
if ('0' <= *p && *p <= '7') {
|
||||
c *= 8;
|
||||
c += *p++ - '0';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i < 64) {
|
||||
ehdr[i++] = c;
|
||||
} else {
|
||||
WARNF("%s: ape printf elf header too long\n", prog);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (i != 64) {
|
||||
WARNF("%s: ape printf elf header too short\n", prog);
|
||||
return -1;
|
||||
}
|
||||
if (READ32LE(ehdr) != READ32LE("\177ELF")) {
|
||||
WARNF("%s: ape printf elf header didn't have elf magic\n", prog);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
WARNF("%s: printf statement not found in first 4096 bytes\n", prog);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars,
|
||||
struct Elf *elf) {
|
||||
int fd;
|
||||
ssize_t rc;
|
||||
int64_t sp;
|
||||
char ehdr[64];
|
||||
struct stat st;
|
||||
size_t i, mappedsize;
|
||||
DCHECK_NOTNULL(prog);
|
||||
elf->prog = prog;
|
||||
if ((fd = open(prog, O_RDONLY)) == -1 ||
|
||||
(fstat(fd, &st) == -1 || !st.st_size)) {
|
||||
fputs(prog, stderr);
|
||||
fputs(": not found\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
elf->mapsize = st.st_size;
|
||||
CHECK_NE(MAP_FAILED,
|
||||
(elf->map = mmap(NULL, elf->mapsize, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE, fd, 0)));
|
||||
CHECK_NE(-1, close(fd));
|
||||
ResetCpu(m);
|
||||
if ((m->mode & 3) == XED_MODE_REAL) {
|
||||
BootProgram(m, elf, elf->mapsize);
|
||||
} else {
|
||||
sp = 0x800000000000;
|
||||
Write64(m->sp, sp);
|
||||
m->cr3 = AllocateLinearPage(m);
|
||||
CHECK_NE(-1, ReserveVirtual(m, sp - 0x800000, 0x800000,
|
||||
PAGE_V | PAGE_RW | PAGE_U | PAGE_RSRV));
|
||||
LoadArgv(m, prog, args, vars);
|
||||
if (memcmp(elf->map, "\177ELF", 4) == 0) {
|
||||
elf->ehdr = (void *)elf->map;
|
||||
elf->size = elf->mapsize;
|
||||
LoadElf(m, elf);
|
||||
} else if (READ64LE(elf->map) == READ64LE("MZqFpD='") &&
|
||||
!GetElfHeader(ehdr, prog, elf->map)) {
|
||||
memcpy(elf->map, ehdr, 64);
|
||||
elf->ehdr = (void *)elf->map;
|
||||
elf->size = elf->mapsize;
|
||||
LoadElf(m, elf);
|
||||
} else {
|
||||
elf->base = IMAGE_BASE_VIRTUAL;
|
||||
elf->ehdr = NULL;
|
||||
elf->size = 0;
|
||||
LoadBin(m, elf->base, prog, elf->map, elf->mapsize);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_LOADER_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_LOADER_H_
|
||||
#include "libc/elf/struct/ehdr.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct Elf {
|
||||
const char *prog;
|
||||
Elf64_Ehdr *ehdr;
|
||||
size_t size;
|
||||
int64_t base;
|
||||
char *map;
|
||||
size_t mapsize;
|
||||
};
|
||||
|
||||
void LoadProgram(struct Machine *, const char *, char **, char **,
|
||||
struct Elf *);
|
||||
void LoadDebugSymbols(struct Elf *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_LOADER_H_ */
|
File diff suppressed because it is too large
Load diff
|
@ -1,206 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_MACHINE_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_MACHINE_H_
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "third_party/xed/x86.h"
|
||||
#include "tool/build/lib/bits.h"
|
||||
#include "tool/build/lib/fds.h"
|
||||
|
||||
#define kMachineHalt -1
|
||||
#define kMachineDecodeError -2
|
||||
#define kMachineUndefinedInstruction -3
|
||||
#define kMachineSegmentationFault -4
|
||||
#define kMachineExit -5
|
||||
#define kMachineDivideError -6
|
||||
#define kMachineFpuException -7
|
||||
#define kMachineProtectionFault -8
|
||||
#define kMachineSimdException -9
|
||||
#define kMachineOverflow -10
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct Machine {
|
||||
struct XedDecodedInst *xedd;
|
||||
uint64_t ip;
|
||||
uint8_t cs[8];
|
||||
uint8_t ss[8];
|
||||
uint64_t codevirt;
|
||||
uint8_t *codehost;
|
||||
uint32_t mode;
|
||||
uint32_t flags;
|
||||
uint32_t tlbindex;
|
||||
uint32_t stashsize;
|
||||
int64_t stashaddr;
|
||||
int64_t readaddr;
|
||||
int64_t writeaddr;
|
||||
uint32_t readsize;
|
||||
uint32_t writesize;
|
||||
union {
|
||||
uint8_t reg[16][8];
|
||||
struct {
|
||||
uint8_t ax[8];
|
||||
uint8_t cx[8];
|
||||
uint8_t dx[8];
|
||||
uint8_t bx[8];
|
||||
uint8_t sp[8];
|
||||
uint8_t bp[8];
|
||||
uint8_t si[8];
|
||||
uint8_t di[8];
|
||||
uint8_t r8[8];
|
||||
uint8_t r9[8];
|
||||
uint8_t r10[8];
|
||||
uint8_t r11[8];
|
||||
uint8_t r12[8];
|
||||
uint8_t r13[8];
|
||||
uint8_t r14[8];
|
||||
uint8_t r15[8];
|
||||
};
|
||||
};
|
||||
struct MachineTlb {
|
||||
int64_t virt;
|
||||
uint64_t entry;
|
||||
} tlb[16];
|
||||
struct MachineReal {
|
||||
size_t i, n;
|
||||
uint8_t *p;
|
||||
} real;
|
||||
uint64_t cr3;
|
||||
uint8_t xmm[16][16];
|
||||
uint8_t es[8];
|
||||
uint8_t ds[8];
|
||||
uint8_t fs[8];
|
||||
uint8_t gs[8];
|
||||
struct MachineFpu {
|
||||
long double st[8];
|
||||
union {
|
||||
uint32_t cw;
|
||||
struct {
|
||||
unsigned im : 1; // invalid operation mask
|
||||
unsigned dm : 1; // denormal operand mask
|
||||
unsigned zm : 1; // zero divide mask
|
||||
unsigned om : 1; // overflow mask
|
||||
unsigned um : 1; // underflow mask
|
||||
unsigned pm : 1; // precision mask
|
||||
unsigned _p1 : 2; // reserved
|
||||
unsigned pc : 2; // precision: 32,∅,64,80
|
||||
unsigned rc : 2; // rounding: even,→-∞,→+∞,→0
|
||||
};
|
||||
};
|
||||
union {
|
||||
uint32_t sw;
|
||||
struct {
|
||||
unsigned ie : 1; // invalid operation
|
||||
unsigned de : 1; // denormalized operand
|
||||
unsigned ze : 1; // zero divide
|
||||
unsigned oe : 1; // overflow
|
||||
unsigned ue : 1; // underflow
|
||||
unsigned pe : 1; // precision
|
||||
unsigned sf : 1; // stack fault
|
||||
unsigned es : 1; // exception summary status
|
||||
unsigned c0 : 1; // condition 0
|
||||
unsigned c1 : 1; // condition 1
|
||||
unsigned c2 : 1; // condition 2
|
||||
unsigned sp : 3; // top stack
|
||||
unsigned c3 : 1; // condition 3
|
||||
unsigned bf : 1; // busy flag
|
||||
};
|
||||
};
|
||||
int tw;
|
||||
int op;
|
||||
int64_t ip;
|
||||
int64_t dp;
|
||||
} fpu;
|
||||
struct MachineSse {
|
||||
union {
|
||||
uint32_t mxcsr;
|
||||
struct {
|
||||
unsigned ie : 1; // invalid operation flag
|
||||
unsigned de : 1; // denormal flag
|
||||
unsigned ze : 1; // divide by zero flag
|
||||
unsigned oe : 1; // overflow flag
|
||||
unsigned ue : 1; // underflow flag
|
||||
unsigned pe : 1; // precision flag
|
||||
unsigned daz : 1; // denormals are zeros
|
||||
unsigned im : 1; // invalid operation mask
|
||||
unsigned dm : 1; // denormal mask
|
||||
unsigned zm : 1; // divide by zero mask
|
||||
unsigned om : 1; // overflow mask
|
||||
unsigned um : 1; // underflow mask
|
||||
unsigned pm : 1; // precision mask
|
||||
unsigned rc : 2; // rounding control
|
||||
unsigned ftz : 1; // flush to zero
|
||||
};
|
||||
};
|
||||
} sse;
|
||||
uint64_t cr0;
|
||||
uint64_t cr2;
|
||||
uint64_t cr4;
|
||||
uint64_t gdt_base;
|
||||
uint64_t idt_base;
|
||||
uint16_t gdt_limit;
|
||||
uint16_t idt_limit;
|
||||
uint32_t mxcsr;
|
||||
struct MachineRealFree {
|
||||
uint64_t i;
|
||||
uint64_t n;
|
||||
struct MachineRealFree *next;
|
||||
} * realfree;
|
||||
struct FreeList {
|
||||
uint32_t i;
|
||||
void *p[6];
|
||||
} freelist;
|
||||
struct MachineMemstat {
|
||||
int freed;
|
||||
int resizes;
|
||||
int reserved;
|
||||
int committed;
|
||||
int allocated;
|
||||
int reclaimed;
|
||||
int pagetables;
|
||||
} memstat;
|
||||
int64_t brk;
|
||||
int64_t bofram[2];
|
||||
jmp_buf onhalt;
|
||||
int64_t faultaddr;
|
||||
bool dlab;
|
||||
bool isfork;
|
||||
bool ismetal;
|
||||
struct MachineFds fds;
|
||||
uint8_t stash[4096];
|
||||
uint8_t icache[1024][40];
|
||||
void (*onbinbase)(struct Machine *);
|
||||
void (*onlongbranch)(struct Machine *);
|
||||
void (*redraw)(void);
|
||||
struct sigaction_bits sighand[28];
|
||||
uint8_t sigmask[8];
|
||||
int sig;
|
||||
uint64_t siguc;
|
||||
uint64_t sigfp;
|
||||
struct {
|
||||
int i, n;
|
||||
struct {
|
||||
int sig;
|
||||
int code;
|
||||
} p[64];
|
||||
} signals;
|
||||
} forcealign(64);
|
||||
|
||||
struct Machine *NewMachine(void) dontdiscard;
|
||||
void FreeMachine(struct Machine *);
|
||||
void ResetMem(struct Machine *);
|
||||
void ResetCpu(struct Machine *);
|
||||
void ResetTlb(struct Machine *);
|
||||
void ResetInstructionCache(struct Machine *);
|
||||
void LoadInstruction(struct Machine *);
|
||||
void ExecuteInstruction(struct Machine *);
|
||||
long AllocateLinearPage(struct Machine *);
|
||||
long AllocateLinearPageRaw(struct Machine *);
|
||||
int ReserveReal(struct Machine *, size_t);
|
||||
int ReserveVirtual(struct Machine *, int64_t, size_t, uint64_t);
|
||||
char *FormatPml4t(struct Machine *) dontdiscard;
|
||||
int64_t FindVirtual(struct Machine *, int64_t, size_t);
|
||||
int FreeVirtual(struct Machine *, int64_t, size_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_MACHINE_H_ */
|
|
@ -1,70 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/macros.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/tab.internal.h"
|
||||
#include "tool/build/lib/buffer.h"
|
||||
#include "tool/build/lib/mda.h"
|
||||
|
||||
#define kBlink 1
|
||||
#define kVisible 2
|
||||
#define kUnderline 4
|
||||
#define kBold 8
|
||||
#define kReverse 16
|
||||
|
||||
/**
|
||||
* Decodes Monochrome Display Adapter attributes.
|
||||
* @see https://www.seasip.info/VintagePC/mda.html
|
||||
*/
|
||||
static uint8_t DecodeMdaAttributes(int8_t a) {
|
||||
uint8_t r = 0;
|
||||
if (a & 0x77) {
|
||||
if ((a & 0x77) == 0x70) r |= kReverse;
|
||||
if ((a & 0x07) == 0x01) r |= kUnderline;
|
||||
if (a & 0x08) r |= kBold;
|
||||
if (a < 0) r |= kBlink;
|
||||
r |= kVisible;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void DrawMda(struct Panel *p, uint8_t v[25][80][2]) {
|
||||
unsigned y, x, n, a, b;
|
||||
n = MIN(25, p->bottom - p->top);
|
||||
for (y = 0; y < n; ++y) {
|
||||
a = -1;
|
||||
for (x = 0; x < 80; ++x) {
|
||||
b = DecodeMdaAttributes(v[y][x][1]);
|
||||
if (a != b) {
|
||||
a = b;
|
||||
AppendStr(&p->lines[y], "\e[0");
|
||||
if (a & kBold) AppendStr(&p->lines[y], ";1");
|
||||
if (a & kUnderline) AppendStr(&p->lines[y], ";4");
|
||||
if (a & kBlink) AppendStr(&p->lines[y], ";5");
|
||||
if (a & kReverse) AppendStr(&p->lines[y], ";7");
|
||||
AppendChar(&p->lines[y], 'm');
|
||||
}
|
||||
if (a) {
|
||||
AppendWide(&p->lines[y], kCp437[v[y][x][0]]);
|
||||
} else {
|
||||
AppendChar(&p->lines[y], ' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_MDA_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_MDA_H_
|
||||
#include "tool/build/lib/panel.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void DrawMda(struct Panel *, uint8_t[25][80][2]);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_MDA_H_ */
|
|
@ -1,288 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/mem/mem.h"
|
||||
#include "libc/nt/struct/importobjectheader.internal.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/pc.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/build/lib/memory.h"
|
||||
#include "tool/build/lib/throw.h"
|
||||
|
||||
void SetReadAddr(struct Machine *m, int64_t addr, uint32_t size) {
|
||||
if (size) {
|
||||
m->readaddr = addr;
|
||||
m->readsize = size;
|
||||
}
|
||||
}
|
||||
|
||||
void SetWriteAddr(struct Machine *m, int64_t addr, uint32_t size) {
|
||||
if (size) {
|
||||
m->writeaddr = addr;
|
||||
m->writesize = size;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t HandlePageFault(struct Machine *m, int64_t virt, uint64_t entry,
|
||||
uint64_t table, unsigned index) {
|
||||
long page;
|
||||
if ((page = AllocateLinearPage(m)) != -1) {
|
||||
--m->memstat.reserved;
|
||||
if (entry & PAGE_GROD) {
|
||||
ReserveVirtual(m, virt - 4096, 4096,
|
||||
PAGE_GROD | PAGE_RSRV |
|
||||
(entry & (PAGE_XD | PAGE_U | PAGE_RW | PAGE_V)));
|
||||
}
|
||||
return (*(uint64_t *)(m->real.p + table + index * 8) =
|
||||
page | entry & ~(PAGE_TA | PAGE_IGN1));
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t FindPage(struct Machine *m, int64_t virt) {
|
||||
uint64_t table, entry;
|
||||
unsigned level, index, i;
|
||||
virt &= -4096;
|
||||
for (i = 0; i < ARRAYLEN(m->tlb); ++i) {
|
||||
if (m->tlb[i].virt == virt && (m->tlb[i].entry & 1)) {
|
||||
return m->tlb[i].entry;
|
||||
}
|
||||
}
|
||||
level = 39;
|
||||
entry = m->cr3;
|
||||
do {
|
||||
table = entry & PAGE_TA;
|
||||
CHECK_LT(table, m->real.n);
|
||||
index = (virt >> level) & 511;
|
||||
entry = *(uint64_t *)(m->real.p + table + index * 8);
|
||||
if (!(entry & 1)) return 0;
|
||||
} while ((level -= 9) >= 12);
|
||||
if ((entry & PAGE_RSRV) &&
|
||||
(entry = HandlePageFault(m, virt, entry, table, index)) == -1) {
|
||||
return 0;
|
||||
}
|
||||
m->tlbindex = (m->tlbindex + 1) & (ARRAYLEN(m->tlb) - 1);
|
||||
m->tlb[m->tlbindex] = m->tlb[0];
|
||||
m->tlb[0].virt = virt;
|
||||
m->tlb[0].entry = entry;
|
||||
return entry;
|
||||
}
|
||||
|
||||
void *FindReal(struct Machine *m, int64_t virt) {
|
||||
uint64_t table, entry, page;
|
||||
unsigned skew, level, index, i;
|
||||
if ((m->mode & 3) != XED_MODE_REAL) {
|
||||
if (IsLegalPointer(virt)) {
|
||||
if (!(entry = FindPage(m, virt))) return NULL;
|
||||
return m->real.p + (entry & PAGE_TA) + (virt & 0xfff);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
} else if (0 <= virt && virt + 0xfff < m->real.n) {
|
||||
return m->real.p + virt;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void *ResolveAddress(struct Machine *m, int64_t v) {
|
||||
void *r;
|
||||
if ((r = FindReal(m, v))) return r;
|
||||
ThrowSegmentationFault(m, v);
|
||||
}
|
||||
|
||||
void VirtualSet(struct Machine *m, int64_t v, char c, uint64_t n) {
|
||||
char *p;
|
||||
uint64_t k;
|
||||
k = 4096 - (v & 0xfff);
|
||||
while (n) {
|
||||
k = MIN(k, n);
|
||||
p = ResolveAddress(m, v);
|
||||
memset(p, c, k);
|
||||
n -= k;
|
||||
v += k;
|
||||
k = 4096;
|
||||
}
|
||||
}
|
||||
|
||||
void VirtualCopy(struct Machine *m, int64_t v, char *r, uint64_t n, bool d) {
|
||||
char *p;
|
||||
uint64_t k;
|
||||
k = 4096 - (v & 0xfff);
|
||||
while (n) {
|
||||
k = MIN(k, n);
|
||||
p = ResolveAddress(m, v);
|
||||
if (d) {
|
||||
memcpy(r, p, k);
|
||||
} else {
|
||||
memcpy(p, r, k);
|
||||
}
|
||||
n -= k;
|
||||
r += k;
|
||||
v += k;
|
||||
k = 4096;
|
||||
}
|
||||
}
|
||||
|
||||
void *VirtualSend(struct Machine *m, void *dst, int64_t src, uint64_t n) {
|
||||
VirtualCopy(m, src, dst, n, true);
|
||||
return dst;
|
||||
}
|
||||
|
||||
void VirtualSendRead(struct Machine *m, void *dst, int64_t addr, uint64_t n) {
|
||||
VirtualSend(m, dst, addr, n);
|
||||
SetReadAddr(m, addr, n);
|
||||
}
|
||||
|
||||
void VirtualRecv(struct Machine *m, int64_t dst, void *src, uint64_t n) {
|
||||
VirtualCopy(m, dst, src, n, false);
|
||||
}
|
||||
|
||||
void VirtualRecvWrite(struct Machine *m, int64_t addr, void *src, uint64_t n) {
|
||||
VirtualRecv(m, addr, src, n);
|
||||
SetWriteAddr(m, addr, n);
|
||||
}
|
||||
|
||||
void *ReserveAddress(struct Machine *m, int64_t v, size_t n) {
|
||||
void *r;
|
||||
DCHECK_LE(n, sizeof(m->stash));
|
||||
if ((v & 0xfff) + n <= 4096) return ResolveAddress(m, v);
|
||||
m->stashaddr = v;
|
||||
m->stashsize = n;
|
||||
r = m->stash;
|
||||
VirtualSend(m, r, v, n);
|
||||
return r;
|
||||
}
|
||||
|
||||
void *AccessRam(struct Machine *m, int64_t v, size_t n, void *p[2],
|
||||
uint8_t *tmp, bool copy) {
|
||||
unsigned k;
|
||||
uint8_t *a, *b;
|
||||
DCHECK_LE(n, 4096);
|
||||
if ((v & 0xfff) + n <= 4096) return ResolveAddress(m, v);
|
||||
k = 4096;
|
||||
k -= v & 0xfff;
|
||||
DCHECK_LE(k, 4096);
|
||||
a = ResolveAddress(m, v);
|
||||
b = ResolveAddress(m, v + k);
|
||||
if (copy) {
|
||||
memcpy(tmp, a, k);
|
||||
memcpy(tmp + k, b, n - k);
|
||||
}
|
||||
p[0] = a;
|
||||
p[1] = b;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void *Load(struct Machine *m, int64_t v, size_t n, uint8_t *b) {
|
||||
void *p[2];
|
||||
SetReadAddr(m, v, n);
|
||||
return AccessRam(m, v, n, p, b, true);
|
||||
}
|
||||
|
||||
void *BeginStore(struct Machine *m, int64_t v, size_t n, void *p[2],
|
||||
uint8_t *b) {
|
||||
SetWriteAddr(m, v, n);
|
||||
return AccessRam(m, v, n, p, b, false);
|
||||
}
|
||||
|
||||
void *BeginStoreNp(struct Machine *m, int64_t v, size_t n, void *p[2],
|
||||
uint8_t *b) {
|
||||
if (!v) return NULL;
|
||||
return BeginStore(m, v, n, p, b);
|
||||
}
|
||||
|
||||
void *BeginLoadStore(struct Machine *m, int64_t v, size_t n, void *p[2],
|
||||
uint8_t *b) {
|
||||
SetWriteAddr(m, v, n);
|
||||
return AccessRam(m, v, n, p, b, true);
|
||||
}
|
||||
|
||||
void EndStore(struct Machine *m, int64_t v, size_t n, void *p[2], uint8_t *b) {
|
||||
uint8_t *a;
|
||||
unsigned k;
|
||||
DCHECK_LE(n, 4096);
|
||||
if ((v & 0xfff) + n <= 4096) return;
|
||||
k = 4096;
|
||||
k -= v & 0xfff;
|
||||
DCHECK_GT(k, n);
|
||||
DCHECK_NOTNULL(p[0]);
|
||||
DCHECK_NOTNULL(p[1]);
|
||||
memcpy(p[0], b, k);
|
||||
memcpy(p[1], b + k, n - k);
|
||||
}
|
||||
|
||||
void EndStoreNp(struct Machine *m, int64_t v, size_t n, void *p[2],
|
||||
uint8_t *b) {
|
||||
if (v) EndStore(m, v, n, p, b);
|
||||
}
|
||||
|
||||
void *LoadStr(struct Machine *m, int64_t addr) {
|
||||
size_t have;
|
||||
char *copy, *page, *p;
|
||||
have = 4096 - (addr & 0xfff);
|
||||
if (!addr) return NULL;
|
||||
if (!(page = FindReal(m, addr))) return NULL;
|
||||
if ((p = memchr(page, '\0', have))) {
|
||||
SetReadAddr(m, addr, p - page + 1);
|
||||
return page;
|
||||
}
|
||||
CHECK_LT(m->freelist.i, ARRAYLEN(m->freelist.p));
|
||||
if (!(copy = malloc(have + 4096))) return NULL;
|
||||
memcpy(copy, page, have);
|
||||
for (;;) {
|
||||
if (!(page = FindReal(m, addr + have))) break;
|
||||
if ((p = memccpy(copy + have, page, '\0', 4096))) {
|
||||
SetReadAddr(m, addr, have + (p - (copy + have)) + 1);
|
||||
return (m->freelist.p[m->freelist.i++] = copy);
|
||||
}
|
||||
have += 4096;
|
||||
if (!(p = realloc(copy, have + 4096))) break;
|
||||
copy = p;
|
||||
}
|
||||
free(copy);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *LoadBuf(struct Machine *m, int64_t addr, size_t size) {
|
||||
size_t have, need;
|
||||
char *buf, *copy, *page;
|
||||
have = 4096 - (addr & 0xfff);
|
||||
if (!addr) return NULL;
|
||||
if (!(buf = FindReal(m, addr))) return NULL;
|
||||
if (size > have) {
|
||||
CHECK_LT(m->freelist.i, ARRAYLEN(m->freelist.p));
|
||||
if (!(copy = malloc(size))) return NULL;
|
||||
buf = memcpy(copy, buf, have);
|
||||
do {
|
||||
need = MIN(4096, size - have);
|
||||
if ((page = FindReal(m, addr + have))) {
|
||||
memcpy(copy + have, page, need);
|
||||
have += need;
|
||||
} else {
|
||||
free(copy);
|
||||
return NULL;
|
||||
}
|
||||
} while (have < size);
|
||||
}
|
||||
SetReadAddr(m, addr, size);
|
||||
return buf;
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_MEMORY_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_MEMORY_H_
|
||||
#include "tool/build/lib/machine.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int RegisterMemory(struct Machine *, int64_t, void *, size_t);
|
||||
uint64_t FindPage(struct Machine *, int64_t);
|
||||
void *AccessRam(struct Machine *, int64_t, size_t, void *[2], uint8_t *, bool);
|
||||
void *BeginLoadStore(struct Machine *, int64_t, size_t, void *[2], uint8_t *);
|
||||
void *BeginStore(struct Machine *, int64_t, size_t, void *[2], uint8_t *);
|
||||
void *BeginStoreNp(struct Machine *, int64_t, size_t, void *[2], uint8_t *);
|
||||
void *FindReal(struct Machine *, int64_t);
|
||||
void *Load(struct Machine *, int64_t, size_t, uint8_t *);
|
||||
void *LoadBuf(struct Machine *, int64_t, size_t);
|
||||
void *LoadStr(struct Machine *, int64_t);
|
||||
void *MallocPage(void);
|
||||
void *RealAddress(struct Machine *, int64_t);
|
||||
void *ReserveAddress(struct Machine *, int64_t, size_t);
|
||||
void *ResolveAddress(struct Machine *, int64_t);
|
||||
void *VirtualSend(struct Machine *, void *, int64_t, uint64_t);
|
||||
void EndStore(struct Machine *, int64_t, size_t, void *[2], uint8_t *);
|
||||
void EndStoreNp(struct Machine *, int64_t, size_t, void *[2], uint8_t *);
|
||||
void ResetRam(struct Machine *);
|
||||
void SetReadAddr(struct Machine *, int64_t, uint32_t);
|
||||
void SetWriteAddr(struct Machine *, int64_t, uint32_t);
|
||||
void VirtualRecv(struct Machine *, int64_t, void *, uint64_t);
|
||||
void VirtualRecvWrite(struct Machine *, int64_t, void *, uint64_t);
|
||||
void VirtualSendRead(struct Machine *, void *, int64_t, uint64_t);
|
||||
void VirtualSet(struct Machine *, int64_t, char, uint64_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_MEMORY_H_ */
|
|
@ -1,224 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/mem/mem.h"
|
||||
#include "libc/runtime/pc.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
|
||||
struct Machine *NewMachine(void) {
|
||||
struct Machine *m;
|
||||
m = xmemalignzero(_Alignof(struct Machine), sizeof(struct Machine));
|
||||
ResetCpu(m);
|
||||
ResetMem(m);
|
||||
return m;
|
||||
}
|
||||
|
||||
static void FreeMachineRealFree(struct Machine *m) {
|
||||
struct MachineRealFree *rf;
|
||||
while ((rf = m->realfree)) {
|
||||
m->realfree = rf->next;
|
||||
free(rf);
|
||||
}
|
||||
}
|
||||
|
||||
void FreeMachine(struct Machine *m) {
|
||||
if (m) {
|
||||
FreeMachineRealFree(m);
|
||||
free(m->real.p);
|
||||
free(m);
|
||||
}
|
||||
}
|
||||
|
||||
void ResetMem(struct Machine *m) {
|
||||
FreeMachineRealFree(m);
|
||||
ResetTlb(m);
|
||||
bzero(&m->memstat, sizeof(m->memstat));
|
||||
m->real.i = 0;
|
||||
m->cr3 = 0;
|
||||
}
|
||||
|
||||
long AllocateLinearPage(struct Machine *m) {
|
||||
long page;
|
||||
if ((page = AllocateLinearPageRaw(m)) != -1) {
|
||||
bzero(m->real.p + page, 4096);
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
long AllocateLinearPageRaw(struct Machine *m) {
|
||||
uint8_t *p;
|
||||
size_t i, n;
|
||||
struct MachineRealFree *rf;
|
||||
if ((rf = m->realfree)) {
|
||||
DCHECK(rf->n);
|
||||
DCHECK_EQ(0, rf->i & 4095);
|
||||
DCHECK_EQ(0, rf->n & 4095);
|
||||
DCHECK_LE(rf->i + rf->n, m->real.i);
|
||||
i = rf->i;
|
||||
rf->i += 4096;
|
||||
if (!(rf->n -= 4096)) {
|
||||
m->realfree = rf->next;
|
||||
free(rf);
|
||||
}
|
||||
--m->memstat.freed;
|
||||
++m->memstat.reclaimed;
|
||||
} else {
|
||||
i = m->real.i;
|
||||
n = m->real.n;
|
||||
p = m->real.p;
|
||||
if (i == n) {
|
||||
if (n) {
|
||||
n += n >> 1;
|
||||
} else {
|
||||
n = 65536;
|
||||
}
|
||||
n = ROUNDUP(n, 4096);
|
||||
if ((p = realloc(p, n))) {
|
||||
m->real.p = p;
|
||||
m->real.n = n;
|
||||
ResetTlb(m);
|
||||
++m->memstat.resizes;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
DCHECK_EQ(0, i & 4095);
|
||||
DCHECK_EQ(0, n & 4095);
|
||||
DCHECK_LE(i + 4096, n);
|
||||
m->real.i += 4096;
|
||||
++m->memstat.allocated;
|
||||
}
|
||||
++m->memstat.committed;
|
||||
return i;
|
||||
}
|
||||
|
||||
static uint64_t MachineRead64(struct Machine *m, unsigned long i) {
|
||||
CHECK_LE(i + 8, m->real.n);
|
||||
return Read64(m->real.p + i);
|
||||
}
|
||||
|
||||
static void MachineWrite64(struct Machine *m, unsigned long i, uint64_t x) {
|
||||
CHECK_LE(i + 8, m->real.n);
|
||||
Write64(m->real.p + i, x);
|
||||
}
|
||||
|
||||
int ReserveReal(struct Machine *m, size_t n) {
|
||||
uint8_t *p;
|
||||
DCHECK_EQ(0, n & 4095);
|
||||
if (m->real.n < n) {
|
||||
if ((p = realloc(m->real.p, n))) {
|
||||
m->real.p = p;
|
||||
m->real.n = n;
|
||||
ResetTlb(m);
|
||||
++m->memstat.resizes;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ReserveVirtual(struct Machine *m, int64_t virt, size_t size, uint64_t key) {
|
||||
int64_t ti, mi, pt, end, level;
|
||||
for (end = virt + size;;) {
|
||||
for (pt = m->cr3, level = 39; level >= 12; level -= 9) {
|
||||
pt = pt & PAGE_TA;
|
||||
ti = (virt >> level) & 511;
|
||||
mi = (pt & PAGE_TA) + ti * 8;
|
||||
pt = MachineRead64(m, mi);
|
||||
if (level > 12) {
|
||||
if (!(pt & 1)) {
|
||||
if ((pt = AllocateLinearPage(m)) == -1) return -1;
|
||||
MachineWrite64(m, mi, pt | 7);
|
||||
++m->memstat.pagetables;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
for (;;) {
|
||||
if (!(pt & 1)) {
|
||||
MachineWrite64(m, mi, key);
|
||||
++m->memstat.reserved;
|
||||
}
|
||||
if ((virt += 4096) >= end) return 0;
|
||||
if (++ti == 512) break;
|
||||
pt = MachineRead64(m, (mi += 8));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int64_t FindVirtual(struct Machine *m, int64_t virt, size_t size) {
|
||||
uint64_t i, pt, got;
|
||||
got = 0;
|
||||
do {
|
||||
if (virt >= 0x800000000000) return enomem();
|
||||
for (pt = m->cr3, i = 39; i >= 12; i -= 9) {
|
||||
pt = MachineRead64(m, (pt & PAGE_TA) + ((virt >> i) & 511) * 8);
|
||||
if (!(pt & 1)) break;
|
||||
}
|
||||
if (i >= 12) {
|
||||
got += 1ull << i;
|
||||
} else {
|
||||
virt += 4096;
|
||||
got = 0;
|
||||
}
|
||||
} while (got < size);
|
||||
return virt;
|
||||
}
|
||||
|
||||
static void AppendRealFree(struct Machine *m, uint64_t real) {
|
||||
struct MachineRealFree *rf;
|
||||
if (m->realfree && real == m->realfree->i + m->realfree->n) {
|
||||
m->realfree->n += 4096;
|
||||
} else if ((rf = malloc(sizeof(struct MachineRealFree)))) {
|
||||
rf->i = real;
|
||||
rf->n = 4096;
|
||||
rf->next = m->realfree;
|
||||
m->realfree = rf;
|
||||
}
|
||||
}
|
||||
|
||||
int FreeVirtual(struct Machine *m, int64_t base, size_t size) {
|
||||
uint64_t i, mi, pt, end, virt;
|
||||
for (virt = base, end = virt + size; virt < end; virt += 1ull << i) {
|
||||
for (pt = m->cr3, i = 39;; i -= 9) {
|
||||
mi = (pt & PAGE_TA) + ((virt >> i) & 511) * 8;
|
||||
pt = MachineRead64(m, mi);
|
||||
if (!(pt & 1)) {
|
||||
break;
|
||||
} else if (i == 12) {
|
||||
++m->memstat.freed;
|
||||
if (pt & PAGE_RSRV) {
|
||||
--m->memstat.reserved;
|
||||
} else {
|
||||
--m->memstat.committed;
|
||||
AppendRealFree(m, pt & PAGE_TA);
|
||||
}
|
||||
MachineWrite64(m, mi, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ResetTlb(m);
|
||||
return 0;
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/strwidth.h"
|
||||
#include "tool/build/lib/buffer.h"
|
||||
#include "tool/build/lib/lines.h"
|
||||
#include "tool/build/lib/panel.h"
|
||||
|
||||
static int GetWidthOfLongestLine(struct Lines *lines) {
|
||||
int i, w, m;
|
||||
for (m = i = 0; i < lines->n; ++i) {
|
||||
w = strwidth(lines->p[i], 0);
|
||||
m = MAX(m, w);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
void PrintMessageBox(int fd, const char *msg, long tyn, long txn) {
|
||||
struct Buffer b;
|
||||
int i, w, h, x, y;
|
||||
struct Lines *lines;
|
||||
lines = NewLines();
|
||||
AppendLines(lines, msg);
|
||||
h = 3 + lines->n + 3;
|
||||
w = 4 + GetWidthOfLongestLine(lines) + 4;
|
||||
x = (txn / 2. - w / 2.) + .5;
|
||||
y = (tyn / 2. - h / 2.) + .5;
|
||||
bzero(&b, sizeof(b));
|
||||
AppendFmt(&b, "\e[%d;%dH", y++, x);
|
||||
for (i = 0; i < w; ++i) AppendStr(&b, " ");
|
||||
AppendFmt(&b, "\e[%d;%dH ╔", y++, x);
|
||||
for (i = 0; i < w - 4; ++i) AppendStr(&b, "═");
|
||||
AppendStr(&b, "╗ ");
|
||||
AppendFmt(&b, "\e[%d;%dH ║ %-*s ║ ", y++, x, w - 8, "");
|
||||
for (i = 0; i < lines->n; ++i) {
|
||||
AppendFmt(&b, "\e[%d;%dH ║ %-*s ║ ", y++, x, w - 8, lines->p[i]);
|
||||
}
|
||||
FreeLines(lines);
|
||||
AppendFmt(&b, "\e[%d;%dH ║ %-*s ║ ", y++, x, w - 8, "");
|
||||
AppendFmt(&b, "\e[%d;%dH ╚", y++, x);
|
||||
for (i = 0; i < w - 4; ++i) AppendStr(&b, "═");
|
||||
AppendStr(&b, "╝ ");
|
||||
AppendFmt(&b, "\e[%d;%dH", y++, x);
|
||||
for (i = 0; i < w; ++i) AppendStr(&b, " ");
|
||||
CHECK_NE(-1, WriteBuffer(&b, fd));
|
||||
free(b.p);
|
||||
}
|
|
@ -1,324 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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 "tool/build/lib/modrm.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "third_party/xed/x86.h"
|
||||
#include "tool/build/lib/address.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#include "tool/build/lib/memory.h"
|
||||
#include "tool/build/lib/throw.h"
|
||||
|
||||
/**
|
||||
* Compactly represents important parts of xed ild result.
|
||||
*/
|
||||
uint32_t EncodeRde(struct XedDecodedInst *x) {
|
||||
uint8_t kWordLog2[2][2][2] = {{{2, 3}, {1, 3}}, {{0, 0}, {0, 0}}};
|
||||
uint32_t osz = x->op.osz ^ x->op.realmode;
|
||||
return kWordLog2[~x->op.opcode & 1][osz][x->op.rexw] << 28 |
|
||||
x->op.mode << 26 | kXedEamode[x->op.asz][x->op.mode] << 24 |
|
||||
(uint32_t)x->op.rep << 30 | x->op.mod << 22 | x->op.asz << 17 |
|
||||
x->op.seg_ovd << 18 | x->op.rexw << 6 | osz << 5 |
|
||||
(x->op.rex << 4 | x->op.rexb << 3 | x->op.srm) << 12 |
|
||||
(x->op.rex << 4 | x->op.rexb << 3 | x->op.rm) << 7 |
|
||||
(x->op.rex << 4 | x->op.rexr << 3 | x->op.reg);
|
||||
}
|
||||
|
||||
struct AddrSeg LoadEffectiveAddress(const struct Machine *m, uint32_t rde) {
|
||||
uint8_t *s = m->ds;
|
||||
uint64_t i = m->xedd->op.disp;
|
||||
DCHECK(!IsModrmRegister(rde));
|
||||
if (Eamode(rde) != XED_MODE_REAL) {
|
||||
if (!SibExists(rde)) {
|
||||
if (IsRipRelative(rde)) {
|
||||
if (Mode(rde) == XED_MODE_LONG) {
|
||||
i += m->ip;
|
||||
}
|
||||
} else {
|
||||
i += Read64(RegRexbRm(m, rde));
|
||||
if (RexbRm(rde) == 4 || RexbRm(rde) == 5) {
|
||||
s = m->ss;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (SibHasBase(m->xedd, rde)) {
|
||||
i += Read64(RegRexbBase(m, rde));
|
||||
if (RexbBase(m, rde) == 4 || RexbBase(m, rde) == 5) {
|
||||
s = m->ss;
|
||||
}
|
||||
}
|
||||
if (SibHasIndex(m->xedd)) {
|
||||
i += Read64(RegRexxIndex(m)) << m->xedd->op.scale;
|
||||
}
|
||||
}
|
||||
if (Eamode(rde) == XED_MODE_LEGACY) {
|
||||
i &= 0xffffffff;
|
||||
}
|
||||
} else {
|
||||
switch (ModrmRm(rde)) {
|
||||
case 0:
|
||||
i += Read16(m->bx);
|
||||
i += Read16(m->si);
|
||||
break;
|
||||
case 1:
|
||||
i += Read16(m->bx);
|
||||
i += Read16(m->di);
|
||||
break;
|
||||
case 2:
|
||||
s = m->ss;
|
||||
i += Read16(m->bp);
|
||||
i += Read16(m->si);
|
||||
break;
|
||||
case 3:
|
||||
s = m->ss;
|
||||
i += Read16(m->bp);
|
||||
i += Read16(m->di);
|
||||
break;
|
||||
case 4:
|
||||
i += Read16(m->si);
|
||||
break;
|
||||
case 5:
|
||||
i += Read16(m->di);
|
||||
break;
|
||||
case 6:
|
||||
if (ModrmMod(rde)) {
|
||||
s = m->ss;
|
||||
i += Read16(m->bp);
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
i += Read16(m->bx);
|
||||
break;
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
i &= 0xffff;
|
||||
}
|
||||
return (struct AddrSeg){i, s};
|
||||
}
|
||||
|
||||
int64_t ComputeAddress(const struct Machine *m, uint32_t rde) {
|
||||
struct AddrSeg ea;
|
||||
ea = LoadEffectiveAddress(m, rde);
|
||||
return AddSegment(m, rde, ea.addr, ea.seg);
|
||||
}
|
||||
|
||||
void *ComputeReserveAddressRead(struct Machine *m, uint32_t rde, size_t n) {
|
||||
int64_t v;
|
||||
v = ComputeAddress(m, rde);
|
||||
SetReadAddr(m, v, n);
|
||||
return ReserveAddress(m, v, n);
|
||||
}
|
||||
|
||||
void *ComputeReserveAddressRead1(struct Machine *m, uint32_t rde) {
|
||||
return ComputeReserveAddressRead(m, rde, 1);
|
||||
}
|
||||
|
||||
void *ComputeReserveAddressRead4(struct Machine *m, uint32_t rde) {
|
||||
return ComputeReserveAddressRead(m, rde, 4);
|
||||
}
|
||||
|
||||
void *ComputeReserveAddressRead8(struct Machine *m, uint32_t rde) {
|
||||
return ComputeReserveAddressRead(m, rde, 8);
|
||||
}
|
||||
|
||||
void *ComputeReserveAddressWrite(struct Machine *m, uint32_t rde, size_t n) {
|
||||
int64_t v;
|
||||
v = ComputeAddress(m, rde);
|
||||
SetWriteAddr(m, v, n);
|
||||
return ReserveAddress(m, v, n);
|
||||
}
|
||||
|
||||
void *ComputeReserveAddressWrite1(struct Machine *m, uint32_t rde) {
|
||||
return ComputeReserveAddressWrite(m, rde, 1);
|
||||
}
|
||||
|
||||
void *ComputeReserveAddressWrite4(struct Machine *m, uint32_t rde) {
|
||||
return ComputeReserveAddressWrite(m, rde, 4);
|
||||
}
|
||||
|
||||
void *ComputeReserveAddressWrite8(struct Machine *m, uint32_t rde) {
|
||||
return ComputeReserveAddressWrite(m, rde, 8);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterMmPointerRead(struct Machine *m, uint32_t rde,
|
||||
size_t n) {
|
||||
if (IsModrmRegister(rde)) {
|
||||
return MmRm(m, rde);
|
||||
} else {
|
||||
return ComputeReserveAddressRead(m, rde, n);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterMmPointerRead8(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterMmPointerRead(m, rde, 8);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterMmPointerWrite(struct Machine *m, uint32_t rde,
|
||||
size_t n) {
|
||||
if (IsModrmRegister(rde)) {
|
||||
return MmRm(m, rde);
|
||||
} else {
|
||||
return ComputeReserveAddressWrite(m, rde, n);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterMmPointerWrite8(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterMmPointerWrite(m, rde, 8);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterBytePointerRead(struct Machine *m, uint32_t rde) {
|
||||
int64_t v;
|
||||
if (IsModrmRegister(rde)) {
|
||||
return ByteRexbRm(m, rde);
|
||||
} else {
|
||||
return ComputeReserveAddressRead1(m, rde);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterBytePointerWrite(struct Machine *m, uint32_t rde) {
|
||||
int64_t v;
|
||||
if (IsModrmRegister(rde)) {
|
||||
return ByteRexbRm(m, rde);
|
||||
} else {
|
||||
return ComputeReserveAddressWrite1(m, rde);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterWordPointerRead(struct Machine *m, uint32_t rde,
|
||||
size_t n) {
|
||||
if (IsModrmRegister(rde)) {
|
||||
return RegRexbRm(m, rde);
|
||||
} else {
|
||||
return ComputeReserveAddressRead(m, rde, n);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterWordPointerRead2(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterWordPointerRead(m, rde, 2);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterWordPointerRead4(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterWordPointerRead(m, rde, 4);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterWordPointerRead8(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterWordPointerRead(m, rde, 8);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterWordPointerReadOsz(struct Machine *m, uint32_t rde) {
|
||||
if (!Osz(rde)) {
|
||||
return GetModrmRegisterWordPointerRead8(m, rde);
|
||||
} else {
|
||||
return GetModrmRegisterWordPointerRead2(m, rde);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterWordPointerReadOszRexw(struct Machine *m,
|
||||
uint32_t rde) {
|
||||
if (Rexw(rde)) {
|
||||
return GetModrmRegisterWordPointerRead8(m, rde);
|
||||
} else if (!Osz(rde)) {
|
||||
return GetModrmRegisterWordPointerRead4(m, rde);
|
||||
} else {
|
||||
return GetModrmRegisterWordPointerRead2(m, rde);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterWordPointerWrite(struct Machine *m, uint32_t rde,
|
||||
size_t n) {
|
||||
if (IsModrmRegister(rde)) {
|
||||
return RegRexbRm(m, rde);
|
||||
} else {
|
||||
return ComputeReserveAddressWrite(m, rde, n);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterWordPointerWrite2(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterWordPointerWrite(m, rde, 2);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterWordPointerWrite4(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterWordPointerWrite(m, rde, 4);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterWordPointerWrite8(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterWordPointerWrite(m, rde, 8);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterWordPointerWriteOszRexw(struct Machine *m,
|
||||
uint32_t rde) {
|
||||
if (Rexw(rde)) {
|
||||
return GetModrmRegisterWordPointerWrite(m, rde, 8);
|
||||
} else if (!Osz(rde)) {
|
||||
return GetModrmRegisterWordPointerWrite(m, rde, 4);
|
||||
} else {
|
||||
return GetModrmRegisterWordPointerWrite(m, rde, 2);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterWordPointerWriteOsz(struct Machine *m, uint32_t rde) {
|
||||
if (!Osz(rde)) {
|
||||
return GetModrmRegisterWordPointerWrite(m, rde, 8);
|
||||
} else {
|
||||
return GetModrmRegisterWordPointerWrite(m, rde, 2);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterXmmPointerRead(struct Machine *m, uint32_t rde,
|
||||
size_t n) {
|
||||
if (IsModrmRegister(rde)) {
|
||||
return XmmRexbRm(m, rde);
|
||||
} else {
|
||||
return ComputeReserveAddressRead(m, rde, n);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterXmmPointerRead4(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterXmmPointerRead(m, rde, 4);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterXmmPointerRead8(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterXmmPointerRead(m, rde, 8);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterXmmPointerRead16(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterXmmPointerRead(m, rde, 16);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterXmmPointerWrite(struct Machine *m, uint32_t rde,
|
||||
size_t n) {
|
||||
if (IsModrmRegister(rde)) {
|
||||
return XmmRexbRm(m, rde);
|
||||
} else {
|
||||
return ComputeReserveAddressWrite(m, rde, n);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterXmmPointerWrite4(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterXmmPointerWrite(m, rde, 4);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterXmmPointerWrite8(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterXmmPointerWrite(m, rde, 8);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterXmmPointerWrite16(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterXmmPointerWrite(m, rde, 16);
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_MODRM_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_MODRM_H_
|
||||
#include "tool/build/lib/abp.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
|
||||
#define Rex(x) ((x & 000000000020) >> 004)
|
||||
#define Osz(x) ((x & 000000000040) >> 005)
|
||||
#define Rep(x) ((x & 030000000000) >> 036)
|
||||
#define Rexr(x) ((x & 000000000010) >> 003)
|
||||
#define Rexw(x) ((x & 000000000100) >> 006)
|
||||
#define Rexb(x) ((x & 000000002000) >> 012)
|
||||
#define Sego(x) ((x & 000007000000) >> 022)
|
||||
#define Mode(x) ((x & 001400000000) >> 032)
|
||||
#define Eamode(x) ((x & 000300000000) >> 030)
|
||||
#define RexbRm(x) ((x & 000000003600) >> 007)
|
||||
#define RexrReg(x) ((x & 000000000017) >> 000)
|
||||
#define RegLog2(x) ((x & 006000000000) >> 034)
|
||||
#define ModrmRm(x) ((x & 000000001600) >> 007)
|
||||
#define ModrmReg(x) ((x & 000000000007) >> 000)
|
||||
#define ModrmSrm(x) ((x & 000000070000) >> 014)
|
||||
#define ModrmMod(x) ((x & 000060000000) >> 026)
|
||||
#define Modrm(x) (ModrmMod(x) << 6 | ModrmReg(x) << 3 | ModrmRm(x))
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define RexbBase(m, x) (Rexb(x) << 3 | m->xedd->op.base)
|
||||
#define AddrByteReg(m, k) ((uint8_t *)m->reg + kByteReg[k])
|
||||
#define ByteRexrReg(m, x) AddrByteReg(m, (x & 00000000037) >> 0)
|
||||
#define ByteRexbRm(m, x) AddrByteReg(m, (x & 00000007600) >> 7)
|
||||
#define ByteRexbSrm(m, x) AddrByteReg(m, (x & 00000370000) >> 12)
|
||||
#define RegSrm(m, x) Abp8(m->reg[(x & 00000070000) >> 12])
|
||||
#define RegRexbRm(m, x) Abp8(m->reg[RexbRm(x)])
|
||||
#define RegRexbSrm(m, x) Abp8(m->reg[(x & 00000170000) >> 12])
|
||||
#define RegRexrReg(m, x) Abp8(m->reg[RexrReg(x)])
|
||||
#define RegRexbBase(m, x) Abp8(m->reg[RexbBase(m, x)])
|
||||
#define RegRexxIndex(m) Abp8(m->reg[m->xedd->op.rexx << 3 | m->xedd->op.index])
|
||||
#define MmRm(m, x) Abp16(m->xmm[(x & 00000001600) >> 7])
|
||||
#define MmReg(m, x) Abp16(m->xmm[(x & 00000000007) >> 0])
|
||||
#define XmmRexbRm(m, x) Abp16(m->xmm[RexbRm(x)])
|
||||
#define XmmRexrReg(m, x) Abp16(m->xmm[RexrReg(x)])
|
||||
|
||||
#define Rexx(m) m->op.rexx
|
||||
#define SibBase(m) m->op.base
|
||||
#define SibIndex(m) m->op.index
|
||||
#define SibExists(x) (ModrmRm(x) == 4)
|
||||
#define IsModrmRegister(x) (ModrmMod(x) == 3)
|
||||
#define SibHasIndex(x) (SibIndex(x) != 4 || Rexx(x))
|
||||
#define SibHasBase(x, r) (SibBase(x) != 5 || ModrmMod(r))
|
||||
#define SibIsAbsolute(x, r) (!SibHasBase(x, r) && !SibHasIndex(x))
|
||||
#define IsRipRelative(x) (Eamode(x) && ModrmRm(x) == 5 && !ModrmMod(x))
|
||||
|
||||
struct AddrSeg {
|
||||
int64_t addr;
|
||||
uint8_t *seg;
|
||||
};
|
||||
|
||||
extern const uint8_t kByteReg[32];
|
||||
|
||||
uint32_t EncodeRde(struct XedDecodedInst *);
|
||||
int64_t ComputeAddress(const struct Machine *, uint32_t);
|
||||
struct AddrSeg LoadEffectiveAddress(const struct Machine *, uint32_t);
|
||||
void *ComputeReserveAddressRead(struct Machine *, uint32_t, size_t);
|
||||
void *ComputeReserveAddressRead1(struct Machine *, uint32_t);
|
||||
void *ComputeReserveAddressRead4(struct Machine *, uint32_t);
|
||||
void *ComputeReserveAddressRead8(struct Machine *, uint32_t);
|
||||
void *ComputeReserveAddressWrite(struct Machine *, uint32_t, size_t);
|
||||
void *ComputeReserveAddressWrite1(struct Machine *, uint32_t);
|
||||
void *ComputeReserveAddressWrite4(struct Machine *, uint32_t);
|
||||
void *ComputeReserveAddressWrite8(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterBytePointerRead(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterBytePointerWrite(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterMmPointerRead(struct Machine *, uint32_t, size_t);
|
||||
uint8_t *GetModrmRegisterMmPointerRead8(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterMmPointerWrite(struct Machine *, uint32_t, size_t);
|
||||
uint8_t *GetModrmRegisterMmPointerWrite8(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterWordPointerRead(struct Machine *, uint32_t, size_t);
|
||||
uint8_t *GetModrmRegisterWordPointerRead2(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterWordPointerRead4(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterWordPointerRead8(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterWordPointerReadOsz(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterWordPointerReadOszRexw(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterWordPointerWrite(struct Machine *, uint32_t, size_t);
|
||||
uint8_t *GetModrmRegisterWordPointerWrite2(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterWordPointerWrite4(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterWordPointerWrite8(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterWordPointerWriteOsz(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterWordPointerWriteOszRexw(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterXmmPointerRead(struct Machine *, uint32_t, size_t);
|
||||
uint8_t *GetModrmRegisterXmmPointerRead16(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterXmmPointerRead4(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterXmmPointerRead8(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterXmmPointerWrite(struct Machine *, uint32_t, size_t);
|
||||
uint8_t *GetModrmRegisterXmmPointerWrite16(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterXmmPointerWrite4(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterXmmPointerWrite8(struct Machine *, uint32_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_MODRM_H_ */
|
|
@ -1,216 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/log.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/memory.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
#include "tool/build/lib/op101.h"
|
||||
#include "tool/build/lib/throw.h"
|
||||
#include "tool/build/lib/time.h"
|
||||
|
||||
static void StoreDescriptorTable(struct Machine *m, uint32_t rde,
|
||||
uint16_t limit, uint64_t base) {
|
||||
uint64_t l;
|
||||
l = ComputeAddress(m, rde);
|
||||
if (l + 10 <= m->real.n) {
|
||||
Write16(m->real.p + l, limit);
|
||||
if (Rexw(rde)) {
|
||||
Write64(m->real.p + l + 2, base);
|
||||
SetWriteAddr(m, l, 10);
|
||||
} else if (!Osz(rde)) {
|
||||
Write32(m->real.p + l + 2, base);
|
||||
SetWriteAddr(m, l, 6);
|
||||
} else {
|
||||
Write16(m->real.p + l + 2, base);
|
||||
SetWriteAddr(m, l, 4);
|
||||
}
|
||||
} else {
|
||||
ThrowSegmentationFault(m, l);
|
||||
}
|
||||
}
|
||||
|
||||
static void LoadDescriptorTable(struct Machine *m, uint32_t rde,
|
||||
uint16_t *out_limit, uint64_t *out_base) {
|
||||
uint16_t limit;
|
||||
uint64_t l, base;
|
||||
l = ComputeAddress(m, rde);
|
||||
if (l + 10 <= m->real.n) {
|
||||
limit = Read16(m->real.p + l);
|
||||
if (Rexw(rde)) {
|
||||
base = Read64(m->real.p + l + 2) & 0x00ffffff;
|
||||
SetReadAddr(m, l, 10);
|
||||
} else if (!Osz(rde)) {
|
||||
base = Read32(m->real.p + l + 2);
|
||||
SetReadAddr(m, l, 6);
|
||||
} else {
|
||||
base = Read16(m->real.p + l + 2);
|
||||
SetReadAddr(m, l, 4);
|
||||
}
|
||||
if (base + limit <= m->real.n) {
|
||||
*out_limit = limit;
|
||||
*out_base = base;
|
||||
} else {
|
||||
ThrowProtectionFault(m);
|
||||
}
|
||||
} else {
|
||||
ThrowSegmentationFault(m, l);
|
||||
}
|
||||
}
|
||||
|
||||
static void SgdtMs(struct Machine *m, uint32_t rde) {
|
||||
StoreDescriptorTable(m, rde, m->gdt_limit, m->gdt_base);
|
||||
}
|
||||
|
||||
static void LgdtMs(struct Machine *m, uint32_t rde) {
|
||||
LoadDescriptorTable(m, rde, &m->gdt_limit, &m->gdt_base);
|
||||
INFOF("set gdt %p lim %,d", m->gdt_base, m->gdt_limit);
|
||||
}
|
||||
|
||||
static void SidtMs(struct Machine *m, uint32_t rde) {
|
||||
StoreDescriptorTable(m, rde, m->idt_limit, m->idt_base);
|
||||
}
|
||||
|
||||
static void LidtMs(struct Machine *m, uint32_t rde) {
|
||||
LoadDescriptorTable(m, rde, &m->idt_limit, &m->idt_base);
|
||||
INFOF("set idt %p lim %,d", m->idt_base, m->idt_limit);
|
||||
}
|
||||
|
||||
static void Monitor(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
static void Mwait(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
static void Swapgs(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
static void Vmcall(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
static void Vmlaunch(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
static void Vmresume(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
static void Vmxoff(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
static void InvlpgM(struct Machine *m, uint32_t rde) {
|
||||
ResetTlb(m);
|
||||
}
|
||||
|
||||
static void Smsw(struct Machine *m, uint32_t rde, bool ismem) {
|
||||
if (ismem) {
|
||||
Write16(GetModrmRegisterWordPointerWrite2(m, rde), m->cr0);
|
||||
} else if (Rexw(rde)) {
|
||||
Write64(RegRexrReg(m, rde), m->cr0);
|
||||
} else if (!Osz(rde)) {
|
||||
Write64(RegRexrReg(m, rde), m->cr0 & 0xffffffff);
|
||||
} else {
|
||||
Write16(RegRexrReg(m, rde), m->cr0);
|
||||
}
|
||||
}
|
||||
|
||||
static void Lmsw(struct Machine *m, uint32_t rde) {
|
||||
m->cr0 = Read16(GetModrmRegisterWordPointerRead2(m, rde));
|
||||
}
|
||||
|
||||
void Op101(struct Machine *m, uint32_t rde) {
|
||||
bool ismem;
|
||||
ismem = !IsModrmRegister(rde);
|
||||
switch (ModrmReg(rde)) {
|
||||
case 0:
|
||||
if (ismem) {
|
||||
SgdtMs(m, rde);
|
||||
} else {
|
||||
switch (ModrmRm(rde)) {
|
||||
case 1:
|
||||
Vmcall(m, rde);
|
||||
break;
|
||||
case 2:
|
||||
Vmlaunch(m, rde);
|
||||
break;
|
||||
case 3:
|
||||
Vmresume(m, rde);
|
||||
break;
|
||||
case 4:
|
||||
Vmxoff(m, rde);
|
||||
break;
|
||||
default:
|
||||
OpUd(m, rde);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (ismem) {
|
||||
SidtMs(m, rde);
|
||||
} else {
|
||||
switch (ModrmRm(rde)) {
|
||||
case 0:
|
||||
Monitor(m, rde);
|
||||
break;
|
||||
case 1:
|
||||
Mwait(m, rde);
|
||||
break;
|
||||
default:
|
||||
OpUd(m, rde);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (ismem) {
|
||||
LgdtMs(m, rde);
|
||||
} else {
|
||||
OpUd(m, rde);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (ismem) {
|
||||
LidtMs(m, rde);
|
||||
} else {
|
||||
OpUd(m, rde);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
Smsw(m, rde, ismem);
|
||||
break;
|
||||
case 6:
|
||||
Lmsw(m, rde);
|
||||
break;
|
||||
case 7:
|
||||
if (ismem) {
|
||||
InvlpgM(m, rde);
|
||||
} else {
|
||||
switch (ModrmRm(rde)) {
|
||||
case 0:
|
||||
Swapgs(m, rde);
|
||||
break;
|
||||
case 1:
|
||||
OpRdtscp(m, rde);
|
||||
break;
|
||||
default:
|
||||
OpUd(m, rde);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
OpUd(m, rde);
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_OP101_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_OP101_H_
|
||||
#include "tool/build/lib/machine.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void Op101(struct Machine *, uint32_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_OP101_H_ */
|
|
@ -1,62 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/mem/arraylist2.internal.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#include "tool/build/lib/pml4t.h"
|
||||
|
||||
static void AppendContiguousMemoryRange(struct ContiguousMemoryRanges *ranges,
|
||||
int64_t a, int64_t b) {
|
||||
APPEND(&ranges->p, &ranges->i, &ranges->n,
|
||||
(&(struct ContiguousMemoryRange){a, b}));
|
||||
}
|
||||
|
||||
static void FindContiguousMemoryRangesImpl(
|
||||
struct Machine *m, struct ContiguousMemoryRanges *ranges, int64_t addr,
|
||||
unsigned level, int64_t pt, int64_t a, int64_t b) {
|
||||
int64_t i, page, entry;
|
||||
for (i = a; i < b; ++i) {
|
||||
entry = Read64(m->real.p + pt + i * 8);
|
||||
if (!(entry & 1)) continue;
|
||||
entry &= 0x7ffffffff000;
|
||||
page = (int64_t)((uint64_t)(addr | i << level) << 16) >> 16;
|
||||
if (level == 12) {
|
||||
if (ranges->i && page == ranges->p[ranges->i - 1].b) {
|
||||
ranges->p[ranges->i - 1].b += 0x1000;
|
||||
} else {
|
||||
AppendContiguousMemoryRange(ranges, page, page + 0x1000);
|
||||
}
|
||||
} else if (entry + 512 * 8 <= m->real.n) {
|
||||
FindContiguousMemoryRangesImpl(m, ranges, page, level - 9, entry, 0, 512);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FindContiguousMemoryRanges(struct Machine *m,
|
||||
struct ContiguousMemoryRanges *ranges) {
|
||||
uint64_t cr3;
|
||||
ranges->i = 0;
|
||||
if ((m->mode & 3) == XED_MODE_LONG) {
|
||||
cr3 = m->cr3 & 0x7ffffffff000;
|
||||
FindContiguousMemoryRangesImpl(m, ranges, 0, 39, cr3, 256, 512);
|
||||
FindContiguousMemoryRangesImpl(m, ranges, 0, 39, cr3, 0, 256);
|
||||
} else {
|
||||
AppendContiguousMemoryRange(ranges, 0, m->real.n);
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_PML4T_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_PML4T_H_
|
||||
#include "tool/build/lib/machine.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define IsValidPage(x) ((x)&1)
|
||||
#define MaskPageAddr(x) ((x)&0x00007ffffffff000)
|
||||
#define UnmaskPageAddr(x) SignExtendAddr(MaskPageAddr(x))
|
||||
#define SignExtendAddr(x) ((int64_t)((uint64_t)(x) << 16) >> 16)
|
||||
|
||||
struct ContiguousMemoryRanges {
|
||||
size_t i, n;
|
||||
struct ContiguousMemoryRange {
|
||||
int64_t a;
|
||||
int64_t b;
|
||||
} * p;
|
||||
};
|
||||
|
||||
void FindContiguousMemoryRanges(struct Machine *,
|
||||
struct ContiguousMemoryRanges *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_PML4T_H_ */
|
|
@ -1,118 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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. │
|
||||
│ │
|
||||
│ 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/mem/mem.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "tool/build/lib/buffer.h"
|
||||
#include "tool/build/lib/memory.h"
|
||||
#include "tool/build/lib/pml4t.h"
|
||||
|
||||
struct Pml4tFormatter {
|
||||
bool t;
|
||||
int64_t start;
|
||||
struct Buffer b;
|
||||
long lines;
|
||||
};
|
||||
|
||||
static int64_t MakeAddress(unsigned short a[4]) {
|
||||
uint64_t x;
|
||||
x = 0;
|
||||
x |= a[0];
|
||||
x <<= 9;
|
||||
x |= a[1];
|
||||
x <<= 9;
|
||||
x |= a[2];
|
||||
x <<= 9;
|
||||
x |= a[3];
|
||||
x <<= 12;
|
||||
return x;
|
||||
}
|
||||
|
||||
static void FormatStartPage(struct Pml4tFormatter *pp, int64_t start) {
|
||||
pp->t = true;
|
||||
pp->start = start;
|
||||
if (pp->lines++) AppendChar(&pp->b, '\n');
|
||||
AppendFmt(&pp->b, "%012lx-", start);
|
||||
}
|
||||
|
||||
static void FormatEndPage(struct Pml4tFormatter *pp, int64_t end) {
|
||||
int64_t size;
|
||||
pp->t = false;
|
||||
size = end - pp->start;
|
||||
AppendFmt(&pp->b, "%012lx %012lx %,ld bytes", end - 1, size, size);
|
||||
}
|
||||
|
||||
static void *GetPt(struct Machine *m, uint64_t r) {
|
||||
CHECK_LE(r + 0x1000, m->real.n);
|
||||
return m->real.p + r;
|
||||
}
|
||||
|
||||
char *FormatPml4t(struct Machine *m) {
|
||||
uint64_t *pd[4];
|
||||
unsigned short i, a[4];
|
||||
struct Pml4tFormatter pp = {0};
|
||||
unsigned short range[][2] = {{256, 512}, {0, 256}};
|
||||
if ((m->mode & 3) != XED_MODE_LONG) return strdup("");
|
||||
pd[0] = GetPt(m, m->cr3);
|
||||
for (i = 0; i < ARRAYLEN(range); ++i) {
|
||||
a[0] = range[i][0];
|
||||
do {
|
||||
a[1] = a[2] = a[3] = 0;
|
||||
if (!IsValidPage(pd[0][a[0]])) {
|
||||
if (pp.t) FormatEndPage(&pp, MakeAddress(a));
|
||||
} else {
|
||||
pd[1] = GetPt(m, UnmaskPageAddr(pd[0][a[0]]));
|
||||
do {
|
||||
a[2] = a[3] = 0;
|
||||
if (!IsValidPage(pd[1][a[1]])) {
|
||||
if (pp.t) FormatEndPage(&pp, MakeAddress(a));
|
||||
} else {
|
||||
pd[2] = GetPt(m, UnmaskPageAddr(pd[1][a[1]]));
|
||||
do {
|
||||
a[3] = 0;
|
||||
if (!IsValidPage(pd[2][a[2]])) {
|
||||
if (pp.t) FormatEndPage(&pp, MakeAddress(a));
|
||||
} else {
|
||||
pd[3] = GetPt(m, UnmaskPageAddr(pd[2][a[2]]));
|
||||
do {
|
||||
if (!IsValidPage(pd[3][a[3]])) {
|
||||
if (pp.t) FormatEndPage(&pp, MakeAddress(a));
|
||||
} else {
|
||||
if (!pp.t) {
|
||||
FormatStartPage(&pp, MakeAddress(a));
|
||||
}
|
||||
}
|
||||
} while (++a[3] != 512);
|
||||
}
|
||||
} while (++a[2] != 512);
|
||||
}
|
||||
} while (++a[1] != 512);
|
||||
}
|
||||
} while (++a[0] != range[i][1]);
|
||||
}
|
||||
if (pp.t) {
|
||||
FormatEndPage(&pp, 0x800000000000);
|
||||
}
|
||||
if (pp.b.p) {
|
||||
return xrealloc(pp.b.p, pp.b.i + 1);
|
||||
} else {
|
||||
return strdup("");
|
||||
}
|
||||
}
|
1407
tool/build/lib/pty.c
1407
tool/build/lib/pty.c
File diff suppressed because it is too large
Load diff
|
@ -1,82 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_PTY_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_PTY_H_
|
||||
#include "tool/build/lib/buffer.h"
|
||||
|
||||
#define kPtyFg 0x0001
|
||||
#define kPtyBg 0x0002
|
||||
#define kPtyBold 0x0004
|
||||
#define kPtyFlip 0x0008
|
||||
#define kPtyFaint 0x0010
|
||||
#define kPtyUnder 0x0020
|
||||
#define kPtyDunder 0x0040
|
||||
#define kPtyTrue 0x0080
|
||||
#define kPtyBlink 0x0100
|
||||
#define kPtyItalic 0x0200
|
||||
#define kPtyFraktur 0x0400
|
||||
#define kPtyStrike 0x0800
|
||||
#define kPtyConceal 0x1000
|
||||
|
||||
#define kPtyBell 0x001
|
||||
#define kPtyRedzone 0x002
|
||||
#define kPtyNocursor 0x004
|
||||
#define kPtyBlinkcursor 0x008
|
||||
#define kPtyNocanon 0x010
|
||||
#define kPtyNoecho 0x020
|
||||
#define kPtyNoopost 0x040
|
||||
#define kPtyLed1 0x080
|
||||
#define kPtyLed2 0x100
|
||||
#define kPtyLed3 0x200
|
||||
#define kPtyLed4 0x400
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct Pty {
|
||||
int y;
|
||||
int x;
|
||||
int yn;
|
||||
int xn;
|
||||
uint32_t u8;
|
||||
uint32_t n8;
|
||||
uint32_t pr;
|
||||
uint32_t fg;
|
||||
uint32_t bg;
|
||||
uint32_t conf;
|
||||
uint32_t save;
|
||||
uint32_t *wcs;
|
||||
uint32_t *prs;
|
||||
uint32_t *fgs;
|
||||
uint32_t *bgs;
|
||||
wchar_t *xlat;
|
||||
enum PtyState {
|
||||
kPtyAscii,
|
||||
kPtyUtf8,
|
||||
kPtyEsc,
|
||||
kPtyCsi,
|
||||
} state;
|
||||
struct PtyEsc {
|
||||
unsigned i;
|
||||
char s[64];
|
||||
} esc;
|
||||
struct PtyInput {
|
||||
size_t i, n;
|
||||
char *p;
|
||||
} input;
|
||||
};
|
||||
|
||||
void FreePty(struct Pty *);
|
||||
struct Pty *NewPty(void) dontdiscard;
|
||||
void PtyResize(struct Pty *, int, int);
|
||||
ssize_t PtyRead(struct Pty *, void *, size_t);
|
||||
ssize_t PtyWrite(struct Pty *, const void *, size_t);
|
||||
ssize_t PtyWriteInput(struct Pty *, const void *, size_t);
|
||||
int PtyAppendLine(struct Pty *, struct Buffer *, unsigned);
|
||||
void PtyFullReset(struct Pty *);
|
||||
void PtyMemmove(struct Pty *, long, long, long);
|
||||
void PtyErase(struct Pty *, long, long);
|
||||
void PtySetY(struct Pty *, int);
|
||||
void PtySetX(struct Pty *, int);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_PTY_H_ */
|
|
@ -1,28 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_PUN_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_PUN_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
union FloatPun {
|
||||
float f;
|
||||
uint32_t i;
|
||||
};
|
||||
|
||||
union DoublePun {
|
||||
double f;
|
||||
uint64_t i;
|
||||
};
|
||||
|
||||
union FloatVectorPun {
|
||||
union FloatPun u[4];
|
||||
float f[4];
|
||||
};
|
||||
|
||||
union DoubleVectorPun {
|
||||
union DoublePun u[2];
|
||||
double f[2];
|
||||
};
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_PUN_H_ */
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue