12


11

私は32K以下に保ちたいARMプロセッサ上で実行するためのhexファイルを作成しています。 それは現在それよりずっと大きいです、そして、誰かがそれをスリムにするための最善のアプローチは何かについて何らかのアドバイスがあるかどうか疑問に思いましたか?

これが私がこれまでにやったことです

  1. だから私は16進数ファイルの大きさを決定するためにそれに 'サイズ’を実行します。

  2. それから、それぞれのオブジェクトファイルがHEXファイルを作成するためにリンクしているサイズを確認するために、再度「サイズ」を指定します。 サイズの大部分は外部ライブラリから来ているようです。

  3. それから私はどの関数が最もメモリを消費するかを見るために 'readelf’を使いました。

  4. これらの関数への呼び出しを排除できるかどうかを確認するためにコードを検索しました。

ここで私は動けなくなります、私が直接呼ばないいくつかの機能があります(例えば。 _vfprintf)そして、何を呼んでいるのかわからないので、その呼を削除することができます(私はそれを必要としないと思います)。

それでは、次のステップは何ですか?

回答に対する返答:

  • ご覧のとおり、大量のメモリを消費する関数が呼び出されています。 しかし、何を呼んでいるのかわかりません。

  • 可能であれば、これらの関数を省略したいのですが、それらを呼び出しているものが見つかりません。 私が推測するライブラリ関数はいくつでも呼び出すことができます。

  • リンカは望みどおりに動作していると思いますが、関連するライブラリファイルのみが含まれています。 関連する機能だけが含まれているかどうか、どうやってわかりますか? そのための旗か何かを設定できますか?

  • GCCを使用しています

8 Answer


13


一般リスト:

  • コンパイラとリンカのデバッグオプションが無効になっていることを確認してください。

  • すべてのサイズオプションをオンにしてコンパイルおよびリンクします(gccでは-O)。

  • 実行ファイルで `strip`を実行する

  • マップファイルを生成して関数のサイズを確認してください。 あなたはどちらかを得ることができます マップファイルを生成するリンカ(ldを使用する場合は -M)、または最終実行可能ファイルでobjdumpを使用できます(これはストリップされていない実行可能ファイルでのみ機能することに注意してください!)これは実際には問題を解決しませんが、最悪の犯罪者をお知らせします。

  • 「nm」を使用して、それぞれの オブジェクトファイル。 これは、あなたが呼び出されたくない関数を誰が呼び出しているのかを見つけるのに役立ちます。

元の質問では、関連する機能のみを含めることについての小質問でした。 `gcc`は使用されるすべてのオブジェクトファイル内のすべての機能を含みます。 別の言い方をすれば、10個の関数を含むオブジェクトファイルがある場合、たとえ1個の関数が実際に呼び出されても、10個の関数すべてが実行可能ファイルに含まれます。

標準ライブラリ(例: libc)は関数をたくさんの別々のオブジェクトファイルに分割し、それらはアーカイブされます。 実行ファイルはアーカイブとリンクされます。 多くのオブジェクトファイルに分割することによって、リンカは実際に呼び出される関数のみを含めることができます。 (これは静的にリンクしていることを前提としています)

あなたが同じトリックをすることができない理由はありません。 もちろん、関数が呼ばれていなければおそらく自分でそれらを削除することができると主張できます。

他のライブラリと静的にリンクしている場合は、それらの上で上記のツールを実行して、それらが類似のルールに従っていることを確認できます。


5


GCCを使用していると仮定すると、作業を節約できるもう1つの最適化は-ffunction-sections、-Wl、 - gc-sectionsです。 しかし、良いツールチェーンはそれを言われる必要はないでしょう。

説明:GNU ldはセクションをリンクします。GCCは、特に指示がない限り、翻訳単位ごとに1つのセクションを生成します。 しかしCでは、依存グラフのノードはオブジェクトと関数です。


2


将来の参照用にダブルチェックして文書化するためだけに、Thumb命令を使用しますか。 それらは通常の命令の16ビットバージョンです。 時にはあなたは2 16ビット命令を必要とするかもしれません、それでそれはコードスペースの50%を節約しないでしょう。

まともなリンカは必要な機能だけを取るべきです。 しかし、あなたはコンパイラが必要かもしれません


2


深く埋め込まれたプロジェクトでは、私は常に標準ライブラリ関数を使わないようにしています。 "strtol()"のような単純な関数でもバイナリサイズを大きくします。 可能であれば、単にそれらの呼び出しを避けてください。

最も深く埋め込まれたプロジェクトでは、多用途の "printf()"や動的なメモリ割り当ては必要ありません(多くのコントローラは32kb以下のRAMを持っています)。

単に "printf()"を使う代わりに、私は非常に単純なカスタムの "printf()"を使いますが、この関数は16進数または10進数のフォーマットでしか数字を表示できません。 ほとんどのデータ構造はコンパイル時に事前に割り当てられます。


1


わかりましたので、最後にプロジェクトを最も単純な形式に縮小し、次に削除したい関数が 'readelf’ファイルに現れるまでゆっくりとファイルを1つずつ追加しました。 それから私がファイルを持っていたとき、私はすべてをコメントアウトして、関数が再びポップアップするまでゆっくりとものを追加しなおしました。 それで、結局私はそれを呼んだものを見つけて、すべてのそれらの呼び出しを取り除きました…​今それは望み通りに働きます…​甘い!

それをするよりよい方法でなければなりません。


1


Andrew EdgeCombeはすばらしいリストを持っています、しかしあなたが本当に最後のバイトをすべて掻き出したいのであれば、http://www.muppetlabs.com/~breadbox/software/elfkickers.html[sstrip]はリストから欠けている良いツールです。そしてさらに数kBを削り取ることができます。

例えば、 `strip`自体で実行した場合、http://cksum.org/blog/284-compiling-and-using-sstrip [それは〜2kBを削り取ることができます]。

古いREADMEから(https://dev.openwrt.org/browser/trunk/tools/sstrip/src/sstrip.c [この]間接ソースファイルの先頭にあるコメントを参照してください):

_ _ sstripは、プログラムのメモリイメージの一部ではないELFファイルの末尾の内容を削除する小さなユーティリティです。

ほとんどのELF実行可能プログラムは、プログラムヘッダーテーブルとセクションヘッダーテーブルの両方で構築されています。 しかしながら、OSがプログラムをロードし、リンクしそして実行するために必要とされるのは前者だけである。 sstripはELFヘッダー、プログラムヘッダーテーブル、およびその内容を抽出しようとし、それ以外はすべてビットバケットに入れます。 保存する部分の後、ファイルの末尾にある部分のみを削除できます。 ただし、これにはほとんどの場合、セクションヘッダーテーブルと、プログラムの実行時には使用されないランダムなセクションがいくつか含まれています。 _ _

削除される情報の中には、ストリップされた実行可能ファイルがhttp://www.mail-archive.com/[email protected]/msg00657.html [問題があるとされています]ということに注意してください。 ]いくつかのツールで。 これについては、ソースのコメントで詳しく説明しています。

また… 可能な限り小さい実行可能ファイルを作成する方法についての面白くて狂った記事については、http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html [この記事]を読む価値があります。


0


この特定のニーズに答えるには:

_ •これらの関数を省略したい(可能であれば)が、それらの呼び出し元が見つからない!! 私が推測するライブラリ関数はいくつでも呼び出すことができます。 _

コードベースを分析して、誰が何を呼び出しているのか、特定の関数が呼び出されているのか、そしてそのようなことを確認したいのであれば、SciToolsが提供する「Understand C」という優れたツールがあります。

私は過去に静的コード分析を実行するためにこれを頻繁に使用しました。 それは本当にライブラリの依存関係ツリーを決定するのに役立ちます。 それは他のものの中でも特に呼び出しツリーを上下に閲覧することを可能にする。

彼らは限られた時間の評価を提供し、あなたはライセンスを購入する必要があります。


-1


あなたは executable compressionのようなものを見ることができます。