Bare-metal C Program compilation fails
apivovarov opened this issue · 3 comments
I'm trying to follow the instructions described in Bare-metal C Program in README
I got the following errors (OS: Ubuntu 20.10 x86_64)
root@292c6ad9bfc1:~/workplace/riscv# riscv64-unknown-elf-gcc -S -nostdlib foo.c
root@292c6ad9bfc1:~/workplace/riscv# riscv64-unknown-elf-gcc -Wl,-Ttext=0x80000000 -nostdlib -o foo foo.s
/opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/../../../../riscv64-unknown-elf/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000080000000
/tmp/ccfhLgt3.o: in function `main':
foo.c:(.text+0x8): relocation truncated to fit: R_RISCV_HI20 against `.LC0'
collect2: error: ld returned 1 exit status
foo.c
#include <stdio.h>
int main() {
puts("Hello World!");
return 0;
}
foo.s
.file "foo.c"
.option nopic
.attribute arch, "rv64i2p0_m2p0_a2p0_f2p0_d2p0_c2p0"
.attribute unaligned_access, 0
.attribute stack_align, 16
.text
.section .rodata
.align 3
.LC0:
.string "Hello World!"
.text
.align 1
.globl main
.type main, @function
main:
addi sp,sp,-16
sd ra,8(sp)
sd s0,0(sp)
addi s0,sp,16
lui a5,%hi(.LC0)
addi a0,a5,%lo(.LC0)
call puts
li a5,0
mv a0,a5
ld ra,8(sp)
ld s0,0(sp)
addi sp,sp,16
jr ra
.size main, .-main
.ident "GCC: (GNU) 10.2.0"
Thank you for trying to use this emulator!
You can't use #include <stdio.h>
in foo.c
because we use -nostdlib
flag at riscv64-unknown-elf-gcc
, which means we can't depend on the standard library.
bin/raw/simple.c is one of the simplest sample C code. We can compile it with the instructions described in Bare-metal C Program in README. Once simple.c is executed in this emulator, we'll see the value of 42 at x10 (a0) register. The x10 register stores a return value of the main function.
I was able to generate simple.text myself, but the content and size of my file is different from the official simple.text
I did the following to generate simple.text (BTW, I got ld
warning)
$ riscv64-unknown-elf-gcc -S -nostdlib simple.c
$ riscv64-unknown-elf-gcc -Wl,-Ttext=0x80000000 -nostdlib -o simple simple.s
/opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/../../../../riscv64-unknown-elf/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000080000000
$ riscv64-unknown-elf-objcopy -O binary simple simple.text
The content of my simple.text is hexdump -C simple.text
00000000 41 11 22 e4 00 08 93 07 a0 02 3e 85 22 64 41 01 |A.".......>."dA.|
00000010 82 80 |..|
00000012
Official simple.text has different content and size
00000000 13 01 01 ff 23 34 81 00 13 04 01 01 93 07 a0 02 |....#4..........|
00000010 13 85 07 00 03 34 81 00 13 01 01 01 67 80 00 00 |.....4......g...|
00000020
As a result if I run my simple.text in rvemu.app it does not set x10= 0x2a
What I'm doing wrong?
My OS is Ubuntu 20.10.
riscv64-unknown-elf-gcc (GCC) 10.2.0
my simple.c is the same as the official simple.c
int main() {
return 42;
}
my simple.s is almost the same as the official simple.s
.file "simple.c"
.option nopic
.attribute arch, "rv64i2p0_m2p0_a2p0_f2p0_d2p0_c2p0"
.attribute unaligned_access, 0
.attribute stack_align, 16
.text
.align 1
.globl main
.type main, @function
main:
addi sp,sp,-16
sd s0,8(sp)
addi s0,sp,16
li a5,42
mv a0,a5
ld s0,8(sp)
addi sp,sp,16
jr ra
.size main, .-main
.ident "GCC: (GNU) 10.2.0"
Sorry for my late response. I've been busy these days.
I think your compiler is using compressed instructions (RV64C). Each length of compressed instructions is 2 bytes and the original simple.text
binary is composed of non-compressed instructions, each length of them is 4 bytes. That's why the length of your binary differs.
The app rvemu.app
didn't support compressed instructions so that you coludn't see the result x10= 0x2a
. It, however, is updated to support compressed instructions now. I think you can see x10= 0x2a
with your binary.
FYI: If you want to compile code into RV64G (without compressed) instructions, you need to compile RISC-V toolchain with --with-arch=rv64g
option.
$ git clone --recursive git@github.com:riscv/riscv-gnu-toolchain.git
$ cd riscv-gnu-toolchain
$ ./configure --prefix=/opt/riscv --with-arch=rv64g
$ make
$ make linux