mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-06 18:00:28 +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
|
@ -31,4 +31,6 @@
|
|||
* @param path is NUL-terminated UTF-8 path
|
||||
* @return pointer inside path or path itself
|
||||
*/
|
||||
char *basename(const char *path) { return basename_n(path, strlen(path)); }
|
||||
textstartup char *basename(const char *path) {
|
||||
return basename_n(path, strlen(path));
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
* @param size is byte length of path
|
||||
* @return pointer inside path or path itself
|
||||
*/
|
||||
char *basename_n(const char *path, size_t size) {
|
||||
textstartup char *basename_n(const char *path, size_t size) {
|
||||
size_t i, l;
|
||||
if (size) {
|
||||
if (isslash(path[size - 1])) {
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CONV_CONV_H_
|
||||
#define COSMOPOLITAN_LIBC_CONV_CONV_H_
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/nt/struct/filetime.h"
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § conversion ─╬─│┼
|
||||
|
@ -23,6 +26,7 @@ long labs(long) libcesque pureconst;
|
|||
long long llabs(long long) libcesque pureconst;
|
||||
char *ltpcpy(char *, long) paramsnonnull() libcesque nocallback;
|
||||
int llog10(unsigned long) libcesque pureconst;
|
||||
int unsleb128(const void *, size_t, int64_t *);
|
||||
int atoi(const char *) paramsnonnull() libcesque nosideeffect;
|
||||
long atol(const char *) paramsnonnull() libcesque nosideeffect;
|
||||
long long atoll(const char *) paramsnonnull() libcesque nosideeffect;
|
||||
|
@ -38,18 +42,12 @@ long wcstol(const wchar_t *, wchar_t **, int);
|
|||
long strtol(const char *, char **, int)
|
||||
paramsnonnull((1)) libcesque nosideeffect;
|
||||
|
||||
intmax_t __imaxabs(intmax_t) asm("imaxabs") libcesque pureconst;
|
||||
#define imaxabs(x) __imaxabs(x)
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § conversion » time ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
struct NtFileTime;
|
||||
struct timespec;
|
||||
struct timeval;
|
||||
|
||||
void filetimetotimespec(struct timespec *, struct NtFileTime) paramsnonnull();
|
||||
struct timespec filetimetotimespec(struct NtFileTime);
|
||||
struct NtFileTime timespectofiletime(struct timespec);
|
||||
struct NtFileTime timetofiletime(int64_t) nothrow pureconst;
|
||||
int64_t filetimetotime(struct NtFileTime) nothrow pureconst;
|
||||
void filetimetotimeval(struct timeval *, struct NtFileTime) nothrow;
|
||||
|
@ -104,6 +102,11 @@ double RoundDecimalPlaces(double, double, double(double));
|
|||
#define lldiv(num, den) ((lldiv_t){(num) / (den), (num) % (den)})
|
||||
#endif
|
||||
|
||||
#ifndef __STRICT_ANSI__
|
||||
intmax_t __imaxabs(intmax_t) asm("imaxabs") libcesque pureconst;
|
||||
#define imaxabs(x) __imaxabs(x)
|
||||
#endif /* !ANSI */
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CONV_CONV_H_ */
|
||||
|
|
|
@ -38,7 +38,8 @@ LIBC_CONV_A_DIRECTDEPS = \
|
|||
LIBC_STUBS \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_SYSV
|
||||
LIBC_SYSV \
|
||||
THIRD_PARTY_COMPILER_RT
|
||||
|
||||
LIBC_CONV_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(LIBC_CONV_A_DIRECTDEPS),$($(x))))
|
||||
|
@ -51,12 +52,10 @@ $(LIBC_CONV_A).pkg: \
|
|||
$(LIBC_CONV_A_OBJS) \
|
||||
$(foreach x,$(LIBC_CONV_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
#o/$(MODE)/libc/conv/strtoimax.o: CC = clang-10
|
||||
#o/$(MODE)/libc/conv/strtoumax.o: CC = clang-10
|
||||
|
||||
o/$(MODE)/libc/conv/itoa64radix10.o \
|
||||
o/$(MODE)/libc/conv/itoa64radix10.greg.o \
|
||||
o/$(MODE)/libc/conv/timetofiletime.o \
|
||||
o/$(MODE)/libc/conv/filetimetotime.o \
|
||||
o/$(MODE)/libc/conv/timespectofiletime.o \
|
||||
o/$(MODE)/libc/conv/filetimetotimespec.o \
|
||||
o/$(MODE)/libc/conv/filetimetotimeval.o: \
|
||||
OVERRIDE_COPTS += \
|
||||
|
|
|
@ -24,9 +24,11 @@
|
|||
/**
|
||||
* Converts Windows COBOL timestamp to UNIX epoch in nanoseconds.
|
||||
*/
|
||||
void filetimetotimespec(struct timespec *ts, struct NtFileTime ft) {
|
||||
uint64_t t = (uint64_t)ft.dwHighDateTime << 32 | ft.dwLowDateTime;
|
||||
uint64_t x = t - MODERNITYSECONDS * HECTONANOSECONDS;
|
||||
ts->tv_sec = x / HECTONANOSECONDS;
|
||||
ts->tv_nsec = x % HECTONANOSECONDS * 100;
|
||||
struct timespec filetimetotimespec(struct NtFileTime ft) {
|
||||
uint64_t x;
|
||||
x = ft.dwHighDateTime;
|
||||
x <<= 32;
|
||||
x |= ft.dwLowDateTime;
|
||||
x -= MODERNITYSECONDS;
|
||||
return (struct timespec){x / HECTONANOSECONDS, x % HECTONANOSECONDS * 100};
|
||||
}
|
||||
|
|
|
@ -23,13 +23,17 @@ COSMOPOLITAN_C_START_
|
|||
|
||||
*/
|
||||
|
||||
size_t int128toarray_radix10(int128_t, char *);
|
||||
size_t uint128toarray_radix10(uint128_t, char *);
|
||||
size_t int64toarray_radix10(int64_t, char *);
|
||||
size_t uint64toarray_radix10(uint64_t, char *);
|
||||
size_t int64toarray(int64_t, char *, int);
|
||||
size_t uint64toarray(uint64_t, char *, int);
|
||||
size_t uint64toarray_radix16(uint64_t, char[hasatleast 17]);
|
||||
size_t uint64toarray_fixed16(uint64_t, char[hasatleast 17], uint8_t);
|
||||
|
||||
#ifndef __STRICT_ANSI__
|
||||
size_t int128toarray_radix10(int128_t, char *);
|
||||
size_t uint128toarray_radix10(uint128_t, char *);
|
||||
#endif
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -20,13 +20,21 @@
|
|||
#include "libc/alg/reverse.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/conv/itoa.h"
|
||||
#include "libc/limits.h"
|
||||
|
||||
uint128_t __udivmodti4(uint128_t, uint128_t, uint128_t *);
|
||||
|
||||
/**
|
||||
* Converts unsigned 128-bit integer to string.
|
||||
* @param a needs at least 40 bytes
|
||||
* @return bytes written w/o nul
|
||||
*/
|
||||
noinline size_t uint128toarray_radix10(uint128_t i, char *a) {
|
||||
size_t j;
|
||||
unsigned rem;
|
||||
uint128_t rem;
|
||||
j = 0;
|
||||
do {
|
||||
i = div10(i, &rem);
|
||||
i = __udivmodti4(i, 10, &rem);
|
||||
a[j++] = rem + '0';
|
||||
} while (i > 0);
|
||||
a[j] = '\0';
|
||||
|
@ -34,10 +42,21 @@ noinline size_t uint128toarray_radix10(uint128_t i, char *a) {
|
|||
return j;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts signed 128-bit integer to string.
|
||||
* @param a needs at least 41 bytes
|
||||
* @return bytes written w/o nul
|
||||
*/
|
||||
size_t int128toarray_radix10(int128_t i, char *a) {
|
||||
if (i < 0) {
|
||||
*a++ = '-';
|
||||
i = -i;
|
||||
if (i != INT128_MIN) {
|
||||
*a++ = '-';
|
||||
return 1 + uint128toarray_radix10(-i, a);
|
||||
} else {
|
||||
memcpy(a, "-170141183460469231731687303715884105728", 41);
|
||||
return 40;
|
||||
}
|
||||
} else {
|
||||
return uint128toarray_radix10(i, a);
|
||||
}
|
||||
return uint128toarray_radix10(i, a);
|
||||
}
|
||||
|
|
38
libc/conv/itoa64fixed16.greg.c
Normal file
38
libc/conv/itoa64fixed16.greg.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*-*- 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/reverse.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/conv/itoa.h"
|
||||
|
||||
size_t uint64toarray_fixed16(uint64_t i, char a[hasatleast 17], uint8_t b) {
|
||||
size_t j;
|
||||
assert(b <= 64);
|
||||
assert(b % 4 == 0);
|
||||
j = 0;
|
||||
if (b) {
|
||||
do {
|
||||
a[j++] = "0123456789abcdef"[i & 15];
|
||||
i >>= 4;
|
||||
} while (b -= 4);
|
||||
}
|
||||
a[j] = '\0';
|
||||
reverse(a, j);
|
||||
return j;
|
||||
}
|
|
@ -20,7 +20,13 @@
|
|||
#include "libc/alg/reverse.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/conv/itoa.h"
|
||||
#include "libc/limits.h"
|
||||
|
||||
/**
|
||||
* Converts unsigned 64-bit integer to string.
|
||||
* @param a needs at least 21 bytes
|
||||
* @return bytes written w/o nul
|
||||
*/
|
||||
noinline size_t uint64toarray_radix10(uint64_t i, char *a) {
|
||||
size_t j;
|
||||
j = 0;
|
||||
|
@ -33,10 +39,21 @@ noinline size_t uint64toarray_radix10(uint64_t i, char *a) {
|
|||
return j;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts signed 64-bit integer to string.
|
||||
* @param a needs at least 21 bytes
|
||||
* @return bytes written w/o nul
|
||||
*/
|
||||
size_t int64toarray_radix10(int64_t i, char *a) {
|
||||
if (i < 0) {
|
||||
*a++ = '-';
|
||||
i = -i;
|
||||
if (i != INT64_MIN) {
|
||||
*a++ = '-';
|
||||
return 1 + uint64toarray_radix10(-i, a);
|
||||
} else {
|
||||
memcpy(a, "-9223372036854775808", 21);
|
||||
return 20;
|
||||
}
|
||||
} else {
|
||||
return uint64toarray_radix10(i, a);
|
||||
}
|
||||
return uint64toarray_radix10(i, a);
|
||||
}
|
||||
|
|
|
@ -22,11 +22,9 @@
|
|||
|
||||
size_t uint64toarray_radix16(uint64_t i, char a[hasatleast 17]) {
|
||||
size_t j;
|
||||
unsigned char d;
|
||||
j = 0;
|
||||
do {
|
||||
d = i % 16;
|
||||
a[j++] = d < 10 ? d + '0' : d + 'a';
|
||||
a[j++] = "0123456789abcdef"[i % 16];
|
||||
i /= 16;
|
||||
} while (i > 0);
|
||||
a[j] = '\0';
|
||||
|
|
|
@ -76,6 +76,10 @@ intmax_t strtoimax(const char *s, char **endptr, int base) {
|
|||
} else {
|
||||
base = 10;
|
||||
}
|
||||
} else if (*s == '0') {
|
||||
++s;
|
||||
if (base == 2 && *s == 'b' && *s == 'B') ++s;
|
||||
if (base == 16 && *s == 'x' && *s == 'X') ++s;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
|
|
|
@ -28,7 +28,10 @@
|
|||
*/
|
||||
uintmax_t strtoumax(const char *s, char **endptr, int base) {
|
||||
const unsigned char *p = (const unsigned char *)s;
|
||||
uintmax_t res = 0;
|
||||
unsigned diglet;
|
||||
uintmax_t res;
|
||||
|
||||
res = 0;
|
||||
|
||||
while (isspace(*p)) {
|
||||
p++;
|
||||
|
@ -49,10 +52,14 @@ uintmax_t strtoumax(const char *s, char **endptr, int base) {
|
|||
} else {
|
||||
base = 10;
|
||||
}
|
||||
} else if (*s == '0') {
|
||||
++s;
|
||||
if (base == 2 && *s == 'b' && *s == 'B') ++s;
|
||||
if (base == 16 && *s == 'x' && *s == 'X') ++s;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
unsigned diglet = kBase36[*p];
|
||||
diglet = kBase36[*p];
|
||||
if (!diglet || diglet > base) break;
|
||||
p++;
|
||||
res *= base;
|
||||
|
|
34
libc/conv/timespectofiletime.c
Normal file
34
libc/conv/timespectofiletime.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/calls/calls.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/nt/struct/filetime.h"
|
||||
|
||||
/**
|
||||
* Converts UNIX nanosecond timestamp to Windows COBOL timestamp.
|
||||
*/
|
||||
struct NtFileTime timespectofiletime(struct timespec ts) {
|
||||
uint64_t x;
|
||||
x = MODERNITYSECONDS;
|
||||
x += ts.tv_sec * HECTONANOSECONDS;
|
||||
x += div100int64(ts.tv_nsec);
|
||||
return (struct NtFileTime){x, x >> 32};
|
||||
}
|
45
libc/conv/unsleb128.c
Normal file
45
libc/conv/unsleb128.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/conv/conv.h"
|
||||
|
||||
/**
|
||||
* Decodes a GNU-style varint from a buffer.
|
||||
*
|
||||
* The GNU Assembler is able to encode numbers this way, since it's used
|
||||
* by the DWARF debug format.
|
||||
*/
|
||||
int unsleb128(const void *buf, size_t size, int64_t *out) {
|
||||
int b;
|
||||
int64_t r, w;
|
||||
unsigned char c;
|
||||
const unsigned char *p, *pe;
|
||||
pe = (p = buf) + size;
|
||||
r = b = 0;
|
||||
do {
|
||||
if (size && p == pe) return -1;
|
||||
c = *p++;
|
||||
w = c & 0x7f;
|
||||
r |= w << b;
|
||||
b += 7;
|
||||
} while (c & 0x80);
|
||||
if (c & 0x40) r |= -1ull << b;
|
||||
if (out) *out = r;
|
||||
return p - (const unsigned char *)buf;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue