Home / Alt manpages / llvm-objcopy-18(1)

  • llvm-objcopy-18(1)
  • User command
  • linux

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.

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 file or llvm-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.