Android ELF64

ELF文件布局

Android ELF64_第1张图片

relocatable类型(ET_REL)的ELF文件(如.o目标文件)无Program Header Table

ELF文件头

例子

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:               0x570
  Start of program headers:          64 (bytes into file)
  Start of section headers:          7520 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         8
  Size of section headers:           64 (bytes)
  Number of section headers:         31
  Section header string table index: 28

数据结构

typedef struct elf64_hdr {
  unsigned char e_ident[EI_NIDENT];     /* ELF "magic number" */
  Elf64_Half e_type;
  Elf64_Half e_machine;
  Elf64_Word e_version;
  Elf64_Addr e_entry;           /* Entry point virtual address */
  Elf64_Off e_phoff;            /* Program header table file offset */
  Elf64_Off e_shoff;            /* Section header table file offset */
  Elf64_Word e_flags;
  Elf64_Half e_ehsize;
  Elf64_Half e_phentsize;
  Elf64_Half e_phnum;
  Elf64_Half e_shentsize;
  Elf64_Half e_shnum;
  Elf64_Half e_shstrndx;
} Elf64_Ehdr;
  • e_type: ELF文件类型
    • ET_REL
    • ET_EXEC
    • ET_DYN
  • e_phoff: Program header table在ELF文件中的偏移
  • e_shoff: Section header table在ELF文件中的偏移
  • e_ehsize: ELF文件头大小
  • e_phentsize: Program header table项的大小
  • e_phnum: Program header table项的数量
  • e_shentsize: Section header table项的大小
  • e_shnum: Section header table项的数量
  • e_shstrndx: Section header字符串表在Section header table中的索引

ELF Program header

例子

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000  ---> 可加载的Segment
                 0x0000000000000718 0x0000000000000718  R E    10000
  LOAD           0x0000000000000dc0 0x0000000000010dc0 0x0000000000010dc0  ---> 可加载的Segment
                 0x000000000000024c 0x000000000000024c  RW     10000
  DYNAMIC        0x0000000000000dd8 0x0000000000010dd8 0x0000000000010dd8
                 0x00000000000001f0 0x00000000000001f0  RW     8
  NOTE           0x0000000000000200 0x0000000000000200 0x0000000000000200
                 0x0000000000000024 0x0000000000000024  R      4
  NOTE           0x0000000000000680 0x0000000000000680 0x0000000000000680
                 0x0000000000000098 0x0000000000000098  R      4
  GNU_EH_FRAME   0x0000000000000634 0x0000000000000634 0x0000000000000634
                 0x0000000000000014 0x0000000000000014  R      4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     10
  GNU_RELRO      0x0000000000000dc0 0x0000000000010dc0 0x0000000000010dc0
                 0x0000000000000240 0x0000000000000240  R      1

Section to Segment mapping:
  Segment Sections...
   00     .note.gnu.build-id .hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .plt .text .rodata .eh_frame_hdr .eh_frame .note.android.ident
   01     .init_array .fini_array .dynamic .got .data
   02     .dynamic
   03     .note.gnu.build-id
   04     .note.android.ident
   05     .eh_frame_hdr
   06
   07     .init_array .fini_array .dynamic .got                                                      

数据结构

typedef struct elf64_phdr {
  Elf64_Word p_type;
  Elf64_Word p_flags;
  Elf64_Off p_offset;           /* Segment file offset */
  Elf64_Addr p_vaddr;           /* Segment virtual address */
  Elf64_Addr p_paddr;           /* Segment physical address */
  Elf64_Xword p_filesz;         /* Segment size in file */
  Elf64_Xword p_memsz;          /* Segment size in memory */
  Elf64_Xword p_align;          /* Segment alignment, file & memory */
} Elf64_Phdr;
  • p_type: Program header(Segment)类型
    • PT_NULL
    • PT_LOAD
    • PT_DYNAMIC
    • ......
  • p_offset: Segment内容在ELF文件中的偏移
  • p_vaddr: Segment的虚拟地址
  • p_paddr: Segment的物理地址

ELF Section header

例子

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .note.gnu.build-i NOTE             0000000000000200  00000200
       0000000000000024  0000000000000000   A       0     0     4
  [ 2] .hash             HASH             0000000000000228  00000228
       0000000000000050  0000000000000004   A       3     0     8
  [ 3] .dynsym           DYNSYM           0000000000000278  00000278
       0000000000000168  0000000000000018   A       4     3     8
  [ 4] .dynstr           STRTAB           00000000000003e0  000003e0
       00000000000000a1  0000000000000000   A       0     0     1
  [ 5] .gnu.version      VERSYM           0000000000000482  00000482
       000000000000001e  0000000000000002   A       3     0     2
  [ 6] .gnu.version_r    VERNEED          00000000000004a0  000004a0
       0000000000000020  0000000000000000   A       4     1     8
  [ 7] .rela.dyn         RELA             00000000000004c0  000004c0
       0000000000000018  0000000000000018   A       3     0     8
  [ 8] .rela.plt         RELA             00000000000004d8  000004d8
       0000000000000048  0000000000000018  AI       3    18     8
  [ 9] .plt              PROGBITS         0000000000000520  00000520
       0000000000000050  0000000000000010  AX       0     0     16
  [10] .text             PROGBITS         0000000000000570  00000570
       0000000000000094  0000000000000000  AX       0     0     4
  [11] .rodata           PROGBITS         0000000000000604  00000604
       000000000000002e  0000000000000001 AMS       0     0     1
  [12] .eh_frame_hdr     PROGBITS         0000000000000634  00000634
       0000000000000014  0000000000000000   A       0     0     4
  [13] .eh_frame         PROGBITS         0000000000000648  00000648
       0000000000000038  0000000000000000   A       0     0     8
  [14] .note.android.ide NOTE             0000000000000680  00000680
       0000000000000098  0000000000000000   A       0     0     4
  [15] .init_array       INIT_ARRAY       0000000000010dc0  00000dc0
       0000000000000008  0000000000000008  WA       0     0     1
  [16] .fini_array       FINI_ARRAY       0000000000010dc8  00000dc8
       0000000000000010  0000000000000008  WA       0     0     8
  [17] .dynamic          DYNAMIC          0000000000010dd8  00000dd8
       00000000000001f0  0000000000000010  WA       4     0     8
  [18] .got              PROGBITS         0000000000010fc8  00000fc8
       0000000000000038  0000000000000008  WA       0     0     8
  [19] .data             PROGBITS         0000000000011000  00001000
       000000000000000c  0000000000000000  WA       0     0     8
  [20] .comment          PROGBITS         0000000000000000  0000100c
       0000000000000064  0000000000000001  MS       0     0     1
  [21] .debug_pubnames   PROGBITS         0000000000000000  00001070
       0000000000000028  0000000000000000           0     0     1
  [22] .debug_info       PROGBITS         0000000000000000  00001098
       000000000000006b  0000000000000000           0     0     1
  [23] .debug_abbrev     PROGBITS         0000000000000000  00001103
       0000000000000054  0000000000000000           0     0     1
  [24] .debug_line       PROGBITS         0000000000000000  00001157
       000000000000009d  0000000000000000           0     0     1
  [25] .debug_str        PROGBITS         0000000000000000  000011f4
       0000000000000110  0000000000000001  MS       0     0     1
  [26] .debug_macinfo    PROGBITS         0000000000000000  00001304
       0000000000000001  0000000000000000           0     0     1
  [27] .debug_pubtypes   PROGBITS         0000000000000000  00001305
       000000000000001a  0000000000000000           0     0     1
  [28] .shstrtab         STRTAB           0000000000000000  00001c1d
       0000000000000143  0000000000000000           0     0     1
  [29] .symtab           SYMTAB           0000000000000000  00001320
       0000000000000708  0000000000000018          30    63     8
  [30] .strtab           STRTAB           0000000000000000  00001a28
       00000000000001f5  0000000000000000           0     0     1

数据结构

typedef struct elf64_shdr {
  Elf64_Word sh_name;           /* Section name, index in string tbl */
  Elf64_Word sh_type;           /* Type of section */
  Elf64_Xword sh_flags;         /* Miscellaneous section attributes */
  Elf64_Addr sh_addr;           /* Section virtual addr at execution */
  Elf64_Off sh_offset;          /* Section file offset */
  Elf64_Xword sh_size;          /* Size of section in bytes */
  Elf64_Word sh_link;           /* Index of another section */
  Elf64_Word sh_info;           /* Additional section information */
  Elf64_Xword sh_addralign;     /* Section alignment */
  Elf64_Xword sh_entsize;       /* Entry size if section holds table */
} Elf64_Shdr;
  • sh_offset: Setion内容在ELF文件中的偏移

Segment与Section

Segment与Section是ELF文件提供的不同视图

Android ELF64_第2张图片

ELF Dynamic Section

描述动态链接所需的信息

例子

Dynamic section at offset 0xdd8 contains 27 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libm.so]  ---> 依赖的库
 0x0000000000000001 (NEEDED)             Shared library: [libdl.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so]
 0x000000000000000e (SONAME)             Library soname: [libtest_dynamiclink.so]
 0x0000000000000019 (INIT_ARRAY)         0x10dc0
 0x000000000000001b (INIT_ARRAYSZ)       8 (bytes)
 0x000000000000001a (FINI_ARRAY)         0x10dc8
 0x000000000000001c (FINI_ARRAYSZ)       16 (bytes)
 0x0000000000000004 (HASH)               0x228 ---> hash表的文件偏移
 0x0000000000000005 (STRTAB)             0x3e0 ---> 动态字符串表的文件偏移
 0x0000000000000006 (SYMTAB)             0x278 ---> 动态符号表的文件偏移
 0x000000000000000a (STRSZ)              161 (bytes) ---> 动态字符串标的大小
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000003 (PLTGOT)             0x10fc8 ---> GOT表的虚拟地址
 0x0000000000000002 (PLTRELSZ)           72 (bytes) ---> 使用PLT重定位的函数表(.rela.plt表)的大小
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000017 (JMPREL)             0x4d8 ---> 使用PLT重定位的函数表地址(.rela.plt表文件偏移)
 0x0000000000000007 (RELA)               0x4c0 ---> 需要重定位的数据表的地址(.rela.dyn表文件偏移)
 0x0000000000000008 (RELASZ)             24 (bytes) ---> 重定位的数据表大小
 0x0000000000000009 (RELAENT)            24 (bytes) ---> 重定位的数据表项大小
 0x0000000000000018 (BIND_NOW)                      ---> 执行前重定位,不采用延迟绑定
 0x000000006ffffffb (FLAGS_1)            Flags: NOW
 0x000000006ffffffe (VERNEED)            0x4a0
 0x000000006fffffff (VERNEEDNUM)         1
 0x000000006ffffff0 (VERSYM)             0x482
 0x000000006ffffff9 (RELACOUNT)          1
 0x0000000000000000 (NULL)               0x0

数据结构

typedef struct {
  Elf64_Sxword d_tag;           /* entry tag value */
  union {
    Elf64_Xword d_val;
    Elf64_Addr d_ptr;
  } d_un;
} Elf64_Dyn;
  • d_tag: Dynamic table项的类型

    enum {
    DT_NULL         = 0,        // Marks end of dynamic array.
    DT_NEEDED       = 1,        // String table offset of needed library.
    DT_PLTRELSZ     = 2,        // Size of relocation entries in PLT.
    DT_PLTGOT       = 3,        // Address associated with linkage table.
    DT_HASH         = 4,        // Address of symbolic hash table.
    DT_STRTAB       = 5,        // Address of dynamic string table.
    DT_SYMTAB       = 6,        // Address of dynamic symbol table.
    DT_RELA         = 7,        // Address of relocation table (Rela entries).
    DT_RELASZ       = 8,        // Size of Rela relocation table.
    DT_RELAENT      = 9,        // Size of a Rela relocation entry.
    DT_STRSZ        = 10,       // Total size of the string table.
    DT_SYMENT       = 11,       // Size of a symbol table entry.
    DT_INIT         = 12,       // Address of initialization function.
    DT_FINI         = 13,       // Address of termination function.
    DT_SONAME       = 14,       // String table offset of a shared objects name.
    DT_RPATH        = 15,       // String table offset of library search path.
    DT_SYMBOLIC     = 16,       // Changes symbol resolution algorithm.
    DT_REL          = 17,       // Address of relocation table (Rel entries).
    DT_RELSZ        = 18,       // Size of Rel relocation table.
    DT_RELENT       = 19,       // Size of a Rel relocation entry.
    DT_PLTREL       = 20,       // Type of relocation entry used for linking.
    DT_DEBUG        = 21,       // Reserved for debugger.
    DT_TEXTREL      = 22,       // Relocations exist for non-writable segments.
    DT_JMPREL       = 23,       // Address of relocations associated with PLT.
    DT_BIND_NOW     = 24,       // Process all relocations before execution.
    DT_INIT_ARRAY   = 25,       // Pointer to array of initialization functions.
    DT_FINI_ARRAY   = 26,       // Pointer to array of termination functions.
    DT_INIT_ARRAYSZ = 27,       // Size of DT_INIT_ARRAY.
    DT_FINI_ARRAYSZ = 28,       // Size of DT_FINI_ARRAY.
    DT_RUNPATH      = 29,       // String table offset of lib search path.
    DT_FLAGS        = 30,       // Flags.
    DT_ENCODING     = 32,       // Values from here to DT_LOOS follow the rules
                              // for the interpretation of the d_un union.
    
    DT_PREINIT_ARRAY = 32,      // Pointer to array of preinit functions.
    DT_PREINIT_ARRAYSZ = 33,    // Size of the DT_PREINIT_ARRAY array.
    
    DT_LOOS         = 0x60000000, // Start of environment specific tags.
    DT_HIOS         = 0x6FFFFFFF, // End of environment specific tags.
    DT_LOPROC       = 0x70000000, // Start of processor specific tags.
    DT_HIPROC       = 0x7FFFFFFF, // End of processor specific tags.
    ......
    }
    
    • DT_NEEDED:
    • DT_PLTRELSZ:
    • DT_PLTGOT:
  • d_un: d_tag决定d_un的意义

ELF rela.dyn Section

存放需要重定位数据引用

例子

Relocation section '.rela.dyn' at offset 0x4c0 contains 1 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000010dc8  000000000403 R_AARCH64_RELATIV                    570

数据结构

typedef struct elf64_rela {
  Elf64_Addr r_offset;  /* Location at which to apply the action */
  Elf64_Xword r_info;   /* index and type of relocation */
  Elf64_Sxword r_addend;        /* Constant addend used to compute value */
} Elf64_Rela;
  • r_offset: 需重定位的存储单元的虚拟地址(EXEC和DYN文件)
  • r_info: 包含需重定位的符号在符号表中的索引以及重定位类型(处理器相关)
    • 索引: r_info的高32位
    • 类型: r_info的低32位
      • R_AARCH64_GLOB_DAT: 重定位类型,创建GOT表项存储特定符号的地址
      • R_AARCH64_JUMP_SLOT: 重定位类型,通过PLT找到目标符号的地址

ELF rela.plt Section

存放需要重定位的函数引用

例子

Relocation section '.rela.plt' at offset 0x4d8 contains 3 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000010fe0  000400000402 R_AARCH64_JUMP_SL 0000000000000000 printf@LIBC + 0
000000010fe8  000500000402 R_AARCH64_JUMP_SL 0000000000000000 __cxa_finalize@LIBC + 0
000000010ff0  000e00000402 R_AARCH64_JUMP_SL 0000000000000000 __cxa_atexit@LIBC + 0

以printf项为例
  r_info : 000400000402
  高32位: 0x0004 => 动态符号表(.dynsym)项索引
  低32位: 0x00000402  => R_AARCH64_JUMP_SLOT

ELF .dynsym Section

例子

Symbol table '.dynsym' contains 15 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000570     0 SECTION LOCAL  DEFAULT   10
     2: 0000000000011000     0 SECTION LOCAL  DEFAULT   19
     3: 000000000001100c     0 NOTYPE  GLOBAL DEFAULT  ABS _bss_end__
     4: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@LIBC (2)
     5: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __cxa_finalize@LIBC (2)
     6: 0000000000011008     4 OBJECT  GLOBAL DEFAULT   19 g_var
     7: 000000000001100c     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
     8: 0000000000011010     0 NOTYPE  GLOBAL DEFAULT  ABS __end__
     9: 000000000001100c     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start__
    10: 000000000001100c     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
    11: 000000000001100c     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_end__
    12: 0000000000011010     0 NOTYPE  GLOBAL DEFAULT  ABS _end
    13: 00000000000005ac    88 FUNC    GLOBAL DEFAULT   10 test_dl
    14: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __cxa_atexit@LIBC (2)

数据结构

typedef struct elf64_sym {
  Elf64_Word st_name;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
  unsigned char st_info;
  unsigned char st_other;
  Elf64_Half st_shndx;
  Elf64_Addr st_value;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
  Elf64_Xword st_size;
} Elf64_Sym;
  • st_name: 符号名在动态字符串表的索引
  • st_info: 符号的类型以及Bind属性
    • 类型
      • STT_NOTYPE
      • STT_OBJECT: 符号是数据对象(变量、数组等)
      • STT_FUNC: 符号是可执行的代码(函数等)
      • STT_SECTION
      • STT_FILE
      • ......
    • Bind属性
      • STB_LOCAL: 本地符号,目标文件外不可见
      • STB_GLOBAL: 全局符号
      • STB_WEAK: 类似与全局符号,但优先级低
  • st_other: 0(保留)
  • st_shndx: 符号定义所在Section的索引(参考Section Header Table)
  • st_value: 符号相关的地址或者值
  • st_size: 符号size

ELF .dynstr Section

例子

Android ELF64_第3张图片

示意图

Android ELF64_第4张图片

动态符号表查找符号字符串过程

Symbol table '.dynsym' contains 15 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
    ......
    13: 00000000000005ac    88 FUNC    GLOBAL DEFAULT   10 test_dl
    14: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __cxa_atexit@LIBC (2)

以动态符号表项13、14为例,也就是查找test_dl以及__cxa_atexit字符串为例。

  1. 动态符号表在ELF中的位置
[ 3] .dynsym           DYNSYM           0000000000000278  00000278
       0000000000000168  0000000000000018   A       4     3     8
在ELF中的位置: 0x278
动态符号表项size: 0x18 = 24字节
动态符号表大小: 0x168

下面查找动态符号表项(test_dl以及__cxa_atexit)st_name字段中的内容

  1. 动态符号表的二进制内容


    Android ELF64_第5张图片
  • 符号test_dl项所在地址 = 0x278 + 13 * 24 = 0x278 + 0x138 = 0x3b0

  • 符号__cxa_atexit项所在的地址 = 0x278 + 14 * 24 = 0x278 + 0x150 = 0x3c8

根据动态符号表项的数据结构可知,st_name字段位于符号表项的起始4个字节中

test_dl项st_name字段内容:2a 00 00 00   --> 0x2a (little-endian)
__cxa_atexit项st_name字段内容:10 00 00 00 --> 0x10 (little-endian)

最终test_dl在动态字符串表中的索引为42, __cxa_atexit的索引为16

ELF .plt Section

过程链表,完成从地址无关的函数调用到绝对地址的转换

Disassembly of section .plt:

0000000000000520 :
 520:   a9bf7bf0        stp     x16, x30, [sp,#-16]!
 524:   90000090        adrp    x16, 10000 
 528:   f947ee11        ldr     x17, [x16,#4056] 
 52c:   913f6210        add     x16, x16, #0xfd8
 530:   d61f0220        br      x17
 534:   d503201f        nop
 538:   d503201f        nop
 53c:   d503201f        nop

0000000000000540 :
 540:   90000090        adrp    x16, 10000 
 544:   f947f211        ldr     x17, [x16,#4064] ----------> X17=0x10fe0
 548:   913f8210        add     x16, x16, #0xfe0
 54c:   d61f0220        br      x17

 ......

ELF .got Section

全局偏移表,在数据段中存储绝对地址,用于产生地址无关的代码

0000000000010fc8 <.got>:
        ...
   10fe0:       00000520        .word   0x00000520 ---------->链接完成后,存储printf的绝对地址
   10fe4:       00000000        .word   0x00000000
   10fe8:       00000520        .word   0x00000520 ----------> __cxa_finalize地址
   10fec:       00000000        .word   0x00000000
   10ff0:       00000520        .word   0x00000520 ----------> __cxa_atexit地址
   10ff4:       00000000        .word   0x00000000
   10ff8:       00010dd8        .word   0x00010dd8
   10ffc:       00000000        .word   0x00000000

理解函数调用过程(使用PLT+GOT)

这里以一个简单的NDK Demo为例。

void test_dl(int param)
{
    printf("Test dynamiclink...\n");
    printf("param %d\n", param);
    printf("Test func end\n");
}

通过Android Studio断点调试功能,分析test_dl()调用printf()的过程。

test_dl()的汇编代码如下:

(lldb) di -f
libtest_dynamiclink.so`test_dl:
    0x7f9af5e5ac <+0>:  sub    sp, sp, #0x20             ; =0x20 
    0x7f9af5e5b0 <+4>:  stp    x29, x30, [sp, #0x10]
    0x7f9af5e5b4 <+8>:  add    x29, sp, #0x10            ; =0x10 
    0x7f9af5e5b8 <+12>: stur   w0, [x29, #-0x4]
    0x7f9af5e5bc <+16>: adrp   x0, 0
    0x7f9af5e5c0 <+20>: add    x0, x0, #0x604            ; =0x604 
->  0x7f9af5e5c4 <+24>: bl     0x7f9af5e540              ; symbol stub for: printf
    ......

调用printf()是通过bl指令跳转到地址0x7f9af5e540,该地址实际是PLT表的printf项地址

使用LLDB查看PLT表项的汇编代码

[0x0000007f9af5e520-0x0000007f9af5e570)  r-x  0x00000520 0x00000050 0x00000006 libtest_dynamiclink.so..plt ---> PLT表

(lldb) di -s 0x7f9af5e540
libtest_dynamiclink.so`printf:
    0x7f9af5e540 <+0>:  adrp   x16, 16
    0x7f9af5e544 <+4>:  ldr    x17, [x16, #0xfe0]
    0x7f9af5e548 <+8>:  add    x16, x16, #0xfe0          ; =0xfe0 
    0x7f9af5e54c <+12>: br     x17

具体指令的含义:

adrp x16, 16 => x16 = PC(低12位清零) + 16 << 12 = 0x7f9af5e000 + 0X10000 = 0x7f9af6e000

ldr x17, [x16, #0xfe0] => x17 = 地址[0x7f9af6e000 + #0xfe0 = 0x7f9af6efe0]中的值

使用LLDB读取地址0x7f9af6efe0中的值

[0x0000007f9af6efc8-0x0000007f9af6f000)  rw-  0x00000fc8 0x00000038 0x00000003 libtest_dynamiclink.so..got ---> GOT表

(lldb) x -s4 -fx -c2 0x7f9af6efe0
0x7f9af6efe0: 0xac1d5868 0x0000007f   ---------> ((四字节)little-endian)
(lldb) x/8xb 0x7f9af6efe0
0x7f9af6efe0: 0x68 0x58 0x1d 0xac 0x7f 0x00 0x00 0x00  ---------> ((字节)little-endian)

以0x7f9af6efe0为起始地址的8个字节内容是0x7fac1d5868, 这就是printf的函数地址。最终指令br x17(0x7fac1d5868)开始执行printf()

使用LLDB反汇编printf()函数进行验证,printf()函数地址的确是0x7fac1d5868

(lldb) di -n printf
libc.so`printf:
    0x7fac1d5868 <+0>:   stp    x20, x19, [sp, #-0x20]!
    0x7fac1d586c <+4>:   stp    x29, x30, [sp, #0x10]
    0x7fac1d5870 <+8>:   add    x29, sp, #0x10            ; =0x10 
    0x7fac1d5874 <+12>:  sub    sp, sp, #0x120            ; =0x120 
    0x7fac1d5878 <+16>:  adrp   x19, 115
    0x7fac1d587c <+20>:  orr    w8, wzr, #0xffffff80

小结

Android函数重定位并未采用延迟绑定,所以外部函数调用相对简单。


Android ELF64_第6张图片

参考

  1. Tool Interface Standard (TIS) Executable and Linking Format (ELF) Specification
  2. http://lldb.llvm.org/lldb-gdb.html

你可能感兴趣的:(Android ELF64)