GNU/Linux >> Znalost Linux >  >> Linux

12 Linux GNU Binary Utilities Příkazy Binutils s příklady (as, ld, ar, nm, objcopy, objdump, size, strings, strip, c++flint, addr2line, readelf příklady příkazů)

GNU Binary Utilities, obvykle nazývané binutils, je kolekce vývojových nástrojů, které zpracovávají soubory sestavení, soubory objektů a knihovny.

Nová generace programovacích jazyků, která přišla v posledních několika letech, skutečně maskuje funkčnost těchto utilit, protože k nim dochází na pozadí. Mnoho vývojářů tedy není těmto nástrojům vystaveno.

Ale pokud jste vývojář, který pracuje na platformě Linux / UNIX, je nezbytné porozumět různým příkazům, které jsou k dispozici jako součást vývojových nástrojů GNU.

Následuje 12 různých příkazů binutils, které jsou popsány v tomto tutoriálu.

  1. as – příkaz GNU Assembler
  2. ld – příkaz GNU Linker
  3. ar – příkaz GNU Archive
  4. nm – Seznam symbolů souborů objektů
  5. objcopy – Kopírování a překlad objektových souborů
  6. objdump – Zobrazení informací o souboru objektu
  7. velikost – Uveďte velikost sekce a celkovou velikost
  8. řetězce – zobrazení tisknutelných znaků ze souboru
  9. strip – Vyřazení symbolů ze souboru objektu
  10. c++filt – příkaz Demangle
  11. addr2line – Převést adresu na název souboru a čísla
  12. readelf – Zobrazení informací o souboru ELF

Tyto nástroje vám pomohou efektivně manipulovat s binárními, objektovými a knihovními soubory.

Z těchto 12 utilit, jak a ld jsou nejdůležitější, jsou výchozím backendem GNU Compiler Collection (gcc). GCC provádí pouze práci, při které se kompiluje z C/C++ do jazyka symbolických instrukcí, a jeho úkolem as a ld je výstup spustitelného binárního souboru.

Připravte si vzorový kód

Abychom pochopili, jak všechny tyto příkazy fungují, nejprve si připravíme ukázkový kód sestavení z kódu C pomocí gcc -S. Všechny zde uvedené experimenty se provádějí na x86 64bitovém linuxovém boxu.

Níže je kód C, který jako návratový kód používá pouze návratovou hodnotu externí funkce. Neexistuje žádný vstup/výstup, takže pokud chcete zkontrolovat, zda se program provedl podle očekávání, zkontrolujte návratový stav (echo $?). Máme tři funkce, hlavní, func1 a func2, a jeden soubor pro každou funkci.

// func1.c file:
int func1() {
	return func2();
}

// func2.c file:
int func2() {
	return 1;
}

// main.c file:
int main() {
	return func1();
}

GCC má podporu runtime knihovny C, takže hlavní funkce je považována za normální funkci. Pro zjednodušení dema nechceme při kompilaci a propojení těchto .s souborů zapojovat knihovnu C. Pro main.s jsou tedy provedeny dvě úpravy:

První změnou je přidání štítku _start pro fázi propojení.

_start label je vstupní bod aplikace, pokud není definován, bude při spuštění ld hlášeno varování jako níže.

ld: warning: cannot find entry symbol _start; defaulting to 0000000000400078

Druhá modifikace spočívá v tom, že ret je nahrazeno voláním ukončení systému.

Měli bychom ručně zvýšit přerušení systému. %eax se používá k uchování návratové hodnoty funkce, ale volání ukončení systému ji podrží v %ebx. Takže jej zkopírujte z %eax do %ebx

Níže je uvedena znovu upravená verze kódu sestavení gcc.

soubor func1.s:

	.file	"func1.c"
	.text
.globl func1
	.type	func1, @function
func1:
	pushq	%rbp
	movq	%rsp, %rbp
	movl	$0, %eax
	call	func2
	leave

soubor func2.s:

	.file	"func2.c"
	.text
.globl func2
	.type	func2, @function
func2:
	pushq	%rbp
	movq	%rsp, %rbp
	movl	$1, %eax
	leave
	ret

soubor 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. jako – příkaz GNU Assembler

as bere soubor sestavení jako vstupní a výstupní soubor objektu. Objektový soubor je pouze interní formát, který bude použit jako vstup ld pro vytvoření konečného spustitelného souboru.

Spusťte příkaz as v souboru main.s, abyste získali soubor objektu main.o, jak je znázorněno níže.

as main.s -o main.o

soubor main.o (produkovaný „as main.s -o main.o“), můžeme získat níže uvedené informace.

main.o: ELF 64-bit LSB relocatable, AMD x86-64, version 1 (SYSV), not stripped

Objektový soubor je ve formátu ELF, což je nejrozšířenější formát souboru pro linuxové distribuce.

Upozorňujeme, že příkaz „as“ má také podporu syntaxe pro předběžné zpracování, symbol, omezení, výraz, pseudo ops/direktivy a komentáře.

GNU Assembler může podporovat velkou sbírku počítačů, ale při kompilaci nebo křížové kompilaci je obvykle vybrán pouze jeden stroj/rodina architektury.

2. ld – Příkaz GNU Linker

Soubor objektu obvykle obsahuje odkaz na externí funkce v jiné knihovně/objektu a úkolem linkeru (ld) je zkombinovat všechny soubory objektů/knihoven potřebné pro finální binární soubor, přemístit sekce a vyřešit odkaz.

Skutečné chování ld je definováno ve skriptu linkeru, který popisuje rozložení paměti spustitelného souboru.

Pokud propojíme pouze main.o (ld main.o -o main), dojde k nedefinované chybě odkazu:

main.o: In function `_start':
main.c:(.text+0xa): undefined reference to `func1'

Bez propojení všech tří souborů námitek (ld main.o func1.o func2.o -o main) nezískáme spustitelný soubor.

# file main 
main: ELF 64-bit LSB executable, AMD x86-64, version 1 (SYSV), statically linked, not stripped

Odlište se od objektového souboru, zde dostaneme staticky propojený spustitelný soubor.

as a ld pracuje na konkrétním cíli/architektuře. Ale existují některé nástroje, které pracují na BFD objektech definovaných v binutils.

Z několika posledních řádků výstupu objcopy -h můžeme získat cíle podpory.

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

Je třeba říci, že verilog, ihex nejsou podporovány skutečným OS, ale mohou být velmi užitečné při zpracování obsahu objektů v textovém formátu. Jsou široce používány v prostředí čipové simulace pro inicializaci paměti/ROM.

3. ar/ranlib – GNU Archive Command

ar lze použít ke generování a manipulaci se statickou knihovnou, což je archivní soubor složený z mnoha objektů.

Chování ar lze ovládat z argumentu příkazové řádky (unixový styl) nebo ze souboru skriptu. ranlib může přidat index symbolů do archivu, což může zrychlit rychlost linky a také usnadnit volání rutin. ar -s udělá to samé jako ranlib.

Pro můj test, s nebo bez -s, ar vždy vypíše index archivu.

Test1, ar bez -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

Úplné podrobnosti o příkazu ar naleznete v tomto:Příkaz ar pro Linux Příklady:Jak vytvářet, zobrazovat, extrahovat, upravovat archivní soubory C (*.a)

Test 2, ar s -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

Test 3, spusťte znovu ranlib.

# 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

Lze ukázat, že každý test dává stejný výsledek.

4. nm – Seznam symbolů souborů objektů

nm umí vypsat symboly z objektového souboru. Ve výše uvedené části jsme ukázali jeho použití.

Příkazy nm poskytují informace o symbolech používaných v objektovém souboru nebo spustitelném souboru.

Výchozí informace, které příkaz nm poskytuje, jsou následující:

  • Virtuální adresa symbolu
  • Znak, který znázorňuje typ symbolu. Pokud je znak napsán malým písmenem, pak je symbol místní, ale pokud je znak velkým, pak je symbol externí
  • Název symbolu
$ 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

Přečtěte si více:10 praktických příkladů příkazů Linux nm

5. objcopy – Kopírování a překlad objektových souborů

objcopy může zkopírovat obsah jednoho objektového souboru do jiného objektového souboru a vstupní/výstupní objekt může mít jiný formát.

Jsou chvíle, kdy potřebujete přenést objektový soubor dostupný pro jeden druh platformy (jako ARM nebo x86) na jiný druh platformy.

Věci jsou relativně snadné, pokud je k dispozici zdrojový kód, protože jej lze znovu zkompilovat na cílové platformě.

Ale co když zdrojový kód není k dispozici a stále potřebujete přenést objektový soubor z typu platformy na jinou? Pokud používáte Linux, pak příkaz objcopy dělá přesně to, co potřebujete

Syntaxe tohoto příkazu je:

objcopy [options] infile [outfile]...

Přečtěte si více:Příklady příkazů Linux Objcopy pro kopírování a překlad objektových souborů

6. objdump – Zobrazení informací o souboru objektu

objdump umí zobrazit vybrané informace z objektových souborů. Můžeme použít objdump -d k použití disassemble na 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   

Přečtěte si více:Příklady příkazů Linux Objdump (rozbalit binární soubor)

7. velikost – List Section Size and Toal Size

size může zobrazit informace o velikosti sekcí v objektových souborech.

# size main
   text	   data	    bss	    dec	    hex	filename
     51	      0	      0	     51	     33	main

8. strings – Zobrazení tisknutelných znaků ze souboru

string může zobrazit tisknutelnou sekvenci znaků ze souborů objektů. Ve výchozím nastavení vyhledává pouze v sekci .data. Pomocí přepínače -a lze prohledávat všechny sekce.

# strings -a main
.symtab
.strtab
.shstrtab
.text
main.c
func1.c
func2.c
func1
_start
__bss_start
main
func2
_edata
_end

Přečtěte si více:Příklady příkazů Linux Strings (Vyhledat text v binárních souborech UNIX)

9. strip – Discard Symbols from Object File

strip může odstranit symboly ze souboru objektu, což může snížit velikost souboru a urychlit provádění.

Tabulku symbolů můžeme zobrazit pomocí objdump. Tabulka symbolů ukazuje vstup/posun pro každou funkci/návěští.

# 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

Po stripu (#strip main) bude tabulka symbolů odstraněna.

#objdump -t main

main:     file format elf64-x86-64

SYMBOL TABLE:
no symbols

Přečtěte si více:10 příkladů příkazů Linux Strip (zmenšit velikost spustitelného/binárního souboru)

10. c++filt – příkaz Demangle

C++ podporuje přetížení, které může nechat stejný název funkce přijmout různé druhy/počet argumentů.

To se provádí změnou názvu funkce na název nízkoúrovňového assembleru, který se nazývá mandlování. c++filt může provést demanglování pro C++ a Java.

Zde vytváříme nový ukázkový kód pro vysvětlení mandlování.

Předpokládejme, že máme dva typy func3, které používají různé druhy vstupních argumentů, void a int.

==> mangling.cpp <==
int func3(int a) {
	return a;
}
int func3() {
	return 0;
}
int main() {
	return func3(1);
}

Ve formátu sestavení mají různé názvy, _Z5func3v a _Z5func3i. A jeden z nich bude volán podle typu argumentu, který jsme předali funkci func3 v mangling.cpp. V tomto příkladu se nazývá _Z5func3i.

==> 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:

Tyto názvy funkcí assembleru můžeme předat c++filt a původní příkaz function define bude obnoven.

#grep func3.*: mangling.s | c++filt 
func3(int):
func3():

objdump také umí demangle s různými styly:

  -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 – Převést adresu na název souboru a čísla

addr2line může získat číslo souboru a řádku dané adresy nebo offset uvnitř přerozdělené sekce předáním informací o ladění.

Nejprve musíme zkompilovat soubor sestavení s parametrem -g, aby se do objektu přidaly ladicí informace. Níže lze ukázat, že nyní existují některé sekce ladění.

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

Z výsledku rozebrání uvedeného v sekci 2.d objdump můžeme vidět, že 0x400090 je záznam funkce func1, což je stejný jako výsledek daný addr2line.

addr2line -e mainD 0x400090
/media/shared/TGS/func1.s:6

12. readelf – Zobrazení informací o souboru ELF

readelf a elfedit mohou pracovat pouze se souborem elf.

readelf umí zobrazit informace ze souboru elf.
Můžeme zobrazit podrobné informace o hlavičce 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

Stejně jako readelf můžete také použít elfedit, který může aktualizovat stroj, typ souboru a OS ABI v hlavičce elf. Vezměte prosím na vědomí, že elfedit nemusí být ve výchozím nastavení součástí vaší distribuce.

Přečtěte si více:Linux ELF Object File Format (a ELF Header Structure) Základy


Linux
  1. 10+ Linux VI příkazy s příklady

  2. Příkaz whoami v Linuxu vysvětlený na příkladech

  3. 10 příkladů příkazů Linux Strip (zmenšit velikost spustitelného/binárního souboru)

  1. Třídit příkaz v Linuxu s příklady

  2. příkaz chattr v Linuxu s příklady

  3. Příklady příkazů Linux Objdump (rozbalení binárního souboru)

  1. Příkaz Netstat v Linuxu - 28 příkazů s příklady

  2. 10 Quick Linux Tail Command s příklady

  3. 17 Užitečný příkaz Tar s praktickými příklady v Linuxu