Sparc程序集 - 全局寄存器在函数调用期间不一致

时间:2014-12-22 07:25:29

标签: assembly cpu-registers sparc

我目前正在研究一个简单的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

我的错误在哪里?

由于

2 个答案:

答案 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的实现也会使用它。