satumaimoの備忘録

個人的なメモ中心

x86_64環境上でのARM64組み込みバイナリのクロスコンパイルに関するメモ

Interface 2022年7月号第3部第3章の内容を(今更)実践したので内容をメモします。

なお、誌面ではmacOSを用いて仮想マイコンの実験を行っていますが、本記事ではUbuntu 22.04 LTSを用いて実験します。

ARMツールチェーンのインストール

仮想マイコン上で動作するバイナリを開発する為に、ツールチェーンを公式サイトからダウンロードします。

$ curl -OL https://developer.arm.com/-/media/Files/downloads/gnu/11.2-2022.02/binrel/gcc-arm-11.2-2022.02-aarch64-arm-none-linux-gnueabihf.tar.xz
$ tar Jxfv gcc-arm-11.2-2022.02-x86_64-aarch64-none-elf.tar.xz

/path/to/gcc-arm-xx-x86_64-aarch64-none-elf/binにパスを通し、任意の場所でコマンドが使えるようにして、インストールを終了します。

補足1

  • none: ベアメタル(OSを持たないプラットフォーム)上で動作するバイナリの生成を意味する

OS上で動作するバイナリであれば、標準Cライブラリを使用でき、実行時にはインタプリタによって仮想メモリ上にバイナリが配置されますが、 ベアメタル上で動作するバイナリは、標準Cライブラリを使用できず、実行前に物理メモリ(ROM)上にバイナリが直接配置されます。

補足2

Ubuntuの公式レポジトリで提供されているパッケージ(gcc-arm-none-eabi)では、64bitARMを対象としたプログラムはコンパイルできないようなので、注意が必要です。

ARM64プログラムのクロスコンパイル

下記コマンドでプログラムを生成します。 (引用の範囲を逸脱するため、プログラムのソースコードは省略)

$ aarch64-none-elf-gcc -g -c -static start.S -o start.o
$ aarch64-none-elf-gcc -g -c -static main.c -o main.o
$ aarch64-none-elf-ld -Ttext 0x40080000 -o out.elf start.o main.o
$ aarch64-none-elf-objcopy -O binary out.elf out.img

これらのコマンドについて(自分の分かる範囲で)解説します。

  • aarch64-none-elf-gcc -g -c -static start.S -o start.oaarch64-none-elf-gcc -g -c -static main.c -o main.o

ソースコードアセンブリをオブジェクトファイルへアセンブルするコマンドです。

-staticオプションは、Man page曰く共有ライブラリとのリンクを抑制するとのことです。

直観的には、「OSの無い環境では動的リンカも存在しないので、共有(動的)ライブラリを使わないようにする必要がある」と理解できるのですが、 一方で、「そもそも(少なくとも今回の場合は)共有ライブラリを使用していないので、-staticオプションは不要なのでは」という疑問があります。

実際に、-staticオプションがある場合と無い場合のout.elfファイルにおけるreadelfの出力をdiffしてみたのですが、目立った違いはありませんでした。 (せいぜいファイル名の違いによって.strtabセクションの内容が違っていた程度)

結論としては、少なくとも今回の場合は-staticオプションは不要ではないかと思われるのですが、とりあえず-staticオプションを付けたまま話を続けます。

  • aarch64-none-elf-ld -Ttext 0x40080000 -o out.elf start.o main.o

オブジェクトファイルstart.omain.oをリンクするコマンドです。

-Ttext 0x40080000は、Man Page曰く出力ファイルにおける.textセクションの絶対アドレスを指定するオプションです。

Interfaceの記事曰く、

QEMUではプログラムが0x40080000に配置される

そうなので、プログラムの本体である.textセクションがQEMUにて最初に読み込まれるよう調整するためのオプションだと思われます。

  • aarch64-none-elf-objcopy -O binary out.elf out.img

out.elfout.imgへ変換する処理をしています。 (なぜelfファイルからimgファイルへの変換が必要なのか、そもそもimgファイルが何なのかは現状よく分かってないです…。)

QEMUでバイナリを実行

$ qemu-system-aarch64 -cpu cortex-a57 -machine virt -kernel out.img -monitor stdio

上記コマンドでHello worldが出力されたコンソールが現れれば、誌面の実験の再現には成功です。

参考サイト

Key difference between GCC arm-none-eabi and arm-eabi - Arm Development Studio forum - Support forums - Arm Community

環境

Ubuntu 22.04 LTS