Android ELF64

作者: lbtrace | 来源:发表于2017-12-24 19:50 被阅读171次

    ELF文件布局

    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文件提供的不同视图

    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

    例子

    示意图

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

    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. 动态符号表的二进制内容


    • 符号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 <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

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

    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函数重定位并未采用延迟绑定,所以外部函数调用相对简单。


    参考

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

    相关文章

      网友评论

        本文标题:Android ELF64

        本文链接:https://www.haomeiwen.com/subject/nkwhgxtx.html