d0iasm / rvemu

RISC-V emulator for CLI and Web written in Rust with WebAssembly. It supports xv6 and Linux (ongoing).
https://rvemu.app/
MIT License
770 stars 57 forks source link

Bare-metal C Program compilation fails #5

Open apivovarov opened 3 years ago

apivovarov commented 3 years ago

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"
d0iasm commented 3 years ago

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.

apivovarov commented 3 years ago

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"
d0iasm commented 3 years ago

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