質問から、ライブラリ関数をプロファイリングしているようです。
測定されている関数が何であるかを知るには、2 つのオプションがあります。
1ライブラリを使用するプログラムを で実行し、gdb
で停止しmain
ます。この時点pid
で、プログラムのPID=...
を取得し、「cat /proc/$PID/maps」を実行します。そこには、次のようなものが表示されます。
➜ ~ ps
PID TTY TIME CMD
18533 pts/4 00:00:00 zsh
18664 pts/4 00:00:00 ps
➜ ~ PID=18533
➜ ~ cat /proc/$PID/maps
00400000-004a2000 r-xp 00000000 08:01 3670052 /bin/zsh5
006a1000-006a2000 r--p 000a1000 08:01 3670052 /bin/zsh5
006a2000-006a8000 rw-p 000a2000 08:01 3670052 /bin/zsh5
006a8000-006bc000 rw-p 00000000 00:00 0
...
7fa174cc9000-7fa174ccd000 r-xp 00000000 08:01 528003 /lib/x86_64-linux-gnu/libcap.so.2.22
7fa174ccd000-7fa174ecc000 ---p 00004000 08:01 528003 /lib/x86_64-linux-gnu/libcap.so.2.22
7fa174ecc000-7fa174ecd000 r--p 00003000 08:01 528003 /lib/x86_64-linux-gnu/libcap.so.2.22
7fa174ecd000-7fa174ece000 rw-p 00004000 08:01 528003 /lib/x86_64-linux-gnu/libcap.so.2.22
...
これはライブラリ7fa174cc9000
のベースアドレスです。/lib/x86_64-linux-gnu/libcap.so.2.22
したがって、取得するすべてのアドレスはreadelf -s
、その値だけオフセットされます。ベースアドレスがわかれば、ファイル内の元のオフセットが何であったかを計算し直すことができます。
7fa174206370
つまり、ライブラリの値とベースアドレスを取得した場合7fa1741cf000
、オフセットは7fa174206370 - 7fa1741cf000 = 37370
です。私の例でsigsuspend
は、GLIBC からのものです。
94: 0000000000037370 132 FUNC WEAK DEFAULT 12 sigsuspend@@GLIBC_2.2.5
2gdb
これらのライブラリを使用するプログラムで実行します。ロードされたライブラリをメモリ内ですぐに見つけるか.text
、ライブラリのセクションを指す必要があります。
> gdb
(gdb) attach YOUR_PID
(a lot of output about symbols)
(gdb) x/i 0x00007fa174206386
=> 0x7fa174206386 <sigsuspend+22>: cmp $0xfffffffffffff000,%rax
0x7fa174206386
このようにして、それが内部にあることがわかりますsigsuspend
。
gdb
単独でシンボルをロードしない場合(Reading symbols from ... Loading symbols for ...
アタッチ後のような出力がない場合)、オプション1のようにライブラリのベース アドレスを検索し、それに.text
セクションのオフセットを追加できます。
➜ ~ readelf -S /lib/x86_64-linux-gnu/libcap.so.2.22 | grep '.text.'
[11] .text PROGBITS 0000000000001620 00001620
7fa174cc9000 + 0000000000001620
16 進数で を与えると、上記のように7FA174CCA620
接続して実行しますgdb
(gdb) add-symbol-file /lib/x86_64-linux-gnu/libcap.so.2.22 7FA174CCA620
次に、シンボルを単独でロードしない場合でも、(x/i ADDRESS
オプション1のように)シンボルを見つけることができるはずです。gdb
ご不明な点がございましたら、ご質問ください。説明を試みます。
なぜこれがそうなのかについての説明:
観測された動作は、 Position-Independent Codeとしてコンパイルされているライブラリによるものです。これにより、動的ライブラリを簡単にサポートできます。PIC は基本的に、ライブラリの ELF にセクション.plt
と.got
セクションがあり、任意のベース アドレスにロードできることを意味します。PLT はプロシージャ リンク テーブルであり、他のモジュールにある関数の呼び出しのトラップが含まれています。最初にプログラム インタープリターに移動して、呼び出された関数を再配置できるようにし、最初の呼び出しの後に関数にジャンプします。これは、プログラム インタープリターが、呼び出す関数のアドレスを含む GOT (グローバル オフセット テーブル) を更新するために機能します。最初にGOTが初期化され、最初の関数呼び出しで、現在呼び出されている関数の解決を実行するプログラムインタープリターの関数にジャンプが実行されます。
x86-64 では、PLT エントリは通常次のようになります。
0000000000001430 <free@plt>:
1430: ff 25 e2 2b 20 00 jmpq *0x202be2(%rip) # 204018 <_fini+0x201264>
1436: 68 00 00 00 00 pushq $0x0
143b: e9 e0 ff ff ff jmpq 1420 <_init+0x28>
1 つ目jmpq
は、GOT の location に保存されているアドレスへのジャンプです%rip + 0x202be2
。
[20] .got PROGBITS 0000000000203fd0 00003fd0
0000000000000030 0000000000000008 WA 0 0 8
%rip + 0x202be2
になり0x204012
、ライブラリのベースアドレスに追加されて、ライブラリが実際にロードされる場所に関連する絶対アドレスが生成されます。つまり、 にロードされた場合0x7f66dfc03000
、対応する GOT エントリの結果のアドレスは になります0x7F66DFE07012
。その場所に格納されているアドレスは、(この例では)free
関数のアドレスです。実際のfree
inを指すようにプログラムインタープリターによって維持されlibc
ます。
詳細については、こちらを参照してください。