Ric*_*wal 2 assembly bios nasm bootloader x86-16
我试图从Bootloader编写引导加载程序。写的代码是
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
Run Code Online (Sandbox Code Playgroud)
我不明白的是我们为什么要写 jmp$. 通过写入jmp$,它进入无限循环。所以,进入无限循环后,最后两行
times 510-($-$$) db 0 ; Pad remainder of boot sector with 0s
dw 0xAA55 ; The standard PC boot signature
Run Code Online (Sandbox Code Playgroud)
永远不会被执行。
此外,为什么我们要在 ax 上添加 288?
$是当前指令的地址,jmp $循环到自身也是如此。这通常是针对致命错误而执行的。
这里,加载器是不完整的,所以它输出一条消息然后循环。“循环”指令[希望]将被真正的代码[待添加]取代。
db用或dw伪操作定义的事物是数据的定义,而不是可执行指令[通常 - 除非您需要汇编器未知的特殊指令]。
因此,如果没有无限循环,您将尝试执行 at 处的数据text_string:,这将产生未定义/意外的结果,更不用说尝试执行引导块的最后部分了。
偏移量288...
引导加载到地址0x07C00。(0x07C00 + 4096 + 512)它正在尝试在位置-->设置其堆栈段0x8E00。但是,它试图将其放入段寄存器中,因此该值必须右移 4 位。已经移位并且0x07C0是或。最终的值是--> [at address ]288(4096 + 512) >> 40x0120SS0x07C0 + 0x01200x08E00x8E00
这似乎是错误的(即算术不匹配),但sp寄存器设置为4096,因此最终的安息地ss:sp是地址0x9E00。
在8086实模式寻址中,所有地址都使用段寄存器和一些偏移量。最终地址为:address = (segreg << 4) + offset。这是由硬件在以某种方式访问内存的每条指令上完成的。
当你在代码中跳转时,你使用CS[代码段]寄存器。数据访问使用DS[数据段]寄存器。以及堆栈访问(例如push/pop或%sp相对的,使用SS[堆栈段]寄存器。还有一个ES[额外段]寄存器用于字符串指令中。