Last Updated: 2023-07-27 08:30:56 Thursday
-- TOC --
readelf命令,是专门用来读取ELF格式文件的工具,Linux系统下的可执行二进制文件,.so文件,编译过程的object文件等,都是ELF格式文件。
-h
,打印ELF文件的头。
$ readelf -h test_time
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: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x4010e0
Start of program headers: 64 (bytes into file)
Start of section headers: 22256 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 13
Size of section headers: 64 (bytes)
Number of section headers: 31
Section header string table index: 30
-S|--sections
,大S,打印ELF文件的sections。
各个section的name和编号可以一目了然。
-s[C]
,小s,打印ELF文件的symbol table,如果加上-C
,可以将C++的符号做demangle,即反向修饰,还原成原来的名字。
object文件中的符号value,一般为符号所在section的offset或size。可执行文件中符号的value,为虚拟地址。用readelf查看符号表,表的第一项永远是UND,不用care。另一个查看符号表的命名是nm。
用readelf命令看符号表,如果符号名比较长,在显示的时候,会被省略掉,不如nm命令。
-p<N|sectionname>
,将N号section按照字符串的方式打印出来,或者使用section name。
查看各种string table,用这个参数很方便:
$ readelf -p13 test_3.o
String dump of section '.shstrtab':
[ 1] .symtab
[ 9] .strtab
[ 11] .shstrtab
[ 1b] .rela.text
[ 26] .data
[ 2c] .bss
[ 31] .rodata
[ 39] .comment
[ 42] .note.GNU-stack
[ 52] .note.gnu.property
[ 65] .rela.eh_frame
查看ELF中保存的动态链接器的位置:
$ readelf -p .interp test
String dump of section '.interp':
[ 0] /lib64/ld-linux-x86-64.so.2
-x<N>
,将N号section按照十六进制的方式打印出来;
比如查看.data section内的全部变量的初始值。
$ readelf -x3 test_3.o
Hex dump of section '.data':
0x00000000 01000000 00000000 02000000 ............
-r
,将文件中的relocation信息打印出来:
$ readelf -r test.o
Relocation section '.rela.text' at offset 0x268 contains 9 entries:
Offset Info Type Sym. Value Sym. Name + Addend
00000000001a 000300000002 R_X86_64_PC32 0000000000000000 .rodata + 18
000000000027 000300000002 R_X86_64_PC32 0000000000000000 .rodata + 1c
00000000006a 00030000000a R_X86_64_32 0000000000000000 .rodata + 0
000000000074 000500000004 R_X86_64_PLT32 0000000000000000 printf - 4
00000000007c 000300000002 R_X86_64_PC32 0000000000000000 .rodata + 1c
00000000008e 00030000000a R_X86_64_32 0000000000000000 .rodata + 18
000000000098 000500000004 R_X86_64_PLT32 0000000000000000 printf - 4
0000000000a9 00030000000a R_X86_64_32 0000000000000000 .rodata + 18
0000000000b3 000500000004 R_X86_64_PLT32 0000000000000000 printf - 4
Relocation section '.rela.eh_frame' at offset 0x340 contains 1 entry:
Offset Info Type Sym. Value Sym. Name + Addend
000000000020 000200000002 R_X86_64_PC32 0000000000000000 .text + 0
-l|--segments
,查看segment信息,即program headers。segment是OS的加载视角,相同属性的section在加载的时候,会被合并成segment,以segment为单位加载,因为内存以page为单位,合并后加载可以有效节省内存。(查看加载属性)
有的物理page还会被多个虚拟地址段映射.....进一步节约内存....
$ readelf -l test_time
Elf file type is EXEC (Executable file)
Entry point 0x4010e0
There are 13 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000002d8 0x00000000000002d8 R 0x8
INTERP 0x0000000000000318 0x0000000000400318 0x0000000000400318
0x000000000000001c 0x000000000000001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x0000000000000740 0x0000000000000740 R 0x1000
LOAD 0x0000000000001000 0x0000000000401000 0x0000000000401000
0x00000000000003b1 0x00000000000003b1 R E 0x1000
LOAD 0x0000000000002000 0x0000000000402000 0x0000000000402000
0x0000000000000158 0x0000000000000158 R 0x1000
LOAD 0x0000000000002e10 0x0000000000403e10 0x0000000000403e10
0x0000000000000264 0x0000000000000268 RW 0x1000
DYNAMIC 0x0000000000002e20 0x0000000000403e20 0x0000000000403e20
0x00000000000001d0 0x00000000000001d0 RW 0x8
NOTE 0x0000000000000338 0x0000000000400338 0x0000000000400338
0x0000000000000040 0x0000000000000040 R 0x8
NOTE 0x0000000000000378 0x0000000000400378 0x0000000000400378
0x0000000000000044 0x0000000000000044 R 0x4
GNU_PROPERTY 0x0000000000000338 0x0000000000400338 0x0000000000400338
0x0000000000000040 0x0000000000000040 R 0x8
GNU_EH_FRAME 0x000000000000209c 0x000000000040209c 0x000000000040209c
0x000000000000002c 0x000000000000002c R 0x4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0x10
GNU_RELRO 0x0000000000002e10 0x0000000000403e10 0x0000000000403e10
0x00000000000001f0 0x00000000000001f0 R 0x1
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt
03 .init .plt .text .fini
04 .rodata .eh_frame_hdr .eh_frame
05 .init_array .fini_array .dynamic .got .got.plt .data .bss
06 .dynamic
07 .note.gnu.property
08 .note.gnu.build-id .note.ABI-tag
09 .note.gnu.property
10 .eh_frame_hdr
11
12 .init_array .fini_array .dynamic .got
.init .plt .text .fini被合并成03 segment!
用readelf -h
查看elf文件头,里面有program header信息!配合-W|--wide
参数,让显示的列数超过80,在较宽的终端上看起来更舒服!
.o文件没有program header,因为.o文件不能被加载执行。而可执行的二进制文件和.so文件因为需要被加载运行,所以存在program header。
可执行文件的加载属性,能看到已经确定的虚拟地址(如上的0x0000000000400000),而动态链接库文件的加载属性,虚拟地址是0,因为动态链接库.so文件在编译的时候,并不能确定自己会被加载到进程虚拟地址空间的什么位置,也就具有了可以被加载到任意位置的属性。这种能力是PIC(Position Independent Code)带来的,而非装载时重定位(Load Time Relocation),后者虽能实现任意位置加载,但不能实现同时被多个进程共享。
-d
,打印文件的dynamic section。
$ readelf -d /usr/lib64/libc.so.6
Dynamic section at offset 0x1f6ba0 contains 26 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [ld-linux-x86-64.so.2]
0x000000000000000e (SONAME) Library soname: [libc.so.6]
0x0000000000000019 (INIT_ARRAY) 0x1f4908
0x000000000000001b (INIT_ARRAYSZ) 16 (bytes)
0x0000000000000004 (HASH) 0x1ef390
0x000000006ffffef5 (GNU_HASH) 0x3e8
0x0000000000000005 (STRTAB) 0x16638
0x0000000000000006 (SYMTAB) 0x4ae8
0x000000000000000a (STRSZ) 32498 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000003 (PLTGOT) 0x1f8000
0x0000000000000002 (PLTRELSZ) 1320 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0x27a00
0x0000000000000007 (RELA) 0x20230
0x0000000000000008 (RELASZ) 30672 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000006ffffffc (VERDEF) 0x1fcc8
0x000000006ffffffd (VERDEFNUM) 37
0x000000000000001e (FLAGS) BIND_NOW STATIC_TLS
0x000000006ffffffb (FLAGS_1) Flags: NOW
0x000000006ffffffe (VERNEED) 0x201f0
0x000000006fffffff (VERNEEDNUM) 1
0x000000006ffffff0 (VERSYM) 0x1e52a
0x000000006ffffff9 (RELACOUNT) 1191
0x0000000000000000 (NULL) 0x0
判断一个动态链接库是否是通过-fPIC
出来的:
$ readelf -d /usr/lib64/libc.so.6 | grep TEXTREL
没有输出,表示这个so库中没有需要动态重定位的指令,是PIC代码。
本文链接:https://cs.pynote.net/sf/c/cdm/202207281/
-- EOF --
-- MORE --