3

C++ ファイル内の静的初期化子をカウントしようとしています。

私がすでに持っている解決策 (gcc-4.4 で動作していた) は、.ctors ELF セクションのサイズを調べています。

gcc-4.6 へのアップグレード後、これは有効な結果を返さなくなったようです (計算された静的初期化子の数は 0 であり、たとえば nm によって返される現実と一致しません)。

問題は、シンボルがなくてもソリューションが機能することです(そうでなければ、nmを使用していたはずです)。

以下は、実行可能ファイルの例の readelf -SW の出力です。

There are 35 section headers, starting at offset 0x4f39820:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        00000174 000174 000013 00   A  0   0  1
  [ 2] .note.ABI-tag     NOTE            00000188 000188 000020 00   A  0   0  4
  [ 3] .note.gnu.build-id NOTE            000001a8 0001a8 000024 00   A  0   0  4
  [ 4] .gnu.hash         GNU_HASH        000001cc 0001cc 000918 04   A  5   0  4
  [ 5] .dynsym           DYNSYM          00000ae4 000ae4 00a5e0 10   A  6   1  4
  [ 6] .dynstr           STRTAB          0000b0c4 00b0c4 00ef72 00   A  0   0  1
  [ 7] .gnu.version      VERSYM          0001a036 01a036 0014bc 02   A  5   0  2
  [ 8] .gnu.version_r    VERNEED         0001b4f4 01b4f4 000450 00   A  6  13  4
  [ 9] .rel.dyn          REL             0001b944 01b944 268480 08   A  5   0  4
  [10] .rel.plt          REL             00283dc4 283dc4 0048c8 08   A  5  12  4
  [11] .init             PROGBITS        0028868c 28868c 00002e 00  AX  0   0  4
  [12] .plt              PROGBITS        002886c0 2886c0 0091a0 04  AX  0   0 16
  [13] .text             PROGBITS        00291860 291860 3ac5638 00  AX  0   0 16
  [14] malloc_hook       PROGBITS        03d56ea0 3d56ea0 00075a 00  AX  0   0 16
  [15] google_malloc     PROGBITS        03d57600 3d57600 008997 00  AX  0   0 16
  [16] .fini             PROGBITS        03d5ff98 3d5ff98 00001a 00  AX  0   0  4
  [17] .rodata           PROGBITS        03d5ffc0 3d5ffc0 ffa640 00   A  0   0 64
  [18] .eh_frame_hdr     PROGBITS        04d5a600 4d5a600 0004b4 00   A  0   0  4
  [19] .eh_frame         PROGBITS        04d5aab4 4d5aab4 001cb8 00   A  0   0  4
  [20] .gcc_except_table PROGBITS        04d5c76c 4d5c76c 0003ab 00   A  0   0  4
  [21] .tbss             NOBITS          04d5df0c 4d5cf0c 000014 00 WAT  0   0  4
  [22] .init_array       INIT_ARRAY      04d5df0c 4d5cf0c 000090 00  WA  0   0  4
  [23] .ctors            PROGBITS        04d5df9c 4d5cf9c 000008 00  WA  0   0  4
  [24] .dtors            PROGBITS        04d5dfa4 4d5cfa4 000008 00  WA  0   0  4
  [25] .jcr              PROGBITS        04d5dfac 4d5cfac 000004 00  WA  0   0  4
  [26] .data.rel.ro      PROGBITS        04d5dfc0 4d5cfc0 1b160c 00  WA  0   0 32
  [27] .dynamic          DYNAMIC         04f0f5cc 4f0e5cc 000220 08  WA  6   0  4
  [28] .got              PROGBITS        04f0f7ec 4f0e7ec 00a800 04  WA  0   0  4
  [29] .data             PROGBITS        04f1a000 4f19000 0206b8 00  WA  0   0 32
  [30] .bss              NOBITS          04f3a6c0 4f396b8 04c800 00  WA  0   0 32
  [31] .comment          PROGBITS        00000000 4f396b8 00002a 01  MS  0   0  1
  [32] .shstrtab         STRTAB          00000000 4f396e2 00013e 00      0   0  1
  [33] .symtab           SYMTAB          00000000 4f39d98 4ff960 10     34 140163  4
  [34] .strtab           STRTAB          00000000 54396f8 144992a 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)

Should I be looking at .init or .init_array instead? Could you point me to corresponding documentation that explains the change between gcc or linker versions?

4

2 に答える 2

8

.init静的コンストラクターは、 、.ctors、または.init_array(古いものから順に新しいものへ) の 3 つのセクションのいずれかによってトリガーできます。.initコードのフラグメントを含み、コードへのポインタを含みます.ctors.init_arrayとの違いは、コンストラクターが実行される全体的な順序に関係しています.ctors.init_array私の知る限り、これはコード コメントとメーリング リストの投稿以外には文書化されていませんが、おそらく ELF ABI ドキュメント (g- と ps- の両方) を確認する価値があります。

これらのセクションのサイズから、ファイル内の静的コンストラクターの数を推測することはできません。ファイル内のすべてのコンストラクターを呼び出す単一の特別な関数をコンパイラが生成し、それが使用するセクションのいずれかでその 1 つの関数のみを参照することは許可されており、一般的です。確かに知ることができるのは(セクションの内容を調べたり、再配置を適用したり、ポインターを追跡したり、セグメントへの命令を呼び出したり、呼び出されたものをリバースエンジニアリングしたりせずに)、次のことだけです。.text、これらのセクションの少なくとも 1 つのサイズがゼロ以外の場合、ファイルには少なくとも 1 つのファイル スコープまたはグローバル スコープのコンストラクターがあります。3 つのセクションがすべて空の場合、何もありません。(実行可能ファイルでは、3 つのセクションはすべて常に空ではありません。これは、それらが定義するデータ構造に、リンク時に自動的に追加されるヘッダーとトレーラーが必要だからです。)

また、ブロック スコープの静的オブジェクトのコンストラクターは、これらのセクションのいずれからも呼び出されないことに注意してください。コントロールが最初に宣言に到達したときに呼び出されます。

于 2013-03-20T19:19:41.023 に答える
-1

私は、アプリケーションのすべてのソース コード (およびおそらくそれが呼び出されるすべてのライブラリ) にアクセスできると想定しています。これは明らかにフリーソフトウェアに当てはまります。

次に、アプリケーションを (GCC の最近のバージョン、たとえば 4.7 または 4.8 を使用して) コンパイルするときに、コンパイル時にそれをより正確に測定することができます。MELT (GCCを拡張する高レベルのドメイン固有言語) で拡張するか、C++ でコーディングされた面倒な GCC プラグインを使用して、そのようなことを測定することができます。

そして、あなたの質問が正確に意味をなすかどうかは完全にはわかりません。たとえば、アプリケーションが静的コンストラクターを非表示にするために可視性トリックを使用する共有ライブラリにリンクされている場合、ライブラリーが呼び出す静的コンストラクターの数を理解することは実際には定義されていません。

于 2013-03-20T19:26:55.990 に答える