web-dev-qa-db-ja.com

gccはLinux ELFにどのような機能を追加しますか?

C(またはasm)のhello-worldのようなプログラムをgccにリンクすると、結果の実行可能オブジェクトファイルに何かが追加されます。ランタイムダイナミックリンカーと_startエントリポイントについてのみ知っていますが、これらの追加された関数の種類は何ですか?

00000000004003f0 t deregister_tm_clones
0000000000400430 t register_tm_clones
0000000000400470 t __do_global_dtors_aux
0000000000400490 t frame_dummy
00000000004004e0 T __libc_csu_init
0000000000400550 T __libc_csu_fini
0000000000400554 T _fini
0000000000600668 t __frame_dummy_init_array_entry
0000000000600668 t __init_array_start
0000000000600670 t __do_global_dtors_aux_fini_array_entry
0000000000600670 t __init_array_end

それらは何のために何のためのものですか?どこかに記載されていますか?グーグルは役に立ちません。

27
Victor Polevoy

これらのほとんどは、「メイン」プログラム自体の前または後にコードを実行するさまざまな方法であり、ほとんどが_crtstuff.c_( https://github.com/gcc-mirror/gcc/blob/master/ libgcc/crtstuff.c )。さまざまなCライクなプログラミング言語の機能をサポートするために存在しますが、Cからもアクセスできます。これらのいくつかはレガシーの手荷物を表し、GCCが実行されるさまざまな異なるアーキテクチャをサポートするために必要なバリエーションもあるので、おそらく複雑すぎるようです。

リストから、1つずつ(または2つずつ):

_00000000004003f0 t deregister_tm_clones
0000000000400430 t register_tm_clones
_

トランザクションメモリは、スレッドを使用したプログラミングを簡単にすることを目的としています。これは、ロックベースの同期の代替手段です。これらのルーチンは、これらの関数をサポートするライブラリ(libitm)によって使用されるテーブルをそれぞれ破棄およびセットアップします。 TMの詳細はこちら https://gcc.gnu.org/wiki/TransactionalMemory とこちら http://pmarlier.free.fr/gcc-tm-tut.html =

_0000000000400470 t __do_global_dtors_aux
_

_.fini_array_が使用できないシステムで、プログラムの終了時にすべてのグローバルデストラクタを実行します。

_0000000000400490 t frame_dummy
_

この関数は_.init_セクションにあります。それはvoid frame_dummy ( void )として定義されており、そのライフポイントは引数を持つ___register_frame_info_bases_を呼び出すことです。どうやら_.init_セクションからの引数を持つ関数の呼び出しは信頼できない可能性があるため、この関数は___register_frame_info_bases_が_.init section_から直接呼び出されないようにします。 _.eh_frame_情報ベースは、例外処理と同様の機能(__attribute__((cleanup(..)))で宣言された関数など)に使用されます。

_00000000004004e0 T __libc_csu_init
0000000000400550 T __libc_csu_fini
_

これらは、プログラムレベルの初期化子とファイナライザー(プログラム全体のようなコンストラクター/デストラクターの一種)を実行します。次のような関数を定義すると、

_void __attribute__ ((constructor)) mefirst () {
    /* ... do something here ... */
}

void __attribute__ ((destructor)) melast () {
    /* ... do something here ... */
}
_

これらは、main()の前と後にそれぞれこれらのルーチンによって呼び出されます。参照 https://gcc.gnu.org/onlinedocs/gccint/Initialization.html

_0000000000400554 T _fini
_

これは、プログラムレベル(実際にはオブジェクトファイルレベル)のデストラクタを実行するために廃止された方法です(これに関する小さな情報は_man dlclose_にあります)。コンストラクターに対応する廃止された関数は___init_です。

_0000000000600668 t __frame_dummy_init_array_entry
0000000000600668 t __init_array_start
_

これらは、すべてのプログラムレベルの初期化子へのポインタを含む_.init_array_セクションの終了と開始を示します(上記の__ libc_csu_initを参照)。

_0000000000600670 t __do_global_dtors_aux_fini_array_entry
0000000000600670 t __init_array_end
_

これらは、すべてのプログラムレベルのファイナライザへのポインタを含む_.fini_array_セクションの終了と開始をマークします(上記の__ libc_csu_finiを参照)。

[EDIT]その他の注意事項:

  • Jesterの質問コメントからのリンク http://dbp-consulting.com/tutorials/debugging/linuxProgramStartup.html には、ニースの図と、これらの動作の全体的な順序を示す小さなサンプルプログラムが含まれています。 Cからこれらの機能の一部にアクセスする方法。

  • ctors」および「dtors」という用語は、「コンストラクタの略語です'および'destructors 'です。

  • グローバルコンストラクター/デストラクターとオブジェクトファイルコンストラクター/デストラクターの違いは、プログラムが複数のオブジェクトファイルから構築されている場合に最も明確になります。

  • [〜#〜] t [〜#〜]」とマークされた記号(__ libc_csu_init、__libc_csu_fini、_fini)は「グローバル」(外部から見える)であり、残り( 't'とマークされている)はそうではありません。

29
John Hascall