Inspect Windows PE files with x86_64-w64-mingw32-objdump
You will use the MinGW-w64 cross-tool to inspect a Windows executable or DLL from Linux. The workflow starts with file and section headers, then narrows to symbols, raw sections or disassembly. objdump only reads the input in these examples; it does not patch or rewrite it.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about 15 minutes for a first inspection, plus time to identify the correct input file. You need the binutils-mingw-w64-x86-64 package and a readable PE file such as PROGRAM.exe or LIBRARY.dll. No elevated privileges are normally needed.
1. Check the installed tool and input
This guide is based on the installed GNU Binutils 2.41.90.20240122 build. The command is a cross-target tool, but it runs on Linux. The x86_64-w64-mingw32ucrt-objdump name is an installed alias with the same manpage content and version on this system.
$ command -v x86_64-w64-mingw32-objdump
/usr/bin/x86_64-w64-mingw32-objdump
$ x86_64-w64-mingw32-objdump --version
GNU objdump (GNU Binutils) 2.41.90.20240122
$ INPUT="$PWD/PROGRAM.exe"
$ test -r "$INPUT" && echo "readable: $INPUT"
readable: /home/me/PROGRAM.exe
Replace PROGRAM.exe with a real path. Keep the path quoted. A filename alone is easy to mistype when you are comparing several builds, and a failed inspection is often just a path error.
2. Read the file and section headers
Start with -f for the overall file header and -h for the section table. These outputs tell you whether the input was recognised and which sections are available before you request more detail.
$ x86_64-w64-mingw32-objdump -f "$INPUT"
$ x86_64-w64-mingw32-objdump -f "$INPUT" > file-header.txt
$ grep -E 'file format|architecture|start address' file-header.txt
$ x86_64-w64-mingw32-objdump -h "$INPUT"
The exact flags, addresses and section list depend on the file. Do not treat the sample values as defaults. The useful checkpoint is a recognised format such as pei-x86-64, followed by sections that match the file you expect.
3. Inspect symbols and demangle names
Use -t to print the normal symbol table. Add -C when C++ names are present and need to be rendered as source-level names. -w keeps long symbol names from being truncated.
$ x86_64-w64-mingw32-objdump -t -C -w "$INPUT" > symbols.txt
$ sed -n '1,12p' symbols.txt
$ test -s symbols.txt && echo "symbol report written"
symbol report written
A stripped binary can show no useful symbols. That is not a failed command. It means the names were removed or were never included. -T asks for dynamic symbols, but it is meaningful mainly for dynamic objects and may also produce little output for an ordinary executable.
4. Disassemble code in a readable syntax
Use -d to disassemble sections that the file format identifies as code. On x86, pass --disassembler-options=intel for Intel syntax. The default output can be large, so limit it by symbol or address when you know what you are looking for.
$ x86_64-w64-mingw32-objdump -d --disassembler-options=intel "$INPUT" | less
$ x86_64-w64-mingw32-objdump -d --disassembler-options=intel \
--start-address=0x140001000 --stop-address=0x140001080 "$INPUT"
$ x86_64-w64-mingw32-objdump -d --disassembler-options=intel "$INPUT" | sed -n '1,18p'
The address range must be meaningful for the input. If you do not know it, read -h first and use the section VMA as a starting point. -d skips sections not expected to contain instructions. -D disassembles every non-empty, non-BSS section and can therefore interpret data as instructions. Use it for a deliberate investigation, not as a default.
5. Examine a selected section or its bytes
Use -j SECTION to focus another operation on a named section. For example, -s displays the full contents, while -Z decompresses compressed sections for that display. This can produce a large report, so redirect it to a new file.
$ x86_64-w64-mingw32-objdump -s -j .rdata "$INPUT" > rdata.txt
$ sed -n '1,14p' rdata.txt
$ test -s rdata.txt && echo "section dump written"
section dump written
Section names are file-specific. If .rdata is absent, repeat -h and choose an existing name. Be careful with output redirection: > truncates an existing destination before objdump starts. Use a new filename, or create a backup before replacing a report you need.
6. Add debug and relocation information only when needed
Use -r for relocation entries and -R for dynamic relocations. Use -W for DWARF debug sections, when the file contains them. -l adds source filenames and line numbers to disassembly or relocations when matching debug information is available.
$ x86_64-w64-mingw32-objdump -r "$INPUT" | less
$ x86_64-w64-mingw32-objdump -Wl "$INPUT" | less
$ x86_64-w64-mingw32-objdump -dl "$INPUT" | less
Debug-link processing can cause objdump to look for separate debug files. The manpage also documents debuginfod support through DEBUGINFOD_URLS. If inspection must remain local and predictable, use --dwarf=do-not-use-debuginfod with a DWARF request. Do not enable remote lookups for an untrusted file or an environment where network access is prohibited.
7. Keep reports reproducible and safe
Save the exact command, tool version and input hash alongside a report. This helps distinguish a changed binary from a changed disassembler. Hashing reads the input and does not alter it:
$ sha256sum "$INPUT"
... hash depends on PROGRAM.exe ...
$ x86_64-w64-mingw32-objdump --version | sed -n '1p'
GNU objdump (GNU Binutils) 2.41.90.20240122
Do not use --no-recurse-limit casually. The installed manual says the normal demangler recursion limit is enabled to reduce the risk of stack exhaustion from hostile or unusually deep names. Leave it enabled unless a controlled investigation genuinely requires more recursion.
There is no undo operation for these read-only inspections. If you overwrote a report with redirection, recover it from your backup or regenerate it from the unchanged input. Do not run an unfamiliar binary merely because objdump recognised its format.
Done means
- You confirmed the installed MinGW-w64 objdump version and selected the intended input.
-fand-hidentified the file format and available sections.- You used symbols, disassembly or section contents for a specific question.
- You treated
-D, debug-link lookups and demangler limit changes as deliberate choices. - Your reports have new filenames or backups, and the original PE file remains unchanged.