2012-11-01 28 views
7

我试图理解.code16的GAS行为。 从手册看,在16位部分,对于32位操作数或指令,将为指令编码生成一个66H操作数覆盖前缀。这是否意味着16位模式下的操作数大小前缀

.code16 
movw %eax, %ebx 

在这种模式下是否合法?那么代码无法在16位处理器上运行?

+0

这是不合法的,因为'w'后缀表示2字节移动。 'movl%eax,%eax'是合法的。 – fuz

回答

10

这些是80386+的法律说明。 从80386开始,我们可以使用操作数大小和地址大小覆盖前缀。这些前缀可以与16位地址模式和32位地址模式组合使用。此外,它可以与真实地址模式以及保护模式和虚拟86模式一起使用。这些前缀反转了codesegment中一个指令的默认操作数大小和/或地址大小。默认的操作数大小和地址大小由代码段描述符中的D标志指定(或者如果没有GDT/LDT,则在完成BIOS的POST处理后我们变为16位地址模式)。

使用16位地址模式,我们必须添加这些前缀,如果我们想要使用32位操作数和/或32位地址。没有这些前缀,我们只能使用16位地址模式中的16位地址/操作数。

对于32位地址模式,如果我们想要使用32位操作数和/或32位地址,我们必须从代码中省略这些前缀。如果我们将这些前缀添加到我们的代码中,那么我们可以在32位地址模式中使用16位地址/操作数。

块引用 英特尔:

指令前缀可以用于覆盖一个代码段的默认操作数大小和地址大小。这些前缀可以用于实地址模式以及保护模式和虚拟8086模式。操作数大小或地址大小前缀仅改变指令持续时间的大小。

以下两个指令前缀允许一个段内的32位和16位操作的混合: •的操作数大小前缀(66H) •地址大小前缀(67H)

这些前缀反转代码段描述符中由D标志选择的默认大小。例如,处理器可以用以下四种方式中的任何一种来解释(MOV mem,reg)指令: •在32位代码段中: - 使用32位有效从32位寄存器移动到存储器的32位地址。 - 如果以操作数大小前缀开头,则使用32位有效地址将16位从16位寄存器移至内存。 - 如果前面有地址大小前缀,则使用16位有效地址将32位从32位寄存器移动到存储器。 - 如果前面有地址大小前缀和操作数大小前缀,则使用16位有效地址将16位从16位寄存器移到内存。

•在16位代码段中: - 使用16位有效地址将16位从16位寄存器移动到存储器。 - 如果前面有操作数大小前缀,则使用16位有效地址将32位从32位寄存器移动到存储器。 - 如果前面有地址大小前缀,则使用32位有效地址将16位从16位寄存器移动到存储器。 - 如果前面有地址大小前缀和操作数大小前缀,则使用32位有效地址将32位从32位寄存器移动到存储器。

前面的例子表明,无论指令是16位还是32位段,任何指令都可以生成操作数大小和地址大小的任意组合。代码段的16位或32位默认值的选择通常基于以下条件: •性能 - 尽可能始终使用32位代码段。它们在P6系列处理器上的运行速度比16位代码段快得多,而在早期的IA-32处理器上运行速度要快一些。 •代码段将在其上运行的操作系统 - 如果操作系统是16位操作系统,则可能不支持32位程序模块。 •操作模式 - 如果代码段被设计为以实地址模式,虚拟8086模式或SMM运行,则它必须是16位代码段。 •向后兼容早期的IA-32处理器 - 如果代码段必须能够在Intel 8086或Intel 286处理器上运行,则它必须是16位代码段。

代码段描述符中的D标志决定了代码段指令的默认操作数大小和地址大小。 (在不使用段描述符的实地址模式和虚拟8086模式下,缺省值为16位。)设置了D标志的代码段是一个32位段;其D标志清除的代码段是一个16位段。

可执行代码段。该标志被称为D标志,它表示段中指令引用的有效地址和操作数的默认长度。如果标志置位,则假定32位地址和32位或8位操作数;如果清楚,则假定16位地址和16位或8位操作数。 指令前缀66H可以用来选择除默认值以外的操作数大小,并且可以使用前缀67H选择非默认值的地址大小。

32位操作数前缀可用于实地址模式程序中以执行32位指令形式。此前缀还允许实地址模式程序使用处理器的32位通用寄存器。 32位地址前缀可用于实地址模式程序,允许32位偏移量。

从Intel386处理器开始的IA-32处理器可以使用地址覆盖前缀生成32位偏移量;然而,在实地址模式下,32位偏移量的值不得超过FFFFH而不会引起异常。

汇编程序用法: 如果定义了要以实地址模式运行的代码段,则必须将其设置为USE 16属性。如果在此代码段的指令中使用32位操作数(例如,MOV EAX,EBX),汇编程序会自动为强制处理器执行32位操作的指令生成操作数前缀,即使其操作数默认的代码段属性是16位。

32位操作数前缀允许实地址模式程序使用32位通用寄存器(EAX,EBX,ECX,EDX,ESP,EBP,ESI和EDI)。

当在段寄存器和32位通用寄存器之间以32位模式移动数据时,Pentium Pro处理器不需要使用16位操作数大小前缀;然而,一些汇编器确实需要这个前缀。处理器假定通用寄存器的16位最低有效位 位是目标或源操作数。将 值从段选择器移动到32位寄存器时,处理器用零填充寄存器的两个高位字节 。

块引用 AMD:

3.3.2。 32位与16位地址和操作数大小 处理器可以配置为32位或16位地址和操作数大小。使用32位地址和操作数大小,最大线性地址或段偏移量为FFFFFFFFH (2^32-1),操作数大小通常为8位或32位。对于16位地址和操作数大小,最大线性地址或段偏移量为FFFFH(2^16-1),操作数大小通常为8位或16位。当使用32位寻址时,逻辑地址(或远指针)由一个16位段 选择器和一个32位偏移量组成;当使用16位寻址时,它由一个16位段选择器 和一个16位偏移量组成。 指令前缀允许临时覆盖程序中默认地址和/或操作数大小 。 在保护模式下运行时,当前正在执行的代码段描述符 段定义了默认地址和操作数大小。段描述符是系统数据 结构对于应用程序代码通常不可见。汇编程序指令允许为程序选择默认的 寻址和操作数大小。然后汇编程序和其他工具将代码段的段描述符合适地设置为 。 在实地址模式下操作时,默认寻址和操作数大小为16位。一个 地址大小覆盖可用于实地址模式,以启用32位寻址;不过,最大允许的32位线性地址仍然是000FFFFFH(2^20-1)。

3.6。操作数大小和地址大小属性 当处理器在保护模式下执行时,每个代码段都具有默认操作数大小 属性和地址大小属性。在代码段的段描述符中使用D(默认大小) 标志选择这些属性(请参阅“英特尔架构软件开发人员手册”第3卷第3章保护模式内存 管理)。当设置D 标志时,将选择32位操作数大小和地址大小属性;当标志清除时,选择16位大小属性。当处理器以实地址模式, 虚拟8086模式或SMM(系统管理模式)执行时,默认操作数大小和地址大小属性始终为16位 位。 操作数大小属性选择指令操作的操作数的大小。当16位操作数大小属性有效时,当32位操作数大小属性有效时,操作数一般可以是8位或16位,而 ,操作数通常可以是8位或32位。 地址大小属性选择用于对存储器寻址的地址大小:16位或32位 位。当16位地址大小属性有效时,段偏移量和位移量为16位0,1235,164,106,1745,151,505369,位。此限制限制了可以发送到64 KB的段的大小。当32位地址大小属性有效时,段偏移量和位移量为32位,因此可以对 段的最大4 GB的字节进行寻址。 通过向指令添加操作数大小和/或地址大小前缀,可以为特定的指令覆盖默认的操作数大小属性和/或地址大小属性(请参阅第2章中的 “指令前缀”英特尔架构软件开发人员手册, 第3卷)。此前缀的作用仅适用于所附的指令。 表3-1显示了有效操作数大小和地址大小(在受保护模式下执行时) ,具体取决于D标志和操作数大小和地址大小前缀的设置。

Dirk