【发布时间】:2019-10-09 20:17:25
【问题描述】:
我的目标是在我的RISCV 模拟器中运行编译后的C 代码。我已经用 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 行我们可以找到一个比较,如果为真,将跳过几行。但由于某种原因,这不是真的,所以我们必须继续。在这里它变得有趣。下一条指令将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_start。s2设置为该数组的大小。如果大小不为零,则数组中肯定有不是NULL的东西,否则你有一些问题。请注意它是数据,因此您不会看到任何代码写入它。 -
@Jester 有道理,谢谢。但这在我的程序启动时运行,在主要设置之前,那么我应该如何修改该地址上的数据?代码是编译器自动生成的,所以我不知道为什么不是 0。
-
__init_array_start数组保存全局构造函数的地址。出于某种原因,链接器将这些地址之一解析为NULL,但如果没有完整的reprocase,就无法说明原因。 -
@yugr 谢谢。我的程序从 _start 部分开始,然后跳转到一些函数,如 _memset 等。请注意,我只从 _start 运行我的程序,并且内存清晰。它从不向该地址写入任何内容。所以我不确定它要做什么以及为什么要这样做。
-
"with clear memory" - 你的意思是所有内存在开始时都设置为零?您需要从 ELF 文件中初始化
.data段。
标签: assembly startup elf riscv