mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-06 11:18:30 +00:00
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:
parent
467504308a
commit
f4f4caab0e
1052 changed files with 65667 additions and 7825 deletions
9
tool/build/lib/abp.h
Normal file
9
tool/build/lib/abp.h
Normal 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
81
tool/build/lib/alu.c
Normal 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
43
tool/build/lib/alu.h
Normal 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
82
tool/build/lib/argv.c
Normal 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
80
tool/build/lib/bitscan.c
Normal 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
13
tool/build/lib/bitscan.h
Normal 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_ */
|
50
tool/build/lib/breakpoint.c
Normal file
50
tool/build/lib/breakpoint.c
Normal 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;
|
||||
}
|
21
tool/build/lib/breakpoint.h
Normal file
21
tool/build/lib/breakpoint.h
Normal 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
167
tool/build/lib/bsu.c
Normal 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
68
tool/build/lib/buffer.c
Normal 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
20
tool/build/lib/buffer.h
Normal 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_ */
|
|
@ -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
11
tool/build/lib/case.h
Normal 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
50
tool/build/lib/cond.h
Normal 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
72
tool/build/lib/cpuid.c
Normal 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
11
tool/build/lib/cpuid.h
Normal 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
316
tool/build/lib/cvt.c
Normal 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
18
tool/build/lib/cvt.h
Normal 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
45
tool/build/lib/debug.c
Normal 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
263
tool/build/lib/dis.c
Normal 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
86
tool/build/lib/dis.h
Normal 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
564
tool/build/lib/disarg.c
Normal 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
151
tool/build/lib/diself.c
Normal 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
34
tool/build/lib/dishigh.c
Normal 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
194
tool/build/lib/disinst.c
Normal 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
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
271
tool/build/lib/divmul.c
Normal 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
20
tool/build/lib/divmul.h
Normal 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_ */
|
|
@ -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
115
tool/build/lib/endian.h
Normal 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
166
tool/build/lib/errnos.S
Normal 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
78
tool/build/lib/flags.h
Normal 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
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
47
tool/build/lib/fpu.h
Normal 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_ */
|
49
tool/build/lib/initmachine.c
Normal file
49
tool/build/lib/initmachine.c
Normal 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);
|
||||
}
|
74
tool/build/lib/instruction.c
Normal file
74
tool/build/lib/instruction.c
Normal 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
42
tool/build/lib/ioports.c
Normal 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
12
tool/build/lib/ioports.h
Normal 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
147
tool/build/lib/loader.c
Normal 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
21
tool/build/lib/loader.h
Normal 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
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
149
tool/build/lib/machine.h
Normal 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
241
tool/build/lib/memory.c
Normal 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
32
tool/build/lib/memory.h
Normal 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_ */
|
50
tool/build/lib/memorymalloc.c
Normal file
50
tool/build/lib/memorymalloc.c
Normal 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
47
tool/build/lib/message.c
Normal 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
232
tool/build/lib/modrm.c
Normal 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
82
tool/build/lib/modrm.h
Normal 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
155
tool/build/lib/panel.c
Normal 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
19
tool/build/lib/panel.h
Normal 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
218
tool/build/lib/pml4t.c
Normal 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
21
tool/build/lib/pml4t.h
Normal 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
112
tool/build/lib/pml4tfmt.c
Normal 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
78
tool/build/lib/reset.c
Normal 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
255
tool/build/lib/sse.c
Normal 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
102
tool/build/lib/sse.h
Normal 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
102
tool/build/lib/stack.c
Normal 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
19
tool/build/lib/stack.h
Normal 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
24
tool/build/lib/stats.c
Normal 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
12
tool/build/lib/stats.h
Normal 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
227
tool/build/lib/string.c
Normal 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
22
tool/build/lib/string.h
Normal 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
647
tool/build/lib/syscall.c
Normal 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
13
tool/build/lib/syscall.h
Normal 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
60
tool/build/lib/throw.c
Normal 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
17
tool/build/lib/throw.h
Normal 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
71
tool/build/lib/x87.c
Normal 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
15
tool/build/lib/x87.h
Normal 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_ */
|
64
tool/build/lib/xlaterrno.c
Normal file
64
tool/build/lib/xlaterrno.c
Normal 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;
|
||||
}
|
10
tool/build/lib/xlaterrno.h
Normal file
10
tool/build/lib/xlaterrno.h
Normal 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_ */
|
Loading…
Add table
Add a link
Reference in a new issue