広く宣伝されているように、最新の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ビットが消去されます。
だから、私は2つの質問があります:
この厄介な動作はどこかに文書化する必要があると思いますが、詳細な説明(64ビットレジスタの32ビットが正確に消去される方法)はどこにも見当たりません。 eax
への書き込みは常にrax
をワイプしますか、それとももっと複雑なことですか?すべての64ビットレジスタに適用されますか、それとも例外がありますか?
強く関連した質問 は同じ振る舞いについて言及していますが、残念ながら、ドキュメントへの正確な参照はありません。
つまり、この動作を指定するドキュメントへのリンクが必要です。
それは私だけですか、この全体は本当に奇妙で非論理的です(つまり、eax-ax-ah-al、rax-ax-ah-alには1つの動作があり、rax-eaxには別の動作があります)?なぜそれがそのように実装されたのかについて、ここで何らかの重要なポイントを見逃しているのでしょうか?
「理由」についての説明は大歓迎です。
Intel/AMDプロセッサマニュアルに記載されているプロセッサモデルは、最新のコアのreal実行エンジンのかなり不完全なモデルです。特に、プロセッサレジスタの概念は現実と一致せず、EAXまたはRAXレジスタのようなものはありません。
命令デコーダーの主な仕事の1つは、レガシーx86/x64命令をmicro-ops、RISCのようなプロセッサーの命令に変換することです。同時に実行しやすく、複数の実行サブユニットを活用できる小さな命令。最大6つの命令を同時に実行できます。
これを機能させるために、プロセッサレジスタの概念も仮想化されています。命令デコーダは、レジスタの大きなバンクからレジスタを割り当てます。命令が非推奨の場合、その動的に割り当てられたレジスタの値は、たとえばRAXの値を現在保持しているレジスタに書き戻されます。
それを円滑かつ効率的に動作させ、多くの命令を同時に実行できるようにするには、これらの操作に相互依存性がないことが非常に重要です。最悪の場合、レジスタ値は他の命令に依存します。 EFLAGSレジスタは悪名高く、多くの命令で修正されています。
like動作する方法と同じ問題。大きな問題は、命令が廃止されたときに2つのレジスタ値をマージする必要があることです。コアを詰まらせるデータ依存関係を作成します。上位32ビットを0に強制すると、その依存関係は即座に消え、マージする必要がなくなります。ワープ9の実行速度。