qemu-system-i386向けにbuildrootをビルドする

buildrootは組込み向けのLinuxを作成できるビルドシステムである。オープン ソースのビルドシステムは各種あるが、最も手軽に触れることができるものの ひとつである。今回はqemu-systemu-i386で利用する手順を記載する。また、 busyboxのinitをGDBでデバッグする。

 

1. メリット

1.1. 小サイズ

Ubuntu等のLinuxディストリビューションは最小構成でインストールしても数 GByteのルートファイルシステムとなるが、buildrootの場合は数MByteのルー トファイルシステムを作成できる。メインのパッケージとしてbusyboxと uClibcが使われている。以下はbuildrootでデフォルトで用意されている設定 のqemu_x86_defconfigを用いて作成した場合のサイズである。

-rw-rw-r-- 1 <me> <me> 2.0M  1月 16 19:05 bzImage
-rw-rw-r-- 1 <me> <me> 2.4M  1月 16 19:05 rootfs.ext2

1.2. 幅広い対応アーキテクチャ

x86向けのみではなく、ARM等の各種CPU向けのバイナリを作成できる。

2. ダウンロード

安定板は以下から取得できる。

http://buildroot.uclibc.org/downloads/buildroot-2013.11.tar.gz

リポジトリは以下。

git clone git://git.buildroot.net/buildroot

3. 構成

自分が把握している構成は以下の通り。

3.1. dlディレクトリ

buildrootはmakeを実行する段階でパッケージのアーカイブを開発元サイトか らダウンロードする仕組みになっており、そのアーカイブが本ディレクトリに 格納される。make distcleanを実行するとdlディレクトリまで削除されてしま うので、パッケージの再ビルドを実行したい場合はmake cleanを使用した方が 良い。make cleanはoutputディレクトリを削除するに留まる為である。

3.2. outputディレクトリ

output/imagesにルートファイルシステムとカーネルのイメージが作成される。 output/targetはoutput/images/root.ext2とは別であるらしい。起動用のルー トファイルシステムとしてoutput/targetを使用すると上手く起動しない場合 がある。output/buildディレクトリにルートファイルシステムに格納されるパッ ケージとそのパッケージのビルドに必要なパッケージが置かれてビルドされる。

3.3. packageディレクトリ

各種パッケージのパッチとコンフィグが置かれている。uClibc-0.9.33.2のコ ンフィグを変えたい場合はpackage/uclibc/uClibc-0.9.33.configに反映させ、 パッチを当てたい場合はpackage/uclibc/0.9.33.2/に置けば良い。

3.4. boardディレクトリ

カーネルのコンフィグが置かれている。カーネルコンフィグを変え、それを恒 久的に反映させたい場合はboardディレクトリ配下に反映させる必要がある。

4. 設定

4.1 buildrootの設定
configsディレクトリ配下にqemu_x86_defconfigがあるので利用する。

$ make qemu_x86_defconfig
$ make menuconfig

GCCのバージョンを4.6.xにする。4.4. GCCのバージョンを4.6.xにする理由を 参照。

Symbol: BR2_GCC_VERSION_4_6_X [=y]
Type  : boolean
Prompt: gcc 4.6.x
  Location:
    -> Toolchain
      -> GCC compiler Version (<choice> [=y])
  Defined at package/gcc/Config.in.host:41
  Depends on: <choice> && !BR2_microblaze [=n] && !BR2_arc [=n] &&
  !BR2_avr32 [=n] && !BR2_bfin [=n] && !BR2_cortex_a7 [=n] &&
  BR2_sparc_sparchfleon [=n] && !BR2_sparc_sparchfleonv8 [=n] &&
  !BR2_sparc_sparcsfleon [=n] && !BR2_sparc_sparcsfleonv8 [=n] &&
  BR2_pj4 [=n]
  Selects: BR2_GCC_NEEDS_MPC [=y]

QEMUで-nographicオプションを利用する為、コンソールをtty1からttyS0にす る。-nographicを使用せず、GUIウィンドウを利用する場合はtty1で良い。

Symbol: BR2_TARGET_GENERIC_GETTY_PORT [=ttyS0]
Type  : string
Prompt: TTY port
  Location:
    -> System configuration
      -> Run a getty (login prompt) after boot (BR2_TARGET_GENERIC_GETTY [=y])
        -> getty options
  Defined at system/Config.in:217
  Depends on: BR2_ROOTFS_SKELETON_DEFAULT [=y] && BR2_TARGET_GENERIC_GETTY [=y] 

4.2. busyboxの設定

busyboxの設定を変える場合は以下を使用。

make busybox-menuconfig

デバッグシンボルを有効にする。

Symbol: DEBUG [=y]
Prompt: Build BusyBox with extra Debugging symbols
  Defined at Config.in:652
  Location:
    -> Busybox Settings
      -> Debugging Options  

最適化を無効にする。なくても良いだろうけど、ステップ実行が飛び飛びにな るのが嫌なので。

Symbol: DEBUG_PESSIMIZE [=y]
Prompt: Disable compiler optimizations
  Defined at Config.in:663
  Depends on: DEBUG
  Location:
    -> Busybox Settings
      -> Debugging Options
        -> Build BusyBox with extra Debugging symbols (DEBUG [=y])

4.3. その他の設定

uClibcの設定を変える場合は以下を使用。

$ make uclibc-menuconfig

Linuxカーネルの設定を変える場合は以下を使用。

$ make linux-menuconfig

4.4. GCCのバージョンを4.6.xにする理由

GCC-4.7.x以降でuClibcをビルドするとundefined referenceな関数がいくつか 存在し、stripコマンドを用いない場合にエラーとなってしまう。buildrootで はuClibcの修正待ちというステータスである。

http://buildroot-busybox.2317881.n4.nabble.com/ucilbc-0-9-33-2-fails-to-build-on-buildroot-2013-11-internal-toolchain-td56650.html

uClibcのパッチを持ってくるこ とでx86では問題が解消されるが、ARMでは完全に解消されないようである。 本書ではこの問題を避ける為に4.6.xを使用している。

commit 8d31a6e50db423b89082b64a3250eec1b94a7456
Author: Bernhard Reutner-Fischer <...>
Date:   Wed Jan 16 13:36:40 2013 +0100
 
    buildsys: link libgcc_eh if DODEBUG
    
    with -O0 we (e.g. lockf) might end up with references to
    _Unwind_Resume, so pull in gcc_eh in this case..
    
    Signed-off-by: Bernhard Reutner-Fischer <...>

5. ビルド

$ make

パッケージをビルドし直すには<package name>-rebuildを実行する。busybox の場合は以下となる。

$ make busybox-rebuild

6. 実行例

output/images/rootfs.ext2にルートファイルシステムのイメージが作成され る。GDBから参照できるようにループバックでバイスとしてマウントする。

$ mkdir mnt
$ sudo mount -t ext2 -o loop,rw output/images/rootfs.ext2 mnt/

QEMUを以下の設定で起動する。-hdaオプションで指定したルートファイルシス テムのイメージはパーティションを設定していないのでroot=/dev/sdaでマウ ント先を指定している。

$ qemu-system-i386 --kernel output/images/bzImage \
                   -hda output/images/rootfs.ext2 \
                   -gdb tcp::10000 -S \
                   -nographic \
                   -append "console=ttyS0,115200 root=/dev/sda rw"

GDBを以下の設定で起動する。

$ cat gdb.scr 
target remote localhost:10000
symbol-file output/build/busybox-1.22.0/busybox
source output/build/busybox-1.22.0
b main
la src
c
$ gdb -x gdb.scr

以下はbusyboxへのシンボリックリンクの/sbin/initからbusyboxが呼び出され、 busyboxのmain関数でbreakした所である。busyboxは複数のコマンド群から形 成されており、シンボリックリンク経由あるいは第一引数にコマンド名を指定 して各コマンドを実行する。