質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.13%

リンクについてです。

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,591

score 585

スタティックリンクの手順は、
1、セクションのマージ
2、再配置
3、シンボル解決

という順番に行われると思います。
ダイナミックリンクの場合、実行時にリンクされると思いますがコンパイルされる段階のリンクでは、何が行われているのでしょうか

ちょっと言葉が分かりにくいんですが・・・
えーーとっ・・・つまり
アセンブルが終了した後ですね。
実行ファイルを生成するとき、スタティックリンクでは、上記の3つをすべて順番に処理するはずです。
では、ダイナミックリンクの時は、リンクの段階で何をしているのでしょうか?

私が見た本では、セクションのマージだけを行っている・・・ような事が書いてあったのですが・・・
では、ダイナミックリンカローダが起動した後に、再配置とシンボル解決が行なわれているんですかね?
手順も再配置 → シンボル解決という順番になっているんですかね?

2、シンボル解決は、外部のライブラリとのシンボルを解決するためのものですよね?
(例えば、printf()など)
内部のシンボルは、アセンブルの段階でアドレスと紐付けているのでしょうか?
その場合、シンボルテーブルには、アセンブルの段階で解決出来なかったシンボルの情報のみが乗っていることになりますよね?

しかし、よく考えるとリンカの段階でアドレスを付けるんですよね?
アセンブルの段階で各命令や各シンボルにアドレスを付ける作業って含まれるのでしょうか?

リンカってすごいですね!!魔法のプログラムみたいですね!

どなたか教えてください。

[追記]
スタティックリンクの場合、オブジェクトファイルの中に含まれていたリローケーション情報、シンボルテーブルはリンク終了後に削除されるようですが、ダイナミックリンクの場合でも同じくダイナミックリンカローダーによるリンク終了後これらの情報は削除されるのでしょうか?
実行の直前ですね。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

0

実行ファイルを生成するとき、スタティックリンクでは、上記の3つをすべて順番に処理するはずです。
では、ダイナミックリンクの時は、リンクの段階で何をしているのでしょうか?

処理としてはほぼ同じですが、ダイナミックリンク用のリンクを行う時はダイナミックリンク用のセクションやシンボルテーブルを生成するので、スタティックリンクのときより処理は増えます。ダイナミックリンク用のリンクでも、複数のオブジェクトファイルから1個の実行可能ファイルやシェアードオブジェクトを生成し、スタティックに解決できるものリンク処理を実行しますので、セクションのマージ、再配置、シンボル解決など必要な処理は変わりません。

しかし、よく考えるとリンカの段階でアドレスを付けるんですよね?
アセンブルの段階で各命令や各シンボルにアドレスを付ける作業って含まれるのでしょうか?

内部シンボルに関してはコンパイラが名前解決を行うので、オブジェクトになった段階で名前解決は必要ありません。アドレスがリンク時に決定するようなものであれば、リロケーション情報からリンカがアドレスを埋めます。これがいわゆる再配置処理です。

例を示します。

#include <stdio.h>
extern int i;
extern b();
static x = 3;

int main(){
  b(); /* リンク時解決 */
  i = i + x; /* iはリンク時解決、 x はコンパイル時解決 */
  printf("i=%d\n", i); /* printf は実行時解決 */
}
int i = 10;

void b() {
i= i+4;
}

こういう2つのプログラムをコンパイルしてリンクすると、
リンカは i と b のシンボルを解決し、 printf がダイナミックリンクできるように
シンボルテーブルや PLT など(以前の質問・回答で議論したもの)を生成します。
xはコンパイル時(アセンブラで)解決されるので、リンカの仕事にはなりません。

上記プログラムが a.c, b.c である場合、以下のようにしてコンパイル・リンクできます。

cc -c a.c
cc -c b.c
cc a.o b.o


最後の行がリンカの呼び出しですが、printf はデフォルトでシェアードオブジェクトで
提供されているため、ダイナミックリンクになります。
つまり、a.o と b.o はスタティックにリンクされますが、 printf は実行時にダイナミックに
リンクされます。私がダイナミックリンク用のリンクと呼んだのはこのような場合です。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/06/19 21:42

    ダイナミックリンクの場合、アセンブルが終了後はセクションのマージのみ行って、
    再配置、シンボル解決は実行の際に行われるという理解で正しいんですよね?

    キャンセル

  • 2017/06/19 22:04

    いえ、ダイナミックリンク用のリンク処理でもスタティックに解決できるものはスタティックリンクを行います。例を追加しましたので参考にしてください。

    キャンセル

  • 2017/06/19 22:20

    スタティックにできるものはダイナミックリンクの場合でもやってしまうという事ですね!!
    つまりハイブリッドですね!!
    共有ライブラリについてのみダイナミックなリンクを適用するわけですね!
    共有ライブラリについてはロード時に再配置とシンボル解決を行うということですね!

    キャンセル

0

具体的なリンカーの実装を知っているわけでは全然ありません(具体的な実装を知っている方ってかなりコアな方のような気がしますw;)ので、回答はできないのですが、こうした仕組みをより深く知るという点では以下のような記事が参考になる気がしました。

Linux 動的ライブラリーの徹底調査

PIC(Position independent code)かどうかなどによってもリンカーの処理詳細は違うと思います。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/06/16 23:53

    ありがとうございます。
    見てみます。

    キャンセル

0

windowsの場合だとImport Address Tableとかで調べれば出てくると思います。

#include <Windows.h>
int main()
{
    ::SendMessage(NULL, 0, 0, 0);
    return 0;
}

例えば上記のようにSendMessageを実行するコードは

call     DWORD PTR __imp__SendMessageW@16


のようにImport Address Tableに保存されているアドレスをcallするコードが生成されます。
このアドレスの値はWindowsのローダーによって実行時に実際のSendMessageWのアドレスに書き換えられます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/06/19 18:31

    windows独自の技術のようですね。

    PEとELF、リンカ1つあげてもかなりの違いがあるんですね。

    キャンセル

0

わかった部分だけを書きます。

再配置 → シンボル解決でスタティックと同じようですね。
セクションのマージの方は確認出来なかったのですが、readelf -S a.out, readelf -l a.out
とやるとオブジェクトファイルと実行ファイルのセクションに差が出ていました。

おそらく、アセンブリが終了次第セクションのマージからセグメントの生成が行われているものと思われます。

nmコマンドによるシンボルテーブルの確認をしました。
シンボルテーブルはスタティックリンク、ダイナミックリンク、オブジェクトファイルそれぞれ残っていました。
ダイナミックリンクされた実行ファイルやオブジェクトファイルにはシンボルテーブルが残っているのは納得いくのですが、スタティックな実行ファイルになぜシンボルテーブルが残っているんですかね?

「追記」
よーく見てみると、スタティックリンクによるシンボルテーブルはどれも外部のライブラリのシンボルでした。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.13%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る