I'm creating an assembly language program with NASM on Linux. I'm trying to do a weighted average of 4 numbers where the 4th number entered has double the weighting of the others. If I use the numbers 30, 40, 50, 60, I'm calculating the weighted average as (30+40+50+60+60)/5. My code is:
SYS_EXIT equ 1
SYS_READ equ 3
SYS_WRITE equ 4
STDIN equ 0
STDOUT equ 1
segment .data
msg1 db "Enter exam grade 1: ", 0xA,0xD
len1 equ $- msg1
msg2 db "Enter exam grade 2: ", 0xA,0xD
len2 equ $- msg2
msg3 db "Enter exam grade 3: ", 0xA,0xD
len3 equ $- msg3
msg4 db "Enter final exam grade (worth double: ", 0xA,0xD
len4 equ $- msg4
msg5 db "The sum is: "
len5 equ $- msg5
segment .bss
num1 resb 3
num2 resb 3
num3 resb 3
num4 resb 3
res resb 4
section .text
global main
main:
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg1
mov edx, len1
int 0x80
mov eax, SYS_READ
mov ebx, STDIN
mov ecx, num1
mov edx, 3
int 0x80
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg2
mov edx, len2
int 0x80
mov eax, SYS_READ
mov ebx, STDIN
mov ecx, num2
mov edx, 4
int 0x80
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg3
mov edx, len3
int 0x80
mov eax, SYS_READ
mov ebx, STDIN
mov ecx, num3
mov edx, 3
int 0x80
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg4
mov edx, len4
int 0x80
mov eax, SYS_READ
mov ebx, STDIN
mov ecx, num4
mov edx, 3
int 0x80
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg5
mov edx, len5
int 0x80
mov eax, [num1] ; move num1 to register eax
sub eax, '0' ; sub '0' to convert eax bl from ASCII to decimal
mov ebx, [num2] ; move num2 to register ebx
sub ebx, '0' ; sub '0' to convert ebx from ASCII to decimal
mov ecx, [num3] ; move num3 to register ecx
sub ecx, '0' ; sub '0' to convert ecx from ASCII to decimal
mov edx, [num4] ; move num4 to register edx
sub edx, '0' ; sub '0' to convert edx from ASCII to decimal
add eax, ebx ; add ebx to eax
add eax, ecx ; add ecx to eax
add eax, edx ; add edx to eax
add eax, edx ; add edx to eax again
mov bl, '5' ; sub '0' to convert bl from ASCII to decimal
sub bl, '0' ; make bl a decimal
div bl ; divide by bl
add eax, '0' ; add '0' to convert the sum from decimal to ASCII
mov [res], eax ; storing the sum in memory location res
; print the sum
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, res
mov edx, 3
int 0x80
exit:
mov eax, SYS_EXIT
xor ebx, ebx
int 0x80
I can produce this exception if I enter these numbers:
Enter exam grade 1:
30
Enter exam grade 2:
40
Enter exam grade 3:
50
Enter final exam grade (worth double:
60
The sum is: Floating point exception
What causes my program to display Floating Point Exception (SIGFPE) and how can I fix this?
Related
I started to learn assembly some days ago and i write my first ever piece of code using user input, string functions, passing arguments by stack or by register etc...
I have some questions. Do you have some advices to make my code faster. For example, in my atoi function, i know that imul is time consuming. Maybe, there are enormous mistakes but as far as i know, many things to improve for sure. So my main question is : are there fatal errors in this first code and my second is : any type to refactoring code with faster instructions
SYS_READ equ 3
SYS_WRITE equ 4
STDIN equ 0
STDOUT equ 1
%macro printm 2
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, %1
mov edx, %2
int 0x80
%endmacro
%macro prolog 0
push ebp,
mov ebp, esp
%endmacro
%macro epilog 0
mov esp, ebp
pop ebp
%endmacro
section .text
global _start
_start:
; first check if our strlen proc works
push dword msgbegin
call strlen
add esp, byte 4
cmp eax, lenbegin
je .suite ; it works, we continue
; exiting prog if the len computed in rax != lenbegin
mov eax, 1
int 0x80
.suite:
; check if strcpy works printing res (msgbegin -> srcdst)
push dword lenbegin
push dword msgbegin
push dword strdst
call strcpy
add esp, byte 12
push dword lenbegin
push dword strdst
call print
add esp, byte 8
; first input
printm msgbinp1, leninp1
mov eax, SYS_READ
mov ebx, STDIN
mov ecx, num1
mov edx, 2
int 0x80
printm msgbinp2, leninp2
mov eax, SYS_READ
mov ebx, STDIN
mov ecx, num2
mov edx, 2
int 0x80
printm msgbinp3, leninp3
mov eax, SYS_READ
mov ebx, STDIN
mov ecx, bignum
mov edx, 4
int 0x80
mov edx, bignum
call atoi
cmp eax, 123
je .success ; exit if bignum != 123
mov eax, 1
int 0x80
.success:
; need to strip line feed from bignum
printm bignum, 4
printm msgoutp, lenoutp
; now we compute the sum
mov eax, [num1]
sub eax, '0'
mov ebx, [num2]
sub ebx, '0'
add eax, ebx
add eax, '0'
mov [sum], eax
printm msgres, lenres
; we print it
printm sum, 1
; exiting the programm
mov eax, 1
int 0x80
print:
push ebp
mov ebp, esp
mov eax, 4
mov ebx, 1
mov ecx, [ebp + 8]
mov edx, [ebp + 12]
int 0x80
mov esp, ebp
pop ebp
ret
strcpy:
push ebp
mov ebp, esp
mov ecx, [ebp + 16]
mov esi, [ebp + 12]
mov edi, [ebp + 8]
rep movsb
mov esp, ebp
pop ebp
ret
strlen:
push ebp
mov ebp, esp
push edi
push ecx
mov edi, [ebp + 8]
sub ecx, ecx
sub al, al
not ecx
cld
repne scasb
not ecx
lea eax, [ecx] ; keep null term in size
pop ecx
pop edi
mov esp, ebp
pop ebp
ret
atoi:
xor eax, eax ; zero a "result so far"
.top:
movzx ecx, byte [edx] ; get a character
inc edx ; ready for next one
cmp ecx, '0' ; valid?
jb .done
cmp ecx, '9'
ja .done
sub ecx, '0' ; "convert" character to number
imul eax, 10 ; multiply "result so far" by ten
add eax, ecx ; add in current digit
jmp .top ; until done
.done:
ret
section .data
msgbegin db "hello everyone !", 0xa, 0
lenbegin equ $ - msgbegin
msgbinp1 db "Enter a digit : ", 0xa, 0
leninp1 equ $ - msgbinp1
msgbinp2 db "Enter second digit : ", 0xa, 0
leninp2 equ $ - msgbinp2
msgbinp3 db "Enter third digit : ", 0xa, 0
leninp3 equ $ - msgbinp3
msgoutp db "is equal to 123 !", 0xa, 0
lenoutp equ $ - msgoutp
msgres db "sum of x and y is ", 0xa, 0
lenres equ $ - msgres
strdst times lenbegin db 0
segment .bss
sum resb 1
num1 resb 2
num2 resb 2
bignum resd 4
Thanks you. I started reading the doc but i'm not sure that i understood key concepts.
What command / function can I use to read the second line in the input section so the 4 and 6 I know I'll have to fix the output to output two digits. I just need helping figuring out how to read the second line of input any help would be greatly appreciated.
SYS_EXIT equ 1
SYS_READ equ 3
SYS_WRITE equ 4
STDIN equ 0
STDOUT equ 1
segment .data
NEWLINE db 0xa, 0xd
LENGTH equ $-NEWLINE
msg1 db "Enter a digit "
len1 equ $- msg1
msg2 db "Please enter a second digit "
len2 equ $- msg2
msg3 db "The sum is: "
len3 equ $- msg3
segment .bss
INPT resd 1
num1 resb 2
num2 resb 2
res resb 1
section .text
global _start ;must be declared for using gcc
_start: ;tell linker entry point
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg1
mov edx, len1
int 0x80
mov eax, SYS_READ
mov ebx, STDIN
mov ecx, num1
mov edx, 2
int 0x80
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, num1
mov edx, 2
int 0x80
mov eax, 0x4
mov ebx, 0x1
mov ecx, NEWLINE
mov edx, LENGTH
int 0x80
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg2
mov edx, len2
int 0x80
mov eax, SYS_READ
mov ebx, STDIN
mov ecx, num2
mov edx, 2
int 0x80
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, num2
mov edx, 2
int 0x80
mov eax, 0x4
mov ebx, 0x1
mov ecx, NEWLINE
mov edx, LENGTH
int 0x80
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg3
mov edx, len3
int 0x80
; moving the first number to eax register and second number to ebx
; and subtracting ascii '0' to convert it into a decimal number
mov eax, [num1]
sub eax, '0'
mov ebx, [num2]
sub ebx, '0'
; add eax and ebx
add eax, ebx
; add '0' to to convert the sum from decimal to ASCII
add eax, '0'
; storing the sum in memory location res
mov [res], eax
; print the sum
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, res
mov edx, 1
int 0x80
exit:
mov eax, SYS_EXIT
xor ebx, ebx
int 0x80
enter image description here
There are my all code:
SYS_EXIT equ 1
SYS_READ equ 3
SYS_WRITE equ 4
STDIN equ 0
STDOUT equ 1
section .data
msg1 db `\xF0\x9F\x98\x8E`, " Enter the A: "
len1 equ $- msg1
msg2 db `\xF0\x9F\x98\x89`, " Than the B: "
len2 equ $- msg2
msg3 db `\xF0\x9F\x8D\xB0`, " A > B: A / B - 1 = "
len3 equ $- msg3
msg4 db `\xF0\x9F\x8D\xAA`, " A = B: -25"
len4 equ $- msg4
msg5 db `\xF0\x9F\x8D\x95`, " A < B: (B^3 - 5) / A = "
len5 equ $- msg5
section .bss
a resb 32
b resb 32
x resb 32
section .text
global _start ;must be declared for using gcc
_start: ;tell linker entry point
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg1
mov edx, len1
int 0x80
mov eax, SYS_READ
mov ebx, STDIN
mov ecx, a
mov edx, 32
int 0x80
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg2
mov edx, len2
int 0x80
mov eax, SYS_READ
mov ebx, STDIN
mov ecx, b
mov edx, 32
int 0x80
; Comparing
mov eax, [a]
sub eax, '0'
mov ecx, [b]
sub ecx, '0'
cmp eax, ecx
jg Ab ;A grate than b
je AB ;A and B are equal
jl aB ;a smoller than B
Ab:
cdq
idiv ecx
dec eax
add eax, '0'
mov [x], eax
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg3
mov edx, len3
int 0x80
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, x
mov edx, 32
int 0x80
jmp exit ;go to exit
AB:
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg4
mov edx, len4
int 0x80
jmp exit ;go to exit
aB:
mov eax, ecx
imul ecx
imul ecx
mov ebx, '5'
sub ebx, '0'
sub eax, ebx
mov ecx, [a]
sub ecx, '0'
idiv ecx
add eax, '0'
mov [x], eax
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg5
mov edx, len5
int 0x80
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, x
mov edx, 1
int 0x80
exit:
mov eax, SYS_EXIT
xor ebx, ebx
int 0x80
In 'a' and 'b' I put different number between 0 and 9 but this operation always return 1. I checked out EDX and noticed that processor subtracts ECX from EAX only one times. In EAX he write 1, and in EDX - remainder from subtraction EAX and ECX.
When I enter a = 9 and b = 4 : EAX after dividing = 1 and EDX = 5. If I enter a = 6 and b = 2 : EAX = 1, EDX = 4
What happened?
Presumably there's a newline character (0xA) after each of the digits. So you end up dividing 0xA09 by 0xA04. You could e.g. use movzx eax, byte [a] instead (and similarly for b).
I'm currently working on a Assembly project. The code works fine on adding 1 digit integer with 1 digit sum, but when I entered 2 digit integers the program will either exit or return no input.
This is my work so far:
SYS_EXIT equ 1
SYS_READ equ 3
SYS_WRITE equ 4
STDIN equ 0
STDOUT equ 1
segment .data
msg1 db "Enter the first digit: ",0xA, 0xD
len1 equ $- msg1
msg2 db "Please second digit: " ,0xA, 0xD
len2 equ $- msg2
msg3 db "The sum is "
len3 equ $- msg3
segment .bss
num1 resb 255
num2 resb 255
res resb 255
section .text
global _start
_start:
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg1
mov edx, len1
int 0x80
mov eax, SYS_READ
mov ebx, STDIN
mov ecx, num1
mov edx, 255
int 0x80
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg2
mov edx, len2
int 0x80
mov eax, SYS_READ
mov ebx, STDIN
mov ecx, num2
mov edx, 255
int 0x80
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, msg3
mov edx, len3
int 0x80
mov eax, [num1]
sub eax, '0'
mov ebx, [num2]
sub ebx, '0'
add eax, ebx
add eax, '0'
mov [res], eax
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, res
mov edx, 1
int 0x80
;move eax, SYS_EXIT
;int 0x80
exit:
mov eax, SYS_EXIT
xor ebx, ebx
int 0x80
This is my sample input:
Please enter first digit: 5
Please second digit: 2
The sum is: 7
My problem is this:
Please enter first digit: 5
Please second digit: 5
The sum is:
The sum returns 0.
this is my code :
section .bss ;Uninitialized data
average resb 5
num1 resb 5
num2 resb 5
num3 resb 5
section .text
global _start ; make the main function externally visible
_start:
;User prompt
mov eax, 4
mov ebx, 1
mov ecx, messaging
mov edx, lenmessaging
int 0x80
;Read and store the user input
mov eax, 3
mov ebx, 0
mov ecx, num1
mov edx, 5 ;5 bytes (numeric, 1 for sign) of that information
int 0x80
mov eax, 4
mov ebx, 1
mov ecx, messaging
mov edx, lenmessaging
int 0x80
;Read and store the user input
mov eax, 3
mov ebx, 0
mov ecx, num2
mov edx, 5 ;5 bytes (numeric, 1 for sign) of that information
int 0x80
mov eax, 4
mov ebx, 1
mov ecx, userMsg
mov edx, lenUserMsg
int 0x80
;Read and store the user input
mov eax, 3
mov ebx, 0
mov ecx, num3
mov edx, 5 ;5 bytes (numeric, 1 for sign) of that information
int 0x80
;Output the message
mov eax, 4
mov ebx, 1
mov ecx, dispMsg
mov edx, lenDispMsg
int 0x80
; moving the first number to eax register and second number to ebx
; and subtracting ascii '0' to convert it into a decimal number
mov eax, [num1]
sub eax, '0'
mov ebx, [num2]
sub ebx, '0'
; add eax and ebx
add eax, ebx
mov ebx, [num3]
sub ebx, '0'
add eax, ebx
mov bl, '3'
sub bl, '0'
div bl
add eax, '0'
mov [average], eax
;Output the number entered
mov eax, 4
mov ebx, 1
mov ecx, average
mov edx, 5
int 0x80
;////////////////
mov eax, 0x1 ; system call number for exit
sub esp, 4 ; OS X (and BSD) system calls needs "extra space" on stack
int 0x80 ; make the system call
section .data ;Data segment
userMsg db 'Please enter a number: ' ;Ask the user to enter a nu
lenUserMsg equ $-userMsg ;The length of the message
dispMsg db 'The average is : '
lenDispMsg equ $-dispMsg
messaging db 'Enter another number : '
lenmessaging equ $-messaging
when I run it ,I have this error :
how can I fix it?
this program is for calculating the average of three numbers.
thanks ;)