我试图编写引导加载程序引导装载程序。写的代码是
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
我不明白的是我们为什么要写 jmp$.通过写入jmp$,它进入无限循环。所以,进入无限循环后,最后两行
times 510-($-$$) db 0 ; Pad remainder of boot sector with 0s
dw 0xAA55 ; The standard PC boot signature
永远不会被执行。
此外,为什么我们要在 ax 上添加 288?
$
是当前指令的地址,所以jmp $
正在循环自身。这通常是针对致命错误而执行的。
这里,加载器是不完整的,所以它输出一条消息然后循环。 “循环”指令[希望]将被真正的代码[待添加]取代。
定义的事物db
or dw
伪操作是定义data并且是not可执行指令[通常——除非您需要汇编器未知的特殊指令]。
因此,如果没有无限循环,您将尝试执行以下位置的数据text_string:
,这会产生未定义/意外的结果,更不用说尝试执行引导块的最后部分了。
The 288
抵消 ...
引导加载到地址0x07C00
。它正在尝试在位置设置其堆栈段(0x07C00 + 4096 + 512)
--> 0x8E00
。但是,它试图将其放入段寄存器中,因此该值必须右移 4 位。0x07C0
is already转移和288
is (4096 + 512) >> 4
or 0x0120
。最终值为SS
is 0x07C0 + 0x0120
--> 0x08E0
[在地址0x8E00
]
这似乎是错误的(即算术不匹配),但是sp
寄存器设置为4096
,所以最后的安息地ss:sp
是地址0x9E00
.
在8086实模式寻址中,所有地址都使用段寄存器和一些偏移量。最终地址为:address = (segreg << 4) + offset
。这是由硬件在以某种方式访问内存的每条指令上完成的。
当你在代码中跳转时,你可以使用CS
[代码段]寄存器。数据访问使用DS
[数据段]寄存器。和堆栈访问(例如push/pop
or %sp
相对,使用SS
[堆栈段]寄存器。还有一个ES
[额外段] 字符串指令中使用的寄存器。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)