We will be using the following System Calls:
sys_read
Quote
ssize_t read(int fd, void *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
sys_write
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
sys_open
Quote
int sys_open(const char *pathname, int flags, mode_t mode)
ebx = pointer to NULL terminated filename
ecx = flags
edx = mode
eax = system call - sys_open
On return, eax contains the file descriptor
ebx = pointer to NULL terminated filename
ecx = flags
edx = mode
eax = system call - sys_open
On return, eax contains the file descriptor
sys_close
Quote
int sys_close(int fd)
ebx = file descriptor
eax == system call - sys_close
On return, eax contains 0 on success
ebx = file descriptor
eax == system call - sys_close
On return, eax contains 0 on success
sys_newstat
Quote
int sys_newstat(const char *path, struct stat *buf)
ebx = pointer to NULL terminated filename
ecx = pointer to stat structure
eax = system call - sys_stat
On return, eax contains 0 on success
ebx = pointer to NULL terminated filename
ecx = pointer to stat structure
eax = system call - sys_stat
On return, eax contains 0 on success
sys_brk
Quote
int sys_brk(void *addr)
ebx = 0 to get address of Program Break (end of .bss section)
ebx = new address of Program Break to allocate memory
eax = system call - sys_brk
On return, eax contains address of Program Break
ebx = 0 to get address of Program Break (end of .bss section)
ebx = new address of Program Break to allocate memory
eax = system call - sys_brk
On return, eax contains address of Program Break
You will have to look at the man pages for the system call to see what gets returned on error. I do no error checking here, you will have to add your own.
We will use those system calls to:
- Get the size of a file (a test file containing 8053 bytes of Lorem Ipsum)
- Get the end of the program break and extend it by 8053 bytes.
- Open test file
- Read contents to temp buffer created with sys_brk
- Write contents to terminal
- Close file
- Set program break back to original.
sys_exit equ 1
sys_read equ 3
sys_write equ 4
sys_open equ 5
sys_close equ 6
sys_brk equ 45
sys_newstat equ 106
O_RDONLY equ 0
O_WRONLY equ 1
O_RDWR equ 2
stdin equ 0
stdout equ 1
stderr equ 2
struc STAT
.st_dev: resd 1
.st_ino: resd 1
.st_mode: resw 1
.st_nlink: resw 1
.st_uid: resw 1
.st_gid: resw 1
.st_rdev: resd 1
.st_size: resd 1
.st_blksize: resd 1
.st_blocks: resd 1
.st_atime: resd 1
.st_atime_nsec: resd 1
.st_mtime: resd 1
.st_mtime_nsec: resd 1
.st_ctime: resd 1
.st_ctime_nsec: resd 1
.unused4: resd 1
.unused5: resd 1
endstruc
%define sizeof(x) x %+ _size
SECTION .data
szFile db "TEST", 0
File_Len equ $-szFile
SECTION .bss
stat resb sizeof(STAT)
Org_Break resd 1
TempBuf resd 1
SECTION .text
global _start
_start:
;~ Get file size
mov ebx, szFile
mov ecx, stat
mov eax, sys_newstat
int 80H
;~ Get end of bss section
xor ebx, ebx
mov eax, sys_brk
int 80H
mov [Org_Break], eax
mov [TempBuf], eax
push eax
; extend it by file size
pop ebx
add ebx, dword [stat + STAT.st_size]
mov eax, sys_brk
int 80H
;~ open file
mov ebx, szFile
mov ecx, O_RDONLY
xor edx, edx
mov eax, sys_open
int 80H
xchg eax, esi
;~ read in file to buffer
mov ebx, esi
mov ecx, [TempBuf]
mov edx, dword [stat + STAT.st_size]
mov eax, sys_read
int 80H
;~ display to terminal
mov ebx, stdout
mov ecx, [TempBuf]
mov edx, eax
mov eax, sys_write
int 80H
;~ close file
mov ebx, esi
mov eax, sys_close
int 80H
;~ "free" memory
mov ebx, [Org_Break]
mov eax, sys_brk
int 80H
Exit:
mov eax, sys_exit
xor ebx, ebx
int 80H
Ok, so the first thing we need to do before creating a buffer is to get the size or the file we are going to read. There are a few ways of doing this, I chose sys_newstat.
;~ Get file size mov ebx, szFile mov ecx, stat mov eax, sys_newstat int 80H
This is a straight forward call, put the pointer to the file name to "stat" in ebx, this could be an absolute path and file name, or just a the file name if it is in the directory of the program (relative path). Next in ecx we put the address of the buffer to hold the "stat" info. If all went well, eax should contain 0 and our stat buffer will contain info, otherwise it will contain ERRNO.
Now, the file size will be at offset 20 from our stat pointer base.
We could access the file size like this: mov eax, dword [stat + 20] but I am all for writing code that is "self documenting" so we will access the file size like this: mov eax, [stat + STAT.st_size]
Now that we have the file size, we need to know the address of the end of our .bss section, this is called the Program Break and we get this by calling sys_brk:
;~ Get end of bss section xor ebx, ebx mov eax, sys_brk int 80H mov [Org_Break], eax mov [TempBuf], eax push eax
To get the address, we set ebx to zero, and on return eax will contain the address of the Program Break. Here I save it to Org_Break so I set the break back to this later. I save it to TempBuf, so I can, well, use this new buffer I will create. After that, I push the address of the break contained in eax onto the stack.
So, how do we extend this break to create a buffer? We take the address of the Program Break, and add to it the number of bytes we want the buffer to be. This will give us a new address that the system will set the new Program Break to:
; extend it by file size pop ebx add ebx, dword [stat + STAT.st_size] mov eax, sys_brk int 80H
What we do here is, pop the address we pushed onto the stack with push eax and put it in ebx - pop ebx, next we add the file size to this address and call sys_brk again.
Lets make sure it works:

Hmm seems good, let's change the file contents, save it and try again:

Great, it works! Now that we have a buffer to hold the file contents, we need to open the file, read the file, display the contents to the terminal, and close the file.
; open file
mov ebx, szFile
mov ecx, O_RDONLY
xor edx, edx
mov eax, sys_open
int 80H
xchg eax, esi
Another "simple" call, ebx needs a pointer to the file to open, the same rule for sys_stat filename apply here. ecx is the access mode for the file - it MUST contain one of the following:
O_RDONLY, O_WRONLY, or O_RDWR, you could also bitwise OR file creation and file status flags here.
edx contains the file permissions. This is ignored if O_CREAT is not specified in the flags parameter.
If the file was opened eax will contain the File Descriptor. Here we save it to esi since this is one of the few registers that are saved across system calls.
Now we can read the file contents into our new buffer:
; read in file to buffer mov ebx, esi mov ecx, [TempBuf] mov edx, dword [stat + STAT.st_size] mov eax, sys_read int 80H
ebx is the File Descriptor of the open file to read from, ecx is the address of the buffer to hold the file contents, edx is the number of bytes to read, here we will read the whole file into our buffer. On return, eax will contain the number of bytes read.
Now let's display 8053 bytes of Lorem Ipsum to the terminal:
; display to terminal mov ebx, stdout mov ecx, [TempBuf] mov edx, eax mov eax, sys_write int 80H
ebx - let's write to terminal, ecx is a pointer to the text to dispaly, edx is the number of bytes to display.
Now close the file:
; close file mov ebx, esi mov eax, sys_close int 80H
ebx is the File Descriptor to close, it is saved in esi from earlier.
Now "Free" the memory we allocated:
; "free" memory
mov ebx, [Org_Break]
mov eax, sys_brk
int 80H
This is setting the Program Break back to what it was when the program started.
And the sample output:

A TODO for you:
Take what you learned from NASM - Linux Getting command line parameters and modify the code in this tutorial to accept the file to open from the command line.
Attached File(s)
-
file_read.tar.gz (5.86K)
Number of downloads: 119







MultiQuote





|