Android ELF64

ELF文件布局

relocatable類型(ET_REL)的ELF文件(如.o目標(biā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

數(shù)據(jù)結(jié)構(gòu)

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項的數(shù)量
  • e_shentsize: Section header table項的大小
  • e_shnum: Section header table項的數(shù)量
  • 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                                                      

數(shù)據(jù)結(jié)構(gòu)

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內(nèi)容在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

數(shù)據(jù)結(jié)構(gòu)

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內(nèi)容在ELF文件中的偏移

Segment與Section

Segment與Section是ELF文件提供的不同視圖

ELF Dynamic Section

描述動態(tài)鏈接所需的信息

例子

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 ---> 動態(tài)字符串表的文件偏移
 0x0000000000000006 (SYMTAB)             0x278 ---> 動態(tài)符號表的文件偏移
 0x000000000000000a (STRSZ)              161 (bytes) ---> 動態(tài)字符串標(biāo)的大小
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000003 (PLTGOT)             0x10fc8 ---> GOT表的虛擬地址
 0x0000000000000002 (PLTRELSZ)           72 (bytes) ---> 使用PLT重定位的函數(shù)表(.rela.plt表)的大小
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000017 (JMPREL)             0x4d8 ---> 使用PLT重定位的函數(shù)表地址(.rela.plt表文件偏移)
 0x0000000000000007 (RELA)               0x4c0 ---> 需要重定位的數(shù)據(jù)表的地址(.rela.dyn表文件偏移)
 0x0000000000000008 (RELASZ)             24 (bytes) ---> 重定位的數(shù)據(jù)表大小
 0x0000000000000009 (RELAENT)            24 (bytes) ---> 重定位的數(shù)據(jù)表項大小
 0x0000000000000018 (BIND_NOW)                      ---> 執(zhí)行前重定位缅茉,不采用延遲綁定
 0x000000006ffffffb (FLAGS_1)            Flags: NOW
 0x000000006ffffffe (VERNEED)            0x4a0
 0x000000006fffffff (VERNEEDNUM)         1
 0x000000006ffffff0 (VERSYM)             0x482
 0x000000006ffffff9 (RELACOUNT)          1
 0x0000000000000000 (NULL)               0x0

數(shù)據(jù)結(jié)構(gòu)

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

存放需要重定位數(shù)據(jù)引用

例子

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

數(shù)據(jù)結(jié)構(gòu)

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: 包含需重定位的符號在符號表中的索引以及重定位類型(處理器相關(guān))
    • 索引: r_info的高32位
    • 類型: r_info的低32位
      • R_AARCH64_GLOB_DAT: 重定位類型,創(chuàng)建GOT表項存儲特定符號的地址
      • R_AARCH64_JUMP_SLOT: 重定位類型男摧,通過PLT找到目標(biāo)符號的地址

ELF rela.plt Section

存放需要重定位的函數(shù)引用

例子

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 => 動態(tài)符號表(.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)

數(shù)據(jù)結(jié)構(gòu)

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: 符號名在動態(tài)字符串表的索引
  • st_info: 符號的類型以及Bind屬性
    • 類型
      • STT_NOTYPE
      • STT_OBJECT: 符號是數(shù)據(jù)對象(變量蔬墩、數(shù)組等)
      • STT_FUNC: 符號是可執(zhí)行的代碼(函數(shù)等)
      • STT_SECTION
      • STT_FILE
      • ......
    • Bind屬性
      • STB_LOCAL: 本地符號,目標(biāo)文件外不可見
      • STB_GLOBAL: 全局符號
      • STB_WEAK: 類似與全局符號耗拓,但優(yōu)先級低
  • st_other: 0(保留)
  • st_shndx: 符號定義所在Section的索引(參考Section Header Table)
  • st_value: 符號相關(guān)的地址或者值
  • st_size: 符號size

ELF .dynstr Section

例子

示意圖

動態(tài)符號表查找符號字符串過程

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)

以動態(tài)符號表項13拇颅、14為例,也就是查找test_dl以及__cxa_atexit字符串為例乔询。

  1. 動態(tài)符號表在ELF中的位置
[ 3] .dynsym           DYNSYM           0000000000000278  00000278
       0000000000000168  0000000000000018   A       4     3     8
在ELF中的位置: 0x278
動態(tài)符號表項size: 0x18 = 24字節(jié)
動態(tài)符號表大小: 0x168

下面查找動態(tài)符號表項(test_dl以及__cxa_atexit)st_name字段中的內(nèi)容

  1. 動態(tài)符號表的二進制內(nèi)容


  • 符號test_dl項所在地址 = 0x278 + 13 * 24 = 0x278 + 0x138 = 0x3b0

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

根據(jù)動態(tài)符號表項的數(shù)據(jù)結(jié)構(gòu)可知樟插,st_name字段位于符號表項的起始4個字節(jié)中

test_dl項st_name字段內(nèi)容:2a 00 00 00   --> 0x2a (little-endian)
__cxa_atexit項st_name字段內(nèi)容:10 00 00 00 --> 0x10 (little-endian)

最終test_dl在動態(tài)字符串表中的索引為42, __cxa_atexit的索引為16

ELF .plt Section

過程鏈表,完成從地址無關(guān)的函數(shù)調(diào)用到絕對地址的轉(zhuǎn)換

Disassembly of section .plt:

0000000000000520 <printf@plt-0x20>:
 520:   a9bf7bf0        stp     x16, x30, [sp,#-16]!
 524:   90000090        adrp    x16, 10000 <note_end+0xf8e8>
 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 <printf@plt>:
 540:   90000090        adrp    x16, 10000 <note_end+0xf8e8>
 544:   f947f211        ldr     x17, [x16,#4064] ----------> X17=0x10fe0
 548:   913f8210        add     x16, x16, #0xfe0
 54c:   d61f0220        br      x17

 ......

ELF .got Section

全局偏移表竿刁,在數(shù)據(jù)段中存儲絕對地址黄锤,用于產(chǎn)生地址無關(guān)的代碼

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

理解函數(shù)調(diào)用過程(使用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斷點調(diào)試功能猜扮,分析test_dl()調(diào)用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
    ......

調(diào)用printf()是通過bl指令跳轉(zhuǎn)到地址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   ---------> ((四字節(jié))little-endian)
(lldb) x/8xb 0x7f9af6efe0
0x7f9af6efe0: 0x68 0x58 0x1d 0xac 0x7f 0x00 0x00 0x00  ---------> ((字節(jié))little-endian)

以0x7f9af6efe0為起始地址的8個字節(jié)內(nèi)容是0x7fac1d5868, 這就是printf的函數(shù)地址旅赢。最終指令br x17(0x7fac1d5868)開始執(zhí)行printf()

使用LLDB反匯編printf()函數(shù)進行驗證惑惶,printf()函數(shù)地址的確是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

小結(jié)

Android函數(shù)重定位并未采用延遲綁定煮盼,所以外部函數(shù)調(diào)用相對簡單。


參考

  1. Tool Interface Standard (TIS) Executable and Linking Format (ELF) Specification
  2. http://lldb.llvm.org/lldb-gdb.html
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末带污,一起剝皮案震驚了整個濱河市僵控,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鱼冀,老刑警劉巖报破,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異千绪,居然都是意外死亡充易,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門荸型,熙熙樓的掌柜王于貴愁眉苦臉地迎上來盹靴,“玉大人,你說我怎么就攤上這事「寰玻” “怎么了梭冠?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長改备。 經(jīng)常有香客問我控漠,道長,這世上最難降的妖魔是什么悬钳? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任润脸,我火速辦了婚禮,結(jié)果婚禮上他去,老公的妹妹穿的比我還像新娘毙驯。我一直安慰自己,他們只是感情好灾测,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布爆价。 她就那樣靜靜地躺著,像睡著了一般媳搪。 火紅的嫁衣襯著肌膚如雪铭段。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天秦爆,我揣著相機與錄音序愚,去河邊找鬼。 笑死等限,一個胖子當(dāng)著我的面吹牛爸吮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播望门,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼形娇,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了筹误?” 一聲冷哼從身側(cè)響起桐早,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎厨剪,沒想到半個月后哄酝,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡祷膳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年陶衅,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钾唬。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡万哪,死狀恐怖侠驯,靈堂內(nèi)的尸體忽然破棺而出抡秆,到底是詐尸還是另有隱情奕巍,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布儒士,位于F島的核電站的止,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏着撩。R本人自食惡果不足惜诅福,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望拖叙。 院中可真熱鬧氓润,春花似錦、人聲如沸薯鳍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽挖滤。三九已至崩溪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間斩松,已是汗流浹背伶唯。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留惧盹,地道東北人乳幸。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像钧椰,于是被迫代替她去往敵國和親反惕。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容