构建x86_64架构Rust内核时的链接器错误解决方案咨询
Rust内核链接器问题解决方案
问题概述
构建Rust内核时,将项目改为库crate并以自定义目标构建staticlib,使用nasm编译bootloader后,链接阶段出现地址计数器回退、段地址空间溢出、段重叠等错误。此前通过cargo rustc -- --emit=obj生成的目标文件可正常链接,但调用panic!()时因缺少core::panic::*符号报错,故改用staticlib方案。
现有配置文件
自定义目标文件 custom_target.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.toml配置
[package] name = "ordinal_system" version = "0.1.0" [dependencies] "x86_64" = "0.14.10" [profile.dev] panic = "abort" [profile.release] panic = "abort" [lib] crate-type = ["staticlib"] path="src/kernel.rs"
原链接脚本 linker.ld
SECTIONS { . = 0x7c00; .text : { os/boot.o(.bootsector) . = 0x7c00+510; SHORT(0xaa55) .=0x7e00; os/libordinal_system.a(.text); } .data : { os/libordinal_system.a(.data) } .bss : { os/libordinal_system.a(.bss) } .rodata : { os/libordinal_system.a(.rodata) } }
编译步骤与错误信息
- 编译bootloader:
nasm -f elf64 -o boot.o os/boot.asm - 构建Rust库:
cargo build --release,复制libordinal_system.a到os目录 - 链接命令:
ld.lld -T linker.ld os/boot.o os/libordinal_system.a -o os/boot.bin
错误信息:
ld.lld: error: linker.ld:7: unable to move location counter backward for: .text ld.lld: error: linker.ld:7: unable to move location counter backward for: .text ld.lld: error: section .text at 0x16CA4 of size 0xFFFFFFFFFFFF115C exceeds available address space ld.lld: error: section .rodata..Lanon.8d34b9bd859d642988e4500c0514c713.23 file range overlaps with .text.rust_begin_unwind >>> .rodata..Lanon.8d34b9bd859d642988e4500c0514c713.23 range is [0xDEE, 0xE2B] >>> .text.rust_begin_unwind range is [0xE00, 0xE31] ld.lld: error: section .text.rust_begin_unwind file range overlaps with .rodata.cst8 >>> .text.rust_begin_unwind range is [0xE00, 0xE31] >>> .rodata.cst8 range is [0xE2C, 0xF03] ...(后续段重叠错误)
解决方案
1. 修复链接脚本的地址计数器与段分配问题
原链接脚本将引导扇区与内核代码放在同一个.text段,导致位置计数器冲突,且未明确内存区域限制。修改后的链接脚本如下:
ENTRY(_start) /* 指定bootloader的入口符号 */ /* 定义内存区域,明确各段的可用地址范围 */ MEMORY { BOOT (rw) : ORIGIN = 0x7c00, LENGTH = 512 /* 引导扇区固定512字节 */ KERNEL (rx) : ORIGIN = 0x7e00, LENGTH = 1M /* 内核区域,可按需调整大小 */ } SECTIONS { /* 引导扇区段:严格占据0x7c00开始的512字节 */ .bootsector 0x7c00 : { os/boot.o(.bootsector); /* 填充到510字节,写入引导标志0xaa55 */ . = 0x7c00 + 510; SHORT(0xaa55); } > BOOT /* 内核代码段:从0x7e00开始 */ .text 0x7e00 : { os/libordinal_system.a(.text); } > KERNEL /* 数据段:紧跟.text段之后 */ .data : { os/libordinal_system.a(.data); } > KERNEL /* BSS段:紧跟.data段之后,自动初始化0 */ .bss : { os/libordinal_system.a(.bss); } > KERNEL /* 只读数据段:放在内核区域内 */ .rodata : { os/libordinal_system.a(.rodata); } > KERNEL }
2. 确保bootloader与Rust函数的调用约定匹配
在Rust代码中,将kmain标记为extern "C"并禁用名称修饰,保证nasm能正确找到符号:
#[no_mangle] pub extern "C" fn kmain() { // 内核主逻辑 loop {} }
同时,boot.asm中需定义_start作为入口,并正确调用kmain:
section .bootsector global _start extern kmain _start: ; 引导扇区初始化代码(如设置栈、保护模式等) ; ... call kmain ; 调用Rust内核入口 hlt ; 防止返回后执行垃圾代码
3. 使用Rust指定的链接器
自定义目标中指定了rust-lld作为链接器,替换系统的ld.lld避免兼容性问题:
rust-lld -T linker.ld os/boot.o os/libordinal_system.a -o os/boot.bin
4. 验证引导扇区大小
确保boot.asm中.bootsector段的代码不超过510字节(预留2字节给0xaa55),若代码过长需精简或改为加载后续扇区。
内容的提问来源于stack exchange,提问作者kushurox TW
相关产品推荐
相关产品推荐

