INT 16h/AH=0h 不等待我的引导加载程序中的击键

INT 16h/AH=0h doesn't wait for keystroke in my bootloader

我使用 GNU 汇编程序和 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, World\n\r"  #here we define the string
  AnyKey: .asciz "Press any key to reboot...\n\r"
 .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 [=10=]x0e, %ah
      int  [=10=]x10
      jmp  .writeStringIn
 .writeStringOut:
 ret
#Gets the pressed key 
.GetPressedKey:
 mov 0, %ah
 int [=10=]x16  #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 将等待击键:

KEYBOARD - GET KEYSTROKE

AH = 00h

Return:
AH = BIOS scan code
AL = ASCII character

你的想法是对的:

mov 0, %ah
int [=11=]x16  #BIOS Keyboard Service 
ret 

问题是 mov 0, %ah 将 0 视为内存操作数。在这种情况下,它与将 DS:[0] 处的字节值移动到 AH 相同。您只想将立即(常量)值 0 移动到 AH。在 AT&T 语法中,立即值前面加上美元符号 $。如果一个值没有前缀 $ GNU 汇编器假定它是一个内存引用。代码应该是:

mov [=12=], %ah
int [=12=]x16  #BIOS Keyboard Service 
ret 

或者您可以使用以下方法将 AH 归零:

xor %ah, %ah

您的代码在您的引导加载程序加载时对 DS 寄存器的值做了一些假设,并且它没有设置自己的堆栈。有关编写适用于更广泛的仿真器和真实硬件的引导加载程序的一些良好实践,您可能希望查看我在之前的 Whosebug 回答中给出的一些

此外,在您的情况下,我可能会在代码之后移动您的数据并删除开头的 JMP ,因为您没有使用 BIOS Parameter Block 。某些 BIOS 会在引导扇区的开头寻找 JMP,并假设您有一个 BPB,并且可能实际上会覆盖您的代码,认为它正在填充数据结构的值。避免这种情况的最好方法是简单地避免将 JMP 作为第一条指令 IF 你没有 BPB。

您可能 运行 在表现出您需要的行为的模拟器下,但如果您将此引导加载程序移动到其他环境(甚至其他模拟器),您可能会发现它不起作用预期。


最后手动编码跳远重启:

.byte 0x0ea 
.word 0x0000 
.word 0xffff 

虽然在某些旧版本的 MASMTASM 中您可能不得不这样做,但具有 AT&T 语法的 GNU 汇编程序支持这样做这样:

jmp [=15=]xffff,[=15=]x0000