input.asm
sys_exit equ 1
sys_read equ 3
sys_write equ 4
stdin equ 0
stdout equ 1
stderr equ 3
SECTION .data
szName db "What is your name? "
Name_Len equ $-szName
szHello db "Hello ", 0
Hello_Len equ $-szHello
SECTION .bss
lpBuffer resb 7
Buf_Len equ $-lpBuffer
SECTION .text
global _start
_start:
mov ecx, szName
mov edx, Name_Len
call DisplayText
mov ecx, lpBuffer
mov edx, Buf_Len
call ReadText
push eax
mov ecx, szHello
mov edx, Hello_Len
call DisplayText
pop edx
mov ecx, lpBuffer
call DisplayText
jmp Exit
DisplayText:
mov eax, sys_write
mov ebx, stdout
int 80H
ret
ReadText:
mov ebx, stdin
mov eax, sys_read
int 80H
ret
Exit:
mov eax, sys_exit
xor ebx, ebx
int 80H
To read from Terminal:
Quote
ssize_t sys_read(unsigned int fd, char * buf, size_t count)
ebx = file descriptor
ecx = pointer to buffer
edx = buffer size
eax = system call - sys_read
On return, eax contains bytes read
ebx = file descriptor
ecx = pointer to buffer
edx = buffer size
eax = system call - sys_read
On return, eax contains bytes read
Ok, so we need 3 things to use sys_read:
1. A file descriptor
2. A pointer to a buffer to store typed characters
3. Size of the buffer including the EOL character - 0xA
1. A file descriptor? Yes a "file". Almost everything in *NIX is a file. To quote Wiki:
Quote
Generally, a file descriptor is an index for an entry in a kernel-resident data structure containing the details of all open files
So, when we set eax to 3, the OS look in the file descriptor table and knows we want to read from the Terminal.
2. A buffer to store typed characters. Our buffer in this sample is 7 bytes long (Gunner is 6 + 0xa)
3. Size of buffer. This should be how big our buffer is. Linux will only put this many characters in our buffer.
To write to Terminal:
Quote
ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
ebx = file descriptor
ecx = pointer to buffer
edx = count of characters to write
eax = system call - sys_write
On return, eax contains bytes written
ebx = file descriptor
ecx = pointer to buffer
edx = count of characters to write
eax = system call - sys_write
On return, eax contains bytes written
Again, we need 3 things to write to the Terminal, same as reading but count is the amount of characters to write to the Terminal.
Ok, lets run it to see what happens:

What the hell?!?! Why is "who else" not in the correct place? This is a common problem and question! Technically there is nothing wrong with this. We told the OS to read 7 bytes from the terminal and put those bytes into our buffer, and that is what it did. Problem is, we typed more than 7 characters into the terminal and hit enter, so there are still bytes left in stdin ("who else") which bash reads.
Ok, so how do we fix this? For one, we could use a buffer larger than 7 bytes which you would do in a normal program; 7 is just to show this problem, or we could check to see if there are anymore characters in stdin and if there are, read them from stdin and do nothing with them.

Ah, that is much better! So how did I fix it? Added a new function called ClearTerminal:
ClearTerminal:
mov edx, 1
mov ecx, Buf
mov ebx, stdin
mov eax, sys_read
int 80h
cmp byte [ecx + edx - 1], 10
jne ClearTerminal
ret
Here I use a 1 byte buffer and tell the OS to read 1 character, after the sys_read call, I check to see if the character is the EOL character (0xa), if it isn't loop back and get and test the next character until we are at the EOL and return.
Here is the fixed code:
sys_exit equ 1
sys_read equ 3
sys_write equ 4
stdin equ 0
stdout equ 1
stderr equ 3
SECTION .data
szName db "What is your name? "
Name_Len equ $-szName
szHello db "Hello ", 0
Hello_Len equ $-szHello
SECTION .bss
lpBuffer resb 7
Buf_Len equ $-lpBuffer
Buf resb 1
SECTION .text
global _start
_start:
mov ecx, szName
mov edx, Name_Len
call DisplayText
mov ecx, lpBuffer
mov edx, Buf_Len
call ReadText
push eax
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
cmp eax, Buf_Len
jl Good
cmp byte [ecx + edx - 1], 10
je Good
mov byte [ecx + edx - 1], 10
call ClearTerminal
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Good:
mov ecx, szHello
mov edx, Hello_Len
call DisplayText
pop edx
mov ecx, lpBuffer
call DisplayText
jmp Exit
ClearTerminal:
mov edx, 1
mov ecx, Buf
mov ebx, stdin
mov eax, sys_read
int 80h
cmp byte [ecx + edx - 1], 10
jne ClearTerminal
ret
DisplayText:
mov eax, sys_write
mov ebx, stdout
int 80H
ret
ReadText:
mov ebx, stdin
mov eax, sys_read
int 80H
ret
Exit:
mov eax, sys_exit
xor ebx, ebx
int 80H
This is what we added:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
cmp eax, Buf_Len
jl Good
cmp byte [ecx + edx - 1], 10
je Good
mov byte [ecx + edx - 1], 10
call ClearTerminal
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DisplayText returns the number of characters read from stdin in eax, we compare this value to the size of our buffer and if eax is less than our buffer size, we continue on to the Good label since our buffer will contain the EOL character.
If eax is NOT less than our buffer size, meaning sys_write filled up our buffer completely, we check to see if the last character is the EOL, and if it is we continue on to Good
Hmm, the last character was not the EOL which means there is more data in stdin, so we put an EOL character in the last place of our buffer and clear the terminal buffer before continuing.
Attached File(s)
-
input.tar.gz (1.47K)
Number of downloads: 100







MultiQuote






|