【问题标题】:Understanding <__libc_init_array> in RISCV assembly理解 RISCV 程序集中的 <__libc_init_array>
【发布时间】:2019-10-09 20:17:25
【问题描述】:

我的目标是在我的RISCV 模拟器中运行编译后的C 代码。我已经用 RISCV32I(32 位)编译器编译了一个 C 代码,它以 ELF 格式输出我的代码(然后我选择了.text 部分并在我的RISC-V 模拟器中使用它)。完美的。然后,我尝试在我的模拟器中运行该编译代码,但我发现在&lt;__libc_init_array&gt; 函数中有“一些”代码总是会跳转到我的程序的地址 0,这显然是我不想要的。

我的输出文件的反汇编:

 000102ec <__libc_init_array>:
   102ec:   ff010113            addi    sp,sp,-16
   102f0:   00812423            sw  s0,8(sp)
   102f4:   01212023            sw  s2,0(sp)
   102f8:   00001417            auipc   s0,0x1
   102fc:   3c840413            addi    s0,s0,968 # 116c0 <__init_array_start>
   10300:   00001917            auipc   s2,0x1
   10304:   3c090913            addi    s2,s2,960 # 116c0 <__init_array_start>
   10308:   40890933            sub s2,s2,s0
   1030c:   00112623            sw  ra,12(sp)
   10310:   00912223            sw  s1,4(sp)
   10314:   40295913            srai    s2,s2,0x2
   10318:   00090e63            beqz    s2,10334 <__libc_init_array+0x48>
   1031c:   00000493            li  s1,0
   10320:   00042783            lw  a5,0(s0)
   10324:   00148493            addi    s1,s1,1
   10328:   00440413            addi    s0,s0,4
   1032c:   000780e7            jalr    a5
   10330:   fe9918e3            bne s2,s1,10320 <__libc_init_array+0x34>
   10334:   00001417            auipc   s0,0x1
   10338:   38c40413            addi    s0,s0,908 # 116c0 <__init_array_start>
   1033c:   00001917            auipc   s2,0x1
   10340:   38c90913            addi    s2,s2,908 # 116c8 <__init_array_end>
   10344:   40890933            sub s2,s2,s0
   10348:   40295913            srai    s2,s2,0x2
   1034c:   dbdff0ef            jal ra,10108 <_fini>
   10350:   00090e63            beqz    s2,1036c <__libc_init_array+0x80>
   10354:   00000493            li  s1,0
   10358:   00042783            lw  a5,0(s0)
   1035c:   00148493            addi    s1,s1,1
   10360:   00440413            addi    s0,s0,4
   10364:   000780e7            jalr    a5
   10368:   fe9918e3            bne s2,s1,10358 <__libc_init_array+0x6c>
   1036c:   00c12083            lw  ra,12(sp)
   10370:   00812403            lw  s0,8(sp)
   10374:   00412483            lw  s1,4(sp)
   10378:   00012903            lw  s2,0(sp)
   1037c:   01010113            addi    sp,sp,16
   10380:   00008067            ret

10350 行我们可以找到一个比较,如果为真,将跳过几行。但由于某种原因,这不是真的,所以我们必须继续。在这里它变得有趣。下一条指令将0 加载到寄存器s1 中,很好,但下一条指令尝试从地址0(s0) 将一些值加载到reg a5 中。但是读取的输出将是0,因为在内存中什么都没有。我找不到任何对此代码开头的特定地址形式的引用(来自_start)。事实上,除了这个函数之外,根本没有尝试写入或读取该地址。

   10350:   00090e63            beqz    s2,1036c <__libc_init_array+0x80>
   10354:   00000493            li  s1,0
   10358:   00042783            lw  a5,0(s0)
   1035c:   00148493            addi    s1,s1,1
   10360:   00440413            addi    s0,s0,4
   10364:   000780e7            jalr    a5

我错过了什么吗?这是程序跳转到主要部分之前的最后一步,所以我不想回到地址0

感谢您的帮助

编辑

.init_array.data 的转储,但我看不出它们如何影响有问题的地址上的值(甚至还有压缩指令和一些未知的 FLD,这两者都不受我的支持模拟器)。

Disassembly of section .init_array:

000116c0 <__init_array_start>:
   116c0:   00ac                    addi    a1,sp,72
   116c2:   0001                    nop

000116c4 <__frame_dummy_init_array_entry>:
   116c4:   01a8                    addi    a0,sp,200
   116c6:   0001                    nop

Disassembly of section .fini_array:

000116c8 <__do_global_dtors_aux_fini_array_entry>:
   116c8:   0160                    addi    s0,sp,140
   116ca:   0001                    nop

Disassembly of section .data:

000116d0 <__DATA_BEGIN__>:
   116d0:   0000                    unimp
   116d2:   0000                    unimp
   116d4:   19bc                    addi    a5,sp,248
   116d6:   0001                    nop
   116d8:   1a24                    addi    s1,sp,312
   116da:   0001                    nop
   116dc:   1a8c                    addi    a1,sp,368
   116de:   0001                    nop
    ...
   11778:   0001                    nop
   1177a:   0000                    unimp
   1177c:   0000                    unimp
   1177e:   0000                    unimp
   11780:   330e                    fld ft6,224(sp)
   11782:   abcd                    j   11d74 <__BSS_END__+0x230>
   11784:   1234                    addi    a3,sp,296
   11786:   e66d                    bnez    a2,11870 <__DATA_BEGIN__+0x1a0>
   11788:   deec                    sw  a1,124(a3)
   1178a:   0005                    c.nop   1
   1178c:   0000000b            0xb
    ...

【问题讨论】:

  • 10338 设置s0 指向__init_array_starts2 设置为该数组的大小。如果大小不为零,则数组中肯定有不是NULL 的东西,否则你有一些问题。请注意它是数据,因此您不会看到任何代码写入它。
  • @Jester 有道理,谢谢。但这在我的程序启动时运行,在主要设置之前,那么我应该如何修改该地址上的数据?代码是编译器自动生成的,所以我不知道为什么不是 0。
  • __init_array_start 数组保存全局构造函数的地址。出于某种原因,链接器将这些地址之一解析为NULL,但如果没有完整的reprocase,就无法说明原因。
  • @yugr 谢谢。我的程序从 _start 部分开始,然后跳转到一些函数,如 _memset 等。请注意,我只从 _start 运行我的程序,并且内存清晰。它从不向该地址写入任何内容。所以我不确定它要做什么以及为什么要这样做。
  • "with clear memory" - 你的意思是所有内存在开始时都设置为零?您需要从 ELF 文件中初始化 .data 段。

标签: assembly startup elf riscv


【解决方案1】:

您指出的代码将.init_array 部分的内容从__init_array_start 扫描到__init_array_end。本节包含在执行 main 之前需要运行的全局构造函数的地址(顺便说一句,正如你提到的,反汇编本节没有意义,因为它包含数据,而不是代码,所以你需要使用 objdump -s 而不是 @ 987654326@)。可以看到这里初始化了地址:

10338:   38c40413            addi    s0,s0,908 # 116c0 <__init_array_start>
...
10340:   38c90913            addi    s2,s2,908 # 116c8 <__init_array_end>

然后用于计算节的大小(以 4 字节字为单位):

10344:   40890933            sub s2,s2,s0
10348:   40295913            srai    s2,s2,0x2

然后启动代码继续循环.init_array 中的指针并执行它们:

10350:   00090e63            beqz    s2,1036c <__libc_init_array+0x80>  ; Skip if .init_array is empty
10354:   00000493            li  s1,0         ; Initialize loop counter
10358:   00042783            lw  a5,0(s0)     ; Load address of global ctor
1035c:   00148493            addi    s1,s1,1  ; Increment loop counter
10360:   00440413            addi    s0,s0,4  ; Compute address which holds address of next global pointer
10364:   000780e7            jalr    a5       ; Execute global ctor
10368:   fe9918e3            bne s2,s1,10358 <__libc_init_array+0x6c>  ; Loop if within .init_array

根据您问题中的数据,.init_array 部分中没有 NULL 条目,所以我唯一的猜测是由于某种原因数据段(.data.rodata.init_array 等)未加载在模拟开始时正确地从 ELF 文件中获取(您还提到您仅向模拟器提供了 .text 部分)。

【讨论】:

    猜你喜欢
    • 2013-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-03
    • 1970-01-01
    • 2020-12-06
    • 1970-01-01
    相关资源
    最近更新 更多