【Linux】GCC程序开发工具(中)

00. 目录

01. GCC的二进制工具

在GCC的开发环境中,除了基本程序生成的编译、链接工具,还有其它一系列二进制的工具可以使用。

ar 归档工具

readelf 读取ELF格式文件信息

strings 查看字符串

nm 显示符号信息

strip 删除符号

02. ar命令

ar工具用于建立、修改、提取归档文件(archive)。一个归档文件是包含多个目标文件的单个文件,它也被称为静态库。归档文件的结构保证了可以从中检索并得到原始的被包含的文件,也就是这个归档文件的成员。被包含的原始文件的内容、模式(权限)、时间戳、所有者和组等属性都保存在归档文件中,在提取后,可以恢复原始文件的相关属性。

2.1 ar用法命令

Usage: ar [emulation options] [-]{dmpqrstx}[abcDfilMNoOPsSTuvV] [--plugin <name>] [member-name] [count] 
	   archive-file file...
       ar -M [<mri-脚本]
 命令:
  d            - 从归档文件中删除文件
  m[ab]        - 在归档文件中移动文件
  p            - 打印在归档文件中找到的文件
  q[f]         - 将文件快速追加到归档文件中
  r[ab][f][u]  - 替换归档文件中已有的文件或加入新文件
  s            - 作为 ranlib 工作
  t[O][v]      - display contents of the archive
  x[o]         - 从归档文件中分解文件
 特定命令修饰符:
  [a]          - 将文件置于 [成员名] 之后
  [b]          - 将文件置于 [成员名] 之前 ([i] 相同)
  [D]          - 将 0 用于时间戳和 uid/gid(默认)
  [D]          - 使用实际时间戳和 uid/gid
  [N]          - 使用名称的实例 [数量]
  [f]          - 截去插入的文件名称
  [P]          - 在匹配时使用完整的路径名
  [o]          - 保留原来的日期
  [O]          - display offsets of files in the archive
  [u]          - 只替换比当前归档内容更新的文件
 通用修饰符:
  [c]          - 不在必须创建库的时候给出警告
  [s]          - 创建归档索引 (cf. ranlib)
  [S]          - 不要创建符号表
  [T]          - 产生一个简单归档
  [v]          - 输出较多信息
  [V]          - 显示版本号
  @<file>       - 从 <file> 读取选项
  --target=BFDNAME - 指定目标对象格式为 BFDNAME
  --output=DIRNAME - specify the output directory for extraction operations
 可选项:
  --plugin <p> - 加载指定的插件程序

2.2 用法示例

在GCC工具系列中,ar工具常用于生成静态库(static lib)文件。

生成静态库

deng@itcast:~/share/3rd/1static_lib$ ar -rv libtest.a add.o sub.o mul.o div.o 
ar: 正在创建 libtest.a
a - add.o
a - sub.o
a - mul.o
a - div.o
deng@itcast:~/share/3rd/1static_lib$ 

2.3 查看已经生成的静态库的内容

deng@itcast:~/share/3rd/1static_lib$ ar -t libtest.a 
add.o
sub.o
mul.o
div.o
deng@itcast:~/share/3rd/1static_lib$ 

2.4 对于一个已经生成的静态库,再次调用ar可以替换静态库中的内容

deng@itcast:~/share/3rd/1static_lib$ ar -rv libtest.a  add.o sub.o
r - add.o
r - sub.o
deng@itcast:~/share/3rd/1static_lib$ 

2.5 使用ar工具加-d选项,可以删除库中的成员

deng@itcast:~/share/3rd/1static_lib$ ar -d libtest.a add.o
deng@itcast:~/share/3rd/1static_lib$ ar -t libtest.a 
sub.o
mul.o
div.o
deng@itcast:~/share/3rd/1static_lib$ 

2.6 追加文件到归档文件中

deng@itcast:~/share/3rd/1static_lib$ ar -rv libtest.a add.o
a - add.o
deng@itcast:~/share/3rd/1static_lib$ 

2.7 提取其中的各个目标文件

deng@itcast:~/share/3rd/1static_lib$ ar -x libtest.a 
deng@itcast:~/share/3rd/1static_lib$ ls -l *.o
-rw-r--r-- 1 deng deng 1368 6月  15 22:38 add.o
-rw-r--r-- 1 deng deng 1368 6月  15 22:38 div.o
-rw-r--r-- 1 deng deng 1368 6月  15 22:38 mul.o
-rw-r--r-- 1 deng deng 1368 6月  15 22:38 sub.o

03. readelf命令

readelf用来显示ELF格式文件的信息,可通过参数选项来控制显示那些特定信息。readelf工具的使用方式如下所示:

deng@itcast:~$ readelf --help
用法:readelf <选项> elf-文件
 显示关于 ELF 格式文件内容的信息
 Options are:
  -a --all               显示所有,等价于-h -l -S -s -r -d -V -A -I
  -h --file-header       显示ELF文件头信息
  -l --program-headers   显示ELF程序头
     --segments          --program-headers的别名
  -S --section-headers   Display the sections' header 显示节头
     --sections          --section-headers的别名
  -g --section-groups    Display the section groups
  -t --section-details   Display the section details
  -e --headers           Equivalent to: -h -l -S
  -s --syms              显示符号表
     --symbols           An alias for --syms
  --dyn-syms             Display the dynamic symbol table
  -n --notes             显示核心注释
  -r --relocs            显示重定向信息
  -u --unwind            显示unwind信息
  -d --dynamic           显示动态段
  -V --version-info      显示版本节
  -A --arch-specific     显示体系架构特定信息
  -c --archive-index     Display the symbol/file index in an archive
  -D --use-dynamic       显示信息使用动态节
  -x --hex-dump=<number|name>
                         Dump the contents of section <number|name> as bytes
  -p --string-dump=<number|name>
                         Dump the contents of section <number|name> as strings
  -R --relocated-dump=<number|name>
                         Dump the contents of section <number|name> as relocated bytes
  -z --decompress        Decompress section before dumping it
  -w[lLiaprmfFsoRtUuTgAckK] or
  --debug-dump[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,
               =frames-interp,=str,=loc,=Ranges,=pubtypes,
               =gdb_index,=trace_info,=trace_abbrev,=trace_aranges,
               =addr,=cu_index,=links,=follow-links]
                         Display the contents of DWARF debug sections
  --dwarf-depth=N        Do not display DIEs at depth N or greater
  --dwarf-start=N        Display DIEs starting with N, at the same depth
                         or deeper
  --ctf=<number|name>    Display CTF info from section <number|name>
  --ctf-parent=<number|name>
                         Use section <number|name> as the CTF parent

  --ctf-symbols=<number|name>
                         Use section <number|name> as the CTF external symtab

  --ctf-strings=<number|name>
                         Use section <number|name> as the CTF external strtab

  -I --histogram         显示柱状图
  -W --wide              对超过80列的输出设备指定一些行的格式
  @<file>                Read options from <file>
  -H --help              显示帮助信息
  -v --version           Display the version number of readelf
将 bug 报告到 <http://www.sourceware.org/bugzilla/>

3.1 显示目标文件ELF文件头信息

deng@itcast:~/share/3rd/1static_lib$ readelf -h add.o
ELF 头:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  类别:                              ELF64
  数据:                              2 补码,小端序 (little endian)
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI 版本:                          0
  类型:                              REL (可重定位文件)
  系统架构:                          Advanced Micro Devices X86-64
  版本:                              0x1
  入口点地址:               0x0
  程序头起点:          0 (bytes into file)
  Start of section headers:          600 (bytes into file)
  标志:             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           64 (bytes)
  Number of section headers:         12
  Section header string table index: 11
deng@itcast:~/share/3rd/1static_lib$ 

3.2 显示共享库头信息

deng@itcast:~/share/3rd/3share_lib$ readelf -h libtest.so 
ELF 头:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  类别:                              ELF64
  数据:                              2 补码,小端序 (little endian)
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI 版本:                          0
  类型:                              DYN (共享目标文件)
  系统架构:                          Advanced Micro Devices X86-64
  版本:                              0x1
  入口点地址:               0x1040
  程序头起点:          64 (bytes into file)
  Start of section headers:          14208 (bytes into file)
  标志:             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         11
  Size of section headers:           64 (bytes)
  Number of section headers:         25
  Section header string table index: 24
deng@itcast:~/share/3rd/3share_lib$ 

3.3 显示可执行文件头信息如下

deng@itcast:~/share/3rd/4share_test$ readelf -h main
ELF 头:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  类别:                              ELF64
  数据:                              2 补码,小端序 (little endian)
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI 版本:                          0
  类型:                              DYN (共享目标文件)
  系统架构:                          Advanced Micro Devices X86-64
  版本:                              0x1
  入口点地址:               0x10e0
  程序头起点:          64 (bytes into file)
  Start of section headers:          14816 (bytes into file)
  标志:             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         13
  Size of section headers:           64 (bytes)
  Number of section headers:         31
  Section header string table index: 30
deng@itcast:~/share/3rd/4share_test$ 

04. strings命令

strings是一个简单的工具,用于查看文件中的字符串。

deng@itcast:~/share/3rd/4share_test$ strings --help
用法:strings [选项] [文件]
 打印 [文件] (默认为标准输入) 中可打印的字符串
 选项为:
  -a - --all                扫描整个文件,而不是数据段
  -d --data                 扫描数据段
  -f --print-file-name      在字符串前面打印文件的名字
  -n --bytes=[number]       定位和打印任何以NUL结束的序列,至少number个字节,默认为4个字节
  -<number>                   least [number] characters (default 4).
  -t --radix={o,d,x}        基于八、十、十六进制打印字符串
  -w --include-all-whitespace Include all whitespace as valid string characters
  -o                        An alias for --radix=o
  -T --target=<BFDNAME>     指定二进制文件的格式
  -e --encoding={s,S,b,l,B,L} 选择字符大小
                            s = 7-bit, S = 8-bit, {b,l} = 16-bit, {B,L} = 32-bit
  -s --output-separator=<string> String used to separate strings in output.
  @<file>                   Read options from <file>
  -h --help                 显示strings的所有选项然后退出
  -v -V --version          显示strings的版本号然后退出
deng@itcast:~/share/3rd/4share_test$ 

4.1 查看目标文件中的字符串

deng@itcast:~/share/3rd/1static_lib$ strings  add.o 
GCC: (Ubuntu 9.3.0-10ubuntu2) 9.3.0
add.c
.symtab
.strtab
.shstrtab
.text
.data
.bss
.comment
.note.GNU-stack
.note.gnu.property
.rela.eh_frame
deng@itcast:~/share/3rd/1static_lib$ 

05. nm命令

nm工具用于显示文件中的符号,可以用于各种ELF格式的文件。使用nm查看前面的目标文件(可重定向文件),将显示符号及其相关内容。

deng@itcast:~/share/3rd/1static_lib$ nm --help
用法:nm [选项] [文件]
 列举 [文件] 中的符号 (默认为 a.out)。
 The options are:
  -a, --debug-syms       只显示调试符号
  -A, --print-file-name  在每个符号前打印输入文件的名称
  -B                     Same as --format=bsd
  -C, --demangle[=STYLE] 将底层的符号解码位用户层的符号。
						 The STYLE, if specified, can be `auto' (the default),
						 `gnu', `lucid', `arm', `hp', `edg', `gnu-v3', `java'
						  or `gnat'
      --no-demangle      不解析底层符号
      --recurse-limit    Enable a demangling recursion limit.  This is the default.
      --no-recurse-limit Disable a demangling recursion limit.
  -D, --dynamic          显示动态符号而不是普通符号。对动态目标文件有意义。
      --defined-only     只显示定义的符号
  -e                     (ignored)
  -f, --format=FORMAT    使用输出的格式  FORMAT can be `bsd',
                           `sysv' or `posix'.  The default is `bsd'
  -g, --extern-only      只显示外部符号
  -l, --line-numbers     对每个符号,使用调试信息去视图找到文件名符号。对于已定义的符号,查找符号地址的行号。
  						 对于未定义的符号,查找指定符号重定位入口的行号。如果可以找到行号信息,
  						 在其它符号信息之后显示该信息。
  -n, --numeric-sort     按符号对应地址的顺序排序,而不是按符号名的字符顺序
  -o                     Same as -A
  -p, --no-sort          不以任何顺序对符号进行排序
  -P, --portability      Same as --format=posix
  -r, --reverse-sort     反转排序的顺序(按照数字或者字母顺序)显示
      --plugin NAME      Load the specified plugin
  -S, --print-size       Print size of defined symbols
  -s, --print-armap      列出归档文件中成员的符号时包含索引,即名字和包含该名字定义的模块的映射
      --size-sort        按照大小排列符号顺序,改大小是按照一个符号的值与它下一个符号的值进行计算
      --special-syms     包括输出特殊符号
      --synthetic        显示综合符号
  -t, --radix=RADIX      Use RADIX for printing symbol values
      --target=BFDNAME   Specify the target object format as BFDNAME
  -u, --undefined-only   仅显示没有定义的符号(那些目标文件中的外部符号)
      --with-symbol-versions  Display version strings after symbol names
  -X 32_64               (ignored)
  @FILE                  Read options from FILE
  -h, --help             Display this information
  -V, --version          Display this program's version number

nm符号类型

符号类型 含义
A Absolute 符号的值是绝对值,并且不会被将来的连接所改变
B BSS 符号位于未初始化数据段
C Common 符号是公共。公共符号是未初始化的数据。在连接时,多个公共符号可能以相同的名字出现。如果符号在其它地方被定义,该符号会被当做未定义的引用来处理。
D Data,符号位于已经初始化数据部分
N 调试符号
R ReadOnly Data 符号位于只读数据段
T Text 符号位于代码段
U Undefined 未被定义的符号
W Weak 弱定义符号,也称为弱符号。当一个弱定义符号和一个已定义的普通符号连接时,使用该以定义的普通符号不会引起错误。当一个未定义的弱符号被连接且该符号位被定义时,该Weak符号变为零,并且不会产生错误。

在nm显示的符号中,小写字母表示这个符号是局部符号,大写字母表示这个符号是全局符号。

5.1 查看目标文件中的符号

deng@itcast:~/share/3rd/1static_lib$ nm add.o 
0000000000000000 T add
deng@itcast:~/share/3rd/1static_lib$ 

5.2 查看共享库中的符号

deng@itcast:~/share/3rd/3share_lib$ nm libtest.so 
00000000000010f9 T add
0000000000004020 b completed.8059
                 w __cxa_finalize
0000000000001040 t deregister_tm_clones
00000000000010b0 t __do_global_dtors_aux
0000000000003e88 d __do_global_dtors_aux_fini_array_entry
0000000000004018 d __dso_handle
0000000000003e90 d _DYNAMIC
0000000000001158 t _fini
00000000000010f0 t frame_dummy
0000000000003e80 d __frame_dummy_init_array_entry
0000000000002118 r __FRAME_END__
0000000000004000 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
0000000000002000 r __GNU_EH_FRAME_HDR
0000000000001000 t _init
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
0000000000001127 T mul
000000000000113e T mydiv
0000000000001070 t register_tm_clones
0000000000001111 T sub
0000000000004020 d __TMC_END__
deng@itcast:~/share/3rd/3share_lib$ 

5.3 查看可执行文件中的符号

deng@itcast:~/share/3rd/2static_test$ nm main 
00000000000011f2 T add
0000000000004010 B __bss_start
0000000000004010 b completed.8059
                 w __cxa_finalize@@GLIBC_2.2.5
0000000000004000 D __data_start
0000000000004000 W data_start
0000000000001090 t deregister_tm_clones
0000000000001100 t __do_global_dtors_aux
0000000000003dc0 d __do_global_dtors_aux_fini_array_entry
0000000000004008 D __dso_handle
0000000000003dc8 d _DYNAMIC
0000000000004010 D _edata
0000000000004018 B _end
00000000000012c8 T _fini

06. strip命令

strip工具用于删除文件中的符号。使用strip既可以删除目标文件中的某个符号,也可以删除整个节。使用strip至少要有一个输入文件,也可以输入一个文件列表。

strip命令用法如下

deng@itcast:~/share/3rd/3share_lib$ strip --help
用法:strip <选项> 输入文件
 从文件中删除符号和节
 选项为:
  -I --input-target=<bfdname>      默认所有输入文件为<bfdname>格式
  -O --output-target=<bfdname>     建立<bfdname>格式的输出文件
  -F --target=<bfdname>            Set both input and output format to <bfdname>
  -p --preserve-dates              保留时间戳信息
  -D --enable-deterministic-archives
                                   Produce deterministic output when stripping archives (default)
  -U --disable-deterministic-archives
                                   Disable -D behavior
  -R --remove-section=<name>       删除名称为<name>的节
     --remove-relocations <name>   Remove relocations from section <name>
  -s --strip-all                   删除所有的节
  -g -S -d --strip-debug           删除所有符号和重定向信息
     --strip-dwo                   Remove all DWO sections
     --strip-unneeded              删除所有重定向不需要的节
     --only-keep-debug             Strip everything but the debug information
  -M  --merge-notes                Remove redundant entries in note sections (default)
      --no-merge-notes             Do not attempt to remove redundant notes
  -N --strip-symbol=<name>         删除名称为name的符号
     --keep-section=<name>         Do not strip section <name>
  -K --keep-symbol=<name>          保留名称为name的符号
     --keep-file-symbols           Do not strip file symbol(s)
  -w --wildcard                    Permit wildcard in symbol comparison
  -x --discard-all                 删除所有非全局符号
  -X --discard-locals              删除所有编译产生的符号
  -v --verbose                     显示所有修改的文件
  -V --version                     Display this program's version number
  -h --help                        Display this output
     --info                        List object formats & architectures supported
  -o <file>                        输出文件为file

6.1 使用strip删除main文件中的符号,输出为main_stripped文件。

# main_stripped是被删除了符号的可执行程序。
deng@itcast:~/projects/Project1$ strip main -o main_stripped
deng@itcast:~/projects/Project1$ ls -lh main main_stripped 
-rwxrwxr-x 1 deng deng 17K 6月  18 20:11 main
-rwxrwxr-x 1 deng deng 15K 6月  18 20:11 main_stripped
deng@itcast:~/projects/Project1$ 

# main_stripped中已经不包含任何符号
deng@itcast:~/projects/Project1$ nm main_stripped 
nm: main_stripped:无符号
deng@itcast:~/projects/Project1$ 

6.2 使用file命令对比main和main_stripped两个文件

deng@itcast:~/projects/Project1$ file main
main: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, 
interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=655998d8473f3943b09638ea12e6bb148838c2e1, 
for GNU/Linux 3.2.0, not stripped

deng@itcast:~/projects/Project1$ file main_stripped 
main_stripped: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-
linux-x86-64.so.2, BuildID[sha1]=655998d8473f3943b09638ea12e6bb148838c2e1, for GNU/Linux 3.2.0, stripped
deng@itcast:~/projects/Project1$ 

友情提示:

strip工具在嵌入式这种存储空间非常有限的系统中很有用,它可以极大程度的减少程序的体积,去掉复杂的符号表,因为符号表主要用于调试,所以可以再PC上调试完成后,烧写到目标板之前就直接利用strip命令。

07. 附录

7.1【Linux】GCC程序开发工具(上)
7.2 【Linux】GCC程序开发工具(中)
7.3 【Linux】GCC程序开发工具(下)

猜你喜欢

转载自blog.csdn.net/dengjin20104042056/article/details/106849502