Turbo_Assembler_Version_2.0_Users_Guide_1990 Turbo Assembler Version 2.0 Users Guide 1990

Turbo_Assembler_Version_2.0_Users_Guide_1990 Turbo_Assembler_Version_2.0_Users_Guide_1990

User Manual: Turbo_Assembler_Version_2.0_Users_Guide_1990

Open the PDF directly: View PDF PDF.
Page Count: 518

DownloadTurbo_Assembler_Version_2.0_Users_Guide_1990 Turbo Assembler Version 2.0 Users Guide 1990
Open PDF In BrowserView PDF
T RB
A E BLER

BORLAND
,

Turbo AssemblefID
Version 2.0

User's Guide

BORLAND INTERNATIONAL. INC. 1800 GREEN HILLS ROAD
P.O. BOX 660001, scons VALLEY, CA 95066-0001

Copyright © 1988, 1990 by Borland International. All rights
reserved. All Borland products are trademarks or registered
trademarks of Borland International, Inc. Other brand and
product names are trademarks or registered trademarks of their
respective holders.

PRINTED IN THE USA.

Rl

10 9 8 7 6 5 4 3 2

c

o

N

T

Introduction
1
Hardware and software requirements .... 2
About the manuals .................... 2
The User's Guide .................. 2
Notational conventions ................. 3
How to contact Borland ................ 4
Chapter 1 Installing Turbo
Assembler

7

Chapter 2 Getting started with Turbo"
Assembler
9

Chapter 3 Command-line
reference

N

T

ll
11
13
14
14

15
17
18
19

21
Starting Turbo Assembler from DOS .... 21
Command-line options ................ 24
la .................................. 25
Ib .................................. 25
Ic .................................. 26
Id ..... ............................. 26
Ie ............... "................... 27
Ih or I? ................ '............. 27

s

Ii ...................... "............ 28
Ij ..•...•••••..•......... ."........... 29

Ikh ................... ~ .. ~ ..........
Iks ............ "....................

II ..................................
Ila .................................

1m .................................

Files on disk .......................... 7
Installing Turbo Assembler ............. 8

Writing your first Turbo Assembler
program .............................
Assembling your first program .......
L'm k'mg your fir st program ...........
Running your first program ..........
What happened? ...................
Modifying your first Turbo Assembler
program ........................... '..
Sending output to a printer ..........
Writing your second Turbo Assembler
program .. "...........................
Running REVERSE.ASM ............

E

Iml .................................
Imu ................................
Imv# ...............................

29
30
30
30
31
31
32
32
32

Irnx. ................................
In .................................. 33
Ip .................................. 33
Iq .................................. 34
Ir .................................. 34
Is .................................. 35
It ............................... ~ .. 35
Iv .................................. 35

Iw .................................
Ix ..................................
Iz ..................................
Izd .................................
Izi .................................

36
37
37
38
38

Indirect command files ................ 39
The configuration file ................. 39

Chapter 4 The nature of assembly
language
41
The architecture of a computer ......... 41
The making of assembly language .... 43
The 8088 and 8086 processors .......... 46
The capabilities of the 8086 ........... 47
Memory ........................... 47
Input and output ................... 50
Registers .......................... 51
The flags register ................. 52

The general-purpose registers ...... 54
The AX register ................ 54
The BX register ................. 55
The CX register ................. 55
The DX register ................ 56
The SI register .................. 56
. The DI register ................. 57
The BP register ................. 58
The SP register ................. 59
The instruction pointer ............ 61
The segment registers ............. 61
The CS register ................. 65
The DS register ................. 66
The ES register ................. 66
The SS register ................. 66
The 8086 instruction set ............. 67
The IBM PC and XT ................... 67
Input and output devices ............ 68
Systems software for the IBM PC ..... 68
DOS ............................ 69
Getting keystrokes .............. 70
Displaying characters on the
screen ......................... 71
Ending a program .............. 72
The BIOS ........................ 73
Selecting display modes ......... 73
Sometimes you absolutely need to go to
the hard ware ...................... 74
Other resources .................... 74

Memory-addressing modes ........ 93
Comments ........................ 101
Segment directives ................... 103
Simplified segment directives ....... 104
.STACK, .CODE,and .DATA ...... 104
DOSSEG ....................... 108
.MODEL ....................... 108
Other simplified segment
directives . . . . . . . . . . . . . . . . . . . . . . . 110
Standard segment directives ........ 111
The SEGMENT directive ......... 112
The ENDS directive .............. 112
The ASSUME directive ........... 112
Simplified versus standard segment
directives . . . . . . . . . . . . . . . . . . . . . . . .. 115
Alloca ting data . . . . . . . . . . . . . . . . . . . . . . 116
Bits, bytes, and bases ............... 116
Decimal, binary, octal, and hexadecimal
notation ........................ 119
Default radix selection ........... 123
Initialized data .................... 125
Initializing arrays ................ 125
Initializing character strings ....... 126
Initializing with expressions and
labels .......................... 128
Uninitialized data ................. 129
Named memory locations .......... 130
Moving data ........................ 132
Selecting data size ................. 133
Signed versus unsigned data ........ 135
Converting between data sizes ...... 136
Accessing segment registers ..... ~ ... 138
Moving data to and from the stack ... 139
Exchanging data ................... 139
I/O .............................. 140
Operations ......................... 141
Arithmetic operations . . . . . . . . . . . . . . 141
Addition and subtraction ......... 142
32-bit operands ................ 142
Incrementing and decrementing . 144
Multiplication and division ....... 145
Changing sign .................. 147
Logicaloperations ................. 148
Shifts and rotates .................. 150

Chapter 5 The elements of an
assembler program

77
The components and structure of an
assembler program ................... 78
Reserved words ...................... 79
The format of a line ................... 81
Labels ............................. 82
Instruction mnemonics and directives. 85
The END directive ................ 86
Operands .......................... 88
Register operands ................ 89
Constant operands ................ 90
Expressions ...................... 91
Label operands ................... 92

II

Loops and jumps ....................
Unconditional jumps ...............
Conditional jumps .................
Looping ..........................
Subroutines .........................
How subroutines work .............
Parameter passing .................
Returning values .... _..............
Preserving registers ................
An example assembly language
program ............................

153
154
156
158
161
162
166
166
167

%LIST and %NOLIST .......... 211
%CONDS and %NOCONDS .... 211
%INCL and %NOINCL ........ 212
%MACS and %NOMACS ....... 212
%CTLS and %NOCTLS ......... 212
&UREF and %NOUREF ........ 213
%SYMS and %NOSYMS ........ 213
The listing format control
directives ....................... 213
Field-width directives .......... 214
%PUSHLCTL and %POPLCTL .. 215
Other listing control directives .... 215
Displaying a message during assembly . 215
Assembling source code conditionally .. 216
Conditional assembly directives ..... 217
IF and IFE ...................... 217
IFDEF and IFNDEF .............. 218
Other conditional assembly
directives ....................... 220
ELSEIF family of directives ....... 222
Conditional error directives ......... 223
.ERR, .ERR1, and .ERR2 .......... 223
.ERRE and .ERRNZ .............. 224
.ERRDEF and .ERRNDEF ......... 224
Other conditional error directives .. 225
Pitfalls in assembler programming ..... 225
Forgetting to return to DOS ......... 226
Forgetting a RET instruction ......... 227
Generating the wrong type of return . 228
Reversing operands ................ 230
Forgetting the stack or reserving a too
small stack ........................ 230
Calling a subroutine that wipes out
needed registers ................... 231
Using the wrong sense for a conditional
jump ............................. 234
Pitfalls with string instructions ...... 235
Forgetting about REP string
overrun ........................ 235
Relying on a zero CX to cover a whole
segment ....................... ~. 237
Using incorrect direction flag
settings ........................ 239

168

Chapter 6 More about programming
173
in Turbo Assembler
Using equate substitutions ............ 174
The EQU directive ................. 174
The $ predefined symbol ......... 178
The = directive .................... 179
The string instructions ....... " ....... 180
Data movement string instructions ... 181
LODS .......................... 181
STOS .......................... 182
MOVS ......................... 183
Repeating a string instruction ..... 184
String pointer overrun ........... 185
Data scanning string instructions .... 185
SCAS .......................... 185
CMPS .......................... 188
Using operands with string
instructions ....................... 189
Multimodule programs ............... 190
The PUBLIC directive .............. 193
The EXTRN directive ............... 194
The GLOBAL directive ............. 197
Include files . . . . . . . . . . . . . . . . . . . . . . . .. 198
The listing file ....................... 200
Annotated source code ............. 201
Listing symbol tables ............... 205
The table of labels ............... 205
The table of groups and segments .. 206
The cross-reference table ............ 207
Controlling the listing contents and
format ........................... 210
The line-listing selection directives . 210

iii

An example of inline assembly ...... 270
Limitations of inline assembly ....... 274
Memory and address operand
limitations ...................... 274
Lack of default automatic variable
sizing in inline assembly .......... 276
The need to preserve registers ..... 277
Preserving calling functions and
register variables .............. 277
Suppressing internal register
variables ..................... 277
Disadvantages of inline assembly versus
pureC ........................... 277
Reduced portability and
maintainability .................. 278
Slower compilation .............. 278
Available with TCC only ......... 278
Optimization loss ................ 278
Error trace-back limitations ....... 279
Debugging limitations ........... 280
Develop in C and compile the final code
with inline assembly ............. 280
Calling Turbo Assembler functions from
Turbo C ............................ 281
The framework .................... 282
Memory models and segments .... 282
Simplified segment directives and
TurboC ...................... 283
Old-style segment directives and
TurboC ...................... 285
Segment defaults: When is it
necessary to load segments? ..... 287
Publics and externals ............. 290
Underscores .................. 290
The significance of uppercase and
lowercase ..................... 291
Label types ................... 292
Far externals .. : ............... 293
Linker command line ............ 294
Between Turbo Assembler and Turbo
C ................................ 295
Parameter-passing ............... 295
Preserving registers .............. 302
. Returning values ................ 302

Using the wrong sense for a t:epeated
string comparison ............... 239
Forgetting about string segment
defaults ........................ 240
Converting incorrectly from byte to
word operations ................. 241
Using multiple prefixes ........... 242
Relying on the operand(s) to a string
instruction ...................... 242
Forgetting about unusual side effects . 243
Wiping out a register with
multiplication ................... 244
Forgetting that string instructions alter
several registers ................. 245
Expecting certain instructions to alter
the carry flag .................... 245
Waiting too long to use flags ...... 246
Confusing memory and immediate
operands ......................... 246
Causing segment wraparound ....... 249
Failing to preserve everything in an
interrupt handler .................. 251
Forgetting group overrides in operands
and data tables .................... 252

Chapter 7 Interfacing Turbo
Assembler with Turbo

C
257
Using inline assembly in Turbo C ...... 258
How inline assembly works ......... 260
How Turbo C knows to use inline
assembly mode .................. 264
Invoking Turbo Assembler for inline
assembly ....................... 265
Where Turbo C assembles inline
assembly ....................... 266
Use the -1 switch for 80186/80286
instructions ..................... 267
The format of inline assembly
statements ........................ 268
Semicolons in inline assembly ..... 268
Comments in inline assembly ..... 268
Accessing structure/union
elements ....................... 269

iv

Stack maintenance ................. 328
Accessing parameters .............. 328
Using BP to address the stack ..... 328
The ARG directive ............. 329
.MODEL and Turbo Pascal ........ 330
Using another base or index
register ......................... 331
Function results in Turbo Pascal ....... 331
Scalar function results ............ 331
Real function results ............. 332
8087 function results ............. 332
String function restilts ............ 332
Pointer function results ......... 332
Allocating space for local data ......... 332
Allocating private static storage .. '... 332
Allocating volatile storage .......... 333
Assembly language routines for Turbo
Pascal .............................. 334
General-purpose hex conversion
routine . . . . . . . . . . . . . . . . . . . . . . . . . . . 334
Exchanging two variables ........... 337
Scanning the DOS environment ..... 340

Calling an assembler function from
C ................................ 304
Pascal calling conventions .......... 307
Calling Turbo C from Turbo Assembler. 308
Link in the C startup code .......... 308
Make sure you've got the right segment
setup ............................ 309
Performing the call ................ 309
Calling a Turbo C function from Turbo
Assembler ........................ 311

Chapter 8 Interfacing Turbo
Assembler with Turbo
Pascal
315
The Turbo Pascal memory map ........ 315
The program segment prefix ........ 316
Code segments .................... 317
The global data segment ............ 317
The stack ......................... 317
The heap ......................... 318
Register use in Turbo Pascal .......... 318
Near or far? ......................... 319
Sharing information with Turbo Pascal . 319
The $1 compiler directive and external
subprograms ...................... 319
The PUBLIC directive .............. 320
The EXTRN directive ............... 321
Restrictions on using EXTRN
objects ......................... 323
Using segment fixups .............. 324
Dead code elimination ............. 325
Turbo Pascal parameter-passing
conventions ......................... 325
Value parameters .................. 325
Scalar types ..................... 326
Reals ........................... 326
Single, Double, Extended, and Comp:
The 8087 types .................. 326
Poin ters ........................ 326
Strings ......................... 327
Records and arrays .............. 327
Sets ............................ 327
Variable parameters ............... 327

Chapter 9 Advanced programming In
Turbo Assembler
345
Segment override prefixes ............ 345
An alternate form .................. 347
When segment override prefixes don't
work ................ 000 .......... 348
Accessing multiple segments ....... 0349
Locallabels ............ 0.... 0... 0. 00 349
Automatic jump-sizing .. 0.. 0. 0....... 353
Forward references to code and data 00. 358
Using repeat blocks and macros . 0. 0. 00362
Repeat blocks ................. 0.. 0 362
Repeat blocks and variable
parameters ...... 0. 0..... 00... 00 364
Macros 0..... 000.00.0000 ... 0.... 0.365
Nestingmacros 00000 ... 00.0 .. 0.0369
Macros and conditionals 0...... 00. 369
Stopping expansion with EXITM 00371
Defining labels within macros ..... 371
Fancy data structures .0.0 .. 00 .. 0.... 0373
The STRUC directive .. 0.......... 0. 374

v

Advantages and disadvantages of using
STRUC ......................... 377
Unique structure field names .... 378
Nesting structures ............. 378
Initializing structures .......... 379
The RECORD directive ............. 380
Accessing records ............... 382
The WIDTH operator .......... 383
The MASK operator ............ 384
.Why use records ................. 385
The UNION directive .............. 387
Segment directives ................... 389
The SEGMENT directive ........... 389
The name and align fields ......... 390
The combine field ................ 390
The use and class fields ........... 392
Segment size, type, name, and
nesting ......................... 392
Segment-ordering ................. 393
The GROUP directive .............. 395
The ASSUME directive ............. 397
The simplified segment directives .... 400
A multisegment program ........... 404

New segment types ................ 420
Simplified segment directives and
80386 segment types ............. 423
The FWORD 48-bit data type ...... 424
New registers ..................... 425
The 32-bit general-purpose
registers ........................ 426
The 32-bit flags register ........... 428
The 32-bit instruction pointer ..... 428
New segment registers ........... 429
New addressing modes ............ 431
New instructions .................. 434
Testing bits ..................... 435
Scanning bits .................... 436
Moving data with sign- or zeroextension ....................... 437
Converting to DWORD or QWORD
data ........................... 437
Shifting across multiple words .... 438
Setting bytes conditionally ........ 439
Loading SS, FS, and GS ........... 440
Extended instructions .............. 441
Special versions of MOV .......... 441
32-bit versions of 8086 instructions . 442
New versions of LOOP and
JCXZ .......................... 442
New versions of the string
instructions ................... 444
IRETD ....................... 444
PUSHFD and POPFD .......... 445
PUSHAD and POPAD ......... 445
New versions ofIMUL ........... 445
Mixing 16-bit and 32-bit instructions and
segments .......................... 446
An example 80386 function ......... 449
The 80287 .......................... 453
The 80387 .......................... 453

Chapter 10 The 80386 and other
processors

409
Switching processor types in assembler
code ............................... 410
The 80186 and 80188 ................. 411
New instructions .................. 411
PUSHAandPOPA .............. 411
ENTER and LEAVE .............. 412
BOUND ........................ 413
INSandOUTS .................. 414
Extended 8086 instructions .......... 415
Pushing immediate values ........ 415
Shifting and rotating by immediate
values .... ; ..................... 416
Multiplying by an immediate
value .......................... 416
The80286 .......................... 417
Enabling 80286 assembly ........... 418
The80386 .......................... 419
Selecting 80386 assembly mode ...... 419

Chapter 11 Turbo Assembler Ideal
Mode
455
What is Ideal mode? ................. 456
Why use Ideal mode? ................ 456
Entering and leaving Ideal mode ...... 457
MASM and Ideal mode differences .... 458

vi

Quoted strings as arguments to
directives ....................... 469
Segments and groups .............. 470
Accessing data in a segment belonging
to a group ...................... 470
Defining near or far code labels ...... 472
External, public, and global symbols .473
Miscellaneous differences ........... 474
Suppressed fixups ............... 474
Operand for BOUND instruction .. 474
Comments inside macros ......... 475
Local symbols ................... 475
A comparison of MASM and Ideal mode
programming ....................... 475
MASM mode sample program .. 476
Ideal mode sample program .... 477
An analysis of MASM And Ideal
modes ........................... 479

Ideal mode tokens ................. 459
Syr,nboltokens .................. 459
Duplicate member names ......... 460
Floating-point tokens ............ 460
EQU and =directives .............. 461
Expressions and operands .......... 461
Square brackets operator ......... 461
Example operands ............... 462
Operators ........................ 464
Periods in structure members ..... 464
Pointers to structures ............. 464
The SYM1YPE operator .......... 465
The HIGH and LOW operators .... 465
The Optional PlR operator ....... 466
The SIZE operator ............... 466
Directives ........................ 467
Listing controls .................. 467
Directives starting with a period (.) . 468
Reversed directive and symbol
name .......................... 469

vii

References

483

Index

485

T

A

L

B

5.1: TASM reserved words ............. 80
5.2: The operation of the 8086 AND, OR, and
XOR logical instructions .......... 148
5.3: Conditional jump instructions ..... 157
6.1: Source and destination for the MUL and
IMUL instructions ................ 244
7.1: Register settings when Turbo Centers
assembler ....................... 287
9.1: Default segments and types for tiny
memory model .................. 401

E

s

9.2: Default segments and types for small
memory model .................. 401
9.3: Default segments and types for medium
memory model .................. 401
9.4: Default segments and types for compact
memory model .................. 401
9.5: Default segments and types for large or
huge memory model ............. 402
9.6: Default segments and types for Turbo
Pascal (TPASCAL) memory model . 402

viii

F

G

u

2.1: The edit, assemble, link, and run
cycle ............................. 12
3.1: Turbo Assembler command line ..... 22
4.1: Five subsystems ................... 42
4.2: Memory address space of the 8086 ... 48
4.3: Separate memory and I/O address of
8086 ............................. 50
4.4: Registers of the 8086 ............... 52
4.5: Flags register of the 8086 ........... 53
4.6: AX, BX, SP, and the stack ........... 60
4.7: 20-bit memory addresses ........... 62
4.8: Calculation of memory address by
mov ............................. 63
4.9: DOS and BIOS systems software as a
control and interface layer .......... 69
5.1: The memory location of the character
string CharString .................. 94
5.2: Addressing the character string
CharString ....................... 95
5.3: Using BX to address CharString ..... 96
5.4: Storing WordVar and DwordVar.... 119
5.5: From binary 001100100 (decimal 1(0) to
octal 1440 ....................... 121
5.6: From binary 01100100 (decimal 100) to
hexadecimal64 .................. 121
5.7: Example of five-entry array ........ 126
5.8: Example of a shift left ............. 150
5.9: Example of SAR (arithmetic right
shift) ........................... 151

R

E

s

5.10: Example of ROR (rotate right) ..... 152
5.11: Example ofRCR (rotate right and
carry) .......................... 153
5.12: Operation of a subroutine ........ 162
6.1: Memory variables: offset vs. value .. 247
6.2: An example of segment
wraparound ..................... 250
6.3: Three segments grouped into one
segment group .................. 252
7.1: Turbo C compile and link cycle .... 260
7.2: Turbo C compile, assembly, and link
cycle ........................... 262
7.3: Compile, assemble, and link with Turbo
C, Turbo Assembler, and TLINK ... 281
7.4: State of the stack just before executing
Test's first instruction ............. 296
7.5: State of the stack after PUSH and
MOV ........................... 297
7.6: State of the stack after PUSH, MOV, and
SUB ............................ 298
7.7: State of the stack immediately after
MOV BP, SP ..................... 308
·8.1: Memory map of a Turbo Pascal 5.0
program ........................ 316
9.1: Locations and initial values of the fields
in 1Rec ......................... 381
10.1: The registers of the 80386 ......... 426

Ix

N

T

o

R

D

u

c

T

o

N

Welcome to Borland's Turbo Assembler, a multi-pass assembler
with forward-reference resolution, assembly speeds of up to
48,000 lines per minute (on an IBM PS/2 model 60), MASM
compatibility, and an optional Ideal mode extended syntax.
Whether you're a novice or an experienced programmer, you'll
appreciate these features along with a number of others we've
provided to make programming in assembly language easier.
We'll mention just a few of the highlights here and describe them
in detailla ter in the book:
•
•
•
•
•
•

full 80386 support
improved syntax type-checking
simplified segmentation directives
improved listing controls
PUSH, POP extensions
extended CALL statement with arguments and optional
language parameter

• local labels
!!! local stack symbols and calling arguments in procedures
• structures and unions
• nested directives
• Quirks mode to emulate MASM
• full source debugging output for Turbo Debugger
• built-in cross-reference utility (TCREF)
• configura tion and command files
Turbo Assembler is a powerful command-line assembler that
takes your source (.ASM) files and produces object (.OBJ)
modules. You then use TLINK.EXE, Borland's high-speed linker
program, to link your object modules and create executable (.EXE)
files.

Introduction

Turbo Assembler is set up to work with the 80x86 and 80x87
processor families. (For more information about the instruction
sets of the 8Ox86/80x87 families, consult the Intel data books.)

Hardware and software requirements
Turbo Assembler runs on the IBM PC family of computers,
including the XT, AT, and PS/2, along with all true compatibles.
Turbo Assembler requires MS-DOS 2.0 or later, and at least 256K
of memory.
Turbo Assembler generates instructions for the 8086, 80186, 80286,
and 80386 processors. It also generates floating-point instructions
for the 8087, 80287, and 80387 numeric coprocessors.

About the manuals
Turbo Assembler comes with two books and a quick-reference
guide: Turbo Assembler User's Guide (this book), Turbo Assembler
Reference Guide, and Turbo Assembler Quick-Reference Guide. The
User's Guide provides basic instructions for using Turbo
Assembler and a thorough examination of assembler
programming. The Reference Guide describes the operators,
predefined symbols, and directives Turbo Assembler uses. The
Quick Reference is a handy guide to processor and coprocessor
instructions.
Here's a more detailed look at what the User's Guide contains.

The User's Guide

Chapter 1: Installing Turbo Assembler tells you about the files on
your distribution disks and what you need to do to install Turbo
Assembler on your system.
Chapter 2: Getting started In Turbo Assembler provides you with
an introduction to programming in assembly language, and a few
sample programs to make you comfortable using the commandline switches.
Chapter 3: Command-line reference details all the command-line
options, plus tells you about using the configuration file and
command files.

2

Turbo Assembler User's Guide

Chapter 4: The nature of assembly language leads you through a
discussion of computers in general and the 8088 processor in
particular.
Chapter 5: The elements of an assembler program describes the
basic components of assembler, with some good solid information
about directives, instructions, accessing memory, segments, and
more.
Chapter 6: More about programming In Turbo Assembler goes one
step further than Chapter 5, discussing some advanced aspects of
Turbo Assembler-more about directives, string instructions, and
so on. This chapter also covers some common pitfalls you may
encounter as an assembly progralnmer.
Chapter 7: Interfacing Turbo Assembler with Turbo C describes
how to use Turbo C, a high-level language, with assembly
language. We detail how to link assembler modules to Turbo C
and how to call Turbo Assembler functions from Turbo C.
Chapter 8: Interfacing Turbo Assembler with Turbo Pascal tells
you how to interface your assembler code with your Turbo Pascal
code; sample programs are also provided.
Chapter 9: Advanced programming In Turbo Assembler provides
you with more details about everything we've touched on in
earlier chapters, such as segment override prefixes, macros,
segment directives, and so on.
Chapter 10: The 80386 and other processors covers programming

with the 80386.
Chapter 11: Turbo Assembler Ideal mode tells you all about Ideal

mode and why you'll want to use it.
References lists several useful books about assembly

programming.

Notational conventions
When we talk about IBM PCs or compatibles, we're referring to
any computer that uses the 8088, 8086, 80186, 80286, and 80386
chips (all of these chips are commonly referred to as 80x86). When
discussing PC-OOS, DOS, or MS-DOS, we're referring to version
2.0 or greater of the operating system.

Introduction

3

All typefaces were produced by Borland's Sprint: The Professional
Word Processor, output on a PostScript printer. The different
typefaces displayed are used for the following purposes:

Italics

In text, italics represent labels, placeholders,
variables, and arrays. In syntax expressions,
placeholders are set in italics to indicate that they
are user-defined.

Boldface

Boldface is used in text for directives, instructions,
symbols, and operators, as well as for commandline options.

CAPITALS

In text, capital letters are used to represent
instructions, directives, registers, and operators.

Monospace

Monospace type is used to display any sample
code, text or code that appears on your screen, and
any text that you must actually type to assemble,
link, and run a program.

Keycaps

In text, keycaps are used to indicate a key on your
keyboard. It is often used when describing a key
you must press to perform a particular function;
for example, "Press Enter after typing your program
name at the prompt."

How to contact Borland
If, after reading this manual and using Turbo Assembler, you
would like to contact Borland with comments, questions, or
suggestions, we suggest the following procedures:

• The best way is to log on to Borland's forum on CompuServe:
Type GO BPROGB at the main CompuServe menu and follow the
menus to Turbo Assembler. Leave your questions or comments
here for the support staff to process .
• If you prefer, write a letter detailing your problem and send it
to
Technical Support Department
Borland International
P.O. Box 660001
1700 Green Hills Drive
Scotts Valley, CA 95066 U.S.A.

4

Turbo Assembler User's Guide

• You can also telephone our Technical Support department at
(408) 438-5300. To help us handle your problem as quickly as
possible, have these items handy before you call:
•
•
•
•

product name and version number
product serial number
computer make and model number
operating system and version number

If you're not familiar with Borland's No-Nonsense License
statement, now's the time to read the agreement at the front of this
manual and mail in your completed product registration card.

Introduction

5

6

Turbo Assembler User's Guide

c

H

p

A

T

R

E

1
Installing Turbo Assembler
Before we get you up to speed on programming in assembler,
you'll need to get one thing out of the way. Take the Turbo
Assembler disks and make copies (via DOS) of each one to create
your "working" copies. Once you've done that, put the original
disks away. (There's a fee to replace disks that you damage, so
only use the originals to make backups and work copies.)
If you are going to use Turbo Assembler as a replacement for
MASM, read Appendix B in the Reference Manual to see in which
areas Turbo Assembler behaves differently from MASM.
Note: Be sure to read the README file before working with
Turbo Assembler. This file contains the latest information about
the program, as well as corrections and/or additions to the
manuals.

Files on disk
•
•
•
•
•
•

TASM.EXE: Turbo Assembler
TLINK.EXE: Turbo Linker
MAKE.EXE: Command-line MAKE utility
TLIB.EXE: Turbo Librarian
README.COM: Program to display README file
README: Any last minute information about the software and
documentation

Chapter 7, Installing Turbo Assembler

7

•
•
•
•
•
•

TCREF.EXE: A source file cross-reference utility
OBJXREF.COM: Object file cross-reference utility
GREP.COM: Grep utility
TOUCH.COM: A file-update utility
INSTALL.EXE: Installation program
MMACROS.ARC: An archived file of MASM mode macros

Installing Turbo Assembler
The INSTALL disk contains a program called INST ALL.EXE that
will assist you with the installation of Turbo Assembler 1.0. There
are two options for installation:
1. Hard Disk Users: This option allows you to pick the
subdirectories where the files will be loaded.
2. Floppy Disk Users: This option will install the files necessary
to use Turbo Assembler on a two-drive system. Be sure to
have four fonnatted disks ready before you start.
To start the installation, change your current drive to the one that
has the INSTALL program on it and type INSTALL. You will be
given instructions for each prompt in a box at the bottom of the
screen. For example, if you will be installing from drive A, type
INSTALL
Before you install Turbo Assembler, be sure to read the README
file to get further infonnation about this release.
Note: If you will be running INSTALL on a laptop or any other
system that uses an LCD display, you should set your system to
black-and-white mode before running INSTALL. You can do this
from DOS with the following command line:
mode bw80
You can also force INSTALL to come up in black-and-white mode
by using the Ib switch:
INSTALL /b

8

Turbo Assembler User's Guide

c

H

A

p

T

E

R

2

Getting staried with Turbo Assembler
If you've never programmed in assembly language before, this is
the place to begin. You might have heard that assembly language
programming is a black art suited only to hackers and wizards.
Don't believe it! Assembly language is nothing more than a
human form of the language of the computer itself and, as you'd
expect, the computer's own language is highly logical. As you
might also expect, assembly language is very powerful-in fact,
assembly language is the only way to tap the full power of the
Intel80x86 family, the processors at the heart of the IBM PC
family and compatibles.

You can write whole programs in nothing but assembly language
or you can, if you want, mix assembly language into programs
written in Turbo C, Turbo Pascal, Turbo Prolog, Turbo Basic, and
other languages. Either way, with assembly language, you can
write small and blindingly fast programs. As important as speed
is the assembly language code's ability to control every aspect of
your computer's operation, down to the last tick of the system
dock.
In this chapter, we'll introduce you to assembly language and
explore the unique qualities of assembly language programming.
You'll enter and run several working assembly language
programs, both to get a feel for the language and to get used to
working with the assembler.
Chapter 5, "The elements of an assembler program," picks up
where this chapter leaves off, covering the structure of ~n

Chapter 2, Getting started with Turbo Assembler

9

assembly language program and fundamental program elements
and summing up everything you've learned with a full-fledged
example program.
Chapter 6, "More about programming in Turbo Assembler,"
continues to explore assembly language programming, and
Chapter 9, "Advanced programming in Turbo Assembler,"
progresses to memory models, macros, and other advanced
topics.
Naturally, we can't make you expert assembly language
programmers in the course of a few chapters; we're simply
introducing you to assembly language and getting you started on
the road to writing your own programs. We strongly suggest that
you get one of the many excellent books devoted entirely to
assembly language programming and PC architecture (see the
references at the end of this book). In addition, you may find
IBM's DOS Technical Reference, BIOS Interface Technical Reference,
and Personal Computer XT Technical Reference manuals to be useful
reference material; these manuals document the assembly
language programming interface to the systems software and
hardware of IBM's personal computers.
Before you read further, you might want to read Chapter 3,
"Command-line reference," to familiarize yourself with the
command-line options. You should also install Turbo Assembler
(make working copies of your Turbo Assembler disks or copy the
files from your Turbo Assembler disks onto your hard disk) as
described in Chapter 1, ''Installing Turbo Assembler," if you
haven't already done so.
One final point: Assembly language is a complex topic, and there
are many things you will need to know in order to write even a
relatively simple assembly language program. Sometimes we'll
have to use features in our examples that we haven't discussed
yet, simply because we have to start somewhere. Bear with us; we'll
explain everything in due course. If, at any time, you're curious
about a specific feature, just look in Chapter 3, "Directives," in the

Reference Guide.
With that out of the way, and with Chapter 3 of the second
volume close at hand, it's time to create your first assembly
language program.
You can follow this tutorial step by step, typing in all the code
examples as you go, or you can unpack the example file on disk
(when you install Turbo Assembler) and have all the programs at

10

Turbo Assembler User's Guide

your fingertips. (Whatever your decision, the file names are
provided at the beginning of each example for your convenience.

Writing your first Turbo Assembler program
In the world of programming, the first program is traditionally a
program that displays the message, "Hello, world" and that's as
good a place as any for us to start.
Get into your text editor of choice (one that outputs ASCII files),
and type in the following lines that make up the program
HELLO.ASM:
.MODEL small
.STACK 100h
•DATA
HelloMessage DB 'Hello, world' ,13,10,'$'
.CODE
mov ax,@data
mov ds,ax
iset OS to point to the data segment
mov ah,9
iDOS print string function
mov dx,OFFSET HelloMessage ipoint to "Hello, world"
int 21h
idisplay "Hello, world"
mov ah,4ch
iDOS terminate program function
int 21h
iterminate the program
END

As soon as you've entered HELLO.ASM, save it to disk.
If you're familiar with C or Pascal, you might be thinking that the
assembler version of "Hello, world" seems a bit long. Well, yes,
assembler programs do tend to be long because each assembler
instruction by itself does less than a C or Pascal instruction. On
the other hand, you've got complete freedom in combining those
assembler instructions in any way you want. That means that,
unlike C and Pascal, assembler lets you program the computer to
do anything it's capable of-and that's often worth typing a few
extra lines.

Assembling your
first program

Now that you've saved HELLO.ASM, you'll want to run it. Before
you can run the program, though, you'll have to convert it into an
executable (able to be run or executed) form. This requires two
additional steps, assembling and linking, as shown in Figure 2.1,

Chapter 2, Getting started with Turbo Assembler

11

which depicts the complete edit, assemble, link, and run program
development cycle.
Figure 2.1
The edit, assemble, link, and
run cycle

Create a New Program

Assembler Source File
HELLO.ASM

Assemble

!
Object File
HELLO.OBJ

I
l

Link

Executable File
HELLO.EXE

I

Run

!

(If changes are needed)

~

The assembly step turns your source code into an intermediate
form called an object module, and the linking step combines one or

12

Turbo Assembler User's Guide

more object modules into an executable program. You can do
your assembling and linking from the command line.
To assemble HELLO.ASM, type
TASM hello

Unless you specify another file name, HELLO.ASM will be
assembled to HELLO.OBJ. (Note that you don't need to type in
the file extension name; Turbo Assembler assumes .ASM in this
case.) This is what you'll see onscreen:
Turbo Assembler Version 2.0 Copyright (c) 1988, 1990 by Borland
International, Inc.
Assembling file:
Error messages:
Warning messages:
Passes: 1
Remaining memory:

HELLO.ASM
None
None
266K

You won't receive any warnings or errors if you typed
HELLO.ASM exactly as shown. If you get warnings or errors,
they'll appear onscreen, along with the line numbers to indicate
where they occurred. If you get errors, check your code and make
sure it's precisely the same as the code we've shown you, then
assemble the program again.

Linking your first
program

After you've successfully assembled HELLO.ASM, you're only
one step away from running your first assembler program. Once
you've linked the just-assembled object code into an executable
form, you can run the program.
To link the program, you'll use TLINK, the linker accompanying
Turbo Assembler. At the command line, type
TLINK hello

Again, there's no need to enter the extension name; TLINK
assumes it's .OBJ. When linking completes (again, after a few
seconds at most), the linker automatically gives the .EXE file the
same name as your object file, unless you've specified otherwise.
When linking is successful, this message appears onscreen:
Turbo Link Version 3.0 Copyright (c) 1987, 1990 by Borland
International, Inc.

Chapter 2, Getting started with Turbo Assembler

13

Errors can occur during the linking process, although that's
unlikely with this example program. If you do receive any link
errors (they'll appear onscreen), modify your code to exactly
rna tch the code shown here, then assemble and link again.

Running your first
program

Now you're ready to run your program. Type hello at the DOS
prompt. The message
Hello, world

will be displayed onscreen. And that's all there is to it-you've
just created and run your first Turbo Assembler program!

What happened?
Now that you've gotten HELLO.ASM up and running, let's go
back and figure out exactly what happened along the path from
entering text to running the program.
When you first entered the assembler source code, the text was
stored by your text editor in memory. If the computer had been
turned off at this point, for whatever reason, the source code
would have been lost; consequently, we suggest you save your
source code early and often in order to avert possible tragedy.
When you saved the source code to disk, a permanent copy of the
text was stored in the file HELLO.ASM, where it would survive
even if you shut off your computer. (HELLO.ASM might not
survive a disk crash, however, so we also suggest that you back
up your disks regularly.) HELLO.ASM is a standard ASCII text
file; you can display it at the DOS prompt by typing
type hello.asm

and you can edit it with any text editor.
When you assembled HELLO.ASM, Turbo Assembler turned the
text instructions in HELLO.ASM into their binary equivalents in
the object file HELLO.OBI. HELLO.OBI is an intermediate file,
partway between source code and an executable file. HELLO.OBI
contains all the information needed to make executable code out
of the instructions that started out in HELLO.ASM, but it's in a
form that can readily be combined with other object files into a
single program. In Chapter 6, "More about programming in
Turbo Assembler," you'll see how useful this can be when you're
developing large programs.

14

Turbo Assembler User's Guide

Next, when you linked HELLO.OB], TLINK converted it into the
executable file HELLO.EXE. Finally, you ran HELLO.EXE when
you typed hello at the prompt.
Now type
dir hello.*

to list the various HELLO files on your disk. You'll find
HELLO.ASM, HELLO.OB], HELLO.EXE, and HELLO.MAP.

Modifying your first Turbo Assembler program
Now go back to your editor and modify your program to accept a
bit of input from the outside world. (The outside world is you,
typing at your keyboard.) Change the code to the following:
.MODEL small
.STACK 100h
•DATA
TimePrompt DB 'Is it after 12 noon (Y/N)?$'
GoodMorningMessage LABEL BYTE
DB 13,10,'Good morning, world!',13,10,'$'
GoodAfternoonMessage LABEL BYTE
DB 13,10,'Good afternoon, world!' ,13,10,'$'
•CODE
mov ax,@data
mov ds,ax
iset OS to point to data segment
mov dx,OFFSET TimePrompt
;point to the time prompt
mov ah,9
;DOS print string function #
int 21h
idisplay the time prompt
mov ah,1
;DOS get character function #
int 21h
;get a single-character response
cmp al,'y'
ityped lowercase y for after noon?
jz IsAfternoon
iyes, it's after noon
cmp al,'Y'
ityped uppercase Y for after noon?
jnz IsMorning
ino, it's before noon
IsAfternoon:
mov dx,OFFSET GoodAfternoonMessage ;point to the afternoon
; greeting
jmp DisplayGreeting
IsMorning:
mov dx,OFFSET GoodMorningMessage
;point to the before noon
i greeting
DisplayGreeting:
mov ah,9
iDOS print string function #
int 21h
;display the appropriate greeting

Chapter 2, Getting started with Turbo Assembler

15

mov ah,4ch
int 21h

;005 terminate program function t
;terminate the program

END

You've added two important new capabilities to your program:
input and decision-making. This program asks you whether it's
after noon, then accepts a single-character response from the
keyboard. If the character typed is an uppercase or lowercase Y,
the program displays a greeting appropriate for the afternoon;
otherwise, it gives a morning greeting. All the essential elements
of a useful program-input from the outside world, data
processing and decision-making, and output to the outside
world-are present in this code.
Save the modified program to disk. (This replaces your original
version of HELLO.ASM with the modified code, so the original
version will be lost.) Then reassemble and relink the program just
as you did in the previous examples. Run the program again by
typing hello at. the DOS prompt. The message
Is it after 12 noon (YIN)?

is displayed, with the cursor blinking after the question mark,
waiting for your response. Press Y. The program responds
Good afternoon, world!

HELLO.ASM is now an interactive, decision-making program.
In the course of your assembler programming, you will surely
make a wide variety of mistakes in typing and in program syntax.
Turbo Assembler ca tches many mistakes for you as it assembles
your code, reporting all such errors. The mistakes reported fall
into two categories: warnings and errors. Turbo Assembler
displays a warning message if it detects something suspicious, but
not necessarily wrong, in your code; sometimes warnings can be
ignored, but it's always best to check them out and make sure you
understand the problem. Turbo Assembler displays an error
message if it encounters something clearly wrong in your code
that makes it impossible to complete assembly and generate an
object file.
In other words, warnings are cautionary or nonfatal, while errors
must be fixed before you can run a program. The many error and
warning messages Turbo Assembler can generate are covered in
Appendix E in the Reference Guide.

16

Turbo Assembler User's Guide

As with any programming language, Turbo Assembler can't catch
logic errors for you. Turbo Assembler can tell you whether your
code can be assembled, but it can't tell you whether the assembled
code will perform as you intended it to-only you can be the
judge of that.
Don't worry if the example code doesn't make much sense to you
right now. Even programmers experienced in other languages
take some time to become fluent in 8086 assembly language;
there's really nothing quite like it under the sun. At this point,
you're just getting a feel for what assembler programs look like.
Later in this chapter, and in Chapter 5, "The elements of an
assembler program," we'll cover each of the elements of the
programs presented.
To list or send your program to a printer, consult your specific
text editor's manual. Turbo Assembler source files are normal
ASCII text files, so you can also print any assembler source file
from the DOS prompt with the PRINT command.

Sending output to
a printer

The printer is a handy output device; not only will you sometimes
want to send your program files to the printer, but you'll also
want your programs to send output to the printer on occasion.
The following is a version of the "Hello, world" program that
displays its output on the printer rather than on the screen:
.MODEL small
.STACK 100h
•DATA
HelloMessage DB 'Hello, world' ,13,10,12
HELLO_MESSAGE_LENGTH EQU $ - HelloMessage
•CODE
mov ax,@data
mov ds,ax
;set OS to point to the data segment
mov ah,40h
;DOS write to device function f
mov bx,4
;printer handle
;number of characters to print
mov cx,HELLO_MESSAGE_LENGTH
mov dx,OFFSET HelloMessage
i string to print
int 21h
iprint "Hello, world"
;DOS terminate program function f
mov ah,4ch
int 21h
;terminate the program
END

In this version of the "Hello, world" program, you've replaced the
OOS function to print a string on the screen with a OOS function

Chapter 2. Gefflng started with Turbo Assembler

17

that sends a string to a selected device or file-in this case, the
printer. Enter and run the program, and see that a sheet containing the familiar ''Hello, world" message is printed. (Don't
forget to save the program before running it. Again, this saves the
modified code in HELLO.ASM, and the previous version of the
program will be lost.)
You can modify this program to send output to the screen rather
than to the printer, displaying "Hello, world" onscreen again,
simply by changing
mov bx,4

;printer handle

mov bx,l

;standard output handle

to
Make this change, then reassemble and relink before running the
program again. You'll note that when the output is displayed on
the screen, the final character shown is the universal symbol for
"female" (~). This is actually a formfeed character, which the
program sent to the printer to force it to eject the sheet on which
you'd printed "Hello, world." Since the screen doesn't have
sheets, it doesn't know about formfeeds, so it simply displays the
corresponding member of the PC's character set when told to
print a formfeed character.

Writing your second Turbo Assembler program
Now you're ready to enter and run a program that actually does
something, REVERSE.ASM. Go back into your text editor and
enter the following:
.MODEL small
.STACK 100h
•DATA
MAXIMUM_STRING_LENGTH EQU 1000
StringToReverse DB MAXIMUM_STRING_LENGTH DUP(?)
ReverseString
DB MAXIMUM_STRING_LENGTH DUP(?)
•CODE
mov ax,@data
mov ds,ax
;set DS to point to the data segment
mov ah,3fh
;DOS read from handle function f
mov bx,O
;standard input handle
mov cx,MAXIMUM_STRING_LENGTH ;read up to maximum number of
; characters

18

Turbo Assembler User's Guide

mov
int
and
jz
mov

dx,OFFSET StringToReverse istore the string here
21h
iget the string
ax,ax
iwere any characters read?
Done
ino, so you're done
cx,ax
iPut string length in ex, where
i you can use it as a counter
push cx
isave the string length
mov bx,OFFSET StringToReverse
mov .si,OFFSET ReverseString
add si,cx
dec si
ipoint to the end of the
i reverse string buffer
ReverseLoop:
mov aI, [bx]
iget the next character
istore the characters in reverse order
mov [si],al
inc bx
ipoint to next character
ipoint to previous location
dec si
i in reverse buffer
loop ReverseLoop
imove next character, if any
pop cx
iget back the string length
iDOS write from handle function f
mov ah,40h
mov bx,l
istandard output handle
mov dx,OFFSET ReverseString iprint this string
iprint the reversed string
int 21h
Done:
iDOS terminate program function f
mov ah,4ch
int 21h
iterminate the program
END

You'll see what the program actually does in a moment; first, as
always, you should save your work.

Running
REVERSE.ASM

To run REVERSE.ASM, you must first assemble it; type

TASM reverse
then type
TLINK reverse

to create the executable file.
Type reverse at the prompt to run your program. If Turbo
Assembler reports any errors or warnings, carefully check your
code to see that it matches the code shown previously, then try
running the program again.

Chapter 2, Geffing started with Turbo Assembler

19

After you run your program, the cursor will sit blinking onscreen.
Apparently, the program is waiting for you to type something.
Try typing
ABCDEFG

then press Enter. The program displays
GFEDCBA

and ends. Type reverse agam at the command line. This time, type
0123456789

and press Enter. The program displays
9876543210

Now it's clear what REVERSE.ASM does: It reverses whatever
string of characters you type in. Speedy manipulation of
characters and strings is one of the areas in which assembly
language excels, as you'll see in the next few chapters.
Congratulations! You've entered, assembled, linked, and run
several assembler programs, and you've seen the fundamentals of
assembler programming-input, processing, and output-in
action.
If you don't want an object file but you do want a listing file, or if
you want a cross-reference file but don't want a listing file or
object file, you can specify the null device (NUL) as the file name.
For example,
TASM FILE1"NUL,

assembles file FILEl.ASM to object file FILE1.0BJ, doesn't
produce a listing file, and creates a cross-reference file FILEl.XRF.
Now you're ready to learn the basic elements of assembler
programming, covered in Chapter 5, liThe elements of an
assembler program."

20

Turbo Assembler User's Guide

c

H

p

A

T

E

R

3

Command-line reference
This chapter is dedicated to familiarizing you with Turbo
Assembler's command-line options. We'll describe each of the
command-line options you can use to alter the assembler's
behavior, then show how and when to use command files. Finally,
we describe the configuration file.

Starting Turbo Assembler from DOS
Turbo Assembler has a very powerful and flexible command-line
syntax. If you start Turbo Assembler without giving it any
arguments, like this,
TASM

you'll get a screenful of help describing many of the commandline options and the syntax for specifying the files you want to
assemble. Figure 3.1 shows you how this looks.

Chapter 3, Command-line reference

21

Figure 3.1
Turbo Assembler command
line

Turbo Assembler Version 2.0 Copyright (C) 1988, 1990 by Borland
International, Inc.
Syntax: TASM [options] source [,object] [,listing] [,xref]
/a,/s
/c
/dSYM[=VAL]
/e,/r
/h,/?

/iPATH
/jCMD
/khl,/ksl
/l,/la
/ml,/mx,/mu
/mvl
/ml
/n
/p
/q
/t

/wO,/wl,/w2
/w-xxx,/w+xxx
/x
/z

/zi,/zd

Alphabetic or Source-code segment ordering
Generate cross-reference in listing
Define symbol SYM = 0, or = value VAL
Emulated or Real floating-point instructions
Display this help screen
Search PATH for include files
Jam in assembler directive CMD (eg. /jIDEAL)
Hash table capacity I, String space capacity I
Generate listing: l=normal listing, la=expanded listing
Case sensitivity on symbols: ml=all, mx=globals, mu=none
Set maximum valid length for symbols
Allow I mUltiple passes to resolve forward references
Suppress symbol tables in listing
Check for code segment overrides in protected mode
Suppress OBJ records not needed for linking
Suppress messages if successful assembly
Set warning level: wO=none, w1=w2=warnings on
Disable (-) or enable (+) warning xxx
Include false conditionals in listing
Display source line with error message
Debug info: zi=full, zd=line numbers only

With the command-line options, you can specify the name of one
or more files that you want to assemble, as well as any options
that control how the files get assembled.
The general form of the command line looks like this:
TASM fileset [; fileset] ...

The semicolon (i) after the left bracket (D allows you to assemble
multiple groups of files on one command line by separating the
file groups. If you prefer, you can set different options for each set
of filesi for example,
TASM Ie FILE1; la FILE2

assembles FILE1.ASM with the Ie command-line option and
assembles file FILE2.ASM with the la command-line option.
In the general form of the command line, fileset can be
[option] ••• sourcefile [[+] sourcefile] ...
[, [objfile] [, [listfile] , [, [xreffile]]]]

This syntax shows that a group of files can start off with any
options you want to apply to those files, followed by the files you

22

Turbo Assembler User's Guide

want to assemble. A file name can be a single file name, or it can
use the normal OOS wildcard characters If- and ? to specify
multiple files to assemble. If your file name does not have an
extension, Turbo Assembler adds the .ASM extension. For
example, to assemble all the .ASM files in the current directory,
you would type
TASM

*

If you want to assemble multiple files, you can separate their
names with the plus sign (+):
TASM MYFILEI + MYFlLE2

You can follow the file name you want to assemble by an optional
object file name, listing file name, and a cross-reference file name.
If you do not specify an object file or listing file, Turbo Assembler
creates an object file with the same name as the source file and an
extension of .OBJ.
A listing file is not generated unless you explicitly request one. To
request one, place a comma after the object file name, followed by
a listing file name. If you don't explicitly provide a listing file
name, Turbo Assembler creates a listing file with the same name
as the source file and the extension .LST. If you supply a listing
file name without an extension, .LST is appended to it.
A cross-reference file is not generated unless you explicitly
request one. To request one, place a comma after the listing file
name, followed by a cross-reference file name. If you don't
explicitly provide a cross-reference file name, Turbo Assembler
creates a cross-reference file with the same name as the source file
and the extension .XRF. If you supply a cross-reference file name
without an extension,.XRF is appended to it. (TCREF, a crossreference utility, is described Oil disk.)

If you want to accept the default object file name and also request
a listing file, you must supply the comma that separates the object
file name from the listing file name:
TASM FILEl" TEST

This assembles FILEl.ASM to FILE1.0BJ and creates a listing file
named TEST.LST.

If you want to accept the default object and listing file names and
also request a cross-reference file, you must supply the commas
that separate the file names:

Chapter 3, Command-line reference

23

TASM MYFILE",MYXREF

This assembles file MYFILE.ASM to MYFILE.OBJ, with a listing in
file MYFILE.LST and a cross-reference in MYXREF.XRF.
If you use wildcards to specify the source files to assemble, you
can also use wildcards to indicate the object and listing file names.
For example, if your current directory contains XXI.ASM and
XX2.ASM, the command line

TASM XX*,YY*

assembles all the files that start with XX, generates object files that
start with W, and derives the remainder of the name from the
source file ·name. The resulting object files are therefore called
YYI.OBJ and YY2.0BJ.
If you don't want an object file but you do want a listing file, or if
you want a cross-reference file but don't want a listing file or
object file, you can specify the null device (NUL) as the file name.
For example,

TASM FlLEl"NUL,

assembles file FILE1.ASM to object file FILE1.0BJ, doesn't
produce a listing file, and creates a cross-reference file FILEI.XRF.

Command-line options
The command-line options let you control the behavior of the
assembler, and how it outputs information to the screen, listing,
and object file. Turbo Assembler provides you with some options
that produce no action, but are accepted for compatibility with the
current and previous versions of MASM:
Ib
Iv

Sets buffer size
Displays extra statistics

You can enter options using any combination of uppercase and
lowercase letters. You can also enter your options in any order
except where you have multiple II or Ij options; these are
processed in sequence. When using the Id option, you must also
be careful to define symbols before using them in subsequent Id
options.
Note: You can override command-line options by using
conflicting directives in your source code.

24

Turbo Assembler User's Guide

la

Figure 3.1 on page 22 summarizes the Turbo Assembler
command-line options; here's a detailed description of each
option.

/a
Function
Syntax
Remarks

Specifies alphabetical segment-ordering
fa

The la option tells Turbo Assembler to place segments in the object file in
alphabetical order. This is the same as using the .ALPHA directive in your
source file.
You usually only have to use this option if you want to assemble a source
file that was written for very early versions of the IBM or Microsoft
assemblers.
The Is option reverses the effect of this option by returning to the default
sequential segment-ordering.
If you specify sequential segment-ordering with the .SEQ directive in
your source file, it will override any la you provide on the command line.

Example

TASM / a TEST!

This command line creates an object file, TEST1.0BJ, that has its segments
in alphabetical order.

/b
Syntax
Remarks

fb

The Ib option is included for compatibility. It performs no action and has
no effect on the assembly.

Chapter 3, Command-line reference

25

Ie

Ie
Function
Syntax
Remarks

Enables cross-reference in listing file
Ie

The Ie option enables cross-reference information in the listing file. Turbo
Assembler adds the cross-reference information to the symbol table at the
end of the listing file. This means that, in order to see the cross-reference
information, you must either explicitly specify a listing file on the
command line or use the II option to enable the listing file.
For each symbol, the cross-reference shows the line on which it is defined
and all lines that refer to it.

Example

TASM /1 /e TEST!

This code creates a listing file that also has cross-reference information in
the symbol table.

Id
Function
Syntax
Remarks

Defines a symbol
Idsymbol [=value or expression]

The Id option defines a symbol for your source file, exactly as if it were
defined on the first line of your file with the directive. You can use this
option as many times as you want on the command line.

=

You can only define a symbol as being equal to another symbol or a
constant value. You can't use an expression with operators to the right of
the equal sign (=). For example, IdX=9 and IdX= Yare allowed, but
IdX= Y-4 is not allowed.
Example

TASM /dMAX=lO /dMIN=2 TESTl

This command line defines two symbols, MAX and MIN, that other
statements in the source file TESTl.ASM can refer to.

26

Turbo Assembler User's Guide

Ie

/e
Function
Syntax
Remarks

Generates floating-point emulator instructions

Ie
The Ie option tells Turbo Assembler to generate floating-point instructions
that will be executed by a software floating-point emulator. Use this
option if your program contains a floating-point emulation library that
mimics the functions of the 80x87 numeric coprocessor.
Normally, you would only use this option if your assembler module is
part of a program written in a high-level language that uses a floatingpoint emulation library. (Turbo C, Turbo Pascal, Turbo Basic, and Turbo
Prolog all support floating-point emulation.) You can't just link an
assembler program with the emulation library, since the library expects to
have been initialized by the compiler's startup code.
The Ir option reverses the effect of this option by enabling the assembly of
real floating-point instructions that can only be executed by a numeric
coprocessor.
If you use the NOEMUL directive in your source file, it will override the Ie
option on the command line.

The Ie command-line option has the same effect as using the EMUL
directive at the start of your source file, and is also the same as using the
IjEMUL command-line option.
Example

TASM / e SECANT
TCC -f TRIG.C SECANT.OBJ

The first command line assembles a module with emulated floating-point
instructions. The second command line compiles a C source module with
floating-point emulation and then links it with the object file from the
assembler.

/h or /?
Function
Syntax
Remarks

Displays a help screen
/h or /?

The Ih option tells Turbo Assembler to display a help screen that describes
the command-line syntax. This includes a list of the options, as well as the
various file names you can supply. The 11 option does the same thing.

Chapter 3, Command-line reference

27

Ih or I?

Example

TASM /h

Function

Sets an Include file path

Ii
Syntax
Remarks

/iPATH

The II option lets you tell Turbo Assembler where to look for files that are
included in your source file by using the INCLUDE directive. You can
place more than one II option on the command line (the number is only
limited by RAM).
When Turbo Assembler encounters an INCLUDE directive, the location
where it searches for the Include file is determined by whether the file
name in the INCLUDE directive has a directory path or is just a simple file
name.
If you supply a directory path as part of the file name, that path is tried
first, then Turbo Assembler searches the directories specified by II
command-line options in the order they appear on the command line. It
then looks in any directories specified by II options in a configuration file.
If you don't supply a directory path as part of the file name, Turbo
Assembler searches first in the directories specified by II command-line
options, then it looks in any directories specified by II options in a
configuration file, and finally it looks in the current directory.

Example

TASM / i \ INCLUDE / iD: \INCLUDE TEST!

If the source file contains the statement

INCLUDE MYMACS.INC

Turbo Assembler will first look for \ INCLUDE \ MYMACS.INC, then it
will look for D:\INCLUDE\MYMACS.INC. If it still hasn't found the file,
it will look for MYMACS.INC in the current directory. If the statement in
your source file had been
INCLUDE INCS\MYMACS.INC

Turbo Assembler would first look for INCS\MYMACS.INC and then it
would look for \INCLUDE\MYMACS.INC, and finally for D:\
INCLUDE\MYMACS.INC.

28

Turbo Assembler User's Guide

Ij

/j
Function
Syntax
Remarks

Defines an assembler startup directive
/jdirective

The Ij option lets you specify a directive that will be assembled before the
first line of the source file. directive can be any Turbo Assembler directive
that does not take any arguments, such as .286, IDEAL, %MACS,
NOJUMPS, and so on. See Chapter 3 in the Reference Guide for a complete
description of all Turbo Assembler directives.
I

You can put more than one Ij option on the command line; they are
processed from left to right across the command line.
Example

TASM /j .286 /jIDEAL TEST!

This code assembles the file TEST1.ASM with 80286 instructions enabled
and Ideal mode expression-parsing enabled.

/kh
Function
Syntax
Remarks

Sets the maximum number of symbols allowed
/khnsymbols

The Ikh option sets the maximum number of symbols that your program
can contain. If you don't use this option, your program can only have a
maximum of 8,192 symbols; using this option increases the number of
symbols to nsymbols, up to a maximum of 32,768.
Use this option if you get the Out of hash space message when assembling
your program.
You can also use this option to reduce the total number of symbols below
the default 8,192. This releases some memory that can be used when you
are trying to assemble a program but don't have enough available
memory.

Example

TASM /khlOOOO BIGFILE

This command tells Turbo Assembler to reserve space for 10,000 symbols
when assembling the file BIGFILE.

Chapter 3, Command-line reference

29

/ks

/ks
Function
Syntax

Sets the maximum size of Turbo Assembler's string space
/kskbytes

Remarks

Usually the string size is determined automatically and does not need to
be adjusted. However, if you have a source file that results in an Out of
string space message, you might want to increase the string space size by
using this option. Try starting with a value of 100, and increase it until
your program assembles without error. The maximum allowable value for
kbytes is 255.

Example

TASM Iksl50 SFILE

This tells Turbo Assembler to reserve 150K of string space.

/1
Function
Syntax

Generates a listing file
Ii

Remarks

The II option indicates that you want a listing file, even if you did not
explicitly ~pecify it on the command line. The listing file will have the
same name as the source file, with an extension of .LST.

Example

TASM 11 TEST!

This command line requests a listing file that will be named TEST1.LST.

/10
Function
Syntax

30

Shows high-level interface code in listing file
/la

Remarks

The Iia option tells Turbo Assembler to show all generated code in the
listing file, including the code that gets generated as a result of the highlevel language interface .MODEL directive.

Example

TASM Ila FILEl

Turbo Assembler User's Guide

1m

1m
Function
Syntax
Remarks

Sets the maximum number of assembly passes
Im[npasses]

Normally, Turbo Assembler functions as a single-pass assembler. The 1m
option allows you to specify the maximum number of passes that the
assembler should make during the assembly process. TASM automatically
decides whether it can perform less than the number of passes specified. If
you don't specify npasses, a default of five is used.
Some modules contain constructions that assemble properly only when
two passes are done. If multiple passes are not enabled, such a module
will produce at least one "Pass-dependent construction encountered"
warning. If the 1m option is enabled, Turbo Assembler will assemble this
module correctly but will not optimize the code by removing NOPs, no
matter how many passes are allowed. The warning IIModule is pass
dependent-<:ompatibility pass was done" is displayed if this occurs.

Example

TASM 1M2 TESTl

This tells Turbo Assembler to use up to two passes when assembling
TESTl.

Iml
Function
Syntax

Treats symbols as case-sensitive
Iml

Remarks

The Iml option tells Turbo Assembler to treat all symbol names as casesensitive. Normally, uppercase and lowercase letters are considered
equivalent so that the names ABCxyz, abcxyz, and ABCXYZ would all refer
to the same symbol. If you specify the Iml option, these three symbols will
be treated as distinct. Even when you specify Iml, you can still enter any
assembler keyword in uppercase or lowercase. Keywords are the symbols
built into the assembler that have special meanings, such as instruction
mnemonics, directives, and operators.

Example

TASM Iml TESTl

where TESTl.ASM contains the following statements:
abc OW 0
ABC OW 1

Chapter 3. Command-line reference

inot a duplicate symbol

31

/mu

Mov Ax,!Bp]

imixed case OK in keywords

/mu
Function
Syntax

Converts symbols to uppercase
/mu

Remarks

The Imu option tells Turbo Assembler to ignore the case of all symbols. By
default, Turbo Assembler specifies that any lowercase letters in symbols
will be converted to uppercase unless you change it by using the Iml
directive.

Example

TASM

/mu TEST!

makes sure that all symbols are converted to uppercase (which is the
default):
EXTRN myfunc:NEAR
call myfunc

idon't know if declared as
MYFUNC, Myfunc, ••.

i

/mv#
Function
Syntax

Sets the maximum length of symbols.

tmv'

Remarks

The Imv# option sets the maximum length of symbols that TASM will
distinguish between. For example, if you set Imv3, TASM will see ABCC
and ABCD as the same symbol, but not AB.

Function

Makes public and external symbols case-sensitive

/mx
Syntax
Remarks

32

/rnx
The Imx option tells Turbo Assembler to treat only external and public
symbols as case-sensitive. All other symbols used (within the source file)
are treated as uppercase.

Turbo Assembler User's Guide

/mx

You should use this directive when you call routines in other modules
that were compiled or assembled so that case-sensitivity is preserved; for
example, modules compiled by Turbo C.
Example

TASM Irnx TEST1;

where TESTl.ASM contains the following source lines:
EXTRN Cfunc:NEAR
rnyproc PROC NEAR
call Cfunc

In
Function
Syntax
Remarks

Suppresses symbol table in listing file

In
The In option indicates that you don't want the usual symbol table at the
end of the listing file. Normally, a complete symbol table listing appears at
the end of the file, showing all symbols, their types, and their values.
You must specify a listing file, either explicitly on the command line or by
using the II option; otherwise, In has no effect.

Example

TASM II In TEST!

This code generates a listing file showing the generated code only, and not
the value of your symbols.

Ip
Function
Syntax
Remarks

Checks for impure code in protected mode

Ip
The Ip option specifies that you want to be warned about any instructions
that generate "impure" code in protected mode. Instructions that move
data into memory by using a CS: override in protected mode are
considered impure because they might not work correctly unless you take
special measures.
You only need to use this option if you are writing a program that runs on
the 80286 or 80386 in protected mode.

Example

TASM Ip TEST!

Chapter 3. Command-line reference

33

/p

where TEST1.ASM contains the following statements:
.286P
CODE SEGMENT
temp OW ?
mov CS:temp,O

;impure in protected mode

/q
Function
Syntax

Suppresses .OBI records not needed for linking
/q

Remarks

The Iq option removes the copyright and file dependency records from
the resulting .OBI files, making it smaller. Don't use this option if you are
using MAKE or a similar program that relies on the dependency records.

Function

Generates real floating-point instructions

/r
Syntax
Remarks

Ir
The Ir option tells Turbo Assembler to generate real floating-point
instructions (instead of generating emulated floating-point instructions).
Use this option if your program is going to run on machines equipped
with an 8Ox87 numeric coprocessor.
The Ie option reverses the effect of this option in generating emulated
floating-point instructions.
If you use the EMUL directive in your source file, it will override the Ir
option on the command line.

The Ir command-line option has the same effect as using the NOEMUL
directive at the start of your source file, and is also the same as using the
IjNOEMUL command-line option.
Example

TASM /r SECANT
TPC /$N+ /$E- TRIG. PAS

The first command line assembles a module with real floating-point
instructions. The second compiles a Pascal source module with real
floating-point instructions that links in the object file from the assembler.

34

Turbo Assembler User's Guide

/s

Is
Function
Syntax
Remarks

Specifies sequential segment-ordering

Is
The Is option tells Turbo Assembler to place segments in the object file in
the order in which they were encountered in the source file. By default,
Turbo Assembler uses segment-ordering, unless you change it by placing
an Is option in the configuration file.
If you specify alphabetical segment-ordering in your source file with the
.ALPHA directive, it will override Is on the command line.

Example

TASM

Is

TEST!

This code creates an object file (TEST1.0BJ) that has its segments ordered
exactly as they were specified in the source file.

It
Function
Syntax
Remarks

Suppresses messages on successful assembly
It

The It option stops any display by Turbo Assembler unless warning or
error messages result from the assembly.
You can use this option when you are assembling many modules, and you
only want warning or error messages to be displayed onscreen.

Example

TASM

It TEST!

Iv
Syntax
Remarks

Iv
The Iv option is included for compatibility. It performs no action and has
no effect on the assembly.

Chapter 3, Command-line reference

35

/w

/w
Function
Syntax

Con troIs the generation of warning messages
/w
w- [warnclass]

w+ [warnclass]
Remarks

The Iw option controls which warning messages are emitted by Turbo
Assembler.
If you specify Iw by itself, "mild" warnings are enabled. Mild warnings
merely indicate that you can improve some aspect of your code's
efficiency.
If you specify Iw- without warnclass, all warnings are disabled. If you
follow Iw- with warnclass, only that warning is disabled. Each warning
message has a three-letter identifier:

ALN
ASS
BRK
ICG
LCO
OPI
OPP
OPS
OVF
POC
PQK
PRO
RES
TPI

Segment alignment
Assuming segment is 16-bit
Brackets needed
Inefficient code generation
Location counter overflow
Open IF conditional
Open procedure
Open segment
Arithmetic overflow
Pass-dependent construction
Assuming constant for [const] wa~ing
Write-to memory in protected mode needs CS override
Reserved word warning
Turbo Pascal illegal warning

If you specify Iw+ without warnclass, all warnings are enabled. If you
specify Iw+ with warnclass from the preceding list, only that warning will
be enabled.

By default, Turbo Assembler first starts assembling your file with all
warnings enabled except the inefficient code-generation (ICG) and the
write-to-memory in protected mode (PRO) warnings.
You can use the WARN and NOWARN directives within your source file to
control whether a particular warning is allowed for a certain range of
source lines. See Chapter 3 in the Reference Guide for more information on
these directives.

36

Turbo Assembler User's Guide

/w

Example

TASM Iw TEST!

The following statement in TEST1.ASM issues a warning message that
would not have appeared without the Iw option:
mov bx,ABC
ABC = 1

;inefficient code generation warning

With the command line
TASM Iw-OVF TEST2

no warnings are generated if TEST2.ASM contains
dw lOOOh

* 20h

Ix
Function
Syntax
Remarks

Includes false conditionals in listing

Ix

If a conditional IF, IFNDEF, IFDEF, and so forth evaluates to False, the Ix
option causes the statements inside the conditional block to appear in the
listing file. This option also causes the conditional directives themselves to
be listed; normally they are not.
You must specify a listing file on the command line or via the II option,
otherwise Ix has no effect.
You can use the .LFCOND, .SFCOND, and .TFCOND directives to override
the effects of the Ix option.
Ix TESTl

Example

TASM

Function

Displays source lines along with error messages

Iz
Syntax
Remarks

Iz
The Iz option tells Turbo Assembler to display the corresponding line
from the source file when an error message is generated. The line that
caused the error is displayed before the error message. With this option
disabled, Turbo Assembler just displays a message that describes the
error.

Chapter 3, Command-line reference

37

/z

Example

TASM / z TEST!

Function

Enables line-number information in object files

/zd
Syntax
Remarks

/zd

The Izd option causes Turbo Assembler to place line-number information
in the object file. This lets Borland's stand-alone debugger, Turbo
Debugger, display the current location in your source code, but does not
put the information in the object file that would allow the debugger to
access your data items.
If you run out of memory when trying to debug your program under
Turbo Debugger, you can use Izd for some modules and Izi for others.

Example

TASM / zd TEST!

Function

Enables debug information in object file

/zi
Syntax
Remarks

/zi

The Izi option tells Turbo Assembler to output complete debugging
information to the object file. This includes line-number records to
synchronize source code display and data type information to allow you
to examine and modify your program's data.
The Izi option lets you use all the features of Turbo Debugger to step
through your program and examine or change your data items. You can
use Izi on all your program's modules, or just on those you're interested in
debugging. Since the Izi switch adds information to the object and
executable programs, you might not want to use it on all your modules if
you run out of memory when running a program under Turbo Debugger.

Example

38

TASM /zi TEST!

Turbo Assembler User's Guide

Indirect command files
At any point when entering a command line, Turbo Assembler
lets you specify an indirect command file by preceding its name
with an "at" sign (@). For example,
TASM /dTESTMODE @MYPROJ.TA

causes the contents of the file MYPROJ.TA to become part of the
command line, exactly as if you had typed in its contents directly.
This useful feature lets you put your most frequently used
command lines and file lists in a separate file. And you don't have
to place your entire command line in one indirect file, since you
can use more than one indirect file on the command line and can
also mix indirect command files with normal arguments; for
example,
TASM @MYFILES @IOLIBS /dBUF=1024

This way you can keep long lists of standard files and options in
files, so that you can quickly and easily alter the behavior of an
individual assembly run.
You can either put all your file names and options on a single line
in the command file or you can split them across as many lines as
you want.

The configuration file
Turbo Assembler also lets you put your most frequently used
options into a configuration file in the current directory. If
running on DOS 3.x or later, it also looks in the directory that
TASM was loaded from. This way, when you run Turbo
Assembler, it looks for a file called TASM.CFG in your current
directory. If Turbo Assembler finds the file, it treats it as an
indirect file and processes it before anything else on the command
line.
This is helpful when you have all the source files for a project in a
single directory and you know that, for example, you always
want to assemble with emulated floating-point instructions (the Ie
option). You can place that option in the TASM.CFG file, so you
don't have to specify that option each time you start Turbo
Assembler.

Chapter 3, Command-line reference

39

The contents of the configuration file have exactly the same
format as an indirect file. The file can contain any valid
command-line options, on as many lines as you want. The options
are treated as if they all appeared on one line.
The contents of the configuration file are processed before any
arguments on the command line. This lets you override any
options set in the configuration file by simply placing an option
with the opposite effect on the command line. For example, if
your configuration file contains

la Ie
and you invoke Turbo Assembler with
TASM Is Ir MYFILE

where MYFILE is your program file, your file will be assembled
with sequential segment-ordering (Is) and real floating-point
instructions (lr), even though the configuration file contained the
la and Ie options that specified alphabetical segment-ordering and
emulated floating-point instructions.

40

Turbo Assembler User's Guide

c

H

A

p

T

E

R

4
The nature of assembly language
Earlier, we said that assembly language is the computer's own
language. In order to understand what that means, you first need
to understand exactly what a computer is. Then we'll teach you
just what it is that makes assembly language unique among the
many languages of the computer world.
In this chapter we'll cover the nature of computers in general, and
the 8086 processor in particular, to give you an understanding of
the special strengths of assembly language programming on the
8086. We'll also discuss issues of assembly language
programming specifically related to the IBM PC.

The architecture of a computer
Deep down, a computer is nothing more than a device that moves
data from one place to another, sometimes transforming the data
in various logical and arithmetical ways. For our purposes,
however, it's more useful to view a computer as a system
consisting of five functional subsystems-input, control,
arithmetic and logical processing, memory, and output-as
shown in Figure 4.1.
(For the moment, we're talking about computers in general; we'll
get to the 8088 shortly.)

Chapter 4, The nature of assembly language

41

Figure 4.1
Five subsystems
Arithmetic Subsystem
(Add, subtract,
multiply, divide,
and, or,
exclusive-or, etc.)

Input
Subsystem
(Keyboard,
Mouse,
Joystick,
Disk)

Control Subsystem
(Overall Coordination)

Output
Subsystem
(Display,
Printer,
Plotter,
Disk)

Memory Subsystem
(Up to 1 megabyte of
RAM and/or ROM)

The arithmetic subsystem of the computer is the aspect most
people think of when they think ofa computer. After all, what is a
computer if not a number-cruncher? As it turns out, though, most
computers spend very little time crunching numbers, and a great
deal of time working with character strings and performing input
and output; what need does a word processor have for
arithmetic? Nonetheless, the arithmetic subsystem is important,
for it is there that not only addition, subtraction, multiplication,
and division are performed, but logical operations (such as and,
or, and exclusive-or) as well.
It's all very well to perform arithmetic, but where do the source
values for, say, addition come from, and where does the result of
each operation go? The computer's memory subsystem comes into
play here, providing instantly accessible storage for many
thousands of characters or numbers. Computers also have floppy
and hard disk drives, which provide permanent (but relatively
slow) storage for enormous amounts of data, but these are
actually input/output (I/O) devices, not part of the memory
subsystem.

42

Turbo Assembler User's Guide

Programs without Input and
output tend to be rare, since
they can't accept new data
(rom the outside world and
can't do anything with whatever results they do
generate.

The input subsystem allows programs to manipulate data from
the outside world, ranging from single keystrokes to mouse
motions to whole databases stored in disk files. The output
subsystem lets programs display prompts and results on screens
and printers, and send data to disk files and tapes.
Finally, the control subsystem ties together the operation of the
other four subsystems and controls data movement.
The control and arithmetic subsystems together form what is
known as the processing unit, or processor. A processor forms the
core of any computer, providing data processing and controlling
the memory, input, and output subsystems. The processor sets the
tone for any computer, since it controls the operation of each of
the subsystems and coordinates them into a smoothly functioning
unit.
Nowadays, an entire processor is frequently built on a single chip.
For instance, the 8088 is a processor on a chip, complete with
arithmetic processing, control, and interfaces to input, output, and
memory.
It's with the processor that we make the connection between the
architecture of the computer and the unique nature of assembly
language.

The making of
assembly
language

We've said that the processor orchestrates the activities of the five
subsystems of a computer-adding values, moving them about
from memory to output, and so on-but that begs a fundamental
question: How does the processor know which operations to
perform? So far, the computer has all the capabilities we need, but
no script to follow.
The answer is surprisingly simple: The processor fetches data
from memory, and that data tells it what to do next. Data that tells
a processor what to do is usually called "instructions," but
instructions are simply values stored in memory, just like any
other data. The set of instructions that a processor can execute
(the instruction set) corresponds exactly to the actions that that
processor's hardware can perform. Put another way, a processor's
instructions comprise all the operations that any software can
ever ask the processor to do.

Chapter 4, The nature of assembly language

43

For example, if a processor lacks a multiplication instruction, then
there is no way the hardware of that computer can perform a
multiplication. Multiplication can instead be performed in
software by perfonning adds and shifts, but this tends to be much
slower. The key point here is that a processor's instruction set
reflects the actions that the computer's hardware is inherently
capable of perfonning. By the same token, each processor's
assembly language is unique to that processor because each
processor has unique capabilities and, therefore, a unique
instruction set.
Each instruction value has a specific, well-defined meaning to a
given processor. For example, the instruction value 4 tells the 8088
to add the value stored at the next memory address to the AL
register. (Don't worry about what the AL register is right nowwe'll get to that soon.) Consequently, a processor can be put
through a desired sequence of actions by an appropriate series of
instruction values; indeed, a program is nothing more than a
sequence of instruction values.
How does a processor know which instruction to execute next? By
maintaining an internal pointer that points to the place in
memory where the value of the next instruction to be performed
is stored. When that next instruction is read from memory and
executed, the pointer is advanced to the following instruction.
Some instructions can set the instruction pointer to a new value;
this gives a processor the ability to execute nonsequential series of
instructions, and even the ability to perform different series of
instructions depending on certain conditions.
Great, but what does that have to do with assembly language?
Just this: A processor's instruction set is that processor's assembly
language. Or, rather, assembly language is a human-oriented form
of a processor's instruction set (known as the processor's machine
language), which an assembler such as Turbo Assembler then
converts to machine language. While assembly language and
machine language are functionally equivalent, assembly language
is much easier for people to program in. After all, surely you'd
rather program with instructions like
add al,l

than with
4
1

44

Turbo Assembler User's Guide

wouldn't you? Both forms work equally well, but assembly
language lets you work with mnemonic names for machinelanguage instructions, with the assembler translating from
mnemonic instructions to their machine-language equivalents.
This is, of course, a tremendous advantage, since humans simply
don't think very well in purely numeric languages. Basically,
assembly language is a direct analog to machine language, but
implemented in a form with which humans can work efficiently.
The good news about assembly language is that it lets you control
the processor's actions one by one, for maximum efficiency. The
bad news is that each of the processor's actions, taken
individually, tend to do relatively little, reflecting the limited
repertoire of which the processor is actually capable. For example,
the process of adding two long integers and storing the result in a
third long integer takes only one line in C:
i

= j + k;

but requires six lines in 8088 assembler:
mov ax, [j]
mov dx, [j+2]
add
adc

mov
mov

ax, [k]
dx, [k+2]
[i],ax
[i+2] ,dx

Of course, the C code compiles to no less (and possibly more)
than the same six machine language instructions required by the
assembler code, but it is easier to write the one line of C code than
the six lines of assembler. (Remember, assembler instructions
reflect the basic ability of the computer, and programs written in
all languages must eventually be translated to machine language
before they can be run.)

Why use assembler at all if it's harder to program in than other
languages? For one thing, assembler lets you reach any part of
memory and control any input or output device directly, since
assembly language programs can do anything the processor is
capable of. For another, because assembler is the native language
of the computer, it stands to reason that well-written assembler
code must be the fastest code possible. The quality of the code
produced by any other language suffers from the need to translate
from that language to machine language, but assembler code
maps directly to machine language, with not one whit of

Chapter 4, The nature of assembly language

45

efficiency lost. In assembly language, you tell the computer what
to do, and it does it-no more and no less.
Of course, if you write an inefficient assembler program, it won't
run very rapidly, since the processor does exactly what assembly
language programs specify. Similarly, assembly language has
relatively little built-in support for data-type conversion, or fc;>r
guarding against mistakes, such as accidentally overwriting a
variable or running off the end of an array. What all this means is
that assembly language gives you the ability to write wonderfully
fast and clever programs, but those programs demand more care
and skill from you as a programmer than do programs written in
other languages.
Now that you understand how a processor and its assembly
language relate to one another, let's look specifically at assembly
language for the 8088.

The 8088 and 8086 processors
The 8088 is the processor used in the IBM PC and XT computers,
which form perhaps one of the most successful line of computers.
However, the 8088 is actually only one of a family of processors
known as the iAPx86 family. Other members of this family
include the 8086 processor used in the IBM Models 25 and 30; the
80286 processor used in the IBM AT, and the IBM PS/2 Models 50
and 60; and the 80386 processor used in the IBM PS/2 Model 80.
Each of these processors is, in some way, different from the 8088.
Chapter 10, liThe 80386 and other processors," provides a detailed
discussion of the various members of the iAPx86 family. The one
thing all iAPx86 family processors share is the ability to run code
written for the 8086 and 8088 processors.
The 8086 is actually the root of the iAPx86 family tree. The 8088 is
just an 8086 with a scaled-down external data bus; while the 8086
can transfer data to and from memory 16 bits at a time, the 8088
can transfer data only 8 bits at a time. The two processors have
exactly the same instruction sets. Consequently, the assembly
language used to program the IBM PC and its successors is
properly known as 8086 assembly language, not 8088 assembly
language. For the remainder of this chapter, understand that 8086
assembly language includes the 8088 as well.

46

Turbo Assembler User's Guide

The capabilities of
the 8086

The 8086 runs at 4.77 or 8 MHz
speeds; the 80286 can run at
6, 8, 10, 12, 16, and 20 MHz:
the 80386 can run at 16, 20,
25, and 33 MHz.

By today's standards, the 8086 is a processor of modest
capabilities. After all, the 8086 was designed ten years ago, and
ten years of technological evolution have brought major
innovations to the chip-design field. Nonetheless, the 8086
remains an important processor. One reason for this is the sheer
number of IBM PCs and compatibles; no one can afford to ignore
ten-million-plus computers. Another reason, however, is that the
8086 meets the needs, even today, of advanced software.
The 8086 can address a large amount of memory (over one million
characters or other byte-sized-8-bit-values), has a powerful
instruction set, and properly programmed can support highperformance programs. But the 8086 is not a super-fast processor,
not every language is capable of providing decent performance on
the 8086, and no other language can match assembly language
when it comes to writing excellent 8086 programs.
The resources the 8086 provides to the assembly language
programmer are memory, input and output (I/O) interfacing,
registers, and, of course, instructions. We'll explore those
resources next.

Memory
The 8086 is capable of addressing 1 megabyte (which is 2 to the
20th power or 1,048,576 storage locations, each of which is 8 bits
long) of memory at anyone time. The first byte of memory is at
address 0, and the last byte of memory "is at address OFFFFFh as
shown in Figure 4.2 on page 48.
(The last address, OFFFFFb, was given in hexadecimal, or base 16,
notation as denoted by the h suffix; it is equivalent to 1,048,575 in
the familiar decimal, or base 10, notation.) Fluency in hexadecimal
notation is essential in assembly language programming. We'll
touch on hexadecimal notation in Chapter 5, liThe elements of an
assembler program."

Chapter 4, The nature of assembly language

47

Figure 4.2
Memory address
space of the 8086

Hexadecimal
Address
00000
00001
00002
00003
00004
00005
00006
00007
00008
00009

OOOOA
OOOOB
OOOOC

00000

Decimal
Address

o
1

2
3
4
5
6

7
8
9
10

11

12

13

OOOOE
OOOOF

15

FFFEF
FFFFO
FFFF1
FFFF2
FFFF3
FFFF4
FFFF5
FFFF6
FFFF7
FFFF8
FFFF9
FFFFA
FFFFB
FFFFC
FFFFD
FFFFE
FFFFF

1048559
1048560
1048561
1048562
1048563
1048564
1048565
1048566
1048567
1048568
1048569
1048570
1048571
1048572
1048573
1048574
1048575

00010

14
16

One byte, 8 bits long, can hold one character, or one integer value
in the range 0 to 255. That doesn't mean that the 8086 can't handle
larger values. Two bytes taken together (known as a word) can
hold one integer value in the range 0 to 65,535; the 8086 can
manipulate word values as readily as byte values.
Four bytes taken together (known as a doubleword, or dword) can
hold one integer value in the range 0 to 4,294,967,295, or can hold
one single-precision floating-point value. Eight bytes together

48

Turbo Assembler User's Guide

(known as a quadword, or qword) can hold one double-precision
floating-point value. The 8086 doesn't handle these two data types
directly; however, the 8087 numeric coprocessor can work directly
with floating-point values and extended precision integer values,
and given the proper software, the 8086 can be made to handle
virtually any data type, albeit fairly slowly.
At any time, an 8086 program can read or change the contents of
any of the more than 1,000,000 bytes of memory. For example, the
code fragment
mov
mov
mov
mov

ax,O
ds,ax
bx,O
aI, [bx]

loads the contents of the byte at address 0 into the AL register.
Don't worry about the details here; the point is that the 8086's
memory address space provides for storage of slightly more than
1,000,000 working values that the 8086 can access quickly and
flexibly.
One megabyte (Mb) is a considerable amount of memory, far
more than the 64K (2 to the 16th power, or 65,536 bytes)
addressable by the processors that preceded the 8086. On the
other hand, the 8086's latest descendent, the 80386, can address
about 4,000 times as much memory as the 8086, so you can see
that the 8086 is, in fact, a little squeezed for memory space. Also,
in the IBM PC, only 640K of the 1 Mb address space is actually
available for use as general-purpose memory; the rest of the
address space is dedicated to use by system software and the
memory used for the display. Then, too, don't forget that
instructions, as well as data, are stored in memory, so both
program code and data must fit into no more than 640K of
memory on the PC.
While the 8086 is capable of addressing 1 Mb of memory, it does
not make it particularly easy to access more than 64K at anyone
time, due to a rather peculiar feature known as segmentation. We'll
look at segmentation in a later section, liThe segment registers,"
on page 61.

Chapter 4, The nature of assembly language

49

Input and output
The 8086 supports input and output devices in two ways: through
input/output (I/O) instructions and through memory addresses.
Some input and output devices are controlled through ports,
which are special I/O addresses in a 64K address space that's
separate from the 1 Mb memory address space, as shown in
Figure 4.3.
Figure 4.3
Separate memory
and I/O address of
8086

Memory
Address

I/O Address
.(fQr1l

00009

0000
0001
0002
0003
0004
0005
0006
0007
0008
0009

OOOOA

OOOA

00000
00001
00002
00003
00004
00005
00006
00007
00008

~

~

FFFF5
FFFF6
FFFF7
FFFF8
FFFF9
FFFFA
FFFFB
FFFFC
FFFFD
FFFFE
FFFFF

1---------1
J.--------1

1---------1
J.--------1
1---------1
1---------1
I . - - _ _ _ _- - - - l

FFF5
FFF6
FFF7
FFF8
FFF9
FFFA
FFFB
FFFC
FFFD
FFFE
FFFF

J.--------i
J.--------i
I---------i
J.--------i
J.--------i
I---------i
J.--------i
I---------i
I---------i
1 . - -_ _ _ _----1

There are far fewer I/O addresses on the 8086 than there are
memory addresses; while there are technically 64K I/O addresses
on the PC, practically speaking, only 4K I/O addresses are
available. Consequently, I/O addresses are not used for storing
values, but rather for providing control and data channels to
input and output devices. For example, serial devices such as
modems are controlled entirely through a few I/O addresses.

50

Turbo Assembler User's Guide

I/O addresses can be accessed only with two special instructions,
IN and OUT, which are used for nothing else. For example,
out dx,al
More on IN and our, and I/O
In general, In Chapter 5.

sends the contents of the AL register to the I/O port selected by
the DX register.
Some output devices are memory-mapped, meaning they are
controlled through normal memory addresses rather than I/O.
This is particularly true of display adapters, which can take up
16K, 32K, or even 256K of the 8086's memory address space with
their bit maps (the arrays of bytes describing the dots that the
.
adapters display on the screen).
A given device can be controlled through both I/O ports and
memory-mapped addresses. In fact, most display adapters
respond to I/O instructions for some functions and to memory
addresses for others.

Registers
The 8086 offers a few fast, on-chip storage elements known as
registers. You might think of registers as memory locations that
the 8086 can access faster than it can access regular memory, but
that's only part of what makes registers special. Each of the
registers has a unique nature, and provides certain capabilities
that no other register or memory location supports.
The registers fall into four categories: the flags register, the
general-purpose registers, the instruction pointer, and the
segment registers, as shown in Figure 4.4. Let's look at each in

turn.

Chapter 4, The nature of assembly language

51

Figure 4.4
Registers of the

8086

Bit Number

15

FLAGS

0

I
sub ex,l
jnz BeginningOfLoop

Don't worry about unfamiliar elements of this program; the
important point is that the instructions between the label
BeginningOfLoop and the JNZ instruction are executed repeatedly
until ex becomes o. Notice that two instructions-SUB eX,1 and
JNZ BeginningOfLoop-are required in order to count down CX
and jump back to BeginningOfLoop if ex is not yet o.

Chapter 4, The nature of assembly language

55

Counting down and looping is a frequently used program
element, so the 8086 provides a special instruction to make loops
faster and more compact. Not surprisingly, that instruction is
called LOOP. The LOOP instruction subtracts 1 from ex: and
jumps if CX isn't 0, all in one instruction. The following is
equivalent to the last example:

...

mov cx,lO
BeginningOfLoop:

loop BeginningOfLoop

We'll cover looping again in Chapter 5; for now, just remember
that the ex: register is especially useful for counting and looping.
The OX register
The DX register can be
treated as two 8-blt registers,
DHandDL.

The OX register is the only register that can be used as an I/O
address pointer with the IN and OUT instructions. In fact, there is
no way to address I/O ports 256 through 65,535 without using
OX. For example, the following code writes the value 62 to I/O
port 1000:
mov al,62
mov dx,lOOO
out dx,al

The other unique properties of OX relate to division and
multiplication. When you divide a 32-bit dividend by a 16-bit
divisor, the upper 16 bits of the dividend must be placed in OX;
after the division, the remainder of the division is stored in OX.
(The lower 16 bits of the dividend must be placed in AX, and the
quotient is stored in AX.) Similarly, when you multiply two 16-bit
factors, the upper 16 bits of the product are stored in OX (the
lower 16 bits of the product are stored in AX).
The SI register

Like the BX register, the SI register can be used as a memory
pointer. For example,

56

Turbo Assembler User's Guide

mov
mov
mov
mov

ax,O
ds,ax
si,20
aI, [si]

loads the 8-bit value stored at address 20 into AL. SI becomes an
unusually powerful memory pointer when used with the 8086's
string instructions. For example,
cld
mov ax,O
mov ds,ax
mov si,20
lodsb

not only loads AX with the value at the memory address pointed
to by SI, but also adds 1 to SI. This can be very effective when
accessing a sequential series of memory locations, such as a text
string. Better still, the string instructions can be made to
automatically repeat their actions any number of times, so a single
instruction can perform hundreds or even thousands of actions.
We'll discuss the string instructions in detail in Chapter 6.
The 01 register

The 01 register is much like the SI register in that it can be used as
a memory pointer and has special properties when used with the
powerful string instructions. For example,
mov
mov
mov
add

ax,O
ds,ax
di,1024
bl, [di]

adds the 8-bit value stored at address 1024 to BL. The 01 register
is a little different from SI when it comes to string instructions;
where SI always serves as a source memory pointer for string
instructions, 01 always serves as a destination memory pointer.
Moreover, with the string instructions, SI normally addresses
memory relative to the OS segment register, while 01 always
addresses memory relative to the ES segment register. (When SI

Chapter 4, The nature of assembly language

57

and 01 are used as memory pointers with non string instructions,
they always point relative to OS.) For example,
cld
mov dx,O
mov es,dx
mov di,2048
stosb

uses the SlOSB string instruction to both store the value in AL at
the memory address pointed to by 01 and add 1 to OI. But we're
getting ahead of ourselves here; you need to learn about segments
and segment registers before you can study the string instructions. Again, we'll look at the string instructions in Chapter 6,
''More about programming in Turbo Assembler."
The BP register

Like BX, 51, and 01, the BP register can be used as a memory
pointer, but with a difference. While the BX, 51, and 01 registers
normally act as memory pointers relative to the OS segment
register (or, in the case of OJ used with the string instructions, the
ES segment register), BP points relative to 55, the stack segment

register.
Chapter 7 explaIns how and
why C uses the stack to pass
parameters.

Once again, we're getting ahead of ourselves, since we haven't
covered segments yet, but the principle is as follows: One useful
way to pass parameters to a subroutine is by pushing the
parameters onto the stack. C and Pascal do this.
The stack resides in the segment pointed to by 55, or the stack
segment. Data, on the other hand, normally resides in the
segment pointed to by OS, or the data segment. Since BX, 51, and
OJ normally point to the data segment, there's no efficient way to
use BX, 51, or OJ to point to parameters passed on the stack
because the stack is usually in a different segment altogether.
BP solves this problem by providing addressing into the stack
segment. For example,

...

push bp
mov bp,sp
mov ax, [bp+4]

58

Turbo Assembler User's Guide

accesses the stack segment to load AX. with the first parameter
passed by a Turbo C call to an assembler subroutine.
In short, BP is designed to provide support for parameters, local
variables, and other stack-based memory-addressing needs.
The SP register

The SP register, also known as the stack pointer, is the least general
of the general-purpose registers, for it is almost always dedicated
to a specific purpose: maintaining the stack. The stack is an area of
memory into which values can be stored and from which they can
be retrieved on a last-in, first-out basis; that is, the last value
stored onto the stack is the first value you'll get when you read a
value from the stack. The classic analogy for the stack is that of a
stack of dishes. Since you can only add plates at the top of the
stack and remove them from the top of the stack, it stands to
reason that the first plate you put on the stack will be the last
plate you can remove.
The SP register points to the top of the stack at any given time; as
with the stack of dishes, the top of the stack is the location at
which the next value placed on the stack will be stored. The action
of placing a value on the stack is known as pushing a value on the
stack, and, indeed, the PUSH instruction is used to place values on
the stack. Similarly, the action of retrieving a value from the stack
is known as popping a value from the stack, and the POP
instruction is used to retrieve values from the stack.
For example, Figure 4.6 illustrates how SP, AX, and BX change as
the following code is executed, assuming that SP is initially set to
1,000:
mov
push
mov
push
pop
pop

ax,l
ax
bx,2
bx
ax
bx

While the 8086 allows you to store values in SP, and add to or
subtract from the value stored in SP, just as with the other
general-purpose registers, you should never do this unless you
know exactly what you're doing. If you change SP, you're

Chapter 4. The nature of assembly language

59

changing the location of the top of the stack, and that can quickly
lead to disaster.
Why? Well, pushes and pops aren't the only way the stack is used.
Whenever you call to or return from a subroutine (a procedure or
function), the stack is used. Also, some system resources, such as
the keyboard and the system clock, use the stack when they
interrupt the 8086 in order to perform their functions. What this
means is that the stack might be needed at any time. If you change
SP, even if only for a few instructions, then the correct stack might
not be available when some system resource needs it.
Figure 4.6

AX. BK SP. and the
stack

At start:
AX

?

996

BX

?

998

SP

1000

. - - - - - - ' r1000

After moy ax,1 I push ax:
AX

1

I

ex

?

SP

998

W

996
....--_r 998
1000

After moy bx,21 push bx:
AX

1

BX

2

SP

996

After pop ax:

U

....---- 996

AX

2

I

BX

2

SP

998

W

998
1000

996
....---- 998
1000

After pop bx:

60

AX

2

996·

?

BX

1

998

.1

SP

L..--_ _ _ _ _....J

~------~-~1000

?

1000

Turbo Assembler User's Guide

In short, leave SP alone unless you know just what you're doing.
Feel free to perform pushes, pops, calls, and returns, but don't
change the value of SP directly. Any of the other seven generalpurpose registers can be changed directly at any time.
The instruction pointer

The instruction pointer (lP) always contains the memory offset at
which the next instruction to be executed is stored. As one
instruction is executed, the instruction pointer is advanced to
point to the instruction at the next memory address. Normally,
the instruction at the next memory address is the next instruction
executed, but some instructions, such as calls and jumps, can
cause the instruction pointer to be loaded with a new value,
thereby branching to other code.
The instruction pointer can't be written to or read from directly;
only branching instructions such as those just described can load
the instruction pointer with a new value.
The instruction pointer does not, by itself, fully specify the
address at which the next instruction to be executed resides. Once
again, the segmented nature of 8086 memory addressing
complicates the picture. For instruction fetching, the CS segment
register provides a base address, and the instruction pointer then
provides an offset from that base address.
Each time we've talked about addressing memory, we've run into
segments, and each time we've postponed a full explanation until
the time came to talk about segments. That time has come.

The segment registers

Now we come to a most unusual aspect of the 8086-memory
segmentation. The basic premise of segmentation is this: The 8086
is capable of addressing 1 Mb of memory. Twenty-bit memory
addresses are required to address all locations in a 1 Mb memory
space. However, the 8086 only uses 16-bit pointers to memory; for
example, recall that the 16-bit BX register can be used to point to
memory. How, then, does the 8086 reconcile 16-bit pointers with a
20-bit address space?
The answer is that the 8086 uses a two-part memory-addressing
scheme. True, 16-bit memory pointers are used, but these form
only part of the full memory address. Each 16-bit memory pointer,
or memory offset, is combin~d with the contents of a 16-bit
segment register to form a full20-bit memory address.

Chapter 4, The nature of assembly language

61

Segments and offsets are combined as follows: The segment value
is shifted left by 4 bits (multiplied by 16) and then added to the
offset as shown in Figure 4.7.
Figure 4.7
20-blt memory
addresses

16-81t
Segment Register

16-81t
Offset

Segment Value
Times 16 Equals
A 20-81t Value

20-81t Memory Address
So, for example, consider the following code:

...

mov
mov
mov
mov

ax,lOOOh
ds,ax
si,201h
dl, lsi]

Here the OS segment register is set to 1000h, and SI is set to 201h,
which we can represent as the segment:offset pair 1000:201h.
(Segment:offset calculations can only be performed efficiently in
base 16-another good reason to familiarize yourself with
hexadecimal notation.) DL is loaded from the address
«DS ,. 16) + S1), or «1000h ,. 16) + 201h):

62

Turbo Assembler User's Guide

l000h
x

16

10000h
+ 201h

10201h
Figure 4.8 illustrates this example.
Figure 4.8
Calculation of
memory address by
mov

os

1000h

SI

201h

10000h

Memory
Address

10201h

Another way to look at this is to simply shift the segment value
left 4 bits, or one hexadecimal digit, which is the same as
multiplying by 16:
10000

+ 201
10201
You can now see that programs can only access the 8086's full
1 Mb memory space by using segment:offset pairs. In fact, you
must always use segment:offset pairs to access memory; all the
instructions and addressing modes of the 8086 default to
operating relative to one or another of the segment registers,

Chapter 4. The nature of assembly language

63

although some instructions can be explicitly told to use a different
segment register if desired.
Rarely will you actually load a number into a segment register.
Instead, you'll load segment registers with segment names, which
are turned into numbers in the course of assembling, linking, and
running a program. This is necessary because there's no way to
tell beforehand where in memory a given segment will reside; it
all depends on the version of DOS, the number and size of
memory-resident programs, and the memory needs of the rest of
the program. Using segment names lets Turbo Assembler and
DOS deal with all those complications.
The most common segment name is @data, which refers to the
default data segment when the simplified segment directives are
used. For example,
.MODEL small
•DATA

Varl DW 0
.CODE
mov ax,@data
mov ds,ax
END

loads OS to point to the default data segment, in which Varl
resides.
Once again, we're getting a bit ahead; in the next chapter, we'll
discuss the simplified segment directives and the loading of
segment registers.
The use of segments on the 8086 has a couple of interesting
implications. For one thing, only a 64K block of memory is
addressable relative to a segment register at anyone time because
64K is the maximum amount of memory that can be addressed
with a 16-bit offset. This means that it can be a real nuisance to
handle large (greater than 64K) blocks of data on the 8086, since
both a segment register and the offset value must be changed
frequently.
The addressing of large blocks of memory on the 8086 is made
still more difficult because, unlike the general-purpose registers,
the segment registers cannot serve as either source or destina tion
for arithmetic and logical instructions. In fact, the only operations
that can be performed on segment registers involve copying

64

Turbo Assembler User's Guide

values between segment registers and either general-purpose
registers or memory. For instance, adding 100 to the ES register
requires the following:
mov ax,es
add ax,lOO
mov es,ax

The upshot of all this is that the 8086 is best suited to handling
memory in chunks no larger than 64K.
A second implication of the use of segments is that any given
memory location is addressable with many possible
segment:offset combinations. For instance, the memory address
100h is addressable with segment:offset values of 0:100h, l:FUh,
2:EOh, and so on, since all those segment:offset pairs work out to
address 100h.
Like the general-purpose registers, each segment register plays a
specific role. The es register points to program code, the OS
register points to data, the SS register points to the stack, and the
ES segment is a wildcard ("extra") segment, free to point
wherever it's needed. Let's look at the segment registers in a bit
more detail.
The CS register

The es register points to the start of the 64K memory block, or
code segment, in which the next instruction to be executed resides.
The next instruction to be executed resides at the offset specified
by IP in the code segment; that is, at the segment:offset address
eS:IP. The 8086 can never fetch an instruction from a segment
other than that defined byeS.
The es register can be changed by a number of instructions,
including certain jumps, calls, and returns. The CS register cannot
be loaded directly under any circumstances.
No memory-addressing modes or memory pointers other than IP
normally operate relative to es.

Chapter 4, The nature of assembly language

6S

The OS register
Memory addressing Is
discussed further In Chapter

5.

The OS register points to the start of the data segment, which is
the 64K memory block where most memory operands reside.
Normally, memory offsets involving BX, SI, or DI operate relative
to OS, as do direct memory addresses. The data segment is,
basically, what its name implies: the segment in which the current
data set normally resides.
The ES register

The ES register points to the start of a 64K memory block known
as the extra segment. As the name implies, the extra segment isn't
dedicated to anyone purpose, but is available for whatever needs
arise. Sometimes, the extra segment is used to make an additional
64K block of memory available for data storage, but accessing
memory in the extra segment is normally less efficient than
accessing memory in the data segment, as discussed in Chapter 9,
"Advanced programming in Turbo Assembler."
Where the extra segment really shines is when the string
instructions are used. All string instructions that write to memory
use ES:DI as the memory address to write to. This means that ES
is extremely useful as the destination segment for block copies,
string comparisons, memory scanning, and clearing blocks of
memory. We'll look at the string instructions and the use of ES
registers in connection with them in Chapter 6, "More about
programming in Turbo Assembler."
The 55 register

The SS register points to the start of the stack segment, which is
the 64K memory block, where the stack resides. All instructions
that implicitly use the SP register-including pushes, pops, calls,
and returns-work in the stack segment because SP is only
capable of addressing memory in the stack segment.
As we discussed earlier, the BP register also operates relative to
the stack segment. This allows BP to be used for addressing
parameters and variables that are stored on the stack. (Again, we
discuss memory addressing in detail in the next chapter.)

66

Turbo Assembler User's Guide

The 8086
instruction set

To a programmer, the key resource of the 8086 is the instruction
set. As we discussed earlier, the instruction set includes all the
actions that a programmer can possibly tell the 8086 to perform.
(The complete instruction set of Turbo Assembler is in the Quick

Reference Guide.)
There are many instructions in the 8086 instruction set that
perform a wide variety of actions, ranging from doing nothing
(NaP) to copying as many as 65,535 bytes (REP MOVSB). We will
spend much of the rest of this chapter, and chapters 5, 6, and 9 as
well, covering the 8086's instruction set in detail.

The IBM PC and XT
We've focused on 8086 assembly language, but the truth of the
matter is that the 8086 processor is just part of a computer system,
and the hardware configuration and operating system of a
computer greatly affect assembly language programming.
The vast majority of programs written for the 8086 processor (and
perhaps the majority of programs written in the history of
computers) have been written for the IBM PC and XT and
compatible computers, running the MS-DOS operating system.
Turbo Assembler itself runs under the MS-DOS operating system
on IBM PCs, XTs, and compatibles (from now on referred to
simply as the IBM PC), so it's likely that you're planning to use
your copy of Turbo Assembler to develop assembler programs for
the IBM PC environment.
Without knowledge of the hardware configuration and the
operating system your assembler programs will run under, there's
no way for you to perform input or output, or even terminate
your programs. We haven't the space to cover nearly all the
capabilities of the IBM PC and its system software, but we'll show
you a few of the basic features of the PC. We suggest you read
more on your own in the books and manuals suggested at the
beginning of this chapter.

Chapter 4, The nature of assembly language

67

Input and output
devices All IBM PCs provide a keyboard, a display adapter and a monitor,
and a floppy disk drive. Modems, printers, mice, and hard disks
are frequently installed as well. Each of these devices is controlled
with a fairly complex series of accesses to I/O ports or memory
(or both). For example, selecting a new video mode on the Color
Graphics Adapter (CGA) requires over 30 OUT instructions;
keyboard, modem, and disk control sequences are more
complicated still.
Does this mean that you need to master endless control sequences
in order to write useful assembler programs on the IBM PC? Not
at all; your PC's systems software already does most of the work
for you.

Systems software
for the IBM PC Systems software is software that serves as a control and interface
layer between applications software, such as Turbo Assembler
and Quattro, and the hardware of your computer, as shown in
Figure 4.9.
In particular, systems software handles the complexities of
interfacing to individual devices. For example, several hundred
lines of assembly language code are required in order for your PC
to process a single keystroke, but your assembler programs can
get keystrokes by invoking just one system function. This is made
possible by the two main systems software components of the PC:
OOS and the BIOS (Basic Input/Output System).
In Figure 4.9, the OOS and BIOS systems software serves as a
control and interface layer between applications software and the
hardware of the IBM PC. Applications software always has the
option of controlling the hardware directly, but should use 005
or BIOS functions instead whenever possible.

68

Turbo Assembler User's Guide

Figure 4.9
DOS and BIOS
systems software as
a control and
interface layer

Applications Software

DOS
Accessed through Int 21 h DOS
functions and other Interrupts.

BIOS
Accessed through BIOS
functions by way of several
Interrupts.

IBM PC Hardware

-----------------------------------------------Display adapter, keyboard, printer, disk, mouse, joystick, and so
on. Accessed at UO ports and/or memory locations, depending
on the specific hardware Item.

DOS

DOS (short for Disk Operating System-also known as MS-DOS
and PC-DOS) is the program that controls your computer from
the moment it reads the disk at power-up until you turn the
power off. DOS takes up part of your precious 640K of available
memory, but there's no helping that, since without DOS your PC
is a very expensive paperweight. It's DOS that provides you with

the A> prompt (or C>, or whatever the prompt is on your
computer), and it's DOS that accepts and executes commands
such as DIR.
That's just the visible part of DOS. It also provides a broad array
of functions that are used heavily by just about every application.

Chapter 4, The nature of assembly language

69

It's through DOS functions that applications read from and write
to files, get keystrokes, allocate memory, run other programs, and
even set and get the time of day. For example, the assembler code
rnov ah,2
rnov dl,'A'
int 21h

;DOS function to display a character
;A is the character to display
;invoke DOS to execute the function

invokes the OOS "Display Output" function in order to display
the character A at the current cursor location on the screen.

IBM's DOS Technical
Reference manual Is the
primary reference for DOS
functions.

You should use OOS functions to perform operations such as
keyboard and file input, screen and file output, and printing
whenever possible. Since DOS itself is actually nothing but an
assembler program, it is certainly possible for you to do with your
own code everything that OOS functions do, but that's generally
not a good idea. Not all PC-compatible computers are alike, and
OOS frequently masks differences between makes of computers;
if you ignore the OOS functions and go straight to the hardware,
your programs might not run on other computers.
Then, too, programs that go around OOS might not coexist with
other programs, most notably memory-resident programs such as
SideKick and SuperKey. Besides, why spend time writing extra
code when OOS has already done the work for you? In short,
whenever a OOS function can do what you need done, use it!
In cases where OOS simply doesn't provide the functions you
need, it's time to use a BIOS function. We'll cover BIOS functions
shortly, but first let's take a look at some OOS functions that fulfill
essential needs: input, output, and program termination.
Getting keystrokes

Typing at the keyboard is the fundamental means of user
interaction with the PC. OOS provides a number of functions by
which an assembler program can obtain keystrokes; we're only
going to discuss one of those functions.
Perhaps the simplest means of getting keystrokes is with the
"Keyboard Input" function, DOS function number 1. OOS
functions are invoked by placing the function number in AH and
then executing an INT 21 h instruction. (The actual operation of the
INT instruction is a bit complex, but right now, all you need to
know is that you must execute an INT 21h instruction each time

70

Turbo Assembler User's GuIde

you want to invoke a DOS function.} The next character typed at
the keyboard is returned in AL.
For example, when this code is executed,
mov ah,l
int 21h

...

DOS places the next character typed at the keyboard into AL.
Note that if there is no keystroke waiting to be read, DOS waits
until a key is pressed, so this function can take an indefinitely
long period of time to complete.
Displaying characters on the screen

If keystrokes are the means of user interaction with software, the
screen is the complement. The PC is capable of all sorts of
displays, ranging from color text to high-resolution graphics, but
for the moment, we'll just go over displaying characters.

DOS function number 2 is a straightforward way to print a
character. Simply put 2 in AH and the character in DL, then
invoke DOS with INT 21 h. The following code echoes each
character typed to the screen:
mov
int
mov
mov
int

ah,l
21h
ah,2
dl,al
21h

;get next key pressed
;move character read from AL to DL
idisplay the character

Several other functions are available for reading and printing
characters and character strings, and you'll encounter some of
them in the example programs in this manual. Since a whole book
would be needed to cover all the DOS functions, we can't cover
them here. We strongly recommend, however, that you do get one
or more of the books and manuals listed at the end of this book
and learn more about the DOS functions-they're a key resource
in assembler programming.
There's one more point we'd like to make about keyboard, screen,
and file input and output in assembly language. Those of you
who are used to scant and prlntf in C and Readln and Writeln in
Pascal might be surprised to learn that DOS (and hence assembly

Chapter 4. The nature of assembly language

71

language) provides no support whatsoever for fonnatted input
and output; OOS only handles character and string input and
·output. In C, all you need to do to print an integer variable i is
this:
printf("%d\n",i);

C automatically converts the integer value, which is stored in a
16-bit memory location, into a string of ASCII characters and
prints the characters. In assembler, your code must explicitly
convert variables to character strings before displaying them.
Likewise, OOS only knows how to read characters and strings
from the keyboard, so you'll have to write code to convert
characters and strings entered by the user to other data types in
your assembler programs.
At the end of the next chapter, we'll show you an example
program that illustrates exactly what you have to do in an
assembler program to print out the value of a variable. For now,
bear in mind that DOS functions can print a character, or a string
of characters-and that's it. It's up to you to convert your data to
the character fonn that DOS can handle.
Ending a program

Now that you know a bit about reading and writing a program,
let's write a simple program that does nothing but echo one line of
keystrokes to the screen. You know all the OOS functions you'll
need, save one: You have no way to end the program once it's
finished executing.
Again, those of you familiar with C or Pascal might think that
assembler programs would simply end when they come to the
end of the main program, but that's not the case. You must
explicitly invoke a DOS function in order to terminate your
assembler programs.
There are several DOS functions for terminating programs, but
the preferred method is to execute a DOS function number 4Ch
(that's 76, for those of you who prefer decimal). With that
knowledge, here's the complete echo program
(ECHOCHAR.ASM):
.MODEL small
.STACK lOOh
•CODE
EchoLoop:

72

Turbo Assembler User's Guide

mov ah,l
int 21h
cmp al,13
jz EchoDone
mov dl,al
mov ah,2
int 21h
jmp EchoLoop
EchoDone:
mov ah,4ch
int 21h
END

iDOS keyboard input function f
iget the next key
iwas the key the Enter key?
iyes, so we're done echoing
iput the character into DL
iDOS display output function
idisplay the character
iecho the next character
iDOS terminate program function f
iterminate the program

Enter the program exactly as shown and run it. You'll see that
each character you type appears twice; once when it is echoed by
DOS as it's typed, and once as your program echoes it. The
important point about this program is that it reads keystrokes,
writes characters to the display, and terminates, all by way of
DOS functions.

The BIOS

IBM's BIOS Interface
Technical Reference manual
is the primary reference for
BIOS functions.

Sometimes DOS functions just don't meet your needs; then it's
time to turn to the PC's Basic Input/Output System, or BIOS.
Unlike DOS and applications software, the BIOS is not loaded
from disk and does not take up any of your 640K of available
memory; instead, the BIOS is stored in Read-Only Memory
(ROM) in the portion of the 8086's address space reserved for
system functions.
The BIOS is the lowest-level software in the PC; even DOS uses
BIOS functions to control the hardware. It's better to use BIOS
functions than to control hardware directly, since, like DOS, the
BIOS can mask differences between various computers and
devices. On the other hand, you should use DOS functions rather
than BIOS functions whenever you can, since programs that use
the BIOS can conflict with other programs, and tend to be less
portable across a variety of computer models.
Selecting display modes

The most pressing reason to use the BIOS is for controlling the
display, since DOS provides virtually no support for the rich
display capabilities of the PC. Only by invoking BIOS functions
can you set the screen mode, control colors, get display adapter
information, and so on. For example, the following code invokes
the BIOS to set the screen to four-color graphics mode on a CGA:

Chapter 4, The nature of assembly language

73

mov ah,O
mov al,4
int lOh

;BIOS set mode function f
;mode number for 320x200 4-color graphics
;execute BIOS video interrupt to set mode

If you recall that we said that over 30 OUT instructions are
required to set a video mode, you'll realize that the BIOS "Set
Mode" function saves you a great deal of work.

The BIOS provides a variety of functions other than those related
to display control, including keystroke-handling and disk control.
In general, however, you're better off performing these tasks
through DOS functions.

Sometimes you
absolutely need
to go to the
hardware

Now that you've heard all the reasons to use DOS functions (or, if
absolutely necessary, BIOS functions), it's time to admit that
sometimes you just flat-out have to access the hardware directly.
For instance, communications software has to control the PC;s
serial port directly with IN and OUT instructions, since neither
DOS nor the BIOS provides adequate support for serial
communications. Similarly, high-performance graphics must be
performed by accessing display memory directly, since DOS
doesn't support graphics, and the BIOS does so only in a painfully
slow manner.
The basic rule about going to the hardware is to make sure you
have no alternative. If there's a DOS or BIOS function you can use,
use it; if not, access the hardware directly. Mer all, the object-of
programming is to produce useful programs, not to follow rules.
On the other hand, the fewer rules you break, the fewer problems
you'll generally have.

Other resources
The PC provides a number of other hardware and software
resources for the assembly language programmer. We can't go
into those resources here, but we can list a few; for more
information, refer to the materials mentioned at the start of this
chapter.
• The ANSI.SYS driver provides enhanced display control
without the need for BIOS functions.

74

Turbo Assembler User's Guide

• The system timers support a time-of-day clock; they also
support sound-generation via the PC's speaker and precision
timing.
• The optional 8087 numeric coprocessor speeds up floating-point
calculations by orders of magnitude.

Chapter 4, The nature of assembly language

75

76

Turbo Assembler User's Guide

c

H

A

p

T

E

R

5
The elements of an assembler program
Now that you understand what it is that makes assembly
language unique, you're ready to tackle the nuts and bolts of
assembler programming.
You'll spend this chapter learning about the fundamental
components of an assembler program. First, we'll teach you about
the minimum requirements of a working assembler program.
Next, we'll discuss the various components of a line, and the
ways in which they can be combined. Along the way, you'llieam
a good bit about instructions, directives, and the ways in which
assembler programs can access memory. You'll find out how
segments are defined and used in Turbo Assembler, and you'll
. look at the allocation and initialization of memory variables.
Finally, we'll look at some commonly used instructions.
That's a lot of ground to cover, but when you're done with this
chapter, you'll know enough to start writing programs. You can,
put that knowledge to work with a word-counting program
provided at the end of the chapter.
Still, this chapter only begins to explore the many aspects of
assembly language, so Chapter 6, ''More about programming in
Turbo Assembler," and Chapter 9, Advanced programming in
Turbo Assembler," continue on to new assembly language topics.
1/

Chapter 5, The elements of an assembler program

77

The components and structure of an assembler
program
Now that you've developed an understanding of what 8086
assembly language is, you're ready to start writing assembler
programs. Let's start by looking at the minimum requirements of
a working assembler program. Even a simple assembler program
requires quite a few lines. For instance, consider the following
program:
•MODEL small
.STACK 200h
•DATA
DisplayString DB 13,10
ThreeChars

DB

3 DUP

DB

'$'

(?)

•CODE
Begin:
mov ax,@data
mov ds,ax
mov bx,OFFSET ThreeChars
mov
int
dec
mov
inc

ah,1
21h
al
[bx],al
bx

int 21h
dec al
mov [bx),al
inc bx
int 21h
dec al
mov [bx],al
mov dx,OFFSET DisplayString
mov
int
mov
int

78

ah,9
21h
ah,4ch
21h

inear code and data models
i512-byte stack
istart of the data segment
icarriage-return/linefeed pair
i to start a new line
istorage for three characters
i typed at the keyboard
ia trailing "$" to tell DOS when
i to stop printing DisplayString
i when function 9 is executed
istart of the code segment
ipoint DS to the data segment
ipoint to the storage location
i for first character
iDOS keyboard input function f
;get the next key pressed
;subtract 1 from the character
istore the modified character
;point to the storage location
i for the next character
;get the next key pressed
;subtract 1 from the character
istore the modified character
ipoint to the storage location
i for the next character
iget the next key pressed
isubtract 1 from the character
istore the modified character
ipoint to the string of
i modified characters
iDOS print string function f
iprint the modified characters
iDOS end program function f
iend the program

Turbo Assembler User's Guide

END Begin

;directive to mark the end of the source
; code and to indicate where to start
; execution when the progra~ is run

This program contains the simplified segment directives .MODEL,
.STACK, .DATA, and .CODE, as well as the END directive. Segment
directives, either simplified or standard, are required in every
assembler program in order to define and control segment usage,
and the END directive must always terminate assembler code.
We'll cover both segment directives and END in this chapter, and
some other directives as well.
Directives only provide the framework for an assembler program,
though; you also need lines in your source code that actually do
something, lines like
mov

(bx],al

and
inc dx

These are instruction mnemonics, corresponding to the
instruction set of the 8086 that you learned about in chapter 4.
Before you can use either instructions or directives, however, you
must first learn about the format of a line of assembler code,
which we'll get to right after a cursory look at Turbo Assembler's
reserved words.
In case you were wondering what the first example program
does, enter it, type in IBM, and the program will respond
HAL

The program reads three characters, subtracts the value 1 from
each of them, and prints the result.

Reserved words
Turbo Assembler reserved words, or keywords, are strictly for
use by the assembler; you can't use them for defining your own
equates, labels, or procedure names. Rather, you should think of
reserved words as the building blocks of assembly language. The
words listed in Table 5.1 include operators (+, *, -, +), directives
(.386, ASSUME, MASM, QUIRKS), and predefined symbols
(??tlme, ??verslon, @WordSlze), which are like predefined
equates, and aliases.

Chapter 5, The elements of an assembler program

79

Table 5.1: TASM reserved words

=
?

[]
I
()

+

*
.186
.286
.286C
.286P
.287
.386
.386C
.387
.8086 .
.8087
ALIGN
.ALPHA
AND
ARG
ASSUME
%BIN
BYTE
CATSTR
@Code
CODESEG
@CodeSize
COMM
COMMENT
%CONDS
.CONST
CONST
@Cpu
%CREF
.CREF
%CREFALL
%CREFREF
%CREFUREF
%CTLS
@Curseg
@data
•DATA
.DATA?
DATAPTR
DATASEG

80

@datasize
??date
DB
DO
%0 EPTH
OF
DISPLAY
DOSSEG
DP
DQ
DT
DUP
OW
DWORD
ELSE
ELSEIF
EMUL
END
ENDIF
ENDM
ENDP
ENDS
EQ
EQU
ERR
.ERR
.ERR1
.ERR2
.ERRB
.ERRDEF
ERRDIF
ERRDIFI
ERRE
ERRIDN
ERRIDNI
ERRIFNB
ERRIFNDEF
ERRNB
ERRNDEF
ERRNZ
EVEN
EVEN DATA
EXITM
EXTRN
FAR
FAR DATA
@fardata
.FARDATA
@fardata?
•FA RDATA?

@filename
??fllename
FWORD
GE
GLOBAL
GROUP
GT
HIGH
IDEAL
IF
IF1
IF2
IFB
IFDEF
IFDIF
IFDIFI
IFE
IRON
IRDNI
IFNB
IFNDEF
%lNCL
INCLUDE
INCLUDELIB
INSTR
IRP
IRPC
JUMPS
LABEL
.LALL
LARGE
LE
LENGTH
.LFCOND
%LlNUM
%LlST
.LlST
LOCAL
LOCALS
LOW
LT
MACRO
%MACS
MASK
MASM
MASM51
MOD
MODEL
.MODEL
MULTERRS

NAME
NE
NEAR
%NEWPAGE
%NOCONDS
%NOCREF
%NOCTLS
NOEMUL
%NOINCL
NOJUMPS
%NOLIST
NOLOCALS
%NOMACS
NOMASM51
NOMULTERRS
NOSMART
%NOSYMS
NOT
NOTHING
%NOTRUNC
NOWARN
OFFSET
OR
ORG
%OUT
P186
P286
P286N
P287
P386
P386N
P386P
P387
P8086
P8087
PAGE
%PAGESIZE
PARA
%PCNT
PN087
%POPLCTL
PROC
PTR
PUBLIC
PURGE
%PUSHLCTL
PWORD
QUIRKS
QWORD
RADIX

.RADIX
RECORD
REPT
.SALL
SEG
SEGMENT
.SEQ
.SFCOND
SHL
SHORT
SHR
SIZE
SIZESTR
SMALL
SMART
STACK
.STACK
STRUC
SUBSTR
SUBTTL
%SUBTTL
%SYMS
SYMTYPE
°kTABSIZE
TBYTE
%TEXT
.TFCOND
THIS
??time
TITLE
%TITLE
%TRUNC
TYPE
.TYPE
UDATASEG
UFARDATA
UNION
UNKNOWN
USES
??version
WARN
WIDTH
WORD
@WordSize
.XALL
.XCREF
.XLlST
XOR

Turbo Assembler User's Guide

The format of a line
Assembly language source code lines follow this format:

Source Exif Data:
File Type                       : PDF
File Type Extension             : pdf
MIME Type                       : application/pdf
PDF Version                     : 1.3
Linearized                      : No
XMP Toolkit                     : Adobe XMP Core 4.2.1-c043 52.372728, 2009/01/18-15:56:37
Producer                        : Adobe Acrobat 9.12 Paper Capture Plug-in
Modify Date                     : 2009:07:18 10:09:15-07:00
Create Date                     : 2009:07:18 10:09:15-07:00
Metadata Date                   : 2009:07:18 10:09:15-07:00
Format                          : application/pdf
Document ID                     : uuid:a3feaab1-3239-4146-8912-00dde15c1a39
Instance ID                     : uuid:adb48330-da18-4de1-a838-34826e2131fb
Page Layout                     : SinglePage
Page Mode                       : UseNone
Page Count                      : 518
EXIF Metadata provided by EXIF.tools

Navigation menu