UMBC CMSC 313 -- File I/O Sample Program Previous | Next


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