I am writing this paper for I find plenty of tutorials and books all about
assembly and how to write programs and how to do loops, if/else statments,
etc... But one thing I did not see plenty of is tutorials on how to set up the
assembler of choice that you grow fond of, for instance nasm, a86, tasm, masm
GAS, etc.
So I am writing about a86 and I'm using my college notes and experience I
learned from my Assembly class. I hope this will help you enjoy a86 and
encourage you to learn how to manage up to x286 opcodes and 16-bit code
before you start tackling with 32bit and Windows programming in assembler.
This is a sort of warning that you will only be able to write DOS programs
but you have to learn how to crawl before you can walk, and you have to learn
how to walk before you can run. I hope to show you how to set up a86, how
to write a few simple programs with the template I use, and how to do some
basic stuff in assembler.
I took a college course on Assembly a couple of months ago, and I was happy to
learn the internals of the system and how to manipulate the registers for some
awesome results. The assembler that we used was a86 by Eric Isaacson. This
is a shareware program, meaning you get to play with it before buying it. To
get this assembler go to - http://www.eji.com/a86/ - and you will see where to
download the programs. It is in a zip file and you just unzip it with your
favorite program like winzip or pkunzip. You should also download d86, the
debugger, for use with your a86 programs. Once you downloaded them, unzip the
files to a directory such as c:\a86, or even put on a floppy disk if you are
worried about space.
Getting Started
Let's get into it: you've got the assembler and the debugger, what next? First
of all, we have to make a text file since all asm source code is nothing but a
plain text code that has a bunch of operands and functions to do what you want
your program to do.
I start all my a86 programming by opening up my template.asm, which what I
got from school; it is a useful template and it makes a good dos .EXE when you
compile it with the supplied batch file. Cut the following code and save it in
a text file called template.asm:
X--------Begin Cutting here--------------------------------------------
; PROGRAM :
;
; AUTHOR :
;
; PURPOSE :
;
; PROGRAM OUTLINE :
;
;============================== EXTERN ===============================
;=========================== STACK SEGMENT ===========================
sseg segment para stack 'STACK'
db 100H dup ( ? ) ; allow 256 bytes of memory for
; use by our program stack.
sseg ends
;============================ DATA SEGMENT ============================
dseg segment para 'DATA'
dseg ends
;============================ CODE SEGMENT ============================
cseg segment para 'CODE'
; Begin the Code segment containing executable machine code
program proc far ; Actual program code is completely
; contained in the FAR procedure
; named PROGRAM
assume cs:cseg, ds:dseg, ss:sseg
; Set Data Segment Register to point to the Data Segment of this program
mov ax,dseg
mov ds,ax
;=============== Rest of MAIN PROGRAM code goes here ==================
exit:
mov ax,4c00h ; terminate program execution and
int 21h ; transfer control to DOS
program endp ; end of the procedure program
;============================ PROCEDURES ==============================
cseg ends ; End of the code segment containing
; executable program.
end program ; The final End statement signals the
; end of this program source file, and
; gives the starting address of the
; executable program
X--------Stop Cutting here--------------------------------------------
Now we have a template to use, and this is just one out of many templates you
can make for your assembly programs. Now let's begin to have fun. These few
programs will get us going for a basic feel of how to set up a basic hello
program.
What we will learn from this example is:
1) The basic mechanics of editing the template file to get an ASM source code
file, assembling and linking it, and possibly fixing syntax errors.
2) Nearly all of the programs have loops in them, having different formats.
3) The operation of several INT 21H functions: 01H, 02H and 08H
(character input and output), 09H(string output), and 4CH(program termination)
4) The operation of the DOSIOLT procedures: inhex16 and outhex16, and how to
assemble and link a program that uses them.
5) Both string and numeric variables will be demonstrated.
Creating an ASM file for the Message Program
To become familiar with the process of creating an assembly program, you will
create a simple program that prints a one line message. As with most
programming languages, Assembly programming starts with a plain text file
containing the program instructions to execute. Ordinarily, a programmer would
have to type in the entire source file from scratch. But 8086 assembler
program files contain a large number of setup directives and declarations
which are essentially the same for every program. It will be easier to start
with a file that has all the necessary directives and declarations already in
it, and just add to it the actual program parts.
The file template.asm is that a template which contains all the necessary
pieces of a program, except for the actual program itself. Make a copy of the
template.asm file, and name it something appropriate: message.asm is a good
choice. The file extension must be ASM. You will edit the new file to create
your first program. DO NOT EDIT template.asm itself!!!! You will use this
template file as the start of your assembly programs so it should not be
alterated(until you get advanced enough to play around with it ;-).
We will be using EDIT in a dos box as our editor, though you can use notepad or
Ultraedit to edit your assembly files as well.
The Comments
All of the progras that you will write should have a descriptive set of header
comments at the top. Any text AFTER a semicolon is considered a comment. The
top of your new program file should already have the basic outline for this
comment. Edit in your message.asm file to have something like this :
; PROGRAM : Message Program
;
; AUTHOR : Your Name here
;
; PURPOSE : This program simply prints a one line message
; to the screen
; PROGRAM OUTLINE : Use INT 21H Function 09H to print the message.
This is just an example to help you know what you want to do, and to have a
reference if you were to walk away from a project for a year or so...the header
will make a nice reminder of what you were trying to get this program to do.
The Ram Variable
The program that you will creat in this part requires a variable. You will
create a string of characters labeled message. The part of the file where all
data is placed is the Data Segment. Look in your ASM file for the following
lines:
dseg segment para 'DATA'
dseg ends
Change this part of the code so that the message to be printed is defined.
The result will look like:
dseg segment para 'DATA'
message db 0DH, 0AH, "WHOPPEEEE!!! My first Message.", 0DH, 0AH, "$"
dseg ends
The HEX values are the two-byte sequence for a DOS newline(CR-LF). The first
characters of "0DH" and "0AH" is ZERO, no capital O. Note that there is NO
semicolon before "message". Do not allow this part to break over two lines.
THE Code -
Now locate the part of the code where the program code goes. It should look
like this:
;========================Main Program================================
;
program proc far ; Actual program code is completely
; contained in the FAR procedure
; named PROGRAM
assume cs:cseg, ds:dseg, ss:sseg
; Set Data Segment Register to point to the Data Segment of this program
mov ax,dseg
mov ds,ax
;=============== Rest of MAIN PROGRAM code goes here ==================
- exit
- mov ax,4c00h ; terminate program execution and
int 21h ; transfer control to DOS
program endp ; end of the procedure program
;============================ PROCEDURES ==============================
cseg ends ; End of the code segment containing
; executable program.
end program ; The final End statement signals the
; end of this program source file, and
; gives the starting address of the
; executable program
All of the code for your program Should REPLACE the comment:
"Rest of Main Program code goes here".
Here is the code you will use to print out the message:
;Print the message
mov dx, offset message
mov ah, 09H
int 21H
This code just calls the DOS Interrupt used to print strings to the screen.
Interrupt 21H is a general starting point for many useful DOS calls. The
sub-function used to print strings is Function 09H; this value must be loaded
into the AH register before calling. Also, Int 21H Function 09H requires the
address of the message be placed in the DX register. The above code performs
these two initialization tasks, and then calls the interrupt.
Take careful note of the semicolons which start the comments. Also, do not
alter any of the other part of the code.
These were the only two changes you needed to make.
Assembling with asm86.bat
Now we have written our first asm file. To assemble with a86 you could try to
use the switches from the manual that is included with the a86 package, or
you can make things easy by using this batch file, which is designed for
programs that use the template file. Here is the batch file:
:------------------------------ASM86-----------------------------------
@echo off
REM This is a simple batch file to use a86 and link:
if exist %1.asm GOTO FOUND
echo %0 ERROR : %1.asm -- FILE NOT FOUND
echo Usage: %0 file [link-file]
GOTO STOP
: FOUND
:-- Assemble the program
echo a86 +O +S +E %1.asm
a86 +O +S +E %1.asm
::-- IF THERE WAS AN ERROR, STOP
IF ERRORLEVEL 1 GOTO STOP
::-- IF there is a second file name, assume it is a OBJ file,
::-- and link it to the %1 name.
IF X%2 == X GOTO ELSELINK
ECHO link %1+%2;
link %1+%2;
GOTO ENDIFLINK
:ELSELINK
echo link %1;
link %1;
:ENDIFLINK
:STOP
and save this as asm86.bat.
All this does is 1) create an object file (+O), 2) suppress the creation of
the symbol table .sym(+S), and 3) copy the errors to a the filename.err instead
of writing in your file(+E).
To assemble the message.asm with the batch file, type
asm86 message
If there were any errors, you will have to edit the asm file to fix them. The
error messages displayed by the assembler should indicate the line number and
cause of the problem. Since you are just copying pregenerated code, any errors
will simply be typos.
Once all of the errors have been corrected, a pair of files will have been
created. The will have the same base name as the original asm file, but will
have different extensions:
OBJ- Object file. Contains the basic machine code, but does not have any
references to external procedures. This is, effectively, an intermediate file
which is used by the linker to produce the final executable file.
EXE- Executable file. All external references resolved. Completely runable.
To run the program just type Message and you will see the line appear on the
screen.
This was a simple Hello program. What you probably want is another example or
two to try out, and that is what we shall do. The next Program that won't be as
long but will have plenty of info.
CharLoop Program
In this part, you will create a simple program that asks the user to enter a
character, and prints it out again. It does this repeatedly, until the user
hits the ESC key. Dos funtions 01H and 02H are introduced with this program,
and it is the first program containing a comparison loop.
Again you should start by copying template.asm to a file called charloop.asm.
Edit the charloop.asm template so that it has the following changes:
Create two messages by adding the following lines to the Data Segment part of
the program (see the message program instructions, if you don't remember how
to do this):
prompt db 0DH, 0AH,"Enter a Character: $"
outmsg db 0DH, 0AH, "You Entered: $"
Now add the code which will put the following "pseudocode" into effect:
Repeat
prompt for and read a character
Print the character back out with a message
While the character read is not esc
Which will turn out to be the following assembly code:
- char loop
-
;Print the prompt
mov dx, offset prompt
mov ah, 09H
int 21H
;Read a character into AL
mov ah, 01H ;(01H - with echo; 08H - no echo)
int 21H
mov bl, al ;save character in BL
;Print the final message
mov dx, offset outmsg
mov ah, 09H
int 21H
;Write the character to the screen
mov dl, bl ;put character in dl
mov ah, 02H
int 21H
;Loop back, only if the character was not esc (1BH)
cmp bl, 1BH
jne char_loop
;End Repeat
Note how the two new DOS interrupts are called. The Function number is always
placed in AH before calling, and the INT 21H instruction is used to invoke the
interrupt. For Function 1H, which reads a character to the screen, the DL
register must be initialized with the appropiate value.
Note also that the character must be stored somewhere throughout the whole
loop, and it can NOT be stored either AL or DL -- AL is modified by Function
02H, and DL is modified when DX is set to the address of teh strings. So BL is
used to store the character, and the value must be transferred between AL, BL
and DL during processing. This kind of juggling happens often in assembly
programming. Get this program running to watch another good program going ;-).
CharLoop Program without Echo
In CharLoop program above. Function 01H was used to read a character from the
keyboard. It does more than just read a character, it also echoes it back to
the screen. This way, when you type something, you get visual feedback of what
you have done.
Function 08H works exactly the same as Function 01H, except for this echo
feature: Function 08H does NOT echo the character after reading it.
Create a new program which is exactly the same as CHARLOOP, except it should
use Function 08H to read the characters, instead of Function 01H. Write and
run the program to see how it works.
NumLoop Program
This program will work in a similar fashion to the Charloop program above, but
it will read and print numbers. Since there is no DOS interrupt to convert
ASCII characters to numbers, your code will have to do this. Fortunately,
there are already procedures to do this. A few extra steps must be taken to
use them, but it will be much easier than writing the code from scratch. See
the info about DOSIOLT for details on how to use thes procedures.
DOSIOLT Procedures
Here is a description of the DOSIOLT procedures:
inhex16
This procedure reads a HEX number in character format from the standard input,
and converts it to a word. Spaces or Tabs may precede or follow then number.
DOS int 21H-0AH is used to read the input string, so it must be terminated by a
RETURN. Both upper and lower case letters A-F may be used. If the number typed
is larger than FFFH, the upper bits are lost. If anything unpredictable is
typed(like non-HEX chars) the function will return junk.
Inputs: None
Outputs: AX- the word-sized number read.
Modifies: AX, flags
outhex16
This simple routine prints the four 'nibbles' of AX as ASCII digits.
Four digits are always printed.
Input: AX- the number to be printed
Outputs: None
Modifies: Flags
outHex8
This simple routine prints the two 'nibbles' of AL as ASCII digits. Two digits
are always Printed.
Input: AL-the number to be printed
OUTPUT: NoneModifies: Flags
Call
Each of these procedures is invoked with the CALL instruction. Any
inputs(registers) must be initialized before the call; any outputs(also
registers) are set by the procedure, and contain the appropriate value after
the call.
For example, to print the 1-byte value "2F" to the screen:
mov al, 2FH
call outhex8 ;Prints: 2F
To Print "2AC5"
mov ax, 2AC5H
call outhex16 ; print 2AC5
To read a number from the keyboard:
call inhex16 ;The ax register now contains the number read
Extern
Since the code for these functions does NOT appear in your ASM file, two
special steps must be taken in creating your executable file. The first is to
declare the names of the procedures as external procedures. This informs the
assembler that the code has been written elsewhere, and you didn't just forget
to write it.
The extern declaration should come someplace early in the ASM file. Although
it doesn't matter greatly where it goes, most programmers will put these
declarations outside of all of the segments. The template file given has a
spot for externals, marked with a commment.
The format for the declaration(in this case) is:
extern procedure_name:far
A86 USERS: The A86 Assembler uses the older version of the extern
declaration, which is spelled extrn. If you are using the a86
assembler(asm86.bat), make sure you spell the name of the instruction
extrn.
procedure_name is the name of the procedure that you will use in the program.
The name only needs to be declared once in this way, no matter how many times
it is used. But if two or more DOSIOLT procedures are to be used, each must
have a separate declaration.
You should NOT place these extern declarations in your code unless you are
actually using the routines. The linker may place the code for the procedure
in your final executable even if it is never called.
LINKING
A special step must be taken in linking (the second half of the compilation
phase done by asm86.bat) to link the code in DOSIOLT. Fortunately, asm86.bat
can handle the extra file fairly automatically. Just include the DOSIOLT on
the command line, after your asm file name.
Example: assuming you have written a program in a file called "calc.asm" which
contains calls to the DOSIOLT procedures. To assemble and link the program:
A:\> asm86 calc dosiolt
If you get an "Undefined Symbol" error, it is because you mistyped, or
forgot, the extern declarations for the DOSIOLT procedures. Make sure
these are correct.
If you get an "Unresolved External" error, it is because you forgot to put
"DOSIOLT" as the second file name; i.e. you typed: asm86 calc instead of
asm86 calc dosiolt.
This program will illustrate the use of two of the DOSIOLT procedures, and also
the use of variables, rather than registers, as places to store information.
The outline of the program is as follows:
Loop forever
Prompt for, and read a number into the variable NUMBER
IF number = 0, then break out of the loop
print Number, with an appropriate announcement.
End Loop
Your program will need a prompt string, a response string and a word-sized
variable in the Data Segment:
prompt1 db 0DH, 0AH, "Enter a number: $"
response db 0DH, 0AH, "You Entered: $"
number dw ?
Number has been declared as a word-sized variable, with no initial value. The
Code can now use the name "Number" just like a register name( in most cases).
The code for the program is:
- number loop
-
;Print the first prompt
mov dx, offset prompt1 mov
ah, 09H
int 21H
;Read a number into AX and put it in NUMBER
call inhex16 mov number, ax
;If number = 0 the exit the loop
cmp number, 0H
je end_number_loop
;Print The second prompt.
mov dx, offset response
mov ah, 09H
int 21H
;Print the number
mov ax, number
call outhex16
jmp number_loop
end_number_loop:
Note that the inhex16 reads a number into AX, and outhex16 prints the number
AX, yet this code went through all the trouble of storing the number in the
variable, rather than just leaving it in AX throughout the loop. WHY?!?
Because AX was needed in between the reading and printing of the code. Again,
this kind of juggling between registers and variables occurs often in assembly
programming.
Since two DOSIOLT procedures are being used, they must be declared. At the top
you will find the EXTERN part of your program template; add these lines to the
section:
;===============================Extern======================================
extrn inhex16:far
extrn outhex16:far
Those are all the changes needed.
Don't forget to include the DOSIOLT file on the command line when compiling,
which will be --- asm86 numloop dosiolt
I do apologize for the length of this but I got to excited when I was messing
with these old files and playing with these procedures in dosiolt.obj file.
If you want to try to use these files, you can email me at
This e-mail address is being protected from spam bots, you need JavaScript enabled to view it
and request the dosiolt.obj to use with the numloop; I will be more than happy
to send it.
|