10

For fun I'm trying to create an assembly program for Sun Solaris on SPARC. I'm emulating the system with QEMU.

My test assembles fine, yet linking fails with "relocation error: R_SPARC_13". Googling that error did not help at all.

        .section        ".text"
        .global main
        .type   main,@function

        .align  16
main:
        mov     4,%g1                   ! 4 is SYS_write
        mov     1,%o0   ! 1 is stdout
        mov     test,%o1        ! pointer to buffer
        mov     6,%o2   ! length
        ta      8

        mov     1,%g1                   ! 1 is SYS_exit
        clr     %o0                     ! return status is 0
        ta      8

test:   .asciz "hallo\n"

I assembled it with:

as test.s
ld a.out -o test

which gives:

ld: fatal: relocation error: R_SPARC_13:
ld: fatal:  file a.out: 
ld: fatal:  symbol <unknown>: 
ld: fatal:  value 0x103b0 does not fit

Any ideas?

EDIT: found that "mov test,%o1" should be "set test,%o1". Because set handles the large pointer value. But I don't understand why then e.g.

        JMP bla
        nop
    bla:
        ...

also still gives that R_SPARC_13 error.

2 Answers 2

20

SPARC instructions are 32-bit in size, so you cannot load a 32-bit pointer as an immediate in one instruction. This is typical of any RISC architecture. The alternatives are to split the immediate value across multiple instructions and logical-OR them, or load indirectly from memory.

The smallest change you can make to make it work as intended is to replace the mov with:

sethi %hi(test), %l0
or %l0, %lo(test), %o1

That will emit two relocation records in the object file, R_SPARC_HI22 and R_SPARC_LO10 which combine to cover an entire 32-bit pointer value, which are fixed-up by the linker.

Testing:

sparc-unknown-linux-gnu-as --32 -o test.o test.s
sparc-unknown-linux-gnu-ld -melf32_sparc -o test test.o
qemu-sparc -strace ./test

2701656 write(1,0x10084,6)hallo
 = 6
2701656 exit(0)
2
  • 1
    Strange that this doesn't generate a compile-time error.
    – PMF
    Apr 21, 2023 at 16:56
  • @PMF It is possible that you're going to use this with a custom linker script that'll ensure that test is small enough to fit into the low 13 bits of a register.The assembler therefore can't error, because it may work, depending on your linker settings, but the linker will give you the R_SPARC_13 error to tell you you've got it wrong at compile time. Apr 27, 2023 at 21:26
7

Try B bla rather than JMP bla. As I understand it, JMP bla is a synthetic instruction that translates to JMPL bla, %g0 and you have the same large point problem. (Unfortunately, I do not know why the JMPL construct fails.)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .