【发布时间】:2018-09-01 10:19:15
【问题描述】:
我想检查一下我对以下引导加载程序代码的理解:
BITS 16
start:
mov ax, 07C0h ; Set up 4K stack space after this bootloader
add ax, 288 ; (4096 + 512) / 16 bytes per paragraph
mov ss, ax
mov sp, 4096
mov ax, 07C0h ; Set data segment to where we're loaded
mov ds, ax
mov si, text_string ; Put string position into SI
call print_string ; Call our string-printing routine
jmp $ ; Jump here - infinite loop!
text_string db 'This is my cool new OS!', 0
print_string: ; Routine: output string in SI to screen
mov ah, 0Eh ; int 10h 'print char' function
.repeat:
lodsb ; Get character from string
cmp al, 0
je .done ; If char is zero, end of string
int 10h ; Otherwise, print it
jmp .repeat
.done:
ret
times 510-($-$$) db 0 ; Pad remainder of boot sector with 0s
dw 0xAA55 ; The standard PC boot signature
以下是我对代码的理解:
移动斧头,07C0h:
- 内存地址可以从栈段值(存储在ss寄存器中)和偏移量(存储在sp寄存器中)中获得。您可以通过执行以下操作获取地址:堆栈段值 x 16 + 偏移值。
- 我们正在使用段 07C0h 在我们的代码中设置空间。所以当 07C0h 偏移 0 时,它将引用到 0x7C00 的地址。 BIOS 尝试从 0x7C00 引导代码。在 0x7C00 中复制的代码示例是 MBR。
- 每个段以 16 字节为单位递增,因此 07C0h 将为您提供地址范围 0x7C00-0x7C0F。下一段 07C1h 将为您提供地址 0x7C10-0x7C1F。
加斧头,288
- 要在引导加载程序之后设置 4K 堆栈空间,我们需要添加从 (4096 + 512)/16 字节获得的 288 每段。十进制值 288 等于 120h。
- 现在存储在 ax 寄存器中的值是 08e0h,我通过以下方式获得:07c0h + 120h = 08e0h(120h 是十进制的 288)。
mov ss, ax
- 将寄存器 ax 中的值复制到 ss 寄存器中。偏移量现在包含段:08e0h。
mov sp, 4096
- 偏移值为 4096,即 0x1000h。 ss:sp 对的值为 08e0:1000。
- 栈底从内存地址 0x8e00 开始,栈顶在 0x9e00(从 0x8e00 + 0x1000 = 0x9e00)。
这是内存中的代码和分配的空间的图表,如下所示。
注意:此图中的引导加载程序和内存引用很可能不正确,我假设它不会是连续的,并且汇编器将以不同的方式编译机器代码。但是,代码的开头将从较低的内存地址 (0x7C00) 开始,引导签名将从较高的地址开始(0xaa55 磁盘签名从 0x7c0:0x1fe 开始(物理地址 0x7c0*16 + 0x1fe=0x7dfe),它们是第一个 512 字节扇区的最后两个字节,从 0x7c0:0x0000 运行到 0x7c0:0x200(0x7C32 是 512 字节的结尾))。
奇怪的是,分配的空间是两个 4096 字节的块:一个用于堆栈,另一个包含代码和数据。我怀疑我在这里遗漏了一些东西。
【问题讨论】:
-
0x7C0 放入 AX。 288(十进制)被添加到它。 288 十进制是 0x120。所以在添加 AX=0x8e0 之后。 0x8e0 放置在 SS(堆栈段)中。4096(0x1000)放置在 SP 中。因此堆栈指针为 SS:SP=0x8e0:0x1000 。即物理地址0x8e0*16+0x1000=0x9E00。堆栈从那里向下增长,但会在 0x8e0:0000 处回绕到 64kb 段的顶部。
-
0xaa55 磁盘签名从 0x7c0:0x1fe(物理地址 0x7c0*16+0x1fe=0x7dfe)开始,这是从 0x7c0:0x0000 运行到 0x7c0:0x200 的第一个 512 字节扇区的最后两个字节
-
谢谢。为了便于其他人在参考这篇文章时理解,我已经编辑了 Michael Petch 所做的更正。更正是 18h 到 120h(十进制 288)、07d8h 到 08e0h(7c0h + 120h)、256h 到 1000h(十进制 4096)、堆栈顶部在 0x9e00、堆栈包装在 0x8e00 和引导签名地址:0x7dfe。
标签: assembly x86-16 bootloader real-mode