提问人:test1 提问时间:11/13/2023 最后编辑:Peter Cordestest1 更新时间:11/13/2023 访问量:86
学习 RISC-V 汇编并需要帮助转换 C 循环
Learning RISC-V assembly and need help converting a C loop
问:
我正在学习如何将 RISC-V 汇编代码转换为 C,但我不明白这种转换。我有几个问题:
- 为什么被初始化为 而不是 ?
t1
6
0
- 我们使用 bne 来比较 t1 和 t2,但我们被教导使用相反的,这意味着 C 代码将是 .这种相反的技术似乎被用于 。为什么?
while (t1 == t0)
if (t1 ==0)
- 最后,为什么用 sub 代替 sub?
addi t0, t0, -1
任何见解都非常感谢。我的课堂环境节奏很快,对提问不是很友好,所以我在课堂上提问很紧张。
main:
# Tests simple looping behavior
li t0, 60
li t1, 0
loop:
addi t1, t1, 5
addi t0, t0, -1
bne t1, t0, loop
bne t1, zero, success
failure:
li a0, 0
li a7, 93
ecall
success:
li a0, 42
li a7, 93
ecall
这是我得到的答案:
int main(){
int t0 = 60;
int t1 = 6;
while(t1 != t0){
t1 = t1 + 5;
t0 = t0 - 1;
}
if(t1 == 0){
int a0 = 0;
return 0;
}else{
int a0 = 42;
return 0;
}
}
我们被教导在将 C 转换为 RISC-V 时使用 bne/beq 的反义词,因此令人困惑的是,为什么这个 RISC-V 汇编的“正确”C 转换会包括 .while (t1 != t0)
将 t1 初始化为 6 对我来说也没有任何意义。它看起来清楚地加载到 0 与“li t1, 0”。
答:
C 与 RISC-V 汇编不太匹配。
你是对的,asm 显然没有.如果此材料被打印出来并扫描回去或其他东西,可能是错别字或 OCR 错误。或者,也许有人只是改变了对循环起点的想法,但忘记更新其中一个版本。 并且两者都会导致循环终止而不环绕(或者实际上是 C 符号溢出未定义行为,因为这不是。t1 = 0
t1 = 6
0
6
unsigned
此外,这些是 和 ,而不是语句。asm 不使用其返回地址。ecall
_exit(0)
_exit(42)
return
不过,其余的看起来都是正确的。自己试一试,单步执行 asm 和单步执行 C 程序,分别观察寄存器或变量的变化。应该清楚的是,执行会一直保持在循环中,直到它们相等,即当它们不相等时。
对于像这样的惯用 asm 循环,最直接的 C 表示是将条件放在底部,就像 asm 一样。(将其显示为 or 循环取决于使条件为 true 的初始值设定项,因此循环体至少运行一次迭代。请参阅为什么循环总是编译为“do...而“风格(尾巴跳跃)?do{}while(t1 != t0);
for
while
(3) 尝试更改 asm 以立即使用 .大多数汇编程序会拒绝它,因为 RISC-V 没有 ,除非可能作为伪指令。它没有 FLAGS / 条件代码寄存器,因此减法完全等同于添加负数,并且 RISC-V 总是符号扩展直接操作数。它从操作码中获得的唯一好处是能够立即更改值,而不是 的范围。这显然不值得再使用一个操作码。subi
1
subi
subi
+4096 .. -4095
addi
-4096 .. +4095
MIPS在这一点上与RISC-V非常相似(没有FLAGS并且没有硬件);请参阅addi和subi之间的“关系”是什么?以及ISA与软件汇编程序伪指令设计选择。subi
评论
main
exit()
exit
atexit
_exit
exit()
_exit
ecall
上一个:无法在程序集中加载内核
评论
t1 = 0
t1 = 6
ecall
exit(0)
exit(42)
return
do ... while ()
while () { /* do */ ...}