|
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!
|
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.