Add files to repository

This commit is contained in:
Alec Murphy 2025-06-09 20:06:04 -04:00
parent 9f200c9084
commit 23d704d496
542 changed files with 75775 additions and 0 deletions

51
System/FFI/Base.HC Normal file
View file

@ -0,0 +1,51 @@
#define PUSH_SYSV_REGS \
asm {PUSH RCX PUSH RDX PUSH RBX PUSH RBP PUSH RSI PUSH RDI PUSH R8 PUSH R9 PUSH \
R10 PUSH R11 PUSH R12 PUSH R13 PUSH R14 PUSH R15}
#define POP_SYSV_REGS \
p0 = p0; \
p1 = p1; \
p2 = p2; \
p3 = p3; \
p4 = p4; \
p5 = p5; \
asm {POP R15 POP R14 POP R13 POP R12 POP R11 POP R10 POP R9 POP R8 POP RDI POP \
RSI POP RBP POP RBX POP RDX POP RCX}
#define GET_SYSV_ARGS \
asm {PUSH R9 PUSH R8 PUSH RCX PUSH RDX PUSH RSI PUSH RDI} \
I64 reg RDI p0; \
I64 reg RSI p1; \
I64 reg RDX p2; \
I64 reg RCX p3; \
I64 reg R8 p4; \
I64 reg R9 p5; \
asm {POP RDI POP RSI POP RDX POP RCX POP R8 POP R9}
#define MOV_ANS_RAX asm { MOV[&ans], RAX }
#define MOV_PARAM0_RDI asm {MOV [&param0], RDI}
I64 param0;
I64 elf_argc;
U8** elf_argv;
asm {
_ELF_CALL::
PUSH RBP
MOV RBP,RSP
MOV RAX,U64 SF_ARG1[RBP]
MOV RDI,U64 SF_ARG2[RBP]
MOV RSI,U64 SF_ARG3[RBP]
TEST RAX,RAX
JZ @@05
CALL RAX
@@05: POP RBP
RET1 8
}
U0 _main()
{
MOV_PARAM0_RDI
CallInd(_ELF_CALL, param0, elf_argc, elf_argv);
UserTaskCont;
}
//U0 _exit() { UserTaskCont; }

300
System/FFI/ELF64.HC Normal file
View file

@ -0,0 +1,300 @@
#define EI_NIDENT 16
#define EM_X86_64 0x3E
#define ET_EXEC 2
#define ET_DYN 3
U0 @elf64_debug_print(U8 fmt, ...)
{
// FIXME: Remove unnecessary debug_print statements and PrintErr for errors.
no_warn fmt, argc, argv;
}
class Elf64_Ehdr {
U8 e_ident[EI_NIDENT]; /* Magic number and other info */
U16 e_type; /* Object file type */
U16 e_machine; /* Architecture */
U32 e_version; /* Object file version */
U64 e_entry; /* Entry point virtual address */
U64 e_phoff; /* Program header table file offset */
U64 e_shoff; /* Section header table file offset */
U32 e_flags; /* Processor-specific flags */
U16 e_ehsize; /* ELF header size in bytes */
U16 e_phentsize; /* Program header table entry size */
U16 e_phnum; /* Program header table entry count */
U16 e_shentsize; /* Section header table entry size */
U16 e_shnum; /* Section header table entry count */
U16 e_shstrndx; /* Section header string table index */
};
class Elf64_Shdr {
U32 sh_name; /* Section name (string tbl index) */
U32 sh_type; /* Section type */
U64 sh_flags; /* Section flags */
U64 sh_addr; /* Section virtual addr at execution */
U64 sh_offset; /* Section file offset */
U64 sh_size; /* Section size in bytes */
U32 sh_link; /* Link to another section */
U32 sh_info; /* Additional section information */
U64 sh_addralign; /* Section alignment */
U64 sh_entsize; /* Entry size if section holds table */
};
class Elf64_Sym {
U32 st_name; /* Symbol name (string tbl index) */
U8 st_info; /* Symbol type and binding */
U8 st_other; /* Symbol visibility */
U16 st_shndx; /* Section index */
U64 st_value; /* Symbol value */
U64 st_size; /* Symbol size */
};
class PLT_entry {
U8 pad[0x10];
};
class RELA_entry {
U64 r_offset;
U64 r_info;
I64 r_addend;
};
class Elf {
union {
U8* u8;
Elf64_Ehdr* ehdr;
} I64 size;
U8* dynstr;
Elf64_Sym* dynsym;
PLT_entry* plt;
RELA_entry* rela_dyn;
RELA_entry* rela_plt;
Elf64_Sym* strtab;
Elf64_Sym* symtab;
I64 rela_dyn_size;
I64 rela_plt_size;
I64 strtab_size;
I64 symtab_size;
};
U0 (*_start)();
U0 unimplemented_symbol()
{
I32 s = 0xDEADF00D;
PrintWarn("Unimplemented symbol: %s\n", s);
Dbg;
while (1)
Sleep(1);
}
Bool is_valid_elf(Elf* elf)
{
Bool res = TRUE;
if (MemCmp(elf->u8 + 1, "ELF", 3)) {
@elf64_debug_print("Invalid signature (not ELF).\n");
res = FALSE;
}
if (elf->ehdr->e_type != ET_EXEC && elf->ehdr->e_type != ET_DYN) {
@elf64_debug_print("Invalid object file type.\n");
res = FALSE;
}
if (elf->ehdr->e_machine != EM_X86_64) {
@elf64_debug_print("Invalid architecture.\n");
res = FALSE;
}
return res;
}
U0 process_elf_section_header_table(Elf* elf)
{
Elf64_Shdr* shdr = elf->u8 + elf->ehdr->e_shoff;
Elf64_Shdr* shdr_shstrtab = shdr + elf->ehdr->e_shstrndx;
U8* shstrtab = elf->u8 + shdr_shstrtab->sh_offset;
I64 i = 0;
while (i < elf->ehdr->e_shnum) {
if (!StrCmp(shstrtab + shdr->sh_name, ".symtab")) {
@elf64_debug_print("found symtab at 0x%08x, size = %d\n", shdr->sh_offset,
shdr->sh_size);
elf->symtab = elf->u8 + shdr->sh_offset;
elf->symtab_size = shdr->sh_size;
}
if (!StrCmp(shstrtab + shdr->sh_name, ".strtab")) {
@elf64_debug_print("found strtab at 0x%08x, size = %d\n", shdr->sh_offset,
shdr->sh_size);
elf->strtab = elf->u8 + shdr->sh_offset;
elf->strtab_size = shdr->sh_size;
}
if (shdr->sh_addr) {
MemCpy(shdr->sh_addr, elf->u8 + shdr->sh_offset, shdr->sh_size);
if (!StrCmp(shstrtab + shdr->sh_name, ".dynstr"))
elf->dynstr = shdr->sh_addr;
if (!StrCmp(shstrtab + shdr->sh_name, ".dynsym"))
elf->dynsym = shdr->sh_addr;
if (!StrCmp(shstrtab + shdr->sh_name, ".plt"))
elf->plt = shdr->sh_addr;
if (!StrCmp(shstrtab + shdr->sh_name, ".rela.dyn")) {
elf->rela_dyn = shdr->sh_addr;
elf->rela_dyn_size = shdr->sh_size / shdr->sh_entsize;
}
if (!StrCmp(shstrtab + shdr->sh_name, ".rela.plt")) {
elf->rela_plt = shdr->sh_addr;
elf->rela_plt_size = shdr->sh_size / shdr->sh_entsize;
}
if (!StrCmp(shstrtab + shdr->sh_name, ".bss") || !StrCmp(shstrtab + shdr->sh_name, ".tbss")) {
MemSet(shdr->sh_addr, NULL, shdr->sh_size);
@elf64_debug_print(
"Zeroed out section '%s' at physical address 0x%06x, size = %d bytes\n",
shstrtab + shdr->sh_name, shdr->sh_addr, shdr->sh_size);
} else
@elf64_debug_print(
"MemCpy section '%s' to physical address 0x%06x, size = %d bytes\n",
shstrtab + shdr->sh_name, shdr->sh_addr, shdr->sh_size);
if (!StrCmp(shstrtab + shdr->sh_name, ".bss")) {
MemSet(shdr->sh_addr, NULL, shdr->sh_size);
@elf64_debug_print("MemSet section '%s' at physical address 0x%06x to NULL, "
"size = %d bytes\n",
shstrtab + shdr->sh_name, shdr->sh_addr, shdr->sh_size);
}
}
shdr++;
i++;
}
}
U0 process_elf_rela_dyn_entries(Elf* elf)
{
I64 i;
U8* entry_name;
RELA_entry* rela_dyn = elf->rela_dyn;
for (i = 0; i < elf->rela_dyn_size; i++) {
entry_name = elf->dynstr + elf->dynsym[(rela_dyn->r_info >> 32)].st_name;
@elf64_debug_print("rela_dyn->r_offset = %08x\n", rela_dyn->r_offset);
@elf64_debug_print("entry name = '%s'\n", entry_name);
if (!StrCmp(entry_name, "__libc_start_main")) {
*(rela_dyn->r_offset)(U64*) = &_main;
@elf64_debug_print("Set value for .rela.dyn entry '%s' to: &_main\n",
entry_name);
}
if (!StrCmp(entry_name, "stdin")) {
*(rela_dyn->r_offset)(U64*) = 0;
@elf64_debug_print("Set value for .rela.dyn entry '%s' to: %d\n", entry_name, 0);
}
if (!StrCmp(entry_name, "stdout")) {
*(rela_dyn->r_offset)(U64*) = 1;
@elf64_debug_print("Set value for .rela.dyn entry '%s' to: %d\n", entry_name, 1);
}
if (!StrCmp(entry_name, "stderr")) {
*(rela_dyn->r_offset)(U64*) = 2;
@elf64_debug_print("Set value for .rela.dyn entry '%s' to: %d\n", entry_name, 2);
}
rela_dyn++;
}
}
CHashClass* get_symbol_hash_entry(U8* entry_name)
{
I64 i;
CHashSrcSym* sym;
CHashTable* tbl = Fs->hash_table;
while (tbl) {
for (i = 0; i < tbl->mask; i++) {
sym = tbl->body[i];
while (sym) {
if (sym->type == HTT_CLASS)
if (!StrCmp(sym->str, entry_name))
return sym;
sym = sym->next;
}
}
tbl = tbl->next;
}
return NULL;
}
U64 get_symbol_address(U8* entry_name)
{
CHash* h = HashFind(entry_name, Fs->hash_table, Fs->hash_table->mask);
if (!h)
return NULL;
switch (h->type) {
case HTT_GLBL_VAR:
return h(CHashGlblVar*)->data_addr;
break;
case HTT_FUN:
return h(CHashFun*)->exe_addr;
break;
default:
return NULL;
break;
}
return NULL;
}
U0 process_elf_rela_plt_entries(Elf* elf)
{
I64 i;
U32 handler;
U32* patch;
U8* entry_name;
Bool symbol_exists;
PLT_entry* plt = elf->plt;
RELA_entry* rela_plt = elf->rela_plt;
plt++;
for (i = 0; i < elf->rela_plt_size; i++) {
symbol_exists = FALSE;
entry_name = elf->dynstr + elf->dynsym[(rela_plt->r_info >> 32)].st_name;
handler = MAlloc(sizeof(unimplemented_symbol), adam_task->code_heap);
MemCpy(handler, &unimplemented_symbol, sizeof(unimplemented_symbol));
patch = handler + 0x0A;
*patch = entry_name;
@patch_jmp_rel32(plt, handler);
@patch_call_rel32(handler + 0x16, &PrintErr);
//@patch_call_rel32(handler + 0x21, &_exit);
if (!StrCmp(entry_name, "__libc_start_main")) {
symbol_exists = TRUE;
@patch_jmp_rel32(plt, &_main);
@elf64_debug_print("Set value for .rela.plt entry '%s' to &_main\n", entry_name);
}
if (get_symbol_address(entry_name)) {
symbol_exists = TRUE;
@patch_jmp_rel32(plt, get_symbol_address(entry_name));
@elf64_debug_print("Set value for .rela.plt entry '%s' to &%s\n", entry_name,
entry_name);
}
if (!symbol_exists)
@elf64_debug_print(
"Set value for .rela.plt entry '%s' to &unimplemented_symbol\n",
entry_name);
rela_plt++;
plt++;
}
}
U0 load_elf(...)
{
if (argc < 1) {
PrintErr("Not enough arguments.\n");
return;
}
if (!FileFind(argv[0])) {
PrintErr("File not found: %s\n", argv[0]);
return;
}
Elf elf;
elf.u8 = FileRead(argv[0], &elf.size);
@elf64_debug_print("Load file '%s', size = %d bytes\n", argv[0], elf.size);
if (!is_valid_elf(&elf)) {
PrintErr("File is not a valid ELF x86-64 executable.\n");
return;
}
process_elf_section_header_table(&elf);
process_elf_rela_dyn_entries(&elf);
process_elf_rela_plt_entries(&elf);
_start = elf.ehdr->e_entry;
elf_argc = argc;
elf_argv = argv;
}

373
System/FFI/LibC.HC Normal file
View file

@ -0,0 +1,373 @@
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
}

60
System/LibTemple/OS.HC Normal file
View file

@ -0,0 +1,60 @@
U0 os_call_ext_str()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
CallExtStr(p0);
POP_SYSV_REGS
}
U0 os_call_ext_str_1()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
CallExtStr(p0, p1);
POP_SYSV_REGS
}
U0 os_call_ext_str_2()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
CallExtStr(p0, p1, p2);
POP_SYSV_REGS
}
U0 os_call_ext_str_3()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
CallExtStr(p0, p1, p2, p3);
POP_SYSV_REGS
}
U0 os_call_ext_str_4()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
CallExtStr(p0, p1, p2, p3, p4);
POP_SYSV_REGS
}
U0 os_call_ext_str_5()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
CallExtStr(p0, p1, p2, p3, p4, p5);
POP_SYSV_REGS
}
U64 @os_jiffies()
{
return cnts.jiffies;
}
U0 os_jiffies()
{
PUSH_SYSV_REGS
GET_SYSV_ARGS
@os_jiffies();
POP_SYSV_REGS
}

44
System/MakeSystem.HC Normal file
View file

@ -0,0 +1,44 @@
/* clang-format off */
WinMax;
AutoComplete(0);
U0 @patch_call_rel32(U32 from, U32 to)
{
*(from(U8*)) = 0xE8;
*((from + 1)(I32*)) = to - from - 5;
}
U0 @patch_jmp_rel32(U32 from, U32 to)
{
*(from(U8*)) = 0xE9;
*((from + 1)(I32*)) = to - from - 5;
}
U0 @sse_enable()
{
/* clang-format off */
asm
{
MOV_EAX_CR0
AND AX, 0xFFFB // clear coprocessor emulation CR0.EM
OR AX, 0x2 // set coprocessor monitoring CR0.MP
MOV_CR0_EAX
MOV_EAX_CR4
OR AX, 3 << 9 // set CR4.OSFXSR and CR4.OSXMMEXCPT at the same time
MOV_CR4_EAX
}
/* clang-format on */
}
@sse_enable;
// FFI support files
#include "FFI/Base";
#include "FFI/LibC";
#include "FFI/ELF64";
// LibTemple support files
#include "LibTemple/OS";
/* clang-format on */