Here’s an example using the gcc toolchain for embedded 32 bit RISC-V (my HiFive1 board):
#include <stdio.h>
int foo(int i){
if (i < 100){
printf(“%d\n”, i);
}
return i;
}
int main(){
foo(10);
return 0;
}
After compiling to a .o with -O2 -march=RV32IC we get (just looking at foo)
00000000 :
0: 1141 addi sp,sp,-16
2: c422 sw s0,8(sp)
4: c606 sw ra,12(sp)
6: 06300793 li a5,99
c: 00a7cb63 blt a5,a0,22 <.L2>
10: 85aa mv a1,a0
12: 00000537 lui a0,0x0
16: 00050513 mv a0,a0
1a: 00000317 auipc t1,0x0
1e: 000300e7 jalr t1
00000022 <.L2>:
22: 40b2 lw ra,12(sp)
24: 8522 mv a0,s0
26: 4422 lw s0,8(sp)
28: 0141 addi sp,sp,16
2a: 8082 ret
And after linking:
00010164 :
10164: 1141 addi sp,sp,-16
10166: c422 sw s0,8(sp)
10168: c606 sw ra,12(sp)
1016a: 06300793 li a5,99
1016e: 842a mv s0,a0
10170: 00a7c863 blt a5,a0,10180 <foo+0x1c>
10174: 85aa mv a1,a0
10176: 0001a537 lui a0,0x1a
1017a: 6a050513 addi a0,a0,1696 # 1a6a0 <__clz_tab+0x100>
1017e: 2a69 jal 10318
10180: 40b2 lw ra,12(sp)
10182: 8522 mv a0,s0
10184: 4422 lw s0,8(sp)
10186: 0141 addi sp,sp,16
10188: 8082 ret
The linker has done quite a lot!
- the format string address generation has had the LUI (Load Upper Immediate)
changed from 0x0 to 0x1a (the literal is in flash memory). If it had stayed at
0x0 it would have been removed by the linker. The mv a0,a0 (which is really
addi a0,a0,#0) has had the real immediate filled in.
-
the call of printf had the general call-anywhere-in-the-address-space auipc
(Add Upper Immediate to PC); jalr (Jump And Link to address in Register (plus
offset)) sequence replaced by a simple jal (Jump And Link, with PC +/- 1 MB range)
-
as the jal offset was in fact less than +/- 2 KB, the 32 bit jal was replaced by a
16 bit jal instruction.
-
the conditional branch has been shortened from 18 bytes to 12 bytes due to
the other changes.