リンカによるシンボル解決(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番目のエントリだと、
- .textセクションの先頭から「5」バイト目に当該シンボルのアドレスが埋め込まれる。
- 埋め込まれる当該シンボルは、シンボルテーブルの「4」番目エントリである。
- 再配置種別は「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)
以上をまとめると、
- .textセクションのオフセット5バイト目に埋め込まれる論理アドレスは、.bssセクションに領域が確保される変数のアドレスである。
- 再配置種別は「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つの変数は存在しません。