90

広く宣伝されているように、最新の 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つの質問があります:

  1. この厄介な動作はどこかに文書化する必要があると思いますが、詳細な説明 (64 ビットレジスタの上位 32 ビットがどのように消去されるか) がどこにも見つからないようです。eax常にワイプに書いているraxのは正しいですか、それとももっと複雑ですか?すべての 64 ビット レジスタに適用されますか、それともいくつかの例外がありますか?

    強く関連する質問で同じ動作について言及されていますが、残念ながら、ドキュメントへの正確な参照はありません。

    つまり、この動作を指定するドキュメントへのリンクが必要です。

  2. それは私だけですか、それともこの全体が本当に奇妙で非論理的であるように思われますか (つまり、eax-ax-ah-al、rax-ax-ah-al には 1 つの動作があり、rax-eax には別の動作があります)? なぜそのように実装されたのかについて、ここである種の重要な点が欠けているのではないでしょうか?

    「なぜ」についての説明をいただければ幸いです。

4

1 に答える 1

89

Intel/AMD プロセッサ マニュアルに記載されているプロセッサ モデルは、最新のコアの実際の実行エンジンにとってはかなり不完全なモデルです。特に、プロセッサ レジスタの概念は現実と一致しません。EAX レジスタや RAX レジスタなどは存在しません。

命令デコーダーの主な仕事の 1 つは、従来の x86/x64 命令をRISC のようなプロセッサの命令であるmicro-opsに変換することです。同時に実行しやすく、複数の実行サブユニットを利用できる小さな命令。同時に 6 つの命令を実行できます。

これを機能させるために、プロセッサ レジスタの概念も仮想化されます。命令デコーダは、レジスタの大きなバンクからレジスタを割り当てます。命令がリタイアすると、その動的に割り当てられたレジスタの値が、現在 RAX の値を保持しているレジスタに書き戻されます。

これをスムーズかつ効率的に機能させ、多くの命令を同時に実行できるようにするには、これらの操作に相互依存性がないことが非常に重要です。そして、あなたが持つことができる最悪の種類は、レジスタ値が他の命令に依存することです. EFLAGS レジスタは悪名高く、多くの命令で変更されます。

好きなように動作する方法と同じ問題。大きな問題は、命令がリタイアしたときに 2 つのレジスタ値をマージする必要があることです。コアを詰まらせるデータ依存関係を作成します。上位 32 ビットを強制的に 0 にすることで、依存関係が即座になくなり、マージする必要がなくなります。ワープ9の実行速度。

于 2014-08-22T21:56:16.320 に答える