Home Linux Introduction to GNU Binutils: A Beginner’s Guide

Introduction to GNU Binutils: A Beginner’s Guide

GNU Binutils for Beginners: Compile, Link, Debug Software

By sk
1.3K views 9 mins read

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.

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:

  1. objdump: Disassembles binary files, displays object file sections, and extracts information from executables.
  2. nm: Lists symbols (functions, variables, etc.) from object files.
  3. 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.

You May Also Like

Leave a Comment

* By using this form you agree with the storage and handling of your data by this website.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

This website uses cookies to improve your experience. By using this site, we will assume that you're OK with it. Accept Read More