Turbo Assembler Version 4.0 Users Guide Nov93
Turbo Assembler Version 4.0 Users Guide Nov93
Turbo Assembler"
Users Guide
Borland
Turbo Assembler®
Version 4.0
Borland may have patents andbr pending patent applications covering subject matter in this
document. The furnishing of this docu ment does not give you any license to these patents.
COPYRIGHT © 1988, 1993 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.
1EOR1193
9394959697-98765
H1
c o N T E N T s
Introduction 1 In ................................. 24
Hardware and software requirements 2 10 ............. ..................... 25
About the manuals .................... 2 loi ................................. 25
Notational conventions ................ 4 lop ................................ 25
Contacting Borland ................... 5 los ....... .......................... 25
Ip ................................. 26
Chapter 1 Getting started with Turbo Iq ................................. 26
Assembler 7 Ir .................................. 26
Installing Turbo Assembler ............. 7 Is .................................. 27
Turbo Assembler's executable files .... 8 It .................................. 27
Utility and example programs ........ 8 lu ................... : ............. 28
Writing your first Turbo Assembler Iv ................................. 28
program ................... 1 • • • 8 • • • • • ••
Iw ... .............................. 28
Assembling your first program ...... 10 Ix ................................. 30
Linking your first program . . . . . . . . .. 11 Iz ................................. 30
Recommended reading ............... 12 Izd ................................ 30
Chapter 2 Using directives and Izi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 31
switches 13 Izn ................................ 31
Starting Turbo Assembler . . . . . . . . . . . .. 13 Indirect command files ............... 31
Command-line options ............... 16 The configuration file . . . . . . . . . . . . . . . .. 32
la ................................. 17 Chapter 3 General programming
Ib ................................. 17 concepts 35
Ic .............................. .... 17 Turbo Assembler Ideal mode .......... 35
Id ................................. 18 Why use Ideal mode? ............. " 36
Ie ................................. 18 Entering and leaving Ideal mode . . . .. 37
Ihor /? ............................ 19 MASM and Ideal mode differences . .. 38
Ii .................................. 19 Expressions and operands . . . . . . . .. 38
Ij .................................. 20 Operators . . . . . . . . . . . . . . . . . . . . . .. 38
Ikh ................................ 21' Suppressed fixups . ~ ........... " 39
II .................................. 21 Operand for BOUND instruction . .. 39
Ila ......... '........................ 21 Segments and groups . ; . . . . . . . . . .. 39
1m .. ............................... 22 Accessing data in a segment belonging
Iml ................................ 22 to a group ................. '.' .... 40
Imu ............................... 23 Commenting the program. . . . . . . . . . . .. 42
Imv# ...................... .' ........ 23 Comments at the end of the line ..... 42
Imx ............................ .... 24
The COMMENT directive ..... '.' . . .. 43 Describing a complex address
Extending the line . . . . . . . . . . . . . . . . . . .. 43 subtype ......................... 'i' 75
Using INCLUDE files ................ , 44 Expressions ...................... , .. 76
Predefined symbols .................. 45 Expression precision ............... 76
Assigning values to symbols . . . . . . . . . .. 46 Constants in expressions ... . . . . . . . .. 77
General module structure ............. 47 Symbols in expressions ............. 77
The VERSION directive ............ , 47 Registers ... . . . . . . . . . . . . . . . . . . . . .. 77
The NAME directive ............. 48 Standard symbol values .......... 77
The END directive . . . . . . . . . . . . . .. 48 Simple symbol values ............ 78
Displaying a message during assembly . 49 The LENGTH unary operator. . . . .. 79
Displaying warning messages ......... 50 The SIZE unary operator . . . . . . . . .. 79
Multiple error-message reporting ...... 51 The WIDTH unary operator ....... 80
The MASK unary operator ........ 80
Chapter 4 Creating object..oriented General arithmetic operators ........ 81
, programs 53 Simple arithmetic operators ....... 81
Terminology ....................... . 53 Logical arithmetic operators ....... 81
Why use objects in Turbo Assembler? .. . 54 Bit shift operators .. . . . . . . . . . . . . .. 81
What is an object? ................... . 54 Comparison operators .. . . . . . . . . .. 82
A sample object ................... . 55 Setting the address subtype of an
Declaring objects .................. . 56 expression ...................... 82
Declaring a base object ........... . 56 Obtaining the type of an expression . 83
Declaring a derived object ........ . 58 Overriding the segment part of an
Declaring a method procedure ......... . 59 address expression . . . . . . . . . . . . . .. 84
The virtual method table ............. . 61 Obtaining the segment and offset of an
Initializing the virtual method table ., 61 address expression . . . . . . . . . . . . . .. 84
Calling an object method ............. . 62 Creating an address expression using
Calling a static method ............ . 62 the location counter .............. 85
Calling a virtual method ............ . 63 Determining the characteristics of an
Calling ancestor virtual methods .... . 65 expression ...................... 86
More on calling methods ........... . 67 Referencing structure, union, and table
Creating an instance of an object ...... . 67 member offsets .................. 86
Programming form for objects ........ . 68 Describing the contents of an
A programming example .......... . 69 address ......................... 87
Chapter 5 Using expressions and Implied addition . . . . . . . . . . . . . . . .. 87
symbol values 71 Obtaining the high or low byte values
Constants .......................... , 71 of an expression ................. 87
Numeric constants ................ . 71 Specifying a 16- or 32-bit expression. 88
Changing the default radix ....... . 72 Chapter 6 Choosing processor
String constants ................... . 73 directives and symbols 91
Symbols ... " ....................... . 73 iAPx86 processor directives ........... 91
Symbol names .................... . 73 Predefined symbols .................. 93
Symbol types ..................... . 73 @Cpu .............................. 93
Simple address subtypes ........... . 74 @WordSize .............. 'J' • • • • • • • • •• 94
ii
8087 coprocessor directives . . . . . . . . . . .. 95 Specifying structure and union
Coprocessor emulation directives ...... 95 members ..................... '. .. 119
Defining structure member labels with
Chapter 7 Using program models and LABEL' ........................ 120
segmentation 97 Aligning structure members . . . . .. 120
The MODEL directive . . . . . . . . . . . . . . . .. 98 Closing a structure or union
Symbols created by the MODEL definition ................... . . . .. 120
directive .. . . . . . . . . . . . . . . . . . . . . . .. 101 Nesting structures and unions ...... 121
The @Model symbol . . . . . . . . . . . .. 101 Including one named structure within
The @32Bit symbol .............. 101 another . . . . . . . . . . . . . . . . . . . . . . . . .. 122
The @CodeSize symbol ... " ..... 102 Using structure names in
The @DataSize symbol ........... 102 expressions ....................... 124
The @Interface symbol ... '" ..... 102 Defining tables ..................... 124
Simplified segment directives . . . . . .. 103 Overriding table members ......... 126
Symbols created by the simplified Defining a named type .............. 126
segment directives .............. 104 Defining a procedure type ........... 127
The STARTUPCODE directive ...... 104 Defining an object . . . . . . . . . . . . . . . . . .. 128
The @Startup symbol· ........... , 105 The TBLPTR directive ............. 129
The EXITCODE directive ........ 105 Symbols defined by the extended STRUC
Defining generic segments and groups. 105 directive . . . . . . . . . . . . . . . . . . . . . . . .. 129
The SEGMENT directive ... . . . . . . .. 105
Segment combination attribute ... 106 Chapter 9 Setting and using the
Segment class attribute .......... 107 location counter 131
Segment alignment attribute. . . . .. 107 The $ location counter symbol ........ 131
Segment size attribute ........... 108 Location counter directives ........... 132
Segment access attribute ......... 108 The ORG directive ................ 132
The ENDS directive ............... 108 The EVEN and EVENDATA
The GROUP directive ............. 109 directives .................... . . .. 134
The ASSUME directive .............. 109 The ALIGN directive " .......... " 135
Segmentordering ................. 111 Defining labels ..................... 135
Changing a module's segment The: operator .................... 136
ordering .... . . . . . . . . . . . . . . . . . .. 111 The LABEL directive .............. 136
The .ALPHA directive ......... 111 The :: directive . . . . . . . . . . . . . . . . . . .. 137
The .sEQ directive ............ 111
DOS ordering of segments: the Chapter 10 Declaring procedures 139
DOSSEG directive. . . . . . . . . . . . . .. 112 Procedure definition syntax .......... 139
Changing the size of the stack ...... 112 Declaring NEAR or FAR procedures. 140
Declaring a procedure language .... 142
Chapter 8 Defining data types 115 Specifying a language modifier ..... 144
Defining enumerated data types ...... 115 Defining arguments and local variables . 145
Defining bit-field records ............ 117 ARG and LOCAL syntax ......... " 146
Defining structures and unions ....... 118 The scope of ARG and LOCAL variable
Opening a structure or union names ........................... 148
definition ........................ 118 Preserving registers ............... 149
iii
Defining procedures using procedure . Additional IRET instructions ......... 177
types .......................... 149 Extended PUSH and POP instructions . 177
Nested procedures and scope rules .... 150 Multiple PUSH and POPs ....... _. .. 177
Declaring method procedures for Pointer PUSH and POPs ........... 178
objects ................. ; . . . . . . . . . .. 152 PUSHing constants on the 8086
Using procedure prototypes . . . . . . . .. .. 152 processor .......... '. . . . . . . . . . . . .. 178
Additional PUSHA, POPA, PUSHF and
Chapter 11 Controlling the scope of POPF instructions ................... 178
symbols 155 Extended shifts .................. . .. 179
Redefina~le symbols ................ 155 Forced segment overrides: SEGxx
Block scoping' ..................... '. 156 instructions ........................ 179
The LOCALS and NOLOCALS Additional smart flag instructions . . . .. 180
directives ........................ 156 ~dditio~al field value manipulation
MASM block scoping . . . . . . . . . . . . .. 157 mstructi<;>ns ...................... . .. 181
MASM-style local labels ............. 158 The SETFIELD instruction. . . . . . . . .. 181
Chapter 12 Allocating data 159 The GETFIELD instruction ...... . .. 182
Simple data directives ............... 160 Additional fast immediate multiply
Creating an instance of a structure or instruction. . . . . . . . . . . . . . . . . . . . . . . .. 182
union ............................. 164 Extensions to necessary instructions for the
Initializing union or structure 80386 processor . . . . . . . . . . . . . . . . . . . .. 183
instances ......................... 164 Calling procedures with stack frames .. 184
Creating an instance of a record . . . . . .. 167 Calling procedures that contain
Initializing record instances ...... 168 RETURNS ................ ,. . . . . .. 186
Creating an instance of an enumerated data Calling procedur>s that have been
type .................' .............. 169 prototyped .... : .................. 186
Initializing enumerated data type Calling method procedures for objects:
instances ....................... 169 CALL..METHOD ................. 187
Creating an instance of a table ........ 170 Tail recursion for object methods:
Initializing table instances .......... 170 JMP ..METHOD ................... 188
Creating and initializing a named-type Additional instruction for object-oriented
instance ........................... 171 prograrnrning ...................... 188
Creating an instance of an object ...... 172 Chapter 14 Using macros 189
Creating an instance of an object's virtual Text macros ........................ 189
method table ........... . . . . . . . . . . .. 172 Defining text macros with the EQU
Chapter 13 Advanced coding directive .. . . . . . . . . . . . . . . . . . . . . . .. 190
instructions 173 String macro manipulation directives. 190
Intelligent code generation: SMART and The CATSTR directive ........... 191
NOSMART ........................ 173 The SUBSTR directive ........... 191
Extendedjumps .................... 174 The INSTR directive . . . . . . . . . . . .. 191
Additional 80386 LOOP instructions ... '175 The SIZESTR directive . . . . . . . . . .. 191
Additional 80386 ENTER and LEAVE Text macro manipulation
instructions ........................ 175 examples ...................... 191
Additional return instructions ........ 176 Multiline macros .................... 192
iv
The multiline macro body ......... . 192 Including conditionals in the list file . .. 218
Using & in macros ............. . 193
Including comments in macro Chapter 16 Interfacing with the
bodies ........................ . 194 linker 219
Local dummy arguments ....... . 194 Publishing symbols externally ........ 219
The EXITM directive ........... . 195 Conventions for a particular
Tags and the GOTO directive .... . 195 language ......................... 219
General multiline macros ......... . 196 Declaring public symbols .......... 220
Invoking a general multiline Declaring library symbols .......... 221
macro ........................ . 197 Defining external symbols .......... 221
The < > literal string brackets .. . 198 Defining global symbols ........... 222
The ! character ............... . 199 Publishing a procedure prototype ... 222
The % expression evaluation Defining communal variables . . . . . .. 222
character .................... . 199 Including a library .................. 224
Redefining a general multiline The ALIAS directive. . . . . . . . . . . . . . . .. 224
macro ......................... 199 Chapter 17 Generating a listing 225
Deleting a general multiline macro: The Listing format ...................... 225
PURGE directive . . . . . . . . . . . . . . .. 200 General list directives ............... 226
Defining nested and recursive Include file list directives ............ 228
macros ........................ 200 Conditional list directives ... . . . . . . . .. 228
The count repeat macro . . . . . . . . . . .. 201 Macro list directives . . . . . . . . . . . . . . . .. 229
The WHILE directive .............. 202 Cross-reference list directives ......... 230
String repeat macros .............. 202 Changing list format parameters ...... 232
The % immediate macro directive ... 204
Including multiline macro expansions in Chapter 18 Interfacing Turbo
the list file . . . . . . . . . . . . . . . . . . . . . . .. 204 Assembler with Borland
Saving the current operating state . . . .. 204 C++ 237
Calling Turbo Assembler functions from
Chapter 15 Using conditional Borland C++ ....................... 238
directives 209 The framework ......... . . . . . . .. .. 239
General conditional directives syntax .. 209 Linking assembly language modules
IFxxx conditional assembly with C++ .... -. . . . . . . . . . . . . . . . .. 239
directives ........................ 209 Using Extern "c" to simplify
ELSEIFxxx conditional assembly linkage ...................... 241
directives ........................ 211 Memory models and segments . . .. 241
ERRxxx error-generation directives .. 212 Simplified segment directives and
Specific directive descriptions ........ 213 Borland C++ ................. 242
Unconditional error-generation Old-style segment directives and
directives ........................ 213 Borland C++ ................. 243
Expression-conditional directives .... 213 Segment defaults: When is it
Symbol-definition conditional necessary to load segments? .... 245
directives ........................ 214 Publics and. externals ... . . . . . . . .. 247
Text-string conditional directives. . .. 215 Underscores and the C language . 248
Assembler-pass conditionals ....... 217
v
The significance of uppercase and Windows programs ................. 279
lowercase ........... ~ ......... 249 Windows DLL blueprint .. . . . . . . . .. 280
Label types . . . . . . . . . . . . . .. . . .. 249 Windows 16-bit application
Far externals ................. 251 blueprint ........................ 281
Linker command line . . . . . . . . . . .. 252 Windows 32-bit application
Parameter passing ................ 252 blueprint ........................ 281
Preserving registers ............. 260
Returning values . . . . . . . . . . . . . . .. 260 Appendix B Turbo Assembler syntax
Calling an assembler function from summary 283
C++ ............................. 262 Lexical grammar . . . . . . . . . . . . . . . . . . .. 283
Writing C++ member functions in MASM mode expression grammar .... 285
. assembly language . . . . . . . . . . . . . . .. 265 Ideal mode expression grammar ...... 287
Pascal calling conventions ........... 267 Keywordprecedence ................ 290
Calling Borland C++ from Turbo Ideal mode precedence .............. 290
Assembler ......................... 269 MASM mode precedence .......... 291
Link in the C++ startup code ....... 269 Keywords and predefined symbols . . .. 291
The segment setup ................ 269 Directive keywords ............... 292
Performing the call . . . . . . . . . . . . . . .. 270 Appendix C ~ompatibility issues 297
Calling a Borland C++ function from One-pass versus two-pass assembly ... 298
Turbo Assembler ................. 271 Environment variables. . . . . . . . . . . . . .. 298
Appendix A Program blueprints 275 Microsoft binary floating-point format . 299
Simplified segmentati~n segment Appendix 0 Error messages 301
description . . . . . . . . . . . . . . . . . . . . . . . .. 275 Information messages ............... 301
DOS programs .................... :. 276 Warning and error messages ......... 302
DOS EXE program blueprint ........ 277 Fatal error messages ................. 329
COM program blueprint .... . . . . . .. 278
Index 333
vi
T A B L E s
1.1: Turbo Assembler's executable files .... 8 7.6: Segment combination attribute ..... 106
4.1: Object-oriented programming 7.7: Segment alignment attribute ....... 107
terminology ....................... 54 7.8: Segment size attribute values ...... 108
4.2: Symbols defined for objects ......... 54 7.9: Segment access attribute ........... 108
4.3: Files in OOP example .............. 69 7.10: Stack size modification directives .. 113
5.1: Radixes .......................... 71 8.1: STRUC, UNION, and ENDS
5.2: Characters determining radixes ..... 72 directives ........................ 121
5.3: Numeric constants ................. 72 8.2: Block members ................... 122
5.4: Symbol types ..................... 74 8.3: Available modifiers ............... 129
5.5: Address subtypes ................. 74 8.4: Symbols used or defined by STRUC .130
5.6: Complex address subtypes ......... 75 12.1: Data size directives .............. 160
5.7: Distance syntax ................... 75 13.1: Intelligent code generation
5.8: Simple expressions ................ 76 directives ....................... 174
5.9: Standard symbols ................. 77 13.2: Return instructions .............. 176
5.10: Values of symbols used by 13.3: Segment override instructions ..... 179
themselves ....................... 78 13.4: Smart flag instructions ........... 180
5.11: LENGTH operator return values .... 79 13.5: Instructions for setting and retrieving
5.12: SIZE values ...................... 79 values ......................... 181
5.13: WIDTH values ................... 80 13.6: Instructions affected by SMALL and
5.14: MASK return values .............. 80 LARGE ........................ 184
5.15: Simple arithmetic operators ........ 81 14.1: Dummy argument types .......... 197
5.16: Logical arithmetic operators ........ 81 14.2: Uses for the! character ........... 199
5.17: Bit shift operators ................. 81 15.1: Conditional assembly directives using
5.18: Comparison operators ............. 82 expressions ..................... 213
5.19: Type override operators ........... 83 15.2: Error-generation directives using
5.20: TYPE values ..................... 83 expressions ..................... 214
5.21: Bit fields from SYMTYPE and 15.3: Evaluation of defined and undefined
.TYPE ........................... 86 symbol ......................... 214
6.1: Processor directives ................ 92 15.4: Symbol-expression directives using
6.2: 8087 coprocessor directives ......... 95 symbol_expr .................... 215
7.1: Standard memory models ......... 100 15.5: Error-generation directives ....... 215
7.2: Model modifiers .................. 100 15.6: Conditional assembly directives using
7.3: Model modifiers .................. 102 text_strings .......... " ......... 215
7.4: Simplified segment directives ...... 103 15.7: Error-generation directives using
7.5: Symbols from simplified segment text_strings " ................... 216
directives ........................ 104
vii
18.1: Register settings when Borland C++ B.1: Turbo Assember V1.0 (VERSION TI00)
enters assembler ................. 245 keywords ......................'. 292
A.1: Default segments and types for TINY B.2: Turbo Assembler V2.0 (VERSION T200)
memory model .................. 275 new keywords ................... 295
A.2: Default segments and types for SMALL B.3: Turbo Assembler V2.5 (VERSION T250)
memory model .................. 275 new keywords ................... 295
A.3: Default segments and types for B.4: Turbo Assembler V3.0 (VERSION T300)
MEDIUM memory model ......... 276 new keywords ......... ~ ...... ~ .. 295
A.4: Default segments and types for B.5: Turbo Assembler V3.1 (VERSION T310) .
. COMPACT memory model ....... 276 new keywords .: ................. 295
A.5: Default segments and types for LARGE B.6: Turbo Assembler V3.2 (VERSION T320)
or HUGE memory model ......... 276 new keywords ................... 295
A.6: Default segments and types for Borland
C++ HUGE (TCHUGE) memory
model .......................... 276
viii
F G u R E s
1.1: The edit, assemble,link, and run 18.2: State of the stack just before executing
cycle ............................. 10 Test's first instruction ............ 254
2.1: Turbo Assembler command line ..... 13 18.3: State of the stack after PUSH and
10.1: How language affects procedures .. 144 MOV ............... ; .......... 255
18.1: Compile, assemble, and link with 18.4: State of the stack after PUSH, MOV,
Borland C++, Turbo Assembler, and and SUB ....................... 256
TLINK ......................... 238 18.5: State of the stack immediately after
MOV BP, SP .................... 268
ix
x
N T R o D u c T o N
Introduction
modules. You then use TLINK.EXE, Borland's high-speed linker
program, to link your object modules and create executable (.EXE)
files.
Introduction 3
Appendix B: Turbo Assembler syntax summary illustrates Turbo
Assembler expressions (both MASM and Ideal modes) in
modified Backus-Naur form (BNF).
Appendix C: Compatibility issues covers the differences between
MASM and Turbo Assembler MASM mode.
Appendix D: Utilities lists the utilities you can use with Turbo
Assembler.
Appendix E: Error messages describes all the error messages that
can be generated when using Turbo Assembler: information
messages, fatal error messages, warning messages, and error
messages.
Notational conventions
When we talk about IBM pes or compatibles, we're referring to
any computer that uses the 8088, 8086, 80186, 80286, 386, and i486
chips (all of these chips are commonly referred to as 80x86).
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, place-
holders are set in italics to indicate they are user-
defined.
Boldface Boldface is used in text for directives, instructions,
symbols; and operators, as well as for command-
line 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 or text that appears on your screen, and any
text that you must actually type to assemble, link,
and run a program.
Keycaps In text, keycaps 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."
Introduction 5
6 Turbo Assembler User's Guide
c H A p T E R
Turbo Assembler's
executable files The Turbo Assembler 4.0 package comes complete with 3
different assemblers, as outlined in the following table:
Table 1.1
Turbo Assembler's File name Description
executable files
TASM.EXE Real-mode assembler. Assembles 16- and 32-bit
applications using the 640K addressable by DOS.
Produces only 16-bit debug information.
TASMX.EXE Protected-mode assembler. Assembles 16-and
.32-bit applications using memory above 640K.
Produces only 16-bit debug information.
TASM32.EXE Protected-mode assembler. Assembles 16-and
32-bit applications using memory above 640K.
Produces only 32-bit debug information.
Utility and
example The Turbo Assembler package includes several utility programs
programs to help you build assembly programs. For a complete list of the
utilities included with Turbo Assembler, refer to the online text
file TSM_INST.TXT. For instructions on using the utilities, refer to
the text file TSM_UTIL.TXT.
To get you $tarted writing assembler programs, the Turbo
Assenlbler pp-ckage includes various example programs that
demonstrate different assembler programming techniques. The
example programs even include complete 16- and 32-bit Windows
assembly programs. For a complete listing of the example
programs, refer to the online text file TSM_INST.TXT.
Assembling your
first program Now that you've saved HELLO.ASM, you'll want to run it.
However, before you can run it, you'll have to assemble it into an
.OBJ file, and then link the file to form an executable program.
This program development cycle is shown in Figure 1.1.
Figure 1.1
The edit, assemble, link, and Create a New Program
run cycle
Assemble
Object File
HELLO.OBJ
Link
Executable File
HELLO.EXE
Run
I
(If changes are needed) ~
Errors can occur during the linking process, although it's unlikely
with this example program. If you do receive linker errors,
modify your code to exactly match the code shown here, then
assemble and link again.
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
want to assemble. A file name can be a single file name, or it can
use the normal wildcard characters * 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,
Command-line options
/0
Function Specifies alphabetical segment-ordering
Syntax la
Remarks 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 wantto 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 / aTESTl
This command line creates an object file, TESTl.OBJ, that has its segments
in alphabetical order.
/b
Syntax Ib
Remarks The Ib option is included for compatibility. It performs no action and has
no effect on the assembly.
Ie
Function Enables cross-reference in listing file
Syntax Ie
Remarks 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 11 1c TESTl
This code creates a listing file that also has cross-reference information in
the symbol table.
Id
Function Defines a symbol
Syntax Idsymbol[=value or expression]
Remarks 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 con-
stant 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.
Example TASM IdMAX=lO IdMIN=2 TESTl
This command line defines two symbols, MAX and MIN, that other
statements in the source file TESTl.ASM can refer to.
Ie
Function Generates floating-point emulator instructions
Syntax Ie
Remarks 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 floating-
point emulation library. (Borland'sline of C++ compilers, Borland 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 comm<;lnd 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 I 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.
Ih or/?
Function Displays a help screen
Syntax Ih or I?
Remarks 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 /? option does the same thing.
Example TASM Ih
Ii
Function Sets an include file path
Syntax liPATH
Remarks 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 specifie~ 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 Ii \ INCLUDE liD: \INCLUDE TESTl
/j
Function Defines an assembler startup directive
Syntax' /jdirective
Remarks 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.
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 I j .286 I j IDEAL TESTl
This code assembles the file TESTl.ASM with 80286 instructions enabled
and Ideal mode expression-parsing enabled.
/kh
Function Sets the maximum number of symbols allowed
Syntax /khnsymbo]s
Remarks 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 IkhlOOOO BIGFILE
This command tells Turbo Assembler to reserve space for 10,000 symbols
when assembling the file BIGFILE.
/1
Function Generates a listing file
Syntax 11
Remarks The II option indicates that you want a listing file, even if you did not
explicitly specify it on the command line. The listing file will have the
same name as the source file, with an extension of .LST.
Example TASM II TESTl
This command line requests a listing file that will be named TESTl.LST.
/10
Function Shows high-level interface code in listing file
Syntax Ila
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 high-
level language int~rface .MODEL directive.
Example TASM Ila FILEl
1m
Function Sets the maximum number of assembly passes
Syntax 1m [npasses]
Remarks Normally, Turbo Assembler functions as a single-pass assembler. The 1m
option lets you specify the maximum number of passes the assembler
should make during the assembly process. TASM automatically decides
whether it can perform less than the number of passes specified. If you
select the 1m option, but don't specify npasses, a default of five is used.
You might want to specify multiple passes either if you want Turbo
Assembler to remove Nap instructions added because of forward
references or if you are assembling a module containing instructions that
require two passes. 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 assembles this
module correctly but will not optimize the code by removing Naps, no
matter how many passes are allowed. The warning "Module is pass
dependent-compatibility pass was done" is displayed if this occurs.
Example TASM 1M2 TESTl
Iml
Function Treats symbols as case-sensitive
Syntax Iml
Remarks The Iml option tells Turbo Assembler to treat all symbol names as case-
sensitive. 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
/mu
Function Converts symbols to uppercase
,Syntax /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 Irnu TESTl
makes sure that all symbols are converted to uppercase (which is the
default):
EXTRN rnyfunc:NEAR
call rnyfunc idon't know if declared as
i MYFUNC, Myfunc, ...
/mv#
Function Sets_ the maximum length of symbols.
Syntax' /mv#
Remarks The Imv# option sets the maximum length of symbols that T ASM will
distinguish between. For example, if you set Imv12, TASM will see
ABCDEFGHIIKLM and ABCDEFGHIIIKLL as the same symbol, but not
ABCDEFGHIIKL. Note that the minimum number you can have here is 12.
Imx
Function Makes public and external symbols case-sensitive
Syntax Irnx
Remarks 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.
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 one of Borland's line of C++ compilers.
Example TASM Irnx TESTli
where TESTl.ASM contains the following source lines:
EXTRN Cfunc:NEAR
myproc PROC NEAR
call Cfunc
Note: using the Imx and Iml optiQns together has a special meaning for
symbols declared as Pascal; if you use these symbols together, the symbols
will be published as all uppercase to the linker. .
In
Function Suppresses symbol table in listing file
Syntax In
Remarks 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!1 In TESTl
This code generates a listing file showing the generated code only, and not
the value of your symbols.
/0
Function Generates overlay code for TLINK
Syntax 10
Remarks Specifying the /0 switch on the command line causes overlay-compatible
fixups to be generated. When this switch is used, 386 references to USE32
segments should not be made since they won't link properly.
/oi
Function Generates overlay code for the IBM linker
Syntax loi
Remarks Specifying the /Oi switch on the command will generate overlay-
compatible fixups for the IBM linker. The resulting object file will not be
compatible with TLINK, Borland's linker.
/op
Function Generates overlay code for the Phar Lap linker
Syntax lop
Remarks Specifying the /op switch on the command will generate overlay-
compatible fixups for the Phar Lap linker. The resulting object file will not
be compatible with TLINK, Borland's linker.
/os
Function Outputs TLINK-compatible objects without overlay support. This is th~
default selection.
Syntax los
Remarks , Specifying the /os switch on the command will generate objects without
overlay support for use with TLINK.
/p
Function Checks for impure code in protected mode
Syntax /p
Remarks The /p 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 con-
sidered 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 in
protected mode on the 80286, 386, or i486.
Example TASM /p TESTl
/q
Function Suppresses .OBJ records not needed for linking
Syntax /q
Remarks The /q option removes the copyright and file dependency records from
the resulting .OBJ files, making it smaller. Don't use this option if you are
using MAKE or a similar program that relies on the dependency records.
/r
Function Generates real floating-point instructions
Syntax /r
Remarks The /r 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 80x87 numeric coprocessor.
/s
Function Specifies sequential segment-ordering
Syntax Is
Remarks 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 la 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 /s TESTl
This code creates an object file (TESTl.OBJ) that has its segments ordered
exactly as they were specified in the source file.
/t
Function Suppresses messages on successful assembly
Syntax It
Remarks 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 TESTl
lu
Function Sets version ID in command line
Syntax lu version
Remarks The lu option lets you specify which version of Turbo Assembler or
MASM you want to use to run your modules. This is the command-line
version of the VERSION directive.
Iv
Syntax Iv
Remarks ,The Iv option is included for compatibility. It performs no action and has
no effect on the assembly.
Iw
Function Controls the generation of warning messages
Syntax Iw
w- [warnclass)
Wt [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 Segment alignment
ASS Assuming segment is 16-bit
Ix
Function Includes false conditionals in listing
Syntax /x
Remarks 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 use 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.
Example TASM Ix TESTl
Iz
Function Displays source lines along with error messages
Syntax /z
Remarks 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.
Example TASM Iz TESTl
Izd
Function Enables line-number information in object files
Syntax /zd
Remarks The Izd option causes Turbo Assembler to place line-number information
in the object file. This lets the 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, you can
use /zd for some modules and /zi for others.
Example TASM / zd TESTl
/zi
Function Enables debug information in object file
Syntax /zi
Remarks The /zi 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 let you
examine and modify your program's data.
The /zi option lets you use all the features of the debugger to step through
your program and examine or change your data items. You can use /zi on
all your program's modules, or just on those you're interested in
debugging. Since the /zi switch adds information to the object and exe- ,
cutable programs, you might not want to use it on all your modules if you
run out of memory when running a program under the debugger.
Example TASM /zi TESTl
/zn
Function Disables debug information in object file
Syntax /zn
Remarks The /zn option tells Turbo Assembler to disable the output of debugging
information to the object file. It's useful for overriding any prevailing /zi
switch in a configuration file.
This way you can keep long lists of standard files and options in files, so
that y()u 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.
Entering and
leaving Ideal Use the IDEAL and MASM directives to switch between Ideal and
mode MASM modes. Turbo Assembler always starts assembling a
source file in MASM mode. To switch to Ideal mode, include the
IDEAL directive in your source file before using any Ideal mode
capabilities. From then on, or until the next MASM directive, all
statements behave as described in this chapter. You can switch
back and forth between MASM and Ideal modes in a source file as
many times as you wish and at any place. Here's a sample:
DATA SEGMENT istart in MASM mode
abc LABEL BYTE iabc addresses xyz as a byte
xyz DW 0 idefine a word at label xyz
DATA ENDS iend of data segment
IDEAL iswitch to Ideal mode
SEGMENT CODE isegment keyword now comes first
PROC MyProc iproc keyword comes first, too
Expressions and The biggest difference between Ideal and MASM mode expres-
operands sions is the way square brackets function. In Ideal mode, square
brackets always refer to the contents of the enclosed quantity.
Brackets never cause implied additions to occur. Many standard
MASM constructions, therefore, are not permitted by Ideal mode.
In Ideal mode, square brackets must be used in order to get the
contents of an item. For example,
mov aX,wordptr
displays a warning message. You're trying to load a pointer
(wordptr) into a register (AX). The correct form is
mov ax, [wordptr]
Using Ideal mode, it's clear you are loading the contents of the
location addressed by wordptr(in the current data segment at DS)
into AX.
If you wish to refer to the offset of a symbol within a segment,
you must explicitly use the OFFSET operator, as in this example:
mov aX,OFFSET wordptr
Suppressed fixups Turbo Assembler in Ideal mode does not generate segment.;.
relative fixups for private segments that are page- or paragraph-
aligned. Because the linker does not require such fixups, assem-
bling programs in Ideal mode can result in smaller object files that
also link more quickly than object files generated by MASM
mode. The following demonstrates how superfluous fixups occur
in MASM but not in Ideal mode:
This difference has no effect SEGMENT DATA PRIVATE PARA
on code that you write. The
documentation here is simply VAR1 DB 0
for your information. VAR2 DW 0
ENDS
SEGMENT CODE
ASSUME ds:DATA
mov ax,VAR2 ino fixup needed
ENDS
Operand for BOUND The BOUND instruction expects a WORD operand, not a DWORD;
instruction This lets you define the lower and upper bounds as two constant
words, eliminating the need to convert the operand to a DWORD
with an explicit DWORD PTR. In MASM mode, you must write
BOUNDS DW 1,4 ilower and upper bounds
BOUND AX, DWORD PTR BOUNDS irequired for MASM mode
but in Ideal mode, you need only write
BOUNDS DW 1,4 ilower and upper bounds
BOUND M, [BOUNDS) ilegal in Ideal mode
Accessing data in a In Ideal mode, any data item in a segment that is part of a group
segment belonging to is considered to be principally a member of the group, not of the
a group
segment. An explicit segment override must be used for Turbo
Assembler to recognize the data item as a member of the segment.
MASM mode handles this differently; sometimes a symbol is
considered to be part of the segment instead of the group. In
particular, MASM mode treats a symbol as part of a segment
when the symbol is used with the OFFSET operator, but as part of
a group when the symbol is used as a,pointer in a data allocation.
This can be confusing because when you directly access the data
without OFFSET, MASM incorrectly generates the reference
relative to the segment instead of the group.
, Here's an example of how easily you can get into trouble with
MASM's addressing quirks. Consider the following incomplete
MASM program, which declares three data segments:
dsegi SEGMENT PARA PUBLIC 'data'
vi DB 0
dsegi ENDS
dseg2 SEGMENT PARA PUBLIC 'data'
v2 DB 0
dseg2 ENDS
dseg3 SEGMENT P~RA PUBLIC 'data'
v3 DB 0
dseg3 ENDS
DGROUP GROUP dsegi,dseg2,dseg3
cseg SEGMENT PARA PUBLIC 'code'
ASSUME cs:cseg,ds:DGROUP
Comments at the
end of the line There are several ways to comment assembler code. One
approach is to add a comment at the end of a line using the
semicolon (;), such as
mov . [bxl, al istore the modified character
The COMMENT
directive The COMMENT directive lets you comment blocks of code.
COMMENT ignores all text from the first delimiter character and
the line containing the next occurrence of the delimiter. The
following example uses * as a delimiter character:
COMMENT only works in
MASMmode. COMMENT *
stuff here
The VERSION
directive Using the VERSION directive lets you specify which version of
Turbo Assembler or MASM you've written particular modules for.
This is helpful for upward and downward compatibility of
various versions of TASM andMASM. The VERSION directive
also puts you into the operating mode for the specified version.
You can specify the VERSION directive as either a command-line
switch or within program source code.
Within code, the syntax is
VERSION <version_ID>
You can specify the following legal version IDs:
M400 MASM 4.0
M500 MASM 5.0
M510 MASM 5.1
M520 MASM 52 (Quick ASM)
TI00' Turbo Assembler 1.0
TI0l Turbo Assembler 1.01
T200 Turbo Assembler 2.0
T250 Turbo Asseinbler 2.5
T300 Turbo Assembler 3.0
T310 Turbo Assembler 3.1
T320 Turbo Assembler 3.2
T400 Turbo Assembler 4.0
The command-line syntax is:
/U<version_ID>
The NAME directive Use the NAME directive to set the object file's module name. Here
is the syntax for it:
NAME modulename
This directive only works in Turbo Assembler usually uses the source file name with any
Ideal mode.
drive, directory, or extension as the module name. Use NAME if
you wish to change this default name; modulenarrze will be the new
name of the module. For example,
NAME loader
The END directive Use the END directive to mark the end of your source file. The
syntax looks like this:
END [ start address 1
startaddress is an optional symbol or expression that specifies the·
address in your program where you want execution to begin. If
Terminology
These terms are described in
detail later in this chapter.
c++ and Pascal use different terms for various entities in object-
oriented programming. Turbo Assembler more closely resembles
What is an object?
An object consists of a data structure and associated procedures
(called methods) that manage data stored in instances of the data
structure.
We strongly recommend that An object can inherit characteristics from a parent object. This
you use Ideal mode for
object-oriented means that the new object's data structure includes the parent
programming in Turbo object's data structure, as well as any new data. Also, the new
Assembler, since symbol
scoping is global in MASM, object can call all the method procedures of the parent object, as
and you can't distinguish well as any new method procedures it declares.
different positions of shown
methods.
An object having no inheritance is called a base object; an object
that inherits another is a derived object.
Turbo Assembler defines several symbols you can use when
declaring objects. The following table lists these symbols.
Table 4.2
Symbols defined for objects Symbol Meaning
@Object A text macro containing the name of the
current object (the object last declared).
A sample object
As an example of where you can use objects, consider any
program that uses linked lists. Think of a linked list as an object
consisting of the linked list data and the operations (methods)
that you can perform on it.
The linked list data consists of pointers to the head and tail of the
linked list (this example contains a doubly linked list because of
its flexibility). Each element of the linked list is a separate object
instance.
The following operations provide the power needed to use a
linked list:
• Creating the linked list (allocating memory for it).
• Destroying the linked list (deallocating memory for it).
• Initializing the linked list.
• Deinitializipg the linked list.
• Inserting an item into the middle of the linked list before an
existing item.
• Appending an item to the end of the linked list.
• Deleting an item from the linked list.
• Returning the first item in the linked list.
• Returning the last item in the linked list.
Keep in mind that create and initialize, as well as destroy and
deinitialize methods are not synonymous. create and destroy
methods allocate and deallocate memory for the linked list object,
while the initialize and deinitialize methods only initialize and
deinitialize previously allocated instances of the object. If you
don't combine initialization with creation, it's possible to statically
allocate linked list objects.
Declaring objects
Declaring an object consists of declaring the data structure for the
object, and declaring the method procedures that you can call for
the object. Declaring an object does not involve creating an
instance of the object. You'llieam how to do this later.
Declaring a base When you declare an object, Turbo Assembler creates a STRUC
object that declares the data for the object, and a TABLE that declares the
methods for the object. The object's data declaration is a structure
with the same name as the object. The object's method
declarations are stored in a TABLE data type, named
@Table_<objectnarne>.
For more on STRUC as it For example, for the list object, two data types are declared:
applies to declaring objects,
see Chapter 8.
list A STRUC declaring the following members:
list_head dword pointer to head of list
list_tail dword pointer to tail of list
Declaring a derived An object that inherits another object's methods and data is called
object a derived object. You can't override the members of the parent data
structure, but you can override the individual methods by
respecifying them in the new object method list.
An object can inherit any other single object" whether that other
object is a base or derived object itself. The inherited object is
called the parent object. The derived object inherits the data and
methods of the parent object, so you should only use inheritance
when these methods and data are useful to the new object.
For example, you can define a queue object that inherits the
linked list object because you can implement a queue as a linked
list. Here's an example of such a derived object:
queue STRUC GLOBAL list METHOD {
init:DWORD=queue_init
virtual insert:word = queue_insert ; (queue node insert
Initializing the
virtual method Simply creating the instance of the VMT is not enough to let you
table make calls to virtual methods. Every object with virtual methods
includes a pointer to the VMT in its data structure. You must
initialize this pointer whenever you create an instance of an
object, and can use TBLINIT to do so.
Ini tialize the VMT pointer in the in it method for the object as
follows:
Notice that the init method iInitialize a Linked List object.
must be static because you
can't call a virtual method iThis is the method "init".
for an object instance until iThis must be a static method!
after you initialize the virtual list_init PROC PASCAL FAR
table pointer.
ARG @@list:dword
USES ds,bx
Ids bX,@@list
i-- Initialize any virtual method table for the object at ds:bx
TBLINIT ds:bx
i-- Initialize the object's data --
Calling a static
method When making a call to a method procedure, you should write the
CALL..METHOD instruction as if you were making a call to a
virtual method, even if you know that you're calling a static
method. Doing so will have no ill effects on static method calls,
and gives you the flexibility of changing methods from static to
virtual or back again without having to change all the calls to the
method. For the same reasons, you should specify a reasonable
selection for the intermediate calling registers, even if you know
that the method you're calling is static.
Calls to static methods are resolved at compile time to direct calls
to the desired method procedure for the object. However, when
making the call, you should not make a direct call to the method
procedure; instead, use the extended CALL..METHOD instruction.
The following example shows a sample call to the static init
method for the linked list object.
CALL foolist METHOD list:init pascal,ds offset foolist
CALL es:di METHOD list:init pascal,es di
The call address itself is the address of an instance of the object.
This address is used for syntactic reasons only; the actual call
generated is a direct call to the method procedure.
In this example, the first call is to the init method for the object list.
Since this is a static method, you make a direct call to the method
procedure list_in it. Turbo Assembler ignores the object instance,
foolist (except that it's passed as an argument to the method
procedure).
The method name is followed by the usual extended call language
and parameter list. The language and parameters depend on the
Calling a virtual
method Any call to a virtual method requires an indirect call to the
method procedure. You can use the extended CALL..METHOD
instruction to let this happen. Turbo Assembler generates the
following instructions to perform the call:
Calling ancestor
virtual methods Using ancestor virtual methods can help you write methods for
derived classes since you can reuse some of the code. For
example, queues can use the same listing method as. a list, as long
as you specify whether the item is a queue or a list. Within the list
class, you can have
virtual show:word = list_show
and within the queue class,
virtual show:word = queue_show
The list_show routine might print LIST SHOW:, followed by a listing
of the individual items in the list. However, if the derived class
queue_show uses the listing routine, it should print its own title,
@@not_a_list:
i Now show the individual list elements.
More on calling
methods Often, you might find it necessary to call a parent object's method
from inside a derived method procedure. You can also use the
CALL..METHOD statement to do this.
You can use the JMP instruction with the METHOD extension in
the same way you use the CALL .. METHOD instruction. This
instruction provides optimal tail recursion. See Chapter 12 for
more information about the CALL..METHOD and JMP.. METHOD
instructions.
MODEL SMALL
LOCALS
i** Define Linked-List object **
INCLUDE node.aso
i** Create instance of Linked-List virtual method table **
DATASEG
TBLINST
i** Linked-List methods **
CODESEG
ii«include all method procedures here»
In general, you should use the following form for object-oriented
programming in Turbo Assembler:
File Contents
<object> .ASO INCLUDEs <parent_object>.ASO, if any; contains
GLOBAL object declaration and a GLOBAL directive
for each method procedure.
<object> .ASM INCLUDEs <object>.ASO; contains TBLINST
directive and method procedure declarations; has an
init method with a TBLINIT somewhere inside.
A programming
example The EXAMPLES directory contains files that demonstrate how to
use the object-oriented features of Turbo Assembler. These
example modules use the list and queue objects described earlier,
and a stack object. A node object is declared that is the base object
of any user data stored in the linked list, queue, or stack. The
following table lists the relevant example files:
Table 4.3
Files in OOP example File Contents
NODE.ASO Declares node object and methods.
NODE.ASM Contains node object methods and virtual
method table instance.
LIST.ASO Declares list object and methods.
LIST.ASM Contains list object methods and virtual
method table instance.
QUEUE.ASO Declares queue object and methods.
QUEUE.ASM Contains queue object methods and virtual
method table instance.
STACK.ASO Declares stack object and methods.
STACK.ASM Contains stack object methods and virtual
method table instance.
OOP.ASM Contains an example of how to use these
objects.
Constants
Constants are numbers or strings that Turbo Assembler interprets
as a fixed numeric value. You can use a variety of different
numeric formats, including decimal, hexadecimal, binary, and
octal.
Numeric
constants A numeric constant in Turbo Assembler always starts with a digit
(0-9), and consists of an arbitrary number of alphanumeric char-
acters. The actual value of the constant depends on the radix you
select to interpret it. Radixes available in Turbo Assembler are
binary, octal, decimal, and hexadecimal, as shown in Table 5.1:
Table 5.1
Radixes Radix Legal digits
Binary 01
Octal 01234567
Decimal 0123456789
Hexadecimal o1 2 34 5 6 78 9 ABC D E F
Changing the default You can use the RADIX or .RADIX directives to change the current
radix default radix. Use the following syntax' for Ideal mode:
RADIX expression
Here's the MASM mode syntax:
.RADIX expression
expression must have a value of either 2 (binary), 8 (octal), 10
(decimal), or 16 (hexadecimal). Turbo Assembler assumes that the
current default radix is decimal while it processes the RADIX
directive.
Symbols
A symbol represents a value, which can be a variable, address
label, or an operand to an assembly instruction and directive.
Symbol names
Symbol names are combinations of letters (both uppercase and
lowercase), digits, and special characters. Symbol names can't
start with a digit. Turbo Assembler treats symbols as either case
sensitive or case insensitive. The command line switches IML, IMU,
and IMX control the case sensitivity of symbols.
See Chapter 2 for Symbols names can be up to 255 characters in length. By default,
information about using
these command-line symbol names are significant up to 32 characters. You can use the
switches. IMV command-line switch to change the number of characters of
significance in symbols.
The underscore L), question mark (?), dollar sign ($), and at-sign
(@) can all be used as part of a symbol name. In MASM mode
only, you can use a dot (.) as the first character of a symbol name.
However, since it's easy to confuse a dot at the start of a symbol
with the dot operator (which performs a structure member
operation), it's better not to use it in symbol names.
Symbol types
Each symbol has a type that describes the characteristics and
information associated with it. The way you define a symbol
determines its type. For example, you can declare a symbol to
represent a numeric expression, a text string, a procedure name,
Simple address
subtypes Symbols subtypes describe whether the symbol represents the
address of a byte, a word, and so forth. Table 5.5 shows the simple
address subtypes that Turbo Assembler provides.
Table 5.5: Address subtypes
Describing a
complex address Several directives let you declare and use complex address
subtype subtypes. These type expressions are similar to C in that they can
represent multiple levels of pointer indirection, for example, the
complex type expression
PTR WORD
represents a pointer to a word. (The size of the pointer depends
on the segmentation mo~el you selected with MODEL.)
Table 5.6 shows a ~yntax summary of complex address subtypes:
Table 5.6
Complex address subtypes Syntax Meaning
simple_address_subtype the specified address
subtype
[dist ]PTR[complex_address _subtype] a pointer to the specified
complex address subtype,
the size of which is
determined by the current
MODEL or by the specified
distance, if present
Expressions
Using expressions lets you produce modular code, because you
can represent program values symbolically. Turbo Assembler
performs any recalculations required because of changes (rather
than requiring you to do them).
Turbo Assembler uses standard infix notation for equations.
Expressions can contain operands and unary or binary operators.
Unary operators are placed before a single operand; binary
operators are placed between two operands. Table 5.8 shows
examples of simple expressions.
Table 5.8
Simple expressions Expression Evaluates to
5 constant 5
-5 constant-5
4+3 constant 7
4*3 constant 12
4*3+2*1 constant 14
4*(3+2)*1 constant 21
Expression
precision Turbo Assembler always uses 32-bit arithmetic in Ideal mode. In
MASM mode, Turbo Assembler uses either 16-; or 32-bit arith-
metic, depending on whether you select the 80386 processor.
Therefore, some expressions might produce different results
depending on which processor you've selected. For example,
(1000h * 1000h) / 1000h
evaluates to 1000h if you select the 80386 processor, or to 0 if you
select the 8086, 80186, or 80286 processors.
Symbols in
expressions When you use a symbol in an expression, the returned value
depends on the type of symbol. You can use a symbol by itself or
in conjunction with certain unary operators that are designed to
extract other information from the entity represented by the
symbol.
Standard symbol Some symbols always represent specific values and don't have to
values be defined for you to use them. The following table lists these
symbols and their values.
Table 5.9
Standard symbols Symbol Value
$ Current program counter
NOTHING a
? a
UNKNOWN a
BYTE . 1
WORD 2
DWORD 4
PWORD 6
FWORD 6
Simple symbol values Turbo Assembler returns the following values for symbols used
by themselves:
Table 5.10: Values of symbols used by themselves
Expression Value
The LENGTH unary The LENGTH operator returns information about the count or
operator number of entities represented by a symbol. The actual value
returned depends on the type of the symbol, as shown in the
following table.
Table 5.11: LENGTH operator return values
Expression Value
LENGTH address_name Returns the count of items allocated when the address name was
defined.
LENGTH struc/table_member_name Returns the count of items allocated when the member was
defined (MASM mode only)
The SIZE unary operator The SIZE operator returns size information about the allocated
data item. The value returned depends on the type of the symbol
you've specified. The following table, lists the available values for
SIZE .
. Table 5.12: SIZE values
Expression Value
SIZE address_name In Ideal mode, returns the actual number of bytes allocated to the
data variable. In MASM mode, returns the size of the subtype of
address_name (UNKNOWN=O, BYTE=l, WORD=2, DWORD=4,
PWORD=FWORD=6, QWORD=8, TBYTE=10,
SHORT=NEAR=Offffh, FAR=Offfeh, structure address=size of
structure) multiplied by the value of LENGTH address_name.
SIZE struc!union_name Returns the number of bytes required to represent the structure or
union.
SIZE table_name Returns the number of bytes required to represent the table.
SIZE struc/ table_member_name Returns the quantity TYPE struc/table_member_name * LENGTH
struc/table_member_name (MASM mode only).
The SIZE operator returns the value 0 when used on all other
symbol types.
The WI DTH unary The WIDTH operator returns the width in bits of a field in a
operator record. The value depends on the type of symbol. The following
table shows these types of symbols. You can't use WIDTH for any
other symbol types.
Table 5.13
WIDTH values Expression Value
WIDTH record_name Returns the total number of bits
reserved in the record definition.
WIDTH recordJield_name Returns the number of bits reserved for
the field in the record definition.
WIDTH enum_name Returns the number of bits required to
represent the maximum value in the
enum definition.
The MASK unary The MASK operator creates a mask from a bit field, where bits are
operator set to 1 in the returned value and correspond to bits in a field that
a symbol represents. The value returned depends on the type of
symbol, as shown in the following table. Note that you can't use
MASK on any other symbols.
Table 5.14
MASK return values Expression Value
MASK record_name Returns a mask where the bits reserved to
represent bit fields in the record
definition are I, the rest O.
MASK recordJield_name Returns a mask where the bits reserved
for the field in the record definition are I,
the rest O.
MASK enum_name Returns a mask where the bits required to
represent up to the maximum value
present in the enum definition are I, the
rest o.
Simple arithmetic Turbo Assembler supports the simple arithmetic operators shown
operators in the following table.
Table 5.15
Simple arithmetic operators Expression Value
+ expression Expression.
- expression Negative of expression.
exprl + expr2 exprl plus expr2.
exprl - expr2 exprl minus expr2.
exprl * expr2 exprl multiplied by expr2.
exprl / expr2 exprl divided by expr2 using signed integer
division; note that expr2 cannot be 0 or greater
than 16 bits in extent.
exprl MOD expr2 Remainder of exprl divided by expr2; same
rules apply as for division.
Logical arithmetic Logical operators let you perform Boolean algebra. Each of these
operators operators performs in a bitwise manner; that is, the logical
operation is performed one bit at a time. The following table
shows the logical operators.
Table 5.16
Logical arithmetic operators Expression Value
NOT expression expression bitwise complemented
exprl AND expr2 exprl bitwise ANDed with expr2
exprl OR expr2 exprl bitwise ORed with expr2
exprl XOR expr2 exprl bitwise XORed with expr2
Bit shift operators Shift operators move values left or right by a fixed number of bits.
You can use them to do quick multiplication or division, or to
access the value of a bitfield within a value. The following table
lists the bit shift operators.
Table 5.17
Bit shift operators Expression Value
exprl SHL expr2 exprl shifted left by expr2 bits (shifted right if
expr2 is negative).
Note that the SHL and SHR operators shift in Os from the right or
left to fill the vacated bits.
Setting the address Turbo Assembler provides operators that let you override or
SUb~~~e~~i~~ change the type of an expression. The following table lists these
operators.
Expression Value
exprl PTR expr2 Converts expr2 to the type determined by exprl, where O=UNKNOWN,
I=BYTE, 2=WORD, 4=DWORD, 6=PWORD, 8=QWORD, 10=TBYTE,
Offffh=NEAR, Offfeh=FAR, al1 others=UNKNOWN; MASM mode only.
type PTR expression Converts expression to the specified address subtype; Ideal mode only.
or type expression
type LOW expression Converts expression to the specified address subtype. Type described must be
smal1er in size than the type of the expression; Ideal mode only.
type HIGH expression Converts expression to the specified address subtype. Type described must be
smal1er in size than the type of the expression; the resulting address is adjusted
to point to the high part of the object described by the address expression; Ideal
mode only.
Obtaining the type of In MASM mode, you can obtain the numeric value of the type of
an expression an expression by using the TYPE operator. (You can't do this in
Ideal mode, because types can never be described numerically).
The syntax of the TYPE operator is
TYPE expression
The TYPE operator returns the size of the object described by the
address expression, as follows:
Table 5.20
TYPE values Type Description
byte 1
word 2
dword 4
pword 6
qword 8
tbyte 10
short Offffh
Here's an example:
avar = 5
bvar db 1
darray dd 10 dup(l)
x struc
dw ?
dt ?
ends
fp label far
tavar = TYPE avar ;=0
tbvar = TYPE bvar i= 1
tdarray = TYPE darray i= 4
tx = TYPE x i= 12
tfp = TYPE fp i= OFFFEh
Obtaining the segment You can use the SEG and OFFSET operators to get the segment
and offset of an and offset of an expression. The SEG operator returns the segment
address expression
value of the address expression. Here's its syntax:
SEG expression
Here is a code example:
Note that when you use the offset operator, be sure that the
expression refers to the correct segment. For example, if you are
using MASM mode and not using the simplified segmentation
directives, the expression
OFFSET BUFFER ;buffer is a memory address
is not the same as
OFFSET DGROUP:BUFFER iDgroup is the group containing the segment
that contains BUFFER
unless the segment that contains BUFFER happens to the first
segment in DGROUP.
In Ideal mode, addresses are automatically calculated relative to
any group that a segment belongs to unless you override them
with the : operator. In MASM mode, the same is true if you use
the simplified segment directives. Otherwise, addresses are
calculated relative to the segment an object is in, rather than any
group.
Creating an address You can use the THIS operator to create an address expression
expression using the that points to the current segment and location counter, and has a
location counter
specific address subtype. You can use the following syntax in
Ideal mode:
THIS type
The Ideal mode syntax lets you build an address expression from
the current segment and location counter of the specified type.
You can use the next syntax in MASM mode:
THIS expression
The MASM mode syntax functions like the syntax in Ideal mode,
but uses the numerical value of the expression to determine the
Referencing structure, Structure, union, and table members are global variables whose
union, and table values are the offset of the member within the structure, union, or
member offsets
table in MASM mode. In Ideal mode, however, members of these
. data types are considered local to the data type. The dot (.)
operator lets you obtain the offsets of members. Here's the Ideal
mode syntax:
expression . symbol
Implied addition In MASM mode, you can add expressions in several ways: using
the addition operator (+), using the dot operator (.), or by implied
addition (when expressions are separated by brackets or
parentheses). For example,
MOV AX, 5 [BX] icontents of address BX+5
MOV AX,5 (XYZ) icontents of address XYZ+5
Here's the general syntax for implicit addition:
exprl [ expr2 1
or
exprl ( expr2 )
Specifying a 16- or 32- When the currently selected processor is the 80386 or higher,
bit expression Turbo Assembler provides two operators that let you control
whether an expression is interpreted as a 16-bit value or as a 32-
bit value: the SMALL and LARGE operators. Here are their
syntaxes:
SMALL expression
LARGE expression
The SMALL operator flags the expression as representing a 16-bit
value. LARGE flags it as r,epresenting a 32-bit value. These oper-
ators are particularly important when you program for an
environment in which some segments are 32-bit and others are
16-bit. For example, the instruction
JMP [DWORD PTR ABC]
represents an indirect jump to the contents of the memory
variable ABC. If you have enabled the 80386 processor, this
instruction could be interpreted as either a far jump with a
segment and 16-bit offset, or a near jump to a 32-bit offset. You
can use SMALL or LARGE to remove the ambiguity, as follows:
JMP SMALL [DWORD PTR ABC]
This instruction causes Turbo Assembler to assemble the jump
instruction so that the value read from ABC is interpreted as a
16-bit segment and 16-bit offset. Turbo Assembler then performs
an indirect FAR jump.
Predefined symbols
Two predefined symbols, @Cpu and' @WordSize, can give you
information about the type of processor you're using, or the size
of the current segment. Here are descriptions of these symbols:
@Cpu
Function Numeric equate that returns information about current processor
Remarks The value returned by @Cpu encodes the processor type in a number of
single-bit fields:
The bits not defined here are reserved for future use. Mask them off when
using @Cpu so that your programs will remain compatible with future
versions of Turbo Assembler. .
Since the 8086 processor family is upward compatible, when you enable a
processor type with a directive like .286, the lower processor type·s (8086,
80186) are automatically enabled as well. .
This equate only provides information about the processor you've selected
at assembly time using the .286 and related directives. The processor type
and the CPU your program is executing on at run time are not indicated.
Example IPUSH = @Cpu AND 2 i allow immediate push on 186 and above
IF IPUSH
PUSH 1234
ELSE
mov ax, 1234
push ax
ENDIF
@WordSize
FUnction Numeric equate that indicates 16- or 32-bit segments
Remarks @WordSize returns 2 if the current segment is a 16-bitsegment, or 4 if the
segment is a 32-bit segment.
Example IF @WordSize EQ 4
movesp,0100h
ELSE
mov sp,0100h
ENDIF
Symbols created
by the MODEL When you use the MODEL directive, Turbo Assembler creates and
directive initializes certain variables to reflect the details of the selected
model. These variables can help you write code that's model
independent, through the use of conditional assembly statements.
See Chapter 15 for information about how you can use variables
to alter the assembly process.
The @Model symbol The @Model symbol contains a representation of the model
currently in effect. It is defined as a text macro with any of the
following values:
1 = tiny model is in effect
2 = small or flat
3 = compact
4 = medium
5 = large
6 = huge
7 = tchuge
o = tpascal
The @CodeSize symbol The@CodeSize text macro symbol indicates the default size of a
code pointer in the curreht memory model. It's set to 0 for the
memory models that use NEAR code pointers (TINY, SMALL,
FLAT, COMPACT, TPASCAL), and 1 for memory models that use
FAR code pointers (all others).
The @DataSize symbol The @DataSize text macro symbol indicates the default size of a
data pointer in the current memory model. It's set to 0 for the
memory models using NEAR data pointers (TINY, SMALL, FLAT,
MEDIUM), 1 for memory models that use FAR data pointers
(COMPACT, LARGE, TPASCAL), and 2 for models using huge
data pointers (HUGE and TCHUGE).
The @Interface symbol The @Interface symbol provides information about the language
and operating system selected by the MODEL statement. This text
macro contains a number whose bits represent the following
values:
Table 7.3
Model modifiers Value in bits 0-6 Meaning
a NOLANGUAGE
1 C
2 SYSCALL
3 STDCALL
4 PASCAL
5 FORTRAN
6 BASIC
7 PROLOG
8 CPP
Symbols created by When you use the simplified segment directives, they create
the simplified segment variables that reflect the details of the selected segment, just as the
directives
MODEL directive does. See Chapter 15 for further information.
The following table lists these symbols.
Table 7.5
Symbols from simplified Symbol name Meaning
segment directives
@code the segment or group that CS is assumed to be
@data the segment or group that DS is assumed to be
@fardata the current FARDATA segment name
@fardata? the current UFARDATA segment name
@curseg the current segment name
@stack the segment or group that SS'is assumed to be
The
STARTUPCODE The STARTUPCODE directive provides initialization code
directive appropriate for the current model and operating system. It also
marks the beginning of the program. Here's its syntax:
STARTUPCODE
or
. STARTUP i (MASM mode only)
STARTUPCODE initializes the DS, SS, and SP registers. For the
SMALL, MEDIUM, COMPACT, LARGE, HUGE, and TPASCAL
models, Turbo Assembler sets DS and 55 to @data, and SP to the
end of the stack. For TINY and TCHUGE models, the
STARTUPCODE directive doesn't change the segment registers.
The EXITCODE directive You can use the EXITCODE directive to produce termination code
appropriate for the current operating system. You can use it more
than once in a module, for each desired exit point. Here's its
syntax:
EXITCODE [return_value_expr]
You can use the following syntax only in MASM mode:
The SEGMENT
directive. The SEGMENT directive opens a segment. All code or data
following it will be included in the segment, until a corresponding
ENDS directive closes the segment.
The Ideal mode syntax for the SEGMENT directive is:
SEGMENT name [attributes]
You ~an use the following syntax for MASM mode:
name SEGMENT [attributes]
name is the name of the segment. You should name segments
according to their usages. See Appendix A for examples of
segment names.
Segment combination The segment combination attribute tells the linker how to
attribute combine segments from different modules that have the same
name. The following table lists the legal values of the segment
combination attribute. Note that if you don't specify the combine
type, Turbo Assembler assumes PRIVATE.
Table 7.6
Segment combination Attribute value Meaning
attribute
PRIVATE Segment will not be combined with any other
segments of the same name outside of this module.
PUBLIC Segment will be concatenated with other segments
of the same name outside of this module to form a
single contiguous segment.
MEMORY Same as PUBLIC. Segment will be concatenated
with other segments of the same name outside this
module to form a single contiguous segment, used
as the default stack. The linker initializes values for
the initial SS and SP registers so that they point to
the end of these segments.
COMMON Locates this segment and all other segments with
the same name at the same address. All segments
of this name overlap shared memory. The length
of the resulting common segment is the length of
the longest segment from a single module.
VIRTUAL Defines a special kind of segment that must be
declared inside an enclosing segment. The linker
treats it as a common area and attaches it to the
enclosing segment. The virtual segment inherits its
attributes from the enclosing segment. The assume
directive considers a virtual segment to be a part of
its parent segment; in all other ways, a virtual
segment is a common area that is combined across
Segment class attribute The segment class attribute is a quoted string that helps the linker
determine the proper ordering of segments when it puts, together
a program from modules. The linker groups together all segments
with the same class name in memory. A typical use of the class
name is to group all the code segments of a program together
(usually the class CODE is used for this). Data and uninitialized
data are also grouped using the class mechanism.
Segment alignment The segment alignment attribute tells the linker to ensure that a
attribute segment begins on a specified boundary. This is important
because data can be loaded faster on the 80x86 processors if it's
properly aligned. The following table lists legal values for this
attribute.
Table 7.7
Segment alignment attribute Attribute value Meaning
BYTE No special alignment; start segment on the
next available byte.
WORD Start segment on the next word-aligned
address.
DWORD Start segment on the next doubleword-aligned
address.
PARA Start segment on the next paragraph (16-byte
aligned) address.
PAGE Start segment on the next page (256-byte
aligned) address.
MEMPAGE Start segment on the next memory page (4Kb
aligned) address.
Segment size' attribute If the currently selected processor is the 80386, segments can be
either 16 bit or 32 bit. The segment size attribute tells the linker
which of these you want for a specific segment. The following
table contains the legal attribute values.
Table 7.8
, Segment size attribute values Attribute value Meaning
USE16 Segment is 16 bit. A 16-bit segment can contain
up to 64K of code and/or data.
USE32 Segment is 32 bit. A 32-bit segment can contain
up to 4 gigabytes of code and/or data.
Segment access Fa!, any segment in protected mode, you can control access so that
attribute certain kinds of memory operations are not permitted. (Note that
this feature is currently supported only by the Phar Lap linker.
You must generate object code compatible with it using the lop
switch if you want to be able to use the segment access attribute.)
The segment access attribute tells the linker to apply specific
access restrictions to a segment.
The following table lists the legal values for this attribute.
Table 7.9
Segment access attribute Attribute value Meaning
EXECONLY -' the segment is executable only
EXEC READ the segment is readable and executable
READONLY the segment is readable only
READWRITE the segment is readable and writable
The ENDS
directive You can use the ENDS directive to close a segment so that no
further data is emitted into it. You should use the ENDS directive
The GROUP
directive You can use the GROUP directive to assign segments to groups. A
group lets you specify a single segment value to access data in all
segments in the group.
Here's the Ideal mode syntax for the GROUP directive:
GROUP name segment_name [, segment_name ... ]
You can use the following syntax for MASM mode:
name GROUP segment_name [, segment_name ... ]
name is the name of the group. segment_name is the name
of a segment you want to assign to that group.
Segment ordering
The linker arranges and locates all segments defined in a
program's modules. Generally, the linker starts with the order in
which it encounters the segments in a program's modules. You
can alter this order using mechanisms such as segment combina-
tion and segment classing.
There are other ways to affect the way the linker arranges
segments in the final program. For example, the order in which
segments appear in a module's source can be changed. There are
also directives that affect segment ordering. Descriptions of these
follow.
Changing a module's The order of segments in each module determines the starting
segment ordering point for the linker's location of segments in the program. In
MASM 1.0, 2.0, and 3.0, segments were passed to the linker in
alphabetical order. Turbo Assembler provides directives (in
MASM mode only) that let you reproduce this behavior.
Note that these directives have the same function as the IA and IS
command line switches. See Chapter 2 for further details.
DOS ordering of Normally, the linker arranges segments in the sequential order it
segments: the DOSSEG encounters them during the generation of the program. When you
directive
include a DOSSEG directive in any module in a program, it
instructs the linker to use standard DOS segment ordering instead.
The linker defines this convention to mean the following arrange-
ment of segments in the final program:
• segments having the class name CODE (typically code
segments)
• segments that do not have class name CODE and are not part of
DGROUP
• segments that are part of DGROUP in the following order:
name is the name of the record data type. You can use it later in
the module to obtain a variety of information about the record
data type. You can also use the names of individual record fields
to obtain information. See Chapter 5 for details about how to
obtain information from record data type names and record field
names using Turbo Assembler expressions.
You can redefine record data types, and define the same name as
a record data type more than once in a module.
1111" You can also use record data type names to create variables and
allocate memory. See Chapter 12 for details.
Turbo Assembler provides special support for record fields that
represent flags and enumerated data types. Additional and
extended instructions provide efficient access to record fields.
Chapter 13 describes this concept further.
Opening a
structure or union Use the following Ideal mode syntaxes to open a structure or
definition union data type definition:
STRUC name or' UNION name
Specifying
structure and Turbo Assembler includes data one line at a time in structures or
union members unions. To allocate data and create members in a structure or
union definition, use the same directives as those for allocating
data and creating labels in an open segment. For example,
memberl DW 1
is equally valid in a segment or in a structure definition. In a
segment, this statement means "reserve a word of value 1, whose
name is memberl." In a structure or union definition, this
statement means "reserve a word of initial value 1, whose
member name is memberl."
You can use the initial value for a structure member if an instance '
of the structure or union is allocated in a segment or a structure. If
you don't intend to allocate structure instances this way, the
initial value of the structure member is not important. You can
use the data value? (the uninitialized data symbol) to indicate
this.
Turbo Assembler allows all methods of allocating data with a
structure definition, including instances of other structures,
unions, records, enuni.erated data types, tables, and objects. For
more information on how to allocate data, see Chapter 12.
MASM and Ideal modes treat structure member names
differently. In MASMmode, structure member names are global
and can't be redefined. In Ideal mode, structure member names
are considered local to a structure or union data type.
Aligning structure You can use the ALIGN directive within structure definitions to
members align structures members on appropriate boundaries. For
example,
ALIGN 4 iDWORD alignment
member dd? imember will be DWORD aligned
Closing a
structure or union You must close the structure or union definition after you define
all structure or union members. Use the ENDS directive to do this.
definition
ENDS has the following syntax in Ideal mode:
ENDS [name]
In MASM mode, you can use the following syntax:
name ENDS
name, if present, is the name of the currently open structure or
union data type definition. If name is not present, the currently
open structure or union will be closed.
You can also use the ENDS directive to close segments. This is not
a conflict, because you can't open a segment inside a structure or
union definition.
Including one
named structure Turbo Assembler provides. a way of incorporating an entire
within another existing structure or union data type, including member names,
into an open structure definition to assist in the inheritance of
objects. It treats the incorporated structure or union as if it were
nested inside the open structure or union definition at that point.
In this way, incorporating a structure or union into another is
intrinsically different from including an instance of a structure or
union in another; an in$fance includes only initialized or
uninitiali2ed data, while incorporation includes data, structure,
and member names.
Here's the Ideal mode syntax:
STRUC struc_name fill-parameters
You can use the following syntax in MASM mode:
struc_name STRUC fill-parameters
Use a statement of this form only inside a structure or union
definition. struc_tlame is the name of the previously defined
structure or union that is to be included. fill..JJarameters represents
the changes you want to make to the initial (default) values of the
included structure's members. A ? keyword indicates that all of
the incorporated structure's members should be considered
uninitialized. Otherwise, the syntax for thefill..JJarameters field is:
{ [member_name [=expression] [, member_name [=expression] ... ]] }
member_name is the name of any member of the included structure
whose initial value should be changed when it's included.
expression is the value you want to change it to. If you have
expression, then the initial value for that member of the structure
will be unchanged when it is included.· If you specify a ? keyword
Defining tables
A table data type represents a collection of table members. Each
member has a specific size (in bytes) and an initial value. A table
member can be either virtual or static. A virtual member of a table
is assigned an offset within the table data type; space is reserved
for it in any instance of the table. A static member does not have
an offset; space isn't reserved for it in an instance of the table.
The size of the table data type as a whole is the sum of the sizes of
all of the virtual members.
Table data types represent method tables, used in object-oriented
programming. An object usually has a number of methods associ-
ated with it, which are pointers to procedures that manipulate
instances of the object. Method procedures can either be called
directly (static methods) or indirectly, using a table of method
procedure pointers (virtual methods).
You can use the following Ideal mode syntax for declaring a table
data type:
TABLE name [table_member [,table_member . .. ]]
or
[VIRTUAL] membecname [[countl_expression]]
[: complex_type [:count2_expression]] [= expression]
Overriding table
members If you declare two or more members of the same name as part of
the same table data type, Turbo Assembler will check to be sure
that their types and sizes agree. If they don't, it will generate an
error. Turbo Assembler will use the last initial value occurring in
the table definition for the member. In this way, you can override
the initial value of a table after it is incorporated into another. For
example,
FOO TABLE VIRTUAL MEM1:WORD=MEMIPROC, VIRTUAL MEM2:WORD=MEM2PROC
F002 TABLE FOO, VIRTUAL MEM1:WORD=MEM3PROC ;Overrides inherited
;MEMl
Defining an object·
An object consists of both a data structure and a list of methods
that correspond to the object. Turbo Assembler uses a structure
data type to represent the data structure associated with an object,
and a table data type to represent the list of methods associated
with an object.
An extension to the STRUC directive lets you define objects. The
Ideal mode syntax follows:
STRUC name [modifiers] [parent_name] [METHOD [table_member
[,table_member . .. ]]]
structure_members
ENDS [name]
The size of the virtual table pointer (if any) depends on whether
data in the current model is addressed as NEAR or FAR if you
don't specify a modifier.
The TBLPTR
directive Inherent in the idea of objects is the concept of the virtual method
table. An instance of this table exists once for any object having
virtual methods. The data structure for any object having virtual
methods also must contain a pointer to the virtual method table
for that object. Turbo Assembler automatically provides a virtual
method table pointer in an object's data structure (if required) and
if you don't specify it explicitly using the TBLPTR directive.
You should use the TBLPTR directive within an object data
structure definition. TBLPTR lets you explicitly locate the virtual
table pomter wherever you want. Here's its syntax:
TBLPTR
Symbols defined
by the extended The extended STRUC directive defines or uses several symbols,
STRUC directive which reflect the object being defined. The following table shows
these symbols.
The ORG
directive You can use the ORG directive to set the location counter in the
current segment. ORG has the following syntax:
"
ORG expression
expression can't contain any forward-referenced symbol names. It
can either be a constant or an offset from a symbol in the current
segment or from the current location counter.
You can back up the location c:ounter before data or code that has
already been emitted into a segment. You can use this to go back
and fill in table entries whose values weren't known at the time
the table was defined. Be careful when using this technique; you
might accidentally overwrite something you didn't intend to.
You can use the ORG directive to connect a label with a specific
absolute address. The ORG directive can also set the starting
location for .COM files. Here's an example of how to use ORG:
This program shows how to create a structure and macro for
declaring instances of the structure, that allows additional
elements to be added to the linked list without regard to
other structures already declared in the list. If the macro
is invoked in a section of code that is between two other
instances of the structure, the new structure will automatically
be inserted in the linked list at that point without your
needing to know the names of the previous or next
structure variables. Similarly, using the macro
at the end of the program easily adds new structures to the
linked list without regard for the name of the previous
, element.
else
i Declare it, with previous pointing to previous
item of structure a.
name a
i Make the next pointer of the previous structure
i point to this structure.
org __ last_a_name.next.
dd name
i Setup the tail pointer for the new member
org __ list_a_tail
dd name
i Go back to location after the current structure
org name+size a
The ALIGN
directive You'll use the ALIGN directive to round up the location counter to
a power-of-two address. ALIGN has the following syntax:
ALIGN boundary
boundary must be a power of two.
Turbo Assembler inserts NOP instructions into the segment to
bring the location counter up to the desired address if the location
counter is not already at an offset that is a multiple of boundary.
This directive has no effect if the location counter is already at a
multiple of boundary.
You can't reliably align to a boundary that's more strict than the
segment alignment in which ALIGN appears. The segment's
alignment is specified when the segment is first started with the
SEGMENT directive. '
For example, if you've defined a segment with
CODE SEGMENT PARA PUBLIC
you can then say ALIGN 16 (same as PARA) but not ALIGN 32,
since that's more strict than the alignment that PARA indicated in
the SEGMENT directive. ALIGN generates a warning-if the
segment alignment isn't strict enough.
The following example shows how you can use the ALIGN
directive:
ALIGN 4 ialign to DWORD boundary for 386
BigNum DD 12345678
Defining labels
Labels let you assign values to symbols. There are three ways of
defining labels:
• using the : operator
• using the LABEL directive
The : operator
The : operator defines a near code label, and has the syntax
name:
where name is a symbol that you haven't previously defined in the
source file. You can place a near code label on a line by itself or at
the start of a line before an instruction. You usually would use a
near code label as the destination of a JMP or CALL instruction
from within the same segment.
The code label will only be accessible from within the current
source file unless you use the PUBLIC directive to make it
accessible from other source files.
This directive functions the same as using the LABEL directive to
define a NEAR label; for example, A: is the same as A -LABEL
NEAR. For example,
A:
is the same as
A LABEL NEAR
Here's an example of using the: operator.
jne A iskip following function
inc si
A: i jne goes here
The LABEL
directive You'll use the LABEL directive to define a symbol with a specified
type. Note that the syntax is different for Ideal and MASM modes.
In Ideal mode, specify ,
LABEL name complex_type
The :: directive
The :: directive only works The :: directive lets you define labels with a scope beyond the
when you're using MASM5 7.
procedure you're in. This differs from the: directive in that labels
defined with: have a scope of only within the current procedure.
Note that :: is different from: only when you specify a language
in the .MODEL statement.
10
Declaring procedures
Turbo Assembler lets you declare procedures in many ways. This
chapter discusses NEAR and FAR procedures, declaring proce-
dure languages using arguments and variables in procedures,
preserving registers, nesting procedures, declaring method
procedures for objects, and declaring procedure prototypes. You
can find more information about how to call language procedures
in Chapter 13.
ENDP [name]
Use the following syntax in MASM mode:
name PROC [[language modifier] language] [distance]
[ARG argument_list] [RETURNS item_list]
[LOCAL argument_list]
[USES item_list]
[name] ENDP
ENDP
Note that the only difference between the older versions of Turbo
Assembler and the later versions is that language and
language_modifier have been moved to follow the procedure name
to facilitate consistent function prototyping.
Declaring NEAR
or FAR NEAR procedures are called with a near call, and contain a near
procedures return; you must call them only from within the same segment in
which they're defined. A near call pushes the return address onto
the stack, and sets the instruction pointer (IP) to the offset of the
procedure. Since the code segment (CS) is not changed, the
procedure must be ifl the same segment as the caller. When the
processor encounters a near return, it pops the return address
from the stack and sets IP to it; again, the code segment is not
changed.
FAR procedures are called with a far call and contain far returns.
You can call FAR procedures from outside the segment in which
they're defined. A far call pushes the return address onto the
stack as a segment and offset, and then sets CS:IP to the address
of the procedure. When the processor encounters a far return, it
pops the segment and offset of the return address from the stack
and sets CS:IP to it.
The currently selected model determines the default distance of a
You can specify this as an procedure. For tiny, small, and compact models, the default .
argument to the MODEL procedure distance is NEAR. For all other models, FAR is the
statement. See Chapter 7 for
more information. default. If you don't use the simplified segmentation directives,
the default procedure distance is always NEAR.
You can override the default distance of a procedure by spe.cify-
ing the desired distance in the procedure definition. To do this,
The same RET mnemonic is used in both NEAR and FAR proce-
dures; Turbo Assembler uses the distance of the procedure to
determine whether a near or far return is required. Similarly,
Turbo Assembler uses the procedure distance to determine
whether a near or far call is required to reference the procedure:
Declaring a
procedure You can easily define procedures that use high-level language
interfacing conventions in Turbo Assembler. Interfacing conven-
language
tions are supported for the NOLANGUAGE (Assembler), BASIC,
FORTRAN, PROLOG, C, CPP (C++), SYSCALL, STDCALL, and
PASCAL languages.
Turbo Assembler does all the work of generating the correct
prolog (procedure entry) and epilog (procedure exit) code
necessary to adhere to the specified language convention.
You can specify a default language as a parameter of the MODEL
directive. See Chapter 7 for further details. If a default language is
present, all procedures that don't otherwise specify a language
use the conventions of the default language.
To override the default language for an individual procedure,
include the language name in the procedure definition. You can
specify a procedure language by including a language identifier
keyword in its declaration. For example, a definition in MASM
mode for a PASCAL procedure would be
See Chapter 73 for further You can use the Iia command-line switch to include procedure
information.
prolog and epilog code in your listing file. This lets you see the
differences between the languages.
Specifying a
language Language modifiers tell Turbo Assembler to include special
modifier prolog and epilog code in procedures that interface with
Windows or the VROOM overlay manager. To use them, specify
one before the procedure language in the model directive, or in
the procedure header. Valid modifiers are NORMAL, WINDOWS,
ODDNEAR, and ODDFAR.
See Chapter 7 for more Additionally, you can specify a default language modifier as a
information.
parameter of the MODEL directive. If a default language modifier
exists, all procedures that don't otherwise specify a language
modifier will use the conventions of the default.
Include the modifier in the procedure definition to specify the
language modifier for an individual procedure. For example,
LOCALS
testl PROC PASCAL FAR
ARG @@a:WORD,@@b:DWORD,@@c:BYTE
LOCAL @@x:WORD,@@y:DWORD
MOV aX,@@a
MOV @@x,ax
LES di,@@b
MOV WORD ptr @@y,di
MOV WORD ptr @@y+2, es
MOV @@c, 'a'
RET
ENDP
test2 PROC PASCAL FAR
ARG @@a:DWORD,@@b:BYTE
LOCAL @@x:WORD
LES' di,@@a
Since this example uses locally scoped variables, the names exist
only within the body of the procedure. Thus, test2 can reuse the
argument names @@a, @@b,and@@x.
Preserving
registers Most higher-level languages require that called procedures
preserve certain registers. You can do this by pushing them at the
start of the procedure, and popping them again at the end of it.
Turbo Assembler can automatically 'generate code to save and
restore these registers as part of a procedure's prolog and epilog
code. You can specify these registers with the USES statement.
Here's its syntax:
USES item [,item] ...
item can be any register or single-token data item that can legally
be pushed or popped. There is a limit of eight items per
procedure. For example,
In this example, it's legal to call testl or test2 from outside the
outer procedure.
If you want to have localized subprocedures, use a locally scoped
name. For example,
The LOCALS directive
enables locally scoped
symbols. See Chapter 77 for LOCALS
further information. testl PROC FAR isome code here
RET
@@test2 PROC NEAR isomecode here
In this case, you can only access the procedure @@test2 from
within the procedure testl. In fact, there can be multiple proce-
dures named @@test2 as long as no two are.within the same
procedure. For example, the following is legal:
LOCALS
testl PROC FAR
MOV si,OFFSET Buffer
CALL @@test2
RET
@@test2 PROC NEAR isome code here
RET
@@test2 ENDP
testl ENDP
test2 PROC FAR
MOV si,OFFSET Buffer2
CALL @@test2
RET
@@test2 PROC NEAR isome code here
RET
@@test2 ENDP
test2 ENDP
LOCALS
testl PROC FAR
MOV si,OFFSET Buffer
CALL @@test2
RET
testl ENDP
@@test2 PROC NEAR
isome code here
RET
@@test2 ENDP
11
Redefinable symbols
Some symbol types that Turbo Assembler supports are consi-
dered redefinable. This means that you can redefine a symbol of
this type to be another symbol of the same type at any point in the
module. For example, numeric symbols have this property:
foo =1
movax/foo iMoves 1 into AX.
foo =2
movax/foo iMoves 2 into AX.
Generally, the scope of a given redefinable symbol starts at the
point of its definition, and proceeds to the point where it's
Block seoping
By default block-scoped Block scoping makes a symbol have a scope that corresponds to a
symbols are disabled in Turbo
Assembler. procedure in a module. Turbo Assembler supports two varieties
of block scoping: MASM-style, and native Turbo Assembler style.
MASM block
seoping In MASM versions 5.1 and 5.2, NEAR labels defined with the
colon directive (:) are considered block-scoped if they are located
inside a procedure, and you've selected a language interfacing
convention with the MODEL statement. However, these symbols
are not truly block-scoped; they can't be defined as anything other
than a near label elsewhere in the program. For example,
version m510
model small,c
codeseg
foo proe
a: jmp a. i Belongs to procedure FOO
foo endp
bar proc
a: jmp a iBelongs to procedure BAR
bar endp
a =1 iIllegal!
12
Allocating data
Data allocation directives are used for allocating bytes in a seg-
ment. You can also use them for filling those bytes with initial
data, and for defining data variables.
All data allocation directives have some features in common.
First, they can generate initialized/data and set aside room for
uninitialized data. Initialized data is defined with some initial
value; uninitialized data is defined without specifying an initial
value (its initial value is said to be indeterminate). Data allocation
directives indicate an uninitialized data value with a ? Anything
else should represent an initialized data value. Chapter 7 explains
why you should distinguish between initialized and uninitialized
data.
Another feature common to all data allocation directives is the use
of the DUP keyword to indicate a repeated block of data. Here's
the general syntax of all data allocation directives:
[name] directive dup_expr [,dup_expr ... ]
Turbo Assembler initializes name to point to the space that the
directive reserves. The variable will have a type depending on the
actual directive used.
The syntax of each dup _expr can be one of the following:
• value
• count_expression DUP ( dup_expr [ , dup_expr ... ] )
The syntax of the value field for each of these directives differs,
based on the capability of each data size to represent certain
quantities. (For example, it's never appropriate to interpret byte
data as a floating-point number.)
DB (byte) values can be
• A constant expression that has a value between -128 and 255
(signed bytes range from -128 to +127; unsigned byte values are
from 0 to 255) .
• An 8-bit relative expression using the HIGH or LOW operators.
Initializing union or
structure Initialized structure'instances are more complex than uninitial-
instances ized instances. When you define a structure, you have to specify
an initial default value for each of the structure members. (You
can use the? keyword as the initial value, which indicates that no
specific initial value should be saved.) When you create an
instance of the structure, you can create it using the default values
or overriding values. The simplest initialized instance of a
structure contains just the initial data specified in the definition.
For example,
AS TRue {}
is equivalent to
DB "xyz"
DW 1
DD 2
You can use the brace initializer to specify the value of any
structure or union member, even in a nested structure or union.
Unions differ from structures because elements in a union overlap
one another. Be careful when you initialize a union instance since
if several union members overlap, Turbo Assembler only lets one
of those members have an initialized value in an instance. For
example,
BUNION {}
In this example, four bytes are reserved because the size of the
union is the size of its largest member (in this case a DWORD). If
the initialized member of the union is not the largest member of
the union, Turbo Assemblermakes up the difference by reserving
space but not emitting data. For example,
BUNION {Z=l}
is equivalent to
Initializing record You must specify an initial value fo:r some or all of the record
instances fields when you define a record. (Turbo Assembler assumes that
any unspecified initial values are 0.) The simplest initialized
instance of a record contains just the initial field data specified in
the definition. For example,
MYREC {}
is equivalent to
DW (4 SHL 6) + (0 SHL 4) + (15 SHL 0)
i8HL is the ,shift left operator for expressions
The braces ({ }) represent a null initializer value for the record.
The initializer value determines what initial values should be
overridden, and by what new values (as you allocate data for the
record instance).
Use this syntax of the brace initializer for records:
{ [field_name' = expression [,field_name = expression ... JJ
field~name is the name of a field in the record. expression is the
value that you want the field to have in this instance. A blank
value indicates that you'll use the initial value of the field from
the record definition. A ? value is equivalent to zero. Turbo
Assembler sets any field that doesn't appear in the initializer to
the initial value of the field from the record definition. For
example,
MYREC {VAL=2,SZE=?}
is equivalent to
DW (2 SHL 6) + (0 SHL 4) + (0 SHL 0)
An alternative method of initializing record instances is to use the
bracket « » initializer. In this case, brackets delineate the initial-
izer. The values in the initializer are unnamed but are laid out in
the same order as the corresponding fields in the record
definition. The syntax of the bracket initializer follows:
< [e~pression [,expression ... JJ >
expression represents the desired value of the corresponding field
in the record definition. A blank value indicates that you'll use the
is equivalent to
DW (4 SHL 6) + (2 SHL 4) + (0 SHL 0)
If you specify fewer values than there are fields, Turbo Assembler
finishes the instance by using the initial values from the record
definition for the remaining fields.
MYREC <1> isame as MYREC <1,,>
Initializing· enumerated. You can use any expression that evaluates to a number that will
data type instances fit within the enumerated datatype instance; for example,
ETYPE ? iuninitialized instance
ETYPE FOO iinitialized instance, value FOO
ETYPE 255 ia number outside the ENUM that also fits
Initializing table
instances When you define a table, you must specify an initial value for all
table members., The simplest initialized instance of a table con-
tains just the initial data specified in the definition. For example,
TTYPE {}
is equivalent to
DW MoveRtn
DD MsgRtn
DW DoneRtn
The braces ({ }) represent a null initializer' value for the structure.
The initializer value determines what members (if any) have
initial values that should be overridden, and by what new values,
as you allocate data for the table instance.
Here's the syntax ()f the brace initializer:
{ [member_name = value [,member_name = value ... JJ
member_name is the name of a member of the table. value is the
value that you want the member to have in this instance. A blank
value indicates that you'll use the initial value of the member
from the table definition.,A ? value indicates that the member
should be uninitialized. Turbo Assembler sets any member that
doesn't appear in the initializer to the initial value of the member
from the table definition. For example,
13
Extended jumps
Conditional jumps such as JC or JE on the 8086,80186, and 80286
processors are only allowed to be near (within a single segment)
and have a maximum extent of -128 bytes to 127 bytes, relative to
the current location counter. The same is true of the loop condi-
tional instructions such as JCXZ or LOOP on all the Intel
processors.
Turbo Assembler can generate complementary jump sequences
where·necessary and remove this restriction. For example, Turbo
Assembler might convert
JC xxx
to
JNC temptag
JMP xxx
might produce unintended results because foo, [bx], and foo [bx]
are all legal expressions. You can use brackets or parentheses to
clarify the instruction, as follows:
PUSH [foo] [bx]
PUSHing
constants on the While the 80186, 80286, and 80386 processors have basicinstruc-
tions available for directly PUSHing a constant value, the 8086 .
8086 processor
does not.
Note: you can only do this if Turbo Assembler permits constants to be PUSHed on the 8086,
you've turned smart code
generation on. and generates a sequence of instructions that has the exact same
result as the PUSH of a constant on the 80186 and higher
processo:s.
The sequence of instructions Turbo Assembler uses to perform the
PUSH of a constant is about ten bytes long. There are shorter and
faster ways of performing the same function, but they all involve
the destruction of the contents of a register; for example,
MOV ax, constant ,
PUSH ax
This sequence is only four bytes long, but the contents of the AX
register is destroyed in the process.
Extended shifts
On the 8086 processor, the shift instructions RCL, RCR, ~OL,
ROR, SHL, SHR, SAL, and SAR cannot accept a constant rotation
count other than 1. The 80186, 80286, and 80386 processors accept
constant rotation counts up to 255.
When Turbo Assembler encounters a shift instruction with a
constant rotation count greater than 1 (with the 8086 processor
selected), it generates an appropriate number of shift instructions
with a rotation count of 1. For example,
.8086
SHL ax,4
generates
SHL ax,l
SHL ax,l
SHL ax,l
SHL ax,l
TESTFLAG AX,RO
In this example, TESTFLAG will generate the most efficient
instruction regardless of where RO exists in the record.
The SETFIELD
instruction SETFIELD generates code that sets a value in a record field. Its
syntax follows:
SETFIELD field~name destination_rim, source_reg
fiild_name is the name of a record member field. destination_rim for
SETFIELD is a register or memory address of type BYTE or
WORD (or DWORD for the 80386). source_reg must be a register of
the same size or smaller. If the source is smaller than the destina-
tion, the source register must be the least significant part of
another register that is the same size as the destination. This full-
size register is called the operating register. Use this register to shift
the value in the source register so that it's aligned with the
destination. For example,
Faa RECORD RO:l,Rl:4,R2:3,R3:1
The entire contents of the SETFIELD shifts the source register efficiently to align it with the
operating register are
destroyed by the SETF/ELD field in the destination, and ORs the result into the destination
operation. register. Otherwise, SETFIELD modifies only the operating
register and the processor flags ..
To perform its function, SETFIELD generates an efficient but
extended series of the following instructions: XOR, XCHG, ROL,
ROR, OR, and MOVZX.
The GETFIELD
instruction GETFIELD retrieves data from a record field. It functions as the
logical reverse of the SETFIELD instruction. Its syntax follows:
GETFIELD field_name destination_reg, source_rim
field_name and destination_reg function as they do for SETFIELD.
You can use source_rim as you wouldfor source_reg (for
SETFIELD). For example,
Instruction Effect
PUSH [SMALL/LARGE] segreg Selects whether 16-bit or 32-bit form of segment register is
PUSHed.
POP [SMALL/LARGE] segreg Selects whether 16-bit or 32-bit form of segment register is
POPped.
FSAVE [SMALL/LARGE] memptr Selects whether small or large version of floating-point state is
saved.
FRSTOR [SMALL/LARGE] memptr Selects whether small or large version of floating-point state is
restored.
FSTENV [SMALL/LARGE] memptr Selects whether small or large version of floating-point state is
stored.
FLOENV [SMALL/LARGE] memptr Selects whether small or large version of floating-point state is
loaded.
LGOT [SMALL/LARGE] memptr Selects whether small or large version of global descriptor table is
loaded.
SGOT [SMALL/LARGE] memptr Selects whether small or large version of global descriptor table is
saved.
LIOT [SMALL/LARGE] memptr Selects whether small or large version of interrupt descriptor table
is loaded.
SlOT [SMALL/LARGE] memptr Selects whether small or large version of interrupt descriptor table
is saved.
JMP [SMALL/LARGE] memptr For DWORD-sized memory addresses, selects between FAR 16-bit
JMP and NEAR 32-bit JMP.
CALL [SMALL/LARGE] memptr For DWORD-sized memory addresses, selects between FAR 16-bit
CALL and NEAR 32-bit CALL.
Calling
procedures that Procedures that define some of their arguments with the
contain RETURNS RETURNS keyword must be considered specially. These argu-
ments are used to return values to the caller; therefore, the caller
always pops them. There is no special extension to the CALL
instruction in Turbo Assembler to help pass those arguments
specified in a procedure declaration after the RETURNS directive.
You must explicitly PUSH these arguments before the CALL, and
POP them afterward.
Calling
procedures that If you've defined the procedure prior to the call or used
have been PROCDESC to prototype the procedure (see Chapter 10), Turbo
Assembler will type check any language and arguments specified
prototyped in the call and generate a warning if the language, number of
parameters, or types of parameters don't match.
For example,
test PROCDESC pascal far :word, :dword,:word
Calling method
procedures for The CALL instruction is extended to support the calling of object
objects: methods. A call to an object method can generate either a direct
call (for static methods) or an indirect call (for virtual methods).
CALL .. METHOD
Because you can use an indirect call, the instructions that perform
the call can destroy the contents of some registers. Therefore,
Turbo Assembler lets you select the proper registers if you're
using a virtual method call.
Here's the syntax of the CALL..METHOD extension: .
CALL instance-ptr MET~OD [object_name:]method_name [USES
[segreg:]offsreg] [language_and_args]
instance-ptr must describe an instance of an object. In MASM
mode, it's often impossible to determine the name of the object
associated with an instance. Therefore, Turbo Assembler allows
the object_name field, so that you can specify the instance's object
name.
See Chapter 8 for further method_name contains the name of the method to be called for the
information about how to
specify a method as virtual specified object instance.
, or static.
If the method is virtual and an indirect call is required, the
CALL..METHOD instruction normally calls indirectly through
ES:BX (or ES:EBX for USE32 models on the 80386 processor). If
you want to use other registers, you can override them with the
USES clause. segreg is the optional segment register to use, and
offsreg is the offset register to use for the call.
Note: It's good programming For objects declared with near tables, CALL..METHOD only loads
practice to specify an
appropriate selection for the offset register. Turbo Assembler assumes that the'segment
indirect calling registers, register is already set up to the correct value.
even if you know that the
method you're calling is
static. As objects are The language_and_args field of the CALL..METHOD instruction
modified, methods can contains the optional language and argument specificati'ons,
change from being static to
virtual. which are identical in form to that listed previously under
HCalling procedures with stack frames."
14
Using macros
Macros let you give a symbolic name to a text string or a block of
code that will be used frequently throughout your program.
Macros go beyond this simple substitution, however. Turbo
Assembler has macro operators that provide great flexibility in
designing macros. Combined with the ability to use multiline
macros with arguments, this makes Turbo Assembler's macro
facility a very powerful tool. This chapter discusses how to use
text and multiline macros in your program.
Text macros
A text macro is a symbol that represents a string of text characters.
When Turbo Assembler encounters the symbol in expressions
(and other situations), it substitutes the text characters for the
symbol. For example, if DoneMsg is a text macro whose value is
"Returning to the OS", the following statement
GoodBye DB DoneMsg
results in
GoodBye DB 'Returning to the OS'
String macro
manipulation Turbo Assembler provides directives that can manipulate string
directives macros. These directives are available in Ideal mode, and for :
versions M510, M520, and T300 or later (as specified by the
VERSION directive).
A string argument for any of these directives can be any of the
following:
• a text string enclosed in brackets; for instance, <abc>
• the name of a previously defined text macro
The CATSTR directive The CATSTR directive defines a new text macro by concatenating
strings together. CATSTR has the following syntax:
name CATSTR string[,string) ...
CATSTR concatenates from left to right. Turbo Assembler creates
a new text macro of the name name.
TheSUBSTR directive The SUBSTR directive defines a new text macro to be a substring
of a string. Here's its syntax:
name SUBSTR string,position_expression[,size_expression)
The new text macro, name consists of the portion of string that
starts at the position_expression character, and is size_expression
characters in length. If you don't supply size_expression, the new
text macro consists of the rest of string from the character at
position_expression. Turbo Assembler considers the first character
of string to be at position 1.
The INSTR directive The INSTR directive returns the position of one string inside
another string. INSTR has the following syntax:
name INSTR [start_expresslon,)stringl,string2
Turbo Assembler assigns name a numeric value that is the position
of the first instance of string2 in stringl. The first character in
stringl has a position of 1. If string2 does not appear anywhere
within stringl, Turbo Assembler returns avalue of O. If you
include start_expression, the search begins at the start_expression
character. The first character of a string is 1.
The SIZESTR directive The SIZESTR directive returns the length of a text macro (the
number of characters in the string). Here's its syntax:
name SIZESTR string
name is set to the numeric value of the length of the string. A null
string < > has a length of zero.
Multiline macros
The multiline macro facility lets you define a body of instructions,
directives, or other macros that you'll include in your source code
whenever the 'macro is invoked. You can supply arguments to the
macro that Turbo Assembler will substitute into the macro body
when you include the macro in the module.
There are several types of multiline macros. One version substi-
tutes each element of a string, one after the other, as'an argument
to the macro. Another version repeats the macro body a certain
number of times. Finally, you can define still another version in
one place, and invoke it many times. All versions have the
definition of a macro body in common.
The multiline
macro body Regardless of its actual content, Turbo Assembler's macro proces-
sing facility treats a multiline macro body as merely a number of
lines of text. Turbo Assembler lets you replace symbols within the
macro body with text specified at the time a macro is invoked.
This feature is called argument substitution. The symbols in the
macro body that will be replaced are called dummy arguments. For
example, suppose the symbol faa is a dummy argument in the
following macro body: .-
Using & in macros The & character has a special meaning when used with the macro
parameters. In general, & separates a dummy argument name
from surrounding text, so Turbo Assembler can recognize it for
substitution. For example, given the following Ideal mode macro:
macro mac1 foo
sym&foo:
DB 'It is &foo time'
endm
if you assign faa the text string party when this macro is invoked,
the actual text included in the module will be
symparty:
DB 'It is party time'
Another example might be
foo&sym:
DB 'We are in O&foo&o'
If you assign faa the text string hi when this macro is invoked, the
text included in the module will be
hisym:
DB 'We are in Ohio'
Including comments in For particularly complicated macros, you might want to include
macro bodies (in the macro body text) comments that won't be included when
the macro is invoked. This also reduces the memory required for
Turbo Assembler to process macros. To do this, use the double
semicolon comment at the beginning of a line. For example, the
following macro body
Note: comments preceded iiWOW, this is a nasty macro!
by single semicolons are
always included in a macro DB 'Nasty macro'
expansion.
will only include the following text when it is invoked:
DB 'Nasty macro'
Local dummy At the beginning of any macro body, you can include one or more
arguments LOCAL directives. LOCAL declares special dummy arguments
that, each time the macro expands, will be assigned a unique
symbol name.
The syntax for the LOCAL directive in macro bodies looks like
this:
LOCAL dummy_argumentl [,dummy_argument2] ...
See Chapter 77 for details on If the dummy_argument name used in the LOCAL directive does
how to enable local symbols
and set the local symbol not have a local symbol prefix the unique symbol name assigned
prefix. to it will be in the form ??xxxx, where xxxx represents a
hexadecimal number. Otherwise, the unique symbol name will be
<local prefix>xxxx.
The LOCAL directives must You can use LOCAL dummy arguments to define labels within
come before any other
statements in a macro body. the macro body. For example, .
The EXITM directive You can use the EXITM directive within a macro body to prema-
turely terminate the assembly of an included macro body. Its
syntax follows:
EXITM
When Turbo Assembler encounters EXITM in a macro body that
has been included in the module source code, assembly of the
expanded macro body stops immediately. Instead, Turbo
Assembler will continue assembling the module at the end of the
macro.
See Chapter 75 for You can use the EXITM statement with a conditional assembly
information about
conditional assembly directive to terminate a macro expansion when certain conditions
directives. are met.
Tags and the GOTO Using macro tags and the GOTO directive Jets you control the
directive sequence in which lines within the macro body expand. You can
place a macro tag at any place within the macro body. The tag
occupies an entire line in the macro, with the following syntax:
: tag_symbol
When the macro expands, all macro tags are discarded.
The GOTO directive tells the assembler to go to a specified point
in your code, namely the tag_symbol. GOTO has the following
syntax:
GOTO tag_symbol
General multiline
macros Turbo Assembler a'ssociates a general multiline macro's body of
directives, instructions, and other macros with a symbolic macro
name. Turbo Assembler inserts the body of statements into your
program wherever you use the macro name as a directive. In this
way, you can use a general multiline macro more than once.
Invoking a general To invoke a general multiline macro, use the name of the macro 'as
multiline macro a directive in your program. Turbo Assembler inserts the macro
body (after all the dummy arguments are substituted) at that
point in the module. The syntax for invoking a general multiline
macro is as follows: .
Deleting a general You can use the PURGE directive to delete a macro. PURGE has
multiline macro: The the following syntax:
PURGE directive
PURGE macroname [,macronamel ...
PURGE deletes the general multiline macro definition associated
with macroname. After you PURGE a macro, Turbo Assembler no
longer treats the symbol macroname as if it were a macro; for
example,
ADD MACRO al,a2
SUB al,a2
ENDM
ADD ax,bx iThis invocation will produce SUB ax,bx
PURGE ADD
ADD ax,bx iThis is no longer a macro, so ADD ax,bx is produced
You can purge several macros at a time by separating their names
with commas. Note, however, that you can't redefine a purged
macro symbol as anything other than another macro.
Defining nested and The statements in a macro body can include statements that
recursive macros invoke or define other macros. If you take this example,
MCREATE MACRO opname,opl,op2,op3,op4,op5,op6,op7
IFNB opname
DO&opname MACRO op,count
IF count LE 4
REPT count
opname op,l
ENDM
ELSE
MOV CL,count
opname op,CL
ENDIF
ENDM ;end of DOopname macro
MCREATE opl,op2,op3,op4,op5,op6,op7 irecurse!
ENDIF ;end of if
ENDM iend of MCREATE macro
The WHILE
directive You can use the WHILE macro directive to repeat a macro body
until a certain expression evaluates to 0 (false). WHILE has the
following syntax:
WHILE while_expression
macro_body
ENDM
Turbo Assembler evaluates while_expression before each iteration
of the macro body. Be careful to avoid infinite loops, which can
cause Turbo Assembler to run out of memory or appear to stop
functioning. Here's an example using WHILE:
WHILE 1
i i Do nothing
ENDM
i We never make it this far
String repeat
macros You can use the IRP and IRPC string repeat macro directives to
repeat a macro body once for each element in a list or each
character in a string. Each of these directives requires you to
specify a single dummy argument. Here's the IRP syntax:
Including multiline
macro expan- Multiline macro expansions are not normally included in the
sions in the list file listing file. However, Turbo Assembler provides the following
directives that let you list macro expansions:
pushstate
nolocals
next4:
@@b: loop @@b
next5:
@@b: loop @@b This will conflict because of nolocals
. popstate
i Show changing local symbol prefix and MASM/IDEAL mode
pushstate
masm
locals @$
testproc proc MASM mode for procedure declaration
jmp @$end
@$end: nop
@@end: ret
testproc endp
testproc2 proc
jmp @$end
@$end: nop i This doesn't conflict with label in
i TESTPROC
@@end: ret This label does conflict
testproc2 endp
pops tate
i Now back to @@ as a local label prefix, and IDEAL mode.
testproc2b .proc This won't work since we are back in
IDEAL mode!
ret
testproc2b endp And this will give an error also.
proc testproc3
jmp @$end2
@$end2: nop
15
IFxxx conditional
assembly You can use IFxxx conditional assembly directives to define blocks
directives of code that are included in the object file if certain conditions are
met (such as whether a symbol is defined or set to a particular
value). Here's the syntax of a conditional assembly statement:
ELSEIFxxx
conditional You can use the ELSEIFxxx as a shortcut where multiplelFs are
assembly required. ELSEIFxxxis equivalent to anELSE followed by a
nested IFxxx, but provides more compact code. For example,
directives
IF mode EQ 0
imode 0 code
ELSEIF mode LT 5
imode 1-4 code
ELSE
imode 5+ code
compares to
IF mode EQ 0
imode 0 code
ELSE
IF mode LT 5
imode 1-4 code
ELSE
imode 5+ code
ENDIF
I
ENDIF
ERRxxx error-
generation ERRxxx directives generate user errors when certain conditions
directives are met. These conditions are the same as for the IFxxxconditional
assembly directives. Here's the general syntax:
ERRxxx [arguments] [message]
In this case, ERRxxx represents any of the conditional error-
generating directives (such as ERRIFB, .ERRB, and so on).
arguments represents arguments that the directive might require
to evaluate its condition. Some directives require an expression,
some require a symbol expression, and some require one or two
text expressions. Other directives require no arguments at all.
If message is included, it represents an optional message that's
displayed along with the error. The message must be enclosed in
single (') or double (") quotation marks.
The error-generating directives generate a user error that is
displayed onscreen and included in the listing file (if there is one)
at the location of the directive in your code. If the directive
specifies a message, it displays on the same line immediately
following the error. For example, the directive
ERRIFNDEF faa "faa not defined!"
generates the error
Unconditional
error-generation The unconditional error-generation directives are ERR and .ERR.
directives These directives always generate an error and require no argu-
ments, although they can have an optional message. You can only
use .ERR in MASM mode.
Expression-
conditional These directives provide conditional assembly or error generation
directives based on the results of evaluating a Turbo Assembler expression.
. For all of these directives, the expression must evaluate to a
constant and can't contain any forward references. If it evaluates
to 0, Turbo Assembler considers the expression to be false;
otherwise, it considers the expression to be true.
The following table shows conditional assembly directives that
use expressions.
Table 15.1
Conditional assembly IFxxx directive Assembles true_conditionaLbody if
directives using expressions IF expression Expression evaluates to true.
IFE expression Expression evaluates to false.
ELSEIF expression Expression evaluates to true.
ELSEIFE expression Expression evaluates to false.
Symbol-definition
conditional These directives provide conditional assembly or error generation
directives based on whether one or more symbols are defined. These
symbols are organized into a symboCexpression.
A symboCexpression is an expression made up of symbol names,
the Boolean operators AND, OR, and NOT, and parentheses. In a
symboCexpression, each symbol name is treated as a Boolean value
that evaluates to true if the symbol currently exists, or false if tne
symbol does not exist (even if it's defined later in the module).
Turbo Assembler combines these values using the Boolean
operators to produce a final true or false result. In its simplest
form, a symbol expression consists of a single symbol name and
evaluates to true if the symbol is defined. The parsing and syntax
rules for symboCexptession are similar to those for other Turbo
Assembler expressions.
For example, if the symbolfoo is defined but the symbol bar is not,
the following symbol-expression evaluations are returned:
Table 15.3
Evaluation of defined and Symbol expression Result
'undefined symbol
faa True
bar False
not faa False
not bar True
faa OR bar True
faa AND bar False
NOT (faa AND bar) True
NOT faa OR NOT bar True (same as "(NOT faa) OR (NOT bar)")
Text-string
conditional These directives provide conditional assembly or error generation
directives based on the contents of text_string. A text_string can be either a
string constant delineated by brackets « » or a text macro name
preceded by a percent sign (%). For example,
See Chapter 74 for <ABC>
information about how to i text string ,ABC
define and manipulate text %foo i the contents of text macro foo
macros.
The conditional assembly directives that use text_string are shown
in the following table:
Table 15.6: Conditional assembly directives using text_strings
You could invoke this example with load test, ex, which would
generate a mov ex, test instruction (or invoke simply load test,
which will generate a mav ax, test instruction because the second
parameter is blank). Alternately, you could use ERRIFB to
generate an error for a macro invocation with a missing critical
argument. Thus,
generates an error when invoked with load, but would not when
invoked with load test.
Assembler-pass
conditionals These directives provide conditional assembly or error generation
based on the current assembly pass:
16
Conventions for d
particular When you name symbols that you plan to use externally,
language remember to use the language specifier for your particular
language. These requirements for variable names are:
Declaring public
symbols When you declare a public symbol, you intend it to be accessible
from other modules. The following types of symbols can be
'public: .
• data variable names
• program labels
• numeric constants defined with EaU
You can use the PUBLIC directive to define public symbols. Its
syntax follows:
PUBLIC [language) symbol [, [language) symbol) ...
Declaring library
symbols You can also use symbols as dynamic link entry points for a
dynamic link library. Use the PUBLlCDLL directive to declare
symbols to be accessible this way. Here's its syntax:
PUBLICDLL [language] symbol [, [language] symbol] .. '
Turbo Assembler publishes symbol in the object file as a dynamic
link entry point (using EXPDEF and IMPDEF records) so that it
can be accessed by other programs. language causes any
language-specific conventions to be applied to the symbol name.
Valid language specifiers are C"PASCAL, BASIC, FORTRAN,
PROLOG, and NOLANGUAGE.
Here's an example of code using PUBLICDLL:
PUBLICDLL XYPROC jmake procedure XYPROC
XYPROC PROC NEAR jaccessible as dynamic link entry point
Defining external
symbols External symbols are symbols that are defined outside a module,
that you can use within the module. These symbols must have
been declared using the PUBLIC directive. EXTRN has the
following syntax:
EXTRN definition [,definition] ...
definition describes a symbol arid has the following format:
[language] name [[countll] :complex_type [:count2]
Publishing a
procedure If you're using version T320 or later and you use PROCDESC to
prototype describe a procedure prototype, Turbo Assembler treats the
procedure name as if it were a GLOBAL symbol. If you've defined
the procedure within the module, it is treated as PUBLIC.
Otherwise, Turbo Assembler assumes it to be EXTRN.
You can place PROCDESC directives in an include file. When you
reference the procedure name in the module, PROCDESC acts as
an EXTRN directive, describing how the procedure is defined in
another module. If the procedure is defined in the module,
PROCDESC acts as a PUBLIC directive to publish the procedure.
Defining
communal Communal variables function like external variables, with a major
variables difference: communal variables are allocated by the linker.
Communal variables are actually like global variables, but you
Including a library
Using INCLUDELIB prevents For the times when you know that your source file will always
you from having to
remember to specify the need to use routines in a specified library, you can use the
library name in the linker INCLUDELIB directive. INCLUDELIB tells the linker to include a
commands.
particular library. The appropriate syntaxes for this directive are:
Ideal mode:
INCLUDELIB "filename" ;note the quotes!
MASMmode:
INCLUDELIB filename
filename is the name of the library you want the linker to include
at link time. !fyou don't supply an extension with filename, the
linker assumes .LIB.
Here's an example:
INCLUDELIB "diskio" ;includes DISKIO.LIB
17
Generating a listing
See the // and //0 switches in A listing file is useful if you want to see exactly what Turbo
Chapter 2.
Assembler generates when each instruction or directive is
assembled. The file is basically the source fil~ annotated with a
variety of information about the results of the assembly. Turbo
Assembler lists the actual machine code for each instruction,
along with the offset in the current segment of the machine code
for each line. What's more, Turbo Assembler provides tables of
information about the labels and segments used in the program,
including the value and type of each label, and the attributes of
each segment.
See the /e command-line Turbo Assembler can also, on demand, generate a cross-reference
option in Chapter 2.
table for all labels used in a source file, showing you where each
label was defined and where it was referenced.
Listing format
The top of each page of the listing file displays a header consisting
of the version of Turbo Assembler that assembled the file, the date
and time of assembly, and the page number within the listing.
There are twoparts to the listing file: the annotated source code
listing and the symbol tables. The original assembly code is dis-
played first, with a header containing the name of the file where
the source code resides. The assembler source code is annotated
with information about the machine code Turbo Assembler
%LlNUM lets you set how many columns the line numbers take up
in the listing file. size must be a constant. If you want to make
your listing as narrow as possible, you can reduce the width of
this field. Also, if your source file contains more than 9,999 lines,
you can increase the width of this field so that the line numbers
are not truncated. The default width for this field is 4 columns.
%TRUNC truncates listing fields that are too long. %TRUNC has
the following syntax:
%TRUNC
The object code field of the listing file has enough room to show
the code emitted for most instructions and data allocations. You
can adjust the width of this field with %BIN. If a single source line
emits more code than can be displayed on a single line, the rest is
normally truncated and therefore not visible. When you want to
see all the code generated, use %NOTRUNC (whichwordwraps
too-long fields in the listing file). Otherwise, use O/oTRUNC. You
can use these directives to toggle truncation on and off.
%NOTRUNC has the following syntax:
%NOTRUNC
%PCNT sets the segment:offset field width in the listing file.
%PCNT has the following syntax:
%PCNT width
where width is the number of columns you want to reserve for the
offset within the current segment being assembled. Turbo
%PUSHLCTL
Conversely, the %POPLCTL directive recalls listing controls from
the stack. Here's its syntax:
%POPLCTL
O/oPOPLCTL resets the listing controls to the way they were when
the last %PUSHLCTL directive was issued. None of the listing
controls that set field width are restored (such as %DEPTH,
%PCNT).
18
The framework
In order to link Borland C++ and Turbo Assembler modules
together, three things must happen:
• The Turbo Assembler modules must use a Borland C++-
compatible segment-naming scheme.
• The Borland C++ and Turbo Assembler modules must share
appropriate function and variable names in a form acceptable
to Borland C++.
• TLINK must be used to combine the modules into an
executable program.
This says nothing about what the Turbo Assembler modules
actually do; at this point, we're only concerned with creating a
framework within which C++-compatible Turbo Assembler
functions can be written.
Memory models and For a given assembler function to be callable from C++, that
segments function must uSe the same memory model as the C++ program
and must use a C++-compatible code segment. Likewise, in order
for data defined in an assembler module to be accessed by C++
code (or for C++ data to be accessed by assembler code), the
assembler code must follow C++ data segment-naming
conventions.
Memory models and segment handling can be quite complex to
implement in assembler. Fortunately, Turbo Assembler does
.FARDATA
Counter DW 0
. CODE
PUBLIC _AsmFunction
_AsmFunction PROC
mov ax/@fardata
mov es/ax ipoint ES to far data segment
inc es: [Counter] iincrement counter variable
_AsmFunction ENDP
or
.FARDATA
Counter DW 0
. CODE
PUBLIC _AsmFunction
_AsmFunction PROC
ASSUME ds:@fardata
mov ax/@fardata
mov ids/ax ipoint DS to far data segment
inc [Counter] iincrement counter variable
ASSUME ds:@data
mav ax/@data
mav ds/ax ipaint'DS ba~k to DGROUP
.FARDATA
. CODE
PUBLIC _AsmFunction
_AsmFunction PROC
push ds
mov aX,@fardata
mov ds', ax
pop ds
ret
_AsmFunction ENDP
Publics and externals Turbo Assembler code can call C++ functions and reference
external Cj-+ variables. Borland C++ code can likewise call public
Turbo Assembler functions and reference public Turbo Assembler
variables. Once Borland C++-compatible segments are set up in
Turbo Assembler, as described in the preceding sections, only the
Label types
While assembler programs are free to access any variable as data
of anysize (8 bit, 16 bit, 32 bit, and so on), it is generally a good
idea to access variables in their native size. For instance, it usually
causes problems if you write a word to a byte variable:
EXTRN c:WORD
inc [c]
could lead to problems, since every 256th time the assembler code
incremented c, c ·would turn over. And, since c is erroneously
declared as a word variable, the byte at OFFSET c + 1 is incor-
rectly incremented, and with unpredictable results.
Correspondence between C++ and assembler data types is as
follows:
.FARDATA
FilelVariable DB
. DATA
EXTRN FilelVariable:BYTE
. CODE
Start PROC
mav aX,SEG FilelVariable
mav ds,ax
SEG FilelVariable will not return the correct segment. The EXTRN
directive is placed within the scope of the DATA directive of
FILE2.ASM, so Turbo Assembler considers Filel Variable to be in
the near DATA segment of FILE2.ASM rather than in the
\ FARDATA segment.
The following code for FILE2.ASM allows SEG FilelVariable to
return the correct segment:
Linker command line The simplest way to link Borland C++ modules with Turbo
Assembler modules is to enter a single Borland C++ command
line and let Borland C++ do all the work. Given the proper
command line, Borland C++ will compile the C++ code, invoke
Turbo Assembler to do the assembling, and invoke TLINK to link
the object files into an executable file. Suppose, for example, that
you have a program consisting of the C++ files MAIN.CPP and
STAT.CPP and the assembler files SUMM.ASM and
DISPLAY.ASM. The command line
bee main.epp stat.cpp surnrn.asm display.asm
compiles MAIN.CPP and STAT.CPP, assembles SUMM.ASM and
DISPLAY.ASM, and links all four object files, along with the,C++
start-up code and any required library functions, into MAIN.EXE.
You only need remember the .ASM extensions when typing your
assembler file names.
If you use TLINK in stand-alone mode, the object files generated
by Turbo Assembler are standard object modules and are treated
just like C++ object modules. See Appendix C for more informa-
tion about using TLINK in stand-alone mode.
Parameter
passing Borland C++ passes parameters to functions on the stack. Before
calling a function, Borland C++ first pushes the parameters to that
function onto the stack, starting with the rightmost parameter and
ending with the leftmost parameter. The C++ function call
compiles to
mov aX,l
push ax
push WORD fTR DGROUP:_j
push WORD PTR DGROUP:_i
call NEAR PTR _Test
add sp,6
in which you can clearly see the rightmost parameter, I, being
pushed first, then j, and finally i.
Upon return from a function, the parameters that Were pushed on
the stack are still there, but are no longer useful. Consequently,
immediately following each function call, Borland C++ adjusts the
stack pointer back to the value it contained before the parameters
were pushed, thereby discarding the parameters. In the previous
example, the three parameters of 2 bytes each take up 6 bytes of
stack space altogether, so Borland C++ adds.6 to the stack pointer
to discard the parameters after the ca11 to Test. The important
point here is that under the default C/C++ calling conventions,
the calling code is responsible for discarding the parameters from
the stack.
Assembler functions can access parameters passed on the stack
relative to the BP register. For example, suppose the function Test
in the previous example is the following assembler function,
called PRMSTACK.ASM:
. MODEL small
. CODE
PUBLIC - Test
- Test PROC
push bp
mov bp,sp
mov ax, [bp+4] iget parameter 1
add ax, [bp+6] iadd parameter 2 to parameter 1
sub ax, [bp+8] isubtract parameter 3 from sum
pop bp
ret
- Test ENDP
END
SP • Return Address
SP+ 2 25 (i)
SP+ 4 4 (j)
SP+ 6 1
push bp
mav bp,sp
push bp
mov bp,sp
sub sp,100
SP + 100
SP + 102
--- Caller's BP
Return Address
.. BP
BP+ 2
- SP + 104 25 (i) BP+ 4
SP + 106 4 (j) BP+ 6
SP + 108 1 BP+ 8
_TestSub PROC
LOCAL LocalArray:BYTE:100,LocalCount:WORD=AUTO_SIZE
push bp ipreserve caller's stack frame pointer
mov bp,sp iset up our own stack frame pointer
sub sp,AUTO_SIZE iallocate room for automatic variables
mov [LocalCount],10 iset local count variable to 10
i (LocalCount is actually [BP-102])
In this example, note that the first field after the definition of a
given automatic variable is the data type of the variable: BYTE,
WORD, DWORD, NEAR, and so on. The second field after the
definition of a given automatic variable is the number of elements
of that variable's type to reserve for that variable. This field is
optional and defines an automatic array if used; if it is omitted,
one element of the specified type is reserved. Consequently,
LocalArray consists of 100 byte-sized elements, while LocalCount
consists of 1 word-sized element. .
Also note that the LOCAL line in the preceding example ends with
=AUTO_SIZE. This field, beginning with an equal sign, is
optional; if present, it sets the label following the equal sign to the
number of bytes of automatic storage required. You must then use
that label to allocate and deallocate storage for automatic vari-
ables, since the LOCAL directive only generates labels, and
doesn't actually generate any code or data storage. To put this
another way: LOCAL doesn't allocate automatic variables, but
Flag EQU 4
AddParml EQU 6
AddParm2 EQU 8
SubParml EQU 10
mov ax, [bp+AddParml]
add ax, [bp+AddParm2]
sub ax,. [bp+SubParml]
but it's still a nuisance to calculate the offsets and maintain them.
There's a more serious problem, too: The size of the pushed return
address grows by 2 bytes in far code models, as do the sizes of
passed code pointers and data pointer in far code and far data
models, respectively. Writing a function that can be easily assem-
bled to access the stack frame properly in any memory model
would thus seem to be a difficult task.
Turbo Assembler, however, provides you with the ARG directive,
which makes it easy to handle passed parameters in your
assembler routines.
main()
{
const int ARRAY_LENGTH=100i
char TestArray[ARRAY_LENGTH]i
FillSub(TestArraY,ARRAY_LENGTH, '*') i
Returning values A C++-callable assembler function can return a value, just like a
C++ function. Function values are returned as follows:
Calling an
assembler· Now look at an example of Borland C++ code calling a Turbo
function from C++ Assembler function. The following Turbo Assembler module;
COUNT .ASM, contains the function LineCount, which returns
counts of the number of lines and characters in a passed string:
Small model C++~callable assembler function to count the number
of lines and characters in a zero-terminated string.
Function prototype:
extern unsigned int LineCount(char * near StringToCount,
unsigned int near * CharacterCountPtr} i
Input:
char near * StringToCount: pointer to the string on which
a line count is to be performed
The two modules are compiled and linked together with the
command line
bcc -ms callct.cpp count.asm
As shown here, LineCount will work only when linked to small-
model C++ programs since pointer sizes and locations on the
stack frame change in other models. Here's a version of LineCount,
COUNTLG.ASM, that will work with large-model C++ programs
(but not small-model ones, unless far pointers are passed, and
LineCount is declared far):
Large model C++-callable assembler function to count the number
of lines and characters in a zero-terminated string.
Function prototype:
extern unsigned int LineCount(char * far StringToCount,
unsigned int * far CharacterCountPtr);
char far * StringToCount: pointer to the string on which
a line count is. to be performed
extern "C" {
II To create some unique, meaningful names for the
II assembler routines, prepend the name of the class
II to the assembler routine. Unlike some assemblers,
II Turbo ASsembler has no problem with long names.
void counter_increment (int *count)i II We will pass a
II pointer to the
II count variable.
II Assembler will
II'do the incrementing.
void counter_add(int *count,int what_to_add)i
void counter::increment(void)
{
counter_increment(&COunt)i
int main ()
{
counter Counter:
printf ( "Before count: %d\n", Counter. get_count () ) i
Counter.increment()':
Counter. add ( 5 ):
printf( "After count: %d\n", Counter.get_count() );
return 0:
Pascal calling
conventions So far, you've seen how C++ normally passes parameters to func-
tions by having the calling code push parameters right to left, call
the function, and discard the parameters from the stack after the
call. Borland C++ is also capable of following the conventions
used by Pascal programs in which parameters are passed from
left to right, and the called function discards the parameters from
the stack. In Borland C++, Pascal conventions are enabled with
the -p command-line option or the pascal keyword.
The following example, ASMPSCL.ASM, shows an assembler
function that uses Pascal conventions:
i Called as: TEST_PROC (i, j, k) i
i equ ileftmost parameter
equ
SP+ 4 k BP+ 4
SP+ 6 BP+ 6
SP+ 8 BP+ 8
The segment
setup As we learned earlier, you must make sure that Borland C++ and
Turbo Assembler are using the same. memory model and that the
segments you use in Turbo Assembler match those used by
Borland C++. Turbo Assembler has a tchuge memory model that
supports Borland C++'s huge memory model. Refer to the
previous section if you need a refresher on matching memory
models and segments. Also, remember to put EXTRN directives
for far symbols either outside all segments or inside the correct
segment.
Calling a Borland
C++ function from One case in which you may wish to call a Borland C++ function
Turbo Assembler from Turbo Assembler is when you need to perform complex
calculations. This is especially true when mixed integer and
floating-point calculations are involved; while it's certainly
possible to perform such operations in assembler, it's simpler to
let C++ handle the details of type conversion and floating-point
arithmetic.
Let's look at an example pf assembler code that calls a Borland
C++ function in order to get a floating-point calculation per-
formed. In fact, let's look at an example in which a Borland C++
function passes a series of integer numbers to a Turbo Assembler
function, which sums the numbers and in tum calls another
Borland C++ function to perform the floating-point calculation of
the average value of the series.
The C++ portion of the program in CALCAVG.CPP is
int main()
{
printf("The average value is: %f\n",
Average (TestValues, NUMBER_OF_TEST_VALUES))i
return Oi
extern "C"
float IntDivide(int Dividend, int Divisor)
{
return ( (float) Dividend I (float) Divisor) i
Function prototype:
extern float Average(int far * Valueptr, int NumberOfValues) i
Input:
int far * Valueptr: ithe array of values to average
int NumberOfValues: ithe number of values to average
.MODEL small
EXTRN - IntDivide:PROC
. CODE
PUBLIC _Average
_Average PROC
~push bp
mov bp,sp
les bx, [bp+4] ipoint ES:BX to array of values
mov cx, [bp+S] i# of values to average
mov ax,O iclear the running total
AverageLoop:
add ax,es: [bx] iadd the current value
add bx,2 ipoint to the next value
loop AverageLoop
Program blueprints
This appendix describes basic program construction information
depending on specific memory models and executable object
formats. .
TableA2
Default segments and types Directive Name Align Combine Class Group
for SMALL memory model .CODE _TEXT WORD PUBLIC 'CODE'
.FARDATA FAR DATA PARA . private 'FAR_DATA'
.FARDATA? FAR=BSS PARA private 'FAR_BSS'
.DATA DATA WORD PUBLIC 'DATA' DGROUP
.CONST CaNST WORD PUBLIC 'CaNST' DGROUP
.DATA? _BSS WORD PUBLIC 'BSS' DGROUP
'sTACK* STACK PARA STACK 'STACK' DGROUP
* STACK not assumed to be in DGROUP if FARST ACK specified in the MODEL directive.
Table A4
Default segments and types Directive Name Align Combi'ne Class Group
for COMPACT memory .CODE _TEXT WORD PUBLIC 'CODE'
model .FARDATA FAR DATA PARA private 'FAR_DATA'
.FARDATA? FAR=BSS PARA private 'FAR_BSS'
.DATA DATA WORD PUBLIC 'DATA' DGROUP
.CONST CaNST WORD PUBLIC 'CaNST' DGROUP
.DATA? BSS WORD PUBLIC 'BSS' DGROUP
.5TACK* STACK PARA STACK 'STACK' DGROUP
* STACK not assumed to be in DGROUP if FARST ACK specified in the MODEL directive.
Table A5
Default segments and types Directive Name Align Combine Class Group
for LARGE or HUGE memory .CODE name_TEXT WORD PUBLIC 'CODE'
model .FARDATA FAR DATA PARA private 'FAR_DATA'
.FARDATA? FAR=BSS PARA private 'FAR_BSS'
.DATA _DATA WORD PUBLIC 'DATA' DGROUP
.CONST CaNST WORD PUBLIC 'CaNST' DGROUP
.DATA? BSS WORD PUBLIC 'BSS' DGROUP
.5TACK* STACK PARA STACK 'STACK' DGROUP
* STACK not assumed to be in DGROUP if FARST ACK specified in the MODEL directive.
Table A6
Default segments and types Directive Name Align Combine Class Group
for Borland C++ HUGE .CODE name_TEXT WORD PUBLIC 'CODE'
(TCHUGE) memory model .FARDATA FAR_DATA PARA private 'FAR DATA'
.FARDATA? FAR BSS PARA private 'FAR-BSS'
.DATA name-DATA PARA private 'DATA'
.STACK* STACK PARA STACK 'STACK'
* STACK is automatically FAR
DOS programs
Programs designed to be executed under DOS are stored in two
formats:
• EXE format (for EXEcutable)
• COM format (for COre iMage)
EXE format permits the most general program segmentation
under DOS. A program can have multiple segments, and can
Register Value
DS,ES Contains the paragraph address of the program
segment prefix (PSP) for the program. The PSP contains
arguments passed to the program from the command
line, and a pointer to the environment string for the
program.
CS:IP Contains the starting address specified by END in one
of the program's modules, or the address of the
STARTUPCODE directive.
SS:SP Contains the address of the last word that the stack
segment specified in the program.
You can define EXE programs with any memory model. You
should use the simplest memory model possible because it makes
programming simpler and faster. For example, if you never expect
your program to use more than 64K of code, data, and stack
space, the TINY model would be the appropriate model to use.
The STARTUPCODE directive in a module emits instructions that
automatically initialize all necessary registers to conform with the
selected model. However, it preserves the paragraph address of
the PSP in ES for the program's use~
When you load an EXE program, the operating system allocates
all remaining memory to it until the program exits. For programs
that don't use a heap, or programs that build their own heaps in
this memory, this behavior is fine. Other programs can allocate
memory from DOS. In this case, the memory must be freed back
to DOS before you can request it from DOS.
To exit from an EXE program, use the EXITCODE directive.
COM program
blueprint COM progra~s are restricted versions of EXE programs. You can
represent every COM program as an EXE program, but not every
EXE program as a COM program. The following restrictions
apply:
• A COM program should be written using the TINY memory
modeL
• You can't have a predefined stack segment for COM programs.
• A COM program can't contain any direct segment or group
address references. This means that the program can't contain
any direct far calls, nor can it reference any segments by name.
All procedures in a COM program must be declared NEAR.
• Execution must begin at offset lOOh in the code segment. To let
this happen, make the first instruction in the code segment the
STARTUPCODE directive.
Turbo Assembler loads'a COM program starting at offset lOOh of
the program segment prefix (PSP). The STARTUPCODE directive
for the TINY model automatically places an ORG lOOh in the
program to compensate for this action.
When you load a COM program, the following registers are set:
Register Value
CS,DS,ES,SS Contains the paragraph address of the PSP and the
program.
IP Set to IOOh.
SP Set to OFFFEh (the'last word in the program
segment).
Windows programs
Turbo Assembler can also be used to create Windows applica-
tions. Windows can run in either real mode (on all 8086
processors) or protected mode (on 80286 and higher processors).
Thus, programs written for Windows canrun in protected mode.
You should carefully separate code and data using the CODESEG,
DATASEG, and UDATASEG directives, and use the WARN PRO
directive to flag any access problems that could occur at assembly
time. Finally, protected mode programs should not attempt to set
segment registers to calculated paragraph segment values.
Segment values in protected mode are not paragraph addresses,
but rather descriptors that have no meaning to an application
program.
See Appendix 0 for more Tools other than Turbo Assembler and a debugger are required to
information about TLiNK and
MAKE. effectively create Windows applications. In particular, you must
have Borland C++ or Borland Pascal (or a Microsoft compiler and
the Windows Software Development Kit) installed. Windows
applications usually require the use of the resource compiler
Windows DLL
blueprint A Dynamic Link Library (DLL) is a group of procedures that you
can call froni. any Windows application. DLLs extend the
Windows application interface.
DLLs perform many functions; for example, you can convert
non-interactive DOS programs to DLLs. Support can be added for
new sorts of screen entities by writing a DLL.
You can find an example program called DLLPROG.ASM that
illustrates a DLL on your Turbo Assembler disks.
You can use the MAKE utility to build the DLL. MAKEFILE
should include all modules to be linked in with the DLL, as
follows:
dllprog . dll: dllprog. obj dllprog .def
TLINK dllprog""dllprog
RC dllprog .dll
dllprog.obj: dllprog.asm
TASM dllprog
This build process requires the following linker definitions file,
DLLPROG.DEF:
LIBRARY DLLPROG
EXETYPE WINDOWS
CODE PRELOAD MOVEABLE DISCARDABLE iCODE applies to segments
i _TEXT or in class CODE
DATA PRELOAD MOVEABLE SINGLE iDATA applies to all segments
i in group DGROUP and class
i DATA
i must be SINGLE for DLL's
HEAPS.IZE 0 ithis DLL needs no heap
Windows 32-bit
application In high-level languages like C, C++, and Pascal, Windows 32-bit
blueprint programs are almost identical to their 16-bit counterparts because
the compiler handles most of the differences. However, you must
deal directly with those differences at the assembly language
Lexical grammar
valid_line ::=
white_space valid_line
punctuation valid_line
number_string valid_line
id_string valid_line
null
white_space ::=
space_char white_space
space_char
space_char ::=
All control characters, character> 128, I I
id_string ::=
id_char id_strng2
mexprl
mexpr1 ::=
SHORT mexprl
.TYPE mexprl
SMALL mexprl ;If 386
LARGE mexprl ;If 386
expr2
Keyword precedence
It's important to understand how Turbo Assembler parses source
lines so that you can avoid writing code that produces unexpected
results. For example, examine the following program fragment:
NAME SEGMENT
1. All keywords in the first position of the line have the highest
priority (priority 1) and are checked first.
MASM mode
precedence The precedence rules for parsing lines in MASM mode are much
more complicated than in Ideal mode. There are three levels of
priority instead of two, as follows:
Note: Turbo Assembler treats
priority 7 keywords like priority 1. The highest priority (priority 1) is assigned to certain
3 keywords inside structure keywords found in the first position, such as NAME or %OUT.
definitions. In this case,
priority 2 keywords have the 2. The next highest priority (priority 2) belongs to all symbols
highest priority.
found in the second position.
3. All other keywords found in first position have the l,owest
priority (priority 3).
Directive
keywords The following list contains all Turbo Assembler directive
keywords. The keywords are grouped by the version of Turbo
Assembler in which they were introduced.
These keywords were introduced in Turbo Assembler 1.0.
Table B.l: Turbo Assember Vl.0 (VERSION T100) keywords
c
Compatibility issues
Turbo Assembler in MASM mode is very compatible with MASM
version 5.2. However, 100% compatibility is an ideal that can only
be approached, since there is no formal specification for the lan-
guage and different versions of MASM are not even compatible
with each other.
For most programs, you will have no problem using Turbo
Assembler as a direct replacement for MASM. Occasionally,
Turbo Assembler will issue a warning or error message where
MASM would not, which usually means that MASM has not
detected an erroneous statement.. For example, MASM accepts
abc EQU [BP+2]
PUBLIC abc
and generates a nonsense object file. Turbo Assembler correctly
detects this and many other questionable constructs.
If you are having trouble assembling a program with Turbo
Assembler, you might try using the QUIRKS directive (which
enables potentially troublesome features of MASM). For example,
TASM IJQUIRKS MYFILE
might make your program assemble properly. If it does, add
QUIRKS to the top of your source file. Even better, review Chapter
3 and determine which statement in your source file needs the
QUIRKS directive. Then you can rewrite the line(s) of code so that
you don't even have to use QUIRKS.
Environment variables
In keeping with the approach used by other Borland language
products, Turbo Assembler does not use environment variables to
control default options. Instead,you can place default options in a
configuration file and then set up different configuration files for
different projects.
If you have used the INCLUDE or MASM environment variables to
configure MASM to behave as you wish, you will have to make a
configuration file for Turbo Assembler. Any options that you have
Error messages
This chapter describes all the messages that Turbo Assembler
generates. Messages usually appear on the screen, but you can
redirect them to a file or printer using the standard OS/2
redirection mechanism of putting the device or file name on the
command line, preceded by the greater than (» symbol. For
example,
TASMMYFILE >ERRORS
Turbo Assembler generates several types of messages:
• Information messages
• Warning messages
• Error messages
• Fatal error messages
Information messages
Turbo Assembler displays two information messages: one when it
starts assembling your source file(s) and another when it has
finished assembling each file. Here's a sample startup display:
Turbo Assembler Version 3.2 Copyright (C) 1988, 1992 Borland
International
Assembling file: TEST.ASM
endp
call fooproc,ax,bx ;Argument mismatch.
Argument needs type override
The expression needs to have a specific size or type supplied,
since its size can't be determined from the context. For
example,
mov [bx),l
You can usually correct this error by using the PTR operator to
set the size of the operand:
mov WORD PTR [bx)-,l
Argument to operation or instruction has illegal size
-An operation was attempted on something that could not
support the required operation. For example~
Q LABEL QWORD
QNOT = not Q ;can't negate a qword
Arithmetic overflow
A loss of arithmetic precision occurred somewhere in the
expression. For example,
x = 20000h * 20000h ;overflows 32 bits
All calculations are performed using 32-bit arithmetic.
ASSUME must be segment register
You have used something other than a segment register in an
ASSUME statement. For example,
ASSUME ax:CODE
ENDIF
MYSYM EQU 1
endp
call fooproc c,ax jLanguage doesn't match.
Language doesn't support variable-length arguments
You specified a variable-length stack frame with a language
that doesn't support it. For example,
foo proctype pascal :word l :unknown jPascal can't have
jvariable arguments.
Line too long-truncating
The current line in the source file is longer than 255 characters.
The excess characters will be ignored.
Location counter overflow
The current segment has filled up, and subsequent code or data
will overwrite the beginning of the segment. For example,
ORG OFFFOh
ARRAY DW 20 DUP (0) joverflow
Method CALL requires object name
The CALL..METHOD statement cannot obtain the object type
from this instance pointer. You must specify the object name.
MiSSing argument list
An IRP or IRPC repeat block directive does not have an argu-
ment to substitute for the dummy parameter. For example,
IRP X jno argument list
DB 'X
ENDM
IRP and IRPC must always have both a dummy parameter and
an argument list.
endp
call fooproc normal pascal,ax ;Style doesn't match.
Symbol already defined:_
The indicated symbol has previously been declared with the
same type. For example,
BB DB 1,2,3
BB DB ? ; error, BB already defined
Symbol already different kind ,
The indicated symbol has already been declared before with a
different type. For example,
BB DB 1,2,3
BB DW ? ;error, BB already a byte
Symbol has no width or mask
The operand of a WIDTH or MASK operator is not the name of a
record or record field. For example,
B DB 0
mov aX,MASK B ;B is not a record field
Symbol is not a segment or already part of a group
The symbol has either already been placed in a group or it is
not a segment name. For example,
DATA SEGMENT
DATA ENDS'
DGROUP GROUP DATA
DGROUP2 GROUP DATA ;error, DATA already belongs to
;DGROUP
I Text macro expansion exceeds maximum .line length
This error occurs when expansion of a text macro causes the
maximum allowable line length to be exceeded.
endp
call fooproc,ax iToo few arguments.
Too few operands to instructi.on
The instruction statement requires more operands than were
supplied. For example,
add ax imissing second arg
Too many arguments to procedure
You called a procedure using too many arguments. For
example,
foo proctype pascal :word, :dword
fooproc proc foo al:word, a2:dword
endp
call fooproc, ax, bx cx, dx iToo many arguments.
Too many errors or warnings
No more error messages will be displayed. The maximum
number of errors that will be displayed is 100; this number has
been exceeded. Turbo Assembler continues to assemble and
prints warnings rather than error messages.
Too many initial values
You have supplied too many values in a structure or union
initialization. For example,
XYZ STRUC
Al DB ?
A2 DD ?
XYZ ENDS
ANXYZ XYZ <1,2,3> ierror, only 2 members in XYZ
You can supply fewer initializers than there are members in a
structure or union, but never more.
Too many register multipliers in expression
An 386 scaled index operand had a scale factor on more than
one register. For example,
Index 333
@32Bit symbol 101 alignment 107
! character 199 class 107
& character, in macros 193 combination 106
= directive 18 size 108
% expression evaluation character .199 values of segments· 106
% immediate macro directive 204
? keyword 122, 147 B
as initial value 164
@B symbol 158
\ line continuation character 197
/b option 16
@-sign 31
\ comment character 42
= sign, argument lists and 147
Backus-Naur form (BNF) grammar 76
$ symbol 131
%BIN directive 232, 233
? symbol 160
binary coded decimal (BCD) encoding
DT directive and 163
A bit-field records, defining 117
/ a option 17, 27 bit shift operators 81
address expressions See expressions BIX, JOIN BORLAND 6
address subtypes block scoping of symbols, defined 156
complex 75 books
setting 82 assembly language 12
address subtypes of symbols Boolean algebra and operators 81
distance parameter and 75 symbol expressions and 214
addresses, calculating 85 Borland
ALIAS 224 contacting 5
alias values 45 Borland C++
ALIGN directive 120, 135 ARG directive and 258
.ALPHA directive 111 assembler modules in 18
ALPHA directive 17, 27 case sensitivity 24, 249
ancestor virtual methods 65 code segment 241
ARG directive 145, 146 data types 249
Borland C++ and 258 external symbols 251
arguments floating-point emulation 18
BYTE 147 linking to 269
names (scope of) 148 LOCAL directive and 256
substitution (defined) 192 memory models 241
arithmetic operators 81,87 parameter passing 252
.ASM files 1, 15 Pascal calling conventions 267
assembling public functions and 247
first program 10 register preservation 260
multiple passes 142 returning values 260
number of passes 22 segment directives and 242
ASSUME directive 110 structures 261
at-sign 31 BOUND instruction
attribute values of segments 106 Ideal mode 39 .
attributes buffers, size of 16
segment bulletin board, Borland 5
access 108 BYTE arguments 147
Index 335
WORDS 160 include files 44
defining 160 module names 48
initialized (defined)' 159 processor 92
repeated blocks 159 program termination'48
storage in memory 162 startup 20
structures See structures symbols 21
uninitialized DISPLAY directive 49
defined 159 distance parameter
specifying 160 complex subtypes and 75
.DATA? directive 103 DOS formats
.DATA directive 103 COM 277
@data symbol 104 EXE 276
data structures See structures DOSSEG directive 112
data types :: directive 137
Borland C++ 249 doubleword values 161
creating named 171 DP directive 160
creating record 167 DQ directive 160, 163
declaring record 11 7 DT directive 160, 163
enumerated 115 dummy arguments
creating instances of 169 defined 192
initializing instances of 169 in macros 197
multiline syntax 116 local 194
pseudo ops and 116 recognizing 193
objects and 56 types of 197
. record, multiline syntax for 117 DUP keyword 159
table 124 DW directive 160
multiline syntax 125 dynamic link libraries (DLL)
with virtual methods 172 defined 280
DATASEG directive 103, 279 example of 280
@DataSize symbol 102
??date symbol 46 E
DB directive 160
/ e option 18, 95
DD directive 160, 163
ELSEIF directive 213
debugging information 31
ELSEIFB directive 215
%DEPTH directive 232
ELSEIFDEF directive 214
derived objects 58
ELSEIFDIF directive 215
development cycle, program 10
ELSEIFDIFI directive 215
DF directive 160
ELSEIFE directive 213
directives See also individual listings
ELSEIFIDN directive 215
conditional 209
ELSEIFIDNI directive 215
assembly pass 217
ELSEIFNB directive 215
symbol-definition 214
ELSEIFNDEF directive 214
conditional expression 213
ELSEIFxxx directives 211
coprocessor 95
EMUL directive 19, 95
displaying assembly messages 49
encoded real numbers 163
error-generation 212
END directive 48
using symbol expressions 215
ENDM keyword 196
Index 337
FAR procedures 140 groups
far returns, instructions for 176 assigning segments to 109
.FARDATA? directive 103 segment registers and 110
@fardata? symbol 104 segments in Ideal mode 39
FARDATA directive 103
.FARDATA directive 103 H
@fardata symbol 104
H2ASH utility See the README file
fast immediate multiply instruction See
FASTIMUL instruction
Ih option 19
FASTIMUL instruction 182 hardware and software requirements 2
HELLO.ASM 10
fatal error messages 329
help
field value manipulation instructions 181
displaying screen 19
file names 47
HIGH operator 87
object-oriented programming format 68
??filename symbol 47
@FileName symbol 47
files i486 processor
.ASM 15 protected mode 26
assembly 47 Ii option 19
configuration 32 IDEAL directive 37
indirect 31 Ideal mode 1
listing See listing files BOUND instruction 39
flag instructions, smart 180 expressions 38
FLDENV instruction 183 features 36
FLIPFLAG instruction 180 include files 44
floating-point· operands 38
emulation 18 operators 38
Ideal vs. MASM mode 299 predefined symbols 45
instructions 2 segment fixups 39
floating-point instructions See coprocessor segment groups 39
emulation directives speed 36
floating-point numbers 163 why to use 35, 36
FRSTOR instruction 183· IF1 directive 210, 217
FSAVE instruction 183 IF2 directive 210, 217
FSTENV instruction 183 IF directive 210, 213
. IFB directive 210, 215
G IFDEF directive 210, 214
IFDIF directive 210, 215
GEnie, BORLAND 6
IFDIFI directive 210, 215
GETFIELD instruction 182
GLOBAL directive 222 IFE directive 213
IFIDN directive 210, 215
in .ASO files 68
IFIDNI directive 210, 215
objects and 58
IFNB directive 201, 210, 215
global symbols, include files and 222
GOTO directive 195 . IFNDEF directive 210, 214
GREP utility See the README file IFxxx directives 209
immediate mq.cro directive (%) 204
GROUP directive 109
implied addition 87
Ideal vs. MASM mode 40
Index 339
line continuation character (\) 197 LOOPE instruction 175
line number information 30 LOOPNE instruction 175
linker See also TLINK utility LOOPWE instruction 175
Borland C++ 252, 269 LOOPWNE instruction 175
PharLap 108 LOOPWNZ instruction 175
segment ord,ering and 111 LOOPWZ instruction 175
%LINUM directive 233 LOOPZ instruction 175
%LIST directive 227 LOW operator 87 '
.LIST directive 227 .LST files 15
listing files 15
IX command-line option and 229 M
conditional listing directives 228
@Mptr member 172
cross-reference information 17
cross-reference table and 225
I m option 22, 142, 298
macros
directives for 226
& character in 193
false conditionals in 30
body of 192
format of 225
controlling expansion 195
format parameters 232
defining new text 191
generating 21
defining substring 191
high-level code in 21
deleting multiline 200
including files in 228
dummy arguments within 197
including multiline macros 204
expansions in listing files 229
macro expansions in 229
including comments in 194
symbol table and 227
invoking arguments with special characters
symbol table in 230
199
symbol tables
invoking general multiline 197
suppressing 24
length of text 191
why to use 225
manipulating string 190
literal string brackets 198
multiline 192
LOCAL directive 146
defining general 196
Borland C++ and 256
multiline expansions in listing file 204
in macros 194
names in expressions 78
local labels
nested and recursive 200
inMASM 158
redefining general multiline 199
LOCALS directive 150, ·156
repeating 201, 202
location counter
returning positions of strings 191
creating address expressions 85
string repeat 202
defined 131
terminating assembly of 195
directives for 132
terminating body of 196
location counter symbol 131
text
LOOP instruction 175
defined 189
loop instructions for 80386 processor 175
examples of manipulation 191
LOOPDinstruction 175 ,
how to define 190
LOOPDE instruction 175
why to use 189
LOOPDNE instruction 175
%MACS directive 204, 229
LOOPDNZ instruction 175
MAKE utility See also the README file
LOOPDZ instruction 175
COM programs and 279
Index 341
NOLANCUAGE procedures derived 58, 59
prolog and epilog code and 144 differences between structures and 172
%NOLIST directive 227 GLOBAL directive and 58
NOLOCALS directive 156 how to define 128.
%NOMACS directive 204, 230 inltializing instance's VMT pointer 188
NOMULTERRS directive 51 linked list example 55
NOPs, avoiding generation of 175 method procedures and 128, 152
NOSMART directive 173 near tables and 63
MASM compatibility 297 structures and 128
%NOSYMS directive 227 TLINK compatable without overlay code 25
NOTHING keyword ·110 virtual method table instances 172
%NOTRUNC directive 233 what they consist of 128
NOWARN directive 50 OBIXREF utility See the README file
NUL device 16 OFFSET operator 38, 84
null string, length of 191 MASM vs. Ideal mode 40
numbers offsets, getting segments and 84
encoded real 163 loi option 25
floating-point 163 lop option 25, 108
numeric constants 71 operands, Ideal mode 38
numeric coprocessor 18 operators See also individual listings
bit shift 81
o Boolean algebra and 81
comments 43
10 option 25 comparison 82
.OBI files 1
general arithmetic 81
suppressing 26
Ideal vs. MASM mode 38
object files
options, command line See command-line
debugging information in 31
options
line number information in 30
ORC directive 132
module name 48
los option 25
segment ordering 17, 27
%OUT directive 49
object methods
overlay code
calling 187
generating 25
tail recursion for 188
IBM linker 25
object modules, defined 10
Phar Lap linker 25
@Object symbol 129
object-oriented programming
advantages of using 53, 54 p
defined 53 P8086 directive 92
filename format 68 P8087 directive 95
list of examples 69 P186 directive 92
table data types and 124 P287 directive 95
objects See also methods P386 directive 92
creating instances of 67, 172 P387 directive 95
data types and 56 P486 directive 92
declaring 56, 57 P487 directive 92
defined 54 P386N directive 92
defining symbols 129 P486N directive 92
MASM vs. Ideal mode 285 writing constructor and destructor 152
. (period) operator 86 pr9cessor directives 92
period, Ideal mode structures 39 processor type, determining 93
Phar Lap linker 108 PROCTYPE directive 127, 149
plus sign 15 program development cycle 10
pointers program termination, END directive and 48
virtual method table 61, 63, 64, 65 prolog code
POP instruction 183 defined 142
multiple 177 languages and 143
pointers and 178 NOLANGUAGE procedures and 144
POPA instruction register preservation and 149
expanded 178 specifying default style 100
POPA W instruction 179 what it does 143
POPFW instruction 179 protected mode 26
%POPLCTL directive 235 segment registers and 97
precedence prototypes
keyword 290 procedure 152
Ideal mode 290 procedure types and 154
MASM mode 291 publishing procedure 222
predefined symbols See symbols prototyping procedures 186
PROC directive 139 PUBLIC directive 220
PROC keyword, Ideal mode 37 public functions, Borland C++ and 247
PROCDESC directive· 152, 186 PUBLICDLL directive 221
procedure prototypes 152 PURGE directive 200
procedure types, defining 149 PUSH instruction 183
procedures multiple 177
calling and having RETURNS 186 pointers and 178
calling with arguments 185 PUSHA instruction
declaring 139 expanded 178
defining types 127 PUSHAW instruction 179
determining distance of 141 PUSHF instruction
FAR 140 expanded 178
interfacing conventions of 184 PUSHFW instruction 179
languages for PUSHing constants 178
arguments and 145 %PUSHLCTL directive 234
MODEL and 142
overriding default 142 Q
method 68
creating 152
Iq option 26
quadword values 161
Index 343
question mark scope rules for nested procedures 150
symbols using 46 SEG operator 84
QUIRKS directive 297 SEGCS instruction 179
SEGDS instruction 179
R SEGES instruction 179
SEGFS in~truction 179
, Ir option 18,26 SEGGS instruction 179
RADIX directive 72, 163
SEGMENT directive 105
.RADIX directive 72
SEGMENT keyword, Ideal mode 37
radixes
segments
available 71
8086 processor and 97
changing default 72
assigning to groups 109
characters determining 72
attributes
default 163
access 108
real mode, segment registers and 97
alignment 107
record data types, multiline syntax for 117
class 107
RECORD directive 117
combination 106
records
size 108
< > and 168
Borland C++-and 241
{} and 168
closing 108, 120
creating instances of 167
code 99
defining 168
default attributes 275
initializing instances 168
directives (Borland C++ and) 242
retrieving data from 182
fixups (Ideal vs. MASM mode) 39
setting values in 181
forced overrides 179
recursive macros See macros
generic 105
reference books 12
getting offsets and 84
registers See also individual listings
groups
initializing with models 277
Ideal mode and 36, 39
names of and expressions 77
MASMmode40
preserving 149
groups and 98
preserving (Borland~ C++) 260
how the stack is treated 98
segment 97
memory models and 99
registration (product)
opening 105
by phone 5
ordering 17, 111
REPT directive 201
alphabetic 111
RET instruction, NEAR or FAR and 176
changing 111
RETCODE instruction 176
DOS 112
RETF instruction 176
sequential 111
RETN instruction 176
overrides of expressions 84
return instructions 176
reg~sters 97, See also individual listings
RETURNS directive 186
regIsters and 110
sequential order 17, 27
5 simplified directives 103
I s option 17, 27 size 94
.sALL directive 204, 230 symbols and 104
scope of symbols, defined 155 writing to uninitialized 106
Index 345
??filename 47 TBLINIT directive 61
@FileName 47 in .ASM files 68
global 222 TBLINIT instruction 188
in expressions 77 TBLINST directive 61
length of 23 in .ASM files 68
location counter 131 TBLINST pseudo-op 172
MASM block scoping 157 TBLPTR directive 129
names of 73 TCREF utility 15, See also the README file
naming conventions for languages 219 Technical Support
overriding language setting 220 contacting 5
public 24, 220 termination, END directive and 48
publishing external 220 termination code 105
redefinable 155, 156 TESTFLAG instruction 180
restrictions 18 text macro names, in expressions 78
scope of (defined) 155 text strings See strings
standard values 77 %TEXT directive 234
??time 47 TFCOND directive 30
types of 73 .TFCOND directive 228
uppercase 23 THELP utility See the README file
values used by themselves 78 THIS operator 85
why to use 71 time 47
@WordSize 94 ??time symbol 47
%SYMS directive 227 TITLE directive 234
SYMTYPE operator 86 %TITLE directive 234
syntax, command-line See command-line TLIB utility See the README file
syntax TLINK utility 252, 269, See also the README
file
T example of 11
%TRUNC directive 233
It option 27 TSM_UTIL.TXT 8
TABLE directive 56
Turbo Librarian See the README file
@Table symbol 129
Turbo Link See TLINK utility
@TableAddr member 172
two-pass assembly
@Table'addr symbol 129
MASM compatibility 298
tables
type checking, Ideal mode 35
creating instances of 170
TYPE operator 83
data types 124
type override operators 82
initializing instances of 170
type-safe linkage 239
overriding members 126
.TYPE operator 86
static members 124
TYPEDEF directive 126
virtual members 124
typefaces in this manual 4
%TABSIZE directive 234
types See also data types
tags, macro 195
complex 125, 126
tail recursion code, instruction for 188
defining named 126
TASM32.EXE 8
defining procedure 127
TASM.CFG32
of expressions 83
TASM.EXE8
procedure 149
TASMX.EXE8
Index 347
..
Borland
Corporate Headquarters: 100 Borland Way, Scotts Valley, CA 95066-3249, (408) 431-1000. Offices in: Australia, Belgium, Canada,
Denmark, France, Germany, Hong Kong, Italy, Japan, Korea, Latin America, Malaysia, Netherlands, New Zealand, Singapore, Spain,
Sweden, Taiwan , and United Kingdom· Part # LSM1240WW21770 • BOR 6284