Ubuntu 14.04でarm 64bit(aarch64)のコードをコンパイルして動かしてみる

先日リリースされたqemu 2.0でaarch64がサポートされました。これをソースからビルドして試そうと思ったのですが、実はUbuntu 14.04ではすでにqemu 2.0が入っていました。なので、以下のように簡単にセットアップできます。

$ sudo apt-get install qemu-user-static
$ sudo apt-get install g++-aarch64-linux-gnu

 テストプログラム

$ cat a.c
#include 

int main()
{
	int i;
	
	for (i = 5; i >=0; i--) {
		printf("count down: %d\n", i);
	}	
	return 0;
}

まずはこれを普通のnativeのgccでビルドして動かしてみます。

$ gcc a.c
$ file a.out
a.out: ELF 64-bit LSB  executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=34c5e280db12d36ed6cd54264843f8bc3ad95f9e, not stripped
$ ./a.out 
count down: 5
count down: 4
count down: 3
count down: 2
count down: 1
count down: 0

aarch64 static link

qemu-user-staticをインストールしたときにbinfmtの設定も行われているので、aarch64のELFオブジェクトを実行しようとすると自動的にqemu-aarch64-user-staticを経由して実行されるようになっています。

$ aarch64-linux-gnu-gcc -static a.c
$ file a.out
a.out: ELF 64-bit LSB  executable, ARM aarch64, version 1 (SYSV), statically linked, for GNU/Linux 3.7.0, BuildID[sha1]=ed63c597eb6c059a968c91ef21ba4e132376fd32, not stripped
$ ./a.out
count down: 5
count down: 4
count down: 3
count down: 2
count down: 1
count down: 0

このようにstatic linkされたaarch64の実行ファイルは問題なく実行することができました。

aarch64 dynamic link

次は普通にダイナミックリンクした場合を試してみます。

$ aarch64-linux-gnu-gcc a.c
$ file a.out
a.out: ELF 64-bit LSB  executable, ARM aarch64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 3.7.0, BuildID[sha1]=8e0f52789566a1c1535495dd4a01805bf3034ed3, not stripped
$ ./a.out
/lib/ld-linux-aarch64.so.1: No such file or directory

/lib/ld-linux-aarch64.so.1が無いと言われました。このファイルは/usr/aarch64-linux-gnu/にあるので、環境変数QEMU_LD_PREFIXでqemuにそれを伝えることにします。

$ export QEMU_LD_PREFIX=/usr/aarch64-linux-gnu/
$ ./a.out
count down: 5
count down: 4
count down: 3
count down: 2
count down: 1
count down: 0

これでdynamic linkでも動作するようになりました。

clangでaarch64をクロスビルド

clang/llvmも以下のように簡単にインストールできます。

$ sudo apt-get install clang

これで、さきほどと同じa.cをaarch64向けにクロスビルドしてみます。

$ clang --target=aarch64-linux-gnu a.c
In file included from a.c:1:
In file included from /usr/include/stdio.h:27:
/usr/include/features.h:374:12: fatal error: 'sys/cdefs.h' file not found
#  include 
           ^
1 error generated.

このようにsys/cdefs.hが見つからないというエラーになってしまいました。
このファイルは/usr/aarch64-linux-gnu/includeにあるので-Iオプションでヘッダファイルの検索パスに追加します。

$ clang --target=aarch64-linux-gnu -I/usr/aarch64-linux-gnu/include a.c
$ file a.out
a.out: ELF 64-bit LSB  executable, ARM aarch64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 3.7.0, BuildID[sha1]=358fac21a5776ec914d6abfbd67fc2958415261a, not stripped
koba@ubuntu1404server:~/aarch64$ ./a.out
count down: 5
count down: 4
count down: 3
count down: 2
count down: 1
count down: 0

これでclang/llvmでビルドしたaarch64の実行オブジェクトも動作することが確認できました。