我有一个任务,在arm_32中编写int power(int n,int m)并在C程序中使用,函数应返回n^m
我这样编写了代码,但由于某种原因,它不起作用
@ Int power (int n, int m)
@ r0 r1 r2
.text
.align 2
.global power
power:
stmfd sp!, {fp, lr}
mov fp, sp
mov r3, #0 @ loop counter is 0
mov r4, r1 @ i moved n to register r 4
loop:
cmp r2,r3 @ if m==loop counter
beq end @ jump to end
mul r4, r1, r4 @ multiply
add r3,r3,#1 @ add 1 on counter
b loop @ jump to begining of loop
mov r0,r4 @ put the result in r0
end:
Mov sp, fp
Ldmfd sp!, {fp,pc}
在我的C程序中,它打印:
4 2 5 2
2 2
这是不正确的,任何有关这方面的帮助将是非常apriciated:D
2条答案
按热度按时间jmo0nnb31#
下面是你可以使用的正确的ARM汇编代码
请确保汇编并链接此更正后的代码,然后在C程序中使用它。计算n^m时,它应该会产生正确的结果
rvpgvaaj2#
正如其他人所指出的那样,
mov r0,r4
物理上位于循环之后,但它并不位于逻辑执行指令流中,因为指令流只是跳过该指令。物理上出现在无条件分支之间的任何指令(例如b loop
)和标签(例如end:
)几乎肯定是我们所说的死代码或不可访问的代码,因此没有任何用处!将该指令从紧接在
end:
标签之前移动到紧接在end:
标签之后。另一方面,当参数实际上分别传递到
r0
和r1
中的n
和m
时,该代码将r1
×r2
相乘。虽然一些ABI/调用约定使用不同的寄存器用于返回值而不是任何参数,但调用约定使用相同的寄存器用于函数返回值作为第一个参数并不罕见。MIPS和x64没有,而RISC V和ARM有。在某些情况下,两种方法中的一种比另一种更好;前一种风格提供了一种清晰度,即返回寄存器可立即用于函数中,而后一种风格允许更多的寄存器用于参数传递。
虽然
r0
在本例中有两种用法,一种是在函数入口处,另一种是在函数出口处,但这些不同的用法在这些端点上技术上并不冲突-只是您可能必须在返回时处理一些值,因为您已经使用r4
作为累加器并稍后复制到r0
。另外,不要使用
r4
-r9
,除非你保存和恢复它们,因为这将违反调用约定。我认为你应该能够使它的工作只使用4 scratch/参数寄存器。回想一下,参数寄存器,当它们保存值时,您可以修改它们,并且调用者不能抱怨这一点。(因此,如果临时寄存器不足,一种方法是递减到零,而不是递增以匹配;然而,在ARM 32中,存在几个其它暂存寄存器,例如,即r12;如有需要,请参阅参考资料。)顺便说一句,你的函数应该在没有堆栈框架的情况下也能正常工作,所以只有在你的任务/问题需要的时候才真正创建一个。