Nasm中断调用被跳过并输出多行

时间:2013-06-20 06:28:24

标签: assembly x86 buffer nasm interrupt

在进行前2次调用后,没有任何不良情况发生,但只要按Enter键选择菜单,它就会输出两个提示,要求输入用户输入,而不是在每次提示时暂停以输入操作数。

为什么中断会跳过?

我现在真的很困惑。

SECTION .data

        AskForCalculationPrompt: db "Choose which operation you want", 0xA, "1. Addition", 0xA, "2.Subtraction", 0xA, "3. Multiplication", 0xA, "4. Division", 0x3
        AskForCalculationPromptln: equ $-AskForCalculationPrompt

        FirstOperandPrompt: db "Enter the first operand:", 0xA
        FirstOperandPromptln: equ $-FirstOperandPrompt

        SecondOperandPrompt: db "Enter the second operand:", 0xA
        SecondOperandPromptln: equ $-SecondOperandPrompt

        AnswerPrompt: db "The answer is: "
        AnswerPromptln: equ $-AnswerPrompt

        ErrorMsg: db "Wrong Choice made...insert correct choice"
        ErrorMsgln: equ $-ErrorMsg


SECTION .bss

        Choice: resb 1
        FirstOperand: resb 1
        SecondOperand: resb 1
        Answer: resb 1

SECTION .text

        ;Make interrupt to ask for a prompt ask for calculation prompt
        global _start

        _start:

        mov eax, 4 ;Specify sys_write call
        mov ebx, 1 ;Standard output
        mov ecx, AskForCalculationPrompt
        mov edx, AskForCalculationPromptln
        int 80h

        ;Make interrupt to read textfrom keyboard
        READ:

        mov eax, 3 ;Sys_read call
        mov ebx, 0 ;Standard input file descriptor 0
        mov ecx, Choice
        mov edx, 1
        int 80h

        ;Determine what we inserted

        ;Prompt for first operand
        mov eax, 4
        mov ebx, 1
        mov ecx, FirstOperandPrompt
        mov edx, FirstOperandPromptln
        int 80h

        ;Retrieve first operand input
        mov eax, 3
        mov ebx, 0
        mov ecx, FirstOperand
        mov ebx, 1
        int 80h

        ;Prompt for second operand
        mov eax, 4
        mov ebx, 1
        mov ecx, SecondOperandPrompt
        mov edx, SecondOperandPromptln
        int 80h

        ;Retrieve second operand input
        mov eax, 3
        mov ebx, 0
        mov ecx, SecondOperand
        mov edx, 1
        int 80h

        ;Load values retrieved into registers eax, ebx, ecx, for comparison and operation
        mov al, byte [Choice]
        mov bl, byte [FirstOperand]
        mov cl, byte [SecondOperand]


        JMP SWITCH
;*******************************************************************************
;SWITCH*************************************************************************
;*******************************************************************************
        SWITCH:

                cmp al, 0x31
                je ADDLABEL

                cmp al, 0x32
                je SUBTRACTLABEL

                cmp al, 0x33
                je MULTIPLICATIONLABEL

                cmp al, 0x34
                je DIVISIONLABEL

                JMP DEFAULTLABEL

        DEFAULTLABEL:

                mov eax, 4
                mov ebx, 1
                mov ecx, ErrorMsg
                mov edx, ErrorMsgln
                int 80h
                JMP READ


;*****************************************************************************
;OPERATIONS*******************************************************************
;*****************************************************************************

        ADDLABEL:
                mov al, cl
                add al, bl
                JMP DISPLAYOPERATION

        SUBTRACTLABEL:
                mov al, cl
                sub al, bl
                JMP DISPLAYOPERATION

        MULTIPLICATIONLABEL:
                mov al, cl
                mul cl
                JMP DISPLAYOPERATION

        DIVISIONLABEL:
                mov al, cl
                div cl
                JMP DISPLAYOPERATION

;*****************************************************************************
;DISPLAYOPERATION*************************************************************
;*****************************************************************************

        DISPLAYOPERATION:

                mov [Answer], eax
                mov eax, 4
                mov ebx, 1
                mov ecx, Answer
                mov edx, 1
                int 80h

                mov eax, 1
                mov ebx, 0
                int 80h

1 个答案:

答案 0 :(得分:1)

我认为你遇到的是sys_read(来自stdin)直到看到换行符(“输入”键)才返回的事实。只有您要查找的一个字符进入缓冲区(选择),换行符保留在OS的缓冲区中(称之为“键盘缓冲区”)。当下一个sys_read出现时,它会将该换行读入您的下一个缓冲区(FirstOperand)...然后继续...接着进行欢闹!

修复它的简单方法是制作缓冲区resb 2并生成edx 2,并信任用户只输入一个密钥然后“输入”...每次...然后刻意忽略每个缓冲区中的第二个字节。

更好的方法可能是“刷新缓冲区” - 操作系统的键盘缓冲区,而不是您刚刚读入的缓冲区。当sys_read返回时,读取的数字位于eax。如果它小于edx,你应该是好的(在这种情况下不会是这样)。如果它相等(它不应该更大),检查最后一个字符是否是换行符。如果是的话,你很好。如果没有,操作系统的缓冲区中会有更多的错误(这会搞砸你的下一个sys_read!)。读入“虚拟”缓冲区(在.bss或堆栈中),一次一个字节,直到找到换行符 - cmp byte [dummybuf], 0Ah左右。然后你准备继续......

这是原始sys_call编程的乐趣。 :)

你没有问,但mov [Answer], eax可能会遇到麻烦。这将写入您的单字节缓冲区......以及它之后的三个字节!它之后什么也没有,并且它没有与你没有“拥有”的内存对接,所以它现在不会引起问题,但它是一个“等待发生的错误”。使用al(应该在这里工作),或者使用答案resd,使其适合所有eax

这不会给你你期望的答案。在对em进行算术运算之前,需要从每个操作数中减去“0”(或30h或48),然后在打印之前将“0”添加回答案。如果不超过一位数,那就更糟了!首先让中断按预期工作。