80x86 Assembly with Masm 5.0: Tutorial IV
ferguson_travis@hotmail.com

Previous tutorials can be found at http://www25.brinkster.com/cheeseball as can code examples.

This tutorial will cover the definition of Arrays as well as File input/output using Microsoft Macro Assembler 5.00. Tutorial II has a link as to where to find the assembler and linker, Google.com is also another good reference.

Arrays in MASM are quite simple. Inside the data segment (The part between the .data and .code) simply put <varname> <type> <number> DUP(X). Where varname is the variable name you wish to declare, type is the type of variable it will be, number is the number of the types in the array, DUP means we are duplicating what is inside the brackets. And a simple code example:
http://www25.brinkster.com/cheeseball/tut04-1.asm
Code:
.model small
.stack
.data
array1	dw 50	DUP("A")	;Set array1 = 50 A's.

.code
start:
mov ax, SEG array1		;Put address of data segment into ax
mov ds, ax			;then into DS (we can't do this directly)
lea di, array1			;put address of array1 into DI

add di, 50			;move to position 50
mov al, "$"			;put $ into al
mov [di], al			;put the $ into DI at position 50	
				;we now have 49 letter A's ending with a $

mov ax, SEG array1		;Put segment address of array1 into AX
mov ds, ax			;Then into DS
mov dx, OFFSET array1	;text at DS:DX
mov ah, 09h			;print text to screen
int 21h				;Function 9h of Interrupt 21h

mov ax, 4c00h			;Function 4c00h of Int 21h
int 21h				;Return to OS

end start			;End program (it starts at Start Label)
As you can see in the above example, arrays open your programming style and let you do things that would otherwise be extremely difficult. We could have easily used any data type before the DUP command (i.e. DW, DB, BYTE, or DWORD). We can create any type of array (I used a character array because it will be the most common).

Now we get to learn about a new register, the FLAGS register. This register is 16 bits and inside there are a series of flags which give the status of certain things the CPU has been doing. The CF flag is the first (and only for this tutorial) we will be working with. The CF flag is stored at the 0 bit of the register, in order to access this we will be working with a new instruction, LAHF, which loads the low byte of the FLAGS register into the high byte of the AX register, thus making AH = first 8 bits of FLAGS. Now that we know how to access FLAGS we need to find out how to only read one flag from it. This part is trivial using the SHL and SHR opcodes. SHL shifts everything in a register one place to the left so 0101 would become 1010 and 0001 would become 0010. So now for a very wonderful example of how this will work:

Code:
      LAHF                     ;put FLAGS into AH
      shl ah, 1                  ;shift ah left one
      shl ah, 1                  ;shift ah left one
      shl ah, 1                  ;shift ah left one
      shl ah, 1                  ;shift ah left one
      shl ah, 1                  ;shift ah left one
      shl ah, 1                  ;shift ah left one
      shl ah, 1                  ;shift ah left one
      shr ah, 1                  ;shift ah right one
      shr ah, 1                  ;shift ah right one
      shr ah, 1                  ;shift ah right one
      shr ah, 1                  ;shift ah right one
      shr ah, 1                  ;shift ah right one
      shr ah, 1                  ;shift ah right one
      shr ah, 1                  ;shift ah right one
                                      ;AH now holds CF flag value 0 or 1
After this we can simply test AH for either 00h or 01h, TRUE or FALSE. There are far better ways to do this, mainly using the AND opcode. The MUCH easier way of doing this would be:

Code:
	LAHF
	AND ah, 01h
The SHL (and SHR) instructions both occupy 2 bytes of space. The AND instruction only takes up 3 bytes, thus we can either take up 14 bytes clearing the other flags out of AH or we can take up 3 bytes. Now for what we have all been waiting for, we are going to open, close, read, and write to a file. (to keep the size of this tutorial down we are not going to be doing this all in the same program, we will split it up into multiple programs).

First of all, opening a file is quite a bit easier than it sounds (actually I think it is easier than in C). First of all, just like almost everything in assembly (at least x86 DOS programming) we are going to be using an interrupt. Most file IO operations are accomplished using INT 21h. To open a file we first need to know what function in INT 21h it is, and what values we must pass along with it. Here is that information
Code:
	AH = 3dh
	AL = bit 0-2 is the Access mode
		000 = Read Only
		001 = Write Only
		010 = Read/Write Mode
	         bits 4-6 is the Sharing mode (DOS 3.5 and up).  (I never use these)
		000 Compatibility mode
		001 Deny all
		010 deny write
		011 deny read
		100 deny none
	DS:DX = SEGMENT:OFFSET of ASCIIZ pathname.  

The output is as follows:
	CF = 0 if it worked
	AX = Handle if it worked
	CF = 1 if we got an error
	AX = Error Code
		01h = missing file sharing program
		02h = file not found
		03h = path not found or no file exist at path
		04h = no file handle available. 
		05h = access denied
		0ch = access mode not permitted
As you can see, there is not that much more needed to open a file than is needed to print text to the screen, and there is also built in handling of errors we simply have the test the end results of opening the file and jump to the correct fix if there is an error. Now to learn how to close files.

Code:
Closing a File:
	AX = 3e00h
	BX = File Handle
	
The output of this will be:
	CF = 0 if it worked
	AX = nothing, it will be random
	CF = 1 if function did not work.
	AX = error code  06h if file not opened or incorrect file handle
Warning:  Do not call this with a 00h file handle as handle 00h is the STDIN and will lock your access to the machine.  

Reading from a file or device:
	AH = 3fh
	BX = Handle
	CX = Number of bytes to read from file
	DS:DX = SEGMENT:OFFSET of buffer to hold info that is in the file
The output will be:
	CF = 0 if successful
	AX = Number of bytes read
	CF = 1 if an error occurred
		05h = Access denied
		06h = incorrect handle or file not opened
	CF + AX = 0 then EOF (End of File)
	CF = 0  AND  AX < CX  EOF or error occurred.

Creating Files:
	AH = 3ch
	CX = File Attrib
		Bit 0 = read only
		Bit 1 = hidden file
		Bit 2 = system file
		Bit 3 = volume (ignore this one)
		Bit 4 = directory (ignore this one too for now)
		Bit 5 = archive bit
		Bit 6-15 = reserved (do not touch)
	DS:DX = ASCIIZ pathname
The output is as follows: 
	CF = 0 if successful
	AX = File Handle
	CF = 1 if an error occurred
		03h = path not found
		04h = no handle available.
		05h = access denied

Writing to files:
	AH = 40h
	BX = File Handle
	CX = number of bytes to write
	DS:DX = SEGMENT:OFFSET of information to write
Now we have all the information needed to do anything with a file. All we need now is to learn how to use it. For doing this we have a very great and informative (slightly non optimized as I am using shl and shr instead of AND in the code) code example:
http://www25.brinkster.com/cheeseball/tut04-2.asm

Code:
.model small
.stack
.data
   failedcf db "Failed to create file!$"
   generr   db "General error!$"
   readf    db "Read Failed!$"
   
   message  db "Message to put into blank file!$",0
   
   filename db "test.tst",0
   buffer   db 50 DUP ("$")
   handle   dw ?
   
.code
start:
   mov ax, @data                 ;Put data segment into AX
   mov ds, ax                    ;Then put it into DS
   
   mov ah, 3dh                   ;function 3dh of int 21h (open file)
   mov al, 02h                   ;for read/write mode
   mov dx, OFFSET filename       ;filename ASCIIZ at DS:DX
   int 21h                       ;Call interrupt to finish open
   
   mov handle, ax                ;put handle or error into handle
   
   LAHF                          ;put FLAGS into AH
   shl ah, 1                     ;shift ah left one
   shl ah, 1                     ;shift ah left one
   shl ah, 1                     ;shift ah left one
   shl ah, 1                     ;shift ah left one
   shl ah, 1                     ;shift ah left one
   shl ah, 1                     ;shift ah left one
   shl ah, 1                     ;shift ah left one
   shr ah, 1                     ;shift ah right one
   shr ah, 1                     ;shift ah right one
   shr ah, 1                     ;shift ah right one
   shr ah, 1                     ;shift ah right one
   shr ah, 1                     ;shift ah right one
   shr ah, 1                     ;shift ah right one
   shr ah, 1                     ;shift ah right one
                                 ;AH now holds CF flag value 0 or 1
   cmp ah, 00h                   ;if successful open
   je fileopen                   ;then goto fileopen
   cmp ah, 01h                   ;if not successful open
   je filenoopen                 ;then goto filenoopen
   
   filenoopen:
      cmp handle, 01h            ;if no file sharing software
      je generror                ;goto generror
      cmp handle, 02h            ;if file not found
      je filenotfound            ;goto filenotfound
      cmp handle, 03h            ;if path not found
      je filenotfound            ;goto filenotfound
      cmp handle, 04h            ;if no handle aval
      je generror                ;goto generror
      cmp handle, 05h            ;if access denied
      je generror                ;goto generror
      cmp handle, 0ch            ;if access mode not permitted
      je generror                ;goto generror
      jne generror               ;else goto generror
   
   generror:
      mov dx, OFFSET generr      ;print generr to screen
      mov ah, 09h                ;function 09h of int 21h (print text)
      int 21h                    ;call int 21h
      
      mov ax, 4c00h              ;function 4ch of int 21h (return to OS)
      int 21h                    ;call int 21h
      
   filenotfound:
      mov ah, 3ch                ;function 3c (create file) int 21h
      mov cx, 00h                ;no special attribs
      mov dx, OFFSET filename    ;ASCIIZ offset of filename
      int 21h                    ;create the file
      
      mov handle, ax             ;save handle into handle
      
      mov dx, OFFSET message     ;put offset of message into DX
      mov bx, handle             ;handle into BX
      mov cx, SIZEOF message     ;send into file message size
      mov ah, 40h                ;function 40h (write to file)
      int 21h                    ;call int 21h
      
      LAHF
      mov dh, ah
      
      mov ax, 3e00h              ;closing file (function 3eh of int 21)
      mov bx, handle             ;file with handle
      int 21h                    ;call int 21h
      
      mov ah, dh                 ;put old EFLAGS into AH
      shl ah, 1                  ;shift ah left one
      shl ah, 1                  ;shift ah left one
      shl ah, 1                  ;shift ah left one
      shl ah, 1                  ;shift ah left one
      shl ah, 1                  ;shift ah left one
      shl ah, 1                  ;shift ah left one
      shl ah, 1                  ;shift ah left one
      shr ah, 1                  ;shift ah right one
      shr ah, 1                  ;shift ah right one
      shr ah, 1                  ;shift ah right one
      shr ah, 1                  ;shift ah right one
      shr ah, 1                  ;shift ah right one
      shr ah, 1                  ;shift ah right one
      shr ah, 1                  ;shift ah right one
                                 ;AH now holds CF flag value 0 or 1
      cmp ah, 00h                ;if successful open
      je start                   ;then goto fileopen
      cmp ah, 01h                ;if not successful open
      je failedcreatefile        ;goto failedcreatefile
      
      failedcreatefile:
         mov dx, OFFSET failedcf ;offset of failedcf
         mov ah, 09h
         int 21h
         
         mov ax, 4c00h           ;return to DOS 
         int 21h                 ;call int 21h
         
   fileopen:
      mov ah, 3fh                ;read file
      mov bx, handle             ;file with handle in handle
      mov cx, 50                 ;num of chars to read
      mov dx, OFFSET buffer      ;offset to store at DS:DX
      int 21h                    ;call int to finish off
      
      LAHF                       ;put FLAGS into AH
      shl ah, 1                  ;shift ah left one
      shl ah, 1                  ;shift ah left one
      shl ah, 1                  ;shift ah left one
      shl ah, 1                  ;shift ah left one
      shl ah, 1                  ;shift ah left one
      shl ah, 1                  ;shift ah left one
      shl ah, 1                  ;shift ah left one
      shr ah, 1                  ;shift ah right one
      shr ah, 1                  ;shift ah right one
      shr ah, 1                  ;shift ah right one
      shr ah, 1                  ;shift ah right one
      shr ah, 1                  ;shift ah right one
      shr ah, 1                  ;shift ah right one
      shr ah, 1                  ;shift ah right one
                                 ;AH now holds CF flag value 0 or 1
      cmp ah, 00h                ;if read worked
      je readsuccess             ;goto readsuccess
      cmp ah, 01h                ;if it did not work
      je readfailed              ;goto readfailed
      
      readfailed:
         mov dx, OFFSET readf    ;print text to screen func
         mov ah, 09h             ;function 09, int 21h
         int 21h                 ;call int 21h
         
         mov ax, 4c00h           ;RETURN TO OS
         int 21h
         
      readsuccess:
         mov ax, 3e00h           ;closing file (function 3eh of int 21)
         mov bx, handle          ;file with handle
         int 21h                 ;call int 21h
         
         mov dx, OFFSET buffer   ;print message at buffer
         mov ah, 09h             ;function 09h of int 21h
         int 21h                 ;call int 21h
         
         mov ax, 4c00h           ;return to OS int 21h end start
         int 21h
end start
Yeah, that is a LOT longer than the rest of the code used in all my tutorials. Sorry I think I got a little carried away with that one (not really, everything there is needed to keep the program flow logical). This code completes this tutorial and hopefully now we understand file handling and arrays in assembly. If anyone has any questions you can reach me at the email address above.