我一直在想32位汇编代码是否是64位汇编代码的子集,即每个32位汇编代码都可以在64位环境中运行?
我猜答案是肯定的,因为64位Windows能够执行32位程序,但是我看到64位处理器支持32位兼容模式?
如果不是,请提供一个小的例子,说明32位汇编代码无法转换为64位汇编代码,并解释64位处理器如何执行32位汇编代码。
现代 x86 处理器有三种主要操作模式(此处描述简化):
维基百科有一个很好的表格,列出了 x86-64 操作模式,包括遗留和实模式以及长模式的所有 3 个子模式。在主流 x86-64 操作系统下,引导 CPU 核心后,它们始终处于长模式,根据 32 位或 64 位用户空间切换不同的子模式。(不考虑系统管理模式中断...)
那么 16 位、32 位和 64 位模式之间有什么区别呢?
16 位和 32 位模式基本相同,除了以下差异:
现在,64位模式有一些不同。大多数指令的行为与32位模式类似,但有以下区别:
inc reg
和 dec reg
指令不可用,它们的指令空间已被重新分配给REX前缀。 两个字节的 inc r/m
和 dec r/m
仍然可用,因此可以编码 inc reg
和 dec reg
。 [disp32]
绝对地址编码方式之一。ah
、bh
、ch
和dh
。REX前缀会导致这些寄存器编号改为表示si
、di
、sp
和bp
寄存器的低8位。fs
和gs
覆盖语句(0x64,0x65),用于支持线程本地存储(TLS)。push/pop seg
(除push/pop fs/gs
外)、arpl
、call far
(只有0xff编码有效)、les
、lds
、jmp far
(只有0xff编码有效)。daa
, das
, aaa
, aas
, aam
, aad
,bound
(很少使用),pusha
/popa
(对于额外的寄存器没有用处),salc
(未经记录)。lahf
和sahf
不可用。基本上就是这些了!
不,不是这样的。
尽管有很多重叠,但64位汇编代码并不是32位汇编代码的超集,因此32位汇编代码在64位模式下通常无效。
这适用于助记符汇编源代码(由汇编器汇编成二进制格式)以及二进制机器码格式本身。
这个问题详细介绍了被移除的指令,但也有许多编码形式的含义发生了改变。
例如,评论中的Jester给出了push eax
在64位代码中无效的示例。根据这个参考,你可以看到32位push被标记为N.E.,意思是不可编码。在64位模式下,该编码用于表示push rax
(一个8字节的push)。因此,相同的字节序列在32位模式和64位模式下具有不同的含义。
总体而言,您可以浏览该网站上的指令列表,并找到许多在64位模式下被列为无效或不可编码的指令。
如上所述,如果不是这样,请提供一个32位汇编代码的小例子,它不能成为64位汇编代码,并解释64位处理器如何执行32位汇编代码。
push eax
就是一个例子。我认为缺失的是64位CPU支持直接运行32位二进制文件。它们并不通过机器语言级别上的32位和64位指令的兼容性来实现,而是通过具有32位模式的方式,其中解码器(尤其是)将指令流解释为32位x86而不是x86-64,以及用于运行64位指令的所谓长模式。当这样的64位芯片首次发布时,通常运行32位操作系统,这几乎意味着芯片永久处于此模式(永远不进入64位模式)。
最近,典型的做法是运行64位操作系统,该操作系统了解这些模式,并且在用户启动32位进程时将CPU置于32位模式下(这仍然非常常见:直到最近我的浏览器仍然是32位的)。
有关模式的所有详细信息和适当术语可以在fuz的答案中找到,这实际上是您应该阅读的答案。