2.2.1 Defining Basic Attributes with .MODEL

The .MODEL directive defines the attributes that affect the entire module: memory model, default calling and naming conventions, operating system, and stack type. This directive enables use of simplified segments and controls the name of the code segment and the default distance for procedures.

You must place .MODEL in your source file before any other simplified segment directive. The syntax is

.MODEL memorymodel [[, modeloptions ]]

The memorymodel field is required and must appear immediately after the .MODEL directive. The use of modeloptions, which define the other attributes, is optional. The modeloptions must be separated by commas. You can also use equates passed from the ML command line to define the modeloptions.

The list below summarizes the memorymodel field and the modeloptions fields (language, operating system, and stack distance):

Field Description

Memory model TINY, SMALL, COMPACT, MEDIUM, LARGE, HUGE, or FLAT. Determines size of code and data pointers. This field is required.
Language C, BASIC, FORTRAN, PASCAL, SYSCALL, or STDCALL. Sets calling and naming conventions for procedures and public symbols.
Operating system OS_OS2 or OS_DOS. Determines behavior of .STARTUP and .EXIT.
Stack distance NEARSTACK or FARSTACK. Specifying NEARSTACK groups the stack segment into a single physical segment (DGROUP) along with data. SS is assumed to equal DS. FARSTACK does not group the stack with DGROUP; thus SS does not equal DS.

You can use no more than one reserved word from each field. The following examples show how you can combine various fields:

.MODEL small ; Small memory model

.MODEL large, c, farstack ; Large memory model,

; C conventions,

; separate stack

.MODEL medium, pascal, os_os2 ; Medium memory model,

; Pascal conventions,

; OS/2 start-up/exit

The next four sections give more detail on each field.

Defining the Memory Model

MASM supports the standard memory models used by Microsoft high-level languages—tiny, small, medium, compact, large, huge, and flat. You specify the memory model with attributes of the same name placed after the .MODEL directive. Your choice of a memory model does not limit the kind of instructions you can write. It does, however, control segment defaults and determine whether data and code are near or far by default (see Table 2.1).

Table 2.1 Attributes of Memory Models

Memory Model Default Code Default Data Operating
System
Data and Code Combined

Tiny Near Near DOS Yes
Small Near Near DOS, OS/2 1.x No
Medium Far Near DOS, OS/2 1.x No
Compact Near Far DOS, OS/2 1.x No
Large Far Far DOS, OS/2 1.x No
Huge Far Far DOS, OS/2 1.x No
Flat Near Near OS/2 2.x Yes

When writing assembler modules for a high-level language, you should use the same memory model as the calling language. Generally, choose the smallest memory model available that can contain your data and code, since near references are more efficient than far references.

The predefined symbol @Model returns the memory model. It encodes memory models as integers 1 through 7. See Section 1.2.3 for more information on predefined symbols, and see online help for an example of how to use them.

The seven memory models supported by MASM 6.0 divide into three groups.

Small, Medium, Compact, Large, and Huge Models

The traditional memory models recognized by many DOS and OS/2 1.x languages are small, medium, compact, large, and huge. Small model supports one data segment and one code segment. All data and code are near by default. Large model supports multiple code and multiple data segments. All data and code are far by default. Medium and compact models are in between. Medium model supports multiple code and single data segments; compact model supports multiple data segments and a single code segment.

Huge model implies individual data items larger than a single segment, but the implementation of huge data items must be coded by the programmer. Since the assembler provides no direct support for this feature, huge model is essentially the same as large model.

In each of these models, you can override the default. For example, you can make large data items far in small model, or internal procedures near in large model.

Tiny Model

OS/2 does not support tiny model, but DOS does under MASM 6.0. This model places all data and code in a single segment. Therefore, the total program size can be no more than 64K. The default is near for code and static data items; you cannot override this default. However, you can allocate far data dynamically at run time using DOS memory allocation services.

Tiny model produces DOS .COM files. Specifying .MODEL tiny automatically sends a /TINY to the linker. Therefore, /AT is not necessary with .MODEL tiny. However, /AT does not insert a .MODEL directive. It only verifies that there are no base or pointer fixups, and sends /TINY to the linker.

Flat Model

The flat memory model is a nonsegmented configuration available for 32-bit operating systems. It is similar to tiny model in that all code and data go in a single 32-bit segment.

OS/2 2.x uses flat model when you specify the .386 or .486 directive before .MODEL FLAT. All data and code (including system resources) are in a single 32-bit segment. Segment registers are initialized automatically at load time; the programmer needs to modify them only when mixing 16-bit and 32-bit segments in a single application. CS, DS, ES, and SS are all assumed to the supergroup FLAT. FS and GS are assumed to ERROR, since 32-bit versions of OS/2 reserve the use of these registers. Addresses and pointers passed to system services are always 32-bit near addresses and pointers. Although the theoretical size of the single flat segment is four gigabytes, OS/2 2.0 actually limits it to 512 megabytes in flat model.

Choosing the Language Convention

Summary: The language type is most important when you write a mixed-language program.

The language option facilitates compatibility with high-level languages by determining the internal encoding for external and public symbol names, the code generated for procedure initialization and cleanup, and the order that arguments are passed to a procedure with INVOKE. It also facilitates compatibility with high-level-language modules. The PASCAL, BASIC, and FORTRAN conventions are identical. C and SYSCALL have the same calling convention but different naming conventions. OS/2 system calls require the PASCAL calling convention for OS/2 1.x, but require the SYSCALL convention for OS/2 2.x. Specifying STDCALL for the calling convention enables a different calling convention and the same naming convention (see Section 20.1).

Procedure definitions (PROC) and high-level procedure calls (INVOKE) automatically generate code consistent with the calling convention of the specified language. The PROC, INVOKE, PUBLIC, and EXTERN directives all use the naming convention of the language. These directives follow the default language conventions from the .MODEL directive unless you specifically override the default. Chapter 7, “Controlling Program Flow,” tells how to use these directives. You can also use the OPTION directive to set the language type. (See Section 1.3.2.) Not specifying a language type in either the .MODEL, OPTION, EXTERN, PROC, INVOKE, or PROTO statement causes the assembler to generate an error.

The predefined symbol @Interface provides information about the language parameters. See online help for a description of the bit flags.

See Chapter 20, “Mixed-Language Programming,” for more information on calling and naming conventions. See Chapter 7, “Controlling Program Flow,” for information about writing procedures and prototypes. See Chapter 8, “Sharing Data and Procedures among Modules and Libraries,” for information on multiple-module programming.

Specifying the Operating System

The operating-system options (OS_DOS or OS_OS2) are arguments of .MODEL. They specify the start-up and exit code generated by the .STARTUP and .EXIT directives. (See Section 2.2.6.) If you do not use .STARTUP and .EXIT, you can omit this option. The default is OS_DOS.

Setting the Stack Distance

The NEARSTACK setting places the stack segment in a group, DGROUP, shared with data. The .STARTUP directive then generates code to adjust SS:SP so that SS (Stack Segment register) holds the same address as DS (Data Segment register). If you do not use .STARTUP, you must make this adjustment yourself or your program may fail to run. (See Section 2.2.6 for information about start-up code.) In this case, you can use DS to access stack items (including parameters and local variables) and SS to access near data. Furthermore, since stack items share the same segment address as near data, you can reliably pass near pointers to stack items.

Summary: Having SS equal to DS gives some programming advantages.

The FARSTACK setting gives the stack a segment of its own. That is, SS does not equal DS. The default stack type, NEARSTACK, is a convenient setting for most programs. Use FARSTACK for special cases such as memory-resident programs and dynamic-link libraries (DLLs) when you cannot assume that the caller's stack is near.

The stack specification also affects the ASSUME statement generated by .MODEL and .STACK. You can use the predefined symbol @Stack to determine if the stack location is DGROUP (for near stacks) or STACK (for far stacks).