A loop in assembly doesn't work why? - linux

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.

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.

assembly doesn't print empty line

I just started to learn x86 assembly and I tried to write a simple program that prints all the ascii characters and a line break to the standard output.
It prints everything as expected except the line break and I can't figure out why.
I compiled it with nasm on a 64 bit ubuntu operating system.
Here is the code:
section .data
curr db ' '
section .text
global _start
_start:
next:
;print current character
mov eax,4
mov ebx,1
mov ecx,curr
mov edx,1
int 0x80
;check condition and increment curr
inc byte [curr]
cmp byte [curr],126
jle next
;new line and exit <--- doesn't work ???
mov eax,4
mov ebx,1
mov ecx,10
mov edx,1
int 0x80
mov eax,1
mov ebx,1
int 0x80
The problem is that in that system call, ECX is a pointer, not the character you want to print. Perhaps modifying it like so?
MOV byte [curr], 10
MOV ECX, curr
MOV EAX, 4
MOV EDX, 1
INT 0x80

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.

How to read and write a byte from and to stdin/stdout using Syscall in x86 with NASM assembler?

I am trying to read a string from stdin and print it back out using x86, NASM, and Syscalls. Reading in a byte will be a function, and writing out a byte will be a function. I am reading the string from stdin and putting each char into an array. Here is my initial idea:
;read_writer.asm
section .data
arr times 100 db 0 ; array of 100 elements initialzed to 0
ptr dd 0
section .text
global _start
_start:
push ebp ; setup stack
mov ebp, esp ; setup stack
push, 0x10 ; allocate space for potential local variables
call readin: ;call read in func
push eax ;return char from readin will be in eax, push it for writeout
call writeout:
leave
mov eax, 1 ;exit
mov ebx, 0
int 0x80
readin:
push ebp
mov ebp, esp ; setup stack
mov eax, 3 ;read
mov ebx, 1 ;stdin
; i feel like i am missing code here bit not sure what
leave ;reset stack
ret ;return eax
writeout:
push ebp
mov ebp, esp ; setup stack
push eax ;push eax since it was pushed earlier
mov eax, 4 ;write
mov ebx, 1 ;stdout
; i feel like i am missing code here bit not sure what
leave ;reset stack
ret ;return eax
Sample input:
Hello World
Sample output:
Hello World
The functions should be used with cdecl, which I dont think I am doing correctly. I also realised I am not putting the chars into arr.
For starters, you're missing the int 0x80 in both readin and writeout.
And, as you can see here, both sys_read and sys_write expect a (const) char* in ecx. That address should point to the buffer where the bytes to write are stored / the read bytes should be stored.The value of edx should be set to the number of bytes to read / write.
So in the readin example you want something like:
mov eax, 3 ;read
mov ebx, 0 ;stdin. NOTE: stdin is 0, not 1
sub esp,4 ; Allocate some space on the stack
mov ecx,esp ; Read characters to the stack
mov edx,1
int 0x80
movzx eax,byte [esp] ; Place the character in eax, which is used for function return values
add esp,4
And similarly for writeout.

How to save a file in assembly language with nasm in Linux x86?

I'm just wondering how I can throw a buffer to a file. I know I can set up the registers like:
mov eax, 4
mov ebx, (file descriptor here)
mov ecx, myBuffer
mov edx, myBufferLen
int 80h
and then close the file with:
mov eax, 6
int 80h
but I'm not sure how to get the file descriptor. Someone told me that whenever you open a file, after calling the service dispatcher, the eax has the file descriptor. Whatever I try, it doesn't create a new file or save the current one.
mov eax, 5 ; __NR_open
mov ebx, filename ; zero terminated!
mov ecx, 2 ; O_WRITE? Check me on this!
mov edx, 777q ; permissions - Check me on this, too!
int 80h
; did we succeed?
cmp eax, -4096
ja exit
mov [descriptor], eax
; and so on...
;...
xor eax, eax ; claim no error
exit:
mov ebx, eax
neg ebx
mov eax, 1 ; __NR_exit
int 80h
I'm uncertain on the "magic numbers" for open flags and permissions, and too lazy to look them up right now (fs.h?). You may need to "or" the open flags with O_CREATE to create a new file(?). The trick at "exit:" negates the (negative) ERRNO (if any) so you can read it easily with "echo $?". Something like that...
Thanks to #gnometorule for the solution. So this is how you store a buffer into file:
in this case you are receiving the file name as a first parameter when you run the program.
section .text
global _start
_start:
pop ebx ; this is the amount of parameter received (in this case 2)
pop ebx ; this is the direction of our program
pop ebx ; this is the first parameter (our file name eg. "text.txt")
so we open it and move it to a buffer to edit or whatever we want with it.
textEdit:
;we open the file
mov eax, 5
push ebx ; we save the file name in the stack for later use
mov ecx,0
int 80h
; and then we move the information read to buffer
mov eax, 3
mov ebx, eax ; really dont know how this works, but it does.
mov ecx, fileBuffer
mov edx, fileBufferSize
int 80h
now fileBuffer (wich is a buffer defined in section .bss) has what we had in the file we opened. Here you can edit the information. When we want to save it back to the file it goes like this:
saveFile:
;open the file
mov eax, 5
pop ebx ; the file name was stored in the stack,
push ebx ; so we retrieve it and save it back for later use
mov ecx, 2 ; ecx has the access mode ("2"aloud us to read/write)
mov edx, $0666
int 80h
;now we are going to write to the file
mov ebx, eax ; eax has the file descriptor we opened. so we move it to ebx.
mov eax, 4 ; we are going to use the write service (#4)
mov ecx, fileBuffer ; ecx has the adress of what we want to write
mov edx, fileBufferSize ; edx has the amount of bytes we want to write
int 80h
; close the file
mov eax, 6
int 80h
jmp exit ; jump wherever you want, or end your program... etc.
This worked for me.

Resources