Introduction à GNU Binutils : Guide du débutant
Si vous avez déjà travaillé avec Linux ou compilé un logiciel à partir du code source, vous avez probablement utilisé GNU Binutils sans même vous en rendre compte. La suite GNU Binutils est essentielle pour l'assemblage, la liaison et la gestion des fichiers binaires. Que vous soyez un débutant essayant de comprendre comment un logiciel se compile ou un développeur expérimenté déboguant un exécutable, Binutils est là pour vous.
Dans ce guide, je vais vous expliquer ce qu'est GNU Binutils, ses avantages, les outils clés, et comment utiliser GNU Binutils pour déboguer des exécutables sous Linux.
Qu'est-ce que GNU Binutils ?
GNU Binutils (abréviation de "Binary Utilities") est un ensemble d'outils en ligne de commande pour la gestion des fichiers objets, des exécutables et des données binaires. Ces outils aident à des tâches telles que l'assemblage de code, la liaison de bibliothèques, le désassemblage d'exécutables et l'analyse de programmes compilés.
Le paquet Binutils inclut certains des outils les plus importants dans la boîte à outils d’un développeur, tels que :
- as (l'assembleur)
- ld (l'éditeur de liens)
- objdump (pour inspecter les fichiers binaires)
- nm (pour lister les symboles dans les fichiers objets)
- readelf (pour lire des informations sur ELF)
- chaînes (pour extraire du texte lisible à partir de fichiers binaires)
- strip (pour supprimer les données inutiles des binaires)
- taille (pour afficher les tailles des sections)
- objcopy (pour copier et modifier des fichiers objets)
- addr2line (pour mapper les adresses au code source)
- ar (pour créer et gérer des archives)
Avantages
Si vous vous intéressez à la programmation (en particulier dans des langages comme C ou C++) et à l'administration système, GNU Binutils est quelque chose que vous rencontrerez probablement tôt ou tard.
- Si vous êtes développeur, Binutils est un incontournable pour compiler et déboguer des logiciels.
- Si vous êtes un administrateur système, ces outils aident à analyser les exécutables pour la sécurité et la compatibilité.
- Si vous vous intéressez à l'ingénierie inverse, Binutils vous permet d'inspecter et de modifier des binaires.
- Pour les amateurs, Binutils aide à apprendre comment les exécutables fonctionnent en coulisses.
- De nombreux environnements de développement et systèmes d'exploitation populaires dépendent de Binutils en coulisses.
- Binutils sont open source. Vous pouvez utiliser, modifier et distribuer ces outils sans vous soucier des frais de licence.
En résumé, comprendre Binutils peut faire de vous un programmeur et un administrateur système plus efficace et efficient.
Comment utiliser les outils GNU Binutils
Décomposons les outils les plus importants de GNU Binutils et voyons comment ils peuvent vous aider.
1. as : L'assembleur GNU
L'outil as convertit le code assembleur en code machine.
Exemple :
as hello.s -o hello.oCela compile un fichier source assembleur (hello.s) en un fichier objet (hello.o).
2. ld : Le lieur GNU
L'outil ld lie les fichiers objets pour créer un exécutable.
Exemple :
ld -o hello hello.oCela lie hello.o dans un exécutable appelé hello.
3. objdump : Inspecter les fichiers exécutables
La commande objdump affiche des informations détaillées sur les fichiers objets et les fichiers exécutables.
Exemple :
objdump -d /bin/ls | less
Cela désassemble la commande ls, montrant ses instructions en assembleur.
4. nm : Lister les symboles dans un binaire
La commande nm liste les symboles (fonctions et variables) à l'intérieur d'un fichier objet ou exécutable.
Exemple :
nm hello.o | headCeci montre les premiers symboles dans le fichier objet hello.o.
5. readelf : Lire les en-têtes ELF
L'outil readelf fournit des informations détaillées sur les fichiers ELF (Executable and Linkable Format).
Exemple :
readelf -h /bin/lsCela affiche l'en-tête ELF de la commande ls.
Lecture connexe :
- Introduction à ELF sous Linux : Un guide simple des fichiers exécutables
- Comment analyser des binaires ELF avec Binsider sous Linux
6. strings : Extraire du texte lisible à partir de fichiers binaires
L'outil strings trouve et extrait le texte lisible des fichiers binaires.
Exemple :
strings /bin/ls | grep "Usage"
Cela recherche les messages d'utilisation à l'intérieur du binaire ls.
7. strip : Réduire la taille binaire en supprimant les symboles
La commande strip supprime les symboles inutiles des exécutables, réduisant ainsi leur taille.
Exemple :
strip myprogramCela réduit la taille de myprogram en supprimant les symboles de débogage.
8. size : Afficher la taille des sections
L'outil size montre l'utilisation de la mémoire des différentes sections dans un fichier objet.
Exemple :
size /bin/lsCeci affiche les tailles des segments texte, données et bss (données non initialisées) de ls.
9. objcopy : Copier et modifier des fichiers objet
L'outil objcopy vous permet de manipuler des fichiers objets.
Exemple :
objcopy --only-keep-debug myprogram myprogram.debugCela extrait les symboles de débogage dans un fichier séparé.
10. addr2line : Mapper les adresses au code source
La commande addr2line aide à mapper une adresse mémoire à la ligne de code source originale.
Exemple :
addr2line -e /bin/ls 0x4005a0Cela vous indique quelle ligne dans le code source de ls correspond à l'adresse mémoire 0x4005a0.
11. ar : L'Archiver
L'outil ar est utilisé pour créer et gérer des archives de fichiers objets. Ces archives, souvent appelées bibliothèques statiques, peuvent être liées à vos programmes pour réutiliser du code.
Exemple:
Vous pouvez créer une bibliothèque avec ar rcs libmylib.a file1.o file2.o puis la lier à votre programme.
Exemple pratique : Débogage d'un programme C simple
Comme nous l'avons déjà mentionné, GNU Binutils est une collection d'outils binaires essentiels pour travailler avec des fichiers exécutables, des fichiers objets et des bibliothèques sous Linux. Ces outils sont utiles pour le débogage, le désassemblage et l'analyse des binaires.
Dans l'exemple suivant, nous nous concentrerons sur l'utilisation de objdump, nm et readelf à des fins de débogage.
Aperçu des outils :
objdump: Désassemble les fichiers binaires, affiche les sections des fichiers objets et extrait des informations des exécutables.nm: Liste les symboles (fonctions, variables, etc.) à partir des fichiers objets.readelf: Affiche des informations détaillées sur les fichiers ELF (Executable and Linkable Format).
Créer un exemple de programme C
Commençons par écrire un programme C simple, le compiler, puis utiliser Binutils pour l'analyser.
Étape 1 : Écrire un programme C simple
Créez un fichier nommé example.c avec le contenu suivant :
#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;
}Étape 2 : Compiler le programme
Compilez le programme avec les symboles de débogage inclus. Cela facilitera l'analyse :
gcc -g -o example example.cL'option -g indique au compilateur d'inclure des informations de débogage dans l'exécutable.
Étape 3 : Analyser l'exécutable avec Binutils
1. Utilisation de objdump pour désassembler le binaire
Pour afficher le code désassemblé de l'exécutable, exécutez :
objdump -d exampleCela affichera le code assembleur de l'exécutable. Recherchez les fonctions main et add dans la sortie. Par exemple :
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)
[...]Cette sortie montre les instructions d'assemblage pour les fonctions add et main.
2. Utilisation de nm pour lister les symboles
Pour lister les symboles (fonctions et variables) dans l'exécutable, exécutez :
nm exampleVous verrez une sortie comme celle-ci :
0000000000401136 T add
000000000040114a T main
U printf@@GLIBC_2.2.5Ici, T indique que le symbole se trouve dans la section de texte (code), et U indique un symbole non défini (par exemple, printf, qui est lié depuis la bibliothèque C).
3. Utilisation de readelf pour inspecter le fichier ELF
Pour afficher des informations détaillées sur le fichier ELF, utilisez readelf. Par exemple, pour voir les en-têtes de section, exécutez :
readelf -S exampleCela affichera des informations sur les sections de l'exécutable, telles que .text (code), .data (données initialisées) et .debug (informations de débogage).
Pour afficher la table des symboles, exécutez :
readelf -s exampleCeci affichera tous les symboles, y compris leurs adresses et types.
Débogage avec objdump et gdb
Si vous voulez déboguer le programme, vous pouvez utiliser gdb (GNU Debugger) en combinaison avec objdump.
Remarque : si gdb n'est pas disponible, vous pouvez l'installer en utilisant le gestionnaire de paquets par défaut, par exemple : sudo apt install gdb.
1. Démarrez gdb avec l'exécutable :
gdb ./exampleVous serez maintenant dans le shell 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. Placez un point d'arrêt à la fonction main :
break main3. Exécutez le programme :
run4. Utilisez disassemble dans gdb pour voir le code désassemblé :
disassemble mainCela affichera le code assembleur pour la fonction main, similaire à ce que objdump a affiché plus tôt.
En combinant ces outils, vous pouvez analyser et déboguer efficacement des exécutables sous Linux.
Conclusion
GNU Binutils est un ensemble d'outils indispensable pour quiconque travaille avec des logiciels compilés. Même si vous êtes nouveau sur Linux, apprendre les bases de ces outils peut vous aider à comprendre ce qui se passe en coulisses lorsque le logiciel s'exécute.