fs
and gs. Although you cannot access data in more than four or
six segments at any one given instant, you can modify the 80x86's segment
registers and point them at other segments in memory under program control.
This means that a program can access more than four or six segments. The
question is "how do you create these different segments in a program
and how do you access them at run-time?"segment
and ends directives. You can put as many segments as
you like in your program. Well, actually you are limited to 65,536 different
segments by the 80x86 processors and MASM probably doesn't even allow that
many, but you will probably never exceed the number of segments MASM allows
you to put in your program. cs at the segment containing your main
program and it points ss at your stack segment. From that point
forward, you are responsible for maintaining the segment registers yourself.
segmentname segment {READONLY} {align} {combine} {use} {'class'}
<statements>
segmentname ends
The following sections describe each of the operands to the segment
directive.ends directive that ends the segment.
CSEG segment
mov ax, bx
ret
CSEG ends
DSEG segment
Item1 byte 0
Item2 word 0
DSEG ends
CSEG segment
mov ax, 10
add ax, Item1
ret
CSEG ends
end
The first segment (CSEG) starts with a location counter value
of zero. The mov ax,bx instruction is two bytes long and the
ret instruction is one byte long, so the location counter is
three at the end of the segment. DSEG is another three byte
segment, so the location counter associated with DSEG also
contains three at the end of the segment. The third segment has the same
name as the first segment (CSEG), therefore the assembler will
assume that they are the same segment with the second occurrence simply
being an extension of the first. Therefore, code placed in the second CSEG
segment will be assembled starting at offset three within CSEG
- effectively continuing the code in the first CSEG segment.ds and es registers so they point at the dseg
segment:
mov ax, dseg ;Loads ax with segment address of dseg.
mov ds, ax ;Point ds at dseg.
mov es, ax ;Point es at dseg.
The other purpose for segment names is to provide the segment component
of a variable name. Remember, 80x86 addresses contain two components: a
segment and an offset. Since the 80x86 hardware defaults most data references
to the data segment, it is common practice among assembly language programmers
to do the same thing; that is, not bother to specify a segment name when
accessing variables in the data segment. In fact, a full variable reference
consists of the segment name, a colon, and the offset name:
mov ax, dseg:Item1
mov dseg:Item2, ax
Technically, you should prefix all your variables with the segment name
in this fashion. However, most programmers don't bother because of the extra
typing involved. Most of the time you can get away with this; however, there
are a few times when you really will need to specify the segment name. Fortunately,
those situations are rare and only occur in very complex programs, not the
kind you're likely to run into for a while.jmp
and call instructions, there are no 80x86 instructions that
let you specify a full 32 bit segmented direct address. All other memory
references use a segment register to supply the segment component of the
address.CSEG
segment into memory before the DSEG segment. Even though the
CSEG segment appears in two parts, both before and after DSEG.
CSEG's declaration before any occurrence of DSEG
tells DOS to load the entire CSEG segment into memory before
DSEG. To load DSEG before CSEG, you
could use the following program:
DSEG segment public
DSEG ends
CSEG segment public
mov ax, bx
ret
CSEG ends
DSEG segment public
Item1 byte 0
Item2 word 0
DSEG ends
CSEG segment public
mov ax, 10
add ax, Item1
ret
CSEG ends
end
The empty segment declaration for DSEG doesn't emit any code.
The location counter value for DSEG is zero at the end of the
segment definition. Hence it's zero at the beginning of the next DSEG
segment, exactly as it was in the previous version of this program. However,
since the DSEG declaration appears first in the program, DOS
will load it into memory first..alpha" directive,
MASM will organize the segments alphabetically rather than in order of first
appearance. The optional operands to the segment directive also control
segment loading order. These operands are the subject of the next section.segment directive allows six different items in the
operand field: an align operand, a combine operand, a class operand, a readonly
operand, a "uses" operand, and a size operand. Three
of these operands control how DOS loads the segment into memory, the other
three control code generation.byte, word,
dword, para, or page. These keywords instruct the assembler,
linker, and DOS to load the segment on a byte, word, double word, paragraph,
or page boundary. The align parameter is optional. If one of the above keywords
does not appear as a parameter to the segment directive, the default alignment
is paragraph (a paragraph is a multiple of 16 bytes).dword boundary will locate the
current segment at the first address that is an even multiple of four after
the last segment. 
seg1 segment
.
.
.
seg1 ends
seg2 segment byte
.
.
.
seg2 ends
If segments one and two are declared as below, and segment #2 is word aligned,
the segments appear in memory as shown below:
seg1 segment
.
.
.
seg1 ends
seg2 segment word
.
.
.
seg2 ends
Another example: if segments one and two are as below, and segment #2 is
double word aligned, the segments will be stored in memory as shown below:
seg1 segment
.
.
.
seg1 ends
seg2 segment dword
.
.
.
seg2 ends
Since the 80x86's segment registers always point at paragraph addresses,
most segments are aligned on a 16 byte paragraph (para) boundary.
For the most part, your segments should always be aligned on a paragraph
boundary unless you have a good reason to choose otherwise. 
seg1 segment
.
.
.
seg1 ends
seg2 segment para
.
.
.
seg2 ends
Page boundary alignment forces the segment to begin at the next address
that is an even multiple of 256 bytes. Certain data buffers may require
alignment on 256 (or 512) byte boundaries. The page alignment option can
be useful in this situation. 
seg1 segment
.
.
.
seg1 ends
seg2 segment page
.
.
.
seg2 ends
If you choose any alignment other than byte, the assembler,
linker, and DOS may insert several dummy bytes between the two segments,
so that the segment is properly aligned. Since the 80x86 segment registers
must always point at a paragraph address (that is, they must be paragraph
aligned), you might wonder how the processor can address a segment that
is aligned on a byte, word, or double word boundary. It's easy. Whenever
you specify a segment alignment which forces the segment to begin at an
address that is not a paragraph boundary, the assembler/linker will assume
that the segment register points at the previous paragraph address and the
location counter will begin at some offset into that segment other than
zero. For example, suppose that segment #1 above ends at physical address
10F87h and segment #2 is byte aligned. The code for segment #2 will begin
at segment address 10F80h. However, this will overlap segment #1 by eight
bytes. To overcome this problem, the location counter for segment #2 will
begin at 8, so the segment will be loaded into memory just beyond segment
#1.
Since the 80x86 requires all segments to start on a paragraph boundary in memory, the Microsoft Assembler (by default) assumes that you want paragraph alignment for your segments. The following segment definition is always aligned on a paragraph boundary:
CSEG segment
mov ax, bx
ret
CSEG ends
end
public, stack,
common, memory, or at. Memory
is a synonym for public provided for compatibility reasons;
you should always use public rather than memory.
Common and at are advanced combine types that
won't be considered in this text. The stack combine type should
be used with your stack segments. The public combine type should
be used with most everything else. public and stack combine types essentially
perform the same operation. They concatenate segments with the same name
into a single contiguous segment, just as described earlier. The difference
between the two is the way that DOS handles the initialization of the stack
segment and stack pointer registers. All programs should have at least one
stack type segment (or the linker will generate a warning);
the rest should all be public . MS-DOS will automatically point
the stack segment register at the segment you declare with the stack
combine type when it loads the program into memory.
CSEG segment public
mov ax, 0
mov VAR1, ax
CSEG ends
DSEG segment public
I word ?
DSEG ends
CSEG segment public
mov bx, ax
ret
CSEG ends
DSEG segment public
J word ?
DSEG ends
end
This program section will produce the same code as:
CSEG segment public
mov ax, 0
mov VAR1, ax
mov bx, ax
ret
CSEG ends
DSEG segment public
I word ?
J word ?
DSEG ends
end
The assembler automatically joins all segments that have the same name and
are public. The reason the assembler allows you to separate the segments
like this is for convenience. Suppose you have several procedures, each
of which requires certain variables. You could declare all the variables
in one segment somewhere, but this is often distracting. Most people like
to declare their variables right before the procedure that uses them. By
using the public combine type with the segment declaration, you may declare
your variables right before using them and the assembler will automatically
move those variable declarations into the proper segment when assembling
the program. For example,
CSEG segment public
; This is procedure #1
DSEG segment public
;Local vars for proc #1.
VAR1 word ?
DSEG ends
mov AX, 0
mov VAR1, AX
mov BX, AX
ret
; This is procedure #2
DSEG segment public
I word ?
J word ?
DSEG ends
mov ax, I
add ax, J
ret
CSEG ends
end
Note that you can nest segments any way you please. Unfortunately, Microsoft's
Macro Assembler scoping rules do not work the same way as a HLL like Pascal.
Normally, once you define a symbol within your program, it is visible everywhere
else in the program.