2010年04月26日

GCCでリンク時に不要なコードとデータを削除する方法

これもまた、ELC(Embedded Linux Conference)でのセッションの紹介です。

ELCのスライドのページのDenys Vlasenkoさんの"Link time dead code and data elimination using GNU toolchain"を見てください。



組み込みシステムではやはりコードやデータのサイズの削減が必要になる場面がしばしばあります。これを毎回手作業でやるのではscaleしません。このセッションではGNU Tool chainでこれを行う方法を紹介しています。

必要なバージョンはgcc 4.x 以上、binutils 2.18以上。

gcc 4.5から入ったlto(link time optimization)はこのセッションの話とは別です。

通常はリンクするときにコードは全て.text セクションに集められてリンクされます。リンカではセクションは一塊で扱うので、実際に使用していない関数があってもそれを取り除くことはできません。

しかし、コンパイル時に以下のようなオプションをつけると、関数やデータはそれぞれ別々のセクションに置かれるようになります。

gcc -ffunction-sections -fdata-sections

そして、リンク時に以下のオプションをつけます。

ld --gc-sections

ld直接でなく、gcc経由でldを呼び出すときには以下のようなオプションをつけます。

gcc -Wl,--gc-sections

このようにすると、リンカはガベージコレクタのような動作でどこからも参照されていないセクションを削除します。

ただし、落とし穴もあって"Magic section"という特殊なデータの持ち方をしていると、必要なデータまで削除してしまい、正常動作しないことがあるそうです。glibcをスタティックリンクするときにこれが発生するそうです。ダイナミックリンクならば大丈夫。具体例がスライドで紹介されています。

LinuxカーネルでもこのMagic sectionがあるそうです。この問題の回避方法はlinker scriptの中でKEEP命令を使って明示的にこのセクションを削除するなと指示することだそうです。

例えば、.smp_locks というセクションが削除されるのを防ぐためには

.text: { *(.text) *(.text.*) *(.smp_locks) }

これのlinker scriptに以下のようにKEEP命令を追加します。

.text: { *(.text) *(.text.*) KEEP(*(.smp_locks)) }

これでどれだけ小さくなるかはもちろんプログラムによりますが、1〜8%削減された例がスライドで紹介されています。

追記 (2013.8.28)

ROM化するプログラムの場合はベクターテーブルは当然KEEPをつける必要があります。

また、どのセクションが削除されたかはマップファイルで確認できます。

マップファイルを出力するにはリンク時に -Wl,-Mapオプションをつけます。

gcc ... -Wl,-Map=filename.map


トラックバックURL

コメント一覧

1. Posted by hik   2010年04月26日 20:40
ちなみに、arm の rvct は default で削除するようになっていますね。
2. Posted by koba   2010年04月27日 20:11
hikさん、コメントありがとうございます。
サイズ削減は組み込みシステム開発では常につきまといますよね。私はgcc 4.5で入ったltoとの組み合わせでさらなる効果を期待しています。
3. Posted by hik   2010年05月04日 22:08
いいえ、こちらこそ、
さらに我田引水ですが、arm では c99 の構文も
一部導入されているようです。gcc の最新でも入ってきているかと思いますが、

cx++ だけだったかもしれませんが、restrict という keyword の導入に
期待しています。さらなる最適化余地が生まれることを、

コメントする

名前
 
  絵文字
 
 
記事検索
最新コメント
アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

QRコード
QRコード