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

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

新規登録して質問してみよう
ただいま回答率
85.50%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

アーキテクチャ

アーキテクチャとは、情報システム(ハードウェア、OS、アプリケーション、ネットワーク等)の設計方法、設計思想、設計思想に基づいて構築されたシステム構造をアーキテクチャと呼びます

コンパイラ

コンパイラは、プログラミング言語で記述したソースコードを、コンピュータの実行形式であるオブジェクトコードに変換するプログラムです。

Q&A

解決済

4回答

2442閲覧

リンクについてです。

strike1217

総合スコア651

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

アーキテクチャ

アーキテクチャとは、情報システム(ハードウェア、OS、アプリケーション、ネットワーク等)の設計方法、設計思想、設計思想に基づいて構築されたシステム構造をアーキテクチャと呼びます

コンパイラ

コンパイラは、プログラミング言語で記述したソースコードを、コンピュータの実行形式であるオブジェクトコードに変換するプログラムです。

0グッド

0クリップ

投稿2017/06/16 11:48

編集2017/06/16 12:04

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

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

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

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

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

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

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

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

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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

実行ファイルを生成するとき、スタティックリンクでは、上記の3つをすべて順番に処理するはずです。

では、ダイナミックリンクの時は、リンクの段階で何をしているのでしょうか?

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

しかし、よく考えるとリンカの段階でアドレスを付けるんですよね?

アセンブルの段階で各命令や各シンボルにアドレスを付ける作業って含まれるのでしょうか?

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

例を示します。

C

1#include <stdio.h> 2extern int i; 3extern b(); 4static x = 3; 5 6int main(){ 7 b(); /* リンク時解決 */ 8 i = i + x; /* iはリンク時解決、 x はコンパイル時解決 */ 9 printf("i=%d\n", i); /* printf は実行時解決 */ 10}

C

1int i = 10; 2 3void b() { 4i= i+4; 5}

こういう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 12:19

編集2017/06/19 13:03
mit0223

総合スコア3401

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

strike1217

2017/06/19 12:25

>ダイナミックリンク用のセクションやシンボルテーブルを生成する。 なるほど! 内部のシンボルは、オブジェクトファイルを生成した段階ですでに解決済みということですか? それはアセンブラの時に行われるで正しいんでしょうか?
mit0223

2017/06/19 12:38

> それはアセンブラの時に行われるで正しいんでしょうか? はい、そうです。コンパイラと書きましたが、コンパイラの最終段階で動くアセンブラで処理します。
strike1217

2017/06/19 12:42

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

2017/06/19 13:04

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

2017/06/19 13:20

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

0

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

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

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

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

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

投稿2017/06/19 09:41

編集2017/06/19 09:46
strike1217

総合スコア651

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

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/17 11:23

hmmm

総合スコア818

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

strike1217

2017/06/19 09:31

windows独自の技術のようですね。 PEとELF、リンカ1つあげてもかなりの違いがあるんですね。
guest

0

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

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

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

投稿2017/06/16 14:13

編集2017/06/16 14:59
KSwordOfHaste

総合スコア18392

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

strike1217

2017/06/16 14:53

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問