Binutils & Binary Validation
GNU binutils and ELF tooling for CI/CD: inspect symbols, verify architecture and ABI, check shared-library dependencies, and validate C, C++, and Python artifacts before they ship.
Overview
Overview GNU binutils is the toolchain layer beneath gcc and clang - the utilities that read, transform, and validate compiled artifacts: object files, static archives (.a), shared libraries (.so), and executables. On a C, C++, and Python build farm (CUDA libraries, EDA and firmware pipelines at companies like NVIDIA, AMD, and ASML), these tools are the CI gates that catch a bad binary before it reaches a GPU node or a customer image - wrong architecture, missing symbols, an ABI mismatch, a leaked debug build, or a shared library that will fail to load at runtime.
The Core Tools - readelf - the authoritative ELF reader: header, sections, dynamic table, symbol versions. Never executes the file, so it is safe on untrusted binaries. - objdump - disassembly, section dumps, relocations, and the dynamic symbol table (objdump -T). - nm - list symbols in an object, archive, or shared library; nm -D reads dynamic symbols, nm -C demangles, nm -u shows undefined. - ldd - print shared-library dependencies by asking the dynamic loader to resolve them. - ldconfig - refresh the shared-library cache (/etc/ld.so.cache) and search paths. - ar and ranlib - create, list, and index static archives. - strip - remove symbol and debug information to shrink release binaries. - strings - extract printable text (leaked paths, version tags, secrets). - c++filt - demangle C++ symbol names, turning _ZN3fooEv into foo(). - addr2line - map a crash address back to file and line using debug info. - objcopy - convert binaries, split debug info, add or remove sections. - file - identify type, architecture, and linkage of any artifact in one line. - patchelf - edit an existing binary in place: RPATH, interpreter, or SONAME.
ELF Anatomy An ELF file has an ELF header (class, endianness, machine, type), program headers (the segments the loader maps), and section headers such as .text, .data, .bss, .symtab, .dynsym, and .dynamic. Dynamic executables and shared objects carry a .dynamic section that lists NEEDED libraries, the SONAME, RPATH or RUNPATH, and symbol-version tables. Almost every validation you run maps to reading one of these structures.
CI/CD Validation Gates A pipeline usually checks, in order: architecture and ABI (readelf -h, file), required libraries present (readelf -d, ldd), no unresolved symbols (nm -D, ldd -r), the glibc symbol-version floor (objdump -T), hardening flags (RELRO, stack canary, NX, PIE), and that release artifacts are stripped and carry no secret strings.
Key concepts
- readelf
- Reads ELF structure without executing the file. readelf -h shows class and machine (architecture), readelf -d shows the dynamic table (NEEDED, SONAME, RPATH), readelf --dyn-syms lists exported symbols, and readelf -l shows segments and GNU_RELRO. The safe first tool for untrusted binaries.
- nm
- Lists symbols. nm reads the static symbol table, nm -D reads dynamic symbols of a shared object, nm -C demangles C++, and nm -u lists undefined symbols. In the output, U is undefined, T is a defined text symbol, and W is weak.
- objdump
- objdump -d disassembles, objdump -T prints the dynamic symbol table with version tags, objdump -x dumps all headers, and objdump -R shows relocations. objdump -T piped through grep GLIBC reveals the minimum glibc version a binary requires.
- ldd vs readelf -d
- ldd prints resolved shared-library dependencies but can execute code in an untrusted binary, so for inspection prefer readelf -d or objdump -p, which only read the file. Use ldd on trusted builds to confirm every NEEDED library actually resolves.
- strip and separate debug
- strip removes .symtab and debug sections to shrink a release binary. Once stripped, addr2line can no longer symbolize crashes, so save debug first with objcopy --only-keep-debug and link it back with --add-gnu-debuglink.
- c++filt and mangling
- C++ encodes namespaces and argument types into symbol names (mangling). An undefined symbol like _ZN3fooEv looks unrelated until demangled with c++filt (or nm -C) into foo(). Always demangle before matching a missing symbol to its source.
- symbol versions
- glibc tags symbols with versions such as GLIBC_2.34. A binary that references a newer version will not run on a host with older glibc even when the library file exists. Check the required floor with objdump -T | grep GLIBC before deploying across distros.
- RPATH and patchelf
- RPATH and RUNPATH embed library search paths into a binary. When a relocated artifact cannot find its .so files, patchelf --set-rpath or patchelf --set-interpreter fixes the binary in place without rebuilding, and ldconfig -p confirms what the loader cache resolves.
When to use it
- A shared library or Python C-extension fails to import at runtime with an undefined-symbol error
- Gating CI so a binary built for the wrong architecture or ABI never reaches a GPU or FPGA node
- Verifying a release build was stripped and does not leak debug paths, symbols, or secret strings
- Confirming a binary built on a newer distro will still run on the older glibc of the deploy target
- Auditing a static archive or shared object for the exact symbols a downstream component expects
Interview questions
- A Python C-extension (.so) fails to import with "undefined symbol: _ZN6caffe28TypeMeta...". How do you diagnose and fix it in CI?
- How do you gate a CI pipeline so an artifact for the wrong architecture or ABI never reaches a GPU node?
- At runtime a service dies with "error while loading shared libraries: libfoo.so.3: cannot open shared object file". Walk through the fix.
- How do you verify in CI that a release binary is stripped and leaks no debug paths or secrets?
- A binary built on Ubuntu 22.04 crashes on RHEL 8 with a "GLIBC_2.34 not found" error. How do you catch and prevent this?
- How do you validate a static archive (.a) and confirm hardening flags on a shipped binary?
Sign up free to read the full topic
More Linux topics
Start free on Cariara · Coding problems · System design studio