跳转至

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查看一个测试程序的符号,我们简单看一下输出:

img

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 ,如图所示

img

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