<--- Turn the page     (contents page)     Turn the page --->


Assembler




In this issue, I will explain the technique of the two executable formats that we can write our assembler programs for; the .COM file and the .EXE file.

First, let us look at the .COM file format. In this format we have to put all our code, data, and stack in one segment, the code segment. Also, this segment can not be larger than 64k. If we are going to write small and simple to moderate programs, this type of technique is preferred.

When DOS loads a .COM file, it places the PSP at offset 00h. This PSP is 100h (256) bytes in length. Therefore, DOS places your program as a mirror image of the file at offset 100h. With this, all data is referenced from the beginning of the PSP. To see more on the PSP, see Page 4 of this issue.

Since we have to have all of our code, data, and stack in the same segment, we can place any of these in any order we want. However, the way I like to do it is place the code first, the data second, and the stack last.

The following source code is a general setup assembler file ready for assembly.
.model tiny
.code

; code goes here

            ret

; data goes here

.end

Notice that once this source is assembled, it will be a one byte .COM file and when ran, will only return to DOS. However, this is the simple makeup of a .COM file. As long as we don't move the stack anywhere, or we make sure that SP = 0FFFEh at the end of our code, we can use RET to exit to DOS. However, if we do use the stack and do not leave it "clean" after use, we will have to use a different way to exit to DOS. INT 20h or MOV AH,4Ch/INT 21h will work fine.

Since DOS allocates all available memory for our program, we can not allocate any for ourself unless we resize the memory that DOS gave us at startup. NBASM includes a directive that will resize the memory block to the size of our code, data, and stack together and then point the stack to the end of this block. (Remember, the stack is used from top-down):
.model tiny
.code
            .START

; code goes here

            ret

; data goes here

.end

This will create a small .COM file that will resize the memory block used by our program. However, if your assembler does not have a directive like this you will have to code this in by hand. The following code will resize our memory block to 64k:
.model tiny
.code

            push ax
            push bx
            push cx
            mov  ah,48h      ; resize memory block
            mov  bx,4096     ; 4096 paragraphs
            int  21h         ; ES already points to block
            pop  cx
            pop  bx
            pop  ax

; code goes here

            ret

; data goes here

.end


If you wanted to, you could find the length of your code, data, and stack, and rather than leaving 64k of memory used, resize to the size found. Then point SP to the last word in this memory block. This is what the NBASM does with the .START directive in a .COM file. Remember that you can not use the RET instruction to exit to DOS when you do this.

Now on to the .EXE make up of an assembler file. When DOS loads an .EXE file, is allocates all available memory just like the .COM file. However, DOS now places the CODE in to a segment just after the PSP, and points CS:IP to this position. Then places the DATA in to a segment and points ES and DS to this position. Then points SS:SP to different place.

Now your code uses DS:0000 as the pointer to the first data position rather than DS:0100h like in the .COM file. Also, with the .EXE file format, you can have a full 64k of memory for each CODE, DATA, and STACK segment. (In protected mode, you can even have more, but we won't even get in to that here).

For an .EXE file, I like to setup the STACK, then DATA, and then the CODE. Again, we could use the .START directive to setup our stack pointers and resize the memory block, but for learning, we will do it by hand.

The general setup of an .EXE assembler source file:
.model small
.stack 4096
.data

; data goes here

.code

           mov  ax,@data     ; @DATA points to DS
           mov  ds,ax        ; point ds to data
           mov  bx,4096*2    ; resize to 2 segments
           mov  ah,4Ah       ; (code & data)
           int  21h          ;
           mov  ah,48h       ; allocate 4k 
           mov  bx,256       ; 
           int  21h          ;
           mov  ss,ax        ; point ss to it
           mov  sp,4096      ; point sp to top
           push ds           ; point es = ds
           pop  es           ;


; code goes here


           mov  ah,4Ch
           int  21h
.end

The assembler now creates an .OBJ file suitable for the linker to create an .EXE file. ¥


<--- Turn the page     (contents page)     Turn the page --->

Page 9