Copy, Inspect and Strip ELF Files with llvm-objcopy-18
You will use Ubuntu's llvm-objcopy-18 to make a semantic copy of an object file, remove debug sections from a separate output, extract one section and produce a raw binary. The original input stays untouched throughout. The installed command is LLVM 18.1.3 from the llvm-18 package.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about 15 minutes. You need a shell, a readable ELF object or executable, and enough free space for each output. These examples do not need elevated privileges when the files are in a directory you can write. Do not use sudo merely because the input is an executable. Use it only when your chosen input or destination is genuinely protected, and check the resulting ownership afterwards.
1. Check the installed command and input
Start by confirming which executable will run and record its version:
$ command -v llvm-objcopy-18
$ llvm-objcopy-18 --version
llvm-objcopy, compatible with GNU objcopy
Ubuntu LLVM version 18.1.3
Choose an input that you can restore or replace. llvm-objcopy accepts object files, executables and archives, and it can infer the format. The following inspection command is read-only:
$ file /path/to/input.elf
$ llvm-readelf-18 -S /path/to/input.elf
Note the section names you intend to use, such as .text or .debug_info. Do not copy a section name from a different binary and assume it exists here. A missing section is an error, not a harmless no-op.
Checkpoint
The input path is readable, the format is known, and the section listing contains the names used by the next command.
2. Make a separate semantic copy
The basic form is an input followed by an output:
$ llvm-objcopy-18 /path/to/input.elf /path/to/work/input-copy.elf
$ file /path/to/work/input-copy.elf
This is a semantic object-file copy, not a byte-for-byte clone. Archive headers and other metadata can be normalised, so do not use cmp as the success test. Check that the output has the expected kind of object and inspect it with the tool that will consume it. With no output path, the manual says the input is modified in place. Treat that form as destructive and avoid it in scripts unless in-place replacement is exactly what you want.
If the destination already exists, decide deliberately whether replacement is acceptable. A safer pattern is to write a new name, inspect it, then move it into place only after a successful check:
$ llvm-objcopy-18 /path/to/input.elf /path/to/work/input.elf.new
$ llvm-readelf-18 -h /path/to/work/input.elf.new
$ mv -- /path/to/work/input.elf.new /path/to/work/input.elf
The final mv changes state and can replace an existing destination. Keep the original until the replacement has passed your application-specific test. If the copy fails, remove only the .new file after checking that it is the incomplete output.
3. Remove debug data into another file
Use --strip-debug, also written -g, when you want to remove debug sections while retaining the normal executable or object contents:
$ llvm-objcopy-18 --strip-debug \
/path/to/input.elf /path/to/work/input-nodebug.elf
$ llvm-readelf-18 -S /path/to/work/input-nodebug.elf
Compare the section lists before and after. Debug information may be absent from a file that was already stripped, so a successful command does not guarantee a smaller output. If you need to remove symbols as well, --strip-all is much more aggressive. On ELF it removes all symbols and non-allocatable sections outside segments, subject to the exceptions documented by this installed manpage. That can break debugging and tooling, so make it a separate, explicit decision.
Warning
Never test a stripping command first on the only copy of a production binary. Keep a known-good input and test the resulting file with the loader or application before replacing anything.
4. Dump one section for inspection
--dump-section writes a named section to a separate file. The dump destination is independent of the normal output argument:
$ llvm-objcopy-18 --dump-section \
.text=/path/to/work/text.bin /path/to/input.elf
$ wc -c /path/to/work/text.bin
On a typical x86-64 executable, this produces a non-empty binary file. Its contents are not text and should not be opened in an editor. Use a byte-oriented tool such as od or xxd if you need a short preview:
$ od -Ax -tx1 -N 32 /path/to/work/text.bin
The command still performs its ordinary copying and editing operation if you also give an output file, but keeping the dump as a focused, read-only operation makes scripts easier to review. If the section is not present, go back to the section listing rather than guessing a replacement name.
5. Produce a raw binary deliberately
Set the output target to binary when another tool needs the input's loadable memory image without ELF headers, symbols or relocation information:
$ llvm-objcopy-18 --output-target=binary \
/path/to/input.elf /path/to/work/image.bin
$ file /path/to/work/image.bin
$ wc -c /path/to/work/image.bin
The output is expected to be reported as generic data by file. The binary starts at the address of the first loadable section, and symbols and relocation information are discarded. That means this is not a general conversion to a runnable Linux executable. Firmware, bootloader and emulator workflows often need an explicit load address as well; use the target system's documented layout before adding options such as --pad-to or --gap-fill.
The inverse operation is also supported. With --input-target=binary, the file is embedded in an ELF relocatable object and receives generated _binary_... start, end and size symbols based on the input path. Verify the generated object with llvm-readelf-18 -s before linking it into anything.
6. Diagnose failures without changing the input
A non-zero exit status means the command reported an error. Capture it immediately when scripting:
if llvm-objcopy-18 --strip-debug "$input" "$output"; then
llvm-readelf-18 -h "$output"
else
status=$?
printf 'llvm-objcopy failed with status %s\n' "$status" >&2
exit "$status"
fi
Common traps are an unreadable input, a destination directory you cannot write, a section name that does not exist, and an option that belongs to another object format. ELF-specific options can error or be ignored for non-ELF objects. For a format mismatch, inspect the file first and use --input-target or --output-target only when you have verified the required format name. The installed manpage also records a known issue: some non-binary and non-ihex values supplied to --input-target or --target may be ignored while the tool guesses the input format.
Keep diagnostics separate from binary output. If you use - as the input, llvm-objcopy-18 reads standard input; if you use - as the output, it writes standard output. Redirecting binary output into a terminal is noisy and can corrupt a pipeline, so send it to a file or another program that expects bytes.
Done means
- The version output identifies Ubuntu LLVM 18.1.3.
- The original input remains available and was not modified in place.
- Each output was inspected with
fileorllvm-readelf-18. - Stripping, section dumping and raw-binary conversion were used only for their stated purpose.
- Any replacement is still reversible because the known-good input was retained.