1

System V AMD64 ABI 呼び出し規則は、次のように義務付けられています。

を登録し%rbp、呼び出し元の関数%rbxに「属して」おり、呼び出された関数はそれらの値を保持する必要があります%r12%r15つまり、呼び出された関数は、呼び出し元のためにこれらのレジスタの値を保持する必要があります。残りのレジスタは、呼び出された関数に「属します」。呼び出し元の関数が関数呼び出し全体でこのようなレジスタ値を保持する場合は、その値をローカル スタック フレームに保存する必要があります。

たとえば、次のコードがあるとします。

void f1(const int i, const double j, const char * k)
{
    printf("i = %d\n", i);
    printf("j = %g\n", j);
    printf("k = %s\n", k);
}

アセンブリ表現は次のとおりです。

f1():
  4004f4:   55                      push   %rbp
  4004f5:   48 89 e5                mov    %rsp,%rbp
  4004f8:   48 83 ec 20             sub    $0x20,%rsp
  4004fc:   89 7d fc                mov    %edi,-0x4(%rbp)
  4004ff:   f2 0f 11 45 f0          movsd  %xmm0,-0x10(%rbp)
  400504:   48 89 75 e8             mov    %rsi,-0x18(%rbp)
  400508:   b8 70 06 40 00          mov    $0x400670,%eax
  40050d:   8b 55 fc                mov    -0x4(%rbp),%edx
  400510:   89 d6                   mov    %edx,%esi
  400512:   48 89 c7                mov    %rax,%rdi
  400515:   b8 00 00 00 00          mov    $0x0,%eax
  40051a:   e8 d1 fe ff ff          callq  4003f0 <printf@plt>
  40051f:   b8 78 06 40 00          mov    $0x400678,%eax
  400524:   f2 0f 10 45 f0          movsd  -0x10(%rbp),%xmm0
  400529:   48 89 c7                mov    %rax,%rdi
  40052c:   b8 01 00 00 00          mov    $0x1,%eax
  400531:   e8 ba fe ff ff          callq  4003f0 <printf@plt>
  400536:   b8 80 06 40 00          mov    $0x400680,%eax
  40053b:   48 8b 55 e8             mov    -0x18(%rbp),%rdx
  40053f:   48 89 d6                mov    %rdx,%rsi
  400542:   48 89 c7                mov    %rax,%rdi
  400545:   b8 00 00 00 00          mov    $0x0,%eax
  40054a:   e8 a1 fe ff ff          callq  4003f0 <printf@plt>
  40054f:   c9                      leaveq 
  400550:   c3                      retq  

この例では、パラメータは%edi%xmm0およびに渡されています%rsi。呼び出し規則では、これらのレジスタは呼び出された関数に「属する」と規定されており、これはf1値を保持する義務がないことを意味します。実際、%edi、 、%xmm0および%rsiはすべて、次の行で破棄されます。

400510: 89 d6                   mov    %edx,%esi
400512: 48 89 c7                mov    %rax,%rdi
..
400524: f2 0f 10 45 f0          movsd  -0x10(%rbp),%xmm0

すべての引数レジスタを保持したい。ドキュメントには、次のように試したローカルスタックに値を保存できると記載されています。

void f1(const int i, const double j, const char * k)
{
    uint32_t edi;
    __asm ("movl %%edi, %0;" : "=r" ( edi ));

    printf("i = %d\n", i);
    printf("j = %g\n", j);
    printf("k = %s\n", k);

    __asm ("movl %0, %%edi;" : "=d"( edi ));
}

これにより、次が生成されます。

f1():
  4004f4:   55                      push   %rbp
  4004f5:   48 89 e5                mov    %rsp,%rbp
  4004f8:   53                      push   %rbx
  4004f9:   48 83 ec 38             sub    $0x38,%rsp
  4004fd:   89 7d dc                mov    %edi,-0x24(%rbp)
  400500:   f2 0f 11 45 d0          movsd  %xmm0,-0x30(%rbp)
  400505:   48 89 75 c8             mov    %rsi,-0x38(%rbp)
  400509:   89 fb                   mov    %edi,%ebx
  40050b:   89 5d ec                mov    %ebx,-0x14(%rbp)
  40050e:   b8 80 06 40 00          mov    $0x400680,%eax
  400513:   8b 55 dc                mov    -0x24(%rbp),%edx
  400516:   89 d6                   mov    %edx,%esi
  400518:   48 89 c7                mov    %rax,%rdi
  40051b:   b8 00 00 00 00          mov    $0x0,%eax
  400520:   e8 cb fe ff ff          callq  4003f0 <printf@plt>
  400525:   b8 88 06 40 00          mov    $0x400688,%eax
  40052a:   f2 0f 10 45 d0          movsd  -0x30(%rbp),%xmm0
  40052f:   48 89 c7                mov    %rax,%rdi
  400532:   b8 01 00 00 00          mov    $0x1,%eax
  400537:   e8 b4 fe ff ff          callq  4003f0 <printf@plt>
  40053c:   b8 90 06 40 00          mov    $0x400690,%eax
  400541:   48 8b 55 c8             mov    -0x38(%rbp),%rdx
  400545:   48 89 d6                mov    %rdx,%rsi
  400548:   48 89 c7                mov    %rax,%rdi
  40054b:   b8 00 00 00 00          mov    $0x0,%eax
  400550:   e8 9b fe ff ff          callq  4003f0 <printf@plt>
  400555:   89 d7                   mov    %edx,%edi
  400557:   89 d3                   mov    %edx,%ebx
  400559:   89 5d ec                mov    %ebx,-0x14(%rbp)
  40055c:   48 83 c4 38             add    $0x38,%rsp
  400560:   5b                      pop    %rbx
  400561:   5d                      pop    %rbp
  400562:   c3                      retq   

これは の値を復元していないようです%edi。すべての引数/パラメータ レジスタを保存する正しい方法は何ですか?

4

1 に答える 1

5

このように C と asm を混在させることはできません。特に、インライン アセンブリで分離されたプッシュまたはポップ命令を実行すると、事態は恐ろしく壊れます。特定のインライン アセンブリ ブロックは、スタック ポインターのネット オフセットが 0 でなければなりません。

実際、ABI ドキュメントはインライン asm の使用とはあまり関係がありません。そのためには、入力と出力に使用するレジスターとクロバーリストの内容を文書化する GCC インライン asm 契約に従う必要があります。.sABI は、関数全体をアセンブラー (ファイルではなくファイル)で記述している場合に関連し.cます。

于 2012-05-26T00:07:14.330 に答える