test.c:
int main()
{
return 0;
}
私はフラグを使用していません(私はgccの初心者です)、コマンドだけです:
gcc test.c
私はwin32でGCCの最新のTDMビルドを使用しました。結果の実行可能ファイルはほぼ23KBで、空のプログラムには大きすぎます。
実行可能ファイルのサイズを減らすにはどうすればよいですか?
その提案に従わないでください、しかし娯楽のために、可能な限り最小のELFバイナリを作ることについてのこの「物語」を読んでください。
サイズを小さくするにはどうすればよいですか?
デフォルトでは、実行可能ファイルにリンクされているいくつかの標準ライブラリ(Cランタイムなど)。詳細については、キー--nostdlib --nostartfiles --nodefaultlib
を確認してください。ここで説明するリンクオプション。
実際のプログラムの場合、2番目のオプションは、-Os(サイズを最適化)などの最適化オプションを試すことです。
あきらめる。 x86 Linuxでは、gcc4.3.2は5Kバイナリを生成します。ちょっと待って!それはダイナミックリンクです!静的にリンクされたバイナリは、半分以上のメガです:516K。リラックスして、膨満感と一緒に暮らすことを学びます。
そして彼らは、Modula-3は200K hello worldバイナリのためにどこにも行かないだろうと言いました!
何が起こっているのか不思議に思うかもしれませんが、Gnu Cライブラリは、プログラムがそれらに依存しているかどうかに関係なく、特定の機能を含むように構成されています。これらの機能には、mallocやfree、dlopen、文字列処理などの雑学クイズや、ロケールや国際化に関係していると思われる大量のコンテンツが含まれますが、関連するマニュアルページは見つかりません。
最小限のサービスを必要とするプログラム用に小さな実行可能ファイルを作成することは、glibcの設計目標ではありません。公平を期すために、これまでに使用したすべてのランタイムシステム(約5ダース)の設計目標でもありませんでした。
実際、コードが何もしない場合でも、コンパイラーが実行可能ファイルを作成するのは公平ですか?;-)
ええと、Windowsでは、実行可能ファイルのサイズはかなり小さいかもしれませんが、それでもサイズはあります。古いMS-DOSシステムでは、完全な何もしないアプリケーションはほんの数バイトになります。(プログラムを閉じるために21h割り込みを使用するのに4バイトだと思います。)次に、これらのアプリケーションはメモリに直接ロードされました。EXE形式が普及すると、状況は少し変わりました。これで、実行可能ファイルには、コードとデータセグメントの再配置に加えて、いくつかのチェックサムとバージョン情報など、プロセス自体に関する追加情報が含まれていました。Windowsの導入により、フォーマットに別のヘッダーが追加され、Windowsで実行する必要があるため、実行可能ファイルを実行できなかったことをMS-DOSに通知しました。そして、Windowsは問題なくそれを認識します。もちろん、実行可能形式もビットマップなどのリソース情報で拡張されました。
何もしない実行可能ファイルのサイズは、コンパイラーとそのサイズを縮小するために使用したすべてのメソッドに応じて、現在4〜8キロバイトになります。これは、UPXが実際に実行可能ファイルを大きくするサイズになります。コードに特定のライブラリを追加したため、実行可能ファイルに追加のバイトが追加される場合があります。特に、初期化されたデータまたはリソースを備えたライブラリは、かなりの量のバイトを追加します。デバッグ情報を追加すると、実行可能ファイルのサイズも大きくなります。
しかし、これはすべてサイズを縮小する上で優れた演習になりますが、アプリケーションの肥大化について心配し続けることが実際的かどうか疑問に思うかもしれません。最新のハードディスクはファイルをセグメントに分割し、非常に大きなディスクの場合、その差は非常に小さくなります。ただし、これらの最適化に慣れている専門の開発者でない限り、サイズをできるだけ小さく保つために必要な問題の量は、開発速度を遅くします。これらの種類の最適化はパフォーマンスを向上させる傾向がなく、ほとんどのシステムの平均ディスク容量を考慮すると、なぜそれが実用的であるかわかりません。(それでも、私は同様の方法で自分のコードを最適化しますが、それでも、これらの最適化の経験があります。)
DJGPPFAQが何年も前にこれに対処した方法が好きです。
一般に、「Hello」プログラムのサイズを見てコードサイズを判断することは、そのようなプログラムがほとんどスタートアップコードで構成されているため、意味がありません。...これらすべての機能の能力のほとんどは、「Hello」プログラムで無駄になります。15バイトの文字列を出力して終了するためだけに、そのすべてのコードを実行しても意味がありません。
この演習の目的は何ですか?
Cのように低レベルの言語であっても、mainを呼び出す前に行わなければならないセットアップはまだたくさんあります。そのセットアップの一部はローダー(特定の情報を必要とする)によって処理され、一部はmainを呼び出すコードによって処理されます。そして、通常のプログラムに必要なライブラリコードが少しあるでしょう。少なくとも、dllにある場合は、おそらく標準ライブラリへの参照があります。
空のプログラムのバイナリサイズを調べること自体は、価値のない演習です。それはあなたに何も教えてくれません。コードサイズについて何かを学びたい場合は、空でない(できれば自明でない)プログラムを書いてみてください。標準ライブラリを使用するプログラムと、すべてを自分で実行するプログラムを比較します。
そのバイナリで何が起こっているのか(そしてなぜそれがとても大きいのか)を本当に知りたい場合は、実行可能形式を見つけてバイナリダンプツールを入手し、それを分解してください。
' size a.out
'は、コード、データ、およびbssセグメントのサイズについて何を教えてくれますか?コードの大部分は、o / sによって呼び出され、呼び出す前に(コマンドライン引数をargc、argvにソートするなどの)作業をセットアップするスタートアップコード(通常crt0.o
はUnixマシン上)である可能性がありmain()
ます。
シンボルを取り除くためにバイナリでstripを実行します。gccバージョン3.4.4(cygming special)では、10kから4Kにドロップします。
カスタムランタイム(mainを呼び出す部分)をリンクして、ランタイム環境をセットアップしてみてください。すべてのプログラムは同じものを使用してgccに付属するランタイム環境をセットアップしますが、実行可能ファイルにはデータやゼロ化されたメモリは必要ありません。つまり、memset / memcpyなどの未使用のライブラリ関数を取り除き、CRT0のサイズを小さくすることができます。この情報を探すときは、組み込み環境のGCCを見てください。一般に、カスタムランタイム環境を使用するのは組み込み開発者だけです。
残りは、実行可能ファイルをロードするOSのオーバーヘッドです。手で調整しない限り、そこにはあまり行きませんか?
GCCを使用して、他の最適化フラグ(または)-Os
の1つではなく、を使用してプログラムをコンパイルします。これは、速度ではなくサイズを最適化するように指示します。ちなみに、重要なセグメントがうまく適合している場合は、速度の最適化よりもプログラムの実行速度が速くなることがあります。一方、実際にはコードサイズの増加を引き起こす可能性があります。-O2
-O3
-O3
また、最終的なバイナリから未使用のコードを除外するように指示するリンカーフラグがいくつかある場合もあります。