使用汇编读取输入(16 位引导加载程序)
Reading input using Assembly (16 bit 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 中找到了一些选择菜单的示例,但问题是这些示例中的代码与本教程中的代码毫无相似之处 "taught" 我。我觉得我被迫做出很大的飞跃,从简单地将 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!
编辑2:
我再次更新了上面的代码,试图实现 Sep 和 John 告诉我的内容。我意识到这不是应该的样子,他们告诉我的某些事情没有实施,因为我还不知道如何去做。
我认为现在的问题是它在显示初始 startLabel 后没有做任何事情。如果我按下任何按钮,什么都不会改变。如果有人能进一步指出我正确的方向,那将不胜感激!
这将为您指明正确的方向。
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
要输入您可以使用键盘上的 BIOS 函数 00h int 16h:
mov ah, 00h
int 16h
如果用户按下“1”,AL
寄存器将保存值 49。
如果用户按下“2”,AL
寄存器将保存值 50。
如果用户按下“3”,AL
寄存器将保存值 51。
现在显示普通消息"Your favourite colour is "。在此操作期间,您必须注意不要意外修改 AL
中的值。通过在这部分代码周围使用 push ax
... pop ax
来保存它。
然后测试您通过读取键盘获得的值,以便 select 一个指向合适消息的指针 (SI
)。显示该消息(只是一种颜色的名称)。最后 halt
.
1) 你错过了@SepRoland 的一个观点。 .loop
中的代码加载每个单独的字符,如果它是 NOT ==0
它会打印出来并重复环形。这意味着您有责任提供数据中的0
:
db "",13,10
应该是:
db 13,10,0
(请注意 ””
是一个空字符串 - 没有要打印的内容 - 因此没有必要。)
看到屏幕截图上的垂直条(带左勾号)了吗?这实际上是计算机打印出以下 mov
指令的操作码!垃圾输出是因为您的代码已停止打印数据,现在正在打印实际代码的字节。它将继续这样做,直到代码恰好有一个 0
- 这(幸运的是?)恰好是下一个字节!以上,0
将阻止这一切。
2) 好的,那么当它(最终)加载 0
时会发生什么?根据您的评论,它将“跳转到停止标签”。果然,代码然后跳转到 cli
和 hlt
指令 - 并且计算机停止。它没有机会执行您在下面添加的 mov ah,00h
和 int 16h
。
您需要将这些行移动到 halt
标签之前 - 并给它们自己的标签:getInput
或其他。然后将上面的 jz halt
更改为 jz getInput
:您希望它获得输入,而不是停止!
然后你需要添加打印结果的代码。您已经知道如何打印字符串:您只需要打印出与之前不同的字符串——您需要为这些字符串添加新的和不同的标签。并且不要每次都忘记最后的 0
!
Sep 为您提供了我所描述的大部分内容;你只是还没有把它们放在一起。您需要在脑海中区分计算机将执行的代码与计算机将处理的数据。对于 PC 来说,它们都只是数字,它会非常愉快地执行代码,然后在遇到它时开始执行数据 - 至少,“快乐”,直到数据让它做一些愚蠢的事情!
[编辑]
3)看来我们需要回到第一原则。假设你是电脑,拿一张纸和一支笔,然后执行你提供的指令。从最上面开始:
- 画一个方框,标记为
si
,然后将startText
放入其中。那是第一个mov
.
- 再画一个方框,标记为
ah
,然后将0x0e
放入其中。那是第二个mov
.
- 记下
.loop
行 - 稍后您将需要它。
lodsb
指令有点复杂。它使用 si
查看内存,将该值加载到 al
(您需要一个新框),然后将 1 添加到 si
。因为 si
包含 startText
,所以 startText
的第一个字节(13
- 请记住,""
是空的)被加载到 al
。将 13
放入 al
,然后将 +1
放入 si
.
Incidentally: take a moment to think about what you've just loaded. It's the first byte of a string of bytes that you want to print out. So pretty soon now you're going to need to call the "print character" routine.
现在您正在比较 al
和 51
- 3
的 ASCII 值,就像 Sep 所建议的那样。 (请注意,您实际上可以使用 '3'
而不是 51
,以使代码更易于理解。请注意单引号(而非双引号)。)
Ummm… What's going on here? You loaded a character to print - and now you're checking to see if it's the number 3? Isn't that processing the answer? Before you've asked the computer to even get the answer? Before you've even printed out the string that asks the user to type the answer?
您已经正确添加了建议的代码 - 但完全在错误的位置。在尝试编写执行这些操作的代码之前,您需要退后一步,用高级语言写下您希望程序执行的操作。
我建议您执行以下操作:
- 写出询问用户喜欢哪种颜色的字符串
- 获取用户的输入
如果答案是三个预期答案之一,写出结果。
否则,写出"Unexpected answer",返回第2步
- 停止
- 要打印的数据
最重要的是所有这些代码需要以正确的顺序放在一起,中间没有数据。代码不仅必须存在,而且还必须按照您希望计算机执行它们的顺序显示。
What you have is:
3.If the answer is one of the three expected answers, write out the result.
1.Write out the string asking for which colour the user prefers
2.Get the input from the user
5.Data
4.Halt
5.More data
作为我的大学开设的一门课程,我按照 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 中找到了一些选择菜单的示例,但问题是这些示例中的代码与本教程中的代码毫无相似之处 "taught" 我。我觉得我被迫做出很大的飞跃,从简单地将 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!
编辑2: 我再次更新了上面的代码,试图实现 Sep 和 John 告诉我的内容。我意识到这不是应该的样子,他们告诉我的某些事情没有实施,因为我还不知道如何去做。
我认为现在的问题是它在显示初始 startLabel 后没有做任何事情。如果我按下任何按钮,什么都不会改变。如果有人能进一步指出我正确的方向,那将不胜感激!
这将为您指明正确的方向。
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
要输入您可以使用键盘上的 BIOS 函数 00h int 16h:
mov ah, 00h
int 16h
如果用户按下“1”,AL
寄存器将保存值 49。
如果用户按下“2”,AL
寄存器将保存值 50。
如果用户按下“3”,AL
寄存器将保存值 51。
现在显示普通消息"Your favourite colour is "。在此操作期间,您必须注意不要意外修改 AL
中的值。通过在这部分代码周围使用 push ax
... pop ax
来保存它。
然后测试您通过读取键盘获得的值,以便 select 一个指向合适消息的指针 (SI
)。显示该消息(只是一种颜色的名称)。最后 halt
.
1) 你错过了@SepRoland 的一个观点。 .loop
中的代码加载每个单独的字符,如果它是 NOT ==0
它会打印出来并重复环形。这意味着您有责任提供数据中的0
:
db "",13,10
应该是:
db 13,10,0
(请注意 ””
是一个空字符串 - 没有要打印的内容 - 因此没有必要。)
看到屏幕截图上的垂直条(带左勾号)了吗?这实际上是计算机打印出以下 mov
指令的操作码!垃圾输出是因为您的代码已停止打印数据,现在正在打印实际代码的字节。它将继续这样做,直到代码恰好有一个 0
- 这(幸运的是?)恰好是下一个字节!以上,0
将阻止这一切。
2) 好的,那么当它(最终)加载 0
时会发生什么?根据您的评论,它将“跳转到停止标签”。果然,代码然后跳转到 cli
和 hlt
指令 - 并且计算机停止。它没有机会执行您在下面添加的 mov ah,00h
和 int 16h
。
您需要将这些行移动到 halt
标签之前 - 并给它们自己的标签:getInput
或其他。然后将上面的 jz halt
更改为 jz getInput
:您希望它获得输入,而不是停止!
然后你需要添加打印结果的代码。您已经知道如何打印字符串:您只需要打印出与之前不同的字符串——您需要为这些字符串添加新的和不同的标签。并且不要每次都忘记最后的 0
!
Sep 为您提供了我所描述的大部分内容;你只是还没有把它们放在一起。您需要在脑海中区分计算机将执行的代码与计算机将处理的数据。对于 PC 来说,它们都只是数字,它会非常愉快地执行代码,然后在遇到它时开始执行数据 - 至少,“快乐”,直到数据让它做一些愚蠢的事情!
[编辑] 3)看来我们需要回到第一原则。假设你是电脑,拿一张纸和一支笔,然后执行你提供的指令。从最上面开始:
- 画一个方框,标记为
si
,然后将startText
放入其中。那是第一个mov
. - 再画一个方框,标记为
ah
,然后将0x0e
放入其中。那是第二个mov
. - 记下
.loop
行 - 稍后您将需要它。 lodsb
指令有点复杂。它使用si
查看内存,将该值加载到al
(您需要一个新框),然后将 1 添加到si
。因为si
包含startText
,所以startText
的第一个字节(13
- 请记住,""
是空的)被加载到al
。将13
放入al
,然后将+1
放入si
.Incidentally: take a moment to think about what you've just loaded. It's the first byte of a string of bytes that you want to print out. So pretty soon now you're going to need to call the "print character" routine.
现在您正在比较
al
和51
-3
的 ASCII 值,就像 Sep 所建议的那样。 (请注意,您实际上可以使用'3'
而不是51
,以使代码更易于理解。请注意单引号(而非双引号)。)Ummm… What's going on here? You loaded a character to print - and now you're checking to see if it's the number 3? Isn't that processing the answer? Before you've asked the computer to even get the answer? Before you've even printed out the string that asks the user to type the answer?
您已经正确添加了建议的代码 - 但完全在错误的位置。在尝试编写执行这些操作的代码之前,您需要退后一步,用高级语言写下您希望程序执行的操作。
我建议您执行以下操作:
- 写出询问用户喜欢哪种颜色的字符串
- 获取用户的输入
如果答案是三个预期答案之一,写出结果。
否则,写出"Unexpected answer",返回第2步
- 停止
- 要打印的数据
最重要的是所有这些代码需要以正确的顺序放在一起,中间没有数据。代码不仅必须存在,而且还必须按照您希望计算机执行它们的顺序显示。
What you have is:
3.If the answer is one of the three expected answers, write out the result.
1.Write out the string asking for which colour the user prefers
2.Get the input from the user
5.Data
4.Halt
5.More data