2017年6月12日月曜日

OS@小さいELFファイルを作ってみる。

■はじめに

私の自作カーネル(Qiitaの紹介記事参照。http://qiita.com/master_mochi/items/431b3b11410a0eed8f4e)にELFローダを実装したのですが、ELFローダをお試しするにはELFファイルを外部記憶装置からメモリに配置しておく必要があります。
ELFファイルを読み込むには、ブートローダにちょっとしたファイルシステムの機能を入れたり、ブートローダからカーネルへ配置情報を渡す機能を入れたりと、たいぶ先が長い道のりとなります。

でも、それはめんどくさいし、もっと手っ取り早く試したい。

というわけで、小っちゃいELFファイルを作って、カーネルに変数として埋め込んでしまおうと企んだわけです。

■コードを用意する

ELFローダを試すといっても、ちゃんとロードされる事だけじゃなくちゃんとプログラムが動く事までを試したいので、無駄に数をカウントアップして画面に表示するプログラムを作って、これをELFファイルにします。

あと、リンカスクリプトも用意しときます。

■単純にコンパイルしてみる

とりあえず、そのままコンパイルしてみます。
サイズを見てみると、
5.2KB!でかい。

■頑張って小さくしてみる

とりあえず、下記コマンドでコンパイルしてみました。サイズ優先の最適化を行うオプション-Osは、悪さしたら嫌なので今回は使いません。
0.6KBくらい減った!
オプション-staticは、共有 ライブラリとのリンクを抑制する様です。がよくわかりません。readelfで確認すると、セクション名.eh_frame_hdrが消えて、セグメント名GNU_EH_FRAMEが消えました。
オプション-fno-identは、#identディレクティブを無視する様です。がよくわかりません。readelfで確認すると、セクション名.commentが消えてました。
オプション-Wl,-sは全てのシンボル情報を削除します。
オプション-Wl,--build-id=noneは、.note.gnu.build-idセクションを削除。ビルドIDはビルドした時に付けられる固有識別番号で、gdbとかで使われたりするのかな?

とはいえ、まだ4.6KB…
readelfで確認してみます。
セクション名.eh_frameは、デバッグ用なのでいりません。オプション-fno-asynchronous-unwind-tablesで消せるようです。
もう一度、readelf。
ん~。セクション名.textがファイルオフセット0x1000から配置されてしまっている為、ELFファイルが4KBを超えてしまっている様です。
これはLDコマンドオプションの--nmagicで詰めれるようです。
もう一度、readelf。
564byteになりました!
GNU_STACKセグメントがいらないけど、まぁいいでしょう。