Dec 082017
A tutorial for PC 8086 assembler (TASM/MASM/A86.) Requires previous programming experience and basic knowledge on PC. (Part 1 of 4).
File ASMTUT1.ZIP from The Programmer’s Corner in
Category Assembly Language
A tutorial for PC 8086 assembler (TASM/MASM/A86.) Requires previous programming experience and basic knowledge on PC. (Part 1 of 4).
File Name File Size Zip Size Zip Type
A86.DOC 17104 5201 deflated
ADD1.ASM 6427 1109 deflated
APP1.DOC 29263 7320 deflated
APP2.DOC 31059 7160 deflated
APP3.DOC 29310 6653 deflated
ASMHELP.OBJ 10446 5406 deflated
ASMLINK.BAT 20 20 stored
BBSINFO.DOC 5663 1947 deflated
CH1STR.OBJ 4453 1754 deflated
COMPARE.ASM 4587 1201 deflated
COMTEMP.ASM 638 252 deflated
DEBUGGER.DOC 14686 4258 deflated
DISK1MAK.BAT 1521 447 deflated
FILELIST.DOC 9176 2260 deflated
HELPMEM.COM 3565 2162 deflated
INTO.COM 80 80 stored
INTRO1.DOC 17699 5625 deflated
INTRO2.DOC 45243 9186 deflated
MISHMASH.DOC 31296 6984 deflated
PSEUDDBG.COM 501 359 deflated
PUSHREGS.MAC 1453 256 deflated
README1.DOC 1369 262 deflated
SETREGS.EXE 8693 3979 deflated
SRCHTBL.OBJ 348 300 deflated
SUBTEMP1.ASM 3260 788 deflated
SUBTEMP2.ASM 2529 630 deflated
TASM.DOC 4291 1192 deflated
TEMP1.ASM 1108 339 deflated
TEMP2.ASM 2414 611 deflated
TEMPLATE.ASM 2957 679 deflated
TPCREAD.ME 199 165 deflated
TRANSTBL.OBJ 340 119 deflated
TWOTALE.DOC 5872 2723 deflated
TWOTALE.OBJ 5985 2881 deflated

Download File ASMTUT1.ZIP Here

Contents of the A86.DOC file



This is intended as a guide to get A86 to work for all the
programs in the Tutor. It only covers things that won't work or
things A86 does differently. It does not cover any of the
benign options like local labels.

===== CHAPTER 1

You need to take your text editor and change the last line of the
template files. At the moment they read:

END start

You may either eliminate the line or change it to:

END main

If you don't, you will get this error message:

END start~40 Conflicting Multiple Definition Not Allowed~

Do this for all the original template files, because this line
will always cause an error. You will find out why when you get to
Chapter 10.

You should also insert the word PUBLIC just before the line with
ASSUME. Do this in all the template files.


You will find out why in Chapter 15.

A86 has some unusual defaults, so you need to change them when
you assemble a file. If your file is named myprog.asm, the
command line you want to use for the rest of this tutorial is:

>a86 +DOSX myprog.asm

You must use the file extension .asm when you call the program.
You can make a batch file (let's call it QASM.BAT) which has:

a86 +DOSX %1.asm

Then all you need to do is:

>qasm myprog

Those four options on the command line are:


The PC Assembler Tutor - Copyright (C) 1990 Chuck Nelson

The PC Assembler Tutor 2

+D numbers with leading 0s are default decimal
+O make an object file
+S don't create an ancillary symbol table
+X require specific declaration of external information

They should be used from now on. When you are through with all
the chapters, you can decide whether you want to continue using
them all. If you are using D86, you need to eliminate the 'S'.
The declaration should be +DOX since you will need the symbol

===== CHAPTER 2

Please read all of chapter 2 before you read these comments.

The defaults and definitions are the same with two exceptions.
First, any number that begins with a '0' is hex by default. That
is, 22 is a decimal number and 022 is a hex number. This has some
serious side effects. Take the number:


This is 847, right? No. It is 0847Dh = 34,637. In Chapter 7 we
will use these binary numbers:


These should be 75 and 4 respectively, but A86 evaluates them as
01001011Bh = 268500992 and 0100Bh = 4107. Since half of the
binary numbers you use will start with a 0, half of your binary
numbers will be wildly incorrect. In order to correct the
situation, you need to put a +D on the command line. This is the
'D' of +DOSX. The D will insure that all numbers starting with 0
will be decimal. This gets rid of all the side effects.
Alternatively, you can put:


at the top of your files before any of the code or data. This has
the same effect. Of course, if you really do want hex numbers,
this can be overridden with a specific 'h' after any number.

There is another major problem with data definitions. Let's say
that you want the following definitions:

weight dw ?
cost dw 20
profit dw ?

but you forget to put in some of the initializations in your text
file (a situation which is not unknown):

weight dw

Using A86 3

cost dw
profit dw ?

All other assemblers will generate an error. You must either put
in an initial value or you must say that you want no initial
value (by putting in a question mark). Not only does A86 not
generate an error, it does something strange. If there is neither
initialization nor a question mark, A86 will calculate an address
for the variable but WILL ALLOCATE NO SPACE FOR IT. What this
means is that in our above example, 'weight', 'cost', and
'profit' will all be at the same memory address. 'Weight' and
'cost' will have the same address with no space allocation.
'Profit' will be at the same memory address too, but will have
space allocated for it.

This is all done silently, so you don't know that this is being
done. There is no way to shut this off. You might be able to find
that this is happening by looking at the symbol table, but that
means that you suspect that it is happening. What you need to
do whenever you use A86 is:


===== CHAPTER 10

We now come to some actual differences. A86 does not produce a
list file. You can read the justification for this in your
documentation. Does this make a difference? It would be nice to
have one, but we can normally live without it. Just follow what
is happening with the MASM listing.

p94 - ASSUME statements. Both TASM and MASM keep track of how you
want the segments to be referenced. A86 doesn't. It simply
ignores any ASSUME statements. This means that any segment
overrides must be coded into the text file with:

mov cx, ss:variable4
mov cx, es:variable2
mov cx, ds:variable1
mov cx, cs:variable3

A86 assumes that all code uses CS (which it must), and that all
data uses DS unless there is a specific segment override. Is this
a big imposition? Not really. If you use a segment register other
than DS, it is normally for dealing with arrays, and in those
cases you need a segment override anyways. You will find out
about that in the next chapter.

p97 - END statements. END is not necessary in A86. It knows that
the end has come when the file is finished. The default starting
point for an A86 file is the label 'main'. If A86 sees a label
name after an END statement, then it RENAMES that word 'main',
and renames all occurances of that word in the file 'main'. It
does not change the default starting name. This means that if you

The PC Assembler Tutor 4

have a statement like:

END start

and you also have the label 'main' in your file, A86 will change
all occurances of 'start' to 'main', causing multiple use of the
same label.

======== Chapter 15

p154 - You do not need PUSHREGS and POPREGS. With A86, PUSH is
exactly the macro PUSHREGS:

PUSHREGS ax, bx, cx, dx, si
PUSH ax, bx, cx, dx, si

These are exactly the same. POP shows the actual order that
things will be popped, while POPREGS has the reverse order so
that you can use a word processor to copy the PUSHREGS part. For
the above PUSH declaration, this is the correct POP:

POP si, dx, cx, bx, ax
POPREGS ax, bx, cx, dx, si

From now on, whenever you see PUSHREGS, change it to PUSH, and
whenever you see POPREGS, change it to POP but reverse the order
of registers so that it is the actual order in which things are
POPped. You can delete the line:

include \pushregs.mac

from your template file.

; - - - - - - - - - -

Please read the whole chapter before reading the rest of these

For some reason, A86 makes ALL normal variables and labels PUBLIC
unless you specifically tell it not to. The whole thrust of
programming for the last 20 years (PASCAL, C, and all structured
languages), has been to make NOTHING public unless specifically
requested, so this is an unwelcome default setting. You turn it
off by naming any normal (but not local) variable PUBLIC. In
fact, if you use the word PUBLIC alone:


without any name after it, A86 will turn this off. That is why
you put it in all the template files. Always have this in all
your assembler files.

A86 also assumes that any variable that has no data declaration
is EXTRN. This is a bad policy. What will happen is the
following. You are using the variable 'last_occurance' and you

Using A86 5

misspell it 'last_ocurrance'. A86 sees no data declaration so
assumes that it is an external variable and assembles the file.
Three hours later you link the 6 modules of your program together
and you get a link error. The linker cannot find 'last_ocurrance'

Just as you should need to explicitly name things PUBLIC, you
should need to explicitly name things EXTRN. You do this by
putting +X (forced external declarations) on the command line.
This is the 'X' in the '+DOSX' that you have been using on the
command line.

===== CHAPTER 21

You need to change the ORG statement so it is in front of main

ORG 100h
main proc near

This is because you are using main as the starting address, so it
must be at 100h. This 100h is optional with A86. If it is making
a .COM file it automatically starts at 100h. A86 is designed to
give you a .COM file directly, so all you need to do with a
single file is:

>a86 +DS myfile.asm

and you will get MYFILE.COM as the output file. In the example
where we make a .COM file from multiple files, these files are
set up to be .OBJ files. If you want to make them into a .COM
file directly, you need to take out all PUBLIC, EXTRN and END
statements (and adjust PUSHREGS and POPREGS) and then do:

>a86 +DS prog1.asm prog2.asm prog3.asm

making sure that prog1.asm is first. The output file should be

===== CHAPTER 26

You need to read all of Chapter 26 before reading any of the

A86 will work fine with any standard segment definitions. It also
has two special segment statements of its own. The first:


will generate the following:


The second statement:


The PC Assembler Tutor 6

is NOT a segment declaration. It generates NO segment, it
allocates NO space and it initializes NO data. What is it? I'll
explain how it operates, but I have no idea why it exists.

The first time you use the 'DATA SEGMENT' instruction in a file
it is followed by ORG:

ORG 1000h

ORG relocates the counter for where the assembler is allocating
space in memory. From this point on, every time you define

time dw ?
distance dw ?
space dw ?

A86 generates an distinct address for each variable. However, it
ALLOCATES NO SPACE. This is just an address that the code can use
when it refers to the variables. If you have the following

year dw 1990
prime dw 73
cost dw 5167

A86 will generate address for these variables but (1) will
allocate NO space, (2) will do NOTHING with those initializing
values and (3) WILL NOT COMPLAIN that you have tried using
initialized data in a DATA SEGMENT statement. A86 will do the
equivalent of:

year dw ?
prime dw ?
cost dw ?

This data is technically in the CODE SEGMENT. If the code is
longer than that initial ORG number, some of the code will be in
the same place as some of the data and if you write to the data
you will overwrite the code. A86 will not complain.

For instance, we had ORG 1000h (4096d). If the code is 6000 bytes
long, the last 2000 bytes of code will share the space with the
data. This leads to either bad data or bad code or both.

Why have this? Well, when DOS loads a .COM file into memory, it
uses ALL of memory. If I have:

INTSCRN.COM 541 07/23/90 17:45

a .COM file that is 541 bytes long, DOS will allocate about
550,000 bytes for it on my computer. 549,459 bytes of this are
wasted space. It is A86's idea to put data in this wasted space.
There is no reason for this, so don't do it. If you have a .COM
file, put all your data in the CODE SEGMENT. If you have an .OBJ

Using A86 7

file you need to create a legitimate SEGMENT for the DATA. Its
name cannot be:


If I have the following program:

; - - - - - - - - - - - - - - -
data1 db "This is the output string", 13, 10, "$"
data2 db 100 dup (0)


mov ax, seg DATA
mov ds, ax

mov ah, 09h ; print string
lea dx, data1
int 21h

mov ax, 4C00h ; exit
int 21h
; - - - - - - - - - - - - - - -

and I try to make an object file with it, I get the following

mov ax, seg DATA~61 Overlapping Local Not Allowed~

The ability to put the segment starting address in the segment
register is a minimal requirement for doing anything. This
effectively eliminates the possibility of using DATA as the name
for a segment. Therefore, those of you who use Turbo Pascal need
to use:


as an alternative. This will work with no problems.

 December 8, 2017  Add comments

Leave a Reply