
Elf Inspection
- 348 installs
- 155 repo stars
- Updated June 27, 2026
- mohitmishra786/low-level-dev-skills
Inspect ELF binaries and shared libraries to debug crashes, verify symbols, audit dependencies, and diagnose loader failures before or after release on Linux systems.
About
Explains how to read and interpret ELF executables and shared objects: segments, sections, dynamic linking metadata, and symbol visibility. Enables engineers to triage loader errors and audit native dependencies in CLI and server releases.
- readelf and objdump workflows
- Dynamic section and relocation tables
- Symbol tables and demangling
- DT_NEEDED dependency graphs
- PIE, RELRO, and hardening flags
Elf Inspection by the numbers
- 348 all-time installs (skills.sh)
- +23 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #116 of 596 Debugging skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/mohitmishra786/low-level-dev-skills --skill elf-inspectionAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 348 |
|---|---|
| repo stars | ★ 155 |
| Last updated | June 27, 2026 |
| Repository | mohitmishra786/low-level-dev-skills ↗ |
What it does
Inspect ELF binaries and shared libraries to debug crashes, verify symbols, audit dependencies, and diagnose loader failures before or after release on Linux systems.
Files
ELF Inspection
Purpose
Guide agents through inspecting Linux ELF binaries: symbol tables, section layout, dynamic linking, debug info, and diagnosing linker errors.
Triggers
- "What libraries does this binary depend on?"
- "Why is this binary so large?"
- "I have an
undefined referenceor symbol not found at runtime" - "How do I check if debug info is in this binary?"
- "How do I find what symbols a library exports?"
- "How do I check if a binary is PIE / has RELRO?"
Workflow
1. Quick overview: file and size
file prog # type, arch, linkage, stripped or not
size prog # section sizes: text, data, bss
size --format=sysv prog # detailed per-section breakdown2. Dynamic dependencies: ldd
ldd ./prog # show all shared lib dependencies
ldd -v ./prog # verbose: include symbol versions
# Check why a library is loaded
ldd ./prog | grep libssl
# For a library (not an executable)
ldd ./libfoo.soIf ldd shows not found, the shared library is missing from LD_LIBRARY_PATH or /etc/ld.so.conf.
Fix:
export LD_LIBRARY_PATH=/path/to/libs:$LD_LIBRARY_PATH
# Or install the library and run ldconfig
sudo ldconfig3. Symbols: nm
nm prog # all symbols (T=text, D=data, U=undefined, etc.)
nm -D ./libfoo.so # dynamic symbols only
nm -C prog # demangle C++ symbols
nm --defined-only prog # only defined symbols
nm -u prog # only undefined (needed) symbols
nm -S prog # include symbol size
# Search for a symbol
nm -D /usr/lib/libssl.so | grep SSL_readSymbol type codes:
T/t— text (code): global / localD/d— data (initialised): global / localB/b— BSS (uninitialised): global / localR/r— read-only data: global / localU— undefined (needs to be provided at link time)W/w— weak symbol
4. Sections: readelf
readelf -h prog # ELF header (arch, type, entry point)
readelf -S prog # all sections
readelf -l prog # program headers (segments)
readelf -d prog # dynamic section (like ldd but raw)
readelf -s prog # symbol table
readelf -r prog # relocations
readelf -n prog # notes (build ID, ABI tag)
readelf --debug-dump=info prog | head -100 # DWARF info
readelf -a prog # all of the above5. Disassembly and source: objdump
# Disassemble all code sections
objdump -d prog
objdump -d -M intel prog # Intel syntax
# Disassemble + intermix source (needs -g at compile time)
objdump -d -S prog
# Disassemble specific symbol
objdump -d prog | awk '/^[0-9a-f]+ <main>:/,/^$/'
# All sections (including data)
objdump -D prog
# Header info
objdump -f prog
objdump -p prog # private headers (including needed libs)6. Binary hardening check
# Check for PIE, RELRO, stack canary, NX
# Use checksec (install separately)
checksec --file=prog
# Manual checks:
readelf -h prog | grep Type # ET_DYN = PIE, ET_EXEC = non-PIE
readelf -d prog | grep GNU_RELRO # RELRO present
readelf -d prog | grep BIND_NOW # full RELRO
readelf -s prog | grep __stack_chk # stack protector
readelf -l prog | grep GNU_STACK # NX bit (RW = no exec, RWE = exec stack)7. Section size analysis (binary bloat)
# Detailed section sizes
size --format=sysv prog | sort -k2 -nr | head -20
# Per-object contribution (with -Wl,--print-map or bloaty)
# Bloaty (install separately): https://github.com/google/bloaty
bloaty prog
# Check stripped vs not
file prog
strip --strip-all -o prog.stripped prog
ls -lh prog prog.stripped8. Build ID
Build IDs uniquely identify a binary/library build, enabling debuginfod lookups.
readelf -n prog | grep 'Build ID'
# or
file prog | grep BuildID9. Common diagnosis flows
"undefined symbol at runtime"
# Which library was expected to provide it?
nm -D libfoo.so | grep mysymbol
# Is the library in the runtime path?
ldd ./prog | grep libfoo
# Check LD_PRELOAD / LD_LIBRARY_PATH"binary is too large"
size --format=sysv prog | sort -k2 -nr | head
nm -S --defined-only prog | sort -k2 -nr | head -20
objdump -d prog | awk '/^[0-9a-f]+ </{fn=$2} /^[0-9a-f]/{count[fn]++} END{for(f in count) print count[f], f}' | sort -nr | head -20For a quick reference, see references/cheatsheet.md.
Related skills
- Use
skills/binaries/linkers-ltofor linker flags and LTO - Use
skills/binaries/binutilsforar,strip,objcopy,addr2line - Use
skills/debuggers/core-dumpsfor build ID and debuginfod usage
ELF Inspection Cheatsheet
Source: <https://man7.org/linux/man-pages/man1/readelf.1.html> Source: <https://man7.org/linux/man-pages/man1/objdump.1.html> Source: <https://man7.org/linux/man-pages/man1/nm.1.html> Source: <https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/8/html-single/developing_c_and_cpp_applications_in_rhel_8/index>
Quick reference
| Task | Command |
|---|---|
| File type | file prog |
| Section sizes | size prog / size --format=sysv prog |
| Dynamic deps | ldd prog |
| All symbols | nm prog |
| Dynamic symbols | nm -D lib.so |
| Demangle C++ | nm -C prog |
| Undefined symbols | nm -u prog |
| ELF header | readelf -h prog |
| Sections | readelf -S prog |
| Segments | readelf -l prog |
| Dynamic section | readelf -d prog |
| Symbol table | readelf -s prog |
| Relocations | readelf -r prog |
| Notes (Build ID) | readelf -n prog |
| Disassemble | objdump -d prog |
| Intel syntax | objdump -d -M intel prog |
| Source + asm | objdump -d -S prog |
| Strings | strings prog |
| Hex dump section | objdump -s -j .rodata prog |
---
nm symbol types
| Code | Meaning |
|---|---|
T | Global function (text) |
t | Local function (text) |
D | Global initialized data |
d | Local initialized data |
B | Global uninitialized data (BSS) |
b | Local uninitialized data |
R | Global read-only data |
r | Local read-only data |
U | Undefined (external dependency) |
W | Weak global symbol |
w | Weak local symbol |
V | Weak object (C++) |
I | Indirect reference |
A | Absolute symbol |
C | Common symbol |
---
readelf sections
Key sections in a typical ELF:
| Section | Content |
|---|---|
.text | Executable code |
.data | Initialized global/static variables |
.bss | Uninitialized globals (zero at startup) |
.rodata | Read-only data (string literals, consts) |
.plt | Procedure Linkage Table (lazy binding) |
.got | Global Offset Table |
.got.plt | GOT for PLT entries |
.dynsym | Dynamic symbol table |
.dynstr | Dynamic symbol strings |
.rela.dyn | Relocations for .data/.got |
.rela.plt | Relocations for PLT |
.debug_* | DWARF debug information |
.note.gnu.build-id | Build ID (SHA1 of content) |
.gnu.hash | Hash table for fast symbol lookup |
---
Hardening checks
# PIE: ET_DYN = PIE executable (position-independent)
readelf -h prog | grep 'Type:'
# RELRO
readelf -l prog | grep 'GNU_RELRO'
readelf -d prog | grep BIND_NOW # full RELRO requires BIND_NOW
# NX (non-executable stack)
readelf -l prog | grep 'GNU_STACK'
# Flags should be 'RW' not 'RWE'
# Stack protector
nm prog | grep __stack_chk_fail
# FORTIFY_SOURCE
nm prog | grep __memcpy_chk
# checksec (comprehensive)
checksec --file=prog --output=json---
Shared library SONAME
# Check SONAME
readelf -d libfoo.so | grep SONAME
objdump -p libfoo.so | grep SONAME
# Create symlinks correctly
ln -sf libfoo.so.1.2.3 libfoo.so.1
ln -sf libfoo.so.1 libfoo.so