Register is not setting with buffer value in NASM x64 - linux

hope you can help me with that problem. I've to read data from an other file in nasm and I wanted to check the registers value with gdb but I found out that we can't so I hard coded the file value in a "String". I'm pretty sure I did something awful and that's why it isn't working but since I'm a beginner in nasm I am not able to find my mistake.
With that code, isn't eax supposed to be the value of the buffer ? (value of DebugStr in the example) ? Why do I see 0x31313130 ? I really hope you guys can help me
SECTION .data
DebugStr: db "01111100 10101010 01111000", 10
DebugStrLen: equ 32
SECTION .bss
SECTION .text
global _start
_start:
xor rax, rax ; rax = 0
xor rbx, rbx ; rbx = 0
xor rcx, rcx ; rcx = 0
xor rdx, rdx ; rdx = 0
mov r8, DebugStr ; r8 = address of ReadBuffer
mov r9, Output ; r9 = address of OutputBuffer
;mov rax, 0 ; Specify sys_read call
;mov rdi, 0 ; Specify File Descriptor 0: Standard Input
;mov rsi, r8 ; Pass offset of the buffer to read to
;mov rdx, ReadBufferSize ; Pass number of bytes to read at one pass
;syscall
mov eax, [r8] ; eax = ReadBuffer value to eax = 01111100 10101010 01111000

Related

Nasm: Print on console

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!

How to use value on address acquired from mmap?

having this nasm:
%define O_RDONLY 0
%define PROT_READ 0x1
%define MAP_PRIVATE 0x2
section .data
fname: db 'test.txt', 0
section .text
global _start
print:
; ---- THIS PART ADDED
mov r15, [rdi]
add r15, 1 ; have tried `inc byte[rdi]` - did not work either
mov [rdi], r15
; ---- END OF ADDED PART
; else is according to book (so correct)
push rdi
call str_len
pop rsi
mov rdx, rax
mov rax, 1
mov rdi, 1
syscall
ret
str_len:
xor rax, rax
.loop:
cmp byte [rdi+rax], 0
je .end
inc rax
jmp .loop
.end:
ret
_start:
;call open
mov rax, 2
mov rdi, fname
mov rsi, O_RDONLY
mov rdx, 0
syscall
;mmap
mov r8, rax
mov rax, 9
mov rdi, 0
mov rsi, 4094
mov rdx, PROT_READ
mov r10, MAP_PRIVATE
mov r9, 0
syscall
mov rdi, rax ;returned address
call print
mov rax, 60
xor rdi, rdi
syscall
The file test.txt contains only one char at the beginning - 5.
I got address from region asked by mmap in rax, which I then move to rdi.
And I simply want to increment the value (at that address - now being in rdi):
mov r15, [rdi]
add r15, 1 ; have tried `inc byte[rdi]` - did not work either
mov [rdi], r15
push rdi
So i temporary move the value on r15, the increment it (add it 1), and try to move it back to address of that region (address still in rdi). But then segfault.
Why is that? Why cannot I use the value on the address (to the acquired region from mmap), which contain 5 - one byte (on which the rdi points), and use it in arithmetic?
If that would be address declared in data segment, then there would be no problem (I have tried). But the address is from mmap, So how does it differ, and how to fix that?
Writing to read-only memory segfaults (mov [rdi], r15 qword store, or inc byte [rdi] byte RMW).
You need PROT_READ | PROT_WRITE if you want to be able to write as well as read.
(Note that writing to a MAP_PRIVATE mapping triggers a copy-on-write, leaving you with a private page that's no longer backed by the file, just like if you'd done a read into a MAP_ANONYMOUS page.)

Message 5 Time repeat?

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

Open a .ppm file and write some data to it. AMD64 linux Assembly Nasm

I am writing a program in AMD64 linux Assembly code (assembler Nasm) that does a whole bunch of stuff. Basicly, my question right now is how can I open a file, and write some data to it.
My code I have seems like it should work.
Basically I want to open a .ppm image file and write the header to it. My professor gave me some pseudo code to to help and here is that code for just the part I am trying to accomplish.
fd = open("gradient.ppm", 577, 0o644)
if fd < 0: return 1 (error)
bufsize = writeHeader(buffer, 256, 256)
status = write(fd, buffer, bufsize)
if status < 0: return 2 (error)
Here is my code. My professor has some test program written in c++ that will run my code and test to see if it works correctly, so I am not running directly from this file. (BTW, the writeheader file has been confirmed to work)
global start
extern writeRGB
extern writeHeader
section .data
filename: db "gradient.ppm",0
section .bss
buffer resb 5000
section .text
; rdi,rsi,rdx
start:
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
; open file
; sys_open: rax=2, rdi=char filename, rsi=int flags, rdx=int mode
mov rax, 2 ; 2 is system call number for sys_open
mov rdi, filename ; filname is in data section
mov rsi, 577 ; flag that is just given to me
mov rdx, 0o644 ; Octol number of the mode that is just given to me
syscall ; execute the sys_open system call
mov r9, rax ; r9 will hold file handle (fd)
; check for error
; compare 0 and data returned to rax from opening file.
; if data in rax < 0, store 1 in r11 and jump .error which will return the 1
mov r11, 1
cmp r9, 0
jl .error
; call writeheader
; writeHeader(rdi = buffer, rsi = 256, rdx = 256)
mov rdi, buffer
mov rsi, 256
mov rdx, 256
call writeHeader
mov r8, rax ; store the buffer size (bufsize) in r8
; status = write(fd, buffer, bufsize)
; sys_write: rax=1, rdi=fd, rsi=buffer, rdx=bufsize)
mov rax, 1 ; 1 is the system call number for sys_write
mov rdi, r9 ; the file handle (fd) is stored in r9
mov rsi, buffer ; the buffer is in the .bss section
mov rdx, r8 ; r8 holds the buffer size (bufsize)
syscall ; execute the sys_write system call
mov r10, rax ; status will be stored in r10
; check for error
; compare 0 and data returned to rax from opening file.
mov r11, 2
cmp r9, 0
jl .error
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
mov rax, 0
ret
.error:
; mov error code in r11 into rax to indicate error, and return it
mov rax, r11 ; rll holds error code
ret
If my code should work, then there is probably something wrong in which the way the test file is accessing it, if thats the case just let me know so that I can focus my resources on fixing that problem rather than fixing my code that already works.
cmp r9, 0
jb .error ; <-- This will never happen!
When testing for a negative number don't use jb. That's reserved to work with unsigned numbers. Use jl.
cmp r9, 0
jl .error
;open file give it a name in section .data file: db "......", 0
mov rsi, 577
mov rdx, 0o644
mov rdi, file
mov rax, sys_open
syscall
mov r13, rax ;save file descriptor
cmp rax, 0 ;return error if negative
jl .error
Copy/paste related error in your code!
; status = write(fd, buffer, bufsize)
; sys_write: rax=1, rdi=fd, rsi=buffer, rdx=bufsize)
mov rax, 1 ; 1 is the system call number for sys_write
mov rdi, r9 ; the file handle (fd) is stored in r9
mov rsi, buffer ; the buffer is in the .bss section
mov rdx, r8 ; r8 holds the buffer size (bufsize)
syscall ; execute the sys_write system call
mov r10, rax ; status will be stored in r10
; check for error
; compare 0 and data returned to rax from opening file.
mov r11, 2
cmp r9, 0
jl .error
You have put the status in R10 but are comparing the value in R9.

x86-64 Bit Assembly Linux Input

I'm trying to input into my program... All it does is run through and print a '0' to the screen. I'm pretty sure that the PRINTDECI function works, I made it a while ago and it works. Do I just have to loop over the input code and only exit when I enter a certain value? I'm not sure how I would do that... Unless it's by ACSII values which might suck.... Anyways, here's my code (Yasm(nasm clone), Intel Syntax):
GLOBAL _start
SECTION .text
PRINTDECI:
LEA R9,[NUMBER + 18] ; last character of buffer
MOV R10,R9 ; copy the last character address
MOV RBX,10 ; base10 divisor
DIV_BY_10:
XOR RDX,RDX ; zero rdx for div
DIV RBX ; rax:rdx = rax / rbx
ADD RDX,0x30 ; convert binary digit to ascii
TEST RAX,RAX ; if rax == 0 exit DIV_BY_10
JZ CHECK_BUFFER
MOV byte [R9],DL ; save remainder
SUB R9,1 ; decrement the buffer address
JMP DIV_BY_10
CHECK_BUFFER:
MOV byte [R9],DL
SUB R9,1
CMP R9,R10 ; if the buffer has data print it
JNE PRINT_BUFFER
MOV byte [R9],'0' ; place the default zero into the empty buffer
SUB R9,1
PRINT_BUFFER:
ADD R9,1 ; address of last digit saved to buffer
SUB R10,R9 ; end address minus start address
ADD R10,1 ; R10 = length of number
MOV RAX,1 ; NR_write
MOV RDI,1 ; stdout
MOV RSI,R9 ; number buffer address
MOV RDX,R10 ; string length
SYSCALL
RET
_start:
MOV RCX, SCORE ;Input into Score
MOV RDX, SCORELEN
MOV RAX, 3
MOV RBX, 0
SYSCALL
MOV RAX, [SCORE]
PUSH RAX ;Print Score
CALL PRINTDECI
POP RAX
MOV RAX,60 ;Kill the Code
MOV RDI,0
SYSCALL
SECTION .bss
SCORE: RESQ 1
SCORELEN EQU $-SCORE
Thanks for any help!
- Kyle
As a side note, the pointer in RCX goes to a insanely large number according to DDD... So I'm thinking I have to get it to pause and wait for me to type, but I have no idea how to do that...
The 'setup' to call syscall 0 (READ) on x86_64 system is:
#xenon:~$ syscalls_lookup read
read:
rax = 0 (0x0)
rdi = unsigned int fd
rsi = char *buf
rdx = size_t count
So your _start code should be something like:
_start:
mov rax, 0 ; READ
mov rdi, 0 ; stdin
mov rsi, SCORE ; buffer
mov rdx, SCORELEN ; length
syscall
The register conventions and syscall numbers for x86_64 are COMPLETELY different than those for i386.
Some conceptual issues you seem to have:
READ does not do ANY interpretation on what you type, you seem to be expecting it to let you type a number (say, 57) and have it return the value 57. Nope. It'll return '5', '7', 'ENTER', 'GARBAGE'... Your SCORELEN is probably 8 (length of resq 1), so you'll read, AT MOST, 8 bytes. or Characters, if you wish to call them that. And unless you type the EOF char (^D), you'll need to type those 8 characters before the READ call will return to your code.
You have to convert the characters you receive into a value... You can do it the easy way and link with ATOI() in the C library, or write your own parser to convert the characters into a value by addition and multiplication (it's not hard, see code below).
Used below, here as a reference:
#xenon:~$ syscalls_lookup write
write:
rax = 1 (0x1)
rdi = unsigned int fd
rsi = const char *buf
rdx = size_t count
Ugh.... So many... I'll just rewrite bits:
global _start
section .text
PRINTDECI:
; input is in RAX
lea r9, [NUMBER + NUMBERLEN - 1 ] ; + space for \n
mov r10, r9 ; save end position for later
mov [r9], '\n' ; store \n at end
dec r9
mov rbx, 10 ; base10 divisor
DIV_BY_10:
xor rdx, rdx ; zero rdx for div
div rbx : rax = rdx:rax / rbx, rdx = remainder
or dl, 0x30 ; make REMAINDER a digit
mov [r9], dl
dec r9
or rax, rax
jnz DIV_BY_10
PRINT_BUFFER:
sub r10, r9 ; get length (r10 - r9)
inc r9 ; make r9 point to initial character
mov rax, 1 ; WRITE (1)
mov rdi, 1 ; stdout
mov rsi, r9 ; first character in buffer
mov rdx, r10 ; length
syscall
ret
MAKEVALUE:
; RAX points to buffer
mov r9, rax ; save pointer
xor rcx, rcx ; zero value storage
MAKELOOP:
mov al, [r9] ; get a character
or al, al ; set flags
jz MAKEDONE ; zero byte? we're done!
and rax, 0x0f ; strip off high nybble and zero rest of RAX (we're lazy!)
add rcx, rcx ; value = value * 2
mov rdx, rcx ; save it
add rcx, rcx ; value = value * 4
add rcx, rcx ; value = value * 8
add rcx, rdx ; value = value * 8 + value * 2 (== value * 10)
add rcx, rax ; add new digit
jmp MAKELOOP ; do it again
MAKEDONE:
mov rax, rcx ; put value in RAX to return
ret
_start:
mov rax, 0 ; READ (0)
mov rdi, 0 ; stdin
mov rsi, SCORE ; buffer
mov rdx, SCORELEN ; length
syscall
; RAX contains HOW MANY CHARS we read!
; -OR-, -1 to indicate error, really
; should check for that, but that's for
; you to do later... right? (if RAX==-1,
; you'll get a segfault, just so you know!)
add rax, SCORE ; get position of last byte
movb [rax], 0 ; force a terminator at end
mov rax, SCORE ; point to beginning of buffer
call MAKEVALUE ; convert from ASCII to a value
; RAX now should have the VALUE of the string of characters
; we input above. (well, hopefully, right?)
mov [VALUE], rax ; store it, because we can!
; it's stored... pretend it's later... we need value of VALUE!
mov rax, [VALUE] ; get the VALUE
call PRINTDECI ; convert and display value
; all done!
mov rax, 60 ; EXIT (60/0x3C)
mov rdi, 0 ; exit code = 0
syscall
section .bss
SCORE: resb 11 ; 10 chars + zero terminator
SCORELEN equ $-SCORE
NUMBER: resb 19 ; 18 chars + CR terminator
NUMBERLEN equ $-NUMBER
I'm going to say that this should work first time, it's off-the-cuff for me, haven't tested it, but it should be good. We read up to 10 chars, terminate it with a zero, convert to a value, then convert to ascii and write it out.
To be more proper, you should save registers to the stack in each subroutine, well, certain ones, and really, only if you're going to interface with libraries... doing things yourself lets you have all the freedom you want to play with the registers, you just have to remember what you put where!
Yes, someone is going to say "why didn't you just multiply by 10 instead of weird adding?" ... uh... because it's easier on the registers and I don't have to set it all up in rdx:rax. Besides, it's just as readable and understandable, especially with the comments. Roll with it! This isn't a competition, it's learning!
Machine code is fun! Gotta juggle all the eggs in your head though... no help from the compiler here!
Technically, you should check return result (RAX) of the syscalls for READ and WRITE, handle errors appropriately, yadda yadda yadda.... learn to use your debugger (gdb or whatever).
Hope this helps.

Resources