程序集引导加载程序代码可在VM中使用,但在实际计算机上却很难

问题描述

我正在弄乱一些NASM代码,该代码对数字做一些数学运算并打印出与答案相对应的ASCII字符。这是代码

Pin<&mut Self>

在vm上运行时,它会打印出“ e”并正常工作。但是,当在启动USB设备的真实计算机上运行时,它变得异常复杂。我必须清除所有寄存器,甚至不需要清除的寄存器,然后将答案从一个寄存器移到另一个寄存器,以使其起作用。我不知道为什么需要这样做。如果代码略有不同,即使没有清除cx和dx之类的内容,也不会打印任何内容。为什么会这样呢?任何帮助表示赞赏。

解决方法

标准int 10h仅需要设置axbx,看来您已正确完成此操作。顶部bx的计算设置为零,ax的计算设置为0865H

    mov ax,1853      ; ax <- 073dH
    mov bl,15        ; bx <- ??0fH
    div bl            ; ax <- 087bH
    sub al,2         ; ax <- 0879H
    mov bx,10        ; bx <- 000AH
subtract:             ; ten times decrement bx,sub 2 from ax
    sub ax,2
    sub bx,1
    cmp bx,0
    jne subtract      ; ax <- 0865H,bx <- 0000H

然后根据需要设置寄存器:

mov bl,al            ; bx <- 0065H
mov ax,0             ; ax <- 0000H
mov cx,0             ; cx <- 0000H
mov dx,0             ; dx <- 0000H
mov ah,0x0e          ; ax <- 0e00H
mov al,bl            ; ax <- 0e65H
mov bx,0             ; bx <- 0000H

最终值ax/bx应该可以将e打印到控制台:

ah = 0eH : teletype output command
al = 65H : The 'e' character.
bh = 00H : page zero.
bl = 00H : forground color (only for graphic modes).

cx/dx的值应该无关紧要。有一个嵌入式BIOS替代品专门处理了cx = abcdH的值,但是在这里这不可能成为问题。

因此,无论是否使用“愚蠢”代码,您的实际代码似乎都可以。但是,正如评论中指出的那样,从USB引导存在一个已知问题(如果您正在这样做)-看来USB引导过程会强制引导扇区的第一位保留某些磁盘属性信息(BIOS参数块或BPB)。这意味着您必须将代码移开,以便它可以正常运行。

This answer提供了所有详细信息,而要解决此问题,您可能只需将代码移到末尾即可,例如:

    [bits 16]
    [org 0x7c00]
    jmp init
    times 510 - ($ - $$) - (last - init) db 0 ; leave as much space as possible.
init:
    jmp $ ; your actual code should go here.
last:
    dw 0xaa55

这样,您最终将获得足够的空间用于USB启动以放置BPB(假设您的代码不太长):

     1                    [bits 16]
     2                    [org 0x7c00]
     3 0000 E9F901        jmp init
     4 0003 00<rept>      times 510 - ($ - $$) - (last - init) db 0
     5                init:
     6 01FC EBFE          jmp $
     7                last:
     8 01FE 55AA          dw 0xaa55

当然,您可能只考虑将正确格式的自己 BPB放在此处。这样就不必将代码移到引导扇区末尾的麻烦了。