linux-command 命令手册:readelf 详解——剖析 ELF 文件结构的 GNU 利器

发布时间:2026/10/3 12:51:26
linux-command 命令手册:readelf 详解——剖析 ELF 文件结构的 GNU 利器 文档教程【免费下载链接】linux-commandLinux命令大全搜索工具内容包含Linux命令手册、详解、学习、搜集。https://git.io/linux项目地址https://gitcode.com/GitHub_Trending/linux/linux-command点击查看免费下载本篇技术指南聚焦 Linux 命令大全项目linux-command中的 readelf 命令手册系统讲解 readelf 的用法、ELF 文件的三种类型与内部组成并通过可执行文件、目标文件、静态库、动态库四类真实样本的-h/-l/-S输出带你掌握从文件头、程序头表到节头表的完整剖析方法。读完本文你将能独立使用 readelf 检查任意 ELF 文件的类型、加载布局与调试信息并理解它与 objdump、ar、nm 等配套工具的分工。readelf 是什么ELF 信息的专业透视镜readelf 命令用来显示一个或者多个 ELF 格式目标文件的信息可以通过它的选项来控制显示哪些信息。这里的elf-file(s)表示那些被检查的文件。它支持 32 位、64 位的 ELF 格式文件也支持包含 ELF 文件的文档——这里一般指使用ar命令将一些 ELF 文件打包之后生成的例如lib*.a之类的静态库文件。这个程序和objdump提供的功能类似但是它显示的信息更为具体并且它不依赖 BFD 库BFD 库是一个 GNU 项目它的目标就是希望通过一种统一的接口来处理不同的目标文件所以即使 BFD 库有什么 bug 存在的话也不会影响到 readelf 程序。两者在 linux-command 命令手册中均有收录可对照参考 objdump 详解 一文。使用约束运行 readelf 的时候除了-v和-H之外其它的选项必须有一个被指定。也就是说readelf 与许多裸跑即可输出默认信息的命令不同它必须带上至少一个功能选项才会执行真正的检查。ELF 文件基础三种类型与两种视角三种类型的 ELF 文件可重定位文件Relocatable File用户和其他目标文件一起创建可执行文件或者共享目标文件例如lib*.a文件。可执行文件Executable File用于生成进程映像载入内存执行例如编译好的可执行文件a.out。共享目标文件Shared Object File用于和其他共享目标文件或者可重定位文件一起生成 ELF 目标文件或者和执行文件一起创建进程映像例如lib*.so文件。ELF 文件的两种观察视角ELF 文件参与程序的连接建立一个程序和程序的执行运行一个程序所以可以从不同的角度来看待 ELF 格式的文件如果用于编译和链接可重定位文件编译器和链接器将把 ELF 文件看作是节头表描述的节的集合程序头表可选。如果用于加载执行可执行文件加载器则将把 ELF 文件看作是程序头表描述的段的集合一个段可能包含多个节节头表可选。如果是共享文件则两者都含有。ELF 文件总体组成ELF 文件头描述 ELF 文件的总体信息包括系统相关、类型相关、加载相关、链接相关四类信息系统相关表示 ELF 文件标识的魔术数以及硬件和平台等相关信息增加了 ELF 文件的移植性使交叉编译成为可能。类型相关就是前面说的那三种文件类型。加载相关包括程序头表相关信息。链接相关节头表相关信息。这一头 程序头表 节头表的分层结构正是 readelf 各选项分别输出的对象。选项全解控制显示哪一部分信息-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-dumpnumber 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选项载入。要点说明-a--all是日常排查最省事的入口一次输出文件头、程序头、节头、符号表、重定位、动态段、版本信息、架构信息与柱状图-e--headers是-h -l -S三者的合并适合只看头部三件套-x与-w面向底层内容前者以十六进制 dump 指定节索引或节名均可后者按需展示各类调试节-w的细分参数可精确到line行号、infoDWARF 信息、abbrev缩写表、frames栈帧等-W宽行输出在符号表、节表列数较多时可避免换行折行便于脚本与终端查看file与 readelf 同族的 binutils 工具保持一致可以把成串的选项写入一个文件再整体载入。实战准备构造四类 ELF 样本1. 可执行文件形式的样本查看可执行程序的源代码如下[rootlocalhost test]$ cat main.cpp #include iostream using std::cout; using std::endl; void my_print(); int main(int argc, char *argv[]) { my_print(); couthello!endl; return 0; } void my_print() { coutprint!endl; }编译如下一条不带调试信息一条带-g[rootlocalhost test]$ g main.cpp -o main [rootlocalhost test]$ g -g main.cpp -o main.debug编译之后查看生成的文件[rootlocalhost test]$ ls -l 总计 64 -rwxr-xr-x 1 quietheart quietheart 6700 07-07 18:04 main -rw-r--r-- 1 quietheart quietheart 201 07-07 18:02 main.cpp -rwxr-xr-x 1 quietheart quietheart 38932 07-07 18:04 main.debug这里main.debug是带有调试信息的可执行文件main是一般的可执行文件。2. 库文件形式的样本查看库的源代码如下//myfile.h #ifndef __MYFILE_H #define __MYFILE_H void printInfo(); #endif //myfile.cpp #include myfile.h #include iostream using std::cout; using std::endl; void printInfo() { couthelloendl; }编译出目标文件、共享库与静态库[rootlocalhost test]$ g -c myfile.cpp [rootlocalhost test]$ g -shared -fPCI -o libmy.so myfile.o [rootlocalhost test]$ ar -r libmy.a myfile.o ar: creating libmy.a编译之后查看生成的文件[rootlocalhost test]$ ls -l 总计 44 -rw-r--r-- 1 quietheart quietheart 2154 07-08 16:14 libmy.a -rwxr-xr-x 1 quietheart quietheart 5707 07-08 16:08 libmy.so -rwxr-xr-x 1 quietheart quietheart 117 07-08 16:06 myfile.cpp -rwxr-xr-x 1 quietheart quietheart 63 07-08 16:08 myfile.h -rw-r--r-- 1 quietheart quietheart 2004 07-08 16:08 myfile.o这里分别生成了目标文件myfile.o、共享库文件libmy.so和静态库文件libmy.a。其中libmy.a正是 readelf 文档开头提到的用 ar 打包 ELF 文件而成的静态库其打包过程可参考 ar 详解。实战一readelf -h 读取文件头识别文件类型读取可执行文件形式的 ELF 文件头[rootlocalhost test]$ readelf -h main ELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2s complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 type: exec (Executable file) Machine: Intel 80386 Version: 0x1 Entry point address: 0x8048580 Start of program headers: 52 (bytes into file) Start of section headers: 3232 (bytes into file) Flags: 0x0 Size of this header: 52 (bytes) Size of program headers: 32 (bytes) Number of program headers: 8 Size of section headers: 40 (bytes) Number of section headers: 29 Section header string table index: 26这里可见可执行文件的 ELF 文件其类型为EXEC可执行文件。另外含调试信息的main.debug和不含调试信息的main除了一些大小信息之外其内容是一样的并且由此可见文件的体系结构为 Intel 80386。注意首行Magic中的7f 45 4c 46正是 ELF 的魔数标识0x7f后紧跟E、L、F三个 ASCII 字符readelf 正是依据它确认文件属于 ELF 格式。读取目标文件形式的 ELF 文件头[rootlocalhost test]$ readelf -h myfile.o ELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2s complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: REL (Relocatable file) Machine: Intel 80386 Version: 0x1 Entry point address: 0x0 Start of program headers: 0 (bytes into file) Start of section headers: 516 (bytes into file) Flags: 0x0 Size of this header: 52 (bytes) Size of program headers: 0 (bytes) Number of program headers: 0 Size of section headers: 40 (bytes) Number of section headers: 15 Section header string table index: 12这里可见目标文件的 ELF 文件其类型为REL可重定位文件。注意其Entry point address为0x0、Number of program headers为0——尚未链接的可重定位文件没有入口点和程序头与前述程序头表可选的理论相互印证。读取静态库文件形式的 ELF 文件头[rootlocalhost test]$ readelf -h libmy.a File: libmy.a(myfile.o) ELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2s complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: REL (Relocatable file) Machine: Intel 80386 Version: 0x1 Entry point address: 0x0 Start of program headers: 0 (bytes into file) Start of section headers: 516 (bytes into file) Flags: 0x0 Size of this header: 52 (bytes) Size of program headers: 0 (bytes) Number of program headers: 0 Size of section headers: 40 (bytes) Number of section headers: 15 Section header string table index: 12这里可见静态库文件的 ELF 文件其类型为REL可重定位文件。注意输出第一行File: libmy.a(myfile.o)——readelf 自动识别出该归档archive内部的实际成员文件对其逐一显示。读取动态库文件形式的 ELF 文件头[rootlocalhost test]$ readelf -h libmy.so ELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2s complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: DYN (Shared object file) Machine: Intel 80386 Version: 0x1 Entry point address: 0x550 Start of program headers: 52 (bytes into file) Start of section headers: 2768 (bytes into file) Flags: 0x0 Size of this header: 52 (bytes) Size of program headers: 32 (bytes) Number of program headers: 5 Size of section headers: 40 (bytes) Number of section headers: 27 Section header string table index: 24这里可见动态库文件的 ELF 文件其类型为DYN共享目标文件。至此四种样本完整覆盖了 ELF 的三大类型EXEC、REL、DYN。在日常工作中readelf -h是最快的类型鉴别手段也可以与 file 详解 的魔法数探测互为印证。实战二readelf -l 读取程序头表看清加载布局查看可执行 ELF 文件的程序头表[rootlocalhost test]$ readelf -l main Elf file type is EXEC (Executable file) Entry point 0x8048580 There are 8 program headers, starting at offset 52 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align PHDR 0x000034 0x08048034 0x08048034 0x00100 0x00100 R E 0x4 INTERP 0x000134 0x08048134 0x08048134 0x00013 0x00013 R 0x1 Requesting program interpreter: /lib/[ld-linux.so.2] LOAD 0x000000 0x08048000 0x08048000 0x00970 0x00970 R E 0x1000 LOAD 0x000970 0x08049970 0x08049970 0x00130 0x001c8 RW 0x1000 DYNAMIC 0x000988 0x08049988 0x08049988 0x000e0 0x000e0 RW 0x4 NOTE 0x000148 0x08048148 0x08048148 0x00020 0x00020 R 0x4 GNU_EH_FRAME 0x000820 0x08048820 0x08048820 0x00044 0x00044 R 0x4 GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4 Section to Segment mapping: Segment Sections... 00 01 .interp 02 .interp .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame 03 .ctors .dtors .jcr .dynamic .got .got.plt .data .bss 04 .dynamic 05 .note.ABI-tag 06 .eh_frame_hdr 07这里含调试信息的main.debug和不含调试信息的main其内容是一样的。输出清晰地体现了段Segment是加载视角的单元一个段可包含多个节Section例如编号 02 的LOAD段可读可执行就聚合了.interp、.text、.rodata等一系列节而下方的Section to Segment mapping正是这种映射关系的逐条展开。INTERP段中标明了动态链接器/lib/ld-linux.so.2GNU_STACK段则描述栈的可执行属性。查看目标文件的程序头表[rootlocalhost test]$ readelf -l myfile.o There are no program headers in this file.这里可知可重定位的目标文件没有程序头表。查看静态库文件的程序头表[rootlocalhost test]$ readelf -l libmy.a File: libmy.a(myfile.o) There are no program headers in this file.这里可知可重定位的静态库文件没有程序头表。查看动态库文件的程序头表[rootlocalhost test]$ readelf -l libmy.so Elf file type is DYN (Shared object file) Entry point 0x550 There are 5 program headers, starting at offset 52 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x000000 0x00000000 0x00000000 0x007f4 0x007f4 R E 0x1000 LOAD 0x0007f4 0x000017f4 0x000017f4 0x0011c 0x00128 RW 0x1000 DYNAMIC 0x000810 0x00001810 0x00001810 0x000e0 0x000e0 RW 0x4 GNU_EH_FRAME 0x000738 0x00000738 0x00000738 0x0002c 0x0002c R 0x4 GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4 Section to Segment mapping: Segment Sections... 00 .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame 01 .ctors .dtors .jcr .data.rel.ro .dynamic .got .got.plt .bss 02 .dynamic 03 .eh_frame_hdr 04这里可知作为共享目标文件的动态库拥有程序头表。对比可执行文件与共享库的输出可以发现两者的LOAD段数量与构成相似但共享库的虚拟地址从0x0起始等待被装载进任意进程地址空间这与 PIE/共享库的加载特性一致。实战三readelf -S 读取节头表看清链接布局查看可执行 ELF 文件的节信息[rootlocalhost test]$ readelf -S main There are 29 section headers, starting at offset 0xca0: Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .interp PROGBITS 08048134 000134 000013 00 A 0 0 1 [ 2] .note.ABI-tag NOTE 08048148 000148 000020 00 A 0 0 4 [ 3] .gnu.hash GNU_HASH 08048168 000168 000030 04 A 4 0 4 [ 4] .dynsym DYNSYM 08048198 000198 0000d0 10 A 5 1 4 [ 5] .dynstr STRTAB 08048268 000268 000183 00 A 0 0 1 [ 6] .gnu.version VERSYM 080483ec 0003ec 00001a 02 A 4 0 2 [ 7] .gnu.version_r VERNEED 08048408 000408 000060 00 A 5 2 4 [ 8] .rel.dyn REL 08048468 000468 000010 08 A 4 0 4 [ 9] .rel.plt REL 08048478 000478 000048 08 A 4 11 4 [10] .init PROGBITS 080484c0 0004c0 000017 00 AX 0 0 4 [11] .plt PROGBITS 080484d8 0004d8 0000a0 04 AX 0 0 4 [12] .text PROGBITS 08048580 000580 000268 00 AX 0 0 16 [13] .fini PROGBITS 080487e8 0007e8 00001c 00 AX 0 0 4 [14] .rodata PROGBITS 08048804 000804 00001a 00 A 0 0 4 [15] .eh_frame_hdr PROGBITS 08048820 000820 000044 00 A 0 0 4 [16] .eh_frame PROGBITS 08048864 000864 00010c 00 A 0 0 4 [17] .ctors PROGBITS 08049970 000970 00000c 00 WA 0 0 4 [18] .dtors PROGBITS 0804997c 00097c 000008 00 WA 0 0 4 [19] .jcr PROGBITS 08049984 000984 000004 00 WA 0 0 4 [20] .dynamic DYNAMIC 08049988 000988 0000e0 08 WA 5 0 4 [21] .got PROGBITS 08049a68 000a68 000004 04 WA 0 0 4 [22] .got.plt PROGBITS 08049a6c 000a6c 000030 04 WA 0 0 4 [23] .data PROGBITS 08049a9c 000a9c 000004 00 WA 0 0 4 [24] .bss NOBITS 08049aa0 000aa0 000098 00 WA 0 0 8 [25] .comment PROGBITS 00000000 000aa0 000114 00 0 0 1 [26] .shstrtab STRTAB 00000000 000bb4 0000e9 00 0 0 1 [27] .symtab SYMTAB 00000000 001128 000510 10 28 53 4 [28] .strtab STRTAB 00000000 001638 0003f4 00 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings) I (info), L (link order), G (group), x (unknown) O (extra OS processing required) o (OS specific), p (processor specific)这里main是可执行文件不含调试信息。观察要点.text是代码节AX可分配、可执行.rodata是只读数据.data/.bss分别承载已初始化与未初始化的数据WA可写、可分配.symtab与.strtab是符号表及其字符串表Lk列中的 28 表示其链接对象Inf列中的 53 表示符号条数ESEntry Size列表示每个表项占用的字节数例如.dynsym为 160x10、.rel.dyn为 80x08。查看包含调试信息的可执行文件的节信息[rootlocalhost test]$ readelf -S main.debug There are 37 section headers, starting at offset 0x88c8: Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .interp PROGBITS 08048134 000134 000013 00 A 0 0 1 [ 2] .note.ABI-tag NOTE 08048148 000148 000020 00 A 0 0 4 [ 3] .gnu.hash GNU_HASH 08048168 000168 000030 04 A 4 0 4 [ 4] .dynsym DYNSYM 08048198 000198 0000d0 10 A 5 1 4 [ 5] .dynstr STRTAB 08048268 000268 000183 00 A 0 0 1 [ 6] .gnu.version VERSYM 080483ec 0003ec 00001a 02 A 4 0 2 [ 7] .gnu.version_r VERNEED 08048408 000408 000060 00 A 5 2 4 [ 8] .rel.dyn REL 08048468 000468 000010 08 A 4 0 4 [ 9] .rel.plt REL 08048478 000478 000048 08 A 4 11 4 [10] .init PROGBITS 080484c0 0004c0 000017 00 AX 0 0 4 [11] .plt PROGBITS 080484d8 0004d8 0000a0 04 AX 0 0 4 [12] .text PROGBITS 08048580 000580 000268 00 AX 0 0 16 [13] .fini PROGBITS 080487e8 0007e8 00001c 00 AX 0 0 4 [14] .rodata PROGBITS 08048804 000804 00001a 00 A 0 0 4 [15] .eh_frame_hdr PROGBITS 08048820 000820 000044 00 A 0 0 4 [16] .eh_frame PROGBITS 08048864 000864 00010c 00 A 0 0 4 [17] .ctors PROGBITS 08049970 000970 00000c 00 WA 0 0 4 [18] .dtors PROGBITS 0804997c 00097c 000008 00 WA 0 0 4 [19] .jcr PROGBITS 08049984 000984 000004 00 WA 0 0 4 [20] .dynamic DYNAMIC 08049988 000988 0000e0 08 WA 5 0 4 [21] .got PROGBITS 08049a68 000a68 000004 04 WA 0 0 4 [22] .got.plt PROGBITS 08049a6c 000a6c 000030 04 WA 0 0 4 [23] .data PROGBITS 08049a9c 000a9c 000004 00 WA 0 0 4 [24] .bss NOBITS 08049aa0 000aa0 000098 00 WA 0 0 8 [25] .comment PROGBITS 00000000 000aa0 000114 00 0 0 1 [26] .debug_aranges PROGBITS 00000000 000bb4 000020 00 0 0 1 [27] .debug_pubnames PROGBITS 00000000 000bd4 000028 00 0 0 1 [28] .debug_info PROGBITS 00000000 000bfc 0067aa 00 0 0 1 [29] .debug_abbrev PROGBITS 00000000 0073a6 000726 00 0 0 1 [30] .debug_line PROGBITS 00000000 007acc 0003e1 00 0 0 1 [31] .debug_frame PROGBITS 00000000 007eb0 00009c 00 0 0 4 [32] .debug_str PROGBITS 00000000 007f4c 000735 00 0 0 1 [33] .debug_loc PROGBITS 00000000 008681 0000f3 00 0 0 1 [34] .shstrtab STRTAB 00000000 008774 000151 00 0 0 1 [35] .symtab SYMTAB 00000000 008e90 000590 10 36 61 4 [36] .strtab STRTAB 00000000 009420 0003f4 00 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings) I (info), L (link order), G (group), x (unknown) O (extra OS processing required) o (OS specific), p (processor specific)可见相对非调试版本的可执行文件多了.debug_*段的信息.debug_info、.debug_abbrev、.debug_line、.debug_frame、.debug_str、.debug_loc、.debug_aranges、.debug_pubnames共 8 个这正是g -g编译选项注入的 DWARF 调试数据。若需进一步展开这些调试节可配合-w系列选项与之对照objdump 详解 中的-g/-S选项也能从调试信息中还原源码级汇编。查看目标文件、静态库、动态库的节信息目标文件myfile.o[rootlocalhost test]$ readelf -S myfile.o There are 15 section headers, starting at offset 0x204: Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .text PROGBITS 00000000 000034 00009e 00 AX 0 0 4 [ 2] .rel.text REL 00000000 000744 000060 08 13 1 4 [ 3] .data PROGBITS 00000000 0000d4 000000 00 WA 0 0 4 [ 4] .bss NOBITS 00000000 0000d4 000001 00 WA 0 0 4 [ 5] .ctors PROGBITS 00000000 0000d4 000004 00 WA 0 0 4 [ 6] .rel.ctors REL 00000000 0007a4 000008 08 13 5 4 [ 7] .rodata PROGBITS 00000000 0000d8 000006 00 A 0 0 1 [ 8] .eh_frame PROGBITS 00000000 0000e0 00008c 00 A 0 0 4 [ 9] .rel.eh_frame REL 00000000 0007ac 000028 08 13 8 4 [10] .comment PROGBITS 00000000 00016c 00002e 00 0 0 1 [11] .note.GNU-stack PROGBITS 00000000 00019a 000000 00 0 0 1 [12] .shstrtab STRTAB 00000000 00019a 00006a 00 0 0 1 [13] .symtab SYMTAB 00000000 00045c 000180 10 14 14 4 [14] .strtab STRTAB 00000000 0005dc 000166 00 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings) I (info), L (link order), G (group), x (unknown) O (extra OS processing required) o (OS specific), p (processor specific)与可执行文件相比目标文件的节表更精简且出现了.rel.text、.rel.ctors、.rel.eh_frame这类重定位节REL类型——它们记录了编译时尚未确定的符号引用等待链接阶段填写这正是可重定位文件名称的由来。静态库文件libmy.a[rootlocalhost test]$ readelf -S libmy.a File: libmy.a(myfile.o) There are 15 section headers, starting at offset 0x204: Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .text PROGBITS 00000000 000034 00009e 00 AX 0 0 4 [ 2] .rel.text REL 00000000 000744 000060 08 13 1 4 [ 3] .data PROGBITS 00000000 0000d4 000000 00 WA 0 0 4 [ 4] .bss NOBITS 00000000 0000d4 000001 00 WA 0 0 4 [ 5] .ctors PROGBITS 00000000 0000d4 000004 00 WA 0 0 4 [ 6] .rel.ctors REL 00000000 0007a4 000008 08 13 5 4 [ 7] .rodata PROGBITS 00000000 0000d8 000006 00 A 0 0 1 [ 8] .eh_frame PROGBITS 00000000 0000e0 00008c 00 A 0 0 4 [ 9] .rel.eh_frame REL 00000000 0007ac 000028 08 13 8 4 [10] .comment PROGBITS 00000000 00016c 00002e 00 0 0 1 [11] .note.GNU-stack PROGBITS 00000000 00019a 000000 00 0 0 1 [12] .shstrtab STRTAB 00000000 00019a 00006a 00 0 0 1 [13] .symtab SYMTAB 00000000 00045c 000180 10 14 14 4 [14] .strtab STRTAB 00000000 0005dc 000166 00 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings) I (info), L (link order), G (group), x (unknown) O (extra OS processing required) o (OS specific), p (processor specific)静态库的节表与其成员myfile.o完全一致再次印证 readelf 对归档文件会展开内部成员进行解析。动态库文件libmy.so[rootlocalhost test]$ readelf -S libmy.so There are 27 section headers, starting at offset 0xad0: Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .gnu.hash GNU_HASH 000000d4 0000d4 00003c 04 A 2 0 4 [ 2] .dynsym DYNSYM 00000110 000110 000120 10 A 3 1 4 [ 3] .dynstr STRTAB 00000230 000230 000199 00 A 0 0 1 [ 4] .gnu.version VERSYM 000003ca 0003ca 000024 02 A 2 0 2 [ 5] .gnu.version_r VERNEED 000003f0 0003f0 000050 00 A 3 2 4 [ 6] .rel.dyn REL 00000440 000440 0000b0 08 A 2 0 4 [ 7] .rel.plt REL 000004f0 0004f0 000010 08 A 2 9 4 [ 8] .init PROGBITS 00000500 000500 000017 00 AX 0 0 4 [ 9] .plt PROGBITS 00000518 000518 000030 04 AX 0 0 4 [10] .text PROGBITS 00000550 000550 0001c4 00 AX 0 0 16 [11] .fini PROGBITS 00000714 000714 00001c 00 AX 0 0 4 [12] .rodata PROGBITS 00000730 000730 000006 00 A 0 0 1 [13] .eh_frame_hdr PROGBITS 00000738 000738 00002c 00 A 0 0 4 [14] .eh_frame PROGBITS 00000764 000764 000090 00 A 0 0 4 [15] .ctors PROGBITS 000017f4 0007f4 00000c 00 WA 0 0 4 [16] .dtors PROGBITS 00001800 000800 000008 00 WA 0 0 4 [17] .jcr PROGBITS 00001808 000808 000004 00 WA 0 0 4 [18] .data.rel.ro PROGBITS 0000180c 00080c 000004 00 WA 0 0 4 [19] .dynamic DYNAMIC 00001810 000810 0000e0 08 WA 3 0 4 [20] .got PROGBITS 000018f0 0008f0 00000c 04 WA 0 0 4 [21] .got.plt PROGBITS 000018fc 0008fc 000014 04 WA 0 0 4 [22] .bss NOBITS 00001910 000910 00000c 00 WA 0 0 4 [23] .comment PROGBITS 00000000 000910 0000e6 00 0 0 1 [24] .shstrtab STRTAB 00000000 0009f6 0000da 00 0 0 1 [25] .symtab SYMTAB 00000000 000f08 000410 10 26 48 4 [26] .strtab STRTAB 00000000 001318 000333 00 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings) I (info), L (link order), G (group), x (unknown) O (extra OS processing required) o (OS specific), p (processor specific)动态库的节表兼具加载与链接两类信息既有.gnu.hash、.dynsym、.dynstr等供动态链接器使用的节也保留了.text、.rodata、.data.rel.ro等常规节同时保留.symtab/.strtab完整符号表可通过-s选项进一步查看符号项亦可参考 nm 详解 用nm -D查看其动态符号。从仓库源码结构看 readelf 的定位linux-command 仓库将每个命令的手册整理为command/目录下的独立 Markdown 文档并在dist/data.json中为每个命令建立索引条目其中 readelf 的条目位于该索引文件中导航路径为/readelf。围绕 readelf 的文档仓库中还收录了与其协同使用的整套 ELF 工具链objdump 详解与 readelf 功能类似的二进制信息显示工具但依赖 BFD 库擅长反汇编与源码级调试输出ar 详解readelf 文档中反复出现的静态库lib*.a的打包工具nm 详解专门显示目标文件符号表与readelf -s输出互补file 详解通过魔法数探测文件类型可在readelf之前快速确认文件是否为 ELF 格式。总结readelf 是 ELF 文件分析链路中结构最完整、依赖最干净的一环不依赖 BFD 库、支持 32/64 位及归档文件、以-h/-l/-S分别透视文件头、程序头表与节头表。通过本文的四类样本实验可以看到-h快速判断文件属于REL/EXEC/DYN中的哪一类-l揭示加载器视角的段布局与段—节映射-S呈现链接器视角的节清单并直观区分是否携带调试信息。掌握 readelf即掌握了用一套命令读懂任意 ELF 文件的骨架。赞分享文档教程【免费下载链接】linux-commandLinux命令大全搜索工具内容包含Linux命令手册、详解、学习、搜集。https://git.io/linux项目地址https://gitcode.com/GitHub_Trending/linux/linux-command点击查看免费下载相关推荐Step-Audio语音合成可扩展性设计支持百万级用户的架构方案Step Audio语音合成可扩展性设计支持百万级用户的架构方案 1. 语音合成服务的扩展性挑战 在当今的AI应用生态中语音合成Text to Speec网络安全逆向工程Linux echo 命令详解linux-command 速查手册中的 Shell 输出利器Linux echo 命令详解linux command 速查手册中的 Shell 输出利器 echo 是 Shell 编程与日常终端操作中使用频率最高的内建文档教程SerenityOS readelf 命令完全指南ELF 文件结构解析与安全加固审计SerenityOS readelf 命令完全指南ELF 文件结构解析与安全加固审计 本指南基于 SerenityOS 内置的 readelf 命令及其 ma操作系统内核驱动创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考