rustoperating-systemkernellinker-errorsrust-cargo

Rust Kernel: Undefined refrence to 'core::panicking::panic_null_pointer_derefrence'


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

Solution

  • 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.