GCC-8/QEmu-3.1を用いたSVE対応版ELFバイナリ用クロスコンパイル環境構築メモ

# はじめに

QEmu-3.1以降でArm向けの機能がより強化されてきています。
例えば、ハイエンド向けのAArch64に対するScalable Vector Extention (SVE)命令のサポートや組込みシステム向けのCortex-M関連機能の強化がなされています。
本稿では, CentOS7/RHEL7環境上にGCC8/QEmu-3.1を用いたELFバイナリ用開発・実行環境を構築する手順を説明します。


# ツール・ライブラリ一覧

本稿で構築するツール, ライブラリの一覧を以下に示します。

| ツール/ライブラリ名| 版数 | 概要 | ソースアーカイブ取得元URL |
----|----|----|----
| GNU MP  | 6.1.0 | 多倍長整数演算ライブラリ | ftp://gcc.gnu.org/pub/gcc/infrastructure/gmp-6.1.0.tar.bz2 |
| MPFR | 3.1.4 | 多精度浮動小数演算ライブラリ | ftp://gcc.gnu.org/pub/gcc/infrastructure/mpfr-3.1.4.tar.bz2 |
| MPC  | 1.0.3 | 任意精度複素数演算ライブラリ | ftp://gcc.gnu.org/pub/gcc/infrastructure/mpc-1.0.3.tar.gz |
| ISL  | 0.18  | 整数集合操作ライブラリ | ftp://gcc.gnu.org/pub/gcc/infrastructure/isl-0.18.tar.bz2 |
| Binutils | 2.31 | アセンブラ/リンカなどの実行バイナリ生成・操作ツール群 | https://ftp.gnu.org/gnu/binutils/binutils-2.31.tar.gz |
| GCC | 8.2.0 | コンパイラ本体 | https://ftp.gnu.org/gnu/gcc/gcc-8.2.0/gcc-8.2.0.tar.gz |
| NEWLIB | 3.0.0 | 組込みシステム向け標準Cライブラリ | ftp://sourceware.org/pub/newlib/newlib-3.0.0.tar.gz |
| GNU Debugger | 8.2 | デバッガ | https://ftp.gnu.org/gnu/gdb/gdb-8.2.tar.gz
| QEMU | 3.1.0 | エミュレータ | https://download.qemu.org/qemu-3.1.0.tar.xz

# ELFバイナリ用クロスコンパイル環境構築手順の概要

GCCを使用したELFバイナリ用のクロスコンパイル環境構築手順は以下の通りになります。

1. コンパイル用の一時ディレクトリを作成する
1. コンパイラ構築に必要なコマンド群をインストールする
1. ソースアーカイブを収集する
1. コンパイル作業時に指定するパラメタをシェル変数に設定する
1. コンパイラの動作に必要なGNU MPライブラリを作成する
1. コンパイラの動作に必要なMPFRライブラリを作成する
1. コンパイラの動作に必要なMPCライブラリを作成する
1. コンパイラの動作に必要なISLライブラリを作成する
1. ターゲット用のバイナリを生成するために必要なbinutilsを生成する
1. ターゲット用の標準Cライブラリを構築するためのCコンパイラを生成する
1. ターゲット用の標準Cライブラリを構築する
1. ターゲット用の標準Cライブラリを使用するC/C++コンパイラを生成する
1. ターゲット用のバイナリを実行するエミュレータを生成する
1. ターゲット用のバイナリをデバッグするためのデバッガを生成する

# コンパイル用の一時ディレクトリを作成する

本稿では, GCCのクロスコンパイラを構築するための一時ディレクトリを生成します。
ソースアーカイブをダウンロードするディレクトリ, ソースアーカイブを展開するディレクトリ, コンパイラ構築処理用の一時ディレクトリをそれぞれ独立したディレクトリとして用意します。

カレントディレクトリに以下のようなディレクトリを作成します。

| ディレクトリ名 | 用途 |
----|----
 downloads | ソースアーカイブをダウンロードするディレクトリ
 src | ソースアーカイブを展開するディレクトリ
 build |  コンパイラ構築処理用の一時ディレクトリ

# コンパイラ構築に必要なコマンド群をインストールする

コンパイル環境構築に必要なコマンド群をインストールします。
一部のコマンドは, Extra Packages for Enterprise Linux (EPEL)から導入する必要があります。 リポジトリに優先順位を設定するyum-prioritiesや構築時に必要なツール群を導入するための支援ツールであるyum-utilsをインストール後, EPELを導入するためのパッケージ ( epel-release )をインストールします。

また, ソースアーカイブのダウンロードに使用するwget, GNU tar, および, GNU makeコマンドをインストールしておきます。

本稿では, sudoコマンドによって, 管理者権限でコマンドを実行可能に設定されていることを前提にしています。 必要に応じて, 別途sudoコマンドの設定を行ってください。

以下のコマンドを入力します。本稿では, $をコマンドプロンプトとして表記しています。

```
$ sudo yum install -y yum-priorities yum-utils
$ sudo yum install -y epel-release
$ sudo yum install -y wget tar make
```
次に, 基本的な開発環境を導入します。

```
$ sudo yum groupinstall -y "Development tools"
```

さらに, 実行環境エミュレータであるQEmuを構築するために必要なライブラリ群をインストールします。

```
$ sudo yum install -y giflib-devel libpng-devel libtiff-devel gtk3-devel       \
ncurses-devel gnutls-devel nettle-devel libgcrypt-devel SDL2-devel             \
gtk-vnc-devel libguestfs-devel curl-devel brlapi-devel bluez-libs-devel        \
libusb-devel libcap-devel libcap-ng-devel libiscsi-devel libnfs-devel          \
libcacard-devel lzo-devel snappy-devel bzip2-devel libseccomp-devel            \
libxml2-devel libssh2-devel xfsprogs-devel mesa-libGL-devel mesa-libGLES-devel \
mesa-libGLU-devel mesa-libGLw-devel spice-server-devel libattr-devel           \
libaio-devel sparse-devel gtkglext-libs vte-devel libtasn1-devel               \
gperftools-devel virglrenderer device-mapper-multipath-devel                   \
cyrus-sasl-devel libjpeg-turbo-devel glusterfs-api-devel                       \
libpmem-devel libudev-devel capstone-devel numactl-devel                       \
librdmacm-devel libibverbs-devel libibumad-devel libvirt-devel                 \
gcc-objc iasl                                                                  \
ceph ceph-base ceph-common ceph-devel-compat ceph-fuse                         \
ceph-libs-compat ceph-mds ceph-mon ceph-osd ceph-radosgw ceph-resource-agents  \
ceph-selinux ceph-test cephfs-java libcephfs1-devel libcephfs_jni1-devel       \
librados2-devel libradosstriper1-devel librbd1-devel librgw2-devel             \
python-ceph-compat python-cephfs python-rados python-rbd rbd-fuse              \
rbd-mirror rbd-nbd
```

最後に, クロスコンパイラやQEmuの構築に必要なコマンド群をインストールします。

```
$ sudo yum-builddep -y binutils gcc gdb qemu-kvm texinfo-tex texinfo
```

# ソースアーカイブを収集する

  downloadsディレクトリに, ソースアーカイブをダウンロードします。
以下のコマンドを入力してください。

```
$ pushd downloads
$ wget ftp://gcc.gnu.org/pub/gcc/infrastructure/gmp-6.1.0.tar.bz2 
$ wget ftp://gcc.gnu.org/pub/gcc/infrastructure/mpfr-3.1.4.tar.bz2 
$ wget ftp://gcc.gnu.org/pub/gcc/infrastructure/mpc-1.0.3.tar.gz 
$ wget ftp://gcc.gnu.org/pub/gcc/infrastructure/isl-0.18.tar.bz2 
$ wget https://ftp.gnu.org/gnu/binutils/binutils-2.31.tar.gz 
$ wget https://ftp.gnu.org/gnu/gcc/gcc-8.2.0/gcc-8.2.0.tar.gz 
$ wget ftp://sourceware.org/pub/newlib/newlib-3.0.0.tar.gz 
$ wget https://ftp.gnu.org/gnu/gdb/gdb-8.2.tar.gz
$ wget https://download.qemu.org/qemu-3.1.0.tar.xz
$ popd
```

# コンパイル作業時に指定するパラメタをシェル変数に設定する

クロスコンパイラ構築時は, インストール先ディレクトリなどを複数回指定することになります。 そこで各工程で指定するパラメタをシェル変数として設定しておきます。

本稿では, クロスコンパイラをホームディレクトリ直下の`cross/gcc-elf/アーキテクチャ名/構築日`ディレクトリに配置することにします。

|変数名|意味|
|----|----|
|TODAY|コンパイル時の日付 (インストール先ディレクトリの指定に使用)|
|CPU|コンパイラが生成するコードのCPUアーキテクチャ|
|TARGET|コンパイラが生成するコードを実行可能な環境|
|QEMU\_CPU|QEMUエミュレータのCPU名|
|CPU\_NR|コンパイラを作成する環境での搭載プロセッサ数|
|SMP\_OPT|makeに指定する並行ビルドオプション|
|CROSS| クロスコンパイラを導入するディレクトリ |
|SYSROOT| ターゲット用の標準Cライブラリを導入するディレクトリ |

`TARGET`, `HOST`や`QEMU_CPU`には, 以下を指定します。

|CPUアーキテクチャ|TARGET|HOST|QEMU\_CPU|
|----|----|----|----|
|AArch64|aarch64-elf|aarch64-elf|aarch64|
|AArch32 (浮動小数点演算プロセッサ使用)|arm-eabihf|arm-eabihf|arm|
|IA32|i686-elf|i686-elf|i386|
|RISC-V 32bit|riscv32-elf|riscv32-elf|riscv32|
|RISC-V 64bit|riscv64-elf|riscv64-elf|riscv64|
|X64|x86\_64-elf|x86\_64-elf|x86\_64|

AArch64向けのコンパイラを作成する場合, 以下のように入力します。

```
$ TODAY=`date "+%F"`
$ CPU=aarch64
$ TARGET=aarch64-elf
$ QEMU_CPU=aarch64
$ CPU_NR=`nproc`
$ SMP_OPT="-j${CPU_NR}"
$ PROGRAM_PREFIX="--program-prefix=${TARGET}-"
$ WORKDIR=`pwd`
$ SRCDIR=${WORKDIR}/src
$ BUILDDIR=${WORKDIR}/build
$ DOWNLOADDIR=${WORKDIR}/downloads
$ CROSS=${HOME}/cross/gcc-elf/${CPU}/${TODAY}
$ SYSROOT=${CROSS}/rfs
```

また, コンパイラ構築時に必要な一時ディレクトリを以下のように作成しておきます。

```
$ rm -fr ${CROSS} ${BUILDDIR} ${SRCDIR}
$ mkdir -p ${CROSS}
$ mkdir -p ${BUILDDIR}
$ mkdir -p ${SRCDIR}
```

さらに, ターゲット用の標準Cライブラリを導入するディレクトリを作成しておきます。

```
$ mkdir -p ${SYSROOT}
```


# コンパイラの動作に必要なGNU MPライブラリを作成する

ここでは, GNUコンパイラが最適化処理を実行するために必要な多桁整数演算ライブラリ (GMP)を導入します。 GNUコンパイラは, GMPをコンパイラ内部の定数のたたみ込み処理 (constant folding)などに使用します。
本ライブラリは, クロスコンパイラ自身が使用するため構築環境向けにライブラリを構築します。

共有ライブラリ版を生成するとクロスコンパイラの動作時に`LD_LIBRARY_PATH`環境変数の設定が必要となるため静的ライブラリのみを生成します。

以下のコマンドを入力します。

```
$ pushd ${SRCDIR}
$ tar xf ${DOWNLOADDIR}/gmp-6.1.0.tar.bz2 
$ popd
$ mkdir -p ${BUILDDIR}/gmp-6.1.0
$ pushd ${BUILDDIR}/gmp-6.1.0
$ ${SRCDIR}/gmp-6.1.0/configure   \
    --prefix=${CROSS}             \
    --enable-cxx                  \
    --disable-shared              \
    --enable-static
$ gmake ${SMP_OPT}
$ gmake install
$ popd
```

# コンパイラの動作に必要なMPFRライブラリを作成する

ここでは, GNUコンパイラが最適化処理を実行するために必要な任意精度浮動小数点演算ライブラリ (MPFR)を導入します。　GNUコンパイラは, MPFRをコンパイラ内部で定数を引数とした超越関数 (指数関数，対数関数，三角関数，逆三角関数など )をコンパイル時に計算する用途などで使用します。
本ライブラリはクロスコンパイラ自身が使用するため構築環境向けにライブラリを構築します。

共有ライブラリ版を生成するとクロスコンパイラの動作時に`LD_LIBRARY_PATH`環境変数の設定が必要となるため静的ライブラリのみを生成します。

以下のコマンドを入力します。

```
$ pushd ${SRCDIR}
$ tar xf ${DOWNLOADDIR}/mpfr-3.1.4.tar.bz2 
$ popd
$ mkdir -p ${BUILDDIR}/mpfr-3.1.4
$ pushd ${BUILDDIR}/mpfr-3.1.4
$ ${SRCDIR}/mpfr-3.1.4/configure      \
    --prefix=${CROSS}                 \
    --with-gmp=${CROSS}               \
    --disable-shared                  \
    --enable-static
$ gmake ${SMP_OPT}
$ gmake install
$ popd
```

# コンパイラの動作に必要なMPCライブラリを作成する

ここでは, GNUコンパイラが最適化処理を実行するために必要な任意精度複素数演算ライブラリ (MPC)を導入します。　本ライブラリはクロスコンパイラ自身が使用するため構築環境向けにライブラリを構築します。

共有ライブラリ版を生成するとクロスコンパイラの動作時に`LD_LIBRARY_PATH`環境変数の設定が必要となるため静的ライブラリのみを生成します。

以下のコマンドを入力します。

```
$ pushd ${SRCDIR}
$ tar xf ${DOWNLOADDIR}/mpc-1.0.3.tar.gz
$ popd
$ mkdir -p ${BUILDDIR}/mpc-1.0.3
$ pushd ${BUILDDIR}/mpc-1.0.3
$ ${SRCDIR}/mpc-1.0.3/configure       \
    --prefix=${CROSS}                 \
    --with-gmp=${CROSS}               \
    --with-mpfr=${CROSS}              \
    --disable-shared                  \
    --enable-static
$ gmake ${SMP_OPT}
$ gmake install
$ popd
```

# コンパイラの動作に必要なISLライブラリを作成する

GNUコンパイラは, ソースコード中のループに対して生成されるコードを最適化するために, 多面体最適化手法 ( Polyhedral Optimization )を使用します。最適化処理時にループ中の変数が使用される範囲を計算するために, 整数集合演算用のライブラリを使用しています。

ここでは, GNUコンパイラが最適化処理を実行するために必要な整数集合演算ライブラリ (ISL)を導入します。　本ライブラリはクロスコンパイラ自身が使用するため構築環境向けにライブラリを構築します。

共有ライブラリ版を生成するとクロスコンパイラの動作時に`LD_LIBRARY_PATH`環境変数の設定が必要となるため静的ライブラリのみを生成します。

以下のコマンドを入力します。

```
$ pushd ${SRCDIR}
$ tar xf ${DOWNLOADDIR}/isl-0.18.tar.bz2 
$ popd
$ mkdir -p ${BUILDDIR}/isl-0.18
$ pushd ${BUILDDIR}/isl-0.18
$ ${SRCDIR}/isl-0.18/configure   \
    --prefix=${CROSS}            \
    --disable-silent-rules       \
    --with-gmp=system            \
    --with-gmp-prefix=${CROSS}   \
    --disable-shared             \
    --enable-static
$ gmake ${SMP_OPT}
$ gmake install
$ popd
```

# ターゲット用のバイナリを生成するために必要なbinutilsを生成する

GNUコンパイラは, 生成したアセンブリコードから実行可能なバイナリ形式にアセンブル, リンクするためのアセンブラ, リンカとして, GNU binutilsを使用します。

ここでは, GNU コンパイラから使用されるターゲット用のGNU binutilsを導入します。
binutilsは, クロスプラットフォーム汎用ライブラリであるlibibertyを生成します。
共有ライブラリ版をlibiberty生成するとクロスコンパイラの動作時に`LD_LIBRARY_PATH`環境変数の設定が必要となるため, configureのオプションに`--disable-shared`を付けて静的ライブラリ版のみを生成します。

以下のコマンドを入力します。

```
$ pushd ${SRCDIR}
$ tar xf ${DOWNLOADDIR}/binutils-2.31.tar.gz 
$ popd
$ mkdir -p ${BUILDDIR}/binutils-2.31
$ pushd ${BUILDDIR}/binutils-2.31
$ ${SRCDIR}/binutils-2.31/configure        \
    --prefix=${CROSS}                      \
    --target=${TARGET}                     \
    "${PROGRAM_PREFIX}"                    \
    --with-local-prefix=${CROSS}/${TARGET} \
    --disable-shared                       \
    --disable-werror                       \
    --with-sysroot=${SYSROOT}              \
    --disable-nls
$ gmake ${SMP_OPT}
$ gmake install
$ popd
```

# ターゲット用の標準Cライブラリを構築するためのCコンパイラを生成する

典型的な場合, C言語でアプリケーションプログラムを作成する際は, 標準Cライブラリが提供する各種ライブラリ関数を使用します。

しかしながら, 標準Cライブラリ自身がC言語で記載されているため, 標準Cライブラリを含めたクロスコンパイル環境を構築するためには, まず標準Cライブラリに依存しないクロスコンパイラ (Free Standing環境向けコンパイラ )を構築し, これを用いて標準Cライブラリを構築する必要があります。

以下のコマンドを入力します。

```
$ pushd ${SRCDIR}
$ tar xf ${DOWNLOADDIR}/gcc-8.2.0.tar.gz 
$ popd
$ mkdir -p ${BUILDDIR}/gcc-8.2.0
$ pushd ${BUILDDIR}/gcc-8.2.0
$ ${SRCDIR}/gcc-8.2.0/configure                      \
    --prefix=${CROSS}                                \
    --target=${TARGET}                               \
    --with-local-prefix=${CROSS}/${TARGET}           \
    --enable-languages="c"                           \
    --disable-bootstrap                              \
    --disable-werror                                 \
    --disable-shared                                 \
    --disable-multilib                               \
    --with-newlib                                    \
    --without-headers                                \
    --disable-lto                                    \
    --disable-threads                                \
    --disable-decimal-float                          \
    --disable-libatomic                              \
    --disable-libitm                                 \
    --disable-libquadmath                            \
    --disable-libvtv                                 \
    --disable-libcilkrts                             \
    --disable-libmudflap                             \
    --disable-libssp                                 \
    --disable-libmpx                                 \
    --disable-libgomp                                \
    --disable-libsanitizer                           \
    --with-gmp=${CROSS}                              \
    --with-mpfr=${CROSS}                             \
    --with-mpc=${CROSS}                              \
    --with-isl=${CROSS}                              \
    --disable-nls
$ gmake ${SMP_OPT}
$ gmake install
$ popd
```

また, ビルド環境のgccとの混乱を避けるため, ターゲット用のプレフィクスなしにコンパイラが呼び出されないようにします。

以下のコマンドを入力します。

```
$ pushd ${CROSS}/bin
$ rm -f cpp gcc gcc-ar gcc-nm gcc-ranlib gcov
$ popd
```

# ターゲット用の標準Cライブラリを構築する

ここでは, 前節で構築したクロスコンパイラを使用してターゲット用の標準Cライブラリを生成します。
本稿では, 組み込みシステムなどのベアメタル環境向けに使用されている`newlib`を構築します。

newlibは, システムコールなどのサポートを行うボードサポートパッケージと標準Cライブラリが独立したロードモジュールとして構成されているため, OSを使用しない環境でも標準Cライブラリ関数の多くを利用することが可能です。

以下のコマンドを入力します。


```
$ pushd ${SRCDIR}
$ tar xf ${DOWNLOADDIR}/newlib-3.0.0.tar.gz 
$ popd
$ mkdir -p ${BUILDDIR}/newlib-3.0.0
$ pushd ${BUILDDIR}/newlib-3.0.0
$ ${SRCDIR}/newlib-3.0.0/configure                          \
    --prefix=/usr                                           \
    --target=${TARGET}
$ gmake ${SMP_OPT}
$ gmake DESTDIR=${SYSROOT} install
$ popd
```

newlibは, インストール先のディレクトリ配下に, configureの`--target`オプションで指定されたターゲット名を持ったディレクトリを生成し, その直下にヘッダとライブラリをインストールします。
そこで, ヘッダとライブラリの位置を補正して, クロスコンパイラからヘッダやライブラリを参照できるようにします。 以下のコマンドを入力します。

```
$ pushd ${SYSROOT}
$ rm -fr ${SYSROOT}/usr/include ${SYSROOT}/usr/lib ${SYSROOT}/usr/lib64
$ mv usr/${TARGET}/* usr
$ rmdir usr/${TARGET}
$ popd
```

# 標準Cライブラリを使用するC/C++コンパイラを生成する

ターゲット用の標準Cライブラリを使用してプログラムを構築するためのC/C++コンパイラを構築します。

ここでは, 組込みシステムでも重要となってきている標準Cに近年取り込まれた仕様やセキュアプログラミングを支援する以下の機能を有効にしてコンパイルします。

*  ISO/IEC WDTR 24732 Decimal Floating-point Arithmetic (十進浮動小数点算術演算) (--enable-decimal-float)
*  4倍精度算術演算 (--enable-libquadmath)
*  バッファー・オーバーフロー, ヒープ領域不正使用検出機構 ( --enable-libmudflap )
*  Stack Smashing Protector (SSP) (バッファーオーバーフロー攻撃検出機構) ( --enable-libssp )
*  Thread Local Storage機能 ( --enable-tls )
* C/C++コンパイラとリンク時最適化機能 (LTO) (--enable-languages="c,c++,lto")

リンク時最適化機能は, AArch64などUnified Extensible Firmware Interface (UEFI)を持った組み込みシステムの構築時に必要な機能です。

また、前節で導入した標準Cライブラリをヘッダ・ライブラリ検索先に指定します (
--with-sysroot=${SYSROOT}  )。

なお, newlibはスレッドライブラリを提供していませんのでスレッド並列関連の機能は無効にしています。

以下のコマンドを入力します。

```
$ pushd ${SRCDIR}
$ tar xf ${DOWNLOADDIR}/gcc-8.2.0.tar.gz 
$ popd
$ mkdir -p ${BUILDDIR}/gcc-8.2.0
$ pushd ${BUILDDIR}/gcc-8.2.0
$ ${SRCDIR}/gcc-8.2.0/configure                      \
    --prefix=${CROSS}                                \
    --target=${TARGET}                               \
    --with-local-prefix=${CROSS}/${TARGET}           \
    --enable-languages="c,c++,lto"                   \
    --disable-bootstrap                              \
    --disable-werror                                 \
    --disable-shared                                 \
    --disable-multilib                               \
    --with-newlib                                    \
    --disable-threads                                \
    --disable-libatomic                              \
    --disable-libitm                                 \
    --disable-libvtv                                 \
    --disable-libcilkrts                             \
    --disable-libmpx                                 \
    --disable-libgomp                                \
    --disable-libsanitizer                           \
    --with-gmp=${CROSS}                              \
    --with-mpfr=${CROSS}                             \
    --with-mpc=${CROSS}                              \
    --with-isl=${CROSS}                              \
    --enable-decimal-float                           \
    --enable-libquadmath                             \
    --enable-libmudflap                              \
    --enable-libssp                                  \
    --enable-tls                                     \
    --with-sysroot=${SYSROOT}                        \
    --disable-nls
$ gmake ${SMP_OPT}
$ gmake install
$ popd
```

ビルド環境のgccとの混乱を避けるため, ターゲット用のプレフィクスなしにコンパイラが呼び出されないようにします。

以下のコマンドを入力します。

```
$ pushd ${CROSS}/bin
$ rm -f cpp gcc gcc-ar gcc-nm gcc-ranlib gcov
$ popd
```
# ターゲット用のバイナリを実行するエミュレータを生成する

次に, ターゲット用のバイナリをビルド環境上で実行するためのエミュレータを生成します。
近年では, 組込み分野でもエミュレータを用いた実機レス開発が進んでいます。
本稿では, オープンソースのエミュレータである`QEmu`を使用することにします。

以下のコマンドを入力して, `QEmu`を導入します。

```
$ pushd ${SRCDIR}
$ tar xf ${DOWNLOADDIR}/qemu-3.1.0.tar.xz
$ popd
$ mkdir -p ${BUILDDIR}/qemu-3.1.0
$ pushd ${BUILDDIR}/qemu-3.1.0
$ ${SRCDIR}/qemu-3.1.0/configure                                \
     --prefix=${CROSS}                                          \
     --interp-prefix=${SYSROOT}                                 \
     --target-list="${QEMU_CPU}-softmmu,${QEMU_CPU}-linux-user" \
     --enable-system                                            \
     --enable-user                                              \
     --enable-linux-user                                        \
     --enable-tcg-interpreter                                   \
     --disable-werror
$ gmake ${SMP_OPT}
$ gmake install
$ popd
```

# ターゲット用のバイナリをデバッグするためのデバッガを生成する

最後に, ターゲット用のバイナリをデバッグするためのデバッガを生成します。
また, QEMUターゲットをgdbでリモートデバッグする際に発生する
``Remote 'g' packet reply is too long``
エラーを回避するためのパッチを適用します。
適用するパッチの内容は, 以下の通りです。

```
--- gdb-8.2.orig/gdb/remote.c   2018-09-05 16:44:28.000000000 +0900
+++ gdb-8.2/gdb/remote.c    2018-11-05 15:30:39.745920969 +0900
@@ -8034,9 +8034,21 @@
   buf_len = strlen (rs->buf);
 
   /* Further sanity checks, with knowledge of the architecture.  */
-  if (buf_len > 2 * rsa->sizeof_g_packet)
-    error (_("Remote 'g' packet reply is too long (expected %ld bytes, got %d "
-        "bytes): %s"), rsa->sizeof_g_packet, buf_len / 2, rs->buf);
+  if (buf_len > 2 * rsa->sizeof_g_packet) {
+  
+    rsa->sizeof_g_packet = buf_len;
+    for(i = 0; i < gdbarch_num_regs(gdbarch); i++){
+
+      if (rsa->regs[i].pnum == -1)
+   continue;
+
+      if (rsa->regs[i].offset >= rsa->sizeof_g_packet)
+   rsa->regs[i].in_g_packet = 0;
+      else
+   rsa->regs[i].in_g_packet = 1;
+    }
+  }
+
 
   /* Save the size of the packet sent to us by the target.  It is used
      as a heuristic when determining the max size of packets that the
```

上記のパッチを`${WORKDIR}`配下に`gdb-8.2-qemu-x86-64.patch`という名前で保存した上で, 以下のコマンドを実行します。

```
$ pushd ${SRCDIR}
$ tar xf ${DOWNLOADDIR}/gdb-8.2.tar.gz
$ popd
$ pushd  ${SRCDIR}/gdb-8.2
$ patch -p1 < ${WORKDIR}/gdb-8.2-qemu-x86-64.patch
$ popd
$ mkdir -p ${BUILDDIR}/gdb-8.2
$ pushd ${BUILDDIR}/gdb-8.2
$ ${SRCDIR}/gdb-8.2/configure                            \
    --prefix=${CROSS}                                    \
    --target=${TARGET}                                   \
    --with-local-prefix=${CROSS}/${TARGET}               \
    --program-prefix="${TARGET}-"                        \
    --disable-werror                                     \
    --disable-nls
$ gmake ${SMP_OPT}
$ gmake install
$ popd
```

# クロスコンパイラ導入先ディレクトリへのシンボリックリンクの設定

以下のコマンドを実行して, 構築したコンパイル環境へのシンボリックリンクを作成します。

```
$ rm -f ${CROSS_PREFIX}/current
$ pushd ${CROSS_PREFIX}
$ ln -sv ${TODAY} current
$ popd
```

以上により, `${HOME}/cross/gcc-elf/アーキテクチャ名/current/bin` を環境変数`PATH`に追加することで, クロスコンパイル環境を利用可能となります。

# SVE命令を体験してみましょう

GCC-8からコンパイラがAArch64のSVE命令を使用したベクトル最適化に対応しており, また, QEmu-3.1からSVE命令をシステムエミュレータ, ユーザランドエミュレータの双方で解釈可能となりました。
そこで上記のクロスコンパイル環境を利用してSVE命令を体験してみましょう。
姫野ベンチマーク ( http://accc.riken.jp/supercom/documents/himenobmt/ )をダウンロードします。

ダウンロードしたソースファイルを`himenoBMTxps.c`という名前でカレントディレクトリに保存し, 以下のコマンドを実行して, プログラムを構築します。

```
$ OLD_PATH=${PATH}
$ PATH=${HOME}/cross/gcc-elf/aarch64/current/bin:${PATH}
$ aarch64-elf-gcc  -D_POSIX_SOURCE -DSMALL -O3 -march=armv8.2-a+sve --specs=rdimon.specs himenoBMTxps.c -o himenoS
```

上記手順でコンパイルするとArm版QEmuのsemihosting機能を使用したバイナリが生成されます。
以下のコマンドを実行することで, QEmuのユーザランドエミュレーション機能を用いてSVE命令を使用した姫野ベンチマークを実行することができます。

```
$ qemu-aarch64 ./himenoS
```

実行結果の例は以下の通りです。

```
$ qemu-aarch64 ./himenoS
mimax = 65 mjmax = 65 mkmax = 129
imax = 64 jmax = 64 kmax =128
 Start rehearsal measurement process.
 Measure the performance in 3 times.

 MFLOPS: 49.403088 time(s): 1.000000 3.288634e-03

 Now, start the actual measurement process.
 The loop will be excuted in 180 times
 This will take about one minute.
 Wait for a while

 Loop executed for 180 times
 Gosa : 1.752712e-03
 MFLOPS measured : 64.438810    cpu : 46.000000
 Score based on Pentium III 600MHz : 0.785839
```

# 備考 クロス環境構築用シェルスクリプト

上記のクロスコンパイル環境を構築するシェルスクリプトを
https://github.com/takeharukato/mkcross
にて公開しています。当該のスクリプトでは上記手順に加え, LLVMやX64/AArch64環境向けのUEFIの構築も行えます。
UEFIを使用した開発を行う方はこちらも参照ください。