随着广告宣传的普及,现代的x86_64处理器拥有64位寄存器,可以以向后兼容的方式用作32位寄存器、16位寄存器甚至8位寄存器,例如:
0x1122334455667788
================ rax (64 bits)
======== eax (32 bits)
==== ax (16 bits)
== ah (8 bits)
== al (8 bits)
这样的方案可以被字面理解,即人们总是可以使用指定名称来读取或写入寄存器的一部分,并且这是高度逻辑的。事实上,对于32位以下的所有内容都是如此。
mov eax, 0x11112222 ; eax = 0x11112222
mov ax, 0x3333 ; eax = 0x11113333 (works, only low 16 bits changed)
mov al, 0x44 ; eax = 0x11113344 (works, only low 8 bits changed)
mov ah, 0x55 ; eax = 0x11115544 (works, only high 8 bits changed)
xor ah, ah ; eax = 0x11110044 (works, only high 8 bits cleared)
mov eax, 0x11112222 ; eax = 0x11112222
xor al, al ; eax = 0x11112200 (works, only low 8 bits cleared)
mov eax, 0x11112222 ; eax = 0x11112222
xor ax, ax ; eax = 0x11110000 (works, only low 16 bits cleared)
然而,一旦涉及到64位的东西,事情似乎变得相当尴尬:
mov rax, 0x1111222233334444 ; rax = 0x1111222233334444
mov eax, 0x55556666 ; actual: rax = 0x0000000055556666
; expected: rax = 0x1111222255556666
; upper 32 bits seem to be lost!
mov rax, 0x1111222233334444 ; rax = 0x1111222233334444
mov ax, 0x7777 ; rax = 0x1111222233337777 (works!)
mov rax, 0x1111222233334444 ; rax = 0x1111222233334444
xor eax, eax ; actual: rax = 0x0000000000000000
; expected: rax = 0x1111222200000000
; again, it wiped whole register
对我来说,这种行为似乎非常荒谬和不合逻辑。看起来似乎通过任何手段将任何内容写入eax
寄存器都会导致rax
寄存器高32位被擦除。
所以,我有两个问题:
我相信这种奇怪的行为必须在某处有文档记录,但是我似乎找不到详细的解释(关于64位寄存器的高32位如何被清除的具体说明)。我是否正确,写入
eax
总是会清除rax
,还是说情况更加复杂?它适用于所有64位寄存器吗,还是有一些例外?一个相关问题提到了同样的行为,但是,遗憾的是,没有确切的文档参考。
换句话说,我想要一个指定此行为的文档链接。
只有我觉得整件事情看起来非常奇怪和不合逻辑吗(即eax-ax-ah-al,rax-ax-ah-al具有一种行为,而rax-eax具有另一种行为)?也许我在这里错过了某种至关重要的点,以至于不得不实现它?
对“为什么”做出解释将会非常感激。
; eax = 0x11110044
。 - User.1