Binary Translation型のエミュレータを作っている。今のところRISC-Vのバイナリをx86に直接バイナリ変換して実行することができるようになった。riscv-tests
の一部を実行してx86上でPassできるようになっている。
QEMUはもともとマルチプラットフォーム向けのDynamic Binary Translationエミュレータだ。エミュレーション元のターゲットはx86やRISC-Vのみならず、AArch64やMIPSなどにも対応しており、さらにホストマシンの機械語としてもx86だけでなくAArch64、MIPS、RISC-Vなどにも対応している。
ターゲットマシン(つまりゲストコード)は以下のアーキテクチャに対応している。
$ ls qemu/target
alpha cris i386 m68k mips nios2 ppc rx sh4 tilegx unicore32
arm hppa lm32 microblaze moxie openrisc riscv s390x sparc tricore xtensa
一方でホストマシン(つまりホストコード)は以下のアーキテクチャに対応している。
$ ls qemu/tcg
aarch64 arm i386 mips ppc riscv s390 sparc
自作エミュレータも同様に対応させたい。このためには、TCGの変換コードを拡張しなければならない。
RustのバイナリをAArch64向けにコンパイルする確認
Rustのビルド環境Cargoはマルチプラットフォームに対応しているようだった。AArch64向けにコンパイルするためには以下のようにビルドする。
$ rustup target add aarch64-unknown-linux-gnu
aarch64-unknown-linux-gnu
で使用するコンパイラを指定する。私はUbuntu 18.04を使用しているので、以下のパッケージをインストールした。
$ sudo apt install gcc-aarch64-linux-gnu
Rustにaarch64-linux-gnu-gcc
を使ってもらうために、~/.cargo/config
に以下を追加した。
[target.aarch64-unknown-linux-gnu] linker = "aarch64-linux-gnu-gcc"
これで自作エミュレータをビルドしてみる。x86の命令をDynamic Binary Translationで生成しているので実行できないのは当然だが、とりあえずビルドだけでも確認してみよう。
$ cargo build --target=aarch64-unknown-linux-gnu
生成されたバイナリを確認する。
$ file target/aarch64-unknown-linux-gnu/debug/uint_execute
target/aarch64-unknown-linux-gnu/debug/uint_execute: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, BuildID[sha1]=389de77b0ea4c87695c438c9c2d728e8a78006cc, with debug_info, not stripped
RustのバイナリをAArch64向けのQEMUで実行する確認
一応AArch64向けにバイナリを作成したので、これを動かしてみたい。Raspberry-Piとかを使えば良いのだが、いちいちバイナリをコピーしたりするのが面倒くさいので、AArch64向けに用意したQEMUを使って確認してみよう。
$ qemu-aarch64 target/aarch64-unknown-linux-gnu/debug/uint_execute riscv-tests/isa/rv64ui-p-slt
000000c0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000000d0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000000e0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000000f0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 reflect tb address = 0x5501b92000 qemu: uncaught target signal 4 (Illegal instruction) - core dumped
Illegal Instructionで落ちた。当たり前だ。一応ディスアセンブル結果も見て確認してみよう。
$ qemu-aarch64 -d in_asm target/aarch64-unknown-linux-gnu/debug/uint_execute riscv-tests/isa/rv64ui-p-slt
IN: _ZN12uint_execute7emu_env6EmuEnv3run17h5bf52c09850d1d5aE 0x550000d014: f946efe1 ldr x1, [sp, #0xdd8] 0x550000d018: f94057e0 ldr x0, [sp, #0xa8] 0x550000d01c: f94023e8 ldr x8, [sp, #0x40] 0x550000d020: d63f0100 blr x8 ---------------- IN: 0x5501b91000: 48515455 ldxrh w21, [x2] 0x5501b91004: 8148ef8b .byte 0x8b, 0xef, 0x48, 0x81 // ここがx86のまま
これを修正していかなければならない。AArch64の命令セットについて調べていこう。