Assembly - How to properly store user input and print it? - linux

I just started learning asm and I am trying to make a program that asks the user for input(N) and prints the numbers from 1 to N.
The problem is that when i try to print the value i get from scanf if it doesn't work. And the loop just prints ";".
Here is what i have so far:
section .data
msg db "Enter a number: "
fmt db "%d", 0
section .bss
N resb 1
section .text
extern scanf
global main
main:
mov rax, 1
mov rdi, 1
mov rsi, msg
mov rdx, 15
syscall
mov rax, 0
mov rdi, fmt
mov rsi, N
call scanf
Here is where I try to print number N i got from scanf
mov rax, 1
mov rdi, 1
mov rsi, N
mov rdx, 1
syscall
And the loop
mov rcx, 0
loop:
inc rcx
mov rax, 1
mov rdi, 1
mov rsi, rcx
mov rdx, 1
syscall
cmp rcx,[N]
jne loop
Close the program
mov rax,60
mov rdi,0
syscall
This is how i compile:
nasm -f elf64 -o program.o program.asm
gcc -o program program.o

Related

Nasm x86_64: Why can't I write and read from the same file?

I have a problem with file handling in Nasm x86_64.
I have opend correctly the file and i can write into it o read from it, but if I try to read something from the file after i have wrote something into it i don't get anything.
So i get read or write from a file.
The strange thing is that if i first read write I don't have any problem and everything works fine, so the problem is only when i first write and then read.
Could someone help me to solve this problem and to figure out the cause?
Here is the code to open the file:
mov rax, SYS_OPEN
mov rdi, filename
mov rsi, O_CREAT+O_RDWR+O_APPEND
mov rdx, 0744o
syscall
push rax
Code to close the file:
mov rax, SYS_CLOSE
mov rdi, r11
syscall
Code to print a string:
mov rdx, rax
mov rax, SYS_WRITE
mov rdi, STDOUT
mov rsi, temp
syscall
Code to of getLength (the argument is the string of which I want to get the length):
%macro getLength 1
mov r10, %1
mov r11, r10
%%begin:
cmp byte [r11], 10
je %%end
inc r11
jmp %%begin
%%end:
sub r11, r10
%endmacro
The code to write:
getLength msg
mov rax, SYS_WRITE
mov rdi, [rsp]
mov rsi, msg
mov rdx, r11
syscall
Code to read:
mov rax, SYS_READ
mov rdi, [rsp]
mov rsi, temp ;buffer to store the string read
mov rdx, 10
syscall
Both the code to read and the code to write works perfectly alone, the problem is when I use the code to read after the code to write.
So this code works.
%include "./standardlib.inc"
section .data
filename db "./file.txt", 0
msg db "hello", 10
section .bss
temp resb 10
section .text
global _start:
_start:
mov rax, SYS_OPEN
mov rdi, filename
mov rsi, O_CREAT+O_RDWR+O_APPEND
mov rdx, 0744o
syscall
push rax
mov rax, SYS_READ
mov rdi, [rsp]
mov rsi, temp
mov rdx, 10
syscall
mov rdx, rax
mov rax, SYS_WRITE
mov rdi, STDOUT
mov rsi, temp
syscall
getLength msg
mov rax, SYS_WRITE
mov rdi, [rsp]
mov rsi, msg
mov rdx, r11
syscall
mov rax, SYS_CLOSE
mov rdi, r11
syscall
exit
This coe doesn't work:
%include "./standardlib.inc"
section .data
filename db "./file.txt", 0
msg db "hello", 10
section .bss
temp resb 10
section .text
global _start:
_start:
mov rax, SYS_OPEN
mov rdi, filename
mov rsi, O_CREAT+O_RDWR+O_APPEND
mov rdx, 0744o
syscall
push rax
getLength msg
mov rax, SYS_WRITE
mov rdi, [rsp]
mov rsi, msg
mov rdx, r11
syscall
mov rax, SYS_READ
mov rdi, [rsp]
mov rsi, temp
mov rdx, 10
syscall
mov rdx, rax
mov rax, SYS_WRITE
mov rdi, STDOUT
mov rsi, temp
syscall
mov rax, SYS_CLOSE
mov rdi, r11
syscall
exit
So i understood that I have to use lseek to return to the beginning of the file.
Is this a good invocation for sys_lseek?
mov rax, 8 ;sys_lseek syscall ID
mov rdi, [rsp] ;file descriptor
mov rsi, 0 ;The offset
mov rdx, 0 ;I imagine the value of SEEK_SET
sys_lseek
I suppose that the offset value is wrong and I should have used ftell to find it, but I can't figure out how to call it.
ftell
Since the file are read sequentially, after a call to sys_read in append mode the cursor is moved to the end of the file, so if you try to read from that position you won't read anything.
To solve this problem you have to reposition the cursor at the beginning of the file.
To do that you can use the lseek system call.
mov rax, 8 ;system call Id for sys_lseek
mov rdi, [rsp] ;file descriptor
mov rsi, 0 ;offset value, so number of characters to move the cursor
mov rdx, 0 ;It indicates the initial position from which move the cursor, in this case the value 0 indicates that the initial position is the beginning of the file
syscall
After a call to this system call the cursor position will be at the beginning of the file and you will be able to read from it.

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.

Assembly, read in 2 ints

I've just started to learn assembler (2 days ago) for x86 arch (but I program on x86_64 see below). I want to read in 2 numbers and for that I use Linux system calls (64 bit system). Well I looked up the corresponding numbers for read/write in unitstd_64.h and seems to work. But one thing bothers me (first the code):
section .data
prompt1 db "Enter a number: ", 0
lenMsg equ $-prompt1
outmsg db "Entered: ", 0
lenOut equ $-outmsg
section .bss
input1 resd 1
input2 resd 1
segment .text
global _start
_start:
mov rax, 1
mov rdi, 1
mov rsi, prompt1
mov rdx, lenMsg
syscall
;read input number 1
mov rax, 0
mov rdi, 2
mov rsi, input1
mov rdx, 1
syscall
;prompt another number
mov rax, 1
mov rdi, 1
mov rsi, prompt1
mov rdx, lenMsg
syscall
;read input number 1
mov rax, 0
mov rdi, 2
mov rsi, input2
mov rdx, 1
syscall
;exit correctly
mov rax, 60
mov rdi, 0
syscall
The program does the following:
Shows prompt1
Let the user enter a number
Shows prompt1 again
quits (should'nt it let the user enter a number instead of quitting?)
Why is the fourth syscall simply ignored? Thanks in advance.
edit:
I use nasm. Object file created with nasm -f elf64 bla.asm. Linked with ld -o bla bla.o

Getting digit instead of Ascii in nasm assembly intel x86

I'm trying to learn the basics of assembly but can't get across on how to display results stored in memory.
section .data
num1 db 1,2,3,4,5
num2 db 1,2,3,4,5
output: db 'The dot product is "'
outputLen1 : equ $-output
output2: db '" in Hex!', 10
output2Len : equ $-output2
section .bss
dotProd resw 1 ; store dot product in here
section .text
global _start
_start:
mov eax, 0
mov ecx, 5
mov edi, 0
mov esi, 0
looper: mov ax, [edi + num1]
mov dx, [esi + num2]
mul dx
add [dotProd], ax
cmp cx, 1
je printOutput
inc edi
inc esi
dec cx
jmp looper ; go back to looper
printOutput:
mov eax,4 ; The system call for write (sys_write)
mov ebx,1 ; File descriptor 1 - standard output
mov ecx, output ;
mov edx, outputLen1 ;
int 80h ; Call the kernel
mov eax, 4
mov ebx, 1
mov ecx, dotProd,
mov edx, 1
int 80h
mov eax, 4
mov ebx, 1
mov ecx, output2,
mov edx, output2Len
int 80h
jmp done
done:
mov eax,1 ; The system call for exit (sys_exit)
mov ebx,0 ; Exit with return code of 0 (no error)
int 80h
What I'm trying to do is get the dot product of the two list of numbers and display it on the screen. However, I keep getting random letters which I believe are hex representations of the real decimal value. How can I convert it to decimal? The current value display is 7, which should is the equivalent ASCII char for 55, which in this case is the dot product of both list of numbers.
esi and edi must be increased such that it points to next element of array.(in this particular example, only one of them is sufficient).
declare mun1 andnum2 as dd, instead of db (see here).
Also, you have to have method for printing number.(see this and this).
Below is a complete code which uses printf.
;file_name:test.asm
;assemble and link with:
;nasm -f elf test.asm && gcc -m32 -o test test.o
extern printf
%macro push_reg 0
push eax
push ebx
push ecx
push edx
%endmacro
%macro pop_reg 0
pop edx
pop ecx
pop ebx
pop eax
%endmacro
section .data
num1: dd 1,2,3,4,5
num2: dd 1,2,3,4,5
msg: db "Dot product is %d",10,0
section .bss
dotProd resd 1 ; store dot product in here
section .text
global main
main:
mov eax, 0
mov ecx, 5
mov edx, 0
mov esi, 0
mov dword[dotProd], 0h
looper: mov eax, dword[esi + num1]
mov edx, dword[esi + num2]
mul edx
add [dotProd], eax
cmp cx, 1
je printOutput
add esi,4
dec cx
jmp looper ; go back to looper
printOutput:
push_reg
push dword[dotProd]
push dword msg
call printf
add esp,8
pop_reg
jmp done
done:
mov eax,1 ; The system call for exit (sys_exit)
mov ebx,0 ; Exit with return code of 0 (no error)
int 80h

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