質問

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

これまでにやったことは

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

ここで行き詰まります。直接呼び出さない関数(_vfprintfなど)があり、呼び出し元を見つけることができないため、呼び出しを削除できます(必要ないと思います)。

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

回答への応答:

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

解決

一般リスト:

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

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

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

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

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

他のヒント

作業を節約する可能性のある別の最適化は、GCCを使用していると仮定した場合の-ffunction-sections、-Wl、-gc-sectionsです。ただし、優れたツールチェーンにそのことを伝える必要はありません。

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

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

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

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

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

" printf()"を使用する代わりに私は非常にシンプルなカスタム" printf()"を使用しますが、この関数は16進数または10進数形式でしか数字を印刷できません。ほとんどのデータ構造は、コンパイル時に事前に割り当てられます。

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

それを行うには、より良い方法でなければなりません。

Andrew EdgeCombeには素晴らしいリストがありますが、本当に最後の1バイトすべてを削りたい場合は、 sstrip はリストにない優れたツールであり、さらにkBを削減できます。

たとえば、 strip 自体で実行する場合、 〜2kBを削ることができます。

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

  

sstripは、ファイルの最後にあるコンテンツを削除する小さなユーティリティです。   プログラムのメモリイメージの一部ではないELFファイル。

     

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

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

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

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

  

•これらの機能を省略したい(可能であれば)が、何が見つかるかわからない   それらを呼び出す!!任意の数のライブラリ関数から呼び出すことができます   推測。

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

https://scitools.com/

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

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

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top