Linux
GCC
ARM
QEMU
arm64

x86_64のUbuntuでC/C++のソースコードをARM/ARM64用にクロスコンパイルしてQEMUで実行する方法のまとめ

はじめに

x86_64のLinux上でQEMUを使ってarm用の実行ファイルを動かす方法は以前に書いたことがあるのですが、最近は「マルチプラットフォームのライブラリをビルドしたときにCIを回す」というユースケースが出てきたので再度まとめてみました。

題材とするソースコードはこれ。

hello.c
#include <stdio.h>

int main()
{
    printf("Hello, world!\n");
}

Ubuntu 16.04 を使用しています。

ネイティブのコンパイルと実行

$ gcc -o hello_native hello.c
$ file hello_native 
hello_native: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=ffce96d91ecac8524b1d8af9f37c9e719364df7e, not stripped
$ ./hello_native 
Hello, world!

クロスコンパイラのインストール

sudo apt install g++-arm-linux-gnueabihf

gccしか必要なくても、あえてg++をインストールするのがコツです。そうするとクロスのlibcなど必要な物が全て芋づる式にインストールされます。

クロスコンパイル

$ arm-linux-gnueabihf-gcc -o hello_arm hello.c 
$ file ./hello_arm 
./hello_arm: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, BuildID[sha1]=9719544312d6cdfb69a31ca70a4655c12e5596d8, not stripped
$ ./hello_arm
-bash: ./hello_arm: cannot execute binary file: Exec format error

そのままではx86_64のUbuntuの上ではARM用の実行ファイルは実行することができません。

QEMUのインストール

sudo apt install qemu-user-binfmt

これでスタティックリンクされたARMの実行ファイルならそのまま実行できるようになります。

$ arm-linux-gnueabihf-gcc -o hello_arm_static -static hello.c 
$ file ./hello_arm_static 
./hello_arm_static: ELF 32-bit LSB executable, ARM, EABI5 version 1 (GNU/Linux), statically linked, for GNU/Linux 3.2.0, BuildID[sha1]=72d599d8f0e385a6daa8ebe6216f8fbe8755bda2, not stripped
$ ./hello_arm_static 
Hello, world!

ダイナミックリンクされたARMの実行ファイルは以下のようにクロスのルートディレクトリをQEMUに明示的に指定すれば実行できるようになります。

$ qemu-arm -L /usr/arm-linux-gnueabihf/ ./hello_arm
Hello, world!

ダイナミックリンクされたARMの実行ファイルもそのまま実行できるようにする

sudo ln -s /usr/arm-linux-gnueabihf/lib /lib/arm-linux-gnueabihf
sudo ln -s /lib/arm-linux-gnueabihf/ld-2.23.so /lib/ld-linux-armhf.so.3
$ ./hello_arm
Hello, world!

arm64の場合

arm64のツールチェインの名前が違うだけで同様にできます。

sudo apt install g++-aarch64-linux-gnu qemu-user-binfmt
sudo ln -s /usr/aarch64-linux-gnu/lib/ /lib/aarch64-linux-gnu
sudo ln -s /lib/aarch64-linux-gnu/ld-2.23.so /lib/ld-linux-aarch64.so.1
$ aarch64-linux-gnu-gcc -o hello_arm64 hello.c
$ file ./hello_arm64 
./hello_arm64: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, BuildID[sha1]=776d40691c4192c0521c641f17b3754b37b73109, not stripped
$ ./hello_arm64 
Hello, world!

参考

QEMUのもうひとつの使い方: ユーザーモードエミュレーションとbinfmtとchrootの組み合わせ
Ubuntu 12.04LTS Beta2でMultiarchを試す
Ubuntu 12.04LTS 正式版でMultiarchを試す