如何在程序集循环后转移控制权?
How do I transfer control after a loop in assembly?
我想将下面的 C 代码翻译成汇编语言。
但是,我没有看到我需要在这个例子中使用堆栈。
此外,我想知道 "beq" 是否像 "jal" 那样在 $ra 中保存了以下指令的地址,因为当循环结束时,我想得到回到原来的函数foo,继续指令(这里只是返回)
int foo(int* a, int N) {
if(N > 0)
{
for(int i = 0; i != N; i = i + 1)
{
a[i] = bar(i << 4, a[i]);
}
}
return N & 7;
}
#assume *a in $a0, N $N in $a1
foo:
slt $t0, $zero, $a1 #put 1 in $t0 if 0 < N
li $t1,0 # use $t1 as loop counter
beq $t0, 1, loop # enter loop if 0 < N
and $v0, $a1, 7 # do bitwise and on N and 7 and save in $v0 as return value
loop:
beq $t1, $a1, exit # exit loop when i = N
sll $t3, $t1, 2 # obtain 4 * i
add $t3, $a1, $t3 # obtain address of a[i] which is address of a plus 4i
lw $t3, o($t3) # load a[i] into $t3
sll $t4, $t1, 4 #perform i<< 4 and save in $t4
# the 2 previous load arguments for bar
jal bar # assume bar saves return value in $v2
sw $t3, 0($v1)
j loop
exit:
and $v0, $a1, 7
beq
用于条件分支,而不是调用——它更改 PC
(有条件地)但不更改 $ra
。我们用它来将结构化语句(例如 if、for)翻译成汇编语言的 if-goto 风格。
However, I do not see that I need to use the stack in this example.
你 必须 为这段代码使用堆栈,因为对 bar
的调用(如 jal bar
) 将消灭 foo
s $ra
,而 bar
将能够 return 回到 foo
, foo
将无法 return 给它的调用者。由于这需要一个堆栈,因此您需要 prologue and epilogue 来分配和释放一些堆栈 space。
您的代码没有正确地向 bar
、i << 4
传递参数,例如,应该在 $a0
中传递参数,而 a[i
] 应该在 $a1
.
您在 foo
中没有 return 指令 — 它缺少 jr $ra
。
如果您的任何一个 beq
指令确实设置了 $ra
,这些将不会对 return 返回有用的点。 但是既然你问了:
I'd like to know whether or not "beq" saves the address of the following instruction in $ra like "jal" does
如果指令助记符不是以al
结尾(表示AndLink),则不会在$ra
中保存一个return地址。
Classic MIPS 有以下指令 link,来自这个 somewhat incomplete reference(缺少 nor
和 IDK 还有什么)。
jal target
(跳转Link)
BGEZAL $reg, target
(条件分支 if >= 0 And Link)
BLTZAL $reg, target
(条件分支 if < 0 And Link)
请注意,条件分支实际上是在寄存器的符号位上分支。
bal
是 bgezal $zero, target
的别名,可用于执行与 PC 相关的函数调用。 (MIPS 分支对分支位移使用完全相对编码,MIPS 跳转使用区域绝对编码替换 PC+4 的低 28 位。这对位置无关代码很重要)。
None 其中与您的情况特别相关;您的 foo
需要在 entry/before jr $ra
上 save/restore $ra
因为您需要使用 jal
或 [=18 调用 bar
=].使用 linking 分支作为循环分支不会有任何影响(除了使您的代码效率更低,并使使用特殊预测器进行 return-地址预测的真实 CPU 上的性能更差假设 jal
和 jr $ra
正确配对)。
使用 bal
/ jal
不会自动让你跳转到任何地方 return;只有当目标曾经使用 jr $ra
时才会发生(可能在将 $ra
复制到其他地方然后恢复它之后)。
我想将下面的 C 代码翻译成汇编语言。
但是,我没有看到我需要在这个例子中使用堆栈。
此外,我想知道 "beq" 是否像 "jal" 那样在 $ra 中保存了以下指令的地址,因为当循环结束时,我想得到回到原来的函数foo,继续指令(这里只是返回)
int foo(int* a, int N) {
if(N > 0)
{
for(int i = 0; i != N; i = i + 1)
{
a[i] = bar(i << 4, a[i]);
}
}
return N & 7;
}
#assume *a in $a0, N $N in $a1
foo:
slt $t0, $zero, $a1 #put 1 in $t0 if 0 < N
li $t1,0 # use $t1 as loop counter
beq $t0, 1, loop # enter loop if 0 < N
and $v0, $a1, 7 # do bitwise and on N and 7 and save in $v0 as return value
loop:
beq $t1, $a1, exit # exit loop when i = N
sll $t3, $t1, 2 # obtain 4 * i
add $t3, $a1, $t3 # obtain address of a[i] which is address of a plus 4i
lw $t3, o($t3) # load a[i] into $t3
sll $t4, $t1, 4 #perform i<< 4 and save in $t4
# the 2 previous load arguments for bar
jal bar # assume bar saves return value in $v2
sw $t3, 0($v1)
j loop
exit:
and $v0, $a1, 7
beq
用于条件分支,而不是调用——它更改 PC
(有条件地)但不更改 $ra
。我们用它来将结构化语句(例如 if、for)翻译成汇编语言的 if-goto 风格。
However, I do not see that I need to use the stack in this example.
你 必须 为这段代码使用堆栈,因为对 bar
的调用(如 jal bar
) 将消灭 foo
s $ra
,而 bar
将能够 return 回到 foo
, foo
将无法 return 给它的调用者。由于这需要一个堆栈,因此您需要 prologue and epilogue 来分配和释放一些堆栈 space。
您的代码没有正确地向 bar
、i << 4
传递参数,例如,应该在 $a0
中传递参数,而 a[i
] 应该在 $a1
.
您在 foo
中没有 return 指令 — 它缺少 jr $ra
。
如果您的任何一个 beq
指令确实设置了 $ra
,这些将不会对 return 返回有用的点。 但是既然你问了:
I'd like to know whether or not "beq" saves the address of the following instruction in $ra like "jal" does
如果指令助记符不是以al
结尾(表示AndLink),则不会在$ra
中保存一个return地址。
Classic MIPS 有以下指令 link,来自这个 somewhat incomplete reference(缺少 nor
和 IDK 还有什么)。
jal target
(跳转Link)BGEZAL $reg, target
(条件分支 if >= 0 And Link)BLTZAL $reg, target
(条件分支 if < 0 And Link)
请注意,条件分支实际上是在寄存器的符号位上分支。
bal
是 bgezal $zero, target
的别名,可用于执行与 PC 相关的函数调用。 (MIPS 分支对分支位移使用完全相对编码,MIPS 跳转使用区域绝对编码替换 PC+4 的低 28 位。这对位置无关代码很重要)。
None 其中与您的情况特别相关;您的 foo
需要在 entry/before jr $ra
上 save/restore $ra
因为您需要使用 jal
或 [=18 调用 bar
=].使用 linking 分支作为循环分支不会有任何影响(除了使您的代码效率更低,并使使用特殊预测器进行 return-地址预测的真实 CPU 上的性能更差假设 jal
和 jr $ra
正确配对)。
使用 bal
/ jal
不会自动让你跳转到任何地方 return;只有当目标曾经使用 jr $ra
时才会发生(可能在将 $ra
复制到其他地方然后恢复它之后)。