ELF文件基础
ELF (Executable Linkable Format,wiki chs)是Linux参考COFF(Common Object File Format)规范而定义的可执行文件格式。
可执行文件、共享目标文件(*.so)、目标中间文件(又称可重定位文件,*.o)、核心转储文件(Core Dump File)都是ELF文件。
按位数可分为:elf32和elf64;支持cpu架构有:aarch64(即:arm64)、arm等。
ELF可能按照不同的字节序(Byte Order)来存储。例如:elf32-bigarm是大端(Big-endian)存储;elf64-littleaarch64是小端(Little-endian)存储。
与COFF一样,ELF也是基于段(Segment,有时也被叫节Section)的结构。其文件结构如下:
ELF头(ELF Header):ELF魔数、文件机器字节长度、数据存储方式(大小端)、版本、运行平台、ABI版本、ELF重定位类型、硬件平台及版本、入口地址、程序头入口和长度、段表的位置和长度、段的数量。
段表(Section header table):描述了ELF各个段的基本信息,如:每个段的段名、段的长度、在文件中偏移、读写权限及段的其他属性。编译器、链接器和装载器都是依靠段表来定位和访问各个段的属性的。
段的类型:
常量 | 值 | 含义 |
SHT_NULL | 0 | 无效段 |
SHT_PROGBITS | 1 | 程序段、代码段、数据段都是这种类型 |
SHT_SYMTAB | 2 | 该段的内容为符号表 |
SHT_STRTAB | 3 | 该段的内容为字符串表 |
SHT_RELA | 4 | 重定位表,包含重定位信息 |
SHT_HASH | 5 | 符号表的哈希表 |
SHT_DYNAMIC | 6 | 动态链接信息 |
SHT_NOTE | 7 | 提示性信息 |
SHT_NOBITS | 8 | 表示该段在文件中没有内容。如:bss段 |
SHT_REL | 9 | 该段包含了重定位信息 |
SHT_SHLIB | 10 | 保留 |
SHT_DNYSYM | 11 | 动态链接的符号表 |
段的标志位表示该段在进程虚拟空间中的属性。包括:是否可写(SHF_WRITE),是否需要分配空间(SHF_ALLOC)及是否可执行(SHF_EXECINSTR)。
常见的段如下:
段名 | 类型 | 标志位 | 说明 |
.text | SHT_PROGBITS |
SHF_ALLOC + SHF_EXECINSTR |
代码段
存放程序的可执行代码 |
.data .data1 |
SHT_PROGBITS |
SHF_ALLOC + SHF_EXECINSTR |
数据段
存放如下内容: ① 显示初始化为非0的局部静态变量 ② 显示初始化为非0的全局变量 |
.rela.text .rel.text |
SHT_RELA |
代码段重定位表
存在于目标中间文件(又称可重定位文件,*.o)中,用于链接时重定位(为静态重定位) |
|
.rela.data .rel.data |
SHT_RELA |
数据段重定位表
存在于目标中间文件(又称可重定位文件,*.o)中,用于链接时重定位(为静态重定位) |
|
.rodata .rodata1 |
SHT_PROGBITS |
SHF_ALLOC |
只读数据段
存放如下内容: ① 字符串常量 ② 全局const变量 |
.bss | SHT_NOBITS |
SHF_ALLOC + SHF_WRITE |
bss段 这个段在程序运行时,在内存中会被清零 在ELF文件中不占用空间
存放如下内容: ① 未初始化的全局变量 ② 未初始化的局部静态变量 ③ 显示初始化为0的局部静态变量 ④ 显示初始化为0的全局变量 |
.tdata | SHF_ALLOC + SHF_WRITE |
用来保存线程局部存储的初始化数据。 默认情况下,每次进程启动新的线程时,系统会产生一份.tdata副本。 |
|
.tbss | SHF_ALLOC + SHF_WRITE |
用来保存线程局部存储的未初始化数据。 默认情况下,每次进程启动新的线程时,系统会产生一份.tbss副本,并将它的内容初始化为0。 |
|
.data.rel.ro | SHF_ALLOC(SHF_WRITE) | 保存的是程序的只读数据,与.rodata类似,唯一不同的是它在重定位时会被改写,然后将会被置为只读。 | |
.dynamic | SHT_DYNAMIC |
SHF_ALLOC + SHF_WRITE 注:在某些系统,可能是只读的,没有SHF_WRITE标志位 |
动态链接信息
① 依赖于哪些共享对象 ② 动态链接符号表(.dynsym)的位置 ③ 动态链接重定位表(.rela.dyn)的位置 ④ 共享对象初始化代码的地址 |
.plt | SHF_ALLOC + SHF_EXECINSTR |
PLT(Procedure Linkage Table,程序链接表) 用于支持延迟绑定,这些指令是用来计算外部函数的最终地址 |
|
.got | SHF_ALLOC + SHF_WRITE |
全局偏移表 (Global Offset Table,GOT) 存放外部变量的地址
GOT表中的地址需要动态链接器在装载模块,进行地址重定位时进行填充。 在访问外部符号,可以先通过相对地址找到GOT表中相关的项,再从中取出最终地址 |
|
.got.plt | SHF_ALLOC + SHF_WRITE |
使用PLT(Procedure Linkage Table,过程链接表)来实现对外部函数延迟绑定(函数第一次调用到时才进行绑定) 以此来提升程序的启动速度
第一项保存的是“.dynamic”段的地址 第N项保存的是运用plt段的指令计算得到的外部函数的最终地址(动态链接器重定位得到外部函数的地址后,会写入在这里) |
|
.rela.dyn .rel.dyn |
SHT_RELA | SHF_ALLOC |
.dynsym段的重定位表
对数据引用的修正,它所修正的位置存放在“.got”以及数据段 |
.rela.plt .rel.plt |
SHT_RELA | SHF_ALLOC |
.plt段的重定位表 对函数引用的修正,它所修正的位置存放在“.got.plt” |
.dynstr | SHF_ALLOC |
动态符号字符串表(Dynamic String Table)
存放动态链接符号的符号名 |
|
.dynsym | SHF_ALLOC |
动态符号表(Dynamic Symbol Table)
① 导入符号(Import Symbol) ② 导出符号(Export Symbol)
编译选项开启:-fvisibility=hidden -fvisibility-inlines-hidden,默认不导出so中的符号
mac机器上,可使用-exported_symbols和-unexported_symbols进行符号导出的更精确控制 // 仅导出白名单exported_symbols.txt中的符号(支持通配符) -exported_symbols_list /Users/admin/MyGame/exported_symbols.txt // 不导出黑名单unexported_symbols.txt中的符号(支持通配符) -unexported_symbols_list /Users/admin/MyGame/unexported_symbols.txt txt表内容形如: *physx* |
|
.hash | SHT_HASH |
SHF_ALLOC |
动态符号哈希表
提升动态符号的查找效率 |
.comment | SHT_PROGBITS |
|
注释信息段
存放的是编译器版本信息,比如字符串:"GCC:(GNU)4.2.0" |
.init | SHF_ALLOC + SHF_EXECINSTR |
程序执行前的初始化代码,这些代码早于main函数被执行,多数被用作实现C++全局构造 |
|
.fini | SHF_ALLOC + SHF_EXECINSTR | 程序退出时执行的代码,这些代码晚于main函数执行,多数被用作实现C++全局析构 | |
.init_array | SHT_PROGBITS |
SHF_ALLOC + SHF_EXECINSTR |
包含一些程序或共享对象刚开始初始化时所须要执行的函数指针 |
.fini_array | SHT_PROGBITS | SHF_ALLOC + SHF_EXECINSTR | 包含一些程序或共享对象退出时须要执行的函数指针 |
.preinit_array | 保存的是早于初始化阶段执行的函数指针数组,这些函数会在.init_array的函数指针数组之前被执行 | ||
.ctors |
保存的是全局构造函数指针 |
||
.dtors |
保存的是全局析构函数指针 |
||
.interp | SHT_PROGBITS |
包含动态链接器的路径(如:/lib/ld-linux.so.2) interp是interpreter(解释器)的缩写
系统在对可执行文件进行加载时,会从该段寻找并装载该可执行文件所需的动态链接器。 |
|
.shstrtab | SHT_STRTAB |
段表字符串表(Section String Table) 用于存放各个段的名字 |
|
.note.GNU-stack | SHT_NOTE | 堆栈提示段 | |
.note.android.ide | SHT_NOTE | 记录使用的android ndk的版本 | |
.note.gnu.build-id | SHT_NOTE | 链接时的唯一标识 | |
.note.ABI-tag | SHT_NOTE | 指定程序的ABI | |
.eh_frame | SHT_PROGBITS |
c++异常处理相关的内容 详见:Exception Frames
异常时栈帧unwind信息(Exception Handling Frame unwinding information) Call Frame Information(CFI)信息,保存了函数的调用关系,可以用于异常发生后的栈回溯
编译时,带上-funwind-tables,可以去除该段 -fno-asynchronous-unwind-tables |
|
.eh_frame_hdr | SHT_PROGBITS |
c++异常处理相关的内容
包含了对.eh_frame的补充信息 ① 一个指针指向.eh_frame包含的数据起始地址 |
|
.gcc_except_table | SHT_PROGBITS | try catch异常处理相关的信息:如异常时的对象清理逻辑 | |
.jcr | Java类注册信息 | ||
.gnu.version |
符号版本相关
所有动态符号的版本信息,它和.dynsym是一一对应的 为0表示内部定义的local的符号,1表示内部定义的global符号 其他的值则来自于.gnu_version_d的Index和.gnu_version_r的Version,前者表示导出的符号版本信息,后者表示导入的符号版本信息 |
||
.gnu.version_d |
符号版本相关
版本定义信息 |
||
.gnu.version_r |
符号版本相关 |
||
.debug_str .debug_loc .debug_abbrev .debug_info .debug_ranges .debug_macinfo .debug_line .debug_aranges |
SHT_PROGBITS |
调试信息
ELF采用DWARF(Debug With Arbitrary Record Format)的标准调试信息格式来存放调试信息 |
|
.symtab | SHT_SYMTAB | 如果有其他装载的段用到该段,则有SHF_ALLOC标志位 |
符号表(Symbol Table) 保存链接时所需要的符号信息 |
.strtab | SHT_STRTAB | 如果有其他装载的段用到该段,则有SHF_ALLOC标志位 |
字符串表(String Table) 通常是符号表里的符号名所需要的字符串
注:目标中间文件(又称可重定位文件,*.o)也存在该段 |
函数重定位原理
在一个进程中,lib2.so调用lib1.so中func()函数的过程
.got.plt中的函数的跳转地址默认会指向一段存放在.plt段的桩代码(Stub)
当函数第一次调用时,这段代码会负责查询真正函数的跳转地址,并且去更新.got.plt中该函数的地址
再次调用函数的时候,则会直接跳转到动态库中代码段真正的函数实现处
readelf
llvm-readelf.exe所在目录在:<android-ndk>\toolchains\llvm\prebuilt\windows-x86_64\bin
llvm-readelf.exe -S libUE4.so // 输出libUE4.so段表中各个段的信息
There are 27 section headers, starting at offset 0xf2c1650: Section Headers: [Nr] Name Type Address Offset Size EntSize Flags Link Info Align ;Size为段的长度;Offset为段在文件中偏移位置 [ 0] NULL 0000000000000000 00000000 ;第一个元素是无效的段描述符,类型为NULL 0000000000000000 0000000000000000 0 0 0 [ 1] .note.android.ide NOTE 0000000000000270 00000270 ;记录使用的android ndk的版本的段 0000000000000098 0000000000000000 A 0 0 4 [ 2] .note.gnu.build-i NOTE 0000000000000308 00000308 ;链接时的唯一标识 0000000000000024 0000000000000000 A 0 0 4 [ 3] .dynsym DYNSYM 0000000000000330 00000330 0000000000dee838 0000000000000018 A 8 1 8 [ 4] .gnu.version VERSYM 0000000000deeb68 00deeb68 000000000012935a 0000000000000002 A 3 0 2 [ 5] .gnu.version_r VERNEED 0000000000f17ec4 00f17ec4 0000000000000080 0000000000000000 A 8 4 4 [ 6] .gnu.hash GNU_HASH 0000000000f17f48 00f17f48 00000000003e61c8 0000000000000000 A 3 0 8 [ 7] .hash HASH 00000000012fe110 012fe110 00000000004a4d70 0000000000000004 A 3 0 4 [ 8] .dynstr STRTAB 00000000017a2e80 017a2e80 000000000326c716 0000000000000000 A 0 0 1 [ 9] .rela.dyn RELA 0000000004a0f598 04a0f598 0000000001a9a510 0000000000000018 A 3 0 8 [10] .rela.plt RELA 00000000064a9aa8 064a9aa8 00000000000041b8 0000000000000018 AI 3 22 8 [11] .rodata PROGBITS 00000000064adc80 064adc80 ; 只读数据段 0000000000b19d08 0000000000000000 AMS 0 0 64 [12] .gcc_except_table PROGBITS 0000000006fc7988 06fc7988 000000000005e32c 0000000000000000 A 0 0 4 [13] .eh_frame_hdr PROGBITS 0000000007025cb4 07025cb4 00000000003aed74 0000000000000000 A 0 0 4 [14] .eh_frame PROGBITS 00000000073d4a28 073d4a28 0000000000e29424 0000000000000000 A 0 0 8 [15] .text PROGBITS 00000000081fe000 081fe000 ; 代码段 0000000006464320 0000000000000000 AX 0 0 16 [16] .plt PROGBITS 000000000e662320 0e662320 0000000000002bf0 0000000000000000 AX 0 0 16 [17] .data.rel.ro PROGBITS 000000000e665000 0e665000 0000000000b40f88 0000000000000000 WA 0 0 16 [18] .fini_array FINI_ARRAY 000000000f1a5f88 0f1a5f88 0000000000000010 0000000000000008 WA 0 0 8 [19] .init_array INIT_ARRAY 000000000f1a5f98 0f1a5f98 0000000000002918 0000000000000008 WA 0 0 8 [20] .dynamic DYNAMIC 000000000f1a88b0 0f1a88b0 00000000000002b0 0000000000000010 WA 8 0 8 [21] .got PROGBITS 000000000f1a8b60 0f1a8b60 00000000000e3280 0000000000000000 WA 0 0 8 [22] .got.plt PROGBITS 000000000f28bde0 0f28bde0 0000000000001600 0000000000000000 WA 0 0 8 [23] .data PROGBITS 000000000f28e000 0f28e000 ; 数据段 0000000000033220 0000000000000000 WA 0 0 16 [24] .bss NOBITS 000000000f2c1240 0f2c1220 ; BSS段 该段在文件中不存在内容 000000000060aaa8 0000000000000000 WA 0 0 64 [25] .comment PROGBITS 0000000000000000 0f2c1220 ; 注释信息段 0000000000000328 0000000000000001 MS 0 0 1 [26] .shstrtab STRTAB 0000000000000000 0f2c1548 0000000000000104 0000000000000000 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), C (compressed), x (unknown), o (OS specific), E (exclude), p (processor specific)
注:以上段的Offset是基于ELF文件起始处
以uam为例,libUE4.so的大小对比:
配置 | so size | debug so size |
Debug | 532MB | 2.07GB |
DebugGame | 389MB | 2.48GB |
Development | 343MB | 2.52GB |
Test | 175MB | 2.11GB |
Shipping | 148MB | 1.81GB |
注:对debug so执行strip -S命令去除掉调试信息,就得到so文件
不同配置的libUE4.so(非debug)各个段的大小对比(单位为byte):
段名 | Debug | DebugGame | Development | Test | Shipping |
.note.android.ident | 152 | 152 | 152 | 152 | 152 |
.note.gnu.build-id | 36 | 36 | 36 | 36 | 36 |
.dynsym | 36937800 | 21539400 | 19843704 | 391176 | 195792 |
.gnu.version | 3078150 | 1794950 | 1653642 | 32598 | 16316 |
.gnu.version_r | 128 | 128 | 128 | 128 | 128 |
.gnu.hash | 11885344 | 6580208 | 6226960 | 110088 | 53272 |
.hash | 12312608 | 7179808 | 6614576 | 130400 | 65272 |
.dynstr | 166468508 | 88218683 | 81551149 | 854321 | 244190 |
.rela.dyn | 35363208 | 34303248 | 34031904 | 29215536 | 27984648 |
.rela.plt | 19488 | 19416 | 19320 | 18768 | 17760 |
.rodata | 15322736 | 15091552 | 15056704 | 11529632 | 10449008 |
.gcc_except_table | 554452 | 597372 | 662504 | 650196 | 544796 |
.eh_frame_hdr | 13486636 | 6668844 | 5787516 | 3948092 | 3640124 |
.eh_frame | 51114172 | 25550380 | 22173820 | 15188700 | 13873572 |
.text | 194929800 | 184359724 | 150390280 | 107480476 | 84720920 |
.plt | 13024 | 12976 | 12912 | 12544 | 11872 |
.data.rel.ro | 14868208 | 14560768 | 14509008 | 13900256 | 13422608 |
.fini_array | 16 | 16 | 16 | 16 | 16 |
.init_array | 11432 | 11288 | 11288 | 11232 | 10320 |
.dynamic | 736 | 736 | 736 | 736 | 736 |
.got | 1234496 | 1196112 | 1189088 | 46504 | 34848 |
.got.plt | 6520 | 6496 | 6464 | 6280 | 5944 |
.data | 398160 | 276400 | 234256 | 161744 | 157440 |
.bss | 6143992 | 6076552 | 6051080 | 5332728 | 4972416 |
.comment | 747 | 747 | 747 | 747 | 747 |
.shstrtab | 260 | 260 | 260 | 260 | 260 |
llvm-readelf.exe -t libUE4.so // 输出libUE4.so段表中各个段的信息
llvm-readelf.exe -h libUE4.so // 输出libUE4.so的ELF头的信息
llvm-readelf.exe -l libUE4.so // 输出libUE4.so的program headers
llvm-readelf.exe -e libUE4.so // 等价于-h -l -S输出的信息
llvm-readelf.exe -d libUE4.so // 输出libUE4.so的dynamic段的信息
llvm-readelf.exe -r libUE4.so // 输出libUE4.so的重定位信息(.rela.dyn段和.rela.plt段)
llvm-readelf.exe --dyn-syms -d -C -W libUE4.so // 输出libUE4.so的dynsym段中所有符号(不截断),且自动对c++符号名进行反修饰(Demangle),并输出libUE4.so依赖的so文件 注:Ndx为UND时,表示是一个导入符号
。。。 。。。 37263: 000000000a0cca50 144 FUNC GLOBAL DEFAULT 15 uprv_stricmp_64 37264: 000000000b1deeb8 56 OBJECT GLOBAL DEFAULT 17 CMS_ReceiptRequest_it 37265: 000000000a3efec4 16 FUNC GLOBAL DEFAULT 15 hb_font_is_immutable 37266: 0000000009f258f8 164 FUNC GLOBAL DEFAULT 15 g6_toolkit_manager::LoginRsp::default_instance() 37267: 0000000009ffdde4 164 FUNC GLOBAL DEFAULT 15 G6ToolKit::google::protobuf::OneofOptions::default_instance() 37268: 0000000002778899 18 OBJECT GLOBAL DEFAULT 11 typeinfo name for icu_64::UObject 37269: 000000000a3e8278 92 FUNC GLOBAL DEFAULT 15 hb_segment_properties_equal 37270: 000000000a462248 68 FUNC GLOBAL DEFAULT 15 png_reciprocal 37271: 0000000009a955b4 236 FUNC GLOBAL DEFAULT 15 ak_rpmalloc_initialize 37272: 0000000009edf7bc 388 FUNC WEAK DEFAULT 15 void physx::RepXPropertyFilter<physx::Sn::RepXVisitorWriter<physx::PxVehicleClutchData> >::operator()<588u, physx::PxVehicleClutchData, unsigned int, unsigned int>(physx::PxPropertyInfo<588u, physx::PxVehicleClutchData, unsigned int, unsigned int> const&, unsigned int) 37273: 000000000a0070b4 56 FUNC GLOBAL DEFAULT 15 G6ToolKit::google::protobuf::SourceCodeInfo_Location::CopyFrom(G6ToolKit::google::protobuf::SourceCodeInfo_Location const&) 37274: 000000000a32976c 36 FUNC GLOBAL DEFAULT 15 d2i_RSA_PUBKEY_bio Dynamic section at offset 0xb211b58 contains 52 entries: Tag Type Name/Value 0x0000000000000001 (NEEDED) Shared library: [libGLESv3.so] 0x0000000000000001 (NEEDED) Shared library: [libEGL.so] 0x0000000000000001 (NEEDED) Shared library: [libandroid.so] 0x0000000000000001 (NEEDED) Shared library: [libOpenSLES.so] 0x0000000000000001 (NEEDED) Shared library: [libc.so] 0x0000000000000001 (NEEDED) Shared library: [libdl.so] 0x0000000000000001 (NEEDED) Shared library: [liblog.so] 0x0000000000000001 (NEEDED) Shared library: [libm.so] 0x0000000000000001 (NEEDED) Shared library: [libz.so] 0x0000000000000001 (NEEDED) Shared library: [libTDataMaster.so] 0x0000000000000001 (NEEDED) Shared library: [libMSDKCore.so] 0x0000000000000001 (NEEDED) Shared library: [libGPM.so] 0x0000000000000001 (NEEDED) Shared library: [libgrobot.so] 0x0000000000000001 (NEEDED) Shared library: [libavcodec.so] 0x0000000000000001 (NEEDED) Shared library: [libavfilter.so] 0x0000000000000001 (NEEDED) Shared library: [libavformat.so] 0x0000000000000001 (NEEDED) Shared library: [libavutil.so] 0x0000000000000001 (NEEDED) Shared library: [libswresample.so] 0x0000000000000001 (NEEDED) Shared library: [libswscale.so] 0x0000000000000001 (NEEDED) Shared library: [libgcloudcore.so] 0x0000000000000001 (NEEDED) Shared library: [libgcloud.so] 0x0000000000000001 (NEEDED) Shared library: [libhttpdns.so] 0x0000000000000001 (NEEDED) Shared library: [libHttpDnsPlugin.so] 0x0000000000000001 (NEEDED) Shared library: [libtersafe.so] 0x0000000000000001 (NEEDED) Shared library: [libGVoice.so] 0x0000000000000001 (NEEDED) Shared library: [libCrashSight.so] 0x0000000000000001 (NEEDED) Shared library: [libc++_shared.so] 0x000000000000000e (SONAME) Library soname: [libUE4.so] 0x000000000000001e (FLAGS) SYMBOLIC BIND_NOW 0x000000006ffffffb (FLAGS_1) NOW 0x0000000000000007 (RELA) 0x3a7500 0x0000000000000008 (RELASZ) 29283912 (bytes) 0x0000000000000009 (RELAENT) 24 (bytes) 0x000000006ffffff9 (RELACOUNT) 1210342 0x0000000000000017 (JMPREL) 0x1f94b48 0x0000000000000002 (PLTRELSZ) 19704 (bytes) 0x0000000000000003 (PLTGOT) 0xb221058 0x0000000000000014 (PLTREL) RELA 0x0000000000000006 (SYMTAB) 0x330 0x000000000000000b (SYMENT) 24 (bytes) 0x0000000000000005 (STRTAB) 0x1721c4 0x000000000000000a (STRSZ) 2315065 (bytes) 0x000000006ffffef5 (GNU_HASH) 0xecdf0 0x0000000000000004 (HASH) 0x1294e4 0x0000000000000019 (INIT_ARRAY) 0xb20ef90 0x000000000000001b (INIT_ARRAYSZ) 11208 (bytes) 0x000000000000001a (FINI_ARRAY) 0xb20ef80 0x000000000000001c (FINI_ARRAYSZ) 16 (bytes) 0x000000006ffffff0 (VERSYM) 0xda9b8 0x000000006ffffffe (VERNEED) 0xeccf0 0x000000006fffffff (VERNEEDNUM) 8 0x0000000000000000 (NULL) 0x0
llvm-readelf.exe -s -C -W libUE4.so // 输出libUE4.so的.symtab段(调试符号)中所有符号(不截断),且自动对c++符号名进行反修饰(Demangle)
llvm-readelf.exe --debug-dump=frames-interp libUE4.so // 输出libUE4.so的eh_frame段的信息
llvm-readelf.exe -V libUE4.so // 输出libUE4.so的符号版本信息
llvm-readelf.exe -x.data libc++_shared.so // 以16进制的方式输出libc++_shared.so的.data段内容到文本文件 注:libc++_shared.so来自于strip后的<android-ndk>\sources\cxx-stl\llvm-libc++\libs\arm64-v8a\libc++_shared.so
llvm-readelf.exe -x.note.gnu.build-id libUE4.so // 以16进制的方式输出libUE4.so的.note.gnu.build-id段内容 注:里面存储着libUE4.so的BuildId,符号表匹配依赖这个 (BuildId: 72e1338dd3e2096ddc9555842ca24ecfafd2586e)
Hex dump of section '.note.gnu.build-id': 0x00000308 04000000 14000000 03000000 474e5500 ............GNU. 0x00000318 72e1338d d3e2096d dc955584 2ca24ecf r.3....m..U.,.N. 0x00000328 afd2586e ..Xn
llvm-readelf.exe -x.comment libUE4.so // 查看libUE4.so的.comment段中编译器相关的信息。从下面内容可以看出libUE4.so是使用clang9.0.8版本编译的
Hex dump of section '.comment': 0x00000000 636c616e 67207665 7273696f 6e20332e clang version 3. 0x00000010 36200041 6e64726f 69642028 36333137 6 .Android (6317 0x00000020 34363720 62617365 64206f6e 20723336 467 based on r36 0x00000030 35363331 63312920 636c616e 67207665 5631c1) clang ve 0x00000040 7273696f 6e20392e 302e3820 28687474 rsion 9.0.8 (htt 0x00000050 70733a2f 2f616e64 726f6964 2e676f6f ps://android.goo 0x00000060 676c6573 6f757263 652e636f 6d2f746f glesource.com/to 0x00000070 6f6c6368 61696e2f 6c6c766d 2d70726f olchain/llvm-pro 0x00000080 6a656374 20653063 61656530 38653566 ject e0caee08e5f 0x00000090 30396233 37346132 37613637 36643034 09b374a27a676d04 0x000000a0 39373863 38316663 62313932 38292028 978c81fcb1928) ( 0x000000b0 62617365 64206f6e 204c4c56 4d20392e based on LLVM 9. 0x000000c0 302e3873 766e2900 416e6472 6f696420 0.8svn).Android 0x000000d0 28353930 30303539 20626173 6564206f (5900059 based o 0x000000e0 6e207233 36353633 31632920 636c616e n r365631c) clan 0x000000f0 67207665 7273696f 6e20392e 302e3820 g version 9.0.8 0x00000100 28687474 70733a2f 2f616e64 726f6964 (https://android 0x00000110 2e676f6f 676c6573 6f757263 652e636f .googlesource.co 0x00000120 6d2f746f 6f6c6368 61696e2f 6c6c766d m/toolchain/llvm 0x00000130 2d70726f 6a656374 20323037 64376162 -project 207d7ab 0x00000140 63316132 61626633 65663864 34333031 c1a2abf3ef8d4301 0x00000150 37333664 36613765 62633232 34613239 736d6a7ebc224a29 0x00000160 30292028 62617365 64206f6e 204c4c56 0) (based on LLV 0x00000170 4d20392e 302e3873 766e2900 416e6472 M 9.0.8svn).Andr 0x00000180 6f696420 636c616e 67207665 7273696f oid clang versio 0x00000190 6e20352e 302e3330 30303830 20202862 n 5.0.300080 (b 0x000001a0 61736564 206f6e20 4c4c564d 20352e30 ased on LLVM 5.0 0x000001b0 2e333030 30383029 00474343 3a202847 .300080).GCC: (G 0x000001c0 4e552920 342e392e 78203230 31353031 NU) 4.9.x 201501 0x000001d0 32332028 70726572 656c6561 73652900 23 (prerelease). 0x000001e0 004c696e 6b65723a 204c4c44 20392e30 .Linker: LLD 9.0 0x000001f0 2e382028 2f627569 6c64626f 742f746d .8 (/buildbot/tm 0x00000200 702f746d 706c6b58 584f4a20 65306361 p/tmplkXXOJ e0ca 0x00000210 65653038 65356630 39623337 34613237 ee08e5f09b374a27 0x00000220 61363736 64303439 37386338 31666362 a676d04978c81fcb 0x00000230 31393238 2900 1928).
llvm-readelf.exe -p.shstrtab libtestSo.so // 以字符串(char)的方式输出libtestSo.so的.shstrtab段内容 注:utf16宽字符串会在解析时截断
llvm-readelf.exe -c libssl.a // 输出静态库libssl.a中包括各个中间目标文件(*.o)中的符号信息
llvm-readelf.exe -n libUE4.so // 输出libUE4.so中所有note段的信息
llvm-readelf.exe -v // 输出readelf的版本信息
llvm-readelf.exe --help // 输出readelf的帮助信息
objdump
llvm-objdump.exe所在目录在:<android-ndk>\toolchains\llvm\prebuilt\windows-x86_64\bin
llvm-objdump.exe -v // 输出objdump的版本信息
llvm-objdump.exe --help // 输出objdump的帮助信息
llvm-objdump.exe -i // 输出支持的ELF的格式和架构(architecture)
llvm-objdump.exe -f libUE4.so // 输出libUE4.so的简要信息
llvm-objdump.exe -h libUE4.so // 输出libUE4.so段表的信息 注:不输出一些辅助性的段(如:符号表、字符串表、段名字符串表、重定位表等)
llvm-objdump.exe -x libUE4.so // 输出llibUE4.so整个头的信息 注:包括段表的信息
llvm-objdump.exe -p libUE4.so // 输出llibUE4.so的program headers和dynsym段基本信息
llvm-objdump.exe -d -s libUE4.so // 对libUE4.so中的代码段进行反编译,并以16进制的形式输出
llvm-objdump.exe -a libpython2.7.a // 列出.a静态库中所有的目标中间文件(*.o)
llvm-objdump.exe -t -C libUE4.so // 显示libUE4.so中的调试符号表,并自动对c++符号名进行反修饰(Demangle)
llvm-objdump.exe -T libtestSo.so // 输出libtestSo.so的动态链接符号表(dynsym段)
llvm-objdump.exe -T -C libtestSo.so // 输出libtestSo.so的动态链接符号表(dynsym段),并自动对c++符号名进行反修饰(Demangle)
llvm-objdump.exe -R libtestSo.so // 输出libtestSo.so的动态链接重定位信息(.rela.dyn段和.rela.plt段)
llvm-objdump.exe -R -C libtestSo.so // 输出libtestSo.so的动态链接重定位信息,并自动对c++符号名进行反修饰(Demangle)
llvm-objdump.exe -d libtestSo.so // 对libtestSo.so中的包含机器指令的段进行反汇编
llvm-objdump.exe -S libtestSo.so // 显示libtestSo.so源代码和机器指令的段的反汇编代码(包含-d参数功能)
llvm-objdump.exe -D libtestSo.so // 对libtestSo.so所有的段进行反汇编
llvm-objdump.exe -r testSo.o // 显示中间文件testSo.o中重定位信息
llvm-objdump.exe -s libtestSo.so // 以16进制的方式输出libtestSo.so的内容
// 输出libUE4.debug.so地址范围为[0x0000000008277724, 0x0000000008277850]的机器指令进行反汇编,并自动其中c++符号名进行反修饰(Demangle)
llvm-objdump.exe -d -C libUE4.debug.so --start-address=0x0000000008277724 --stop-address=0x0000000008277850
注1:[0x0000000008277724, 0x0000000008277850]的机器指令对应UAkGameplayStatics::SetState(UAkStateValue const*, FName, FName)函数
注2:可通过命令:llvm-nm.exe -n -C libUE4.debug.so | findstr "UAkGameplayStatics::SetState"来获取该函数的起始地址
// 输出libUE4.debug.so地址范围为[0x0000000008277724, 0x0000000008277850]的机器指令进行反汇编(配合源代码),并自动其中c++符号名进行反修饰(Demangle)
llvm-objdump.exe -S -C libUE4.debug.so --start-address=0x0000000008277724 --stop-address=0x0000000008277850 --include="D:\svn\MyGame\Plugins\Wwise\Source\AkAudio\Private"
注:可通过命令:llvm-addr2line.exe -e libUE4.debug.so 0x000000008277724来获取地址为0x000000008277724(该地址为RVA地址,即已减去libUE4.so模块的基地址)对应的源代码文件和行数,得到如下结果
E:/tiyan/MyGame/Plugins/Wwise/Source/AkAudio/Private/AkGameplayStatics.cpp:377
更多的llvm工具命令详见:https://llvm.org/docs/CommandGuide/index.html
参考