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

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?

Related

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?

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

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.

Search for and replace characters in a string in assembly nasm issues

I've got this working to where it copies a string into another. I'm trying to make it search for a term and swap it. For some reason, if the replace function isn't commented, it somehow manages to delete the output in the console (literally goes backwards!). If I comment the replace function out, I just get an exact copy. Trying to change cat to dog.
bits 64
global main
extern printf
section .text
main:
; function setup
push rbp
mov rbp, rsp
sub rsp, 32
;
lea rdi, [rel message]
mov al, 0
call printf
;print source message
lea rdi, [rel source]
mov al, 0
call printf
;print target message
lea rdi, [rel target]
mov al, 0
call printf
lea rdi, [rel target]
lea rsi, [rel source]
cld
jmp Loop
Loop:
lodsb ;Load byte at address RSI into AL
stosb ;Store AL at address RDI
;push [rdi]
cmp byte RDI, 'c'
je replace
;pop [rdi]
test al,al ;code will jump only if al is not equ 0
jnz Loop
replace:
;lea rdi, [rel success]
mov byte [rdi], 'd'
;call printf
ret
;print new version of target
lea rdi, [rel target]
mov al, 0
call printf
; function return
mov eax, 0
add rsp, 32
pop rbp
ret
section .data
message: db 'Project:',0x0D,0x0a,'Author:',0x0D,0x0a,0x0D,0x0a,0
source: db "The cat chased the bird.",0x0a,0x0D,0
target: db '0000000000000000000000000000000000000000000',0x0D,0x0a,0
success: db "Success",0
This is what you want. I tested it in Ubuntu 64 with:
(assumed this file is a.asm)
nasm -f elf64 -l a.lst a.asm &
gcc -m64 -o a a.o
bits 64
global main
extern printf
section .text
main:
; function setup
push rbp
mov rbp, rsp
sub rsp, 32
;
lea rdi, [rel message]
mov al, 0
call printf
;print source message
lea rdi, [rel source]
mov al, 0
call printf
;print target message
lea rdi, [rel target]
mov al, 0
call printf
lea rdi, [rel target]
lea rsi, [rel source]
cld
Loop:
lodsb ;Load byte at address RSI into AL
stosb ;Store AL at address RDI
cmp al, 'c'
jne LoopBack
lodsb ;Load byte at address RSI into AL
stosb ;Store AL at address RDI
cmp al, 'a'
jne LoopBack
lodsb ;Load byte at address RSI into AL
stosb ;Store AL at address RDI
cmp al, 't'
jne LoopBack
sub rdi, 3
mov byte [rdi], 'd'
inc rdi
mov byte [rdi], 'o'
inc rdi
mov byte [rdi], 'g'
inc rdi
LoopBack:
cmp al, 0
jne Loop
;print new version of target
lea rdi, [rel target]
mov al, 0
call printf
; function return
mov eax, 0
add rsp, 32
pop rbp
ret
section .data
message: db 'Project:',0x0D,0x0a,'Author:',0x0D,0x0a,0x0D,0x0a,0
source: db "The cat chased the bird.",0x0a,0x0D,0
target: db '0000000000000000000000000000000000000000000',0x0D,0x0a,0
success: db "Success",0
The output is this:
Project:
Author:
The cat chased the bird.
0000000000000000000000000000000000000000000
The dog chased the bird.

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