I'm implementing a small OS on a RaspberryPi Zero. I've done a similar project in C, using the arm-none-eabi
toolchain. I'm now attempting to port the code to Rust by cross-compiling it.
I've followed the popular blogs: OSDev, Philipp Oppermann and seen the popular issues: "how-to-compile-freestanding-binary-for-armv6" and "armv6-z-bare-metal-cross-compilation-fails" (can't put links lol)
I've implemented all the workarounds and fixes mentioned in these posts, and my code worked for naively turning on an LED. However, when I try to add some sort of loop while
or for n in 1..10
for example, the .rlib file builds fine, but when I try to link:
I get this error:
/Users/joshdelg/krust/src/lib.rs:52: undefined reference to `core::panicking::panic'
/opt/homebrew/Cellar/arm-none-eabi-test/9-2019q4-cs107e/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld: /Users/joshdelg/krust/src/lib.rs:44: undefined reference to core::panicking::panic'
I have the following in my Cargo.toml
[profile.dev]
panic = "abort"
and I've defined my custom build target like this. arm-none-eabihf.json:
{
"llvm-target": "arm-none-eabihf",
"target-endian": "little",
"target-pointer-width": "32",
"target-c-int-width": "32",
"os": "none",
"env": "eabi",
"vendor": "unknown",
"arch": "arm",
"linker-flavor": "gcc",
"linker": "arm-none-eabi-gcc",
"data-layout": "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64",
"executables": true,
"relocation-model": "static",
"no-compiler-rt": true,
"disable-redzone": true,
"panic-strategy": "abort"
}
For reference the source code of lib.rs
is as follows:
#![no_std] // don't link the Rust standard library
#![no_main] // disable all Rust-level entry points
#![feature(core_intrinsics, lang_items, rustc_attrs)]
use core::panic::PanicInfo;
extern "C" {
fn GET32(addr: u32) -> u32;
}
extern "C" {
fn PUT32(addr: u32, val: u32);
}
#[no_mangle] // don't mangle the name of this function
pub extern fn krust_entry() {
// this function is the entry point, since the linker looks for a function
// named `_start` by default
// loop {}
const FSEL: *mut u32 = 0x20200008 as *mut u32;
const SET0: *mut u32 = 0x2020001C as *mut u32;
const CLR0: *mut u32 = 0x20200028 as *mut u32;
// Set output
unsafe {
// let mut existing = volatile_load(FSEL);
let mut existing = GET32(FSEL as u32);
existing &= (!0b111);
existing |= 0b001;
// volatile_store(FSEL, existing);
PUT32(FSEL as u32, existing);
loop {
unsafe {
// Set on
PUT32(SET0 as u32, 1 << 20);
let mut i = 0;
while i < 1_000_000 {
i += 1;
}
// Set off
PUT32(CLR0 as u32, 1 << 20);
let mut i = 0;
while i < 1_000_000 {
i += 1;
}
}
}
}
}
/// This function is called on panic.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
#[no_mangle]
pub extern fn __aeabi_unwind_cpp_pr0() {}
#[lang = "eh_personality"]
pub extern fn eh_personality() {}
#[rustc_nounwind]
pub extern fn panic_nounwind() {}
#[allow(non_snake_case)]
#[no_mangle]
pub extern fn _Unwind_Resume() { loop {} }
I've implemented dummy versions of some of the handlers according to the blog posts to try to skirt this issue. Any help would be appreciated!