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.5Here, 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.
