Assembly, read in 2 ints - linux

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

Related

I want my Assembly Code to takes user input and outputs it along with other text but the output isn't correct

My code works but the output isn't just right because when I enter the name, the output becomes this; "What is your member name? Welcome to the club, Bob!!!!!!!!!!!!!!!!!!, enjoy the party." with the "!!!!!!" at the end of the name. What am I doing wrong?
Here is my assembly code:
section .data
prompt: db "What is your member name? "
prompt_len: equ $-prompt
greet1: db "Welcome to the club, "
greet1_len: equ $-greet1
greet2: db ", enjoy the party."
greet2_len: equ $-greet2
inputbuffer_len: equ 256
inputbuffer: times inputbuffer_len db '!'
STDIN: equ 0
STDOUT: equ 1
SYS_READ: equ 0
SYS_WRITE: equ 1
SYS_EXIT: equ 60
section .text
global _start
_start:
mov rdx, prompt_len ;output prompt
mov rax, SYS_WRITE
mov rdi, STDOUT
mov rsi, prompt
syscall
mov rax, SYS_READ ;user input here
mov rdi, STDIN
mov rsi, inputbuffer
mov rdx, inputbuffer_len
syscall
mov rdx, greet1_len ; output "Welcome to the club, "
mov rax, SYS_WRITE
mov rdi, STDOUT
mov rsi, greet1
syscall
mov rdx, rax ;output user's inputted name
mov rax, SYS_WRITE
mov rdi, STDOUT
mov rsi, inputbuffer
syscall
mov rdx, greet2_len ; output ", enjoy the party."
mov rax, SYS_WRITE
mov rdi, STDOUT
mov rsi, greet2
syscall
mov rax, SYS_EXIT
mov rdi, 0
syscall
The length of Bob!!!!!!!!!!!!!!!!!! is the length of Welcome to the club, .
This is no coincidence.
Following the write(2) system call rax contains the number of successfully written Bytes.
(This might be less than the desired number of Bytes as the manual page describes.)
Like David C. Rankin commented you will need to mind the return value of read(2).
On success, read(2) returns the number of Bytes read in rax.
However, you are overwriting this value for and with the intervening write(2) system call.
Store and recall somewhere the number of successfully read Bytes (e. g. push/pop) and you’re good.
PS:
You could save one write(2) system call by rearranging the buffer to follow after greet_1.
Then you could write(2) rax + greet1_len Bytes at once.
But one problem at a time.

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

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

Linux system call for X86 64 echo program

I'm still learning assembly so my question may be trivial.
I'm trying to write an echo program with syscall, in which I get a user input and give it as output on the next line.
section .text
global _start
_start:
mov rax,0
mov rdx, 13
syscall
mov rsi, rax
mov rdx, 13
mov rax, 1
syscall
mov rax, 60
mov rdi, 0
syscall
I'm assuming all you want to do is return the input to the output stream, so to do that you need to do a few things.
First, create a section .bss in your code. This is for initializing data. You will initialize a string with any name you want and do so with label resb sizeInBits. for demonstration it will be a 32 bit string called echo.
Extra note, the ';' character is used for comments similar to what // is in c++.
Example code
section .data
text db "Please enter something: " ;This is 24 characters long.
section .bss
echo resb 32 ;Reserve 32 bits (4 bytes) into string
section .text
global _start
_start:
call _printText
call _getInput
call _printInput
mov rax, 60 ;Exit code
mov rdi, 0 ;Exit with code 0
syscall
_getInput:
mov rax, 0 ;Set ID flag to SYS_READ
mov rdi, 0 ;Set first argument to standard input
; SYS_READ works as such
;SYS_READ(fileDescriptor, buffer, count)
;File descriptors are: 0 -> standard input, 1 -> standard output, 2 -> standard error
;The buffer is the location of the string to write
;And the count is how long the string is
mov rsi, echo ;Store the value of echo in rsi
mov rdx, 32 ;Due to echo being 32 bits, set rdx to 32.
syscall
ret ;Return to _start
_printText:
mov rax, 1
mov rdi, 1
mov rsi, text ;Set rsi to text so that it can display it.
mov rdx, 24 ;The length of text is 24 characters, and 24 bits.
syscall
ret ;Return to _start
_printInput:
mov rax, 1
mov rdi, 1
mov rsi, echo ;Set rsi to the value of echo
mov rdx, 32 ;Set rdx to 32 because echo reserved 32 bits
syscall
ret ;Return to _start

Linux Intel 64bit Assembly Division

I am battling to understand why my division is not working, below is my current code, which simply takes in two single digits and attempts to divide them:
STDIN equ 0
SYS_READ equ 0
STDOUT equ 1
SYS_WRITE equ 1
segment .data
num1 dq 0
num2 dq 0
quot dq 0
rem dq 0
segment .text
global _start
_start:
mov rax, SYS_READ
mov rdi, STDIN
mov rsi, num1
mov rdx, 2
syscall
mov rax, SYS_READ
mov rdi, STDIN
mov rsi, num2
mov rdx, 2
syscall
mov rax, [num1]
sub rax, '0'
mov rbx, [num2]
sub rbx, '0'
xor rdx, rdx
div rbx
add rax, '0'
mov [quot], rax
mov [rem], rdx
mov rax, SYS_WRITE
mov rdi, STDOUT
mov rsi, quot
mov rdx, 1
syscall
mov rax, 60
xor rdi, rdi
syscall
Now as far as I understand when dividing the assembler will divide RDX:RAX by the operand RBX. I can only assume this is where the problem is coming in, the fact that I am dividing a 128bit value by a 64bit value. Whenever I enter something such as 8 / 2 or something similar, I receive the value 1 as the quotient. What am I missing here? Any help would be greatly appreciated.
You read 2 bytes for the operands, but it seems you ignore the 2nd, when you shouldn't.
Assuming you type 8 and 2 and one line each, you will read "8\n" and "2\n". You then subtract '0', but you leave the '\n', so your operands will be 0x08 0x0A and 0x02 0x0A, which are 2568 and 2562. And 2568 / 2562 = 1.

How to read from and write to files using NASM for x86-64bit

I have a NASM program for 64bit Linux system which works with standard I/O devices and it looks something like that:
section .data
prompt db "Enter your text: ", 10
length equ $ - prompt
text times 255 db 0
textSize equ $ - text
section .text
global main
main:
mov rax, 1
mov rdi, 1
mov rsi, prompt
mov rdx, length
syscall ;print prompt
mov rax, 0
mov rdi, 0
mov rsi, text
mov rdx, textSize
syscall ;read text input from keyboard
mov rcx, rax ; rcx - character counter
mov rsi, text ; a pointer to the current character starting from the beginning.
****
exit:
mov rax, 60
mov rdi, 0
syscall
I need the program to read from and write to the files, but I can't find anywhere which syscalls has to be used and how they should be used to achieve these results. So, I am wondering if someone of you could help me. Thanks in advance.
Use system calls "open" and "close":
Open a file under 64-bit Linux:
rax = 2
rdi = pointer to NUL-terminated filename
rsi = something like O_WRONLY
rdx = file flags if creating a file (e.g. 0644 = rw-r--r--)
syscall
now rax contains the file hanle
Close a file:
rax = 3
rdi = file handle
syscall
Reading/writing from/to a file:
rax = 0 or 1 (like keyboard/screen in/output)
rdi = file handle (instead of 0/1)
...
;this program is only overwrite the result.txt
;to write it on bottom you need to lseek to the end
section .data
prompt db "Enter your text: ",10
length equ $ - prompt
text times 255 db 0
textsize equ $-text
fname db "result.txt",0
fd dq 0
thefox dq 0
global _start
section .text
_start:
mov al,1
mov dil,al
mov esi,prompt
mov dl,length
syscall
mov al,0
mov dil,al
mov rsi,text
mov rdx,textsize
syscall
mov [thefox],rax
mov rax,2
mov rdi,fname
mov rsi,0102o
mov rdx,0666o
syscall
mov [fd],rax
mov rdx,[thefox]
mov rsi,text
mov rdi,[fd]
mov rax,1
syscall
mov rdi,[fd]
mov rax,3
syscall
mov rax,60
syscall

Resources