更新:写出来让我可以发现哪里出了问题,但不能确定原因。很明显,我用错误的方式调用fgets,因为在五次调用后,我得到了地址0x221000,这就是mmapped内存所在的位置——我在更高的地址上写——但我不知道为什么会发生这种情况。有人能解释一下吗?
这有点复杂,我不知道为什么会出现这种行为:我不知道我是不是基本错了,或者这是Spike/PK的一个特点。
注意:这里的libc是由newlib提供的,代码编译为riscv64未知elf。
短版本我有用RISC-V程序集编写的输入代码,以前运行平稳,但由于我引入了对mmap的系统调用,它在第五次执行时崩溃。问题是因为我得到了错误的调用序列,还是可能是Spike模拟器和PK代理内核的问题?
详细解释
我正在写一种福斯式的螺纹解释语言。它目前的目标是Spike模拟器上的PK代理内核,但希望很快能在"真正的"硬件上运行。代码位于https://github.com/mcmenaminadrian/riscyforth
TIL实现了一个无休止的循环来获取输入,依次调用一个获取标准输入的文件指针的例程,然后调用一个获得输入的例程。
要获得标准输入文件指针(存储在堆栈上(:
mv a0, zero
la a1, stdinopen
call fdopen
addi sp, sp, -8
sw a0 0(sp)
(stdinopen在.data部分中作为.asciz"r"(
然后要获得输入-将其从堆栈中弹出。。。
lw a2, 0(sp)
addi sp, sp, 8
la a0, INPUT_BUFFER
li a1, BUFFERLEN #0x200
call fgets
INPUT_BUFFER在.bss部分中定义为.common INPUT_BUFFER、BUFFERLEN、8
这一切都很好,直到我添加了新的代码,这些代码在一些内存中映射为R/W/X——如果你了解Forth,你就会知道我需要具有这组不寻常权限的内存,因为我必须允许用户定义新的关键字。
现在,尝试获取输入在第四次调用时失败。(尽管如果我定义了mmap,问题就会消失。(
下面是一个失败的例子:
欢迎来到RISCYFORTH-版权所有Adrian McMenamin 2020-2021
RISCYFORTH是一种紧密基于FORTH的线程解释语言。目前我们正在EXECUTE模式下运行,您键入的任何内容都将在输入每一行时执行。RISCYFORTH是根据GNU通用公共许可证第2版获得许可的。看见https://github.com/mcmenaminadrian/riscyforth.git3465622*dupOK
重复OK
重复OK
。1945212 OK
z 000000000000000000000000 ra 00000000000 10442 sp 0000003fffffaf8 gp 00000000000 1fe30tp 0000000000000000 t0 00000000000 9fa60 t1 000000000000000 a t2 000000000000000 3s0 000000000000000000000000 s1 0000000000000000 a0 00000000000 1e530 a1 00000000000 9fa60a2 00000000000000200 a3 0000000000000000 a4 0000000000221000 a5 0000000000000001a6 00000000000 1ec88 a7 00000000000000d6 s2 00000000000001f s3 00000000000 9fa60s4 00000000000 1e530 s5 00000000000 9fa60 s6 00000000000 s7 00000000000 11b64s8 00000000000 10400 s9 0000000000 11fc58 sA 00000000000 9f950 sB 0000000000000000t3 0000000000000064 t4 0000003 fffffb08 t5 0000000000000054 t6 0000000000000054pc 00000000000 11ca4 va/inst 000000000000000 8 sr 8000000200006020用户加载segfault@0x0000000000000008
这里是代码失败的地方:
0000000000011c64 <_fgets_r>:
11c64: 4785 li a5,1
11c66: 0ac7de63 bge a5,a2,11d22 <_fgets_r+0xbe>
11c6a: 7139 addi sp,sp,-64
11c6c: f822 sd s0,48(sp)
11c6e: f04a sd s2,32(sp)
11c70: ec4e sd s3,24(sp)
11c72: e852 sd s4,16(sp)
11c74: fc06 sd ra,56(sp)
11c76: f426 sd s1,40(sp)
11c78: e456 sd s5,8(sp)
11c7a: e05a sd s6,0(sp)
11c7c: 8932 mv s2,a2
11c7e: 8a2a mv s4,a0
11c80: 89ae mv s3,a1
11c82: 8436 mv s0,a3
11c84: c119 beqz a0,11c8a <_fgets_r+0x26>
11c86: 493c lw a5,80(a0)
11c88: cbc1 beqz a5,11d18 <_fgets_r+0xb4>
11c8a: 397d addiw s2,s2,-1
11c8c: 8ace mv s5,s3
11c8e: a819 j 11ca4 <_fgets_r+0x40>
11c90: 601c ld a5,0(s0)
11c92: 9f05 subw a4,a4,s1
11c94: 9aa6 add s5,s5,s1
11c96: 94be add s1,s1,a5
11c98: c418 sw a4,8(s0)
11c9a: e004 sd s1,0(s0)
11c9c: 3cb000ef jal ra,12866 <memcpy>
11ca0: 04090f63 beqz s2,11cfe <_fgets_r+0x9a>
11ca4: 441c lw a5,8(s0)
(fgets调用_fgets_r(
0000000000011d26 <fgets>:
11d26: 87aa mv a5,a0
11d28: 8401b503 ld a0,-1984(gp) # 1f670 <_impure_ptr>
11d2c: 86b2 mv a3,a2
11d2e: 862e mv a2,a1
11d30: 85be mv a1,a5
11d32: bf0d j 11c64 <_fgets_r>
memcpy中出现了问题,给我留下了一个相当于空指针的指针,但我不清楚是什么,但我更基本的问题是:我是否正确地调用了fgets的基本过程
我相信我以前也没有遇到过任何问题,但关于这方面的文档很少,所以确认一下会很有帮助,至少会建议我更仔细地查看mmap代码。
当然,如果有人能发现其他错误,我们将不胜感激。
通过反复打开文件,我的代码消耗了越来越多的内存,最终覆盖了通过mmap分配的部分内存范围。我通过将文件指针的值存储在.bss(inputfileptr(中并只打开一次来解决这个问题:
la t0, inputfileptr
lw a0, 0(t0)
bne a0, zero, getstdin_getin
la a1, stdinopen
call fdopen
la t0, inputfileptr
sw a0, 0(t0)
getstdin_getin:
PUSH a0 #store value on stack