FLAT操作数对SEGMENT指令的影响?

时间:2017-07-16 02:14:21

标签: assembly x86 masm

MASM提供SEGMENT指令。该指令采用了几个参数。 use参数可以取值FLAT。我不清楚这个价值是做什么的。

Microsoft docs将其指定为可接受的值,但不要尝试描述它:

  

使用
   USE16 USE32 FLAT

在线提供的书籍The Art of Assembly Language Programming提到它,但称其超出范围并建议阅读MASM程序员指南:

  

use32flat操作数告诉MASM为32位段生成代码。由于本文不涉及保护模式编程,因此我们不会考虑这些选项。有关详细信息,请参阅MASM程序员指南。

在Microsoft的MASM 6.1程序员指南中,在描述SEGMENT指令的部分中,提到了FLAT值,但从未描述过它的影响:

  

尺寸属性可以是 USE16 USE32 FLAT

FLAT操作数对SEGMENT指令有什么影响?

1 个答案:

答案 0 :(得分:5)

对于大多数用途,在段指令中使用FLAT关键字与USE32具有相同的含义。 USE32和FLAT关键字都表明该段可以大于64K,并且在段中组装的任何指令都应该使用32位编码而不是16位编码。区别在于汇编程序对CS寄存器的假设。通常情况下,SEGMENT指令会生成隐式ASSUME CS:xxx指令,其中xxx是段的名称,但使用FLAT会导致隐式ASSUME CS:FLAT

ASSUME指令告诉汇编器将哪些段加载到哪个段寄存器中,以便它可以在需要时自动使用正确的段覆盖。在大多数32位操作系统使用的平面存储器模型中,只有一个4千兆字节的段。告诉汇编程序可以通过该段寄存器访问程序中定义的所有段,告诉汇编程序它可以采用段寄存器。例如ASSUME DS:FLAT表示可以通过DS寄存器访问所有段。另一方面,ASSUME DS:_DATA表示DS寄存器只能用于访问_DATA段而不能用于访问任何其他段。

您可以通过汇总以下代码来查看此行为:

_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

如果您反汇编生成的目标文件,您会看到前两条指令:

  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

对于这两条指令,汇编程序必须使用CS段覆盖(2E)才能访问zerovar。这是因为虽然汇编程序知道CS可用于访问所有段,包括_TEXT_DATA,但它并不知道可以使用任何其他段寄存器来访问这些semgents。

这是在ASSUME DS:_FLAT指令之后为下两条指令生成的代码:

  0000000C: A1 00 00 00 00     mov         eax,dword ptr [zero]
  00000011: A3 00 00 00 00     mov         dword ptr [var],eax

现在汇编程序知道CS和DS都可以用来访问所有段。由于使用DS访问zerovar并不需要段覆盖,因此它使用DS代替CS,从而导致更短的指令。

最后,在ASSUME DS:_DATAASSUME CS:_TEXT指令之后的最后两条指令显示了如果根本不使用FLAT关键字,汇编器将生成的代码:

  00000016: 2E A1 00 00 00 00  mov         eax,dword ptr cs:[zero]
  0000001C: A3 00 00 00 00     mov         dword ptr [var],eax

在这种情况下,汇编程序假设CS只能用于访问_TEXT,而DS只能用于访问_DATA。它必须使用CS覆盖来访问zero,而它只能通过DS访问var,这不需要分段覆盖。

注意如果在上面的示例代码中将SATMENT指令中的FLAT更改为USE32,则第一条指令最终使用CS覆盖,但第二条指令会产生以下错误:

error A2074:cannot access label through segment registers

那是因为虽然汇编程序知道它可以通过CS寄存器访问_TEXT,但它并不知道它可以用来访问_DATA的任何段寄存器。

如果您在代码开头使用.MODEL FLAT指令,则不必担心任何此类指令。然后USE32和FLAT在段指令中具有完全相同的效果,因为假定每个段寄存器都是FLAT。