@@ -96,6 +96,9 @@ class BackendARM64 : CompilerBackend {
9696 version (linux ) {
9797 defaultOS = " linux" ;
9898 }
99+ version (OSX ) {
100+ defaultOS = " osx" ;
101+ }
99102 else {
100103 defaultOS = " bare-metal" ;
101104 WarnNoInfo(" Default operating system, defaulting to bare-metal OS" );
@@ -198,6 +201,11 @@ class BackendARM64 : CompilerBackend {
198201 ret ~= [" Linux" , " IO" , " File" , " Args" , " Time" , " Heap" , " Exit" ];
199202 break ;
200203 }
204+ case " osx" : {
205+ ret ~= [" OSX" , " IO" , " File" , " Args" , " Time" , " Exit" ];
206+ if (useLibc) ret ~= " Heap" ;
207+ break ;
208+ }
201209 default : break ;
202210 }
203211
@@ -233,25 +241,31 @@ class BackendARM64 : CompilerBackend {
233241 }
234242
235243 if (useLibc) {
236- string [] possiblePaths = [
237- " /usr/aarch64-linux-gnu/lib/crt1.o" ,
238- " /usr/lib/crt1.o" ,
239- " /usr/lib64/crt1.o" ,
240- ];
241- bool crt1;
242-
243- foreach (ref path ; possiblePaths) {
244- if (path.exists) {
245- crt1 = true ;
246- linkCommand ~= format(" %s" , path);
247- linkCommand ~= format(" %s/crti.o" , path.dirName);
248- linkCommand ~= format(" %s/crtn.o" , path.dirName);
249- break ;
244+ if (os == " linux" ) {
245+ string [] possiblePaths = [
246+ " /usr/aarch64-linux-gnu/lib/crt1.o" ,
247+ " /usr/lib/crt1.o" ,
248+ " /usr/lib64/crt1.o" ,
249+ ];
250+ bool crt1;
251+
252+ foreach (ref path ; possiblePaths) {
253+ if (path.exists) {
254+ crt1 = true ;
255+ linkCommand ~= format(" %s" , path);
256+ linkCommand ~= format(" %s/crti.o" , path.dirName);
257+ linkCommand ~= format(" %s/crtn.o" , path.dirName);
258+ break ;
259+ }
250260 }
251- }
252261
253- if (! crt1) {
254- stderr.writeln(" WARNING: Failed to find crt1.o, program may behave incorrectly" );
262+ if (! crt1) {
263+ stderr.writeln(" WARNING: Failed to find crt1.o, program may behave incorrectly" );
264+ }
265+ } else if (os == " osx" ) {
266+ linkCommand ~= " -lSystem -syslibroot `xcrun --sdk macosx --show-sdk-path`" ;
267+ } else {
268+ WarnNoInfo(" Cannot use libc on operating system '%s'" , os);
255269 }
256270 }
257271
@@ -286,7 +300,7 @@ class BackendARM64 : CompilerBackend {
286300 // call constructors
287301 foreach (name, global ; globals) {
288302 if (global.type.hasInit) {
289- output ~= format( " ldr x9, = __global_%s\n " , name.Sanitise());
303+ LoadAddress( " x9 " , format( " __global_%s" , name.Sanitise() ));
290304 output ~= " str x9, [x19], #8\n " ;
291305 output ~= format(" bl __type_init_%s\n " , global.type.name.Sanitise());
292306 }
@@ -302,7 +316,7 @@ class BackendARM64 : CompilerBackend {
302316 }
303317 }
304318 else if (word.type == WordType.Raw) {
305- output ~= format(" bl %s\n " , name);
319+ output ~= format(" bl %s\n " , ExternSymbol( name) );
306320 }
307321 else if (word.type == WordType.C) {
308322 assert (0 ); // TODO: error
@@ -313,13 +327,16 @@ class BackendARM64 : CompilerBackend {
313327 }
314328
315329 override void Init () {
316- string [] oses = [" linux" , " bare-metal" ];
330+ string [] oses = [" linux" , " osx " , " bare-metal" ];
317331 if (! oses.canFind(os)) {
318332 ErrorNoInfo(" Backend doesn't support operating system '%s'" , os);
319333 }
320334
321335 output ~= " .text\n " ;
322- if (useLibc) {
336+ if (os == " osx" ) {
337+ output ~= " .global _main\n " ;
338+ output ~= " _main:\n " ;
339+ } else if (useLibc) {
323340 output ~= " .global main\n " ;
324341 output ~= " main:\n " ;
325342 } else {
@@ -355,7 +372,7 @@ class BackendARM64 : CompilerBackend {
355372 // call destructors
356373 foreach (name, global ; globals) {
357374 if (global.type.hasDeinit) {
358- output ~= format( " ldr x9, = __global_%s\n " , name.Sanitise());
375+ LoadAddress( " x9 " , format( " __global_%s" , name.Sanitise() ));
359376 output ~= " str x9, [x19], #8\n " ;
360377 output ~= format(" bl __type_deinit_%s\n " , global.type.name.Sanitise());
361378 }
@@ -395,6 +412,7 @@ class BackendARM64 : CompilerBackend {
395412 // create arrays
396413 output ~= " .data\n " ;
397414 foreach (i, ref array ; arrays) {
415+ output ~= " .align 8\n " ;
398416 if (exportSymbols) {
399417 output ~= format(" .global __array_%d\n " , i);
400418 }
@@ -416,6 +434,7 @@ class BackendARM64 : CompilerBackend {
416434 output ~= ' \n ' ;
417435
418436 if (array.global) {
437+ output ~= " .align 8\n " ;
419438 output ~= format(
420439 " __array_%d_meta: .8byte %d, %d, __array_%d\n " , i,
421440 array.values .length,
@@ -437,7 +456,7 @@ class BackendARM64 : CompilerBackend {
437456 }
438457 else {
439458 if (word.type == WordType.Raw) {
440- output ~= format(" bl %s\n " , node.name);
459+ output ~= format(" bl %s\n " , ExternSymbol( node.name) );
441460 }
442461 else if (word.type == WordType.C) {
443462 // TODO: support more of the calling convention (especially structs)
@@ -451,7 +470,7 @@ class BackendARM64 : CompilerBackend {
451470 output ~= format(" ldr x%d, [x19, #-8]!\n " , reg);
452471 }
453472
454- output ~= format(" bl %s\n " , word.symbolName);
473+ output ~= format(" bl %s\n " , ExternSymbol( word.symbolName) );
455474
456475 if (! word.isVoid) {
457476 output ~= " str x0, [x19], #8\n " ;
@@ -486,8 +505,7 @@ class BackendARM64 : CompilerBackend {
486505 Error(node.error, " Can't push value of struct" );
487506 }
488507
489- string symbol = format(" __global_%s" , node.name.Sanitise());
490- output ~= format(" ldr x9, =%s\n " , symbol);
508+ LoadAddress(" x9" , format(" __global_%s" , node.name.Sanitise()));
491509
492510 switch (var.type.size) {
493511 case 1 : output ~= " ldrb w9, [x9]\n " ; break ;
@@ -798,14 +816,14 @@ class BackendARM64 : CompilerBackend {
798816 arrays ~= array;
799817
800818 if (! inScope || node.constant) {
801- output ~= format( " ldr x9, = __array_%d_meta\n " , arrays.length - 1 );
819+ LoadAddress( " x9 " , format( " __array_%d_meta" , arrays.length - 1 ) );
802820 output ~= " str x9, [x19], #8\n " ;
803821 }
804822 else {
805823 // allocate a copy of this array
806824 OffsetLocalsStack(array.Size(), true );
807825 output ~= " mov x9, x20\n " ;
808- output ~= format( " ldr x10, = __array_%d\n " , arrays.length - 1 );
826+ LoadAddress( " x10" , format( " __array_%d" , arrays.length - 1 ) );
809827 output ~= format(" ldr x11, =%d\n " , array.Size());
810828 output ~= " 1:\n " ;
811829 output ~= " ldrb w12, [x10], #1\n " ;
@@ -1060,7 +1078,7 @@ class BackendARM64 : CompilerBackend {
10601078 }
10611079
10621080 if (word.type != WordType.Callisto) {
1063- output ~= format(" .extern %s\n " , node.func);
1081+ output ~= format(" .extern %s\n " , ExternSymbol( node.func) );
10641082 }
10651083
10661084 words[funcName] = word;
@@ -1075,15 +1093,15 @@ class BackendARM64 : CompilerBackend {
10751093 if (node.func in words) {
10761094 auto word = words[node.func];
10771095 string symbol = word.type == WordType.Callisto?
1078- format(" __func__%s" , node.func.Sanitise()) : node.func;
1096+ format(" __func__%s" , node.func.Sanitise()) : ExternSymbol( node.func) ;
10791097
1080- output ~= format( " ldr x9, =%s \n " , symbol);
1098+ LoadAddress( " x9 " , symbol);
10811099 output ~= " str x9, [x19], #8\n " ;
10821100 }
10831101 else if (node.func in globals) {
10841102 auto var = globals[node.func];
10851103
1086- output ~= format( " ldr x9, = __global_%s\n " , node.func.Sanitise());
1104+ LoadAddress( " x9 " , format( " __global_%s" , node.func.Sanitise() ));
10871105 output ~= " str x9, [x19], #8\n " ;
10881106 }
10891107 else if (VariableExists(node.func)) {
@@ -1184,8 +1202,7 @@ class BackendARM64 : CompilerBackend {
11841202 Error(node.error, " Can't set struct value" );
11851203 }
11861204
1187- string symbol = format(" __global_%s" , node.var.Sanitise());
1188- output ~= format(" ldr x10, =%s\n " , symbol);
1205+ LoadAddress(" x10" , format(" __global_%s" , node.var.Sanitise()));
11891206
11901207 switch (global.type.size) {
11911208 case 1 : output ~= " strb w9, [x10]\n " ; break ;
@@ -1200,12 +1217,29 @@ class BackendARM64 : CompilerBackend {
12001217 }
12011218 }
12021219
1203- void OffsetLocalsStack (size_t offset, bool sub) {
1220+ private void OffsetLocalsStack (size_t offset, bool sub) {
12041221 if (offset >= 4096 ) {
12051222 output ~= format(" mov x9, #%d\n " , offset);
12061223 output ~= format(" %s x20, x20, x9\n " , sub ? " sub" : " add" );
12071224 } else {
12081225 output ~= format(" %s x20, x20, #%d\n " , sub ? " sub" : " add" , offset);
12091226 }
12101227 }
1228+
1229+ private void LoadAddress (string reg, string symbol) {
1230+ if (os == " osx" ) {
1231+ output ~= format(" adrp %s, %s@PAGE\n " , reg, symbol);
1232+ output ~= format(" add %s, %s, %s@PAGEOFF\n " , reg, reg, symbol);
1233+ } else {
1234+ output ~= format(" ldr %s, =%s\n " , reg, symbol);
1235+ }
1236+ }
1237+
1238+ private string ExternSymbol (string name) {
1239+ if (os == " osx" ) {
1240+ return " _" ~ name;
1241+ } else {
1242+ return name;
1243+ }
1244+ }
12111245}
0 commit comments