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

NASM org指令与链接脚本的等效性及二进制差异问题

org 0x7C00 与链接脚本实现MBR的差异及问题解决

org 0x7C00配合nasm -f bin和用链接脚本替代的方式并非完全等效,后者需要严格的配置才能达到前者的效果,你遇到的问题都是因为链接脚本的配置不符合MBR的要求。

1. org 0x7C00的本质作用

org 0x7C00是NASM的伪指令,核心作用有两个:

  • 告诉汇编器,程序加载到内存的起始地址是0x7C00,所有跳转标签、变量等符号的地址计算都会以0x7C00为基址。
  • 配合nasm -f bin时,汇编器直接生成从偏移0开始的纯二进制文件,你可以通过times 510-($-$$) db 0+dw 0xAA55精准控制文件大小为512字节,确保MBR魔数落在最后两个字节。

2. 链接脚本方式的核心要求

如果不用org,想用链接脚本实现同样的MBR效果,必须满足三个关键条件:

(1)指定输出格式为纯二进制

链接器默认生成ELF格式文件(包含段表、符号表等额外元数据),这就是你得到4040字节文件的原因——ELF文件远大于512字节,且BIOS无法识别。必须在链接脚本开头添加:

OUTPUT_FORMAT("binary")

(2)设置代码段起始地址为0x7C00

链接脚本需要明确告诉链接器,代码加载到内存的起始地址是0x7C00,对应二进制文件的偏移0:

ENTRY(start)
SECTIONS {
    . = 0x7C00;  /* 设置当前地址指针为0x7C00 */
    .text : {
        *(.text)  /* 包含所有目标文件的.text段内容 */
    }
}

(3)强制控制文件大小为512字节,并确保魔数位置正确

MBR要求文件大小必须是512字节,且最后两个字节为0xAA55。你需要在链接脚本中截断超出部分,并把魔数放在正确位置:

OUTPUT_FORMAT("binary")
ENTRY(start)
SECTIONS {
    . = 0x7C00;
    .text : {
        *(.text)
        /* 直接在链接脚本中添加魔数,确保落在最后两个字节 */
        BYTE(0x55)
        BYTE(0xAA)
    }
    /* 将地址指针移到0x7C00+512,截断后续内容 */
    . = 0x7C00 + 0x200;
    /* 丢弃不需要的段(比如数据段、bss段) */
    /DISCARD/ : { *(.data) *(.bss) *(.comment) }
}

3. 你遇到的问题根源

  • 二进制大小4040字节:链接器默认生成了ELF格式文件,而非纯二进制,包含大量额外元数据。
  • rizin显示起始地址差异:前者是纯二进制文件,rizin默认从0x0开始解析;后者如果是ELF文件,rizin会读取ELF头中的加载地址,显示为0x7C00。
  • 无法运行:BIOS只会读取磁盘前512字节作为MBR,而你的ELF文件中0xAA55魔数不在前512字节的最后两位,BIOS无法识别为有效的MBR。

4. 正确的链接脚本使用流程

  1. 编写汇编代码(无需org 0x7C00):
global start
start:
    ; 你的bootloader核心代码
    jmp $  ; 示例:无限循环
  1. 汇编为32位ELF目标文件:
nasm -f elf32 boot.s -o boot.o
  1. 用链接脚本生成MBR二进制:
ld -m elf_i386 -T link.ld boot.o -o boot.bin

此时生成的boot.bin应该是512字节,最后两位为0xAA55,可以正常被BIOS加载。

总结

  • org 0x7C00+nasm -f bin是编写MBR最直接、不易出错的方式,适合快速开发。
  • 链接脚本方式更灵活(比如支持多文件编译),但需要严格配置输出格式、地址布局和文件大小,才能达到和前者等效的效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 17:17:47