File I/O Sample Program
;; Standard files
%define STDIN 0
%define STDOUT 1
%define STDERR 2
;; in /usr/include/asm/unistd.h
;; #define __NR_read 3
;; #define __NR_write 4
;; #define __NR_open 5
;; #define __NR_close 6
;; #define __NR_creat 8
%define READ 3
%define WRITE 4
%define OPEN 5
%define CLOSE 6
%define CREATE 8
;; in /usr/include/bits/fcntl.h:
;;
;; O_RDONLY 00
;; O_WRONLY 01
;; O_RDWR 02
%define O_RDONLY 00
%define O_WRONLY 01
%define O_RDWR 02
;; The conventions used in Linux 2.2, the parameters are stored in left to right
;; order in the registers EBX, ECX, EDX, EDI, and ESI respectively.
;; The man pages show:
;; int creat(const char *pathname, mode_t mode);
;; mov eax, dword CREATE ; System Call -- open
;; mov ebx, myFile1 ; Pointer to filename
;; mov ecx, O_WRONLY ; Flag for Write Only
;; mov edx, 01FDh ; Mode -- 755 in octal
;; int 80h
;; mov dword [ fdWrite ], eax; save the file descriptor
;; int open(const char *pathname, int flags, mode_t mode);
;; mov eax, dword OPEN ; System Call -- open
;; mov ebx, myFile ; Pointer to filename
;; mov ecx, O_RDONLY ; Flag for Read Only
;; mov edx, 0 ; Mode -- not used to open existing file
;; int 80h
;; mov dword [ fdRead ], eax ; save the file descriptor
;; ssize_t read(int fd, void *buf, size_t count);
;; mov eax, READ ; System Call -- read
;; mov ebx, dword [ fdRead ]; File descriptor opened for reading
;; mov ecx, dword inBuff ; Pointer to input buffer
;; mov edx, dword BUFSIZE ; Number of bytes to read
;; int 80h
;; mov dword [ bytesRead ], eax ; Actual amount read
;; ssize_t write(int fd, const void *buf, size_t count);
;; mov eax, WRITE ; System Call -- write
;; mov ebx, dword [ fdWrite ]; File descriptor opened for writing
;; mov ecx, dword outBuff ; Pointer to output buffer
;; mov edx, dword [ bytesWritten ] ; Number of bytes to write
;; mov 80h
;; int close(int fd);
;; mov eax, CLOSE
;; mov ebx, dword [ fdRead ]
;; int 80h
;;
;; What is this size_t/ssize_t/mode_t stuff?????
;; /usr/src/linux/include/asm-i386/posix_types.h:typedef unsigned short __kernel_mode_t;
;; /usr/src/linux/include/linux/types.h: typedef __kernel_mode_t mode_t;
;; /usr/src/linux/include/asm-i386/posix_types.h:typedef int __kernel_ssize_t;
;; /usr/src/linux/include/linux/types.h: typedef __kernel_ssize_t ssize_t;
;; /usr/src/linux/include/asm-i386/posix_types.h:typedef unsigned int __kernel_size_t
;; /usr/src/linux/include/linux/types.h: typedef __kernel_size_t size_t;
;;
;; Whenever working with buffers, you must declare the buffer to be at least
;; as large as what you the the largest file will be. This is then a
;; hard-coded constraint. It is one of the shortcomings of arrays because
;; you can waste a lot(!) of memory that way.
;;
;; The solution to that constraint is to stat(2) the file file and get the file size from
;; st_size component of the stat structure and use malloc/calloc to dynamically
;; allocate the buffer.
;;
%define BUFSIZE 7FFFh
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
section .data
myFile db 'data.txt',0
myFile1 db 'data1.txt',0
bytesIn db ' bytes read',10
BINlen equ $ - bytesIn
bytesOut db ' bytes written', 10
BOUTlen equ $ - bytesOut
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
section .bss
inBuff resb BUFSIZE ; Used for both input and output in this program.
fdRead resd 1 ; File descriptor for input file
fdWrite resd 1 ;
bytesRead resd 1
bytesWritten resd 1
nrOut resb 11 ; The largest 32-big signed value is 2GB with sign.
nrLen EQU $-nrOut
signFlag resb 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
section .text
global main ;must be declared for gcc
main: ;tell linker what the entry point is
;; Open input file
mov eax, OPEN ; System Call -- open
mov ebx, myFile ; Pointer to filename
mov ecx, O_RDONLY ; Flag for Read Only
mov edx, 0 ; Mode -- not used to open existing file
int 80h
mov dword [ fdRead ], eax ; save the file description of the opened file
;; Create a new output file
mov eax, CREATE ; System Call -- open
mov ebx, myFile1 ; Pointer to filename
mov ecx, dword 001FDh ; Mode = 775 octal or 01FDh
; mode is really mode &= ~umask
; you can see the settings for umask with the
; umask command
int 80h
mov dword [ fdWrite ], eax ; save the file description of the opened file
;; Read Input file
mov eax, READ ; System Call -- read
mov ebx, dword [ fdRead ]; File descriptor opened for reading
mov ecx, dword inBuff ; Pointer to input buffer
mov edx, dword BUFSIZE ; Number of bytes to read
int 80h
mov dword [ bytesRead ], eax ; Actual amount read
call numOut
mov eax, WRITE ; System Call -- write
mov ebx, STDOUT ; File descriptor opened for writing
mov ecx, bytesIn ; Pointer to output buffer
mov edx, BINlen ; Number of bytes to write
int 80h
;; Write Output file
mov eax, WRITE ; System Call -- write
mov ebx, dword [ fdWrite ]; File descriptor opened for reading
mov ecx, dword inBuff ; Pointer to input buffer because it is
; also our output buffer in this case.
mov edx, dword [ bytesRead ] ; Number of bytes to write
int 80h
mov dword [ bytesWritten ], eax ;; Number actually written
call numOut
mov eax, WRITE ; System Call -- write
mov ebx, STDOUT ; File descriptor opened for writing
mov ecx, bytesOut ; Pointer to output buffer
mov edx, BOUTlen ; Number of bytes to write
int 80h
mov eax, CLOSE
mov ebx, dword [ fdRead ]
int 80h
mov eax, CLOSE
mov ebx, dword [ fdWrite ]
int 80h
done:
mov ebx,0 ;successful termination of program
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
;========================================================================================
;;
;; numOut -- receives a signed integer in EAX and outputs it to the screen.
;; To make things more reusable, the conversion is done is
;; a subprogram, nrCnvt.
;;
;; registers used: None. All are restored.
;========================================================================================
numOut:
push esi
push eax
push ebx
push ecx
push edx
mov esi, dword nrOut ; Go to the start of output buffer
add esi, nrLen ; Jump to the end of it (one past, actually)
dec esi ; Back up to the last byte of buffer
call nrCnvt
mov edx, eax ; Number of bytes to write
mov eax, WRITE ; System Call -- read
mov ebx, STDOUT ; File descriptor opened for reading
mov ecx, esi ; Pointer to input buffer because it is
int 80h
pop edx
pop ecx
pop ebx
pop eax
pop esi
ret
;========================================================================================
;; nrCnvt -- receives a signed 32-bit integer in EAX and converts it to ASCII
;; for output. ESI has the address of an output buffer to put
;; ASCII characters while converting. NOTE: This does not correctly
;; convert the single value that is MININT (INT_MIN) or -2147483648,
;; To be technically correct, this special case should be checked and
;; handled. "This exercise is left to the reader."
;;
;; To make this truely portable and reusable, you could make this
;; so that CL holds the count and CH holds the sign.
;;
;; registers used:
;; EAX -- contents destoryed, returns number of characters to print.
;;
;========================================================================================
nrCnvt:
push ebx
push ecx
push edx
mov ebx, 10
mov ecx, 0
mov byte [ signFlag ], ' '
cmp eax, 0
jge doLoop
mov byte [ signFlag ], '-'
neg eax
doLoop:
cdq
idiv ebx
add dl, 30h
mov byte [ esi ], dl
dec esi
inc ecx
cmp eax, 0
jne doLoop
mov dl, byte [ signFlag ]
mov byte [ esi ], dl
inc ecx
mov eax, ecx ; return number of character to output
pop edx
pop ecx
pop ebx
ret
Previous |
Next
©2005, Gary L. Burt