Do I get this right that this effectively dlopens glibc (indirectly) into an executable that is statically linked to musl? How can the two runtimes coexist? What about malloc/free? AFAIK both libc's allocators take ownership of brk, that can't be good. What about malloc/free across the dynamic library interface? There are certainly libraries that hand out allocated objects and expect the user to free them, but that's probably uncommon in graphics.
You have to tell musl to use mmap instead of brk. You're right that it doesn't work in all cases but as long as you switch TLS on calls (and callbacks), at least with a project the size of Godot, you can approach a workable solution.
> In an ideal world, there would be a header-only C library provided by the Linux kernel; we would include that file and be done with it. As it turns out, there is no such file, and interfacing with syscalls is complicated.
Nolibc, which is incorporated in the Linux kernel sources (under "tools"), contains generic wrappers for the Linux syscalls and a set of simplified implementations for the most frequently needed libc functions.
It is useful for very small executables or for some embedded applications.
It is not useful for someone who would want to use the Linux syscalls directly from another programming language than C, bypassing glibc or other libc implementations, except by providing models of generic wrappers for the Linux syscalls.
It also does not satisfy the requirement of the parent article, because it does not contain a table of syscalls that could be used for separate compilations.
Nolibc implements its functions like this:
long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
return my_syscall3(__NR_ioctl, fd, cmd, arg);
}
where the syscall numbers like "__NR_ioctl" are collected from the Linux kernel headers, because nolibc is compiled in the kernel source tree.
As explained in the parent article, there is no unique "__NR_ioctl" in the kernel sources. The C headers that are active during each compilation are selected or generated automatically based on the target architecture and on a few other configuration options, so searching for the applicable "__NR_ioctl" can be tedious, hence the value of the parent article and of a couple of other places mentioned by other posters, where syscall tables can be found.
Funny how you chose `ioctl` specifically to illustrate your point, when that's quite uniquely just a syscall inside a syscall… Ideally, high level library devs should abstract ioctl while treating libc as the stable userland kernel ABI, as has always been the case for the BSD's.
I think the real problem is GNU libc devs' unwillingness to stabilize it (not sure why, perhaps the menace of HURD still haunting them?)
I chose "ioctl" precisely because it has maximum simplicity, in order to show that in "nolibc" it needs externally provided syscall numbers.
Some other syscall wrappers from "nolibc" may be somewhat more complex, by doing some processing on the arguments, before invoking a generic syscall wrapper like "my_syscall3", "my_syscall5" etc. (where the number from the name of the generic syscall wrapper refers to the number of syscall arguments).
Ioctls are the single most complex example for API design, cause like, that's another opaque interface inside one opaque interface. Ioctls will be routed to the desired kernel module (driver) depending on the FD, after all.
Basically all I'm saying is that a syscall "ABI" is but a red herring for everyone but the [mainline] Linux devs themselves.
Java solved it by having exceptions be able to attach secondary exceptions, in particular those occurring during stack unwinding (via try-with-resources).
The result is an exception tree that reflects the failures that occurred in the call tree following the first exception.
reply