mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-02 17:28: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
|
@ -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;
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/runtime/mappings.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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_ */
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue