実行可能ファイルのサイズを大幅に最適化する必要があり(ARM
開発)、現在のビルドスキーム(gcc
+ ld
)で未使用のシンボルが削除されないことに気付きました。
結果の実行可能ファイル/ライブラリのarm-strip --strip-unneeded
の使用は、実行可能ファイルの出力サイズを変更しません(理由はわかりませんが、単にできないのかもしれません)。
ビルドパイプラインを変更して、使用されていないシンボルが結果のファイルから削除されるようにする方法(存在する場合)はどうなりますか?
私はこれを考えさえしませんが、私の現在の組み込み環境は非常に「強力」ではなく、500K
を2M
からでも保存すると、非常に素晴らしいロードパフォーマンスが向上します。
更新:
残念ながら、現在使用しているgcc
バージョンには-dead-strip
オプションがなく、ld
の-ffunction-sections... + --gc-sections
は結果の出力に大きな違いを与えません。
gcc + ld
が未使用のシンボルを自動的に削除するはずだと確信していたため、これが問題になったことにショックを受けました(なぜそれらを保持しなければならないのですか?)。
GCCの場合、これは2段階で行われます。
最初にデータをコンパイルしますが、翻訳単位内のコードを個別のセクションに分割するようコンパイラーに指示します。これは、次の2つのコンパイラフラグを使用して、関数、クラス、および外部変数に対して行われます。
-fdata-sections -ffunction-sections
リンカー最適化フラグを使用して翻訳単位をリンクします(これにより、リンカーは参照されていないセクションを破棄します)。
-Wl,--gc-sections
そのため、2つの関数が宣言されているtest.cppというファイルがあり、そのうちの1つが使用されていない場合、次のgcc(g ++)のコマンドを使用して未使用のファイルを省略できます。
gcc -Os -fdata-sections -ffunction-sections test.cpp -o test -Wl,--gc-sections
(-Osは、GCCにサイズの最適化を指示する追加のコンパイラフラグであることに注意してください)
このスレッド を使用する場合は、gccに -ffunction-sections
および-fdata-sections
を指定する必要があります。これにより、各関数とデータオブジェクトが独自のセクションに配置されます。次に、 --gc-sections
をGNU ldに指定して、未使用のセクションを削除します。
Gccとldのバージョンのドキュメントを確認する必要があります。
ただし、私(OS X gcc 4.0.1)では、これらをldで見つけます
-dead_strip
エントリポイントまたはエクスポートされたシンボルが到達できない関数とデータを削除します。
-dead_strip_dylibs
エントリポイントまたはエクスポートされたシンボルが到達できないdylibを削除します。つまり、リンク中にシンボルを提供しなかったdylibのロードコマンドコマンドの生成を抑制します。このオプションは、dylibに重要なイニシャライザーがあるなど、何らかの間接的な理由で実行時に必要なdylibにリンクする場合は使用しないでください。
そしてこの便利なオプション
-why_live symbol_name
Symbol_nameへの一連の参照を記録します。
-dead_strip
でのみ適用可能。デッドストリップを削除する必要があると思われるものが削除されない理由をデバッグするのに役立ちます。
Gcc/g ++ manには、コンパイル時に最適化が有効になっている場合にのみ特定の種類のデッドコードの除去が実行されるという注意事項もあります。
これらのオプション/条件はコンパイラに当てはまらない場合がありますが、ドキュメントで同様のものを探すことをお勧めします。
プログラミングの習慣も役立ちます。例えば特定のファイルの外部からアクセスされない関数にstatic
を追加します。シンボルに短い名前を使用します(少し助けになるかもしれませんが、多すぎないでしょう)。可能な場合はconst char x[]
を使用します。 ... このペーパー は、動的共有オブジェクトについて説明していますが、従えば、最終バイナリ出力サイズを小さくするのに役立つ提案を含めることができます(ターゲットがELFの場合)。
答えは-flto
です。コンパイル手順とリンク手順の両方に渡す必要があります。そうしないと、何も実行されません。
それは実際に非常にうまく機能します-私が書いたマイクロコントローラープログラムのサイズを以前のサイズの50%未満に減らしました!
残念ながら、それは少しバグのように見えました-私は物事が正しく構築されていないのインスタンスを持っていました。使用しているビルドシステム(QBS、非常に新しい)が原因である可能性がありますが、いずれにしても、可能であれば最終ビルドに対してのみ有効にし、そのビルドを徹底的にテストすることをお勧めします。
厳密にはシンボルについてではありませんが、サイズを選択する場合は、常に-Os
および-s
フラグを使用してコンパイルします。 -Os
は結果のコードを最小の実行可能サイズに最適化し、-s
はシンボルテーブルと再配置情報を実行可能ファイルから削除します。
時々-小さいサイズが必要な場合-異なる最適化フラグをいじることが重要な場合とそうでない場合があります。たとえば、-ffast-math
や-fomit-frame-pointer
を切り替えると、数十バイトも節約される場合があります。
Nemoが提供する答えは正しいものであるように思えます。これらの手順が機能しない場合、問題は使用しているgcc/ldのバージョンに関連している可能性があります。演習として、詳細な手順を使用してプログラム例をコンパイルしました here
#include <stdio.h>
void deadcode() { printf("This is d dead codez\n"); }
int main(void) { printf("This is main\n"); return 0 ; }
次に、徐々に攻撃的なデッドコード削除スイッチを使用してコードをコンパイルしました。
gcc -Os test.c -o test.elf
gcc -Os -fdata-sections -ffunction-sections test.c -o test.elf -Wl,--gc-sections
gcc -Os -fdata-sections -ffunction-sections test.c -o test.elf -Wl,--gc-sections -Wl,--strip-all
これらのコンパイルおよびリンクパラメータは、それぞれサイズ8457、8164、および6160バイトの実行可能ファイルを生成しました。これは、「ストリップオール」宣言による最も大きな貢献です。プラットフォームで同様の削減を実現できない場合、gccのバージョンがこの機能をサポートしていない可能性があります。 Linux Mint 2.6.38-8-generic x86_64でgcc(4.5.2-8ubuntu4)、ld(2.21.0.20110327)を使用しています
strip --strip-unneeded
は、実行可能ファイルのシンボルテーブルでのみ動作します。実際には、実行可能なコードは削除されません。
標準ライブラリは、すべての機能を個別のオブジェクトファイルに分割し、ar
を使用して結合することで、目的の結果を達成します。次に、結果のアーカイブをライブラリとしてリンクする(つまり、オプション-l your_library
をldに与える)と、ldには、実際に使用されるオブジェクトファイル、したがってシンボルのみが含まれます。
また、この 類似した質問 の使用に対する回答のいくつかを見つけるかもしれません。
これが最近の機能であるため、これが現在の苦境に役立つかどうかはわかりませんが、グローバルな方法でシンボルの可視性を指定できます。コンパイル時に-fvisibility=hidden -fvisibility-inlines-hidden
を渡すと、リンカが後で不要なシンボルを取り除くのに役立ちます。 (共有ライブラリとは対照的に)実行可能ファイルを作成している場合、それ以上のことはありません。
詳細情報(およびライブラリなどのきめ細かなアプローチ)は、 GCC wiki で入手できます。
GCC 4.2.1マニュアルのセクション-fwhole-program
:
現在のコンパイル単位がコンパイル中のプログラム全体を表していると仮定します。
main
および属性externally_visible
によってマージされたものを除くすべてのパブリック関数および変数は、静的関数になり、プロシージャ内オプティマイザーによってより積極的に最適化されます。このオプションは、単一ファイルで構成されるプログラムに対するstatic
キーワードの適切な使用と同等ですが、オプション--combine
と組み合わせて、このフラグを使用して、関数および変数が単一のソースファイル自体ではなく、結合されたコンパイルユニット全体に対してローカルです。