HelloSilicon icon indicating copy to clipboard operation
HelloSilicon copied to clipboard

Opting out of libc on Apple Silicon

Open saagarjha opened this issue 3 years ago • 7 comments

Embedded platforms don't do static. However, if you're still curious here's how you can convince Xcode to make those files:

diff --git a/AsMain/main.s b/AsMain/main.s
index 953236a..61760cd 100644
--- a/AsMain/main.s
+++ b/AsMain/main.s
@@ -6,12 +6,11 @@
 // X16 - Mach function number
 //
 
-.global _main	            // Provide program starting address to linker
+.global start	            // Provide program starting address to linker
 .align 2
-
 // Setup the parameters to print hello world
 // and then call Linux to do it.
-_main: mov	X0, #1	    // 1 = StdOut
+start: mov	X0, #1	    // 1 = StdOut
     adr	X1, helloworld // string to print
 	mov	X2, #13	    // length of our string
 	mov	X16, #4	    // linux write system call
diff --git a/MacAs.xcodeproj/project.pbxproj b/MacAs.xcodeproj/project.pbxproj
index 11b501e..f95d6bd 100644
--- a/MacAs.xcodeproj/project.pbxproj
+++ b/MacAs.xcodeproj/project.pbxproj
@@ -318,6 +318,8 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				CODE_SIGN_STYLE = Automatic;
+				LINK_WITH_STANDARD_LIBRARIES = NO;
+				OTHER_LDFLAGS = "-static";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 			};
 			name = Debug;
@@ -326,6 +328,8 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				CODE_SIGN_STYLE = Automatic;
+				LINK_WITH_STANDARD_LIBRARIES = NO;
+				OTHER_LDFLAGS = "-static";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 			};
 			name = Release;
Screen Shot 2020-07-04 at 19 50 03

If you put an underscore in front of main in both places and give up on static linking:

Screen Shot 2020-07-04 at 19 51 31

saagarjha avatar Jul 05 '20 02:07 saagarjha

That's cool to know! Although now that I have solved the issue of in the makefile, I will continue to work on that!

below avatar Jul 05 '20 11:07 below

I lied, that code is likely outdated/not complete. I know of at least one statically linked binary running.

saagarjha avatar Jul 06 '20 06:07 saagarjha

I lied, that code is likely outdated/not complete. I know of at least one statically linked binary running.

Most interesting, the documentation I could find is also that Mach-O doesn't do static binaries.

That said, currently I am happy as long as I can easily build and deploy assembler source from the command line, and I might come back to the issue of building a Mach-O binary later ;)

below avatar Jul 06 '20 07:07 below

Oh, no, Mach-O totally does static binaries. In fact, here's how to make one you can run on your Intel machine:

$ clang -x assembler-with-cpp -static -nostdlib -
.intel_syntax noprefix

#include <sys/syscall.h>

#define UNIX_SYSCALL 0x2000000

.globl start
start:
	mov rax, UNIX_SYSCALL | SYS_write
	mov rdi, 1
	lea rsi, text[rip]
	lea rdx, length
	syscall
	mov rax, UNIX_SYSCALL | SYS_exit
	xor rdi, rdi
	syscall

text:
.asciz "Hello, world!\n"
.equ length, . - text
$ ./a.out
Hello, world!

saagarjha avatar Jul 06 '20 16:07 saagarjha

Most interesting! Any idea why the documentation would claim such a thing?

below avatar Jul 06 '20 18:07 below

System call numbers on macOS are not stable, so Apple would like you to go through libc. Go used to create static binaries on macOS but they would constantly break whenever an update came out, so they've starting linking against the system libraries. The only reason you should be making system calls yourself is curiosity or if you have an extremely good reason that you cannot link against libSystem ;)

saagarjha avatar Jul 06 '20 18:07 saagarjha

Oh, no, Mach-O totally does static binaries. In fact, here's how to make one you can run on your Intel machine:

While you can create static binaries, the macOS kernel (XNU) allows the execution of static binaries on x86_64 only (or with debug kernels, which probably nobody outside Apple is using). On all other platforms (ARM64), the kernel enforces that an executable must use the dynamic linker (this was already linked to in the issue above). It's a restriction that cannot be bypassed. However, you can create a dynamically linked executable and simply not link to any library/framework.

DarkDust avatar Feb 03 '24 11:02 DarkDust