Introduce dummy ELF writer

This commit is contained in:
David Gonzalez Martin 2024-08-09 12:47:11 +02:00
parent 89c4a98b44
commit fa043dfbc0
5 changed files with 429 additions and 82 deletions

View File

@ -148,35 +148,39 @@ fn void compile_c(const CompileOptions *const options, char** envp)
run_command((CStringSlice) { .pointer = args->pointer, .length = args->length }, envp); run_command((CStringSlice) { .pointer = args->pointer, .length = args->length }, envp);
} }
typedef enum ExecutionEngine typedef enum CompilerBackend
{ {
EXECUTION_ENGINE_INTERPRETER, COMPILER_BACKEND_INTERPRETER,
EXECUTION_ENGINE_C, COMPILER_BACKEND_C,
EXECUTION_ENGINE_COUNT, COMPILER_BACKEND_MACHINE,
} ExecutionEngine; COMPILER_BACKEND_COUNT,
declare_slice(ExecutionEngine); } CompilerBackend;
declare_slice(CompilerBackend);
fn void compile_and_run(const CompileOptions* const options, char** envp, ExecutionEngine execution_engine, u8 debug, char* nest_source_path) fn void compile_and_run(const CompileOptions* const options, char** envp, CompilerBackend compiler_backend, u8 debug, char* nest_source_path)
{ {
compile_c(options, envp); compile_c(options, envp);
CStringSlice args = {}; CStringSlice args = {};
char* execution_engine_string; char* compiler_backend_string;
switch (execution_engine) switch (compiler_backend)
{ {
case EXECUTION_ENGINE_C: case COMPILER_BACKEND_C:
execution_engine_string = "c"; compiler_backend_string = "c";
break; break;
case EXECUTION_ENGINE_INTERPRETER: case COMPILER_BACKEND_INTERPRETER:
execution_engine_string = "i"; compiler_backend_string = "i";
break; break;
case EXECUTION_ENGINE_COUNT: case COMPILER_BACKEND_MACHINE:
compiler_backend_string = "m";
break;
case COMPILER_BACKEND_COUNT:
unreachable(); unreachable();
} }
#define common_compile_and_run_args \ #define common_compile_and_run_args \
options->out_path, \ options->out_path, \
nest_source_path, \ nest_source_path, \
execution_engine_string, \ compiler_backend_string, \
0, 0,
if (debug) if (debug)
@ -193,7 +197,7 @@ fn void compile_and_run(const CompileOptions* const options, char** envp, Execut
})); }));
#elif defined(__APPLE__) #elif defined(__APPLE__)
args = (CStringSlice) array_to_slice(((char*[]){ args = (CStringSlice) array_to_slice(((char*[]){
"lldb", "/usr/bin/lldb",
"--", "--",
common_compile_and_run_args common_compile_and_run_args
})); }));
@ -221,7 +225,7 @@ struct TestOptions
Slice(Linkage) linkages; Slice(Linkage) linkages;
Slice(OptimizationMode) optimization_modes; Slice(OptimizationMode) optimization_modes;
Slice(String) test_paths; Slice(String) test_paths;
Slice(ExecutionEngine) execution_engines; Slice(CompilerBackend) compiler_backends;
}; };
typedef struct TestOptions TestOptions; typedef struct TestOptions TestOptions;
@ -304,33 +308,36 @@ fn void run_tests(Arena* arena, TestOptions const * const test_options, char** e
auto test_dir = string_no_extension(test_path); auto test_dir = string_no_extension(test_path);
auto test_name = string_base(test_dir); auto test_name = string_base(test_dir);
for (u32 engine_i = 0; engine_i < test_options->execution_engines.length; engine_i += 1) for (u32 engine_i = 0; engine_i < test_options->compiler_backends.length; engine_i += 1)
{ {
ExecutionEngine execution_engine = test_options->execution_engines.pointer[engine_i]; CompilerBackend compiler_backend = test_options->compiler_backends.pointer[engine_i];
char* execution_engine_arg; char* compiler_backend_string;
switch (execution_engine) switch (compiler_backend)
{ {
case EXECUTION_ENGINE_C: case COMPILER_BACKEND_C:
execution_engine_arg = "c"; compiler_backend_string = "c";
break; break;
case EXECUTION_ENGINE_INTERPRETER: case COMPILER_BACKEND_INTERPRETER:
execution_engine_arg = "i"; compiler_backend_string = "i";
break; break;
case EXECUTION_ENGINE_COUNT: case COMPILER_BACKEND_MACHINE:
compiler_backend_string = "m";
break;
case COMPILER_BACKEND_COUNT:
unreachable(); unreachable();
} }
char* arguments[] = { char* arguments[] = {
compile_options.out_path, compile_options.out_path,
test_path_c, test_path_c,
execution_engine_arg, compiler_backend_string,
0, 0,
}; };
run_command((CStringSlice) array_to_slice(arguments), envp); run_command((CStringSlice) array_to_slice(arguments), envp);
if (execution_engine != EXECUTION_ENGINE_INTERPRETER) if (compiler_backend != COMPILER_BACKEND_INTERPRETER)
{ {
String out_program = arena_join_string(arena, ((Slice(String)) array_to_slice(((String[]){ String out_program = arena_join_string(arena, ((Slice(String)) array_to_slice(((String[]){
strlit(nest_dir "/"), strlit(nest_dir "/"),
@ -356,7 +363,7 @@ int main(int argc, char* argv[], char** envp)
return 1; return 1;
} }
ExecutionEngine preferred_execution_engine = EXECUTION_ENGINE_COUNT; CompilerBackend preferred_compiler_backend = COMPILER_BACKEND_COUNT;
Command command = COMMAND_COUNT; Command command = COMMAND_COUNT;
u8 test_every_config = 0; u8 test_every_config = 0;
String source_file_path = {}; String source_file_path = {};
@ -367,11 +374,15 @@ int main(int argc, char* argv[], char** envp)
auto argument = cstr(c_argument); auto argument = cstr(c_argument);
if (s_equal(argument, strlit("i"))) if (s_equal(argument, strlit("i")))
{ {
preferred_execution_engine = EXECUTION_ENGINE_INTERPRETER; preferred_compiler_backend = COMPILER_BACKEND_INTERPRETER;
} }
else if (s_equal(argument, strlit("c"))) else if (s_equal(argument, strlit("c")))
{ {
preferred_execution_engine = EXECUTION_ENGINE_C; preferred_compiler_backend = COMPILER_BACKEND_C;
}
else if (s_equal(argument, strlit("m")))
{
preferred_compiler_backend = COMPILER_BACKEND_MACHINE;
} }
else if (s_equal(argument, strlit("test"))) else if (s_equal(argument, strlit("test")))
{ {
@ -391,12 +402,19 @@ int main(int argc, char* argv[], char** envp)
{ {
auto* c_argument = argv[2]; auto* c_argument = argv[2];
auto argument = cstr(c_argument); auto argument = cstr(c_argument);
auto expected_start = strlit("tests/"); String expected_starts[] = { strlit("tests/"), strlit("src/") };
if (expected_start.length < argument.length)
for (u32 i = 0; i < array_length(expected_starts); i += 1)
{ {
if (strncmp(c_argument, "tests/", sizeof("tests/") - 1) == 0) auto expected_start = expected_starts[i];
if (expected_start.length < argument.length)
{ {
source_file_path = argument; // TODO: make our own function
if (strncmp(c_argument, string_to_c(expected_start), expected_start.length) == 0)
{
source_file_path = argument;
break;
}
} }
} }
} }
@ -409,7 +427,10 @@ int main(int argc, char* argv[], char** envp)
if ((command == COMMAND_DEBUG) | ((command == COMMAND_RUN_TESTS) & (test_every_config == 0))) if ((command == COMMAND_DEBUG) | ((command == COMMAND_RUN_TESTS) & (test_every_config == 0)))
{ {
preferred_execution_engine = EXECUTION_ENGINE_INTERPRETER; if (preferred_compiler_backend == COMPILER_BACKEND_COUNT)
{
preferred_compiler_backend = COMPILER_BACKEND_INTERPRETER;
}
} }
switch (command) switch (command)
@ -427,8 +448,12 @@ int main(int argc, char* argv[], char** envp)
.debug_info = 1, .debug_info = 1,
.error_on_warning = 0, .error_on_warning = 0,
.optimization_mode = O0, .optimization_mode = O0,
#if defined(__linux__)
.linkage = LINKAGE_STATIC, .linkage = LINKAGE_STATIC,
}, envp, EXECUTION_ENGINE_INTERPRETER, 1, string_to_c(source_file_path)); #else
.linkage = LINKAGE_DYNAMIC,
#endif
}, envp, preferred_compiler_backend, 1, string_to_c(source_file_path));
break; break;
case COMMAND_RUN_TESTS: case COMMAND_RUN_TESTS:
{ {
@ -453,12 +478,17 @@ int main(int argc, char* argv[], char** envp)
strlit("tests/simple_arg.nat"), strlit("tests/simple_arg.nat"),
strlit("tests/comparison.nat"), strlit("tests/comparison.nat"),
}; };
ExecutionEngine all_execution_engines[] = { EXECUTION_ENGINE_INTERPRETER, EXECUTION_ENGINE_C }; CompilerBackend all_compiler_backends[] = {
static_assert(array_length(all_execution_engines) == EXECUTION_ENGINE_COUNT); COMPILER_BACKEND_INTERPRETER,
COMPILER_BACKEND_C,
#ifdef __linux__
COMPILER_BACKEND_MACHINE,
#endif
};
Slice(Linkage) linkage_selection; Slice(Linkage) linkage_selection;
Slice(OptimizationMode) optimization_selection; Slice(OptimizationMode) optimization_selection;
Slice(ExecutionEngine) execution_engine_selection; Slice(CompilerBackend) compiler_backend_selection;
if (test_every_config) if (test_every_config)
{ {
@ -468,13 +498,13 @@ int main(int argc, char* argv[], char** envp)
linkage_selection = (Slice(Linkage)) { .pointer = &all_linkages[0], .length = 1 }; linkage_selection = (Slice(Linkage)) { .pointer = &all_linkages[0], .length = 1 };
#endif #endif
optimization_selection = (Slice(OptimizationMode)) array_to_slice(all_optimization_modes); optimization_selection = (Slice(OptimizationMode)) array_to_slice(all_optimization_modes);
execution_engine_selection = (Slice(ExecutionEngine)) array_to_slice(all_execution_engines); compiler_backend_selection = (Slice(CompilerBackend)) array_to_slice(all_compiler_backends);
} }
else else
{ {
linkage_selection = (Slice(Linkage)) { .pointer = &all_linkages[0], .length = 1 }; linkage_selection = (Slice(Linkage)) { .pointer = &all_linkages[0], .length = 1 };
optimization_selection = (Slice(OptimizationMode)) { .pointer = &all_optimization_modes[0], .length = 1 }; optimization_selection = (Slice(OptimizationMode)) { .pointer = &all_optimization_modes[0], .length = 1 };
execution_engine_selection = (Slice(ExecutionEngine)) { .pointer = &preferred_execution_engine, .length = 1 }; compiler_backend_selection = (Slice(CompilerBackend)) { .pointer = &preferred_compiler_backend, .length = 1 };
} }
Slice(String) test_selection; Slice(String) test_selection;
@ -491,7 +521,7 @@ int main(int argc, char* argv[], char** envp)
.linkages = linkage_selection, .linkages = linkage_selection,
.optimization_modes = optimization_selection, .optimization_modes = optimization_selection,
.test_paths = test_selection, .test_paths = test_selection,
.execution_engines = execution_engine_selection, .compiler_backends = compiler_backend_selection,
}, envp); }, envp);
} break; } break;
case COMMAND_COUNT: case COMMAND_COUNT:

View File

@ -177,7 +177,8 @@ fn u64 strlen (const char* c_string)
#endif #endif
#define slice_from_pointer_range(T, start, end) (Slice(T)) { .pointer = start, .length = (u64)(end - start), } #define slice_from_pointer_range(T, start, end) (Slice(T)) { .pointer = start, .length = (u64)(end - start), }
#define strlit(s) (String){ .pointer = (u8*)(s), .length = sizeof(s) - 1, } #define strlit_len(s) (sizeof(s) - 1)
#define strlit(s) (String){ .pointer = (u8*)(s), .length = strlit_len(s), }
#define ch_to_str(ch) (String){ .pointer = &ch, .length = 1 } #define ch_to_str(ch) (String){ .pointer = &ch, .length = 1 }
#define array_to_slice(arr) { .pointer = (arr), .length = array_length(arr) } #define array_to_slice(arr) { .pointer = (arr), .length = array_length(arr) }
#define pointer_to_bytes(p) (String) { .pointer = (u8*)(p), .length = sizeof(*p) } #define pointer_to_bytes(p) (String) { .pointer = (u8*)(p), .length = sizeof(*p) }
@ -1466,6 +1467,13 @@ fn u8* vb_generic_add(VirtualBuffer(u8)* vb, u32 item_size, u32 item_count)
return vb_generic_add_assume_capacity(vb, item_size, item_count); return vb_generic_add_assume_capacity(vb, item_size, item_count);
} }
may_be_unused fn u8* vb_append_bytes(VirtualBuffer(u8*) vb, Slice(u8) bytes)
{
vb_generic_ensure_capacity(vb, sizeof(u8), bytes.length);
auto* pointer = vb_generic_add_assume_capacity(vb, sizeof(u8), bytes.length);
memcpy(pointer, bytes.pointer, bytes.length);
return pointer;
}
// fn u8* vb_generic_append(VirtualBuffer(u8)* vb, void* item_pointer, u32 item_size, u32 item_count) // fn u8* vb_generic_append(VirtualBuffer(u8)* vb, void* item_pointer, u32 item_size, u32 item_count)
// { // {
@ -1475,3 +1483,4 @@ fn u8* vb_generic_add(VirtualBuffer(u8)* vb, u32 item_size, u32 item_count)
#define vb_add(a, count) (typeof((a)->pointer)) vb_generic_add((VirtualBuffer(u8)*)(a), sizeof(*((a)->pointer)), count) #define vb_add(a, count) (typeof((a)->pointer)) vb_generic_add((VirtualBuffer(u8)*)(a), sizeof(*((a)->pointer)), count)
#define vb_append_one(a, item) (typeof((a)->pointer)) vb_generic_append((VirtualBuffer(u8)*)(a), &(item), sizeof(*((a)->pointer)), 1) #define vb_append_one(a, item) (typeof((a)->pointer)) vb_generic_append((VirtualBuffer(u8)*)(a), &(item), sizeof(*((a)->pointer)), 1)
#define vb_to_bytes(vb) (Slice(u8)) { .pointer = (u8*)((vb).pointer), .length = sizeof(*((vb).pointer)) * (vb).length, }

View File

@ -1,4 +1,6 @@
#include "lib.h" #include "lib.h"
#define clang_path "/usr/bin/clang"
struct StringMapValue struct StringMapValue
{ {
String string; String string;
@ -208,9 +210,49 @@ fn StringMapPut string_map_put(StringMap* map, Arena* arena, String key, u32 val
} }
} }
// fn void string_map_get_or_put(StringMap* map, Arena* arena, String key, u32 value)
// {
// assert(value);
// auto hash = hash_bytes(key);
// auto index = hash & (map->capacity - 1);
// auto slot = string_map_find_slot(map, index, key);
// if (slot != -1)
// {
// auto* values = string_map_values(map);
// auto* key_pointer = &map->pointer[slot];
// todo();
// // auto old_key_pointer = *key_pointer;
// // *key_pointer = hash;
// // values[slot].string = key;
// // values[slot].value = value;
// // return (StringMapPut) {
// // .value = value,
// // .existing = old_key_pointer != 0,
// // };
// }
// else
// {
// if (map->length < map->capacity)
// {
// todo();
// }
// else if (map->length == map->capacity)
// {
// todo();
// // auto result = string_map_put_assume_not_existent(map, arena, hash, key, value);
// // assert(!result.existing);
// // return result;
// }
// else
// {
// todo();
// }
// }
// }
fn int file_write(String file_path, String file_data) fn int file_write(String file_path, String file_data)
{ {
int file_descriptor = syscall_open((char*)file_path.pointer, O_WRONLY | O_CREAT | O_TRUNC, 0644); int file_descriptor = syscall_open(string_to_c(file_path), O_WRONLY | O_CREAT | O_TRUNC, 0644);
assert(file_descriptor != -1); assert(file_descriptor != -1);
auto bytes = syscall_write(file_descriptor, file_data.pointer, file_data.length); auto bytes = syscall_write(file_descriptor, file_data.pointer, file_data.length);
@ -225,7 +267,7 @@ fn int file_write(String file_path, String file_data)
fn String file_read(Arena* arena, String path) fn String file_read(Arena* arena, String path)
{ {
String result = {}; String result = {};
int file_descriptor = syscall_open((char*)path.pointer, 0, 0); int file_descriptor = syscall_open(string_to_c(path), 0, 0);
assert(file_descriptor != -1); assert(file_descriptor != -1);
struct stat stat_buffer; struct stat stat_buffer;
@ -263,23 +305,23 @@ fn void print_string(String message)
typedef enum ELFSectionType : u32 typedef enum ELFSectionType : u32
{ {
null = 0x00, ELF_SECTION_NULL = 0X00,
program = 0x01, ELF_SECTION_PROGRAM = 0X01,
symbol_table = 0x02, ELF_SECTION_SYMBOL_TABLE = 0X02,
string_table = 0x03, ELF_SECTION_STRING_TABLE = 0X03,
relocation_with_addends = 0x04, ELF_SECTION_RELOCATION_WITH_ADDENDS = 0X04,
symbol_hash_table = 0x05, ELF_SECTION_SYMBOL_HASH_TABLE = 0X05,
dynamic = 0x06, ELF_SECTION_DYNAMIC = 0X06,
note = 0x07, ELF_SECTION_NOTE = 0X07,
bss = 0x08, ELF_SECTION_BSS = 0X08,
relocation_no_addends = 0x09, ELF_SECTION_RELOCATION_NO_ADDENDS = 0X09,
lib = 0x0a, // reserved ELF_SECTION_LIB = 0X0A, // RESERVED
dynamic_symbol_table = 0x0b, ELF_SECTION_DYNAMIC_SYMBOL_TABLE = 0X0B,
init_array = 0x0e, ELF_SECTION_INIT_ARRAY = 0X0E,
fini_array = 0x0f, ELF_SECTION_FINI_ARRAY = 0X0F,
preinit_array = 0x10, ELF_SECTION_PREINIT_ARRAY = 0X10,
group = 0x11, ELF_SECTION_GROUP = 0X11,
symbol_table_section_header_index = 0x12, ELF_SECTION_SYMBOL_TABLE_SECTION_HEADER_INDEX = 0X12,
} ELFSectionType; } ELFSectionType;
struct ELFSectionHeaderFlags struct ELFSectionHeaderFlags
@ -295,8 +337,10 @@ struct ELFSectionHeaderFlags
u64 os_non_conforming:1; u64 os_non_conforming:1;
u64 group:1; u64 group:1;
u64 tls:1; u64 tls:1;
u64 reserved:53;
}; };
typedef struct ELFSectionHeaderFlags ELFSectionHeaderFlags; typedef struct ELFSectionHeaderFlags ELFSectionHeaderFlags;
static_assert(sizeof(ELFSectionHeaderFlags) == sizeof(u64));
struct ELFSectionHeader struct ELFSectionHeader
{ {
@ -313,6 +357,7 @@ struct ELFSectionHeader
}; };
typedef struct ELFSectionHeader ELFSectionHeader; typedef struct ELFSectionHeader ELFSectionHeader;
static_assert(sizeof(ELFSectionHeader) == 64); static_assert(sizeof(ELFSectionHeader) == 64);
decl_vb(ELFSectionHeader);
typedef enum ELFBitCount : u8 typedef enum ELFBitCount : u8
{ {
@ -376,7 +421,6 @@ struct ELFHeader
u16 section_header_size; u16 section_header_size;
u16 section_header_count; u16 section_header_count;
u16 section_header_string_table_index; u16 section_header_string_table_index;
}; };
typedef struct ELFHeader ELFHeader; typedef struct ELFHeader ELFHeader;
static_assert(sizeof(ELFHeader) == 0x40); static_assert(sizeof(ELFHeader) == 0x40);
@ -409,8 +453,20 @@ struct ELFSymbol
u64 size; u64 size;
}; };
typedef struct ELFSymbol ELFSymbol; typedef struct ELFSymbol ELFSymbol;
decl_vb(ELFSymbol);
static_assert(sizeof(ELFSymbol) == 24); static_assert(sizeof(ELFSymbol) == 24);
// DWARF
struct DWARFCompilationUnit
{
u32 length;
u16 version;
u8 type;
u8 address_size;
u32 debug_abbreviation_offset;
};
typedef struct DWARFCompilationUnit DWARFCompilationUnit;
struct NameReference struct NameReference
{ {
u32 offset; u32 offset;
@ -440,6 +496,7 @@ struct TypeIndex
{ {
u32 index; u32 index;
}; };
typedef struct TypeIndex TypeIndex; typedef struct TypeIndex TypeIndex;
#define index_equal(a, b) (a.index == b.index) #define index_equal(a, b) (a.index == b.index)
static_assert(sizeof(TypeIndex) == sizeof(u32)); static_assert(sizeof(TypeIndex) == sizeof(u32));
@ -4434,8 +4491,7 @@ typedef struct CBackend CBackend;
fn void c_lower_append_string(CBackend* backend, String string) fn void c_lower_append_string(CBackend* backend, String string)
{ {
u8* pointer = vb_add(&backend->buffer, string.length); vb_append_bytes(&backend->buffer, string);
memcpy(pointer, string.pointer, string.length);
} }
fn void c_lower_append_ch(CBackend* backend, u8 ch) fn void c_lower_append_ch(CBackend* backend, u8 ch)
@ -4761,11 +4817,12 @@ fn void unit_tests()
Slice(String) arguments; Slice(String) arguments;
typedef enum ExecutionEngine : u8 typedef enum CompilerBackend : u8
{ {
EXECUTION_ENGINE_C = 'c', COMPILER_BACKEND_C = 'c',
EXECUTION_ENGINE_INTERPRETER = 'i', COMPILER_BACKEND_INTERPRETER = 'i',
} ExecutionEngine; COMPILER_BACKEND_MACHINE = 'm',
} CompilerBackend;
struct Interpreter struct Interpreter
{ {
@ -4900,6 +4957,233 @@ fn s32 interpreter_run(Interpreter* interpreter, Thread* thread)
return result; return result;
} }
struct ELFOptions
{
char* object_path;
char* exe_path;
Slice(u8) code;
};
typedef struct ELFOptions ELFOptions;
struct ELFBuilder
{
VirtualBuffer(u8) file;
VirtualBuffer(u8) string_table;
VirtualBuffer(ELFSymbol) symbol_table;
VirtualBuffer(ELFSectionHeader) section_table;
};
typedef struct ELFBuilder ELFBuilder;
fn u32 elf_builder_add_string(ELFBuilder* builder, String string)
{
u32 name_offset = 0;
if (string.length)
{
name_offset = builder->string_table.length;
vb_append_bytes(&builder->string_table, string);
*vb_add(&builder->string_table, 1) = 0;
}
return name_offset;
}
fn void elf_builder_add_symbol(ELFBuilder* builder, ELFSymbol symbol, String string)
{
symbol.name_offset = elf_builder_add_string(builder, string);
*vb_add(&builder->symbol_table, 1) = symbol;
}
fn void vb_align(VirtualBuffer(u8)* buffer, u64 alignment)
{
auto current_length = buffer->length;
auto target_len = align_forward(current_length, alignment);
auto count = target_len - current_length;
auto* pointer = vb_add(buffer, count);
memset(pointer, 0, count);
}
fn ELFSectionHeader* elf_builder_add_section(ELFBuilder* builder, ELFSectionHeader section, String section_name, Slice(u8) content)
{
section.name_offset = elf_builder_add_string(builder, section_name);
section.offset = builder->file.length;
section.size = content.length;
if (content.length)
{
vb_align(&builder->file, section.alignment);
section.offset = builder->file.length;
vb_append_bytes(&builder->file, content);
}
auto* section_header = vb_add(&builder->section_table, 1);
*section_header = section;
return section_header;
}
fn void write_elf(Thread* thread, char** envp, const ELFOptions* const options)
{
// {
// auto main_c_content = strlit("int main()\n{\n return 0;\n}");
// int fd = syscall_open("main.c", O_WRONLY | O_CREAT | O_TRUNC, 0644);
// assert(fd != -1);
// auto result = syscall_write(fd, main_c_content.pointer, main_c_content.length);
// assert(result >= 0);
// assert((u64)result == main_c_content.length);
// syscall_close(fd);
// }
// {
// char* command[] = {
// clang_path,
// "-c",
// "main.c",
// "-o",
// "main.o",
// "-Oz",
// "-fno-exceptions",
// "-fno-asynchronous-unwind-tables",
// "-fno-addrsig",
// "-fno-stack-protector",
// "-fno-ident",
// 0,
// };
// run_command((CStringSlice) array_to_slice(command), envp);
// }
//
// {
// char* command[] = {
// "/usr/bin/objcopy",
// "--remove-section",
// ".note.GNU-stack",
// "main.o",
// "main2.o",
// 0,
// };
// run_command((CStringSlice) array_to_slice(command), envp);
// }
//
// {
//
// main_o = file_read(thread->arena, strlit("main2.o"));
// auto r1 = syscall_unlink("main.o");
// assert(!r1);
// auto r2 = syscall_unlink("main2.o");
// assert(!r2);
// auto r3 = syscall_unlink("main.c");
// assert(!r3);
// }
ELFBuilder builder_stack = {};
ELFBuilder* builder = &builder_stack;
auto* elf_header = (ELFHeader*)(vb_add(&builder->file, sizeof(ELFHeader)));
// vb_append_bytes(&file, struct_to_bytes(elf_header));
// .symtab
// Null symbol
*vb_add(&builder->string_table, 1) = 0;
elf_builder_add_symbol(builder, (ELFSymbol){}, (String){});
elf_builder_add_section(builder, (ELFSectionHeader) {}, (String){}, (Slice(u8)){});
assert(builder->string_table.length == 1);
elf_builder_add_symbol(builder, (ELFSymbol){
.type = ELF_SYMBOL_TYPE_FILE,
.binding = LOCAL,
.section_index = (u16)ABSOLUTE,
.value = 0,
.size = 0,
}, strlit("main.c"));
assert(builder->string_table.length == 8);
elf_builder_add_symbol(builder, (ELFSymbol) {
.type = ELF_SYMBOL_TYPE_FUNCTION,
.binding = GLOBAL,
.section_index = 1,
.value = 0,
.size = 3,
}, strlit("main"));
elf_builder_add_section(builder, (ELFSectionHeader) {
.type = ELF_SECTION_PROGRAM,
.flags = {
.alloc = 1,
.executable = 1,
},
.address = 0,
.size = options->code.length,
.link = 0,
.info = 0,
.alignment = 4,
.entry_size = 0,
}, strlit(".text"), options->code);
elf_builder_add_section(builder, (ELFSectionHeader) {
.type = ELF_SECTION_SYMBOL_TABLE,
.link = builder->section_table.length + 1,
// TODO: One greater than the symbol table index of the last local symbol (binding STB_LOCAL).
.info = builder->symbol_table.length - 1,
.alignment = alignof(ELFSymbol),
.entry_size = sizeof(ELFSymbol),
}, strlit(".symtab"), vb_to_bytes(builder->symbol_table));
auto strtab_name_offset = elf_builder_add_string(builder, strlit(".strtab"));
auto strtab_bytes = vb_to_bytes(builder->string_table);
auto strtab_offset = builder->file.length;
vb_append_bytes(&builder->file, strtab_bytes);
auto* strtab_section_header = vb_add(&builder->section_table, 1);
*strtab_section_header = (ELFSectionHeader) {
.name_offset = strtab_name_offset,
.type = ELF_SECTION_STRING_TABLE,
.offset = strtab_offset,
.size = strtab_bytes.length,
.alignment = 1,
};
vb_align(&builder->file, alignof(ELFSectionHeader));
auto section_header_offset = builder->file.length;
vb_append_bytes(&builder->file, vb_to_bytes(builder->section_table));
*elf_header = (ELFHeader)
{
.identifier = { 0x7f, 'E', 'L', 'F' },
.bit_count = bits64,
.endianness = little,
.format_version = 1,
.abi = system_v_abi,
.abi_version = 0,
.padding = {},
.type = relocatable,
.machine = x86_64,
.version = 1,
.entry_point = 0,
.program_header_offset = 0,
.section_header_offset = section_header_offset,
.flags = 0,
.elf_header_size = sizeof(ELFHeader),
.program_header_size = 0,
.program_header_count = 0,
.section_header_size = sizeof(ELFSectionHeader),
.section_header_count = builder->section_table.length,
.section_header_string_table_index = builder->section_table.length - 1,
};
auto object_path_z = options->object_path;
{
int fd = syscall_open(object_path_z, O_WRONLY | O_CREAT | O_TRUNC, 0644);
assert(fd != -1);
syscall_write(fd, builder->file.pointer, builder->file.length);
syscall_close(fd);
}
char* command[] = {
clang_path,
object_path_z,
"-o",
options->exe_path,
0,
};
run_command((CStringSlice) array_to_slice(command), envp);
}
#if LINK_LIBC #if LINK_LIBC
int main(int argc, const char* argv[], char* envp[]) int main(int argc, const char* argv[], char* envp[])
{ {
@ -4933,7 +5217,7 @@ void entry_point(int argc, const char* argv[])
} }
String source_file_path = arguments.pointer[1]; String source_file_path = arguments.pointer[1];
ExecutionEngine execution_engine = arguments.pointer[2].pointer[0]; CompilerBackend compiler_backend = arguments.pointer[2].pointer[0];
Thread* thread = arena_allocate(global_arena, Thread, 1); Thread* thread = arena_allocate(global_arena, Thread, 1);
thread_init(thread); thread_init(thread);
@ -4969,36 +5253,36 @@ void entry_point(int argc, const char* argv[])
fail(); fail();
} }
auto c_source_path = arena_join_string(thread->arena, (Slice(String)) array_to_slice(((String[]) { auto object_path = arena_join_string(thread->arena, (Slice(String)) array_to_slice(((String[]) {
strlit("nest/"), strlit("nest/"),
test_name, test_name,
strlit(".c"), compiler_backend == COMPILER_BACKEND_C ? strlit(".c") : strlit(".o"),
}))); })));
auto exe_path_view = s_get_slice(u8, c_source_path, 0, c_source_path.length - 2); auto exe_path_view = s_get_slice(u8, object_path, 0, object_path.length - 2);
auto exe_path = (char*)arena_allocate_bytes(thread->arena, exe_path_view.length + 1, 1); auto exe_path = (char*)arena_allocate_bytes(thread->arena, exe_path_view.length + 1, 1);
memcpy((char*)exe_path, exe_path_view.pointer, exe_path_view.length); memcpy(exe_path, exe_path_view.pointer, exe_path_view.length);
exe_path[exe_path_view.length] = 0; exe_path[exe_path_view.length] = 0;
switch (execution_engine) switch (compiler_backend)
{ {
case EXECUTION_ENGINE_C: case COMPILER_BACKEND_C:
{ {
auto lowered_source = c_lower(thread); auto lowered_source = c_lower(thread);
// print("Transpiled to C:\n```\n{s}\n```\n", lowered_source); // print("Transpiled to C:\n```\n{s}\n```\n", lowered_source);
file_write(c_source_path, lowered_source); file_write(object_path, lowered_source);
char* command[] = { char* command[] = {
"/usr/bin/cc", "-g", clang_path, "-g",
"-o", exe_path, "-o", exe_path,
(char*)c_source_path.pointer, string_to_c(object_path),
0, 0,
}; };
run_command((CStringSlice) array_to_slice(command), envp); run_command((CStringSlice) array_to_slice(command), envp);
} break; } break;
case EXECUTION_ENGINE_INTERPRETER: case COMPILER_BACKEND_INTERPRETER:
{ {
auto* main_function = &thread->buffer.functions.pointer[thread->main_function]; auto* main_function = &thread->buffer.functions.pointer[thread->main_function];
auto* interpreter = interpreter_create(thread); auto* interpreter = interpreter_create(thread);
@ -5010,6 +5294,21 @@ void entry_point(int argc, const char* argv[])
print("Interpreter exited with exit code: {u32}\n", exit_code); print("Interpreter exited with exit code: {u32}\n", exit_code);
syscall_exit(exit_code); syscall_exit(exit_code);
} break; } break;
case COMPILER_BACKEND_MACHINE:
{
// TODO:
// Code:
// main:
// xor eax, eax
// ret
u8 code[] = { 0x31, 0xc0, 0xc3 };
auto code_slice = (Slice(u8)) { .pointer = code, .length = sizeof(code) };
write_elf(thread, envp, &(ELFOptions) {
.object_path = string_to_c(object_path),
.exe_path = exe_path,
.code = code_slice,
});
} break;
} }
thread_clear(thread); thread_clear(thread);

4
src/main.nat Normal file
View File

@ -0,0 +1,4 @@
fn main() s32
{
return 0;
}

5
tests/unsigned.nat Normal file
View File

@ -0,0 +1,5 @@
fn main() s32
{
>a: u32 = 0;
return a;
}