0

Given this .cargo/config:

[build]
target = "riscv32i-unknown-none-elf"

and this main.rs:

#![no_std]
#![no_main]
use core::arch::global_asm;

global_asm!(".globl _start

.section \".text\"

_start:
    call      rust_main
");

#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
    loop {

    }
}

#[no_mangle]
pub extern "C" fn rust_main() -> ! {
    loop {
        test();
    }
}

fn test() {
    unsafe {
        (0 as *mut u32).write(42);
    }
}

cargo build --release produces a binary where all rust functions are missing:

$ riscv64-unknown-elf-objdump -d ./target/riscv32i-unknown-none-elf/release/BINARY_NAME

./target/riscv32i-unknown-none-elf/release/BINARY_NAME:     file format elf32-littleriscv


Disassembly of section .text:

000110b4 <_start>:
   110b4:       00000097                auipc   ra,0x0
   110b8:       008080e7                jalr    8(ra) # 110bc <rust_main>

000110bc <rust_main>:
   110bc:       c0001073                unimp

However the linker appears to be "finding" rust_main, because if I change just the function name, the linking fails because the then undefined symbol.

Am I missing something, or is this a bug in the rust buildchain? Rust was installed with rustup, cargo version cargo 1.60.0-nightly (25fcb135d 2022-02-01).

Herohtar
  • 5,347
  • 4
  • 31
  • 41
Benni
  • 1,030
  • 2
  • 11
  • 18
  • 1
    The compiler has inlined everything, recognized that writing to address 0 is a bug that should trap and replaced it with the `unimp` instruction. If you compile without `--release`, you should see the functions you expect. – Jmb Feb 09 '22 at 13:03
  • I am new to riscv, would writing to 0 *always* trap? Can't I write stuff to 0 before I set up virtual memory? – Benni Feb 09 '22 at 13:12
  • (or create a virtual memory section at the virtual address 0) – Benni Feb 09 '22 at 13:33
  • 1
    The thing is that a literal 0 used as a pointer is a null pointer, and writing through it is UB. If you want to really write to address `0x0` use `write_volatile()`, which you should probably be using anyway if you are writing to well-known arch-specific memory addresses. – rodrigo Feb 09 '22 at 15:27
  • With `write_volatile()` I get the `sw` I was hoping for. The documentation of `core::ptr`/`core::ptr::write` also (correctly) mentions that the pointer must be non-null if you don't want UB - I assumed that the nullyness of a pointer would not have an impact on its validness. Thanks for enlightening me! In practive I will naturally abstain from using 0 as a valid memory range. Do you want to create an answer with references to the documentation, or should I? – Benni Feb 09 '22 at 18:59
  • Note that according to [the `write_volatile` docs](https://doc.rust-lang.org/1.54.0/std/ptr/fn.write_volatile.html) the destination should be [valid](https://doc.rust-lang.org/1.54.0/std/ptr/index.html#safety), which means that it shouldn't be null. – Jmb Feb 10 '22 at 07:29
  • @Benni: I think you should write your own answer, you have more details than I do. – rodrigo Feb 10 '22 at 08:34

0 Answers0