Live data from Hacker News

The Journey Before main()

amit.prasad.me

71–80 of 145 posts

Re: The Journey Before main()

#71
post #46

Earlier quoted context omitted.

I've always wondered why there weren't more popular loaders to choose from given that on Linux loaders are user-space

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.

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...

Re: The Journey Before main()

#72
post #68

Earlier quoted context omitted.

I'm sick of glibc compatibility problems. Are there any recommended replacements?

.interp to a glibc/libc you ship or static linking. These days it’s probably faster (in dev time) to just run a container than setting up a bespoke interp and a parallel set of libraries (and the associated toolchain changes or binary patching needed to support it).

Running a container is exactly my current solution as well.

Are there any other solutions that don't depend on glibc?

Re: The Journey Before main()

#74

Earlier quoted context omitted.

> some of it will only ever run on linux servers. I’ve spent quite a lot of time dealing with code that will ever run on Linux which did not in fact only ever run on Linux! Obviously for hobby projects anyone can do what they want. But adult projects should support Windows imho and consider Windows support from the start. Cross-platform is super easy unless you choose to make it hard.

> But adult projects should support Windows imho and consider Windows support from the start. Hope whatever "adult" is working on the project this is getting paid handsomely. They'd certainly need to pay me big bucks to care about Windows support. In any case, Linux system call ABI is becoming a lingua franca of systems programming. BSDs have implemented Linux system calls. Windows has straight up included Linux in t…

> Windows has straight up included Linux in the system. It looks like simply targeting Linux can easily result in a binary that actually does run anywhere.

Kind of. But not really. WSL2 is a thing. But most code isn’t running in WSL2 so if your thing “runs on windows” but requires running in a WSL2 context then oftentimes it might as well not exist.

> They'd certainly need to pay me big bucks to care about Windows support.

The great irony is that Windows is a much much much better and more pleasant dev environment. Linux is utterly miserable and it’s all modern programmers know. :(

Re: The Journey Before main()

#75
post #46

Earlier quoted context omitted.

I've always wondered why there weren't more popular loaders to choose from given that on Linux loaders are user-space

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 s…

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?

Re: The Journey Before main()

#76
post #37

Earlier quoted context omitted.

Not exactly the same, but on Windows if you use entirely Win32 calls you can avoid linking any C runtime library. Win32 is below the C standard library on Windows and the C runtime is optional.

This is one of the cornerstones that guarantee Windows can easily upgrade the C runtime and make performance and security upgrades. Win32 APIs have a different function calling ABI too. So only part of that gets "bloated" is Win32 API itself (which is spread across multiple DLLs and don't actually bloat RAM usage). Most of the time even those functions and structures are carefully designed to have some future-proofne…

> Glibc broke certain games / Steam by removing some parts of their ELF implementation: https://sourceware.org/bugzilla/show_bug.cgi?id=32653 . They backed due to huge backlash from the community.

It would be better if you specified which part was removed: support for executable code on stack. This is used in 99% cases by malware so it is better to break 1% of broken programs and have other 99% run safer.

Re: The Journey Before main()

#77

I wonder how many C projects prefer to avoid standard library, just invoking Linux syscalls directly. Much more fun to write software this way, IMO.

I think using syscalls directly is a worse idea than loading shared libraries, and new kernel features, like ALSA (audio playback), DRM (graphics rendering) and other use libraries instead of documenting syscalls and ioctls. This is better because it allows intercepting and subverting the calls, adding support for features even if the kernel doesn't support it, makes it easier to port code to other OSes, support different architectures (32-bit code on 64-bit kernel), and allows changing kernel interface without breaking anything. So Windows-style approach with system libraries is better in every aspect.

Re: The Journey Before main()

#78

Earlier quoted context omitted.

> some of it will only ever run on linux servers. I’ve spent quite a lot of time dealing with code that will ever run on Linux which did not in fact only ever run on Linux! Obviously for hobby projects anyone can do what they want. But adult projects should support Windows imho and consider Windows support from the start. Cross-platform is super easy unless you choose to make it hard.

> But adult projects should support Windows imho and consider Windows support from the start. Hope whatever "adult" is working on the project this is getting paid handsomely. They'd certainly need to pay me big bucks to care about Windows support. In any case, Linux system call ABI is becoming a lingua franca of systems programming. BSDs have implemented Linux system calls. Windows has straight up included Linux in t…

Try playing audio or displaying image on the screen using only documented syscalls. And make it work on all platforms you mentioned.

Re: The Journey Before main()

#79

As someone who teaches this stuff at university, I see students getting confused every single year by how textbooks draw memory. The problem is mostly visual, not conceptual. Most diagrams in books and slides use an old hardware-centric convention: they draw higher addresses at the top of the page and lower addresses at the bottom. People sometimes justify this with an analogy like “floors in a building go up,” so ad…

The stack does grow down though no matter what, in the sense that the pushing decrements the stack pointer. You can represent this as "up" in your diagram, but I don't think this makes it any easier conceptually because by analogy to a simple push/pop on an array, you'd naively expect higher addresses to contain more recent stack contents. The core of the issue is that the direction stack growth differs from "usual"…

Please try to draw, step by step, a process where lower addresses are at the top and higher addresses are at the bottom. You’ll see that this makes everything much easier to understand.

Do not confuse this with push and pop on an abstract stack data structure. That is not the same as the process stack. On a real process stack, newer data is stored at LOWER addresses. In fact, every push decrements the stack pointer (the address is decreased).

If you want an example, think about how a string is placed and accessed on the stack. First, the stack pointer is decremented to reserve space (so in my diagram this “moves up” visually). Then the string can be read byte by byte by incrementing an index from the lower address toward the higher address. This is exactly like reading a book: left to right, top to bottom. If you flip memory upside down, everything becomes unnatural to understand: you would have to read the string from the bottom to the top.

Try decompiling a program with Ghidra. Open the disassembly view and look at the addresses on the left. Lower addresses are shown at the top. Higher addresses are shown at the bottom. In my diagram this matches perfectly. Everything is consistent and you never have to mentally flip the memory layout.

Years of practice led me to this, not just theory.

Re: The Journey Before main()

#80
post #49

Earlier quoted context omitted.

> > split Glibc into 3 parts: syscalls, dynamic loader and the actual C library. > What is left of the C standard library, if you remove syscall wrappers? Still quite a bit actually. Stuff like malloc, realloc, free, fopen, FILE, getaddrinfo, getlogin, math functions like cos, sin tan, stdatomic implementations, some string functions are all defined in C library. They are not direct system calls unlike: open, read, w…

> malloc, realloc, free Wrapper around sbrk, mmap, etc. whatever the modern variant is. > fopen, FILE Wrapper around open, write, read, close. > stdatomic implementations You can argue, these are wrappers around thread syscalls. > math functions like cos, sin tan, some string functions are all defined in C library True for these, but they are so small, they could just be inlined directly, on their own they wouldn't n…

> malloc, realloc, free > Wrapper around sbrk, mmap, etc. whatever the modern variant is.

I don't think that's correct. While `malloc` uses `brk` syscall to allocate large memory areas, it uses non-trivial algorithms and data-structures to further divide that areas into smaller chunks which actually returned. Using syscall for every `malloc`/`free` is quite an overhead.

> fopen, FILE

> Wrapper around open, write, read, close.

They're not just wrappers. They implement internal buffering, some transformations (for example see "binary" mode, "text" mode.

> stdatomic implementations

> You can argue, these are wrappers around thread syscalls.

No, they're wrappers around compiler intrinsics which emit specific assembly instructions. At least for any sane architecture.

> I personally consider libc and the compiler (which both make a C implementation) to be part of the OS. I think this is both grounded in theory and in practice. Only in some weird middle ground between theory and practice you can consider them to not be.

C is used a lot in embedded projects. I even think that's the majority of C code nowadays. These projects usually don't use libc (as there's no operating system, so concept of file or process just doesn't make sense). So it's very important to separate C compiler and libc and C compiler must be able to emit code with zero dependencies.

Post reply on HN