広く宣伝されているように、最新の x86_64 プロセッサには、32 ビット レジスタ、16 ビット レジスタ、さらには 8 ビット レジスタとして下位互換性のある方法で使用できる 64 ビット レジスタがあります。次に例を示します。
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
の上位 32 ビットが消去されるようrax
です。
だから、私は2つの質問があります:
この厄介な動作はどこかに文書化する必要があると思いますが、詳細な説明 (64 ビットレジスタの上位 32 ビットがどのように消去されるか) がどこにも見つからないようです。
eax
常にワイプに書いているrax
のは正しいですか、それとももっと複雑ですか?すべての 64 ビット レジスタに適用されますか、それともいくつかの例外がありますか?強く関連する質問で同じ動作について言及されていますが、残念ながら、ドキュメントへの正確な参照はありません。
つまり、この動作を指定するドキュメントへのリンクが必要です。
それは私だけですか、それともこの全体が本当に奇妙で非論理的であるように思われますか (つまり、eax-ax-ah-al、rax-ax-ah-al には 1 つの動作があり、rax-eax には別の動作があります)? なぜそのように実装されたのかについて、ここである種の重要な点が欠けているのではないでしょうか?
「なぜ」についての説明をいただければ幸いです。