3

バイナリをライブラリと動的にリンクする場合、再配置情報を使用して、さまざまな 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 グローバル変数をどのように解決することになっていますか?

4

2 に答える 2

0

(@Employed Russian が提供する Oracle ドキュメントを読みました。)

グローバル変数の再インスタンス化は、非 PIC コードにパッチを適用せずに非 PIC の方法で変数を逆参照するために、非 PIC コードに対して行われます。

  • 非 PIC コードに対して変数のコピーが行われます。
  • 変数は実行可能ファイルでインスタンス化されます。
  • コピー再配置命令は、動的リンク時にソース共有オブジェクトからデータをコピーするために使用されます。
  • 共有オブジェクトのインスタンスは使用されません (再配置コピーが行われた後)。

移転手順をコピーします。

$readelf -r b

Relocation section '.rela.dyn' at offset 0x638 contains 2 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000600c58  000300000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0
000000600ca8  001200000005 R_X86_64_COPY     0000000000600ca8 foo + 0

関数の場合、PIC コードで使用されるのと同じ方法で GOT+PLT 手法が使用されます。

于 2014-02-17T08:29:15.297 に答える