readelf 命令以及 ELF 格式简要介绍

2021/9/26

ELF 文件格式简要介绍。 以及显示有关 ELF 文件的信息 - readelf。

# ELF 文件格式

ELF(Executable and Linking Format)是一种对象文件的格式,用于定义不同类型的对象文件(Object files)中都放了什么东西、以及都以什么样的格式去放这些东西。

  1. 可重定位的对象文件(Relocatable file)

    这是由汇编器汇编生成的 .o 文件。后面的链接器(link editor)拿一个或一些 Relocatable object files 作为输入,经链接处理后,生成一个可执行的对象文件 (Executable file) 或者一个可被共享的对象文件(Shared object file)。我们可以使用 ar 工具将众多的 .o Relocatable object files 归档(archive)成 .a 静态库文件。

  2. 可执行的对象文件(Executable file)

    可执行应用程序

  3. 可被共享的对象文件(Shared object file)

    动态库文件,也即 .so 文件。如果拿前面的静态库来生成可执行程序,那每个生成的可执行程序中都会有一份库代码的拷贝。如果在磁盘中存储这些可执行程序,那就会占用额外的磁盘空间;另外如果拿它们放到 Linux 系统上一起运行,也会浪费掉宝贵的物理内存。如果将静态库换成动态库,那么这些问题都不会出现。动态库在发挥作用的过程中,必须经过两个步骤:

    1. 链接编辑器(link editor)拿它和其他 Relocatable object file 以及其他 shared object file 作为输入,经链接处理后,生存另外的 shared object file 或者 executable file。
    2. 在运行时,动态链接器(dynamic linker)拿它和一个 Executable file 以及另外一些 Shared object file 来一起处理,在 Linux 系统里面创建一个进程映像。

ELF 格式需要使用在两种场合:

  1. 组成不同的可重定位文件,以参与可执行文件或者可被共享的对象文件的链接构建;
  2. 组成可执行文件或者可被共享的对象文件,以在运行时内存中进程映像的构建。

sections 是在 ELF 文件里头,用以装载内容数据的最小容器。在 ELF 文件里面,每一个 sections 内都装载了性质属性都一样的内容,比方:

  • .text section 里装载了可执行代码;
  • .data section 里面装载了被初始化的数据;
  • .bss section 里面装载了未被初始化的数据;
  • 以 .rec 打头的 sections 里面装载了重定位条目;
  • .symtab 或者 .dynsym section 里面装载了符号信息;
  • .strtab 或者 .dynstr section 里面装载了字符串信息;

# readelf 描述

readelf 显示有关一个或多个 ELF 格式对象文件的信息。 选项控制要显示的特定信息。 支持 32 位和 64 位 ELF 文件,以及包含 ELF 文件的存档。 该程序执行与 objdump 类似的功能,但它更详细,它独立于 BFD 库存在,所以如果 BFD 中有错误则 readelf 不会受到影响。

# readelf 用法

这里显示的长和短形式的选项是等价的。除了-v 或-H 之外,必须至少提供一个选项。

  • -a --all 相当于指定 --file-header --program-headers --sections --symbols --relocs --dynamic --notes--version-info

  • -h --file-header 显示文件开头的 ELF 头中包含的信息

  • -l --program-headers --segments 显示文件的 segment 头中包含的信息(如果有)。

  • -S --sections --section-headers 显示文件的 section 头中包含的信息(如果有)。

  • -g --section-groups 显示文件的 section group 中包含的信息(如果有)。

  • -t --section-details 显示详细的 section 信息。意味着 -S。

  • -s --symbols --syms 显示文件的 symbol table section 中的条目(如果有)。

  • -e --headers 显示文件中的所有 headers。相当于 -h -l -S。

  • -n --notes 显示 NOTE segment(和/或)section 的内容(如果有)。

  • -r --relocs 显示文件 relocation section 的内容(如果有)。

  • -u --unwind 显示文件的 unwind section 的内容(如果有)。目前仅支持 IA64 ELF 文件的 unwind section

  • -d --dynamic 显示文件 dynamic section 的内容(如果有)。

  • -V --version-info 显示文件中 version section 的内容,如果存在。

  • -A --arch-specific 显示文件中特定于体系结构的信息(如果有)。

  • -D --use-dynamic 显示符号时,此选项使 readelf 使用文件 dynamic section 中的符号表,而不是 symbol section 中的符号表。

  • -x <number or name> --hex-dump=<number or name> 以十六进制字节显示 indecated section 的内容。一个数字通过索引 section 表标识一个特定的 section;任何其他 string 标识目标文件中具有该名称的所有 section。

  • -R <number or name> --relocated-dump=<number or name> 以十六进制字节显示 indecated section 的内容。一个数字通过索引 section 表标识一个特定的 section;任何其他 string 标识目标文件中具有该名称的所有 section。该 section 的内容将在显示之前重新定位。

  • -p <number or name> --string-dump=<number or name> 将 indicated section 的内容显示为可打印字符串。一个数字通过索引 section 表标识一个特定的 section;任何其他 string 标识目标文件中具有该名称的所有 section。

  • -c --archive-index 显示二进制归档的 header 部分中包含的文件符号索引信息。对 ar 执行与 t 命令相同的功能,但不使用 BFD 库。

  • -w[lLiaprmfFsoR] --debug-dump[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=loc,=Ranges] 显示文件中 debug section 的内容(如果存在)。如果后面有一个可选的字母或单词,则只会转储在这些特定部分中找到的数据。
    注意:=codedline 选项将显示.debug_line section 解释后的内容,而=rawline 选项将以原始格式转储内容。

  • -I --histogram 显示符号表的内容时,显示桶列表长度的直方图。

  • -v --version 显示 readelf 的版本号。

  • -W --wide 不破坏输出线以适应 80 列。默认情况下,readelf 会断开 64 位 ELF 文件的 section header 和 segment 列表行,以便它们适合 80 列。此选项使 readelf 打印每个节标题 resp。每个 segment 只有一行,在 80 列以上的终端上可读性更高。

  • -H --help 显示 readelf 理解的命令行选项。

  • @file 从文件中读取命令行选项。读取的选项将替换原始@file 选项。如果文件不存在或无法读取,则该选项将按字面处理,而不会被删除。
    文件中的选项由空格分隔。通过用单引号或双引号括起整个选项,可以在选项中包含空格字符。可以通过在字符前加上反斜杠来包含任何字符(包括反斜杠)。该文件本身可能包含其他 @file 选项; 任何此类选项将以递归方式处理。

# readelf 实例 - 查看编译器版本

readelf [xxx] -p .comment
1

例如

>>> readelf ./libnetcdff.so -p .comment

String dump of section '.comment':
  [     0]  GCC: (GNU) 8.4.1 20200928 (Red Hat 8.4.1-1)
1
2
3
4

# 参考

Last Updated: 2023-10-29T08:26:04.000Z