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

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

Related

To display characters in reverse order using nasm [infinite loop running]

THE PROGRAM IS USED TO ACCEPT CHARACTERS AND DISPLAY THEM IN REVERSE ORDER
The code is included here:
section .bss
num resb 1
section .text
global _start
_start:
call inputkey
call outputkey
;Output the number entered
mov eax, 1
mov ebx, 0
int 80h
inputkey:
;Read and store the user input
mov eax, 3
mov ebx, 2
mov ecx, num
mov edx, 1
int 80h
cmp ecx, 1Ch
je .sub2
push ecx
jmp inputkey
.sub2:
push ecx
ret
outputkey:
pop ecx
;Output the message
mov eax, 4
mov ebx, 1
;mov ecx, num
mov edx, 1
int 80h
cmp ecx, 1Ch
je .sub1
jmp outputkey
.sub1:
ret
The code to compile and run the program
logic.asm
is given here:
nasm -f elf logic.asm
ld -m elf_i386 -s -o logic logic.o
./logic
There are a few problems with the code. Firstly, for the sys_read syscall (eax = 3) you supplied 2 as the file descriptor, however 2 refers to stderr, but in this case you'd want stdin, which is 0 (I like to remember it as the non-zero numbers 1 and 2 being the output).
Next, an important thing to realize about the ret instruction is that it pops the value off the top of the stack and returns to it (treating it as an address). Meaning that even if you got to the .sub2 label, you'd likely get a segfault. With this in mind, the stack also tends to not be permanent storage, as in it is not preserved throughout procedures, so I'd recommend just making your buffer larger to e.g. 256 bytes and increment a value to point to an index in the buffer. (Using a fixed-size buffer will keep you from getting into the complications of memory allocation early, though if you want to go down that route you could do an external malloc call or just an mmap syscall.)
To demonstrate what I mean by an index into the reserved buffer:
section .bss
buf resb 256
; ...
inputkey:
xor esi, esi ; clear esi register, we'll use it as the index
mov eax, 3
mov ebx, 0 ; stdin file descriptor
mov edx, 1 ; read one byte
.l1: ; loop can start here instead of earlier, since the values eax, ebx and edx remain unchanged
lea ecx, [buf+esi] ; load the address of buf + esi
int 80h
cmp [buf+esi], 0x0a ; check for a \n character, meaning the user hit enter
je .e1
inc esi
jmp .l1
.e1:
ret
In this case, we also get to preserve esi up until the output, meaning that to reverse the input, we just print in descending order.
outputkey:
mov eax, 4
mov ebx, 1 ; stdout
mov edx, 1
.l2:
lea ecx, [buf+esi]
int 80h
test esi, esi ; if esi is zero it will set the ZF flag
jz .e2:
jmp .l2
.e2:
ret
Note: I haven't tested this code, so if there are any issues with it let me know.

Linux Assembly segmentation fault print using loop

I'm writing an assembly program that would print even numbers between 0-9 using a loop. I encountered this problem, segmentation fault while running the code. I check other answers on the site but couldn't find an answer that satisfies my issue.
I suspect that the function nwLine might be the source of the problem.
;;this program prints even numbers from 0-8 using loop function
section .text
global _start
cr db 10
_start: ;tell linker entry point
mov ecx, 5
mov eax, '0'
evenLoop:
mov [evnum], eax ;add eax to evnum
mov eax, 4
mov ebx, 1
push ecx
mov ecx, evnum
mov edx, 1
int 80h
call nwLine
mov eax, [evnum]
sub eax, '1'
inc eax
add eax, '2'
pop ecx
loop evenLoop
nwLine: ;function to move pointer to next line
mov eax,4 ; System call number(sys_write)
mov ebx,1 ; File descriptor 1 - standard output
mov ecx, cr
mov edx, 1
int 80h ; Call the kernel
ret
mov eax,1 ;system call number (sys_exit)
int 80h ;call kernel
section .bss
evnum resb 1
if anyone knows how to solve the problem with the nwLine function, please tell me.

Create/Write to file x86 Linux

I have been trying to teach myself some 32-bit x86 (NASM). I am trying to have a user input a file name, open/create the file, then take a user's message and write that message to the file. I have gone through it in GDB and all syscalls returned correctly. After the program runs the file appears to be created improperly and nothing is written to it. I ahev seen some of the other question that are similar but my code seems to be nearly the same as their's so I can't seem to figure out what the heck is going on.
Here is my noob code:
global _start
section .data
fmsg: db "Enter Filename: ", 0
.len: equ $ - fmsg
umsg: db "Enter message: ", 0
.len: equ $ - umsg
buff: times 50 db 0 ;array for user string
.blen: equ $ - buff
fname: times 50 db 0 ;array for filename
.flen: equ $ - fname
;modes
O_RDONLY: db 0 ;read-only
O_WRONLY: db 1 ;wirte-only
O_RDWR: db 2 ;read and write
;flags
O_CREAT: dw 100o ;create file if file doesnt exists
O_TRUNC: dw 1000o ;truncate file
O_APPEND: dw 2000o ;append to file
section .bss
fd: resd 1 ;file descriptor
bret: resd 1 ;read buffer return value
fret: resd 1 ;read filename return value
tmp: resd 1 ;temp 4 byte variable
section .text
_start:
fprompt: ;Print prompt
mov eax, 0x4 ;syscall 4 - write()
mov ebx, 0x1 ;file desc 1 - stdout
mov ecx, fmsg ;print message
mov edx, fmsg.len ;length of message
int 80h ;syscall interupt
filein:
mov eax, 0x3 ;syscall 3 - read()
mov ebx, 0x0 ;file desc 0 - stdin
mov ecx, fname ;dst buffer
mov edx, fname.flen ;length of buffer
int 80h ;syscall interupt
mov [fret], eax ;save return value to file return variable
cmp eax, edx ;read max bytes or more?
jb fileopen ;jmp is bytes read < max
mov bl, [ecx+eax-1] ;grab last byte # last index before '\0'
cmp bl, 10 ;does it = '\n' ?
je clean1
inc DWORD [fret] ;len++
clean1: ;loop to clear excess input, if any
mov eax, 0x3 ;syscall 3 - read()
mov ebx, 0x0 ;file desc 0 - stdin
mov ecx, tmp ;temp buffer
mov edx, 0x1 ;read only 1 byte
int 80h ;;syscall interupt
test eax, eax ;EOF?
jz fileopen ;Yes, jump to pback
mov al, [tmp] ;put character into lower 8 bits of EAX
cmp al, 10 ;is it = to lf ?
jne clean1 ;no, jump to begining of loop
fileopen:
mov eax, 0x05
mov ebx, fname ;filename
or ecx, O_CREAT ;if it doesn't exist create the file
or ecx, O_TRUNC ;truncate
mov edx, O_WRONLY ;write only
int 80h ;syscall interupt
mov [fd], eax ;save file descripor
prompt2:
mov eax, 0x4 ;syscall 4 - write()
mov ebx, 0x1 ;file desc 1 - stdout
mov ecx, umsg ;print message
mov edx, umsg.len ;length of message
int 80h
userin:
mov eax, 0x3 ;syscall 3 - read()
mov ebx, 0x0 ;file desc 0 - stdin
mov ecx, buff ;dst buffer
mov edx, buff.blen ;length of buffer
int 80h ;syscall interupt
mov [bret], eax ;save return value to buff return variable
cmp eax, edx ;read max bytes or more?
jb writetofile ;jmp is bytes read < max
mov bl, [ecx+eax-1] ;grab last byte # last index before '\0'
cmp bl, 10 ;does it = '\n' ?
je clean2
inc DWORD [bret] ;len++
clean2: ;loop to clear excess input, if any
mov eax, 0x3 ;syscall 3 - read()
mov ebx, 0x0 ;file desc 0 - stdin
mov ecx, tmp ;temp buffer
mov edx, 0x1 ;read only 1 byte
int 80h ;syscall
test eax, eax ;EOF?
jz writetofile ;Yes, jump to pback
mov al, [tmp] ;put character into lower 8 bits of EAX
cmp al, 10 ;is it = to lf ?
jne clean2 ;no, jump to begining of loop
writetofile:
mov eax, 0x4 ;syscall 4 - write()
mov ebx, [fd] ;file desc 1 - stdout
mov ecx, buff ;print message
mov edx, [bret] ;length of message
int 80h ;syscall interupt
closefile:
mov eax, 0x6 ;syscall 6 - close()
mov ebx, [fd] ;file desc
int 80h ;syscall interupt
exit: ;return 0
mov eax, 1 ;syscall 1 - exit()
mov ebx, 0 ;return val
int 80h ;syscall interupt
Here is an example of what I get after running it:
The file "test.txt?" shows up and also shows up as an executable even though I set only read/write for the file. Even when I try to open it there is nothing there. Any thoughts? Also As I mentioned, i am new and teaching myself so if you have any good tips on improvement for other areas of the program please let me know! :)
We have multiple errors (or one big one) in the following three lines of code:
or ecx, O_CREAT ;if it doesn't exist create the file
or ecx, O_TRUNC ;truncate
mov edx, O_WRONLY ;write only
The problem:
What values do the registers ecx and edx have after these lines?
You perform two or operations with the ecx register but obviously it is not initialized at that moment!
This means that you can be sure that the bits representing O_CREAT and O_TRUNC (whatever these values mean - see below) are set but you don't know which values the other bits have.
The O_WRONLY bit should be set in ecx, not in edx. edx should contain the desired file mode instead.
Unfortunately there are two different types of assembler - I don't know which type NASM is of:
One type of assembler would interpret the first instruction as: or ecx, [O_CREAT]
The other type would interpret it as: or ecx, address_of(O_CREAT)
In the first case the instruction mov edx, O_WRONLY will read four bytes starting with the O_WRONLY byte into the edx register so edx will have the value 0x400201 (O_CREAT*0x10000+O_RDWR*0x100+O_WRONLY).
In the second case edx will contain the address of O_WRONLY rather than the value.
The value will be wrong in any case.
Storing your mode constants in memory is really inefficient, even if you were doing it right (which you aren't).
You could trace what system calls you're actually making by running strace ./writefile.
You use O_RDONLY: db 0 to store a byte of static data (in the read/write section instead of .rodata for some reason). Instead, you should define assembler constants with equ:
O_RDONLY equ 0
O_WRONLY equ 1
O_RDWR equ 2
O_CREAT equ 100o ;create file if file doesnt exists
O_TRUNC equ 1000o ;truncate file
O_APPEND equ 2000o ;append to file
Then you can write
mov ecx, O_CREAT | O_TRUNC | O_WRONLY
mov edx, 0777o ; mode is the permission bits if open() creates the file
See the open(2) man page to learn how its args work.
The assembler will do the OR for you at assemble time, instead of having the CPU do 2 loads from memory.
What you actually wrote:
or ecx, O_CREAT ;if it doesn't exist create the file
or ecx, O_TRUNC ;truncate
assembles to two or ecx, imm32 instructions, which OR the addresses of the two dw locations into the original value of ecx. If you had written
movzx ecx, word [O_CREAT]
or cx, [O_TRUNC]
or cx, [O_WRONLY]
your code would have worked, but that would be really silly. (And on some CPUs cause a partial-register stall when something reads the full ecx after you wrote only the low 16 bits.)
If you'd written or ecx, [O_TRUNC], it would do a 32-bit load, so you'd effectively be doing ecx |= (2000o << 16) | 1000o. i.e. the word stored at O_APPEND would be ORed into the high 16 bits of ECX, where it may have a different meaning.
Similarly, mov edx, O_WRONLY assembles to mov edx, imm32, where the address is the immediate. This is why you ended up with weird garbage for the file mode (including the sticky bit set).
Use a debugger.

Display contents of register

hi i need help displaying contents of a register.my code is below.i have been able to display values of the data register but i want to display flag states. eg 1 or 0. and it would be helpful if to display also the contents of other registers like esi,ebp.
my code is not printing the states of the flags ..what am i missing
section .text
global _start ;must be declared for using gcc
_start : ;tell linker entry point
mov eax,msg ; moves message "rubi" to eax register
mov [reg],eax ; moves message from eax to reg variable
mov edx, 8 ;message length
mov ecx, [reg];message to write
mov ebx, 1 ;file descriptor (stdout)
mov eax, 4 ;system call number (sys_write)
int 0x80 ;call kernel
mov eax, 100
mov ebx, 100
cmp ebx,eax
pushf
pop dword eax
mov [save_flags],eax
mov edx, 8 ;message length
mov ecx,[save_flags] ;message to write
mov ebx, 1 ;file descriptor (stdout)
mov eax, 4 ;system call number (sys_write)
int 0x80
mov eax, 1 ;system call number (sys_exit)
int 0x80 ;call kernel
section .data
msg db "rubi",10
section .bss
reg resb 100
save_flags resw 100
I'm not going for anything fancy here since this appears to be a homework assignment (two people have asked the same question today). This code should be made as a function, and it can have its performance enhanced. Since I don't get an honorary degree or an A in the class it doesn't make sense to me to offer the best solution, but one you can work from:
BITS_TO_DISPLAY equ 32 ; Number of least significant bits to display (1-32)
section .text
global _start ; must be declared for using gcc
_start : ; tell linker entry point
mov edx, msg_len ; message length
mov ecx, msg ; message to write
mov ebx, 1 ; file descriptor (stdout)
mov eax, 4 ; system call number (sys_write)
int 0x80 ; call kernel
mov eax, 100
mov ebx, 100
cmp ebx,eax
pushf
pop dword eax
; Convert binary to string by shifting the right most bit off EAX into
; the carry flag (CF) and convert the bit into a '0' or '1' and place
; in the save_flags buffer in reverse order. Nul terminate the string
; in the event you ever wish to use printf to print it
mov ecx, BITS_TO_DISPLAY ; Number of bits of EAX register to display
mov byte [save_flags+ecx], 0 ; Nul terminate binary string in case we use printf
bin2ascii:
xor bl, bl ; BL = 0
shr eax, 1 ; Shift right most bit into carry flag
adc bl, '0' ; bl = bl + '0' + Carry Flag
mov [save_flags-1+ecx], bl ; Place '0'/'1' into string buffer in reverse order
dec ecx
jnz bin2ascii ; Loop until all bits processed
mov edx, BITS_TO_DISPLAY ; message length
mov ecx, save_flags ; address of binary string to write
mov ebx, 1 ; file descriptor (stdout)
mov eax, 4 ; system call number (sys_write)
int 0x80
mov eax, 1 ;system call number (sys_exit)
int 0x80 ;call kernel
section .data
msg db "rubi",10
msg_len equ $ - msg
section .bss
save_flags resb BITS_TO_DISPLAY+1 ; Add one byte for nul terminator in case we use printf
The idea behind this code is that we continually shift the bits (using the SHR instruction) in the EAX register to the right one bit at a time. The bit that gets shifted out of the register gets placed in the carry flag (CF). We can use ADC to add the value of the carry flag (0/1) to ASCII '0' to get an ASCII value of '0` and '1'. We place these bytes into destination buffer in reverse order since we are moving from right to left through the bits.
BITS_TO_DISPLAY can be set between 1 and 32 (since this is 32-bit code). If you are interested in the bottom 8 bits of a register set it to 8. If you want to display all the bits of a 32-bit register, specify 32.
Note that you can pop directly into memory.
And if you want to binary dump register and flag data with write(2), your system call needs to pass a pointer to the buffer, not the data itself. Use a mov-immediate to get the address into the register, rather than doing a load. Or lea to use a RIP-relative addressing mode. Or pass a pointer to where it's sitting on the stack, instead of copying it to a global!
mov edx, 8 ;message length
mov ecx,[save_flags] ;message to write ;;;;;;; <<<--- problem
mov ebx, 1 ;file descriptor (stdout)
mov eax, 4 ;system call number (sys_write)
int 0x80
Passing a bad address to write(2) won't cause your program to receive a SIGSEGV, like it would if you used that address in user-space. Instead, write will return EFAULT. And you're not checking the return status from your system calls, so your code doesn't notice.
mov eax,msg ; moves message "rubi" to eax register
mov [reg],eax ; moves message from eax to reg variable
mov ecx, [reg];
This is silly. You should just mov ecx, msg to get the address of msg into ecx, rather than bouncing it through memory.
Are you building for 64bit? I see you're using 8 bytes for a message length. If so, you should be using the 64bit function call ABI (with syscall, not int 0x80). The system-call numbers are different. See the table in one of the links at x86. The 32bit ABI can only accept 32bit pointers. You will have a problem if you try to pass a pointer that has any of the high32 bits set.
You're probably also going to want to format the number into a string, unless you want to pipe your program's output into hexdump.

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.

Resources