elf 文件解析及相关工具使用

ELF 文件类型

ELF文件有三种类型,可以通过ELF Header中的 e_type 成员进行区分:

  • 可重定位文件(Relocatable File):ETL_REL。一般为.o文件,可以与其他目标文件链接来创建可执行文件或共享目标文件的代码和数据。静态链接库属于可重定位文件
  • 可执行文件(Executable File):ET_EXEC。可以执行的一个程序,此文件规定了exec()如何创建一个程序的进程映像。
  • 共享目标文件(Shared Object File):ET_DYN。一般为.so文件。有两种情况可以使用:链接器将其与其他可重定位文件、共享目标文件链接成新的目标文件;动态链接器(Dynamic Linker)将其与某个可执行文件或其他共享目标文件结合一个可执行文件,创建进程映像。

ELF 文件格式

different-elf-type

ELF文件的基本结构,主要由四部分组成:

  • ELF Header,用来描述整个文件的组织。
  • ELF Program Header Table(PHT),如果存在的话,告诉系统如何创建进程映像。用来构造进程映像的目标文件必须具有程序头部表,可重定位文件不需要这个表。
  • ELF Section Header Table(SHT),包含了描述文件节区的信息,每个节区在表中都有一项,每一项给出诸如节区名称、节区大小这类信息。用于链接的目标文件必须包含节区头部表,其他目标文件可以有,也可以没有这个表。
  • ELF Section,节区部包含链接视图的大量信息:指令、数据、符号表、重定位信息等等。

注意:除了 ELF Header,其他节点的顺序都不固定。段(Segment)与节(Section)的区别在于,段是程序执行的必要组成,当多个目标文件链接成一个可执行文件时,会将相同权限的节合并到一个段中。相比而言,节的粒度更小。

ELF 头部信息

elf-file-format

ELF Header

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# ELF header
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: 0xbb5b0
Start of program headers: 64 (bytes into file)
Start of section headers: 8733112 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 6
Size of section headers: 64 (bytes)
Number of section headers: 21
Section header string table index: 20

ELF Header: e_type, 目标文件类型:

名称 取值 含义
ET_NONE 0 未知目标文件格式
ET_REL 1 可重定位文件
ET_EXEC 2 可执行文件
ET_DYN 3 共享目标文件
ET_CORE 4 Core文件(转储格式)
ET_LOPROC 0xff00 特定处理器文件
ET_HIPROC 0xffff 特定处理器文件

ELF Header: e_machine, 目标体系结构类型:

名称 取值 含义
EM_NONE 0 未指定
EM_M32 1 AT&T WE 32100
EM_SPARC 2 SPARC
EM_386 3 Intel 80386
EM_68K 4 Motorola 68000
EM_88K 5 Motorola 88000
EM_860 7 Intel 80860
EM_MIPS 8 MIPS RS3000

ELF Header: e_version, 目标文件版本:

名称 取值 含义
EV_NONE 0 非法版本
EV_CURRENT 1 当前版本

Program Header

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# program-headers 

Elf file type is DYN (Shared object file)
Entry point 0xbb5b0
There are 6 program headers, starting at offset 64

Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x00000000008055d0 0x00000000008055d0 R E 10000
LOAD 0x0000000000805e80 0x0000000000815e80 0x0000000000815e80
0x000000000004e258 0x000000000006d870 RW 10000
DYNAMIC 0x0000000000846140 0x0000000000856140 0x0000000000856140
0x0000000000000200 0x0000000000000200 RW 8
GNU_EH_FRAME 0x00000000006a1b40 0x00000000006a1b40 0x00000000006a1b40
0x000000000003445c 0x000000000003445c R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 10
GNU_RELRO 0x0000000000805e80 0x0000000000815e80 0x0000000000815e80
0x0000000000042180 0x0000000000042180 R 1

Section to Segment mapping:
Segment Sections...
00 .hash .dynsym .dynstr .rela.dyn .rela.plt .plt .text .rodata .eh_frame_hdr .eh_frame .gcc_except_table
01 .init_array .fini_array .data.rel.ro .dynamic .got .data .bss
02 .dynamic
03 .eh_frame_hdr
04
05 .init_array .fini_array .data.rel.ro .dynamic .got

Section Header

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# Section-headers 

There are 21 section headers, starting at offset 0x8541b8:

Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .hash HASH 0000000000000190 00000190
0000000000002fa4 0000000000000004 A 2 0 8
[ 2] .dynsym DYNSYM 0000000000003138 00003138
000000000000bd00 0000000000000018 A 3 3 8
[ 3] .dynstr STRTAB 000000000000ee38 0000ee38
0000000000010e7f 0000000000000000 A 0 0 1
[ 4] .rela.dyn RELA 000000000001fcb8 0001fcb8
00000000000991c8 0000000000000018 A 2 0 8
[ 5] .rela.plt RELA 00000000000b8e80 000b8e80
0000000000001770 0000000000000018 AI 2 6 8
[ 6] .plt PROGBITS 00000000000ba5f0 000ba5f0
0000000000000fc0 0000000000000010 AX 0 0 16
[ 7] .text PROGBITS 00000000000bb5b0 000bb5b0
0000000000521fac 0000000000000000 AX 0 0 16
[ 8] .rodata PROGBITS 00000000005dd560 005dd560
00000000000c45e0 0000000000000000 A 0 0 16
[ 9] .eh_frame_hdr PROGBITS 00000000006a1b40 006a1b40
000000000003445c 0000000000000000 A 0 0 4
[10] .eh_frame PROGBITS 00000000006d5fa0 006d5fa0
000000000010ad70 0000000000000000 A 0 0 8
[11] .gcc_except_table PROGBITS 00000000007e0d10 007e0d10
00000000000248c0 0000000000000000 A 0 0 4
[12] .init_array INIT_ARRAY 0000000000815e80 00805e80
0000000000000ae0 0000000000000000 WA 0 0 8
[13] .fini_array FINI_ARRAY 0000000000816960 00806960
0000000000000010 0000000000000000 WA 0 0 8
[14] .data.rel.ro PROGBITS 0000000000816970 00806970
000000000003f7d0 0000000000000000 WA 0 0 16
[15] .dynamic DYNAMIC 0000000000856140 00846140
0000000000000200 0000000000000010 WA 3 0 8
[16] .got PROGBITS 0000000000856340 00846340
0000000000001cc0 0000000000000008 WA 0 0 8
[17] .data PROGBITS 0000000000858000 00848000
000000000000c0d8 0000000000000000 WA 0 0 16
[18] .bss NOBITS 00000000008640e0 008540d8
000000000001f610 0000000000000000 WA 0 0 16
[19] .comment PROGBITS 0000000000000000 008540d8
0000000000000025 0000000000000001 MS 0 0 1
[20] .shstrtab STRTAB 0000000000000000 008540fd
00000000000000b4 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)

ELF Section Headers: sh_type, 节类型:

名称 含义
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 动态链接的符号表

ELF Section Headers: sh_flag, 节标志位表示该节在进程虚拟地址空间中的属性。如是否可写、是否可执行等。

常量 含义
SHF_WRITE 1 表示该节在进程空间中可写
SHF_ALLOC 2 表示该节在进程空间中需要分配空间
SHF_EXECINSTR 4 表示该节在进程空间中可以被执行

ELF Section

  • bss: 类型为SHT_NOBITS,包含程序运行时未初始化的数据(全局变量和静态变量)。当程序运行时,这些数据初始化为0。
  • comment: 类型SHT_PROGBITS,包含版本控制信息(不包含注释信息,注释在预处理时已经被删除了)。
  • data: 类型SHT_PROGBITS,包含初始化的全局变量和静态变量。
  • debug: 类型SHT_PROGBITS,包含了符号调试用的信息,我们要想用gdb等工具调试程序,需要该类型信息。
  • dynamic: 类型SHT_DYNAMIC,包含了动态链接的信息。
  • dynstr: 类型SHT_STRTAB,包含了动态链接用的字符串,通常是和符号表中的符号关联的字符串。
  • dynsym: 类型SHT_DYNSYM,包含动态链接符号表。
  • fini: 类型SHT_PROGBITS,程序正常结束时,要执行该section中的指令。现在ELF还包含.fini_array section。
  • got: 类型SHT_PROGBITS,全局偏移表(global offset table)。
  • hash: 类型SHT_HASH,包含符号hash表,以后细讲。
  • init: 类型SHT_PROGBITS,程序运行时,先执行该节中的代码。和.fini对应。现在ELF还包含.init_array section。
  • interp: 类型SHT_PROGBITS,该节内容是一个字符串,指定了程序解释器的路径名。
  • line: 类型SHT_PROGBITS,包含符号调试的行号信息,描述了源程序和机器代码的对应关系。gdb等调试器需要此信息。
  • note: 类型SHT_NOTE。
  • plt : 类型SHT_PROGBITS, 过程链接表(Procedure Linkage Table)。
  • rel.NAME: 类型SHT_REL, 包含重定位信息。NAME,是应用重定位的节的名字,比如 rel.text、rel.dyn、rel.plt。
  • rela.NAME: 类型SHT_RELA,和.rel相同。
  • rodata: 类型SHT_PROGBITS, 包含只读数据,组成不可写的段。
  • shstrtab: 类型SHT_STRTAB,包含section的名字。section header 中的 sh_name 包含的是.shstrtab 中的索引,真正的字符串存储在.shstrtab中。
  • strtab : SHT_STRTAB,包含字符串,通常是符号表中符号对应的变量名字。字符串以\0结束, section以\0开始,也以\0结束。一个.strtab可以是空的,它的sh_size将是0。针对空字符串表的非0索引是允许的。
  • symtab: 类型SHT_SYMTAB,Symbol Table,符号表。包含了定位、重定位符号定义和引用时需要的信息。符号表是一个数组,Index 0 第一个入口,它的含义是 undefined symbol index, STN_UNDEF。

符号表(Symbol Table)

符号是对某些类型的数据或代码(如全局变量或函数)的符号引用,函数名或变量名就是符号名。在大多数共享库和动态链接可执行文件中,存在两个符号表。即.dynsym和.symtab。

  • .symtab中保存了所有的符号。.symtab不是在运行时必需的,因此不会被装载到内存中,只是用来进行调试和链接的。
  • .dynsym保存的符号是.symtab所保存符合的子集,保存了引用外部文件的符号。dynsym保存的符号只能在运行时被解析,因此是运行时动态链接器所需的唯一符号。dynsym对于动态链接可执行文件的执行是必需的。 sh_flag 被标记为ALLOC。

elf-symtab-strtab

符号表中的每一项都是一个Elf_Sym结构,对应可以在字符串表中索引得到一个字符串。

字符串表(String Table)

在大多数共享库和动态链接可执行文件中,存在两个字符串表,即.dynstr和.strtab,分别对应于.dynsym和.symtab。此外,还有一个.shstrtab的节头字符串表,用于保存节头表中用到的字符串,可通过sh_name进行索引。

常用命令

elf 文件分析,通常使用 readelf 和 objdump 两个命令。

  • readelf 来看 ELF 文件头部或者其它各 section 的内容。
  • objdump 来对指定的内容(.text, .data等)进行反汇编。

命令行配置

mac 平台可以使用 gnu binutils 来执行相关命令。

1
2
3
4
5
6
7
8
9
10
# 安装 binutils
brew install binutils

# 配置环境变量(~/.zshrc)
# export BINUTILS_PATH="/usr/local/opt/binutils/bin"
# export PATH="$BINUTILS_PATH:$PATH"

# 配置编译选项(不支持 ld)
# export LDFLAGS="-L/usr/local/opt/binutils/lib"
# export CPPFLAGS="-I/usr/local/opt/binutils/include"

环境变量配置生效后,使用 greadelf 和 gobjdump 命令。

readelf 命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
Display information about the contents of ELF format files
Options are:
-a --all Equivalent to: -h -l -S -s -r -d -V -A -I
-h --file-header Display the ELF file header
-l --program-headers Display the program headers
--segments An alias for --program-headers
-S --section-headers Display the sections' header
--sections An alias for --section-headers
-g --section-groups Display the section groups
-t --section-details Display the section details
-e --headers Equivalent to: -h -l -S
-s --syms Display the symbol table
--symbols An alias for --syms
--dyn-syms Display the dynamic symbol table
-n --notes Display the core notes (if present)
-r --relocs Display the relocations (if present)
-u --unwind Display the unwind info (if present)
-d --dynamic Display the dynamic section (if present)
-V --version-info Display the version sections (if present)
-A --arch-specific Display architecture specific information (if any)
-c --archive-index Display the symbol/file index in an archive
-D --use-dynamic Use the dynamic section info when displaying symbols
-x --hex-dump=<number|name>
Dump the contents of section <number|name> as bytes
-p --string-dump=<number|name>
Dump the contents of section <number|name> as strings
-R --relocated-dump=<number|name>
Dump the contents of section <number|name> as relocated bytes
-w[lLiaprmfFsoRt] o
--debug-dump[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,
=frames-interp,=str,=loc,=Ranges,=pubtypes,
=gdb_index,=trace_info,=trace_abbrev,=trace_aranges,
=addr,=cu_index]
Display the contents of DWARF2 debug sections
--dwarf-depth=N Do not display DIEs at depth N or greater
--dwarf-start=N Display DIEs starting with N, at the same depth
or deeper
-I --histogram Display histogram of bucket list lengths
-W --wide Allow output width to exceed 80 characters
@<file> Read options from <file>
-H --help Display this information
-v --version Display the version number of readelf

objdump 命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
Display information from object <file(s)>.
At least one of the following switches must be given:
-a, --archive-headers Display archive header information
-f, --file-headers Display the contents of the overall file header
-p, --private-headers Display object format specific file header contents
-P, --private=OPT,OPT... Display object format specific contents
-h, --[section-]headers Display the contents of the section headers
-x, --all-headers Display the contents of all headers
-d, --disassemble Display assembler contents of executable sections
-D, --disassemble-all Display assembler contents of all sections
-S, --source Intermix source code with disassembly
-s, --full-contents Display the full contents of all sections requested
-g, --debugging Display debug information in object file
-e, --debugging-tags Display debug information using ctags style
-G, --stabs Display (in raw form) any STABS info in the file
-W[lLiaprmfFsoRt] or
--dwarf[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,
=frames-interp,=str,=loc,=Ranges,=pubtypes,
=gdb_index,=trace_info,=trace_abbrev,=trace_aranges,
=addr,=cu_index]
Display DWARF info in the file
-t, --syms Display the contents of the symbol table(s)
-T, --dynamic-syms Display the contents of the dynamic symbol table
-r, --reloc Display the relocation entries in the file
-R, --dynamic-reloc Display the dynamic relocation entries in the file
@<file> Read options from <file>
-v, --version Display this program's version number
-i, --info List object formats and architectures supported
-H, --help Display this information

The following switches are optional:
-b, --target=BFDNAME Specify the target object format as BFDNAME
-m, --architecture=MACHINE Specify the target architecture as MACHINE
-j, --section=NAME Only display information for section NAME
-M, --disassembler-options=OPT Pass text OPT on to the disassembler
-EB --endian=big Assume big endian format when disassembling
-EL --endian=little Assume little endian format when disassembling
--file-start-context Include context from start of file (with -S)
-I, --include=DIR Add DIR to search list for source files
-l, --line-numbers Include line numbers and filenames in output
-F, --file-offsets Include file offsets when displaying information
-C, --demangle[=STYLE] Decode mangled/processed symbol names
The STYLE, if specified, can be `auto', `gnu',
`lucid', `arm', `hp', `edg', `gnu-v3', `java'
or `gnat'
-w, --wide Format output for more than 80 columns
-z, --disassemble-zeroes Do not skip blocks of zeroes when disassembling
--start-address=ADDR Only process data whose address is >= ADDR
--stop-address=ADDR Only process data whose address is <= ADDR
--prefix-addresses Print complete address alongside disassembly
--[no-]show-raw-insn Display hex alongside symbolic disassembly
--insn-width=WIDTH Display WIDTH bytes on a single line for -d
--adjust-vma=OFFSET Add OFFSET to all displayed section addresses
--special-syms Include special symbols in symbol dumps
--prefix=PREFIX Add PREFIX to absolute paths for -S
--prefix-strip=LEVEL Strip initial directory names for -S
--dwarf-depth=N Do not display DIEs at depth N or greater
--dwarf-start=N Display DIEs starting with N, at the same depth
or deeper
--dwarf-check Make additional dwarf internal consistency checks.
命令 说明
-a 显示库文件的header信息。除了可以列出ar tv所能展示的信息,还可以显示lib文件中每一个对象文件的格式。
-b bfdname 为obj文件指定对象码(object-code)格式。本选项是非必需的,objdump命令可以自动的识别许多种格式。
-C 将修饰后的符号名解码成用户级的名称。
-d 从objfile中对机器指令进行反汇编。本选项只对那些包含指令的section进行反汇编。
–prefix-addresses 反汇编的时候,显示每一行的完整地址。这是一种比较老的反汇编格式
- 显示每一个obj文件的整体头部摘要信息
-j name 仅仅显示指定名称为name的section的信息
-l 用文件名和行号标注相应的目标代码,仅仅和-d、-D或者-r一起使用时有效。通常要求具有调试信息,即编译时使用了-g之类的选项。
-m machine 指定反汇编目标文件时使用的架构。
-r 显示文件的重定位入口。如果和-d或者-D一起使用,重定位部分以反汇编后的格式显示出来
-s 显示所有非空section

addr2line 命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Usage: ./aarch64-linux-android-addr2line [option(s)] [addr(s)]
Convert addresses into line number/file name pairs.
If no addresses are specified on the command line, they will be read from stdin
The options are:
@<file> Read options from <file>
-a --addresses Show addresses
-b --target=<bfdname> Set the binary file format
-e --exe=<executable> Set the input file name (default is a.out)
-i --inlines Unwind inlined functions
-j --section=<name> Read section-relative offsets instead of addresses
-p --pretty-print Make the output easier to read for humans
-s --basenames Strip directory names
-f --functions Show function names
-C --demangle[=style] Demangle function names
-h --help Display this information
-v --version Display the program's version
命令 说明
-e 指定输入
-s 不显示文件路径
-f 显示方法名
-C 将修饰后的符号名解码成用户级的名称。

常用操作

获取 ELF 文件头信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
readelf -h {YourSO}

# [RESULT]
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: 0x1e1970
Start of program headers: 64 (bytes into file)
Start of section headers: 7515136 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 6
Size of section headers: 64 (bytes)
Number of section headers: 21
Section header string table index: 20

查看对象文件的所有sections的头部摘要信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
objdump -h {YourSO}

# [RESULT]

libgcloudcore.so: file format ELF64-aarch64-little

Sections:
Idx Name Size VMA Type
0 00000000 0000000000000000
1 .note.gnu.build-id 00000024 00000000000001c8
2 .hash 00004de8 00000000000001f0
3 .dynsym 000112c8 0000000000004fd8
4 .dynstr 0001b454 00000000000162a0
5 .gnu.version 000016e6 00000000000316f4
6 .gnu.version_r 00000060 0000000000032de0
7 .rela.dyn 00015540 0000000000032e40
8 .rela.plt 00000f30 0000000000048380
9 .plt 00000a40 00000000000492b0 TEXT
10 .text 000b7d8c 0000000000049cf0 TEXT
11 .rodata 0000d2b8 0000000000101a80 DATA
12 .eh_frame_hdr 00008584 000000000010ed38 DATA
13 .eh_frame 0002f180 00000000001172c0 DATA
14 .gcc_except_table 00007050 0000000000146440 DATA
15 .init_array 000000c0 000000000015dd80
16 .fini_array 00000010 000000000015de40
17 .data.rel.ro 00009020 000000000015de50 DATA
18 .dynamic 00000230 0000000000166e70
19 .got 00000f58 00000000001670a0 DATA
20 .data 00000340 0000000000168000 DATA
21 .bss 00014828 0000000000168340 BSS
22 .comment 00000027 0000000000000000
23 .shstrtab 000000e3 0000000000000000

查看对象文件的架构信息

1
2
3
4
5
6
7
objdump -f {YourSO}

# 结果示例
libgcloudcore.so: file format ELF64-aarch64-little

architecture: aarch64
start address: 0x0000000000049cf0
1
2
3
4
file {YourSO}

# 结果示例
libgcloudcore.so: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, BuildID[sha1]=6a9fd231cd5e50ddac58f7e3bbb512d730fcaec4, stripped

查看对象文件的符号表

1
2
3
4
5
# 所有符号表(适用so)
readelf -s {YourSO}

# 动态符号表(适用so)
readelf --dyn-syms {YourSO}
1
2
3
4
5
# 所有符号表(适用于未 strip 的符号表)
objdump -t {YourSO}

# 动态符号表(适用so)
objdump -T {YourSO}

查看指定段信息

1
objdump -s -j {section-name} {YourSO}

查看 SO Name 及依赖库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
readelf -d {YourSO}

# 结果示例
Dynamic section at offset 0x156e70 contains 31 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [liblog.so]
0x0000000000000001 (NEEDED) Shared library: [libz.so]
0x0000000000000001 (NEEDED) Shared library: [libstdc++.so]
0x0000000000000001 (NEEDED) Shared library: [libm.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so]
0x0000000000000001 (NEEDED) Shared library: [libdl.so]
0x000000000000000e (SONAME) Library soname: [libgcloudcore.so]
0x0000000000000010 (SYMBOLIC) 0x0
0x0000000000000019 (INIT_ARRAY) 0x15dd80
0x000000000000001b (INIT_ARRAYSZ) 192 (bytes)
0x000000000000001a (FINI_ARRAY) 0x15de40
0x000000000000001c (FINI_ARRAYSZ) 16 (bytes)
0x0000000000000004 (HASH) 0x1f0
0x0000000000000005 (STRTAB) 0x162a0
0x0000000000000006 (SYMTAB) 0x4fd8
0x000000000000000a (STRSZ) 111700 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000003 (PLTGOT) 0x1670a0
0x0000000000000002 (PLTRELSZ) 3888 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0x48380
0x0000000000000007 (RELA) 0x32e40
0x0000000000000008 (RELASZ) 87360 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x0000000000000018 (BIND_NOW)
0x000000006ffffffb (FLAGS_1) Flags: NOW
0x000000006ffffffe (VERNEED) 0x32de0
0x000000006fffffff (VERNEEDNUM) 3
0x000000006ffffff0 (VERSYM) 0x316f4
0x000000006ffffff9 (RELACOUNT) 3634
0x0000000000000000 (NULL) 0x0

使用 petchelf 修改 SONAME

1
petchelf --set-soname {soname} {YourSO}

使用 addr2line 还原符号

1
addr2line {address} -e {YourSO} -f -C -s

参考

http://www.chuquan.me/2018/05/21/elf-introduce/
https://sourceware.org/binutils/docs-2.17/binutils/nm.html
http://sourceware.org/binutils/docs/binutils/readelf.html
https://github.com/NixOS/patchelf