Flat model version


[BITS 16]               ;Set code generation to 16 bit mode
[ORG 0x0100]            ;Set code start address to 0100h
                        ; the first 0x100 bytes (0x00-0xff) are for the
                        ; PSP (program segment prefix)


SEGMENT .text      ;Main code segment
                        ; (can also be [SECTION .text]
                        ; Sections are a bigger deal in the segmented
                        ;  model where sections map into segments
                        ;
                        ; it is unclear to me if segments do anything at
                        ;  all in flat-model executables.  The binary
                        ;  compiled without these directives is identical

START:                  ; not really needed, since there are no jumps!

    mov dx, eatmsg      ; put the *memory address* of the eatmsg data
                        ;  in dx

    mov ah, 9           ; DOS function 9 displays text to stdout.
                        ; DOS expects string address to display to be in dx
    
    int 21H             ; makes call into DOS via s/w interrupt
    int 21H             ; heck, do it again for fun

                        ; ready to quit.  we'll call the DOS term_process
                        ;  command.  If we skip this, really bad things
                        ;  happen

                        ; note, this loads the value of the data
                        ;  stored at 'term_process'.  Without the
                        ;  []'s it loads the address
    mov ah, [term_process]

                        ; also set the exit code so ERRORLEVEL is peachy
    mov al, [exit_code]

    int 21H             ; make the DOS call happen


SEGMENT .data      ; This is the initialized data segment (or section)

                        ; this is a string variable.  13 and 10 are CR LF.
                        ;  DOS needs the '$' evidently to end the string
                        ;
                        ; note you cannot use C-style things like \n
eatmsg   db "Eat at Joe's", 13, 10, "$"

term_process db 0x04c00
exit_code db 0x00

Segmented version


[BITS 16]      ; 16 code

         ; this is actually optional; the code segment
         ;  gets set up for us.
      SEGMENT   junk   

..start:       ; '..' tells linker to tell DOS to start executing
         ;   here.  This is needed for the segmented model
         ;   because segments can get shuffled around by the linker
         ;   and this may not be the first nor only segment

; setting up the segments

; We're going to be using the real mode segmented model, so we need
;  to set up our three segments in the three corresponding segment
;  registers.  This code was written for NASM.  If it was running
;  in MASM, this would be handled by the ASSUME directive.

; Each segment has a name, and the names are identifiers of their
;  segment addresses.

; Note you can't move an address directly into a segment register.
;  You must first move it into a GP register.

   mov ax, data_seg   ; load the data's segment address.  Note, 
                      ;  mov ds, data_seg would be illegal.

   mov ds, ax         ; DOS needs DS to be set right for the INT 21h
                      ;  call.  It assumes DS is the segment for the
                      ;  offset in DX

   mov ax, stack_seg  ; load the stack's segment address
   mov ss, ax

   mov sp, stacktop   ; point SP to top of the stack

   mov dx, eatmsg     ; same as before
   mov ah, 9
   int 0x21

   mov ax, 0x04c00
   int 0x21

; by convention, this would be called the 'data' segment
;  but I've named it conspicuously for clarity (ditto
;  for the stack segment).  You can have more than 
;  one of these!
      SEGMENT data_seg

eatmsg db "Eat at Joe's!", 13, 10, "$"

; we need to tell the linker that this is a special
;  segment - not a data segment.
;
; There must be one, and only one stack segment

      SEGMENT stack_seg stack
               ; means segment of type 'stack'
               ;  that's named 'stack_seg'
   resb 64     ; reserve 64 bytes

   stacktop:   ; this label points to the LAST of the
               ;  reserved 64 bytes.  Won't work if it 
               ;  was the first!
               ;
               ; As this label shows, labels are like
               ;  markers for code *OR* memory, and 
               ;  work more informally than with other
               ;  languages

Using procedures and a Macro

Notes
  • CALL / RET work more or less the same as INT / IRET save they don't have to do the TheX86SoftwareInterruptTable indirection for the jump
  • Functions can have multiple entry points!

[BITS 16]      ;Set code generation to 16 bit mode
[ORG 0x0100]

%macro GotoXY 2   ; new parms - x & y
      mov dh, %2      ; Y goes into DH
      mov dl, %1      ; X goes into DL
      mov ah, 0x02   ; BIOS VIDEO service 2 - posn. cursor
      mov bh, 0      ; stay with display page 0
      int 10h         ; call VIDEO
%endmacro

SEGMENT .text   

START:
   call ClrScr
;   jmp Die
   GotoXY 4,4
   call DefaultWrite

   GotoXY 5,5
   mov dx, msg1
   call WriteLn

   GotoXY 6, 6
   mov dx, msg2
   call WriteLn

   Die:
   mov ah, [term_process]
   mov al, [exit_code]
   int 0x21                        

   DefaultWrite:
      mov dx, defaultMsg
   Write:
      mov ah, 9
      int 0x21
      ret

   WriteLn:
      call Write
      mov DX, CRLF
      call Write
      ret
   
   ClrScr:
      mov CX, 0
      mov DX, [MAX_XY]
   ClrWin:
      mov AL, 0
   ScrlWin:
      mov BH, 0x07   ; 'normal' attribute for blanked line(s)
   VIDEO6:
      mov AH, 0x06
      INT 0x10
      ret

SEGMENT .data

   msg1   db "This is line one", "$"
   msg2   db "This is line two", "$"
   defaultMsg db "This is a default string", "$"

   CRLF   db 0x0D, 0x0A, '$'
   MAX_XY dw 0x182f ; 80 x 25 (zero based)   

   term_process db 0x04c00
   exit_code    db 0x00

Multiple object files!

  • batch script to build it
del *.exe
del *.obj

..\nasmw.exe vidlib.ASM -f obj -o vidlib.obj
..\nasmw.exe eat4.asm -f obj -o eat4.obj
..\alink eat4.obj vidlib.ob

  • file vidlib.asm
; compile this file like this:
;  nasmw.exe vidlib.ASM -f obj -o vidlib.obj

[BITS 16]   
; note, no need for an '[ORG 0x0100]' statment

; Note: both the functions/data AND the segments
;  must be declared properly for external interaction

;  ** IF THE SEGMENTS HAVE DIFFERENT NAMES BETWEENT
;     FILES, THIS WON'T ALWAYS WORK! **
;
; e.g., 'defaultMsg' resolved to 0x00 if this data
;  segment is defined as anything other than 'data_seg'

; These items are defined externally.
SEGMENT data_seg PUBLIC
   EXTERN CRLF, LRXY, defMsg
   defaultMsg db "This is a default string", "$"

; This segment can be accessed externally
SEGMENT code_seg PUBLIC
   GLOBAL GotoXY, ClrScr, ClrWin, ScrlWin, VIDEO6
   GLOBAL DefaultWriteLn, Write, WriteLn

GotoXY:
      mov ah, 0x02   ; BIOS VIDEO service 2 - posn. cursor
      mov bh, 0      ; stay with display page 0
      int 10h         ; call VIDEO
      ret

ClrScr:
   mov CX, 0
   mov DX, word [LRXY] ; ? word ?
ClrWin:
   mov AL, 0
ScrlWin:
   mov BH, 0x07   ; 'normal' attribute for blanked line(s)
VIDEO6:
   mov AH, 0x06
   INT 0x10
   ret

Write:
   mov ah, 9
   int 0x21
   ret

DefaultWriteLn:
   mov dx, defaultMsg
WriteLn:
   call Write
   mov DX, CRLF
   call Write
   ret

  • file eat4.asm
; compile with
;  nasmw.exe eat4.asm -f obj -o eat4.obj
;
; then link against vidlib.obj like so
;  alink eat4.obj vidlib.obj
;  (seems like you have to have the file with the 
;   entry point listed first)

[BITS 16]

EXTERN GotoXY, Write, WriteLn, DefaultWriteLn, ClrScr
   
SEGMENT code_seg PUBLIC

   ..start:

; get our segments all set up
      mov ax, data_seg
      mov ds, ax
      mov ax, stack_seg
      mov ss, ax

; point sp to top of stack
      mov sp, stacktop
      call ClrScr

; Load **WORD** memory address of 'TextPos' with immediate.
;  note, there is no 'byte' sized address pointer.; 0x0914 = x @ 20, y @ 9
      mov word [TextPos], 0x0914 ; 'word' qualifies the pointer
      mov DX, [TextPos] ;
      call GotoXY
      mov DX, msg1
      call Write

; re-use 'TextPos', but overwrite the Y coord
      mov DX, [TextPos]
      mov DH, 0x0A
      call GotoXY
      mov DX, msg2
      call WriteLn

; re-use 'TextPos', but overwrite the Y coord
      mov DX, [TextPos]
      mov DH, 0x0b
      call GotoXY
      call DefaultWriteLn

      mov AH, 4CH
      mov AL, 0
      int 21H

SEGMENT data_seg PUBLIC 
GLOBAL LRXY, CRLF, defMsg

   LRXY       DW 0x184F ; 24x79
   TextPos   DW 0
   msg1      DB "Message number 1", "$"
   msg2      DB "Second message number 2", "$"
   CRLF      DB 0x0D, 0x0A, '$'

SEGMENT stack_seg stack

   resb 64
stacktop:

-- MattWalsh - 17 Apr 2004

Topic revision: r6 - 24 Apr 2004 - MattWalsh
 
This site is powered by the TWiki collaboration platformCopyright © 2008-2012 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback