Can't open file in Linux via 0x80 - linux

I'm trying to implement in GAS a simple test program which opens a file, writes to it some text and exits. However, the system call for 'open' keeps returning '-14' ("EFAULT - bad address" if I understand correctly). The program code is the following:
.intel_syntax noprefix
.section .data
textoutput:
.asciz "Hello world!"
pstr_end:
.set lentext, pstr_end - textoutput
filetoopen:
.asciz "/tmp/tsttxt"
.section .text
.globl main
.func main
main:
mov eax, 5 # open
mov ebx, filetoopen # filname
mov ecx, 2 # flags: read and write
mov edx, 0700 # mode
int 0x80
mov ebx, eax # <<< !!! eax here contains -14
mov eax, 4
mov ecx, textoutput
mov edx, lentext
int 0x80
mov eax, 1
mov ebx, 0
int 0x80
The problem seems to be with the filetoopen string (the manpage to open says that EFAULT means pathname points outside your accessible address space.) Is the filetoopen declared properly in the program's code? What can be the cause of this error?
Thanks.

In intel syntax you need to use mov ebx, offset filetoopen.
If you look at the actual instruction as assembled you can see it's a memory load:
80483e1: 8b 1d 2d 96 04 08 mov ebx,DWORD PTR ds:0x804962d
That is of course wrong, you need the address here. This applies to the other two occurrences of this pattern as well.

Related

NASM - How can I solve the input reading problem from the terminal? [duplicate]

This question already has answers here:
Read STDIN using syscall READ in Linux: unconsumed input is sent to bash
(2 answers)
Closed 4 months ago.
section .data
yourinputis db "your input is =",0
len equ $ - yourinputis
section .bss
msginput resb 10
section .text
global _start
_start:
mov eax,3 ;read syscall
mov ebx,2
mov ecx,msginput
mov edx,9 ; I don't know that is correct?
int 80h
mov eax,4 ;write syscall
mov ebx,1
mov ecx,yourinputis
mov edx,len
int 80h
mov eax,4 ;write syscall
mov ebx,1
mov ecx,msginput
mov edx,10
int 80h
exit:
mov eax,1 ;exit syscall
xor ebx,ebx
int 80h
This code working very well. But It is so terrible bug(for me:(). If I enter an input longer than 10 --->
$./mycode
012345678rm mycode
your input is 012345678$rm mycode
$
This is happening. And of course "mycode" is not exist right now.
What should I do?
EDIT:The entered input is correctly printed on the screen. But if you enter a long input, it moves after the 9th character to the shell and runs it.
In the example, the "rm mycode" after "012345678" is running in the shell.
If you enter more than 9 characters, they're left in the terminal driver's input buffer. When the program exits, the shell reads from the terminal and tries to execute the rest of the line as a command.
To prevent this, your program should keep reading in a loop until it gets a newline.
You can read the characters one by one until you reach 0x0a. Something like:
_read:
mov esi, msginput
_loop:
mov eax,3 ;read syscall
mov ebx,0
mov ecx, esi
mov edx,1 ; I don't know that is correct?
int 80h
cmp byte[esi], 0x0a
je end
inc esi
jmp _loop
end:
ret
You would have to increase the size of msginput tho.
IMPORTANT: Do note that this is not the efficient way to do this (see the comments), it is only put here as an example to the answer above.

nasm linux x64 how do i find and cmp EOF to stop printing data from file to screen

nasm linux x64 how do i find and cmp EOF to stop printing data from file to screen
section .data
Nile_2 db '/home/mark/Desktop/mynewfile.txt', 0;
section .bss
fd_out resd 4 ; use this here instead of resb so there is enough room for long file names
fd_in resd 4
info resd 26
section .text
global _start ;must be declared for using gcc
_start:
;open the file for reading
mov rax, 5
mov rbx, Nile_2 ; was file_name
mov rcx, 0 ;for read only access
; mov rdx, 0777 ;read, write and execute by all
int 0x80
mov [fd_in], eax
;mov rdx, 20
READ:
;read from file
mov rax, 3
mov rbx, [fd_in]
mov rcx, info
;mov rdx, 26
int 0x80
; print the info
mov rax, 4
mov rbx, 1
mov rcx, info
;mov rdx, 26
int 0x80
mov r10, info ; dec rdx
cmp r10, 00
jnz READ
;jmp READ ;jnz Read
HERE:
; close the file
mov rax, 6
mov rbx, [fd_in]
int 0x80
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
how do i find out if sys_read or info is zero
how do i find out EOF ??? i dont know how to use sys_read to check if no bytes have been read... when i try to cmp that info is zero bytes read i get the last few bytes over and over ???
You are using int 0x80 in your 64-bit code. Normally, in 64-bit code, you would use the syscall instruction and use other register arguments. For some light reading, see
What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?
how do i find out if sys_read or info is zero how do i find out EOF ???
If a request to read a certain number of bytes from a file, reports a count that is less than the number that you requested, then the end-of-file has been reached. If the reported count is 0, then the end-of-file was already reached before you made the request, else we say that a partial record was read.
i dont know how to use sys_read to check if no bytes have been read...
sys_read provides you with the number of bytes that were actually read in the eax register. I mentioned this already in my answer to your previous question Nasm linux for some reason i cant use two file variable names at the same time for opening a file and creating a file?
when i try to cmp that info is zero bytes read i get the last few bytes over and over ???
You have managed to create an endless loop!
In NASM, an instruction like mov r10, info loads the address of info in the register. So not the contents that are stored at info which is what you were trying to get.
Since the address is not zero, code like:
mov r10, info
cmp r10, 00
jnz READ
will always jump and thus continue the loop ad infinitum.
fd_out resd 4 ; use this here instead of `resb` so there is **enough room for long file names**
fd_in resd 4
info resd 26
What sys_creat and sys_open return to you in the eax register is a file descriptor (it's in the names fd_in and fd_out), and it's a handle by which the system can identify the open file. It is a single dword and it is meaningless to assign 4 dwords for its storage.
Also, I find it strange that, in response to my previous answer, you changed info resb 26 into info resd 26. This does not make much sense.
With using 64-bit registers this time, you did introduce another mismatch on the fd_in variable! If you stored a dword (mov [fd_in], eax) then don't retrieve a qword (mov rbx, [fd_in])
section .bss
fd_out resd 1
fd_in resd 1
info resb 26
...
READ:
;read from file
mov edx, 26
mov ecx, info
mov ebx, [fd_in]
mov eax, 3
int 0x80 ; -> EAX
test eax, eax
js ERROR ; Some error occured
jz HERE ; End-of-file
; print the info
mov edx, eax ; Could be a partial record
mov ecx, info
mov ebx, 1
mov eax, 4
int 0x80
jmp READ
ERROR:
HERE:
i found out that if i check eax and if its zero thats the end of file
cmp rax, 0
je HERE
'''
so that there does the job and not it will end almost properly when it reaches the end of the file it does spit out an extra bit tho dont know why

A loop in assembly doesn't work why?

i have problem. I tried build a loop in assembly (nasm,linux). The loop should "cout" number 0 - 10, but it not work and i don't know why. Here is a code :
section .text
global _start
_start:
xor esi,esi
_ccout:
cmp esi,10
jnl _end
inc esi
mov eax,4
mov ebx,1
mov ecx,esi
mov edx,2
int 80h
jmp _ccout
_end:
mov eax,1
int 80h
section .data
Well, the loop is working, but you aren't using the syscall correctly. There are some magic numbers involved here, so let's get that out of the way first:
4 is the syscall number for write
1 is the file descriptor for the standard output
So far, so good. write requires a file descriptor, the address of a buffer and the length of that buffer or the part of it that it's supposed to write to the file descriptor. So, the way this is supposed to look is similar to
mov eax,4 ; write syscall
mov ebx,1 ; stdout
mov ecx,somewhere_in_memory ; buffer
mov edx,1 ; one byte at a time
compare that to your code:
mov eax,4
mov ebx,1
mov ecx,esi ; <-- particularly here
mov edx,2
int 80h
What you are doing there (apart from passing the wrong length) is passing the contents of esi to write as a memory address from which to read the stuff it's supposed to write to stdout. By pure happenstance this doesn't crash, but there's no useful data at that position in memory.
In order to solve this, you will need a location in memory to put it. Moreover, since write works on characters, not numbers, you'll have to to the formatting yourself by adding '0' (which is 48 in ASCII). All in all, it could look something like this:
section .data
text db 0 ; text is a byte in memory
section .text
global _start
_start:
xor esi,esi
_ccout:
cmp esi,10
jnl _end
inc esi
lea eax,['0'+esi] ; print '0' + esi. lea == load effective address
mov [text],al ; is useful here even though we're not really working on addresses
mov eax,4 ; write
mov ebx,1 ; to fd 1 (stdout)
mov ecx,text ; from address text
mov edx,1 ; 1 byte
int 80h
jmp _ccout
_end:
mov [text],byte 10 ; 10 == newline
mov eax,4 ; write that
mov ebx,1 ; like before.
mov ecx,text
mov edx,1
int 80h
mov eax,1
mov ebx,0
int 80h
The output 123456789: is probably not exactly what you want, but you should be able to take it from here. Exercise for the reader and all that.

unable to read from file when user provides filename (x86 assembly program using nasm)

I'm having a problem trying to open a file and read from it. The user is prompted for the file name.
The program compiles without error but doesn't show anything. When I hardcode the filename in the .data section it runs fine, but when I get the filename from the user it fails to read the file. Where am I doing wrong? I can't find any error.
Output using hardcoded name: welcome
Output when user enters the name: ���
Here is my code:
section .data
promptUsr db 'enter a file name:',0xA,0xD
lenPrompt equ $-promptUsr
info db 1
;file_name db 'data.txt' (NOTE:harcoded name works when used)
section .bss
fd_in resb 1
buffer resb 7
file_name resb 20
section .text
global _start
_start:
;prompt user to enter a file name
mov eax,4 ;sys_write
mov ebx,1 ;stdout
mov ecx,promptUsr
mov edx,lenPrompt
int 0x80
;read filename (NOTE:when user enters the same name 'data.txt',this is the output:���)
mov eax,3
mov ebx,2
mov ecx,file_name ;(NOTE:tried using 'dword[file_name]',doesnt work)
mov edx,20
int 0x80
;open file
mov eax,5
mov ebx,file_name ;(NOTE:also tried using 'dword[file_name]',doesnt work too)
mov ecx,2 ;read n write
mov edx,7777h ;all file permissions
int 0x80
mov [fd_in],eax
;read 7 bytes of the file
mov eax,3
mov ebx,[fd_in]
mov ecx,buffer
mov edx,7
int 0x80
;close the file
mov eax,6
int 0x80
;print out what was read
mov eax,4
mov ebx,1
mov ecx,buffer
mov edx,7
int 0x80
;end program
mov eax,1
int 0x80
To add to what Michael says... 1) fd_in is too small - make it resd 1. 2) sys_read doesn't return a zero-terminated string, and sys_open wants one.
mov byte [ecx + eax - 1], 0
after the sys_read of the filename should zero-terminate it.
Looks like you're trying to read from STDERR:
mov eax,3
mov ebx,2
mov ecx,file_name ;(NOTE:tried using 'dword[file_name]',doesnt work)
mov edx,20
That mov ebx,2 ought to be mov ebx,0 if you want to read from STDIN.
would also love to know how to check first if the file exists before opening it
If you use sys_open without the O_CREAT flag set, it should fail and return -1 if the file doesn't already exist. You could also use access (syscall 33) or stat (syscall 18) if you want to.

Assembly code doesn't print string

So basically I'm trying to write a hello world program in assembly. The program exits as it should but no string is printed along the way. There are no errors anywhere either. I suspect that I am declaring or using the string wrong somehow.
.intel_syntax noprefix
.data
msg:
.ascii "Hello World"
.text
.globl _start
_start:
mov eax, 4 #call write
mov ebx, 1 #output into stdout
mov ecx, msg #what to write
mov edx, 11 #length of what to write
int 0x80
mov eax, 1 #exit
mov ebx, 0
int 0x80
I have also tried replacing
mov ecx, msg
with
mov ecx, [msg]
but it doesn't seem to make a difference.
You need to use mov ecx, offset msg or lea ecx, msg.
Also make sure you are assembling as 32 bit code in case you are on a 64 bit system.

Resources