问题描述
我正在尝试将一些 Forth 加载到我在 RISC-V SBC 上运行的 Forth 编译器中(不过我不认为这是一个与 Forth 相关的问题):
>load /root/repos/riscyforth/test2.4th
: cuboid * * [ The cuboid has a volume of ] . ;
OK
cuboid
Program received signal SIGILL,Illegal instruction.
0x0000003ff7dbd038 in ?? ()
上面显示的是我用Forth加载文件,第一行,回显到终端,是cuboid这个词的定义。随后的 OK 说明 Forth 编译器已经成功编译了这个词。
然后第二行是这个词的调用,长方体,然后是程序(在这种情况下在 GDB 下运行)已经用 SIGILL 兑现的消息。
(gdb) disassemble 0x3ff7dbd038,0x3ff7dbd078
Dump of assembler code from 0x3ff7dbd038 to 0x3ff7dbd078:
=> 0x0000003ff7dbd038: addi s9,s9,-8
0x0000003ff7dbd03c: sd s7,0(s9)
0x0000003ff7dbd040: li s8,63
0x0000003ff7dbd044: slli s8,s8,0x20
0x0000003ff7dbd048: lui t0,0xf7dbd
0x0000003ff7dbd04c: ori t0,t0,0
0x0000003ff7dbd050: slli t0,0x20
0x0000003ff7dbd054: srli t0,0x20
0x0000003ff7dbd058: or s8,t0
0x0000003ff7dbd05c: addi s8,112
0x0000003ff7dbd060: mv s7,s8
0x0000003ff7dbd062: nop
0x0000003ff7dbd064: lui t0,0x10
0x0000003ff7dbd068: addi t0,1976 # 0x107b8 <COLON_NEXT>
0x0000003ff7dbd06c: jr t0
0x0000003ff7dbd070: addi a2,sp,868
0x0000003ff7dbd072: nop
0x0000003ff7dbd074: unimp
0x0000003ff7dbd076: unimp
这完全符合我的预期,并且可以看出在 0x0000003ff7dbd038 处有一条非常好的指令。
这个内存作为可执行文件映射到系统中,这种机制适用于我在命令行上定义的单词(而不是从文件中读入)。此外,如果我只是在我加载的文件中定义这个词,然后从命令行运行它也没有问题(我知道这些可能表明加载有问题,但我看不到它或它为什么会生成这个信号。
更重要的是,如果我使用 GDB 单步执行代码,那么我不会遇到这个 SIGILL 问题,并且以 0x0000003ff7dbd038 开头的代码会按照我的预期执行。
这是 RVBoards Nezha 上的 RV64 - 在此之前执行标准的 Forth 解释器命令:
NEXT:
ld s8,0(s7) #word address register takes content of next secondary
addi s7,s7,ADDRWIDTH #next secondary along
RUN:
ld t0,0(s8) #extract first instruction address of primative
解决方法
与 x86 不同,RISC-V 不允许编写机器代码并在没有同步的情况下执行它,即使在同一线程中也是如此。在执行新编写的机器码之前,发出 fence.i
指令以将指令缓存与内存的当前状态同步。