我的目标是在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
...
答案 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
部分)。