Rustがサポートするアーキテクチャ少なすぎる!

FUJITA Tomonori
nttlabs
Published in
Feb 20, 2024

「RustでLinuxカーネルモジュールを実装しよう!」とはしゃいできましたが、実は、X86-64とLoongArchという2つのCPUアーキテクチャしかサポートされていません。近いうちに、ARM64もサポートされそうですが、Linuxカーネルがサポートする大半のアーキテクチャで、Rustは使えません。

Linuxカーネルの標準コンパイラのGCCは、CのソースコードをLinuxカーネルがサポートする様々なCPUアーキテクチャ用の実行ファイルに変換することができます。一方、Rustの公式コンパイラがサポートを保証しているCPUアーキテクチャはARM64とX86、X86–64だけです。

Rustの公式コンパイラがサポートしているアーキテクチャが少なすぎるということで、別のコンパイラを試してみました。

Rustの公式コンパイラ

Rustの公式コンパイラは、コンパイラを実装するための基盤的なソフトウェアのLLVMを使って実装されています。CPU、コンパイラ、OSは低レイヤプログラミング界の三種の神器。LLVMを使った自作コンパイラを実装して、概要を知っている読者はこの部分を読み飛ばしてください。

一般に、コンパイラは、図に示すように、フロントエンド、ミドルエンド、バックエンドという3層で構成され、LLVMも同様です。

RustコンパイラとLLVMの構成

フロントエンドは、プログラミング言語ごとに実装される部分で、ソースコードを解析し、ミドルエンドが理解するアーキテクチャ非依存な表現を出力します。Rust用のフロントエンドを実現するコマンドがrustcで、Rustコミュニティが開発しています。

ミドルエンドは、アーキテクチャ非依存な表現を用いて、最適化を行う部分です。LLVMで使われるアーキテクチャ非依存な表現は、LLVM-IRと呼ばれます。

バックエンドは、CPUアーキテクチャごとに実装される部分で、LLVM-IRから各アーキテクチャが実行できるファイルを生成します。

GCCと比べると、LLVMは各機能のモジュール性が高く、独自のフロントエンドやバックエンドが実装しやすいという利点があると言われます。一方、LLVMがサポートするCPUアーキテクチャは数が少なく、特に古いアーキテクチャについてはGCCのほうが安定していると考えられています。

GCCを使ってRustをコンパイルする

RustがサポートするCPUアーキテクチャを増やすためには、LLVMのバックエンドを実装する必要があることがわかりました。でも、GCCは、すでに数多くのアーキテクチャをサポートしています。じゃあ、GCCでRustのコードをコンパイルすればよさそうですね!

RustのソースコードをGCCでコンパイルする試みは2つの異なるアプローチで取り組まれています。

GCCを使ったRustコンパイルの方式の比較

rustc_codegen_gccは、公式コンパイラのフロントエンドのrustcを使い、ミドルエンドとバックエンドにGCCを使うというアプローチです。rustcがLLVMの中間表現の代わりに、GCCの中間表現を生成します。

gccrsは、Rust用のGCCフロントエンドを実装するプロジェクトです。Rustコミュニティが開発しているrustcと同じような機能を持つGCCフロントエンドを開発しています。

なお、この2つのアプローチは、エディタの選択のようなセンシティブなトピックです。インターネット上で見ず知らずの人たちと優劣を論争するのは避けましょう。

rustc_codegen_gccを試す

Rust for Linuxプロジェクトが推すrust_codegen_gccを試してみました。対象とするCPUアーキテクチャは、CIでテストされているm68kとしました。

早速、Hello, world!をコンパイルします。

~/rustc_codegen_gcc$ file target/out/hello_world
target/out/hello_world: ELF 32-bit MSB pie executable, Motorola m68k, 68020, version 1 (SYSV), dynamically linked, interpreter /lib/ld.so.1, for GNU/Linux 5.16.20, with debug_info, not stripped
~/rustc_codegen_gcc$ readelf -p .comment target/out/hello_world
String dump of section '.comment':
[ 0] GCC: (crosstool-NG 1.26.0.45_76758dd) 14.0.1 20240207 (experimental)
[ 45] rustc version 1.76.0-nightly (a57770440 2023-11-16) with libgccjit 14.0.1

rustcとlibgccjitという組み合わせに気持ちの昂りが抑えられませんね!なお、名前が紛らわしいですが、JITではなく、AOTコンパイルされたバイナリです。

次は、QEMUでバイナリを実行してみましょう。クロスコンパイルしたバイナリを試験する際の定石は、chrootとQEMUユーザースペースエミュレーションの組み合わせです。しかし、ユーザースペースエミュレーションは、バイナリ変換するだけで、m68kを動かす感動が味わえませんよね。高くて買えなかったAppleのMacintoshを思い出しながら、システムエミュレーションで、Hello, world!が実行できました。

# uname -a
Linux codgen 4.19.0-5-m68k #1 Debian 4.19.37-5 (2019-06-19) m68k GNU/Linux
# /root/hello_world
Hello, world!

まとめ

LinuxカーネルにRustのコードがどんどん採用されるためには、RustのC言語サポートやコンパイラの改善など、様々な課題がありそうです。NTT研究所では、低レイヤの開発に興味がある仲間を募集中です。連絡お待ちしています。

--

--

FUJITA Tomonori
nttlabs

Janitor at the 34th floor of NTT Tamachi office, had worked on Linux kernel, founded GoBGP, TGT, Ryu, RustyBGP, etc. https://twitter.com/brewaddict