linux应用程序-ELF查看工具
原文地址¶
https://www.jianshu.com/p/d9489aba95a9
正文¶
可用于查看分析 ELF文件 的工具如下所示:
工具 | 功能说明 |
---|---|
strings | 输出 ELF文件 中的所有字符串 |
strip | 删除 ELF文件 中一些无用的信息 |
nm | 显示目标文件中的所有符号 |
size | 显示目标文件中的 section 大小及目标文件大小 |
readelf | 显示ELF文件中的内容,主要的ELF分析工具 |
objdump | 显示目标文件的汇编信息,主要用于反汇编 |
ar | 将目标文件链接为静态库 |
addr2line | 将地址转换为文件、行号 |
2.1 nm¶
2.1.1 使用格式¶
nm 的使用格式为 nm [-options] [files],当没有输入文件时,默认使用当前目录下的 a.out 文件作为输入。 我们说一下几个常用的选项; nm的用法很简单,以下几个关键字比较常用:
- -A:列出符号名的时候并显示来自于文件来源,一般用于查看 多个文件(比如库文件) 的符号时比较有用
- -a:列出所有符号,该选线会将 调试符号 也列出来。默认状态下 不显示 调试符号。
- -l:列出符号在源代码中对应的行号,对于 未定义符号 显示为空
- -n:根据符号的地址来排序,默认按符号名的字母顺序进行排序的
- -u:只列出 未定义符号
- --defined-only:只列出 已定义符号
- -f:指定输出格式,可以使用 nm -f sysv 查看变量所在的节区
- -r:按顺序打印出符号
2.1.2 输出¶
下面是一个 nm查看一个测试程序的符号,我们简单看一下输出:
nm输出
其输出一共有 3 列,分别如下:
- 第一列:符号 起始地址
- 第二列:符号 类型
- 第三列:符号 名称
2.1.3 符号类型¶
我们重点看一下符号类型,如下表所示:
符号类型 | 含义 |
---|---|
A | 该符号的值是绝对的,在以后的链接过程中,不允许进行改变。该符号类型常常出现在中断向量表中,比如用符号来表示各个中断向量函数在中断向量表中的位置 |
B | 该符号出现在 BSS段 中,同时也位于 bss section。其值表示该符号在 BSS段 中的 偏移。一般而言,BSS段 分配于RAM中 |
D | 该符号位于data段 中,同时也位于 data section |
N | 该符号是一个 调试符号 |
R | 该符号位于 只读数据区,比如由 const 修饰的变量或者字符串常量等 |
S | 该符号位于非初始化数据区,一般也位于 rodata section |
T | 该符号位于代码段 的 text section |
U | 该符号在当前文件中是未定义的,即该符号的定义在别的文件 |
2.2 size¶
使用方法为: size file_name ,如图所示
size输出
其输出含义如下:
- text:表示文件中指令的大小
- data:表示文件有初值的全局变量和静态变量的大小
- bss:表示文件中未赋初值或初值为 0 的全局变量和静态变量的大小
- dec:text + data + bss
- hex:dec 的 16 进制表示
2.3 readelf¶
readelf 的 使用方法为:readelf [-options] [files]。下面列举几个我们常用的选项:
- -h:查看 ELF文件头,其输出含义如下:
输出字段 | 含义 |
---|---|
Magic | 该行给出了ELF文件的一些标识信息 |
Entry point address | 程序入口的 虚拟地址。如果目标文件没有程序入口,可以为 0。在程序加载完成后,loader 会将程序指针转移到该地址。 |
Start of program headers | 表明 程序头部表(program header) 在 ELF文件 中的位置。 |
Start of section headers | 表明 节区头部表(section header) 在 ELF文件 中的位置。 |
Size of this heade | 表明 ELF文件头 的大小。 |
Size of program headers | 表明 程序头部表 中每行的大小为 32 个字节。 |
Number of program headers | 表明在 程序头部表 的行数,也就意味着程序的段数。 |
Size of section headers | 表明 节区头部表 每行的大小 |
Number of section headers | 表明在 节区头部表 中的行数,也就意味着程序中节数 |
- -S:查看 节(section) 信息,其输出字段为:
- Type:节区类型,其含义如下
段类型 | 含义 |
---|---|
NULL | 此值标志节区头部是非活动的,没有对应的节区。此节区头部中的其他 成员取值无意义 |
PROGBITS | 此节区包含程序定义的信息,其格式和含义都由程序来解释,代码节区 和 数据节区 都是这种类型 |
SYMTAB | 此节区包含 符号表。符号表中每一个符号是值都是一个 数字,该数字是对应符号的符号名在 字符串表 中的下标 |
STRTAB | 此节区包含 字符串表,目标文件可能包含多个字符串表节区 |
RELA | 此节区包含 重定位表项。目标文件可能拥有多个重定位节区 |
HASH | 此节区包含符号哈希表。所有参与动态链接的目标都必须包含一个 符号哈希表 |
DYNAMIC | 此节区包含动态链接的信息 |
NOTE | 此节区包含以某种方式来标记文件的信息 |
NOBITS | 这种类型的节区不占用文件中的空间,其他方面和 SHT_PROGBITS 相似,如bss段 |
DYNSYM | 动态链接符号表,它可能包含很多对动态链接而言不必要的符号 |
INIT_ARRAY | 在 main函数 之前运行的函数指针数组 |
FINI_ARRAY | 在退出 main函数 之后,运行的函数指针数组 |
- Addr:如果节区将出现在进程的内存映像中,此成员给出节区的第一个字节应处的位置。 否则此字段为 0
- Off:表示该节内容在距离 文件起始 的偏移地址。
- Size:表示该节在文件中的 大小
- ES:某些节区中包含 固定大小 的项目,如 符号表。对于这类节区,此成员给出每个表项的 长度字节数 。 如果节区中并不包含固定长度表项的表格,此成员取值为 0
- Flag: 表示该节的内存分配属性,A(分配内存) , X(可执行) , W(可写)
- Lk: 此成员给出节区头部表 索引链接
-
AL: 某些节区带有 地址对齐约束
-
-l:查看 段(segment) 信息及 节与段之间的映射关系,其输出字段为
- Type:段类型,其含义如下
段类型 | 含义 |
---|---|
PHDR | 此段给出了程序头部表自身的 大小 和 位置,同时包括 在文件 和 在内存 中的信息 |
INTERP | 该段给出一个NULL结尾的字符串。该字符串将被当作解释器调用。对于 ELF文件 来讲,该段指定了启动进程的 Loader |
LOAD | 该段是一个可加载的段,段的大小由 FileSiz 和 MemSiz 描述。文件中的字节被映射到内存段开始处 |
DYNAMIC | 该段给出动态链接信息 |
NOTE | 此段给出附加信息的位置和大小 |
- Offset:该段在距离文件开头的 偏移地址
- VirtAddr:此成员给出段的第一个字节将被放到内存中的 虚拟地址
- PhysAddr:此成员仅用于与物理地址相关的系统中
- FileSiz:此成员给出段在 文件映像 中所占的 字节数
- MemSiz:此成员给出段在 内存映像 中占用的 字节数
- Flg:该段的属性,R(可读),E(可执行),W(可写)
- Align:表示该段的要求 字节对齐 属性
注意,MemSize 可能与 FileSize 不等,主要是因为 .bss段 只占据 内存空间,不占据 文件空间。
- -r:查看 重定位节区信息
- -s:查看 符号表
- -d:读取 .dynamic段,该段包含 可执行文件所依赖的库
2.4 addr2line¶
addr2line的 使用方法为:addr2line[-options] [files]。下面列举几个我们常用的选项:
- -e:指定 可执行文件,在 执行文件 需要在编译时加入 -g 选项来加入调试信息
25 objdump¶
- -h:打印ELF文件中所有section头,输出字段如下:
- Idx Name:section 名
- Size:大小
- File off:在文件中的偏移
- -r:查看目标文件的静态重定位表:
- OFFSET:重定位入口偏移
- TYPE:重定位入口类型
- VALUE:重定位入口的符号
- -R:查看共享对象的 动态 重定位表:
2.6 objcopy¶
objcopy 可以将 非ELF文件 编译为 section,使其能够直接链接到 可执行文件 中。 其使用方法为 objcopy [-optoins] input output 常用选项如下:
- -I:输入文件格式
- O:输出文件格式
- -B:设置输出文件的体系架构,比如i386