了解RISCV程序集中的<__ libc_init_array>

时间:2019-10-09 20:17:25

标签: assembly startup elf riscv

我的目标是在C模拟程序中运行已编译的RISCV代码。我已使用RISCV32I(32位)编译器编译了C代码,并以ELF格式输出了我的代码(然后,我选择了.text部分,并在RISC-V模拟器中使用了它)。完善。然后,我尝试在模拟器中运行该编译后的代码,但是我发现在<__libc_init_array>函数中,有一些“某些”代码将始终跳转到我程序的地址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上,我们可以找到一个比较,如果为true,则将跳过几行。但是由于某种原因,这是不正确的,因此我们必须继续。在这里变得有趣。下一条指令可以将0加载到寄存器s1中,很好,但是下一条指令尝试将一些值从地址a5加载到寄存器0(s0)中。但是读取的输出将为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
    ...

1 个答案:

答案 0 :(得分:1)

您指出的代码将.init_array部分的内容从__init_array_start扫描到__init_array_end。本节包含需要在执行main之前运行的全局构造函数的地址(如前所述,顺便说一句,由于本节包含数据而不是代码,因此反汇编本节是没有意义的,因此您需要使用{{1} }代替objdump -s)。您可以在此处看到地址已初始化:

objdump -d

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

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

然后,启动代码将继续遍历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 部分中没有NULL条目,因此我唯一的猜测是由于某种原因数据段(.init_array.data,{{1} }等)在仿真开始时未从ELF文件正确加载(您还提到您仅向仿真器提供.rodata部分)。