雑記
リンクの話
最終更新:
匿名ユーザー
-
view
プログラムの入門書などを見ても、コンパイラについては結構皆さん意識してるんだけど、リンカについてはあんまり記述がない気がします。
実際、ソースファイルを実行ファイルにするには、「コンパイル」+「リンク」というあわせ技は必須なわけですが、どうにもリンカは影が薄い気がしてしまうのです(笑)。
単体のソースファイルのみでプログラムを書いているときはあまり気になりませんが、複数のソースファイルに分割して書いているならば、多少は意識があると思います。
リンカの役割は、(主にソースファイルごとに作られる)オブジェクトファイルの結合です。
・・・といってしまうと、ソースファイルから機械語のオブジェクトファイルを作るコンパイラの方が主でリンカは従であるようなイメージを受けてしまうかもしれません。
・・・といってしまうと、ソースファイルから機械語のオブジェクトファイルを作るコンパイラの方が主でリンカは従であるようなイメージを受けてしまうかもしれません。
しかし、そうではないのです。
ソースファイル内にない関数、たとえばprintfなどのような標準ライブラリ関数などは、ユーザのオブジェクトファイル内には機械語コードとしては存在しません。これらはC処理系の用意したライブラリとリンクすることで初めて使えるわけです。
また、グローバル変数やユーザ定義の関数などもソースファイルが違えばそれは個々のオブジェクトファイル内には存在しないわけです。
それらは、オブジェクトファイルをリンクして実効ファイルにした段階で、初めて同一の舞台にそろうことができるわけです。
このようなことを実現するために、各オブジェクトファイル内では識別子などの情報(アドレス)が相対参照になっていることが多いです。
そうすることで、オブジェクトのリンク順が変わったり、リンクするオブジェクトに増減があってもリンケージ(リンク作業)の時に調節することができます。
これも、リンカの役割のひとつです。
これも、リンカの役割のひとつです。
また、一般にプログラムが実行されるときにはmain()から入るわけですが、このプログラムが実行されるまでにはいろいろと準備があるわけです。
まずプログラムをメモリに展開・グローバル変数領域の確保、コマンドラインオプションをargc、argvとして準備、main()を呼び出す、という前準備があって初めてmain()の処理が呼び出されます。
こうした前準備を行うのは一部はOSの役目ですが、ほとんどは「ローダオブジェクト」と呼ばれるモジュールによって行われます。
この「ローダオブジェクト」が前準備をして、かつ我々が普段C言語でエントリポイントだと思っているmain()をコールしてくれることによってプログラムを実行させることができるわけです。
この「ローダオブジェクト」もまた、リンケージの時に実行ファイルにリンクされます。
また、オブジェクトファイルは(処理系にもよりますが)機械語の「実行ファイル一歩手前」ですので、当然他の言語でも作ることができます。
たとえば、基本的な処理はC言語で書いて、クリティカルな処理や速度が必要な処理のみアセンブラで書く、などということができるわけです(無論、C言語でインラインアセンブラ使ってもいいわけですけど(笑))。
このときアセンブラソース側ではC言語の関数呼び出し規約に準じたサブルーチンとして記述してやれば、あとはオブジェクトファイルをリンクすることで実行ファイルを得ることができます。
実際、C処理系についている標準ライブラリなどは実装はアセンブラで行われている処理系も多いです。
実際、C処理系についている標準ライブラリなどは実装はアセンブラで行われている処理系も多いです。
というわけで、リンカは「縁の下の力持ち」と言ったところでしょうか。
コンパイラほど派手な(?)仕事ではありませんが、実にイイ仕事をするリンカを応援してあげましょう(笑)
コンパイラほど派手な(?)仕事ではありませんが、実にイイ仕事をするリンカを応援してあげましょう(笑)