upvote
Yeah it turns out the kernel doesn't care about sections at all. It only ever cares about the PT_LOAD segments in the program header table, which is essentially a table of arguments for the mmap system call. Sections are just dynamic linker metadata and are never covered by PT_LOAD segments.

This seems to be a common misconception. I too suffered from it once... Tried to embed arbitrary files into ELF files using objcopy. The tool could easily create new sections with the file contents just fine, but the kernel wouldn't load them into memory. It was really confusing at first.

https://stackoverflow.com/q/77468641

There were no tools for patching the program header table, I ended up making them! The mold linker even added a feature just to make this patching easy!

https://www.matheusmoreira.com/articles/self-contained-lone-...

reply
I've always wondered why there weren't more popular loaders to choose from given that on Linux loaders are user-space
reply
With containers, you usually get incompatible dynamic loaders in the containers (see mananaysiempre' comment; the glibc dynamic linker sees rather active development in some LTS distributions). This wouldn't be possible if the loader were part of the kernel.

Non-ELF loaders are fairly common, too. It's how Wine works, and how Microsoft reuses PE/COFF SQL Server binaries on Linux.

reply
There's also binfmt support, which can check a supposedly executable file against some magic and auto-launch an interpreter (like wine or java or dosemu). I looked into it for something once but in my case the magic wasn't good enough.

https://www.kernel.org/doc/html/latest/admin-guide/binfmt-mi...

reply
Its super awesome for qemu. It let's you chroot into a arm root (full of arm binaries) on you x86 machine and just run it like normal. No VM required.
reply
Part of it is the Glibc loader’s carnal knowledge of Glibc proper; there’s essentially no module boundary there. (That’s not completely unjustified, but Glibc is especially hostile there, like in its many other architectural choices.) Musl outright merges the two into a single binary. So if you want to do a loader then you’re also doing a libc.

Part of it for desktop Linux specifically is that a lot of the graphics stack is very unfriendly to alternative libcs or loaders. For example, Wayland is nominally a protocol admitting multiple implementations, but if you want to not be dumb[1] and do GPU-accelerated graphics, then the ABI ties you to libwayland.so specifically (event-loop opinions and all) in order to load vendor-specific userspace drivers, which entails your distro’s preferred libc (probably Glibc).

[1] There can of course be good engineering reasons to be dumb.

reply
Why do you need "vendor-specific userspace drivers"? I thought graphic acceleration uses OpenGL/Vulkan, and non-accelerated graphics uses DRM? And there are no "drivers" for Wayland compositors?
reply
OpenGL and Vulkan are implemented as libraries in user space as the Mesa project.
reply
I suspect it is because they get really hairy.

Loading ELFs and processing relocations is actually not too bad. It’s fun after the initial learning curve.

Then one has to worry about handling of “dlopen” and the loader creating the data structures it cares about. Yuck!!!

It’s kinda a shame because the glibc loader is a bit bloated with all the audit and preload handling. Great for flexibility, not for security.

reply
It's hard to describe how complex this stuff is. Shared object loaders are essentially primitive package managers, topologically sortinf dependencies and everything...

https://blogs.oracle.com/solaris/post/init-and-fini-processi...

reply
You’re right, and I knew this back in February when I wrote most of this post. I must have revised it down incorrectly before posting; will correct. Bit of a facepalm from my side.
reply