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

Linux x86-64 関数呼び出しで保持されるレジスタ

レジスターの完全な表とドキュメントからの使用方法は次のとおりです [PDF リンク]:

r12r13r14r15rbxrsprbp 呼び出し先保存レジスタです - 「関数呼び出し間で保持」列に「はい」があります。


実験的アプローチ:GCC コードの逆アセンブル

主に楽しみのためですが、ABI を正しく理解していることを簡単に確認するためでもあります。

インライン アセンブリを使用してすべてのレジスタを上書きして、GCC にそれらの保存と復元を強制してみましょう:

main.c

#include <inttypes.h>

uint64_t inc(uint64_t i) {
    __asm__ __volatile__(
        ""
        : "+m" (i)
        :
        : "rax",
          "rbx",
          "rcx",
          "rdx",
          "rsi",
          "rdi",
          "rbp",
          "rsp",
          "r8",
          "r9",
          "r10",
          "r11",
          "r12",
          "r13",
          "r14",
          "r15",
          "ymm0",
          "ymm1",
          "ymm2",
          "ymm3",
          "ymm4",
          "ymm5",
          "ymm6",
          "ymm7",
          "ymm8",
          "ymm9",
          "ymm10",
          "ymm11",
          "ymm12",
          "ymm13",
          "ymm14",
          "ymm15"
    );
    return i + 1;
}

int main(int argc, char **argv) {
    (void)argv;
    return inc(argc);
}

GitHub アップストリーム。

コンパイルと逆アセンブル:

 gcc -std=gnu99 -O3 -ggdb3 -Wall -Wextra -pedantic -o main.out main.c
 objdump -d main.out

分解には以下が含まれます:

00000000000011a0 <inc>:
    11a0:       55                      push   %rbp
    11a1:       48 89 e5                mov    %rsp,%rbp
    11a4:       41 57                   push   %r15
    11a6:       41 56                   push   %r14
    11a8:       41 55                   push   %r13
    11aa:       41 54                   push   %r12
    11ac:       53                      push   %rbx
    11ad:       48 83 ec 08             sub    $0x8,%rsp
    11b1:       48 89 7d d0             mov    %rdi,-0x30(%rbp)
    11b5:       48 8b 45 d0             mov    -0x30(%rbp),%rax
    11b9:       48 8d 65 d8             lea    -0x28(%rbp),%rsp
    11bd:       5b                      pop    %rbx
    11be:       41 5c                   pop    %r12
    11c0:       48 83 c0 01             add    $0x1,%rax
    11c4:       41 5d                   pop    %r13
    11c6:       41 5e                   pop    %r14
    11c8:       41 5f                   pop    %r15
    11ca:       5d                      pop    %rbp
    11cb:       c3                      retq   
    11cc:       0f 1f 40 00             nopl   0x0(%rax)

そのため、以下がプッシュおよびポップされていることが明確にわかります:

rbx
r12
r13
r14
r15
rbp

仕様から唯一欠けているのは rsp です 、しかしもちろんスタックが復元されることを期待しています。アセンブリを注意深く読むと、この場合にアセンブリが維持されていることが確認されます:

  • sub $0x8, %rsp :%rdi を保存するためにスタックに 8 バイトを割り当てます %rdi, -0x30(%rbp) で 、インライン アセンブリ +m に対して行われます 制約
  • lea -0x28(%rbp), %rsp %rsp を復元します sub の前に戻る 、つまり mov %rsp, %rbp の後に 5 ポップ
  • 6 つのプッシュと 6 つの対応するポップがあります
  • 他の命令は %rsp に触れていません

Ubuntu 18.10、GCC 8.2.0 でテスト済み。


Linux
  1. Linuxのシェルの種類は何ですか?

  2. UNIX / Linux :シェルとは?異なるシェルとは何ですか?

  3. Linux の DNS ネームサーバー タイプとは

  1. Linux のメッセージ キューの短所は何ですか?

  2. Linux カーネル モジュール内からユーザー空間関数を呼び出す

  3. Linux のハイ メモリとロー メモリとは何ですか?

  1. Linux – Gnu / linuxでファイルパーミッションなどを設定するさまざまな方法は何ですか?

  2. Linux のダーティ ページとは

  3. Linux の Bash 終了コードとは