C 到 MIPS 汇编
C to MIPS Assembly
我试图解决这个问题并将其转换为 MIPS 汇编代码
但是书中的答案令人困惑 me.so,谁能解释一下这段代码是如何在 c 中得到这个结果的?
B[g] = A[f] + A[f+1];
我已经插入了我认为正确的评论,如果我错了请纠正我。
Assume we have variables f, g, h, i, j stored in $s0, $s1, $s2, $s3 and $s4, respectively. Assume the base addresses of arrays A and B are at $s6 and $s7.
代码:
add $t0, $s6, $s0 #This will add f bytes to the base address and it's not equal to A[f].
add $t1, $s7, $s1 #This will add g bytes to the base address and it's not equal to B[g]
lw $s0, 0($t0) #This will point to the value in (f +base address of A +0) bytes
lw $t0, 4($t0) #This will point to the value in (f +base address of A +4) bytes
add $t0, $t0, $s0
sw $t0, 0($t1)
add $t0, $s6, $s0 # t0 = A + f
add $t1, $s7, $s1 # t1 = B + g
lw $s0, 0($t0) # s0 = *(t0 + 0) = *(A + f) = A[f]
lw $t0, 4($t0) # t0 = *(t0 + 4) = *(A + f + 1) = A[f+1]
add $t0, $t0, $s0 # t0 = t0 + s0 = A[f] + A[f+1]
sw $t0, 0($t1) # *(t1 + 0) = *(B + g) = B[g] = t0
请记住,C 指针算法按项目大小缩放,但汇编使用字节。因此,前进 4 个字节在 C 中前进 1 项。
转念一想,这实际上意味着 f
和 g
也应该按 4 缩放,但它们似乎不是。
我注释的你的编译片段:
add $t0, $s6, $s0
将寄存器 s6
和 s0
中的内容添加并存储在寄存器 t0
中。由于您已经指出 f
存储在 s0
中,而 A
的基地址存储在 s6
中,因此添加地址以准备稍后的寄存器间接加载在。在 C 中更简单的 A[f] == *(A + f)
,这是为稍后的 (A + f)
取消引用做准备。
add $t1, $s7, $s1
B
和 g
也发生了同样的事情。添加它们的内容并将它们存储在中间寄存器中,稍后用作基于地址的取消引用目标。
lw $s0, 0($t0)
这是加载到 s0
寄存器,使用所谓的 cpu 的 register-indirect
寻址模式,无论 t0
指向的地址是什么加上 0 个字节。在 c 中,这等于 s0 = *(A + f)
.
lw $t0, 4($t0)
和上面一样,只是这次它加载到寄存器t0
任何指向t0
的东西加上4个字节。等于Ct0 = *(A + f + 1)
.
add $t0, $t0, $s0
这是它在您的代码中执行加法的地方。等于A[f] + A[f + 1]
.
的C代码片段
sw $t0, 0($t1)
这是在t1
所指向的地址中存放上次相加的结果。
~~~~~~~~~~~
如果您正在寻找您所拥有的代码的一些参考资料,我找到了这两个 MIPS instruction set reference useful and, of course, Matt Godbolt's interactive compiler。
如果您想查看哪些代码使用交互式编译器执行哪些操作,只需将您的代码包装在 void
函数中,select 作为编译器 x86 clang
并在编译器选项中--target=mips
。然后从滤镜中应用colourise,你将能够看到什么C代码生成什么汇编代码,得到如下图的东西
sll $t0, $s0, 2 # $t0 = f * 4
add $t0, $s6, $t0
sll $t1, $s1, 2 # $t1 = g * 4
add $t1, $s7, $t1
lw $s0, 0($t0)
lw $t0, 4($t0)
add $t0, $t0, $s0
sw $t0, 0($t1)
是的,代码缺少这两行,您只需要将 f
和 g
都缩放 4。
我试图解决这个问题并将其转换为 MIPS 汇编代码 但是书中的答案令人困惑 me.so,谁能解释一下这段代码是如何在 c 中得到这个结果的?
B[g] = A[f] + A[f+1];
我已经插入了我认为正确的评论,如果我错了请纠正我。
Assume we have variables f, g, h, i, j stored in $s0, $s1, $s2, $s3 and $s4, respectively. Assume the base addresses of arrays A and B are at $s6 and $s7.
代码:
add $t0, $s6, $s0 #This will add f bytes to the base address and it's not equal to A[f].
add $t1, $s7, $s1 #This will add g bytes to the base address and it's not equal to B[g]
lw $s0, 0($t0) #This will point to the value in (f +base address of A +0) bytes
lw $t0, 4($t0) #This will point to the value in (f +base address of A +4) bytes
add $t0, $t0, $s0
sw $t0, 0($t1)
add $t0, $s6, $s0 # t0 = A + f
add $t1, $s7, $s1 # t1 = B + g
lw $s0, 0($t0) # s0 = *(t0 + 0) = *(A + f) = A[f]
lw $t0, 4($t0) # t0 = *(t0 + 4) = *(A + f + 1) = A[f+1]
add $t0, $t0, $s0 # t0 = t0 + s0 = A[f] + A[f+1]
sw $t0, 0($t1) # *(t1 + 0) = *(B + g) = B[g] = t0
请记住,C 指针算法按项目大小缩放,但汇编使用字节。因此,前进 4 个字节在 C 中前进 1 项。
转念一想,这实际上意味着 f
和 g
也应该按 4 缩放,但它们似乎不是。
我注释的你的编译片段:
add $t0, $s6, $s0
将寄存器 s6
和 s0
中的内容添加并存储在寄存器 t0
中。由于您已经指出 f
存储在 s0
中,而 A
的基地址存储在 s6
中,因此添加地址以准备稍后的寄存器间接加载在。在 C 中更简单的 A[f] == *(A + f)
,这是为稍后的 (A + f)
取消引用做准备。
add $t1, $s7, $s1
B
和 g
也发生了同样的事情。添加它们的内容并将它们存储在中间寄存器中,稍后用作基于地址的取消引用目标。
lw $s0, 0($t0)
这是加载到 s0
寄存器,使用所谓的 cpu 的 register-indirect
寻址模式,无论 t0
指向的地址是什么加上 0 个字节。在 c 中,这等于 s0 = *(A + f)
.
lw $t0, 4($t0)
和上面一样,只是这次它加载到寄存器t0
任何指向t0
的东西加上4个字节。等于Ct0 = *(A + f + 1)
.
add $t0, $t0, $s0
这是它在您的代码中执行加法的地方。等于A[f] + A[f + 1]
.
sw $t0, 0($t1)
这是在t1
所指向的地址中存放上次相加的结果。
~~~~~~~~~~~
如果您正在寻找您所拥有的代码的一些参考资料,我找到了这两个 MIPS instruction set reference useful and, of course, Matt Godbolt's interactive compiler。
如果您想查看哪些代码使用交互式编译器执行哪些操作,只需将您的代码包装在 void
函数中,select 作为编译器 x86 clang
并在编译器选项中--target=mips
。然后从滤镜中应用colourise,你将能够看到什么C代码生成什么汇编代码,得到如下图的东西
sll $t0, $s0, 2 # $t0 = f * 4
add $t0, $s6, $t0
sll $t1, $s1, 2 # $t1 = g * 4
add $t1, $s7, $t1
lw $s0, 0($t0)
lw $t0, 4($t0)
add $t0, $t0, $s0
sw $t0, 0($t1)
是的,代码缺少这两行,您只需要将 f
和 g
都缩放 4。