Inspect ELF Files with the MinGW-w64 readelf Command
You will finish with a small, repeatable set of commands for examining an ELF file: its identity, loadable segments, sections, symbols and diagnostics. The commands are read-only. They do not rewrite the file, require root, or change a service.
The route
Jump straight to the step you need, or tick off Done means at the end.
This guide uses x86_64-w64-mingw32-readelf from binutils-mingw-w64-x86-64, package version 2.41.90.20240122-1ubuntu1+11.4 on this machine. The x86_64-w64-mingw32ucrt-readelf name is an alias for the same readelf purpose. Allow about ten minutes. You need a shell and a path to an ELF file.
Checkpoint
Start here if you are returning to the guide.
1. Confirm the binary and the input format
Check which executable the shell will run, then record its version. This is an ordinary command:
$ command -v x86_64-w64-mingw32-readelf
/usr/bin/x86_64-w64-mingw32-readelf
$ x86_64-w64-mingw32-readelf --version
GNU readelf (GNU Binutils) 2.41.90.20240122
Despite its MinGW-w64 prefix, this program reads ELF object files. The prefix identifies the binutils target build; it does not turn readelf into a PE or Windows executable inspector. Replace /bin/true in the examples with your own ELF file, object file or archive. If you are unsure, use the system file command first:
$ file /bin/true
/bin/true: ELF 64-bit LSB pie executable, x86-64, ...
Do not treat a file's name or extension as proof of its format. A non-ELF input produces an error. Reading an untrusted file can still consume time and memory, especially with large or unusual debug data, so inspect files in a suitable account and environment.
2. Read the ELF file header
Use -h, also spelled --file-header, for the file's top-level identity:
$ x86_64-w64-mingw32-readelf -h /bin/true
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 ...
Class: ELF64
Data: 2's complement, little endian
Type: DYN (Position-Independent Executable file)
Machine: Advanced Micro Devices X86-64
Number of section headers: 30
The exact addresses, counts and type depend on the file. The useful checks are the ELF class, byte order, machine architecture and type. A 32-bit file and a 64-bit file can both be valid ELF inputs, but they are not interchangeable build artefacts.
Checkpoint
If you only need to answer "what is this ELF?", -h is usually enough. Stop before using -a; broad output is harder to search and can include a large amount of debug information.
3. Compare segments with sections
Sections describe information such as code, data, symbols and debug data. Use -S to list them. The -W option keeps each 64-bit row on one line instead of wrapping it for an 80-column terminal:
$ x86_64-w64-mingw32-readelf -W -S /bin/true
There are 30 section headers, starting at offset 0x61b8:
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 1] .interp PROGBITS 0000000000000318 000318 00001c 00 A 0 0 1
[ 6] .dynsym DYNSYM 00000000000003d8 0003d8 000450 18 A 7 1 8
Use -l for program headers, also called segments. These describe the portions the loader maps or uses at runtime:
$ x86_64-w64-mingw32-readelf -W -l /bin/true
Elf file type is DYN (Position-Independent Executable file)
Entry point 0x19f0
There are 13 program headers, starting at offset 64
Use -e when you specifically want the file header, program headers and section headers together. It is equivalent to -h -l -S. Neither command changes the file.
4. Inspect symbols and relocations
Use -s or --symbols for the ordinary symbol table. Use --dyn-syms for the dynamic symbol table, which is often the useful view for a dynamically linked executable:
$ x86_64-w64-mingw32-readelf -W --dyn-syms /bin/true
Symbol table '.dynsym' contains 46 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 OBJECT GLOBAL DEFAULT UND __progname@GLIBC_2.2.5
Names may include symbol-version suffixes such as @GLIBC_2.2.5. That is metadata in the file, not a command option. -D changes symbol and relocation display to use the dynamic section's information, so add it only when that is the view you need. Use -r for relocation entries.
Long C++ names remain mangled by default. Add -C or --demangle when readable C++ names help. Keep the default when you need to compare the exact stored names. The demangler has a recursion limit enabled by default. Disabling that limit with --no-recurse-limit can allow stack exhaustion on hostile or extremely complicated names, so leave it enabled for routine inspection.
5. Dump one section deliberately
First obtain a section name with -S, then ask for only that section. -p prints printable strings; -x prints hexadecimal bytes; -R prints relocated bytes:
$ x86_64-w64-mingw32-readelf -p .interp /bin/true
String dump of section '.interp':
[ 0] /lib64/ld-linux-x86-64.so.2
$ x86_64-w64-mingw32-readelf -x .interp /bin/true
Hex dump of section '.interp':
0x00000318 2f6c6962 36342f6c 642d6c69 6e75782d /lib64/ld-linux-
...
A section can also be selected by its numeric index. Do not guess the index from another file: section numbering is file-specific. If the selected section is compressed, add -z to request decompression before a hex, relocated or string dump.
6. Diagnose instead of guessing
-L, also spelled --lint, asks readelf to report possible problems. On its own it examines the file's contents:
$ x86_64-w64-mingw32-readelf -L /bin/true
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 ...
The warnings are the useful part when a file is malformed or inconsistent. A quiet-looking run is not a proof that an executable is safe or compatible; it only means this checker found no reportable issue in the material it examined.
For an absent path, expect a non-zero status and an error on standard error:
$ x86_64-w64-mingw32-readelf -h /tmp/does-not-exist-readelf
readelf: Error: '/tmp/does-not-exist-readelf': No such file
Check the path, permissions and format before reaching for sudo. No example in this guide needs elevated privileges. If you dump DWARF data with -w, remember that separate debug links may be followed by default on this build. Use -wN when you want to prevent following those links, and avoid unexpected network lookups from debuginfod-enabled builds.
Done means
- You confirmed the installed MinGW-w64 readelf version and the input is ELF.
- You can read identity with
-h, sections with-Sand segments with-l. - You know when to use
--dyn-syms,-r,-pand-x. - You use exact section names from the file instead of guessing indexes.
- You have kept the inspection read-only and have not changed the binary or system.