Illegal instruction when executing function call on RISC-V

2.6k views Asked by At

Goodmorning,

I am trying to write a simple program in assembly for RISC-V architecture, in which I have a simple main (_start) that perform a function call that does nothing and return to the caller.

The code I wrote is the following:

.section .text
.global _start

test:
    lw a1, 0(sp)



    # ritorna al chiamante
    jr ra

_start:
    # push sullo stack
    addi sp, sp, -4

    li a1, 5

    # mette valore di ritorno sullo stack
    # salva a1 sullo stack
    sw a1, 0(sp)

    # chiamata a funzione
    jal ra, test

    # pop dallo stack
    addi sp, sp, +4

    li a6, 2

For executing this program I run:

$ riscv64-unknown-elf-as somma.s -o somma.o
$ riscv64-unknown-elf-ld somma.o -o somma.elf
$ spike pk somma.elf

As output I get:

z  0000000000000000 ra 0000000000010090 sp 000000007f7e9b50 gp 0000000000000000
tp 0000000000000000 t0 0000000000000000 t1 0000000000000000 t2 0000000000000000
s0 0000000000000000 s1 0000000000000000 a0 0000000000000000 a1 0000000000000005
a2 0000000000000000 a3 0000000000000000 a4 0000000000000000 a5 0000000000000000
a6 0000000000000002 a7 0000000000000000 s2 0000000000000000 s3 0000000000000000
s4 0000000000000000 s5 0000000000000000 s6 0000000000000000 s7 0000000000000000
s8 0000000000000000 s9 0000000000000000 sA 0000000000000000 sB 0000000000000000
t3 0000000000000000 t4 0000000000000000 t5 0000000000000000 t6 0000000000000000
pc 0000000000010098 va 0000000000000000 insn       00000000 sr 8000000200046020
An illegal instruction was executed!

In this case we have 2 in the a6 register, so I suppose that the control of the program is correctly returned to the caller, since the last instruction is correctly executed, but I anyway get the error "An illegal instruction was executed!" Could you please give me some hints for solving this problem?

Thank you

1

There are 1 answers

0
Palmer Dabbelt On

This is one of the differences between C and assembly programming: in C the compiler handles the function entry/exit code for you, while in assembly you're meant to handle it yourself. In this specific case, your _start function doesn't end in a ret and therefor execution will continue past the end of the function. Since that's the end of your binary, the next bytes are probably an illegal instruction (the all-0 instruction is illegal in RISC-V).

The _start function is a bit of a special case: while most RISC-V ABIs say it's OK to return from _start, the canonical _start will never return and will instead call exit() directly. Your best bet for _start is to have it end with li a0, 0; call exit; ret.