文章目录
- 一、GUN binutis概述
- 二、工具集详细说明
- nm指令使用
- size指令使用
- objdump指令使用
- addr2line指令使用
- readelf指令使用
- strip指令使用
一、GUN binutis概述
什么是GUN binutis?
它是一个二进制工具集,默认情况下所有 Linux 发行版中都会安装这些二进制工具。实际大部分人是用过这些工具的,我一说大家就知道了。常用的二进制工具包括nm,size,addr2line,objcopy,objdump,readelf, strip
。
工具 | 用途 |
---|---|
nm | 列出目标文件中的符号 |
size | 列出目标文件中各个段的大小和总大小,如数据段,代码段 |
addr2line | 将程序地址翻译成文件名和行号 |
objcopy | section复制和删除 |
objdump | 显示目标文件的信息和反汇编 |
readelf | 显示有关ELF文件的信息 |
strip | 从目标文件中剥离符号 |
二、工具集详细说明
为了更好的说明工具集的使用,我们写个简单的hello word程序
#include<stdio.h>
void main(int argc,char **argv)
{
printf("hello word \r\n");
}
nm指令使用
使用gcc -o hello_word hello.c
进行编译,使用nm指令
查看hello_word程序的符号:
root@ubuntu:~/temp$ nm hello_word
0000000000601040 B __bss_start
0000000000601040 b completed.6982
0000000000601030 D __data_start
0000000000601030 W data_start
0000000000400470 t deregister_tm_clones
00000000004004e0 t __do_global_dtors_aux
0000000000600e18 t __do_global_dtors_aux_fini_array_entry
0000000000601038 D __dso_handle
0000000000600e28 d _DYNAMIC
0000000000601040 D _edata
0000000000601048 B _end
00000000004005c4 T _fini
0000000000400500 t frame_dummy
0000000000600e10 t __frame_dummy_init_array_entry
0000000000400708 r __FRAME_END__
0000000000601000 d _GLOBAL_OFFSET_TABLE_
w __gmon_start__
00000000004003e0 T _init
0000000000600e18 t __init_array_end
0000000000600e10 t __init_array_start
00000000004005d0 R _IO_stdin_used
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
0000000000600e20 d __JCR_END__
0000000000600e20 d __JCR_LIST__
w _Jv_RegisterClasses
00000000004005c0 T __libc_csu_fini
0000000000400550 T __libc_csu_init
U __libc_start_main@@GLIBC_2.2.5
000000000040052d T main
U puts@@GLIBC_2.2.5
00000000004004a0 t register_tm_clones
0000000000400440 T _start
0000000000601040 D __TMC_END__
nm指令的详细用法如下图:
Usage: nm [option(s)] [file(s)]
List symbols in [file(s)] (a.out by default).
The options are:
-a, --debug-syms Display debugger-only symbols
-A, --print-file-name Print name of the input file before every symbol
-B Same as --format=bsd
-C, --demangle[=STYLE] Decode low-level symbol names into user-level names
The STYLE, if specified, can be `auto' (the default),
`gnu', `lucid', `arm', `hp', `edg', `gnu-v3', `java'
or `gnat'
--no-demangle Do not demangle low-level symbol names
-D, --dynamic Display dynamic symbols instead of normal symbols
--defined-only Display only defined symbols
-e (ignored)
-f, --format=FORMAT Use the output format FORMAT. FORMAT can be `bsd',
`sysv' or `posix'. The default is `bsd'
-g, --extern-only Display only external symbols
-l, --line-numbers Use debugging information to find a filename and
line number for each symbol
-n, --numeric-sort Sort symbols numerically by address
-o Same as -A
-p, --no-sort Do not sort the symbols
-P, --portability Same as --format=posix
-r, --reverse-sort Reverse the sense of the sort
--plugin NAME Load the specified plugin
-S, --print-size Print size of defined symbols
-s, --print-armap Include index for symbols from archive members
--size-sort Sort symbols by size
--special-syms Include special symbols in the output
--synthetic Display synthetic symbols as well
-t, --radix=RADIX Use RADIX for printing symbol values
--target=BFDNAME Specify the target object format as BFDNAME
-u, --undefined-only Display only undefined symbols
-X 32_64 (ignored)
@FILE Read options from FILE
-h, --help Display this information
-V, --version Display this program's version number
size指令使用
对hello_word程序使用size指令,我们可以看到各个段的大小。
root@ubuntu:~/temp$ size hello_word
text data bss dec hex filename
1215 560 8 1783 6f7 hello_word
//size指令的详细用法如下图:
root@ubuntu:~/temp$ size --help
Usage: size [option(s)] [file(s)]
Displays the sizes of sections inside binary files
If no input file(s) are specified, a.out is assumed
The options are:
-A|-B --format={sysv|berkeley} Select output style (default is berkeley)
-o|-d|-x --radix={8|10|16} Display numbers in octal, decimal or hex
-t --totals Display the total sizes (Berkeley only)
--common Display total size for *COM* syms
--target=<bfdname> Set the binary file format
@<file> Read options from <file>
-h --help Display this information
-v --version Display the program's version
objdump指令使用
objdump主要用来反汇编,将可执行文件的二进制指令反汇编成汇
编文件,各个参数及详细说明如下:
root@ubuntu:~/temp$ objdump -d hello_word
hello_word: file format elf64-x86-64
Disassembly of section .init:
00000000004003e0 <_init>:
4003e0: 48 83 ec 08 sub $0x8,%rsp
4003e4: 48 8b 05 0d 0c 20 00 mov 0x200c0d(%rip),%rax # 600ff8 <_DYNAMIC+0x1d0>
4003eb: 48 85 c0 test %rax,%rax
4003ee: 74 05 je 4003f5 <_init+0x15>
4003f0: e8 3b 00 00 00 callq 400430 <__gmon_start__@plt>
4003f5: 48 83 c4 08 add $0x8,%rsp
4003f9: c3 retq
... ...
Disassembly of section .text:
... ...
000000000040052d <main>:
40052d: 55 push %rbp
40052e: 48 89 e5 mov %rsp,%rbp
400531: 48 83 ec 10 sub $0x10,%rsp
400535: 89 7d fc mov %edi,-0x4(%rbp)
400538: 48 89 75 f0 mov %rsi,-0x10(%rbp)
40053c: bf d4 05 40 00 mov $0x4005d4,%edi
400541: e8 ca fe ff ff callq 400410 <puts@plt>
400546: c9 leaveq
400547: c3 retq
400548: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)
40054f: 00
... ...
addr2line指令使用
addr2line 工具可以从二进制文件中的这些地址映射到 C 源代码匹配的地址,注意下面的hello_word程序编译是增加-g调试参数
,其中400535地址为上面objdump 反汇编hello_word程序后main函数中的一行 400535: 89 7d fc mov %edi,-0x4(%rbp)
root@ubuntu:~/temp$ addr2line -e hello_word 400535
/fwork/temp/hello.c:3
root@ubuntu:~/temp$ addr2line --help
Usage: addr2line [option(s)] [addr(s)]
Convert addresses into line number/file name pairs.
If no addresses are specified on the command line, they will be read from stdin
The options are:
@<file> Read options from <file>
-a --addresses Show addresses
-b --target=<bfdname> Set the binary file format
-e --exe=<executable> Set the input file name (default is a.out)
-i --inlines Unwind inlined functions
-j --section=<name> Read section-relative offsets instead of addresses
-p --pretty-print Make the output easier to read for humans
-s --basenames Strip directory names
-f --functions Show function names
-C --demangle[=style] Demangle function names
-h --help Display this information
-v --version Display the program's version
readelf指令使用
readelf是比较常用的命令,主要用来查看二进制文件的
各个section信息。各个参数详细说明如下:
我们对hello_word执行程序使用readelf指令查看下:
root@ubuntu:~/temp$ readelf -h hello_word
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: 0x400440
Start of program headers: 64 (bytes into file)
Start of section headers: 5104 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 9
Size of section headers: 64 (bytes)
Number of section headers: 35
Section header string table index: 32
另外再多提一个ldd 命令
它可以列出动态库依赖关系非常有用:
root@ubuntu:~/temp$ ldd hello_word
linux-vdso.so.1 => (0x00007fff80b59000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6914c73000)
/lib64/ld-linux-x86-64.so.2 (0x00005563c6986000)
strip指令使用
该命令通常用于将二进制文件中的调试信息等剥离出来,会使得二进制文件大小变小,但不影响二进制文件的实际执行。我们仍然以hello_word为例,编译时第一次加-g参数,然后使用strip指令:
root@ubuntu:~/temp$ gcc -g -o hello_word hello.c
root@ubuntu:~/temp$
root@ubuntu:~/temp$
root@ubuntu:~/temp$
root@ubuntu:~/temp$ file hello_word
hello_word: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=6c4297ace1dd7a8d76137d4ff272461c459bbb27, not stripped
root@ubuntu:~/temp$
root@ubuntu:~/temp$
root@ubuntu:~/temp$ ls -al
-rwxrwxr-x 1 root root 9591 May 28 23:00 hello_word
root@ubuntu:~/temp$
root@ubuntu:~/temp$ strip hello_word
root@ubuntu:~/temp$
root@ubuntu:~/temp$ file hello_word
hello_word: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=6c4297ace1dd7a8d76137d4ff272461c459bbb27, stripped
root@ubuntu:~/temp$
root@ubuntu:~/temp$ ls -al
-rwxrwxr-x 1 root root 6248 May 28 22:56 hello_word
可以看到前后二进制文件大小有3k差异,当程序复杂时这个差异会更加的明显。