Add x86_64-linux-gnu emulator

I wanted a tiny scriptable meltdown proof way to run userspace programs
and visualize how program execution impacts memory. It helps to explain
how things like Actually Portable Executable works. It can show you how
the GCC generated code is going about manipulating matrices and more. I
didn't feel fully comfortable with Qemu and Bochs because I'm not smart
enough to understand them. I wanted something like gVisor but with much
stronger levels of assurances. I wanted a single binary that'll run, on
all major operating systems with an embedded GPL barrier ZIP filesystem
that is tiny enough to transpile to JavaScript and run in browsers too.

https://justine.storage.googleapis.com/emulator625.mp4
This commit is contained in:
Justine Tunney 2020-08-25 04:23:25 -07:00
parent 467504308a
commit f4f4caab0e
1052 changed files with 65667 additions and 7825 deletions

View file

@ -7,13 +7,16 @@ TOOL_BUILD_FILES := $(wildcard tool/build/*)
TOOL_BUILD_SRCS = $(filter %.c,$(TOOL_BUILD_FILES))
TOOL_BUILD_HDRS = $(filter %.h,$(TOOL_BUILD_FILES))
TOOL_BUILD_CTESTS = $(filter %.ctest,$(TOOL_BUILD_FILES))
TOOL_BUILD_COMS = $(TOOL_BUILD_OBJS:%.o=%.com)
TOOL_BUILD_BINS = $(TOOL_BUILD_COMS) $(TOOL_BUILD_COMS:%=%.dbg)
TOOL_BUILD_CALCULATOR = o/$(MODE)/tool/build/calculator.com
TOOL_BUILD_OBJS = \
$(TOOL_BUILD_SRCS:%=o/$(MODE)/%.zip.o) \
$(TOOL_BUILD_SRCS:%.c=o/$(MODE)/%.o)
TOOL_BUILD_COMS = \
$(TOOL_BUILD_SRCS:%.c=o/$(MODE)/%.com)
TOOL_BUILD_LINK = \
$(TOOL_BUILD_DEPS) \
o/$(MODE)/tool/build/%.o \
@ -68,6 +71,13 @@ o/$(MODE)/tool/build/build.pkg: \
$(TOOL_BUILD_OBJS) \
$(foreach x,$(TOOL_BUILD_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/%.ctest.ok: \
%.ctest \
$(TOOL_BUILD_CALCULATOR)
@TARGET=$@ ACTION=MKWIDES build/do \
$(TOOL_BUILD_CALCULATOR) $< && \
touch $@
o/$(MODE)/tool/build/%.com.dbg: \
$(TOOL_BUILD_DEPS) \
o/$(MODE)/tool/build/build.pkg \
@ -79,18 +89,14 @@ o/$(MODE)/tool/build/%.com.dbg: \
o/$(MODE)/tool/build/mkdeps.o: tool/build/mkdeps.c
-@ACTION=OBJECTIFY.c build/compile $(OBJECTIFY.c) $(OUTPUT_OPTION) $<
o/$(MODE)/tool/build/generatematrix.o \
o/$(MODE)/tool/build/mkdeps.o: \
o/$(MODE)/tool/build/emulator.o: \
OVERRIDE_COPTS += \
-O2
o/$(MODE)/%.ctest.ok: %.ctest o/$(MODE)/tool/build/calculator.com
@TARGET=$@ ACTION=MKWIDES build/do \
o/$(MODE)/tool/build/calculator.com $< && \
touch $@
-fno-sanitize=pointer-overflow
.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)

View file

@ -18,6 +18,7 @@
#include "libc/conv/itoa.h"
#include "libc/dce.h"
#include "libc/fmt/fmt.h"
#include "libc/limits.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/math.h"
@ -30,6 +31,7 @@
#include "libc/sysv/consts/exit.h"
#include "libc/sysv/consts/sig.h"
#include "libc/tinymath/emodl.h"
#include "libc/x/x.h"
#include "third_party/dtoa/dtoa.h"
#include "third_party/getopt/getopt.h"
@ -112,6 +114,11 @@ enum Severity {
kWarning,
};
enum Exception {
kUnderflow = 1,
kDivideError,
};
struct Bytes {
size_t i, n;
char *p;
@ -139,8 +146,8 @@ struct Function {
const char *doc;
};
jmp_buf thrower;
const char *file;
jmp_buf underflow;
struct Bytes token;
struct History history;
struct Value stack[128];
@ -200,6 +207,14 @@ void Log(enum Severity l, const char *fmt, ...) {
if (interactive) ShowStack();
}
void __on_arithmetic_overflow(void) {
Warning("arithmetic overflow");
}
void OnDivideError(void) {
longjmp(thrower, kDivideError);
}
struct Value Push(struct Value x) {
if (sp >= ARRAYLEN(stack)) Fatal("stack overflow");
return (stack[sp++] = x);
@ -209,7 +224,7 @@ struct Value Pop(void) {
if (sp) {
return stack[--sp];
} else {
longjmp(underflow, 1);
longjmp(thrower, kUnderflow);
}
}
@ -240,10 +255,39 @@ void Pushf(FLOAT f) {
void OpDrop(void) {
Pop();
}
void OpDup(void) {
Push(Push(Pop()));
}
void OpExit(void) {
exit(Popi());
}
void OpSrand(void) {
srand(Popi());
}
void OpEmit(void) {
fputwc(Popi(), stdout);
}
void OpCr(void) {
Cr(stdout);
}
void OpPrint(void) {
printf("%s ", Repr(Pop()));
}
void OpComment(void) {
comment = true;
}
void Glue0f(FLOAT fn(void)) {
Pushf(fn());
}
void Glue0i(INT fn(void)) {
Pushi(fn());
}
void Glue1f(FLOAT fn(FLOAT)) {
Pushf(fn(Popf()));
}
void Glue1i(INT fn(INT)) {
Pushi(fn(Popi()));
}
void OpSwap(void) {
struct Value a, b;
@ -262,10 +306,6 @@ void OpOver(void) {
Push(a);
}
void OpSrand(void) {
srand(Popi());
}
void OpKey(void) {
wint_t c;
ttyraw(kTtyCursor | kTtySigs | kTtyLfToCrLf);
@ -274,22 +314,6 @@ void OpKey(void) {
if (c != -1) Pushi(c);
}
void OpEmit(void) {
fputwc(Popi(), stdout);
}
void OpCr(void) {
Cr(stdout);
}
void OpPrint(void) {
printf("%s ", Repr(Pop()));
}
void OpComment(void) {
comment = true;
}
void OpAssert(void) {
if (!Popi()) Fatal("assert failed");
}
@ -298,30 +322,11 @@ void OpExpect(void) {
if (!Popi()) Warning("expect failed");
}
void OpExit(void) {
exit(Popi());
}
void OpMeminfo(void) {
OpCr();
OpCr();
meminfo(stdout);
}
void Glue0f(FLOAT fn(void)) {
Pushf(fn());
}
void Glue0i(INT fn(void)) {
Pushi(fn());
}
void Glue1f(FLOAT fn(FLOAT)) {
Pushf(fn(Popf()));
}
void Glue1i(INT fn(INT)) {
Pushi(fn(Popi()));
fflush(stdout);
meminfo(fileno(stdout));
}
void Glue2f(FLOAT fn(FLOAT, FLOAT)) {
@ -438,18 +443,25 @@ bool ConsumeLiteral(const char *literal) {
}
void ConsumeToken(void) {
enum Exception ex;
if (!token.i) return;
token.p[token.i] = 0;
token.i = 0;
if (history.i) history.p[history.i - 1].i = 0;
if (comment) return;
if (startswith(token.p, "#!")) return;
if (!setjmp(underflow)) {
if (CallFunction(token.p)) return;
if (ConsumeLiteral(token.p)) return;
Warning("bad token: %s", token.p);
} else {
Warning("stack underflow");
switch (setjmp(thrower)) {
default:
if (CallFunction(token.p)) return;
if (ConsumeLiteral(token.p)) return;
Warning("bad token: %s", token.p);
break;
case kUnderflow:
Warning("stack underflow");
break;
case kDivideError:
Warning("divide error");
break;
}
}
@ -549,16 +561,12 @@ void GotoStartOfLine(void) {
void GotoEndOfLine(void) {
}
void GotoPrevLine(void) {
}
void GotoNextLine(void) {
}
void GotoPrevChar(void) {
}
void GotoNextChar(void) {
}
@ -694,7 +702,9 @@ void GetOpts(int argc, char *argv[]) {
int main(int argc, char *argv[]) {
int i, rc;
showcrashreports();
GetOpts(argc, argv);
xsigaction(SIGFPE, OnDivideError, 0, 0, 0);
if (optind == argc) {
file = "/dev/stdin";
StartInteractive();

View file

@ -37,6 +37,8 @@ M(2, g, "rem", Remainder, remainderl(x, y), "float remainder")
M(0, i, "false", False, 0, "0")
M(0, i, "true", True, 1, "1")
M(0, i, "intmin", IntMin, INT128_MIN, "native integer minimum")
M(0, i, "intmax", IntMax, INT128_MAX, "native integer maximum")
M(0, f, "e", Euler, M_E, "𝑒")
M(0, f, "pi", Fldpi, fldpi(), "π")
M(0, f, "epsilon", Epsilon, EPSILON, "ɛ")
@ -54,7 +56,7 @@ M(1, g, "exp2", Exp2, exp2l(x), "2ˣ")
M(1, g, "exp10", Exp10, exp10l(x), "10ˣ")
M(2, g, "ldexp", Ldexp, ldexpl(x, y), "𝑥×")
M(2, f, "log", Log, logl(x), "logₑ𝑥")
M(1, f, "log", Log, logl(x), "logₑ𝑥")
M(1, g, "log2", Log2, log2l(x), "log₂𝑥")
M(1, g, "log10", Log10, log10l(x), "log₁₀𝑥")

View file

@ -0,0 +1,55 @@
#-*-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:%=o/$(MODE)/%.zip.o) \
$(TOOL_BUILD_EMUBIN_SRCS:%.c=o/$(MODE)/%.o)
TOOL_BUILD_EMUBIN_CHECKS = \
$(TOOL_BUILD_EMUBIN_HDRS:%=o/$(MODE)/%.ok)
TOOL_BUILD_EMUBIN_DIRECTDEPS = \
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 max-page-size=0x10
.PHONY: o/$(MODE)/tool/build/emubin
o/$(MODE)/tool/build/emubin: \
$(TOOL_BUILD_EMUBIN_BINS) \
$(TOOL_BUILD_EMUBIN_CHECKS)

View file

@ -0,0 +1,156 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/xmmintrin.h"
#include "libc/intrin/repstosb.h"
#include "tool/build/emubin/metalsha256.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);
}

View file

@ -0,0 +1,19 @@
#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_ */

50
tool/build/emubin/mips.c Normal file
View file

@ -0,0 +1,50 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "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 < 1400 * 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;
}

56
tool/build/emubin/pi.c Normal file
View file

@ -0,0 +1,56 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/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;
}

42
tool/build/emubin/prime.c Normal file
View file

@ -0,0 +1,42 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
noinline 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;
}

View file

@ -0,0 +1,53 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "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;
}

View file

@ -0,0 +1,34 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
cmpxchg %ecx,(%rdx)
.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

View file

@ -0,0 +1,81 @@
/*-*- 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 │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
ENTRY(_start)
SECTIONS {
.text : {
*(.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)
*(.*)
}
}

View file

@ -0,0 +1,12 @@
#-*-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 \
tool/build/emucrt/emucrt.lds
.PHONY: o/$(MODE)/tool/build/emucrt
o/$(MODE)/tool/build/emucrt: \
o/$(MODE)/tool/build/emucrt/emucrt.o

1480
tool/build/emulator.c Normal file

File diff suppressed because it is too large Load diff

372
tool/build/helpop.c Normal file
View file

@ -0,0 +1,372 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/safemacros.h"
#include "libc/conv/conv.h"
#include "libc/macros.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/exit.h"
#include "third_party/getopt/getopt.h"
#define USAGE \
" [FLAGS] OPERAND..\n\
Decodes geek operand notation used by ref.x86asm.net\n\
\n\
Flags:\n\
-s succinct mode\n\
-b BITS sets 16/32/64 bit mode [default 64]\n\
-? shows this information\n\
\n\
Examples:\n\
o/tool/cpu/help-operand -b64 Evqp\n\
\n"
int bits_;
bool succinct_;
void PrintUsage(int rc, FILE *f) {
fputs("Usage: ", f);
fputs(program_invocation_name, f);
fputs(USAGE, f);
exit(rc);
}
void GetOpts(int argc, char *argv[]) {
int opt;
bits_ = 64;
while ((opt = getopt(argc, argv, "?hbs")) != -1) {
switch (opt) {
case 's':
succinct_ = true;
break;
case 'b':
bits_ = atoi(optarg);
break;
case '?':
case 'h':
PrintUsage(EXIT_SUCCESS, stdout);
default:
PrintUsage(EX_USAGE, stderr);
}
}
}
const struct Descriptors {
const char prefix[8];
const char *succinct;
const char *description;
} kDescriptors[] = {
{"AL", "AL", "AL register"},
{"CS", "CS", "CS register (code segment)"},
{"va", "?",
"Word or doubleword, according to asz address-size attribute (only REP "
"and LOOP families)."},
{"dqa", "?",
"Doubleword or quadword, according to asz address-size attribute (only "
"REP and LOOP families)."},
{"wa", "?",
"Word, according to asz address-size attribute (only JCXZ instruction)."},
{"wo", "?",
"Word, according to current operand size (e. g., MOVSW instruction)."},
{"ws", "?",
"Word, according to current stack size (only PUSHF and POPF instructions "
"in 64-bit mode)."},
{"da", "?",
"Doubleword, according to asz address-size attribute (only JECXZ "
"instruction)."},
{"do", "?",
"Doubleword, according to current osz operand size (e. g., MOVSD "
"instruction)."},
{"qa", "?",
"Quadword, according to asz address-size attribute (only JRCXZ "
"instruction)."},
{"qs", "64/16",
"Quadword, according to current stack size via osz operand-size (only "
"PUSHFQ and POPFQ instructions)."},
{"va", "16/32",
"Word or doubleword sign extended to the size of the stack pointer (for "
"example, PUSH (68))."},
{"vqp", "16/32/64",
"Word or doubleword, depending on operand-size attribute, or "
"quadword, promoted by REX.W in 64-bit mode."},
{"vs", "16/32",
"Word or doubleword sign extended to the size of the stack pointer (for "
"example, PUSH (68))."},
{"vds", "16/32",
"Word or doubleword, depending on operand-size attribute, or doubleword, "
"sign-extended to 64 bits for 64-bit operand size."},
{"vq", "64/16",
"Quadword (default) or word if operand-size prefix is used (for "
"example, PUSH (50))."},
{"EST", "STi",
"A ModR/M byte follows the opcode and specifies the x87 FPU stack "
"register."},
{"ES", "STi/m",
"A ModR/M byte follows the opcode and specifies the operand. The "
"operand is either a x87 FPU stack register or a memory address. If "
"it is a memory address, the address is computed from a segment "
"register and any of the following values: a base register, an "
"index register, a scaling factor, or a displacement."},
{"SC", "",
"Stack operand, used by instructions which either push an operand to the "
"stack or pop an operand from the stack. Pop-like instructions are, for "
"example, POP, RET, IRET, LEAVE. Push-like are, for example, PUSH, CALL, "
"INT. No Operand type is provided along with this method because it "
"depends on source/destination operand(s)."},
{"BA", "m",
"Memory addressed by DS:EAX, or by rAX in 64-bit mode (only 0F01C8 "
"MONITOR)."},
{"BB", "m",
"Memory addressed by DS:eBX+AL, or by rBX+AL in 64-bit mode (only XLAT)."},
{"BD", "m",
"Memory addressed by DS:eDI or by RDI (only 0FF7 MASKMOVQ and 660FF7 "
"MASKMOVDQU)"},
{"A", "ptr",
"Direct address. The instruction has no ModR/M byte; the address of the "
"operand is encoded in the instruction; no base register, index register, "
"or scaling factor can be applied (for example, far JMP (EA))."},
{"C", "CRn",
"The reg field of the ModR/M byte selects a control register (only MOV "
"(0F20, 0F22))."},
{"D", "DRn",
"The reg field of the ModR/M byte selects a debug register (only MOV "
"(0F21, 0F23))."},
{"I", "imm",
"Immediate data. The operand value is encoded in subsequent bytes of the "
"instruction."},
{"J", "rel",
"The instruction contains a relative offset to be added to the "
"instruction pointer register (for example, JMP (E9), LOOP))."},
{"E", "r/m",
"A ModR/M byte follows the opcode and specifies the operand. The "
"operand is either a general-purpose register or a memory address. "
"If it is a memory address, the address is computed from a segment "
"register and any of the following values: a base register, an index "
"register, a scaling factor, or a displacement."},
{"G", "r",
"The reg field of the ModR/M byte selects a general register (for "
"example, AX (000))."},
{"H", "r",
"The r/m field of the ModR/M byte always selects a general register, "
"regardless of the mod field (for example, MOV (0F20))."},
{"M", "rm",
"The ModR/M byte may refer only to memory: mod != 11bin (BOUND, LEA, "
"CALLF, JMPF, LES, LDS, LSS, LFS, LGS, CMPXCHG8B, CMPXCHG16B, F20FF0 "
"LDDQU)."},
{"N", "mm",
"The R/M field of the ModR/M byte selects a packed quadword MMX "
"technology register."},
{"O", "moffs",
"The instruction has no ModR/M byte; the offset of the operand is coded "
"as a word, double word or quad word (depending on address size "
"attribute) in the instruction. No base register, index register, or "
"scaling factor can be applied (only MOV (A0, A1, A2, A3))."},
{"P", "mm",
"The reg field of the ModR/M byte selects a packed quadword MMX "
"technology register."},
{"Q", "mm/m64",
"A ModR/M byte follows the opcode and specifies the operand. The "
"operand is either an MMX technology register or a memory address. "
"If it is a memory address, the address is computed from a segment "
"register and any of the following values: a base register, an index "
"register, a scaling factor, and a displacement."},
{"R", "r",
"The mod field of the ModR/M byte may refer only to a general "
"register (only MOV (0F20-0F24, 0F26))."},
{"S", "Sreg",
"The reg field of the ModR/M byte selects a segment register (only MOV "
"(8C, 8E))."},
{"T", "TRn",
"The reg field of the ModR/M byte selects a test register (only MOV "
"(0F24, 0F26))."},
{"U", "xmm",
"The R/M field of the ModR/M byte selects a 128-bit XMM register."},
{"sr", "32real",
"Single-real. Only x87 FPU instructions (for example, FADD)."},
{"dr", "64real",
"Double-real. Only x87 FPU instructions (for example, FADD)."},
{"er", "80real",
"Extended-real. Only x87 FPU instructions (for example, FLD)."},
{"e", "14/28", "x87 FPU environment (for example, FSTENV)."},
{"V", "xmm",
"The reg field of the ModR/M byte selects a 128-bit XMM register."},
{"W", "xmm/m",
"A ModR/M byte follows the opcode and specifies the operand. The operand "
"is either a 128-bit XMM register or a memory address. If it is a memory "
"address, the address is computed from a segment register and any of the "
"following values: a base register, an index register, a scaling factor, "
"and a displacement"},
{"X", "m",
"Memory addressed by the DS:eSI or by RSI (only MOVS, CMPS, OUTS, "
"and LODS). In 64-bit mode, only 64-bit (RSI) and 32-bit (ESI) "
"address sizes are supported. In non-64-bit modes, only 32-bit (ESI) "
"and 16-bit (SI) address sizes are supported."},
{"Y", "m",
"Memory addressed by the ES:eDI or by RDI (only MOVS, CMPS, INS, "
"STOS, and SCAS). In 64-bit mode, only 64-bit (RDI) and 32-bit (EDI) "
"address sizes are supported. In non-64-bit modes, only 32-bit (EDI) "
"and 16-bit (DI) address sizes are supported. The implicit ES "
"segment register cannot be overriden by a segment prefix."},
{"Z", "r",
"The instruction has no ModR/M byte; the three least-significant "
"bits of the opcode byte selects a general-purpose register."},
{"F", "-", "rFLAGS register."},
{"si", "32real",
"Doubleword integer register (e. g., eax). (unused even by Intel?)"},
{"ss", "-",
"Scalar element of a 128-bit packed single-precision floating data."},
{"stx", "512", "x87 FPU and SIMD state (FXSAVE and FXRSTOR)."},
{"st", "94/108", "x87 FPU state (for example, FSAVE)."},
{"s", "-",
"6-byte pseudo-descriptor, or 10-byte pseudo-descriptor in 64-bit mode "
"(for example, SGDT)."},
{"bcd", "80dec",
"Packed-BCD. Only x87 FPU instructions (for example, FBLD)."},
{"bsq", "", "(Byte, sign-extended to 64 bits.)"},
{"bss", "8",
"Byte, sign-extended to the size of the stack pointer (for example, PUSH "
"(6A))."},
{"bs", "8", "Byte, sign-extended to the size of the destination operand."},
{"a", "16/32&16/32",
"Two one-word operands in memory or two double-word operands in memory, "
"depending on operand-size attribute (only BOUND)."},
{"b", "8", "Byte, regardless of operand-size attribute."},
{"c", "?",
"Byte or word, depending on operand-size attribute. (unused even by "
"Intel?)"},
{"dqp", "32/64",
"Doubleword, or quadword, promoted by REX.W in 64-bit mode (for example, "
"MOVSXD)."},
{"dq", "128",
"Double-quadword, regardless of operand-size attribute (for example, "
"CMPXCHG16B)."},
{"ds", "32",
"Doubleword, sign-extended to 64 bits (for example, CALL (E8)."},
{"di", "32int",
"Doubleword-integer. Only x87 FPU instructions (for example, FIADD)."},
{"d", "32", "Doubleword, regardless of operand-size attribute."},
{"qi", "64int",
"Qword-integer. Only x87 FPU instructions (for example, FILD)."},
{"qp", "64", "Quadword, promoted by REX.W (for example, IRETQ)."},
{"q", "64",
"Quadword, regardless of operand-size attribute (for example, CALL (FF "
"/2))."},
{"v", "16/32",
"Word or doubleword, depending on operand-size attribute (for example, "
"INC (40), PUSH (50))."},
{"wi", "16int",
"Word-integer. Only x87 FPU instructions (for example, FIADD)."},
{"w", "16",
"Word, regardless of operand-size attribute (for example, ENTER)."},
{"pi", "-", "Quadword MMX technology data."},
{"psq", "-", "64-bit packed single-precision floating-point data."},
{"pd", "-", "128-bit packed double-precision floating-point data."},
{"ps", "-", "128-bit packed single-precision floating-point data."},
{"ptp", "16:16/32/64",
"32-bit or 48-bit pointer, depending on operand-size attribute, or 80-bit "
"far pointer, promoted by REX.W in 64-bit mode (for example, "
"CALLF (FF /3))."},
{"p", "16:16/32",
"32-bit or 48-bit pointer, depending on operand-size attribute (for "
"example, CALLF (9A)."},
};
void HandleOperand(const char *op) {
int i;
bool found;
while (*op) {
found = false;
for (i = 0; i < ARRAYLEN(kDescriptors); ++i) {
if (startswith(op, kDescriptors[i].prefix)) {
found = true;
op += strlen(kDescriptors[i].prefix);
if (succinct_) {
printf("%s ", kDescriptors[i].succinct);
} else if (!isempty(kDescriptors[i].succinct) &&
strcmp(kDescriptors[i].succinct, "-") != 0 &&
strcmp(kDescriptors[i].succinct, "?") != 0) {
printf("%s (%s): %s\n", kDescriptors[i].prefix,
kDescriptors[i].succinct, kDescriptors[i].description);
} else {
printf("%s: %s\n", kDescriptors[i].prefix,
kDescriptors[i].description);
}
break;
}
}
if (!found) {
printf("%c?", *op);
if (succinct_) {
printf(" ");
} else {
printf("\n");
}
op++;
}
}
printf("\n");
}
int main(int argc, char *argv[]) {
int i;
GetOpts(argc, argv);
for (i = optind; i < argc; ++i) {
HandleOperand(argv[i]);
}
return 0;
}

9
tool/build/lib/abp.h Normal file
View file

@ -0,0 +1,9 @@
#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_ */

81
tool/build/lib/alu.c Normal file
View file

@ -0,0 +1,81 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "tool/build/lib/alu.h"
#include "tool/build/lib/flags.h"
/**
* NexGen32e Arithmetic Unit.
*/
int64_t Alu(int w, int h, uint64_t x, uint64_t y, uint32_t *flags) {
bool zf, sf, c, o, cf;
uint64_t t, z, s, m, k;
assert(w < 4);
k = 8;
k <<= w;
s = 1;
s <<= k - 1;
m = s;
m |= s - 1;
t = x;
c = 0;
o = 0;
cf = GetFlag(*flags, FLAGS_CF);
switch (h & 7) {
case ALU_OR:
z = x | y;
break;
case ALU_AND:
z = x & y;
break;
case ALU_XOR:
z = x ^ y;
break;
case ALU_CMP:
h |= 8;
cf = 0;
case ALU_SBB:
t = (x & m) - cf;
c = (x & m) < (t & m);
case ALU_SUB:
z = (t & m) - (y & m);
c |= (t & m) < (z & m);
o = !!((z ^ x) & (x ^ y) & s);
break;
case ALU_ADC:
t = (x & m) + cf;
c = (t & m) < (x & m);
case ALU_ADD:
z = (t & m) + (y & m);
c |= (z & m) < (y & m);
o = !!((z ^ x) & (z ^ y) & s);
break;
default:
unreachable;
}
z &= m;
zf = !z;
sf = !!(z & s);
*flags &= ~(1 << FLAGS_CF | 1 << FLAGS_ZF | 1 << FLAGS_SF | 1 << FLAGS_OF);
*flags |= c << FLAGS_CF | zf << FLAGS_ZF | sf << FLAGS_SF | o << FLAGS_OF;
*flags = SetLazyParityByte(*flags, x);
if (h & ALU_TEST) z = x;
return z;
}

43
tool/build/lib/alu.h Normal file
View file

@ -0,0 +1,43 @@
#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_TEST 8
#define ALU_FLIP 16
#define ALU_XCHG 64
#define ALU_BYTE 128
#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 uint64_t (*aluop1_f)(struct Machine *, uint64_t);
typedef uint64_t (*aluop2_f)(struct Machine *, uint64_t, uint64_t);
int64_t Alu(int, int, uint64_t, uint64_t, uint32_t *);
int64_t Bsu(int, int, uint64_t, uint64_t, uint32_t *);
uint64_t AluBt(struct Machine *, uint64_t, uint64_t);
uint64_t AluBtc(struct Machine *, uint64_t, uint64_t);
uint64_t AluBtr(struct Machine *, uint64_t, uint64_t);
uint64_t AluBts(struct Machine *, uint64_t, uint64_t);
uint64_t BsuDoubleShift(int, uint64_t, uint64_t, uint8_t, bool, uint32_t *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_ALU_H_ */

82
tool/build/lib/argv.c Normal file
View file

@ -0,0 +1,82 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/arraylist2.h"
#include "libc/assert.h"
#include "libc/bits/popcnt.h"
#include "libc/bits/safemacros.h"
#include "libc/log/check.h"
#include "libc/mem/mem.h"
#include "libc/runtime/gc.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/auxv.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);
}

80
tool/build/lib/bitscan.c Normal file
View file

@ -0,0 +1,80 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "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 AluBsr(struct Machine *m, uint64_t _, uint64_t x) {
unsigned i;
if (Rexw(m->xedd)) {
x &= 0xffffffffffffffff;
m->flags = SetFlag(m->flags, FLAGS_ZF, !x);
if (!x) return 0;
return 63 ^ __builtin_clzll(x);
} else if (!Osz(m->xedd)) {
x &= 0xffffffff;
m->flags = SetFlag(m->flags, FLAGS_ZF, !x);
if (!x) return 0;
return 31 ^ __builtin_clz(x);
} else {
x &= 0xffff;
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, uint64_t _, uint64_t x) {
unsigned i;
if (Rexw(m->xedd)) {
x &= 0xffffffffffffffff;
m->flags = SetFlag(m->flags, FLAGS_ZF, !x);
if (!x) return 0;
return __builtin_ctzll(x);
} else if (!Osz(m->xedd)) {
x &= 0xffffffff;
m->flags = SetFlag(m->flags, FLAGS_ZF, !x);
if (!x) return 0;
return __builtin_ctz(x);
} else {
x &= 0xffff;
m->flags = SetFlag(m->flags, FLAGS_ZF, !x);
if (!x) return 0;
for (i = 0; !(x & 1); ++i) x >>= 1;
return i;
}
}
uint64_t AluPopcnt(struct Machine *m, uint64_t _, 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;
}

13
tool/build/lib/bitscan.h Normal file
View file

@ -0,0 +1,13 @@
#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_
uint64_t AluBsr(struct Machine *, uint64_t, uint64_t);
uint64_t AluBsf(struct Machine *, uint64_t, uint64_t);
uint64_t AluPopcnt(struct Machine *, uint64_t, uint64_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_BITSCAN_H_ */

View file

@ -0,0 +1,50 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/arraylist2.h"
#include "libc/assert.h"
#include "tool/build/lib/breakpoint.h"
ssize_t AddBreakpoint(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;
}

View file

@ -0,0 +1,21 @@
#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 AddBreakpoint(struct Breakpoints *, struct Breakpoint *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_BREAKPOINT_H_ */

167
tool/build/lib/bsu.c Normal file
View file

@ -0,0 +1,167 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/dce.h"
#include "libc/macros.h"
#include "tool/build/lib/alu.h"
#include "tool/build/lib/endian.h"
#include "tool/build/lib/flags.h"
#include "tool/build/lib/modrm.h"
/**
* NexGen32e Bit Shift Unit.
*/
int64_t Bsu(int w, int h, uint64_t x, uint64_t y, uint32_t *f) {
bool of;
uint64_t s, k, t, xm, ym, cf;
assert(w < 4);
k = 8;
k <<= w;
s = 1;
s <<= k - 1;
xm = s;
xm |= s - 1;
ym = w == 3 ? 0x3F : 0x1F;
switch (h & 7) {
case BSU_SHR:
x &= xm;
if ((y &= ym)) {
*f = SetFlag(*f, FLAGS_CF, !!(x & (1ull << (y - 1))));
x = x >> y;
*f = SetLazyParityByte(*f, x);
*f = SetFlag(*f, FLAGS_OF, !!(((x << 1) ^ x) & s));
*f = SetFlag(*f, FLAGS_ZF, !x);
*f = SetFlag(*f, FLAGS_SF, !!(x & s));
}
return x;
case BSU_SAL:
case BSU_SHL:
x &= xm;
if ((y &= ym)) {
*f = SetFlag(*f, FLAGS_CF, (cf = !!(x & (1ull << ((k - y) & ym)))));
x = (x << y) & xm;
*f = SetLazyParityByte(*f, x);
*f = SetFlag(*f, FLAGS_OF, !!(x & s) ^ cf);
*f = SetFlag(*f, FLAGS_ZF, !x);
*f = SetFlag(*f, FLAGS_SF, !!(x & s));
}
return x;
case BSU_SAR:
x &= xm;
if ((y &= ym)) {
x &= xm;
t = !!(x & s);
x >>= (y - 1);
if (t) x |= ~(xm >> (y - 1));
*f = SetFlag(*f, FLAGS_CF, x & 1);
x >>= 1;
if (t) x = (x | ~(xm >> y)) & xm;
*f = SetLazyParityByte(*f, x);
*f = SetFlag(*f, FLAGS_OF, 0);
*f = SetFlag(*f, FLAGS_ZF, !x);
*f = SetFlag(*f, FLAGS_SF, !!(x & s));
}
return x;
case BSU_ROL:
x &= xm;
if (y & (k - 1)) {
y &= k - 1;
x = (x << y | x >> (k - y)) & xm;
*f = SetFlag(*f, FLAGS_CF, x & 1);
*f = SetFlag(*f, FLAGS_OF, ((x >> (k - 1)) ^ x) & 1);
} else if (y & 0x1F) {
*f = SetFlag(*f, FLAGS_CF, x & 1);
*f = SetFlag(*f, FLAGS_OF, ((x >> (k - 1)) ^ x) & 1);
}
return x;
case BSU_ROR:
x &= xm;
if (y & (k - 1)) {
y &= k - 1;
x = (x >> y | x << (k - y)) & xm;
*f = SetFlag(*f, FLAGS_CF, (x >> (k - 1)) & 1);
*f = SetFlag(*f, FLAGS_OF, ((x >> (k - 2)) ^ (x >> (k - 1))) & 1);
} else if (y & 0x1F) {
*f = SetFlag(*f, FLAGS_CF, (x >> (k - 1)) & 1);
*f = SetFlag(*f, FLAGS_OF, ((x >> (k - 2)) ^ (x >> (k - 1))) & 1);
}
return x;
case BSU_RCR:
x &= xm;
if ((y = (y & ym) % (k + 1))) {
cf = GetFlag(*f, FLAGS_CF);
*f = SetFlag(*f, FLAGS_CF, (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;
}
*f = SetFlag(*f, FLAGS_OF, (((x << 1) ^ x) >> (k - 1)) & 1);
}
return x;
case BSU_RCL:
x &= xm;
if ((y = (y & ym) % (k + 1))) {
cf = GetFlag(*f, FLAGS_CF);
*f = SetFlag(*f, FLAGS_CF, (t = (x >> (k - y)) & 1));
if (y == 1) {
x = (x << 1 | cf) & xm;
} else {
x = (x << y | cf << (y - 1) | x >> (k + 1 - y)) & xm;
}
*f = SetFlag(*f, FLAGS_OF, t ^ !!(x & s));
}
return x;
default:
unreachable;
}
}
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;
*f = SetFlag(*f, FLAGS_CF, cf);
*f = SetFlag(*f, FLAGS_OF, of);
*f = SetFlag(*f, FLAGS_ZF, !x);
*f = SetFlag(*f, FLAGS_SF, !!(x & s));
*f = SetLazyParityByte(*f, x & 0xff);
}
return x;
}

68
tool/build/lib/buffer.c Normal file
View file

@ -0,0 +1,68 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/arraylist2.h"
#include "libc/calls/calls.h"
#include "libc/fmt/fmt.h"
#include "libc/mem/mem.h"
#include "libc/str/tpencode.h"
#include "tool/build/lib/buffer.h"
void AppendChar(struct Buffer *b, char c) {
APPEND(&b->p, &b->i, &b->n, &c);
}
void AppendData(struct Buffer *b, char *data, size_t len) {
CONCAT(&b->p, &b->i, &b->n, data, len);
}
void AppendStr(struct Buffer *b, const char *s) {
AppendData(b, s, strlen(s));
}
void AppendWide(struct Buffer *b, wint_t wc) {
char cbuf[8];
AppendData(b, cbuf, tpencode(cbuf, 8, wc, false));
}
void AppendFmt(struct Buffer *b, const char *fmt, ...) {
int size;
char *tmp;
va_list va;
tmp = NULL;
va_start(va, fmt);
size = vasprintf(&tmp, fmt, va);
va_end(va);
if (size != -1) AppendData(b, tmp, size);
free(tmp);
}
/**
* Writes buffer until completion, interrupt, or error occurs.
*/
ssize_t WriteBuffer(struct Buffer *b, int fd) {
size_t i;
ssize_t rc;
for (i = 0; i < b->i; i += rc) {
if ((rc = write(fd, b->p + i, b->i - i)) == -1) {
return -1;
}
}
return i;
}

20
tool/build/lib/buffer.h Normal file
View file

@ -0,0 +1,20 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_BUFFER_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_BUFFER_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct Buffer {
size_t i, n;
char *p;
};
void AppendChar(struct Buffer *, char);
void AppendData(struct Buffer *, char *, size_t);
void AppendStr(struct Buffer *, const char *);
void AppendWide(struct Buffer *, wint_t);
void AppendFmt(struct Buffer *, const char *, ...);
ssize_t WriteBuffer(struct Buffer *, int);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_BUFFER_H_ */

View file

@ -10,7 +10,10 @@ TOOL_BUILD_LIB_A_FILES := $(wildcard tool/build/lib/*)
TOOL_BUILD_LIB_A_HDRS = $(filter %.h,$(TOOL_BUILD_LIB_A_FILES))
TOOL_BUILD_LIB_A_SRCS_S = $(filter %.S,$(TOOL_BUILD_LIB_A_FILES))
TOOL_BUILD_LIB_A_SRCS_C = $(filter %.c,$(TOOL_BUILD_LIB_A_FILES))
TOOL_BUILD_LIB_A_CHECKS = $(TOOL_BUILD_LIB_A).pkg
TOOL_BUILD_LIB_A_CHECKS = \
$(TOOL_BUILD_LIB_A_HDRS:%=o/$(MODE)/%.ok) \
$(TOOL_BUILD_LIB_A).pkg
TOOL_BUILD_LIB_A_SRCS = \
$(TOOL_BUILD_LIB_A_SRCS_S) \
@ -22,17 +25,30 @@ TOOL_BUILD_LIB_A_OBJS = \
$(TOOL_BUILD_LIB_A_SRCS_C:%.c=o/$(MODE)/%.o)
TOOL_BUILD_LIB_A_DIRECTDEPS = \
LIBC_ALG \
LIBC_BITS \
LIBC_CONV \
LIBC_CALLS \
LIBC_CALLS_HEFTY \
LIBC_ELF \
LIBC_FMT \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_STUBS \
LIBC_INTRIN \
LIBC_SYSV \
LIBC_SYSV_CALLS \
LIBC_TIME \
LIBC_LOG \
LIBC_X
LIBC_STR \
LIBC_SOCK \
LIBC_UNICODE \
LIBC_STDIO \
LIBC_X \
LIBC_TINYMATH \
THIRD_PARTY_COMPILER_RT \
THIRD_PARTY_XED
TOOL_BUILD_LIB_A_DEPS := \
$(call uniq,$(foreach x,$(TOOL_BUILD_LIB_A_DIRECTDEPS),$($(x))))

11
tool/build/lib/case.h Normal file
View file

@ -0,0 +1,11 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_CASE_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_CASE_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
#define CASE(OP, CODE) \
case OP: \
CODE; \
break
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_CASE_H_ */

50
tool/build/lib/cond.h Normal file
View file

@ -0,0 +1,50 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_COND_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_COND_H_
#include "tool/build/lib/flags.h"
#include "tool/build/lib/machine.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
forceinline bool GetCond(struct Machine *m, int x) {
uint32_t f = m->flags;
switch (x) {
case 0:
return GetFlag(f, FLAGS_OF);
case 1:
return !GetFlag(f, FLAGS_OF);
case 2:
return GetFlag(f, FLAGS_CF);
case 3:
return !GetFlag(f, FLAGS_CF);
case 4:
return GetFlag(f, FLAGS_ZF);
case 5:
return !GetFlag(f, FLAGS_ZF);
case 6:
return GetFlag(f, FLAGS_CF) || GetFlag(f, FLAGS_ZF);
case 7:
return !GetFlag(f, FLAGS_CF) && !GetFlag(f, FLAGS_ZF);
case 8:
return GetFlag(f, FLAGS_SF);
case 9:
return !GetFlag(f, FLAGS_SF);
case 10:
return GetFlag(f, FLAGS_PF);
case 11:
return !GetFlag(f, FLAGS_PF);
case 12:
return GetFlag(f, FLAGS_SF) != GetFlag(f, FLAGS_OF);
case 13:
return GetFlag(f, FLAGS_SF) == GetFlag(f, FLAGS_OF);
case 14:
return GetFlag(f, FLAGS_ZF) ||
GetFlag(f, FLAGS_SF) != GetFlag(f, FLAGS_OF);
case 15:
return !GetFlag(f, FLAGS_ZF) &&
GetFlag(f, FLAGS_SF) == GetFlag(f, FLAGS_OF);
default:
unreachable;
}
}
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_COND_H_ */

72
tool/build/lib/cpuid.c Normal file
View file

@ -0,0 +1,72 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "tool/build/lib/endian.h"
#include "tool/build/lib/machine.h"
void OpCpuid(struct Machine *m) {
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;
cx = 'i' | 'n' << 8 | 'e' << 16 | 'C' << 24;
dx = 'o' | 's' << 8 | 'm' << 16 | 'o' << 24;
break;
case 1:
cx |= 1 << 0; /* sse3 */
cx |= 0 << 1; /* pclmulqdq */
cx |= 1 << 9; /* ssse3 */
cx |= 1 << 23; /* popcnt */
cx |= 0 << 30; /* rdrnd */
cx |= 0 << 25; /* aes */
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 << 25; /* sse */
dx |= 1 << 26; /* sse2 */
break;
case 7:
bx |= 1 << 9; /* erms */
break;
case 0x80000001:
cx |= 1 << 0; /* lahf/sahf */
dx |= 1 << 11; /* syscall */
dx |= 1 << 29; /* long mode */
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);
}

11
tool/build/lib/cpuid.h Normal file
View file

@ -0,0 +1,11 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_CPUID_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_CPUID_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#include "tool/build/lib/cvt.h"
void OpCpuid(struct Machine *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_CPUID_H_ */

316
tool/build/lib/cvt.c Normal file
View file

@ -0,0 +1,316 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
#include "libc/math.h"
#include "tool/build/lib/cvt.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/throw.h"
static void OpGdqpWssCvttss2si(struct Machine *m) {
float f;
int64_t n;
memcpy(&f, GetModrmRegisterXmmPointerRead4(m), 4);
n = f;
if (!Rexw(m->xedd)) n &= 0xffffffff;
Write64(RegRexrReg(m), n);
}
static void OpGdqpWsdCvttsd2si(struct Machine *m) {
double d;
int64_t n;
memcpy(&d, GetModrmRegisterXmmPointerRead8(m), 8);
n = d;
if (!Rexw(m->xedd)) n &= 0xffffffff;
Write64(RegRexrReg(m), n);
}
static void OpGdqpWssCvtss2si(struct Machine *m) {
float f;
int64_t n;
memcpy(&f, GetModrmRegisterXmmPointerRead4(m), 4);
n = rintf(f);
if (!Rexw(m->xedd)) n &= 0xffffffff;
Write64(RegRexrReg(m), n);
}
static void OpGdqpWsdCvtsd2si(struct Machine *m) {
double d;
int64_t n;
memcpy(&d, GetModrmRegisterXmmPointerRead8(m), 8);
n = nearbyint(d);
if (!Rexw(m->xedd)) n &= 0xffffffff;
Write64(RegRexrReg(m), n);
}
static void OpVssEdqpCvtsi2ss(struct Machine *m) {
float f;
int64_t n;
uint8_t *p;
if (Rexw(m->xedd)) {
n = (int64_t)Read64(GetModrmRegisterWordPointerRead8(m));
} else {
n = (int32_t)Read32(GetModrmRegisterWordPointerRead4(m));
}
f = n;
memcpy(XmmRexrReg(m), &f, 4);
}
static void OpVsdEdqpCvtsi2sd(struct Machine *m) {
double d;
int64_t n;
uint8_t *p;
if (Rexw(m->xedd)) {
n = (int64_t)Read64(GetModrmRegisterWordPointerRead8(m));
} else {
n = (int32_t)Read32(GetModrmRegisterWordPointerRead4(m));
}
d = n;
memcpy(XmmRexrReg(m), &d, 8);
}
static void OpVpsQpiCvtpi2ps(struct Machine *m) {
uint8_t *p;
float f[2];
int32_t i[2];
p = GetModrmRegisterMmPointerRead8(m);
i[0] = Read32(p + 0);
i[1] = Read32(p + 4);
f[0] = i[0];
f[1] = i[1];
memcpy(XmmRexrReg(m), f, 8);
}
static void OpVpdQpiCvtpi2pd(struct Machine *m) {
uint8_t *p;
double f[2];
int32_t n[2];
p = GetModrmRegisterMmPointerRead8(m);
n[0] = Read32(p + 0);
n[1] = Read32(p + 4);
f[0] = n[0];
f[1] = n[1];
memcpy(XmmRexrReg(m), f, 16);
}
static void OpPpiWpsqCvtps2pi(struct Machine *m) {
float f[2];
int32_t n[2];
memcpy(f, GetModrmRegisterXmmPointerRead8(m), 8);
n[0] = nearbyintf(f[0]);
n[1] = nearbyintf(f[1]);
Write32(MmReg(m) + 0, n[0]);
Write32(MmReg(m) + 4, n[1]);
}
static void OpPpiWpsqCvttps2pi(struct Machine *m) {
float f[2];
int32_t n[2];
memcpy(&f, GetModrmRegisterXmmPointerRead8(m), 8);
n[0] = f[0];
n[1] = f[1];
Write32(MmReg(m) + 0, n[0]);
Write32(MmReg(m) + 4, n[1]);
}
static void OpPpiWpdCvtpd2pi(struct Machine *m) {
double d[2];
int32_t n[2];
memcpy(d, GetModrmRegisterXmmPointerRead16(m), 16);
n[0] = nearbyint(d[0]);
n[1] = nearbyint(d[1]);
Write32(MmReg(m) + 0, n[0]);
Write32(MmReg(m) + 4, n[1]);
}
static void OpPpiWpdCvttpd2pi(struct Machine *m) {
double d[2];
int32_t n[2];
memcpy(&d, GetModrmRegisterXmmPointerRead16(m), 16);
n[0] = d[0];
n[1] = d[1];
Write32(MmReg(m) + 0, n[0]);
Write32(MmReg(m) + 4, n[1]);
}
static void OpVpdWpsCvtps2pd(struct Machine *m) {
float f[2];
double d[2];
memcpy(f, GetModrmRegisterXmmPointerRead8(m), 8);
d[0] = f[0];
d[1] = f[1];
memcpy(XmmRexrReg(m), d, 16);
}
static void OpVpsWpdCvtpd2ps(struct Machine *m) {
float f[2];
double d[2];
memcpy(d, GetModrmRegisterXmmPointerRead16(m), 16);
f[0] = d[0];
f[1] = d[1];
memcpy(XmmRexrReg(m), f, 8);
}
static void OpVssWsdCvtsd2ss(struct Machine *m) {
float f;
double d;
memcpy(&d, GetModrmRegisterXmmPointerRead8(m), 8);
f = d;
memcpy(XmmRexrReg(m), &f, 4);
}
static void OpVsdWssCvtss2sd(struct Machine *m) {
float f;
double d;
memcpy(&f, GetModrmRegisterXmmPointerRead4(m), 4);
d = f;
memcpy(XmmRexrReg(m), &d, 8);
}
static void OpVpsWdqCvtdq2ps(struct Machine *m) {
unsigned i;
float f[4];
int32_t n[4];
memcpy(n, GetModrmRegisterXmmPointerRead16(m), 16);
for (i = 0; i < 4; ++i) f[i] = n[i];
memcpy(XmmRexrReg(m), f, 16);
}
static void OpVpdWdqCvtdq2pd(struct Machine *m) {
unsigned i;
double d[2];
int32_t n[2];
memcpy(n, GetModrmRegisterXmmPointerRead8(m), 8);
for (i = 0; i < 2; ++i) d[i] = n[i];
memcpy(XmmRexrReg(m), d, 16);
}
static void OpVdqWpsCvttps2dq(struct Machine *m) {
unsigned i;
float f[4];
int32_t n[4];
memcpy(f, GetModrmRegisterXmmPointerRead16(m), 16);
for (i = 0; i < 4; ++i) n[i] = f[i];
memcpy(XmmRexrReg(m), n, 16);
}
static void OpVdqWpsCvtps2dq(struct Machine *m) {
unsigned i;
float f[4];
int32_t n[4];
memcpy(f, GetModrmRegisterXmmPointerRead16(m), 16);
for (i = 0; i < 4; ++i) n[i] = nearbyintf(f[i]);
memcpy(XmmRexrReg(m), n, 16);
}
static void OpVdqWpdCvttpd2dq(struct Machine *m) {
unsigned i;
double d[2];
int32_t n[2];
memcpy(d, GetModrmRegisterXmmPointerRead16(m), 16);
for (i = 0; i < 2; ++i) n[i] = d[i];
memcpy(XmmRexrReg(m), n, 8);
}
static void OpVdqWpdCvtpd2dq(struct Machine *m) {
unsigned i;
double d[2];
int32_t n[2];
memcpy(d, GetModrmRegisterXmmPointerRead16(m), 16);
for (i = 0; i < 2; ++i) n[i] = nearbyintf(d[i]);
memcpy(XmmRexrReg(m), n, 8);
}
void OpCvt(struct Machine *m, unsigned long op) {
op |= m->xedd->op.rep;
op |= Prefix66(m->xedd);
switch (op) {
case kOpCvt0f2a + 0:
OpVpsQpiCvtpi2ps(m);
break;
case kOpCvt0f2a + 1:
OpVpdQpiCvtpi2pd(m);
break;
case kOpCvt0f2a + 2:
OpVsdEdqpCvtsi2sd(m);
break;
case kOpCvt0f2a + 3:
OpVssEdqpCvtsi2ss(m);
break;
case kOpCvtt0f2c + 0:
OpPpiWpsqCvttps2pi(m);
break;
case kOpCvtt0f2c + 1:
OpPpiWpdCvttpd2pi(m);
break;
case kOpCvtt0f2c + 2:
OpGdqpWsdCvttsd2si(m);
break;
case kOpCvtt0f2c + 3:
OpGdqpWssCvttss2si(m);
break;
case kOpCvt0f2d + 0:
OpPpiWpsqCvtps2pi(m);
break;
case kOpCvt0f2d + 1:
OpPpiWpdCvtpd2pi(m);
break;
case kOpCvt0f2d + 2:
OpGdqpWsdCvtsd2si(m);
break;
case kOpCvt0f2d + 3:
OpGdqpWssCvtss2si(m);
break;
case kOpCvt0f5a + 0:
OpVpdWpsCvtps2pd(m);
break;
case kOpCvt0f5a + 1:
OpVpsWpdCvtpd2ps(m);
break;
case kOpCvt0f5a + 2:
OpVssWsdCvtsd2ss(m);
break;
case kOpCvt0f5a + 3:
OpVsdWssCvtss2sd(m);
break;
case kOpCvt0f5b + 0:
OpVpsWdqCvtdq2ps(m);
break;
case kOpCvt0f5b + 1:
OpVdqWpsCvtps2dq(m);
break;
case kOpCvt0f5b + 3:
OpVdqWpsCvttps2dq(m);
break;
case kOpCvt0fE6 + 1:
OpVdqWpdCvtpd2dq(m);
break;
case kOpCvt0fE6 + 2:
OpVdqWpdCvttpd2dq(m);
break;
case kOpCvt0fE6 + 3:
OpVpdWdqCvtdq2pd(m);
break;
default:
OpUd(m);
}
}

18
tool/build/lib/cvt.h Normal file
View file

@ -0,0 +1,18 @@
#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_
#define kOpCvt0f2a 0
#define kOpCvtt0f2c 4
#define kOpCvt0f2d 8
#define kOpCvt0f5a 12
#define kOpCvt0f5b 16
#define kOpCvt0fE6 20
void OpCvt(struct Machine *, unsigned long);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_CVT_H_ */

45
tool/build/lib/debug.c Normal file
View file

@ -0,0 +1,45 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/log/check.h"
#include "libc/runtime/gc.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;
void *elfmap;
struct stat st;
if (elf->ehdr) return;
DCHECK_NOTNULL(elf->prog);
if ((fd = open(gc(xstrcat(elf->prog, ".dbg")), O_RDONLY)) != -1) {
if (fstat(fd, &st) != -1 &&
(elfmap = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) !=
MAP_FAILED) {
elf->ehdr = elfmap;
elf->size = st.st_size;
}
close(fd);
}
}

263
tool/build/lib/dis.c Normal file
View file

@ -0,0 +1,263 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/alg.h"
#include "libc/alg/arraylist2.h"
#include "libc/bits/safemacros.h"
#include "libc/conv/itoa.h"
#include "libc/fmt/bing.h"
#include "libc/fmt/fmt.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/str/tpencode.h"
#include "third_party/xed/x86.h"
#include "tool/build/lib/case.h"
#include "tool/build/lib/dis.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) {
if (g_dis_high) p = DisHigh(p, g_dis_high->keyword);
p = DisColumn(stpcpy(p, ".byte"), p, NAMELEN);
if (g_dis_high) p = DisHigh(p, -1);
p = DisOctets(p, d, n);
return p;
}
static char *DisError(struct DisBuilder b, char *p) {
p = DisColumn(DisByte(p, b.xedd->bytes, MIN(15, b.xedd->length)), p, CODELEN);
if (g_dis_high) p = DisHigh(p, g_dis_high->comment);
*p++ = '#';
*p++ = ' ';
p = stpcpy(p, indexdoublenulstring(kXedErrorNames, b.xedd->op.error));
if (g_dis_high) p = DisHigh(p, -1);
*p = '\0';
return p;
}
static char *DisAddr(struct DisBuilder b, char *p) {
if (INT_MIN <= b.addr && b.addr <= INT_MAX) {
return p + uint64toarray_fixed16(b.addr, p, 32);
} else {
return p + uint64toarray_fixed16(b.addr, p, 48);
}
}
static char *DisRaw(struct DisBuilder b, char *p) {
long i;
for (i = 0; i < PFIXLEN - MIN(PFIXLEN, b.xedd->op.PIVOTOP); ++i) {
*p++ = ' ';
*p++ = ' ';
}
for (i = 0; i < MIN(15, b.xedd->length); ++i) {
if (i == b.xedd->op.PIVOTOP) *p++ = ' ';
*p++ = "0123456789abcdef"[(b.xedd->bytes[i] & 0xf0) >> 4];
*p++ = "0123456789abcdef"[b.xedd->bytes[i] & 0x0f];
}
*p = '\0';
return p;
}
static char *DisCode(struct DisBuilder b, char *p) {
char optspecbuf[128];
if (!b.xedd->op.error) {
return DisInst(b, p, DisSpec(b.xedd, optspecbuf));
} else {
return DisError(b, p);
}
}
static char *DisLineCode(struct DisBuilder b, char *p) {
p = DisColumn(DisAddr(b, p), p, ADDRLEN);
p = DisColumn(DisRaw(b, p), p, PFIXLEN * 2 + 1 + BYTELEN * 2);
p = DisCode(b, p);
return p;
}
static char *DisLineData(struct DisBuilder b, char *p, const uint8_t *d,
size_t n) {
size_t i;
p = DisColumn(DisAddr(b, p), p, ADDRLEN);
p = DisColumn(DisByte(p, d, n), p, 64);
if (g_dis_high) p = DisHigh(p, g_dis_high->comment);
*p++ = '#';
*p++ = ' ';
for (i = 0; i < n; ++i) p += tpencode(p, 8, bing(d[i], 0), false);
if (g_dis_high) p = DisHigh(p, -1);
*p = '\0';
return p;
}
static char *DisLabel(struct DisBuilder b, char *p, const char *name) {
p = DisColumn(DisAddr(b, p), p, ADDRLEN);
if (g_dis_high) p = DisHigh(p, g_dis_high->label);
p = stpcpy(p, name);
if (g_dis_high) p = DisHigh(p, -1);
*p++ = ':';
*p = '\0';
return p;
}
long DisFind(struct Dis *d, int64_t addr) {
long i;
for (i = 0; i < d->ops.i; ++i) {
if (addr >= d->ops.p[i].addr &&
addr < d->ops.p[i].addr + d->ops.p[i].size) {
return i;
}
}
return -1;
}
void Dis(struct Dis *d, struct Machine *m, int64_t addr) {
char *p;
void *r[2];
bool iscode;
int64_t unique;
struct DisOp op;
long i, j, n, si, max, toto, symbol;
unique = 0;
max = 99999;
DisFreeOps(&d->ops);
for (i = 0; i < max; ++i) {
xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_LONG_64);
if ((symbol = DisFindSym(d, addr)) != -1) {
iscode = true; /* d->syms.p[symbol].iscode; */
n = iscode ? CODELIM : DATALIM;
if (d->syms.p[symbol].size) {
n = MIN(n, d->syms.p[symbol].size);
} else if (symbol + 1 < d->syms.i &&
d->syms.p[symbol + 1].addr > d->syms.p[symbol].addr) {
n = MIN(n, d->syms.p[symbol + 1].addr - d->syms.p[symbol].addr);
}
if (addr == d->syms.p[symbol].addr && d->syms.p[symbol].name) {
op.addr = addr;
op.unique = unique++;
op.size = 0;
op.active = true;
DisLabel((struct DisBuilder){d, d->xedd, addr}, d->buf,
d->syms.stab + d->syms.p[symbol].name);
if (!(op.s = strdup(d->buf))) break;
APPEND(&d->ops.p, &d->ops.i, &d->ops.n, &op);
}
} else {
iscode = DisIsText(d, addr);
n = CODELIM;
}
DCHECK_GT(n, 0);
DCHECK_LE(n, ARRAYLEN(d->raw));
memset(r, 0, sizeof(r));
if (!(r[0] = FindReal(m, addr))) {
max = MIN(100, max);
n = MIN(DATALIM, 0x1000 - (addr & 0xfff));
DCHECK_GT(n, 0);
memset(d->raw, 0xCC, DATALIM);
} else if ((addr & 0xfff) + n <= 0x1000) {
memcpy(d->raw, r[0], n);
} else if ((r[1] = FindReal(m, ROUNDUP(addr, 0x1000)))) {
si = 0x1000 - (addr & 0xfff);
memcpy(d->raw, r[0], si);
memcpy(d->raw + si, r[1], n - si);
} else {
n = 0x1000 - (addr & 0xfff);
DCHECK_GT(n, 0);
memcpy(d->raw, r[0], n);
}
if (!NoDebug()) memset(d->buf, 0x55, sizeof(d->buf));
if (1 || iscode) {
xed_instruction_length_decode(d->xedd, d->raw, n);
DCHECK_GT(n, 0);
p = DisLineCode((struct DisBuilder){d, d->xedd, addr}, d->buf);
n = d->xedd->op.error ? 1 : d->xedd->length;
DCHECK_GT(n, 0);
} else {
p = DisLineData((struct DisBuilder){d, d->xedd, addr}, d->buf, d->raw, n);
}
DCHECK_LT(p, d->buf + sizeof(d->buf));
DCHECK_LT(strlen(d->buf), sizeof(d->buf));
op.addr = addr;
op.unique = unique++;
op.size = n;
op.active = true;
if (!(op.s = strdup(d->buf))) break;
APPEND(&d->ops.p, &d->ops.i, &d->ops.n, &op);
addr += n;
n = 0;
}
}
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);
memset(ops, 0, sizeof(*ops));
}
void DisFree(struct Dis *d) {
long i;
DisFreeOps(&d->ops);
free(d->edges.p);
free(d->loads.p);
free(d->syms.p);
memset(d, 0, sizeof(*d));
}

86
tool/build/lib/dis.h Normal file
View file

@ -0,0 +1,86 @@
#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_
struct Dis {
struct DisOps {
size_t i, n;
struct DisOp {
int64_t addr;
int unique;
int 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 rank;
int unique;
int size;
int name;
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];
uint8_t raw[512];
char buf[512];
};
struct DisBuilder {
struct Dis *dis;
struct XedDecodedInst *xedd;
int64_t addr;
};
struct DisHigh {
uint8_t keyword;
uint8_t reg;
uint8_t literal;
uint8_t label;
uint8_t comment;
};
extern struct DisHigh *g_dis_high;
long DisFind(struct Dis *, int64_t);
void Dis(struct Dis *, struct Machine *, 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);
const char *DisSpec(struct XedDecodedInst *, char *);
char *DisInst(struct DisBuilder, char *, const char *);
char *DisArg(struct DisBuilder, char *, const char *);
char *DisHigh(char *, int);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_DIS_H_ */

564
tool/build/lib/disarg.c Normal file
View file

@ -0,0 +1,564 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/conv/itoa.h"
#include "libc/limits.h"
#include "libc/log/check.h"
#include "libc/macros.h"
#include "libc/str/str.h"
#include "tool/build/lib/dis.h"
#include "tool/build/lib/modrm.h"
static const char kScale[4][4] = {"", ",2", ",4", ",8"};
static const char kSegName[8][3] = {"es", "cs", "ss", "ds", "fs", "gs"};
static const char kSegOverride[8][3] = {"", "cs", "ds", "es", "fs", "gs", "ss"};
static const char kRegisterName8[2][2][8][5] = {
{{"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"},
{"al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil"}},
{{"???", "???", "???", "???", "???", "???", "???", "???"},
{"r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b"}},
};
static const char kRegisterName[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", "re9w", "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 DisBuilder b, int64_t d) {
return b.addr + b.xedd->length + d;
}
static const char *GetAddrReg(struct DisBuilder b, uint8_t x, uint8_t r) {
return kRegisterName[0][!Asz(b.xedd)][x & 1][r & 7];
}
static char *DisRegister(char *p, const char *s) {
if (g_dis_high) p = DisHigh(p, g_dis_high->reg);
*p++ = '%';
p = stpcpy(p, s);
if (g_dis_high) p = DisHigh(p, -1);
return p;
}
static char *DisLiteral(char *p, const char *s) {
if (g_dis_high) p = DisHigh(p, g_dis_high->literal);
p = stpcpy(p, s);
if (g_dis_high) p = DisHigh(p, -1);
return p;
}
static char *DisComment(char *p, const char *s) {
if (g_dis_high) p = DisHigh(p, g_dis_high->comment);
p = stpcpy(p, s);
if (g_dis_high) p = DisHigh(p, -1);
return p;
}
static char *DisRegisterByte(struct DisBuilder b, char *p, bool g, int r) {
return DisRegister(p, kRegisterName8[g][Rex(b.xedd)][r]);
}
static char *DisRegisterWord(struct DisBuilder b, char *p, bool g, int r) {
return DisRegister(p, kRegisterName[Osz(b.xedd)][Rexw(b.xedd)][g][r]);
}
static char *DisGvqp(struct DisBuilder b, char *p) {
return DisRegisterWord(b, p, Rexr(b.xedd), ModrmReg(b.xedd));
}
static char *DisGdqp(struct DisBuilder b, char *p) {
return DisRegister(
p, kRegisterName[0][Rexw(b.xedd)][Rexr(b.xedd)][ModrmReg(b.xedd)]);
}
static char *DisGb(struct DisBuilder b, char *p) {
return DisRegisterByte(b, p, Rexr(b.xedd), ModrmReg(b.xedd));
}
static uint8_t DisSeg(struct DisBuilder b) {
return b.xedd->op.seg_ovd ? b.xedd->op.seg_ovd : b.xedd->op.hint;
}
static char *DisInt(char *p, int64_t x) {
if (-15 <= x && x <= 15) {
p += int64toarray_radix10(x, p);
} 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 *DisSym(struct DisBuilder b, char *p, int64_t addr) {
long sym;
int64_t addend;
const char *name;
if ((sym = DisFindSym(b.dis, addr)) != -1 && b.dis->syms.p[sym].name) {
addend = addr - b.dis->syms.p[sym].addr;
name = b.dis->syms.stab + b.dis->syms.p[sym].name;
p = stpcpy(p, name);
if (addend) {
*p++ = '+';
p = DisInt(p, addend);
}
return p;
} else {
return DisInt(p, addr);
}
}
static char *DisM(struct DisBuilder b, char *p) {
int64_t disp;
const char *seg, *base, *index, *scale;
base = index = scale = NULL;
seg = kSegOverride[b.xedd->op.seg_ovd ? b.xedd->op.seg_ovd : b.xedd->op.hint];
if (*seg) {
p = DisRegister(p, seg);
*p++ = ':';
}
if (ModrmMod(b.xedd) == 0b01 || ModrmMod(b.xedd) == 0b10 ||
IsRipRelative(b.xedd) ||
(ModrmMod(b.xedd) == 0b00 && ModrmRm(b.xedd) == 0b100 &&
SibBase(b.xedd) == 0b101)) {
disp = b.xedd->op.disp;
if (IsRipRelative(b.xedd)) disp = RipRelative(b, disp);
p = DisSym(b, p, disp);
}
if (!SibExists(b.xedd)) {
DCHECK(!b.xedd->op.has_sib);
if (IsRipRelative(b.xedd)) {
base = "rip";
} else {
base = GetAddrReg(b, Rexb(b.xedd), ModrmRm(b.xedd));
}
} else if (!SibIsAbsolute(b.xedd)) {
DCHECK(b.xedd->op.has_sib);
if (SibHasBase(b.xedd)) {
base = GetAddrReg(b, Rexb(b.xedd), SibBase(b.xedd));
}
if (SibHasIndex(b.xedd)) {
index = GetAddrReg(b, Rexx(b.xedd), SibIndex(b.xedd));
} else if (b.xedd->op.scale) {
index = Asz(b.xedd) ? "eiz" : "riz";
}
scale = kScale[b.xedd->op.scale];
}
if (base || index) {
*p++ = '(';
if (base) {
p = DisRegister(p, base);
}
if (index) {
*p++ = ',';
p = DisRegister(p, index);
p = stpcpy(p, scale);
}
*p++ = ')';
}
*p = '\0';
return p;
}
static char *DisEb(struct DisBuilder b, char *p) {
if (IsModrmRegister(b.xedd)) {
return DisRegisterByte(b, p, Rexb(b.xedd), ModrmRm(b.xedd));
} else {
return DisM(b, p);
}
}
static char *DisEvqp(struct DisBuilder b, char *p) {
if (IsModrmRegister(b.xedd)) {
return DisRegisterWord(b, p, Rexb(b.xedd), ModrmRm(b.xedd));
} else {
return DisM(b, p);
}
}
static char *DisEdqp(struct DisBuilder b, char *p) {
if (IsModrmRegister(b.xedd)) {
return DisRegister(
p, kRegisterName[0][Rexw(b.xedd)][Rexb(b.xedd)][ModrmRm(b.xedd)]);
} else {
return DisM(b, p);
}
}
static char *DisEvq(struct DisBuilder b, char *p) {
const char *s;
if (IsModrmRegister(b.xedd)) {
if (Osz(b.xedd)) {
s = kRegisterName[1][0][Rexb(b.xedd)][ModrmRm(b.xedd)];
} else {
s = kRegisterName[0][1][Rexb(b.xedd)][ModrmRm(b.xedd)];
}
return DisRegister(p, s);
} else {
return DisM(b, p);
}
}
static char *DisEd(struct DisBuilder b, char *p) {
if (IsModrmRegister(b.xedd)) {
return DisRegister(p, kRegisterName[0][0][Rexb(b.xedd)][ModrmRm(b.xedd)]);
} else {
return DisM(b, p);
}
}
static char *DisEq(struct DisBuilder b, char *p) {
if (IsModrmRegister(b.xedd)) {
return DisRegister(p, kRegisterName[0][1][Rexb(b.xedd)][ModrmRm(b.xedd)]);
} else {
return DisM(b, p);
}
}
static char *DisZvq(struct DisBuilder b, char *p) {
if (Osz(b.xedd)) {
return DisRegister(p, kRegisterName[1][0][Rexb(b.xedd)][ModrmSrm(b.xedd)]);
} else {
return DisRegister(p, kRegisterName[0][1][Rexb(b.xedd)][ModrmSrm(b.xedd)]);
}
}
static char *DisZvqp(struct DisBuilder b, char *p) {
return DisRegisterWord(b, p, Rexb(b.xedd), ModrmSrm(b.xedd));
}
static char *DisZb(struct DisBuilder b, char *p) {
return DisRegisterByte(b, p, Rexb(b.xedd), ModrmSrm(b.xedd));
}
static char *DisEax(struct DisBuilder b, char *p) {
return DisRegister(p, kRegisterName[Osz(b.xedd)][0][0][0]);
}
static char *DisRax(struct DisBuilder b, char *p) {
return DisRegister(p, kRegisterName[Osz(b.xedd)][Rexw(b.xedd)][0][0]);
}
static char *DisRdx(struct DisBuilder b, char *p) {
return DisRegister(p, kRegisterName[Osz(b.xedd)][Rexw(b.xedd)][0][2]);
}
static char *DisImm(struct DisBuilder b, char *p) {
*p++ = '$';
if (g_dis_high) p = DisHigh(p, g_dis_high->literal);
p = DisSym(b, p, b.xedd->op.uimm0);
if (g_dis_high) p = DisHigh(p, -1);
return p;
}
static char *DisJbs(struct DisBuilder b, char *p) {
if (b.xedd->op.disp > 0) *p++ = '+';
p += int64toarray_radix10(b.xedd->op.disp, p);
return p;
}
static char *DisJb(struct DisBuilder b, char *p) {
if (b.xedd->op.disp > 0) *p++ = '+';
p += uint64toarray_radix10(b.xedd->op.disp & 0xff, p);
return p;
}
static char *DisJvds(struct DisBuilder b, char *p) {
return DisSym(b, p, RipRelative(b, b.xedd->op.disp));
}
static char *DisAbs(struct DisBuilder b, char *p) {
return DisSym(b, p, b.xedd->op.disp);
}
static char *DisSw(struct DisBuilder b, char *p) {
if (kSegName[ModrmReg(b.xedd)][0]) {
p = DisRegister(p, kSegName[ModrmReg(b.xedd)]);
}
*p = '\0';
return p;
}
static char *DisY(struct DisBuilder b, char *p) {
*p++ = '(';
p = DisRegister(p, Asz(b.xedd) ? "edi" : "rdi");
*p++ = ')';
*p = '\0';
return p;
}
static char *DisX(struct DisBuilder b, char *p) {
if (kSegOverride[b.xedd->op.seg_ovd][0]) {
p = DisRegister(p, kSegOverride[b.xedd->op.seg_ovd]);
}
*p++ = '(';
p = DisRegister(p, Asz(b.xedd) ? "esi" : "rsi");
*p++ = ')';
*p = '\0';
return p;
}
static char *DisBBb(struct DisBuilder b, char *p) {
if (kSegOverride[b.xedd->op.seg_ovd][0]) {
p = DisRegister(p, kSegOverride[b.xedd->op.seg_ovd]);
}
*p++ = '(';
p = DisRegister(p, Asz(b.xedd) ? "ebx" : "rbx");
*p++ = ')';
*p = '\0';
return p;
}
static char *DisXmm(struct DisBuilder b, char *p, const char *s, int reg) {
if (g_dis_high) p = DisHigh(p, g_dis_high->reg);
*p++ = '%';
p = stpcpy(p, s);
p += uint64toarray_radix10(Rexr(b.xedd) << 3 | reg, p);
if (g_dis_high) p = DisHigh(p, -1);
return p;
}
static char *DisNq(struct DisBuilder b, char *p) {
return DisXmm(b, p, "mm", ModrmRm(b.xedd));
}
static char *DisUq(struct DisBuilder b, char *p) {
return DisXmm(b, p, "mm", ModrmRm(b.xedd));
}
static char *DisPq(struct DisBuilder b, char *p) {
return DisXmm(b, p, "mm", ModrmReg(b.xedd));
}
static char *DisUdq(struct DisBuilder b, char *p) {
return DisXmm(b, p, "xmm", ModrmRm(b.xedd));
}
static char *DisVdq(struct DisBuilder b, char *p) {
return DisXmm(b, p, "xmm", ModrmReg(b.xedd));
}
static char *DisQq(struct DisBuilder b, char *p) {
if (IsModrmRegister(b.xedd)) {
return DisNq(b, p);
} else {
return DisM(b, p);
}
}
static char *DisEst(struct DisBuilder b, char *p) {
p = DisRegister(p, "st");
if (ModrmRm(b.xedd) != 0) {
*p++ = '(';
*p++ = '0' + ModrmRm(b.xedd);
*p++ = ')';
*p = '\0';
}
return p;
}
static char *DisEst1(struct DisBuilder b, char *p) {
if (ModrmRm(b.xedd) != 1) {
p = DisEst(b, p);
} else {
*p = '\0';
}
return p;
}
static char *DisEssr(struct DisBuilder b, char *p) {
if (IsModrmRegister(b.xedd)) {
return DisEst(b, p);
} else {
return DisM(b, p);
}
}
static char *DisWps(struct DisBuilder b, char *p) {
if (IsModrmRegister(b.xedd)) {
return DisUdq(b, p);
} else {
return DisM(b, p);
}
}
#define DisEdr DisM
#define DisEqp DisEq
#define DisEsr DisM
#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 DisMps DisM
#define DisMq DisM
#define DisMqi DisM
#define DisMsr DisEssr
#define DisMw DisM
#define DisMwi DisM
#define DisOb DisAbs
#define DisOvqp DisAbs
#define DisPpi DisPq
#define DisQpi DisQq
#define DisRdqp DisGdqp
#define DisRvqp DisGvqp
#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
static const struct DisArg {
char s[8];
char *(*f)(struct DisBuilder, char *);
} kDisArgs[] = /* <sorted> */ {
{"%Gb", DisGb}, //
{"%Gdqp", DisGdqp}, //
{"%Gvqp", DisGvqp}, //
{"%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}, //
{"%Zvq", DisZvq}, //
{"%Zvqp", DisZvqp}, //
{"%eAX", DisEax}, //
{"%rAX", DisRax}, //
{"%rDX", DisRdx}, //
{"BBb", DisBBb}, //
{"EST", DisEst}, //
{"EST1", DisEst1}, //
{"ESsr", DisEssr}, //
{"Eb", DisEb}, //
{"Ed", DisEd}, //
{"Edqp", DisEdqp}, //
{"Edr", DisEdr}, //
{"Eq", DisEq}, //
{"Eqp", DisEqp}, //
{"Esr", DisEsr}, //
{"Ev", DisEvqp}, //
{"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}, //
{"M", DisM}, //
{"Mdi", DisMdi}, //
{"Mdq", DisMdq}, //
{"Mdqp", DisMdqp}, //
{"Mdr", DisMdr}, //
{"Me", DisMe}, //
{"Mer", DisMer}, //
{"Mps", DisMps}, //
{"Mq", DisMq}, //
{"Mqi", DisMqi}, //
{"Msr", DisMsr}, //
{"Mw", DisMw}, //
{"Mwi", DisMwi}, //
{"Ob", DisOb}, //
{"Ovqp", DisOvqp}, //
{"Qpi", DisQpi}, //
{"Qq", DisQq}, //
{"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 DisBuilder b, char *p, const char *s) {
int c, m, l, r;
l = 0;
r = ARRAYLEN(kDisArgs) - 1;
while (l <= r) {
m = (l + r) >> 1;
c = strcmp(kDisArgs[m].s, s);
if (c < 0) {
l = m + 1;
} else if (c > 0) {
r = m - 1;
} else {
return kDisArgs[m].f(b, p);
}
}
if (*s == '%') {
p = DisRegister(p, s + 1);
} else {
p = stpcpy(p, s);
}
return p;
}

151
tool/build/lib/diself.c Normal file
View file

@ -0,0 +1,151 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/alg.h"
#include "libc/alg/arraylist2.h"
#include "libc/elf/elf.h"
#include "libc/elf/struct/sym.h"
#include "libc/log/check.h"
#include "tool/build/lib/dis.h"
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;
int64_t addr;
uint64_t size;
Elf64_Phdr *phdr;
struct DisLoad l;
d->loads.i = 0;
for (i = 0; i < elf->ehdr->e_phnum; ++i) {
phdr = getelfsegmentheaderaddress(elf->ehdr, elf->size, i);
if (phdr->p_type != PT_LOAD) continue;
l.addr = phdr->p_vaddr;
l.size = phdr->p_memsz;
l.istext = (phdr->p_flags & PF_X) == PF_X;
APPEND(&d->loads.p, &d->loads.i, &d->loads.n, &l);
}
}
static void DisLoadElfSyms(struct Dis *d, struct Elf *elf) {
size_t i, n;
int64_t stablen;
struct DisSym t;
const Elf64_Sym *st, *sym;
bool isabs, iscode, isweak, islocal, ishidden, isprotected, isfunc, isobject;
d->syms.i = 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;
for (i = 0; i < n; ++i) {
if (!st[i].st_name) continue;
if (!(0 <= st[i].st_name && st[i].st_name < stablen)) continue;
if (ELF64_ST_TYPE(st[i].st_info) == STT_SECTION) 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;
t.unique = i;
t.size = st[i].st_size;
t.name = st[i].st_name;
t.addr = st[i].st_value;
t.rank = -islocal + -isweak + -isabs + isprotected + isobject + isfunc;
t.iscode = DisIsText(d, st[i].st_value) ? !isobject : isfunc;
APPEND(&d->syms.p, &d->syms.i, &d->syms.n, &t);
}
}
qsort(d->syms.p, d->syms.i, sizeof(struct DisSym), (void *)DisSymCompare);
}
bool DisIsProg(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 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) {
size_t i;
if (DisIsProg(d, addr)) {
for (i = 0; i < d->syms.i; ++i) {
if (addr == d->syms.p[i].addr) return i;
}
for (i = 0; i < d->syms.i; ++i) {
if (addr >= d->syms.p[i].addr &&
addr < d->syms.p[i].addr + d->syms.p[i].size) {
return i;
}
}
for (i = 0; i < d->syms.i; ++i) {
if (addr >= d->syms.p[i].addr &&
(i + 1 == d->syms.i || addr < d->syms.p[i + 1].addr)) {
return i;
}
}
}
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);
}

34
tool/build/lib/dishigh.c Normal file
View file

@ -0,0 +1,34 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/conv/itoa.h"
#include "libc/str/str.h"
#include "tool/build/lib/dis.h"
struct DisHigh *g_dis_high;
char *DisHigh(char *p, int h) {
if (h != -1) {
p = stpcpy(p, "\e[38;5;");
p += uint64toarray_radix10(h, p);
} else {
p = stpcpy(p, "\e[39");
}
return stpcpy(p, "m");
}

194
tool/build/lib/disinst.c Normal file
View file

@ -0,0 +1,194 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/log/check.h"
#include "libc/nexgen32e/tinystrcmp.h"
#include "libc/str/str.h"
#include "tool/build/lib/case.h"
#include "tool/build/lib/dis.h"
#include "tool/build/lib/modrm.h"
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 int IsRepOpcode(struct DisBuilder b) {
switch (b.xedd->op.opcode & ~1u) {
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 DisBuilder b, char *p) {
const char *s;
if (b.xedd->op.rep && b.xedd->op.map == XED_ILD_MAP0) {
switch (IsRepOpcode(b)) {
case 0:
break;
case 1:
p = stpcpy(p, "rep ");
break;
case 2:
p = stpcpy(p, b.xedd->op.rep == 2 ? "repnz " : "repz ");
break;
default:
break;
}
}
return p;
}
static char *DisBranchTaken(struct DisBuilder b, char *p) {
switch (b.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 DisBuilder b, char *bp, const char *name,
bool ambiguous) {
char *p, *np;
bool notbyte, notlong, wantsuffix, wantsuffixsd;
p = bp;
if (b.xedd->op.lock) p = stpcpy(p, "lock ");
p = DisRepPrefix(b, p);
if (tinystrcmp(name, "BIT") == 0) {
p = stpcpy(p, kBitOp[ModrmReg(b.xedd)]);
} else if (tinystrcmp(name, "CALL") == 0) {
p = stpcpy(p, "call");
} else if (tinystrcmp(name, "JMP") == 0) {
p = stpcpy(p, "jmp");
} else if (tinystrcmp(name, "jcxz") == 0) {
p = stpcpy(p, Asz(b.xedd) ? "jecxz" : "jrcxz");
p = DisBranchTaken(b, p);
} else if (tinystrcmp(name, "loop") == 0) {
p = stpcpy(p, Asz(b.xedd) ? "loopl" : "loop");
p = DisBranchTaken(b, p);
} else if (tinystrcmp(name, "loope") == 0) {
p = stpcpy(p, Asz(b.xedd) ? "loopel" : "loope");
p = DisBranchTaken(b, p);
} else if (tinystrcmp(name, "loopne") == 0) {
p = stpcpy(p, Asz(b.xedd) ? "loopnel" : "loopne");
p = DisBranchTaken(b, p);
} else if (tinystrcmp(name, "cwtl") == 0) {
if (Osz(b.xedd)) name = "cbtw";
if (Rexw(b.xedd)) name = "cltq";
p = stpcpy(p, name);
} else if (tinystrcmp(name, "cltd") == 0) {
if (Osz(b.xedd)) name = "cwtd";
if (Rexw(b.xedd)) 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 (tinystrcmp(name, "ALU") == 0) {
p = stpcpy(p, kAluOp[ModrmReg(b.xedd)]);
} else if (tinystrcmp(np, "WLQ") == 0) {
notbyte = true;
wantsuffix = true;
} else if (tinystrcmp(np, "WQ") == 0) {
notbyte = true;
notlong = true;
wantsuffix = true;
} else if (tinystrcmp(np, "LQ") == 0 || tinystrcmp(np, "WL") == 0) {
notbyte = true;
wantsuffix = true;
} else if (tinystrcmp(np, "SD") == 0) {
notbyte = true;
wantsuffixsd = true;
} else if (tinystrcmp(np, "ABS") == 0) {
if (Rexw(b.xedd)) p = stpcpy(p, "abs");
} else if (tinystrcmp(np, "BT") == 0) {
p = DisBranchTaken(b, p);
}
if (wantsuffixsd) {
if (b.xedd->op.prefix66) {
*p++ = 'd';
} else {
*p++ = 's';
}
} else if (wantsuffix || (ambiguous && !startswith(name, "f") &&
!startswith(name, "set"))) {
if (Osz(b.xedd)) {
*p++ = 'w';
} else if (Rexw(b.xedd)) {
*p++ = 'q';
} else if (ambiguous && !notbyte && IsProbablyByteOp(b.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 DisBuilder b, char *p, const char *spec) {
long i, n;
char sbuf[128];
char args[4][64];
char *s, *name, *state;
bool hasarg, hasmodrm, hasregister, hasmemory;
DCHECK_LT(strlen(spec), 128);
hasarg = false;
hasmodrm = b.xedd->op.has_modrm;
hasmemory = hasmodrm && !IsModrmRegister(b.xedd);
hasregister = hasmodrm && IsModrmRegister(b.xedd);
name = strtok_r(strcpy(sbuf, spec), " ", &state);
for (n = 0; (s = strtok_r(NULL, " ", &state)); ++n) {
hasarg = true;
hasregister |= *s == '%';
hasmemory |= *s == 'O';
DisArg(b, args[n], s);
}
if (g_dis_high) p = DisHigh(p, g_dis_high->keyword);
p = DisName(b, p, name, hasarg && !hasregister && hasmemory);
if (g_dis_high) p = DisHigh(p, -1);
for (i = 0; i < n; ++i) {
if (i && args[n - i][0]) {
*p++ = ',';
}
p = stpcpy(p, args[n - i - 1]);
}
return p;
}

1117
tool/build/lib/disspec.c Normal file

File diff suppressed because it is too large Load diff

271
tool/build/lib/divmul.c Normal file
View file

@ -0,0 +1,271 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/limits.h"
#include "libc/log/log.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"
void OpDivAlAhAxEbSigned(struct Machine *m) {
int8_t y, rem;
int16_t x, quo;
x = Read16(m->ax);
y = Read8(GetModrmRegisterBytePointerRead(m));
if (!y || (x == INT16_MIN && y < 0)) ThrowDivideError(m);
quo = x / y;
rem = x % y;
if (!(INT8_MIN <= quo && quo <= INT8_MAX)) ThrowDivideError(m);
m->ax[0] = quo & 0xff;
m->ax[1] = rem & 0xff;
}
void OpDivAlAhAxEbUnsigned(struct Machine *m) {
uint8_t y, rem;
uint16_t x, quo;
x = Read16(m->ax);
y = Read8(GetModrmRegisterBytePointerRead(m));
if (!y) ThrowDivideError(m);
quo = x / y;
rem = x % y;
if (!(UINT8_MIN <= quo && quo <= UINT8_MAX)) ThrowDivideError(m);
m->ax[0] = quo & 0xff;
m->ax[1] = rem & 0xff;
}
static void OpDivRdxRaxEvqpSigned64(struct Machine *m, uint8_t *p) {
int64_t y, rem;
int128_t x, quo;
x = (uint128_t)Read64(m->dx) << 64 | Read64(m->ax);
y = Read64(p);
if (!y || (x == INT128_MIN && y < 0)) ThrowDivideError(m);
quo = x / y;
rem = x % y;
if (!(INT64_MIN <= quo && quo <= INT64_MAX)) ThrowDivideError(m);
Write64(m->ax, quo);
Write64(m->dx, rem);
}
static void OpDivRdxRaxEvqpSigned32(struct Machine *m, uint8_t *p) {
int32_t y, rem;
int64_t x, quo;
x = (uint64_t)Read32(m->dx) << 32 | Read32(m->ax);
y = Read32(p);
if (!y || (x == INT64_MIN && y < 0)) ThrowDivideError(m);
quo = x / y;
rem = x % y;
if (!(INT32_MIN <= quo && quo <= INT32_MAX)) ThrowDivideError(m);
Write64(m->ax, quo & 0xffffffff);
Write64(m->dx, rem & 0xffffffff);
}
static void OpDivRdxRaxEvqpSigned16(struct Machine *m, uint8_t *p) {
int16_t y, rem;
int32_t x, quo;
x = (uint32_t)Read16(m->dx) << 16 | Read16(m->ax);
y = Read16(p);
if (!y || (x == INT32_MIN && y < 0)) ThrowDivideError(m);
quo = x / y;
rem = x % y;
if (!(INT16_MIN <= quo && quo <= INT16_MAX)) ThrowDivideError(m);
Write16(m->ax, quo);
Write16(m->dx, rem);
}
static void OpDivRdxRaxEvqpUnsigned16(struct Machine *m, uint8_t *p) {
uint16_t y, rem;
uint32_t x, quo;
x = (uint32_t)Read16(m->dx) << 16 | Read16(m->ax);
y = Read16(p);
if (!y) ThrowDivideError(m);
quo = x / y;
rem = x % y;
if (!(UINT16_MIN <= quo && quo <= UINT16_MAX)) ThrowDivideError(m);
Write16(m->ax, quo);
Write16(m->dx, rem);
}
static void OpDivRdxRaxEvqpUnsigned32(struct Machine *m, uint8_t *p) {
uint32_t y, rem;
uint64_t x, quo;
x = (uint64_t)Read32(m->dx) << 32 | Read32(m->ax);
y = Read32(p);
if (!y) ThrowDivideError(m);
quo = x / y;
rem = x % y;
if (!(UINT32_MIN <= quo && quo <= UINT32_MAX)) ThrowDivideError(m);
Write64(m->ax, quo & 0xffffffff);
Write64(m->dx, rem & 0xffffffff);
}
static void OpDivRdxRaxEvqpUnsigned64(struct Machine *m, uint8_t *p) {
uint64_t y, rem;
uint128_t x, quo;
x = (uint128_t)Read64(m->dx) << 64 | Read64(m->ax);
y = Read64(p);
if (!y) ThrowDivideError(m);
quo = x / y;
rem = x % y;
if (!(UINT64_MIN <= quo && quo <= UINT64_MAX)) ThrowDivideError(m);
Write64(m->ax, quo);
Write64(m->dx, rem);
}
void OpDivRdxRaxEvqpSigned(struct Machine *m) {
uint8_t *p;
p = GetModrmRegisterWordPointerReadOszRexw(m);
if (Rexw(m->xedd)) {
OpDivRdxRaxEvqpSigned64(m, p);
} else if (!Osz(m->xedd)) {
OpDivRdxRaxEvqpSigned32(m, p);
} else {
OpDivRdxRaxEvqpSigned16(m, p);
}
}
void OpDivRdxRaxEvqpUnsigned(struct Machine *m) {
uint8_t *p;
p = GetModrmRegisterWordPointerReadOszRexw(m);
if (Rexw(m->xedd)) {
OpDivRdxRaxEvqpUnsigned64(m, p);
} else if (!Osz(m->xedd)) {
OpDivRdxRaxEvqpUnsigned32(m, p);
} else {
OpDivRdxRaxEvqpUnsigned16(m, p);
}
}
void OpMulAxAlEbSigned(struct Machine *m) {
bool of;
int16_t ax;
uint8_t *p;
p = GetModrmRegisterBytePointerRead(m);
__builtin_mul_overflow((int8_t)Read8(m->ax), (int8_t)Read8(p), &ax);
of = (int)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) {
int ax;
bool of;
uint8_t *p;
p = GetModrmRegisterBytePointerRead(m);
__builtin_mul_overflow(Read8(m->ax), Read8(p), &ax);
of = (uint8_t)ax != 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) {
bool of;
uint8_t *p;
int32_t dxax;
int64_t edxeax;
int128_t rdxrax;
p = GetModrmRegisterWordPointerReadOszRexw(m);
if (Rexw(m->xedd)) {
__builtin_mul_overflow((int128_t)(int64_t)Read64(m->ax), (int64_t)Read64(p),
&rdxrax);
of = (int128_t)rdxrax != (int64_t)rdxrax;
Write64(m->ax, rdxrax);
Write64(m->dx, rdxrax >> 64);
} else if (!Osz(m->xedd)) {
__builtin_mul_overflow((int64_t)(int32_t)Read32(m->ax), (int32_t)Read32(p),
&edxeax);
of = (int64_t)edxeax != (int32_t)edxeax;
Write64(m->ax, edxeax);
Write64(m->dx, edxeax >> 32);
} else {
__builtin_mul_overflow((int32_t)(int16_t)Read16(m->ax), (int16_t)Read16(p),
&dxax);
of = (int32_t)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) {
bool of;
uint8_t *p;
uint32_t dxax;
uint64_t edxeax;
uint128_t rdxrax;
p = GetModrmRegisterWordPointerReadOszRexw(m);
if (Rexw(m->xedd)) {
__builtin_mul_overflow((uint128_t)Read64(m->ax), Read64(p), &rdxrax);
of = (uint64_t)rdxrax != rdxrax;
Write64(m->ax, rdxrax);
Write64(m->dx, rdxrax >> 64);
} else if (!Osz(m->xedd)) {
__builtin_mul_overflow((uint64_t)Read32(m->ax), Read32(p), &edxeax);
of = (uint32_t)edxeax != edxeax;
Write64(m->ax, edxeax);
Write64(m->dx, edxeax >> 32);
} else {
__builtin_mul_overflow((uint32_t)(uint16_t)Read16(m->ax),
(uint16_t)Read16(p), &dxax);
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, uint8_t *a, uint8_t *b) {
unsigned of;
if (Rexw(m->xedd)) {
int64_t x, y, z;
x = Read64(a);
y = Read64(b);
of = __builtin_mul_overflow(x, y, &z);
Write64(RegRexrReg(m), z);
} else if (!Osz(m->xedd)) {
int32_t x, y, z;
x = Read32(a);
y = Read32(b);
of = __builtin_mul_overflow(x, y, &z);
Write64(RegRexrReg(m), z & 0xffffffff);
} else {
int16_t x, y, z;
x = Read16(a);
y = Read16(b);
of = __builtin_mul_overflow(x, y, &z);
Write16(RegRexrReg(m), z);
}
m->flags = SetFlag(m->flags, FLAGS_CF, of);
m->flags = SetFlag(m->flags, FLAGS_OF, of);
}
void OpImulGvqpEvqp(struct Machine *m) {
AluImul(m, RegRexrReg(m), GetModrmRegisterWordPointerReadOszRexw(m));
}
void OpImulGvqpEvqpImm(struct Machine *m) {
uint8_t b[8];
Write64(b, m->xedd->op.uimm0);
AluImul(m, GetModrmRegisterWordPointerReadOszRexw(m), b);
}

20
tool/build/lib/divmul.h Normal file
View file

@ -0,0 +1,20 @@
#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 *);
void OpDivAlAhAxEbUnsigned(struct Machine *);
void OpDivRdxRaxEvqpSigned(struct Machine *);
void OpDivRdxRaxEvqpUnsigned(struct Machine *);
void OpImulGvqpEvqp(struct Machine *);
void OpImulGvqpEvqpImm(struct Machine *);
void OpMulAxAlEbSigned(struct Machine *);
void OpMulAxAlEbUnsigned(struct Machine *);
void OpMulRdxRaxEvqpSigned(struct Machine *);
void OpMulRdxRaxEvqpUnsigned(struct Machine *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_DIVMUL_H_ */

View file

@ -25,7 +25,7 @@
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/runtime/gc.h"
#include "libc/runtime/mappings.h"
#include "libc/runtime/memtrack.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/mremap.h"

115
tool/build/lib/endian.h Normal file
View file

@ -0,0 +1,115 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_ENDIAN_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_ENDIAN_H_
#include "libc/str/str.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
#if __BYTE_ORDER__ + 0 == 1234
#define Read8(P) \
({ \
uint8_t *Ptr = (P); \
*Ptr; \
})
#define Read16(P) \
({ \
uint16_t Res; \
uint8_t *Ptr = (P); \
memcpy(&Res, Ptr, 2); \
Res; \
})
#define Read32(P) \
({ \
uint32_t Res; \
uint8_t *Ptr = (P); \
memcpy(&Res, Ptr, 4); \
Res; \
})
#define Read64(P) \
({ \
uint64_t Res; \
uint8_t *Ptr = (P); \
memcpy(&Res, Ptr, 8); \
Res; \
})
#define Write8(P, B) \
do { \
uint8_t *Ptr = (P); \
*Ptr = (B); \
} while (0)
#define Write16(P, V) \
do { \
uint16_t Val = (V); \
uint8_t *Ptr = (P); \
memcpy(Ptr, &Val, 2); \
} while (0)
#define Write32(P, V) \
do { \
uint32_t Val = (V); \
uint8_t *Ptr = (P); \
memcpy(Ptr, &Val, 4); \
} while (0)
#define Write64(P, V) \
do { \
uint64_t Val = (V); \
uint8_t *Ptr = (P); \
memcpy(Ptr, &Val, 8); \
} while (0)
#else
forceinline uint16_t Read8(const uint8_t p[hasatleast 1]) {
return p[0];
}
forceinline uint16_t Read16(const uint8_t p[hasatleast 2]) {
return p[0] | p[1] << 010;
}
forceinline uint32_t Read32(const uint8_t bytes[hasatleast 4]) {
return (uint32_t)bytes[0] << 000 | (uint32_t)bytes[1] << 010 |
(uint32_t)bytes[2] << 020 | (uint32_t)bytes[3] << 030;
}
forceinline uint64_t Read64(const uint8_t bytes[hasatleast 8]) {
return (uint64_t)bytes[0] << 000 | (uint64_t)bytes[1] << 010 |
(uint64_t)bytes[2] << 020 | (uint64_t)bytes[3] << 030 |
(uint64_t)bytes[4] << 040 | (uint64_t)bytes[5] << 050 |
(uint64_t)bytes[6] << 060 | (uint64_t)bytes[7] << 070;
}
forceinline void Write8(unsigned char p[hasatleast 1], uint8_t x) {
p[0] = x >> 000;
}
forceinline void Write16(unsigned char p[hasatleast 2], uint16_t x) {
p[0] = x >> 000;
p[1] = x >> 010;
}
forceinline void Write32(unsigned char p[hasatleast 4], uint64_t x) {
p[0] = x >> 000;
p[1] = x >> 010;
p[2] = x >> 020;
p[3] = x >> 030;
}
forceinline void Write64(unsigned char p[hasatleast 8], uint64_t x) {
p[0] = x >> 000;
p[1] = x >> 010;
p[2] = x >> 020;
p[3] = x >> 030;
p[4] = x >> 040;
p[5] = x >> 050;
p[6] = x >> 060;
p[7] = x >> 070;
}
#endif /* ENDIAN */
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_ENDIAN_H_ */

166
tool/build/lib/errnos.S Normal file
View file

@ -0,0 +1,166 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.macro .errno local:req linux:req
.globl \local
.long \local-kLinuxErrnos
.long \linux
.endm
/ Lookup table translating errnos between systems.
/
/ @see libc/sysv/systemfive.S
.rodata
.align 8
kLinuxErrnos:
.errno EPERM,1
.errno ENOENT,2
.errno ESRCH,3
.errno EINTR,4
.errno EIO,5
.errno ENXIO,6
.errno E2BIG,7
.errno ENOEXEC,8
.errno EBADF,9
.errno ECHILD,10
.errno EAGAIN,11
.errno ENOMEM,12
.errno EACCES,13
.errno EFAULT,14
.errno ENOTBLK,15
.errno EBUSY,16
.errno EEXIST,17
.errno EXDEV,18
.errno ENODEV,19
.errno ENOTDIR,20
.errno EISDIR,21
.errno EINVAL,22
.errno ENFILE,23
.errno EMFILE,24
.errno ENOTTY,25
.errno ETXTBSY,26
.errno EFBIG,27
.errno ENOSPC,28
.errno ESPIPE,29
.errno EROFS,30
.errno EMLINK,31
.errno EPIPE,32
.errno EDOM,33
.errno ERANGE,34
.errno EDEADLK,35
.errno ENAMETOOLONG,36
.errno ENOLCK,37
.errno ENOSYS,38
.errno ENOTEMPTY,39
.errno ELOOP,40
.errno ENOMSG,42
.errno EIDRM,43
.errno EUSERS,87
.errno ENOTSOCK,88
.errno EDESTADDRREQ,89
.errno EMSGSIZE,90
.errno EPROTOTYPE,91
.errno ENOPROTOOPT,92
.errno EPROTONOSUPPORT,93
.errno ESOCKTNOSUPPORT,94
.errno EOPNOTSUPP,95
.errno EPFNOSUPPORT,96
.errno EAFNOSUPPORT,97
.errno EADDRINUSE,98
.errno EADDRNOTAVAIL,99
.errno ECHRNG,44
.errno EL2NSYNC,45
.errno EL3HLT,46
.errno EL3RST,47
.errno ELNRNG,48
.errno EUNATCH,49
.errno ENOCSI,50
.errno EL2HLT,51
.errno EBADE,52
.errno EBADR,53
.errno EXFULL,54
.errno ENOANO,55
.errno EBADRQC,56
.errno EBADSLT,57
.errno ENOSTR,60
.errno ENODATA,61
.errno ETIME,62
.errno ENOSR,63
.errno ENONET,64
.errno ENOPKG,65
.errno EREMOTE,66
.errno ENOLINK,67
.errno EADV,68
.errno ESRMNT,69
.errno ECOMM,70
.errno EPROTO,71
.errno EMULTIHOP,72
.errno EDOTDOT,73
.errno EBADMSG,74
.errno EOVERFLOW,75
.errno ENOTUNIQ,76
.errno EBADFD,77
.errno EREMCHG,78
.errno ELIBACC,79
.errno ELIBBAD,80
.errno ELIBSCN,81
.errno ELIBMAX,82
.errno ELIBEXEC,83
.errno EILSEQ,84
.errno ERESTART,85
.errno ESTRPIPE,86
.errno ENETDOWN,100
.errno ENETUNREACH,101
.errno ENETRESET,102
.errno ECONNABORTED,103
.errno ECONNRESET,104
.errno ENOBUFS,105
.errno EISCONN,106
.errno ENOTCONN,107
.errno ESHUTDOWN,108
.errno ETOOMANYREFS,109
.errno ETIMEDOUT,110
.errno ECONNREFUSED,111
.errno EHOSTDOWN,112
.errno EHOSTUNREACH,113
.errno EALREADY,114
.errno EINPROGRESS,115
.errno ESTALE,116
.errno EUCLEAN,117
.errno ENOTNAM,118
.errno ENAVAIL,119
.errno EISNAM,120
.errno EREMOTEIO,121
.errno EDQUOT,122
.errno ENOMEDIUM,123
.errno EMEDIUMTYPE,124
.errno ECANCELED,125
.errno ENOKEY,126
.errno EKEYEXPIRED,127
.errno EKEYREVOKED,128
.errno EKEYREJECTED,129
.errno EOWNERDEAD,130
.errno ENOTRECOVERABLE,131
.errno ERFKILL,132
.errno EHWPOISON,133
.endobj kLinuxErrnos,globl
kLinuxErrnosLength = (.-kLinuxErrnos)/8
.globl kLinuxErrnosLength

78
tool/build/lib/flags.h Normal file
View file

@ -0,0 +1,78 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_FLAGS_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_FLAGS_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
#define GetLazyParityBool(f) GetParity((f) >> 24)
#define SetLazyParityByte(f, x) (((f) & ~0xFF000000u) | ((x)&0xFF) << 24)
#define GetParity(WORD) \
({ \
unsigned Byte = (WORD); \
Byte ^= Byte >> 4; \
Byte ^= Byte >> 2; \
Byte ^= Byte >> 1; \
~Byte & 1; \
})
#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; \
})
forceinline 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;
}
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_FLAGS_H_ */

1080
tool/build/lib/fpu.c Normal file

File diff suppressed because it is too large Load diff

47
tool/build/lib/fpu.h Normal file
View file

@ -0,0 +1,47 @@
#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
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void OpFpu(struct Machine *);
void OpFinit(struct Machine *);
void OpFwait(struct Machine *);
void FpuPush(struct Machine *, long double);
long double FpuPop(struct Machine *);
forceinline long double *FpuSt(struct Machine *m, unsigned i) {
i += m->fpu.sp;
i &= 0b111;
return m->fpu.st + i;
}
forceinline int FpuGetTag(struct Machine *m, unsigned i) {
unsigned t;
t = m->fpu.tw;
i += m->fpu.sp;
i &= 0b111;
i *= 2;
t &= 0b11 << i;
t >>= i;
return t;
}
forceinline void FpuSetTag(struct Machine *m, unsigned i, unsigned t) {
i += m->fpu.sp;
t &= 0b11;
i &= 0b111;
i *= 2;
m->fpu.tw &= ~(0b11 << i);
m->fpu.tw |= t << i;
}
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_FPU_H_ */

View file

@ -0,0 +1,49 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "tool/build/lib/machine.h"
static void InitRegisterBytePointers(struct Machine *m) {
unsigned i, j, k;
for (i = 0; i < 2; ++i) {
for (j = 0; j < 2; ++j) {
for (k = 0; k < 8; ++k) {
if (i) {
m->beg[i << 4 | j << 3 | k] = m->reg[j << 3 | k];
} else {
m->beg[i << 4 | j << 3 | k] = &m->reg[k & 0b11][(k & 0b100) >> 2];
}
}
}
}
}
static void InitRegisterXmmPointers(struct Machine *m) {
unsigned i, j;
for (i = 0; i < 2; ++i) {
for (j = 0; j < 8; ++j) {
m->veg[i << 3 | j] = m->xmm[i][j];
}
}
}
void InitMachine(struct Machine *m) {
InitRegisterBytePointers(m);
InitRegisterXmmPointers(m);
}

View file

@ -0,0 +1,74 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
#include "libc/str/str.h"
#include "third_party/xed/x86.h"
#include "tool/build/lib/machine.h"
#include "tool/build/lib/memory.h"
#include "tool/build/lib/stats.h"
#include "tool/build/lib/throw.h"
static bool IsOpcodeEqual(uint8_t *a, uint8_t b[16], size_t size) {
if (likely(size)) {
return memcmp(a, b, size) == 0;
} else {
return false;
}
}
void LoadInstruction(struct Machine *m) {
unsigned i;
enum XedError err;
uint8_t *addr, *toil, copy[15];
if ((i = 0x1000 - (m->ip & 0xfff)) >= 15) {
if (ROUNDDOWN(m->ip, 0x1000) == m->codevirt && m->ip) {
addr = m->codereal + (m->ip & 0xfff);
} else {
m->codevirt = ROUNDDOWN(m->ip, 0x1000);
m->codereal = ResolveAddress(m, m->codevirt);
addr = m->codereal + (m->ip & 0xfff);
}
m->xedd = m->icache + (m->ip & (ARRAYLEN(m->icache) - 1));
if (IsOpcodeEqual(addr, m->xedd->bytes, m->xedd->length)) {
taken++;
} else {
ntaken++;
xed_decoded_inst_zero_set_mode(m->xedd, XED_MACHINE_MODE_LONG_64);
if (xed_instruction_length_decode(m->xedd, addr, 15)) {
HaltMachine(m, kMachineDecodeError);
}
}
} else {
m->xedd = m->icache;
xed_decoded_inst_zero_set_mode(m->xedd, XED_MACHINE_MODE_LONG_64);
addr = ResolveAddress(m, m->ip);
if ((toil = FindReal(m, m->ip + i))) {
memcpy(copy, addr, i);
memcpy(copy + i, toil, 15 - i);
if ((err = xed_instruction_length_decode(m->xedd, copy, 15))) {
HaltMachine(m, kMachineDecodeError);
}
} else {
if ((err = xed_instruction_length_decode(m->xedd, addr, i))) {
HaltMachine(m, kMachineDecodeError);
}
}
}
}

42
tool/build/lib/ioports.c Normal file
View file

@ -0,0 +1,42 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/stdio/stdio.h"
#include "tool/build/lib/ioports.h"
uint64_t OpIn(struct Machine *m, uint16_t p) {
switch (p) {
case 0xE9:
return getc(stdin);
default:
return -1;
}
}
void OpOut(struct Machine *m, uint16_t p, uint32_t x) {
switch (p) {
case 0xE9:
do {
putc(x, stdout);
} while (x >> 8);
break;
default:
break;
}
}

12
tool/build/lib/ioports.h Normal file
View file

@ -0,0 +1,12 @@
#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_ */

147
tool/build/lib/loader.c Normal file
View file

@ -0,0 +1,147 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/popcnt.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/log/check.h"
#include "libc/macros.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#include "tool/build/lib/endian.h"
#include "tool/build/lib/loader.h"
#include "tool/build/lib/machine.h"
#include "tool/build/lib/memory.h"
#define DSOLOL "ERROR: ELF not ET_EXEC try `gcc -static -o foo foo.c`\n"
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);
CHECK_EQ(1, popcnt(align));
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 = ROUNDDOWN(felf + phdr->p_offset, align);
fend = ROUNDUP(felf + phdr->p_offset + phdr->p_filesz, align);
bsssize = vend - vbss;
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, RegisterMemory(m, vstart, (void *)fstart, fend - fstart));
if (bsssize) {
CHECK_NE(MAP_FAILED, (rbss = mmap(NULL, bsssize, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
CHECK_NE(-1, RegisterMemory(m, vbss, rbss, bsssize));
}
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;
if (elf->ehdr->e_type != ET_EXEC) {
write(STDERR_FILENO, DSOLOL, strlen(DSOLOL));
exit(1);
}
m->ip = elf->base = elf->ehdr->e_entry;
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, BIGPAGESIZE),
.p_align = PAGESIZE,
};
LoadElfLoadSegment(m, code, codesize, &phdr);
m->ip = base;
}
void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars,
struct Elf *elf) {
int fd;
struct stat st;
void *code, *stack;
size_t codesize, stacksize;
DCHECK_NOTNULL(prog);
elf->prog = prog;
if ((fd = open(prog, O_RDONLY)) == -1 ||
(fstat(fd, &st) == -1 || !st.st_size) || !S_ISREG(st.st_mode)) {
fputs(prog, stderr);
fputs(": not found\n", stderr);
exit(1);
}
codesize = st.st_size;
stacksize = STACKSIZE;
CHECK_NE(MAP_FAILED, (stack = mmap(NULL, stacksize, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
CHECK_NE(MAP_FAILED, (code = mmap(NULL, codesize, PROT_READ | PROT_WRITE,
MAP_PRIVATE, fd, 0)));
CHECK_NE(-1, close(fd));
ResetCpu(m);
Write64(m->sp, 0x800000000000);
RegisterMemory(m, 0x800000000000 - stacksize, stack, stacksize);
LoadArgv(m, prog, args, vars);
if (memcmp(code, "\177ELF", 4) == 0) {
elf->ehdr = code;
elf->size = codesize;
LoadElf(m, elf);
} else {
elf->base = IMAGE_BASE_VIRTUAL;
elf->ehdr = NULL;
elf->size = 0;
LoadBin(m, elf->base, prog, code, codesize);
}
}

21
tool/build/lib/loader.h Normal file
View file

@ -0,0 +1,21 @@
#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;
};
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_ */

2381
tool/build/lib/machine.c Normal file

File diff suppressed because it is too large Load diff

149
tool/build/lib/machine.h Normal file
View file

@ -0,0 +1,149 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_MACHINE_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_MACHINE_H_
#include "libc/elf/struct/ehdr.h"
#include "third_party/xed/x86.h"
#include "tool/build/lib/pml4t.h"
#define kXmmIntegral 0
#define kXmmDouble 1
#define kXmmFloat 2
#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
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct Machine {
struct XedDecodedInst *xedd;
uint64_t ip;
uint64_t codevirt;
uint8_t *codereal;
uint32_t flags;
uint32_t stashsize;
int64_t stashaddr;
int64_t readaddr;
int64_t writeaddr;
uint32_t readsize;
uint32_t writesize;
union {
uint8_t reg[2 * 8][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];
};
} aligned(8);
uint32_t tlbindex;
struct TlbEntry {
int64_t v;
void *r;
} tlb[4];
uint8_t *veg[2 * 8];
uint8_t *beg[2 * 2 * 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 {
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;
struct FreeList {
uint32_t i;
void *p[6];
} freelist;
pml4t_t cr3;
uint8_t xmm[2][8][16] aligned(16);
int64_t bofram[2];
jmp_buf onhalt;
int64_t faultaddr;
uint8_t stash[4096];
uint8_t xmmtype[2][8];
struct XedDecodedInst icache[512];
};
void ResetCpu(struct Machine *);
void LoadInstruction(struct Machine *);
void ExecuteInstruction(struct Machine *);
struct Machine *NewMachine(void) nodiscard;
void LoadArgv(struct Machine *, const char *, char **, char **);
void InitMachine(struct Machine *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_MACHINE_H_ */

241
tool/build/lib/memory.c Normal file
View file

@ -0,0 +1,241 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/log/check.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/x/x.h"
#include "tool/build/lib/endian.h"
#include "tool/build/lib/machine.h"
#include "tool/build/lib/memory.h"
#include "tool/build/lib/pml4t.h"
#include "tool/build/lib/stats.h"
#include "tool/build/lib/throw.h"
void SetReadAddr(struct Machine *m, int64_t addr, uint32_t size) {
m->readaddr = addr;
m->readsize = size;
}
void SetWriteAddr(struct Machine *m, int64_t addr, uint32_t size) {
m->writeaddr = addr;
m->writesize = size;
}
void *FindReal(struct Machine *m, int64_t v) {
uint64_t *p;
unsigned skew;
unsigned char i;
skew = v & 0xfff;
v &= -0x1000;
for (i = 0; i < ARRAYLEN(m->tlb); ++i) {
if (m->tlb[i].v == v && m->tlb[i].r) {
return (char *)m->tlb[i].r + skew;
}
}
for (p = m->cr3, i = 39; i >= 12; i -= 9) {
if (IsValidPage(p[(v >> i) & 511])) {
p = UnmaskPageAddr(p[(v >> i) & 511]);
} else {
return NULL;
}
}
m->tlbindex = (m->tlbindex + 1) & (ARRAYLEN(m->tlb) - 1);
m->tlb[m->tlbindex] = m->tlb[0];
m->tlb[0].r = p;
m->tlb[0].v = ROUNDDOWN(v, 0x1000);
DCHECK_NOTNULL(p);
return (char *)p + skew;
}
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 = 0x1000 - (v & 0xfff);
while (n) {
k = MIN(k, n);
p = ResolveAddress(m, v);
memset(p, c, k);
n -= k;
v += k;
k = 0x1000;
}
}
void VirtualCopy(struct Machine *m, int64_t v, char *r, uint64_t n, bool d) {
char *p;
uint64_t k;
k = 0x1000 - (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 = 0x1000;
}
}
void VirtualSend(struct Machine *m, void *dst, int64_t src, uint64_t n) {
VirtualCopy(m, src, dst, n, true);
}
void VirtualRecv(struct Machine *m, int64_t dst, void *src, uint64_t n) {
VirtualCopy(m, dst, src, n, false);
}
void *ReserveAddress(struct Machine *m, int64_t v, size_t n) {
void *r;
DCHECK_LE(n, sizeof(m->stash));
if ((v & 0xfff) + n <= 0x1000) 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[n], bool copy) {
unsigned k;
uint8_t *a, *b;
DCHECK_LE(n, 0x1000);
if ((v & 0xfff) + n <= 0x1000) return ResolveAddress(m, v);
k = 0x1000;
k -= v & 0xfff;
DCHECK_LE(k, 0x1000);
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[n]) {
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[n]) {
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[n]) {
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[n]) {
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[n]) {
uint8_t *a;
unsigned k;
DCHECK_LE(n, 0x1000);
if ((v & 0xfff) + n <= 0x1000) return;
k = 0x1000;
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[n]) {
if (v) EndStore(m, v, n, p, b);
}
void *LoadStr(struct Machine *m, int64_t addr) {
size_t have;
char *copy, *page, *p;
have = 0x1000 - (addr & 0xfff);
if (!addr) return NULL;
if (!(page = FindReal(m, addr))) return NULL;
if ((p = memchr(page, '\0', have))) {
SetReadAddr(m, addr, p - page);
return page;
}
CHECK_LT(m->freelist.i, ARRAYLEN(m->freelist.p));
if (!(copy = malloc(have + 0x1000))) return NULL;
memcpy(copy, page, have);
for (;;) {
if (!(page = FindReal(m, addr + have))) break;
if ((p = memccpy(copy + have, page, '\0', 0x1000))) {
SetReadAddr(m, addr, have + (p - (copy + have)));
return (m->freelist.p[m->freelist.i++] = copy);
}
have += 0x1000;
if (!(p = realloc(copy, have + 0x1000))) break;
copy = p;
}
free(copy);
return NULL;
}
void *LoadBuf(struct Machine *m, int64_t addr, size_t size) {
char *buf, *copy;
size_t have, need;
have = 0x1000 - (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;
memcpy(copy, buf, have);
do {
need = MIN(0x1000, size - have);
if ((buf = FindReal(m, addr + have))) {
memcpy(copy + have, buf, need);
have += need;
} else {
free(copy);
return NULL;
}
} while (have < size);
}
SetReadAddr(m, addr, size);
return buf;
}

32
tool/build/lib/memory.h Normal file
View file

@ -0,0 +1,32 @@
#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_
#define GetSegment(m) 0
int RegisterMemory(struct Machine *, int64_t, void *, size_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 *ReserveAddress(struct Machine *, int64_t, size_t);
void *ResolveAddress(struct Machine *, int64_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 VirtualSend(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_ */

View file

@ -0,0 +1,50 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "tool/build/lib/machine.h"
#include "tool/build/lib/memory.h"
#include "tool/build/lib/pml4t.h"
void *MallocPage(void) {
void *p;
size_t n;
if ((p = memalign(4096, 4096))) {
memset(p, 0, 4096);
}
return p;
}
int RegisterMemory(struct Machine *m, int64_t v, void *r, size_t n) {
return RegisterPml4t(m->cr3, v, (int64_t)(intptr_t)r, n, MallocPage);
}
void ResetRam(struct Machine *m) {
FreePml4t(m->cr3, -0x800000000000, 0x800000000000, free, munmap);
}
struct Machine *NewMachine(void) {
struct Machine *m;
m = memalign(alignof(struct Machine), sizeof(struct Machine));
memset(m, 0, sizeof(struct Machine));
InitMachine(m);
return m;
}

47
tool/build/lib/message.c Normal file
View file

@ -0,0 +1,47 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/log/check.h"
#include "libc/math.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "tool/build/lib/buffer.h"
#include "tool/build/lib/panel.h"
void PrintMessageBox(int fd, const char *msg, long tyn, long txn) {
char buf[1];
struct Buffer b;
int i, w, h, x, y;
h = 2 + 1 + 2;
w = 3 + strlen(msg) + 3;
x = lrint(txn / 2. - w / 2.);
y = lrint(tyn / 2. - h / 2.);
memset(&b, 0, sizeof(b));
AppendFmt(&b, "\e[%d;%dH╔", y++, x);
for (i = 0; i < w - 2; ++i) AppendStr(&b, "");
AppendStr(&b, "");
AppendFmt(&b, "\e[%d;%dH║ %-*s ║", y++, x, w - 6, "");
AppendFmt(&b, "\e[%d;%dH║ %-*s ║", y++, x, w - 6, msg);
AppendFmt(&b, "\e[%d;%dH║ %-*s ║", y++, x, w - 6, "");
AppendFmt(&b, "\e[%d;%dH╚", y++, x);
for (i = 0; i < w - 2; ++i) AppendStr(&b, "");
AppendStr(&b, "");
CHECK_NE(-1, WriteBuffer(&b, fd));
free(b.p);
}

232
tool/build/lib/modrm.c Normal file
View file

@ -0,0 +1,232 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/log/check.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"
/**
* Computes virtual address based on modrm and sib bytes.
*/
int64_t ComputeAddress(const struct Machine *m) {
uint64_t i;
DCHECK(m->xedd->op.has_modrm);
DCHECK(!IsModrmRegister(m->xedd));
i = m->xedd->op.disp;
if (!SibExists(m->xedd)) {
i += IsRipRelative(m->xedd) ? m->ip : Read64(RegRexbRm(m));
} else {
DCHECK(m->xedd->op.has_sib);
if (SibHasBase(m->xedd)) i += Read64(RegRexbBase(m));
if (SibHasIndex(m->xedd)) i += Read64(RegRexxIndex(m)) << m->xedd->op.scale;
}
i += GetSegment(m);
if (Asz(m->xedd)) i &= 0xffffffff;
return i;
}
void *ComputeReserveAddressRead(struct Machine *m, size_t n) {
int64_t v;
v = ComputeAddress(m);
SetReadAddr(m, v, n);
return ReserveAddress(m, v, n);
}
void *ComputeReserveAddressRead1(struct Machine *m) {
return ComputeReserveAddressRead(m, 1);
}
void *ComputeReserveAddressRead8(struct Machine *m) {
return ComputeReserveAddressRead(m, 8);
}
void *ComputeReserveAddressWrite(struct Machine *m, size_t n) {
int64_t v;
v = ComputeAddress(m);
SetWriteAddr(m, v, n);
return ReserveAddress(m, v, n);
}
void *ComputeReserveAddressWrite1(struct Machine *m) {
return ComputeReserveAddressWrite(m, 1);
}
void *ComputeReserveAddressWrite4(struct Machine *m) {
return ComputeReserveAddressWrite(m, 4);
}
void *ComputeReserveAddressWrite8(struct Machine *m) {
return ComputeReserveAddressWrite(m, 8);
}
uint8_t *GetModrmRegisterMmPointerRead(struct Machine *m, size_t n) {
if (IsModrmRegister(m->xedd)) {
return MmRm(m);
} else {
return ComputeReserveAddressRead(m, n);
}
}
uint8_t *GetModrmRegisterMmPointerRead8(struct Machine *m) {
return GetModrmRegisterMmPointerRead(m, 8);
}
uint8_t *GetModrmRegisterMmPointerWrite(struct Machine *m, size_t n) {
if (IsModrmRegister(m->xedd)) {
return MmRm(m);
} else {
return ComputeReserveAddressWrite(m, n);
}
}
uint8_t *GetModrmRegisterMmPointerWrite8(struct Machine *m) {
return GetModrmRegisterMmPointerWrite(m, 8);
}
uint8_t *GetModrmRegisterBytePointerRead(struct Machine *m) {
int64_t v;
if (IsModrmRegister(m->xedd)) {
return ByteRexbRm(m);
} else {
return ComputeReserveAddressRead1(m);
}
}
uint8_t *GetModrmRegisterBytePointerWrite(struct Machine *m) {
int64_t v;
if (IsModrmRegister(m->xedd)) {
return ByteRexbRm(m);
} else {
return ComputeReserveAddressWrite1(m);
}
}
uint8_t *GetModrmRegisterWordPointerRead(struct Machine *m, size_t n) {
if (IsModrmRegister(m->xedd)) {
return RegRexbRm(m);
} else {
return ComputeReserveAddressRead(m, n);
}
}
uint8_t *GetModrmRegisterWordPointerRead2(struct Machine *m) {
return GetModrmRegisterWordPointerRead(m, 2);
}
uint8_t *GetModrmRegisterWordPointerRead4(struct Machine *m) {
return GetModrmRegisterWordPointerRead(m, 4);
}
uint8_t *GetModrmRegisterWordPointerRead8(struct Machine *m) {
return GetModrmRegisterWordPointerRead(m, 8);
}
uint8_t *GetModrmRegisterWordPointerReadOsz(struct Machine *m) {
if (!Osz(m->xedd)) {
return GetModrmRegisterWordPointerRead8(m);
} else {
return GetModrmRegisterWordPointerRead2(m);
}
}
uint8_t *GetModrmRegisterWordPointerReadOszRexw(struct Machine *m) {
if (Rexw(m->xedd)) {
return GetModrmRegisterWordPointerRead8(m);
} else if (!Osz(m->xedd)) {
return GetModrmRegisterWordPointerRead4(m);
} else {
return GetModrmRegisterWordPointerRead2(m);
}
}
uint8_t *GetModrmRegisterWordPointerWrite(struct Machine *m, size_t n) {
if (IsModrmRegister(m->xedd)) {
return RegRexbRm(m);
} else {
return ComputeReserveAddressWrite(m, n);
}
}
uint8_t *GetModrmRegisterWordPointerWrite4(struct Machine *m) {
return GetModrmRegisterWordPointerWrite(m, 4);
}
uint8_t *GetModrmRegisterWordPointerWrite8(struct Machine *m) {
return GetModrmRegisterWordPointerWrite(m, 8);
}
uint8_t *GetModrmRegisterWordPointerWriteOszRexw(struct Machine *m) {
if (Rexw(m->xedd)) {
return GetModrmRegisterWordPointerWrite(m, 8);
} else if (!Osz(m->xedd)) {
return GetModrmRegisterWordPointerWrite(m, 4);
} else {
return GetModrmRegisterWordPointerWrite(m, 2);
}
}
uint8_t *GetModrmRegisterWordPointerWriteOsz(struct Machine *m) {
if (!Osz(m->xedd)) {
return GetModrmRegisterWordPointerWrite(m, 8);
} else {
return GetModrmRegisterWordPointerWrite(m, 2);
}
}
uint8_t *GetModrmRegisterXmmPointerRead(struct Machine *m, size_t n) {
if (IsModrmRegister(m->xedd)) {
return XmmRexbRm(m);
} else {
return ComputeReserveAddressRead(m, n);
}
}
uint8_t *GetModrmRegisterXmmPointerRead4(struct Machine *m) {
return GetModrmRegisterXmmPointerRead(m, 4);
}
uint8_t *GetModrmRegisterXmmPointerRead8(struct Machine *m) {
return GetModrmRegisterXmmPointerRead(m, 8);
}
uint8_t *GetModrmRegisterXmmPointerRead16(struct Machine *m) {
return GetModrmRegisterXmmPointerRead(m, 16);
}
uint8_t *GetModrmRegisterXmmPointerWrite(struct Machine *m, size_t n) {
if (IsModrmRegister(m->xedd)) {
return XmmRexbRm(m);
} else {
return ComputeReserveAddressWrite(m, n);
}
}
uint8_t *GetModrmRegisterXmmPointerWrite4(struct Machine *m) {
return GetModrmRegisterXmmPointerWrite(m, 4);
}
uint8_t *GetModrmRegisterXmmPointerWrite8(struct Machine *m) {
return GetModrmRegisterXmmPointerWrite(m, 8);
}
uint8_t *GetModrmRegisterXmmPointerWrite16(struct Machine *m) {
return GetModrmRegisterXmmPointerWrite(m, 16);
}

82
tool/build/lib/modrm.h Normal file
View file

@ -0,0 +1,82 @@
#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"
#include "tool/build/lib/memory.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define IsModrmRegister(x) (ModrmMod(x) == 3)
#define IsProbablyByteOp(x) !((x)->op.opcode & 1)
#define SibExists(x) (ModrmRm(x) == 4)
#define SibHasIndex(x) (SibIndex(x) != 4 || Rexx(x))
#define SibHasBase(x) (SibBase(x) != 5 || ModrmMod(x))
#define SibIsAbsolute(x) (!SibHasBase(x) && !SibHasIndex(x))
#define IsRipRelative(x) (ModrmRm(x) == 5 && !ModrmMod(x))
#define SibBase(x) (((x)->op.rde & 000007000000) >> 18)
#define SibIndex(x) (((x)->op.rde & 000700000000) >> 24)
#define ModrmRm(x) (((x)->op.rde & 000000000700) >> 6)
#define ModrmReg(x) (((x)->op.rde & 000000000007) >> 0)
#define ModrmSrm(x) (((x)->op.rde & 000000070000) >> 12)
#define ModrmMod(x) (((x)->op.rde & 000060000000) >> 22)
#define RegLog2(x) (((x)->op.rde & 006000000000) >> 28)
#define Rexx(x) (((x)->op.rde & 001000000000) >> 27)
#define Asz(x) (((x)->op.rde & 000000400000) >> 17)
#define Rexw(x) (((x)->op.rde & 000000004000) >> 11)
#define Rexr(x) (((x)->op.rde & 000000000010) >> 3)
#define Rexb(x) (((x)->op.rde & 000010000000) >> 21)
#define Rex(x) (((x)->op.rde & 000000000020) >> 4)
#define Osz(x) (((x)->op.rde & 000000000040) >> 5)
#define Prefix66(x) (((x)->op.rde & 010000000000) >> 30)
#define ByteRexrReg(m) m->beg[(m->xedd->op.rde & 00000000037) >> 0]
#define ByteRexbRm(m) m->beg[(m->xedd->op.rde & 00000003700) >> 6]
#define ByteRexbSrm(m) m->beg[(m->xedd->op.rde & 00000370000) >> 12]
#define RegRexrReg(m) Abp8(m->reg[(m->xedd->op.rde & 00000000017) >> 0])
#define RegRexbRm(m) Abp8(m->reg[(m->xedd->op.rde & 00000001700) >> 6])
#define RegRexbSrm(m) Abp8(m->reg[(m->xedd->op.rde & 00000170000) >> 12])
#define RegRexbBase(m) Abp8(m->reg[(m->xedd->op.rde & 00017000000) >> 18])
#define RegRexxIndex(m) Abp8(m->reg[(m->xedd->op.rde & 01700000000) >> 24])
#define XmmRexrReg(m) Abp16(m->veg[(m->xedd->op.rde & 00000000017) >> 0])
#define XmmRexbRm(m) Abp16(m->veg[(m->xedd->op.rde & 00000001700) >> 6])
#define MmReg(m) Abp16(m->veg[(m->xedd->op.rde & 00000000007) >> 0])
#define MmRm(m) Abp16(m->veg[(m->xedd->op.rde & 00000000700) >> 6])
int64_t ComputeAddress(const struct Machine *) nosideeffect;
void *ComputeReserveAddressRead(struct Machine *, size_t);
void *ComputeReserveAddressRead1(struct Machine *);
void *ComputeReserveAddressRead8(struct Machine *);
void *ComputeReserveAddressWrite(struct Machine *, size_t);
void *ComputeReserveAddressWrite1(struct Machine *);
void *ComputeReserveAddressWrite4(struct Machine *);
void *ComputeReserveAddressWrite8(struct Machine *);
uint8_t *GetModrmRegisterBytePointerRead(struct Machine *);
uint8_t *GetModrmRegisterBytePointerWrite(struct Machine *);
uint8_t *GetModrmRegisterMmPointerRead(struct Machine *, size_t);
uint8_t *GetModrmRegisterMmPointerRead8(struct Machine *);
uint8_t *GetModrmRegisterMmPointerWrite(struct Machine *, size_t);
uint8_t *GetModrmRegisterMmPointerWrite8(struct Machine *);
uint8_t *GetModrmRegisterWordPointerRead(struct Machine *, size_t);
uint8_t *GetModrmRegisterWordPointerRead2(struct Machine *);
uint8_t *GetModrmRegisterWordPointerRead4(struct Machine *);
uint8_t *GetModrmRegisterWordPointerRead8(struct Machine *);
uint8_t *GetModrmRegisterWordPointerReadOsz(struct Machine *);
uint8_t *GetModrmRegisterWordPointerReadOszRexw(struct Machine *);
uint8_t *GetModrmRegisterWordPointerWrite(struct Machine *, size_t);
uint8_t *GetModrmRegisterWordPointerWrite4(struct Machine *);
uint8_t *GetModrmRegisterWordPointerWrite8(struct Machine *);
uint8_t *GetModrmRegisterWordPointerWriteOsz(struct Machine *);
uint8_t *GetModrmRegisterWordPointerWriteOszRexw(struct Machine *);
uint8_t *GetModrmRegisterXmmPointerRead(struct Machine *, size_t);
uint8_t *GetModrmRegisterXmmPointerRead16(struct Machine *);
uint8_t *GetModrmRegisterXmmPointerRead4(struct Machine *);
uint8_t *GetModrmRegisterXmmPointerRead8(struct Machine *);
uint8_t *GetModrmRegisterXmmPointerWrite(struct Machine *, size_t);
uint8_t *GetModrmRegisterXmmPointerWrite16(struct Machine *);
uint8_t *GetModrmRegisterXmmPointerWrite4(struct Machine *);
uint8_t *GetModrmRegisterXmmPointerWrite8(struct Machine *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_MODRM_H_ */

155
tool/build/lib/panel.c Normal file
View file

@ -0,0 +1,155 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/safemacros.h"
#include "libc/conv/conv.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/str/tpdecode.h"
#include "libc/unicode/unicode.h"
#include "tool/build/lib/buffer.h"
#include "tool/build/lib/panel.h"
/**
* Renders panel div flex boxen inside terminal display for tui.
*
* You can use all the UNICODE and ANSI escape sequences you want.
*
* @param fd is file descriptor
* @param pn is number of panels
* @param p is panel list in logically sorted order
* @param tyn is terminal height in cells
* @param txn is terminal width in cells
* @return bytes emitted, or -1 w/ errno
* @see nblack's notcurses project too!
*/
ssize_t PrintPanels(int fd, long pn, struct Panel p[pn], long tyn, long txn) {
wint_t wc;
ssize_t rc;
struct Buffer b, *l;
int x, y, i, j, width;
enum { kUtf8, kAnsi, kAnsiCsi } state;
memset(&b, 0, sizeof(b));
AppendStr(&b, "\e[H");
for (y = 0; y < tyn; ++y) {
if (y) AppendStr(&b, "\r\n");
for (x = i = 0; i < pn; ++i) {
if (p[i].top <= y && y < p[i].bottom) {
j = state = 0;
l = &p[i].lines[y - p[i].top];
while (x < p[i].left) {
AppendChar(&b, ' ');
x += 1;
}
while (x < p[i].right || j < l->i) {
wc = '\0';
width = 0;
if (j < l->i) {
wc = l->p[j];
switch (state) {
case kUtf8:
switch (wc & 0xff) {
case '\e':
state = kAnsi;
++j;
break;
default:
j += abs(tpdecode(l->p + j, &wc));
if (x < p[i].right) {
width = max(0, wcwidth(wc));
} else {
wc = 0;
}
break;
}
break;
case kAnsi:
switch (wc & 0xff) {
case '[':
state = kAnsiCsi;
++j;
break;
case '@':
case ']':
case '^':
case '_':
case '\\':
case 'A' ... 'Z':
state = kUtf8;
++j;
break;
default:
state = kUtf8;
continue;
}
break;
case kAnsiCsi:
switch (wc & 0xff) {
case ':':
case ';':
case '<':
case '=':
case '>':
case '?':
case '0' ... '9':
++j;
break;
case '`':
case '~':
case '^':
case '@':
case '[':
case ']':
case '{':
case '}':
case '_':
case '|':
case '\\':
case 'A' ... 'Z':
case 'a' ... 'z':
state = kUtf8;
++j;
break;
default:
state = kUtf8;
continue;
}
break;
default:
unreachable;
}
if (x > p[i].right) {
break;
}
} else if (x < p[i].right) {
wc = ' ';
width = 1;
}
if (wc) {
x += width;
AppendWide(&b, wc);
}
}
}
}
}
rc = WriteBuffer(&b, fd);
free(b.p);
return rc;
}

19
tool/build/lib/panel.h Normal file
View file

@ -0,0 +1,19 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_PANEL_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_PANEL_H_
#include "tool/build/lib/buffer.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct Panel {
int i;
int top, bottom;
int left, right;
struct Buffer *lines;
};
ssize_t PrintPanels(int, long, struct Panel *, long, long);
void PrintMessageBox(int, const char *, long, long);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_PANEL_H_ */

218
tool/build/lib/pml4t.c Normal file
View file

@ -0,0 +1,218 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/log/check.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
#include "tool/build/lib/memory.h"
#include "tool/build/lib/pml4t.h"
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 SignExtendAddr(x);
}
static uint64_t *GetPageTable(pml4t_t p, long i, void *NewPhysicalPage(void)) {
uint64_t *res;
DCHECK_ALIGNED(4096, p);
DCHECK(0 <= i && i < 512);
if (IsValidPage(p[i])) {
res = UnmaskPageAddr(p[i]);
} else if ((res = NewPhysicalPage())) {
DCHECK_ALIGNED(4096, res);
p[i] = MaskPageAddr(res) | 0b11;
}
return res;
}
/**
* Maps virtual page region to system memory region.
*
* @param pml4t is root of 48-bit page tables
* @param v is fixed page-aligned virtual address, rounded down
* @param r is real memory address, rounded down
* @param n is number of bytes needed, rounded up
* @return 0 on success, or -1 w/ errno
* @note existing pages are overwritten
*/
int RegisterPml4t(pml4t_t pml4t, int64_t v, int64_t r, size_t n,
void *NewPhysicalPage(void)) {
unsigned i, j, k, l;
uint64_t *pdpt, *pdt, *pd, u;
if (!n) return 0;
u = ROUNDDOWN(r, 4096);
n = ROUNDUP(n, 4096) >> 12;
i = (v >> 39) & 511;
j = (v >> 30) & 511;
k = (v >> 21) & 511;
l = (v >> 12) & 511;
if (u + n > 0x800000000000) return eoverflow();
if (r + n > 0x800000000000) return eoverflow();
for (; i < 512; ++i) {
if (!(pdpt = GetPageTable(pml4t, i, NewPhysicalPage))) return -1;
for (; j < 512; ++j) {
if (!(pdt = GetPageTable(pdpt, j, NewPhysicalPage))) return -1;
for (; k < 512; ++k) {
if (!(pd = GetPageTable(pdt, k, NewPhysicalPage))) return -1;
for (; l < 512; ++l) {
pd[l] = MaskPageAddr(u) | 0b11;
if (!--n) return 0;
u += 4096;
}
l = 0;
}
k = 0;
}
j = 0;
}
return enomem();
}
/**
* Locates free memory range.
*
* @param hint specifies signedness and around where to start searching
* @return virtual page address with size bytes free, or -1 w/ errno
*/
int64_t FindPml4t(pml4t_t pml4t, int64_t hint, uint64_t size,
void *NewPhysicalPage(void)) {
int64_t res;
unsigned short a[4], b[4];
uint64_t *pdpt, *pdt, *pd, have;
if (!size) return einval();
have = 0;
size = ROUNDUP(size, 4096) >> 12;
b[0] = a[0] = (hint >> 39) & 511;
b[1] = a[1] = (hint >> 30) & 511;
b[2] = a[2] = (hint >> 21) & 511;
a[3] = 0;
for (; b[0] < 512; ++b[0]) {
if (!(pdpt = GetPageTable(pml4t, b[0], NewPhysicalPage))) return -1;
for (; b[1] < 512; ++b[1]) {
if (!(pdt = GetPageTable(pdpt, b[1], NewPhysicalPage))) return -1;
for (; b[2] < 512; ++b[2]) {
if (!IsValidPage(pdt[b[2]])) {
if ((have += 512) >= size) {
return MakeAddress(a);
}
} else if (size < 0x200) {
pd = UnmaskPageAddr(pdt[b[2]]);
for (b[3] = 0; b[3] < 512; ++b[3]) {
if (!IsValidPage(pd[b[3]])) {
if ((have += 1) >= size) {
return MakeAddress(a);
}
} else {
have = 0;
a[0] = b[0];
a[1] = b[1];
a[2] = b[2];
a[3] = b[3];
if ((a[3] += 1) == 512) {
a[3] = 0;
if ((a[2] += 1) == 512) {
a[2] = 0;
if ((a[1] += 1) == 512) {
a[1] = 0;
a[0] += 1;
if (a[0] == 256 || a[0] == 512) {
return eoverflow();
}
}
}
}
}
}
}
}
a[2] = 0;
}
a[1] = 0;
}
return enomem();
}
/**
* Unmaps pages and frees page tables.
*/
int FreePml4t(pml4t_t pml4t, int64_t addr, uint64_t size,
void FreePhysicalPageTable(void *),
int FreePhysicalPages(void *, size_t)) {
int rc;
char *pages;
uint64_t i, *pdpt, *pdt, *pd;
unsigned short r, s[4], a[4], R[2][2] = {{256, 512}, {0, 256}};
a[0] = addr >> 39;
a[1] = addr >> 30;
a[2] = addr >> 21;
a[3] = addr >> 12;
size = ROUNDUP(size, 4096) >> 12;
for (rc = r = 0; r < ARRAYLEN(R); ++r) {
for (a[0] &= 511; size && R[r][0] <= a[0] && a[0] < R[r][1]; ++a[0]) {
if (!IsValidPage(pml4t[a[0]])) continue;
pdpt = UnmaskPageAddr(pml4t[a[0]]);
for (s[1] = (a[1] &= 511); size && a[1] < 512; ++a[1]) {
if (!IsValidPage(pdpt[a[1]])) continue;
pdt = UnmaskPageAddr(pdpt[a[1]]);
for (s[2] = (a[2] &= 511); size && a[2] < 512; ++a[2]) {
if (!IsValidPage(pdt[a[2]])) continue;
pd = UnmaskPageAddr(pdt[a[2]]);
for (s[3] = (a[3] &= 511); size && a[3] < 512; ++a[3]) {
if (IsValidPage(pd[a[3]])) {
pages = UnmaskPageAddr(pd[a[3]]);
pd[a[3]] = 0;
for (i = 1; i + 1 < size && a[3] + i < 512; ++i) {
if (!IsValidPage(pd[a[3] + i])) break;
if (UnmaskPageAddr(pd[a[3] + i]) != pages + i * 4096) break;
pd[a[3] + i] = 0;
}
FreePhysicalPages(pages, i * 4096);
a[3] += i - 1;
size -= i;
}
}
if (s[3] == 0 && a[3] == 512) {
FreePhysicalPageTable(pd);
pdt[a[2]] = 0;
}
}
if (s[2] == 0 && a[2] == 512) {
FreePhysicalPageTable(pdt);
pdpt[a[1]] = 0;
}
}
if (s[1] == 0 && a[1] == 512) {
FreePhysicalPageTable(pdpt);
pml4t[a[0]] = 0;
}
}
}
return 0;
}

21
tool/build/lib/pml4t.h Normal file
View file

@ -0,0 +1,21 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_PML4T_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_PML4T_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define IsValidPage(x) ((x)&1)
#define UnmaskPageAddr(x) ((void *)SignExtendAddr(MaskPageAddr(x)))
#define MaskPageAddr(x) ((int64_t)(intptr_t)(x)&0x00007ffffffff000)
#define SignExtendAddr(x) (!((x)&0x800000000000) ? (x) : (x) | -0x800000000000)
typedef uint64_t pml4t_t[512] aligned(4096);
int FreePml4t(pml4t_t, int64_t, uint64_t, void (*)(void *),
int (*)(void *, size_t));
int RegisterPml4t(pml4t_t, int64_t, int64_t, size_t, void *(*)(void));
int64_t FindPml4t(pml4t_t, int64_t, uint64_t, void *(*)(void));
char *FormatPml4t(pml4t_t) nodiscard;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_PML4T_H_ */

112
tool/build/lib/pml4tfmt.c Normal file
View file

@ -0,0 +1,112 @@
/*-*- mode:c;indent-tabs-mode:nil;c-bansic-offset:2;tab-width:8;coding:utf-8
-*- vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "tool/build/lib/buffer.h"
#include "tool/build/lib/memory.h"
#include "tool/build/lib/pml4t.h"
struct Pml4tFormater {
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 Pml4tFormater *pp, int64_t start) {
pp->t = true;
pp->start = start;
if (pp->lines++) AppendChar(&pp->b, '\n');
AppendFmt(&pp->b, "%p-", start);
}
static void FormatEndPage(struct Pml4tFormater *pp, int64_t end) {
int64_t size;
pp->t = false;
size = end - pp->start;
AppendFmt(&pp->b, "%p %p %,ld bytes", end - 1, size, size);
}
char *FormatPml4t(uint64_t pml4t[512]) {
uint64_t *pd[4];
unsigned short i, a[4];
struct Pml4tFormater pp = {0};
unsigned short range[][2] = {{256, 512}, {0, 256}};
pd[0] = pml4t;
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] = 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] = 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] = 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) {
realloc(pp.b.p, pp.b.i + 1);
return pp.b.p;
} else {
return strdup("");
}
}

78
tool/build/lib/reset.c Normal file
View file

@ -0,0 +1,78 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
#include "libc/math.h"
#include "libc/str/str.h"
#include "tool/build/lib/flags.h"
#include "tool/build/lib/machine.h"
#define LDBL 3
#define RINT 0
static void ResetFpu(struct Machine *m) {
long i;
long double fval;
fval = -NAN;
m->fpu.sw = 0;
m->fpu.tw = -1;
m->fpu.cw = 0;
m->fpu.im = true;
m->fpu.dm = true;
m->fpu.zm = true;
m->fpu.om = true;
m->fpu.um = true;
m->fpu.pm = true;
m->fpu.pc = LDBL;
m->fpu.rc = RINT;
for (i = 0; i < ARRAYLEN(m->fpu.st); ++i) {
memcpy(&m->fpu.st[i], &fval, sizeof(fval));
}
}
static void ResetSse(struct Machine *m) {
m->sse.mxcsr = 0;
m->sse.daz = false;
m->sse.im = true;
m->sse.dm = true;
m->sse.zm = true;
m->sse.om = true;
m->sse.um = true;
m->sse.pm = true;
m->sse.rc = RINT;
m->sse.ftz = false;
memset(m->xmm, 0, sizeof(m->xmm));
memset(m->xmmtype, 0, sizeof(m->xmmtype));
}
void ResetCpu(struct Machine *m) {
InitMachine(m);
m->flags = SetFlag(m->flags, FLAGS_DF, false);
m->flags = SetFlag(m->flags, FLAGS_CF, false);
m->flags = SetFlag(m->flags, FLAGS_ZF, false);
m->flags = SetFlag(m->flags, FLAGS_SF, false);
m->flags = SetFlag(m->flags, FLAGS_IF, true);
m->flags = SetFlag(m->flags, FLAGS_F1, true);
m->flags = SetFlag(m->flags, FLAGS_F0, false);
m->flags = SetFlag(m->flags, FLAGS_IOPL, 3);
memset(m->reg, 0, sizeof(m->reg));
memset(m->bofram, 0, sizeof(m->bofram));
ResetSse(m);
ResetFpu(m);
}

255
tool/build/lib/sse.c Normal file
View file

@ -0,0 +1,255 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/intrin/pabsb.h"
#include "libc/intrin/pabsd.h"
#include "libc/intrin/pabsw.h"
#include "libc/intrin/packssdw.h"
#include "libc/intrin/packsswb.h"
#include "libc/intrin/packuswb.h"
#include "libc/intrin/paddb.h"
#include "libc/intrin/paddd.h"
#include "libc/intrin/paddq.h"
#include "libc/intrin/paddsb.h"
#include "libc/intrin/paddsw.h"
#include "libc/intrin/paddusb.h"
#include "libc/intrin/paddusw.h"
#include "libc/intrin/paddw.h"
#include "libc/intrin/palignr.h"
#include "libc/intrin/pand.h"
#include "libc/intrin/pandn.h"
#include "libc/intrin/pavgb.h"
#include "libc/intrin/pavgw.h"
#include "libc/intrin/pcmpeqb.h"
#include "libc/intrin/pcmpeqd.h"
#include "libc/intrin/pcmpeqw.h"
#include "libc/intrin/pcmpgtb.h"
#include "libc/intrin/pcmpgtd.h"
#include "libc/intrin/pcmpgtw.h"
#include "libc/intrin/phaddd.h"
#include "libc/intrin/phaddsw.h"
#include "libc/intrin/phaddw.h"
#include "libc/intrin/phsubd.h"
#include "libc/intrin/phsubsw.h"
#include "libc/intrin/phsubw.h"
#include "libc/intrin/pmaddubsw.h"
#include "libc/intrin/pmaddwd.h"
#include "libc/intrin/pmaxsw.h"
#include "libc/intrin/pmaxub.h"
#include "libc/intrin/pminsw.h"
#include "libc/intrin/pminub.h"
#include "libc/intrin/pmulhrsw.h"
#include "libc/intrin/pmulhuw.h"
#include "libc/intrin/pmulhw.h"
#include "libc/intrin/pmulld.h"
#include "libc/intrin/pmullw.h"
#include "libc/intrin/pmuludq.h"
#include "libc/intrin/por.h"
#include "libc/intrin/psadbw.h"
#include "libc/intrin/pshufb.h"
#include "libc/intrin/psignb.h"
#include "libc/intrin/psignd.h"
#include "libc/intrin/psignw.h"
#include "libc/intrin/pslld.h"
#include "libc/intrin/pslldq.h"
#include "libc/intrin/psllq.h"
#include "libc/intrin/psllw.h"
#include "libc/intrin/psrad.h"
#include "libc/intrin/psraw.h"
#include "libc/intrin/psrld.h"
#include "libc/intrin/psrldq.h"
#include "libc/intrin/psrlq.h"
#include "libc/intrin/psrlw.h"
#include "libc/intrin/psubb.h"
#include "libc/intrin/psubd.h"
#include "libc/intrin/psubq.h"
#include "libc/intrin/psubsb.h"
#include "libc/intrin/psubsw.h"
#include "libc/intrin/psubusb.h"
#include "libc/intrin/psubusw.h"
#include "libc/intrin/psubw.h"
#include "libc/intrin/punpckhbw.h"
#include "libc/intrin/punpckhdq.h"
#include "libc/intrin/punpckhqdq.h"
#include "libc/intrin/punpckhwd.h"
#include "libc/intrin/punpcklbw.h"
#include "libc/intrin/punpckldq.h"
#include "libc/intrin/punpcklqdq.h"
#include "libc/intrin/punpcklwd.h"
#include "libc/intrin/pxor.h"
#include "libc/macros.h"
#include "libc/str/str.h"
#include "tool/build/lib/case.h"
#include "tool/build/lib/machine.h"
#include "tool/build/lib/memory.h"
#include "tool/build/lib/modrm.h"
#include "tool/build/lib/sse.h"
union MachineVector {
float f32[4];
double f64[2];
int8_t i8[16];
int16_t i16[8];
int32_t i32[4];
int64_t i64[2];
uint8_t u8[16];
uint16_t u16[8];
uint32_t u32[4];
uint64_t u64[2];
};
void OpSse(struct Machine *m, enum OpSseKernel kernel) {
int i;
uint8_t *p;
union MachineVector x, y, t;
p = GetModrmRegisterXmmPointerRead16(m);
if (Prefix66(m->xedd)) {
memcpy(&y, p, 16);
} else {
memset(&t, 0, 16);
memcpy(&t, p, 8);
memcpy(&y, &t, 16);
}
memcpy(&x, XmmRexrReg(m), 16);
switch (kernel) {
CASE(kOpSsePsubb, psubb(x.i8, x.i8, y.i8));
CASE(kOpSsePaddb, paddb(x.i8, x.i8, y.i8));
CASE(kOpSsePsubw, psubw(x.i16, x.i16, y.i16));
CASE(kOpSsePaddw, paddw(x.i16, x.i16, y.i16));
CASE(kOpSsePsubd, psubd(x.i32, x.i32, y.i32));
CASE(kOpSsePaddd, paddd(x.i32, x.i32, y.i32));
CASE(kOpSsePaddq, paddq(x.i64, x.i64, y.i64));
CASE(kOpSsePsubq, psubq(x.i64, x.i64, y.i64));
CASE(kOpSsePsubsb, psubsb(x.i8, x.i8, y.i8));
CASE(kOpSsePsubsw, psubsw(x.i16, x.i16, y.i16));
CASE(kOpSsePaddsb, paddsb(x.i8, x.i8, y.i8));
CASE(kOpSsePaddsw, paddsw(x.i16, x.i16, y.i16));
CASE(kOpSsePaddusb, paddusb(x.u8, x.u8, y.u8));
CASE(kOpSsePaddusw, paddusw(x.u16, x.u16, y.u16));
CASE(kOpSsePor, por(x.u64, x.u64, y.u64));
CASE(kOpSsePxor, pxor(x.u64, x.u64, y.u64));
CASE(kOpSsePand, pand(x.u64, x.u64, y.u64));
CASE(kOpSsePandn, pandn(x.u64, x.u64, y.u64));
CASE(kOpSsePsubusb, psubusb(x.u8, x.u8, y.u8));
CASE(kOpSsePsubusw, psubusw(x.u16, x.u16, y.u16));
CASE(kOpSsePminub, pminub(x.u8, x.u8, y.u8));
CASE(kOpSsePmaxub, pmaxub(x.u8, x.u8, y.u8));
CASE(kOpSsePminsw, pminsw(x.i16, x.i16, y.i16));
CASE(kOpSsePmaxsw, pmaxsw(x.i16, x.i16, y.i16));
CASE(kOpSsePunpcklbw, punpcklbw(x.u8, x.u8, y.u8));
CASE(kOpSsePunpckhbw, punpckhbw(x.u8, x.u8, y.u8));
CASE(kOpSsePunpcklwd, punpcklwd(x.u16, x.u16, y.u16));
CASE(kOpSsePunpckldq, punpckldq(x.u32, x.u32, y.u32));
CASE(kOpSsePunpckhwd, punpckhwd(x.u16, x.u16, y.u16));
CASE(kOpSsePunpckhdq, punpckhdq(x.u32, x.u32, y.u32));
CASE(kOpSsePunpcklqdq, punpcklqdq(x.u64, x.u64, y.u64));
CASE(kOpSsePunpckhqdq, punpckhqdq(x.u64, x.u64, y.u64));
CASE(kOpSsePacksswb, packsswb(x.i8, x.i16, y.i16));
CASE(kOpSsePackuswb, packuswb(x.u8, x.i16, y.i16));
CASE(kOpSsePackssdw, packssdw(x.i16, x.i32, y.i32));
CASE(kOpSsePcmpgtb, pcmpgtb(x.i8, x.i8, y.i8));
CASE(kOpSsePcmpgtw, pcmpgtw(x.i16, x.i16, y.i16));
CASE(kOpSsePcmpgtd, pcmpgtd(x.i32, x.i32, y.i32));
CASE(kOpSsePcmpeqb, pcmpeqb(x.u8, x.u8, y.u8));
CASE(kOpSsePcmpeqw, pcmpeqw(x.i16, x.i16, y.i16));
CASE(kOpSsePcmpeqd, pcmpeqd(x.i32, x.i32, y.i32));
CASE(kOpSsePsrawv, psrawv(x.i16, x.i16, y.u64));
CASE(kOpSsePsrlwv, psrlwv(x.u16, x.u16, y.u64));
CASE(kOpSsePsllwv, psllwv(x.u16, x.u16, y.u64));
CASE(kOpSsePsradv, psradv(x.i32, x.i32, y.u64));
CASE(kOpSsePsrldv, psrldv(x.u32, x.u32, y.u64));
CASE(kOpSsePslldv, pslldv(x.u32, x.u32, y.u64));
CASE(kOpSsePsrlqv, psrlqv(x.u64, x.u64, y.u64));
CASE(kOpSsePsllqv, psllqv(x.u64, x.u64, y.u64));
CASE(kOpSsePavgb, pavgb(x.u8, x.u8, y.u8));
CASE(kOpSsePavgw, pavgw(x.u16, x.u16, y.u16));
CASE(kOpSsePsadbw, psadbw(x.u64, x.u8, y.u8));
CASE(kOpSsePmaddwd, pmaddwd(x.i32, x.i16, y.i16));
CASE(kOpSsePmulhuw, pmulhuw(x.u16, x.u16, y.u16));
CASE(kOpSsePmulhw, pmulhw(x.i16, x.i16, y.i16));
CASE(kOpSsePmuludq, pmuludq(x.u64, x.u32, y.u32));
CASE(kOpSsePmullw, pmullw(x.i16, x.i16, y.i16));
CASE(kOpSsePmulld, pmulld(x.i32, x.i32, y.i32));
CASE(kOpSsePshufb, pshufb(x.u8, x.u8, y.u8));
CASE(kOpSsePhaddw, phaddw(x.i16, x.i16, y.i16));
CASE(kOpSsePhaddd, phaddd(x.i32, x.i32, y.i32));
CASE(kOpSsePhaddsw, phaddsw(x.i16, x.i16, y.i16));
CASE(kOpSsePmaddubsw, pmaddubsw(x.i16, x.u8, y.i8));
CASE(kOpSsePhsubw, phsubw(x.i16, x.i16, y.i16));
CASE(kOpSsePhsubd, phsubd(x.i32, x.i32, y.i32));
CASE(kOpSsePhsubsw, phsubsw(x.i16, x.i16, y.i16));
CASE(kOpSsePsignb, psignb(x.i8, x.i8, y.i8));
CASE(kOpSsePsignw, psignw(x.i16, x.i16, y.i16));
CASE(kOpSsePsignd, psignd(x.i32, x.i32, y.i32));
CASE(kOpSsePmulhrsw, pmulhrsw(x.i16, x.i16, y.i16));
CASE(kOpSsePabsb, pabsb(x.u8, x.i8));
CASE(kOpSsePabsw, pabsw(x.u16, x.i16));
CASE(kOpSsePabsd, pabsd(x.u32, x.i32));
default:
unreachable;
}
if (Prefix66(m->xedd)) {
memcpy(XmmRexrReg(m), &x, 16);
} else {
memcpy(XmmRexrReg(m), &x, 8);
}
}
void OpSseUdqIb(struct Machine *m, enum OpSseUdqIbKernel kernel) {
uint8_t i;
union MachineVector x;
i = m->xedd->op.uimm0;
memcpy(&x, XmmRexbRm(m), 16);
switch (kernel) {
CASE(kOpSseUdqIbPsrlw, (psrlw)(x.u16, x.u16, i));
CASE(kOpSseUdqIbPsraw, (psraw)(x.i16, x.i16, i));
CASE(kOpSseUdqIbPsllw, (psllw)(x.u16, x.u16, i));
CASE(kOpSseUdqIbPsrld, (psrld)(x.u32, x.u32, i));
CASE(kOpSseUdqIbPsrad, (psrad)(x.i32, x.i32, i));
CASE(kOpSseUdqIbPslld, (pslld)(x.u32, x.u32, i));
CASE(kOpSseUdqIbPsrlq, (psrlq)(x.u64, x.u64, i));
CASE(kOpSseUdqIbPsrldq, (psrldq)(x.u8, x.u8, i));
CASE(kOpSseUdqIbPsllq, (psllq)(x.u64, x.u64, i));
CASE(kOpSseUdqIbPslldq, (pslldq)(x.u8, x.u8, i));
default:
unreachable;
}
if (Prefix66(m->xedd)) {
memcpy(XmmRexbRm(m), &x, 16);
} else {
memcpy(XmmRexbRm(m), &x, 8);
}
}
static void OpSsePalignrMmx(struct Machine *m) {
char t[24];
memcpy(t, GetModrmRegisterXmmPointerRead8(m), 8);
memcpy(t + 8, XmmRexrReg(m), 8);
memset(t + 16, 0, 8);
memcpy(XmmRexrReg(m), t + MIN(m->xedd->op.uimm0, 16), 8);
}
void OpSsePalignr(struct Machine *m) {
if (Prefix66(m->xedd)) {
palignr(XmmRexrReg(m), XmmRexrReg(m), GetModrmRegisterXmmPointerRead8(m),
m->xedd->op.uimm0);
} else {
OpSsePalignrMmx(m);
}
}

102
tool/build/lib/sse.h Normal file
View file

@ -0,0 +1,102 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_SSE_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_SSE_H_
#include "tool/build/lib/machine.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
enum OpSseKernel {
kOpSsePaddb,
kOpSsePaddw,
kOpSsePaddd,
kOpSsePaddq,
kOpSsePsubb,
kOpSsePsubw,
kOpSsePsubd,
kOpSsePsubq,
kOpSsePaddsb,
kOpSsePaddsw,
kOpSsePaddusb,
kOpSsePaddusw,
kOpSsePsubsb,
kOpSsePsubsw,
kOpSsePor,
kOpSsePxor,
kOpSsePand,
kOpSsePandn,
kOpSsePsubusb,
kOpSsePsubusw,
kOpSsePminub,
kOpSsePmaxub,
kOpSsePminsw,
kOpSsePmaxsw,
kOpSsePunpcklbw,
kOpSsePunpckhbw,
kOpSsePunpcklwd,
kOpSsePunpckldq,
kOpSsePunpckhwd,
kOpSsePunpckhdq,
kOpSsePunpcklqdq,
kOpSsePunpckhqdq,
kOpSsePacksswb,
kOpSsePackuswb,
kOpSsePackssdw,
kOpSsePcmpgtb,
kOpSsePcmpgtw,
kOpSsePcmpgtd,
kOpSsePcmpeqb,
kOpSsePcmpeqw,
kOpSsePcmpeqd,
kOpSsePsrawv,
kOpSsePsradv,
kOpSsePsrlwv,
kOpSsePsrldv,
kOpSsePsrlqv,
kOpSsePsllwv,
kOpSsePslldv,
kOpSsePsllqv,
kOpSsePavgb,
kOpSsePavgw,
kOpSsePmulhuw,
kOpSsePmulhw,
kOpSsePmuludq,
kOpSsePmaddwd,
kOpSsePmullw,
kOpSsePmulld,
kOpSsePsadbw,
kOpSsePshufb,
kOpSsePhaddw,
kOpSsePhaddd,
kOpSsePhaddsw,
kOpSsePmaddubsw,
kOpSsePhsubw,
kOpSsePhsubd,
kOpSsePhsubsw,
kOpSsePsignb,
kOpSsePsignw,
kOpSsePsignd,
kOpSsePmulhrsw,
kOpSsePabsb,
kOpSsePabsw,
kOpSsePabsd,
};
enum OpSseUdqIbKernel {
kOpSseUdqIbPsrlw,
kOpSseUdqIbPsraw,
kOpSseUdqIbPsllw,
kOpSseUdqIbPsrld,
kOpSseUdqIbPsrad,
kOpSseUdqIbPslld,
kOpSseUdqIbPsrlq,
kOpSseUdqIbPsrldq,
kOpSseUdqIbPsllq,
kOpSseUdqIbPslldq,
};
void OpSse(struct Machine *, enum OpSseKernel);
void OpSseUdqIb(struct Machine *, enum OpSseUdqIbKernel);
void OpSsePalignr(struct Machine *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_SSE_H_ */

102
tool/build/lib/stack.c Normal file
View file

@ -0,0 +1,102 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/log/check.h"
#include "libc/macros.h"
#include "tool/build/lib/endian.h"
#include "tool/build/lib/memory.h"
#include "tool/build/lib/modrm.h"
#include "tool/build/lib/stack.h"
void Push64(struct Machine *m, uint64_t x) {
uint64_t v;
void *p[2];
uint8_t b[8];
v = Read64(m->sp);
v -= 8;
Write64(m->sp, v);
Write64(AccessRam(m, v, 8, p, b, false), x);
EndStore(m, v, 8, p, b);
}
void Push16(struct Machine *m, uint16_t x) {
uint64_t v;
void *p[2];
uint8_t b[2];
v = Read64(m->sp);
v -= 2;
Write64(m->sp, v);
Write16(b, x);
Write64(AccessRam(m, v, 2, p, b, false), x);
EndStore(m, v, 2, p, b);
}
uint64_t Pop64(struct Machine *m, uint16_t extra) {
void *p[2];
uint8_t b[8];
uint64_t v, x;
v = Read64(m->sp);
x = Read64(AccessRam(m, v, 8, p, b, true));
Write64(m->sp, v + 8 + extra);
return x;
}
uint16_t Pop16(struct Machine *m, uint16_t extra) {
void *p[2];
uint8_t b[2];
uint16_t v, x;
v = Read64(m->sp);
x = Read16(AccessRam(m, v, 2, p, b, true));
Write64(m->sp, v + 2 + extra);
return x;
}
static void OpCall(struct Machine *m, uint64_t func) {
Push64(m, m->ip);
m->ip = func;
}
void OpCallJvds(struct Machine *m) {
OpCall(m, m->ip + m->xedd->op.disp);
}
void OpCallEq(struct Machine *m) {
void *p[2];
uint8_t b[8];
OpCall(m, Read64(IsModrmRegister(m->xedd)
? RegRexbRm(m)
: AccessRam(m, ComputeAddress(m), 8, p, b, true)));
}
void OpLeave(struct Machine *m) {
memcpy(m->sp, m->bp, sizeof(m->sp));
Write64(m->bp, Pop64(m, 0));
}
void OpRet(struct Machine *m, uint16_t n) {
m->ip = Pop64(m, n);
}
void PushOsz(struct Machine *m, uint64_t x) {
if (!Osz(m->xedd)) {
Push64(m, x);
} else {
Push16(m, x);
}
}

19
tool/build/lib/stack.h Normal file
View file

@ -0,0 +1,19 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_STACK_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_STACK_H_
#include "tool/build/lib/machine.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void Push64(struct Machine *, uint64_t);
uint64_t Pop64(struct Machine *, uint16_t);
void Push16(struct Machine *, uint16_t);
uint16_t Pop16(struct Machine *, uint16_t);
void OpCallJvds(struct Machine *);
void OpRet(struct Machine *, uint16_t);
void OpLeave(struct Machine *);
void PushOsz(struct Machine *, uint64_t);
void OpCallEq(struct Machine *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_STACK_H_ */

24
tool/build/lib/stats.c Normal file
View file

@ -0,0 +1,24 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "tool/build/lib/stats.h"
unsigned long ops;
unsigned long taken;
unsigned long ntaken;

12
tool/build/lib/stats.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_STATS_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_STATS_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern unsigned long ops;
extern unsigned long taken;
extern unsigned long ntaken;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_STATS_H_ */

227
tool/build/lib/string.c Normal file
View file

@ -0,0 +1,227 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/runtime/runtime.h"
#include "tool/build/lib/alu.h"
#include "tool/build/lib/endian.h"
#include "tool/build/lib/flags.h"
#include "tool/build/lib/ioports.h"
#include "tool/build/lib/machine.h"
#include "tool/build/lib/memory.h"
#include "tool/build/lib/modrm.h"
#include "tool/build/lib/string.h"
#include "tool/build/lib/throw.h"
static uint64_t ReadInt(uint8_t p[8], unsigned long w) {
switch (w) {
case 0:
return Read8(p);
case 1:
return Read16(p);
case 2:
return Read32(p);
case 3:
return Read64(p);
default:
unreachable;
}
}
static void WriteInt(uint8_t p[8], uint64_t x, unsigned long w) {
switch (w) {
case 0:
Write8(p, x);
break;
case 1:
Write16(p, x);
break;
case 2:
Write64(p, x);
break;
case 3:
Write64(p, x);
break;
default:
unreachable;
}
}
void OpString(struct Machine *m, int op) {
void *p[2];
bool compare;
int64_t sgn, v;
uint8_t s[3][8];
unsigned n, lg2;
uint64_t asz, seg;
sgn = GetFlag(m->flags, FLAGS_DF) ? -1 : 1;
asz = Asz(m->xedd) ? 0xffffffff : 0xffffffffffffffff;
seg = GetSegment(m);
lg2 = RegLog2(m->xedd);
n = 1 << lg2;
for (;;) {
if (m->xedd->op.rep && !Read64(m->cx)) break;
v = 0;
*p = NULL;
compare = false;
switch (op) {
case STRING_CMPS:
Alu(lg2, ALU_SUB,
ReadInt(Load(m, (Read64(m->si) + seg) & asz, n, s[2]), lg2),
ReadInt(Load(m, Read64(m->di) & asz, n, s[1]), lg2), &m->flags);
Write64(m->di, (Read64(m->di) + sgn * n) & asz);
Write64(m->si, (Read64(m->si) + sgn * n) & asz);
compare = true;
break;
case STRING_MOVS:
memcpy(BeginStore(m, (v = Read64(m->di) & asz), n, p, s[0]),
Load(m, (Read64(m->si) + seg) & asz, n, s[1]), n);
Write64(m->di, (Read64(m->di) + sgn * n) & asz);
Write64(m->si, (Read64(m->si) + sgn * n) & asz);
break;
case STRING_STOS:
memcpy(BeginStore(m, (v = Read64(m->di) & asz), n, p, s[0]), m->ax, n);
Write64(m->di, (Read64(m->di) + sgn * n) & asz);
break;
case STRING_LODS:
memcpy(m->ax, Load(m, (Read64(m->si) + seg) & asz, n, s[1]), n);
Write64(m->si, (Read64(m->si) + sgn * n) & asz);
break;
case STRING_SCAS:
Alu(lg2, ALU_SUB, ReadInt(Load(m, Read64(m->di) & asz, n, s[1]), lg2),
ReadInt(m->ax, lg2), &m->flags);
Write64(m->di, (Read64(m->di) + sgn * n) & asz);
compare = true;
break;
case STRING_OUTS:
OpOut(m, Read16(m->dx),
ReadInt(Load(m, (Read64(m->si) + seg) & asz, n, s[1]), lg2));
Write64(m->si, (Read64(m->si) + sgn * n) & asz);
break;
case STRING_INS:
WriteInt(BeginStore(m, (v = Read64(m->di) & asz), n, p, s[0]),
OpIn(m, Read16(m->dx)), lg2);
Write64(m->di, (Read64(m->di) + sgn * n) & asz);
break;
default:
abort();
}
EndStore(m, v, n, p, s[0]);
if (!m->xedd->op.rep) break;
Write64(m->cx, Read64(m->cx) - 1);
if (compare) {
if (m->xedd->op.rep == 2 && GetFlag(m->flags, FLAGS_ZF)) break;
if (m->xedd->op.rep == 3 && !GetFlag(m->flags, FLAGS_ZF)) break;
}
}
}
void OpRepMovsbEnhanced(struct Machine *m) {
bool failed;
uint8_t *direal, *sireal;
unsigned diremain, siremain, i, n;
uint64_t divirtual, sivirtual, diactual, siactual, failaddr, seg, asz, cx;
if (!(cx = Read64(m->cx))) return;
failed = false;
failaddr = 0;
seg = GetSegment(m);
asz = Asz(m->xedd) ? 0xffffffff : 0xffffffffffffffff;
divirtual = Read64(m->di) & asz;
sivirtual = Read64(m->si) & asz;
SetWriteAddr(m, (seg + divirtual) & asz, cx);
SetReadAddr(m, (seg + sivirtual) & asz, cx);
do {
diactual = (seg + divirtual) & asz;
siactual = (seg + sivirtual) & asz;
if (!(direal = FindReal(m, diactual))) {
failaddr = diactual;
failed = true;
break;
}
if (!(sireal = FindReal(m, siactual))) {
failaddr = siactual;
failed = true;
break;
}
diremain = 0x1000 - (divirtual & 0xfff);
siremain = 0x1000 - (sivirtual & 0xfff);
n = MIN(cx, MIN(diremain, siremain));
for (i = 0; i < n; ++i) {
direal[i] = sireal[i];
}
cx -= n;
divirtual = (divirtual + n) & asz;
sivirtual = (sivirtual + n) & asz;
} while (cx);
Write64(m->cx, cx);
Write64(m->di, divirtual);
Write64(m->si, sivirtual);
if (failed) ThrowSegmentationFault(m, failaddr);
}
void OpRepStosbEnhanced(struct Machine *m) {
bool failed;
uint8_t *direal, al;
unsigned diremain, i, n;
uint64_t divirtual, diactual, failaddr, seg, asz, cx;
if (!(cx = Read64(m->cx))) return;
failaddr = 0;
failed = false;
al = Read8(m->ax);
seg = GetSegment(m);
asz = Asz(m->xedd) ? 0xffffffff : 0xffffffffffffffff;
divirtual = Read64(m->di) & asz;
SetWriteAddr(m, (seg + divirtual) & asz, cx);
do {
diactual = (seg + divirtual) & asz;
if (!(direal = FindReal(m, diactual))) {
failaddr = diactual;
failed = true;
break;
}
diremain = 0x1000 - (divirtual & 0xfff);
n = MIN(cx, diremain);
for (i = 0; i < n; ++i) {
direal[i] = al;
}
cx -= n;
divirtual = (divirtual + n) & asz;
} while (cx);
Write64(m->cx, cx);
Write64(m->di, divirtual);
if (failed) ThrowSegmentationFault(m, failaddr);
}
void OpMovsb(struct Machine *m) {
if (m->xedd->op.rep && !GetFlag(m->flags, FLAGS_DF)) {
OpRepMovsbEnhanced(m);
} else {
OpString(m, STRING_MOVS);
}
}
void OpStosb(struct Machine *m) {
if (m->xedd->op.rep && !GetFlag(m->flags, FLAGS_DF)) {
OpRepStosbEnhanced(m);
} else {
OpString(m, STRING_STOS);
}
}

22
tool/build/lib/string.h Normal file
View file

@ -0,0 +1,22 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_STRING_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_STRING_H_
#include "tool/build/lib/machine.h"
#define STRING_CMPS 0
#define STRING_MOVS 1
#define STRING_STOS 2
#define STRING_LODS 3
#define STRING_SCAS 4
#define STRING_OUTS 5
#define STRING_INS 6
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void OpString(struct Machine *, int);
void OpMovsb(struct Machine *);
void OpStosb(struct Machine *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_STRING_H_ */

647
tool/build/lib/syscall.c Normal file
View file

@ -0,0 +1,647 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/ioctl.h"
#include "libc/calls/struct/sigaction-linux.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timeval.h"
#include "libc/errno.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/msync.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/ok.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/so.h"
#include "libc/sysv/consts/tcp.h"
#include "libc/sysv/errfuns.h"
#include "libc/time/struct/timezone.h"
#include "libc/time/time.h"
#include "tool/build/lib/case.h"
#include "tool/build/lib/endian.h"
#include "tool/build/lib/machine.h"
#include "tool/build/lib/memory.h"
#include "tool/build/lib/pml4t.h"
#include "tool/build/lib/syscall.h"
#include "tool/build/lib/throw.h"
#include "tool/build/lib/xlaterrno.h"
#define AT_FDCWD_LINUX -100
#define POINTER(x) ((void *)(intptr_t)(x))
#define UNPOINTER(x) ((int64_t)(intptr_t)(x))
#define SYSCALL(x, y) CASE(x, asm("# " #y); ax = y)
#define XLAT(x, y) CASE(x, return y)
#define PNN(x) ResolveAddress(m, x)
#define P(x) ((x) ? PNN(x) : 0)
#define ASSIGN(D, S) memcpy(&D, &S, MIN(sizeof(S), sizeof(D)))
static int XlatSignal(int sig) {
switch (sig) {
XLAT(1, SIGHUP);
XLAT(2, SIGINT);
XLAT(3, SIGQUIT);
XLAT(4, SIGILL);
XLAT(5, SIGTRAP);
XLAT(6, SIGABRT);
XLAT(7, SIGBUS);
XLAT(8, SIGFPE);
XLAT(9, SIGKILL);
XLAT(10, SIGUSR1);
XLAT(11, SIGSEGV);
XLAT(13, SIGPIPE);
XLAT(14, SIGALRM);
XLAT(15, SIGTERM);
XLAT(21, SIGTTIN);
XLAT(22, SIGTTOU);
XLAT(24, SIGXCPU);
XLAT(25, SIGXFSZ);
XLAT(26, SIGVTALRM);
XLAT(27, SIGPROF);
XLAT(28, SIGWINCH);
XLAT(17, SIGCHLD);
XLAT(18, SIGCONT);
XLAT(29, SIGIO);
XLAT(19, SIGSTOP);
XLAT(31, SIGSYS);
XLAT(20, SIGTSTP);
XLAT(23, SIGURG);
XLAT(12, SIGUSR2);
XLAT(0x2000, SIGSTKSZ);
XLAT(30, SIGPWR);
XLAT(0x10, SIGSTKFLT);
default:
return sig;
}
}
static int XlatMapFlags(int x) {
unsigned res = 0;
if (x & 1) res |= MAP_SHARED;
if (x & 2) res |= MAP_PRIVATE;
if (x & 16) res |= MAP_FIXED;
if (x & 32) res |= MAP_ANONYMOUS;
return res;
}
static int XlatAccess(int x) {
unsigned res = F_OK;
if (x & 1) res |= X_OK;
if (x & 2) res |= W_OK;
if (x & 4) res |= R_OK;
return res;
}
static int XlatSigaction(int x) {
unsigned res = 0;
if (x & 0x04000000) res |= SA_RESTORER;
if (x & 0x08000000) res |= SA_ONSTACK;
if (x & 0x10000000) res |= SA_RESTART;
if (x & 1) res |= SA_NOCLDSTOP;
if (x & 2) res |= SA_NOCLDWAIT;
if (x & 4) res |= SA_SIGINFO;
if (x & 0x40000000) res |= SA_NODEFER;
if (x & 0x40000000) res |= SA_NOMASK;
if (x & 0x80000000) res |= SA_RESETHAND;
if (x & 0x80000000) res |= SA_ONESHOT;
return res;
}
static int XlatSo(int x) {
switch (x) {
XLAT(-1, SO_EXCLUSIVEADDRUSE);
XLAT(1, SO_DEBUG);
XLAT(2, SO_REUSEADDR);
XLAT(3, SO_TYPE);
XLAT(4, SO_ERROR);
XLAT(5, SO_DONTROUTE);
XLAT(6, SO_BROADCAST);
XLAT(7, SO_SNDBUF);
XLAT(8, SO_RCVBUF);
XLAT(9, SO_KEEPALIVE);
XLAT(10, SO_OOBINLINE);
XLAT(13, SO_LINGER);
XLAT(15, SO_REUSEPORT);
XLAT(17, SO_PEERCRED);
XLAT(18, SO_RCVLOWAT);
XLAT(19, SO_SNDLOWAT);
XLAT(20, SO_RCVTIMEO);
XLAT(21, SO_SNDTIMEO);
XLAT(29, SO_TIMESTAMP);
XLAT(30, SO_ACCEPTCONN);
XLAT(38, SO_PROTOCOL);
XLAT(39, SO_DOMAIN);
XLAT(47, SO_MAX_PACING_RATE);
default:
return x;
}
}
static int XlatClock(int x) {
switch (x) {
XLAT(0, CLOCK_REALTIME);
XLAT(4, CLOCK_MONOTONIC);
default:
return x;
}
}
static int XlatTcp(int x) {
switch (x) {
XLAT(1, TCP_NODELAY);
XLAT(2, TCP_MAXSEG);
XLAT(23, TCP_FASTOPEN);
XLAT(4, TCP_KEEPIDLE);
XLAT(5, TCP_KEEPINTVL);
XLAT(6, TCP_KEEPCNT);
default:
return x;
}
}
static int XlatAfd(int x) {
if (x == AT_FDCWD_LINUX) x = AT_FDCWD;
return x;
}
static int XlatAtf(int x) {
unsigned res = 0;
if (x & 0x0100) res |= AT_SYMLINK_NOFOLLOW;
if (x & 0x0200) res |= AT_REMOVEDIR;
if (x & 0x0400) res |= AT_SYMLINK_FOLLOW;
if (x & 0x1000) res |= AT_EMPTY_PATH;
return res;
}
static int XlatMsyncFlags(int x) {
unsigned res = 0;
if (x & 1) res |= MS_ASYNC;
if (x & 2) res |= MS_INVALIDATE;
if (x & 4) res |= MS_SYNC;
return res;
}
static unsigned XlatOpenFlags(unsigned flags) {
unsigned res = 0;
if ((flags & 3) == 0) res = O_RDONLY;
if ((flags & 3) == 1) res = O_WRONLY;
if ((flags & 3) == 3) res = O_RDWR;
if (flags & 0x80000) res |= O_CLOEXEC;
if (flags & 0x400) res |= O_APPEND;
if (flags & 0x40) res |= O_CREAT;
if (flags & 0x80) res |= O_EXCL;
if (flags & 0x200) res |= O_TRUNC;
if (flags & 0x0800) res |= O_NDELAY;
if (flags & 0x4000) res |= O_DIRECT;
if (flags & 0x0800) res |= O_NONBLOCK;
if (flags & 0x1000) res |= O_DSYNC;
if (flags & 0x101000) res |= O_RSYNC;
if (flags & 0x040000) res |= O_NOATIME;
return res;
}
static struct sigaction *CoerceSigactionToCosmo(
struct sigaction *dst, const struct sigaction$linux *src) {
if (!src) return NULL;
memset(dst, 0, sizeof(*dst));
ASSIGN(dst->sa_handler, src->sa_handler);
ASSIGN(dst->sa_restorer, src->sa_restorer);
ASSIGN(dst->sa_flags, src->sa_flags);
ASSIGN(dst->sa_mask, src->sa_mask);
return dst;
}
static struct sigaction$linux *CoerceSigactionToLinux(
struct sigaction$linux *dst, const struct sigaction *src) {
if (!dst) return NULL;
memset(dst, 0, sizeof(*dst));
ASSIGN(dst->sa_handler, src->sa_handler);
ASSIGN(dst->sa_restorer, src->sa_restorer);
ASSIGN(dst->sa_flags, src->sa_flags);
ASSIGN(dst->sa_mask, src->sa_mask);
return dst;
}
static int OpMprotect(struct Machine *m, int64_t addr, uint64_t len, int prot) {
return 0;
}
static int OpMadvise(struct Machine *m, int64_t addr, size_t length,
int advice) {
return enosys();
}
static int64_t OpMmap(struct Machine *m, int64_t virt, size_t size, int prot,
int flags, int fd, int64_t off) {
void *real;
flags = XlatMapFlags(flags);
real = mmap(NULL, size, prot, flags & ~MAP_FIXED, fd, off);
if (real == MAP_FAILED) return -1;
if (!(flags & MAP_FIXED)) {
if (0 <= virt && virt < 0x400000) virt = 0x400000;
if ((virt = FindPml4t(m->cr3, virt, size, MallocPage)) == -1) return -1;
}
CHECK_NE(-1, RegisterMemory(m, virt, real, size));
return virt;
}
static int OpMunmap(struct Machine *m, int64_t addr, uint64_t size) {
return FreePml4t(m->cr3, addr, size, free, munmap);
}
static int OpMsync(struct Machine *m, int64_t virt, size_t size, int flags) {
size_t i;
void *page;
virt = ROUNDDOWN(virt, 4096);
flags = XlatMsyncFlags(flags);
for (i = 0; i < size; i += 4096) {
if (!(page = FindReal(m, virt + i))) return efault();
if (msync(page, 4096, flags) == -1) return -1;
}
return 0;
}
static void *GetDirectBuf(struct Machine *m, int64_t addr, size_t *size) {
void *page;
*size = MIN(*size, 0x1000 - (addr & 0xfff));
if (!(page = FindReal(m, addr))) return MAP_FAILED;
return page;
}
static ssize_t OpRead(struct Machine *m, int fd, int64_t addr, size_t size) {
void *data;
ssize_t rc;
if ((data = GetDirectBuf(m, addr, &size)) == MAP_FAILED) return efault();
if ((rc = read(fd, data, size)) != -1) SetWriteAddr(m, addr, rc);
return rc;
}
static ssize_t OpWrite(struct Machine *m, int fd, int64_t addr, size_t size) {
void *data;
ssize_t rc;
if ((data = GetDirectBuf(m, addr, &size)) == MAP_FAILED) return efault();
if ((rc = write(fd, data, size)) != -1) SetReadAddr(m, addr, size);
return rc;
}
static ssize_t OpPread(struct Machine *m, int fd, int64_t addr, size_t size,
int64_t offset) {
void *data;
ssize_t rc;
if ((data = GetDirectBuf(m, addr, &size)) == MAP_FAILED) return efault();
if ((rc = pread(fd, data, size, offset)) != -1) SetWriteAddr(m, addr, rc);
return rc;
}
static ssize_t OpPwrite(struct Machine *m, int fd, int64_t addr, size_t size,
int64_t offset) {
void *data;
ssize_t rc;
if ((data = GetDirectBuf(m, addr, &size)) == MAP_FAILED) return efault();
if ((rc = pwrite(fd, data, size, offset)) != -1) SetReadAddr(m, addr, size);
return rc;
}
static int OpFstatat(struct Machine *m, int dirfd, int64_t path, int64_t st,
int flags) {
int rc;
void *stp[2];
uint8_t *stbuf;
if (!(stbuf = malloc(sizeof(struct stat)))) return enomem();
if ((rc = fstatat(XlatAfd(dirfd), LoadStr(m, path),
BeginStoreNp(m, st, sizeof(stbuf), stp, stbuf),
XlatAtf(flags))) != -1) {
EndStoreNp(m, st, sizeof(stbuf), stp, stbuf);
}
free(stbuf);
return rc;
}
static int OpFstat(struct Machine *m, int fd, int64_t st) {
int rc;
void *stp[2];
uint8_t *stbuf;
if (!(stbuf = malloc(sizeof(struct stat)))) return enomem();
if ((rc = fstat(fd, BeginStoreNp(m, st, sizeof(stbuf), stp, stbuf))) != -1) {
EndStoreNp(m, st, sizeof(stbuf), stp, stbuf);
}
free(stbuf);
return rc;
}
static int OpOpenat(struct Machine *m, int dirfd, int64_t path, int flags,
int mode) {
return openat(XlatAfd(dirfd), LoadStr(m, path), XlatOpenFlags(flags), mode);
}
static int OpFaccessat(struct Machine *m, int dirfd, int64_t path, int mode,
int flags) {
return faccessat(XlatAfd(dirfd), LoadStr(m, path), XlatAccess(mode),
XlatAtf(flags));
}
static int OpChdir(struct Machine *m, int64_t path) {
return chdir(LoadStr(m, path));
}
static int OpMkdir(struct Machine *m, int64_t path, int mode) {
return mkdir(LoadStr(m, path), mode);
}
static int OpMknod(struct Machine *m, int64_t path, uint32_t mode,
uint64_t dev) {
return mknod(LoadStr(m, path), mode, dev);
}
static int OpRmdir(struct Machine *m, int64_t path) {
return rmdir(LoadStr(m, path));
}
static int OpUnlink(struct Machine *m, int64_t path) {
return unlink(LoadStr(m, path));
}
static int OpRename(struct Machine *m, int64_t src, int64_t dst) {
return rename(LoadStr(m, src), LoadStr(m, dst));
}
static int OpTruncate(struct Machine *m, int64_t path, uint64_t length) {
return truncate(LoadStr(m, path), length);
}
static int OpLink(struct Machine *m, int64_t existingpath, int64_t newpath) {
return link(LoadStr(m, existingpath), LoadStr(m, newpath));
}
static int OpSymlink(struct Machine *m, int64_t target, int64_t linkpath) {
return symlink(LoadStr(m, target), LoadStr(m, linkpath));
}
static int OpChmod(struct Machine *m, int64_t path, uint32_t mode) {
return chmod(LoadStr(m, path), mode);
}
static int64_t OpGetcwd(struct Machine *m, int64_t bufaddr, size_t size) {
size_t n;
char *buf;
int64_t res;
size = MIN(size, PATH_MAX);
if (!(buf = malloc(size))) return enomem();
if ((getcwd)(buf, size)) {
n = strlen(buf);
VirtualRecv(m, bufaddr, buf, n);
SetWriteAddr(m, bufaddr, n);
res = bufaddr;
} else {
res = -1;
}
free(buf);
return res;
}
static int OpSigaction(struct Machine *m, int sig, int64_t act, int64_t old) {
int rc;
struct OpSigactionMemory {
struct sigaction act, old;
uint8_t b[sizeof(struct sigaction$linux)];
void *p[2];
} * mem;
if (!(mem = malloc(sizeof(*mem)))) return enomem();
if ((rc = sigaction(
XlatSignal(sig),
CoerceSigactionToCosmo(
&mem->act, LoadBuf(m, act, sizeof(struct sigaction$linux))),
&mem->old)) != -1) {
CoerceSigactionToLinux(BeginStoreNp(m, old, sizeof(mem->b), mem->p, mem->b),
&mem->old);
EndStoreNp(m, old, sizeof(mem->b), mem->p, mem->b);
}
free(mem);
return rc;
}
static int OpPipe(struct Machine *m, int64_t pipefds_addr) {
int rc;
void *p[2];
uint8_t b[8];
if ((rc = pipe(BeginStoreNp(m, pipefds_addr, 8, p, b))) != -1) {
EndStoreNp(m, pipefds_addr, 8, p, b);
}
return rc;
}
static int OpNanosleep(struct Machine *m, int64_t req, int64_t rem) {
int rc;
void *p[2];
uint8_t b[sizeof(struct timespec)];
if ((rc = nanosleep(LoadBuf(m, req, sizeof(b)),
BeginStoreNp(m, rem, sizeof(b), p, b))) != -1) {
EndStoreNp(m, rem, sizeof(b), p, b);
}
return rc;
}
static int OpSigsuspend(struct Machine *m, int64_t maskaddr) {
void *p;
sigset_t mask;
if (!(p = LoadBuf(m, maskaddr, 8))) return efault();
memset(&mask, 0, sizeof(mask));
memcpy(&mask, p, 8);
return sigsuspend(&mask);
}
static int OpClockGettime(struct Machine *m, int clockid, int64_t ts) {
int rc;
void *tsp[2];
uint8_t tsb[sizeof(struct timespec)];
if ((rc = clock_gettime(XlatClock(clockid),
BeginStoreNp(m, ts, sizeof(tsb), tsp, tsb))) != -1) {
EndStoreNp(m, ts, sizeof(tsb), tsp, tsb);
}
return rc;
}
static int OpGettimeofday(struct Machine *m, int64_t tv, int64_t tz) {
int rc;
void *tvp[2], *tzp[2];
uint8_t tvb[sizeof(struct timeval)];
uint8_t tzb[sizeof(struct timezone)];
if ((rc = gettimeofday(BeginStoreNp(m, tv, sizeof(tvb), tvp, tvb),
BeginStoreNp(m, tz, sizeof(tzb), tzp, tzb))) != -1) {
EndStoreNp(m, tv, sizeof(tvb), tvp, tvb);
EndStoreNp(m, tz, sizeof(tzb), tzp, tzb);
}
return rc;
}
static int DoOpen(struct Machine *m, int64_t path, int flags, int mode) {
return OpOpenat(m, AT_FDCWD_LINUX, path, flags, mode);
}
static int DoCreat(struct Machine *m, int64_t file, int mode) {
return DoOpen(m, file, 0x241, mode);
}
static int DoAccess(struct Machine *m, int64_t path, int mode) {
return OpFaccessat(m, AT_FDCWD_LINUX, path, mode, 0);
}
static int DoStat(struct Machine *m, int64_t path, int64_t st) {
return OpFstatat(m, AT_FDCWD_LINUX, path, st, 0);
}
static int DoLstat(struct Machine *m, int64_t path, int64_t st) {
return OpFstatat(m, AT_FDCWD_LINUX, path, st, 0x0400);
}
void OpSyscall(struct Machine *m) {
uint64_t i, ax, di, si, dx, r0, r8, r9;
ax = Read64(m->ax);
di = Read64(m->di);
si = Read64(m->si);
dx = Read64(m->dx);
r0 = Read32(m->r10);
r8 = Read32(m->r8);
r9 = Read32(m->r9);
switch (ax & 0x1ff) {
SYSCALL(0x000, OpRead(m, di, si, dx));
SYSCALL(0x001, OpWrite(m, di, si, dx));
SYSCALL(0x002, DoOpen(m, di, si, dx));
SYSCALL(0x003, close(di));
SYSCALL(0x004, DoStat(m, di, si));
SYSCALL(0x005, OpFstat(m, di, si));
SYSCALL(0x006, DoLstat(m, di, si));
SYSCALL(0x007, poll(PNN(di), si, dx));
SYSCALL(0x008, lseek(di, si, dx));
SYSCALL(0x009, OpMmap(m, di, si, dx, r0, r8, r9));
SYSCALL(0x01A, OpMsync(m, di, si, dx));
SYSCALL(0x00A, OpMprotect(m, di, si, dx));
SYSCALL(0x00B, OpMunmap(m, di, si));
SYSCALL(0x00D, OpSigaction(m, di, si, dx));
SYSCALL(0x00E, sigprocmask(di, P(si), P(dx)));
SYSCALL(0x010, ioctl(di, si, P(dx)));
SYSCALL(0x011, OpPread(m, di, si, dx, r0));
SYSCALL(0x012, OpPwrite(m, di, si, dx, r0));
SYSCALL(0x013, readv(di, P(si), dx));
SYSCALL(0x014, writev(di, P(si), dx));
SYSCALL(0x015, DoAccess(m, di, si));
SYSCALL(0x016, OpPipe(m, di));
SYSCALL(0x017, select(di, P(si), P(dx), P(r0), P(r8)));
SYSCALL(0x018, sched_yield());
SYSCALL(0x01C, OpMadvise(m, di, si, dx));
SYSCALL(0x020, dup(di));
SYSCALL(0x021, dup2(di, si));
SYSCALL(0x022, pause());
SYSCALL(0x023, OpNanosleep(m, di, si));
SYSCALL(0x024, getitimer(di, PNN(si)));
SYSCALL(0x025, alarm(di));
SYSCALL(0x026, setitimer(di, PNN(si), P(dx)));
SYSCALL(0x027, getpid());
SYSCALL(0x028, sendfile(di, si, P(dx), r0));
SYSCALL(0x029, socket(di, si, dx));
SYSCALL(0x02A, connect(di, PNN(si), dx));
SYSCALL(0x02B, accept(di, PNN(di), PNN(dx)));
SYSCALL(0x02C, sendto(di, PNN(si), dx, r0, P(r8), r9));
SYSCALL(0x02D, recvfrom(di, P(si), dx, r0, P(r8), P(r9)));
SYSCALL(0x030, shutdown(di, si));
SYSCALL(0x031, bind(di, PNN(si), dx));
SYSCALL(0x032, listen(di, si));
SYSCALL(0x033, getsockname(di, PNN(si), PNN(dx)));
SYSCALL(0x034, getpeername(di, PNN(si), PNN(dx)));
SYSCALL(0x036, setsockopt(di, si, dx, PNN(r0), r8));
SYSCALL(0x037, getsockopt(di, si, dx, PNN(r0), PNN(r8)));
SYSCALL(0x039, fork());
SYSCALL(0x03B, execve(PNN(r8), PNN(r8), PNN(r8)));
SYSCALL(0x03D, wait4(di, P(si), dx, P(r0)));
SYSCALL(0x03E, kill(di, si));
SYSCALL(0x03F, uname(P(di)));
SYSCALL(0x048, fcntl(di, si, dx));
SYSCALL(0x049, flock(di, si));
SYSCALL(0x04A, fsync(di));
SYSCALL(0x04B, fdatasync(di));
SYSCALL(0x04C, OpTruncate(m, di, si));
SYSCALL(0x04D, ftruncate(di, si));
SYSCALL(0x04F, OpGetcwd(m, di, si));
SYSCALL(0x050, OpChdir(m, di));
SYSCALL(0x052, OpRename(m, di, si));
SYSCALL(0x053, OpMkdir(m, di, si));
SYSCALL(0x054, OpRmdir(m, di));
SYSCALL(0x055, DoCreat(m, di, si));
SYSCALL(0x056, OpLink(m, di, si));
SYSCALL(0x057, OpUnlink(m, di));
SYSCALL(0x058, OpSymlink(m, di, si));
SYSCALL(0x05A, OpChmod(m, di, si));
SYSCALL(0x05B, fchmod(di, si));
SYSCALL(0x060, OpGettimeofday(m, di, si));
SYSCALL(0x061, getrlimit(di, P(si)));
SYSCALL(0x062, getrusage(di, P(si)));
SYSCALL(0x063, sysinfo(PNN(di)));
SYSCALL(0x064, times(PNN(di)));
SYSCALL(0x066, getuid());
SYSCALL(0x068, getgid());
SYSCALL(0x06E, getppid());
SYSCALL(0x075, setresuid(di, si, dx));
SYSCALL(0x077, setresgid(di, si, dx));
SYSCALL(0x082, OpSigsuspend(m, di));
SYSCALL(0x085, OpMknod(m, di, si, dx));
SYSCALL(0x08C, getpriority(di, si));
SYSCALL(0x08D, setpriority(di, si, dx));
SYSCALL(0x0A0, setrlimit(di, P(si)));
SYSCALL(0x084, utime(PNN(di), PNN(si)));
SYSCALL(0x0EB, utimes(P(di), P(si)));
SYSCALL(0x09E, arch_prctl(di, si));
SYSCALL(0x0BA, gettid());
SYSCALL(0x0CB, sched_setaffinity(di, si, P(dx)));
SYSCALL(0x0DD, fadvise(di, si, dx, r0));
SYSCALL(0x0E4, OpClockGettime(m, di, si));
SYSCALL(0x101, OpOpenat(m, di, si, dx, r0));
SYSCALL(0x102, mkdirat(XlatAfd(di), P(si), dx));
SYSCALL(0x104, fchownat(XlatAfd(di), P(si), dx, r0, XlatAtf(r8)));
SYSCALL(0x105, futimesat(XlatAfd(di), P(si), P(dx)));
SYSCALL(0x106, OpFstatat(m, di, si, dx, r0));
SYSCALL(0x107, unlinkat(XlatAfd(di), P(si), XlatAtf(dx)));
SYSCALL(0x108, renameat(XlatAfd(di), P(si), XlatAfd(dx), P(r0)));
SYSCALL(0x10D, OpFaccessat(m, di, si, dx, r0));
SYSCALL(0x113, splice(di, P(si), dx, P(r0), r8, XlatAtf(r9)));
SYSCALL(0x115, sync_file_range(di, si, dx, XlatAtf(r0)));
SYSCALL(0x118, utimensat(XlatAfd(di), P(si), P(dx), XlatAtf(r0)));
SYSCALL(0x177, vmsplice(di, P(si), dx, r0));
CASE(0xE7, HaltMachine(m, di | 0x100));
default:
DEBUGF("missing syscall %03x", ax);
ax = enosys();
break;
}
Write64(m->ax, ax != -1 ? ax : -(XlatErrno(errno) & 0xfff));
for (i = 0; i < m->freelist.i; ++i) free(m->freelist.p[i]);
m->freelist.i = 0;
}

13
tool/build/lib/syscall.h Normal file
View file

@ -0,0 +1,13 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_SYSCALL_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_SYSCALL_H_
#include "tool/build/lib/machine.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
enum MachineStatus;
void OpSyscall(struct Machine *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_SYSCALL_H_ */

60
tool/build/lib/throw.c Normal file
View file

@ -0,0 +1,60 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/log/check.h"
#include "libc/runtime/runtime.h"
#include "tool/build/lib/throw.h"
static bool IsHaltingInitialized(struct Machine *m) {
jmp_buf zb;
memset(zb, 0, sizeof(zb));
return memcmp(m->onhalt, zb, sizeof(m->onhalt)) != 0;
}
void HaltMachine(struct Machine *m, int code) {
CHECK(IsHaltingInitialized(m));
longjmp(m->onhalt, code);
}
void ThrowDivideError(struct Machine *m) {
HaltMachine(m, kMachineDivideError);
}
void ThrowSegmentationFault(struct Machine *m, int64_t va) {
m->faultaddr = va;
if (m->xedd) m->ip -= m->xedd->length;
HaltMachine(m, kMachineSegmentationFault);
}
void ThrowProtectionFault(struct Machine *m) {
HaltMachine(m, kMachineProtectionFault);
}
void OpUd(struct Machine *m) {
m->ip -= m->xedd->length;
HaltMachine(m, kMachineUndefinedInstruction);
}
void OpHlt(struct Machine *m) {
HaltMachine(m, kMachineHalt);
}
void OpInterrupt(struct Machine *m, int i) {
HaltMachine(m, i);
}

17
tool/build/lib/throw.h Normal file
View file

@ -0,0 +1,17 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_THROW_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_THROW_H_
#include "tool/build/lib/machine.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void OpUd(struct Machine *) noreturn;
void HaltMachine(struct Machine *, int) noreturn;
void ThrowDivideError(struct Machine *) noreturn;
void ThrowSegmentationFault(struct Machine *, int64_t) noreturn;
void ThrowProtectionFault(struct Machine *) noreturn;
void OpHlt(struct Machine *) noreturn;
void OpInterrupt(struct Machine *, int) noreturn;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_THROW_H_ */

71
tool/build/lib/x87.c Normal file
View file

@ -0,0 +1,71 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "ape/lib/pc.h"
#include "libc/math.h"
#include "tool/build/lib/x87.h"
static long ltruncl(long double x) {
return x;
}
static int ClearC2(int sw) {
return sw & ~FPU_C2;
}
static long double x87remainder(long double x, long double y, uint32_t *sw,
long double rem(long double, long double),
long rnd(long double)) {
int s;
long q;
long double r;
s = 0;
r = rem(x, y);
q = rnd(x / y);
s &= ~FPU_C2; /* ty libm */
if (q & 0b001) s |= FPU_C1;
if (q & 0b010) s |= FPU_C3;
if (q & 0b100) s |= FPU_C0;
if (sw) *sw = s | (*sw & ~(FPU_C0 | FPU_C1 | FPU_C2 | FPU_C3));
return r;
}
long double f2xm1(long double x) {
return exp2l(x) - 1;
}
long double fyl2x(long double x, long double y) {
return y * log2l(x);
}
long double fyl2xp1(long double x, long double y) {
return y * log2l(x + 1);
}
long double fscale(long double significand, long double exponent) {
return scalbnl(significand, exponent);
}
long double fprem(long double dividend, long double modulus, uint32_t *sw) {
return x87remainder(dividend, modulus, sw, fmodl, ltruncl);
}
long double fprem1(long double dividend, long double modulus, uint32_t *sw) {
return x87remainder(dividend, modulus, sw, remainderl, lrintl);
}

15
tool/build/lib/x87.h Normal file
View file

@ -0,0 +1,15 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_X87_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_X87_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
long double f2xm1(long double);
long double fyl2x(long double, long double);
long double fyl2xp1(long double, long double);
long double fscale(long double, long double);
long double fprem(long double, long double, uint32_t *);
long double fprem1(long double, long double, uint32_t *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_X87_H_ */

View file

@ -0,0 +1,64 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/errno.h"
#include "libc/mem/mem.h"
#include "libc/runtime/carsort.h"
#include "tool/build/lib/xlaterrno.h"
struct LinuxErrno {
int32_t local;
int32_t linux;
};
extern const char kLinuxErrnosLength[];
extern const struct LinuxErrno kLinuxErrnos[];
static struct LinuxErrno *errnos;
/**
* Turns local errno into Linux errno.
*/
int XlatErrno(int local) {
static bool once;
long i, n, m, l, r;
n = (uintptr_t)kLinuxErrnosLength;
if (!once) {
errnos = malloc(sizeof(struct LinuxErrno) * n);
for (i = 0; i < n; ++i) {
errnos[i].local =
*(int *)((intptr_t)kLinuxErrnos + kLinuxErrnos[i].local);
errnos[i].linux = kLinuxErrnos[i].linux;
}
carsort100(n, (void *)errnos);
once = true;
}
l = 0;
r = n - 1;
while (l <= r) {
m = (l + r) / 2;
if (errnos[m].local < local) {
l = m + 1;
} else if (errnos[m].local > local) {
r = m - 1;
} else {
return errnos[m].linux;
}
}
return ENOSYS;
}

View file

@ -0,0 +1,10 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_XLATERRNO_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_XLATERRNO_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
int XlatErrno(int);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_XLATERRNO_H_ */

View file

@ -30,11 +30,12 @@
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/nexgen32e/crc32.h"
#include "libc/runtime/ezmap.h"
#include "libc/runtime/gc.h"
#include "libc/runtime/mappings.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/knuthmultiplicativehash.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/madv.h"
#include "libc/sysv/consts/map.h"
@ -53,7 +54,7 @@
* 50k+ lines of make code in ~80ms using one core and a meg of ram.
*/
static const char *const kSourceExts[] = {".s", ".S", ".c", ".cc", ".cpp"};
static const char kSourceExts[][5] = {".s", ".S", ".c", ".cc", ".cpp"};
static alignas(16) const char kIncludePrefix[] = "include \"";
static const char *const kModelessPackages[] = {
@ -141,7 +142,9 @@ void Rehash(void) {
uint32_t GetSourceId(const char *name, size_t len) {
size_t i, step;
uint32_t hash = Hash(name, len);
uint32_t hash;
i = 0;
hash = Hash(name, len);
if (sources.n) {
step = 0;
do {
@ -162,7 +165,7 @@ uint32_t GetSourceId(const char *name, size_t len) {
} while (sources.p[i].hash);
}
sources.p[i].hash = hash;
sources.p[i].name = concat(&strings, name, len);
sources.p[i].name = CONCAT(&strings.p, &strings.i, &strings.n, name, len);
strings.p[strings.i++] = '\0';
return (sources.p[i].id = g_sourceid++);
}
@ -248,7 +251,7 @@ const char *StripExt(const char *s) {
__cxa_atexit(free_s, &p, NULL);
}
i = 0;
CONCAT(&p, &i, &n, s, strlen(s));
CONCAT(&p, &i, &n, s, strlen(s) + 1);
dot = strrchr(p, '.');
if (dot) *dot = '\0';
return p;

View file

@ -22,12 +22,11 @@
#include "libc/alg/bisect.h"
#include "libc/alg/bisectcarleft.h"
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/bswap.h"
#include "libc/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/conv/conv.h"
#include "libc/conv/sizemultiply.h"
#include "libc/elf/def.h"
#include "libc/elf/elf.h"
#include "libc/elf/struct/rela.h"
@ -143,7 +142,7 @@ struct Packages {
size_t i, n;
struct Op {
int32_t offset;
uint8_t decoded_length;
uint8_t length;
uint8_t pos_disp;
uint16_t __pad;
} * p;
@ -243,7 +242,7 @@ void GetOpts(struct Package *pkg, struct Packages *deps, int argc,
exit(1);
}
}
CHECK_NE(-1, pkg->path);
CHECK_NE(-1, pkg->path, "no packages passed to package.com");
CHECK_LT(optind, argc,
"no objects passed to package.com; "
"is your foo.mk $(FOO_OBJS) glob broken?");
@ -290,17 +289,16 @@ void IndexSections(struct Object *obj) {
}
if (shdr->sh_flags & SHF_EXECINSTR) {
CHECK_NOTNULL((code = getelfsectionaddress(obj->elf, obj->size, shdr)));
for (op.offset = 0; op.offset < shdr->sh_size;
op.offset += op.decoded_length) {
for (op.offset = 0; op.offset < shdr->sh_size; op.offset += op.length) {
if (xed_instruction_length_decode(
xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64),
&code[op.offset],
min(shdr->sh_size - op.offset, XED_MAX_INSTRUCTION_BYTES)) ==
XED_ERROR_NONE) {
op.decoded_length = xedd.decoded_length;
op.pos_disp = xedd.operands.pos_disp;
op.length = xedd.length;
op.pos_disp = xedd.op.pos_disp;
} else {
op.decoded_length = 1;
op.length = 1;
op.pos_disp = 0;
}
CHECK_NE(-1, append(&sect.ops, &op));
@ -484,11 +482,11 @@ void OptimizeRelocations(struct Package *pkg, struct Packages *deps,
op = &obj->sections.p[shdr->sh_info].ops.p[bisectcarleft(
(const int32_t(*)[2])obj->sections.p[shdr->sh_info].ops.p,
obj->sections.p[shdr->sh_info].ops.i, rela->r_offset)];
CHECK_GT(op->decoded_length, 4);
CHECK_GT(op->length, 4);
CHECK_GT(op->pos_disp, 0);
rela->r_info = ELF64_R_INFO(ELF64_R_SYM(rela->r_info), R_X86_64_32S);
rela->r_addend = -IMAGE_BASE_VIRTUAL + rela->r_addend +
(op->decoded_length - op->pos_disp);
(op->length - op->pos_disp);
code[rela->r_offset - 1] = ChangeRipToRbx(code[rela->r_offset - 1]);
}
#endif
@ -658,6 +656,7 @@ void Package(int argc, char *argv[], struct Package *pkg,
int main(int argc, char *argv[]) {
struct Package pkg;
struct Packages deps;
showcrashreports();
memset(&pkg, 0, sizeof(pkg));
memset(&deps, 0, sizeof(deps));
Package(argc, argv, &pkg, &deps);

48
tool/build/tinyemu.c Normal file
View file

@ -0,0 +1,48 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/ex.h"
#include "tool/build/lib/loader.h"
#include "tool/build/lib/machine.h"
struct Machine m[1];
int main(int argc, char *argv[]) {
int rc;
struct Elf elf;
const char *codepath;
codepath = argv[1];
if (argc < 2) {
fputs("Usage: ", stderr);
fputs(argv[0], stderr);
fputs(" PROG [ARGS...]\n", stderr);
return EX_USAGE;
}
LoadProgram(m, argv[1], argv + 2, environ, &elf);
if (!(rc = setjmp(m->onhalt))) {
for (;;) {
LoadInstruction(m);
ExecuteInstruction(m);
}
} else {
return rc;
}
}

192
tool/build/x86combos.c Normal file
View file

@ -0,0 +1,192 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/log/check.h"
#include "libc/macros.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#include "third_party/xed/x86.h"
const char kPrefixes[][8] = {
{},
{0x66},
{0x67},
{0x40},
{0x6F},
{0x66, 0x6F},
{0x66, 0x40},
{0x66, 0x6F},
{0x67, 0x40},
{0x67, 0x6F},
{0x66, 0x67},
{0x66, 0x67, 0x40},
{0x66, 0x67, 0x6F},
{0x0F},
{0x0F, 0x66},
{0x0F, 0x67},
{0x0F, 0x40},
{0x0F, 0x6F},
{0x0F, 0x66, 0x6F},
{0x0F, 0x66, 0x40},
{0x0F, 0x66, 0x6F},
{0x0F, 0x67, 0x40},
{0x0F, 0x67, 0x6F},
{0x0F, 0x66, 0x67},
{0x0F, 0x66, 0x67, 0x40},
{0x0F, 0x66, 0x67, 0x6F},
{0xF3, 0x0F},
{0xF3, 0x66, 0x0F},
{0xF3, 0x67, 0x0F},
{0xF3, 0x40, 0x0F},
{0xF3, 0x6F, 0x0F},
{0xF3, 0x66, 0x6F, 0x0F},
{0xF3, 0x66, 0x40, 0x0F},
{0xF3, 0x66, 0x6F, 0x0F},
{0xF3, 0x67, 0x40, 0x0F},
{0xF3, 0x67, 0x6F, 0x0F},
{0xF3, 0x66, 0x67, 0x0F},
{0xF3, 0x66, 0x67, 0x40, 0x0F},
{0xF3, 0x66, 0x67, 0x6F, 0x0F},
{0xF2, 0x0F},
{0xF2, 0x66, 0x0F},
{0xF2, 0x67, 0x0F},
{0xF2, 0x40, 0x0F},
{0xF2, 0x6F, 0x0F},
{0xF2, 0x66, 0x6F, 0x0F},
{0xF2, 0x66, 0x40, 0x0F},
{0xF2, 0x66, 0x6F, 0x0F},
{0xF2, 0x67, 0x40, 0x0F},
{0xF2, 0x67, 0x6F, 0x0F},
{0xF2, 0x66, 0x67, 0x0F},
{0xF2, 0x66, 0x67, 0x40, 0x0F},
{0xF2, 0x66, 0x67, 0x6F, 0x0F},
};
const uint8_t kModrmPicks[] = {
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x0, 0x8, 0x10,
0x18, 0x20, 0x28, 0x30, 0x38, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
0x46, 0x47, 0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78, 0x80,
0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x80, 0x88, 0x90, 0x98,
0xa0, 0xa8, 0xb0, 0xb8, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6,
0xc7, 0xc0, 0xc8, 0xd0, 0xd8, 0xe0, 0xe8, 0xf0, 0xf8,
};
const uint8_t kOpMap0[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,
195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224,
225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
255,
};
void WriteOp(int fd, struct XedDecodedInst *xedd) {
int i;
char buf[128], *p;
p = stpcpy(buf, ".byte ");
for (i = 0; i < xedd->length; ++i) {
if (i) *p++ = ',';
*p++ = '0';
*p++ = 'x';
*p++ = "0123456789abcdef"[(xedd->bytes[i] & 0xf0) >> 4];
*p++ = "0123456789abcdef"[xedd->bytes[i] & 0x0f];
}
*p++ = '\n';
CHECK_NE(-1, write(fd, buf, p - buf));
}
int main(int argc, char *argv[]) {
int i, j, k, l, m, n, p, o, fd;
uint8_t op[16];
struct XedDecodedInst xedd[1];
fd = open("/tmp/ops.s", O_CREAT | O_TRUNC | O_RDWR, 0644);
for (o = 0; o < ARRAYLEN(kOpMap0); ++o) {
for (p = 0; p < ARRAYLEN(kPrefixes); ++p) {
memset(op, 0x55, 16);
n = strlen(kPrefixes[p]);
memcpy(op, kPrefixes[p], n);
op[n] = kOpMap0[o];
xed_decoded_inst_zero_set_mode(xedd, XED_MACHINE_MODE_LONG_64);
if (!xed_instruction_length_decode(xedd, op, XED_MAX_INSTRUCTION_BYTES)) {
if (xedd->op.has_modrm && xedd->op.has_sib) {
for (i = 0; i < ARRAYLEN(kModrmPicks); ++i) {
for (j = 0; j < ARRAYLEN(kModrmPicks); ++j) {
memset(op, 0x55, 16);
n = strlen(kPrefixes[p]);
memcpy(op, kPrefixes[p], n);
op[n] = kOpMap0[o];
op[xedd->op.pos_modrm] = kModrmPicks[i];
op[xedd->op.pos_sib] = kModrmPicks[j];
xed_decoded_inst_zero_set_mode(xedd, XED_MACHINE_MODE_LONG_64);
if (!xed_instruction_length_decode(xedd, op,
XED_MAX_INSTRUCTION_BYTES)) {
WriteOp(fd, xedd);
}
}
}
} else if (xedd->op.has_modrm) {
for (i = 0; i < ARRAYLEN(kModrmPicks); ++i) {
memset(op, 0x55, 16);
n = strlen(kPrefixes[p]);
memcpy(op, kPrefixes[p], n);
op[n] = kOpMap0[o];
op[xedd->op.pos_modrm] = kModrmPicks[i];
xed_decoded_inst_zero_set_mode(xedd, XED_MACHINE_MODE_LONG_64);
if (!xed_instruction_length_decode(xedd, op,
XED_MAX_INSTRUCTION_BYTES)) {
WriteOp(fd, xedd);
}
}
} else {
WriteOp(fd, xedd);
}
}
}
}
close(fd);
system("as -o /tmp/ops.o /tmp/ops.s");
system("objdump -wd /tmp/ops.o |"
" grep -v data16 |"
" grep -v addr32 |"
" grep -v '(bad)' |"
" sed 's/^[ :[:xdigit:]]*//' |"
" sed 's/^[ :[:xdigit:]]*//' |"
" sed 's/[[:space:]]#.*$//' |"
" grep -v 'rex\\.' |"
" sort -u");
return 0;
}

View file

@ -30,7 +30,9 @@
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/mem/alloca.h"
#include "libc/nexgen32e/crc32.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/struct/imageauxsymbolex.h"
#include "libc/runtime/gc.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.h"
@ -264,14 +266,20 @@ void EmitZip(struct ElfWriter *elf, const char *name, size_t namesize,
void ProcessFile(struct ElfWriter *elf, const char *path) {
int fd;
void *map;
size_t pathlen;
struct stat st;
pathlen = strlen(path);
CHECK_NE(-1, (fd = open(path, O_RDONLY)));
CHECK_NE(-1, fstat(fd, &st));
CHECK_NE(MAP_FAILED,
(map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)));
EmitZip(elf, path, strlen(path), map, &st);
if (st.st_size) {
CHECK_NE(MAP_FAILED,
(map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)));
CHECK_NE(-1, close(fd));
} else {
map = NULL;
}
EmitZip(elf, path, pathlen, map, &st);
CHECK_NE(-1, munmap(map, st.st_size));
CHECK_NE(-1, close(fd));
}
void PullEndOfCentralDirectoryIntoLinkage(struct ElfWriter *elf) {

View file

@ -6,12 +6,14 @@ PKGS += TOOL_DECODE
TOOL_DECODE_FILES := $(wildcard tool/decode/*)
TOOL_DECODE_HDRS = $(filter %.h,$(TOOL_DECODE_FILES))
TOOL_DECODE_SRCS = $(filter %.c,$(TOOL_DECODE_FILES))
TOOL_DECODE_COMS = $(TOOL_DECODE_OBJS:%.o=%.com)
TOOL_DECODE_OBJS = \
$(TOOL_DECODE_SRCS:%=o/$(MODE)/%.zip.o) \
$(TOOL_DECODE_SRCS:%.c=o/$(MODE)/%.o)
TOOL_DECODE_COMS = \
$(TOOL_DECODE_SRCS:%.c=o/$(MODE)/%.com)
TOOL_DECODE_BINS = \
$(TOOL_DECODE_COMS) \
$(TOOL_DECODE_COMS:%=%.dbg)
@ -37,6 +39,7 @@ TOOL_DECODE_DIRECTDEPS = \
LIBC_UNICODE \
LIBC_X \
TOOL_DECODE_LIB \
THIRD_PARTY_DTOA \
THIRD_PARTY_GETOPT \
THIRD_PARTY_XED

View file

@ -108,7 +108,7 @@ static void printelfsegmentheader(int i) {
firstnonnull(findnamebyid(kElfSegmentTypeNames, phdr->p_type),
format(b1, "%#x", phdr->p_type)),
"phdr->p_type");
show(".long", recreateflags(kElfSegmentFlagNames, phdr->p_flags),
show(".long", RecreateFlags(kElfSegmentFlagNames, phdr->p_flags),
"phdr->p_flags");
show(".quad", format(b1, "%#x", phdr->p_offset), "phdr->p_offset");
show(".quad", format(b1, "%#x", phdr->p_vaddr), "phdr->p_vaddr");
@ -140,7 +140,7 @@ static void printelfsectionheader(int i, char *shstrtab) {
firstnonnull(findnamebyid(kElfSectionTypeNames, shdr->sh_type),
format(b1, "%d", shdr->sh_type)),
"shdr->sh_type");
show(".long", recreateflags(kElfSectionFlagNames, shdr->sh_flags),
show(".long", RecreateFlags(kElfSectionFlagNames, shdr->sh_flags),
"shdr->sh_flags");
show(".quad", format(b1, "%#x", shdr->sh_addr), "shdr->sh_addr");
show(".quad", format(b1, "%#x", shdr->sh_offset), "shdr->sh_offset");

View file

@ -17,6 +17,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/elf/def.h"
#include "libc/elf/elf.h"
#include "tool/decode/lib/elfidnames.h"

View file

@ -17,17 +17,12 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/arraylist.h"
#include "libc/alg/arraylist2.h"
#include "libc/fmt/fmt.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "tool/decode/lib/flagger.h"
struct FlagNameBuf {
size_t i, n;
char *p;
};
/**
* Formats numeric flags integer as symbolic code.
*
@ -35,28 +30,32 @@ struct FlagNameBuf {
* @param id is the flags
* @return NUL-terminated string that needs free()
*/
nodiscard char *recreateflags(const struct IdName *names, unsigned long id) {
struct FlagNameBuf buf = {};
char extrabuf[20];
nodiscard char *RecreateFlags(const struct IdName *names, unsigned long id) {
bool first;
size_t bufi, bufn;
char *bufp, extrabuf[20];
bufi = 0;
bufn = 0;
bufp = NULL;
first = true;
for (; names->name; names++) {
if ((id == 0 && names->id == 0) ||
(id != 0 && names->id != 0 && (id & names->id) == names->id)) {
id &= ~names->id;
if (!first) {
append(&buf, "|");
APPEND(&bufp, &bufi, &bufn, "|");
} else {
first = false;
}
concat(&buf, names->name, strlen(names->name));
CONCAT(&bufp, &bufi, &bufn, names->name, strlen(names->name));
}
}
if (id) {
if (buf.i) append(&buf, "|");
concat(&buf, extrabuf, snprintf(extrabuf, sizeof(extrabuf), "%#x", id));
} else if (!buf.i) {
append(&buf, "0");
if (bufi) APPEND(&bufp, &bufi, &bufn, "|");
CONCAT(&bufp, &bufi, &bufn, extrabuf,
snprintf(extrabuf, sizeof(extrabuf), "%#x", id));
} else if (!bufi) {
APPEND(&bufp, &bufi, &bufn, "0");
}
return buf.p;
return bufp;
}

View file

@ -4,7 +4,7 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
char *recreateflags(const struct IdName *, unsigned long) nodiscard;
char *RecreateFlags(const struct IdName *, unsigned long) nodiscard;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -49,7 +49,7 @@ kPollNamesRo:
.previous
/ Mapping of poll() flags to their string names.
/ @see recreateflags()
/ @see RecreateFlags()
.initbss 301,_init_kPollNames
kPollNames:
.rept .Lrows

View file

@ -20,7 +20,7 @@
#include "third_party/xed/x86.h"
#include "tool/decode/lib/idname.h"
const struct IdName kXedErrorNames[] = {
const struct IdName kXedErrorIdNames[] = {
{XED_ERROR_NONE, "NONE"},
{XED_ERROR_BUFFER_TOO_SHORT, "BUFFER_TOO_SHORT"},
{XED_ERROR_GENERAL_ERROR, "GENERAL_ERROR"},

View file

@ -4,7 +4,7 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern const struct IdName kXedErrorNames[];
extern const struct IdName kXedErrorIdNames[];
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -19,12 +19,12 @@
*/
#include "libc/assert.h"
#include "libc/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/conv/conv.h"
#include "libc/macho.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/calls.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
@ -66,7 +66,7 @@ static void showmachoheader(void) {
showinthex(macho->loadcount);
showinthex(macho->loadsize);
show(".long",
firstnonnull(recreateflags(kMachoFlagNames, macho->flags),
firstnonnull(RecreateFlags(kMachoFlagNames, macho->flags),
format(b1, "%#x", macho->flags)),
"macho->flags");
showinthex(macho->__reserved);
@ -107,16 +107,16 @@ static void showmacholoadsegment(unsigned i, struct MachoLoadSegment *loadseg) {
showint64hex(loadseg->offset);
showint64hex(loadseg->filesz);
show(".long",
firstnonnull(recreateflags(kMachoVmProtNames, loadseg->maxprot),
firstnonnull(RecreateFlags(kMachoVmProtNames, loadseg->maxprot),
format(b1, "%#x", loadseg->maxprot)),
"loadseg->maxprot");
show(".long",
firstnonnull(recreateflags(kMachoVmProtNames, loadseg->initprot),
firstnonnull(RecreateFlags(kMachoVmProtNames, loadseg->initprot),
format(b1, "%#x", loadseg->initprot)),
"loadseg->initprot");
showinthex(loadseg->sectioncount);
show(".long",
firstnonnull(recreateflags(kMachoSegmentFlagNames, loadseg->flags),
firstnonnull(RecreateFlags(kMachoSegmentFlagNames, loadseg->flags),
format(b1, "%#x", loadseg->flags)),
"loadseg->flags");
for (unsigned j = 0; j < loadseg->sectioncount; ++j) {

View file

@ -94,6 +94,7 @@ void GetOpts(int argc, char *argv[]) {
* e.g. A̸B̸C̸D̸ 41CCB8 42CCB8 43CCB8 44CCB8
*
* @see unicode.org/reports/tr11/#Definitions
* @see https://www.compart.com/en/unicode/category/Sk (Modifier Symbol)
*/
int main(int argc, char *argv[]) {
GetOpts(argc, argv);
@ -109,7 +110,7 @@ int main(int argc, char *argv[]) {
if (bit != 0x00AD &&
((0x1160 <= bit && bit <= 0x11FF) ||
(strcmp(category, "Me") == 0 || strcmp(category, "Mn") == 0 ||
strcmp(category, "Cf") == 0 || strcmp(category, "Sk") == 0))) {
strcmp(category, "Cf") == 0))) {
maxbit = max(bit, maxbit);
CHECK(bitabuilder_setbit(bitset, bit));
}

Some files were not shown because too many files have changed in this diff Show more