本文介绍了NASM引导加载程序中的JMP$的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从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

我不明白的是,我们为什么要写JMP$。通过编写JMP$,它进入无限循环。因此,在进入无限循环后,最后两行

times 510-($-$$) db 0   ; Pad remainder of boot sector with 0s
    dw 0xAA55       ; The standard PC boot signature

从不执行。

此外,我们为什么要向AX添加288个?

推荐答案

$是当前指令的地址,因此jmp $循环到其自身。这通常是在发生致命错误时执行的。

这里,加载器是不完整的,所以它输出一条消息,然后循环。"循环"指令[希望]将被实际代码[添加]所取代。

使用dbdw伪操作定义的内容是数据的定义,而不是可执行指令[通常--除非您需要汇编程序不知道的特殊指令]。

因此,如果没有无限循环,您将尝试在text_string:处执行数据,这将产生未定义/意外的结果,更不用说尝试执行引导块的最后部分了。


288偏移量...

引导装入地址0x07C00。它正在尝试在(0x07C00 + 4096 + 512)-->0x8E00位置设置其堆栈段。但是,它试图将其放入段寄存器,因此该值必须右移4位。0x07C0移位,288(4096 + 512) >> 40x0120SS的最终值是0x07C0 + 0x0120-->[在地址0x8E00]

这似乎是错误的(即算术不匹配),但sp寄存器设置为4096,因此ss:sp的最终休眠位置是地址0x9E00

在8086实模式寻址中,所有地址都使用一个段寄存器和一些偏移量。最后的地址是:address = (segreg << 4) + offset。这是由硬件以某种方式访问内存的每条指令完成的。

当您在代码中跳来跳去时,您使用CS[代码段]寄存器。数据访问使用DS[数据段]寄存器。和堆栈访问(例如push/pop%sp相对),使用SS[堆栈段]寄存器。还有一个ES[Extra Segment]寄存器用于字符串指令。

这篇关于NASM引导加载程序中的JMP$的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-03 06:57