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

裸机MCU项目混合Rust与C时rust_begin_unwind重复符号问题求助

解决裸机Rust静态库链接时rust_begin_unwind重复符号问题

在裸机微控制器项目中混合使用Rust与C,未采用Cargo,直接调用rustc配合自定义构建系统。编写了两个结构类似的Rust静态库,每个库都包含#[panic_handler]定义,示例代码如下:

#![no_std]
#![no_main]
#![crate_type="lib"]

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

#[no_mangle]
pub extern "C" fn rust_sample_lib_for_c(a: i8) -> i8 {
    return a+53;
}

编译命令:

rustc --target thumbv7em-none-eabihf -C panic=abort -C opt-level=3 --emit obj --crate-type staticlib src/rust_sample_lib_for_c.rs -o src/librust_sample_lib_for_c.a

链接C源码与两个Rust库时出现错误:

ld.lld: error: duplicate symbol: rust_begin_unwind

经objdump检查,两个静态库中均存在rust_begin_unwind符号——原因是每个Rust库编译时都要求定义panic_handler,最终导致符号重复。


解决方案

1. 抽离公共panic处理库

将panic处理逻辑单独做成一个独立的Rust库,所有业务Rust库依赖这个公共库,不再各自定义panic_handler:

公共panic库代码(src/panic_common.rs)

#![no_std]
#![crate_type="lib"]

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

编译公共库

rustc --target thumbv7em-none-eabihf -C panic=abort -C opt-level=3 --emit obj --crate-type staticlib src/panic_common.rs -o src/libpanic_common.a

修改业务库并编译

移除业务库中的panic_handler代码,编译时链接公共panic库:

#![no_std]
#![no_main]
#![crate_type="lib"]

#[no_mangle]
pub extern "C" fn rust_sample_lib_for_c(a: i8) -> i8 {
    return a+53;
}

编译命令添加依赖参数:

rustc --target thumbv7em-none-eabihf -C panic=abort -C opt-level=3 --emit obj --crate-type staticlib src/rust_sample_lib_for_c.rs -o src/librust_sample_lib_for_c.a --extern panic_common=src/libpanic_common.a

最终链接时,只需将两个业务库、公共panic库与C代码一起链接即可,避免符号重复。

2. 用条件编译控制panic_handler

给业务库添加条件编译标记,仅在单独测试时启用panic_handler,实际项目中由全局代码提供统一的panic处理:

修改业务库代码

#![no_std]
#![no_main]
#![crate_type="lib"]

// 仅在standalone特性启用时编译panic_handler
#[cfg(feature = "standalone")]
#[panic_handler]
fn my_panic(_info: &core::panic::PanicInfo) -> ! {
    loop {}
}

#[no_mangle]
pub extern "C" fn rust_sample_lib_for_c(a: i8) -> i8 {
    return a+53;
}

编译业务库

编译时不启用standalone特性,这样不会生成rust_begin_unwind符号:

rustc --target thumbv7em-none-eabihf -C panic=abort -C opt-level=3 --emit obj --crate-type staticlib src/rust_sample_lib_for_c.rs -o src/librust_sample_lib_for_c.a

添加全局panic处理

创建单独的panic实现文件(src/panic_impl.rs):

#![no_std]

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

编译成目标文件:

rustc --target thumbv7em-none-eabihf -C panic=abort -C opt-level=3 --emit obj src/panic_impl.rs -o src/panic_impl.o

链接时将这个目标文件、两个业务库和C代码一起链接即可。

3. 标记弱符号(应急方案,不推荐)

如果暂时无法修改代码,可尝试将其中一个库的rust_begin_unwind标记为弱符号,让链接器优先选择强符号:

rustc --target thumbv7em-none-eabihf -C panic=abort -C opt-level=3 --emit obj --crate-type staticlib src/rust_sample_lib_for_c.rs -o src/librust_sample_lib_for_c.a -Clink-args="-Wl,--defsym=rust_begin_unwind=__weak_rust_begin_unwind"

该方式依赖链接器特性,可能隐藏潜在问题,仅作为临时应急方案使用。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 07:22:49