GNU/Linux >> Linux の 問題 >  >> Linux

i386 および x86-64 での UNIX および Linux システム コール (およびユーザー空間関数) の呼び出し規則は何ですか?

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 に関するその他の優れた情報がたくさんあります。)

このセクションのスニペットは次のとおりです:

<ブロック引用> <オール>
  • ユーザーレベルのアプリケーションは、シーケンス %rdi、%rsi、%rdx、%rcx、%r8、および %r9 を渡すための整数レジスタとして使用します。 カーネル インターフェースは %rdi、%rsi、%rdx、%r10、%r8、%r9 を使用します。
  • システムコールは syscall 経由で行われます 命令 .これにより、%rcx と %r11、および %rax の戻り値が破壊されますが、他のレジスタは保持されます。
  • syscall の番号をレジスタ %rax で渡す必要があります。
  • システム コールは 6 つの引数に制限されており、スタックに直接渡される引数はありません。
  • システムコールから戻ると、レジスタ %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 で使用) の最新バージョンでは、%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」を参照してください。その一部は次のとおりです。

    <ブロック引用>

    引数が分類されると、次のように渡すためにレジスタが (左から右の順序で) 割り当てられます。

    <オール>
  • クラスが MEMORY の場合、引数をスタックに渡します。
  • クラスが INTEGER の場合、シーケンス %rdi、%rsi、%rdx、%rcx、%r8、および %r9 の次に使用可能なレジスタが使用されます
  • だから %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


    Linux
    1. LinuxとUnix:違いは何ですか?

    2. 上級ユーザー向けの優れた Linux/Unix の本は何ですか?

    3. exec と execve のようなシステム コールの exec ファミリーの機能の違いは何ですか?

    1. Linux でのアプリケーションの従来のインストール場所は?

    2. Linux でのライブラリ呼び出しとシステム呼び出しの違いは何ですか?

    3. Unix、Linux、BSD、GNU の違いは何ですか?

    1. 最新のLinuxシステムのスワップスペースの適切な量はどれくらいですか?

    2. Linux –システムに搭載されているハードディスクを確認する方法は?

    3. Unixシステムの文字特殊ファイルとブロック特殊ファイルとは何ですか?