Guide to Linux System Calls (2016)(blog.packagecloud.io) |
Guide to Linux System Calls (2016)(blog.packagecloud.io) |
syscall should have a stable ABI at the very least, because this would otherwise break all statically linked code.
Ah, here we go: https://github.com/golang/go/issues/36435
> Upcoming changes to the OpenBSD kernel will prevent system calls from being made unless they are coming from libc.so (with some exceptions, for example, a static binary). There are also likely to be changes to the APIs used for system calls. As such, the Go runtime (and other packages) need to stop using direct syscalls, rather calling into libc functions instead (as has always been done for Solaris and now also for macOS).
(and the "with some exceptions" is why I say "strongly encouraged")
As mentioned below, on Windows syscalls are highly unstable. They change with every single update to the OS. You have to call functions in ntdll and they in turn will call the kernel. Think of it like a kind of libc but one that must be dynamically linked. You can't statically link it because it's tied to the exact version of Windows you're using.
Of course Window's actual stable interface is the Win32 API, which will call ntdll which in turn makes the syscall.
I was recently working on generating some assembly language output and I added the ability to generate a breakpoint at the start of my executable.
It took me an embarassingly long time to realize that the reason my executables were crashing, not dropping into the debugger, was that "INT3" was assembled differently than "INT 03h" - I knew I needed 0x03, and I knew it was the one-byte form of the instruction (0xCC) rather than (0xCD 0xNN), to ease patching, but .. yeah.
Why?
On non-POSIX OSes like NT and plenty of others, libc is part of whatever compiler one decides to use and as such not part of any OS interface as such.
On NT the stable OS APIs are provided via the OS personalities, meaning OS/2 (dead now), the old POSIX one (also dead and replaced by WSL), and Win32 (actually User, Kernel, GDI as the main ones), which as of Windows 8 and MinWin refactoring is split into redirection dlls know as API sets, https://docs.microsoft.com/en-us/windows/win32/apiindex/wind....
Which is why on code that never intends to be portable, you will see calls like ZeroMemory instead of memset.
EDIT: Found https://web.archive.org/web/20121224002314/http://netcode.cz... which if I'm reading right indicates that ntdll is indeed the bottom-layer library that's allowed to actually talk to the kernel.
The personality DLLs are the applications entry point with the kernel.
ucrt is available on all modern version of Windows (since 7) and doesn't need to be statically linked or distributed with the application. It has most functions needed for the c runtime and library.
vcruntime comes with Microsoft's C/C++ compiler. It has functions such as longjmp, memcpy, memset etc and C++ exception handlers. This does not come with Windows. It can be installed separately by the user or distributed with the application (either by placing it the same folder as the exe or by statically linking).
That's a bit annoying, especially since you're already using raw syscall numbers anyways. Here's how to make it static:
.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
Compile that with clang -static -nostdlib. ld -arch x86_64 -o hello hello.o -macosx_version_min 10.8 -static -e _main
is sufficient if you're determined to violate the OS vendor's compatibility requirements.