asm { _SETJMP:: MOV [RDI], RBX // Store caller saved registers MOV [RDI+8], RBP // ^ MOV [RDI+16], R12 // ^ MOV [RDI+24], R13 // ^ MOV [RDI+32], R14 // ^ MOV [RDI+40], R15 // ^ LEA RDX, [RSP+8] // go one value up (as if setjmp wasn't called) MOV [RDI+48], RDX // Store the new rsp pointer in env[7] MOV RDX, [RSP] // go one value up (as if setjmp wasn't called) MOV [RDI+56], RDX // Store the address we will resume at in env[8] XOR EAX, EAX // Always return 0 RET _LONGJMP:: XOR EAX, EAX CMP ESI, 1 ADC EAX, ESI MOV RBX, [RDI] MOV RBP, [RDI + 8] MOV R12, [RDI + 16] MOV R13, [RDI + 24] MOV R14, [RDI + 32] MOV R15, [RDI + 40] MOV RSP, [RDI + 48] JMP U64 [RDI + 56] } _extern _SETJMP U64 _setjmp(U64 jmp_buf); _extern _LONGJMP U64 longjmp(U64 jmp_buf, U64 ret); U0 free() { PUSH_SYSV_REGS GET_SYSV_ARGS Free(p0); POP_SYSV_REGS } U0 putchar() { PUSH_SYSV_REGS GET_SYSV_ARGS PutChars(p0); POP_SYSV_REGS } U64 @localtime(U64 p0) { // FIXME: implement this? no_warn p0; return 0; } U0 localtime() { PUSH_SYSV_REGS GET_SYSV_ARGS @localtime(p0); POP_SYSV_REGS } I64 @strncmp(U8* s1, U8* s2, I32 n) { U64 u1, u2; while (n-- > 0) { u1 = *s1++; u2 = *s2++; u1 = u1 & 0xff; u2 = u2 & 0xff; if (u1 != u2) return u1 - u2; if (u1 == '\0') return 0; } return 0; } U0 strncmp() { PUSH_SYSV_REGS GET_SYSV_ARGS @strncmp(p0, p1, p2); POP_SYSV_REGS } U0 strcpy() { PUSH_SYSV_REGS GET_SYSV_ARGS StrCpy(p0, p1); POP_SYSV_REGS } U0 fprintf() { PUSH_SYSV_REGS GET_SYSV_ARGS Print(p1, p2, p3, p4, p5); POP_SYSV_REGS } U0 printf() { PUSH_SYSV_REGS GET_SYSV_ARGS Print(p0, p1, p2, p3, p4, p5); POP_SYSV_REGS } U0 puts() { PUSH_SYSV_REGS GET_SYSV_ARGS PutS(p0); "\n"; POP_SYSV_REGS } U0 fputs() { PUSH_SYSV_REGS GET_SYSV_ARGS PutS(p0); POP_SYSV_REGS } U0 fputc() { PUSH_SYSV_REGS GET_SYSV_ARGS PutChars(p0); POP_SYSV_REGS } U64 @fwrite(U8* buffer, I64 size, I64 count, U64 stream) { if (!buffer || !size || !count || !stream) return NULL; I64 bytes = size * count; switch (stream) { case 1...2: U8* s = CAlloc(bytes + 1); MemCpy(s, buffer, bytes); "%s", s; Free(s); break; default: break; } return bytes; } U0 fwrite() { PUSH_SYSV_REGS GET_SYSV_ARGS @fwrite(p0, p1, p2, p3); POP_SYSV_REGS } U0 strerror() { PUSH_SYSV_REGS GET_SYSV_ARGS "strerror: %d\n", p0; PressAKey; POP_SYSV_REGS } U0 strlen() { PUSH_SYSV_REGS GET_SYSV_ARGS StrLen(p0); POP_SYSV_REGS } U8 *@strchr(U8 *str, I64 chr) { while (*str) { if (*str == chr) { return str; } str++; } return NULL; } U0 strchr() { PUSH_SYSV_REGS GET_SYSV_ARGS @strchr(p0, p1); POP_SYSV_REGS } U8* @strrchr(U8 *str, I64 chr) { U8* str2 = str + (StrLen(str) - 1); while (str2 > str - 1) { if (*str2 == chr) { return str2; } str2--; } return NULL; } U0 strrchr() { PUSH_SYSV_REGS GET_SYSV_ARGS @strrchr(p0, p1); POP_SYSV_REGS } U0 strcmp() { PUSH_SYSV_REGS GET_SYSV_ARGS //"strcmp: '%s', '%s'\n", p0, p1; StrCmp(p0, p1); POP_SYSV_REGS } U0 memcpy() { PUSH_SYSV_REGS GET_SYSV_ARGS MemCpy(p0, p1, p2); POP_SYSV_REGS } U0 memset() { PUSH_SYSV_REGS GET_SYSV_ARGS MemSet(p0, p1, p2); POP_SYSV_REGS } U0 malloc() { PUSH_SYSV_REGS GET_SYSV_ARGS MAlloc(p0); POP_SYSV_REGS } U8* @realloc(U8* ptr, I64 size) { U8* new; if (!ptr) { new = MAlloc(size); } else { new = MAlloc(size); MemCpy(new, ptr, size); Free(ptr); } return new; } U0 realloc() { PUSH_SYSV_REGS GET_SYSV_ARGS @realloc(p0, p1); POP_SYSV_REGS } #define MY_TIME_OFFSET 9488 public I64 CDate2Unix(CDate dt) { // TempleOS datetime to Unix timestamp. return ToI64((dt - Str2Date("1/1/1970")) / CDATE_FREQ) - MY_TIME_OFFSET; } I64 @time(I64* ptr) { no_warn ptr; return CDate2Unix(Now); } U0 time() { PUSH_SYSV_REGS GET_SYSV_ARGS @time(p0); POP_SYSV_REGS } U64 @gettimeofday(U64* tv) { if (!tv) return 0; U64 seconds = CDate2Unix(Now); tv[0] = seconds; tv[1] = NULL; return 0; } U0 gettimeofday() { PUSH_SYSV_REGS GET_SYSV_ARGS @gettimeofday(p0); POP_SYSV_REGS } U0 @fgets(U8* p0, I64 p1) { GetS(p0, p1); while (*p0) { if (*p0 == 0x1f) *p0 = 0x20; ++p0; } Print(""); } U0 fgets() { PUSH_SYSV_REGS GET_SYSV_ARGS @fgets(p0, p1); POP_SYSV_REGS } U64 @ferror() { return 0; } U0 ferror() { PUSH_SYSV_REGS GET_SYSV_ARGS @ferror; POP_SYSV_REGS } U64 @strcat(U8* dst, U8* src) { StrCpy(dst + StrLen(dst), src); return 0; } U0 strcat() { PUSH_SYSV_REGS GET_SYSV_ARGS @strcat(p0, p1); POP_SYSV_REGS } U0 strstr() { PUSH_SYSV_REGS GET_SYSV_ARGS StrFind(p1, p0); POP_SYSV_REGS } U0 sprintf() { PUSH_SYSV_REGS GET_SYSV_ARGS StrPrint(p0, p1, p2, p3, p4, p5); POP_SYSV_REGS }