我已经用AT&T语法。假设将hello world
打印到屏幕上,然后通知用户按下任何键都会导致重新启动。只有在按下某个键之后,才可能启动重新启动。我的引导程序代码不等待密钥,并在打印信息后自动重新启动。为什么这个代码不等待击键,我该如何修复它?
我的引导扇区代码:
#generate 16-bit code
.code16
#hint the assembler that here is the executable code located
.text
.globl _start;
#boot code entry
_start:
jmp _boot #jump to boot code
welcome: .asciz "Hello, Worldnr" #here we define the string
AnyKey: .asciz "Press any key to reboot...nr"
.macro mWriteString str #macro which calls a function to print a string
leaw str, %si
call .writeStringIn
.endm
#function to print the string
.writeStringIn:
lodsb
orb %al, %al
jz .writeStringOut
movb $0x0e, %ah
int $0x10
jmp .writeStringIn
.writeStringOut:
ret
#Gets the pressed key
.GetPressedKey:
mov 0, %ah
int $0x16 #BIOS Keyboard Service
ret
.Reboot:
mWriteString AnyKey
call .GetPressedKey
#Sends us to the end of the memory
#causing reboot
.byte 0x0ea
.word 0x0000
.word 0xffff
_boot:
mWriteString welcome
call .Reboot
#move to 510th byte from the start and append boot signature
. = _start + 510
.byte 0x55
.byte 0xaa
Int 0x16 AH=0将等待击键:
键盘-获取按键
AH = 00h Return: AH = BIOS scan code AL = ASCII character
你的想法是正确的:
mov 0, %ah
int $0x16 #BIOS Keyboard Service
ret
问题是mov 0, %ah
将0视为内存操作数。在这种情况下,它将与将DS:[0]处的字节值移动到AH中相同。您只想将立即数(常量)值0移动到AH。在AT&T语法的立即值以美元符号$
开头。如果一个值没有前缀为$
,则GNU汇编程序假定它是内存引用。代码应该是:
mov $0, %ah
int $0x16 #BIOS Keyboard Service
ret
或者,您可以使用将AH归零
xor %ah, %ah
当您的引导加载程序加载时,您的代码对DS寄存器的值进行了一些假设,并且它不会设置自己的堆栈。关于编写一个能在更广泛的模拟器和实际硬件上运行的引导程序的一些好做法,你可能希望看看我在之前的Stackoverflow回答中给出的一些通用引导程序提示。
此外,在您的情况下,我可能会在代码之后移动您的数据,并在开始时删除JMP,因为您没有使用BIOS参数块。一些BIOS会在引导扇区开始时查找JMP,并假设您有一个BPB,并且可能会覆盖您的代码,认为它正在填充数据结构的值。避免这种情况的最佳方法是简单地避免将JMP作为第一条指令IF,因为您没有BPB。
您可能在一个展示您所需行为的模拟器下运行,但如果您将此引导加载程序移动到其他环境(甚至其他模拟器),您可能会发现它无法按预期工作。
最后,您手动编码一个跳远以进行重新启动:
.byte 0x0ea
.word 0x0000
.word 0xffff
尽管您可能不得不在MASM或TASM的一些旧版本中执行此操作,但使用AT&T语法支持这样做:
jmp $0xffff,$0x0000