Sparc assembly - Global registers not consistent throughout functions call

280 views Asked by At

I am currently working on a simple SPARC assembly code which computes the factorial of 5. I would like to know why the global registers that I used are not consistent througout function calls.

With the traditionnal version using of local registers and the output/input parameters (into %o0), I have no problem, the code works fine,

but when I want to use another version with global registers, I have this issue of consistency.

Here's the code :

.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

My problem is that, into fact function, the global register %g1 is set to 0 at each call, so that the print of %g1 gives always -1 at execution.

From this link, I thought that global registers were persistent throughout functions call, i.e their scope were global and shared by any function in the code.

For example, here, I put set 5, %g1 in main section and normally, I should get 4 for the printed value in fact function.

If anyone could see what's wrong ?

Thanks

UPDATE:

call printf uses %o0 and %o1, not %g1. I still have problems with the scope of global registers (%g5-g7). Here is an example using them like this :

.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

In this code, I print the value of global %g5 register at each recursive call and the output is :

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
...

seems like the first call of fact from main make lose the initial value for %g5 (initialized to 5)

Where is my error ?

Thanks

2

There are 2 answers

0
drRobertz On BEST ANSWER

From the SPARC Assembly Language Reference Manual (https://docs.oracle.com/cd/E26502_01/html/E28387/toc.html)

6.2 Register Usage

The global registers %g0-%g7 are more complicated. The %g0 register is always zero. The %g6 and %g7 are always reserved for the operating system, so assembly code should not modify them. The other global registers, %g1-%g5, are caller saves, and are usable by applications code. But note that %g1 and %g5 may be used in the program linkage table (PLT) or other interposition code, and thus cannot be used to pass parameters from caller to callee.

(my emphasis)

I think your problem is that "Consistent throughout functions call" means that the call and return instructions (et al) do not affect the registers (with register window shifting) but that the calling convention does allow the callee to alter the registers, and hence the contents may not survive a call.

0
mirabilos On

%g1 - %g4 are volatile – your call to printf overrides the value you put into %g1 earlier, because printf’s implementation also uses it.