C/C++でシンボル情報を読み出す方法

March 23,2018 12:03 AM
Category:[C/C++]
Tag:[C/C++]
Permalink

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)が取得できました。

Comments [0] | Trackbacks [0]

確定申告でクレジットカードを使って納税する方法

March 15,2018 12:03 AM
Category:[サービス]
Tag:[]
Permalink

確定申告でクレジットカードを使って納税する方法を紹介します。

1.はじめに

申告所得税はクレジットカード支払に対応しています。

ということで、クレジットカードによる納税方法を紹介します。

使えるクレジットカードは、Visa、Mastercard、JCB、American Express、Diners Club、TS CUBIC CARDのいずれかです。

なお、クレジットカードによる納税の場合、決済手数料がかかります。

金額は、1万円の納税で76円(消費税込で82円)、以後、1万円ごとに76円加算されるので、たとえば納税額が10万円の場合、820円の決済手数料が納税額に加算されます。

2.クレジットカードを使って納税する

国税クレジットカードお支払サイト」のページにアクセス。

国税クレジットカードお支払サイト
国税クレジットカードお支払サイト

納付税額を入力。入力すると決済手数料と支払額合計が表示されます。

納付税額

「上記の注意事項を確認しました」をチェック。

上記の注意事項を確認しました

同意ボタンをクリック。

同意

納税者の情報を入力

(クリックで拡大、以下同様)
納税者の情報

納付内容のところに記載されているとおり、「納付項目」から、一番上にある「申告所得税及復興特別所得税」を選択。

納付内容

選択すると入力項目が表示されるので、「課税期間(今回は29年)」、「申告区分(確定申告)」、通常の申告であれば「本税」および「合計額」を入力して「次へ」をクリック。

「本税」には"*"がついていませんが入力しないと警告が表示されます。また前の画面で入力した納付税額は引き継がれないので、「合計額」に再度入力します。

納付内容

クレジットカード情報を入力して「次へ」をクリック。

クレジットカード情報

入力内容が表示されるので、間違いがなければ「納付」をクリック。

納付

確認のダイアログが表示されるので問題なければ「はい」をクリック。

確認のダイアログ

これで納付手続き完了です。

納付手続き完了

Comments [0] | Trackbacks [0]

.bssと.sbss/.dataと.sdataの違い

March 13,2018 12:03 AM
Category:[C/C++]
Tag:[]
Permalink

.bssと.sbss/.dataと.sdataの違いについて調べてみました。

1.問題点

C++で、やや規模の大きなプログラムを作り、ビルドしたところ、リンクマップには

 .data
 .bss

以外に

 .sdata
 .sbss

というセクションができました。

.dataは初期値ありのデータ、.bssは初期値なしのデータを配置するセクションですが、.sdata/.sbssとの違いが分かりません。

ということで、.bssと.sbss/.dataと.sdataの違いについて調べてみました。

2..bssと.sbss/.dataと.sdataの違い

通常、プログラムが変数の値を読み書きするには、

  • 変数のアドレスをレジスタに代入
  • レジスタの指す先のメモリを読み書き

という、2つの手順が必要です。

.bssセクションや.dataセクションのデータはこの手順で読み書きします。

つまり、変数のアドレスを直接指定したメモリ読み書きは行なえません。

ただ、すべての変数でこれを行うのはコストがかかります。

そこで、データ領域を常に指すレジスタをひとつ設けておき、そのレジスタ値にインデックスを加えた位置(=変数)を読み書きすることで、アドレスをレジスタに設定するコストを削減するという方法があります。

このためのレジスタを「グローバルポインタ(またはベースレジスタ)」と呼びます.

これによりアセンブラは、通常2ワードで参照を行うところ、 1ワードのメモリ参照命令が生成可能となります。

グローバル・ポインタを利用してアクセスする変数を .sbssまたは.sdataというセクションに集めます。

.sbss/.sdataにサイズの小さい変数が多いのは、たくさんの変数を格納できた方がグローバル・ポインタを効率的に利用できるためです。

Comments [0] | Trackbacks [0]
 1  |  2  |  3  |  4  |  5  | All pages