17

ARM プロセッサで実行する 16 進ファイルを作成していますが、これを 32K 未満に抑えたいと考えています。現在、それよりもはるかに大きく、スリム化するための最善の方法について誰かがアドバイスをしてくれるのではないかと思いましたか?

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

  1. そこで、16 進ファイルの大きさを判断するために「サイズ」を実行しました。
  2. 次に、再度「サイズ」を指定して、16 進ファイルを作成するためのリンクである各オブジェクト ファイルの大きさを確認します。サイズの大部分は外部ライブラリに由来するようです。
  3. 次に、「readelf」を使用して、どの関数が最もメモリを消費しているかを確認しました。
  4. コードを検索して、これらの関数の呼び出しを削除できるかどうかを確認しました。

ここで行き詰まります。直接呼び出さない関数 (_vfprintf など) がいくつかあり、それを呼び出すものが見つからないため、呼び出しを削除できます (必要ないと思うため)。

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

回答への対応:

  • ご覧のとおり、多くのメモリを消費する関数が呼び出されています。しかし、それを呼んでいるものを見つけることができません。
  • これらの関数を (可能であれば) 省略したいのですが、それらを呼び出しているものが見つかりません! 私が推測する任意の数のライブラリ関数から呼び出すことができます。
  • リンカーは希望どおりに機能しています。関連するライブラリ ファイルのみが含まれていると思います。関連する機能だけが含まれているかどうかは、どうすればわかりますか? そのためにフラグか何かを設定できますか?
  • 私はGCCを使用しています
4

8 に答える 8

17

一般的なリスト:

  • コンパイラとリンカーのデバッグ オプションが無効になっていることを確認します。
  • すべてのサイズ オプションをオンにしてコンパイルおよびリンクします (gcc では -Os)。
  • 実行strip可能ファイルで実行
  • マップ ファイルを生成し、関数のサイズを確認します。リンカにマップ ファイルを生成させるか ( -Mld を使用する場合)、最終的な実行可能ファイルで objdump を使用することができます (これはストリップされていない実行可能ファイルでのみ機能することに注意してください!) これは実際には問題を解決しませんが、最悪の犯罪者を知らせます。
  • nm各オブジェクト ファイルから呼び出されるシンボルを調査するために使用します。これは、呼び出されたくない関数を誰が呼び出しているかを見つけるのに役立ちます。

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

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

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

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

于 2008-10-14T10:04:58.977 に答える
5

作業を節約できるもう 1 つの最適化は、GCC を使用していると仮定して、-ffunction-sections、-Wl、--gc-sections です。ただし、優れたツールチェーンには、そのように伝える必要はありません。

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

于 2008-10-14T11:24:58.863 に答える
3

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

最も深く組み込まれたプロジェクトでは、多目的な「printf()」や動的メモリ割り当ては必要ありません (多くのコントローラの RAM は 32kb 以下です)。

「printf()」を使用する代わりに、非常に単純なカスタム「printf()」を使用します。この関数は、16 進数または 10 進数形式でのみ数値を出力できます。ほとんどのデータ構造は、コンパイル時に事前に割り当てられます。

于 2008-12-09T20:19:17.310 に答える
2

将来の参照用に再確認して文書化するだけですが、Thumb 命令を使用していますか? これらは、通常の命令の 16 ビット バージョンです。場合によっては、2 つの 16 ビット命令が必要になることがあるため、コード スペースを 50% 節約することはできません。

適切なリンカーは、必要な機能だけを使用する必要があります。ただし、個々のリンク用に関数をパッケージ化するには、コンパイラとリンクの設定が必要になる場合があります。

于 2008-10-14T08:15:58.013 に答える
1

Andrew EdgeCombe には優れたリストがありますが、本当に最後のバイトをすべてスクレイピングしたい場合は、sstripがリストにない優れたツールであり、さらに数 kB を削ることができます。

たとえば、stripそれ自体で実行すると、最大 2kB 削減できます。

古い README から (この間接ソース ファイルの上部にあるコメントを参照してください):

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

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

いくつかの情報が削除されるため、sstrip された実行可能ファイルにはいくつかのツールで問題があると噂されていることに注意してください。これについては、ソースのコメントで詳しく説明されています。

また...可能な限り最小の実行可能ファイルを作成する方法についての面白い/クレイジーな読み物については、この記事を読む価値があります。

于 2012-04-26T19:37:16.507 に答える
1

最後に、プロジェクトを最も単純な形式に縮小し、削除したい関数が「readelf」ファイルに表示されるまで、ファイルを 1 つずつゆっくりと追加しました。次に、ファイルを取得したら、すべてをコメントアウトし、関数が再びポップアップするまで、ゆっくりと元に戻しました。結局、私はそれを呼び出したものを見つけて、それらの呼び出しをすべて削除しました...今では希望どおりに機能します...甘いです!

しかし、それを行うためのより良い方法でなければなりません。

于 2008-10-14T09:37:25.413 に答える
0

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

•それらの関数を (できれば) 省略したいのですが、呼び出し元がわかりません!! 私が推測する任意の数のライブラリ関数から呼び出すことができます。

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

https://scitools.com/

私は過去に静的コード分析を実行するために非常に頻繁に使用しました。ライブラリの依存関係ツリーを決定するのに非常に役立ちます。とりわけ、呼び出しツリーを上下に簡単にブラウズできます。

期間限定の評価版が提供されるため、ライセンスを購入する必要があります。

于 2015-07-24T13:21:54.193 に答える
-1

実行可能な圧縮のようなものを見ることができます。

于 2008-10-14T08:02:39.553 に答える