Hatena::Grouplinux2

Going My Linux Way このページをアンテナに追加 RSSフィード

2012年05月27日(日)

Ubuntu 12.04 で hello.c をARMバイナリとしてコンパイルして実行してみる

| 14:52 | Ubuntu 12.04 で hello.c をARMバイナリとしてコンパイルして実行してみる - Going My Linux Way を含むブックマーク はてなブックマーク - Ubuntu 12.04 で hello.c をARMバイナリとしてコンパイルして実行してみる - Going My Linux Way Ubuntu 12.04 で hello.c をARMバイナリとしてコンパイルして実行してみる - Going My Linux Way のブックマークコメント

こちらの記事を参考に Ubuntu 12.04 の Multiarch を試してみました。

ARM 用のバイナリビルドしてネイティブ(x86-64bit)で実行しようと思います。

以下、要点メモです。

Ubuntu 12.04 ですが上記の記事とはパスなどが若干異なりました。

インストール

ツールチェーンとエミュレータインストールします。

$ suto apt-get install g++-arm-linux-gnueabihf \
                       qemu-user               \
                       qemu-user-static

g++-arm-linux-gnueabihf の依存関係によりツールがインストールされます。

C++ が不要の場合は、gcc-arm-linux-gnueabihf でもいいと思います。

インストールされる gcc のバージョンは 4.6.3 (2012/05/14現在)です。

...abihf は Embedded-ABI Hard-Float を表します。

ARM アーキテクチャでは EABI と OABI (Old ABI) の二つがあるそうです。

Hard Float (FPU命令を使用する) に対するのは Soft Float です。

qemu-user と qemu-user-static はネイティブ上で ARM (や他の CPU アーキテクチャ)のバイナリを動かすエミュレータです。エミュレートしないならインストールする必要はありません。また、用途によってどちらか片方でも構いません。

qemu-user-static のほうは、static link したバイナリを動かすのに便利なように構成されています。特筆すべきは binfmt の設定をしてくれることです。

$ update-binfmts --display qemu-arm
qemu-arm (enabled):
     package = qemu-user-static
        type = magic
      offset = 0
       magic = \x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00
        mask = \xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff
 interpreter = /usr/bin/qemu-arm-static
    detector = 
$ cat /proc/sys/fs/binfmt_misc/qemu-arm
enabled
interpreter /usr/bin/qemu-arm-static
flags: OC
offset 0
magic 7f454c4601010100000000000000000002002800
mask ffffffffffffff00fffffffffffffffffeffffff

binfmt は Linuxバイナリのロード/実行の方法(インタプリタの選択)を指定できる仕組みです。マジックナンバーで識別/特定されたバイナリは指定のインタプリタで実行されます。

これは、実行可能ファイルの先頭2バイトが '#!' の場合に先頭行に記述されたインタプリタに実行が任される、shebang の仕組みに似ています。

ちなみに、qemu-user-static が設定する binfmt は ARM 以外もいっぱいあります。

$ ls /proc/sys/fs/binfmt_misc/
jar         qemu-armeb       qemu-mipsel      qemu-sh4eb        status
python2.7   qemu-cris        qemu-ppc         qemu-sparc
python3.2   qemu-m68k        qemu-ppc64       qemu-sparc32plus
qemu-alpha  qemu-microblaze  qemu-ppc64abi32  qemu-sparc64
qemu-arm    qemu-mips        qemu-sh4         register

hello.c のコンパイル(static link)

$ hello-c >hello.c
$ CC=arm-linux-gnueabihf-gcc
$ CFLAGS=-static make hello

$ ./hello            # binfmt の設定により、そのまま実行可能
hello, world
$ qemu-arm ./hello  # エミュレータを指定して実行
hello, world
$ qemu-arm-static ./hello  # エミュレータ(static版)を指定して実行
hello, world

hello-c は hello.c を出力する bash 関数 - lnzntのプログラミング日記 - プログラマの秘密のあれこれ で書いた hello.c を出力する bash関数です。

hello.c のコンパイル(dynamic link)

$ hello-c >hello.c
$ CC=arm-linux-gnueabihf-gcc
$ make hello

$ qemu-arm -L /usr/arm-linux-gnueabihf ./hello  # 実行
hello, world

実行する場合は、通常版のエミュレータ(qemu-arm)に -L オプションとしてインタプリタのパスの prefix を指定する必要があります。

chroot、jail、あるいは仮想環境化などで ARM バイナリが動く環境などを作ってやればいいと思うんですが、とりあえず以下のような対処でそのまま実行が可能です。

# ローダと共有ライブラリのディレクトリのシンボリックリンクを /lib に作る
$ cd /lib/
$ sudo ln -s /usr/arm-linux-gnueabihf/lib/ld-linux-armhf.so.3 .
$ sudo ln -s /usr/arm-linux-gnueabihf/lib arm-linux-gnueabihf

$ ./hello           # そのまま実行可能
hello, world
$ qemu-arm ./hello  # エミュレータを指定して実行
hello, world
$ qemu-arm-static ./hello  # エミュレータ(static版)を指定して実行
hello, world

(2013.11.30 追記)

hard float でない版の場合は、上記のシンボリックリンクを作る作業を以下のようにする。

$ cd /lib/
$ sudo ln -s /usr/arm-linux/gnueabi/lib/ld-linux.so.3 ld-linux-arm.so.3
$ sudo ln -s /usr/arm-linux/gnueabi/lib arm-linux-gnueabi