Add x86_64-linux-gnu emulator

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

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

View file

@ -38,7 +38,7 @@
int fclose(FILE *f) {
int rc;
if (!f) return 0; /* good java behavior; glibc crashes */
fflushunregister(f);
_fflushunregister(f);
fflush(f);
free_s(&f->buf);
f->state = EOF;

View file

@ -18,7 +18,6 @@
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/runtime/mappings.h"
#include "libc/stdio/stdio.h"
/**

View file

@ -37,7 +37,7 @@ FILE *fdopen(int fd, const char *mode) {
res->reader = freadbuf;
res->writer = fwritebuf;
if ((res->iomode & O_ACCMODE) != O_RDONLY) {
fflushregister(res);
_fflushregister(res);
}
}
return res;

View file

@ -79,7 +79,7 @@ int fflush(FILE *f) {
return res;
}
int fflushregister(FILE *f) {
textstartup int _fflushregister(FILE *f) {
size_t i;
struct StdioFlush *sf;
sf = &g_fflush;
@ -98,7 +98,7 @@ int fflushregister(FILE *f) {
return append(&sf->handles, &f);
}
void fflushunregister(FILE *f) {
void _fflushunregister(FILE *f) {
size_t i;
struct StdioFlush *sf;
sf = &g_fflush;

View file

@ -17,7 +17,8 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/stdio/fputc.h"
#include "libc/calls/calls.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio.h"
/**
@ -25,4 +26,21 @@
*
* @return c (as unsigned char) if written or -1 w/ errno
*/
int fputc(int c, FILE *f) { return __fputc(c, f); }
noinstrument int fputc(int c, FILE *f) {
if (c != -1) {
c &= 0xff;
f->buf[f->end] = c;
f->end = (f->end + 1) & (f->size - 1);
if (unlikely(f->beg == f->end || f->bufmode == _IONBF ||
(f->bufmode == _IOLBF && c == '\n'))) {
if (f->writer) {
return f->writer(f);
} else if (f->beg == f->end) {
return fseteof(f);
}
}
return c;
} else {
return fseteof(f);
}
}

View file

@ -1,36 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_STDIO_FPUTC_H_
#define COSMOPOLITAN_LIBC_STDIO_FPUTC_H_
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/o.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
/**
* Writes byte to stream.
*
* @return c (as unsigned char) if written or -1 w/ errno
*/
forceinline int __fputc(int c, FILE *f) {
/* assert((f->iomode & O_ACCMODE) != O_RDONLY); */
if (c != -1) {
unsigned char ch = (unsigned char)c;
f->buf[f->end] = ch;
f->end = (f->end + 1) & (f->size - 1);
if (f->beg == f->end || f->bufmode == _IONBF ||
(f->bufmode == _IOLBF && ch == '\n')) {
if (f->writer) {
return f->writer(f);
} else if (f->beg == f->end) {
return fseteof(f);
}
}
return ch;
} else {
return fseteof(f);
}
}
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_STDIO_FPUTC_H_ */

View file

@ -18,7 +18,6 @@
02110-1301 USA
*/
#include "libc/errno.h"
#include "libc/stdio/fputc.h"
#include "libc/stdio/stdio.h"
/**
@ -36,7 +35,7 @@ int fputs(const char *s, FILE *f) {
unsigned char *p = (unsigned char *)s;
int res = 0;
while (*p) {
if (__fputc(*p++, f) == -1) {
if (fputc(*p++, f) == -1) {
if (ferror(f) == EINTR) continue;
if (feof(f)) errno = f->state = EPIPE;
return -1;

View file

@ -18,7 +18,6 @@
02110-1301 USA
*/
#include "libc/limits.h"
#include "libc/stdio/fputc.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
@ -35,7 +34,7 @@ wint_t fputwc(wchar_t wc, FILE *f) {
if (wc != -1) {
len = tpencode(buf, sizeof(buf), wc, false);
for (i = 0; i < len; ++i) {
if (__fputc(buf[i], f) == -1) return -1;
if (fputc(buf[i], f) == -1) return -1;
}
return wc;
} else {

View file

@ -18,7 +18,6 @@
02110-1301 USA
*/
#include "libc/conv/conv.h"
#include "libc/conv/sizemultiply.h"
#include "libc/errno.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/internal.h"
@ -34,17 +33,16 @@
*/
size_t fread(void *buf, size_t stride, size_t count, FILE *f) {
int c;
size_t i, bytes;
size_t i, n;
unsigned char *p;
if (!sizemultiply(&bytes, stride, count)) {
return fseterr(f, EOVERFLOW);
}
for (p = buf, i = 0; i < bytes; ++i) {
if ((c = fgetc(f)) == -1) {
if (i % stride != 0) abort(); /* todo(jart) */
for (n = stride * count, p = buf, i = 0; i < n; ++i) {
if ((c = fgetc(f)) != -1) {
p[i] = c & 0xff;
} else if (!(i % stride)) {
return i / stride;
} else {
return fseterr(f, EOVERFLOW);
}
p[i] = c & 0xff;
}
return count;
}

View file

@ -19,4 +19,6 @@
*/
#include "libc/stdio/internal.h"
long fseteof(FILE *f) { return fseterr(f, -1); }
long fseteof(FILE *f) {
return fseterr(f, -1);
}

View file

@ -17,10 +17,8 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/conv/sizemultiply.h"
#include "libc/errno.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/fputc.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio.h"
@ -32,14 +30,15 @@
* @return count on success, [0,count) on EOF, 0 on error or count==0
*/
size_t fwrite(const void *data, size_t stride, size_t count, FILE *f) {
int rc;
size_t i, bytes;
const unsigned char *p = (const unsigned char *)data;
if (!sizemultiply(&bytes, stride, count)) return fseterr(f, EOVERFLOW);
for (i = 0; i < bytes; ++i) {
if ((rc = __fputc(p[i], f)) == -1) {
if (i % stride != 0) abort(); /* todo(jart) */
return i / stride;
size_t i, n;
const unsigned char *p;
for (n = stride * count, p = data, i = 0; i < n; ++i) {
if (fputc(p[i], f) == -1) {
if (!(i % stride)) {
return i / stride;
} else {
return fseterr(f, EOVERFLOW);
}
}
}
return count;

View file

@ -26,7 +26,8 @@ FILE *stderr;
hidden FILE g_stderr;
hidden unsigned char g_stderr_buf[BUFSIZ] aligned(PAGESIZE);
static textstartup void g_stderr_init() {
fflushregister(stderr);
static textstartup void _init_g_stderr2() {
_fflushregister(stderr);
}
const void *const g_stderr_ctor[] initarray = {g_stderr_init};
const void *const g_stderr_ctor[] initarray = {_init_g_stderr2};

View file

@ -27,6 +27,7 @@ hidden FILE g_stdin;
hidden unsigned char g_stdin_buf[BUFSIZ] aligned(PAGESIZE);
static textstartup void g_stdin_init() {
fflushregister(stdin);
_fflushregister(stdin);
}
const void *const g_stdin_ctor[] initarray = {g_stdin_init};

View file

@ -29,14 +29,14 @@ FILE *stdout;
hidden FILE g_stdout;
hidden unsigned char g_stdout_buf[BUFSIZ] aligned(PAGESIZE);
static textstartup void g_stdout_init() {
static textstartup void _init_g_stdout2() {
struct FILE *sf;
sf = stdout;
asm("" : "+r"(sf));
if (IsWindows() || ischardev(pushpop(sf->fd))) {
sf->bufmode = _IOLBF;
}
fflushregister(sf);
_fflushregister(sf);
}
const void *const g_stdout_ctor[] initarray = {g_stdout_init};
const void *const g_stdout_ctor[] initarray = {_init_g_stdout2};

View file

@ -9,8 +9,8 @@ extern unsigned char g_stdinbuf[BUFSIZ];
extern unsigned char g_stdoutbuf[BUFSIZ];
extern unsigned char g_stderrbuf[BUFSIZ];
int fflushregister(FILE *) hidden;
void fflushunregister(FILE *) hidden;
int _fflushregister(FILE *) hidden;
void _fflushunregister(FILE *) hidden;
int freadbuf(FILE *) hidden;
int fwritebuf(FILE *) hidden;

View file

@ -17,7 +17,6 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/stdio/fputc.h"
#include "libc/stdio/stdio.h"
/**

View file

@ -32,7 +32,7 @@ static void fout(FILE *f) {
f->beg = (f->beg + 1) & (f->size - 1);
}
static int serialstdio(FILE *f, unsigned char status, void action(FILE *f)) {
static int serialstdio(FILE *f, unsigned char status, void action(FILE *)) {
int block = 1;
unsigned tally = 0;
while (f->end != f->beg) {
@ -47,5 +47,9 @@ static int serialstdio(FILE *f, unsigned char status, void action(FILE *f)) {
return (int)tally;
}
int fsreadbuf(FILE *f) { return serialstdio(f, UART_TTYDA, fin); }
int fswritebuf(FILE *f) { return serialstdio(f, UART_TTYTXR, fout); }
int fsreadbuf(FILE *f) {
return serialstdio(f, UART_TTYDA, fin);
}
int fswritebuf(FILE *f) {
return serialstdio(f, UART_TTYTXR, fout);
}

View file

@ -10,17 +10,17 @@ COSMOPOLITAN_C_START_
*/
typedef struct FILE {
uint8_t bufmode; /* 0: _IOFBF, etc. (ignored if fd is -1) */
bool noclose; /* 1: for fake dup() */
uint32_t iomode; /* 4: O_RDONLY, etc. (ignored if fd is -1) */
int32_t state; /* 8: 0=OK, -1=EOF, >0=errno */
int fd; /* 12: ≥0=fd, -1=closed|buffer */
uint32_t beg; /* 16 */
uint32_t end; /* 20 */
uint8_t *buf; /* 24 */
size_t size; /* 32 */
int (*reader)(struct FILE *f); /* 40 */
int (*writer)(struct FILE *f); /* 48 */
uint8_t bufmode; // 0x00 _IOFBF, etc. (ignored if fd=-1)
bool noclose; // 0x01 for fake dup()
uint32_t iomode; // 0x04 O_RDONLY, etc. (ignored if fd=-1)
int32_t state; // 0x08 0=OK, -1=EOF, >0=errno
int fd; // 0x0c ≥0=fd, -1=closed|buffer
uint32_t beg; // 0x10
uint32_t end; // 0x14
uint8_t *buf; // 0x18
size_t size; // 0x20
int (*reader)(struct FILE *); // 0x28
int (*writer)(struct FILE *); // 0x30
} FILE;
extern FILE *stdin;
@ -35,7 +35,7 @@ int putc(int, FILE *) paramsnonnull();
int fflush(FILE *);
int fgetc(FILE *) paramsnonnull();
int ungetc(int, FILE *) paramsnonnull();
int fileno(FILE *) paramsnonnull();
int fileno(FILE *) paramsnonnull() nosideeffect;
int fputc(int, FILE *) paramsnonnull();
int fputs(const char *, FILE *) paramsnonnull();
int fputws(const wchar_t *, FILE *) paramsnonnull();

View file

@ -53,6 +53,10 @@ $(LIBC_STDIO_A).pkg: \
$(LIBC_STDIO_A_OBJS) \
$(foreach x,$(LIBC_STDIO_A_DIRECTDEPS),$($(x)_A).pkg)
#o/$(MODE)/libc/stdio/fputc.o: \
OVERRIDE_CFLAGS += \
$(NO_MAGIC)
LIBC_STDIO_LIBS = $(foreach x,$(LIBC_STDIO_ARTIFACTS),$($(x)))
LIBC_STDIO_SRCS = $(foreach x,$(LIBC_STDIO_ARTIFACTS),$($(x)_SRCS))
LIBC_STDIO_HDRS = $(foreach x,$(LIBC_STDIO_ARTIFACTS),$($(x)_HDRS))

View file

@ -17,7 +17,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/hefty/ntspawn.h"
#include "libc/calls/internal.h"

View file

@ -13,7 +13,7 @@ nodiscard int mkostempsm(char *, int, unsigned, int);
compatfn char *mktemp(char *);
int mkostempsmi(char *, int, unsigned, uint64_t *, int,
int openit(const char *, int, ...)) hidden nodiscard;
int (*)(const char *, int, ...)) hidden nodiscard;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -19,28 +19,23 @@
*/
#include "libc/fmt/fmt.h"
#include "libc/limits.h"
#include "libc/stdio/fputc.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/errfuns.h"
struct state {
FILE *const f;
unsigned toto;
FILE *f;
int n;
};
static int vfprintfputchar(int c, struct state *st) {
if (st->toto <= INT_MAX) {
st->toto++;
return __fputc(c, st->f);
} else {
return eoverflow();
}
st->n++;
return fputc(c, st->f);
}
int(vfprintf)(FILE *f, const char *fmt, va_list va) {
struct state st[1] = {{f, 0}};
if (palandprintf(vfprintfputchar, st, fmt, va) != -1) {
return st->toto;
return st->n;
} else {
return -1;
}