If you've ever worked with Linux or compiled software from source, you've likely used GNU Binutils without even realizing it. The GNU Binutils suite is essential for assembling, linking, and managing binary files. Whether you're a beginner trying to understand how software compiles or an experienced developer debugging an executable, Binutils has got your back.
In this guide, I'll walk you through what GNU Binutils is, its benefits, Key tools, and how to use GNU Binutils for debugging executables in Linux.
Table of Contents
What is GNU Binutils?
GNU Binutils (short for "Binary Utilities") is a set of command-line tools for handling object files, executables, and binary data. These tools help with tasks like assembling code, linking libraries, disassembling executables, and analyzing compiled programs.
The Binutils package includes some of the most important tools in a developer’s toolkit, such as:
- as (the assembler)
- ld (the linker)
- objdump (for inspecting binary files)
- nm (for listing symbols in object files)
- readelf (for reading information about ELF)
- strings (for extracting readable text from binaries)
- strip (for removing unnecessary data from binaries)
- size (for displaying section sizes)
- objcopy (for copying and modifying object files)
- addr2line (for mapping addresses to source code)
- ar (for creating and managing archives)
Benefits
If you’re into programming (especially in languages like C or C++) and system administration, GNU Binutils is something you’ll likely encounter sooner or later.
- If you're a developer, Binutils is a must-have for compiling and debugging software.
- If you're a system administrator, these tools help analyze executables for security and compatibility.
- If you're into reverse engineering, Binutils allows you to inspect and modify binaries.
- For Hobbyists, Binutils helps to learn how executables work under the hood.
- Many popular development environments and operating systems rely on Binutils under the hood.
- Binutils are opensource. You can use, modify, and distribute these tools without worrying about licensing fees.
In short, understanding Binutils can make you a more effective and efficient programmer and system administrator.
How to Use GNU Binutils Tools
Let's break down the most important tools in GNU Binutils and how they can help you.
1. as
: The GNU Assembler
The as
tool converts assembly code into machine code.
Example:
as hello.s -o hello.o
This compiles an assembly source file (hello.s
) into an object file (hello.o
).
2. ld
: The GNU Linker
The ld
tool links object files to create an executable.
Example:
ld -o hello hello.o
This links hello.o
into an executable called hello
.
3. objdump
: Inspect Executable Files
The objdump
command displays detailed information about object files and executables.
Example:
objdump -d /bin/ls | less
This disassembles the ls
command, showing its assembly instructions.
4. nm
: List Symbols in a Binary
The nm
command lists symbols (functions and variables) inside an object file or executable.
Example:
nm hello.o | head
This shows the first few symbols in the hello.o
object file.
5. readelf
: Read ELF Headers
The readelf
tool provides detailed information about ELF (Executable and Linkable Format) files.
Example:
readelf -h /bin/ls
This displays the ELF header of the ls
command.
Related Read:
6. strings
: Extract Readable Text from Binaries
The strings
tool finds and extracts readable text from binary files.
Example:
strings /bin/ls | grep "Usage"
This searches for usage messages inside the ls
binary.
7. strip
: Reduce Binary Size by Removing Symbols
The strip
command removes unnecessary symbols from executables, reducing their size.
Example:
strip myprogram
This minimizes the size of myprogram
by removing debugging symbols.
8. size
: Display Section Sizes
The size
tool shows the memory usage of different sections in an object file.
Example:
size /bin/ls
This displays the text, data, and bss (uninitialized data) segment sizes of ls
.
9. objcopy
: Copy and Modify Object Files
The objcopy
tool allows you to manipulate object files.
Example:
objcopy --only-keep-debug myprogram myprogram.debug
This extracts debugging symbols into a separate file.
10. addr2line
: Map Addresses to Source Code
The addr2line
command helps map a memory address to the original source code line.
Example:
addr2line -e /bin/ls 0x4005a0
This tells you which line in the ls
source code corresponds to the memory address 0x4005a0
.
11. ar
: The Archiver
The ar
tool is used to create and manage archives of object files. These archives, often called static libraries, can be linked into your programs to reuse code.
Example:
You can create a library with ar rcs libmylib.a file1.o file2.o
and then link it to your program.
Practical Example: Debugging a Simple C Program
As we already mentioned, GNU Binutils is a collection of binary tools that are essential for working with executable files, object files, and libraries in Linux. These tools are useful for debugging, disassembling, and analyzing binaries.
In the following example, we'll focus on using objdump
, nm
, and readelf
for debugging purposes.
Tools Overview:
objdump
: Disassembles binary files, displays object file sections, and extracts information from executables.nm
: Lists symbols (functions, variables, etc.) from object files.readelf
: Displays detailed information about ELF (Executable and Linkable Format) files.
Create an Example C Program
Let's start by writing a simple C program, compiling it, and then using Binutils to analyze it.
Step 1: Write a Simple C Program
Create a file named example.c
with the following content:
#include <stdio.h> int add(int a, int b) { return a + b; } int main() { int result = add(3, 4); printf("Result: %d\n", result); return 0; }
Step 2: Compile the Program
Compile the program with debugging symbols included. This will make it easier to analyze:
gcc -g -o example example.c
The -g
flag tells the compiler to include debugging information in the executable.
Step 3: Analyze the Executable with Binutils
1. Using objdump
to Disassemble the Binary
To view the disassembled code of the executable, run:
objdump -d example
This will display the assembly code for the executable. Look for the main
and add
functions in the output. For example:
example: file format elf64-x86-64 Disassembly of section .init: 0000000000001000 <_init>: 1000: 48 83 ec 08 sub $0x8,%rsp 1004: 48 8b 05 c5 2f 00 00 mov 0x2fc5(%rip),%rax # 3fd0 <__gmon_start__@Base> 100b: 48 85 c0 test %rax,%rax 100e: 74 02 je 1012 <_init+0x12> 1010: ff d0 call *%rax 1012: 48 83 c4 08 add $0x8,%rsp 1016: c3 ret Disassembly of section .plt: 0000000000001020 <printf@plt-0x10>: 1020: ff 35 ca 2f 00 00 push 0x2fca(%rip) # 3ff0 <_GLOBAL_OFFSET_TABLE_+0x8> 1026: ff 25 cc 2f 00 00 jmp *0x2fcc(%rip) # 3ff8 <_GLOBAL_OFFSET_TABLE_+0x10> 102c: 0f 1f 40 00 nopl 0x0(%rax) 0000000000001030 <printf@plt>: 1030: ff 25 ca 2f 00 00 jmp *0x2fca(%rip) # 4000 <printf@GLIBC_2.2.5> 1036: 68 00 00 00 00 push $0x0 103b: e9 e0 ff ff ff jmp 1020 <_init+0x20> Disassembly of section .plt.got: 0000000000001040 <__cxa_finalize@plt>: 1040: ff 25 9a 2f 00 00 jmp *0x2f9a(%rip) # 3fe0 <__cxa_finalize@GLIBC_2.2.5> 1046: 66 90 xchg %ax,%ax Disassembly of section .text: 0000000000001050 <_start>: 1050: 31 ed xor %ebp,%ebp 1052: 49 89 d1 mov %rdx,%r9 1055: 5e pop %rsi 1056: 48 89 e2 mov %rsp,%rdx 1059: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp 105d: 50 push %rax 105e: 54 push %rsp 105f: 45 31 c0 xor %r8d,%r8d 1062: 31 c9 xor %ecx,%ecx 1064: 48 8d 3d e2 00 00 00 lea 0xe2(%rip),%rdi # 114d <main> 106b: ff 15 4f 2f 00 00 call *0x2f4f(%rip) # 3fc0 <__libc_start_main@GLIBC_2.34> 1071: f4 hlt 1072: 66 2e 0f 1f 84 00 00 cs nopw 0x0(%rax,%rax,1) 1079: 00 00 00 107c: 0f 1f 40 00 nopl 0x0(%rax) [...]
This output shows the assembly instructions for the add
and main
functions.
2. Using nm
to List Symbols
To list the symbols (functions and variables) in the executable, run:
nm example
You'll see output like this:
0000000000401136 T add 000000000040114a T main U printf@@GLIBC_2.2.5
Here, T
indicates that the symbol is in the text (code) section, and U
indicates an undefined symbol (e.g., printf
, which is linked from the C library).
3. Using readelf
to Inspect the ELF File
To view detailed information about the ELF file, use readelf
. For example, to see the section headers, run:
readelf -S example
This will display information about the sections in the executable, such as .text
(code), .data
(initialized data), and .debug
(debugging information).
To view the symbol table, run:
readelf -s example
This will show all symbols, including their addresses and types.
Debugging with objdump
and gdb
If you want to debug the program, you can use gdb
(GNU Debugger) in combination with objdump
.
Note: If gdb isn't available, you can install it using the default package manager, for example: sudo apt install gdb
.
1. Start gdb
with the executable:
gdb ./example
You will now be in the gdb shell:
GNU gdb (Debian 13.1-3) 13.1 Copyright (C) 2023 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <https://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from ./example... (gdb)
2. Set a breakpoint at the main
function:
break main
3. Run the program:
run
4. Use disassemble
in gdb
to view the disassembled code:
disassemble main
This will show the assembly code for the main
function, similar to what objdump
displayed earlier.
By combining these tools, you can analyze and debug executables effectively in Linux.
Conclusion
GNU Binutils is a must-know toolset for anyone dealing with compiled software. Even if you're new to Linux, learning the basics of these tools can help you understand what’s happening behind the scenes when software runs.