バイナリをライブラリと動的にリンクする場合、再配置情報を使用して、さまざまな ELF オブジェクトの変数/関数をバインドします。ただし、DWARF は再配置の影響を受けません。デバッガーはグローバル変数をどのように解決するのでしょうか?
グローバル変数を定義する liba.so (ac) があるとします (GCC または Clang で GNU/Linux を使用):
#include <stdio.h>
int foo = 10;
int test(void) {
printf("&foo=%p\n", &foo);
}
liba.so (bc) に対してリンクされたプログラム b:
#include <stdio.h>
extern int foo;
int main(int argc, char** argv) {
test();
printf("&foo=%p\n", &foo);
return 0;
}
「foo」は liba.so でインスタンス化されると予想していますが、実際には liba.so と b の両方でインスタンス化されています。
$ ./b
&foo=0x600c68 # <- b .bss
&foo=0x600c68 # <- b .bss
(b と lib.so の両方で) 使用される foo 変数は、liba.so ではなく b の .bss にあります。
[...]
0x0000000000600c68 - 0x0000000000600c70 is .bss
[...]
0x00007ffff7dda9c8 - 0x00007ffff7dda9d4 is .data in /home/foo/bar/liba.so
0x00007ffff7dda9d4 - 0x00007ffff7dda9d8 is .bss in /home/foo/bar/liba.so
foo 変数は 2 回インスタンス化されます。
liba.so で 1 回 (このインスタンスは、プログラム b とリンクされている場合は使用されません)
b で 1 回 (このインスタンスは b で他のインスタンスに使用されます)。
(変数が実行可能ファイルでインスタンス化される理由がよくわかりません。)
DWARF 情報の b には (予想どおり) 宣言のみがあります。
$ readelf -wi b
[...]
<1><ca>: Abbrev Number: 9 (DW_TAG_variable)
<cb> DW_AT_name : foo
<cf> DW_AT_decl_file : 1
<d0> DW_AT_decl_line : 3
<d1> DW_AT_type : <0x57>
<d5> DW_AT_external : 1
<d5> DW_AT_declaration : 1
[...]
場所は liba.so にあります。
$ readelf -wi liba.so
[...]
<1><90>: Abbrev Number: 5 (DW_TAG_variable)
<91> DW_AT_name : foo
<95> DW_AT_decl_file : 1
<96> DW_AT_decl_line : 3
<97> DW_AT_type : <0x57>
<9b> DW_AT_external : 1
<9b> DW_AT_location : 9 bloc d'octets: 3 d0 9 20 0 0 0 0 0 (DW_OP_addr: 2009d0)
[...]
このアドレスは、liba.so (.data) 内の foo の (使用されていない) インスタンスの場所です。
- foo グローバル変数の 2 つのインスタンス (liba.so の on と b の 1 つ) になります。
- DWARF で表示できるのは最初の 1 つだけです。
- 2 番目の 1 つだけが使用されます。
デバッガーは foo グローバル変数をどのように解決することになっていますか?