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

使用链接器脚本在不同内存地址链接目标文件开发bootloader问题求助

问题根因定位

  • 段地址与虚拟地址不匹配:链接脚本中.kernel段的虚拟地址设置为0x1000,但你跳转用的jmp 0x1000:0x0000对应的物理地址是0x1000 <<4 + 0 = 0x10000,两者完全不匹配,内核代码执行时寻址会全部错位。
  • 引导扇区格式错误:.boot段没有显式指定加载地址,默认和虚拟地址0x7c00一致,生成的二进制文件开头会填充大量空字节到0x7c00位置,导致MBR魔数0xaa55不在第一个扇区的最后两个字节,BIOS识别不到这是合法引导扇区。
  • 16位实模式寻址错误:kernel.s中用offset flat:是32位平坦模式的寻址方式,在16位实模式下会出现地址计算错误。

修复方案

1. 修正链接脚本linker.ld

ENTRY(_start)
OUTPUT_FORMAT("binary")

SECTIONS {
 /* 引导扇区虚拟地址为0x7c00,加载地址为0,生成的二进制文件无前置空填充 */
 .boot 0x7c00 : AT(0)
 {
   *(.boot)
   /* 固定.boot段占512字节,避免内核内容侵入引导扇区 */
   . = 512;
 }

 /* 内核虚拟地址对应0x1000:0的物理地址0x10000,加载地址接在引导扇区之后的0x200位置 */
 .kernel 0x10000 : AT(0x200)
 {
   *(.kernel)
   *(.text)
   *(.rodata)
   *(.data)
   . = ALIGN(4);
   __bss_start = .;
   *(.bss)
   *(COMMON)
   __bss_end = .;
 }
}

2. 修正Boot.s的扇区加载逻辑

读扇区前先设置段寄存器es,保证内核写入的物理地址和链接脚本的虚拟地址匹配:

mov dh, 1       # 读取1个扇区
mov ax, 0x1000
mov es, ax      # 段地址设为0x1000
mov bx, 0x0000  # 偏移为0,对应物理地址0x10000

call read_sectors
jmp 0x1000:0x0000

3. 修正kernel.s代码

添加全局入口符号,调整寻址写法适配16位实模式:

.code16
.section .kernel
.text 
.intel_syntax noprefix
.globl kernel_entry
kernel_entry:
mov si, offset tesing_msg
mov bl, 0xf0
call print16
call new_line16

逻辑校验

你的核心设计逻辑是合理的:BIOS默认将合法引导扇区加载到物理地址0x7c00,所以.boot段虚拟地址必须设置为0x7c00保证内部寻址正确;内核加载到0x10000位置用段地址0x1000访问,不会和低地址的BIOS中断向量、引导代码区域冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 05:21:02