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

构建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)
    }

}

编译步骤与错误信息

  1. 编译bootloader:nasm -f elf64 -o boot.o os/boot.asm
  2. 构建Rust库:cargo build --release,复制libordinal_system.a到os目录
  3. 链接命令: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 01:47:10