LLVM-OBJCOPY(1)

okay so bestie, you've stumbled into the manual for llvm-objcopy(1) from the LLVM project πŸ’– this is part one of four, and we're gonna go through it together, no cap. it's giving "object copying and editing tool" energy. let's get into it ✨

✨ NAME ✨

llvm-objcopy β€” object copying and editing tool, bestie πŸ’…

🌸 SYNOPSIS 🌸

llvm-objcopy [options] input [output]

πŸ’… DESCRIPTION πŸ’…

so llvm-objcopy is literally a tool to copy and manipulate objects. in basic usage, it makes a semantic copy of the input to the output. if you specify any options, the output may be modified along the way, like by removing sections. periodt.

if you don't give an output file, the input file gets modified in-place. if you pass "-" for the input file, the input is read from the program's standard input stream. if you pass "-" for the output file, the output is written to the standard output stream of the program. iconic.

if the input is an archive, any requested operations will be applied to each archive member individually. so each member gets the glow-up separately πŸ’…

the tool is still in active development, but in most scenarios it works as a drop-in replacement for GNU's objcopy. so yeah, it's giving reliable but also still cooking πŸ”₯

πŸŽ€ GENERIC AND CROSS-PLATFORM OPTIONS πŸŽ€

the following options are either agnostic of the file format, or apply to multiple file formats. so they're flexible like that ✨

  • --add-gnu-debuglink <debug-file> β€” adds a .gnu_debuglink section for <debug-file> to the output. so the debug info knows where to find its bestie 🫢
  • --add-section <section=file> β€” adds a section named <section> with the contents of <file> to the output. for ELF objects, if the name starts with .note, the section will be of type SHT_NOTE. otherwise, it's SHT_PROGBITS. can be specified multiple times to add multiple sections. for MachO objects, <section> must be formatted as <segment name>,<section name>. no cap.
  • --binary-architecture <arch>, -B β€” literally ignored for compatibility. it's just there so old scripts don't break. πŸ’€
  • --disable-deterministic-archives, -U β€” uses real values for UIDs, GIDs and timestamps when updating archive member headers. so not deterministic, if you're into that.
  • --discard-all, -x β€” removes most local symbols from the output. different file formats may limit this to a subset of the local symbols. for example, file and section symbols in ELF objects will not be discarded. plus, it removes all debug sections. bye bye debug πŸ‘‹
  • --dump-section <section>=<file> β€” dumps the contents of section <section> into the file <file>. can be specified multiple times to dump multiple sections to different files. <file> is unrelated to the input and output files provided to llvm-objcopy, so the normal copying and editing operations will still be performed. no operations are performed on the sections prior to dumping them. for MachO objects, <section> must be formatted as <segment name>,<section name>.
  • --enable-deterministic-archives, -D β€” enables deterministic mode when copying archives, i.e. use 0 for archive member header UIDs, GIDs and timestamp fields. it's on by default, so you're already slaying.
  • --globalize-symbol <symbol> β€” marks any defined symbols named <symbol> as global symbols in the output. can be specified multiple times to mark multiple symbols. make them main characters πŸ‘‘
  • --globalize-symbols <filename> β€” reads a list of names from the file <filename> and marks defined symbols with those names as global in the output. in the file, each line represents a single symbol, with leading and trailing whitespace ignored, as is anything following a '#'. can be specified multiple times to read names from multiple files.
  • --help, -h β€” prints a summary of command line options. the classic cry for help, but make it helpful πŸ’…
  • --keep-global-symbol <symbol>, -G β€” marks all symbols local in the output, except for symbols with the name <symbol>. can be specified multiple times to ignore multiple symbols. so these are the only ones staying global, periodt.
  • --keep-global-symbols <filename> β€” marks all symbols local in the output, except for symbols named in the file <filename>. in the file, each line represents a single symbol, with leading and trailing whitespace ignored, as is anything following a '#'. can be specified multiple times to read names from multiple files.
  • --localize-symbol <symbol>, -L β€” marks any defined non-common symbol named <symbol> as a local symbol in the output. can be specified multiple times to mark multiple symbols as local. so they're not global anymore, they're just vibing locally.
  • --localize-symbols <filename> β€” reads a list of names from the file <filename> and marks defined non-common symbols with those names as local in the output. in the file, each line represents a single symbol, with leading and trailing whitespace ignored, as is anything following a '#'. can be specified multiple times to read names from multiple files.
  • --only-keep-debug β€” produces a debug file as the output that only preserves contents of sections useful for debugging purposes. for ELF objects, this removes the contents of SHF_ALLOC sections that are not SHT_NOTE by making them SHT_NOBITS and shrinking the program headers where possible. so it's debug-only, no extra baggage.
  • --only-section <section>, -j β€” removes all sections from the output, except for sections named <section>. can be specified multiple times to keep multiple sections. for MachO objects, <section> must be formatted as <segment name>,<section name>. so only the chosen ones survive, it's giving survivor but for sections.
  • --redefine-sym <old>=<new> β€” renames symbols called <old> to <new> in the output. can be specified multiple times to rename multiple symbols. glow-up for symbol names ✨
  • --redefine-syms <filename> β€” renames symbols in the output as described in the file <filename>. in the file, each line represents a single symbol to rename, with the old name and new name separated by whitespace. leading and trailing whitespace is ignored, as is anything following a '#'. can be specified multiple times to read names from multiple files.
  • --regex β€” if specified, symbol and section names specified by other switches are treated as extended POSIX regular expression patterns. so you can go regex wild, bestie.
  • --remove-symbol-prefix <prefix> β€” removes <prefix> from the start of every symbol name. no-op for symbols that do not start with <prefix>. so if they don't have it, they're left alone.
  • --remove-section <section>, -R β€” removes the specified section from the output. can be specified multiple times to remove multiple sections simultaneously. for MachO objects, <section> must be formatted as <segment name>,<section name>. yeet those sections πŸ—‘οΈ
  • --set-section-alignment <section>=<align> β€” sets the alignment of section <section> to <align>. can be specified multiple times to update multiple sections. alignment is key, bestie.
  • --set-section-flags <section>=<flag>[,<flag>,...] β€” sets section properties in the output of section <section> based on the specified <flag> values. can be specified multiple times to update multiple sections.

supported flag names are alloc, load, noload, readonly, exclude, debug, code, data, rom, share, contents, merge, strings, and large. not all flags are meaningful for all object file formats or target architectures.

for ELF objects, the flags have the following effects:

  • alloc = add the SHF_ALLOC flag.
  • load = if the section has SHT_NOBITS type, mark it as a SHT_PROGBITS section.
  • readonly = if this flag is not specified, add the SHF_WRITE flag.
  • exclude = add the SHF_EXCLUDE flag.
  • code = add the SHF_EXECINSTR flag.
  • merge = add the SHF_MERGE flag.
  • strings = add the SHF_STRINGS flag.
  • contents = if the section has SHT_NOBITS type, mark it as a SHT_PROGBITS section.
  • large = add the SHF_X86_64_LARGE on x86_64; rejected if the target architecture is not x86_64.

for COFF objects, the flags have the following effects:

  • alloc = add the IMAGE_SCN_CNT_UNINITIALIZED_DATA and IMAGE_SCN_MEM_READ flags, unless the load flag is specified.
  • noload = add the IMAGE_SCN_LNK_REMOVE and IMAGE_SCN_MEM_READ flags.
  • readonly = if this flag is not specified, add the IMAGE_SCN_MEM_WRITE flag.
  • exclude = add the IMAGE_SCN_LNK_REMOVE and IMAGE_SCN_MEM_READ flags.
  • debug = add the IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE and IMAGE_SCN_MEM_READ flags.
  • code = add the IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE and IMAGE_SCN_MEM_READ flags.
  • data = add the IMAGE_SCN_CNT_INITIALIZED_DATA and IMAGE_SCN_MEM_READ flags.
  • share = add the IMAGE_SCN_MEM_SHARED and IMAGE_SCN_MEM_READ flags.
  • --skip-symbol <symbol> β€” does not change the parameters of symbol <symbol> when executing other options that can change the symbol's name, binding or visibility. so leave this one alone, please and thank you.
  • --skip-symbols <filename> β€” does not change the parameters of symbols named in the file <filename> when executing other options that can change the symbol's name, binding or visibility. in the file, each line represents a single symbol, with leading and trailing whitespace ignored, as is anything following a '#'. can be specified multiple times to read names from multiple files.
  • --strip-all-gnu β€” removes all symbols, debug sections and relocations from the output. this option is equivalent to GNU objcopy's --strip-all switch. so it's the GNU way, but make it LLVM.
  • --strip-all, -S β€” for ELF objects, removes from the output all symbols and non-alloc sections not within segments, except for .gnu.warning, .ARM.attribute sections and the section name table. for COFF and Mach-O objects, removes all symbols, debug sections, and relocations from the output. so it's the ultimate strip, except for those special ones.
  • --strip-debug, -g β€” removes all debug sections from the output. debug who? don't know her πŸ’…
  • --strip-symbol <symbol>, -N β€” removes all symbols named <symbol> from the output. can be specified multiple times to remove multiple symbols. bye bestie πŸ‘‹
  • --strip-symbols <filename> β€” removes all symbols whose names appear in the file <filename>, from the output. in the file, each line represents a single symbol name, with leading and trailing whitespace ignored, as is anything following a '#'. can be specified multiple times to read names from multiple files.
  • --strip-unneeded-symbol <symbol> β€” removes from the output all symbols named <symbol> that are local or undefined and are not required by any relocation. so if they're not needed, they're out. no dead weight.
  • --strip-unneeded-symbols <filename> β€” bestie, this one yeets every symbol whose name appears in <filename> out of the output, but only if it's local or undefined AND not required by any relocation. In that file, each line is one symbol name, leading and trailing whitespace is ignored, and anything after a # is ignored too. You can drop this flag multiple times to read names from multiple files. πŸ’…
  • --strip-unneeded β€” strips out all local or undefined symbols from the output that relocations don't need. Also removes all debug sections. Periodt, debug info is gone. 🧹
  • --update-section <name>=<file> β€” replaces the contents of section <name> with contents from file <file>. If <name> is part of a segment, the new contents cannot be larger than the existing section. No growing allowed, bestie. πŸ“
  • --version, -V β€” shows the version of the llvm-objcopy executable. Slay. ✨
  • --wildcard, -w β€” lets you use wildcard magic for symbol-related flags. It's on by default for section-related flags. Incompatible with --regex. πŸƒ

Wildcard syntax gives you these special characters:

  • * β€” any number of characters, equivalent to .*
  • ? β€” any single character, equivalent to .
  • \ β€” escape the next character, equivalent to \
  • [a-z] β€” character class, equivalent to [a-z]
  • [!a-z], [^a-z] β€” negated character class, equivalent to [^a-z]

Also, if a wildcard starts with !, it will prevent a match even if another flag matches. For example, -w -N '*' -N '!x' strips all symbols except for x. And the order doesn't matter: -w -N '*' -N '!x' is the same as -w -N '!x' -N '*'. πŸ’–

  • @<FILE> β€” reads command-line options and commands from response file <FILE>. It's giving "too many flags? put 'em in a file." πŸ“„

✨ ELF-SPECIFIC OPTIONS ✨

okay so these ones? only work on ELF objects bestie πŸ’… if you try them on anything else, llvm-objcopy will either yell at you with an error or just straight-up ignore them (lowkey rude of it ngl).

  • --add-symbol <name>=[<section>:]<value>[,<flags>] β€” drops a whole new symbol called <name> into the output symbol table 🫢 it lives in the section named <section> with value <value>. If you don't give a <section>, it becomes an absolute symbol. The <flags> control its properties. Accepted values are:
    • global = the symbol will have global binding.
    • local = the symbol will have local binding.
    • weak = the symbol will have weak binding.
    • default = the symbol will have default visibility.
    • hidden = the symbol will have hidden visibility.
    • protected = the symbol will have protected visibility.
    • file = the symbol will be an STT_FILE symbol.
    • section = the symbol will be an STT_SECTION symbol.
    • object = the symbol will be an STT_OBJECT symbol.
    • function = the symbol will be an STT_FUNC symbol.
    • indirect-function = the symbol will be an STT_GNU_IFUNC symbol.

Also these flags get accepted but literally ignored πŸ™ˆ debug, constructor, warning, indirect, synthetic, unique-object, before.

You can specify it multiple times to add multiple symbols. stacking symbols like it's nothing πŸ’–

  • --allow-broken-links β€” lets llvm-objcopy remove sections even if doing that would leave behind invalid section references. Any broken sh_link fields get set to zero. it's giving chaos but make it intentional πŸ’€
  • --change-section-lma *{+-}<val> β€” shifts the LMA of non-zero-sized segments by <val>.
  • --change-section-address <section>{=+-}<val>, --adjust-section-vma β€” changes the address of sections matching the <section> pattern to the value you give, or applies +<val>/-<val> to whatever the current value is. Can be specified multiple times for multiple patterns. Each section only gets modified by one --change-section-address argument, and if a section name matches multiple patterns, the rightmost change is the one that wins. Heads up: the object file needs to be of ET_REL type.
  • --change-start <incr>, --adjust-start β€” adds <incr> to the program's start address. Specify it multiple times and the values pile up cumulatively ✨
  • --compress-debug-sections [<format>] β€” compresses DWARF debug sections in the output using <format>. Supported formats are zlib and zstd. If you omit <format>, it uses zlib.
  • --compress-sections <section>=<format> β€” compresses or decompresses sections matched by <section> with the given format. Supported formats are zlib and zstd. Say none for decompression. When a section gets matched by multiple options, the last one wins. A wildcard <section> starting with '!' is not allowed. Also, sections within a segment cannot be (de)compressed. sorry bestie πŸ₯²
  • --decompress-debug-sections β€” decompresses any compressed DWARF debug sections in the output.
  • --discard-locals, -X β€” yeets local symbols that start with ".L" out of the output πŸ—‘οΈ
  • --extract-dwo β€” removes every section that isn't a DWARF .dwo section from the output.
  • --extract-main-partition β€” extracts the main partition from the output.
  • --extract-partition <name> β€” extracts the named partition from the output.
  • --gap-fill <value> β€” for binary outputs, fills the gaps between sections with <value> instead of zero. The value has to be an unsigned 8-bit integer.
  • --input-target <format>, -I β€” reads the input as <format>. Peep the SUPPORTED FORMATS section for the list of valid <format> values. If you don't specify it, llvm-objcopy tries to figure out the format automatically πŸ”
  • --keep-file-symbols β€” keeps symbols of type STT_FILE, even if they'd otherwise get stripped. protect them at all costs πŸ₯Ή
  • --keep-section <section> β€” when removing sections from the output, don't remove the ones named <section>. Specify multiple times to keep multiple sections.
  • --keep-symbol <symbol>, -K β€” when removing symbols from the output, don't remove the ones named <symbol>. Specify multiple times to keep multiple symbols.
  • --keep-symbols <filename> β€” when removing symbols from the output, don't remove symbols named in the file <filename>. In that file, each line is a single symbol, leading and trailing whitespace is ignored, and so is anything after a '#'. Specify multiple times to read names from multiple files.
  • --localize-hidden β€” marks every symbol with hidden or internal visibility as local in the output.
  • --new-symbol-visibility <visibility> β€” sets the visibility of the symbols that get automatically created when you use binary input or --add-symbol. Valid options are:
    • default
    • hidden
    • internal
    • protected

The default is default.

  • --no-verify-note-sections β€” when adding note sections, skip checking whether the section format is valid.
  • --output-target <format>, -O β€” writes the output as <format>. Check SUPPORTED FORMATS for the valid <format> values. If you don't specify it, the output format is assumed to be whatever you gave --input-target, or the input file's format if that option is also unspecified.
  • --pad-to <address> β€” for binary outputs, pads the output up to the load address <address> using a value of zero, or the value you gave --gap-fill.
  • --prefix-alloc-sections <prefix> β€” slaps <prefix> onto the front of the names of all allocatable sections in the output.
  • --prefix-symbols <prefix> β€” slaps <prefix> onto the front of every symbol name in the output.
  • --preserve-dates, -p β€” preserves access and modification timestamps in the output.
  • --remove-note [<name>/]<type> β€” removes notes of integer type <type> and name <name> from SHT_NOTE sections that aren't inside a segment. Can be specified multiple times.
  • --rename-section <old>=<new>[,<flag>,...] β€” renames sections called <old> to <new> in the output and applies any <flag> values you give. Check --set-section-flags for the list of supported flags. Specify multiple times to rename multiple sections.
  • --set-section-type <section>=<type> β€” sets the type of section <section> to the integer <type>. Specify multiple times to update multiple sections.
  • --set-start <addr> β€” sets the start address of the output to <addr>. This overrides any --change-start or --adjust-start options you specified earlier. it said what it said πŸ’…
  • --set-symbol-visibility <symbol>=<visibility> β€” changes a symbol's visibility to the value you give.
  • --set-symbols-visibility <filename>=<visibility> β€” reads a list of symbols from <filename> and changes their visibility to the given value. Visibility values: default, internal, hidden, protected.
  • --split-dwo <dwo-file> β€” same thing as running llvm-objcopy with --extract-dwo and <dwo-file> as the output file and no other options, and then running it with --strip-dwo on the input file.
  • --strip-dwo β€” removes all DWARF .dwo sections from the output.
  • --strip-non-alloc β€” removes from the output all non-allocatable sections that aren't inside segments.
  • --strip-sections β€” removes from the output all section headers and all section data that isn't inside segments.
⚠️ bestie listen. lots of tools will not be able to use an object without section headers. this is not a drill 🚨
  • --target <format>, -F β€” same as using --input-target and --output-target for <format>. Check SUPPORTED FORMATS for the valid <format> values.
  • --verify-note-sections β€” when adding note sections, checks whether the section format is valid. On by default ✨
  • --weaken-symbol <symbol>, -W β€” marks global symbols named <symbol> as weak symbols in the output. Specify multiple times to weaken multiple symbols.
  • --weaken-symbols <filename> β€” reads a list of names from the file <filename> and marks global symbols with those names as weak in the output. In the file, each line is a single symbol, leading and trailing whitespace is ignored, and so is anything after a '#'. Specify multiple times to read names from multiple files.
  • --weaken β€” marks all defined global symbols as weak in the output.

🍎 MACH-O-SPECIFIC OPTIONS 🍎

  • --keep-undefined β€” keeps undefined symbols, even if they'd otherwise get stripped. don't touch them 🫢

β˜• COFF-SPECIFIC OPTIONS β˜•

  • --subsystem <name>[:<version>] β€” sets the PE subsystem, and optionally the subsystem version.

🌈 SUPPORTED FORMATS 🌈

so these are the values llvm-objcopy currently supports for the --input-target, --output-target, and --target options πŸ’– and for GNU objcopy compatibility, they're all bfdnames. iykyk.

  • binary
  • ihex
  • elf32-i386
  • elf32-x86-64
  • elf64-x86-64
  • elf32-iamcu
  • elf32-littlearm
  • elf64-aarch64
  • elf64-littleaarch64
  • elf32-littleriscv
  • elf64-littleriscv
  • elf32-powerpc
  • elf32-powerpcle
  • elf64-powerpc
  • elf64-powerpcle
  • elf32-bigmips
  • elf32-ntradbigmips
  • elf32-ntradlittlemips
  • elf32-tradbigmips
  • elf32-tradlittlemips
  • elf64-tradbigmips
  • elf64-tradlittlemips
  • elf32-sparc
  • elf32-sparcel
  • elf32-hexagon
  • elf32-loongarch
  • elf64-loongarch
  • elf64-s390

And these next ones are supported by llvm-objcopy for --output-target only:

  • srec

Alsoooo, all targets except binary, ihex, and srec can have -freebsd as a suffix πŸ¦‹


🧚 BINARY INPUT AND OUTPUT 🧚

If binary is used as the value for --input-target, the input file gets embedded as a data section inside an ELF relocatable object, with symbols _binary_<file_name>_start, _binary_<file_name>_end, and _binary_<file_name>_size representing the start, end, and size of the data β€” where <file_name> is the path of the input file as you specified it on the command line, with non-alphanumeric characters converted to _. slay ✨

If binary is used as the value for --output-target, the output file becomes a raw binary file containing the memory image of the input file. Symbols and relocation information get discarded πŸ’€ The image starts at the address of the first loadable section in the output.

πŸ’₯ EXIT STATUS πŸ’₯

okay so here's the vibe check on how this thing says goodbye πŸ‘‹

  • If there's an error, llvm-objcopy exits with a non-zero exit code. That's your sign something went wrong, bestie 😭
  • Otherwise? It exits with code 0. Clean, chill, no drama, slay ✨

πŸ› BUGS πŸ›

Found something cursed?? We gotta hear about it, fr fr. To report bugs, please visit:

https://github.com/llvm/llvm-project/labels/tools:llvm-objcopy/strip/

Like. Please actually report them. We can't fix what we don't know about πŸ₯Ί

⚠️ The Known Issue (iykyk)

There is a known issue with --input-target and --target causing only binary and ihex formats to have any effect. πŸ’€

Any other values? Ignored. Completely. And then llvm-objcopy will just... try to guess the input format on its own πŸ™ˆ

no cap, that's the actual documented behaviour. don't come for me, come for the flags.

πŸ‘€ SEE ALSO πŸ‘€

  • llvm-strip(1) β€” the sibling. the other half of the duo. go say hi 🫢

πŸ‘‘ AUTHOR πŸ‘‘

Maintained by the LLVM Team (https://llvm.org/). Legends, honestly. Main character energy for decades πŸ’…


2003-2025, LLVM Project

two whole decades of shipping code, iconic behaviour only ✨


okay bestie, that's the whole page πŸŽ€ this was LLVM-OBJCOPY(1), version 20, dated 2025-09-03 β€” go forth and copy some objects, you absolute icon πŸ’–πŸ¦‹πŸŒΈ

πŸ“¦ where this page comes from