字符串不会在汇编程序中打印出来

时间:2012-09-25 00:06:42

标签: assembly x86 keyboardinterrupt

我正在尝试通过DOS中的汇编程序x86学习一些深度编程,因为它启用了实际的地址模式。但是在我尝试这样做时,我试图制作一个打印出来的程序,用户已经按下了一个控制键; CTRL,CAPS LOCK或SCROLL LOCK但问题是该程序不打印出来。感觉缺乏某种基本知识,所以我想这里有人知道我的程序有什么问题。它没有写出任何东西,但是如果我按q(如退出)就可以关闭?...谢谢

;reads the key and prints out whether a control key has been entered 
; (CTRL, CAPS LOCK or SCROLL LOCK)

[BITS 16]

SEGMENT data
ctrlmsg           db    'ctrl has been pressed', '$'
capslockmsg       db    'caps lock has been pressed', '$'
scrollmsg         db    'scroll lock has been pressed', '$'

SEGMENT code
..start:
mov ax, pile
mov ss, ax
mov ax, topofstack
mov sp, ax
mov ax, data
mov ds, ax
mov ax, ctrlmsg

WAITER:
    mov ah, 00h
    int 16h
    cmp al, 71h          ; user pressed q, and wants to end program
    je END
    mov ah, 02h          ; wait until user press keyboard and return keyboard flag in AL
    int 16h
    add al, 71h          ; add 71h back to al, so it goes unchanged in other comparisons
    cmp al, 02h          ; if key board flag is 02h then I expect user to have pressed CTRL
    je CTRL              ; then jump to CTRL label, in the same way it goes...
    add al, 02h
    cmp al, 04h
    je SCROLLOCK
    add al, 04h
    cmp al, 06h
    je CAPSLOCK
    jmp WAITER

END:
    mov ax, 04c00h        ; ends program
    int 21h

WRITESTRING:
    mov ah, 13h           ; 13h of int 10 is print string
    mov al, 00h           ; write mode 0 (no attributes)
    mov bh, 0h            ; video page number
    mov bl, 07h           ; foreground color
    mov cx, 05h           ; string length
    mov dh, 25            ; row
    mov dl, 80            ; col
    int 10h
    ret

CTRL:                     ; the other labels CAPS LOCK and SCROLL LOCK are quite similar why I haven't included them in the codesnippet
    push ds               ; save ds for subroutine 
    pop es                ; pop it in es
    push bp
    move bp, ctrlmsg      ; base pointer point to string
    call WRITESTRING
    pop bs
    jmp waiter            ; loop

2 个答案:

答案 0 :(得分:1)

我对int 16h BIOS调用的确切行为的记忆是模糊的,但我认为切换(capslock / numlock / scrollock)或修改器(shift / ctrl / alt)键不会自己返回任何内容全部来自int 16h。一旦用户按下非修改键,这些键用于修改实际 返回的内容。

要按下实际击键,你可能需要为IRQ 9编写一个ISR(我很确定这是键盘硬件中断的编号)。此时,您可以获得键盘上每个键的原始“make”和“break”扫描码,并采取您想要的任何操作。 (当然,在ISR中,该操作可能应限于将按键信息存储在缓冲区中,以便以后在ISR之外进行处理。)

此外,我注意到您在程序开始时设置了sssp,但DOS会自动为您设置堆栈。通常你根本不需要这样做。但是,如果这样做,则应始终使用clisti在修改寄存器期间禁用中断。如果在您更改ss但尚未sp时发生中断,则ISR将覆盖您可能不想要的内容。

答案 1 :(得分:1)

格雷格是对的。你不应该加载ss:sp。我知道它显示在手册中的示例中,但dos为您执行...如果您的堆栈被正确声明。你没有表现出来。应该是这样的:

segment pile stack ; the "stack" is important!
    resw 100h ; should be enough for anybody

segment pile stack ; the "stack" is important! resw 100h ; should be enough for anybody

你必须像你一样加载ds。我也会这样做,而不是留到“CTRL:”。你的“Writestring”取决于它。 (奇怪的中断,10h / 13h!)

int 16h,ah = 0对于旧的83键键盘是正确的。它将“几乎”所有键击,但它错过了一些。我对那个人非常困惑! (很久以前,但我还记得它!)现代键盘使用啊= 10h。无论哪种方式,你检查'q'并退出。到目前为止一切都很好!

然后你得到int 16h / 2的标志。在那之后你的逻辑逃避了我!你在键盘标志上加了71h?然后将它与2进行比较?我不认为你的任何条件跳跃。这可以解释为什么没有打印出来! :)(你也打印到第25行,第80列,这看起来很奇怪)

我认为你想用...(等待它)测试标志“test”指令。由于这些条件中不止一个可能是真的,可能是......

    test al, 4 ; bit 2 - control key
    jnz notctrl
    call print_control
notctrl:
    test al, 16 ; bit 4 - scrollock active
    jnz not_scrl
    call print_scroll
notscrl:
    test al, 64 ; bit 6 - capslock active
; etc...

显然,您必须在子程序中保留al。 Greg也是正确的,如果您为键盘编写自己的int 9(irq 1)处理程序,则将此信息保存在缓冲区中。现有的处理程序就是这样做的。在Bios数据区,段40h ......我忘了偏移...你会发现这些标志。这是int 16h / 2发现它们的地方,我很确定。您可以自己访问它们,但BIOS中断可能更容易(也许可以尝试它作为练习?)。

最后但并非最不重要的是,wtf是“pop bs”? BS不是段寄存器。 Nasm不会没有BS! CPU不会没有BS! :)

最佳, 弗兰克