Timeline for Why do common Rust packages depend on C code?
Current License: CC BY-SA 4.0
27 events
when toggle format | what | by | license | comment | |
---|---|---|---|---|---|
Dec 3, 2023 at 15:08 | comment | added | Matheus Moreira | "On Linux, one can perhaps quibble with this (though I still think it would be quite ill-advised)" For those who would enjoy quibbling with this, I have written somewhat at length about it on my website. Linux system calls are stable and can be safely used directly. "it is the intended mechanism by which every programming language in existence calls into your operating system" Not every language. I created a lisp interpreter with builtin syscall support. Go also does it. There are more examples but I'm running out of characters :) | |
Dec 2, 2023 at 22:00 | vote | accept | StoneThrow | ||
Nov 28, 2023 at 12:24 | comment | added | Austin Hemmelgarn |
@StoneThrow And even aside from the OS kernel ABI, there are quite a few things that libc makes significantly easier to work with. For example, on Linux, system call numbers vary based on what CPU architecture you’re on (as an example, read is 0 on 64-bit x86, 3 on 32-bit ARM, and 63 on 64-bit ARM). libc hides all of that cleanly though, so you don’t need to care as long as you’re only calling things it supports. A lot of other languages take advantage of that (among other things) when running on Linux, even if they are not inherently tied to C.
|
|
Nov 28, 2023 at 12:12 | comment | added | Austin Hemmelgarn | @StoneThrow Historically, there were systems that provided interfaces other than the C ABI as the primary or only ABI. Prominent examples include Lisp machines from various vendors, WD’s Pascal MicroEngine, and the Java Card platform. But the C ABI is what UNIX and Windows systems provide these days, so that’s what software that runs on those platforms has to use. Even if you use assembly code to make a system call on Linux, you’re still using C calling conventions and the C ABI to make the call, because that’s the only way you can make the call. | |
Nov 28, 2023 at 5:21 | comment | added | Peter Cordes |
A C ABI doesn't have to define anything only C++ needs, like conventions for vtable layout. A C++ ABI does that on top of a C ABI; for example g++ uses what's called the "Itanium C++ ABI" across most (all?) platforms as its convention for name-mangling, vtables, how try/catch exception blocks find each other, and when by-value args can actually be passed by value in registers vs. when they actually get passed by pointer in terms of the C ABI so the object always has an address. (something like non-trivially-copyable)
|
|
Nov 28, 2023 at 5:18 | comment | added | Peter Cordes | Re: "C ABI" even though ISO C doesn't define an ABI: The way to read that term is that it's an ABI that supports C, making compatible C implementations possible. A C ABI defines all the functionality needed by C, but usually not much more. e.g. it defines how to call functions with a fixed signature or C-style variadic, and to return one value, possibly an aggregate. And sizes / alignments for the C primitive types. You can have multiple ABIs on a platform, like AArch64 64-bit vs. ILP32. Or some embedded platforms like ARM Linux have had a few different ABIs, not binary compatible. | |
Nov 28, 2023 at 4:15 | comment | added | StoneThrow | @AustinHemmelgarn - I wonder if I might be able to nudge you to expand your comment on the historical/modern aspect into an answer. I know extended chats are discouraged, but my curiosity is piqued by your statement that "if you were to try to use Free Pascal’s runtime libraries in place of libc for your tools, you’d still be making C ABI calls to the OS itself, if not calling into the platform’s libc routines" -- I don't fully understand why: I thought the point of Pascal's runtime libraries would be to be outright equivalent to libc, i.e. offer their own syscall implementation, etc. | |
Nov 28, 2023 at 0:33 | comment | added | Alex Jasmin | On Windows, Microsoft now maintains portable API descriptions (winmd) for Win32, COM and WinRT. The official Rust bindings for Windows are generated from these. | |
Nov 27, 2023 at 23:57 | comment | added | Austin Hemmelgarn | @StoneThrow Historically yes. In modern times no though. You can’t get away from the calling conventions of the OS kernel as long as you’re using an OS, and pretty much all of them use C, C++, or some close equivalent these days. So, for example, if you were to try to use Free Pascal’s runtime libraries in place of libc for your tools, you’d still be making C ABI calls to the OS itself, if not calling into the platform’s libc routines. | |
Nov 27, 2023 at 8:35 | comment | added | Matthieu M. | To add to the list of OSes: OpenBSD is considering restricting syscalls to libc (its own, obviously) for security reasons. The security aspect, as I understand it, being that it's easier to craft a syscall than it is to craft a call to a function from an ASLR loaded libc, and therefore mandating going through libc will make exploits more difficult to perform. | |
Nov 27, 2023 at 8:21 | comment | added | MSalters |
@StoneThrow: Yes, on UNIX and similar systems (such as non-Android Linux). But no, on Windows and Android. Windows is especially interesting because its COM API's are thinly disguised C++ API's.
|
|
Nov 27, 2023 at 1:08 | comment | added | StoneThrow | Is it fair for me to summarize that (nearly) all programming languages' runtimes ultimately have a reliance on libc to make system calls, because libc has already implemented all the ugly/difficult/low-level work of making those system calls, e.g. which registers are used to pass values? I gather from other commenters that there are "equivalents" to libc, written in other languages like Pascal, so presumably programming language implementers could choose to "call out" to the Pascal-equivalent-of-libc if they had a foreign-function interface to Pascal? | |
Nov 27, 2023 at 0:29 | comment | added | Chris Dodd |
Old Windows was also more Pascal based than C based -- this shows up in calling conventions with cdecl vs stdcall . C mostly came into the picture with the dominance of UNIX.
|
|
Nov 26, 2023 at 23:42 | history | edited | Alexis King♦ | CC BY-SA 4.0 |
deleted 7 characters in body
|
Nov 26, 2023 at 23:35 | history | edited | Alexis King♦ | CC BY-SA 4.0 |
deleted 5 characters in body
|
Nov 26, 2023 at 23:22 | history | edited | Alexis King♦ | CC BY-SA 4.0 |
deleted 14 characters in body
|
Nov 26, 2023 at 23:16 | comment | added | user71659 | Funny you mention macOS because that was the huge exception. Classic macOS was not C-based, but Pascal. The Carbon API made it more C-friendly, but most functions utilized Pascal calling, as it was needed for Macintosh Toolbox, and Pascal strings were everywhere. Carbon was finally removed in macOS 10.15 (2020). | |
Nov 26, 2023 at 23:03 | history | edited | Alexis King♦ | CC BY-SA 4.0 |
added 1 character in body
|
Nov 26, 2023 at 23:00 | comment | added | Alexis King♦ | @StoneThrow Essentially: yes. | |
Nov 26, 2023 at 22:31 | comment | added | StoneThrow | @AlexisKing -- I apologize for the extended chat, I know it's frowned upon, but this Q&A has revealed many enticing rabbit holes to explore. My question was perhaps a bit more primitive than you might have interpreted: in this context, does the word "runtime" mean "stuff the language provides during the program's time of execution that was not explicitly written by the coder"? E.g. garbage-collection, from, maybe, languages like Go...the coder doesn't explicitly garbage-collect, but the language provides it -- is that, then, (part of) the language's "runtime"? | |
Nov 26, 2023 at 22:17 | comment | added | Alexis King♦ | @StoneThrow I think that getting into that is largely out of scope for this answer, but essentially: if you have a runtime, then that runtime can always be used to assist with making calls. For example, if the language is garbage collected (using a stop-the-world collector), there fundamentally must be some way for the program to temporarily stop executing and allow the GC to do its work. This is known as “yielding to the runtime”, and that same mechanism can be used to request that the runtime make a call on the program’s behalf. | |
Nov 26, 2023 at 22:14 | comment | added | StoneThrow | ...also, I got a little lost in the sentence "...a compiled language that uses its own binary object format and does its own linking and loading and has its own runtime can largely get away with not knowing how to generate code that calls into C code because a C call can always yield to the runtime’s scheduler, which is written in a language that knows how to perform the call into C" -- could you either expand on that, or maybe bring that description one step closer to lay terms? I didn't quite understand "yield[ing] to the runtime's scheduler" and what entity makes the call into C thereof...? | |
Nov 26, 2023 at 22:14 | history | edited | Alexis King♦ | CC BY-SA 4.0 |
added 9 characters in body
|
Nov 26, 2023 at 16:26 | comment | added | Joshua | "There will always be people who quixotically struggle to avoid depending on the C toolchain at all costs, but doing so is essentially hopeless." I've got some projects where this was most expedient. Recent cases involved tools to repair fundamental damage to the C userspace infrastructure, so not using it was essential to getting the job done. Yes, this meant looking up the syscall ABI and invoking it directly. | |
Nov 26, 2023 at 13:39 | comment | added | ilkkachu | (re. "C does not specify an ABI, nor is it really defined at the level that would allow specifying one"), C (the standard library) does pretty much define the storage format for strings, though, and that does end up as part of the ABI for any OS calls that expect e.g. a filename from the caller. | |
Nov 26, 2023 at 7:41 | history | edited | Alexis King♦ | CC BY-SA 4.0 |
added 1 character in body
|
Nov 26, 2023 at 7:35 | history | answered | Alexis King♦ | CC BY-SA 4.0 |