Skips one input every time after a jmp


Skips one input every time after a jmp



So I have this code that is supposed to ask for 2 numbers and then make some operations with them, and after finishing one operation and outputting the answer, it should ask again for 2 numbers and an option until the user selects the option to exit. But for some reason, right after printing the result one time, the second time it skips one input.


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



I would really appreciate someone pointing out what's wrong with it as I am very new to this programming language.



Edit: Here's what happens when I run the code.


./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



So right after going through one jmp back to _start it skips one input, but if I take the "getMenuOption" out and just make it do one operation every time it works fine.





A transcript of a run of the program, exhibiting the problem you describe, would make this a much clearer question. In particular, when you say "skips one input", do you mean the first or second input? Is it just the opportunity to type something in that is skipped, or the prompt text as well?
– jasonharper
Jul 2 at 4:15





Well, 2 things occur to me right off: 1) If the code to figure out which menu option they picked fails, it drops into Addition (probably not what you intended). Perhaps an unconditional jmp at the end of the last back to _start? 2) Is this really 64bit code (as the tag implies)? If so, you shouldn't be using int 80, but syscall (see this). Other than that, the details jason has requested would make this much clearer.
– David Wohlferd
Jul 2 at 5:14


jmp


int 80


syscall





@jasonharper: you can use [mcve] in a comment, it expands to Minimal, Complete, and Verifiable example. And yes, agreed that the description of how it fails is not clear, so it's not a good MCVE. (@Robert: It's also nowhere near minimal: step 1 in debugging a problem is to use a debugger and single-step) . If that doesn't work, step 2 is cutting your code down until it's as small as possible while still having the behaviour you don't understand. Often this will clue you in to the bug when you see which line or statement was relevant.)
– Peter Cordes
Jul 2 at 6:03


[mcve]





You could also use strace to see what system calls your code is making, but that will show the wrong system calls if you build a 64-bit executable out of this code that uses the 32-bit ABI. (strace decodes 32-bit system calls from 64-bit processes incorrectly, which is one of several reasons not to use int 80h in x86-64 code. But given that all your addressing modes are using 32-bit regs, it looks like you should build this as 32-bit.)
– Peter Cordes
Jul 2 at 6:06


strace


int 80h





Try one of these solutions: stackoverflow.com/a/23040860/3512216
– rkhb
Jul 2 at 12:18




1 Answer
1



The problem seems to be that you read only one character at the end of getMenuOption. The newline charater that you enters after your menu choice is then kept in the input buffer until getNumbers is called, resulting in an automatic empty input for the first number.



A simple solution is to read more than one character in getMenuOption.






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

PHP contact form sending but not receiving emails

PHP parse/syntax errors; and how to solve them?

iOS Top Alignment constraint based on screen (superview) height