C/C++でシンボル情報を読み出す方法
C/C++でシンボル情報を読み出す方法を紹介します。
1.はじめに
C/C++のプログラムでBセクションの開始アドレスと終了アドレスを読み出す必要が生じました。
ひとつの方法として、Bセクションのシンボル情報を読み出せばよいのですが、読み出す方法がわかりません。
ということで、C/C++でシンボル情報を読み出す方法を紹介します。
2.C/C++でシンボル情報を読み出す
C/C++でシンボル情報を読み出すには、下記のようにします。
test.cc
#include <stdio.h>
extern const void * __bss_start;
int main() {
printf("__bss_start:%p\n", &__bss_start);
}
__bss_startがBセクションの開始シンボルです。
このプログラムのビルドおよび実行結果は次の通りです。
% g++ test.cc
% ./a.out
__bss_start:0x6009dc
nmコマンドでのシンボル情報は下記です。
% nm ./a.out
:
00000000006007d8 d __JCR_END__
00000000006007d8 d __JCR_LIST__
00000000006009dc A __bss_start
00000000006009d8 D __data_start
0000000000400680 t __do_global_ctors_aux
0000000000400510 t __do_global_dtors_aux
00000000004006d0 R __dso_handle
w __gmon_start__
U __gxx_personality_v0@@CXXABI_1.3
00000000006007b4 d __init_array_end
00000000006007b4 d __init_array_start
00000000004005e0 T __libc_csu_fini
00000000004005f0 T __libc_csu_init
U __libc_start_main@@GLIBC_2.2.5
00000000006009dc A _edata
00000000006009f0 A _end
00000000004006b8 T _fini
0000000000400460 T _init
00000000004004c0 T _start
:
これでBセクションの開始アドレス(__bss_start)が取得できました。
3.終了アドレスを取得する
実験したLinuxでは__bss_endというシンボルがないので、ちょっと面倒ですが、リンカスクリプトに追加する方法で実施します。
まず、g++に"-Wl,--verbose"オプションを追加して、リンク時のリンカスクリプトを表示させます。
% g++ -Wl,--verbose test.cc
GNU ld version 2.20.51.0.2-5.36.el6 20100205
Supported emulations:
elf_x86_64
elf_i386
i386linux
elf_l1om
using internal linker script:
==================================================
/* Script for -z combreloc: combine and sort reloc sections */
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64",
"elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
SEARCH_DIR("/usr/x86_64-redhat-linux/lib64"); SEARCH_DIR("/usr/local/lib64"); SEARCH_DIR("/lib64"); SEARCH_DIR("/usr/lib64"); SEARCH_DIR("/usr/x86_64-redhat-linux/lib"); SEARCH_DIR("/usr/lib64"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib");
SECTIONS
{
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
.interp : { *(.interp) }
:
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
/* Sharable data sections. */
.sharable_data : ALIGN(CONSTANT (MAXPAGESIZE))
{
PROVIDE_HIDDEN (__sharable_data_start = .);
*(.sharable_data .sharable_data.* .gnu.linkonce.shrd.*)
/* Align here to ensure that the sharable data section ends at the
page boundary. */
. = ALIGN(. != 0 ? CONSTANT (MAXPAGESIZE) : 1);
PROVIDE_HIDDEN (__sharable_data_end = .);
}
_edata = .; PROVIDE (edata = .);
__bss_start = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we don't
pad the .data section. */
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
.lbss :
{
*(.dynlbss)
*(.lbss .lbss.* .gnu.linkonce.lb.*)
*(LARGE_COMMON)
}
:
/* DWARF 3 */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
}
==================================================
attempt to open /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64/crt1.o succeeded
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64/crt1.o
:
ld-linux-x86-64.so.2 needed by /usr/lib/gcc/x86_64-redhat-linux/4.4.7/libstdc++.so
found ld-linux-x86-64.so.2 at /lib64/ld-linux-x86-64.so.2
出力された下記の部分をコピーして、linker.scriptなど、任意の名称で保存します。
/* Script for -z combreloc: combine and sort reloc sections */
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64",
"elf64-x86-64")
:
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
SEARCH_DIR("/usr/x86_64-redhat-linux/lib64"); SEARCH_DIR("/usr/local/lib64"); SEARCH_DIR("/lib64"); SEARCH_DIR("/usr/lib64"); SEARCH_DIR("/usr/x86_64-redhat-linux/lib"); SEARCH_DIR("/usr/lib64"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib");
SECTIONS
{
:
}
linker.scriptをvimなどで開き、__bss_end(赤色部分)を追加します。
__bss_start = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we don't
pad the .data section. */
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
__bss_end = .;
.lbss :
{
*(.dynlbss)
*(.lbss .lbss.* .gnu.linkonce.lb.*)
*(LARGE_COMMON)
}
サンプルソースに__bss_endの対応(赤色)を追加します。
test.cc
#include <stdio.h>
extern const void * __bss_start;
extern const void * __bss_end;
int main() {
printf("__bss_start:%p\n", &__bss_start);
printf("__bss_end:%p\n", &__bss_end);
}
ビルド時に"-T"オプションでリンカスクリプトを指定します。
% g++ -Tlinker.script test.cc
実行します。
% ./a.out
__bss_start:0x6009dc
__bss_end:0x6009f0
nmコマンドの実行結果は下記です。
% nm a.out
:
00000000006007c8 d __DTOR_LIST__
00000000004007b0 r __FRAME_END__
00000000006007d8 d __JCR_END__
00000000006007d8 d __JCR_LIST__
00000000006009f0 A __bss_end
00000000006009dc A __bss_start
00000000006009d8 D __data_start
0000000000400680 t __do_global_ctors_aux
0000000000400510 t __do_global_dtors_aux
:
これでBセクションの開始アドレス(__bss_start)と終了アドレス(__bss_end)が取得できました。
Posted by yujiro このページの先頭に戻る
トラックバックURL
コメントする
greeting