Hacker News new | ask | show | jobs
by mbeddedartistry 1399 days ago
Please provide a source for a statically linked application on MacOS, Intel or otherwise. When I wrote this article, Apple's own documentation said it was not supported. libSystem is also only provided as a dynamic library.
4 comments

IMO it's worth distinguishing between what the OS allows and what the OS vendor supports. The macOS kernel still has a lot of FreeBSD heritage, including the ability to make direct syscalls, but Apple only guarantees compatibility for syscalls made via libSystem.

This is a reflection of historical differences in opinion about whether the stable ABI for an OS kernel should be the kernel itself (ala Linux), libc (ala Solaris or OpenBSD), or a language-agnostic library (Windows NT's ntdll).

macOS seems to be in a transition period toward the Windows model, with libSystem providing trampolines into the kernel. However, they don't yet enforce this model like OpenBSD does, so if you're willing to risk the syscall numbers changing you can do without libSystem.

Here's an example, lightly adapted from <https://john-millikin.com/unix-syscalls#darwin-x86-64>:

  .data
   .set L_STDOUT,        1
   .set L_SYSCALL_EXIT,  0x2000001
   .set L_SYSCALL_WRITE, 0x2000004
   L_message:
    .ascii "Hello, world!\n"
    .set L_message_len, . - L_message
  
  .text
   .global start
   start:
    # write(STDOUT, message, message_len)
    mov     $L_SYSCALL_WRITE, %rax
    mov     $L_STDOUT,        %rdi
    lea     L_message(%rip),  %rsi
    mov     $L_message_len,   %rdx
    syscall
  
    # exit(0)
    mov     $L_SYSCALL_EXIT, %rax
    mov     $0,              %rdi
    syscall
Compile (assemble?) it to a static binary:

  $ as -arch x86_64 hello.S -o hello.o
  $ ld -arch x86_64 -o hello -static hello.o
  $ file hello
  hello: Mach-O 64-bit executable x86_64
It runs fine:

  $ ./hello
  Hello, world!
Hey John,

Thanks for commenting. I had read your article via another comment here. I had not thought about the syscall approach before, because as you note Apple does not (well, did not previously) guarantee syscall stability.

Don’t.
Thanks. It is a clever approach. But at best all I can do is amend the original statement to "only dynamically linked applications are supported". Apple does not guarantee syscall stability (as is evident by Go's big break, and eventual move to libSystem).
Apple actually guarantees syscall stability of x86-64 applications :)
Believe me, I know: https://hn.algolia.com/?dateRange=all&page=0&prefix=true&que.... But with Rosetta Apple seems to have committed to the ABI now.
TIL! I hadn't come across this change of heart yet.
I thought "statically linked" just meant that all of the dependency binaries were rolled into the main executable at build time - how could macOS even stop you doing that?

I assume my understanding of static linking is too simplistic though.

On some OSes (Linux and macOS for example) a dynamically linked executable specifies the runtime linker as its “interpreter”, and the runtime linker contains the initial entry point that the kernel starts the process’s execution from. A statically linked executable is then one that doesn’t specify any interpreter at all, and which directly receives control from the kernel.

This distinction is related to but not the same as statically or dynamically linking an individual dependency; only if all dependencies are statically linked can an executable then be statically linked.

One dependency would be libc, which is typically how you would call into the OS using system calls. macOS has not typically supported a stable interface for these.