ELF Internals: Section Headers and Symbol Resolution
Understanding What Happens When You Run a Program
You’ve compiled thousands of programs, but have you ever wondered what happens between
gcc -o myappand that first function call? When you type./myapp, the kernel doesn’t just jump to main() – there’s a complex dance of symbol resolution, memory mapping, and relocation that happens first. Get this wrong, and you’ll spend your Saturday debugging “undefined symbol” errors in production.
The Linking vs. Loading Distinction That Matters
Here’s what trips people up: ELF files serve two masters. The linker (ld) cares about section headers – those .text, .data, .bss entries you see in
readelf -S. But at runtime? The kernel and dynamic linker only read program headers. You can strip all section headers from a binary (strip --strip-all) and it still runs perfectly because the loader uses PT_LOAD segments, not sections.Netflix learned this the hard way when debugging a custom allocator. Their LD_PRELOAD wrapper worked fine until they hit an IFUNC resolver (a modern glibc feature for CPU-specific optimizations). IFUNCs run during symbol resolution before the application’s constructors, so their malloc override hadn’t initialized yet. The resolver tried to allocate memory, found an uninitialized allocator, and crashed. The fix? Understanding that symbol resolution happens in multiple phases, and IFUNC resolvers execute earlier than you think.



