从iso映像启动为什么引导加载程序的内存地址不是0x7c00

L. *_*ang 1 x86 assembly osdev bootloader iso-image

我写了一个小bootloader用于学习目的,它会打印出bootloader第一条指令的内存地址,肯定是0x7c00。看下面的汇编源代码运行良好。

boot.s

.code16
.global init
init:
  mov $0x07c0, %ax
  mov %ax, %ds
  mov $0x07e0, %ax
  mov %ax, %ss
  mov $0x2000, %sp

  call next
next:
  pop %bx
  sub $(next-init), %bx  # starting point of memory address, now stored in %bx
  call print_register
  jmp .

print_register:  # always print out value in %bx
  mov %bh, %cl
  shr $0x4, %cl
  and $0x0f, %cl
  call print_digit
  mov %bh, %cl
  and $0x0f, %cl
  call print_digit
  mov %bl, %cl
  shr $0x4, %cl
  and $0x0f, %cl
  call print_digit
  mov %bl, %cl
  and $0x0f, %cl
  call print_digit
  ret

print_digit: # %cl has digit to be printed
  cmp $0x9, %cl
  jg print_digit_atof
print_digit_1to9:
  add $0x30, %cl
  jmp print_digit_out
print_digit_atof:
  add $0x57, %cl
print_digit_out:
  mov %cl, %al
  mov $0x0e, %ah
  int $0x10
  ret

.=510
.byte 0x55
.byte 0xaa
Run Code Online (Sandbox Code Playgroud)
as -o boot.o boot.s
ld -o boot.bin --oformat binary -e init boot.o
Run Code Online (Sandbox Code Playgroud)

在VMWare Player中创建一个虚拟机,并设置boot.bin为软盘的内容,然后开机。我可以看到7c00屏幕上打印的内容。

到目前为止,一切都很好。

请参考这个答案Creating a bootable ISO image with custom bootloader,但是现在如果我boot.bin通过以下命令将其作为引导加载程序放入iso映像中:

dd if=/dev/zero of=floppy.img bs=1024 count=1440
dd if=boot.bin of=floppy.img seek=0 count=1 conv=notrunc
mkdir iso
cp floppy.img iso/
genisoimage -quiet -V 'MYOS' -input-charset iso8859-1 -o myos.iso -b floppy.img \
    -hide floppy.img iso/
Run Code Online (Sandbox Code Playgroud)

并启动虚拟机myos.iso,屏幕上显示0000

为什么不是7c00


阅读答案后更新,当我打印出 %cs 时,我可以看到:

1. boot from floppy disk, start address is 0x0000:7c00
2. boot from cd rom, start address is 0x07c0:0000
Run Code Online (Sandbox Code Playgroud)

Ros*_*dge 5

这是由于对 El Torito CD-ROM 引导规范的常见误解造成的,该规范规定模拟引导扇区默认情况下应加载到“7C0 的传统段”。它并没有说应该使用非传统的起始地址 07C0:0000 来代替传统的 0000:7C00,但 BIOS 编写者仍然将其解释为一个要求。

虽然您可以假设引导扇区加载到线性地址 00007C00 并且 BIOS 在引导扇区的第一个字节处开始执行代码,但您不能假设 CS:IP 的任何特定值。虽然大多数引导扇区可以编写为不依赖于加载到 CS 中的段值,因为近 JMP 和 CALL 指令是相对的,如果您的引导扇区如此,那么您需要在代码中放置远 JMP 指令,以确保 CS 加载预期的内容段值:

  jmp $0x07c0,$start
start:
Run Code Online (Sandbox Code Playgroud)

请注意,上例中段 (0x07c0) 的选择是基于引导扇区的“org”为 0 的事实,因此假定引导扇区的第一个字节的偏移量为 0,而不是 0x7c00。这意味着将上述代码添加到引导扇区的开头,它将始终打印0000.