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

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

新規登録して質問してみよう
ただいま回答率
85.50%
アセンブリ言語

アセンブリ言語とは、機械語を人間にわかりやすい形で記述した低水準言語です。

C

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

コンパイラ

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

Q&A

解決済

1回答

2252閲覧

ダイナミックリンク、遅延BIND、GOTを追う

strike1217

総合スコア651

アセンブリ言語

アセンブリ言語とは、機械語を人間にわかりやすい形で記述した低水準言語です。

C

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

コンパイラ

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

0グッド

0クリップ

投稿2017/07/11 13:58

編集2017/07/11 14:14

簡単なコードで考察します。

#include<stdio.h> int main(){ int c = 1000; printf("Technology%d\n", c); return 0; }

アセンブリコードを一応載せておきます。

0000000000000550 <.plt>: 550: ff 35 b2 0a 20 00 pushq 0x200ab2(%rip) # 201008 <_GLOBAL_OFFSET_TABLE_+0x8> 556: ff 25 b4 0a 20 00 jmpq *0x200ab4(%rip) # 201010 <_GLOBAL_OFFSET_TABLE_+0x10> 55c: 0f 1f 40 00 nopl 0x0(%rax) 0000000000000560 <printf@plt>: 560: ff 25 b2 0a 20 00 jmpq *0x200ab2(%rip) # 201018 <printf@GLIBC_2.2.5> 566: 68 00 00 00 00 pushq $0x0 56b: e9 e0 ff ff ff jmpq 550 <.plt> 00000000000006b0 <main>: 6b0: 55 push %rbp 6b1: 48 89 e5 mov %rsp,%rbp 6b4: 48 83 ec 10 sub $0x10,%rsp 6b8: c7 45 fc e8 03 00 00 movl $0x3e8,-0x4(%rbp) 6bf: 8b 45 fc mov -0x4(%rbp),%eax 6c2: 89 c6 mov %eax,%esi 6c4: 48 8d 3d 99 00 00 00 lea 0x99(%rip),%rdi # 764 <_IO_stdin_used+0x4> 6cb: b8 00 00 00 00 mov $0x0,%eax 6d0: e8 8b fe ff ff callq 560 <printf@plt> 6d5: b8 00 00 00 00 mov $0x0,%eax 6da: c9 leaveq 6db: c3 retq 6dc: 0f 1f 40 00 nopl 0x0(%rax)

上記のようなコードの場合、
GDBで実行して、stepiで進みます。
callq 560 printf@plt → 560 printf@plt: → 550 <.plt>:

の順にPLTを飛んで行きます。

その次に、GOTに入るかと思ったのですが・・・
_dl_runtime_resolve_avx_slow()
_dl_runtime_resolve_sse_vex()
_dl_fixup()
_dl_lookup_symbol_x()
do_lookup_x()
_dl_name_match_p()

という順に入って行きます。
(名前からしてintelのSSE命令やAVX命令、ベクトル演算用の関数のようです。)
全く関係のない場所に入って行きます。
(どうやら、私の予測が外れました。)

2回目移行の場合
printf@plt: の場所の一番最初 jmpq *0x200ab2(%rip) の命令からダイナミックリンカの環境で実行するとここからGOTに入る事ができるようです。
(遅延BIND)

GDBでGOT内に入れないのが不思議ですが・・・、入り方を教えてください。
_dl_name_match_p()の後に、なぜかstrcmp()に入ってしまいます。
完全に迷子です。

dynamic linker(具体的には__dl_runtime_resolve関数)に、「アドレス*0x200ab2(%rip) の値」を本物のprintf関数のアドレスに書き換えてもらった上で、本物のprintf関数にジャンプする処理になっています

「ああ~~。なるほど!」


その後の2回め以降のアクセスは、
callq 560 printf@plt → 560 printf@plt:までで、GOTにアクセス出来るということですね。

__dl_runtime_resolve()のベクトル命令に関する関数群に入っているんですが、本当にこれで正しいのでしょうか?
GDBは、実際の実行時と違ってGOTを追えない??とか?

わかる方お願いします。

ちなみに、stepi(si)ではなく、_dl_runtime_resolve_avx_slow()に入った時点で、stepを実行するとprintf()に入れます。
どういうことでしょうか?

「追記」

readelf -x 23 test2 セクション '.got' の 十六進数ダンプ: 0x00200fd0 00000000 00000000 00000000 00000000 ................ 0x00200fe0 00000000 00000000 00000000 00000000 ................ 0x00200ff0 00000000 00000000 00000000 00000000 ................

GOTセクションのダンプは何も入っていませんでした。

GOTは、実行時に初期化される・・・?ってことですかね

GDBで追った時に、jmpq *0x200ab2(%rip)のアドレスにbreakpointを張ってそこから入ろうとしましたが、
segmentation faultです。
1回目でprintf()に到達できなければ、segmentation faultになってしまいます。
(_dl_runtime_resolve()が未処理の状態ではsegmentation fault)

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

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

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

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

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

guest

回答1

0

ベストアンサー

GDBでGOT内に入れないのが不思議ですが・・・、入り方を教えてください。

GOTはアドレスが書き込まれているテーブルなので、GOTに入る(=プログラムカウンタがGOTのアドレスになる)ことはありません。 jmpq *0x200ab2(%rip) のように参照されるだけです。0x200ab2(%rip)はGOTのアドレスですが、*がついているので、そのアドレスには jump せずにその値のアドレスに jump します。
遅延BINDでは(すでに学習されているようですが)、1回目はダイナミックリンカに jump して、GOTの値を設定した後、GOTが指す先に jump することで実装されます。

__dl_runtime_resolve()のベクトル命令に関する関数群に入っているんですが、本当にこれで正しいのでしょうか?

デバッグ情報がついていないコードを gdb でデバッグすると、見える関数名は必ずしも正しくありません。 gdb はプログラムカウンタのアドレスから遡って最も近いシンボルを見つけてそれを関数名として見せています。本当の関数名が知りたければ、デバッグ情報付きのダイナミックリンカを用意して、 gdb にデバッグ情報を読み込ませてみる必要があります(結構、難易度は高いと思います)。

したがって、

という順に入って行きます。
(名前からしてintelのSSE命令やAVX命令、ベクトル演算用の関数のようです。)
全く関係のない場所に入って行きます。

というのは全く信用できない、というよりもおそらく間違っています。

投稿2017/07/12 00:58

mit0223

総合スコア3401

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

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

strike1217

2017/07/12 01:02

「関数名があてにならない」ということですか! むむ~~~ 「0x200ab2(%rip)はGOTのアドレスですが、*がついているので、そのアドレスには jump せずにその値のアドレスに jump します。」 「その値のアドレス」とは、どういうことでしょう??
mit0223

2017/07/12 01:05

> その値のアドレス」とは、どういうことでしょう? 0x200ab2(%rip) が指すメモリの中に書き込まれているアドレスという意味です。
strike1217

2017/07/12 01:37 編集

ああ~! なるほど! GDBを使って、stepiで進めていく時に、 1回目のGOTに対するアクセスの時に、jmpq *0x200ab2(%rip)の行は無視されます。 (ジャンプしないです。) なぜですか? アセンブリ言語は上から順番に処理していくはずです。 どうやって無視するように設定されているんでしょう? 直前の行でcmp命令みたいなものがあるならわかるんですが・・・・ _dl_runtime_resolve()によって*0x200ab2(%rip)の設定が行われていないので、Jmpされたら困ります、なので1回目は無視されるという理由は分かるんですが、条件分岐も使用しないでどうやって実現しているんですかね・・・
strike1217

2017/07/12 02:43 編集

まさか・・・ _dl_runtime_resolve()って共有ライブラリの中のすべての関数を走査するんですか? 質問中にも書いたのですが、一番最初にstrcmp()に到着しました。 共有ライブラリの中のすべての関数をGOTに登録するわけではないですよね? 例えば、printf()だったら、1回目はprintf()のアドレスを調べて登録 2回目以降は、_dl_runtime_resolve()は呼び出さい。 printf()の後に、strcpy()を初めて呼び出したら、これも1回目は_dl_runtime_resolve()は呼び出すんですか? 関数ごとにGOTに登録するんでしょうか?それとも最初の1回目ですべて登録してしまうんですか?
strike1217

2017/07/12 02:55

GDBでやってみました。 全関数をGOTに登録はしていませんでした。 遅延BINDが適応されるのは同一の関数の場合のみですね。 じゃぁ・・・なんで一番最初にstrcmp()に到着してしまったんでしょうね・・・・
strike1217

2017/07/12 03:55

printf()見つけました。 _dl_runtime_resolve_sse_vex()内にありました。 strcmp()は、おそらく_dl_runtime_resolve自体が使用しているのでしょう。 では・・・残りの問題を・・・・
strike1217

2017/07/12 04:23

ああ~~。 やっと、分かりました。 0x200ab2(%rip) = 0x555555755018 だったので、 x 0x555555755018 とやると 566: pushq $0x0 次の命令を示すアドレスが入っていました。 なるほど!だから条件分岐なしでも大丈夫なんですね! _dl_runtime_resolveがGOTを設定すると、アドレスが変更されるんですね!! GOTはビルドした段階では、空っぽだが、PLT経由でアクセスしたときに初めて初期化されるという理解で正しいでしょうか??
mit0223

2017/07/13 03:01

> GOTはビルドした段階では、空っぽだが、PLT経由でアクセスしたときに初めて初期化されるという理解で正しいでしょうか?? はい、それを遅延BINDというのではないでしょうか。ダイナミックリンクされていても、最後まで呼ばれない関数もたくさんあるので、遅延BINDすることで性能を改善しています。
strike1217

2017/07/13 03:36 編集

なるほど・・・・ GDBで調べたところ、_dl_runtime_resolve()もGOTの中に登録されていました。 共有ライブラリだけでなく、共有ライブラリを使用するための関数群もGOTに登録されるんですね!! 共有ライブラリを使用するための関数群の場合は、ロード時に誰がGOTに登録しているんでしょうか? ダイナミックリンカローダですか?
mit0223

2017/07/13 10:56

> ダイナミックリンカローダですか? そうかもしれません。わかりません。
strike1217

2017/07/13 12:00

そうですか! 長々付き合っていただきありがとうございます。
strike1217

2017/07/13 12:02

あ、もしかしたらカーネルかもしれませんね・・・・
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問