从 iso 映像引导为什么引导加载程序的内存地址不是 0x7c00
Booting from iso image why memory address of bootloader is not 0x7c00
为了学习写了一个小bootloader,会打印出bootloader第一条指令的内存地址,肯定是0x7c00。看下面的汇编源码是运行好
boot.s
.code16
.global init
init:
mov [=10=]x07c0, %ax
mov %ax, %ds
mov [=10=]x07e0, %ax
mov %ax, %ss
mov [=10=]x2000, %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 [=10=]x4, %cl
and [=10=]x0f, %cl
call print_digit
mov %bh, %cl
and [=10=]x0f, %cl
call print_digit
mov %bl, %cl
shr [=10=]x4, %cl
and [=10=]x0f, %cl
call print_digit
mov %bl, %cl
and [=10=]x0f, %cl
call print_digit
ret
print_digit: # %cl has digit to be printed
cmp [=10=]x9, %cl
jg print_digit_atof
print_digit_1to9:
add [=10=]x30, %cl
jmp print_digit_out
print_digit_atof:
add [=10=]x57, %cl
print_digit_out:
mov %cl, %al
mov [=10=]x0e, %ah
int [=10=]x10
ret
.=510
.byte 0x55
.byte 0xaa
as -o boot.o boot.s
ld -o boot.bin --oformat binary -e init boot.o
在VMWare Player中创建虚拟机,将boot.bin
设置为软盘内容,然后开机。我可以在屏幕上看到 7c00
。
到目前为止一切顺利。
参考这个答案,但是现在如果我通过以下命令将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/
并使用 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
这是由于对 El Torito CD-ROM 引导规范的常见误解造成的,该规范认为模拟引导扇区默认应加载到 "traditional segment of 7C0"。它并没有说应该使用非传统的起始地址 07C0:0000 来代替传统的 0000:7C00,但是 BIOS 作者仍然将此解释为一项要求。
虽然您可以假定您的引导扇区加载到线性地址 00007C00 并且 BIOS 在引导扇区的第一个字节开始执行您的代码,但您不能假定任何特定值 CS:IP.虽然大多数引导扇区可以编写为不依赖于加载到 CS 中的段值,因为 near JMP 和 CALL 指令是相对的,如果你这样做,那么你需要在你的代码中放置一个 far JMP 指令以确保 CS 加载了预期的段值:
jmp [=10=]x07c0,$start
start:
注意上面例子中段(0x07c0)的选择是基于你的bootsector的"org"为0,所以假设bootsector第一个字节的偏移量是0 而不是 0x7c00。这意味着将上面的代码添加到引导扇区的开头,它将始终打印 0000
.
为了学习写了一个小bootloader,会打印出bootloader第一条指令的内存地址,肯定是0x7c00。看下面的汇编源码是运行好
boot.s
.code16
.global init
init:
mov [=10=]x07c0, %ax
mov %ax, %ds
mov [=10=]x07e0, %ax
mov %ax, %ss
mov [=10=]x2000, %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 [=10=]x4, %cl
and [=10=]x0f, %cl
call print_digit
mov %bh, %cl
and [=10=]x0f, %cl
call print_digit
mov %bl, %cl
shr [=10=]x4, %cl
and [=10=]x0f, %cl
call print_digit
mov %bl, %cl
and [=10=]x0f, %cl
call print_digit
ret
print_digit: # %cl has digit to be printed
cmp [=10=]x9, %cl
jg print_digit_atof
print_digit_1to9:
add [=10=]x30, %cl
jmp print_digit_out
print_digit_atof:
add [=10=]x57, %cl
print_digit_out:
mov %cl, %al
mov [=10=]x0e, %ah
int [=10=]x10
ret
.=510
.byte 0x55
.byte 0xaa
as -o boot.o boot.s
ld -o boot.bin --oformat binary -e init boot.o
在VMWare Player中创建虚拟机,将boot.bin
设置为软盘内容,然后开机。我可以在屏幕上看到 7c00
。
到目前为止一切顺利。
参考这个答案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/
并使用 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
这是由于对 El Torito CD-ROM 引导规范的常见误解造成的,该规范认为模拟引导扇区默认应加载到 "traditional segment of 7C0"。它并没有说应该使用非传统的起始地址 07C0:0000 来代替传统的 0000:7C00,但是 BIOS 作者仍然将此解释为一项要求。
虽然您可以假定您的引导扇区加载到线性地址 00007C00 并且 BIOS 在引导扇区的第一个字节开始执行您的代码,但您不能假定任何特定值 CS:IP.虽然大多数引导扇区可以编写为不依赖于加载到 CS 中的段值,因为 near JMP 和 CALL 指令是相对的,如果你这样做,那么你需要在你的代码中放置一个 far JMP 指令以确保 CS 加载了预期的段值:
jmp [=10=]x07c0,$start
start:
注意上面例子中段(0x07c0)的选择是基于你的bootsector的"org"为0,所以假设bootsector第一个字节的偏移量是0 而不是 0x7c00。这意味着将上面的代码添加到引导扇区的开头,它将始终打印 0000
.