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

6
每篇文章都说.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

有三个问题:

  1. 为什么会有1字节偏移?在Arm架构中,所有指令都对齐到2字节边界,但它们并没有。
  2. 数组中的ffffffff是什么?
  3. 数组中的00000000是什么?
1个回答

4
对于问题#1,从反汇编结果看,你的ARM代码处于Thumb模式下 - Thumb指令的地址采用最低位设置以便在从标准ARM模式调用时触发切换到Thumb模式。 为了兼容性,即使ARM处理器仅支持Thumb模式,我认为通常也会这样做。
对于第2和第3个数字,根据Android链接器自述文件
DT_INIT_ARRAY
指向必须按顺序调用的函数地址数组以执行初始化。 数组中的某些条目可以为0或-1,并且应被忽略。
注意:这通常存储在.init_array部分中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接