Если вы когда-либо работали с Linux или компилировали программное обеспечение из исходного кода, то, скорее всего, использовали GNU Binutils, даже не подозревая об этом. Набор GNU Binutils необходим для сборки, компоновки и управления двоичными файлами. Независимо от того, являетесь ли вы новичком, пытающимся понять, как компилируется программное обеспечение, или опытным разработчиком, отлаживающим исполняемый файл, Binutils поможет вам.
В этой статье мы расскажем вам, что такое GNU Binutils, о его преимуществах, основных инструментах и о том, как использовать GNU Binutils для отладки исполняемых файлов в Linux.
Что такое GNU Binutils?
GNU Binutils (сокращение от «бинарные утилиты») — это набор инструментов командной строки для работы с объектными файлами, исполняемыми файлами и двоичными данными. Эти инструменты помогают выполнять такие задачи, как сборка кода, связывание библиотек, дизассемблирование исполняемых файлов и анализ скомпилированных программ.
Пакет Binutils включает в себя некоторые из наиболее важных инструментов в наборе разработчика, такие как:
- as (ассемблер)
- ld (компоновщик)
- objdump (для проверки двоичных файлов)
- nm (для перечисления символов в объектных файлах)
- readelf (для чтения информации о ELF)
- strings (для извлечения читаемого текста из двоичных файлов)
- strip (для удаления ненужных данных из двоичных файлов)
- размер (для отображения размеров сечений)
- objcopy (для копирования и изменения объектных файлов)
- addr2line (для сопоставления адресов с исходным кодом)
- ar (для создания архивов и управления ими)
Преимущества
Если вы увлекаетесь программированием (особенно на таких языках, как C или C++) и системным администрированием, то рано или поздно столкнётесь с GNU Binutils.
- Если вы разработчик, Binutils — обязательный инструмент для компиляции и отладки программного обеспечения.
- Если вы системный администратор, эти инструменты помогут проанализировать исполняемые файлы на предмет безопасности и совместимости.
- Если вы увлекаетесь реверс-инжинирингом, Binutils позволяет проверять и изменять двоичные файлы.
- Для любителей Binutils помогает понять, как работают исполняемые файлы.
- Многие популярные среды разработки и операционные системы изначально полагаются на Binutils.
- Binutils — это программное обеспечение с открытым исходным кодом. Вы можете использовать, изменять и распространять эти инструменты, не беспокоясь о лицензионных сборах.
Короче говоря, понимание Binutils поможет вам стать более эффективным программистом и системным администратором.
Как использовать инструменты GNU Binutils
Давайте рассмотрим наиболее важные инструменты GNU Binutils и то, как они могут вам помочь.
1. as
: Ассемблер GNU
Инструмент as
преобразует ассемблерный код в машинный.
Пример:
as hello.s -o hello.o
Это компилирует исходный файл сборки (hello.s
) в объектный файл (hello.o
).
2. ld
: Компоновщик GNU
Инструмент ld
связывает объектные файлы для создания исполняемого файла.
Пример:
ld -o hello hello.o
Это связывает hello.o
с исполняемым файлом с именем hello
.
3. objdump
: Проверьте исполняемые файлы
Команда objdump
отображает подробную информацию об объектных файлах и исполняемых файлах.
Пример:
ld -o hello hello.o
При этом команда ls разбирается, показывая инструкции по ее сборке.
4. nm
: Список символов в двоичном файле
Команда nm
выводит список символов (функций и переменных) внутри объектного файла или исполняемого файла.
Пример:
objdump -d /bin/ls | less
Здесь показаны первые несколько символов в объектном файле hello.o
.
5. readelf
: Прочитайте заголовки ELF
Инструмент readelf
предоставляет подробную информацию о файлах ELF (исполняемый и компонуемый формат).
Пример:
readelf -h /bin/ls
При этом отображается заголовок ELF команды ls
.
6. strings
: Извлечение читаемого текста из двоичных файлов
Инструмент strings
находит и извлекает читаемый текст из двоичных файлов.
Пример:
strings /bin/ls | grep "Usage"
При этом выполняется поиск сообщений об использовании внутри двоичного файла ls
.
7. strip
: Уменьшите размер двоичного файла, удалив символы
Команда strip
удаляет ненужные символы из исполняемых файлов, уменьшая их размер.
Пример:
strip myprogram
Это сводит к минимуму размер myprogram
за счет удаления символов отладки.
8. size
: Отображение размеров секций
Инструментsize
показывает использование памяти различными разделами объектного файла.
Пример:
size /bin/ls
Здесь отображаются размеры сегментов текста, данных и bss (неинициализированных данных) для ls
.
9. objcopy
: Копирование и изменение объектных файлов
Инструментobjcopy
позволяет вам манипулировать объектными файлами.
Пример:
objcopy --only-keep-debug myprogram myprogram.debug
При этом символы отладки извлекаются в отдельный файл.
10. addr2line
: Сопоставление адресов с исходным кодом
Команда addr2line
помогает сопоставить адрес памяти с исходной строкой исходного кода.
Пример:
addr2line -e /bin/ls 0x4005a0
Это показывает, какая строка в исходном коде ls
соответствует адресу памяти 0x4005a0
.
11. ar
: Архиватор
Инструмент ar
используется для создания архивов объектных файлов и управления ими. Эти архивы, часто называемые статическими библиотеками, можно подключать к программам для повторного использования кода.
Пример:
Вы можете создать библиотеку с помощью ar rcs libmylib.a file1.o file2.o
, а затем связать ее со своей программой.
Практический пример: Отладка простой программы на языке Си
Как мы уже упоминали, GNU Binutils — это набор двоичных инструментов, необходимых для работы с исполняемыми, объектными файлами и библиотеками в Linux. Эти инструменты полезны для отладки, дизассемблирования и анализа двоичных файлов.
В следующем примере мы сосредоточимся на использовании objdump
, nm
и readelf
для целей отладки.
Обзор инструментов:
objdump
: Разбирает двоичные файлы, отображает разделы объектных файлов и извлекает информацию из исполняемых файлов.nm
: Перечисляет символы (функции, переменные и т.д.) Из объектных файлов.readelf
: Отображает подробную информацию о файлах ELF (исполняемый и компонуемый формат).
Создайте пример программы на языке Си
Давайте начнём с написания простой программы на C, её компиляции, а затем анализа с помощью Binutils.
Шаг 1: Напишите простую программу на C
Создайте файл с именем example.c
со следующим содержимым:
#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; }
Шаг 2: Скомпилируйте программу
Скомпилируйте программу с включёнными символами отладки. Это упростит анализ:
gcc -g -o example example.c
Флаг -g
указывает компилятору включить отладочную информацию в исполняемый файл.
Шаг 3: Проанализируйте исполняемый файл с помощью Binutils
1. Использование objdump
для дизассемблирования двоичного файла
Чтобы просмотреть дизассемблированный код исполняемого файла, запустите:
objdump -d example
Это отобразит код сборки исполняемого файла. Найдите в выводе функции main
и add
. Например:
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) [...]
В этом выводе показаны инструкции по сборке для функций add
и main
.
2. Использование nm
для перечисления символов
Чтобы составить список символов (функций и переменных) в исполняемом файле, выполните:
nm example
Вы увидите результат, подобный этому:
0000000000401136 T add 000000000040114a T main U printf@@GLIBC_2.2.5
Здесь T
указывает на то, что символ находится в текстовом (кодовом) разделе, а U
указывает на неопределённый символ (например, printf
, который связан с библиотекой C).
3. Использование readelf
для проверки файла ELF
Чтобы просмотреть подробную информацию о файле ELF, используйте readelf
. Например, чтобы увидеть заголовки разделов, выполните:
readelf -S example
Это отобразит информацию о разделах исполняемого файла, таких как .text
(код), .data
(инициализированные данные) и .debug
(информация для отладки).
Чтобы просмотреть таблицу символов, выполните:
readelf -s example
При этом будут показаны все символы, включая их адреса и типы.
Отладка с помощью objdump
и gdb
Если вы хотите отладить программу, вы можете использовать gdb
(GNU Debugger) в сочетании с objdump
.
Примечание: если gdb недоступен, вы можете установить его с помощью менеджера пакетов по умолчанию, например:
sudo apt install gdb
1. Начните gdb
с исполняемого файла:
gdb ./example
Теперь вы будете находиться в оболочке gdb:
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. Установите точку останова в функции main
:
break main
3. Запустите программу:
run
4. Используйте disassemble
in gdb
для просмотра дизассемблированного кода:
disassemble main
Здесь будет показан код сборки для функции main
, аналогичный тому, что был показан ранее для objdump
Комбинируя эти инструменты, вы можете эффективно анализировать и отлаживать исполняемые файлы в Linux.
Заключение
GNU Binutils — это обязательный к изучению набор инструментов для всех, кто работает с компилированным программным обеспечением. Даже если вы новичок в Linux, изучение основ этих инструментов поможет вам понять, что происходит за кулисами при запуске программного обеспечения.