From b0d3fbba4761aff3dfc3bcded3da7000699a7766 Mon Sep 17 00:00:00 2001 From: Nakst Date: Sun, 26 Nov 2017 11:03:11 +0000 Subject: [PATCH] essence cross compile --- core/os.odin | 1 + core/os_essence.odin | 115 ++++++++++++++++++++++++++ core/sys/essence_linker_userland64.ld | 24 ++++++ src/build_settings.cpp | 12 ++- src/ir.cpp | 8 ++ src/main.cpp | 52 ++++++++++-- 6 files changed, 206 insertions(+), 6 deletions(-) create mode 100644 core/os_essence.odin create mode 100644 core/sys/essence_linker_userland64.ld diff --git a/core/os.odin b/core/os.odin index 8f7a4ff92..1ed920a45 100644 --- a/core/os.odin +++ b/core/os.odin @@ -1,6 +1,7 @@ when ODIN_OS == "windows" do export "core:os_windows.odin"; when ODIN_OS == "osx" do export "core:os_x.odin"; when ODIN_OS == "linux" do export "core:os_linux.odin"; +when ODIN_OS == "essence" do export "core:os_essence.odin"; import "mem.odin"; diff --git a/core/os_essence.odin b/core/os_essence.odin new file mode 100644 index 000000000..b6670850f --- /dev/null +++ b/core/os_essence.odin @@ -0,0 +1,115 @@ +foreign import api "system:api" + +Handle :: int; +Errno :: int; + +O_RDONLY :: 1; +O_WRONLY :: 2; +O_CREATE :: 4; +O_TRUNC :: 4; + +OS_Node_Type :: enum i32 { + File = 0, + Directory = 1, +} + +OS_Node_Information :: struct #ordered { + handle: Handle, + id: [16]u8, + ntype: OS_Node_Type, + size: i64, + position: i64, +} + +foreign api { + @(link_name="OSHelloWorld") os_hello_world :: proc() ---; + @(link_name="OSPrintDirect") os_print_direct :: proc(string: ^u8, length: int) ---; + @(link_name="OSHeapAllocate") os_heap_allocate :: proc(bytes: int, zero: bool) -> rawptr ---; + @(link_name="OSHeapFree") os_heap_free :: proc(address: rawptr) ---; + @(link_name="OSOpenNode") os_open_node :: proc(path: ^u8, path_length: int, flags: u64, information: ^OS_Node_Information) -> Errno ---; + @(link_name="OSResizeFile") os_resize_file :: proc(handle: Handle, new_size: u64) -> Errno ---; + @(link_name="OSCloseHandle") os_close_handle :: proc(handle: Handle) ---; + @(link_name="OSWriteFileSync") os_write_file_sync :: proc(handle: Handle, offset: i64, size: i64, buffer: rawptr) -> i64 ---; + @(link_name="OSReadFileSync") os_read_file_sync :: proc(handle: Handle, offset: i64, size: i64, buffer: rawptr) -> i64 ---; + @(link_name="OSInitialiseAPI") os_initialise_api :: proc() -> int ---; + @(link_name="OSTerminateProcess") os_terminate_process :: proc(handle: Handle) ---; + @(link_name="realloc") os_heap_reallocate :: proc(address: rawptr, size: int) -> rawptr ---; +} + +stdin := cast(Handle) -1; // Not implemented +stdout := cast(Handle) 0; +stderr := cast(Handle) 0; + +current_thread_id :: proc() -> int { + // Not implemented + return int(-1); +} + +heap_alloc :: proc(size: int) -> rawptr { + return os_heap_allocate(size, true); +} + +heap_free :: proc(address: rawptr) { + os_heap_free(address); +} + +heap_resize :: proc(address: rawptr, new_size: int) -> rawptr { + return os_heap_reallocate(address, new_size); +} + +open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) { + information := new(OS_Node_Information); + error := os_open_node(&path[0], len(path), cast(u64) mode, information); + if (error < -1) { return 0,1; } + information.position = 0; + if (mode&O_TRUNC==O_TRUNC) { + error := os_resize_file(information.handle, 0); + if (error < -1) { return 0,1; } + } + return cast(Handle) cast(uintptr) information,0; +} + +close :: proc(fd: Handle) { + information := cast(^OS_Node_Information) cast(uintptr) fd; + os_close_handle(information.handle); + free(information); +} + +file_size :: proc(fd: Handle) -> (i64, Errno) { + // Not (properly) implemented + information := cast(^OS_Node_Information) cast(uintptr) fd; + return information.size,0; +} + +write :: proc(fd: Handle, data: []u8) -> (int, Errno) { + if (fd == 0) { + os_print_direct(&data[0], len(data)); + return len(data), 0; + } else if (fd == 1) { + assert(false); + return 0, 1; + } else { + information := cast(^OS_Node_Information) cast(uintptr) fd; + count := os_write_file_sync(information.handle, information.position, cast(i64) len(data), cast(rawptr) &data[0]); + if (count < 0) { return 0, 1; } + information.position += count; + return cast(int) count, 0; + } +} + +read :: proc(fd: Handle, data: []u8) -> (int, Errno) { + if (fd == 0 || fd == 1) { + assert(false); + return 0, 1; + } else { + information := cast(^OS_Node_Information) cast(uintptr) fd; + count := os_read_file_sync(information.handle, information.position, cast(i64) len(data), cast(rawptr) &data[0]); + if (count < 0) { return 0, 1; } + information.position += count; + return cast(int) count, 0; + } +} + +os_terminate_this_process :: proc() { + os_terminate_process(0x1001); +} diff --git a/core/sys/essence_linker_userland64.ld b/core/sys/essence_linker_userland64.ld new file mode 100644 index 000000000..5f6d92791 --- /dev/null +++ b/core/sys/essence_linker_userland64.ld @@ -0,0 +1,24 @@ +ENTRY(_start) + +SECTIONS +{ + . = 0x100000; + .text BLOCK(4K) : ALIGN(4K) + { + *(.text) + } + .rodata BLOCK(4K) : ALIGN(4K) + { + *(.rodata) + } + .data BLOCK(4K) : ALIGN(4K) + { + *(.data) + } + + .bss BLOCK(4K) : ALIGN(4K) + { + *(COMMON) + *(.bss) + } +} diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 496de46ba..95c418839 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -309,6 +309,8 @@ String get_fullpath_core(gbAllocator a, String path) { String const ODIN_VERSION = str_lit("0.7.1"); +String cross_compile_target = str_lit(""); +String cross_compile_lib_dir = str_lit(""); void init_build_context(void) { BuildContext *bc = &build_context; @@ -330,6 +332,10 @@ void init_build_context(void) { bc->ODIN_OS = str_lit("linux"); #endif + if (cross_compile_target.len) { + bc->ODIN_OS = cross_compile_target; + } + #if defined(GB_ARCH_64_BIT) bc->ODIN_ARCH = str_lit("amd64"); #else @@ -376,7 +382,11 @@ void init_build_context(void) { bc->max_align = 16; bc->llc_flags = str_lit("-march=x86-64 "); - bc->link_flags = str_lit(LINK_FLAG_X64 " "); + if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) { + bc->link_flags = str_lit(" "); + } else { + bc->link_flags = str_lit(LINK_FLAG_X64 " "); + } } else if (bc->ODIN_ARCH == "x86") { bc->word_size = 4; bc->max_align = 8; diff --git a/src/ir.cpp b/src/ir.cpp index bf7c8c260..6913675ea 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8634,6 +8634,14 @@ void ir_gen_tree(irGen *s) { if (!(build_context.is_dll && !has_dll_main)) { // main :: proc(argc: i32, argv: ^^u8) -> i32 String name = str_lit("main"); + + if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) { + // This is a bit hacky, + // because this makes this function the first function run in the executable + // so it won't actually have the argc/argv arguments. + name = str_lit("ProgramEntry"); + } + Type *proc_params = make_type_tuple(a); Type *proc_results = make_type_tuple(a); diff --git a/src/main.cpp b/src/main.cpp index 7d9470a0f..1ef193e3d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -77,6 +77,7 @@ i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) { va_end(va); cmd = make_string(cast(u8 *)&cmd_line, cmd_len-1); + //printf("do: %s\n", cmd_line); exit_code = system(&cmd_line[0]); // pid_t pid = fork(); @@ -210,6 +211,8 @@ enum BuildFlagKind { BuildFlag_Collection, BuildFlag_BuildMode, BuildFlag_Debug, + BuildFlag_CrossCompile, + BuildFlag_CrossLibDir, BuildFlag_COUNT, }; @@ -246,6 +249,8 @@ bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_Collection, str_lit("collection"), BuildFlagParam_String); add_flag(&build_flags, BuildFlag_BuildMode, str_lit("build-mode"), BuildFlagParam_String); add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None); + add_flag(&build_flags, BuildFlag_CrossCompile, str_lit("cross-compile"), BuildFlagParam_String); + add_flag(&build_flags, BuildFlag_CrossLibDir, str_lit("cross-lib-dir"), BuildFlagParam_String); Array flag_args = args; @@ -399,6 +404,33 @@ bool parse_build_flags(Array args) { build_context.keep_temp_files = true; break; + case BuildFlag_CrossCompile: { + GB_ASSERT(value.kind == ExactValue_String); + cross_compile_target = value.value_string; +#ifdef GB_SYSTEM_UNIX +#ifdef GB_ARCH_64_BIT + if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) { +#endif +#endif + } else { + gb_printf_err("Unsupported cross compilation target '%.*s'\n", LIT(cross_compile_target)); + gb_printf_err("Currently supported targets: Essence (from 64-bit Unixes only)\n"); + bad_flags = true; + } + break; + } + + case BuildFlag_CrossLibDir: { + GB_ASSERT(value.kind == ExactValue_String); + if (cross_compile_lib_dir.len) { + gb_printf_err("Multiple cross compilation library directories\n"); + bad_flags = true; + } else { + cross_compile_lib_dir = concatenate_strings(heap_allocator(), str_lit("-L"), value.value_string); + } + break; + } + case BuildFlag_Collection: { GB_ASSERT(value.kind == ExactValue_String); String str = value.value_string; @@ -831,10 +863,12 @@ int main(int arg_count, char **arg_ptr) { "llc \"%.*s.bc\" -filetype=obj -relocation-model=pic -O%d " "%.*s " // "-debug-pass=Arguments " + "%s" "", LIT(output_base), build_context.optimization_level, - LIT(build_context.llc_flags)); + LIT(build_context.llc_flags), + str_eq_ignore_case(cross_compile_target, str_lit("Essence")) ? "-mtriple=x86_64-pc-none-elf" : ""); if (exit_code != 0) { return exit_code; } @@ -916,14 +950,19 @@ int main(int arg_count, char **arg_ptr) { // It probably has to do with including the entire CRT, but // that's quite a complicated issue to solve while remaining distro-agnostic. // Clang can figure out linker flags for us, and that's good enough _for now_. - linker = "clang -Wno-unused-command-line-argument"; + if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) { + linker = "x86_64-elf-gcc -T core/sys/essence_linker_userland64.ld -ffreestanding -nostdlib -lgcc -g -z max-page-size=0x1000 -Wno-unused-command-line-argument"; + } else { + linker = "clang -Wno-unused-command-line-argument"; + } #endif exit_code = system_exec_command_line_app("ld-link", true, "%s \"%.*s.o\" -o \"%.*s%s\" %s " - "-lc -lm " + " %s " " %.*s " " %s " + " %.*s " #if defined(GB_SYSTEM_OSX) // This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit. // NOTE: If you change this (although this minimum is as low as you can go with Odin working) @@ -933,8 +972,11 @@ int main(int arg_count, char **arg_ptr) { " -e _main " #endif , linker, LIT(output_base), LIT(output_base), output_ext, - lib_str, LIT(build_context.link_flags), - link_settings + lib_str, + str_eq_ignore_case(cross_compile_target, str_lit("Essence")) ? "" : "-lc -lm", + LIT(build_context.link_flags), + link_settings, + LIT(cross_compile_lib_dir) ); if (exit_code != 0) { return exit_code;