binutils
Use when building static archives with ar, stripping or converting binaries, mapping crash addresses with addr2line, or demangling C++ symbols. Not for ELF analysis: use elf-inspection.
Install
npx skills add https://github.com/OutlineDriven/outline-driven-development/tree/main/.devin/skills/binutils
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install outlinedriven-outline-driven-development@llmmart
git clone https://github.com/OutlineDriven/outline-driven-development.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole outlinedriven/outline-driven-development collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
GNU binutils
The GNU binutils manipulate existing binaries: static archives, symbol stripping, address to source mapping, and name demangling. Inspection of ELF structure belongs to elf-inspection.
Contract
| Field | Bound contract |
|---|---|
| Trigger | The task creates or modifies a static archive, strips or converts a binary, separates debug info, maps a crash address to source, extracts printable strings, or demangles a symbol. |
| Authority | Reversible local: writes only the archive, binary, or debug files the user names, and preserves each input when producing a new output file; rollback is version control or the preserved input. No remote mutation. |
| Side effect | Local writes to archives, binaries, .debug files, and generated object files. Local reads of every other file. |
| Done | The named artifact exists with the requested transformation applied, verified by re-running the matching inspection command (ar t, file, addr2line, nm -C) on the output. |
Inputs
- The target file or files: required. Name every input; the skill writes only named targets.
- The transformation: required. Create, strip, convert, debuglink, embed, map, or demangle.
- The target architecture: required for cross targets, so the tool prefix is
aarch64-linux-gnu-orarm-none-eabi-instead of the host tools.
Procedure
- Build a static archive with
ar.rinserts,ccreates without a warning,swrites the symbol index. Done when:ar tlists the expected members andnm libfoo.ashows their symbols.
ar rcs libfoo.a foo.o bar.o baz.o
ar t libfoo.a # list members
ar x libfoo.a foo.o # extract one member
ar r libfoo.a new.o # insert or replace
ar d libfoo.a old.o # delete
ranlib libfoo.a # rebuild the index after an external edit
LTO objects carry GIMPLE IR that plain ar indexes incorrectly. Use gcc-ar and gcc-ranlib for GCC, or llvm-ar for Clang.
- Strip a binary. Choose the flag from what must survive. Done when:
file progreportsstripped(or not) as intended, and the symbols that must remain do.
strip --strip-all prog # smallest output, no symbols
strip --strip-debug prog # keep the symbol table for crash reports
strip --strip-unneeded prog # for shared libraries: keep exported symbols
strip -o prog.stripped prog # write a copy, preserve the input
- Separate debug info so a small shipped binary still debugs. Done when: GDB loads
prog.debugthrough the debuglink without a manualsymbol-file.
gcc -g -O2 -o prog main.c
objcopy --only-keep-debug prog prog.debug # save debug info
strip --strip-debug prog # slim the shipped binary
objcopy --add-gnu-debuglink=prog.debug prog # GDB finds prog.debug by name
- Convert and reshape binaries with
objcopy. Done when: the output loads on the target or links into the project.
objcopy -O binary prog prog.bin # raw binary for embedded flashing
objcopy -O ihex prog prog.hex # Intel HEX
objcopy -O srec prog prog.srec # Motorola S-record
objcopy --remove-section .comment prog
objcopy --rename-section .text=.boot_text prog
objcopy --compress-debug-sections prog
Embed a data file as linkable symbols. The --rename-section flags move the blob out of .data so it lands in read-only memory:
objcopy -I binary -O elf64-x86-64 \
--rename-section .data=.rodata,alloc,load,readonly,data,contents \
data.bin data_blob.o
# links as _binary_data_bin_start / _binary_data_bin_end / _binary_data_bin_size
- Map a crash address to source with
addr2line. The binary needs debug info from-g. For a stripped binary, point-eat the unstripped build or the.debugfile. Done when: every address resolves to a file and line, with inline frames shown by-i.
addr2line -e prog -f -i 0x400a12
grep -o '0x[0-9a-f]*' crash.log | addr2line -e prog -f -i
- Demangle C++ symbols with
c++filt, or letnm -Cdemangle inline. Done when: the mangled name from the linker error or crash log reads as a plain signature.
c++filt _ZN3foo3barEv # foo::bar()
nm prog | c++filt
- Extract printable strings. Default minimum length is 4; raise it with
-nto cut noise. Print offsets with-t xso a hit can be located in a hex dump. Done when: the searched string and its offset are reported. Scan only data sections with-dto skip code bytes.
strings -n 8 -t x prog
strings -d prog | grep -i version
objdump -s -j .rodata prog # dump the section itself, no version quirks
- For cross-compiled targets, prefix every tool with the target triplet; the host tools reject foreign objects. Done when: each command runs the triplet-prefixed tool.
aarch64-linux-gnu-objcopy -O binary prog prog.bin
aarch64-linux-gnu-addr2line -e prog -f 0x400a12
arm-none-eabi-nm libfirmware.a
Failure and recovery
| Failure class | Behavior |
|---|---|
addr2line prints ??:0 |
The binary has no debug info, or the address comes from a different build. Point -e at the exact build, or rebuild with -g. |
x: index not found from ar or link errors on an LTO archive |
The archive was built with plain ar. Rebuild it with gcc-ar or llvm-ar. |
| Strip removed a needed symbol | Redo the strip from the preserved input with --strip-debug or --strip-unneeded instead of --strip-all. |
objcopy rejects the format |
The target architecture differs from the host tool. Switch to the triplet-prefixed tool and pass the matching -O format. |
| Debuglink does not resolve | GDB searches a build-id route and fixed dirs, not next to the binary by default. Verify with readelf -n prog that the build ID matches prog.debug. |
Output
The transformed artifact plus a one-line verification per step: archive members, file classification of the stripped output, an addr2line resolution, or the demangled symbol. A reference table of the flags above is in references/cheatsheet.md.
Files (outline-driven-development)
-
agents
-
openai.yaml 205 B
interface: display_name: "Binutils" short_description: "Use when building static archives with ar, stripping or converting binaries, mapping crash addresses with addr2line, or demangling C++ symbols."
-
-
references
-
cheatsheet.md 4.6 KB
# GNU binutils cheatsheet Sources: <https://sourceware.org/binutils/docs/binutils/> and the binutils man pages. ## ar: static archives ```bash ar rcs libfoo.a foo.o bar.o baz.o # insert, create, index ar t libfoo.a # list members ar tv libfoo.a # verbose: sizes and dates ar x libfoo.a foo.o # extract one member ar r libfoo.a new.o # insert or replace ar d libfoo.a old.o # delete ar m libfoo.a foo.o # move member to end ar p libfoo.a foo.o # print member to stdout ar s libfoo.a # rebuild index, same as ranlib nm libfoo.a # symbols across all members ``` Operation codes: | Code | Meaning | |------|---------| | `r` | Insert or replace members | | `d` | Delete members | | `t` | List contents | | `x` | Extract members | | `p` | Print a member to stdout | | `m` | Move members | | `s` | Write the symbol index | Modifiers appended to the operation: | Modifier | Meaning | |----------|---------| | `c` | Create the archive if absent | | `s` | Write the index | | `v` | Verbose | | `u` | Copy only files newer than the archive copy | | `D` | Deterministic mode: zero timestamps and UIDs, reproducible builds | LTO archives need the toolchain driver: `gcc-ar`, `gcc-ranlib`, or `llvm-ar`. ## strip: remove symbols ```bash strip --strip-all prog # smallest output strip --strip-debug prog # keep the symbol table strip --strip-unneeded prog # keep dynamic symbols for shared libraries strip -o prog.stripped prog # write a copy, keep the input strip --remove-section=.comment prog strip -v prog # report what was removed ``` Distribution split: ```bash gcc -g -O2 -o prog main.c objcopy --only-keep-debug prog prog.debug strip --strip-debug prog objcopy --add-gnu-debuglink=prog.debug prog ``` ## objcopy: binary transformation ```bash objcopy --only-keep-debug prog prog.debug objcopy --strip-debug prog objcopy --add-gnu-debuglink=prog.debug prog objcopy -O binary prog prog.bin # raw binary objcopy -O ihex prog prog.hex # Intel HEX objcopy -O srec prog prog.srec # Motorola S-record objcopy --add-section .firmware=firmware.bin \ --set-section-flags .firmware=alloc,load,readonly,contents prog objcopy --remove-section .comment prog objcopy --rename-section .text=.boot_text prog objcopy --compress-debug-sections prog objcopy --change-start 0x1000 prog # shift the entry address ``` Embed a blob as linkable symbols: ```bash objcopy -I binary -O elf64-x86-64 \ --rename-section .data=.rodata,alloc,load,readonly,data,contents \ data.bin data_blob.o # defines _binary_data_bin_start, _binary_data_bin_end, _binary_data_bin_size ``` Format flags: | Flag | Meaning | |------|---------| | `-I binary` | Input is a raw binary | | `-I elf64-x86-64` | Input is 64-bit ELF | | `-O binary` | Output raw binary | | `-O ihex` | Output Intel HEX | | `-O srec` | Output Motorola S-record | | `-O elf32-littlearm` | Output 32-bit little-endian ARM ELF | | `-B i386:x86-64` | Set the architecture | ## addr2line: address to source ```bash addr2line -e prog 0x400a12 # file:line addr2line -e prog -f 0x400a12 # add the function name addr2line -e prog -f 0x400a12 0x400b34 0x401000 addr2line -e prog -f -i 0x400a12 # unwind inline frames addr2line -e prog -p -f -i 0x400a12 # one readable line per frame grep -o '0x[0-9a-f]*' crash.log | addr2line -e prog -f -i ``` The binary needs `-g`. For a stripped binary, point `-e` at the debug build or `.debug` file. ## strings: extract text ```bash strings prog # minimum length 4 strings -n 8 prog # minimum length 8 strings -t x prog # offsets in hex strings -t d prog # offsets in decimal strings -d prog # scan data sections only strings prog | grep -i version objdump -s -j .rodata prog # dump a section; strings has no section filter ``` ## c++filt: demangle symbols ```bash c++filt _ZN3foo3barEv echo _ZN3foo3barEv | c++filt nm prog | c++filt nm -C prog # demangle inside nm ``` ## ranlib: archive index ```bash ranlib libfoo.a # same as: ar s libfoo.a gcc-ranlib libfoo.a # GCC LTO archives llvm-ranlib libfoo.a # LLVM LTO archives ``` ## Cross-binutils naming Prefix every tool with the target triplet: ```bash aarch64-linux-gnu-ar rcs libfoo.a foo.o aarch64-linux-gnu-strip prog aarch64-linux-gnu-objcopy -O binary prog prog.bin aarch64-linux-gnu-addr2line -e prog -f 0x400a12 aarch64-linux-gnu-nm libfoo.a aarch64-linux-gnu-strings prog arm-none-eabi-objcopy -O binary firmware.elf firmware.bin arm-none-eabi-size firmware.elf ```
-
-
SKILL.md 6.1 KB
--- name: binutils description: 'Use when building static archives with ar, stripping or converting binaries, mapping crash addresses with addr2line, or demangling C++ symbols. Not for ELF analysis: use elf-inspection.' --- # GNU binutils The GNU binutils manipulate existing binaries: static archives, symbol stripping, address to source mapping, and name demangling. Inspection of ELF structure belongs to `elf-inspection`. ## Contract | Field | Bound contract | |---|---| | Trigger | The task creates or modifies a static archive, strips or converts a binary, separates debug info, maps a crash address to source, extracts printable strings, or demangles a symbol. | | Authority | Reversible local: writes only the archive, binary, or debug files the user names, and preserves each input when producing a new output file; rollback is version control or the preserved input. No remote mutation. | | Side effect | Local writes to archives, binaries, `.debug` files, and generated object files. Local reads of every other file. | | Done | The named artifact exists with the requested transformation applied, verified by re-running the matching inspection command (`ar t`, `file`, `addr2line`, `nm -C`) on the output. | ## Inputs - The target file or files: required. Name every input; the skill writes only named targets. - The transformation: required. Create, strip, convert, debuglink, embed, map, or demangle. - The target architecture: required for cross targets, so the tool prefix is `aarch64-linux-gnu-` or `arm-none-eabi-` instead of the host tools. ## Procedure 1. Build a static archive with `ar`. `r` inserts, `c` creates without a warning, `s` writes the symbol index. Done when: `ar t` lists the expected members and `nm libfoo.a` shows their symbols. ```bash ar rcs libfoo.a foo.o bar.o baz.o ar t libfoo.a # list members ar x libfoo.a foo.o # extract one member ar r libfoo.a new.o # insert or replace ar d libfoo.a old.o # delete ranlib libfoo.a # rebuild the index after an external edit ``` LTO objects carry GIMPLE IR that plain `ar` indexes incorrectly. Use `gcc-ar` and `gcc-ranlib` for GCC, or `llvm-ar` for Clang. 2. Strip a binary. Choose the flag from what must survive. Done when: `file prog` reports `stripped` (or not) as intended, and the symbols that must remain do. ```bash strip --strip-all prog # smallest output, no symbols strip --strip-debug prog # keep the symbol table for crash reports strip --strip-unneeded prog # for shared libraries: keep exported symbols strip -o prog.stripped prog # write a copy, preserve the input ``` 3. Separate debug info so a small shipped binary still debugs. Done when: GDB loads `prog.debug` through the debuglink without a manual `symbol-file`. ```bash gcc -g -O2 -o prog main.c objcopy --only-keep-debug prog prog.debug # save debug info strip --strip-debug prog # slim the shipped binary objcopy --add-gnu-debuglink=prog.debug prog # GDB finds prog.debug by name ``` 4. Convert and reshape binaries with `objcopy`. Done when: the output loads on the target or links into the project. ```bash objcopy -O binary prog prog.bin # raw binary for embedded flashing objcopy -O ihex prog prog.hex # Intel HEX objcopy -O srec prog prog.srec # Motorola S-record objcopy --remove-section .comment prog objcopy --rename-section .text=.boot_text prog objcopy --compress-debug-sections prog ``` Embed a data file as linkable symbols. The `--rename-section` flags move the blob out of `.data` so it lands in read-only memory: ```bash objcopy -I binary -O elf64-x86-64 \ --rename-section .data=.rodata,alloc,load,readonly,data,contents \ data.bin data_blob.o # links as _binary_data_bin_start / _binary_data_bin_end / _binary_data_bin_size ``` 5. Map a crash address to source with `addr2line`. The binary needs debug info from `-g`. For a stripped binary, point `-e` at the unstripped build or the `.debug` file. Done when: every address resolves to a file and line, with inline frames shown by `-i`. ```bash addr2line -e prog -f -i 0x400a12 grep -o '0x[0-9a-f]*' crash.log | addr2line -e prog -f -i ``` 6. Demangle C++ symbols with `c++filt`, or let `nm -C` demangle inline. Done when: the mangled name from the linker error or crash log reads as a plain signature. ```bash c++filt _ZN3foo3barEv # foo::bar() nm prog | c++filt ``` 7. Extract printable strings. Default minimum length is 4; raise it with `-n` to cut noise. Print offsets with `-t x` so a hit can be located in a hex dump. Done when: the searched string and its offset are reported. Scan only data sections with `-d` to skip code bytes. ```bash strings -n 8 -t x prog strings -d prog | grep -i version objdump -s -j .rodata prog # dump the section itself, no version quirks ``` 8. For cross-compiled targets, prefix every tool with the target triplet; the host tools reject foreign objects. Done when: each command runs the triplet-prefixed tool. ```bash aarch64-linux-gnu-objcopy -O binary prog prog.bin aarch64-linux-gnu-addr2line -e prog -f 0x400a12 arm-none-eabi-nm libfirmware.a ``` ## Failure and recovery | Failure class | Behavior | |---|---| | `addr2line` prints `??:0` | The binary has no debug info, or the address comes from a different build. Point `-e` at the exact build, or rebuild with `-g`. | | `x: index not found` from `ar` or link errors on an LTO archive | The archive was built with plain `ar`. Rebuild it with `gcc-ar` or `llvm-ar`. | | Strip removed a needed symbol | Redo the strip from the preserved input with `--strip-debug` or `--strip-unneeded` instead of `--strip-all`. | | `objcopy` rejects the format | The target architecture differs from the host tool. Switch to the triplet-prefixed tool and pass the matching `-O` format. | | Debuglink does not resolve | GDB searches a build-id route and fixed dirs, not next to the binary by default. Verify with `readelf -n prog` that the build ID matches `prog.debug`. | ## Output The transformed artifact plus a one-line verification per step: archive members, `file` classification of the stripped output, an `addr2line` resolution, or the demangled symbol. A reference table of the flags above is in `references/cheatsheet.md`.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.