我想检查一下我对以下引导程序代码的理解:
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:
添加斧头,288
mov ss,ax
mov sp,4096
下面是内存中的代码和分配的空间的图表,如下所示。
注意:此图中的引导程序和内存引用很可能是错误的,我假设它不是顺序的,并且汇编程序将以不同的方式编译机器代码。但是,代码的开始将从较低的内存地址(0x7C00)开始,引导签名将从较高的地址(0xaa55磁盘签名从0x7c0:0x1fe(物理地址0x7c0 * 16 + 0x1fe = 0x7dfe)开始第一个512字节扇区的最后两个字节,从0x7c0:0x0000到0x7c0:0x200(0x7C32,即512字节的末尾))。
奇怪的是,看到分配的空间是两个4096字节的块:一个用于堆栈,另一个包含代码和数据。我怀疑我在这里错过了一些东西。
答案 0 :(得分:1)
以下是引导加载程序代码:
缺少有关如何设置汇编代码的相对地址的信息,即如何计算局部偏移量。通常,引导加载程序以org 0x7C00
开头,以明确表明期望从cs:ip = 0000:7C00
开始的代码。但是您会这样做,ds=07C0
会是错误的,因为有人建议代码期望偏移量像从07C0:0000
而不是0000:7C00
开始一样被汇编。虽然两个地址都针对相同的物理内存地址,但是segment:offset对却不同。
每个段以16字节为块递增,因此07C0h将为您提供地址范围0x7C00-0x7C0F。下一个段07C1h将为您提供地址0x7C10-0x7C1F。
每个段为您提供64kiB的范围,尽管起始地址仅增加16个字节,所以段之间有很多重叠,您可以通过许多组合来寻址相同的物理地址。即ds=07C0
使您可以进入物理内存范围07C00-17BFF
。
然后,您将值转换为十六进制是错误的(另请参阅Michael注释),288 = 0x120,以及4096 = 0x1000,但是您正确地得出结论:512B的引导加载程序代码(块设备的单个扇区),4096B的备用空间,然后是4096B的堆栈空间。您是否希望通过向堆栈中推入4096个以上的字节来填充堆栈,所以它不会在代码执行后到达备用空间,而是会缠绕到08E0:FFFE
(远高于堆栈的原始开头)。
我假设它不是顺序的,汇编器将以不同的方式编译机器代码。
与之相反,指令和源代码中定义的字节在生成的机器代码中顺序发出。使用“列表”命令行开关来查看汇编程序如何发出特定行的机器代码。例如,您是否将text_string db 'This is my cool new OS!', 0
行移到BITS 16
指令之后的开头,那么该文本将位于机器代码的开头,由BIOS从0000:7C00
地址加载和执行,执行文本字节作为指令。