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

It is not just compatibility. You cannot load them into the memory with your system dynamic loader. You need to also ship ld-linux.so with the new version of glibc you have, if you were to distribute your program independently.

On Windows you don't need to ship a new binary loader. I can just ship Windows 10 UCRT DLL (which is the new libc of Windows) to Vista and my binaries will work. The binary loader isn't interlinked with the libc.



Windows doesn't even have a concept of a loader binary right? I think its hardcoded into the kernel/win32 itself.


Windows loader is part of the system ABI, and programs' libc(s) are loaded by it.

One of the ways Windows manages to support multiple libc's is by being careful not to mix allocators; if a system API you call allocates on your behalf, your libc can't free it, the system API will offer a function to free it.

Windows loader is certainly available to user programs though; LoadLibrary has been around longer than many developers.


LoadLibrary will also not be able to load arbitrary libraries compiled for newer versions of Windows though. Just like with gcc, Windows also does not guarantee forwards compatibility - because that would men freezing the feature set the system libraries provide.


Windows handles this much better than any other OS. The API passes versions (== structure sizes on the calling side), and WinAPI can handle that.

As for older Windows systems not being able to load new DLLs, they can; the format hasn't changed in a very long time. I've had experience with installing some DLLs on Windows NT 3.51 and running a modern Firefox, which is about 20 years behind the times.


Targeting an older version of Windows is "set a define so that the system headers don't expose functions that didn't exist on older Windows". You don't need an old toolchain to target old systems, you ask the newer toolchains to target it.

MS haven't made this work arbitrarily far back, I believe they deprecated targeting Windows XP in one of the more recent toolchains, but that was purely a "not worth supporting" situation.

EDIT: mixed up talking about older & newer


It kind of does but in a "it is an implementation detail that you cannot access and it doesn't matter" sense. Unlike ELF, PE32+ files do not have an "interpreter" that you can specify.

csrss.exe handles some of the loading functionality: https://en.wikipedia.org/wiki/Client/Server_Runtime_Subsyste...


Why? If you compile your program against an older glibc it will run on newer glibc. glibc is the loader.


Why? What kind of single-responsibility-principle that predicates the C standard library to become the both syscall interface and the binary loader as well?

What happened to the Unix principle "do one thing and do it well"? Windows solved this quite modularly and it works perfectly well.

Glibc is terribly designed and it is the core component of almost any Linux userspace app today. Let's not try to find excuses for horrible designs.


I don't disagree that the loader and the libc should be decoupled, but it's not as simple a split as you're making it out to be.

The reason they're tightly coupled is because there needs to be a bridge between Sys-V ELF ABI and the C runtime, and it makes sense for the implementation of that bridge to use libc itself which means special-casing the bootstrapping of libc during program loading.

glibc isn't unique here btw - musl libc ships its own loader that does the exact same thing as rtld (parse auxv/envp off the stack, relocate itself and load libc, initialize the CRT, then load the rest of the program's SOs in order).

Even if they were fully decoupled it is not unreasonable for software targeting newer versions of an operating system to only run on that version or later. Linux is actually the outlier here where the syscall interface is stable enough to make this a non-obvious problem.

There's a universe where you can load multiple versions of the same libc into the same address space but that isn't ELF, and it's not common. aiui the only reason PE can support e.g. multiple versions of malloc/free in the same executable is due to two level namespaces in symbol relocation tables.

---

edit: another observation is that for a functioning ELF loader you basically need a three stage bootstrap. Stage one parses the stack passed by the kernel and performs self-relocation. You need that to make non-static function calls and read/write global variables. Stage two loads libc and initializes the CRT with stuff like environment variables, aux vector, any dso for syscalls passed by the kernel, etc. That has to coupled because POSIX specifies stupid stuff like "getenv" and "argv" requires the loader to know how to move from the stack passed by the kernel to the memory reserved by the CRT that gets used by the final executable. Finally in stage 3 it can relocate and load shared objects and run any constructor functions pre-main, before jumping to start where the precompiled CRT start (then jump to main goes).

So if you want an ELF loader on Sys-V you probably need to couple the loader to the libc, just for libc to work at all. Unless you want to specify a bunch of behavior and binary layout in the C standard.

None of this is designed by glibc, it's the simplest way to go from exec to main.




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

Search: