次のリンクでは、UNIX (BSD フレーバー) と Linux の両方の x86-32 システム コール規則について説明しています。
しかし、UNIX と Linux の両方での x86-64 システム コールの規則は何ですか?
次のリンクでは、UNIX (BSD フレーバー) と Linux の両方の x86-32 システム コール規則について説明しています。
しかし、UNIX と Linux の両方での x86-64 システム コールの規則は何ですか?
ここのトピックの詳細については、Linux システム コールの決定版ガイドを参照してください。
Linux で GNU Assembler (gas) を使用してこれらを検証しました。
x86-32 別名 i386 Linux システム コールの規則:
x86-32 では、Linux システム コールのパラメータはレジスタを使用して渡されます。%eax
syscall_number 用。%ebx、%ecx、%edx、%esi、%edi、%ebp は、システム コールに 6 つのパラメータを渡すために使用されます。
戻り値は です%eax
。他のすべてのレジスタ (EFLAGS を含む) は、int $0x80
.
Linux Assembly Tutorialから次のスニペットを取りましたが、これについては疑問があります。誰かが例を示すことができれば、それは素晴らしいことです。
6 つ以上の引数がある場合
%ebx
は、引数のリストが保存されているメモリの場所を含める必要がありますが、6 つ以上の引数を持つシステムコールを使用する可能性は低いため、これについて心配する必要はありません。
例ともう少し読み物については、http://www.int80h.org/bsdasm/#alternate-calling-conventionを参照してください。を使用した i386 Linux の Hello World の別の例int 0x80
: Hello, world in assembly language with Linux system calls?
32 ビット システム コールを行うより高速な方法がありますsysenter
。カーネルは、メモリのページをすべてのプロセス (vDSO) にマップします。sysenter
ダンスのユーザー空間側では、リターン アドレスを見つけるためにカーネルと協力する必要があります。マッピングを登録する引数は と同じですint $0x80
。通常は、直接使用するのではなく、vDSO を呼び出す必要がありますsysenter
。( vDSO へのリンクと呼び出しに関する情報、およびシステム コールに関するその他すべての情報については、 The Definitive Guide to Linux System Callssysenter
を参照してください。)
x86-32 [Free|Open|Net|DragonFly]BSD UNIX システム コール規則:
パラメータはスタックで渡されます。パラメーター (最初にプッシュされた最後のパラメーター) をスタックにプッシュします。次に、追加の 32 ビットのダミー データ (実際にはダミー データではありません。詳細については、次のリンクを参照してください) をプッシュし、システム コール命令を与えます。int $0x80
http://www.int80h.org/bsdasm/#default-calling-convention
(注: x86-64 Mac OS X は Linux と似ていますが異なります。TODO: *BSD の動作を確認してください)
System V Application Binary Interface AMD64 Architecture Processor Supplementの「A.2 AMD64 Linux Kernel Conventions」セクションを参照してください。i386 および x86-64 System V psABI の最新バージョンは、ABI 管理者のリポジトリのこのページからリンクされています。(最新の ABI リンクや x86 asm に関するその他の優れた情報については、 x86タグ wiki も参照してください。)
このセクションのスニペットは次のとおりです。
- ユーザーレベルのアプリケーションは、シーケンス %rdi、%rsi、%rdx、%rcx、%r8、および %r9 を渡すための整数レジスタとして使用します。カーネル インターフェイスは、%rdi、%rsi、%rdx、%r10、%r8、および %r9 を使用します。
- システムコールは、
syscall
命令によって行われます。これにより、%rcx と %r11、および %rax の戻り値が破壊されますが、他のレジスタは保持されます。- syscall の番号は、レジスタ %rax で渡す必要があります。
- システムコールは 6 つの引数に制限されており、スタックに直接渡される引数はありません。
- syscall から戻ると、レジスタ %rax にはシステム コールの結果が含まれます。-4095 ~ -1 の範囲の値はエラーを示します
-errno
。- クラス INTEGER またはクラス MEMORY の値のみがカーネルに渡されます。
これは ABI への Linux 固有の付録からのものであることを忘れないでください。(しかし、実際には正確です。)
この 32 ビットint $0x80
ABIは64 ビット コードで使用できます (ただし、強くお勧めしません)。 32 ビット int 0x80 Linux ABI を 64 ビット コードで使用するとどうなりますか? それでも入力が 32 ビットに切り捨てられるため、ポインターには適しておらず、r8 ~ r11 をゼロにします。
x86-32 関数呼び出し規約:
x86-32 では、パラメーターはスタックで渡されました。すべてのパラメータが完了するまで、最後のパラメータが最初にスタックにプッシュされ、その後call
命令が実行されました。これは、アセンブリから Linux 上の C ライブラリ (libc) 関数を呼び出すために使用されます。
i386 System V ABI (Linux で使用) の最新バージョンでは、x86-64 System V ABI が常に必要としていたように、の%esp
前に の16 バイト アラインメントが必要です。call
呼び出し先は、それを想定して、アライメントされていない場合にフォールトする SSE 16 バイトのロード/ストアを使用することができます。しかし、歴史的に、Linux は 4 バイトのスタック アラインメントしか必要としなかったため、8 バイトdouble
などでも自然にアラインされたスペースを予約するには余分な作業が必要でした。
他の最新の 32 ビット システムの中には、まだ 4 バイトを超えるスタック アラインメントを必要としないものがあります。
x86-64 System V は引数をレジスターで渡します。これは、i386 System V のスタック引数規則よりも効率的です。これにより、引数をメモリ (キャッシュ) に格納し、呼び出し先でそれらを再度読み込むという待ち時間と余分な命令が回避されます。より多くのレジスタが使用できるため、これはうまく機能し、レイテンシとアウトオブオーダー実行が重要な最新の高性能 CPU に適しています。(i386 ABI は非常に古いものです)。
この新しいメカニズムでは、まずパラメーターがクラスに分割されます。各パラメーターのクラスによって、呼び出された関数に渡される方法が決まります。
完全な情報については、 System V Application Binary Interface AMD64 Architecture Processor Supplementの「3.2 Function Calling Sequence」を参照してください。
引数が分類されると、次のように渡すためにレジスタが (左から右の順序で) 割り当てられます。
- クラスが MEMORY の場合、引数をスタックに渡します。
- クラスが INTEGER の場合、シーケンス %rdi、%rsi、%rdx、%rcx、%r8、および %r9 の次に使用可能なレジスタが使用されます
整数/ポインター (つまりINTEGER クラス) パラメーターをアセンブリーから任意の libc 関数に渡すために%rdi, %rsi, %rdx, %rcx, %r8 and %r9
使用されるレジスターも同様です。%rdi は最初の INTEGER パラメータに使用されます。2 番目の場合は %rsi、3 番目の場合は %rdx など。その後、指示を与える必要があります。スタック ( ) は、実行時に 16B にアラインされている必要があります。call
%rsp
call
INTEGER パラメータが 6 つ以上ある場合は、7 番目以降の INTEGER パラメータがスタックに渡されます。(x86-32 と同じように発信者がポップします。)
最初の 8 個の浮動小数点引数は、後でスタックの %xmm0-7 に渡されます。呼び出し保存ベクトル レジスタはありません。(FP 引数と整数引数が混在する関数は、合計で 8 個を超えるレジスタ引数を持つことができます。)
可変引数関数 (などprintf
) は常に%al
= FP レジスタ引数の数を必要とします。
いつ構造体をレジスタにパックするか (rdx:rax
戻り時) とメモリにパックするかについてのルールがあります。詳細については ABI を参照し、コンパイラの出力をチェックして、何かを渡す/返す方法についてコードがコンパイラと一致していることを確認してください。
Windows x64 の関数呼び出し規則には、x86-64 System V との重要な違いが複数あることに注意してください。たとえば、(レッド ゾーンではなく) 呼び出し元が予約しなければならないシャドウ スペースや、呼び出しが保持される xmm6-xmm15 などです。そして、どの引数がどのレジスタに入るかについての非常に異なるルール。
おそらく、x86_64 ABI をお探しですか?
それがあなたの求めているものではない場合は、お好みの検索エンジンで「x86_64 abi」を使用して、別の参照を見つけてください。
呼び出し規約は、他のプログラムを呼び出したり呼び出したりするときに、パラメーターがレジスターでどのように渡されるかを定義します。そして、これらの規則の最良の情報源は、これらのハードウェアごとに定義されたABI標準の形式です。コンパイルを容易にするために、同じABIがユーザースペースとカーネルプログラムでも使用されます。Linux / Freebsdは、x86-64用の同じABIと32ビット用の別のセットに従います。ただし、x86-64 ABIforWindowsはLinux/FreeBSDとは異なります。また、通常、ABIはシステムコールと通常の「関数呼び出し」を区別しません。つまり、これはx86_64呼び出し規約の特定の例であり、Linuxユーザースペースとカーネルの両方で同じです:http: //eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64 /(パラメーターのシーケンスa、b、c、d、e、fに注意してください):
パフォーマンスは、これらのABIの理由の1つです(たとえば、メモリスタックに保存する代わりに、レジスタを介してパラメータを渡す)
ARMにはさまざまなABIがあります。
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.subset.swdev.abi/index.html
ARM64規則:
http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
Linux on PowerPCの場合:
http://refspecs.freestandards.org/elf/elfspec_ppc.pdf
http://www.0x04.net/doc/elf/psABI-ppc64.pdf
組み込み用には、PPCEABIがあります。
http://www.freescale.com/files/32bit/doc/app_note/PPCEABI.pdf
このドキュメントは、さまざまな規則すべての概要を示しています。