c - MIPS:在函数调用和返回中将 C 代码转换为 MIPS 问题
问题描述
我需要将 C 代码从下面更改为 MIPS 代码,但我是 MIPS 的新手并坚持使用它。
这是C代码:
int main()
{
int a, b, result;
if(a == b)
result = a*b;
else
result = assess(a, b);
return result;
}
int assess(int a, int b)
{
if(b<a)
return upgrade(a, b);
else
return demote(a, b);
}
int upgrade(int a, int b)
{
return 4*(a+b);
}
int demote(int a, int b)
{
return 4*(b-a);
}
这是我编写的 MIPS 代码,它不起作用(我知道存在重大错误和错误)。因为我对语言不熟悉,所以我的主要问题是使用堆栈、返回和调用函数。
.data
a:.word 8
b:.word 8
result:.word 0
main:
li $s0 a
li $s1 b
li $s3 result
beq $s0,$s1,Resultmul ELSE
add $s3,$s3,assess
assess:
blt $s1,$s0,upgrade
bge $s1,$0,demote
Resultmul :
mul $s3,$s1,$0
upgrade:
addi $sp,$sp,-4
sw $0,0($sp)
add $t1,$a0,$a1
mul $t1,$t1,4
add $v0,$s0,$zero
lw $s0,0($sp)
addi $sp,$sp,4
jr $ra
demote:
addi $sp,$sp,-4
sw $0,0($sp)
sub $t1,$a0,$a1
mul $t1,$t1,4
add $v0,$s0,$zero
lw $s0,0($sp)
addi $sp,$sp,4
jr $ra
如果有人可以提供帮助,那将是救命稻草。
解决方案
我不会给你完整的解决方案,所以你可以从练习中学习,但我建议你使用模板,例如在这个模板中。
我使用了 Visual Studio Code(具有 MIPS 支持和更好的 MIPS 支持突出显示),其中每个空格或选项卡都让我有可能通过这些空格折叠它,而 QtSpim 我能够在其上运行它并获得输出64
。
另外,我习惯于使用标签进行编码;这对我来说更清楚,但对你来说可能不是,所以如果你必须删除所有标签和评论,我很抱歉。
######################## pseudo ####################################
#
# int main()
# {
# int a, b, result;
# if(a == b)
# result = a*b;
# else
# result = assess(a, b);
# return result;
# }
#
# int assess(int a, int b)
# {
# if(b<a)
# return upgrade(a, b);
# else
# return demote(a, b);
# }
#
# int upgrade(int a, int b)
# {
# return 4*(a+b);
# }
#
# int demote(int a, int b)
# {
# return 4*(b-a);
# }
#
###################### DATA Segment ################################
.data
A:
.word 8
B:
.word 8
result:
.word 0
###################### CODE Segment ################################
.text
.globl main
main:
在这里你犯了一个小错误:你已经存储了单词,所以你也应该加载单词。否则,您必须输入li $t0, 8
.
# int A = A, B = B, result
lw $s0, A # $s0 = A
lw $s1, B # $s1 = B
lw $s2, result # $s2 = result
# if (a == b)
bne $s0, $s1, noteq # if $s0 != $s1 then noteq
# result = multiply(a,b);
move $a0, $s0 # $a0 = $s0
move $a1, $s1 # $a1 = $s1
jal multiply # jump to multiply and save position to $ra
sw $v0, result #
b end # branch to end
# else
noteq:
# result = assess(a,b);
move $a0, $s0 # $a0 = $s0
move $a1, $s1 # $a1 = $s1
# jal assess # jump to assess and save position to $ra
sw $v0, result #
b end # branch to end (this rule can be left out)
end:
# printf("%i", result)
li $v0, 1 # $v0 = 1
lw $a0, result #
syscall
# exit()
li $v0, 10 # $v0 = 10
syscall
由于它们是伪代码中的函数,因此它们也应该被视为程序集中的函数。这意味着它们被调用j
(对于非返回函数,如退出)或jal
(并返回jr
)。
我制作了一个完全不必要的函数multiply
来向您展示模板,这对于较大的函数非常方便。
###################### FUNC Segment ################################
###################### FUNCTION ####################################
# multiply(A, B)
#
# Purpose: <General description>
######################## i/0 #######################################
# Input:
# $a0 = A
# $a1 = B
# Output:
# $v0 = value
# Registers being used:
# $s0 = A
# $s1 = B
# $s2 = value
######################## pseudo ####################################
#
# int multiply(int A, int B)
# {
# return A * B;
# }
#
######################## <code> ####################################
multiply:#(A, B)
始终存储您要覆盖的寄存器的内容,这样您就可以调用其他函数而不会丢失任何内容。还要立即初始化存储在$a0-$a3
新寄存器中的参数,因为在使用syscall
.
存储变量有两个主要原因:
- 函数调用想在不知不觉中更改您的一个
$s0-$s7
寄存器。 - 可以在当前函数内调用其他函数,并使用它们自己的堆栈处理,因此无需担心寄存器。
assess
在制作-function之前知道可能会很有趣。
函数参数的初始化如下所示:
# store(&return, parameters that are about overwritten)
sub $sp, $sp, 16 # $sp = $sp - 16
sw $ra, 0($sp) #
sw $s0, 4($sp) #
sw $s1, 8($sp) #
sw $s2, 12($sp) #
# int A = A, B = B, value
move $s0, $a0 # $s0 = $a0
move $s1, $a1 # $s1 = $a1
这是函数的非常短的主体。如您所知,存储所有这些参数是愚蠢的,所以不要使用这些开销函数。
# value = A * B;
mul $s2, $s0, $s1
这是处理函数的返回。在较大的函数中,您大部分时间都需要一个标签来跳转到返回处理。foo
我总是在像这样的函数中调用标签foo_thisLabel
,但这只是我的建议。
move $v0, $s2 # $v0 = $s2
# restore()
lw $ra, 0($sp) #
lw $s0, 4($sp) #
lw $s1, 8($sp) #
lw $s2, 12($sp) #
addi $sp, $sp, 12 # $sp = $sp + 12
# return index
jr $ra # jump to $ra
######################## </code> ###################################
请注意,我只等待函数的返回段移入value
返回寄存器,$v0
.
这是其他功能的空模板。
###################### FUNCTION ####################################
# <name of function>
#
# Purpose: <General description>
######################## i/0 #######################################
# Input:
# $a0 =
# $a1 =
# $a2 =
# $a3 =
# Output:
# $v0 =
# Registers being used:
# $t0 =
# $t1 =
# $t2 =
# $s0 =
# $s1 =
# $s2 =
# $s3 =
# $s4 =
######################## pseudo ####################################
#
# int assess(int a, int b)
# {
# if(b<a)
# return upgrade(a, b);
# else
# return demote(a, b);
# }
#
######################## <code> ####################################
#
######################## </code> ###################################
PS我已经重命名了你的变量名,因为b
可能会导致错误。
推荐阅读
- reactjs - Antd库:尝试渲染图像时如何处理?
- r - 输出对象的类别因输入数据不同而不同
- css - Bootstrap CSS - 关于调整大小的第 2 列下的第 3 列
- php - 为 Codeigniter 4 创建作曲家包
- dynamics-crm - Business Central 夫妇未同步 CRM 帐户 - Business Central 客户
- flutter - 在 Flutter 上的 TextField 上键入时滚动到顶部
- javascript - 想要为显示的日期列表添加删除功能
- c++ - 在 C++ 中使用 FFmpeg 覆盖视频帧
- android - Java.lang.IllegalStateException:应为 BEGIN_OBJECT,但在要将数据获取到 recyclerview 时为 BEGIN_ARRAY
- react-native - 反应本机 Webview 进程终止