Basic assembly calculator assignment not working - linux

We need to do addition, subtraction, multiplication and division with single digits that are entered in using syscalls. For some reason my addition is the only thing that works. I cannot figure out why the rest don't work. All of them outputs nothing, except for multiplication that works if you multiply by 1.
My subtract code:
segment .data
one db 0
two db 0
diff db 0
segment .text
global _start
_start:
mov rax, 0
mov rdi, 0
lea rsi, [one]
mov rdx, 2
syscall
mov rbx, [one]
sub rbx, 48
mov rax, 0
mov rdi, 0
lea rsi, [two]
mov rdx, 2
syscall
sub rbx, [two]
mov [diff], rbx
;xor rbx, rbx
mov rax, 1
mov rdi, 1
mov rdx, 1
lea rsi, [diff]
syscall
mov rax, 60
xor rdi, rdi
syscall
My multiplication code:
segment .data
one db 0
two db 0
multi db 0
segment .text
global _start
_start:
mov eax, 0
mov edi, 0
lea esi, [one]
mov edx, 2
syscall
;mov ebx, [one]
;sub ebx, '0'
mov eax, 0
mov edi, 0
lea rsi, [two]
mov edx, 2
syscall
mov eax, [one]
sub eax, '0'
;mov ecx, [two]
;sub ecx, '0'
mul dword [two]
mov [multi], eax
xor edx, edx
mov eax, 1
mov edi, 1
mov edx, 1
lea esi, [multi]
syscall
mov eax, 60
xor edi, edi
syscall
And division code:
segment .data
one db 0
two db 0
qout db 0
segment .text
global _start
_start:
mov rax, 0
mov rdi, 0
lea rsi, [one]
mov rdx, 2
syscall
;mov rbx, [one]
;sub rbx, '0'
mov rax, 0
mov rdi, 0
lea rsi, [two]
mov edx, 2
syscall
mov eax, [one]
sub eax, '0'
mov edx, 0
mov ecx, two
;sub ecx, '0'
div ecx
mov [qout], [rax]
;xor rdx, rdx
mov rax, 1
mov rdi, 1
mov rdx, 1
lea rsi, [qout]
syscall
mov rax, 60
xor rdi, rdi
syscall
Can someone please tell me why this is not working.
This is my addition for reference:
segment .data
one db 0
two db 0
sum db 0
segment .text
global _start
_start:
mov eax, 0 ;read
mov edi, 0 ;file descriptor
lea esi, [one] ;write to one
mov edx, 2 ;size of input in bytes
syscall
mov ebx, [one]
sub ebx, '0' ;'convert' to int
mov eax, 0 ;again another input
mov edi, 0
lea rsi, [two]
mov edx, 2
syscall
add ebx, [two] ;add two to one
mov [sum], ebx ;move sum into [sum]
xor ebx, ebx ;clear the register
mov eax, 1 ;syscall write
mov edi, 1 ;file descriptor
mov edx, 1 ;output one byte
lea esi, [sum] ;output sum
syscall
mov eax, 60 ;syscall 60 is exit
xor edi, edi ;exit(0)
syscall

I found a solution. In my code I subtracted '0' from both numbers and after the operation I just added '0' again.For Division I did what the solution to this question suggested.

Related

Compare User Entered Character x86_64 Assembly

I am trying to compare a user entered character (A - E) and run a specific label if they are equal. However, it does not seem to be comparing correctly, and is running my default fail label. It gets the input successfully, but it seems the cmp is not working correctly. Below is my code:
section .data
; constants
NULL equ 0
EXIT_SUCCESS equ 0
EXIT_FAIL equ 1
SYS_exit equ 60
SYS_read equ 0
SYS_write equ 1
STD_in equ 0
STD_out equ 1
lA equ "A"
lB equ "B"
lC equ "C"
lD equ "D"
lE equ "E"
; other
text1 db "Please enter an upper-case letter from A-E: "
errmsg db "Error: incorrect letter chosen."
sucmsg db "Success."
section .bss
; reserve space for user input
letter resb 1
section .text
global _start
_start:
; print question
; sys_write (1, text, 43)
mov rax, SYS_write
mov rdi, STD_out
mov rsi, text1
mov rdx, 43
syscall
; get user input
; sys_read (0, letter, 1)
mov rax, SYS_read
mov rdi, STD_in
mov rsi, letter
mov rdx, 1
syscall
; jump conditionals
mov rdx, lA
cmp rsi, rdx
je _printA
mov rdx, lB
cmp rsi, rdx
je _printB
mov rdx, lC
cmp rsi, rdx
je _printC
mov rdx, lD
cmp rsi, rdx
je _printD
mov rdx, lE
cmp rsi, rdx
je _printE
; default jump if no match
jmp _exitFail
_printA:
; sys_write (1, text, 1)
mov rax, SYS_write
mov rdi, STD_out
; mov rsi, "A"
mov rdx, 1
syscall
jmp _exitSuccess
_printB:
; sys_write (1, text, 1)
mov rax, SYS_write
mov rdi, STD_out
; mov rsi, "B"
mov rdx, 1
syscall
jmp _exitSuccess
_printC:
; sys_write (1, text, 1)
mov rax, SYS_write
mov rdi, STD_out
; mov rsi, "C"
mov rdx, 1
syscall
jmp _exitSuccess
_printD:
; sys_write (1, text, 1)
mov rax, SYS_write
mov rdi, STD_out
; mov rsi, "D"
mov rdx, 1
syscall
jmp _exitSuccess
_printE:
; sys_write (1, text, 1)
mov rax, SYS_write
mov rdi, STD_out
; mov rsi, "E"
mov rdx, 1
syscall
jmp _exitSuccess
_exitSuccess:
; print success msg
; sys_write (1, errmsg, 8)
mov rax, SYS_write
mov rdi, STD_out
mov rsi, sucmsg
mov rdx, 8
syscall
; sys_exit (0)
mov rax, SYS_exit
mov rdi, EXIT_SUCCESS
syscall
_exitFail:
; print fail msg
; sys_write (1, errmsg, 31)
mov rax, SYS_write
mov rdi, STD_out
mov rsi, errmsg
mov rdx, 31
syscall
; sys_exit (1)
mov rax, SYS_exit
mov rdi, EXIT_FAIL
syscall
Before syscall SYS_read you have correctly loaded RSI with address of letter.
At the ; jump conditionals you compare the letters in RDX with address of letter, which remains in RSI.
Dereference RSI prior to jump conditionals with MOVZX RSI,[byte letter].
Or simply use
CMP byte [byte letter],'A'
JE _printA
CMP byte [byte letter],'B'
JE _printB
... etc
Or, if you want to avoid jumps (for performace reason), make an array of QWORD pointers to _printA, _printB etc in SECTION .data, convert the obtained letter A, B, C, D, E to numeric index 0, 1, 2, 3, 4 in RSI and instead of jump conditionals use one jump JMP [qword array+8*RSI].

How to compare the count of command line arguments correctly in NASM?

I am learning x86_64 NASM assembly on Ubuntu 16.10 on Docker for Mac.
The following program takes two command line arguments, and sum these.
If number of command line arguments is not two, print error message (jump to argcError).
When I exec this program, it jump to argcError section despite passed to two command line arguments.
Why this program jump to argError?
section .data
SYS_WRITE equ 1
STD_IN equ 1
SYS_EXIT equ 60
EXIT_CODE equ 0
NEW_LINE db 0xa
WRONG_ARGC db "Must be two command line arguments", 0xa
section .text
global _start
_start:
pop rcx
cmp rcx, 3
jne argcError
add rsp, 8
pop rsi
call str_to_int
mov r10, rax
pop rsi
call str_to_int
mov r11, rax
add r10, r11
argcError:
mov rax, 1
mov rdi, 1
mov rsi, WRONG_ARGC
mov rdx, 35
syscall
jmp exit
str_to_int:
xor rax, rax
mov rcx, 10
next:
cmp [rsi], byte 0
je return_str
mov bl, [rsi]
sub bl, 48
mul rcx ; rax = rax * rcx
add rax, rbx
inc rsi
jmp next
return_str:
ret
int_to_str:
mov rdx, 0
mov rbx, 10
div rbx
add rdx, 48
add rdx, 0x0
push rdx
inc r12
cmp rax, 0x0
jne int_to_str
jmp print
print:
; calculate byte length of number string
mov rax, 1
mul r12
mov r12, 8
mul r12
mov rdx, rax
; print sum
mov rax, SYS_WRITE
mov rdi, STD_IN
mov rsi, rsp
syscall
jmp printNewline
printNewline:
mov rax, SYS_WRITE
mov rdi, STD_IN
mov rsi, NEW_LINE
mov rdx, 1
syscall
jmp exit
exit:
mov rax, SYS_EXIT
mov rdi, EXIT_CODE
syscall
There probably other errors in your code as pointed out by Micheal Petch, but the way you've initialized RSI is incorrect. Yes, ESP does point to the number of arguments passed, but popping it off the stack and then adding 8 to ESP again is functionally equivalent too.
mov rcx, [rsp]
Then by popping into RSI it only becomes a copy of RCX. If you want to do that it should look like this
pop rcx
.......
add rsp, 24 ; Now RSP is pointing to proper place in array of pointers
pop rsi
add rsp, 16 ; Now point to pointer to second argument
pop rsi
An alternative would be this next example only because my personal preference is not to use stack pointer for other than that which it was intended.
mov rsi, rsp
lodsq ; Read # of arguments passed by OS
add rsi, 8 ; bounce over application name
cmp al, 3
jnz argError
push rsi
lodsq
mov rsi, rax ; RSI points to first agument
call Convert
pop rsi
lodsq
mov rsi, rax
call Convert

nasm 32 word division always giving 1 as an answer

I've been trying to divide a word sized variables and the resulting quotient is always 1 and the remainder is always dividend-divisor. What could have gone wrong? Thank you in advance.
section .data
section .bss
num1a resw 1
num1b resw 1
num2a resw 1
num2b resw 1
section .text
global _start
_start:
;get inputs
mov eax, 3
mov ebx, 0
mov ecx, num1a
mov edx, 1
int 80h
mov eax, 3
mov ebx, 0
mov ecx, num1b
mov edx, 2
int 80h
mov eax, 3
mov ebx, 0
mov ecx, num2a
mov edx, 1
int 80h
mov eax, 3
mov ebx, 0
mov ecx, num2b
mov edx, 2
int 80h
;convert
sub word[num1a], 30h
sub word[num1b], 30h
sub word[num2a], 30h
sub word[num2b], 30h
mov ax, 0
mov bx, 0
mov ax, [num1a]
mov bx, 10
mul bx
add ax, [num1b]
mov word[num1a], ax
mov ax, 0
mov bx, 0
mov ax, [num2a]
mov bx, 10
mul bx
add ax, [num2b]
mov word[num2a], ax
;divide
mov ax, 0
mov dx, 0
mov ax, [num1a]
div word[num2a]
mov word[num1a], ax
mov word[num2a], dx
mov ax, 0
mov dx, 0
mov ax, [num1a]
mov bx, 10
div bx
mov word[num1a], ax
mov word[num2a], dx
;convert
add word[num1a], 30h
add word[num2a], 30h
;print
mov eax, 4
mov ebx, 1
mov ecx, num1a
mov edx, 1
int 80h
mov eax, 4
mov ebx, 1
mov ecx, num2a
mov edx, 1
int 80h
exit:
mov eax, 1
mov ebx, 0
int 80h

Assembly language and printing result. Fibbonacci sequence

I use Assembly on x86 Linux, with instructions for Intel 8086. I have a problem with my program, which should count the element of Fibbonacci sequence.
This program I run with args, for e.g.:
./fibb 1 2 3 ,
what means: 1st element of sequence is 1, the 2st element is 2 and we want to get the 3rd.
And that example works great, but when I try to run like:
./fibb 1 2 4 ,
then I've got some junk.
Please help me. I'm new in Assembly so please explain me clearly what I'm doing wrong.
Here is my code:
.intel_syntax noprefix
.global _start
.data
var1:
.ascii "To few args\n"
.equ len1, $-var1
var2:
.ascii "Wrong data\n"
.equ len2, $-var2
var3:
.ascii "wrong element of the sequence\n"
.equ len3, $-var3
var4:
.ascii "element of the sequence is higher than 255\n"
.equ len4, $-var4
var5:
.ascii "result: "
.equ len5, $-var5
var6:
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
var7:
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
var8:
.byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.text
_start:
jmp ety5
ety1:
mov bh, 48
ety2:
cmp [eax], bh
jz ety3
inc bh
cmp bh, 58
jnz ety2
ety3:
cmp bh, 58
jnz ety4
inc bl
ety4:
inc eax
cmp [eax], byte ptr 0
jnz ety1
ret
ety5:
jmp ety10
invert:
xor ecx, ecx
ety6:
inc ebx
inc ecx
cmp [ebx], byte ptr 0
jnz ety6
ety7:
dec ecx
cmp ecx, 0
jz ety8
mov [ebx], byte ptr 0
dec ebx
cmp [ebx], byte ptr 48
jz ety7
inc ebx
ety8:
inc ecx
push ecx
xor ecx, ecx
ety9:
add ecx, 2
push ecx
dec ebx
mov cl, [eax]
mov ch, [ebx]
mov [eax], ch
mov [ebx], cl
inc eax
pop ecx
cmp ecx, [ebp-8]
jb ety9
pop ecx
ret
ety10:
jmp ety18
ety11:
mov cl, [eax]
cmp cl, 0
jz ety12
sub cl, 48
ety12:
mov ch, [ebx]
sub ch, 48
add cl, dh
xor dh, dh
add cl, ch
cmp cl, 10
jb ety13
inc dh
sub cl, 10
ety13:
add cl, 48
mov [eax], cl
inc eax
inc ebx
cmp [ebx], byte ptr 0
jnz ety11
ety14:
cmp [eax], byte ptr 0
jz ety16
mov cl, [eax]
sub cl, 48
add cl, dh
xor dh, dh
cmp cl, 10
jb ety15
sub cl, 10
inc dh
ety15:
add cl, 48
mov [eax], cl
inc eax
jmp ety14
ety16:
cmp dh, 0
jz ety17
add dh, 48
mov [eax], dh
ety17:
ret
ety18:
jmp ety22
ety19:
mov esi, 3
mov dl, [ecx]
sub dl, 48
loop_mul:
add dl, dl
dec esi
cmp esi,0
jnz loop_mul
add dl, dh
xor dh, dh
cmp dl, 10
jb ety20
sub dl,10
inc dh
ety20:
add dl, 48
mov [ebx], dl
inc ebx
inc ecx
cmp [ecx], byte ptr 0
jnz ety19
cmp dh, 0
jz ety21
add dh, 48
mov [ebx], dh
ety21:
mov ebx, offset var8
ret
ety22:
mov ebp, esp
mov eax, [ebp+8]
cmp eax, 0
jnz ety23
mov eax, 4
mov ebx, 1
mov ecx, offset var1
mov edx, offset len1
int 0x80
mov eax, 1
mov ebx, 0
int 0x80
ety23:
mov eax, [ebp+12]
cmp eax, 0
jnz ety24
mov eax, 4
mov ebx, 1
mov ecx, offset var1
mov edx, offset len1
int 0x80
mov eax, 1
mov ebx, 0
int 0x80
ety24:
mov eax, [ebp+16]
cmp eax, 0
jnz ety25
mov eax, 4
mov ebx, 1
mov ecx, offset var1
mov edx, offset len1
int 0x80
mov eax, 1
mov ebx, 0
int 0x80
ety25:
xor bl, bl
mov eax, [ebp+8]
call ety1
mov eax, [ebp+12]
call ety1
cmp bl, 0
jz ety26
mov eax, 4
mov ebx, 1
mov ecx, offset var2
mov edx, offset len2
int 0x80
mov eax, 1
mov ebx, 0
int 0x80
ety26:
mov eax, [ebp+16]
call ety1
cmp bl, 0
jz ety27
mov eax, 4
mov ebx, 1
mov ecx, offset var3
mov edx, offset len3
int 0x80
mov eax, 1
mov ebx, 0
int 0x80
ety27:
xor ebx, ebx;
mov eax, [ebp+16]
mov ecx, [ebp+16]
ety28:
cmp [eax], byte ptr 0
jnz ety29
mov eax, 4
mov ebx, 1
mov ecx, offset var3
mov edx, offset len3
int 0x80
mov eax, 1
mov ebx, 0
int 0x80
ety29:
cmp [eax], byte ptr 48
jnz ety30
inc eax
inc ecx
jmp ety28
ety30:
inc ecx
cmp [ecx], byte ptr 0
jz ety35
inc ecx
cmp [ecx], byte ptr 0
jz ety33
inc ecx
cmp [ecx], byte ptr 0
jz ety31
mov eax, 4
mov ebx, 1
mov ecx, offset var4
mov edx, offset len4
int 0x80
mov eax, 1
mov ebx, 0
int 0x80
ety31:
mov cl, [eax]
inc eax
sub cl, 48
ety32:
add ebx, 100
dec cl
cmp cl, 0
jnz ety32
ety33:
mov cl, [eax]
inc eax
sub cl, 48
cmp cl, 0
jz ety35
ety34:
add ebx, 10
dec cl
cmp cl, 0
jnz ety34
ety35:
mov cl, [eax]
sub cl, 48
cmp cl, 0
jz ety37
ety36:
inc ebx
dec cl
cmp cl, 0
jnz ety36
ety37:
cmp ebx, 256
jb ety38
mov eax, 4
mov ebx, 1
mov ecx, offset var4
mov edx, offset len4
int 0x80
mov eax, 1
mov ebx, 0
int 0x80
ety38:
xor dl, dl
ety39:
dec ebx
inc dl
cmp ebx,0
jnz ety39
mov eax, [ebp+12]
mov ebx, offset var7
xor dh, dh
ety40:
inc eax
inc dh
cmp [eax], byte ptr 0
jnz ety40
xor ch, ch
ety41:
dec eax
dec dh
mov cl, [eax]
mov [ebx], cl
inc ebx
cmp dh, 0
jnz ety41
mov eax, [ebp+8]
mov ebx, offset var6
ety42:
inc eax
inc dh
cmp [eax], byte ptr 0
jnz ety42
ety43:
dec eax
dec dh
mov cl, [eax]
mov [ebx], cl
inc ebx
cmp dh, 0
jnz ety43
cmp dl, 1
jnz ety44
jmp ety46
ety44:
dec dl
cmp dl, 1
jnz ety45
jmp ety47
ety45:
dec dl
cmp dl, 0
jz ety47
push edx
xor dh, dh
mov eax, offset var6
mov ebx, offset var8
mov ecx, offset var7
call ety19
xor dh, dh
call ety11
pop edx
dec dl
cmp dl, 0
jz ety46
push edx
xor dh, dh
mov eax, offset var7
mov ebx, offset var8
mov ecx, offset var6
call ety19
xor dh, dh
call ety11
pop edx
jmp ety45
ety46:
mov eax, 4
mov ebx, 1
mov ecx, offset var5
mov edx, offset len5
int 0x80
mov eax, offset var6
mov ebx, offset var6
call invert
mov eax, 4
mov ebx, 1
mov edx, ecx
mov ecx, offset var6
int 0x80
mov eax, 4
mov ebx, 1
mov [ecx], byte ptr 10
mov edx, 1
int 0x80
mov eax, 1
mov ebx, 0
int 0x80
ety47:
mov eax, 4
mov ebx, 1
mov ecx, offset var5
mov edx, offset len5
int 0x80
mov eax, offset var7
mov ebx, offset var7
call invert
mov eax, 4
mov ebx, 1
mov edx, ecx
mov ecx, offset var7
int 0x80
mov eax, 4
mov ebx, 1
mov [ecx], byte ptr 10
mov edx, 1
int 0x80
mov eax, 1
mov ebx, 0
int 0x80
int 0x80
This code supposedly fills EAX with the first parameter (a number, not an address).
mov eax, [ebp+8]
call ety1
But at ety1 this code compares the byte at the address EAX with BH.
ety1:
mov bh, 48
ety2:
cmp [eax], bh
jz ety3
How is that going to work?
EDIT
By the time I arrived at the real entry point of this program through a ridiculously long cascade of jumps I totally forgot that this is in fact an application and not just some subroutine. Parameters are thus addresses rendering my answer void!
EDIT2
Are you sure the DS register is properly initialized?

64bit NASM file handling problems

I managed to write a NASM program on my 64bit Linux system which removes non-letter symbols from an input and prints each word in separate line. The problem is that I get RCX = -1 where i have to get the readed character number , and as a result I get segmentation fault. I've already spent hours trying to figure out how to fix this bug. Hope you guys will be able to help me. Thanks in advance.
Heres my code:
section .data
file1 db "data", 0
file2 db "results", 0
text times 255 db 0
textSize equ $ - text
buff times 255 db 0
buffSize equ $ - buff
section .text
global main
main:
mov rax, 2
mov rdi, file1
mov rsi, 0 ;read only
mov rdx, 0x7777
syscall ;open file1
mov rbx, rax ;save fd to rbx
mov rsi, text ; a pointer to the current character
mov rax, 0
mov rdi, rbx ;fd of file1
mov rsi, text
mov rdx, textSize
syscall ;read the text from file1
mov rax, 3
mov rdi, rbx
syscall ;close file1
mov rcx, rax ; rcx - character counter
mov rbx, buff ;rbx will be our buffer
cmp rcx, 0
je exit ; if nothing to read - exit
process_loop1:
mov dl, byte[rsi]
cmp byte[rsi], 0x41 ; "A"
jl inc1
cmp byte[rsi], 0x5a ; "Z"
jle save
cmp byte[rsi], 0x61 ; "a"
jl inc1
cmp byte[rsi], 0x7a ; "z"
jle save
jmp inc1 ;check text
inc1:
inc rsi
dec rcx
jnz process_loop1
jmp print
save:
mov byte [ebx], dl
jmp inc2 ;save letters
inc2:
inc rsi
inc rbx
dec rcx
jnz process_loop2
jmp print
process_loop2:
mov dl, byte[rsi]
cmp byte[rsi], 0x41 ; "A"
jl enter
cmp byte[rsi], 0x5a ; "Z"
jle save
cmp byte[rsi], 0x61 ; "a"
jl enter
cmp byte[rsi], 0x7a ; "z"
jle save
jmp enter
enter:
mov byte [ebx], 10 ;enter
inc rsi
inc rbx
dec rcx
jnz process_loop1
jmp print
print:
mov rax, 2
mov rdi, file2
mov rsi, 1 ;write only
mov rdx, 0x7777
syscall ;open file2
mov rbx, rax ;save fd to rbx
mov rax, 1
mov rdi, rbx
mov rsi, buff
mov rdx, buffSize
syscall ;print result
mov rax, 3
mov rdi, rbx
syscall ;close file2
jmp exit
exit:
mov rax, 60
mov rdi, 0
syscall
You have a sys_close between the sys_read and the time you try to check the number of bytes received. Thus, you are checking the return value of the close, not the read. Also note that rcx is destroyed by syscall so you can't just move up the mov rcx, rax line.
Also, in a few places you use [ebx] instead of [rbx].
Furthermore, you probably want use O_CREAT for the result file and only write as many bytes as you have processed, not buffSize.
section .data
filename db 'AVG.asm'
section .bss
buffer resb 2000
fd_in resb 1
section .text
global _start
_start:
mov rax,2
mov rdi,filename
mov rsi,0
mov rdx,0777
syscall
mov [fd_in],rax
mov rax,0
mov rdi,[fd_in]
mov rsi,buffer
mov rdx,2000
syscall
mov rax,1
mov rdi,1
mov rsi,buffer
mov rdx,2000
syscall
mov rax,3
mov rdi,[fd_in]
syscall
mov rax,60
mov rdi,0
syscall

Resources