Im writing a kernel in Rust, but are having some problems with the panicking module. I have written a build script that should build the boot image of the OS, but i seem to get an error while trying to draw text to the VGA.
Here is the error im getting:
ld: /home/pollen/projects/pollos/kernel/target/i386/debug/deps/kernel-285a1fe9a5f16fae.o: in function `core::ptr::mut_ptr::<impl *mut T>::offset::precondition_check':
/home/pollen/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ub_checks.rs:68:(.text._ZN4core3ptr7mut_ptr31_$LT$impl$u20$$BP$mut$u20$T$GT$6offset18precondition_check17hf78ea68a8deeea7eE+0x33): undefined reference to `core::panicking::panic_nounwind'
ld: /home/pollen/projects/pollos/kernel/target/i386/debug/deps/kernel-285a1fe9a5f16fae.o: in function `_start':
/home/pollen/projects/pollos/kernel/src/main.rs:21:(.text._start+0x73): undefined reference to `core::panicking::panic_null_pointer_dereference'
Here is my rust code:
// src/main.rs
#![no_std] // don't link the Rust standard library
#![no_main] // disable all Rust-level entry points
use core::panic::PanicInfo;
/// This function is called on panic.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
#[unsafe(no_mangle)] // don't mangle the name of this function
pub extern "C" fn _start() -> ! {
// this function is the entry point, since the linker looks for a function
// named `_start` by default
let vga = 0xb8000 as *mut u8;
unsafe {
*vga = b'H';
*vga.offset(1) = 0x0f;
}
loop {}
}
I am not sure why the linker is throwing an error, and i have had trouble figuring out all the build arguments and config files. Here is my .cargo/config.toml:
# in .cargo/config.toml
[unstable]
build-std = ["core", "compiler_builtins"]
build-std-features = ["compiler-builtins-mem"]
I have written a custom target, for compiling to the i386 architecture:
{
"llvm-target": "i386-unknown-none",
"data-layout": "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128",
"arch": "x86",
"os": "none",
"vendor": "unknown",
"linker-flavor": "ld.lld",
"linker": "rust-lld",
"executables": true,
"disable-redzone": true,
"panic-strategy": "abort",
"relocation-model": "static",
"code-model": "kernel",
"target-pointer-width": "32",
"features": "-mmx,-sse,+soft-float",
"rustc-abi": "x86-softfloat"
}
The last (but most important) file im going to show you, is the build.sh file which i run to compile and link the kernel and bootloader:
#!/bin/bash
set -e # Exit on any error
KERNEL_DIR="/home/pollen/projects/pollos/kernel"
KERNEL_TARGET="$KERNEL_DIR/i386.json"
BL_DIR="/home/pollen/projects/pollos/bootloader"
BL_BUILD=$BL_DIR"/build"
compile_kernel () {
echo "[*] Compiling kernel..."
export RUSTFLAGS="--emit=obj"
rustup override set nightly
(cd kernel && cargo clean)
# Run Cargo with explicit --target path
cargo build -Z build-std=core --target "$KERNEL_TARGET" --manifest-path "$KERNEL_DIR/Cargo.toml"
# Optional: move resulting .o file if needed
KERNEL_OBJ=$(find "$KERNEL_DIR/target/i386/debug/deps/" -name "kernel-*.o")
if [ -z "$KERNEL_OBJ" ]; then
echo "Kernel object file not found!"
exit 1
fi
echo "[+] Kernel object file: $KERNEL_OBJ"
}
compile_bootloader() {
echo "[*] Compiling bootloader..."
mkdir -p "$BL_DIR/build"
nasm "$BL_DIR/bootsector.asm" -f bin -o "$BL_DIR/build/bootsector.bin" -I"$BL_DIR"
nasm "$BL_DIR/kernel_entry.asm" -f elf -o "$BL_DIR/build/kernel_entry.o"
echo "[+] Bootloader binaries created."
}
link() {
echo "[*] Linking kernel and bootloader..."
ld -m elf_i386 -o "$BL_DIR/build/bootable_kernel.bin" \
--entry _start \
"$BL_DIR/build/kernel_entry.o" \
"$KERNEL_OBJ" \
-Ttext 0x1000 \
--oformat binary
echo "[+] Bootable kernel created."
}
link2() {
ld -m elf_i386 -T $BL_DIR/linker.ld -o kernel.elf $BL_BUILD/kernel_entry.o "$KERNEL_OBJ"
objcopy -O binary kernel.elf kernel.bin
cat $BL_BUILD/bootsector.bin kernel.bin > bootable_kernel.bin
}
compile_kernel
compile_bootloader
link
You don't link core
and compiler_builtins
. Beside your kernel object files, you also need to link the files compiler_builtins-<hash>.o
and core-<hash>.o
from target/deps
.