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

从零手写Boot Loader:未设置ES寄存器为何仍能正常工作?

关于《Writing tiny OS from scratch》磁盘读取代码中ES寄存器的疑问

我正在跟着Nick Blundell的《Writing tiny OS from scratch》学习从零编写操作系统,已经完成了大部分内容和习题。在学习磁盘扇区读取章节时,发现书中示例代码存在疑问:

代码中有一行注释标注:

mov bx, 0x9000      ;load 5 sectors to 0x0000(ES):0x9000(BX) Why?

但完整示例代码中并未对ES寄存器进行任何设置,完整代码如下:

[org 0x7c00]
;;; read secotrs from the boot disk
    mov [BOOT_DRIVE], dl    ;bios stores our drive in dl, remember later
    mov bp, 0x8000
    mov sp, bp

    mov bx, 0x9000      ;load 5 sectors to 0x0000(ES):0x9000(BX) Why?
    mov dh, 5       ; this is an error by the book, shall be 2
                ; i've added however the missing 3 sectors 

    mov dl, [BOOT_DRIVE]
    call disk_load       

    mov dx, [0x9000]
    call print_hex

    mov dx, [0x9000 + 512]          ;first
    call print_hex

    mov dx, [0x9000 + 512 + 512]        ;second
    call print_hex

    mov dx, [0x9000 + 512 + 512 + 512]  ;third
    call print_hex

    mov dx, [0x9000 + 512 + 512 + 512 + 512] ;fourth
    call print_hex
    
    jmp $
    %include "../utils/print_string.asm"
    %include "../utils/print_hex.asm"
    %include "../utils/disk_load.asm"
;;; variables for later
BOOT_DRIVE:  db 0
    times 510-($-$$) db 0
    dw 0xaa55

;;; we know bios will load only first 512 bytes from disk so we in purpose add 
;;; more sectors to our code by repeating some familiar numbers so we can prove
;;; we actually loaded those 5 sectors from the disk
    times 256 dw 0xdada
    times 256 dw 0xface
    times 256 dw 0xdead
    times 256 dw 0xbeef
    times 256 dw 0x1111

我已修正书中的错误(将dh的值改为2并补充了对应扇区数据),且代码能通过以下脚本正常编译运行并输出正确结果:

#!/bin/bash
nasm boot_sec.asm -f bin -o boot_sec.bin
qemu-system-amd64 boot_sec.bin

但我有两个疑问:

  • 未设置ES寄存器却能正常工作的原理是什么?
  • 如何在原示例中更明确地体现ES与BX的关联?

未设置ES却正常工作的原因

BIOS在将引导扇区加载到内存0x7c00并跳转执行时,ES寄存器的初始值默认是0x0000。这是x86实模式下BIOS引导的标准行为——绝大多数BIOS会将段寄存器(包括ES、DS等)初始化为0。

实模式下物理地址的计算公式是:段基址 × 16 + 偏移量。当ES=0时,ES:BX对应的物理地址就是0×16 + 0x9000 = 0x9000,和你代码中直接访问[0x9000]的物理地址完全一致。因此磁盘加载的数据会被写入正确位置,后续读取自然能得到预期结果。

需要注意:这个默认行为是BIOS的通用约定,但并非所有老旧BIOS都严格遵守,显式设置ES是更严谨的做法,能避免潜在的兼容性问题。

如何明确体现ES与BX的关联

要在代码中清晰展示ES和BX的配合逻辑,只需在设置BX之前显式将ES设置为0即可,同时可以优化注释让意图更明确:

修改代码中的对应片段:

mov ax, 0x0000   ; 显式初始化段寄存器ES为0
mov es, ax
mov bx, 0x9000   ; 磁盘数据将被加载到ES:BX指向的物理地址(0x0000*16 + 0x9000 = 0x9000)

如果想进一步验证ES的作用,还可以尝试调整段寄存器和偏移量的组合:比如将ES设为0x0900,BX设为0x0000,此时ES:BX对应的物理地址仍是0x0900×16 + 0x0000 = 0x9000,运行后结果和之前一致,能直观验证实模式下地址计算的逻辑。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.02 05:13:11