Compare User Entered Character x86_64 Assembly - linux

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

Related

Nasm: Print on console

I made this program that open a image file and find a hidden message in the file. I have to print the message on the console.
i think the part where i open the file and search for the hidden message is right, but i don´t know for sure because i can´t print the output to confirm.
this is the code:
; Example program to demonstrate file I/O.
; This example will open/create a file, write some
; information to the file, and close the file.
; Note, the file name is hard-coded for this example.
; This example program will open a file, read the
; contents, and write the contents to the screen.
; This routine also provides some very simple examples
; regarding handling various errors on system services.
; -------------------------------------------------------
section .data
; -----
; Define standard constants.
LF equ 10 ; line feed
NULL equ 0 ; end of string
TRUE equ 1
FALSE equ 0
EXIT_SUCCESS equ 0 ; success code
STDIN equ 0 ; standard input
STDOUT equ 1 ; standard output
STDERR equ 2 ; standard error
SYS_write equ 1; write
SYS_read equ 0 ; read
SYS_open equ 2 ; file open
SYS_close equ 3 ; file close
SYS_exit equ 60 ; terminate
SYS_creat equ 85 ; file open/create
SYS_time equ 201 ; get time
O_CREAT equ 0x40
O_TRUNC equ 0x200
O_APPEND equ 0x400
O_RDONLY equ 000000q ; read only
O_WRONLY equ 000001q ; write only
S_IRUSR equ 00400q
S_IWUSR equ 00200q
S_IXUSR equ 00100q
; -----
; Variables/constants for main.
BUFF_SIZE equ 256
newLine db LF, NULL
db LF, LF, NULL
fileName dq 6
fileDesc dq 0
errMsgOpen db "Error opening the file.", LF, NULL
errMsgRead db "Error reading from the file.", LF, NULL
offset db 1
size db 1
; -------------------------------------------------------
section .bss
readBuffer: resb BUFF_SIZE
; -------------------------------------------------------
section .text
global _start
_start:
xor rax, rax
xor rcx, rcx
xor rdx, rdx
xor rbx, rbx
mov rbx, rsp
mov rax, qword [rbx+16]
mov [fileName], rax
xor rax, rax
push rsp
; Attempt to open file - Use system service for file open
openInputFile:
pop rax ; pop argc value - should be 2
cmp rax, 0x2
jne done
mov rax, SYS_open ; file open
mov rdi, fileName ; file name string
mov rsi, O_RDONLY ; read only access
syscall ; call the kernel
cmp rax, 0 ; check for success
jl errorOnOpen
mov qword [fileDesc], rax ; save descriptor
; -----
; Read from file.
;
mov rax, SYS_read
mov rdi, qword [fileDesc]
mov rsi, readBuffer
mov rdx, BUFF_SIZE
syscall
cmp rax, 0
jl errorOnRead
; -----
; Print the buffer.
; add the NULL for the print string
mov rax, qword [readBuffer+2] ;SSSS
mov qword [size], rax
mov rax, qword [readBuffer+10] ;OOOO
mov [offset], rax
mov rcx, 0
ler: ;ler um caracter
mov rbp, 0
xor rbx, rbx
xor rdx, rdx
lerloop:
inc rax
cmp rax, [size]
je errorOnRead
saltaQuartobyte:
inc ecx
cmp ecx, 4
jne continua
inc rax ;incremneta rax outra vez para saltar o quarto
cmp rax, [size]
je errorOnRead
mov ecx, 0
continua:
mov bl, byte [readBuffer+rax]
shl rdx, 1
shr rbx, 1
adc rdx, 0
inc rbp
cmp rbp, 7 ;fim do caracter ASCII, 0X 0XXX XXXX
jne lerloop
mov rdi, rdx
call printString ; imprime caracter ASCII
cmp rax, [size] ;comea o priximo
jne ler
; -----
; Close the file.
mov rax, SYS_close
mov rdi, qword [fileDesc]
syscall
jmp done
; -----
; Error on open.
errorOnOpen:
mov rdi, errMsgOpen
call printString
jmp done
; Error on read.
errorOnRead:
mov rdi, errMsgRead
call printString
jmp done
; -----
; program done.
done:
mov rax, SYS_exit
mov rdi, EXIT_SUCCESS
syscall
; **********************************************************
; Generic procedure to display a string to the screen.
global printString
printString:
push rbp
mov rbp, rsp
push rbp
; -----
; Call OS to output string.
mov rax, SYS_write ; code for write()
mov rsi, rdi ; addr of characters
mov rdi, STDOUT ; file descriptor
; count set above
syscall ; system call
; -----
; String printed, return to calling routine.
prtDone:
pop rbx
pop rbp
ret
this is my last attempt of the print but the program still don't print anything, and I don't understand why? or what's wrong?
A fundamental error
push rsp
; Attempt to open file - Use system service for file open
openInputFile:
pop rax ; pop argc value - should be 2
cmp rax, 0x2
jne done
mov rax, SYS_open ; file open
Your program starts with copying the stackpointer RSP to the accumulator RAX, and then compares to see if the value is 2, but when is the stackpointer ever going to be 2? And so, the program will always prematurely exit. No wonder that nothing gets printed.
A selection of other errors
offset db 1
size db 1
...
mov rax, qword [readBuffer+2] ;SSSS
mov qword [size], rax
mov rax, qword [readBuffer+10] ;OOOO
mov [offset], rax
You have reserved not enough room to store the qwords size and offset!
Better store them in the .bss section using resq:
section .bss
readBuffer: resb BUFF_SIZE
offset resq 1
size resq 1
mov rax, qword [readBuffer+2] ;SSSS
mov qword [size], rax
mov rax, qword [readBuffer+10] ;OOOO
mov [offset], rax
If the file is a .BMP (I'm considering those well-known offsets), then the size and offset fields are actually dwords. You would have to write instead (loading EAX automatically zero extends the value into RAX):
mov eax, [readBuffer+2] ;SSSS
mov [size], rax
mov eax, [readBuffer+10] ;OOOO
mov [offset], rax
printString:
push rbp
mov rbp, rsp
push rbp <<<<
...
pop rbx <<<<
pop rbp
ret
Because of the mismatch, you're destroying RBX on return.
The code that you used depends on calculating the length of the ASCIIZ string. You cannot just leave that out!

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

Linux NASM Compiler doesn't compile "aaa"

Here's my current problem with NASM. I keep compiling this code right here but it just shows the error:
carry.asm:10: error: instruction not supported in 64-bit mode
Here is my code for this:
section .text
global main
main:
mov rsi, 4
mov rcx, 5
clc
add_loop:
mov al, [num1 + rsi]
mov al, [num2 + rsi]
aaa
pushf
or al, 30h
popf
mov [sum + rsi], al
dec rsi
loop add_loop
mov rdx, len
mov rcx, msg
mov rbx, 1
mov rax, 4
int 0x80
mov rdx, 5
mov rcx, sum
mov rbx, 1
mov rax, 4
int 0x80
mov rax, 1
int 0x80
section .data
msg db 'The sum is:', 0xa
len equ $- msg
num1 db '12345'
num2 db '23456'
sum db ' '
I can't seem to figure out what to do on this.

Basic assembly calculator assignment not working

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.

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