讲解上面三条命令之前要先了解一下ELF格式文件https://blog.csdn.net/u014608280/article/details/81983055

一、readelf

 readelf命令可以查看ELF文件的详细信息。

选项

-a
--all 显示全部信息,等价于 -h -l -S -s -r -d -V -A -I. 

-h
--file-header 显示elf文件开始的文件头信息. 

-l
--program-headers 
--segments 显示程序头(段头)信息(如果有的话)。 

-S
--section-headers 
--sections 显示节头信息(如果有的话)。 

-g
--section-groups 显示节组信息(如果有的话)。 

-t
--section-details 显示节的详细信息(-S的)。 

-s
--syms       
--symbols 显示符号表段中的项(如果有的话)。 

-e
--headers 显示全部头信息,等价于: -h -l -S 

-n
--notes 显示note段(内核注释)的信息。 

-r
--relocs 显示可重定位段的信息。 

-u
--unwind 显示unwind段信息。当前只支持IA64 ELF的unwind段信息。 

-d
--dynamic 显示动态段的信息。 

-V
--version-info 显示版本段的信息。 

-A
--arch-specific 显示CPU构架信息。 

-D
--use-dynamic 使用动态段中的符号表显示符号,而不是使用符号段。 

-x <number or name>
--hex-dump=<number or name> 以16进制方式显示指定段内内容。number指定段表中段的索引,或字符串指定文件中的段名。 

-w[liaprmfFsoR] or
--debug-dump[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=loc,=Ranges] 显示调试段中指定的内容。 

-I
--histogram 显示符号的时候,显示bucket list长度的柱状图。 

-v
--version 显示readelf的版本信息。 

-H
--help 显示readelf所支持的命令行选项。 

-W
--wide 宽行输出。 

@file 可以将选项集中到一个文件中,然后使用这个@file选项载入。

查看ELF文件头信息

readelf nm objdump 命令详解

从输出结果我们可以得到:ELF魔数、文件机器字节长度、数据存储方式、版本、运行平台、ABI版本、ELF重定位类型、硬件平台、硬件平台版本、入口地址、程序头入口和长度、段表的位置和长度及段数量等。

ELF文件中有很多各式各样的段,段表就是保存这些段的基本属性的结构。段表是ELF文件中除了文件头以外最重要的结构。

虽然用objdump -h 命令也可以查看ELF文件中包含的段,但是只能查看关键的段,其他辅助的段会省略掉。我们可以用readelf -S命令查看详细的段表结构。

对比一下

objdump -h 

readelf nm objdump 命令详解

.text(代码段) 、.data(数据段)、.bss是最基本的段,.rodata(只读数据段)、.comment(注释信息段)、.note.GNU-stack(堆栈提示段)。Name 为段名称、Size 是段的长度,File off 为段所在的位置。第二行表示段的各种属性CONTENTS表示改段在文件中存在。

这里提一下另外一个命令size,可以查看目标文件中主要段的大小

readelf nm objdump 命令详解

readelf -S

readelf nm objdump 命令详解

段表就是有11个元素的数组,Name为段名,Type为段的类型(详细见附表1),Address为段虚拟地址,Offset为段偏移,Size为段的长度,Entsize为Section Entry Size项的长度(有些段包含了一些固定大小的项,比如符号表,它包含的每个符号所占的大小都是一样的。对于这种段,Entsize表示每个项的大小),Flage为段的标志位(详细见附表2),Link和Info为段的连接信息,Align为段地址对齐。

ELF文件中还有一个重要的是符号表,用readelf -s 查看

readelf nm objdump 命令详解

Value为符号相对应的值,Size为符号的大小(对于包含数据的符号,即为该数据类型的大小),Type为符号类型(见符号类型表),Bind绑定信息(LOCAL 表示局部符号,对目标文件外部不可见;GLOBAL表示全局符号,外部可见;WEAK 表示弱引用),Ndx表示为符号所在的段(ABS表示该符号包含一个绝对值,COMMON 表示一般为为初始化的全局符号,UNDEF表示改符号未定义,在本目标文件中被引用但是定义在其他目标文件中)

 

二、objdump

objdump 查看目标文件或者可执行的目标文件

常用参数:

  • -f 显示文件头信息
  • -D 反汇编所有section (-d反汇编特定section)
  • -h 显示目标文件各个section的头部摘要信息
  • -x 显示所有可用的头信息,包括符号表、重定位入口。-x 等价于 -a -f -h -r -t 同时指定。
  • -i 显示对于 -b 或者 -m 选项可用的架构和目标格式列表。
  • -r 显示文件的重定位入口。如果和-d或者-D一起使用,重定位部分以反汇编后的格式显示出来。
  • -R 显示文件的动态重定位入口,仅仅对于动态目标文件有意义,比如某些共享库。
  • -s 将所有段的内容以十六进制的方式打印出来
  • -S 尽可能反汇编出源代码,尤其当编译的时候指定了-g这种调试参数时,效果比较明显。隐含了-d参数。
  • -t 显示文件的符号表入口。类似于nm -s提供的信息

objdump  -d   查看每个段的汇编

readelf nm objdump 命令详解readelf nm objdump 命令详解

输出太长只截取了一部分

objdump -t 查看符号信息

readelf nm objdump 命令详解

三、nm

nm -s   

readelf nm objdump 命令详解

 

输出符号含义说明:

A 该符号的值是绝对的,在以后的链接过程中,不允许进行改变。这样的符号值,常常出现在中断向量表中,例如用符号来表示各个中断向量函数在中断向量表中的位置。
B 该符号的值出现在非初始化数据段(bss)中。例如,在一个文件中定义全局static int test。则该符号test的类型为b,位于bss section中。其值表示该符号在bss段中的偏移。一般而言,bss段分配于RAM中
C 该符号为common。common symbol是未初始话数据段。该符号没有包含于一个普通section中。只有在链接过程中才进行分配。符号的值表示该符号需要的字节数。例如在一个c文件中,定义int test,并且该符号在别的地方会被引用,则该符号类型即为C。否则其类型为B。
D 该符号位于初始话数据段中。一般来说,分配到data section中。例如定义全局int baud_table[5] = {9600, 19200, 38400, 57600, 115200},则会分配于初始化数据段中。
G 该符号也位于初始化数据段中。主要用于small object提高访问small data object的一种方式。
I 该符号是对另一个符号的间接引用。
N 该符号是一个debugging符号。
R 该符号位于只读数据区。例如定义全局const int test[] = {123, 123};则test就是一个只读数据区的符号。注意在cygwin下如果使用gcc直接编译成MZ格式时,源文件中的test对应_test,并且其符号类型为D,即初始化数据段中。但是如果使用m6812-elf-gcc这样的交叉编译工具,源文件中的test对应目标文件的test,即没有添加下划线,并且其符号类型为R。一般而言,位于rodata section。值得注意的是,如果在一个函数中定义const char *test = “abc”, const char test_int = 3。使用nm都不会得到符号信息,但是字符串“abc”分配于只读存储器中,test在rodata section中,大小为4。
S 符号位于非初始化数据区,用于small object。
T 该符号位于代码区text section。
U 该符号在当前文件中是未定义的,即该符号的定义在别的文件中。例如,当前文件调用另一个文件中定义的函数,在这个被调用的函数在当前就是未定义的;但是在定义它的文件中类型是T。但是对于全局变量来说,在定义它的文件中,其符号类型为C,在使用它的文件中,其类型为U。
V 该符号是一个weak object。
W The symbol is a weak symbol that has not been specifically tagged as a weak object symbol.
- 该符号是a.out格式文件中的stabs symbol。
? 该符号类型没有定义

 

附表1 段的类型 

readelf nm objdump 命令详解 readelf nm objdump 命令详解

附表2 段的标志位

readelf nm objdump 命令详解

以及系统保留段的属性

readelf nm objdump 命令详解readelf nm objdump 命令详解

2、符号类型表

readelf nm objdump 命令详解

相关文章: