操作数大小前缀为16位模式

Oxd*_*eef 7 overriding 16-bit operand

我试图了解GAS的.code16的行为.从手册中可以看出,在16位部分中,对于32位操作数或指令,将为指令编码生成66H操作数覆盖前缀.这是什么意思

.code16
movw %eax, %ebx
Run Code Online (Sandbox Code Playgroud)

在这种模式下合法吗?那么代码不能在16位处理器上运行?

小智 11

这些是80386+的法律说明.从80386开始,我们可以使用operandsize-和addresssize- override前缀.这些前缀可以与16位地址模式和32位地址模式结合使用.另外,它可以与真实地址模式一起使用,也可以与受保护模式和虚拟86模式一起使用.这些前缀反转了代码段中一条指令的默认操作数大小和/或地址大小.默认的operandsize和addresssize由代码段描述符中的D标志指定(或者如果没有GDT/LDT,那么我们将在完成BIOS的POST过程后成为16位地址模式.)

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

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

Blockquote英特尔:

指令前缀可用于覆盖代码段的默认操作数大小和地址大小.这些前缀可用于实地址模式以及受保护模式和虚拟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位寄存器时,处理器用零填充寄存器的两个高位字节.

Blockquote 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位.operand-size属性选择指令操作的操作数的大小.当16位操作数大小属性有效时,操作数通常可以是8位或16位,当32位操作数大小属性有效时,操作数通常可以是8位或32位.address-size属性选择用于寻址内存的地址大小:16位或32位.当16位地址大小属性生效时,段偏移和位移为16位.此限制限制了可以寻址为64 KB的段的大小.当32位地址大小属性生效时,段偏移和位移为32位,允许最多4 GB的段被寻址.通过向指令添加操作数大小和/或地址大小前缀,可以为特定指令覆盖缺省操作数大小属性和/或地址大小属性(请参阅英特尔架构软件第2章中的"指令前缀")开发人员手册,第3卷).此前缀的效果仅适用于它所附加的指令.表3-1显示了有效的操作数大小和地址大小(在保护模式下执行时),具体取决于D标志的设置以及操作数大小和地址大小前缀.

短剑