The segmented architecture of the 8086-family of processors does not require you to specify two addresses every time you access memory. As Chapter 2, “Organizing MASM Segments,” explains, the 8086 family of processors uses a system of default segment registers to simplify access to the most commonly used data and code.
The segment registers DS, SS, and CS are normally initialized to default segments at the beginning of a program. If you write the main module in a high-level language, the compiler initializes the segment registers. If you write the main module in assembly language, you must initialize them yourself. Follow these two steps to initialize segments:
1.Tell the assembler which segment is associated with a register. The assembler must know the default segments at assembly time.
2.Tell the processor which segment is associated with a register by writing the necessary code to load the correct segment value into the segment register on the processor.
These steps are discussed separately in the following sections.
Summary: Use ASSUME to inform the assembler about default segments.
The first step in initializing segments is to tell the assembler which segment to associate with a register. You do this with the ASSUME directive. If you use simplified segment directives, the assembler generates the appropriate ASSUME statements automatically. If you use full segment definitions, you must code the ASSUME statements for registers other than CS yourself. (ASSUME can also be used on general-purpose registers, as explained in Section 3.3.2, “Defining Register Types with ASSUME.”)
With simplified segment directives, the .STARTUP directive and the start-up code initialize DS to be equal to SS (unless you specify FARSTACK), which allows default data to be accessed through either SS or DS. This can improve efficiency in the code generated by compilers. The “DS equals SS” convention may not work with certain applications, such as memory-resident programs in DOS and multithread programs in OS/2. The code generated for .STARTUP is shown in Section 2.2.6, “Starting and Ending Code with .STARTUP and .EXIT.” You can use similar code to set DS equal to SS in programs using full segment definitions.
Here is an example using full segment definitions; it is equivalent to the ASSUME statement generated with simplified segment directives in small model with NEARSTACK:
ASSUME cs:_TEXT, ds:DGROUP, ss:DGROUP
In the example above, DS and SS are part of the same segment group. It is also possible to have different segments for data and code, and to use ASSUME to set ES, as shown below:
ASSUME cs:MYCODE, ds:MYDATA, ss:MYSTACK, es:OTHER
Correct use of the ASSUME statement can help find addressing errors. With .CODE, the assembler assumes CS to the current segment. When you use the simplified segment directives .DATA, .DATA?, .CONST, .FARDATA, or .FARDATA?, the assembler automatically assumes CS to ERROR. This prevents
instructions from appearing in these segments. If you use full segment definitions, you can accomplish the same by placing ASSUME CS:ERROR in a data segment.
With either simple or full segments, you can cancel the control of an ASSUME statement by assuming NOTHING. No assumptions is the default condition. For example, you cancel the assumption for ES above with the following statement:
ASSUME es:NOTHING
Prior to the .MODEL statement (or in its absence), the assembler sets the ASSUME statement for DS, ES, and SS to the current segment.
The second step in initializing segments is to inform the processor of segment values at run time. How segment values are initialized at run time differs for each segment register and depends on your use of simplified segment directives or full segment definitions and on the operating system.
The CS segment register and the IP (instruction pointer) register are initialized automatically if you use the .STARTUP directive with simplified segment directives. If you use full segment definitions, you must specifically set a label in the code segment at the instruction you want executed first. Then provide that label as an argument to the END directive. Both CS and IP are set at load time to the start address the linker gets from the END directive:
_TEXT SEGMENT WORD PUBLIC 'CODE
ORG 100h ; Use this declaration for .COM files only start: ; First instruction here
.
.
.
_TEXT ENDS
END start ; Name of starting label
The operating system automatically resolves the value of CS:IP at load time. The label specified as the start address becomes the initial value of IP. In an executable (.EXE) file, the start address is encoded into the header and is initialized by the operating system at load time. In a .COM file, the initial IP is always assumed to be 100h. Therefore, you must use the ORG directive to set the start address to 100h. CS and IP cannot be directly modified except through jump, call, and interrupt instructions.
Summary: DS is initialized auto-matically under OS/2, but you must initialize it for DOS.
The DS register is automatically initialized to the correct value (DGROUP) if you use .STARTUP or if you are writing a program for OS/2. If you do not use .STARTUP with DOS, you must initialize DS using the following instructions:
mov ax, DGROUP
mov ds, ax
The initialization requires two instructions because the segment name is a constant and the assembler does not allow a constant to be loaded directly to a segment register. The example above loads DGROUP, but you can load any valid segment or group.
Summary: SS and SP are initialized automatically.
The SS and SP registers are initialized automatically if you use the .STACK directive with simplified segments or if you define a segment that has the STACK combine type with full segment definitions. Using the STACK directive initializes SS to the stack segment. If you want SS to be equal to DS, use .STARTUP or its equivalent. (See “Combining Segments” in Section 2.3.1.) For an executable file, the values are encoded into the executable header and resolved at link time. For a .COM file, SS is initialized to the first address of the 64K program segment and SP is initialized to 0FFFEh.
If you do not need to access far data in your program, you do not need to initialize the ES register, although you can do so. Use the same technique as for the DS register. You can initialize SS to a far stack in the same way.