
Introduktion till GNU Binutils: En Nybörjarguide
GNU Binutils för Nybörjare: Kompilera, Länka och Felsöka Programvara
Vad är GNU Binutils?
GNU Binutils (förkortning av ”Binary Utilities”) är en uppsättning kommandoradsverktyg för att hantera objektfiler, körbara filer och binära data. Dessa verktyg används för uppgifter som att assemblra kod, länka bibliotek, disassemblra körbara filer och analysera kompilerade program.
Paketet Binutils innehåller några av de viktigaste verktygen i en utvecklares verktygslåda, såsom:
- as (assemblatorn)
- ld (länkaren)
- objdump (för att inspektera binärfiler)
- nm (för att lista symboler i objektfiler)
- readelf (för att läsa information om ELF-filer)
- strings (för att extrahera läsbar text från binärfiler)
- strip (för att ta bort onödig data från binärfiler)
- size (för att visa sektionernas storlekar)
- objcopy (för att kopiera och modifiera objektfiler)
- addr2line (för att koppla adresser till källkod)
- ar (för att skapa och hantera arkiv)
Fördelar
Om du sysslar med programmering (särskilt i språk som C eller C++) och systemadministration kommer du förr eller senare att stöta på GNU Binutils.
- För utvecklare: Binutils är ett måste för att kompilera och felsöka programvara.
- För systemadministratörer: Dessa verktyg hjälper till att analysera körbara filer för säkerhet och kompatibilitet.
- För de som sysslar med reverse engineering: Binutils gör det möjligt att inspektera och modifiera binärfiler.
- För hobbyister: Binutils hjälper dig att förstå hur körbara filer fungerar under ytan.
- Många populära utvecklingsmiljöer och operativsystem förlitar sig på Binutils i bakgrunden.
- Binutils är öppen källkod: Du kan använda, modifiera och distribuera dessa verktyg utan att oroa dig för licensavgifter.
Kort sagt kan förståelse för Binutils göra dig till en mer effektiv och skicklig programmerare eller systemadministratör.
Hur Man Använder GNU Binutils Verktyg
Låt oss gå igenom några av de viktigaste verktygen i GNU Binutils och hur de kan hjälpa dig.
1. as: GNU Assemblator
as
konverterar assemblerkod till maskinkod.
Exempel:
as hello.s -o hello.o
Detta kompilerar en assembler-källfil (hello.s) till en objektfil (hello.o).
2. ld: GNU Länkare
ld
länkar objektfiler för att skapa en körbar fil.
Exempel:
ld -o hello hello.o
Detta länkar hello.o till en körbar fil kallad hello.
3. objdump: Inspektera Körbara Filer
objdump
visar detaljerad information om objektfiler och körbara filer.
Exempel:
objdump -d /bin/ls | less
Detta disassemblrar kommandot ls, vilket visar dess assemblerinstruktioner.
4. nm: Lista Symboler i en Binär
nm
listar symboler (funktioner och variabler) i en objektfil eller körbar fil.
Exempel:
nm hello.o | head
Detta visar de första symbolerna i objektfilen hello.o.
5. readelf: Läs ELF-huvuden
readelf
ger detaljerad information om ELF-filer (Executable and Linkable Format).
Exempel:
readelf -h /bin/ls
Detta visar ELF-huvudet för kommandot ls.
6. strings: Extrahera Läsbar Text från Binärfiler
Verktyget strings
hittar och extraherar läsbar text från binärfiler.
Exempel:
strings /bin/ls | grep "Usage"
Detta söker efter användningsmeddelanden inuti binärfilen ls.
7. strip: Minska Binärfilens Storlek genom att Ta Bort Symboler
Kommandot strip
tar bort onödiga symboler från körbara filer, vilket minskar deras storlek.
Exempel:
strip myprogram
Detta minimerar storleken på myprogram genom att ta bort felsökningssymboler.
8. size: Visa Sektioners Storlek
Verktyget size
visar minnesanvändningen för olika sektioner i en objektfil.
Exempel:
size /bin/ls
Detta visar storleken på text-, data- och bss-segmenten (oinitierad data) för ls.
9. objcopy: Kopiera och Modifiera Objektfiler
Verktyget objcopy
låter dig manipulera objektfiler.
Exempel:
objcopy --only-keep-debug myprogram myprogram.debug
Detta extraherar felsökningssymboler till en separat fil.
10. addr2line: Kartlägga Adresser till Källkod
Kommandot addr2line
hjälper till att koppla en minnesadress till motsvarande rad i källkoden.
Exempel:
addr2line -e /bin/ls 0x4005a0
Detta visar vilken rad i ls-källkoden som motsvarar minnesadressen 0x4005a0.
11. ar: Arkivverktyget
Verktyget ar
används för att skapa och hantera arkiv med objektfiler. Dessa arkiv, ofta kallade statiska bibliotek, kan länkas in i dina program för att återanvända kod.
Exempel:
Du kan skapa ett bibliotek med:
ar rcs libmylib.a file1.o file2.o
och sedan länka det till ditt program.
Praktiskt Exempel: Felsökning av ett Enkelt C-program
Som tidigare nämnts är GNU Binutils en samling binärverktyg som är avgörande för att arbeta med körbara filer, objektfiler och bibliotek i Linux. Dessa verktyg är användbara för felsökning, disassemblering och analys av binärfiler.
I följande exempel kommer vi att använda objdump, nm och readelf för att felsöka.
Översikt över Verktygen
- objdump: Disassemblerar binärfiler, visar objektfilsektioner och extraherar information från körbara filer.
- nm: Visar symboler (funktioner, variabler, etc.) från objektfiler.
- readelf: Visar detaljerad information om ELF-filer (Executable and Linkable Format).
Skapa ett Exempelprogram i C
Låt oss börja med att skriva ett enkelt C-program, kompilera det och sedan analysera det med Binutils.
Steg 1: Skapa en fil med namnet example.c
Skapa en fil example.c
och lägg in följande innehåll:
#include <stdio.h>
int add(int a, int b) {
return a + b;
}
int main() {
int result = add(3, 4);
printf("Resultat: %d\n", result);
return 0;
}
Steg 2: Kompilera Programmet
Kompilera programmet med felsökningssymboler inkluderade. Detta gör det enklare att analysera:
gcc -g -o example example.c
Flaggan -g
instruerar kompilatorn att inkludera felsökningsinformation i den körbara filen.
Steg 3: Analysera den Körbara Filen med Binutils
1. Använd objdump
för att Disassemblera Binärfilen
För att visa den disassemblerade koden för den körbara filen, kör:
objdump -d example
Detta kommer att visa assemblerkoden för den körbara filen. Leta efter funktionerna main och add i utmatningen.
Exempel på utmatning:
example: filformat elf64-x86-64
Denna utmatning visar att filformatet är ELF (Executable and Linkable Format) för x86-64-arkitekturen.
Jag glömde den inte med flit! Här är hela översättningen inklusive Disassembly of section .init: och resten av analysen. 😊
Steg 3: Analysera den Körbara Filen med Binutils
1. Använd objdump
för att Disassemblera Binärfilen
För att visa den disassemblerade koden för den körbara filen, kör:
objdump -d example
Detta kommer att visa assemblerkoden för den körbara filen. Leta efter funktionerna main och add i utmatningen.
Disassemblering av sektionen .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
Förklaring:
_init
är en särskild funktion som körs innanmain
.- Denna kod sparar utrymme på stacken och anropar
__gmon_start__
, vilket är en funktion som används av GNU-profileringsverktyg. - Om den inte behövs (dvs. om
%rax
är noll), hoppar den över anropet. - Avslutas med
ret
för att återgå till nästa instruktion.
Disassemblering av sektionen .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>
Förklaring:
.plt
(Procedure Linkage Table) används av dynamisk länkning för att anropa externa funktioner, somprintf
.- Här ser vi hoppinstruktioner som används för att skicka kontrollen till
printf
vid körning.
Disassemblering av sektionen .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
Förklaring:
__cxa_finalize
är en funktion som används för att stänga programmet korrekt vid avslut..plt.got
(Global Offset Table) används för att hantera adresser till dynamiska funktioner vid programkörning.
Disassemblering av sektionen .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
Förklaring:
_start
är den första koden som körs när programmet startar.- Den sätter upp stacken och anropar
main
. call *0x2f4f(%rip)
kallar__libc_start_main
, vilket hanterar start avmain
och städning vid programslut.
2. Använd nm
för att Lista Symboler
nm example
Exempel på utmatning:
0000000000401136 T add
000000000040114a T main
U printf@@GLIBC_2.2.5
- T = Symbol i textsektionen (kod).
- U = Odefinierad symbol (
printf
finns i standardbiblioteket).
3. Använd readelf
för att Inspektera ELF-filen
För att visa detaljerad information om ELF-filen, använd readelf
.
För att se sektionernas namn och egenskaper, kör:
readelf -S example
Detta visar information om sektionerna i den körbara filen, såsom:
.text
(kodsektionen, där programkoden finns).data
(initierad data).debug
(felsökningsinformation, om programmet kompilerades med-g
)
För att visa symboltabellen, kör:
readelf -s example
Detta visar alla symboler, inklusive deras adresser och typer.
Felsökning med objdump
och gdb
Om du vill felsöka programmet kan du använda GDB (GNU Debugger) i kombination med objdump
.
Obs! Om gdb
inte är installerat kan du installera det med:
sudo apt install gdb
1. Starta gdb
med den körbara filen
gdb ./example
Nu kommer du att befinna dig i gdb
-skalet:
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>
Detta är fri programvara: du får ändra och distribuera den.
Det finns INGEN GARANTI, i den utsträckning lagen tillåter.
Skriv "show copying" och "show warranty" för mer information.
Den här GDB är konfigurerad som "x86_64-linux-gnu".
Läs symboler från `./example`...
(gdb)
2. Sätt en brytpunkt vid main
break main
Detta gör att programmet pausas när det når main
, så att du kan inspektera register och variabler.
3. Kör programmet
run
Programmet startas och pausas vid main
.
4. Visa den disassemblerade koden i gdb
disassemble main
Detta visar assemblerkoden för main
, ungefär som objdump -d example
gjorde tidigare.
Genom att kombinera dessa verktyg kan du analysera och felsöka körbara filer effektivt i Linux.
Slutsats
GNU Binutils är en viktig verktygssamling för alla som arbetar med kompilerad programvara. Även om du är ny inom Linux kan grundläggande kunskaper om dessa verktyg hjälpa dig att förstå vad som händer i bakgrunden när program körs.
Genom att använda verktyg som objdump
, nm
, readelf
och gdb
, kan du:
✅ Analysera och inspektera binärkod
✅ Felsöka och optimera program
✅ Förstå hur körbara filer är uppbyggda