可可西

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”段的地址
第二项保存的是本模块的ID
第三项保存的是_dl_runtime_resolve()的地址

第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*
png_set_rows
Java_com_*

.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包含的数据起始地址
② 指向.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

 

参考

程序员的自我修养

Executable and Linkable Format (ELF) 

ELF(Special Sections) 

-fPIC和got and plt的故事

【底层】动态链接库(dll)是如何工作的?

posted on 2020-10-25 02:08  可可西  阅读(3532)  评论(0编辑  收藏  举报

导航