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

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.

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?

how to fix killed by SIGSEGV (core dumped) error

So i am writing a program in linux x86_64 assembly, the program needs to open a test directory specified in a "section data" , then list the bytes readed from a file with system call "getdents64" , then parse the bytes to get the filenames since "getdents64" returns the number of bytes.
here is the code
global _start
section .data
dir : db "test",0
len: equ 1024 ;define buffer size
section .bss
buffer: resb len
section .text
_start:
;open folder
mov rax, 2 ;sys_open
mov rdi, dir ;folder to open
mov rsi, 0 ;read only
mov rdx, 0
syscall
cmp rax, 0 ;if there is no folder go to exit
jbe exit
list:
mov rdi, rax ;directory in rdi
mov rax, 217 ;sys_getdents64
mov rsi, buffer
mov rdx, len ;length of the buffer
syscall
xchg r10, rax ;save buffer in r10 to loop through it
xor rax, rax ;zero out rax for the next system call
close:
mov rax, 3 ;sys_close
syscall
find_fname_start:
; look for the sequence 0008 which occurs before the start of a filename
add r15, 1
cmp r15, len
jge exit
cmp byte [buffer+r15],
jnz find_fname_start
add r15, 1
cmp byte [buffer+r15], 0x08
jnz find_fname_start
xor rcx, rcx
find_fname_end:
; look for the 00 which denotes the end of a filename
add r15, 1 ;
cmp r15, len
jge exit
mov rdi, [buffer+r15] ;<<< PROBLEM
mov [r15+rcx], rdi
inc rcx ;increment offset stored in rcx
cmp byte [buffer+r15], 0x00 ;denotes end of the filename
jnz find_fname_end
mov byte [r15+rcx], 0x00 ;filename should be in r15
;delete the file
jmp find_fname_start
unlink:
cmp r10, 0 ;if done, exit the program
jbe exit
mov rax, 87 ;sys_unlink
mov rdi, buffer ;list of files
syscall
jmp unlink
exit:
mov rax, 60 ;sys_exit
mov rdi, 80
syscall
i used gdb to investigate the problem and at the in "find_fname_end", when i try to move byte from a file to a buffer it gets an error
"Program received signal SIGSEGV, Segmentation fault.
0x0000000000400136 in find_fname_end ()"
i put a arrow in code to show you the line that gets this output

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.

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

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