Effects of the FLAT operand to the SEGMENT directive?
Asked Answered
U

1

5

MASM provides a SEGMENT directive. The directive takes several parameters. The use parameter can take a value FLAT. It's unclear to me what this value does.

The Microsoft docs specify it as an accepted value but make no attempt to describe it:

use
USE16, USE32, FLAT

The book The Art of Assembly Language Programming available online mentions it but calls it out of scope and recommends reading the MASM Programmer's Guide:

The use32 and flat operands tell MASM to generate code for a 32 bit segment. Since this text does not deal with protected mode programming we will not consider these options. See the MASM Programmer's Guide for more details.

In the MASM 6.1 Programmer's Guide from Microsoft, in the section describing the SEGMENT directive, the FLAT value is mentioned but its effects are never described:

The size attribute can be USE16, USE32, or FLAT.

What are the effects of the FLAT operand to the SEGMENT directive?

Unpeople answered 16/7, 2017 at 2:14 Comment(4)
Do you know about 16-bit segmentation? All the major 32-bit and 64-bit OSes use a flat memory model, rather than having different bases for for different segment registers. IDK what that keyword means in MASM exactly, but maybe you're having trouble with the manual if you don't know about segmentation in the first place?Bicameral
Thanks @PeterCordes. I'm familiar with segmented and flat memory models. In MASM there's a .MODEL FLAT directive for enabling the flat model. I'm not sure when you would use FLAT on individual SEGMENT directives.Unpeople
IDK either, but I've fortunately never had to write any code for a segmented memory model (except toy SO answers), or even use MASM :P Now I'm curious, too, about this question. MASM does a lot of "magic" inferring of things, so it's probably something weird.Bicameral
Turns out it wasn't weird at all. Ross's answer makes perfect sense. :)Bicameral
G
7

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.

Gyron answered 16/7, 2017 at 9:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.