使用汇编读取输入(16位引导程序)

时间:2019-01-07 20:18:42

标签: assembly nasm bootloader

作为我的大学提供的一门课程,我遵循了一个教程,在http://3zanders.co.uk/2017/10/13/writing-a-bootloader/的Assembly中编写了16位的引导程序。这部分(第1部分)是到目前为止我应该做的所有事情。它基本上什么也没做,只是在屏幕上打印Hello World。

现在,请记住,这是我在Assembly中编写引导加载程序的唯一经验(这是我唯一的经验,期间)-现在,我应该将其扩展为一个菜单,用户可以从中选择一个菜单三个选项,然后相应地输出一个字符串ergo:

What is your favourite colour?
Press 1 for red
Press 2 for green
Press 3 for blue

[user input here]

Your favourite colour is [whatever corresponding colour].

我一直试图弄清楚从何处开始甚至到现在都已经结束了几个小时。我在Assembly中找到了选择菜单的一些示例,但问题是这些示例中的代码与本教程“教给我”的内容完全没有相似之处。我觉得我被迫从简单的将Hello World打印到屏幕,到制作根据用户输入打印不同输出的菜单,实现了飞跃。

这是我目前拥有的:

bits 16 ; tell NASM this is 16 bit code
org 0x7c00 ; tell NASM to start outputting stuff at offset 0x7c00
boot:
    mov si,startText ; point si register to startText label memory location
    mov ah,0x0e ; 0x0e means 'Write Character in TTY mode'
.loop:
    lodsb
    cmp al,51
    je blue
    cmp al,50
    je green
    cmp al,49
    je red

    or al,al ; is al == 0 ?
    jz getInput  ; if (al == 0) jump to halt label
    int 0x10 ; runs BIOS interrupt 0x10 - Video Services
    jmp .loop
getInput:
    mov ah,00h
    int 16h
red:
    db "Your favourite colour is red",0
green:
    db "Your favourite colour is green",0
blue:
    db "Your favourite colour is blue",0
halt:
    cli ; clear interrupt flag
    hlt ; halt execution
startText:
    db "",13,10
    db "what is your favourite colour?",13,10
    db "Press one for red",13,10
    db "Press two for green",13,10
    db "Press three for blue",13,10
    db 13,10,0

times 510 - ($-$$) db 0 ; pad remaining 510 bytes with zeroes
dw 0xaa55 ; magic bootloader magic - marks this 512 byte sector bootable!

EDIT2: 我再次更新了上面的代码,尝试实现Sep和John告诉我的内容。我意识到这不是应该的样子,他们告诉我的某些事情没有实现,因为我还不知道如何实现。

我认为现在的问题是在显示初始startLabel之后它什么也没做。如果我按任何按钮,什么都不会改变。如果有人能指出我正确的方向,将不胜感激!

enter image description here

2 个答案:

答案 0 :(得分:2)

1)您错过了@SepRoland的其中一项。您在.loop中的代码会加载每个字符,如果它是 NOT ==0,则会将其打印出来并重复循环。这意味着您有责任在数据中提供 0

db "",13,10

应为:

db 13,10,0

(请注意,””是一个空字符串-无需打印,因此没有必要。)

在屏幕截图上看到竖线(带有左勾号)吗?实际上,这是计算机为以下mov指令打印操作码!该垃圾输出是因为您的代码已停止打印数据,现在正在打印实际代码的字节。它将继续这样做,直到代码碰巧有一个0为止-幸运的是,它恰好是下一个字节!上面的,0将阻止所有这些情况。

2)好了,那么当它(最终)加载0时会发生什么呢?根据您的评论,它将“跳转以暂停标签”。果然,代码然后跳至clihlt指令-并且计算机停止运行。无法执行下面添加的mov ah,00hint 16h

您需要将这些行移动到halt标签之前-给它们加上自己的标签:getInput或其他名称。然后将上面的jz halt更改为jz getInput:您希望它获得输入,而不是停止!

然后,您需要添加代码以打印出结果。您已经知道如何打印字符串:您只需要打印与以前不同的字符串-这些字符串需要新的标签和不同的标签。而且不要忘记最后的0

Sep为您提供了我所描述的大部分内容;您还没有将所有内容放在一起。您需要在头脑中区分计算机将执行的代码与计算机将处理的数据。对PC来说,它们只是数字,它将很高兴地执行代码,然后在遇到数据时开始执行数据-至少“高兴”直到数据使它变得愚蠢!

[编辑] 3)看来我们需要回到第一原理。假设是计算机,拿起纸和笔,然后执行提供的说明。从最顶部开始:

  • 绘制一个框,将其标记为si,然后将startText放入其中。那是第一个mov
  • 绘制另一个框,将其标记为ah,然后将0x0e放入其中。那是第二个mov
  • 请牢记.loop行-您稍后将需要。
  • lodsb指令有点复杂。它使用si查看内存,将该值加载到al中(您需要一个新框),然后将其添加到si中。由于si持有startText,因此startText的第一个字节(13-请记住,""为空)被加载到al中。将13放在al中,然后在+1内附加si

      

    偶然地:花点时间考虑一下您刚刚加载的内容。这是要打印的字节串的第一个字节。因此,很快您将需要调用“打印字符”例程。

  • 现在,您正在将al51进行比较-3的ASCII值,就像Sep建议的那样。 (请注意,您实际上可以放'3'而不是51,以使代码更易于理解。请注意单引号(而不是双引号)。

      

    嗯……这是怎么回事?您加载了要打印的字符-现在您要检查它是否是数字3?那不是在处理答案吗?在您要求计算机获得答案之前?在甚至打印出要求用户键入答案的字符串之前?

您已经添加了建议的所有代码-但完全在错误的位置。在尝试编写执行这些操作的代码之前,您需要先退一步并用高级的语言写下您想要程序执行的操作。

我建议您执行以下操作:

  1. 写出要求用户选择哪种颜色的字符串
  2. 从用户那里获取输入
  3. 如果答案是三个预期答案之一,请写出结果。

    否则,写下“意外答案”,然后返回到步骤2。

  4. 停止
  5. 要打印的数据

最重要的是,所有这些代码都必须以正确的顺序组合在一起,中间没有数据。该代码不仅必须存在,而且还必须按照您希望计算机执行它们的顺序显示。

  

您拥有的是:

     

3。如果答案是三个预期答案之一,则写出结果。

     

1。编写字符串,询问用户喜欢哪种颜色

     

2。从用户那里获取输入

     

5。数据

     

4。停止

     

5。更多数据

答案 1 :(得分:1)

这将为您指明正确的方向。

hello: 
db "What is your favourite colour?",13,10
db "Press 1 for red"13,10
db "Press 2 for green"13,10
db "Press 3 for blue"13,10
db "",13,10

首先通过正确地将其终止为零而不忽略逗号来更正此消息:

hello: 
db "What is your favourite colour?",13,10
db "Press 1 for red",13,10
db "Press 2 for green",13,10
db "Press 3 for blue",13,10
db 13,10,0

要输入,可以在键盘int 16h上使用BIOS功能00h:

mov ah, 00h
int 16h

如果用户按下“ 1”,则AL寄存器将保留值49。
如果用户按下“ 2”,则AL寄存器将保留值50。
如果用户按下“ 3”,则AL寄存器将保留值51。

现在显示常见消息“您喜欢的颜色是”。在执行此操作期间,必须注意不要意外修改AL中的值。通过在代码的这一部分使用push ax ... pop ax来保留它。

然后测试您从阅读键盘获得的值,以便选择一个指向适当消息的指针(SI)。显示该消息(只是颜色的名称)。最后halt