这是溢出,还是更多的键盘数据?
Is this an overflow, or maybe more keyboard data?
我正在编写引导加载程序,它的功能基本上仅限于打印字符串,然后在键入时将键盘字符复制到屏幕上。在编写读取和写入密钥的例程时,我注意到我的打印例程没有检测到存储键入密钥的双字数组的偏移量(加号)中的空终止符。现在我只是在重置终结器,但我想我会问这里发生了什么。有问题的行标有 ; THIS LINE
.
bits 16
org 0x7C00
start: jmp main
; IMPORTED GET KEY BLOCKING
; IN: NONE
; OUT: AX
bgetkey:
pusha
mov ax, 0
mov ah, 10h
int 16h
mov [.buf], ax
popa
mov ax, [.buf]
ret
.buf dw 0
; END IMPORTED FILE
; IMPORTED PRINT STRING TO SCREEN
; IN: ds->si
; OUT: NONE
prints:
mov ah, 0x0e
mov al, [si]
cmp al, 0
jz print_end
mov bh, 0x00
mov bl, 0x07
int 0x10
inc si
jmp prints
print_end:
ret
; END IMPORTED FILE
main:
mov ax, 0x0000 ; clear ax and
mov ds, ax ; data segment
mov si, welcome
call prints
type:
mov si, qbuf
call bgetkey
mov [qbuf], ax
mov dword [qbuf + 1], 0 ; THIS LINE
call prints
jmp type
welcome db "moose os", 0x0A, 0x0D, 0x00
newline db 0x0D, 0x0A, 0x00
qbuf dw 0, 0
times 0200h - 2 - ($ - $$) db 0
dw 0xAA55
如果我注释掉有问题的行,这就是键入 "abcdefg" 的输出:
这是未注释行的所需输出:
为什么我必须重置 qbuf + 1
?
问题是INT 16h AH=00h returns一个AL中的ASCII字符码,AH中的一个扫描码。 mov [qbuf], ax
指令将两者都存储在缓冲区中,但 INT 10h AH=0Eh 仅打印 ASCII 字符。它最终会将您存储在缓冲区中的扫描码解释为 ASCII 字符,并相应地在屏幕上显示它。
您的 mov dword [qbuf + 1], 0
语句通过在 qbuf
中的第一个字符后写入 4 个零字节解决了这个问题。这将覆盖存储在 qbuf
的第二个字节中的扫描码。它还将剩余的两个字节设置为 0,并在 4 字节长 qbuf
末尾再设置一个字节。 qbuf
之后的任何内容都会被此语句覆盖,但幸运的是那里什么都没有。
你应该做什么:
call bgetkey
mov [qbuf], al
mov byte [qbuf + 1], 0
call prints
第二个 MOV 指令在你的程序中不是必需的,因为它现在是 0。这仍然是一个好主意,所以如果你最终使用 qbuf
用于您程序中的其他内容。
我正在编写引导加载程序,它的功能基本上仅限于打印字符串,然后在键入时将键盘字符复制到屏幕上。在编写读取和写入密钥的例程时,我注意到我的打印例程没有检测到存储键入密钥的双字数组的偏移量(加号)中的空终止符。现在我只是在重置终结器,但我想我会问这里发生了什么。有问题的行标有 ; THIS LINE
.
bits 16
org 0x7C00
start: jmp main
; IMPORTED GET KEY BLOCKING
; IN: NONE
; OUT: AX
bgetkey:
pusha
mov ax, 0
mov ah, 10h
int 16h
mov [.buf], ax
popa
mov ax, [.buf]
ret
.buf dw 0
; END IMPORTED FILE
; IMPORTED PRINT STRING TO SCREEN
; IN: ds->si
; OUT: NONE
prints:
mov ah, 0x0e
mov al, [si]
cmp al, 0
jz print_end
mov bh, 0x00
mov bl, 0x07
int 0x10
inc si
jmp prints
print_end:
ret
; END IMPORTED FILE
main:
mov ax, 0x0000 ; clear ax and
mov ds, ax ; data segment
mov si, welcome
call prints
type:
mov si, qbuf
call bgetkey
mov [qbuf], ax
mov dword [qbuf + 1], 0 ; THIS LINE
call prints
jmp type
welcome db "moose os", 0x0A, 0x0D, 0x00
newline db 0x0D, 0x0A, 0x00
qbuf dw 0, 0
times 0200h - 2 - ($ - $$) db 0
dw 0xAA55
如果我注释掉有问题的行,这就是键入 "abcdefg" 的输出:
这是未注释行的所需输出:
为什么我必须重置 qbuf + 1
?
问题是INT 16h AH=00h returns一个AL中的ASCII字符码,AH中的一个扫描码。 mov [qbuf], ax
指令将两者都存储在缓冲区中,但 INT 10h AH=0Eh 仅打印 ASCII 字符。它最终会将您存储在缓冲区中的扫描码解释为 ASCII 字符,并相应地在屏幕上显示它。
您的 mov dword [qbuf + 1], 0
语句通过在 qbuf
中的第一个字符后写入 4 个零字节解决了这个问题。这将覆盖存储在 qbuf
的第二个字节中的扫描码。它还将剩余的两个字节设置为 0,并在 4 字节长 qbuf
末尾再设置一个字节。 qbuf
之后的任何内容都会被此语句覆盖,但幸运的是那里什么都没有。
你应该做什么:
call bgetkey
mov [qbuf], al
mov byte [qbuf + 1], 0
call prints
第二个 MOV 指令在你的程序中不是必需的,因为它现在是 0。这仍然是一个好主意,所以如果你最终使用 qbuf
用于您程序中的其他内容。