SPARC Assembly - Printing an integer value and Loading 64 bit value into register

Tags: sparc, assembly lang

[draft article]

Introduction

Printing the value

The primary problem we try to solve here is not printing an integer value but loading a value into the register. From our intro article we already know how to print/display a string using sparc assembly language program. We used the format string with printf which included %s. Moreover, from our article on Parameter Passing we know how to pass parameters and get return values from subroutines.

s0:     .asciz  "foo %s\n"

This allowed us printing a string. Now, to print a 64 bit value we will use as format specifier %lld.

 s0:     .asciz  "foo %lld\n"

As we recall, second argument of printf (for the string printing program) was passed using register %O1 and the first argument was passed using %O0. Therefore to print an integer by passing it to printf using a format specifier string we need to pass this using the second register %O1 just like before. So we need to figure out how to put/load that value into register %O1.

Loading a value into register - Intro

To load a value into a register sparc does not have native mov instructions like x86. Instead we use the or or add (check sparc v9 doc) instruction. From the article, SPARC Registers we know that the global variable G0 is hardwired zero. Therefore an instruction like this easily loads a value into the register,

or %g0, 1, %l1

The or instruction does an or between 0 and 1 and loads into first local register. An add instruction would serve the same purpose.

add %g0, 1, %l1

Loading 64 bit value into the register

We load the 64 bit value in 3 steps. First, we load a 32 bit value (higher 32 bit parts of the value) into the register. Then, shift this value 32 bits (lower 32 bit parts of the value). Afterwards, we load 32 bit value. Finally, we add those two which gives us the final 64 bit value into the register.

Loading a 32 bit value into register

Let's say, we want to load 4097 = 2^12+1 into the register.

  • 1 can be loaded into the register using a simple or or add instruction.
  • 2^12 can be loaded into the register using the sethi instruction.

As we know, sethi instruction sets bits starting from 11th bit upto 32nd bit. The number 2^12 has 13th bit set to 1 and others to 0. Therefore, to make it 2^12 we need to set 13-10 = 3 3rd bit starting from 11tbit.

  • first bit - 11th bit
  • second bit - 12th bit
  • third bit - 13th bit

The binary representation for this value is: 0b0100. Hex representation is: 0x4 Following two instructions enable us to load the value 4097 into a register,

sethi   0x4, %o1
or      %o1, 0x1, %o1

If you try our example program with above two instructions we will get,

$ ./p64_07_load_32bit_value
Loaded value 4097

On powershell we get,

[math]::pow(2,12)+1
4097

The values match.

Shifting Higher Part

Now let's say we want to load the same value but on the higher 32 bit part of the register. For the same value, 4097 on the higher part does this: it sets 44th bit of the 64bit register to 1 and 32nd register to 1. Which is equivalent to, 2^44 + 2^32 = 17596481011712

We need to shift the loaded value 32 bits to make room for the lower 32 bit part. We use sllx instruction to do the shifting.

sethi   0x4, %o1
or      %o1, 0x1, %o1
sllx    %o1, 32, %o1

This does following: it sets 44th bit of the 64bit register to 1 and 32nd register to 1.

If you try our example program with above three instructions we get,

$ ./p64_08_load_64bit_shift
Loaded value 17596481011712

To verify, we run following on powershell,

$ [math]::pow(2,44)+[math]::pow(2,32)
17596481011712

Which validates that our program is correct so far.

Loading HI 32 bit and LO 32 bit (actually 64 bit)

If we are able to load the HI part of the value on higher part of the register and LO part of the value into lower part of the register: say for easy illustration hi 32 bits and low 32 bits we are done. In previous section we have seen demonstration of loading HI part. Can we just add the instructions for loading the LO part?

What about the example instructions below,

sethi   0x4, %o1
or      %o1, 0x1, %o1
sllx    %o1, 32, %o1
sethi   0x4, %o1
or      %o1, 0x1, %o1

Do you think this would work? No. Becacuse the second sethi will set the left 32 bits to 0. As a result, we will be lefft with the value 4097 and HI part will be set to 0. For this reason, this is what we see,

$ ./p64_08_load_64bit_value_fail
Loaded value 4097

Therefore, we are gonna need another temporary register to hold the value before sethi sets the high part to 0. We are gonna use the first local register %l0 as the temporary register. Then the implementation looks like following,

sethi   0x4, %l0
or      %l0, 0x1, %l0
sllx    %l0, 32, %l0
sethi   0x4, %o1
or      %o1, 0x1, %o1
or      %l0, %o1, %o1

Entire example program is illustrated below,

 .data
s0:     .asciz  "Loaded value %lld\n"
  .text
  .global main
  .align 4
  .type main, #function

main:
  save    %sp, -0xc0, %sp
  call    print_large_val
  nop
  ret
  restore

print_large_val:
  save    %sp, -0xc0, %sp
  setx    s0, %l4, %o0      ! for illustration (not complicating) we are not replacing setx
  sethi   0x4, %l0
  or      %l0, 0x1, %l0
  sllx    %l0, 32, %l0
  sethi   0x4, %o1
  or      %o1, 0x1, %o1
  or      %l0, %o1, %o1
  call    printf
  nop
  ret
  restore

Compiling and running the output binary we see,

$ suncc -m64 -s p64_08_load_64bit_value.S -o p64_08_load_64bit_value
$ ./p64_08_load_64bit_value
Loaded value 17596481015809

On powershell, we verify this,

$ [math]::pow(2,44)+[math]::pow(2,32)+[math]::pow(2,12)+1
17596481015809

setx instruction

Finally, if we look at the synthetic setx instruction we will see it is performing exactly the same thing.

  1. Loading the HI part of the value into the register
  2. shifting that 32 bits to make room for low HI bits
  3. Loading the LO 32 bits into the register
  4. Finally, adding them and put into the destination register

Reference

  1. Logical Operators: AND, NAND, OR, NOR, XOR, XNOR - Section A.31 page# 208
  2. sparc synthetic mov and setex instruction - sparc v9 ref table#37, page# 321
  3. SETHI sparc v9 ref - Section# A.48 page# 248
  4. A.49 shift instructions including slx page# 248
  5. Section 8.5.1 - LOading 32-bit Constants of SPARC Architecture, Assembly Language Programming, and C (2nd Edition)

No Comments

Add a Comment

Comments