0

I'm learning OR1K assembly for a project I'm working on. clang and LLVM are used to provide front end and the back end for the compiler. I found this link and it is almost everything I need, however assembly I'm looking at has @hi and @lo symbols in it. I have intuitive understanding of these "instructions" do but it would be better to get official explanation of what they mean.

Below are the C and the corresponding assembly code that was generated for it. The assembly lines I'm talking about are almost at the bottom. Here is how they look

l.sw    0(r1), r11
l.movhi r3, hi(.L.str@hi)
l.jal   printf
l.ori   r3, r3, lo(.L.str@lo)

C code

#include <stdio.h>
#include <assert.h>

int sum(int a, int b) {
  return a + b;
}

int main(int argc, char** argv) {
  printf("Hello World! %d\n", sum(argc, 1));
  return 0;
}

Assembly Code

    .text
    .file   "hello_world.ll"
    .globl  _Z3sumii
    .align  4
    .type   _Z3sumii,@function
_Z3sumii:                               # @_Z3sumii
    .cfi_startproc
# BB#0:                                 # %entry
    l.sw    -4(r1), r2
.Ltmp0:
    .cfi_offset 2, -4
    l.addi  r2, r1, 0
.Ltmp1:
    .cfi_def_cfa_register 2
    l.addi  r1, r1, -12
    l.sw    -8(r2), r3
    l.sw    -12(r2), r4
    l.lwz   r3, -8(r2)
    l.add   r11, r3, r4
    l.addi  r1, r2, 0
    l.jr    r9
    l.lwz   r2, -4(r1)
.Ltmp2:
    .size   _Z3sumii, .Ltmp2-_Z3sumii
    .cfi_endproc

    .globl  main
    .align  4
    .type   main,@function
main:                                   # @main
    .cfi_startproc
# BB#0:                                 # %entry
    l.sw    -4(r1), r9
.Ltmp3:
    .cfi_offset 9, -4
    l.sw    -8(r1), r2
.Ltmp4:
    .cfi_offset 2, -8
    l.addi  r2, r1, 0
.Ltmp5:
    .cfi_def_cfa_register 2
    l.addi  r13, r1, -32
    l.srli  r13, r13, 3
    l.slli  r1, r13, 3
    l.movhi r5, 0
    l.sw    20(r1), r5
    l.sw    16(r1), r3
    l.sw    8(r1), r4
    l.lwz   r3, 16(r1)
    l.jal   _Z3sumii
    l.addi  r4, r0, 1
    l.sw    0(r1), r11
    l.movhi r3, hi(.L.str@hi)
    l.jal   printf
    l.ori   r3, r3, lo(.L.str@lo)
    l.movhi r11, 0
    l.addi  r1, r2, 0
    l.lwz   r9, -4(r1)
    l.jr    r9
    l.lwz   r2, -8(r1)
.Ltmp6:
    .size   main, .Ltmp6-main
    .cfi_endproc

    .type   .L.str,@object          # @.str
    .section    .rodata.str1.1,"aMS",@progbits,1
.L.str:
    .asciz  "Hello World! %d\n"
    .size   .L.str, 17

Any help is appreciated.

flashburn
  • 4,180
  • 7
  • 54
  • 109
  • Presumably documented in the manual of your assembler. The stock GNU binutils don't seem to support OR1K so I assume you got some patched version. – Jester Oct 05 '15 at 19:11
  • I probably should add that I'm using `clang/llvm` and not gcc – flashburn Oct 05 '15 at 19:12

1 Answers1

2

OpenRISC like many assembly languages can only use 16 bit immediate values. So to do a load it first loads the high 16 bits and then performs an or operation on the low 16 bits. In psuedo-C:

int32_t addr = &str;
register r3;
r3 = addr & 0xFFFF0000; /* load hi bits, note this is a 16 bit value */
r3 |= addr &0xFFFF; /* load the lo bits of addr, note again only a 16 bit value */

Then what on earth is going on with that printf call either side of the load of r3? Well, OpenRISC has a branch delay slot. So the call to printf happens after the or instruction.

dave
  • 4,812
  • 4
  • 25
  • 38