将 C 数组操作转换为汇编
Converting C array operations to Assembly
我正在努力尝试将 a[i+1] = a[i-1] + b[4]
转换为程序集。其中$s0
是a
的地址,$s1
是b
的地址,$s2
是变量i
。教授提到它可以分 6 个步骤完成。
我有:
addi $t0, $s2, 4 #i + 1
addi $t1, $s2, -4 #i - 1
lw $t2, $t1($s0) #load a[i-1] - I know this is wrong
lw $t3, 16($s1) #load b[4]
add $t4, $t2, $t3 #add a[i-1] + b[4]
sw $t4, $t0($s0) #save to a[i+1] - I know this is wrong
我知道错误的地方,我知道我不能立即使用寄存器,但我不确定如何解决这个问题。我也可能完全错了,感谢您的帮助。
temp0 = $s0 + $s2
temp2 = load -4(temp0)
temp3 = load 16($s1)
temp1 = temp2 + temp3
store +4(temp0) = temp1
下面是一些我认为可行的注释代码:
.text
.globl main
# main -- main program
#
# a[i + 1] = a[i - 1] + b[4]
#
# arguments:
# s0 -- address of a
# s1 -- address of b
# s2 -- i
#
# registers:
# t0 -- address of a[i]
# t1 -- value of b[4]
# t2 -- i << 2 (i.e. a byte offset)
# t3 -- value of a[i - 1]
# t4 -- a[i - 1] + b[4]
main:
sll $t2,$s2,2 # get i << 2
add $t0,$s0,$t2 # get &a[i]
lw $t3,-4($t0) # get a[i - 1]
lw $t1,16($s1) # get b[4]
add $t4,$t3,$t1 # sum them
sw $t4,4($t0) # a[i + 1] = sum
这非常接近仅可以使用的序列。 lw
指令的顺序可以翻转,但除此之外,指令 必须 是显示的顺序,除非使用不同的寄存器来保存不同的值。
对于清晰度,每个中间体term/step都有自己的t
寄存器。但是,如果 reassign/reuse 寄存器,我们可以减少使用的寄存器数量。例如,在前两条指令中,我们可以将 $t2
替换为 $t0
,因为在那之后我们不再使用 $t2
。
优化编译器could/would 可以做到这一点。我们最终只需要 $t0-$t2
而不是 $t0-$t4
:
.text
.globl main
# main -- main program
#
# a[i + 1] = a[i - 1] + b[4]
#
# arguments:
# s0 -- address of a
# s1 -- address of b
# s2 -- i
#
# registers:
# t0 -- i << 2
# address of a[i]
# t1 -- value of b[4]
# t2 -- value of a[i - 1]
# sum of a[i - 1] + b[4]
main:
sll $t0,$s2,2 # get i << 2
add $t0,$s0,$t0 # get &a[i]
lw $t2,-4($t0) # get a[i - 1]
lw $t1,16($s1) # get b[4]
add $t2,$t2,$t1 # sum them
sw $t2,4($t0) # a[i + 1] = sum
如果代码是函数的一部分,我们可以使用 $v0, $v1, $a0
作为我们的临时寄存器,因为如果函数愿意,允许使用 $v0-$v1
和 $a0-$a3
作为内部临时寄存器.
更新:
The comments definitely help me understand what is occurring during each instruction
良好的编程风格[因此理解]有很多评论。正确的类型。这对于 asm 特别 很重要,因为在 C 中,像 number_of_users
这样的变量有点描述性。但是,$t0
不是。
我添加的注释是我为自己编写的任何 asm 代码所做的。而且,我已经写了 asm 几十年了。
此外,"optimized" 版本还有一个目的:简化。通过释放 $t3-$t4
,它们可以用来容纳其他东西。在一个更复杂的函数中,这可以区分一个简单易懂的函数,以及一个不必要的复杂函数,它更难理解和维护。
有关这方面的更多信息,以及如何根据我自己的经验编写好 asm 的技巧,请参阅我的回答:
the professor is not the greatest at relaying information
在课堂环境中只能传达这么多。它可以涵盖基础知识。而且,课程作业可以帮助您学习给定语言的基础知识。而且,IMO,教授们从来都不擅长很好地注释代码 [够了 ;-)]。
当我 [在不同的体系结构上] 学习 asm 时,除了课程作业,我还能够作为付费程序员从事 100% 用 asm 编写的多用户分时 OS。它的评论风格与上述相同。
IMO,最好的学习方法之一是分析 "expert" 代码。问问题:"Why did they do that in that way?"。这就是我所做的,我学到了很多东西。直到今天,我[仍然]相信那次经历。
我正在努力尝试将 a[i+1] = a[i-1] + b[4]
转换为程序集。其中$s0
是a
的地址,$s1
是b
的地址,$s2
是变量i
。教授提到它可以分 6 个步骤完成。
我有:
addi $t0, $s2, 4 #i + 1
addi $t1, $s2, -4 #i - 1
lw $t2, $t1($s0) #load a[i-1] - I know this is wrong
lw $t3, 16($s1) #load b[4]
add $t4, $t2, $t3 #add a[i-1] + b[4]
sw $t4, $t0($s0) #save to a[i+1] - I know this is wrong
我知道错误的地方,我知道我不能立即使用寄存器,但我不确定如何解决这个问题。我也可能完全错了,感谢您的帮助。
temp0 = $s0 + $s2
temp2 = load -4(temp0)
temp3 = load 16($s1)
temp1 = temp2 + temp3
store +4(temp0) = temp1
下面是一些我认为可行的注释代码:
.text
.globl main
# main -- main program
#
# a[i + 1] = a[i - 1] + b[4]
#
# arguments:
# s0 -- address of a
# s1 -- address of b
# s2 -- i
#
# registers:
# t0 -- address of a[i]
# t1 -- value of b[4]
# t2 -- i << 2 (i.e. a byte offset)
# t3 -- value of a[i - 1]
# t4 -- a[i - 1] + b[4]
main:
sll $t2,$s2,2 # get i << 2
add $t0,$s0,$t2 # get &a[i]
lw $t3,-4($t0) # get a[i - 1]
lw $t1,16($s1) # get b[4]
add $t4,$t3,$t1 # sum them
sw $t4,4($t0) # a[i + 1] = sum
这非常接近仅可以使用的序列。 lw
指令的顺序可以翻转,但除此之外,指令 必须 是显示的顺序,除非使用不同的寄存器来保存不同的值。
对于清晰度,每个中间体term/step都有自己的t
寄存器。但是,如果 reassign/reuse 寄存器,我们可以减少使用的寄存器数量。例如,在前两条指令中,我们可以将 $t2
替换为 $t0
,因为在那之后我们不再使用 $t2
。
优化编译器could/would 可以做到这一点。我们最终只需要 $t0-$t2
而不是 $t0-$t4
:
.text
.globl main
# main -- main program
#
# a[i + 1] = a[i - 1] + b[4]
#
# arguments:
# s0 -- address of a
# s1 -- address of b
# s2 -- i
#
# registers:
# t0 -- i << 2
# address of a[i]
# t1 -- value of b[4]
# t2 -- value of a[i - 1]
# sum of a[i - 1] + b[4]
main:
sll $t0,$s2,2 # get i << 2
add $t0,$s0,$t0 # get &a[i]
lw $t2,-4($t0) # get a[i - 1]
lw $t1,16($s1) # get b[4]
add $t2,$t2,$t1 # sum them
sw $t2,4($t0) # a[i + 1] = sum
如果代码是函数的一部分,我们可以使用 $v0, $v1, $a0
作为我们的临时寄存器,因为如果函数愿意,允许使用 $v0-$v1
和 $a0-$a3
作为内部临时寄存器.
更新:
The comments definitely help me understand what is occurring during each instruction
良好的编程风格[因此理解]有很多评论。正确的类型。这对于 asm 特别 很重要,因为在 C 中,像 number_of_users
这样的变量有点描述性。但是,$t0
不是。
我添加的注释是我为自己编写的任何 asm 代码所做的。而且,我已经写了 asm 几十年了。
此外,"optimized" 版本还有一个目的:简化。通过释放 $t3-$t4
,它们可以用来容纳其他东西。在一个更复杂的函数中,这可以区分一个简单易懂的函数,以及一个不必要的复杂函数,它更难理解和维护。
有关这方面的更多信息,以及如何根据我自己的经验编写好 asm 的技巧,请参阅我的回答:
the professor is not the greatest at relaying information
在课堂环境中只能传达这么多。它可以涵盖基础知识。而且,课程作业可以帮助您学习给定语言的基础知识。而且,IMO,教授们从来都不擅长很好地注释代码 [够了 ;-)]。
当我 [在不同的体系结构上] 学习 asm 时,除了课程作业,我还能够作为付费程序员从事 100% 用 asm 编写的多用户分时 OS。它的评论风格与上述相同。
IMO,最好的学习方法之一是分析 "expert" 代码。问问题:"Why did they do that in that way?"。这就是我所做的,我学到了很多东西。直到今天,我[仍然]相信那次经历。