mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-05 02:38:31 +00:00
Add fixes performance and static web server
This commit is contained in:
parent
b6793d42d5
commit
c45e46f871
108 changed files with 2927 additions and 819 deletions
|
@ -35,6 +35,7 @@ TOOL_BUILD_DIRECTDEPS = \
|
|||
LIBC_ELF \
|
||||
LIBC_FMT \
|
||||
LIBC_LOG \
|
||||
LIBC_LOG_ASAN \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
|
|
|
@ -27,6 +27,7 @@ TOOL_BUILD_EMUBIN_CHECKS = \
|
|||
|
||||
TOOL_BUILD_EMUBIN_DIRECTDEPS = \
|
||||
LIBC_STUBS \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_TINYMATH
|
||||
|
||||
TOOL_BUILD_EMUBIN_DEPS := \
|
||||
|
@ -57,10 +58,10 @@ o/dbg/tool/build/emubin/lisp.real.com.dbg: \
|
|||
$(APE)
|
||||
-@$(APELINK)
|
||||
|
||||
o/tiny/tool/build/emubin/lisp.bin.dbg: \
|
||||
o/$(MODE)/tool/build/emubin/lisp.bin.dbg: \
|
||||
$(TOOL_BUILD_EMUBIN_DEPS) \
|
||||
o/tiny/tool/build/emubin/lisp.real.o \
|
||||
o/tiny/tool/build/emubin/lispstart.o \
|
||||
o/$(MODE)/tool/build/emubin/lisp.real.o \
|
||||
o/$(MODE)/tool/build/emubin/lispstart.o \
|
||||
tool/build/emubin/lisp.lds
|
||||
@$(ELFLINK) -z max-page-size=0x10
|
||||
|
||||
|
|
|
@ -3,36 +3,35 @@
|
|||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ 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. │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ 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 │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
|
||||
#define TRACE 0
|
||||
#define ERRORS 1
|
||||
#define LONG long
|
||||
#define WORD short
|
||||
#define WORDS 2048
|
||||
#define WORDS 8192
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ The LISP Challenge § 8086 PC BIOS / x86_64 Linux System Integration ─╬─│┼
|
||||
│ The LISP Challenge § Impure x86_64 Linux 8086 PC BIOS System Integration ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
#define ATOM(x) /* a.k.a. !(x&1) */ \
|
||||
({ \
|
||||
char IsAtom; \
|
||||
asm("test%z1\t$1,%1" : "=@ccz"(IsAtom) : "Qm"((char)x)); \
|
||||
IsAtom; \
|
||||
#define TYPE(x) /* a.k.a. x&1 */ \
|
||||
({ \
|
||||
char IsAtom; \
|
||||
asm("test%z1\t$1,%1" : "=@ccnz"(IsAtom) : "Qm"((char)x)); \
|
||||
IsAtom; \
|
||||
})
|
||||
|
||||
#define OBJECT(t, v) /* a.k.a. v<<1|t */ \
|
||||
|
@ -57,71 +56,109 @@
|
|||
c; \
|
||||
})
|
||||
|
||||
#define REAL_READ(BASE, INDEX, DISP) /* a.k.a. b[i] */ \
|
||||
({ \
|
||||
__typeof(*(BASE)) Reg; \
|
||||
if (__builtin_constant_p(INDEX) && !(INDEX)) { \
|
||||
asm("mov\t%c2(%1),%0" \
|
||||
: "=Q"(Reg) \
|
||||
: "bDS"(BASE), "i"((DISP) * sizeof(*(BASE)))); \
|
||||
} else { \
|
||||
asm("mov\t%c3(%1,%2),%0" \
|
||||
: "=Q"(Reg) \
|
||||
: "b"(BASE), "DS"((long)(INDEX) * sizeof(*(BASE))), \
|
||||
"i"((DISP) * sizeof(*(BASE)))); \
|
||||
} \
|
||||
Reg; \
|
||||
#define REAL_READ_(REG, BASE, INDEX, DISP) \
|
||||
({ \
|
||||
__typeof(*(BASE)) Reg; \
|
||||
if (__builtin_constant_p(INDEX) && !(INDEX)) { \
|
||||
asm("mov\t%c2(%1),%0" \
|
||||
: REG(Reg) \
|
||||
: "bDS"(BASE), "i"((DISP) * sizeof(*(BASE))), \
|
||||
"m"(BASE[(INDEX) + (DISP)])); \
|
||||
} else { \
|
||||
asm("mov\t%c3(%1,%2),%0" \
|
||||
: REG(Reg) \
|
||||
: "b"(BASE), "DS"((long)(INDEX) * sizeof(*(BASE))), \
|
||||
"i"((DISP) * sizeof(*(BASE))), "m"(BASE[(INDEX) + (DISP)])); \
|
||||
} \
|
||||
Reg; \
|
||||
})
|
||||
|
||||
#define REAL_READ_ARRAY_FIELD(OBJECT, MEMBER, INDEX, DISP) /* o->m[i] */ \
|
||||
/* #ifdef __REAL_MODE__ */
|
||||
#define REAL_READ(BASE, INDEX, DISP) /* a.k.a. b[i] */ \
|
||||
(sizeof(*(BASE)) == 1 ? REAL_READ_("=Q", BASE, INDEX, DISP) \
|
||||
: REAL_READ_("=r", BASE, INDEX, DISP))
|
||||
/* #else */
|
||||
/* #define REAL_READ(BASE, INDEX, DISP) BASE[INDEX + DISP] */
|
||||
/* #endif */
|
||||
|
||||
#define REAL_READ_ARRAY_FIELD_(REG, OBJECT, MEMBER, INDEX, DISP) \
|
||||
({ \
|
||||
__typeof(*(OBJECT->MEMBER)) Reg; \
|
||||
if (!(OBJECT)) { \
|
||||
asm("mov\t%c2(%1),%0" \
|
||||
: "=Q"(Reg) \
|
||||
: REG(Reg) \
|
||||
: "bDS"((long)(INDEX) * sizeof(*(OBJECT->MEMBER))), \
|
||||
"i"(__builtin_offsetof(__typeof(*(OBJECT)), MEMBER) + \
|
||||
sizeof(*(OBJECT->MEMBER)) * (DISP))); \
|
||||
sizeof(*(OBJECT->MEMBER)) * (DISP)), \
|
||||
"m"(OBJECT->MEMBER)); \
|
||||
} else { \
|
||||
asm("mov\t%c3(%1,%2),%0" \
|
||||
: "=Q"(Reg) \
|
||||
: REG(Reg) \
|
||||
: "b"(OBJECT), "DS"((long)(INDEX) * sizeof(*(OBJECT->MEMBER))), \
|
||||
"i"(__builtin_offsetof(__typeof(*(OBJECT)), MEMBER) + \
|
||||
sizeof(*(OBJECT->MEMBER)) * (DISP))); \
|
||||
sizeof(*(OBJECT->MEMBER)) * (DISP)), \
|
||||
"m"(OBJECT->MEMBER)); \
|
||||
} \
|
||||
Reg; \
|
||||
})
|
||||
|
||||
#define REAL_WRITE_ARRAY_FIELD(OBJECT, MEMBER, INDEX, DISP, VALUE) \
|
||||
do { \
|
||||
__typeof(*(OBJECT->MEMBER)) Reg; \
|
||||
if (!(OBJECT)) { \
|
||||
asm volatile("mov\t%0,%c2(%1)" \
|
||||
: /* manual output */ \
|
||||
: "Q"((__typeof(*(OBJECT->MEMBER)))(VALUE)), \
|
||||
"bDS"((long)(INDEX) * sizeof(*(OBJECT->MEMBER))), \
|
||||
"i"(__builtin_offsetof(__typeof(*(OBJECT)), MEMBER) + \
|
||||
sizeof(*(OBJECT->MEMBER)) * (DISP)) \
|
||||
: "memory"); \
|
||||
} else { \
|
||||
asm volatile("mov\t%0,%c3(%1,%2)" \
|
||||
: /* manual output */ \
|
||||
: "Q"((__typeof(*(OBJECT->MEMBER)))(VALUE)), "b"(OBJECT), \
|
||||
"DS"((long)(INDEX) * sizeof(*(OBJECT->MEMBER))), \
|
||||
"i"(__builtin_offsetof(__typeof(*(OBJECT)), MEMBER) + \
|
||||
sizeof(*(OBJECT->MEMBER)) * (DISP)) \
|
||||
: "memory"); \
|
||||
} \
|
||||
/* #ifdef __REAL_MODE__ */
|
||||
#define REAL_READ_ARRAY_FIELD(OBJECT, MEMBER, INDEX, DISP) /* o->m[i] */ \
|
||||
(sizeof(*(OBJECT->MEMBER)) == 1 \
|
||||
? REAL_READ_ARRAY_FIELD_("=Q", OBJECT, MEMBER, INDEX, DISP) \
|
||||
: REAL_READ_ARRAY_FIELD_("=r", OBJECT, MEMBER, INDEX, DISP))
|
||||
/* #else */
|
||||
/* #define REAL_READ_ARRAY_FIELD(o, m, i, d) o->m[i + d] */
|
||||
/* #endif */
|
||||
|
||||
#define REAL_WRITE_ARRAY_FIELD_(REG, OBJECT, MEMBER, INDEX, DISP, VALUE) \
|
||||
do { \
|
||||
if (!(OBJECT)) { \
|
||||
asm("mov\t%1,%c3(%2)" \
|
||||
: "=m"(OBJECT->MEMBER) \
|
||||
: REG((__typeof(*(OBJECT->MEMBER)))(VALUE)), \
|
||||
"bDS"((long)(INDEX) * sizeof(*(OBJECT->MEMBER))), \
|
||||
"i"(__builtin_offsetof(__typeof(*(OBJECT)), MEMBER) + \
|
||||
sizeof(*(OBJECT->MEMBER)) * (DISP))); \
|
||||
} else { \
|
||||
asm("mov\t%1,%c4(%2,%3)" \
|
||||
: "=m"(OBJECT->MEMBER) \
|
||||
: REG((__typeof(*(OBJECT->MEMBER)))(VALUE)), "b"(OBJECT), \
|
||||
"DS"((long)(INDEX) * sizeof(*(OBJECT->MEMBER))), \
|
||||
"i"(__builtin_offsetof(__typeof(*(OBJECT)), MEMBER) + \
|
||||
sizeof(*(OBJECT->MEMBER)) * (DISP))); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static void *SetMemory(void *di, int al, unsigned long cx) {
|
||||
/* #ifdef __REAL_MODE__ */
|
||||
#define REAL_WRITE_ARRAY_FIELD(OBJECT, MEMBER, INDEX, DISP, VALUE) \
|
||||
do { \
|
||||
__typeof(*(OBJECT->MEMBER)) Reg; \
|
||||
switch (sizeof(*(OBJECT->MEMBER))) { \
|
||||
case 1: \
|
||||
REAL_WRITE_ARRAY_FIELD_("Q", OBJECT, MEMBER, INDEX, DISP, VALUE); \
|
||||
break; \
|
||||
default: \
|
||||
REAL_WRITE_ARRAY_FIELD_("ri", OBJECT, MEMBER, INDEX, DISP, VALUE); \
|
||||
break; \
|
||||
} \
|
||||
} while (0)
|
||||
/* #else */
|
||||
/* #define REAL_WRITE_ARRAY_FIELD(o, m, i, d, v) o->m[i + d] = v */
|
||||
/* #endif */
|
||||
|
||||
long jb[8];
|
||||
int setjmp(void *) __attribute__((__returns_twice__));
|
||||
int longjmp(void *, int) __attribute__((__noreturn__));
|
||||
|
||||
static inline void *SetMemory(void *di, int al, unsigned long cx) {
|
||||
asm("rep stosb"
|
||||
: "=D"(di), "=c"(cx), "=m"(*(char(*)[cx])di)
|
||||
: "0"(di), "1"(cx), "a"(al));
|
||||
return di;
|
||||
}
|
||||
|
||||
static void *CopyMemory(void *di, void *si, unsigned long cx) {
|
||||
static inline void *CopyMemory(void *di, void *si, unsigned long cx) {
|
||||
asm("rep movsb"
|
||||
: "=D"(di), "=S"(si), "=c"(cx), "=m"(*(char(*)[cx])di)
|
||||
: "0"(di), "1"(si), "2"(cx));
|
||||
|
@ -147,14 +184,13 @@ static void RawMode(void) {
|
|||
#endif
|
||||
}
|
||||
|
||||
__attribute__((__noinline__)) static int PrintChar(LONG c) {
|
||||
__attribute__((__noinline__)) static void PrintChar(LONG c) {
|
||||
#ifdef __REAL_MODE__
|
||||
asm volatile("mov\t$0x0E,%%ah\n\t"
|
||||
"int\t$0x10"
|
||||
: /* no outputs */
|
||||
: "a"(c), "b"(7)
|
||||
: "memory");
|
||||
return 0;
|
||||
#else
|
||||
static short buf;
|
||||
int rc;
|
||||
|
@ -163,7 +199,6 @@ __attribute__((__noinline__)) static int PrintChar(LONG c) {
|
|||
: "=a"(rc)
|
||||
: "0"(1), "D"(1), "S"(&buf), "d"(1)
|
||||
: "rcx", "r11", "memory");
|
||||
return rc;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -177,6 +212,7 @@ static void PrintString(char *s) {
|
|||
}
|
||||
|
||||
static int XlatChar(LONG c) {
|
||||
if (c == 0x7F) return '\b';
|
||||
if (c >= 'a') {
|
||||
asm volatile("" ::: "memory");
|
||||
if (c <= 'z') c -= 'a' - 'A';
|
||||
|
@ -185,19 +221,16 @@ static int XlatChar(LONG c) {
|
|||
}
|
||||
|
||||
static int EchoChar(LONG c) {
|
||||
if (c == '\b' || c == 0x7F) {
|
||||
PrintString("\b \b");
|
||||
return '\b';
|
||||
} else {
|
||||
if (c != '\b') {
|
||||
PrintChar(c);
|
||||
if (c == '\r') {
|
||||
PrintChar('\n');
|
||||
}
|
||||
return c;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
static noinline int ReadChar(void) {
|
||||
__attribute__((__noinline__)) static noinline int ReadChar(void) {
|
||||
int c;
|
||||
#ifdef __REAL_MODE__
|
||||
asm volatile("int\t$0x16" : "=a"(c) : "0"(0) : "memory");
|
||||
|
@ -213,13 +246,13 @@ static noinline int ReadChar(void) {
|
|||
}
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ The LISP Challenge § LISP Machine ─╬─│┼
|
||||
│ The LISP Challenge § Pure Original LISP Machine ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
#define TYPE_ATOM 0
|
||||
#define TYPE_CONS 1
|
||||
#define ATOM 0
|
||||
#define CONS 1
|
||||
|
||||
#define ATOM_NIL 0
|
||||
#define NIL 0
|
||||
#define ATOM_T 8
|
||||
#define ATOM_QUOTE 12
|
||||
#define ATOM_ATOM 24
|
||||
|
@ -234,7 +267,7 @@ static noinline int ReadChar(void) {
|
|||
#define ATOM_DEFUN 110
|
||||
|
||||
#define Quote(x) List(ATOM_QUOTE, x)
|
||||
#define List(x, y) Cons(x, Cons(y, ATOM_NIL))
|
||||
#define List(x, y) Cons(x, Cons(y, NIL))
|
||||
#define Caar(x) Car(Car(x)) // ((A B C D) (E F G) H I) → A
|
||||
#define Cdar(x) Cdr(Car(x)) // ((A B C D) (E F G) H I) → (B C D)
|
||||
#define Cadar(x) Cadr(Car(x)) // ((A B C D) (E F G) H I) → B
|
||||
|
@ -242,22 +275,40 @@ static noinline int ReadChar(void) {
|
|||
#define Cadr(x) Car(Cdr(x)) // ((A B C D) (E F G) H I) → (E F G)
|
||||
#define Caddr(x) Cadr(Cdr(x)) // ((A B C D) (E F G) H I) → H
|
||||
|
||||
#define BOOL(x) ((x) ? ATOM_T : ATOM_NIL)
|
||||
#define BOOL(x) ((x) ? ATOM_T : NIL)
|
||||
#define VALUE(x) ((x) >> 1)
|
||||
#define PTR(i) ((i) << 1 | CONS)
|
||||
|
||||
#define ARRAYLEN(A) \
|
||||
((sizeof(A) / sizeof(*(A))) / ((unsigned)!(sizeof(A) % sizeof(*(A)))))
|
||||
|
||||
struct Lisp {
|
||||
WORD memory[WORDS];
|
||||
WORD mem[WORDS];
|
||||
unsigned char syntax[256];
|
||||
unsigned char look;
|
||||
char token[16];
|
||||
WORD look;
|
||||
WORD globals;
|
||||
int index;
|
||||
WORD index;
|
||||
char token[128];
|
||||
char str[WORDS];
|
||||
};
|
||||
|
||||
const char kSymbols[] aligned(1) = "\
|
||||
_Static_assert(sizeof(struct Lisp) <= 0x7c00 - 0x600,
|
||||
"LISP Machine too large for real mode");
|
||||
|
||||
_Alignas(char) const char kSymbols[] = "\
|
||||
NIL\0T\0QUOTE\0ATOM\0EQ\0COND\0CAR\0CDR\0CONS\0LABEL\0LAMBDA\0SET\0DEFUN\0";
|
||||
|
||||
_Alignas(WORD) const WORD kGlobals[] = {
|
||||
[0] = PTR(2), // ((T . T) (NIL . NIL))
|
||||
[1] = PTR(4), //
|
||||
[2] = ATOM_T, // (T . T)
|
||||
[3] = ATOM_T, //
|
||||
[4] = PTR(6), // ((NIL . NIL))
|
||||
[5] = NIL, //
|
||||
[6] = NIL, // (NIL . NIL)
|
||||
[7] = NIL, //
|
||||
};
|
||||
|
||||
#ifdef __REAL_MODE__
|
||||
static struct Lisp *const q;
|
||||
#else
|
||||
|
@ -281,28 +332,39 @@ static void SetupSyntax(void) {
|
|||
q->syntax['\''] = '\'';
|
||||
}
|
||||
|
||||
forceinline WORD Car(LONG x) {
|
||||
return REAL_READ_ARRAY_FIELD(q, memory, VALUE(x), 0);
|
||||
static inline WORD Car(LONG x) {
|
||||
return REAL_READ_ARRAY_FIELD(q, mem, VALUE(x), 0);
|
||||
}
|
||||
|
||||
forceinline WORD Cdr(LONG x) {
|
||||
return REAL_READ_ARRAY_FIELD(q, memory, VALUE(x), 1);
|
||||
static inline WORD Cdr(LONG x) {
|
||||
return REAL_READ_ARRAY_FIELD(q, mem, VALUE(x), 1);
|
||||
}
|
||||
|
||||
static WORD Cons(WORD car, WORD cdr) {
|
||||
int i, c;
|
||||
#if TRACE
|
||||
PrintString("CONS->");
|
||||
Print(car);
|
||||
PrintString(" ");
|
||||
Print(cdr);
|
||||
#endif
|
||||
int i, cell;
|
||||
i = q->index;
|
||||
REAL_WRITE_ARRAY_FIELD(q, memory, i, 0, car);
|
||||
REAL_WRITE_ARRAY_FIELD(q, memory, i, 1, cdr);
|
||||
q->index += 2;
|
||||
c = OBJECT(TYPE_CONS, i);
|
||||
return c;
|
||||
REAL_WRITE_ARRAY_FIELD(q, mem, i, 0, car);
|
||||
REAL_WRITE_ARRAY_FIELD(q, mem, i, 1, cdr);
|
||||
q->index = i + 2;
|
||||
cell = OBJECT(CONS, i);
|
||||
#if TRACE
|
||||
PrintString("CONS<-");
|
||||
Print(cell);
|
||||
#endif
|
||||
return cell;
|
||||
}
|
||||
|
||||
static void SetupBuiltins(void) {
|
||||
CopyMemory(q->str, kSymbols, sizeof(kSymbols));
|
||||
q->globals =
|
||||
Cons(Cons(ATOM_NIL, ATOM_NIL), Cons(Cons(ATOM_T, ATOM_T), ATOM_NIL));
|
||||
CopyMemory(q->mem, kGlobals, sizeof(kGlobals));
|
||||
q->index = ARRAYLEN(kGlobals);
|
||||
q->globals = PTR(0);
|
||||
}
|
||||
|
||||
static char *StpCpy(char *d, char *s) {
|
||||
|
@ -314,7 +376,7 @@ static char *StpCpy(char *d, char *s) {
|
|||
return d;
|
||||
}
|
||||
|
||||
static WORD Intern(char *s) {
|
||||
WORD Intern(char *s) {
|
||||
int j, cx;
|
||||
char c, *z, *t;
|
||||
z = q->str;
|
||||
|
@ -325,7 +387,7 @@ static WORD Intern(char *s) {
|
|||
break;
|
||||
}
|
||||
if (!c) {
|
||||
return OBJECT(TYPE_ATOM, z - q->str - j - 1);
|
||||
return OBJECT(ATOM, z - q->str - j - 1);
|
||||
}
|
||||
c = LODS(z);
|
||||
}
|
||||
|
@ -334,11 +396,11 @@ static WORD Intern(char *s) {
|
|||
}
|
||||
--z;
|
||||
StpCpy(z, s);
|
||||
return OBJECT(TYPE_ATOM, SUB((long)z, q->str));
|
||||
return OBJECT(ATOM, SUB((long)z, q->str));
|
||||
}
|
||||
|
||||
forceinline unsigned char XlatSyntax(unsigned char b) {
|
||||
return REAL_READ_ARRAY_FIELD(q, syntax, b, 0); /* a.k.a. q->syntax[b] */
|
||||
return REAL_READ_ARRAY_FIELD(q, syntax, b, 0);
|
||||
}
|
||||
|
||||
static void GetToken(void) {
|
||||
|
@ -357,7 +419,8 @@ static void GetToken(void) {
|
|||
if (b != '\b') {
|
||||
STOS(t, b);
|
||||
} else if (t > q->token) {
|
||||
--t;
|
||||
PrintString("\b \b");
|
||||
if (t > q->token) --t;
|
||||
}
|
||||
b = ReadChar();
|
||||
}
|
||||
|
@ -387,7 +450,7 @@ static WORD GetList(void) {
|
|||
case '\'':
|
||||
return AddList(GetQuote());
|
||||
case ')':
|
||||
return ATOM_NIL;
|
||||
return NIL;
|
||||
case '.':
|
||||
return ConsumeObject();
|
||||
}
|
||||
|
@ -422,7 +485,7 @@ static void PrintList(LONG x) {
|
|||
PrintChar('(');
|
||||
PrintObject(Car(x));
|
||||
while ((x = Cdr(x))) {
|
||||
if (!ATOM(x)) {
|
||||
if (TYPE(x) == CONS) {
|
||||
PrintChar(' ');
|
||||
PrintObject(Car(x));
|
||||
} else {
|
||||
|
@ -434,7 +497,7 @@ static void PrintList(LONG x) {
|
|||
}
|
||||
|
||||
static void PrintObject(LONG x) {
|
||||
if (ATOM(x)) {
|
||||
if (TYPE(x) == ATOM) {
|
||||
PrintAtom(x);
|
||||
} else {
|
||||
PrintList(x);
|
||||
|
@ -447,8 +510,7 @@ static void Print(LONG i) {
|
|||
}
|
||||
|
||||
__attribute__((__noreturn__)) static void Reset(void) {
|
||||
asm volatile("jmp\tRepl");
|
||||
__builtin_unreachable();
|
||||
longjmp(jb, 1);
|
||||
}
|
||||
|
||||
__attribute__((__noreturn__)) static void OnUndefined(LONG x) {
|
||||
|
@ -472,7 +534,7 @@ __attribute__((__noreturn__)) static void OnArity(void) {
|
|||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
static WORD Atom(LONG x) {
|
||||
return BOOL(ATOM(x));
|
||||
return BOOL(TYPE(x) == ATOM);
|
||||
}
|
||||
|
||||
static WORD Null(LONG x) {
|
||||
|
@ -480,24 +542,32 @@ static WORD Null(LONG x) {
|
|||
}
|
||||
|
||||
static WORD Eq(LONG x, LONG y) {
|
||||
return BOOL(x == y); /* undefiled if !ATOM(x)||!ATOM(y) */
|
||||
return BOOL(x == y); /* undefined if !Atom(x)||!Atom(y) */
|
||||
}
|
||||
|
||||
static WORD Assoc(LONG x, LONG y) {
|
||||
for (;;) {
|
||||
if (!y) OnUndefined(x);
|
||||
if (Eq(Caar(y), x)) break;
|
||||
y = Cdr(y);
|
||||
}
|
||||
return Cdar(y);
|
||||
if (Null(y)) OnUndefined(x);
|
||||
if (Eq(Caar(y), x)) return Cdar(y);
|
||||
return Assoc(x, Cdr(y));
|
||||
}
|
||||
|
||||
static WORD Append(LONG x, LONG y) {
|
||||
if (x) {
|
||||
return Cons(Car(x), Append(Cdr(x), y));
|
||||
#if TRACE
|
||||
PrintString("APPEND->");
|
||||
Print(x);
|
||||
PrintString(" ");
|
||||
Print(y);
|
||||
#endif
|
||||
if (!Null(x)) {
|
||||
x = Cons(Car(x), Append(Cdr(x), y));
|
||||
} else {
|
||||
return y;
|
||||
x = y;
|
||||
}
|
||||
#if TRACE
|
||||
PrintString("APPEND<-");
|
||||
Print(x);
|
||||
#endif
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -506,26 +576,41 @@ static WORD Append(LONG x, LONG y) {
|
|||
* @note recoded to make lists in dot notation
|
||||
* @note it's zip() basically
|
||||
*/
|
||||
static WORD Pair(LONG x, LONG y) {
|
||||
if (!x && !y) {
|
||||
return ATOM_NIL;
|
||||
} else if (!ATOM(x) && !ATOM(y)) {
|
||||
return Cons(Cons(Car(x), Car(y)), Pair(Cdr(x), Cdr(y)));
|
||||
static WORD Pair_(LONG x, LONG y) {
|
||||
if (Null(x) && Null(y)) {
|
||||
return NIL;
|
||||
} else if (TYPE(x) == CONS && TYPE(y) == CONS) {
|
||||
return Cons(Cons(Car(x), Car(y)), Pair_(Cdr(x), Cdr(y)));
|
||||
} else {
|
||||
OnArity();
|
||||
}
|
||||
}
|
||||
|
||||
static WORD Pair(LONG x, LONG y) {
|
||||
#if TRACE
|
||||
PrintString("PAIR->");
|
||||
Print(x);
|
||||
PrintString(" ");
|
||||
Print(y);
|
||||
#endif
|
||||
x = Pair_(x, y);
|
||||
#if TRACE
|
||||
PrintString("PAIR<-");
|
||||
Print(x);
|
||||
#endif
|
||||
return x;
|
||||
}
|
||||
|
||||
static WORD Appq(long m) {
|
||||
if (m) {
|
||||
return Cons(List(ATOM_QUOTE, Car(m)), Appq(Cdr(m)));
|
||||
} else {
|
||||
return ATOM_NIL;
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
static WORD Apply(long f, long a) {
|
||||
return Eval(Cons(f, Appq(a)), ATOM_NIL);
|
||||
return Eval(Cons(f, Appq(a)), NIL);
|
||||
}
|
||||
|
||||
static WORD Evcon(LONG c, LONG a) {
|
||||
|
@ -536,14 +621,29 @@ static WORD Evcon(LONG c, LONG a) {
|
|||
}
|
||||
}
|
||||
|
||||
static WORD Evlis(LONG m, LONG a) {
|
||||
static WORD Evlis_(LONG m, LONG a) {
|
||||
if (m) {
|
||||
return Cons(Eval(Car(m), a), Evlis(Cdr(m), a));
|
||||
return Cons(Eval(Car(m), a), Evlis_(Cdr(m), a));
|
||||
} else {
|
||||
return ATOM_NIL;
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
static WORD Evlis(LONG m, LONG a) {
|
||||
#if TRACE
|
||||
PrintString("EVLIS->");
|
||||
Print(m);
|
||||
PrintString(" ");
|
||||
Print(a);
|
||||
#endif
|
||||
m = Evlis_(m, a);
|
||||
#if TRACE
|
||||
PrintString("EVLIS<-");
|
||||
Print(m);
|
||||
#endif
|
||||
return m;
|
||||
}
|
||||
|
||||
static WORD Set(LONG e) {
|
||||
WORD name, value;
|
||||
name = Car(e);
|
||||
|
@ -563,9 +663,9 @@ static WORD Defun(LONG e) {
|
|||
}
|
||||
|
||||
static WORD Evaluate(LONG e, LONG a) {
|
||||
if (ATOM(e)) {
|
||||
if (Atom(e)) {
|
||||
return Assoc(e, a);
|
||||
} else if (ATOM(Car(e))) {
|
||||
} else if (Atom(Car(e))) {
|
||||
switch (Car(e)) {
|
||||
case ATOM_QUOTE:
|
||||
return Cadr(e);
|
||||
|
@ -601,6 +701,8 @@ static WORD Eval(LONG e, LONG a) {
|
|||
#if TRACE
|
||||
PrintString("->");
|
||||
Print(e);
|
||||
PrintString(" ");
|
||||
Print(a);
|
||||
#endif
|
||||
e = Evaluate(e, a);
|
||||
#if TRACE
|
||||
|
@ -615,6 +717,7 @@ static WORD Eval(LONG e, LONG a) {
|
|||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
void Repl(void) {
|
||||
setjmp(jb);
|
||||
for (;;) {
|
||||
PrintString("* ");
|
||||
Print(Eval(Read(), q->globals));
|
||||
|
@ -622,7 +725,7 @@ void Repl(void) {
|
|||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
RawMode();
|
||||
/* RawMode(); */
|
||||
SetupSyntax();
|
||||
SetupBuiltins();
|
||||
PrintString("THE LISP CHALLENGE V1\r\n"
|
|
@ -29,6 +29,7 @@ SECTIONS {
|
|||
. = 0x1fe;
|
||||
SHORT(0xaa55);
|
||||
*(.text .text.*)
|
||||
_etext = .;
|
||||
. = ALIGN(512);
|
||||
}
|
||||
|
||||
|
@ -43,10 +44,11 @@ SECTIONS {
|
|||
}
|
||||
}
|
||||
|
||||
syntax = 0x600+2048*2;
|
||||
look = 0x600+2048*2+256;
|
||||
token = 0x600+2048*2+256+1;
|
||||
globals = 0x600+2048*2+256+1+16;
|
||||
index = 0x600+2048*2+256+1+16+2;
|
||||
str = 0x600+2048*2+256+1+16+2+4;
|
||||
v_sectors = SIZEOF(.text) / 512;
|
||||
boot = 0x7c00;
|
||||
q.syntax = 8192*2;
|
||||
q.look = 8192*2+256;
|
||||
q.globals = 8192*2+256+2;
|
||||
q.index = 8192*2+256+2+2;
|
||||
q.token = 8192*2+256+2+2+2;
|
||||
q.str = 8192*2+256+2+2+2+128;
|
||||
v_sectors = SIZEOF(.text) / 512;
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
.code16
|
||||
.section .start,"ax",@progbits
|
||||
_start: jmp 1f
|
||||
1: ljmp $0x600>>4,$2f
|
||||
2: push %cs
|
||||
1: ljmp $0x600>>4,$_begin
|
||||
_begin: push %cs
|
||||
pop %ds
|
||||
push %cs
|
||||
pop %es
|
||||
|
@ -50,3 +50,45 @@ _start: jmp 1f
|
|||
.globl _start
|
||||
.globl v_sectors
|
||||
.globl main
|
||||
|
||||
setjmp: mov %sp,%ax
|
||||
stosw # sp
|
||||
xchg %ax,%si
|
||||
movsw %ss:(%si),(%di) # ip
|
||||
mov %bp,%ax
|
||||
stosw # bp
|
||||
ret
|
||||
.type setjmp,@function
|
||||
.size setjmp,.-setjmp
|
||||
.globl setjmp
|
||||
|
||||
longjmp:
|
||||
mov (%di),%sp
|
||||
mov 2(%di),%dx
|
||||
mov 4(%di),%bp
|
||||
pop %ax
|
||||
mov %si,%ax
|
||||
jmp *%dx
|
||||
.type longjmp,@function
|
||||
.size longjmp,.-longjmp
|
||||
.globl longjmp
|
||||
|
||||
.globl q.syntax
|
||||
.type q.syntax,@function
|
||||
.globl q.look
|
||||
.type q.look,@function
|
||||
.globl q.globals
|
||||
.type q.globals,@function
|
||||
.globl q.index
|
||||
.type q.index,@function
|
||||
.globl q.token
|
||||
.type q.token,@function
|
||||
.globl q.str
|
||||
.type q.str,@function
|
||||
|
||||
.globl boot
|
||||
.type boot,@function
|
||||
.globl bss
|
||||
.type bss,@function
|
||||
.globl rodata
|
||||
.type rodata,@function
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/unicode/unicode.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/dtoa/dtoa.h"
|
||||
|
@ -91,8 +92,7 @@ DESCRIPTION\n\
|
|||
\n\
|
||||
FLAGS\n\
|
||||
\n\
|
||||
-h\n\
|
||||
-? help\n\
|
||||
-h help\n\
|
||||
-v verbosity\n\
|
||||
-r real mode\n\
|
||||
-s statistics\n\
|
||||
|
@ -137,8 +137,9 @@ COMPLETENESS\n\
|
|||
#define QUIT 0x200
|
||||
#define EXIT 0x400
|
||||
|
||||
#define CTRL(C) ((C) ^ 0100)
|
||||
#define ALT(C) (('\e' << 010) | (C))
|
||||
#define CTRL(C) ((C) ^ 0100)
|
||||
#define ALT(C) (('\e' << 010) | (C))
|
||||
#define SEX(x, b) ((x) | ((x) & (1ull << (b)) ? -(1ull << (b)) : 0))
|
||||
|
||||
struct Panels {
|
||||
union {
|
||||
|
@ -215,16 +216,6 @@ static struct Breakpoints breakpoints;
|
|||
static void SetupDraw(void);
|
||||
static void Redraw(void);
|
||||
|
||||
static uint64_t SignExtend(uint64_t x, uint8_t b) {
|
||||
uint64_t s;
|
||||
s = 1;
|
||||
b -= 1;
|
||||
b &= 63;
|
||||
s <<= b;
|
||||
if (x & s) x |= ~(s - 1);
|
||||
return x;
|
||||
}
|
||||
|
||||
static char *FormatDouble(char *b, double x) {
|
||||
return g_fmt(b, x);
|
||||
}
|
||||
|
@ -234,16 +225,15 @@ static void SetCarry(bool cf) {
|
|||
}
|
||||
|
||||
static bool IsCall(void) {
|
||||
return m->xedd->op.map == XED_ILD_MAP0 &&
|
||||
(m->xedd->op.opcode == 0xE8 ||
|
||||
(m->xedd->op.opcode == 0xFF && m->xedd->op.reg == 2));
|
||||
return (m->xedd->op.dispatch == 0x0E8 ||
|
||||
(m->xedd->op.dispatch == 0x0FF && m->xedd->op.reg == 2));
|
||||
}
|
||||
|
||||
static bool IsLongBranch(void) {
|
||||
return m->xedd && m->xedd->op.map == XED_ILD_MAP0 &&
|
||||
(m->xedd->op.opcode == 0xEA || m->xedd->op.opcode == 0x9A ||
|
||||
(m->xedd->op.opcode == 0xFF && m->xedd->op.reg == 3) ||
|
||||
(m->xedd->op.opcode == 0xFF && m->xedd->op.reg == 5));
|
||||
return m->mode != XED_MODE_LONG &&
|
||||
(m->xedd->op.dispatch == 0x0EA || m->xedd->op.dispatch == 0x09A ||
|
||||
(m->xedd->op.opcode == 0x0FF && m->xedd->op.reg == 3) ||
|
||||
(m->xedd->op.opcode == 0x0FF && m->xedd->op.reg == 5));
|
||||
}
|
||||
|
||||
static bool IsDebugBreak(void) {
|
||||
|
@ -370,13 +360,16 @@ static void GetTtySize(void) {
|
|||
static void TuiRejuvinate(void) {
|
||||
GetTtySize();
|
||||
ttyhidecursor(STDOUT_FILENO);
|
||||
ttyraw(0);
|
||||
ttyraw(kTtySigs);
|
||||
xsigaction(SIGBUS, OnBusted, SA_NODEFER, 0, NULL);
|
||||
}
|
||||
|
||||
static void OnCtrlC(void) {
|
||||
LOGF("OnCtrlC");
|
||||
action |= INT;
|
||||
if (tuimode) {
|
||||
action |= INT;
|
||||
} else {
|
||||
HaltMachine(m, kMachineExit);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnQ(void) {
|
||||
|
@ -404,7 +397,7 @@ static void OnCont(void) {
|
|||
static void TuiCleanup(void) {
|
||||
sigaction(SIGWINCH, oldsig + 0, NULL);
|
||||
sigaction(SIGCONT, oldsig + 2, NULL);
|
||||
ttyraw((enum TtyRawFlags)(-1u));
|
||||
ttyraw(-1);
|
||||
ttyshowcursor(STDOUT_FILENO);
|
||||
CHECK_NE(-1, close(ttyfd));
|
||||
tuimode = false;
|
||||
|
@ -447,6 +440,7 @@ void TuiSetup(void) {
|
|||
CHECK_NE(-1, (ttyfd = open("/dev/tty", O_RDWR)));
|
||||
xsigaction(SIGWINCH, OnWinch, 0, 0, oldsig + 0);
|
||||
xsigaction(SIGCONT, OnCont, SA_RESTART, 0, oldsig + 2);
|
||||
xsigaction(SIGINT, OnCtrlC, 0 /* SA_NODEFER */, 0, oldsig + 3);
|
||||
memcpy(&m[1], &m[0], sizeof(m[0]));
|
||||
TuiRejuvinate();
|
||||
}
|
||||
|
@ -660,12 +654,19 @@ static void SetupDraw(void) {
|
|||
pan.display.right - pan.display.left);
|
||||
}
|
||||
|
||||
static long Disassemble(void) {
|
||||
long lines, current;
|
||||
lines = pan.disassembly.bottom - pan.disassembly.top * 2;
|
||||
CHECK_NE(-1, Dis(dis, m, GetIp(), m->ip, lines));
|
||||
current = DisFind(dis, GetIp());
|
||||
CHECK_NE(-1, current);
|
||||
return current;
|
||||
}
|
||||
|
||||
static long GetDisIndex(void) {
|
||||
long i;
|
||||
if ((i = DisFind(dis, GetIp())) == -1 || IsLongBranch()) {
|
||||
Dis(dis, m, GetIp(), m->ip,
|
||||
pan.disassembly.bottom - pan.disassembly.top * 2);
|
||||
CHECK_NE(-1, (i = DisFind(dis, GetIp())));
|
||||
if ((i = DisFind(dis, GetIp())) == -1) {
|
||||
i = Disassemble();
|
||||
}
|
||||
while (i + 1 < dis->ops.i && !dis->ops.p[i].size) ++i;
|
||||
return i;
|
||||
|
@ -864,7 +865,7 @@ static void DrawXmm(struct Panel *p, long i, long r) {
|
|||
if (0 && ssewidth == 1 && (040 <= ival && ival < 0200 - 1)) {
|
||||
sprintf(buf, "%`'c", ival);
|
||||
} else {
|
||||
int64toarray_radix10(SignExtend(ival, ssewidth * 8), buf);
|
||||
int64toarray_radix10(SEX(ival, ssewidth * 8), buf);
|
||||
}
|
||||
} else {
|
||||
uint64toarray_fixed16(ival, buf, ssewidth * 8);
|
||||
|
@ -977,7 +978,7 @@ static void DrawBreakpoints(struct Panel *p) {
|
|||
name = sym != -1 ? dis->syms.stab + dis->syms.p[sym].name : "UNKNOWN";
|
||||
s = buf;
|
||||
s += sprintf(s, "%p ", addr);
|
||||
CHECK_LT(Demangle(s, name), buf + ARRAYLEN(buf));
|
||||
CHECK_LT(Demangle(s, name, DIS_MAX_SYMBOL_LENGTH), buf + ARRAYLEN(buf));
|
||||
AppendPanel(p, line, buf);
|
||||
if (sym != -1 && addr != dis->syms.p[sym].addr) {
|
||||
snprintf(buf, sizeof(buf), "+%#lx", addr - dis->syms.p[sym].addr);
|
||||
|
@ -1015,7 +1016,7 @@ static void DrawTrace(struct Panel *p) {
|
|||
name = sym != -1 ? dis->syms.stab + dis->syms.p[sym].name : "UNKNOWN";
|
||||
s = line;
|
||||
s += sprintf(s, "%p %p ", Read64(m->ss) + bp, rp);
|
||||
s = Demangle(s, name);
|
||||
s = Demangle(s, name, DIS_MAX_SYMBOL_LENGTH);
|
||||
AppendPanel(p, i, line);
|
||||
if (sym != -1 && rp != dis->syms.p[sym].addr) {
|
||||
snprintf(line, sizeof(line), "+%#lx", rp - dis->syms.p[sym].addr);
|
||||
|
@ -1417,7 +1418,6 @@ static void OnVidyaServiceTeletypeOutput(void) {
|
|||
char buf[12];
|
||||
n = FormatCga(m->bx[0], buf);
|
||||
n += tpencode(buf + n, 6, VidyaServiceXlatTeletype(m->ax[0]), false);
|
||||
LOGF("teletype output %`'.*s", n, buf);
|
||||
MachinePtyWrite(pty, buf, n);
|
||||
}
|
||||
|
||||
|
@ -1520,6 +1520,7 @@ static void OnInt15h(void) {
|
|||
}
|
||||
|
||||
static bool OnHalt(int interrupt) {
|
||||
LOGF("OnHalt(%d)", interrupt);
|
||||
ReactiveDraw();
|
||||
switch (interrupt) {
|
||||
case 1:
|
||||
|
@ -1577,15 +1578,24 @@ static void OnPageDown(void) {
|
|||
|
||||
static void OnUpArrow(void) {
|
||||
if (action & CONTINUE) {
|
||||
speed = MIN(0x40000000, MAX(1, speed) << 1);
|
||||
if (speed >= -1) {
|
||||
speed = MIN(0x40000000, MAX(1, speed) << 1); // 1..40mips skip
|
||||
} else {
|
||||
speed >>= 1;
|
||||
}
|
||||
} else {
|
||||
--opstart;
|
||||
}
|
||||
LOGF("speed %d", speed);
|
||||
}
|
||||
|
||||
static void OnDownArrow(void) {
|
||||
if (action & CONTINUE) {
|
||||
speed >>= 1;
|
||||
if (speed > 0) {
|
||||
speed >>= 1;
|
||||
} else {
|
||||
speed = MAX(-(5 * 1000), MIN(-10, speed) << 1); // 10ms..5s delay
|
||||
}
|
||||
} else {
|
||||
++opstart;
|
||||
}
|
||||
|
@ -1897,6 +1907,9 @@ static void Tui(void) {
|
|||
action &= ~WINCHED;
|
||||
}
|
||||
interactive = ++tick > speed;
|
||||
if (interactive && speed < 0) {
|
||||
dsleep(.001L * -speed);
|
||||
}
|
||||
if (!(action & CONTINUE) || interactive) {
|
||||
tick = 0;
|
||||
GetDisIndex();
|
||||
|
@ -1907,7 +1920,8 @@ static void Tui(void) {
|
|||
LOGF("TUI FAILURE");
|
||||
PrintMessageBox(ttyfd, systemfailure, tyn, txn);
|
||||
ReadKeyboard();
|
||||
} else if (!IsExecuting() || (interactive && HasPendingKeyboard())) {
|
||||
} else if (!IsExecuting() || ((interactive || !(action & CONTINUE)) &&
|
||||
!(action & INT) && HasPendingKeyboard())) {
|
||||
ReadKeyboard();
|
||||
}
|
||||
if (action & INT) {
|
||||
|
@ -1961,6 +1975,9 @@ static void Tui(void) {
|
|||
}
|
||||
if (!IsDebugBreak()) {
|
||||
ExecuteInstruction(m);
|
||||
if (IsLongBranch()) {
|
||||
Disassemble();
|
||||
}
|
||||
} else {
|
||||
m->ip += m->xedd->length;
|
||||
action &= ~NEXT;
|
||||
|
@ -1997,7 +2014,7 @@ static void Tui(void) {
|
|||
static void GetOpts(int argc, char *argv[]) {
|
||||
int opt;
|
||||
stpcpy(stpcpy(stpcpy(logpath, kTmpPath), basename(argv[0])), ".log");
|
||||
while ((opt = getopt(argc, argv, "?hvtrRsb:HL:")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "hvtrRsb:HL:")) != -1) {
|
||||
switch (opt) {
|
||||
case 't':
|
||||
tuimode = true;
|
||||
|
@ -2007,6 +2024,7 @@ static void GetOpts(int argc, char *argv[]) {
|
|||
break;
|
||||
case 'r':
|
||||
m->mode = XED_MACHINE_MODE_REAL;
|
||||
g_disisprog_disable = true;
|
||||
break;
|
||||
case 's':
|
||||
printstats = true;
|
||||
|
@ -2024,7 +2042,6 @@ static void GetOpts(int argc, char *argv[]) {
|
|||
strcpy(logpath, optarg);
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
PrintUsage(EXIT_SUCCESS, stdout);
|
||||
default:
|
||||
PrintUsage(EX_USAGE, stderr);
|
||||
|
|
|
@ -64,13 +64,12 @@ ssize_t WriteBuffer(struct Buffer *b, int fd) {
|
|||
p = b->p;
|
||||
n = b->i;
|
||||
do {
|
||||
TryAgain:
|
||||
if ((rc = write(fd, p, n)) != -1) {
|
||||
wrote = rc;
|
||||
p += wrote;
|
||||
n -= wrote;
|
||||
} else if (errno == EINTR) {
|
||||
goto TryAgain;
|
||||
break;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -17,10 +17,14 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/hefty/spawn.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/build/lib/demangle.h"
|
||||
|
||||
|
@ -37,12 +41,14 @@ void CloseCxxFilt(void) {
|
|||
|
||||
void SpawnCxxFilt(void) {
|
||||
int pid;
|
||||
const char *cxxfilt;
|
||||
char path[PATH_MAX];
|
||||
if (commandv("c++filt", path)) {
|
||||
cxxfilt = firstnonnull(getenv("CXXFILT"), "c++filt");
|
||||
if (commandv(cxxfilt, path)) {
|
||||
g_cxxfilt.fds[0] = -1;
|
||||
g_cxxfilt.fds[1] = -1;
|
||||
g_cxxfilt.fds[2] = 2;
|
||||
if ((pid = spawnve(0, g_cxxfilt.fds, path, (char *const[]){"c++filt", NULL},
|
||||
if ((pid = spawnve(0, g_cxxfilt.fds, path, (char *const[]){cxxfilt, NULL},
|
||||
environ)) != -1) {
|
||||
atexit(CloseCxxFilt);
|
||||
}
|
||||
|
@ -52,30 +58,50 @@ void SpawnCxxFilt(void) {
|
|||
g_cxxfilt.pid = pid;
|
||||
}
|
||||
|
||||
char *DemangleCxxFilt(char *p, const char *symbol) {
|
||||
int n;
|
||||
char buf[512];
|
||||
bool iscomplicated;
|
||||
char *CopySymbol(char *p, size_t pn, const char *s, size_t sn) {
|
||||
size_t extra;
|
||||
bool showdots, iscomplicated;
|
||||
assert(pn >= 1 + 3 + 1 + 1);
|
||||
iscomplicated = memchr(s, ' ', sn) || memchr(s, '(', sn);
|
||||
extra = 1;
|
||||
if (iscomplicated) extra += 2;
|
||||
if (sn + extra > pn) {
|
||||
sn = pn - extra - 3;
|
||||
showdots = true;
|
||||
} else {
|
||||
showdots = false;
|
||||
}
|
||||
if (iscomplicated) *p++ = '"';
|
||||
p = mempcpy(p, s, sn);
|
||||
if (showdots) p = stpcpy(p, "...");
|
||||
if (iscomplicated) *p++ = '"';
|
||||
*p = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
char *DemangleCxxFilt(char *p, size_t pn, const char *s, size_t sn) {
|
||||
ssize_t rc;
|
||||
size_t got;
|
||||
struct iovec iov[2];
|
||||
static char buf[PAGESIZE];
|
||||
if (!g_cxxfilt.pid) SpawnCxxFilt();
|
||||
if (g_cxxfilt.pid == -1) return NULL;
|
||||
if ((n = strlen(symbol)) >= ARRAYLEN(buf)) return NULL;
|
||||
memcpy(buf, symbol, n);
|
||||
buf[n] = '\n';
|
||||
write(g_cxxfilt.fds[0], buf, n + 1);
|
||||
n = read(g_cxxfilt.fds[1], buf, ARRAYLEN(buf));
|
||||
if (n > 1 && buf[n - 1] == '\n') {
|
||||
if (buf[n - 2] == '\r') --n;
|
||||
--n;
|
||||
iscomplicated = memchr(buf, ' ', n) || memchr(buf, '(', n);
|
||||
if (iscomplicated) *p++ = '"';
|
||||
p = mempcpy(p, buf, n);
|
||||
if (iscomplicated) *p++ = '"';
|
||||
*p = '\0';
|
||||
return p;
|
||||
} else {
|
||||
CloseCxxFilt();
|
||||
return NULL;
|
||||
buf[0] = '\n';
|
||||
iov[0].iov_base = s;
|
||||
iov[0].iov_len = sn;
|
||||
iov[1].iov_base = buf;
|
||||
iov[1].iov_len = 1;
|
||||
writev(g_cxxfilt.fds[0], iov, ARRAYLEN(iov));
|
||||
if ((rc = read(g_cxxfilt.fds[1], buf, sizeof(buf))) != -1) {
|
||||
got = rc;
|
||||
if (got >= 2 && buf[got - 1] == '\n') {
|
||||
if (buf[got - 2] == '\r') --got;
|
||||
--got;
|
||||
return CopySymbol(p, pn, buf, got);
|
||||
}
|
||||
}
|
||||
CloseCxxFilt();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -85,10 +111,12 @@ char *DemangleCxxFilt(char *p, const char *symbol) {
|
|||
* x86_64 disassembler. That's just for the GNU encoding scheme. So
|
||||
* what we'll do, is just offload this work to the c++filt program.
|
||||
*/
|
||||
char *Demangle(char *p, const char *symbol) {
|
||||
char *Demangle(char *p, const char *symbol, size_t n) {
|
||||
char *r;
|
||||
size_t sn;
|
||||
sn = strlen(symbol);
|
||||
if (startswith(symbol, "_Z")) {
|
||||
if ((r = DemangleCxxFilt(p, symbol))) return r;
|
||||
if ((r = DemangleCxxFilt(p, n, symbol, sn))) return r;
|
||||
}
|
||||
return stpcpy(p, symbol);
|
||||
return CopySymbol(p, n, symbol, sn);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
char *Demangle(char *, const char *);
|
||||
char *Demangle(char *, const char *, size_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -150,7 +150,7 @@ static char *DisLineData(struct Dis *d, char *p, const uint8_t *b, size_t n) {
|
|||
static char *DisLabel(struct Dis *d, char *p, const char *name) {
|
||||
p = DisColumn(DisAddr(d, p), p, ADDRLEN);
|
||||
p = HighStart(p, g_high.label);
|
||||
p = Demangle(p, name);
|
||||
p = Demangle(p, name, DIS_MAX_SYMBOL_LENGTH);
|
||||
p = HighEnd(p);
|
||||
*p++ = ':';
|
||||
*p = '\0';
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define DIS_MAX_SYMBOL_LENGTH 32
|
||||
|
||||
struct Dis {
|
||||
struct DisOps {
|
||||
size_t i, n;
|
||||
|
@ -50,6 +52,8 @@ struct Dis {
|
|||
char buf[512];
|
||||
};
|
||||
|
||||
extern bool g_disisprog_disable;
|
||||
|
||||
long Dis(struct Dis *, struct Machine *, uint64_t, uint64_t, int);
|
||||
long DisFind(struct Dis *, int64_t);
|
||||
void DisFree(struct Dis *);
|
||||
|
|
|
@ -143,21 +143,30 @@ static char *DisInt(char *p, int64_t x) {
|
|||
return p;
|
||||
}
|
||||
|
||||
static char *DisSym(struct Dis *d, char *p, int64_t addr, int64_t ip) {
|
||||
long sym;
|
||||
static char *DisSymImpl(struct Dis *d, char *p, int64_t x, long sym) {
|
||||
int64_t addend;
|
||||
const char *name;
|
||||
if ((sym = DisFindSym(d, ip)) != -1 && d->syms.p[sym].name) {
|
||||
addend = ip - d->syms.p[sym].addr;
|
||||
name = d->syms.stab + d->syms.p[sym].name;
|
||||
p = Demangle(p, name);
|
||||
if (addend) {
|
||||
*p++ = '+';
|
||||
p = DisInt(p, addend);
|
||||
}
|
||||
return p;
|
||||
addend = x - d->syms.p[sym].addr;
|
||||
name = d->syms.stab + d->syms.p[sym].name;
|
||||
p = Demangle(p, name, DIS_MAX_SYMBOL_LENGTH);
|
||||
if (addend) {
|
||||
*p++ = '+';
|
||||
p = DisInt(p, addend);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisSym(struct Dis *d, char *p, int64_t x1, int64_t x2,
|
||||
bool isrelative) {
|
||||
long sym;
|
||||
if ((sym = DisFindSym(d, x2)) != -1 && d->syms.p[sym].name &&
|
||||
(d->syms.p[sym].isabs ^ isrelative)) {
|
||||
return DisSymImpl(d, p, x2, sym);
|
||||
} else if ((sym = DisFindSym(d, x1)) != -1 && d->syms.p[sym].name &&
|
||||
(d->syms.p[sym].isabs ^ isrelative)) {
|
||||
return DisSymImpl(d, p, x1, sym);
|
||||
} else {
|
||||
return DisInt(p, addr);
|
||||
return DisInt(p, x1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,7 +174,7 @@ static char *DisSymLiteral(struct Dis *d, uint32_t rde, char *p, uint64_t addr,
|
|||
uint64_t ip) {
|
||||
*p++ = '$';
|
||||
p = HighStart(p, g_high.literal);
|
||||
p = DisSym(d, p, addr, ip);
|
||||
p = DisSym(d, p, addr, addr, false);
|
||||
p = HighEnd(p);
|
||||
return p;
|
||||
}
|
||||
|
@ -196,27 +205,36 @@ static bool IsRealModrmAbsolute(uint32_t rde) {
|
|||
return Eamode(rde) == XED_MODE_REAL && ModrmRm(rde) == 6 && !ModrmMod(rde);
|
||||
}
|
||||
|
||||
static char *DisM(struct Dis *d, uint32_t rde, char *p) {
|
||||
static char *DisDisp(struct Dis *d, uint32_t rde, char *p) {
|
||||
bool rela;
|
||||
int64_t disp;
|
||||
const char *base, *index, *scale;
|
||||
p = DisSego(d, rde, p);
|
||||
base = index = scale = NULL;
|
||||
if (ModrmMod(rde) == 0b01 || ModrmMod(rde) == 0b10 || IsRipRelative(rde) ||
|
||||
IsRealModrmAbsolute(rde) ||
|
||||
(ModrmMod(rde) == 0b00 && ModrmRm(rde) == 0b100 &&
|
||||
SibBase(d->xedd) == 0b101)) {
|
||||
(Eamode(rde) != XED_MODE_REAL && ModrmMod(rde) == 0b00 &&
|
||||
ModrmRm(rde) == 0b100 && SibBase(d->xedd) == 0b101)) {
|
||||
disp = d->xedd->op.disp;
|
||||
if (IsRipRelative(rde)) {
|
||||
if (Mode(rde) == XED_MODE_LONG) {
|
||||
disp = RipRelative(d, disp);
|
||||
rela = true;
|
||||
} else {
|
||||
disp = Unrelative(rde, disp);
|
||||
rela = false;
|
||||
}
|
||||
} else if (IsRealModrmAbsolute(rde)) {
|
||||
disp = Unrelative(rde, disp);
|
||||
rela = false;
|
||||
} else {
|
||||
rela = true;
|
||||
}
|
||||
p = DisSym(d, p, disp, disp);
|
||||
p = DisSym(d, p, disp, disp, rela);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisBis(struct Dis *d, uint32_t rde, char *p) {
|
||||
const char *base, *index, *scale;
|
||||
base = index = scale = NULL;
|
||||
if (Eamode(rde) != XED_MODE_REAL) {
|
||||
if (!SibExists(rde)) {
|
||||
DCHECK(!d->xedd->op.has_sib);
|
||||
|
@ -290,6 +308,13 @@ static char *DisM(struct Dis *d, uint32_t rde, char *p) {
|
|||
return p;
|
||||
}
|
||||
|
||||
static char *DisM(struct Dis *d, uint32_t rde, char *p) {
|
||||
p = DisSego(d, rde, p);
|
||||
p = DisDisp(d, rde, p);
|
||||
p = DisBis(d, rde, p);
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisRegMem(struct Dis *d, uint32_t rde, char *p,
|
||||
char *f(struct Dis *, uint32_t, char *)) {
|
||||
if (IsModrmRegister(rde)) {
|
||||
|
@ -452,11 +477,11 @@ static char *DisJb(struct Dis *d, uint32_t rde, char *p) {
|
|||
|
||||
static char *DisJvds(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisSym(d, p, RipRelative(d, d->xedd->op.disp),
|
||||
RipRelative(d, d->xedd->op.disp) - Read64(d->m->cs));
|
||||
RipRelative(d, d->xedd->op.disp) - Read64(d->m->cs), true);
|
||||
}
|
||||
|
||||
static char *DisAbs(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisSym(d, p, d->xedd->op.disp, d->xedd->op.disp);
|
||||
return DisSym(d, p, d->xedd->op.disp, d->xedd->op.disp, false);
|
||||
}
|
||||
|
||||
static char *DisSw(struct Dis *d, uint32_t rde, char *p) {
|
||||
|
@ -477,12 +502,12 @@ static char *DisY(struct Dis *d, uint32_t rde, char *p) {
|
|||
}
|
||||
|
||||
static char *DisX(struct Dis *d, uint32_t rde, char *p) {
|
||||
DisSego(d, rde, p);
|
||||
p = DisSego(d, rde, p);
|
||||
return DisSpecialAddr(d, rde, p, 6); // ds:si
|
||||
}
|
||||
|
||||
static char *DisBBb(struct Dis *d, uint32_t rde, char *p) {
|
||||
DisSego(d, rde, p);
|
||||
p = DisSego(d, rde, p);
|
||||
return DisSpecialAddr(d, rde, p, 3); // ds:bx
|
||||
}
|
||||
|
||||
|
|
|
@ -22,9 +22,13 @@
|
|||
#include "libc/elf/elf.h"
|
||||
#include "libc/elf/struct/sym.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/build/lib/dis.h"
|
||||
|
||||
bool g_disisprog_disable;
|
||||
|
||||
static int DisSymCompare(const struct DisSym *a, const struct DisSym *b) {
|
||||
if (a->addr != b->addr) {
|
||||
if (a->addr < b->addr) return -1;
|
||||
|
@ -72,6 +76,8 @@ static void DisLoadElfSyms(struct Dis *d, struct Elf *elf) {
|
|||
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;
|
||||
if (ELF64_ST_TYPE(st[i].st_info) == STT_FILE) continue;
|
||||
if (startswith(d->syms.stab + st[i].st_name, "v_")) 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;
|
||||
|
@ -85,6 +91,7 @@ static void DisLoadElfSyms(struct Dis *d, struct Elf *elf) {
|
|||
t.addr = st[i].st_value;
|
||||
t.rank = -islocal + -isweak + -isabs + isprotected + isobject + isfunc;
|
||||
t.iscode = DisIsText(d, st[i].st_value) ? !isobject : isfunc;
|
||||
t.isabs = isabs;
|
||||
APPEND(&d->syms.p, &d->syms.i, &d->syms.n, &t);
|
||||
}
|
||||
}
|
||||
|
@ -93,6 +100,7 @@ static void DisLoadElfSyms(struct Dis *d, struct Elf *elf) {
|
|||
|
||||
bool DisIsProg(struct Dis *d, int64_t addr) {
|
||||
long i;
|
||||
if (g_disisprog_disable) return true;
|
||||
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) {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/log/check.h"
|
||||
#include "libc/nexgen32e/tinystrcmp.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/zlib/zlib.h"
|
||||
#include "tool/build/lib/dis.h"
|
||||
#include "tool/build/lib/high.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
|
@ -163,7 +164,7 @@ static char *DisName(struct Dis *d, char *bp, const char *name,
|
|||
} else if (wantsuffix || (ambiguous && !startswith(name, "f") &&
|
||||
!startswith(name, "set"))) {
|
||||
if (Osz(rde)) {
|
||||
if (Mode(rde) != XED_MODE_REAL) {
|
||||
if (ambiguous || Mode(rde) != XED_MODE_REAL) {
|
||||
*p++ = 'w';
|
||||
}
|
||||
} else if (Rexw(rde)) {
|
||||
|
@ -187,8 +188,8 @@ static char *DisName(struct Dis *d, char *bp, const char *name,
|
|||
*/
|
||||
char *DisInst(struct Dis *d, char *p, const char *spec) {
|
||||
long i, n;
|
||||
char sbuf[300];
|
||||
char args[4][300];
|
||||
char sbuf[64];
|
||||
char args[4][256];
|
||||
char *s, *name, *state;
|
||||
bool hasarg, hasmodrm, hasregister, hasmemory;
|
||||
CHECK_EQ(0, (int)d->xedd->op.error);
|
||||
|
|
|
@ -48,7 +48,7 @@ COSMOPOLITAN_C_START_
|
|||
#define SibHasIndex(x) (SibIndex(x) != 4 || Rexx(x))
|
||||
#define SibHasBase(x, r) (SibBase(x) != 5 || ModrmMod(r))
|
||||
#define SibIsAbsolute(x, r) (!SibHasBase(x, r) && !SibHasIndex(x))
|
||||
#define IsRipRelative(x) (ModrmRm(x) == 5 && !ModrmMod(x))
|
||||
#define IsRipRelative(x) (Eamode(x) && ModrmRm(x) == 5 && !ModrmMod(x))
|
||||
|
||||
struct AddrSeg {
|
||||
int64_t addr;
|
||||
|
|
|
@ -474,11 +474,8 @@ ssize_t MachinePtyWrite(struct MachinePty *pty, const void *data, size_t n) {
|
|||
break;
|
||||
case kMachinePtyUtf8:
|
||||
if (ThomPikeCont(p[i])) {
|
||||
pty->u8 <<= 6;
|
||||
pty->u8 |= p[i] & 0b00111111;
|
||||
if (--pty->n8) {
|
||||
break;
|
||||
}
|
||||
pty->u8 = ThomPikeMerge(pty->u8, p[i]);
|
||||
if (--pty->n8) break;
|
||||
}
|
||||
SetMachinePtyCell(pty, pty->u8);
|
||||
pty->state = kMachinePtyAscii;
|
||||
|
|
|
@ -130,7 +130,7 @@ void GetDosLocalTime(int64_t utcunixts, uint16_t *out_time,
|
|||
struct tm tm;
|
||||
CHECK_NOTNULL(localtime_r(&utcunixts, &tm));
|
||||
*out_time = DOS_TIME(tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
*out_date = DOS_DATE(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
|
||||
*out_date = DOS_DATE(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday + 1);
|
||||
}
|
||||
|
||||
static unsigned char *EmitZipLfileHdr(unsigned char *op, const void *name,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue