ELF二进制文件中的.init_array部分是什么?

时间:2012-05-06 06:03:50

标签: android c arm loader elf

每篇文章都说.init_array部分是一个函数数组,但根据我的经验,它不是。

这是我为Android编译的libc.so的.init_array:

$ prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-objdump -s -j .init_array out/target/product/e910/obj/SHARED_LIBRARIES/libc_intermediates/LINKED/libc.so 

out/target/product/e910/obj/SHARED_LIBRARIES/libc_intermediates/LINKED/libc.so:     file format elf32-littlearm

Contents of section .init_array:
 42000 e1620100 ffffffff 75940200 00000000  .b......u.......

它包含4个字(小端):

000162e1
ffffffff
00029475
00000000

000162e100029475似乎是一些函数指针:

000162e0 <__libc_preinit>:
 * as soon as the shared library is loaded.
 */
void __attribute__((constructor)) __libc_preinit(void);

void __libc_preinit(void)
{
   162e0:   b510        push    {r4, lr}
     * Note that:
     * - we clear the slot so no other initializer sees its value.
     * - __libc_init_common() will change the TLS area so the old one
     *   won't be accessible anyway.
     */
    void**      tls_area = (void**)__get_tls();
   162e2:   4805        ldr r0, [pc, #20]   (162f8 <__libc_preinit+0x18>)
    unsigned*   elfdata   = tls_area[TLS_SLOT_BIONIC_PREINIT];

    tls_area[TLS_SLOT_BIONIC_PREINIT] = NULL;
   162e4:   2200        movs    r2, #0
     * Note that:
     * - we clear the slot so no other initializer sees its value.
     * - __libc_init_common() will change the TLS area so the old one
     *   won't be accessible anyway.
     */
    void**      tls_area = (void**)__get_tls();
   162e6:   6803        ldr r3, [r0, #0]
    unsigned*   elfdata   = tls_area[TLS_SLOT_BIONIC_PREINIT];
   162e8:   68d8        ldr r0, [r3, #12]

    tls_area[TLS_SLOT_BIONIC_PREINIT] = NULL;
   162ea:   60da        str r2, [r3, #12]

    __libc_init_common(elfdata);
   162ec:   f010 fed6   bl  2709c <__libc_init_common>

    /* Setup malloc routines accordingly to the environment.
     * Requires system properties
     */
    extern void malloc_debug_init(void);
    malloc_debug_init();
   162f0:   f7ff fd0e   bl  15d10 <malloc_debug_init>
}
   162f4:   bd10        pop {r4, pc}
   162f6:   46c0        nop         (mov r8, r8)
   162f8:   ffff0ff0    .word   0xffff0ff0

00029475是:

00029474 <__guard_setup>:

/* Initialize the canary with a random value from /dev/urandom.
 * If that fails, use the "terminator canary". */
static void __attribute__ ((constructor))
__guard_setup(void)
{
   29474:   b570        push    {r4, r5, r6, lr}
    int fd;

    fd = open("/dev/urandom", O_RDONLY);
   29476:   4810        ldr r0, [pc, #64]   (294b8 <__guard_setup+0x44>)
   29478:   2100        movs    r1, #0
   2947a:   4478        add r0, pc
   2947c:   f7ef f89a   bl  185b4 <open>
    if (fd != -1) {
        ssize_t len = read(fd, &__stack_chk_guard,
   29480:   4d0e        ldr r5, [pc, #56]   (294bc <__guard_setup+0x48>)
   29482:   447d        add r5, pc
static void __attribute__ ((constructor))
__guard_setup(void)
{
    int fd;

    fd = open("/dev/urandom", O_RDONLY);
   29484:   1c06        adds    r6, r0, #0
    if (fd != -1) {
   29486:   1c43        adds    r3, r0, #1
   29488:   d00a        beq.n   294a0 <__guard_setup+0x2c>
        ssize_t len = read(fd, &__stack_chk_guard,
   2948a:   4b0d        ldr r3, [pc, #52]   (294c0 <__guard_setup+0x4c>)
   2948c:   2204        movs    r2, #4
   2948e:   58e9        ldr r1, [r5, r3]
   29490:   f7e3 e8fe   blx c690 <read>
   29494:   1c04        adds    r4, r0, #0
                           sizeof(__stack_chk_guard));
        close(fd);
   29496:   1c30        adds    r0, r6, #0
   29498:   f7e3 e96a   blx c770 <close>
        if (len == sizeof(__stack_chk_guard))
   2949c:   2c04        cmp r4, #4
   2949e:   d009        beq.n   294b4 <__guard_setup+0x40>
            return;
    }

    /* If that failed, switch to 'terminator canary' */
    ((unsigned char *)&__stack_chk_guard)[0] = 0;
   294a0:   4c07        ldr r4, [pc, #28]   (294c0 <__guard_setup+0x4c>)
    ((unsigned char *)&__stack_chk_guard)[1] = 0;
    ((unsigned char *)&__stack_chk_guard)[2] = '\n';
    ((unsigned char *)&__stack_chk_guard)[3] = 255;
   294a2:   2101        movs    r1, #1
        if (len == sizeof(__stack_chk_guard))
            return;
    }

    /* If that failed, switch to 'terminator canary' */
    ((unsigned char *)&__stack_chk_guard)[0] = 0;
   294a4:   2600        movs    r6, #0
   294a6:   5928        ldr r0, [r5, r4]
    ((unsigned char *)&__stack_chk_guard)[1] = 0;
    ((unsigned char *)&__stack_chk_guard)[2] = '\n';
    ((unsigned char *)&__stack_chk_guard)[3] = 255;
   294a8:   424a        negs    r2, r1
    }

    /* If that failed, switch to 'terminator canary' */
    ((unsigned char *)&__stack_chk_guard)[0] = 0;
    ((unsigned char *)&__stack_chk_guard)[1] = 0;
    ((unsigned char *)&__stack_chk_guard)[2] = '\n';
   294aa:   250a        movs    r5, #10
        if (len == sizeof(__stack_chk_guard))
            return;
    }

    /* If that failed, switch to 'terminator canary' */
    ((unsigned char *)&__stack_chk_guard)[0] = 0;
   294ac:   7006        strb    r6, [r0, #0]
    ((unsigned char *)&__stack_chk_guard)[1] = 0;
   294ae:   7046        strb    r6, [r0, #1]
    ((unsigned char *)&__stack_chk_guard)[2] = '\n';
   294b0:   7085        strb    r5, [r0, #2]
    ((unsigned char *)&__stack_chk_guard)[3] = 255;
   294b2:   70c2        strb    r2, [r0, #3]
}
   294b4:   bd70        pop {r4, r5, r6, pc}
   294b6:   46c0        nop         (mov r8, r8)
   294b8:   0001451d    .word   0x0001451d
   294bc:   0001a09e    .word   0x0001a09e
   294c0:   ffffff1c    .word   0xffffff1c

有3个问题:

  1. 为什么有1个字节的偏移?在arm架构中,所有指令都与2字节边界对齐,但它们不是。
  2. 该阵列中的ffffffff是什么?
  3. 该阵列中的00000000是什么?

1 个答案:

答案 0 :(得分:3)

对于问题#1,查看反汇编,您的ARM代码处于Thumb模式 - Thumb指令的地址是在设置最低有效位的情况下生成的,这样当从标准ARM模式调用时,它们会触发将处理器切换到Thumb模式。为了兼容性,我认为即使ARM处理器只支持Thumb,这通常也会完成。

对于数字2和3,来自readme on the Android linker

  

DT_INIT_ARRAY

     

指向必须调用的函数地址数组,   按顺序,执行初始化。数组中的一些条目   可以是0或-1,应该被忽略。

     

注意:这通常存储在.init_array部分