目次: GCC
引き続き、超基本的なbinutils + GCC + glibcの組み合わせのクロスビルド環境を作っています。やや苦戦したものの、ARM, AArch64, RISC-V 64でビルドが通りました。良かった良かった。
残念ながらRISC-V 32はglibcが対応しておらず、libcなしのベアメタル向けコンパイラしか作れませんでした。glibc does not yet support 32-bit systemsと怒られます。glibcの代わりにnewlibなどを使えば、libcありのLinux向けコンパイラが作れるかもしれませんが、試していないのでわかりません。
昔作ったクロスコンパイラをビルドするMakefile(GitHubへのリンク)を改造して、作りました。
前回(その1)検討した通り、本格的に運用するなら独自のビルドツールよりcrosstool-NGかbuildrootに切り替えた方が良いと思います。
詳細はGitHubを見た方が良いですが、configureに指定しているオプションだけ、ざっと列挙しておきます。
CROSS_ARCH = riscv64-unknown-linux-gnu
TOP_DIR = `pwd`
CROSS_ROOT = $TOP_DIR/buildroot
PREFIX ?= $(CROSS_ROOT)
SYSROOT ?= $(CROSS_ROOT)/$(CROSS_ARCH)/sysroot
まずbinutilsは、
./configure \
--target=$(CROSS_ARCH) \
--prefix=$(CROSS_ROOT) \
--disable-nls \
--disable-static \
--disable-werror \
--with-lib-path=$(CROSS_ROOT)/lib \
--with-sysroot=$(CROSS_ROOT)
次にgccは、
./configure \
--target=$(CROSS_ARCH) \
--prefix=$(PREFIX) \
--enable-languages=c \
--disable-libatomic \
--disable-libitm \
--disable-libgomp \
--disable-libmudflap \
--disable-libquadmath \
--disable-libsanitizer \
--disable-libssp \
--disable-libstdcxx-pch \
--enable-long-long \
--enable-lto \
--disable-multiarch \
--disable-multilib \
--disable-nls \
--disable-plugin \
--disable-shared \
--disable-threads \
--disable-__cxa_atexit \
--without-headers \
--with-local-prefix=$(SYSROOT) \
--with-sysroot=$(SYSROOT) \
--with-newlib
難関のglibcはこんな感じ、
./configure \
--host=$(CROSS_ARCH) \
--prefix=$(SYSROOT)/usr \
--disable-profile \
--disable-multilib \
--enable-add-ons \
--enable-kernel=3.0.0 \
--disable-multi-arch \
--enable-obsolete-rpc \
--with-binutils=$(PREFIX)/bin \
--with-headers=$(SYSROOT)/usr/include \
--with-sysroot=$(SYSROOT)
最後にglibcを動的リンク可能なgccは、
./configure \
--target=$(CROSS_ARCH) \
--prefix=$(PREFIX) \
--enable-languages=c,c++,fortran \
--enable-libatomic \
--disable-libitm \
--enable-libgomp \
--enable-libmudflap \
--enable-libquadmath \
--disable-libsanitizer \
--enable-libssp \
--enable-libstdcxx-pch \
--enable-long-long \
--enable-lto \
--disable-multiarch \
--disable-multilib \
--enable-nls \
--enable-plugin \
--enable-shared \
--enable-threads=posix \
--enable-__cxa_atexit \
--with-local-prefix=$(SYSROOT)/usr \
--with-build-sysroot=$(SYSROOT) \
--with-sysroot=$(SYSROOT) \
--with-native-system-header-dir=/usr/include
この設定が正しいかどうか確証は持てませんが、printfを呼び出すCソースコードをエラーなくビルド可能なコンパイラが作成できるので、良しとします。
色々引っかかったのですが、覚えている限りのエラーと自分が取った対策を列挙しておきます。
エラーメッセージだけ読むとさっぱりですが、config.logに記録されたテストプログラムとテスト結果によれば、pthread.hが見当たらないと言っているようです。
もちろんGCCの前にglibcのクロスビルドに成功しているので、pthread.hは存在しているものの、
これらの原因によって、pthread.hが見えなくなっていたようです。
ツールチェーン構築って大変です。実際に体験すると、crosstool-NGやbuildrootのありがたさが身に沁みます。
目次: GCC
先日(2019年3月27日の日記参照)クロスビルド向けLLVMのビルド方法がわかったので、今度はクロスビルド向けGCCのツールチェーン(超基本的なbinutils + GCC + glibcの組み合わせ)を作ろうとしていますが、さっぱりうまくいかないです。
そもそもどのバージョンの組み合わせならビルドが通るのか全くわかりません……。対象となるクロス環境(ARM向けなのか、RISC-V向けなのか)と、ホスト側のコンパイラバージョンが影響するようで、昔ビルドが通っていた組み合わせを引っ張り出してきても、今の環境だとビルドが通らないなんてことがおきます。
ビルドできる組み合わせは頑張れば見つけられるとは思いますが、本来やりたいことはクロスビルド用のコンパイラのソースコードリポジトリをダウンロードし、自分でソースコードに何か変更を入れ、変更した内容も含めてビルドすることです(ダウンロードは最悪手動でも良いですけど)。
世の中にはクロスビルド用のツールチェーンを作成できるツールはいくつかありますが、いずれもtarballからのビルドを想定していて、改変を入れて再ビルドする方法が良くわかりません。
ツールが想定しているリリース用のビルドは、
開発用は、リリース用に加え、
が必要ですが、意外とできないです……。
いくつかツールを調べてみました。
ツールチェーン単体だとcrosstool-NGですし、将来的に追加するものを考えるとbuildrootが良さそうですけど。変更を反映して差分ビルドする方法ないのかな……??
目次: RISC-V
Linuxが動くくらいのRISC-VのSoC搭載ボードを探していたのですが、どうやらまだ市販されてなさそうでした……。
代わり(?)にSiFiveの高性能RISC-V SoCであるHiFive Unleashed(リンク)のマニュアルを眺めていました。
HiFive Unleashedは高性能と紹介されていることが多いですが、現状RISC-VはArduinoくらいの小規模SoCがほとんどで、それらと比較して高性能、と言っているのだと思われます。
特に珍しい機能もないですし、最近のテレビやタブレット向けの巨大なARM系SoCと比べると、どうしてもショボく見えてしまうのは仕方ないでしょう。
ああ、でもErrataの章があるのは珍しいかもしれません。
などの豪快なバグがある様子が伺えます。特にROCK-2のWorkaroundは全然Workaroundになっておらずのが面白いです。アクセス違反をするな、と言ってアクセス違反がなくなるならOSの苦労はないでしょ。かなり悲惨なバグです。
ボードには修正したSoCを載せるのか、バグったSoCを強引に搭載するのか、どちらなんでしょうね……。
メモ: 技術系の話はFacebookから転記しておくことにした。
目次: Linux
昨今のキャッシュを持ったCPUでは、DMAを行う際にCPUのキャッシュのフラッシュ(ダーティデータをメインメモリに書きだす、パージともいう)やインバリデート(キャッシュから消しさる、クリーンともいう)が必須です。
しかしアーキテクチャやCPUの実装によってキャッシュの操作方法は異なるため、LinuxではDMA APIというレイヤでアーキテクチャの差分を隠蔽しています。
LinuxでDMAを行うドライバを書くときの一番単純な作法(=単一の領域にDMAを行う、スキャッターギャザーなどはしない)は、
ざっくりいってこのような感じです。先ほど述べた通り、LinuxのDMA APIにキャッシュのフラッシュやインバリデート関数はありません。ハード依存の操作をなるべく減らし、多数のアーキテクチャに対応しやすくなっているんですね。
そうはいっても、実際にどこでキャッシュフラッシュしているか、気になると思います。昔、Linux 4.4を調べた情報を引っ張り出してきました。アーキテクチャはAArch64つまり64bitのARMコアです。
AArch64の場合、キャッシュ操作をしているのはdma_sync_single_for_cpu() とdma_sync_single_for_device() です。前者がインバリデート、後者がフラッシュ+インバリデートを行っています。
前者のdma_sync_single_for_cpu() を追いかけてみると、
こんな感じですね。しつこいですがAArch64の実装を見ただけですので、将来的に変わるかもしれないし、他のアーキテクチャでは仕組みが違います。
昔のLinuxではキャッシュ操作関数をドライバから使うことができました。その記憶からなのか、たまにフラッシュやインバリデートのようなアーキテクチャ依存の操作を直接呼びたがる人がいます。
今のLinuxではキャッシュ操作関数は当然ありますが、ドライバからは呼べない、つまり呼ぶことを推奨していません。もちろんオープンソースなので改造すれば何でもできますけど、メンテナンス性や再利用性、移植性を下げるだけで、損しかないでしょう。
< | 2019 | > | ||||
<< | < | 04 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | 1 | 2 | 3 | 4 | 5 | 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 | - | - | - | - |
合計:
本日: