You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在非#![no_std]环境下覆盖Rust标准库默认Panic处理程序

问题描述

我正在尝试用Rust编写内核,发现通过以下配置可以从源码编译并使用标准库:

[unstable]
build-std = ["core", "std", "panic_abort"]

显然初始状态下很多功能无法正常工作。目前我试图让panic!()正常运行,但从标准库实现代码来看,panic会因尝试打印栈跟踪而触发异常。

对应标准库std::panicking::rust_panic_with_hook代码片段:

if must_abort || panics > 2 {
    if panics > 2 {
        // Don't try to print the message in this case
        // - perhaps that is causing the recursive panics.
        rtprintpanic!("thread panicked while processing panic. aborting.\n");
    } else {
        // Unfortunately, this does not print a backtrace, because creating
        // a `Backtrace` will allocate, which we must to avoid here.
        let panicinfo = PanicInfo::internal_constructor(message, location, can_unwind);
        rtprintpanic!("{panicinfo}\npanicked after panic::always_abort(), aborting.\n");
    }
    crate::sys::abort_internal();
}

在完成堆分配设置后,我尝试通过以下代码添加无限循环作为panic hook:

std::panic::set_hook(Box::new(|_| loop {}))

但打印操作发生在hook执行之前,这部分逻辑是标准库硬编码的。

请问是否存在无需使用#![no_std]即可覆盖标准库默认panic处理程序的方案?

编辑补充:
我使用的是v1.70.0-nightly版本,并启用了#![feature(restricted_std)]特性。

附上所有配置文件:

x86_64-my_os.json

{
    "llvm-target": "x86_64-unknown-none",
    "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
    "arch": "x86_64",
    "target-endian": "little",
    "target-pointer-width": "64",
    "target-c-int-width": "32",
    "os": "none",
    "executables": true,
    "linker-flavor": "ld.lld",
    "linker": "rust-lld",
    "panic-strategy": "abort",
    "disable-redzone": true,
    "features": "-mmx,-sse,+soft-float"
}

.cargo/config.toml

[unstable]
build-std = ["core", "std", "panic_abort", "compiler_builtins", "alloc"]
build-std-features = ["compiler-builtins-mem"]

[build]
target = "x86_64-my_os.json"

[target.'cfg(target_os = "none")']
runner = "bootimage runner"

Cargo.toml

[package]
name = "my_os"
version = "0.1.0"
edition = "2021"

[dependencies]
bootloader = "0.9.8"
linked_list_allocator = "0.10"
解决方案

由于你使用的是panic_abort panic策略,且目标为无OS环境,标准库的panic处理逻辑确实会在调用自定义hook前执行打印操作,这是硬编码在rust_panic_with_hook中的行为,无法通过set_hook跳过。但可以通过以下方式解决:

  1. 自定义panic_handler完全替代默认逻辑
    利用#[panic_handler]属性,你可以直接覆盖标准库的panic处理流程——即使使用std(restricted_std特性允许在无OS环境中使用受限标准库的同时,保留自定义panic handler的能力)。示例代码:

    #![feature(panic_handler)]
    
    #[panic_handler]
    fn panic(info: &core::panic::PanicInfo) -> ! {
        // 这里实现自定义panic逻辑,比如输出信息到串口、进入无限循环等
        loop {}
    }
    

    这个handler会完全跳过标准库中触发异常的打印步骤,直接执行你定义的逻辑。

  2. 实现rtprintpanic的底层支持
    标准库的rtprintpanic!宏依赖目标平台的底层打印实现,在无OS环境中需要你手动提供对应的底层函数支持。实现std::sys模块下的打印相关接口后,rtprintpanic就能正常工作,不会触发异常。

  3. 切换panic_unwind策略(不推荐)
    若切换到panic_unwind,panic处理流程会变化,但这需要你实现unwind的底层支持,对于内核开发来说复杂度较高,不是首选方案。

注意:即使使用std,无OS环境下多数标准库功能都需要你手动实现底层syscall支持,restricted_std仅允许链接标准库,不提供这些底层实现。


内容的提问来源于stack exchange,提问作者Gian Laager

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 08:07:50