LLVM-OBJCOPY(1)

๐Ÿ’– NAME ๐Ÿ’–

llvm-objcopy โ€” the object copying and editing tool, bestie ๐Ÿ’…


โœจ SYNOPSIS โœจ

llvm-objcopy [options] input [output]

๐Ÿฆ‹ DESCRIPTION ๐Ÿฆ‹

Okay so, llvm-objcopy is a tool to copy and manipulate objects. In basic usage, it makes a semantic copy of the input to the output โ€” no cap, that's literally the whole job. ๐Ÿซถ

But here's where it gets iconic: if you specify any options, the output may be modified along the way โ€” like, for example, by removing sections. The way that it just... does that. ๐Ÿ˜ญ๐Ÿ”ฅ

And now the details you actually need, bestie, write these down:

  • If no output file is specified, the input file is modified in-place. ๐Ÿ‘€ (yes, like that, careful.)
  • If - is specified for the input file, the input is read from the program's standard input stream.
  • If - is specified for the output file, the output is written to the standard output stream of the program. Pipes? Slay.

Also, vibe check for archives: if the input is an archive, any requested operations will be applied to each archive member individually. Every single one. Fr fr. ๐Ÿงš

๐Ÿ’€ The tool is still in active development, but in most scenarios it works as a drop-in replacement for GNU's objcopy. Lowkey iconic of it.

โœจ GENERIC AND CROSS-PLATFORM OPTIONS โœจ

Okay bestie, these are the options that either don't care at all what file format you're in, or they work their magic across several formats at once. Universal queen behavior honestly. ๐Ÿ‘‘


  • --add-gnu-debuglink <debug-file> โ€” Slaps a .gnu_debuglink section into the output that points at <debug-file>. Cute little breadcrumb trail for your debugger. ๐Ÿ“
  • --add-section <section=file> โ€” Adds a brand new section called <section> to the output, filled with whatever's inside <file>. For ELF objects the section gets type SHT_NOTE if the name starts with .note โ€” otherwise it's SHT_PROGBITS, no in-between. You can pass this multiple times to stack up multiple sections. ๐Ÿ’…

For MachO objects, <section> has to be formatted as <segment name>,<section name> โ€” comma and all, don't forget it.

  • --binary-architecture <arch>, -B โ€” Ignored for compatibility. She's just standing there. ๐Ÿ’€
  • --disable-deterministic-archives, -U โ€” Uses the real UID, GID and timestamp values when updating archive member headers. Like, the actual ones. Unfiltered truth. ๐Ÿ™ˆ
  • --discard-all, -x โ€” Removes most local symbols from the output. Heads up though โ€” different file formats might limit this to just a subset of local symbols. For example, file and section symbols in ELF objects will not be discarded, periodt. Also removes all debug sections while it's at it.
  • --dump-section <section>=<file> โ€” Dumps the contents of section <section> into the file <file>. Can be specified multiple times to dump multiple sections into different files. Important vibe check: <file> is completely unrelated to the input and output files you gave to llvm-objcopy, so like, the normal copying and editing operations still happen anyway. And no operations are performed on the sections before dumping them โ€” pure, untouched content. โœจ

For MachO objects, <section> must be formatted as <segment name>,<section name>.

  • --enable-deterministic-archives, -D โ€” Turns on deterministic mode when copying archives, i.e. uses 0 for archive member header UID, GID and timestamp fields. This one is on by default, so she's already slaying. ๐Ÿ‘‘
  • --help, -h โ€” Prints a summary of command line options. The classic "wait what does this do again" button.
  • --only-keep-debug โ€” Produces a debug file as the output that only preserves contents of sections useful for debugging purposes. Diet version of your binary, debug-only edition. ๐Ÿงš

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.

  • --only-section <section>, -j โ€” Removes all the sections from the output except the ones named <section>. Can be specified multiple times to keep multiple sections. Very "you're all uninvited except you three" energy. ๐Ÿ’…

For MachO objects, <section> must be formatted as <segment name>,<section name>.

  • --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 your symbol table. โœจ
  • --redefine-syms <filename> โ€” Renames symbols in the output as described in the file <filename>. In that file, each line is 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 # โ€” so go off with your comments. Can be specified multiple times to read names from multiple files. ๐ŸŽ€
  • --regex โ€” If specified, symbol and section names given by other switches are treated as extended POSIX regular expression patterns. Fancy. ๐Ÿ”ฅ
  • --remove-symbol-prefix <prefix> โ€” Removes <prefix> from the start of every symbol name. Total no-op for symbols that don't start with <prefix> โ€” she doesn't touch what isn't hers.
  • --remove-section <section>, -R โ€” Removes the specified section from the output. Can be specified multiple times to remove multiple sections simultaneously. Blocked. Uninvited. Gone. ๐Ÿ’€

For MachO objects, <section> must be formatted as <segment name>,<section name>.

  • --set-section-alignment <section>=<align> โ€” Sets the alignment of section <section> to <align>. Can be specified multiple times to update multiple sections at once.
  • --set-section-flags <section>=<flag>[,<flag>,...] โ€” Sets section properties in the output of section <section> based on the <flag> values you list. 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. Ngl though, not all flags are meaningful for all object file formats or target architectures โ€” some of them are just there for the vibe.

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.
  • --strip-all-gnu โ€” Removes all symbols, debug sections and relocations from the output. This option is equivalent to GNU objcopy's --strip-all switch. Basically the certified classic. ๐Ÿ‘‘
  • --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 โ€” those three get to stay, they're VIPs. ๐ŸŒˆ

For COFF and Mach-O objects, removes all symbols, debug sections, and relocations from the output.

  • --strip-debug, -g โ€” Removes all debug sections from the output. Bye bestie, you were fun but you're taking up space. ๐Ÿ‘‹
  • --strip-symbol <symbol>, -N โ€” Removes all symbols named <symbol> from the output. Can be specified multiple times to remove multiple symbols.
  • --strip-symbols <filename> โ€” Removes all symbols whose names appear in the file <filename> from the output. In that file, each line is 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. She only takes out the ones nobody's using. ๐Ÿ’…
  • --strip-unneeded-symbols <filename> โ€” Removes all symbols whose names appear in the file <filename> from the output, if they are local or undefined and are not required by any relocation. In the file, each line is 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 โ€” Removes from the output all local or undefined symbols that are not required by relocations. Also removes all debug sections. Two birds, zero regrets. ๐Ÿ”ฅ
  • --update-section <name>=<file> โ€” Replaces the contents of the section <name> with contents from the file <file>. But careful โ€” if the section <name> is part of a segment, the new contents cannot be larger than the existing section. She will not stretch for you, no cap. โš ๏ธ
  • --version, -V โ€” Displays the version of the llvm-objcopy executable. Identity check. ๐Ÿ’–
  • --wildcard, -w โ€” Allows wildcard syntax for symbol-related flags. It's on by default for section-related flags. Incompatible with --regex โ€” pick a lane bestie. ๐Ÿฆ‹

Wildcard syntax allows the following special symbols:

  • * โ€” 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]

Additionally, starting a wildcard with ! will prevent a match, even if another flag matches. For example -w -N '*' -N '!x' will strip all symbols except for x. Iconic exclusion behavior honestly. โœจ

The order of wildcards does not matter. For example, -w -N '*' -N '!x' is the same as -w -N '!x' -N '*' โ€” she's not picky about your order. ๐Ÿซถ

  • @<FILE> โ€” Reads command-line options and commands from response file <FILE>. Like a little note passed to the program. ๐Ÿ’Œ

okay so these next ones? they're the ELF-only girlies ๐Ÿ’… โ€” they only work on ELF objects. Try them on anything else and llvm-objcopy will either throw an error at you or just silently ignore you (which, honestly, is so passive-aggressive of it ๐Ÿ˜ญ).


  • --add-symbol <name>=[<section>:]<value>[,<flags>] โ€” bestie, this one adds a whole new symbol called <name> to the output symbol table. It lives in the section named <section>, and its value is <value>. If you don't tell it a <section>, the symbol gets added as an absolute symbol instead. The <flags> bit changes up the symbol's properties, and here's the whole menu of accepted values:
    • global โ€” the symbol gets global binding.
    • local โ€” the symbol gets local binding.
    • weak โ€” the symbol gets weak binding.
    • default โ€” the symbol gets default visibility.
    • hidden โ€” the symbol gets hidden visibility.
    • protected โ€” the symbol gets protected visibility.
    • file โ€” the symbol becomes an STT_FILE symbol.
    • section โ€” the symbol becomes an STT_SECTION symbol.
    • object โ€” the symbol becomes an STT_OBJECT symbol.
    • function โ€” the symbol becomes an STT_FUNC symbol.
    • indirect-function โ€” the symbol becomes an STT_GNU_IFUNC symbol.

Also, these flags are technically accepted but just vibing, ignored ๐Ÿ™ˆ: debug, constructor, warning, indirect, synthetic, unique-object, before.

You can drop this option multiple times to add multiple symbols โ€” go off โœจ

  • --allow-broken-links โ€” lets llvm-objcopy remove sections even if doing so would leave you with invalid section references ๐Ÿ˜ฌ. Any invalid sh_link fields get set to zero, so it's like, broken but contained, yk?
  • --change-section-lma \*{+-}<val> โ€” shifts the LMA of non-zero-sized segments by <val>. Move it, move it ๐Ÿ•บ
  • --change-start <incr>, --adjust-start โ€” adds <incr> to the program's start address. Drop it multiple times and the values stack cumulatively โ€” main character energy, everything piles on top ๐Ÿ’ซ
  • --compress-debug-sections [<format>] โ€” compresses the DWARF debug sections in your output using whatever <format> you named. Supported formats are zlib and zstd. Leave <format> off and it just uses zlib by default ๐ŸŽ€
  • --compress-sections <section>=<format> โ€” compresses or decompresses the sections matched by <section> using the specified format. Supported formats are zlib and zstd; say none to decompress. When multiple options match the same section, the last one wins ๐Ÿ‘‘. A wildcard <section> starting with '!' is not allowed, and heads up: sections within a segment cannot be (de)compressed ๐Ÿซถ
  • --decompress-debug-sections โ€” unzips any compressed DWARF debug sections in the output. We're letting them breathe ๐Ÿ’จ
  • --discard-locals, -X โ€” removes local symbols that start with ".L" from the output. Bye local symbols, hope you had a good run ๐Ÿฆ‹
  • --extract-dwo โ€” nukes every section that isn't a DWARF .dwo section from the output. DWARF-only diet, no cap ๐Ÿ“
  • --extract-main-partition โ€” pulls the main partition out of the output.
  • --extract-partition <name> โ€” pulls the partition named <name> out of the output.
  • --gap-fill <value> โ€” for binary outputs, this fills the gaps between sections with <value> instead of zero. The value must be an unsigned 8-bit integer, so don't try anything fancy ๐Ÿ‘€
  • --globalize-symbol <symbol> โ€” marks any defined symbols named <symbol> as global symbols in the output. Drop it multiple times to globalize multiple symbols โ€” glow-up for everyone โœจ
  • --globalize-symbols <filename> โ€” reads a list of names from <filename> and marks defined symbols with those names as global in the output. In the file, each line is one single symbol; leading and trailing whitespace gets ignored, same with anything after a '#'. Can be specified multiple times to read names from multiple files ๐Ÿ“‚
  • --input-target <format>, -I โ€” reads the input as the specified format. Peep SUPPORTED FORMATS for the list of valid <format> values. If you don't specify one, llvm-objcopy will try to figure the format out automatically โ€” it's giving psychic ๐Ÿ”ฎ
  • --keep-file-symbols โ€” keeps symbols of type STT_FILE, even when they'd otherwise get stripped. Protecting the file symbols with their life ๐Ÿ’–
  • --keep-global-symbol <symbol>, -G โ€” marks all symbols local in the output, except the ones named <symbol>. Specify it multiple times to ignore multiple symbols โ€” VIP list only, periodt ๐Ÿ‘‘
  • --keep-global-symbols <filename> โ€” marks all symbols local in the output, except the ones named in the file <filename>. In the file, each line is one symbol; leading and trailing whitespace is ignored, same with anything after a '#'. Can be specified multiple times to read names from multiple files ๐Ÿ“
  • --keep-section <section> โ€” when sections are being removed from the output, don't remove the ones named <section>. Specify it multiple times to keep multiple sections. Protected by the group chat ๐Ÿ›ก๏ธ
  • --keep-symbol <symbol>, -K โ€” when symbols are getting removed from the output, don't remove the ones named <symbol>. Multiple times = multiple kept symbols ๐Ÿซถ
  • --keep-symbols <filename> โ€” when removing symbols from the output, don't remove symbols named in the file <filename>. In the file, each line is one symbol; leading and trailing whitespace ignored, and so is anything after a '#'. Can be specified multiple times to read names from multiple files ๐Ÿ“š
  • --localize-hidden โ€” marks every symbol with hidden or internal visibility as local in the output. Hidden girlies stay hidden ๐Ÿ’€
  • --localize-symbol <symbol>, -L โ€” marks any defined non-common symbol named <symbol> as a local symbol in the output. Specify it multiple times to localize multiple symbols ๐Ÿ’…
  • --localize-symbols <filename> โ€” reads a list of names from <filename> and marks defined non-common symbols with those names as local in the output. In the file, each line is one symbol; leading and trailing whitespace ignored, as is anything after a '#'. Can be specified multiple times to read names from multiple files ๐ŸŒธ
  • --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, obviously ๐Ÿ’ซ

  • --no-verify-note-sections โ€” when adding note sections, this skips the check on whether the section format is valid. Living dangerously, love that for you ๐Ÿ™ˆ
  • --output-target <format>, -O โ€” writes the output as the specified format. See SUPPORTED FORMATS for the list of valid <format> values. If you leave it off, the output format is assumed to be whatever you gave to --input-target, or the input file's format if that option was also left off ๐ŸŽ€
  • --pad-to <address> โ€” for binary outputs, pads the output up to the load address <address>, using zero or whatever value you gave to --gap-fill. Filling in the blanks ๐Ÿงš
  • --prefix-alloc-sections <prefix> โ€” slaps <prefix> onto the front of the names of every allocatable section in the output โœจ
  • --prefix-symbols <prefix> โ€” slaps <prefix> onto the front of every single symbol name in the output. Everyone gets a lil name tag ๐Ÿท๏ธ
  • --preserve-dates, -p โ€” preserves the access and modification timestamps in the output. Time is a construct but we respect it โฐ
  • --rename-section <old>=<new>[,<flag>,...] โ€” renames sections called <old> to <new> in the output, and applies any <flag> values you specified. Peep --set-section-flags for the list of supported flags. Can be specified multiple times to rename multiple sections ๐Ÿ’–
  • --set-section-type <section>=<type> โ€” sets the type of section <section> to the integer <type>. Multiple times = multiple sections updated ๐Ÿ”ฅ
  • --set-start <addr> โ€” sets the start address of the output to <addr>. This one overrides any --change-start or --adjust-start you already specified. It's the main character, the others get no lines ๐Ÿ‘‘
  • --set-symbol-visibility <symbol>=<visibility> โ€” changes the visibility of a symbol to the value you specify.
  • --set-symbols-visibility <filename>=<visibility> โ€” reads a list of symbols from <filename> and changes their visibility to the specified value. Visibility values you can use: default, internal, hidden, protected.
  • --skip-symbol <symbol> โ€” don't change the parameters of the symbol <symbol> when other options that can change a symbol's name, binding or visibility are running. It's sitting this one out ๐Ÿ™…
  • --skip-symbols <filename> โ€” don't change the parameters of the symbols named in the file <filename> when other options that can change a symbol's name, binding or visibility are running. In the file, each line is one symbol; leading and trailing whitespace ignored, as is anything after a '#'. Can be specified multiple times to read names from multiple files ๐Ÿ“„
  • --split-dwo <dwo-file> โ€” this is exactly equivalent to running llvm-objcopy with --extract-dwo and <dwo-file> as the output file and no other options, and then running it again with --strip-dwo on the input file. Two-for-one situation, we love efficiency ๐Ÿ’…
  • --strip-dwo โ€” removes every DWARF .dwo section from the output. Gone, reduced to atoms ๐Ÿ’€
  • --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, plus all section data that isn't within segments.
โš ๏ธ heads up bestie: lots of tools will not be able to use an object that has no section headers. This is a real one, not a drill ๐Ÿ˜ญ
  • --target <format>, -F โ€” equivalent to setting both --input-target and --output-target to the specified format. See SUPPORTED FORMATS for the list of valid <format> values. One option, both jobs, iconic ๐ŸŒˆ
  • --verify-note-sections โ€” when adding note sections, checks whether the section format is valid. This one is on by default โœ…
  • --weaken-symbol <symbol>, -W โ€” marks global symbols named <symbol> as weak symbols in the output. Multiple times = multiple symbols weakened ๐Ÿ’ช
  • --weaken-symbols <filename> โ€” reads a list of names from <filename> and marks global symbols with those names as weak in the output. In the file, each line is one symbol; leading and trailing whitespace ignored, as is anything after a '#'. Can be specified multiple times to read names from multiple files ๐Ÿ“
  • --weaken โ€” marks all defined global symbols as weak in the output. Everyone's weak now, it's a whole mood ๐Ÿซ 

๐ŸŽ MACH-O-SPECIFIC OPTIONS

  • --keep-undefined โ€” keeps undefined symbols around, even if they'd otherwise get stripped. Can't let them go ๐Ÿฅบ

๐ŸชŸ COFF-SPECIFIC OPTIONS

  • --subsystem <name>[:<version>] โ€” sets the PE subsystem, and optionally the subsystem version too. Very demure, very PE ๐ŸŽ€

โœจ SUPPORTED FORMATS โœจ

okay so bestie, here's the tea on what llvm-objcopy actually eats for the --input-target, --output-target, and --target options ๐Ÿซถ. These are the values it supports rn. And for GNU objcopy compatibility reasons, literally all of them are bfdnames. slay.

  • 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? llvm-objcopy supports them for --output-target only, no cap:

  • srec

Also, heads up: every single target except binary, ihex, and srec can have -freebsd tacked on as a suffix. cute, right? ๐ŸŽ€


๐Ÿงš BINARY INPUT AND OUTPUT ๐Ÿงš

So if you pass binary as the value for --input-target, the input file gets embedded as a data section in an ELF relocatable object. And it gets these three symbols โ€” _binary_<file_name>_start, _binary_<file_name>_end, and _binary_<file_name>_size โ€” representing the start, end, and size of the data. Here <file_name> is the path of the input file exactly as you specified it on the command line, but with all the non-alphanumeric characters converted to _. iconic behavior tbh ๐Ÿ’…

If you use binary as the value for --output-target, the output file will be a raw binary file containing the memory image of the input file. Symbols and relocation information? discarded, gone, not invited to the party ๐Ÿ˜ญ. The image will start at the address of the first loadable section in the output. periodt.


๐Ÿ’€ EXIT STATUS ๐Ÿ’€

llvm-objcopy exits with a non-zero exit code if there's an error. Otherwise it exits with code 0. no drama, no stress ๐ŸŒˆ.


๐Ÿ™ˆ BUGS ๐Ÿ™ˆ

to report bugs, please visit <โ€ https://github.com/llvm/llvm-project/labels/tools:llvm-objcopy/strip/.

โš ๏ธ also there's a known issue with --input-target and --target where only the binary and ihex formats have any effect. the other values get ignored and llvm-objcopy will just attempt to guess the input format. not me finding out the hard way ๐Ÿ’€

๐Ÿฆ‹ SEE ALSO ๐Ÿฆ‹


๐Ÿ‘‘ AUTHOR ๐Ÿ‘‘

Maintained by the LLVM Team (https://llvm.org/). they're serving, fr fr ๐Ÿ’œ


2003-2025, LLVM Project


that's the whole page bestie, you ate ๐Ÿ’…โœจ and for the cute lil sign-off: this was page version 19, dated 2025-01-17, aka LLVM-OBJCOPY(1) โ€” go forth and copy some objects ๐ŸŽ€๐Ÿซถ

๐Ÿ“ฆ where this page comes from