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 を参照してください。 int 0x80
を使用した i386 Linux の Hello World の別の例 :Hello, world in assembly language with Linux system calls?
32 ビット システム コールを行うより高速な方法があります:sysenter
を使用します。 .カーネルはメモリのページをすべてのプロセス (vDSO) にマップし、sysenter
のユーザー空間側を使用します。 dance はカーネルと協力して戻りアドレスを見つける必要があります。マッピングを登録する引数は int $0x80
の場合と同じです . sysenter
を使用する代わりに、通常は vDSO を呼び出す必要があります。 直接。 (Linux システム コール決定版ガイドを参照) vDSO へのリンクと呼び出しに関する情報、および sysenter
の詳細については、 、およびシステム コールに関連するその他すべて)
x86-32 [Free|Open|Net|DragonFly]BSD UNIX システム コールの規則:
パラメータはスタックで渡されます。パラメーター (最初にプッシュされた最後のパラメーター) をスタックにプッシュします。次に、追加の 32 ビットのダミー データ (実際にはダミー データではありません。詳細については、次のリンクを参照してください) をプッシュし、システム コール命令 int $0x80
を与えます。
http://www.int80h.org/bsdasm/#default-calling-convention
x86-64 Linux システム コールの規則:
(注:x86-64 Mac OS X は Linux と似ていますが異なります。TODO:*BSD の動作を確認してください)
セクションを参照してください:"A.2 AMD64 Linux System V Application Binary Interface AMD64 Architecture Processor Supplement の Kernel Conventions"最新の ABI リンクと、x86 asm に関するその他の優れた情報がたくさんあります。)
このセクションのスニペットは次のとおりです:
<ブロック引用> <オール>syscall
経由で行われます 命令 .これにより、%rcx と %r11、および %rax の戻り値が破壊されますが、他のレジスタは保持されます。-errno
です。 .これは 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 で使用) の最新バージョンでは、%esp
の 16 バイト アラインメントが必要です。 call
の前 、x86-64 System V ABI が常に要求してきたように。呼び出し先は、それを想定して、アライメントされていない場合にフォールトする SSE 16 バイトのロード/ストアを使用することができます。しかし、歴史的に、Linux は 4 バイトのスタック アラインメントしか必要としなかったため、8 バイトの double
でも自然にアラインされたスペースを予約するには余分な作業が必要でした。 または何か。
他の最新の 32 ビット システムの中には、4 バイトを超えるスタック アラインメントをまだ必要としないものもあります。
x86-64 System V ユーザー空間関数呼び出し規約:
x86-64 System V は引数をレジスターで渡します。これは、i386 System V のスタック引数規則よりも効率的です。これにより、引数をメモリ (キャッシュ) に格納し、呼び出し先でそれらを再度読み込むという待ち時間と余分な命令が回避されます。より多くのレジスタが使用できるため、これはうまく機能し、レイテンシとアウトオブオーダー実行が重要な最新の高性能 CPU に適しています。 (i386 ABI は非常に古いものです)。
この新しい メカニズム:まず、パラメーターがクラスに分割されます。各パラメーターのクラスは、呼び出された関数に渡される方法を決定します。
完全な情報については、System V Application Binary Interface AMD64 Architecture Processor Supplement の「3.2 Function Calling Sequence」を参照してください。その一部は次のとおりです。
<ブロック引用>引数が分類されると、次のように渡すためにレジスタが (左から右の順序で) 割り当てられます。
<オール>
だから %rdi, %rsi, %rdx, %rcx, %r8 and %r9
順番に登録されています アセンブリから任意の libc 関数に整数/ポインター (つまり、INTEGER クラス) パラメーターを渡すために使用されます。 %rdi は最初の INTEGER パラメータに使用されます。 2 番目の場合は %rsi、3 番目の場合は %rdx など。次に call
指示を与えるべきです。スタック (%rsp
) call
の場合は 16B に揃える必要があります 実行します。
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 をお探しですか?
- www.x86-64.org/documentation/abi.pdf (2018 年 11 月 24 日の 404)
- www.x86-64.org/documentation/abi.pdf (2018 年 11 月 24 日の Wayback Machine 経由)
- x86-64 System V ABI はどこに文書化されていますか? - https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI は (ABI メンテナーの 1 人である HJ Lu によって) 最新の状態に保たれ、公式の現行バージョンの PDF へのリンクが含まれています。リ>
それがあなたの求めているものではない場合は、お好みの検索エンジンで「x86_64 abi」を使用して、別の参照を見つけてください。
呼び出し規則は、他のプログラムを呼び出すとき、または他のプログラムから呼び出されるときに、パラメーターがレジスターに渡される方法を定義します。そして、これらの規則の最良の情報源は、これらのハードウェアごとに定義された ABI 標準の形式です。コンパイルを容易にするために、同じ ABI がユーザー空間とカーネル プログラムでも使用されます。 Linux/Freebsd は、x86-64 用に同じ ABI に従い、32 ビット用に別のセットに従います。ただし、Windows 用の x86-64 ABI は 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
https://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/iPhoneOSABIReference.pdf
ARM64 規則:
http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
PowerPC 上の Linux の場合:
http://refspecs.freestandards.org/elf/elfspec_ppc.pdf
http://www.0x04.net/doc/elf/psABI-ppc64.pdf
埋め込み用には、PPC EABI があります:
http://www.freescale.com/files/32bit/doc/app_note/PPCEABI.pdf
このドキュメントは、さまざまな規則すべての概要です:
http://www.agner.org/optimize/calling_conventions.pdf