はじめに
以下はJake Edge氏による2017 Linux Plumber Conferenceのレポートの訳です。
ライセンスは原文に準じます。
CC-BY-SA-4.0
仕事ではFreeBSDを使っており、GCCが標準のCCで無くなって久しいのですが、Linuxはどうなんだろう、と思い調べたら2017年の秋に開かれたLPCについてのこの記事を見つけました。
GCC依存からの脱却というと、ともすると政治的な話題が先行しがちですが、技術的にも興味深い問題を含んでいることがわかりました。
※見出しは訳者が整理のために付与したものです。
Building the kernel with clang(by Jake Edge)
概要
これまで何年にも渡ってClang CコンパイラでLinuxカーネルをビルドする粘り強い努力が続けられて来ました。Clang CコンパイラはLLVMプロジェクトの一部です。2015年のLinux Plumbers Conference(LPC)内のLLVMマイクロカンファレンスの報告を覗き見たのが最後でしたが、その後も前と変わらず彼らの動きを追っていました。
今年のLPCでは、2人のGoogleのカーネルエンジニア、グレッグ・ハックマンとニック・デソルニエーズがAndroidマイクロカンファレンスに来て、新しい情報をもたらしてくれました。それによると現時点で、2つの長期サポートカーネル(4.4と4.9)がClangでビルド可能とのことです。
Clangを使用することでもたらされる益
Googleの意向
デソルニエーズは一番多く寄せられる質問の回答からプレゼンテーションを始めました。質問は、「なぜカーネルをClangでビルドするのか?」です。始めに言及したのは、Androidのユーザスペースは最近全てClangでビルドされており、Googleはサポートするツールチェーンを減らしたい意向です。もっともそれは単にGoogleの都合でしかなく、汎用的に役立つわけではないようです。ですが、コミュニティのもっと広い範囲でも有益と言える幾つかの理由があります。
デバッグツール
カーネルコードにおいて頻繁に起こる共通のバグがあります。それは特にカーネルツリー外の、例えばAndroidデバイス等サードパーティのドライバで起こります。開発者たちはClangの静的解析を使用してバグを特定することに関心があります。そのためにはカーネルをClangでビルドしなければなりませんが、種々のサニタイザー(例:Asan,アドレスサニタイザー)のような種々の動的解析ツールや、カーネルで同等のツール(例:KASAN,カーネルアドレスサニタイザー)も使用できるようになります。
ClangはGCCとは違う警告のセットを提供します。それらを検証することで高い品質のコードがもたらされます。もちろん全てのユーザにとってカーネル内のバグは少なければ少ないほどいいに決まっています。Clangを利用するなら使えるツールがさらにあります。ひとつはコントロール・フロー解析ツールで、有効なスタック・フレームをコンパイル時に列挙可能にします。それらによりリターン・オリエンテッド・プログラミング攻撃を実行時にチェックして排除できます。Clangのリンクタイム最適化・プロファイルによる最適化の作業も行われていますが、これにより特にホットパス使用時に実行速度を改善できます。
コードベースの改良
別のコンパイラでコードをビルドするのは、未定義動作に依存しているコードを振るい落とすのにとてもよい方法です。言語仕様が明確な動作を定義していない場合、コンパイラの開発者は都合の良い方法を任意に選択できてしまいます。その選択は変化しうるので、GCCをアップグレードしただけで、未定義動作に依存したカーネルコードにより間違った動作が引き起こされるかもしれません。
デソルニエーズは「カーネルとLLVM/Clang双方が、この取り組みによってコードベースの改良を図れる」と希望を述べました。カーネルは大量のコードを含む巨大プロジェクトですので、コンパイラのバグを発見し得ますし、実際にそうなっています。
グレッグ・クラー=ハートマンは「競争は良いことだ」と述べ、その取り組みに非常に好意的です。GCCとの強い結び付きが当のカーネル開発者たちによって保護されていることをクラー=ハートマンや他の人たちも懸念していると聞き、デソルニエーズは喜んでいました。クラー=ハートマンは、カーネルをビルドできるコンパイラはこれまで他にもあった、と述べました。ビハン・ウェブスターはLLVMとの競合によって過去五年にGCCにもたらされた全ての特徴について指摘しました。クラー=ハートマンはLinuxカーネルにも競争相手がいれば良いのだが、と述べました。
現状と課題
現状
ハックマンはアップストリームのカーネルの状況について触れました。「我々はClangでビルド可能なカーネルに極めて近づいている」と。確かに、幾つかの修正が施された最近のClangが必要になりますが、x86_64とARM64カーネルはビルド可能です。カーネルツリー外のパッチも当てなければなりませんが。アンドロイド特有のKbuildにも変更が必要ですが、Android Open Source Project(AOSP)によるビルド済みのツールチェーンを使用しているならばのことです。
カーネルメーリングリスト上で告知されたように、4.4と4.9に適応可能なパッチがあります。まだ実験的なブランチですが、4.4、4.9用のAndroidカーネルもAOSPから使用可能です。もっと詳しくはこちらのスライドをどうぞ。これらのブランチは数日前にプッシュされ、そのすぐ後にHikey boardsでもコードのビルドとブートができるようになった、とハックマンは言います。
課題
「このプロセスの間に、LLVMのバグが発見され、現時点ではほぼ修正されている」とデソルニエーズは言いました。最初の仕事はLLVM4.0で完成しましたが、その後も5.0にアップデートされ、現在のLLVM開発ツリー(6.0になる予定)でもビルドされています。カーネルを4.0で多分ビルドできますが、5.0やその後のバージョンでビルドするよりもっと遅くなるでしょう。
他にも大きな課題があります。GCCでは構造体に終端が無いフィールドを持たせるため、可変長配列を利用することがありますが、Clangではサポートされていません。サポートされていないGNU C拡張インライン機能の一つで、このためLLVMアセンブラではカーネルをビルドすることはできません。ハックマンはGNUアセンブラの受け入れるものが寛容過ぎると述べています。
「この作業により、新しいツールチェーンをカーネルに使用するときにつきまとう不安や恐れに根拠が無いことが明らかになる」とデソルニエーズは言います。まだ作業中ですが、注釈を加えねばなりません。Clangはフロントエンドとしてカーネルをコンパイルできますが、ビルドプロセスを完了するためにアセンブラとリンカはGNU Binutilsのものを使う必要があります。
次の話題はLLVMとカーネルのテスト自動化の方法を考えよう、というものでした。現在は2つの特定のLTSカーネルと1つのLLVMバージョンでしか作業していません。コンフィグレーションオプションに大量の相違があるので、どんなカーネルでもClangでビルドできるとは言えないと述べました。この作業で使われている、どのカーネルパッチがClangビルド中に失敗するのか検出するボットも同様です。聴衆の一人が、kernelci.orgがビルト・ブートテスト用のコンパイラの追加を検討していると述べました。
結びに
ハックマンとデソルニエーズはClangを使ってビルドしてみるよう皆を励ましました。適切なビルドシステム上で、”make CC=clang"とすれば良いだけです。私達は、2つのコンパイラによりLinuxカーネルがビルドできる世界に、かつてなく近づいているように思えました。