UMBC | CMSC 313 -- File I/O Sample Program | Previous | Next |
;; 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