2017-08-28 17 views
3

this questionを参照して:gccはどのライブラリに暗黙的にインクルードするかをどのように決定しますか?

小さなマイクロの埋め込みプロジェクトでは、コンパイルされたコードサイズが予想よりもはるかに大きいことがわかりました。 assert()を使用したコードが含まれていたためです。 assertの使用はインクルードされたコードでは適切でしたが、コンパイルされたコードサイズはほぼ倍増しました。

アサルトを使用するべきであるが、アサーションに必要なすべてのオーバーヘッドをコンパイラ/リンカがどのように組み込むかを決める際に、問題はありません。他のポストから

私の元の質問:

誰かがgccがアサートが呼び出されたときに、ライブラリの関数を含めることを決定した方法を私に説明することができれば便利でしょうか? assert.hが外部関数__assert_funcを宣言していることがわかります。リンカーは、単に "__asert_funcへの未定義の参照"というより、ライブラリからそのリンカーを参照する方法を知っていますか?

答えて

6

ツールチェーンを設定するとき、作成者はデフォルトでリンクするライブラリを決定します。

これは、ランタイムスタートアップ/初期化コードと、C標準の実装を含むライブラリlibcを含みます(例えば、libcはPosix、カスタムボード固有の関数などを実装する可能性があります)。 )、組み込みターゲットの場合、ターゲットのRTOSを実装するライブラリにリンクすることも珍しくありません。

gccに-nodefaultlibsフラグを使用すると、リンクステージでこれらのデフォルトライブラリを省略できます。

assert()の場合、通常はlibcに実装されている標準のCマクロ/関数です。 assert()が失敗するとstdoutに出力される可能性があります。したがって、assert()を使用すると、libcに実装されているFILE *処理/バッファリング、printfなどを実装するstdio機構全体を引き出すことができます。

リンクステージでgcc -vを実行すると、gccがデフォルトでリンクするライブラリが表示されます。

+0

これはまさにそれがしたことです。 stdioやprintfなどに引っ張られました...私はいくつかの素朴な理由から、リンカはlibcを含むすべてのライブラリにリンクする必要があると仮定していました。 –

4

gcc(または)コマンドは単なるドライバです。コンパイラ本体(Cコードではcc1、C++コードではcc1plus)とアセンブラとリンカを含む他のプログラムを実行します。

実行されるプログラムは、spec fileによって決まります(暗黙のプログラムがあります)。-dumpspecsdeveloper optionを参照してください。ところでgcc-vオプションで実行すると、実際のプログラムが表示されます。

assertマクロはNDEBUGが定義されたプリプロセッサシンボルでない場合にのみ、<assert.h>にいくつかのチェックを行うために(ファイル/usr/include/assert.hを参照)が定義されています。私のLinux/Glibcシステムでは、C標準ライブラリから__assert_failed内部関数を呼び出すことができます。 assert(3)ドキュメント引用:マクロNDEBUGは現時点<assert.h>で定義されている場合は、最後の が含まれていた

を、マクロassert()は何のコードを生成しない、したがって、まったく 何もしません。

一部のプロジェクトでは、-DNDEBUGコードがプロダクションモードでコンパイルされています。

ドキュメントのInvoking GCCの章をお読みください。

恐らく​​は、余分なライブラリを避けたいと思っています。

2

組み込みシステムでは、リンクは静的です。静的リンクは次のように動作します。

スタティックライブラリは、オブジェクトファイルのアーカイブです。リンカーは各オブジェクトを個別に考慮します。

静的ライブラリにある参照された関数または変数は、参照されたシンボルを含むオブジェクトファイル全体と共に、結果として得られる実行可能ファイルに含まれます。参照シンボルを含まないオブジェクトファイルは引き込まれません。

これは、gcc固有のものではありません。リンカーズは、このように、時の幕開けから動作します。

関連する問題