x64 での 4 つの引数レジスタの選択- UN*X / Win64 に共通
x86 について留意すべきことの 1 つは、レジスタ名から「reg 番号」へのエンコーディングが明確でないことです。命令エンコーディング ( MOD R/Mバイト、http: //www.c-jump.com/CIS77/CPU/x86/X77_0060_mod_reg_r_m_byte.htm を参照) に関しては、レジスタ番号 0...7 は - この順序で - ?AX
, ?CX
, ?DX
, ?BX
, ?SP
, ?BP
, . ?SI
_?DI
したがって、戻り値と最初の 2 つの引数に A/C/D (regs 0..2) を__fastcall
選択することは論理的な選択です (これは「古典的な」32 ビット規則です)。64ビットへの移行に関する限り、「より高い」regが注文され、MicrosoftとUN * X / Linuxの両方が最初のものとしてR8
/に行きました。R9
これを念頭に置いて、引数に4 つのレジスタを選択する場合、Microsoft のRAX
(戻り値) とRCX
, RDX
, R8
, (arg[0..3]) の選択は理解できる選択です。R9
RDX
AMD64 UN*X ABI が以前に選択された理由はわかりませんRCX
。
x64 での 6 つの引数レジスタの選択- UN*X 固有
RISC アーキテクチャ上の UN*X は、伝統的にレジスタで引数を渡してきました。具体的には、最初の6 つの引数についてです (少なくとも PPC、SPARC、MIPS ではそうです)。これは、AMD64 (UN*X) ABI 設計者がそのアーキテクチャでも 6 つのレジスタを使用することを選択した主な理由の 1 つかもしれません。
では、6 つのレジスタに引数を渡す必要があり、そのうちの 4 つに対してRCX
、RDX
、R8
およびを選択するのが論理的R9
である場合、他の 2 つを選択する必要があります。
「より高い」レジスタは、それらを選択するために追加の命令プレフィックスバイトを必要とするため、命令サイズのフットプリントが大きくなるため、オプションがある場合はそれらのいずれも選択したくないでしょう。古典的なレジスタのうち、 and の暗黙の意味によりRBP
、RSP
これらは利用できず、RBX
伝統的に UN*X (グローバルオフセットテーブル) で特別な用途を持っていますが、AMD64 ABI 設計者は不必要に非互換になることを望まなかったようです。
したがって、唯一の選択肢はRSI
/でしたRDI
。
RSI
/RDI
を引数レジスタとして使用する必要がある場合、どの引数を使用する必要がありますか?
それらを作るarg[0]
と、arg[1]
いくつかの利点があります。cHao のコメントを参照してください。
?SI
と?DI
は文字列命令のソース/宛先オペランドであり、cHao が述べたように、引数レジスタとしての使用は、AMD64 UN*X 呼び出し規則ではstrcpy()
、repz movsb; ret
ソース/ターゲットがアドレスは、呼び出し元によって正しいレジスターに入れられました。特に、低レベルおよびコンパイラによって生成された「接着剤」コードに存在します (たとえば、一部の C++ ヒープ アロケータは、構築時にオブジェクトをゼロで埋めたり、カーネルでヒープ ページをゼロで埋めたりします。sbrk()
、またはコピー オン ライト ページフォールト) は膨大な量のブロック コピー/フィルを生成するため、そうでなければそのようなソース/ターゲット アドレス引数を「正しい」レジスタ。
したがって、ある意味では、UN*X と Win64 の違いは、UN*X が、、およびの 4 つの引数の自然な選択に、意図的に選択されたRSI
/RDI
レジスタで 2 つの追加の引数を「先頭に追加」することだけです。RCX
RDX
R8
R9
それ以上 ...
UN*X と Windows x64 ABI の間には、特定のレジスタへの引数のマッピング以外にも多くの違いがあります。Win64 の概要については、以下を確認してください。
http://msdn.microsoft.com/en-us/library/7kcdt6fy.aspx
Win64 と AMD64 UN*X では、スタックスペースの使用方法も著しく異なります。たとえば、Win64 では、args 0...3 がレジスタで渡されても、呼び出し元は関数の引数にスタック領域を割り当てる必要があります。一方、UN*X では、リーフ関数 (つまり、他の関数を呼び出さない関数) は、128 バイト以下しか必要としない場合、スタック領域を割り当てる必要さえありません (はい、所有していて使用できます)。それを割り当てずに一定量のスタックを...まあ、あなたがカーネルコードでない限り、気の利いたバグの原因です)。これらはすべて特定の最適化の選択であり、それらの理論的根拠のほとんどは、元の投稿者のウィキペディア参照が指す完全な ABI 参照で説明されています。