コードから実行可能プロセスまでの C++ (プリコンパイル、コンパイル、アセンブリ、リンク) (Linux を参考として使用)

Axiuの学習ノートを参照

テストコード

#include<iostream>
using namespace std;
#define PI 3.14
int main(){
    
    
        //测试代码
        cout<<PI<<endl;
        cout<<"hello world"<<endl;
        return 0;
}

前処理

処理内容

  • 定義を削除し、すべてのマクロ定義を展開します
  • 「#if」、「#endif」、「#ifdef」、「#elif」、「#else」など、すべての条件付きプリコンパイル済みディレクティブを処理します。
  • 「#include」プリコンパイル済みディレクティブは、ファイルの内容をその場所に置き換えるために処理されます。このプロセスは再帰的であり、ファイルには他のファイルが含まれています。
  • すべてのコメント「//」と「/**/」を削除します。
  • すべての #pragma コンパイラ ディレクティブを保持します。コンパイラは、次のようなそれらを使用する必要があります。 #pragma Once は、ファイルが繰り返し参照されるのを防ぐためです。
  • 行番号とファイル ID を追加すると、コンパイラはコンパイル時にデバッグ用の行番号情報を生成したり、コンパイル中にコンパイル エラーや警告が生成されたときに行番号を表示したりできます。

g++ main.cpp -E -o main.i

  • -E: 前処理を示します
  • -o はターゲットファイルを示します
......
# 2 "main.cpp" 2

# 2 "main.cpp"
using namespace std;

int main(){
    
    

 cout<<3.14<<endl;
 cout<<"hello world"<<endl;
 return 0;
}

コンパイル

コンパイル

プリコンパイル後に生成された xxx.i または xxx.ii ファイルに対して一連の字句解析、構文解析、意味解析、および最適化を実行して、対応するアセンブリ コード ファイルを生成します。

  • 字句解析: 「有限状態マシン」に似たアルゴリズムを使用して、ソース コード プログラムがスキャナーに入力され、その中の文字シーケンスが一連のトークンに分割されます。
  • 構文分析: 構文アナライザーは、スキャナーによって生成されたトークンに対して構文分析を実行して、構文ツリーを生成します。パーサーによって出力される構文ツリーは、式をノードとして含むツリーです。
  • 意味分析: 文法アナライザーは式の文法レベルの分析のみを完了し、意味アナライザーは式が意味があるかどうかを判断します。動的セマンティクスは、実行時にのみ決定できるセマンティクスです。
  • 最適化: ソースコードレベルでの最適化プロセス。
  • オブジェクト コードの生成: 中間コードはコード ジェネレーターによってオブジェクト マシン コードに変換され、一連のコード シーケンス (アセンブリ言語表現) が生成されます。
  • ターゲット コードの最適化: ターゲット コード オプティマイザーは、適切なアドレッシング モードを見つけたり、ディスプレースメントを使用して乗算を置き換えたり、冗長な命令を削除したりするなど、上記のターゲット マシン コードを最適化します。

g++ main.i -S -o main.s

  • -S はコンパイルを意味します
        .file   "main.cpp"
        .text
        .section        .rodata
        .type   _ZStL19piecewise_construct, @object
        .size   _ZStL19piecewise_construct, 1
_ZStL19piecewise_construct:
        .zero   1
        .local  _ZStL8__ioinit
        .comm   _ZStL8__ioinit,1,1
.LC1:
        .string "hello world"
        .text
        .globl  main
        .type   main, @function
main:
.LFB1493:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $16, %rsp
        movq    .LC0(%rip), %rax
        movq    %rax, -8(%rbp)
        movsd   -8(%rbp), %xmm0
        leaq    _ZSt4cout(%rip), %rdi
        call    _ZNSolsEd@PLT
        movq    %rax, %rdx
        movq    _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GOTPCREL(%rip), %rax
        movq    %rax, %rsi
        movq    %rdx, %rdi
        call    _ZNSolsEPFRSoS_E@PLT
        leaq    .LC1(%rip), %rsi
        leaq    _ZSt4cout(%rip), %rdi
        call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@PLT
        movq    %rax, %rdx
        movq    _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GOTPCREL(%rip), %rax
        movq    %rax, %rsi
        movq    %rdx, %rdi
        call    _ZNSolsEPFRSoS_E@PLT
        movl    $0, %eax
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE1493:
        .size   main, .-main
        .type   _Z41__static_initialization_and_destruction_0ii, @function
_Z41__static_initialization_and_destruction_0ii:
.LFB1983:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $16, %rsp
        movl    %edi, -4(%rbp)
        movl    %esi, -8(%rbp)
        cmpl    $1, -4(%rbp)
        jne     .L5
        cmpl    $65535, -8(%rbp)
        jne     .L5
        leaq    _ZStL8__ioinit(%rip), %rdi
        call    _ZNSt8ios_base4InitC1Ev@PLT
        leaq    __dso_handle(%rip), %rdx
        leaq    _ZStL8__ioinit(%rip), %rsi
        movq    _ZNSt8ios_base4InitD1Ev@GOTPCREL(%rip), %rax
        movq    %rax, %rdi
        call    __cxa_atexit@PLT
.L5:
        nop
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE1983:
        .size   _Z41__static_initialization_and_destruction_0ii, .-_Z41__static_initialization_and_destruction_0ii
        .type   _GLOBAL__sub_I_main, @function
_GLOBAL__sub_I_main:
.LFB1984:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movl    $65535, %esi
        movl    $1, %edi
        call    _Z41__static_initialization_and_destruction_0ii
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE1984:
        .size   _GLOBAL__sub_I_main, .-_GLOBAL__sub_I_main
        .section        .init_array,"aw"
        .align 8
        .quad   _GLOBAL__sub_I_main
        .section        .rodata
        .align 8
.LC0:
        .long   1374389535
        .long   1074339512
        .hidden __dso_handle
        .ident  "GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0"
        .section        .note.GNU-stack,"",@progbits

編集

アセンブリ コードをマシン実行可能命令 (マシン コード ファイル) に変換します。アセンブラのアセンブル処理はコンパイラに比べて単純であり、複雑な構文、セマンティクス、命令の最適化は必要なく、アセンブリ命令と機械語命令の対比表に従って一つずつ翻訳するだけです。アセンブリプロセスには、アセンブラが完了しています。コンパイル後、オブジェクトファイル(実行ファイルとほぼ同じ形式)xxx.o(Linuxの場合)、xxx.obj(Windowsの場合)が生成されます。

g++ main.s -s -o main.o

リンク

さまざまなソース ファイルによって生成されたオブジェクト ファイルをリンクして、実行可能プログラムを形成します。

静的リンク

実行可能ファイルをコンパイルおよびリンクする場合、リンカーはこれらの関数とデータをライブラリからコピーし、参照されるプログラムの他のモジュールと結合して、最終的な実行可能ファイルを作成します。リンカは主に次の 2 つのタスクを実行します。

  • シンボル解決: 各シンボルは関数、グローバル変数、または静的変数に対応します。
  • 再配置: リンカは、各シンボル定義をメモリ位置に関連付けることによって機能し、その後、それらのシンボルへのすべての参照を変更して、シンボルがそのメモリ位置を指すようにします。
    ここに画像の説明を挿入
欠点がある

スペースの無駄です。各実行可能プログラムにはすべてのオブジェクト ファイルのコピーが必要です。そのため、複数のプログラムが同じオブジェクト ファイルに依存している場合、同じオブジェクト ファイルが表示されます。

アドバンテージ

プログラムの実行に必要なものがすべて実行可能ファイルにすでに存在しているため、高速に実行されます。

ダイナミックリンク

プログラムをモジュールごとに比較的独立した部分に分割し、実行時にそれらをリンクします。Linux は .so 形式、Windows は dll ファイルです。== メモリ内では、共有ライブラリの .text セクション (コンパイルされたプログラムのマシン コード) の 1 つのコピーを、実行中のさまざまなプロセスで共有できます。
ここに画像の説明を挿入

欠点がある
  • パフォーマンスの低下。プログラムが実行されるたびにリンクする必要があるため、一定のパフォーマンスの低下が発生します。
  • 対応するランタイム ライブラリがコンピュータにインストールされていない場合、動的にコンパイルされた実行可能ファイルは実行できません。
アドバンテージ
  • 共有ライブラリ: 複数のプログラムが実行時に同じコピーを共有します。
  • 更新が簡単: 更新時に元のターゲット ファイルを置き換えるだけで、次回プログラムを実行するときに、新しいバージョンのターゲット ファイルが自動的にメモリにロードされてリンクされます。

おすすめ

転載: blog.csdn.net/qaaaaaaz/article/details/130786287