Utilitas Biner GNU, biasanya disebut sebagai binutils, adalah kumpulan alat pengembangan yang menangani file perakitan, file objek , dan perpustakaan.
Generasi baru bahasa pemrograman yang datang dalam beberapa tahun terakhir benar-benar menutupi fungsionalitas utilitas ini, seperti yang terjadi di latar belakang. Jadi, banyak pengembang yang tidak menggunakan alat ini.
Namun, jika Anda seorang pengembang yang bekerja pada platform Linux / UNIX, penting untuk memahami berbagai perintah yang tersedia sebagai bagian dari alat pengembangan GNU.
Berikut ini adalah 12 perintah binutils berbeda yang tercakup dalam tutorial ini.
- sebagai – Perintah Perakit GNU
- ld – Perintah Penaut GNU
- ar – Perintah Arsip GNU
- nm – Mencantumkan Simbol File Objek
- objcopy – Menyalin dan Menerjemahkan File Objek
- objdump – Menampilkan Informasi File Objek
- ukuran – Daftar Ukuran Bagian dan Ukuran Toal
- string – Menampilkan Karakter yang Dapat Dicetak dari File
- strip – Buang Simbol dari File Objek
- c++filt – Perintah Demangle
- addr2line – Mengonversi Alamat ke Nama File dan Angka
- readelf – Menampilkan Info File ELF
Alat ini akan membantu Anda untuk memanipulasi file biner, objek, dan perpustakaan Anda secara efektif.
Dari 12 utilitas ini, as dan ld adalah yang paling penting, mereka adalah backend default dari GNU Compiler Collection (gcc). GCC hanya melakukan pekerjaan yang dikompilasi dari C/C++ ke bahasa assembly, dan tugas as dan ld untuk menghasilkan biner yang dapat dieksekusi.
Siapkan Kode Contoh
Untuk memahami bagaimana semua perintah ini bekerja, pertama, mari kita siapkan beberapa contoh kode assembly dari kode C dengan menggunakan gcc -S. Semua eksperimen yang ditampilkan di sini, dilakukan pada kotak linux x86 64bits.
Di bawah ini adalah kode C, yang hanya menggunakan nilai balik dari fungsi eksternal sebagai kode pengembalian. Tidak ada input/output, jadi jika ingin mengecek apakah program sudah dijalankan seperti yang diharapkan, silahkan cek kembali statusnya (echo $?). Kami memiliki tiga fungsi, main, func1 dan func2, dan satu file untuk setiap fungsi.
// func1.c file: int func1() { return func2(); } // func2.c file: int func2() { return 1; } // main.c file: int main() { return func1(); }
GCC memiliki dukungan library runtime C, sehingga fungsi utama diperlakukan sebagai fungsi normal. Untuk menyederhanakan demo, kami tidak ingin melibatkan pustaka C saat mengkompilasi dan menautkan file .s ini. Jadi, dua modifikasi dilakukan untuk main.s:
Modifikasi pertama adalah label _start ditambahkan untuk tahap tautan.
_start label adalah titik masuk Aplikasi, jika tidak ditentukan, peringatan seperti di bawah ini akan dilaporkan saat dijalankan ld.
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400078
Modifikasi kedua adalah ret diganti dengan panggilan keluar sistem.
Kita harus menaikkan interupsi keluar sistem secara manual. %eax digunakan untuk menyimpan nilai kembalian fungsi, tetapi panggilan keluar sistem menahannya di %ebx. Jadi, salin dari %eax ke %ebx
Di bawah ini adalah versi edit ulang kode perakitan gcc.
file func1.s:
.file "func1.c" .text .globl func1 .type func1, @function func1: pushq %rbp movq %rsp, %rbp movl $0, %eax call func2 leave
file func2.s:
.file "func2.c" .text .globl func2 .type func2, @function func2: pushq %rbp movq %rsp, %rbp movl $1, %eax leave ret
file main.s:
.file "main.c" .text .globl main .globl _start .type main, @function _start: main: pushq %rbp movq %rsp, %rbp movl $0, %eax call func1 movl %eax, %ebx movl $1, %eax int $0x80 leave
1. sebagai – Perintah Perakit GNU
sebagai mengambil file perakitan sebagai input dan output file objek. File objek hanyalah format internal, yang akan digunakan sebagai input ld untuk menghasilkan file executable akhir.
Jalankan perintah as pada file main.s untuk mendapatkan file objek main.o seperti gambar di bawah ini.
as main.s -o main.o
file main.o (diproduksi oleh "as main.s -o main.o"), kita bisa mendapatkan informasi di bawah ini.
main.o: ELF 64-bit LSB relocatable, AMD x86-64, version 1 (SYSV), not stripped
File objek dalam format ELF, yang merupakan format file yang paling banyak digunakan untuk distribusi linux.
Harap diperhatikan bahwa perintah “as” juga memiliki dukungan sintaks untuk prapemrosesan, simbol, batasan, ekspresi, pseudo ops/direktif, dan komentar.
GNU Assembler dapat mendukung banyak koleksi mesin, tetapi biasanya hanya satu keluarga mesin/arsitektur yang dipilih saat dikompilasi atau dikompilasi silang.
2. ld – Perintah Penaut GNU
File objek biasanya berisi referensi ke fungsi eksternal di library/objek yang berbeda, dan tugas linker (ld) untuk menggabungkan semua file objek/library yang diperlukan untuk biner akhir, memindahkan bagian, dan menyelesaikan referensi.
Perilaku sebenarnya dari ld didefinisikan dalam skrip linker, yang menjelaskan tata letak memori dari file yang dapat dieksekusi.
Jika kita menautkan main.o saja (ld main.o -o main), akan ada kesalahan referensi yang tidak ditentukan:
main.o: In function `_start': main.c:(.text+0xa): undefined reference to `func1'
Kami tidak akan mendapatkan file yang dapat dieksekusi tanpa menautkan ketiga file keberatan (ld main.o func1.o func2.o -o main).
# file main main: ELF 64-bit LSB executable, AMD x86-64, version 1 (SYSV), statically linked, not stripped
Berbeda dengan file objek, di sini kita mendapatkan executable yang terhubung secara statis.
as dan ld bekerja pada target/arsitektur tertentu. Tetapi ada beberapa alat yang bekerja pada objek BFD yang didefinisikan dalam binutils.
Dari beberapa baris terakhir dari output objcopy -h, kita bisa mendapatkan target dukungan.
objcopy: supported targets: elf64-x86-64 elf32-i386 a.out-i386-linux pei-i386 pei-x86-64 elf64-l1om elf64-little elf64-big elf32-little elf32-big plugin srec symbolsrec verilog tekhex binary ihex
Perlu dikatakan bahwa Verilog, ihex tidak didukung oleh OS nyata, tetapi dapat sangat berguna dalam memproses konten objek dalam format teks. Mereka banyak digunakan dalam lingkungan simulasi chip untuk inisialisasi memori/rom.
3. ar/ranlib – Perintah Arsip GNU
ar dapat digunakan untuk menghasilkan dan memanipulasi perpustakaan statis, yang merupakan file arsip yang disusun oleh banyak objek.
Perilaku ar dapat dikontrol dari argumen baris perintah (gaya unix) atau file skrip. ranlib dapat menambahkan indeks simbol ke arsip, yang dapat mempercepat kecepatan tautan dan juga memfasilitasi panggilan rutin. ar -s akan melakukan hal yang sama seperti ranlib.
Untuk pengujian saya, dengan atau tanpa -s, ar akan selalu menampilkan indeks arsip.
Test1, tanpa -s.
# ar -r extern.a func1.o func2.o && nm -s extern.a ar: creating extern.a Archive index: func1 in func1.o func2 in func2.o func1.o: 0000000000000000 T func1 U func2 func2.o: 0000000000000000 T func2
Untuk detail lengkap tentang perintah ar, baca ini:Perintah ar Linux Contoh:Cara Membuat, Melihat, Mengekstrak, Memodifikasi File Arsip C (*.a)
Uji 2, dengan -s.
# ar -r -s externS.a func1.o func2.o && nm -s externS.a ar: creating externS.a Archive index: func1 in func1.o func2 in func2.o func1.o: 0000000000000000 T func1 U func2 func2.o: 0000000000000000 T func2
Tes 3, jalankan ranlib lagi.
# cp extern.a externR.a && ranlib externR.a && nm -s externR.a Archive index: func1 in func1.o func2 in func2.o func1.o: 0000000000000000 T func1 U func2 func2.o: 0000000000000000 T func2
Dapat ditunjukkan bahwa setiap pengujian menghasilkan hasil yang sama.
4. nm – Daftar Simbol File Objek
nm dapat membuat daftar simbol dari file objek. Kami telah menunjukkan penggunaannya di bagian atas.
Perintah nm memberikan informasi tentang simbol yang digunakan dalam file objek atau file yang dapat dieksekusi.
Informasi default yang disediakan oleh perintah nm adalah sebagai berikut:
- Alamat virtual simbol
- Karakter yang menggambarkan tipe simbol. Jika karakter dalam huruf kecil maka simbol lokal tetapi jika karakter dalam huruf besar maka simbol eksternal
- Nama simbol
$ nm -A ./*.o | grep func ./hello2.o:0000000000000000 T func_1 ./hello3.o:0000000000000000 T func_2 ./hello4.o:0000000000000000 T func_3 ./main.o: U func ./reloc.o: U func ./reloc.o:0000000000000000 T func1 ./test1.o:0000000000000000 T func ./test.o: U func
Baca selengkapnya:10 Contoh Perintah Linux nm Praktis
5. objcopy – Menyalin dan Menerjemahkan File Objek
objcopy dapat menyalin konten dari satu file objek ke file objek lain, dan objek input/output dapat dalam format yang berbeda.
Ada kalanya Anda perlu mem-port file objek yang tersedia untuk satu jenis platform (seperti ARM atau x86) ke jenis platform lain.
Hal-hal relatif mudah jika kode sumber tersedia karena dapat dikompilasi ulang pada platform target.
Tapi, bagaimana jika kode sumber tidak tersedia dan Anda masih perlu mem-porting file objek dari jenis platform ke platform lain? Nah, jika Anda menggunakan Linux maka perintah objcopy melakukan persis seperti yang diperlukan
Sintaks dari perintah ini adalah :
objcopy [options] infile [outfile]...
Baca selengkapnya:Contoh Perintah Objcopy Linux untuk Menyalin dan Menerjemahkan File Objek
6. objdump – Menampilkan Informasi File Objek
objdump dapat menampilkan informasi yang dipilih dari file objek. Kita bisa menggunakan objdump -d untuk menerapkan disassemble ke main.
# objdump -d main main: file format elf64-x86-64 Disassembly of section .text: 0000000000400078 <main>: 400078: 55 push %rbp 400079: 48 89 e5 mov %rsp,%rbp 40007c: b8 00 00 00 00 mov $0x0,%eax 400081: e8 0a 00 00 00 callq 400090 <func1> 400086: c9 leaveq 400087: 89 c3 mov %eax,%ebx 400089: b8 01 00 00 00 mov $0x1,%eax 40008e: cd 80 int $0x80 0000000000400090 <func1>: 400090: 55 push %rbp 400091: 48 89 e5 mov %rsp,%rbp 400094: b8 00 00 00 00 mov $0x0,%eax 400099: e8 02 00 00 00 callq 4000a0 <func2> 40009e: c9 leaveq 40009f: c3 retq 00000000004000a0 <func2>: 4000a0: 55 push %rbp 4000a1: 48 89 e5 mov %rsp,%rbp 4000a4: b8 01 00 00 00 mov $0x1,%eax 4000a9: c9 leaveq 4000aa: c3 retq
Baca lebih lanjut:Contoh Perintah Linux Objdump (Membongkar File Biner)
7. size – Daftar Ukuran Bagian dan Ukuran Toal
size dapat menampilkan informasi ukuran bagian dalam file objek.
# size main text data bss dec hex filename 51 0 0 51 33 main
8. strings – Menampilkan Karakter yang Dapat Dicetak dari File
string dapat menampilkan urutan karakter yang dapat dicetak dari file objek. Secara default, hanya mencari di bagian .data. Dengan -a switch, semua bagian dapat dicari.
# strings -a main .symtab .strtab .shstrtab .text main.c func1.c func2.c func1 _start __bss_start main func2 _edata _end
Baca lebih lanjut:Contoh Perintah String Linux (Teks Pencarian di File Biner UNIX)
9. strip – Buang Simbol dari File Objek
strip dapat menghapus simbol dari file objek, yang dapat mengurangi ukuran file dan mempercepat eksekusi.
Kita dapat menampilkan tabel simbol dengan objdump. Tabel simbol menunjukkan entri/offset untuk setiap fungsi/label.
# objdump -t main main: file format elf64-x86-64 SYMBOL TABLE: 0000000000400078 l d .text 0000000000000000 .text 0000000000000000 l df *ABS* 0000000000000000 main.c 0000000000000000 l df *ABS* 0000000000000000 func1.c 0000000000000000 l df *ABS* 0000000000000000 func2.c 0000000000400090 g F .text 0000000000000000 func1 0000000000400078 g .text 0000000000000000 _start 00000000006000ab g *ABS* 0000000000000000 __bss_start 0000000000400078 g F .text 0000000000000000 main 00000000004000a0 g F .text 0000000000000000 func2 00000000006000ab g *ABS* 0000000000000000 _edata 00000000006000b0 g *ABS* 0000000000000000 _end
Setelah strip (#strip main), tabel simbol akan dihapus.
#objdump -t main main: file format elf64-x86-64 SYMBOL TABLE: no symbols
Baca selengkapnya:10 Contoh Perintah Strip Linux (Mengurangi Ukuran File yang Dapat Dieksekusi/Binary)
10. c++filt – Perintah Demangle
C++ mendukung kelebihan beban yang memungkinkan nama fungsi yang sama mengambil jenis/jumlah argumen yang berbeda.
Ini dilakukan dengan mengubah nama fungsi menjadi nama assembler tingkat rendah, yang disebut mangling. c++filt dapat melakukan demangling untuk C++ dan Java.
Di sini, kami membuat kode sampel baru untuk penjelasan mangling.
Misalkan kita memiliki dua jenis func3 yang mengambil jenis argumen input yang berbeda, void dan int.
==> mangling.cpp <== int func3(int a) { return a; } int func3() { return 0; } int main() { return func3(1); }
Dalam format assembly, mereka memiliki nama yang berbeda, _Z5func3v dan _Z5func3i. Dan, salah satunya akan dipanggil sesuai dengan jenis argumen yang kita berikan ke func3 di mangling.cpp. Dalam contoh ini, _Z5func3i dipanggil.
==> mangling.s <== .file "mangling.cpp" .text .globl _Z5func3i .type _Z5func3i, @function _Z5func3i: pushq %rbp movq %rsp, %rbp movl %edi, -4(%rbp) movl -4(%rbp), %eax leave ret .globl _Z5func3v .type _Z5func3v, @function _Z5func3v: pushq %rbp movq %rsp, %rbp movl $0, %eax leave ret .globl main .type main, @function main: pushq %rbp movq %rsp, %rbp movl $1, %edi call _Z5func3i leave ret #grep func3.*: mangling.s _Z5func3i: _Z5func3v:
Kita dapat meneruskan nama fungsi assembly ini ke c++filt, dan pernyataan definisi fungsi asli akan dipulihkan.
#grep func3.*: mangling.s | c++filt func3(int): func3():
objdump juga dapat melakukan demangle dengan gaya yang berbeda:
-C, --demangle[=STYLE] Decode mangled/processed symbol names The STYLE, if specified, can be 'auto', 'gnu', 'lucid', 'arm', 'hp', 'edg', 'gnu-v3', 'java' or 'gnat'
11. addr2line – Ubah Alamat menjadi Nama File dan Angka
addr2line bisa mendapatkan file dan nomor baris dari alamat yang diberikan atau offset di dalam bagian yang dialokasikan kembali, dengan meneruskan informasi debug.
Pertama, kita harus mengkompilasi file assembly dengan flag -g, sehingga informasi debug akan ditambahkan ke objek. Dapat ditunjukkan dari bawah bahwa ada beberapa bagian debug sekarang.
objdump -h mainD mainD: file format elf64-x86-64 Sections: Idx Name Size VMA LMA File off Algn 0 .text 00000033 0000000000400078 0000000000400078 00000078 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE 1 .debug_aranges 00000090 0000000000000000 0000000000000000 000000b0 2**4 CONTENTS, READONLY, DEBUGGING 2 .debug_info 000000dd 0000000000000000 0000000000000000 00000140 2**0 CONTENTS, READONLY, DEBUGGING 3 .debug_abbrev 0000003c 0000000000000000 0000000000000000 0000021d 2**0 CONTENTS, READONLY, DEBUGGING 4 .debug_line 000000ba 0000000000000000 0000000000000000 00000259 2**0 CONTENTS, READONLY, DEBUGGING
Dari hasil pembongkaran yang ditunjukkan pada bagian 2.d objdump, kita dapat melihat bahwa 0x400090 adalah entri dari func1, yang sama dengan hasil yang diberikan oleh addr2line.
addr2line -e mainD 0x400090 /media/shared/TGS/func1.s:6
12. readelf – Menampilkan Info File ELF
readelf dan elfedit hanya dapat beroperasi pada file elf.
readelf dapat menampilkan informasi dari file elf.
Kami dapat menampilkan informasi detail dari header ELF.
#readelf -h main_full ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: Advanced Micro Devices X86-64 Version: 0x1 Entry point address: 0x400078 Start of program headers: 64 (bytes into file) Start of section headers: 208 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 1 Size of section headers: 64 (bytes) Number of section headers: 5 Section header string table index: 2
Sama seperti readelf, Anda juga dapat menggunakan elfedit yang dapat memperbarui mesin, jenis file dan OS ABI di header elf. Harap dicatat bahwa, elfedit mungkin tidak disertakan secara default dalam distribusi Anda.
Baca selengkapnya:Dasar-dasar Format File Objek ELF Linux (dan Struktur Header ELF)