For most purposes the FLAT keyword when used in a segment directive has the same meaning as USE32. Both the USE32 and FLAT keywords indicate that the segment can be bigger than 64K and that any instructions assembled in the segment should use 32-bit encoding rather than 16-bit encoding. The difference is what the assembler assumes about the CS register. Normally a SEGMENT directive results in an implicit ASSUME CS:xxx
directive where xxx
is the name of the segment, but with FLAT it results in an implicit ASSUME CS:FLAT
.
The ASSUME directive tells the assembler which segments are loaded into which segment registers so it can automatically use the correct segment overrides where needed. In the flat memory model used by most 32-bit operating systems there only one single 4 gigabyte segment. Telling the assembler that it can assume a segment register is FLAT tells the assembler that all segments defined in the program can be accessed through that segment register. For example ASSUME DS:FLAT
says that all segments can accessed through the DS register. On the other hand ASSUME DS:_DATA
says that the DS register can only be used to access the _DATA segment and not any other segment.
You can see this behaviour by assembling the following code:
_DATA SEGMENT PUBLIC USE32
var DD ?
_DATA ENDS
_TEXT SEGMENT PUBLIC PARA 'CODE' FLAT
mov eax, [zero]
mov [var],eax
ASSUME DS:FLAT
mov eax, [zero]
mov [var],eax
ASSUME CS:_TEXT
ASSUME DS:_DATA
mov eax, [zero]
mov [var],eax
zero DD 0
_TEXT ENDS
END
If you disassemble the resulting object file you see this for the first two instructions:
00000000: 2E A1 00 00 00 00 mov eax,dword ptr cs:[zero]
00000006: 2E A3 00 00 00 00 mov dword ptr cs:[var],eax
For these two instructions the assembler has to use the CS segment override (2E
) in order to access zero
and var
. That's because while the assembler knows that CS can be used to access all segments, including _TEXT
and _DATA
, it doesn't know that any other segment register can be used to access these semgents.
Here's the code it generates for the next two instructions, after the ASSUME DS:_FLAT
directive:
0000000C: A1 00 00 00 00 mov eax,dword ptr [zero]
00000011: A3 00 00 00 00 mov dword ptr [var],eax
Now the assembler knows that both CS and DS can be used to access all segments. Since using DS to access zero
and var
doesn't require a segment override, it uses DS instead of CS resulting in shorter instructions.
Finally the last two instructions, after the ASSUME DS:_DATA
and ASSUME CS:_TEXT
directives, show the code assembler would generate if the FLAT keyword isn't used at all:
00000016: 2E A1 00 00 00 00 mov eax,dword ptr cs:[zero]
0000001C: A3 00 00 00 00 mov dword ptr [var],eax
In this case the assembler assumes CS can only be used to access _TEXT, and DS only to access _DATA. It has to use a CS override to access zero
, while it can only access var
through DS, which requires no segment override.
Note if you change the FLAT to USE32 in the SEGMENT directive in the example code above then first instruction ends up using a CS override, but the second instruction generates the following error:
error A2074:cannot access label through segment registers
That's because while the assembler knows it can access _TEXT through the CS register, it doesn't know of any segment register it can use to access _DATA.
If you use the .MODEL FLAT
directive at the start of you code you shouldn't have to worry about any of this. Then USE32 and FLAT have exactly same effect in segment directives as every segment register is assumed to be FLAT.
.MODEL FLAT
directive for enabling the flat model. I'm not sure when you would useFLAT
on individualSEGMENT
directives. – Unpeople