I made this program that open a image file and find a hidden message in the file. I have to print the message on the console.
i think the part where i open the file and search for the hidden message is right, but i don´t know for sure because i can´t print the output to confirm.
this is the code:
; Example program to demonstrate file I/O.
; This example will open/create a file, write some
; information to the file, and close the file.
; Note, the file name is hard-coded for this example.
; This example program will open a file, read the
; contents, and write the contents to the screen.
; This routine also provides some very simple examples
; regarding handling various errors on system services.
; -------------------------------------------------------
section .data
; -----
; Define standard constants.
LF equ 10 ; line feed
NULL equ 0 ; end of string
TRUE equ 1
FALSE equ 0
EXIT_SUCCESS equ 0 ; success code
STDIN equ 0 ; standard input
STDOUT equ 1 ; standard output
STDERR equ 2 ; standard error
SYS_write equ 1; write
SYS_read equ 0 ; read
SYS_open equ 2 ; file open
SYS_close equ 3 ; file close
SYS_exit equ 60 ; terminate
SYS_creat equ 85 ; file open/create
SYS_time equ 201 ; get time
O_CREAT equ 0x40
O_TRUNC equ 0x200
O_APPEND equ 0x400
O_RDONLY equ 000000q ; read only
O_WRONLY equ 000001q ; write only
S_IRUSR equ 00400q
S_IWUSR equ 00200q
S_IXUSR equ 00100q
; -----
; Variables/constants for main.
BUFF_SIZE equ 256
newLine db LF, NULL
db LF, LF, NULL
fileName dq 6
fileDesc dq 0
errMsgOpen db "Error opening the file.", LF, NULL
errMsgRead db "Error reading from the file.", LF, NULL
offset db 1
size db 1
; -------------------------------------------------------
section .bss
readBuffer: resb BUFF_SIZE
; -------------------------------------------------------
section .text
global _start
_start:
xor rax, rax
xor rcx, rcx
xor rdx, rdx
xor rbx, rbx
mov rbx, rsp
mov rax, qword [rbx+16]
mov [fileName], rax
xor rax, rax
push rsp
; Attempt to open file - Use system service for file open
openInputFile:
pop rax ; pop argc value - should be 2
cmp rax, 0x2
jne done
mov rax, SYS_open ; file open
mov rdi, fileName ; file name string
mov rsi, O_RDONLY ; read only access
syscall ; call the kernel
cmp rax, 0 ; check for success
jl errorOnOpen
mov qword [fileDesc], rax ; save descriptor
; -----
; Read from file.
;
mov rax, SYS_read
mov rdi, qword [fileDesc]
mov rsi, readBuffer
mov rdx, BUFF_SIZE
syscall
cmp rax, 0
jl errorOnRead
; -----
; Print the buffer.
; add the NULL for the print string
mov rax, qword [readBuffer+2] ;SSSS
mov qword [size], rax
mov rax, qword [readBuffer+10] ;OOOO
mov [offset], rax
mov rcx, 0
ler: ;ler um caracter
mov rbp, 0
xor rbx, rbx
xor rdx, rdx
lerloop:
inc rax
cmp rax, [size]
je errorOnRead
saltaQuartobyte:
inc ecx
cmp ecx, 4
jne continua
inc rax ;incremneta rax outra vez para saltar o quarto
cmp rax, [size]
je errorOnRead
mov ecx, 0
continua:
mov bl, byte [readBuffer+rax]
shl rdx, 1
shr rbx, 1
adc rdx, 0
inc rbp
cmp rbp, 7 ;fim do caracter ASCII, 0X 0XXX XXXX
jne lerloop
mov rdi, rdx
call printString ; imprime caracter ASCII
cmp rax, [size] ;comea o priximo
jne ler
; -----
; Close the file.
mov rax, SYS_close
mov rdi, qword [fileDesc]
syscall
jmp done
; -----
; Error on open.
errorOnOpen:
mov rdi, errMsgOpen
call printString
jmp done
; Error on read.
errorOnRead:
mov rdi, errMsgRead
call printString
jmp done
; -----
; program done.
done:
mov rax, SYS_exit
mov rdi, EXIT_SUCCESS
syscall
; **********************************************************
; Generic procedure to display a string to the screen.
global printString
printString:
push rbp
mov rbp, rsp
push rbp
; -----
; Call OS to output string.
mov rax, SYS_write ; code for write()
mov rsi, rdi ; addr of characters
mov rdi, STDOUT ; file descriptor
; count set above
syscall ; system call
; -----
; String printed, return to calling routine.
prtDone:
pop rbx
pop rbp
ret
this is my last attempt of the print but the program still don't print anything, and I don't understand why? or what's wrong?
A fundamental error
push rsp
; Attempt to open file - Use system service for file open
openInputFile:
pop rax ; pop argc value - should be 2
cmp rax, 0x2
jne done
mov rax, SYS_open ; file open
Your program starts with copying the stackpointer RSP to the accumulator RAX, and then compares to see if the value is 2, but when is the stackpointer ever going to be 2? And so, the program will always prematurely exit. No wonder that nothing gets printed.
A selection of other errors
offset db 1
size db 1
...
mov rax, qword [readBuffer+2] ;SSSS
mov qword [size], rax
mov rax, qword [readBuffer+10] ;OOOO
mov [offset], rax
You have reserved not enough room to store the qwords size and offset!
Better store them in the .bss section using resq:
section .bss
readBuffer: resb BUFF_SIZE
offset resq 1
size resq 1
mov rax, qword [readBuffer+2] ;SSSS
mov qword [size], rax
mov rax, qword [readBuffer+10] ;OOOO
mov [offset], rax
If the file is a .BMP (I'm considering those well-known offsets), then the size and offset fields are actually dwords. You would have to write instead (loading EAX automatically zero extends the value into RAX):
mov eax, [readBuffer+2] ;SSSS
mov [size], rax
mov eax, [readBuffer+10] ;OOOO
mov [offset], rax
printString:
push rbp
mov rbp, rsp
push rbp <<<<
...
pop rbx <<<<
pop rbp
ret
Because of the mismatch, you're destroying RBX on return.
The code that you used depends on calculating the length of the ASCIIZ string. You cannot just leave that out!
Related
This is my code with commented explanations:
SECTION .data ; Section containing initialised data
EatMsg: db "Eat at Joe's!",10
EatLen: equ $-EatMsg
SECTION .bss ; Section containing uninitialized data
SECTION .text ; Section containing code
global _start ; Linker needs this to find the entry point!
_start:
nop ; This no-op keeps gdb happy...
mov rax,1 ; Code for Sys_write call
mov rdi, 1 ; Specify File Descriptor 1: Standard Output
mov rsi, EatMsg ; Pass offset of the message
mov rdx, EatLen ; Pass the length of the message
mov R9, [EatMsg] ; move the adresse of Msg into R9
syscall
mov rcx, 5
DoMore:
mov rax, 1 ; Code for Sys_write call
mov rdi, 1 ; Specify File Descriptor 1: Standard Output
mov rsi, EatMsg ; Pass offset of the message
mov rdx, EatLen ; Pass the length of the message
dec rcx
jnz DoMore
syscall ; Make kernel call
mov rax, 1 ; Code for exit
mov rdi, 0 ; Return a code of zero
syscall ; Make kernel call
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?
I'm not sure where I have errored, I'm trying to output a gradient pattern from 0-255 red horizontally and 0-255 green vertically. I know the linked files worked correctly as they have been throughly tested. Any help would be very appreciated.
global _start
global start
extern writeRGB
extern writeHeader
_start:
call start
sys_write: equ 1
sys_open: equ 2
sys_close: equ 3
sys_exit: equ 60
newLine : equ 10
section .data
filename: db "gradient.ppm", 0
section .bss
buffer: resb 4096
section .text
start:
push r12
push r13
push r14
push r15
push rbx
push rbp
mov rax, sys_open ; setup to open file
mov rdi, filename ; move filename
mov rsi, 577 ; given
mov rdx, 0o644 ; given
syscall ; open file
cmp rax, 0 ; check status
jl end
mov r12, 0 ; red
mov r13, 0 ; green
mov r14, rax ; opened file
mov r15, buffer ; buffer
mov rbx, 0 ; buffer counter
lea rdi, [r15+rbx] ; setup for writeheader call
mov rsi, 256
mov rdx, 256
call writeHeader
add rbx, rax ; add buffer space used by writeheader
call makeRGB ; create 0 0 0 rgb
lea rdi, [r15+rbx] ; setup for writeRGB
call writeRGB
add rbx, rax ; add buffer space used by writeRGB
call incRed
incRed:
call addSpace
inc r12 ; red++
call makeRGB ; convert to RBG
lea rdi, [r15+rbx] ; setup for writeRGB call
call writeRGB
add rbx, rax ; add buffer space used by writeRGB
cmp r12, 255 ; check to see if end of row
jl incRed ; if not end of row repeat
je incGreen ; if end of row start new row
incGreen:
cmp r13, 255 ; if last line is written move to end
je write
call addNewLine
mov r12, 0 ; reset red to 0
inc r13 ; green++
call makeRGB ; convert to RGB
lea rdi, [r15+rbx] ; setup for writeRGB call
call writeRGB
add rbx, rax ; add buffer space used by writeRGB
call addSpace
jmp incRed ; ret to incRed
makeRGB:
mov r12, rsi ; mov red into rsi
shl rsi, 8 ; shift left 8 to make room for green
add rsi, r13 ; add green
shl rsi, 8 ; shift left to set blue to 0
ret
addSpace:
mov al, ' ' ; insert space
mov [r15+rbx], al
inc rbx
ret
addNewLine:
mov al, newLine ; insert newline
mov [r15+rbx], al
inc rbx
ret
write:
mov rax, sys_write
mov rdi, r14 ; move opened file into rdi
mov rsi, r15 ; buffer location
mov rdx, rbx ; load buffer size
syscall ; write to file
mov rbp, rax ; status stored in rbp
cmp rbp, 0 ; check status
jl end
mov rdi, r14 ; move opened file into rdi
mov rax, sys_close ; close file
syscall
call end ; end
end:
pop rbp
pop rbx
pop r15
pop r14
pop r13
pop r12
mov rdi, rax ; prepare to exit
mov rax, sys_exit
syscall ; exit
I'm trying to learn NASM. I want to write a procedure to get one character at a time from the console until a newline (0xA) is encountered using only kernel calls. So far I have
global _start
section .data
sys_read equ 3
sys_write equ 4
stdin equ 0
stdout equ 1
section .bss
line resb 11
index resb 4
section .text
_start:
push ebp
mov ebp, esp
call _readLine
afterReadLine:
call _printLine
mov esp, ebp
pop ebp
jmp exit
_readLine:
; Reads into line until new line (0xA)
; Number of bytes read will be stored in index when _readLine returns
mov eax, sys_read ; syscall to read
mov ebx, stdin ; stdin
mov edx, [index] ; put index into edx
mov ecx, dword line ; put line addr in ecx
add ecx, edx ; add index to addr in ecx
mov edx, 1 ; read one char
int 0x80 ; call kernel to read char
mov ecx, [index] ; put index into ecx
cmp dword [line + ecx], 0xA ; compare value at line + ecx to new line char
inc byte [index] ; increment index
je afterReadLine ; if last char is newline return
jne _readLine ; if last char is not new line, loop
_printLine:
mov eax, sys_write
mov ebx, stdout
mov ecx, line
mov edx, [index]
int 0x80
ret
exit:
mov eax, 01h ; exit()
xor ebx, ebx ; errno
int 80h
When I test against the value stored in the index variable at the end, it always equals 0. I tried moving the value of index into eax, but it's also zero after the jump. I tried using the ret keyword, but that also seemed to overwrite my values. What is the best practice way to return the value of characters read from this procedure?
EDIT:
I tried the following and I'm still not getting any output. With input "abcd[newline]" the program outputs "abcd" if I hardcode the value of 4 in edx in the _printLine procedure, but as written won't output anything.
global _start
section .data
sys_read equ 3
sys_write equ 4
stdin equ 0
stdout equ 1
bytesRead dd 0
termios: times 36 db 0
ICANON: equ 1<<1
ECHO: equ 1<<3
section .bss
line resb 11
index resb 4
section .text
_start:
push ebp
mov ebp, esp
call canonical_off
call echo_off
call _readLine
call _printLine
call canonical_on
call echo_on
mov esp, ebp
pop ebp
jmp exit
_readLine:
; Reads into line until new line (0xA)
; Number of bytes read will be stored in bytesRead when _readLine returns
mov eax, sys_read ; syscall to read
mov ebx, stdin ; stdin
mov edx, [index] ; put index into edx
mov ecx, dword line ; put line addr in ecx
add ecx, edx ; add index to addr in ecx
mov edx, 1 ; read one char
int 0x80 ; call kernel to read char
mov ecx, [index] ; put index into ecx
cmp dword [line + ecx], 0xA ; compare value at line + ecx to new line char
inc byte [index] ; increment index
jne _readLine ; if last char is not new line, loop
ret
_printLine:
mov eax, sys_write
mov ebx, stdout
mov ecx, line
mov edx, [index] ; Works if hardcoded 4 here!
int 0x80
ret
canonical_off:
call read_stdin_termios
; clear canonical bit in local mode flags
;push rax
mov eax, ICANON
not eax
and [termios+12], eax
;pop rax
call write_stdin_termios
ret
echo_off:
call read_stdin_termios
; clear echo bit in local mode flags
;push rax
mov eax, ECHO
not eax
and [termios+12], eax
;pop rax
call write_stdin_termios
ret
canonical_on:
call read_stdin_termios
; set canonical bit in local mode flags
or dword [termios+12], ICANON
call write_stdin_termios
ret
echo_on:
call read_stdin_termios
; set echo bit in local mode flags
or dword [termios+12], ECHO
call write_stdin_termios
ret
read_stdin_termios:
; push rax
; push rbx
; push rcx
;push rdx
mov eax, 36h
mov ebx, stdin
mov ecx, 5401h
mov edx, termios
int 80h
;pop rdx
; pop rcx
;pop rbx
;pop rax
ret
write_stdin_termios:
; push rax
;push rbx
;push rcx
; push rdx
mov eax, 36h
mov ebx, stdin
mov ecx, 5402h
mov edx, termios
int 80h
;pop rdx
;pop rcx
; pop rbx
;pop rax
ret
exit:
mov eax, 01h ; exit()
xor ebx, ebx ; errno
int 80h
link here http://ideone.com/Lw3fyV
First off, you are calling _readLine but not returning from it, instead you are jumping to the label after call _readLine conveniently called afterReadLine. You should use ret to exit from your function.
Now to your question. By default, the terminal is in canonical mode (Cooked mode), meaning all input is buffered. The system will fill your buffer until the return key is pressed and adds 0xA to the end of the buffer.
What you want is non-canonical mode (raw mode). This means the system does not process the key presses but passes it on to you.
How do i read single character input from keyboard using nasm (assembly) under ubuntu?
By switching to raw mode, you can get each character pressed until the return key and do what you will with it.
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