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

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

Related

Getting segmentation fault or bus error when moved some code from place before function ret after place just after function call in Assembly [duplicate]

This question already has answers here:
Why does the x86-64 / AMD64 System V ABI mandate a 16 byte stack alignment?
(1 answer)
glibc scanf Segmentation faults when called from a function that doesn't align RSP
(1 answer)
Calling printf in x86_64 using GNU assembler
(2 answers)
Closed 1 year ago.
Welcome.
I have following code:
%define ESC 0x1b
section .text
global _start
_start:
.drawer:
call getdata
mov rdi, 1
call sleep
jmp .drawer
mov rdi, 0
mov rax, 60 ;; sys_exit
syscall ;; exit
sleep:
mov [timespec.tv_sec], rdi
xor rdi, rdi
mov [timespec.tv_usec], rdi
mov rdi, timespec
xor rsi, rsi
mov rax, 35 ;; sys_nanosleep
syscall ;; nanosleep
ret
getuptime:
mov rdx, 16
mov rsi, data.uptimebuf
mov rdi, filename.uptime
call readfile
mov rdi, rsi
mov rsi, 0x2e ;; ASCII '.'
call strclen
mov rsi, rax
call stoin
mov qword [data.uptime], rax
mov rdi, qword [data.uptime]
call printi
ret
getdata:
call getuptime
ret
section .data
data:
.uptime dq 0
.uptimebuf times 16 db 0
timespec:
.tv_sec dq 0
.tv_usec dq 0
section .rodata
ansi:
.clear db ESC, "[2J", ESC, "[H"
.clearlen equ $ - .clear
filename:
.uptime db "/proc/uptime"
;; Content under this line is included on beginning like this:
;; %include "libasm.asm"
;; under line
;; %define ESC 0x1b
section .text
strlen: ;; string: rdi
push rbx
mov rbx, rdi
.again:
cmp byte [rbx], 0
jz .done
inc rbx
jmp .again
.done:
sub rbx, rdi
mov rax, rbx
pop rbx
ret
strclen: ;; string: rdi, char: rsi
push rbx
mov rbx, rsi
mov al, bl
mov rbx, rdi
.again:
cmp byte [rbx], 0
jz .done
cmp byte [rbx], al
je .done
inc rbx
jmp .again
.done:
sub rbx, rdi
mov rax, rbx
pop rbx
ret
printn: ;; string: rdi, len: rsi
push rdx
push rsi
push rdi
mov rdx, rsi
mov rsi, rdi
mov rdi, 1
mov rax, 1 ;; sys_write
syscall ;; write(unsigned int fd, const char *buf, size_t count)
pop rdi
pop rsi
pop rdx
ret
stoin: ;; string: rdi, len: rsi
push rdx
push rcx
push rbx
mov rdx, rdi
xor rcx, rcx
xor rax, rax
.again:
mov rbx, 10
cmp rcx, rsi
jge .done
push rdx
mul rbx
pop rdx
xor rbx, rbx
mov bl, byte [rdx]
sub bl, 0x30 ;; ASCII '0'
add rax, rbx
inc rdx
inc rcx
jmp .again
.done:
pop rbx
pop rcx
pop rdx
ret
readfile: ;; filename: rdi, buffer: rsi, length: rdx
push rsi
xor rsi, rsi
mov rax, 2 ;; sys_open
syscall ;; open(char *filename, int flags, int mode)
pop rsi
push rdi
mov rdi, rax
mov rax, 0 ;; sys_read
syscall ;; read(unsigned int fd, const char *buf, size_t count)
mov rax, 3 ;; sys_close
syscall ;; close(unsigned int fd);
pop rdi
ret
printi: ;; long: rdi
extern printf
section .data
fmt db "%ld", 10, 0
section .text
push rsi
mov rsi, rdi
mov rdi, fmt
call printf
pop rsi
ret
If it stays like that, everyething works properly, but I want to move last 2 instructions before ret in getuptime function to place just after calling getuptime, just like that:
getuptime:
mov rdx, 16
mov rsi, data.uptimebuf
mov rdi, filename.uptime
call readfile
mov rdi, rsi
mov rsi, 0x2e ;; ASCII '.'
call strclen
mov rsi, rax
call stoin
mov qword [data.uptime], rax
ret
getdata:
call getuptime
mov rdi, qword [data.uptime]
call printi
ret
but when I'll do it, i am getting Segmentation Fault or Bus Error. Why?

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.

Get end of data segment in assembly in Linux

I am trying to build a malloc function in assembly. My plan is to use the brk syscall, however in order to do this, I need to be able to know where the end of the current segment is. In c I could use sbrk(0) however this isn't available in assembly. Is there anyway to get the end of the data segment, aside from just putting a label at the bottom.
I am using Ubuntu, nasm, and ld if it helps.
I am assembling and linking with:
nasm -f elf64 mem.s -o mem.o
ld -m elf_x86_64 -o mem mem.o -e _start
mem.asm
global _start
%include "stdasm.s"
section .text
_start:
mov rax, 1
mov rbx, str
call print
mov rax, 0x0123456789ABCDEF
call regPrint
mov rax, end
call regPrint
mov rax, _end
call regPrint
call exit
section .data
str: db 'Hello, world!',0x0A,0
end:
stdasm.s
section .text
exit:
mov rax, 1
mov rbx, 0
int 0x80
print:;rax = fd, rbx = string
push rdx
push rcx
mov rcx, rbx
mov rbx, rax
.loop:
cmp byte [rcx], 0
je .exit
mov rdx, 1
mov rax, 4
int 0x80
inc rcx
jmp .loop
.exit:
pop rcx
pop rdx
ret
regPrint:
push rbx
push rcx
push rdx
xor rcx, rcx
mov rbx, regPrintBuf
.loop:
rol rax, 4
mov dl, al
and rdx, 0x0F
add rdx, hexStr
mov dl, byte [rdx]
mov byte [rbx], dl
inc rcx
inc rbx
cmp rcx, 16
jl .loop
mov rbx, regPrintBuf
mov rax, 1
call print
pop rdx
pop rcx
pop rbx
ret
section .data
hexStr: db '0123456789ABCDEF'
regPrintBuf: db '0000000000000000', 0x0A,0
The linker creates the symbol _end pointing to the end of the data segment at link time. You can use this symbol to find the end of the data segment.
The area allocated by brk is not continuous with the data segment of the executable unless address space layout randomisation is disabled.
To find the current end of this area call brk with an argument of 0. At program start the size is zero so the end address is the same as the start address.

Printing binary string in assembly

I'm writing a program to print binary string of a hardcoded word. Here is how it looks like currently:
main.asm
section .text
global _start
extern _print_binary_content
_start:
push word [word_to_print] ; pushing word. Can we push just one byte?
call _print_binary_content
mov rax, 60
mov rdi, 0
syscall
section .data
word_to_print: dw 0xAB0F
printer.asm
SYS_BRK_NUM equ 0x0C
BITS_IN_WORD equ 0x10
SYS_WRITE_NUM equ 0x01
STD_OUT_FD equ 0x01
FIRST_BIT_BIT_MASK equ 0x01
ASCII_NUMBER_OFFSET equ 0x30
section .text
global _print_binary_content
_print_binary_content:
pop rbp
xor ecx, ecx ;zeroing rcx
xor ebx, ebx ;zeroing rbx
pop bx ;the word to print the binary content of
;sys_brk for current location
mov rax, SYS_BRK_NUM
mov rdi, 0
syscall
;end sys_brk
mov r12, rax ;save the current brake location
;sys_brk for memory allocation 16 bytes
lea rdi, [rax + BITS_IN_WORD]
mov rax, SYS_BRK_NUM
syscall
;end sys_brk
xor ecx, ecx
mov cl, byte BITS_IN_WORD - 1; used as a counter in the loop below
loop:
mov dx, bx
and dx, FIRST_BIT_BIT_MASK
add dx, ASCII_NUMBER_OFFSET
mov [r12 + rcx], dl
shr bx, 0x01
dec cl
cmp cl, 0
jge loop
mov rsi, r12
mov rax, SYS_WRITE_NUM
mov rdi, STD_OUT_FD
mov rdx, BITS_IN_WORD
syscall
push rbp ; pushing return address back
ret
If I compile link and run this program it works. But the question is about performance and maybe conventions of writing assembly programs. In the file printer.asm I cleaned ecx twice which looks kind of not optimal. Maybe some registers were used not by their purpose (I used intel-manual).
Can you please help me to improve this very simple program?

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