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