首页 > 解决方案 > 每次 jmp 后跳过一个输入

问题描述

所以我有这段代码应该要求输入 2 个数字,然后对它们进行一些操作,在完成一个操作并输出答案后,它应该再次要求输入 2 个数字和一个选项,直到用户选择退出选项。但是由于某种原因,在打印一次结果之后,第二次它跳过了一个输入。

segment .data

    prompt db "Please enter the first number: "
    promptLen equ $-prompt
    prompt2 db "Please enter the second number: "
    prompt2Len equ $-prompt2
    prompt3 db 10, "Your result is: "
    prompt3Len equ $-prompt3
    linefeed db 10
    menu1 db "Please chose what to do with the numbers: ", 10
    menu1Len equ $-menu1
    menu2 db "1. Add", 10
    menu2Len equ $-menu2
    menu3 db "2. Multiply", 10
    menu3Len equ $-menu3
    menu4 db "3. Divide", 10
    menu4Len equ $-menu4
    menu5 db "4. Nothing, exit.", 10
    menu5Len equ $-menu5
    menu6 db "5. Surprise me"
    menu6Len equ $-menu6
    menu7 db 10, "Selection: "
    menu7Len equ $-menu7

segment .bss

    Num1 resb 8
    Num2 resb 8
    uNum1 resd 1
    uNum2 resd 1
    choice resd 1
    uRes resd 1
    Result resb 8
    ResultLen resd 1

segment .text
    global _start

_start:
    call getNumbers
    call getMenuOption

    mov eax, [choice]
    cmp eax, 49
    je Addition
    cmp eax, 50
    je Multiply
    cmp eax, 51
    je Divide
    cmp eax, 52
    je exit
    cmp eax, 53
    je surprise

getNumbers:
    mov eax, 4
    mov ebx, 1
    mov ecx, prompt
    mov edx, promptLen
    int 80h

    mov eax, 3
    mov ebx, 0
    mov ecx, Num1
    mov edx, 8
    int 80h

    mov esi, Num1
    call dec2eax
    mov [uNum1], eax

    mov eax, 4
    mov ebx, 1
    mov ecx, prompt2
    mov edx, prompt2Len
    int 80h

    mov eax, 3
    mov ebx, 0
    mov ecx, Num2
    mov edx, 8
    int 80h

    mov esi, Num2
    call dec2eax
    mov [uNum2], eax
    ret

dec2eax:                            ; Arg ESI: ASCII-string (0x0A-terminated) with decimal digits
    xor eax,eax                     ; Result
    xor edx, edx                    ; Especially to clear the 32-bit-part of EDX

    .loop:
    mov dl, byte [esi]              ; Read digit
    cmp dl, 10                      ; End of string (SYS_READ - in certain cases not existent)?
    je .finish                      ; Yes: done
    lea eax, [eax*4+eax]            ; EAX = 5 * EAX ...
    add eax, eax                    ;   ... and EAX = 2 * EAX results in EAX = EAX * 10
    add esi, 1                      ; Increment pointer to string
    and dl, 0x0F                    ; Eliminate ASCII part of digit
    add eax, edx                    ; Add digit to result
    jmp .loop                       ; Next character

    .finish:
    ret                             ; Result: Converted unsigned integer in EAX

eax2dec:                            ; Arg EDI: Pointer to string that gets ASCII-characters
    mov ebx, 10                     ; Divisor
    xor ecx, ecx                    ; CX=0 (number of digits)

    .first_loop:
    xor edx, edx                    ; Attention: DIV applies also DX!
    div ebx                         ; DX:AX / BX = AX remainder: DX
    push dx                         ; LIFO
    inc cl                          ; Increment number of digits
    test eax, eax                   ; AX = 0?
    jnz .first_loop                 ; No: once more

    mov ebx, ecx                    ; Save strlen

    .second_loop:
    pop ax                          ; Get back pushed digit
    or al, 00110000b                ; AL to ASCII
    mov byte [edi], al              ; Save AL
    inc edi                         ; DI points to next character in string DECIMAL
    loop .second_loop               ; Until there are no digits left

    mov byte [edi], 0               ; End-of-string delimiter (ASCIZ)
    mov eax, ebx                    ; Return strlen in EAX
    ret

getMenuOption:
    mov eax, 4
    mov ebx, 1
    mov ecx, menu1
    mov edx, menu1Len
    int 80h

    mov eax, 4
    mov ebx, 1
    mov ecx, menu2
    mov edx, menu2Len
    int 80h

    mov eax, 4
    mov ebx, 1
    mov ecx, menu3
    mov edx, menu3Len
    int 80h

    mov eax, 4
    mov ebx, 1
    mov ecx, menu4
    mov edx, menu4Len
    int 80h

    mov eax, 4
    mov ebx, 1
    mov ecx, menu5
    mov edx, menu5Len
    int 80h

    mov eax, 4
    mov ebx, 1
    mov ecx, menu6
    mov edx, menu6Len
    int 80h

    mov eax, 4
    mov ebx, 1
    mov ecx, menu7
    mov edx, menu7Len
    int 80h

    mov eax, 3
    mov ebx, 0
    mov ecx, choice
    mov edx, 1
    int 80h

    ret

Addition:
    xor edx, edx
    mov eax, [uNum1]
    mov ebx, [uNum2]
    add eax, ebx
    mov [uRes], eax

    call printResult

    jmp _start

Multiply:
    xor edx, edx
    mov eax, [uNum1]
    mov ebx, [uNum2]
    mul ebx
    mov [uRes], eax

    call printResult

    jmp _start

Divide:
    xor edx, edx
    mov eax, [uNum1]
    mov ebx, [uNum2]
    div ebx
    mov [uRes], eax

    call printResult

    jmp _start

surprise:
    jmp _start

printResult:
    mov eax, [uRes]
    mov edi, Result
    call eax2dec
    mov [ResultLen], eax

    mov eax, 4
    mov ebx, 1
    mov ecx, prompt3
    mov edx, prompt3Len
    int 80h

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

    mov eax, 4
    mov ebx, 1
    mov ecx, linefeed
    mov edx, 1
    int 80h

    ret

exit:
    mov eax, 1
    xor ebx, ebx
    int 80h

我非常感谢有人指出它有什么问题,因为我对这种编程语言非常陌生。

编辑:这是我运行代码时发生的情况。

./menu
Please enter the first number: 3
Please enter the second number: 5
Please chose what to do with the numbers:
1. Add
2. Multiply
3. Divide
4. Nothing, exit.
5. Surprise me
Selection: 1

Your result is: 8
Please enter the first number: Please enter the second number: 3
Please chose what to do with the numbers:
1. Add
2. Multiply
3. Divide
4. Nothing, exit.
5. Surprise me
Selection: 1

Your result is: 3
Please enter the first number: Please enter the second number: 3
Please chose what to do with the numbers:
1. Add
2. Multiply
3. Divide
4. Nothing, exit.
5. Surprise me
Selection: 1

Your result is: 3
Please enter the first number: Please enter the second number: ^C

因此,在通过一个 jmp 回到 _start 之后,它会跳过一个输入,但是如果我取出“getMenuOption”并让它每次运行正常时都执行一个操作。

标签: assemblyx86-64yasm

解决方案


问题似乎是您在 getMenuOption 末尾只读取了一个字符。您在选择菜单后输入的换行符将保留在输入缓冲区中,直到调用 getNumbers,从而导致第一个数字的自动输入为空。

一个简单的解决方案是在 getMenuOption 中读取多个字符。


推荐阅读