Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> C is the de facto standard for interacting with anything not written in your language.

Not necessarily. C is how your language interacts with the OS if you use the OS's C library. But not all languages do. Go doesn't.

The only thing you have to do to interact with the OS is make system calls. You can do that without going through the C library. It might be a PITA to do it if you're not working on Go for Google, but if that's the real problem, that's what the author of this article should have complained about. (It's actually less of a PITA on Linux because the syscall interface is implemented using software interrupts. Windows is more of a PITA because the OS goes out of its way to make its syscall interface look like a C interface.)



> The only thing you have to do to interact with the OS is make system calls. You can do that without going through the C library.

If by "the OS" you mean "Linux". On Windows, calling syscalls is explicitly unsupported and Microsoft will break you mercilessly by changing syscall IDs between versions. On macOS and iOS, libSystem.dylib is the only supported way to call syscalls; syscalls are SPI and Apple will break you if you try to call them directly. BSDs likewise discourage you from calling syscalls.

The "syscalls are stable API" principle that Linux is famous for is a weird Linux-specific thing; other OS's don't do it.


Not since Windows Server 2022 and Windows 11.

To enable the same kind of container image portability between kernel versions that Linux has, Microsoft has decided to stabilise the kernel syscall ABI.


I'd like to read more about this. Do you have additional resources that you can link to?


> C is how your language interacts with the OS if you use the OS's C library. But not all languages do. Go doesn't.

...on Linux. Pretty much everywhere else, libc is the way to interact with the kernel; even Go goes through libc on ex. Darwin and OpenBSD, because Linux presenting a stable kernel ABI is actually pretty unusual.


>.. libc is the way to interact with the kernel..

On UNIX clones, written in C.

Win32 isn't libc, nor the mainframes ones are (language environments), or Android (Java)/ChromeOS(Brower APIs).


> Win32 isn't libc,

I'm less familiar with the Microsoft ecosystem, but I'm pretty sure it is; Microsoft named their libc MSVCRT.DLL, but it's still the canonical system ABI, and NT, AIUI, actively shuffles system calls between builds to prevent people even trying to use them directly.

The rest, and your general point, are fair, though; there's nothing preventing the creation of a system that doesn't work like this.


No, msvcrt.dll isn't the system ABI. It's officially not even part of the OS and you aren't supposed to rely on it existing. Kernel32.dll is the primary entry point for OS things, and it's distinctly not a libc.


MSVCRT is short for "Microsoft Visual C (++) Run Time".

It is not an API to the OS.


> Linux presenting a stable kernel ABI is actually pretty unusual.

Did you mean "portable"? Because the ABI to the Linux kernel system calls is very stable. Literally the 32-bit syscall interface has not changed (except by addition) in 30 years.

The darwin kernel is also pretty stable, except Apple moves so fast from one architecture to the next that they drop support for old ISAs pretty fast. I predict they'll drop support for x86 altogether in ~5 years.


> Did you mean "portable"? Because the ABI to the Linux kernel system calls is very stable.

I think the GP meant that the Linux syscall ABI is indeed very stable and always has been, as you say, but that the syscall ABI of other OSs is not. So Linux is "unusual" in that sense, not in the sense that its syscall ABI is stable now but wasn't in the past.


Sorry, yes, I misunderstood the comment.

AFAICT, SunOS (Solaris), BSD, and Darwin have stable kernel ABIs for the core (UNIX) system calls. I've never used the Mach syscalls on Darwin, but I can imagine those changing more often, because Apple does that. I would imagine that Windows supports 32-bit syscalls still pretty well...but I stopped using Windows in 2002, so tbh, not sure.


Darwin has always explicitly not had a stable kernel ABI (https://developer.apple.com/library/archive/qa/qa1118/_index...). Go tried to bypass the system libraries on macOS and it resulted in things breaking, so now they do use system libraries (https://github.com/golang/go/issues/17490).


I have a very different understanding of the situation; the best description of the situation I can find is https://utcc.utoronto.ca/~cks/space/blog/programming/Go116Op... (discussed at https://news.ycombinator.com/item?id=25997506 ) - from that article,

> The official API for Illumos and Solaris system calls requires you to use their C library, and OpenBSD wants you to do this as well for security reasons (for OpenBSD system call origin verification). Go has used the C library on Solaris and Illumos for a long time, but through Go 1.15 it made direct system calls on OpenBSD and so current released versions of OpenBSD had a special exemption from their system call origin verification because of it.


read is unlikely to change anytime soon on macOS but Apple can and does change its numbering for lesser-used but still very important system calls all the time.


They also change the syscall abi without touching the numbering. gettimeofday(2) is a pretty famous one there.

Then there’s also the Linux-specific issue of vDSO, which are not kernel code and to which the article applies in full (see: “debugging an evil ho runtime bug”).


As sibling comment notes, yes Linux has a stable ABI, and amongst all operating systems that is incredibly rare.


Even Go gave up and switched to using libc for OpenBSD[1]. You can use syscalls on Linux because Linux, lacking a blessed libc implementation, guarantees stability of syscalls as an interface. The BSDs, afaik, do not, so circumventing libc is liable to render your binary forwards-incompatible with future kernel versions.

[1] https://go.dev/doc/go1.16#openbsd


> The BSDs, afaik, do not,

That isn't just about the lack of guaranteed stability, as far as I understand it is considered a security feature. System calls that are not made through the libc may be actively blocked. So an attacker can't just use an exploit to inject a system call into a process, the call has to pass through the libc wrapper and in combination with ASLR that wont be trivial.


A better way of accomplishing this would have been to randomize the syscall numbers on a per-process basis, and map a "syscall number translation table" into the process when loading the executable.


Again, there's more than the OS kernel that a programming language will need to interact with. You don't go through syscalls to make an X11 window or read keyboard/mouse inputs or draw graphics. There are thousands of utilities that are meant to be usable cross-language, but in actuality use the C ABI (well, at least one of the 176 C ABIs there are).


>> C is the de facto standard for interacting with anything not written in your language.

> Not necessarily. C is how your language interacts with the OS if you use the OS's C library. But not all languages do. Go doesn't.

Go doesn't interact with anything written in a different language? I find this really hard to believe - it would result in Go not having a GUI library, not being able to use PostgreSQL, not being able to start external processes (like shells), etc.

I'm pretty sure that Go can do all those things, hence Go does interact with libraries written in a different language.


> Go doesn't interact with anything written in a different language?

That's not what I said. I said Go doesn't interact with the OS using the OS's C library. But, as others have pointed out, that's only true on Linux.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: