readelf介绍
readelf
是一个在 Unix 和类 Unix 系统上用于查看 ELF(Executable and Linkable Format)文件信息的命令行工具。ELF 文件是一种常用的文件格式,用于定义程序或系统所需的不同类型的文件,如可执行文件、目标文件、共享库等。
readelf
提供了许多选项来查看 ELF 文件的不同部分和属性,例如程序头、段头、符号表、重定位条目等。这对于理解程序的编译和链接方式、调试以及进行系统级编程非常有用。
常用 readelf
命令选项:
-
查看文件头 (
h
或-file-header
):
显示 ELF 文件的文件头信息,包括文件类型、机器类型、版本等。readelf -h <filename> ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: DYN (Shared object file) Machine: AArch64 Version: 0x1 Entry point address: 0xc000 Start of program headers: 64 (bytes into file) Start of section headers: 113640 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 10 Size of section headers: 64 (bytes) Number of section headers: 26 Section header string table index: 24
-
查看段头 (
S
或-section-headers
):
显示 ELF 文件的段头信息,包括各个段(如**.text
、.data
**)的大小、位置等。readelf -S <filename> Section Headers: [Nr] Name Type Address Offset Size EntSize Flags Link Info Align [ 0] NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0 [ 1] .note.android.ide NOTE 0000000000000270 00000270 0000000000000018 0000000000000000 A 0 0 4 [ 2] .note.gnu.build-i NOTE 0000000000000288 00000288 0000000000000020 0000000000000000 A 0 0 4 [ 3] .dynsym DYNSYM 00000000000002a8 000002a8 0000000000001c20 0000000000000018 A 7 1 8 [ 4] .gnu.version VERSYM 0000000000001ec8 00001ec8 0000000000000258 0000000000000002 A 3 0 2 [ 5] .gnu.version_r VERNEED 0000000000002120 00002120 0000000000000050 0000000000000000 A 7 2 4 [ 6] .gnu.hash GNU_HASH 0000000000002170 00002170 0000000000000664 0000000000000000 A 3 0 8 [ 7] .dynstr STRTAB 00000000000027d4 000027d4 0000000000005ac2 0000000000000000 A 0 0 1 [ 8] .rela.dyn LOOS+0x2 0000000000008298 00008298 0000000000000728 0000000000000001 A 3 0 8 [ 9] .relr.dyn 00000013: <unkn 00000000000089c0 000089c0 0000000000000060 0000000000000008 A 0 0 8 [10] .rela.plt RELA 0000000000008a20 00008a20 0000000000000888 0000000000000018 AI 3 21 8 [11] .rodata PROGBITS 00000000000092b0 000092b0 00000000000002c6 0000000000000000 AMS 0 0 16 [12] .eh_frame_hdr PROGBITS 0000000000009578 00009578 000000000000074c 0000000000000000 A 0 0 4 [13] .eh_frame PROGBITS 0000000000009cc8 00009cc8 0000000000001f9c 0000000000000000 A 0 0 8 [14] .text PROGBITS 000000000000c000 0000c000 000000000000d6cc 0000000000000000 AX 0 0 4 [15] .plt PROGBITS 00000000000196d0 000196d0 00000000000005d0 0000000000000000 AX 0 0 16 [16] .data.rel.ro PROGBITS 000000000001a000 0001a000 0000000000000fe0 0000000000000000 WA 0 0 8 [17] .fini_array FINI_ARRAY 000000000001afe0 0001afe0 0000000000000010 0000000000000000 WA 0 0 8 [18] .init_array INIT_ARRAY 000000000001aff0 0001aff0 0000000000000020 0000000000000000 WA 0 0 8 [19] .dynamic DYNAMIC 000000000001b010 0001b010 0000000000000200 0000000000000010 WA 7 0 8 [20] .got PROGBITS 000000000001b210 0001b210 00000000000000b8 0000000000000000 WA 0 0 8 [21] .got.plt PROGBITS 000000000001b2c8 0001b2c8 00000000000002f0 0000000000000000 WA 0 0 8 [22] .data PROGBITS 000000000001c5b8 0001b5b8 0000000000000030 0000000000000000 WA 0 0 8 [23] .bss NOBITS 000000000001c5e8 0001b5e8 0000000000000070 0000000000000000 WA 0 0 8 [24] .shstrtab STRTAB 0000000000000000 0001b5e8 0000000000000102 0000000000000000 0 0 1 [25] .gnu_debugdata PROGBITS 0000000000000000 0001b6ea 00000000000004fc 0000000000000000 0 0 1
-
查看程序头 (
l
或-program-headers
或-segments
):
显示程序头信息,通常用于可执行文件和共享库,展示如何映射到内存。readelf -l <filename> Elf file type is DYN (Shared object file) Entry point 0xc000 There are 10 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040 0x0000000000000230 0x0000000000000230 R 0x8 LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x000000000000bc64 0x000000000000bc64 R 0x1000 LOAD 0x000000000000c000 0x000000000000c000 0x000000000000c000 0x000000000000dca0 0x000000000000dca0 R E 0x1000 LOAD 0x000000000001a000 0x000000000001a000 0x000000000001a000 0x00000000000015b8 0x00000000000015b8 RW 0x1000 LOAD 0x000000000001b5b8 0x000000000001c5b8 0x000000000001c5b8 0x0000000000000030 0x00000000000000a0 RW 0x1000 DYNAMIC 0x000000000001b010 0x000000000001b010 0x000000000001b010 0x0000000000000200 0x0000000000000200 RW 0x8 GNU_RELRO 0x000000000001a000 0x000000000001a000 0x000000000001a000 0x00000000000015b8 0x0000000000002000 R 0x1 GNU_EH_FRAME 0x0000000000009578 0x0000000000009578 0x0000000000009578 0x000000000000074c 0x000000000000074c R 0x4 GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 RW 0x0 NOTE 0x0000000000000270 0x0000000000000270 0x0000000000000270 0x0000000000000038 0x0000000000000038 R 0x4 Section to Segment mapping: Segment Sections... 00 01 .note.android.ident .note.gnu.build-id .dynsym .gnu.version .gnu.version_r .gnu.hash .dynstr .rela.dyn .relr.dyn .rela.plt .rodata .eh_frame_hdr .eh_frame 02 .text .plt 03 .data.rel.ro .fini_array .init_array .dynamic .got .got.plt 04 .data .bss 05 .dynamic 06 .data.rel.ro .fini_array .init_array .dynamic .got .got.plt 07 .eh_frame_hdr 08 09 .note.android.ident .note.gnu.build-id
-
查看符号表 (
s
或-symbols
):
显示符号表,其中包含函数和变量等符号的信息。readelf -s <filename> Symbol table '.dynsym' contains 300 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __cxa_atexit@LIBC (2) 2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __cxa_finalize@LIBC (2) 75: 0000000000000000 0 FUNC GLOBAL DEFAULT UND malloc@LIBC (2) 76: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strerror@LIBC (2) 77: 0000000000000000 0 FUNC GLOBAL DEFAULT UND syslog@LIBC (2) 78: 000000000001c620 8 OBJECT WEAK DEFAULT 23 _ZGVN4aidl6vendor3qti8har 79: 00000000000151e8 4 FUNC GLOBAL DEFAULT 14 _ZN4aidl6vendor3qti8hardw 80: 0000000000010150 492 FUNC GLOBAL DEFAULT 14 _ZN4aidl6vendor3qti8hardw 81: 00000000000123b8 484 FUNC GLOBAL DEFAULT 14 _ZN4aidl6vendor3qti8hardw 82: 000000000001602c 52 FUNC GLOBAL DEFAULT 14 _ZN4aidl6vendor3qti8hardw 83: 000000000000c778 328 FUNC WEAK DEFAULT 14 _ZNSt3__16vectorIiNS_9all 84: 0000000000010950 428 FUNC GLOBAL DEFAULT 14 _ZN4aidl6vendor3qti8hardw 85: 0000000000016264 8 FUNC GLOBAL DEFAULT 14 _ZN4aidl6vendor3qti8hardw 86: 0000000000016aa4 4 FUNC WEAK DEFAULT 14 _ZNSt3__120__shared_ptr_p 87: 0000000000018b00 52 FUNC GLOBAL DEFAULT 14 _ZN4aidl6vendor3qti8hardw 88: 00000000000189e8 176 FUNC GLOBAL DEFAULT 14 _ZN4aidl6vendor3qti8hardw 89: 0000000000017a44 68 FUNC GLOBAL DEFAULT 14 _ZN4aidl6vendor3qti8hardw
-
查看动态段 (
d
或-dynamic
):
显示动态段的信息,主要用于共享库和动态链接。readelf -d <filename> Dynamic section at offset 0x1b010 contains 32 entries: Tag Type Name/Value 0x0000000000000001 (NEEDED) Shared library: [libbinder_ndk.so] 0x0000000000000001 (NEEDED) Shared library: [android.hardware.common-V2-ndk_platform.so] 0x0000000000000001 (NEEDED) Shared library: [libc++.so] 0x0000000000000001 (NEEDED) Shared library: [libc.so] 0x0000000000000001 (NEEDED) Shared library: [libm.so] 0x0000000000000001 (NEEDED) Shared library: [libdl.so] 0x000000000000000e (SONAME) Library soname: [vendor.qti.hardware.display.config-V6-ndk_platform.so] 0x000000000000001e (FLAGS) BIND_NOW 0x000000006ffffffb (FLAGS_1) Flags: NOW 0x0000000060000011 (Operating System specific: 60000011) 0x8298 0x0000000060000012 (Operating System specific: 60000012) 0x728 0x0000000000000009 (RELAENT) 24 (bytes) 0x0000000000000024 (<unknown>: 24) 0x89c0 0x0000000000000023 (<unknown>: 23) 0x60 0x0000000000000025 (<unknown>: 25) 0x8 0x0000000000000017 (JMPREL) 0x8a20 0x0000000000000002 (PLTRELSZ) 2184 (bytes) 0x0000000000000003 (PLTGOT) 0x1b2c8 0x0000000000000014 (PLTREL) RELA 0x0000000000000006 (SYMTAB) 0x2a8
-
查看重定位条目 (
r
):
显示重定位条目,重要于了解动态链接过程。readelf -r <filename> Relocation section '.rela.plt' at offset 0x8a20 contains 91 entries: Offset Info Type Sym. Value Sym. Name + Addend 00000001b2e0 000200000402 R_AARCH64_JUMP_SL 0000000000000000 __cxa_finalize@LIBC + 0 00000001b2e8 000300000402 R_AARCH64_JUMP_SL 0000000000000000 AParcel_getDataPositio@LIBBINDER_NDK + 0 00000001b2f0 000600000402 R_AARCH64_JUMP_SL 0000000000000000 AParcel_readInt32@LIBBINDER_NDK + 0 00000001b2f8 000500000402 R_AARCH64_JUMP_SL 0000000000000000 AParcel_readFloat@LIBBINDER_NDK + 0 00000001b300 000400000402 R_AARCH64_JUMP_SL 0000000000000000 AParcel_readBool@LIBBINDER_NDK + 0 00000001b308 000700000402 R_AARCH64_JUMP_SL 0000000000000000 AParcel_setDataPositio@LIBBINDER_NDK + 0 00000001b310 000b00000402 R_AARCH64_JUMP_SL 0000000000000000 __stack_chk_fail@LIBC + 0 00000001b318 000a00000402 R_AARCH64_JUMP_SL 0000000000000000 AParcel_writeInt32@LIBBINDER_NDK + 0 00000001b320 000900000402 R_AARCH64_JUMP_SL 0000000000000000 AParcel_writeFloat@LIBBINDER_NDK + 0 00000001b328 000800000402 R_AARCH64_JUMP_SL 0000000000000000 AParcel_writeBool@LIBBINDER_NDK + 0 00000001b330 000c00000402 R_AARCH64_JUMP_SL 0000000000000000 AParcel_readDouble@LIBBINDER_NDK + 0 00000001b338 000d00000402 R_AARCH64_JUMP_SL 0000000000000000 AParcel_writeDouble@LIBBINDER_NDK + 0 00000001b340 000e00000402 R_AARCH64_JUMP_SL 0000000000000000 AParcel_readInt32Array@LIBBINDER_NDK + 0 00000001b348 000f00000402 R_AARCH64_JUMP_SL 0000000000000000 AParcel_writeInt32Arra@LIBBINDER_NDK + 0 00000001b350 005300000402 R_AARCH64_JUMP_SL 000000000000c778 _ZNSt3__16vectorIiNS_9 + 0 00000001b358 001200000402 R_AARCH64_JUMP_SL 0000000000000000 _Znwm + 0 00000001b360 001500000402 R_AARCH64_JUMP_SL 0000000000000000 memset@LIBC + 0
-
查看所有信息 (
a
):
显示 ELF 文件的所有信息。readelf -a <filename> #结果就是上面的所有信息
ELF的格式
so文件,bin,object file都是ELF的格式?
是的,你的理解是正确的。在Unix和类Unix系统(如Linux)中,.so
文件(共享库)、二进制可执行文件(通常没有扩展名,简称为 “bin”)、以及目标文件(.o
文件)通常都采用 ELF(Executable and Linkable Format)格式。
- 共享库(
.so
文件):这些是动态链接的库文件,可以被多个程序共享。它们在运行时被加载,而不是在编译时静态链接到程序中。 - 二进制可执行文件:这些是编译后的程序,可以直接运行。在Unix-like系统中,它们没有扩展名,通常被称为"binaries"或"executable files"。
- 目标文件(
.o
文件):这些是编译源代码(如C或C++源文件)得到的中间结果。它们通常在创建可执行文件或共享库之前被链接器处理。
ELF格式为这些不同类型的文件提供了一个标准化的方式来描述它们的内容和结构,如程序的代码段、数据段、符号表、重定位信息等。这使得操作系统和工具能够有效地解析和处理这些文件。
这些文件的后缀名却是不同的呢?
是的,文件的后缀名和文件的格式是两个不同的概念,它们并不总是直接相关。
- 文件格式:这是文件内容的结构化描述,它定义了数据如何在文件内部组织。文件格式由文件的创建者或生成程序决定,它决定了文件的内部结构。例如,ELF(Executable and Linkable Format)是一种文件格式,用于指定可执行文件、目标文件、和动态链接库的结构。
- 文件后缀名:这通常是文件名的一部分,位于文件名的最后,用于指示文件的类型或用途。在许多操作系统中,文件后缀名(如**
.txt
、.jpg
、.o
、.so
**)帮助用户和程序快速识别文件的用途和打开方式。但后缀名本身并不改变文件的内容或格式。
对于使用ELF格式的文件,虽然它们内部结构相似或相同,但不同类型的文件(如目标文件、可执行文件、动态链接库)可能会使用不同的后缀名(如**.o
、无后缀、.so
**),这主要是为了方便使用和识别。例如,在Linux系统中:
- 目标文件(Object files)通常有**
.o
**后缀。 - 可执行文件通常没有特定后缀。
- 动态链接库(Shared libraries)通常有**
.so
**后缀。
因此,虽然这些文件可能都是ELF格式,它们的后缀名却不同,以反映它们的不同用途。