diff --git a/source/backends/arm64.d b/source/backends/arm64.d index 3a7bbc2..26d9839 100644 --- a/source/backends/arm64.d +++ b/source/backends/arm64.d @@ -96,6 +96,9 @@ class BackendARM64 : CompilerBackend { version (linux) { defaultOS = "linux"; } + version (OSX) { + defaultOS = "osx"; + } else { defaultOS = "bare-metal"; WarnNoInfo("Default operating system, defaulting to bare-metal OS"); @@ -198,6 +201,11 @@ class BackendARM64 : CompilerBackend { ret ~= ["Linux", "IO", "File", "Args", "Time", "Heap", "Exit"]; break; } + case "osx": { + ret ~= ["OSX", "IO", "File", "Args", "Time", "Exit"]; + if (useLibc) ret ~= "Heap"; + break; + } default: break; } @@ -233,25 +241,31 @@ class BackendARM64 : CompilerBackend { } if (useLibc) { - string[] possiblePaths = [ - "/usr/aarch64-linux-gnu/lib/crt1.o", - "/usr/lib/crt1.o", - "/usr/lib64/crt1.o", - ]; - bool crt1; - - foreach (ref path ; possiblePaths) { - if (path.exists) { - crt1 = true; - linkCommand ~= format(" %s", path); - linkCommand ~= format(" %s/crti.o", path.dirName); - linkCommand ~= format(" %s/crtn.o", path.dirName); - break; + if (os == "linux") { + string[] possiblePaths = [ + "/usr/aarch64-linux-gnu/lib/crt1.o", + "/usr/lib/crt1.o", + "/usr/lib64/crt1.o", + ]; + bool crt1; + + foreach (ref path ; possiblePaths) { + if (path.exists) { + crt1 = true; + linkCommand ~= format(" %s", path); + linkCommand ~= format(" %s/crti.o", path.dirName); + linkCommand ~= format(" %s/crtn.o", path.dirName); + break; + } } - } - if (!crt1) { - stderr.writeln("WARNING: Failed to find crt1.o, program may behave incorrectly"); + if (!crt1) { + stderr.writeln("WARNING: Failed to find crt1.o, program may behave incorrectly"); + } + } else if (os == "osx") { + linkCommand ~= " -lSystem -syslibroot `xcrun --sdk macosx --show-sdk-path`"; + } else { + WarnNoInfo("Cannot use libc on operating system '%s'", os); } } @@ -286,7 +300,7 @@ class BackendARM64 : CompilerBackend { // call constructors foreach (name, global ; globals) { if (global.type.hasInit) { - output ~= format("ldr x9, =__global_%s\n", name.Sanitise()); + LoadAddress("x9", format("__global_%s", name.Sanitise())); output ~= "str x9, [x19], #8\n"; output ~= format("bl __type_init_%s\n", global.type.name.Sanitise()); } @@ -302,7 +316,7 @@ class BackendARM64 : CompilerBackend { } } else if (word.type == WordType.Raw) { - output ~= format("bl %s\n", name); + output ~= format("bl %s\n", ExternSymbol(name)); } else if (word.type == WordType.C) { assert(0); // TODO: error @@ -313,13 +327,16 @@ class BackendARM64 : CompilerBackend { } override void Init() { - string[] oses = ["linux", "bare-metal"]; + string[] oses = ["linux", "osx", "bare-metal"]; if (!oses.canFind(os)) { ErrorNoInfo("Backend doesn't support operating system '%s'", os); } output ~= ".text\n"; - if (useLibc) { + if (os == "osx") { + output ~= ".global _main\n"; + output ~= "_main:\n"; + } else if (useLibc) { output ~= ".global main\n"; output ~= "main:\n"; } else { @@ -355,7 +372,7 @@ class BackendARM64 : CompilerBackend { // call destructors foreach (name, global ; globals) { if (global.type.hasDeinit) { - output ~= format("ldr x9, =__global_%s\n", name.Sanitise()); + LoadAddress("x9", format("__global_%s", name.Sanitise())); output ~= "str x9, [x19], #8\n"; output ~= format("bl __type_deinit_%s\n", global.type.name.Sanitise()); } @@ -395,6 +412,7 @@ class BackendARM64 : CompilerBackend { // create arrays output ~= ".data\n"; foreach (i, ref array ; arrays) { + output ~= ".align 8\n"; if (exportSymbols) { output ~= format(".global __array_%d\n", i); } @@ -416,6 +434,7 @@ class BackendARM64 : CompilerBackend { output ~= '\n'; if (array.global) { + output ~= ".align 8\n"; output ~= format( "__array_%d_meta: .8byte %d, %d, __array_%d\n", i, array.values.length, @@ -437,7 +456,7 @@ class BackendARM64 : CompilerBackend { } else { if (word.type == WordType.Raw) { - output ~= format("bl %s\n", node.name); + output ~= format("bl %s\n", ExternSymbol(node.name)); } else if (word.type == WordType.C) { // TODO: support more of the calling convention (especially structs) @@ -451,7 +470,7 @@ class BackendARM64 : CompilerBackend { output ~= format("ldr x%d, [x19, #-8]!\n", reg); } - output ~= format("bl %s\n", word.symbolName); + output ~= format("bl %s\n", ExternSymbol(word.symbolName)); if (!word.isVoid) { output ~= "str x0, [x19], #8\n"; @@ -486,8 +505,7 @@ class BackendARM64 : CompilerBackend { Error(node.error, "Can't push value of struct"); } - string symbol = format("__global_%s", node.name.Sanitise()); - output ~= format("ldr x9, =%s\n", symbol); + LoadAddress("x9", format("__global_%s", node.name.Sanitise())); switch (var.type.size) { case 1: output ~= "ldrb w9, [x9]\n"; break; @@ -798,14 +816,14 @@ class BackendARM64 : CompilerBackend { arrays ~= array; if (!inScope || node.constant) { - output ~= format("ldr x9, =__array_%d_meta\n", arrays.length - 1); + LoadAddress("x9", format("__array_%d_meta", arrays.length - 1)); output ~= "str x9, [x19], #8\n"; } else { // allocate a copy of this array OffsetLocalsStack(array.Size(), true); output ~= "mov x9, x20\n"; - output ~= format("ldr x10, =__array_%d\n", arrays.length - 1); + LoadAddress("x10", format("__array_%d", arrays.length - 1)); output ~= format("ldr x11, =%d\n", array.Size()); output ~= "1:\n"; output ~= "ldrb w12, [x10], #1\n"; @@ -1060,7 +1078,7 @@ class BackendARM64 : CompilerBackend { } if (word.type != WordType.Callisto) { - output ~= format(".extern %s\n", node.func); + output ~= format(".extern %s\n", ExternSymbol(node.func)); } words[funcName] = word; @@ -1075,15 +1093,15 @@ class BackendARM64 : CompilerBackend { if (node.func in words) { auto word = words[node.func]; string symbol = word.type == WordType.Callisto? - format("__func__%s", node.func.Sanitise()) : node.func; + format("__func__%s", node.func.Sanitise()) : ExternSymbol(node.func); - output ~= format("ldr x9, =%s\n", symbol); + LoadAddress("x9", symbol); output ~= "str x9, [x19], #8\n"; } else if (node.func in globals) { auto var = globals[node.func]; - output ~= format("ldr x9, =__global_%s\n", node.func.Sanitise()); + LoadAddress("x9", format("__global_%s", node.func.Sanitise())); output ~= "str x9, [x19], #8\n"; } else if (VariableExists(node.func)) { @@ -1184,8 +1202,7 @@ class BackendARM64 : CompilerBackend { Error(node.error, "Can't set struct value"); } - string symbol = format("__global_%s", node.var.Sanitise()); - output ~= format("ldr x10, =%s\n", symbol); + LoadAddress("x10", format("__global_%s", node.var.Sanitise())); switch (global.type.size) { case 1: output ~= "strb w9, [x10]\n"; break; @@ -1200,7 +1217,7 @@ class BackendARM64 : CompilerBackend { } } - void OffsetLocalsStack(size_t offset, bool sub) { + private void OffsetLocalsStack(size_t offset, bool sub) { if (offset >= 4096) { output ~= format("mov x9, #%d\n", offset); output ~= format("%s x20, x20, x9\n", sub ? "sub" : "add"); @@ -1208,4 +1225,21 @@ class BackendARM64 : CompilerBackend { output ~= format("%s x20, x20, #%d\n", sub ? "sub" : "add", offset); } } + + private void LoadAddress(string reg, string symbol) { + if (os == "osx") { + output ~= format("adrp %s, %s@PAGE\n", reg, symbol); + output ~= format("add %s, %s, %s@PAGEOFF\n", reg, reg, symbol); + } else { + output ~= format("ldr %s, =%s\n", reg, symbol); + } + } + + private string ExternSymbol(string name) { + if (os == "osx") { + return "_" ~ name; + } else { + return name; + } + } } diff --git a/source/backends/x86_64.d b/source/backends/x86_64.d index 9cfc0bb..88674aa 100644 --- a/source/backends/x86_64.d +++ b/source/backends/x86_64.d @@ -208,7 +208,8 @@ class BackendX86_64 : CompilerBackend { break; } case "osx": { - ret ~= ["OSX", "IO", "Args", "Exit"]; + ret ~= ["OSX", "IO", "Exit", "Time", "File", "Args"]; + if (useLibc) ret ~= "Heap"; break; } default: break; @@ -255,29 +256,35 @@ class BackendX86_64 : CompilerBackend { linkCommand ~= format(" -l%s", lib); } - if (!link.empty()) { + if (!link.empty() && os == "linux") { // idk if this is correct on all linux systems but whatever linkCommand ~= " -dynamic-linker /lib64/ld-linux-x86-64.so.2"; } if (useLibc) { - string[] possiblePaths = [ - "/usr/lib/crt1.o", - "/usr/lib/x86_64-linux-gnu/crt1.o" - ]; - bool crt1; - - foreach (ref path ; possiblePaths) { - if (exists(path)) { - crt1 = true; - linkCommand ~= format(" %s", path); - linkCommand ~= format(" %s/crti.o", path.dirName()); - linkCommand ~= format(" %s/crtn.o", path.dirName()); + if (os == "linux") { + string[] possiblePaths = [ + "/usr/lib/crt1.o", + "/usr/lib/x86_64-linux-gnu/crt1.o" + ]; + bool crt1; + + foreach (ref path ; possiblePaths) { + if (exists(path)) { + crt1 = true; + linkCommand ~= format(" %s", path); + linkCommand ~= format(" %s/crti.o", path.dirName()); + linkCommand ~= format(" %s/crtn.o", path.dirName()); + } } - } - if (!crt1) { - stderr.writeln("WARNING: Failed to find crt1.o, program may behave incorrectly"); + if (!crt1) { + stderr.writeln("WARNING: Failed to find crt1.o, program may behave incorrectly"); + } + } else if (os == "osx") { + linkCommand ~= " -syslibroot `xcrun --sdk macosx --show-sdk-path`"; + } else { + WarnNoInfo("Cannot use libc on operating system '%s'", os); } } @@ -313,8 +320,9 @@ class BackendX86_64 : CompilerBackend { foreach (name, global ; globals) { if (global.type.hasInit) { output ~= format( - "mov qword [r15], qword __global_%s\n", name.Sanitise() + "lea rax, qword [__global_%s]\n", name.Sanitise() ); + output ~= "mov [r15], rax\n"; output ~= "add r15, 8\n"; output ~= format("call __type_init_%s\n", global.type.name.Sanitise()); } @@ -330,7 +338,7 @@ class BackendX86_64 : CompilerBackend { } } else if (word.type == WordType.Raw) { - output ~= format("call %s\n", name); + output ~= format("call %s\n", ExternSymbol(name)); } else if (word.type == WordType.C) { assert(0); // TODO: error @@ -346,15 +354,19 @@ class BackendX86_64 : CompilerBackend { ErrorNoInfo("Backend doesn't support operating system '%s'", os); } - if (useLibc) output ~= "global main\n"; - else if (os == "osx") output ~= "default rel\nglobal _main\n"; - else output ~= "global _start\n"; - output ~= "section .text\n"; - - if (useLibc) output ~= "main:\n"; - else if (os == "osx") output ~= "_main:\n"; - else output ~= "_start:\n"; + + if (os == "osx") { + output ~= "default rel\n"; + output ~= "global _main\n"; + output ~= "_main:\n"; + } else if (useLibc) { + output ~= "global main\n"; + output ~= "main:\n"; + } else { + output ~= "global _start\n"; + output ~= "_start:\n"; + } output ~= "call __init\n"; @@ -388,7 +400,8 @@ class BackendX86_64 : CompilerBackend { // call destructors foreach (name, global ; globals) { if (global.type.hasDeinit) { - output ~= format("mov qword [r15], qword __global_%s\n", Sanitise(name)); + output ~= format("lea rax, qword [__global_%s]\n", Sanitise(name)); + output ~= "mov [r15], rax\n"; output ~= "add r15, 8\n"; output ~= format("call __type_deinit_%s\n", Sanitise(global.type.name)); } @@ -484,7 +497,7 @@ class BackendX86_64 : CompilerBackend { } else { if (word.type == WordType.Raw) { - output ~= format("call %s\n", node.name); + output ~= format("call %s\n", ExternSymbol(node.name)); } else if (word.type == WordType.C) { if (word.params.length >= 1) { @@ -521,7 +534,7 @@ class BackendX86_64 : CompilerBackend { // TODO: support more than 6 parameters - output ~= format("call %s\n", word.symbolName); + output ~= format("call %s\n", ExternSymbol(word.symbolName)); if (!word.isVoid) { output ~= "mov [r15], rax\n"; @@ -1155,7 +1168,7 @@ class BackendX86_64 : CompilerBackend { } if (word.type != WordType.Callisto) { - output ~= format("extern %s\n", node.func); + output ~= format("extern %s\n", ExternSymbol(node.func)); } words[funcName] = word; @@ -1171,7 +1184,7 @@ class BackendX86_64 : CompilerBackend { if (node.func in words) { auto word = words[node.func]; string symbol = word.type == WordType.Callisto? - format("__func__%s", node.func.Sanitise()) : node.func; + format("__func__%s", node.func.Sanitise()) : ExternSymbol(node.func); output ~= format("mov rax, %s\n", symbol); output ~= "mov [r15], rax\n"; @@ -1310,4 +1323,12 @@ class BackendX86_64 : CompilerBackend { Error(node.error, "Variable '%s' doesn't exist", node.var); } } + + private string ExternSymbol(string name) { + if (os == "osx") { + return "_" ~ name; + } else { + return name; + } + } } diff --git a/std b/std index d4b0e78..61946de 160000 --- a/std +++ b/std @@ -1 +1 @@ -Subproject commit d4b0e78663f57802a0aa24ffc179d63edee2e4c4 +Subproject commit 61946de9cbe30d54f041b0db5ad604040f06343c