我目前正在研究一个简单的SPARC汇编代码,它可以计算5的阶乘。 我想知道为什么我使用的全局寄存器通过函数调用不一致。
使用传统版本使用本地寄存器和输出/输入参数(进入%o0),我没有问题,代码工作正常,
但是当我想使用另一个带有全局寄存器的版本时,我遇到了这个一致性问题。
以下是代码:
.data
.LLC0: .asciz "fact(5) = %d\n"
.text
.global main
main:
save %sp, -96, %sp
set 5, %g1 ! value 5 into %g1 register
sethi %hi(.LLC0), %g2
or %g2, %lo(.LLC0), %o0
mov %g1, %o1
call printf
nop
mov %g1, %o0 ! set %g1 into parameter for fact function
call fact
nop
mov %o0, %g4
sethi %hi(.LLC0), %g3
or %g3, %lo(.LLC0), %o0
mov %g4, %o1
call printf
nop
ret
fact:
addcc %g1, -1, %g1 ! current index of the procedure -
! supposed to be decremented at each call -
be term ! PROBLEM : %g1 always set to 0 before decrement
nop
sethi %hi(.LLC0), %g2
or %g2, %lo(.LLC0), %o0
mov %g1, %o1
call printf ! printf the value of %g1 :
! still equal to -1 at execution
nop
call fact
nop
mov %o0, %g2
umul %g2, %g1, %g2
mov %g2, %i0
ret
term: set 1, %o0
ret
我的问题是,在fact
函数中,每次调用时全局注册%g1
都设置为0
,因此%g1
的打印始终为{{} 1}}执行时。
从这个link开始,我认为全局寄存器在函数调用中是持久的,即它们的范围是全局的并且由代码中的任何函数共享。
例如,在这里,我将-1
放在主要部分中,通常情况下,set 5, %g1
函数中的打印值应为4
。
如果有人能看出什么错了?
由于
更新:
调用printf使用%o0和%o1,而不是%g1。我仍然有全局寄存器范围的问题(%g5-g7)。以下是使用它们的示例:
fact
在此代码中,我在每次递归调用时打印.data
.LLC0: .asciz "fact(5) = %d\n"
.text
.global main
main:
save %sp, -120, %sp
set 5, %g5
sethi %hi(.LLC0), %g2
or %g2, %lo(.LLC0), %o0
mov %g5, %o1
call printf
nop
mov %g5, %o0
call fact
nop
mov %o0, %g7
sethi %hi(.LLC0), %g3
or %g3, %lo(.LLC0), %o0
mov %g7, %o1
call printf
nop
ret
restore
fact:
addcc %g5, -1, %g5
be term
nop
sethi %hi(.LLC0), %g2
or %g2, %lo(.LLC0), %o0
mov %g5, %o1
call printf
nop
call fact
nop
mov %o0, %g6
smul %g6, %g5, %g6
mov %g6, %o0
ret
term: set 1, %o0
ret
的值,输出为:
global %g5 register
似乎是来自main make的第一个事实调用失去了fact(5) = 5
fact(5) = 838860799
fact(5) = 838860798
fact(5) = 838860797
fact(5) = 838860796
fact(5) = 838860795
fact(5) = 838860794
fact(5) = 838860793
fact(5) = 838860792
fact(5) = 838860791
fact(5) = 838860790
...
的初始值(初始化为%g5
)
我的错误在哪里?
由于
答案 0 :(得分:1)
来自SPARC汇编语言参考手册(https://docs.oracle.com/cd/E26502_01/html/E28387/toc.html)
6.2注册用法
全局寄存器%g0-%g7更复杂。 %g0寄存器始终为零。 %g6和%g7始终为操作系统保留,因此汇编代码不应修改它们。其他全局寄存器%g1-%g5是调用者保存,可供应用程序代码使用。但请注意,%g1和%g5可用于程序链接表(PLT)或其他插入代码,因此不能用于将参数从调用者传递给被调用者。
(我的重点)
我认为你的问题是"在整个功能调用中保持一致"表示调用和返回指令(等)不会影响寄存器(带寄存器窗口移位),但调用约定确实允许被调用者更改寄存器,因此内容可能无法存活一个电话。
答案 1 :(得分:0)
%g1 - %g4 are volatile
- 您对printf
的调用会覆盖您之前添加到%g1
的值,因为printf
的实现也会使用它。