リンカによるシンボル解決(2)ファイル内変数のシンボル解決(後編)

変数の論理アドレスが実行コード中に埋め込まれる場所は、以下の.rel.text(再配置テーブル)で管理されます。

Relocation section '.rel.text' at offset 0x410 contains 2 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
00000005  00000401 R_386_32          00000000   .bss
0000000a  00000301 R_386_32          00000000   .data

「Offset」は、.textセクションの埋め込み場所のオフセットアドレス。「Info」は、上位24ビットで対応するシンボルテーブル・エントリの番号、下位8ビットで再配置の種別をそれぞれ示しています。

1番目のエントリだと、

  1. .textセクションの先頭から「5」バイト目に当該シンボルのアドレスが埋め込まれる。
  2. 埋め込まれる当該シンボルは、シンボルテーブルの「4」番目エントリである。
  3. 再配置種別は「R_386_32(=1)」。

.textセクションの5バイト目というと、以下の「04 00 00 00」の配置場所です。

$ objdump -d sample.o -M intel
(略)
00000000 
: 0: 55 push ebp 1: 89 e5 mov ebp,esp 3: 8b 15 04 00 00 00 mov edx,DWORD PTR ds:0x4 9: a1 08 00 00 00 mov eax,ds:0x8 e: 01 d0 add eax,edx 10: 5d pop ebp 11: c3 ret

また、シンボルテーブルのNdxは、関連するセクションエントリの番号を示します。シンボルテーブルの4番エントリ(以下★)の場合、関連するセクションエントリは、4番セクションとなります。

Symbol table '.symtab' contains 14 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00000000     0 FILE    LOCAL  DEFAULT  ABS sample.c
     2: 00000000     0 SECTION LOCAL  DEFAULT    1 
     3: 00000000     0 SECTION LOCAL  DEFAULT    3 
   ★4: 00000000     0 SECTION LOCAL  DEFAULT    4 
     5: 00000000     4 OBJECT  LOCAL  DEFAULT    4 dummy_bss_val
     6: 00000000     4 OBJECT  LOCAL  DEFAULT    3 dummy_val
     7: 00000004     4 OBJECT  LOCAL  DEFAULT    3 dummy_val2
     8: 00000004     4 OBJECT  LOCAL  DEFAULT    4 bss_val
     9: 00000008     4 OBJECT  LOCAL  DEFAULT    3 val
    10: 00000000     0 SECTION LOCAL  DEFAULT    6 
    11: 00000000     0 SECTION LOCAL  DEFAULT    7 
    12: 00000000     0 SECTION LOCAL  DEFAULT    5 
    13: 00000000    18 FUNC    GLOBAL DEFAULT    1 main

セクションヘッダを見ると、4番セクションは.bssセクション(★)に該当します。

There are 12 section headers, starting at offset 0x110:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        00000000 000034 000012 00  AX  0   0  4
  [ 2] .rel.text         REL             00000000 000410 000010 08     10   1  4
  [ 3] .data             PROGBITS        00000000 000048 00000c 00  WA  0   0  4
★[ 4] .bss              NOBITS          00000000 000054 000008 00  WA  0   0  4
  [ 5] .comment          PROGBITS        00000000 000054 00002b 01  MS  0   0  1
  [ 6] .note.GNU-stack   PROGBITS        00000000 00007f 000000 00      0   0  1
  [ 7] .eh_frame         PROGBITS        00000000 000080 000038 00   A  0   0  4
  [ 8] .rel.eh_frame     REL             00000000 000420 000008 08     10   7  4
  [ 9] .shstrtab         STRTAB          00000000 0000b8 000057 00      0   0  1
  [10] .symtab           SYMTAB          00000000 0002f0 0000e0 10     11  13  4
  [11] .strtab           STRTAB          00000000 0003d0 00003e 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

以上をまとめると、

  1. .textセクションのオフセット5バイト目に埋め込まれる論理アドレスは、.bssセクションに領域が確保される変数のアドレスである。
  2. 再配置種別は「R_386_32」なので、.text+5バイト目に埋め込まれた仮の値「0x00000004」を.bssセクションの先頭アドレスに加算したものが、実際に埋め込まれる論理アドレスとなる。

リンク後の実行形式では、.bssの先頭アドレスは「0804a01c」なので(以下参照)、これにオフセット4バイトを加算すると、埋め込まれる値は「0x0804a01c + 0x04 = 0x0804a020」となるはずです。

  [24] .data             PROGBITS        0804a008 001008 000014 00  WA  0   0  4
  [25] .bss              NOBITS          0804a01c 00101c 000010 00  WA  0   0  4

しかし、実行形式における当該変数のアドレスをnmコマンドで確認してみると、以下のように「0804a028」と、8バイト分ずれていることが分かります。

$ nm sample
(略)
0804a028 b bss_val
0804a01c b completed.6159
0804a008 W data_start
0804a020 b dtor_idx.6161
0804a024 b dummy_bss_val
0804a010 d dummy_val
0804a014 d dummy_val2
08048390 t frame_dummy
080483b4 T main
0804a018 d val

上記nmコマンドの結果から、.bss上に確保される変数領域をアドレス順に抽出してみると、

0804a01c b completed.6159★←リンクによって他のオブジェクトファイルの.bssが挿入された。
0804a020 b dtor_idx.6161★←同上
0804a024 b dummy_bss_val
0804a028 b bss_val

となります。つまり実行形式では、★のついた2つの変数(completed.6159とdtor_idx.6161)が挿入されているため、8バイト分、アドレスがシフトしています。実際に、オブジェクトファイル(sample.o)の.bss格納領域を確認してみると、

00000000 b dummy_bss_val
00000004 b bss_val

★のついた2つの変数は存在しません。