目次: GCC
GCCをデバッグする入り口まで辿り着くのも案外大変だったので、方法を書き残しておこうと思います。
C言語(じゃなくても良いですが)をコンパイルする際に、gcc a.cのようにコマンドを起動します。一般的にgccコマンドをコンパイラと呼びますが、正確にいえばgccはコンパイラドライバ(コンパイラ、アセンブラ、リンカを順に呼び出すプログラム)です。
GCCの場合、コンパイラはcc1という名前で、コンパイラドライバgccとは別のプログラムとして存在します。コンパイラの役目は高級言語(Cなら *.cファイル)からアセンブリ言語(*.sファイル)に変換することです。
DebianのGCC 8.0だと /usr/lib/gcc/x86_64-linux-gnu/8/cc1に置かれています。クロスコンパイラの場合は様々ですが、crostool-NGでRISC-V 64bit Linux向けにビルドした場合(ビルド方法は 2019年2月26日の日記参照)は、~/x-tools/riscv64-unknown-linux-gnu/libexec/gcc/riscv64-unknown-linux-gnu/8.2.0/cc1に置かれます。ローカルビルドしないときは、~/x-toolsをクロスコンパイラをインストールしたディレクトリで読み替えてください。
デバッガでコンパイラを追うとき、コンパイラドライバ → コンパイラだと余計な処理がたくさん挟まって邪魔なので、コンパイラ単体で起動したくなりますよね?私はなりました。特に気にならない人は読み飛ばしてください。
コンパイラcc1のオプションは、コンパイラドライバgccに渡したオプション以外にも、cc1用のオプションが渡されます。そのためcc1をシェルなどから手打ちで起動するのはちょっと難しいです。
しかし無理してコンパイラcc1のオプションを調べずとも、コンパイラドライバgccが渡すオプションをそのままパクれば良いです。gcc/gcc.cのexecute() 関数を下記のように書き換えると、cc1の起動オプションが表示されます。
diff --git a/gcc/gcc.c b/gcc/gcc.c
index a716f708259..e48e5cca79b 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -3084,6 +3084,12 @@ execute (void)
const char *errmsg;
int err;
const char *string = commands[i].argv[0];
+ int kkk;
+
+ printf("\n------------------------------\n");
+ for (kkk = 0; commands[i].argv[kkk]; kkk++)
+ printf("%s ", commands[i].argv[kkk]);
+ printf("\n------------------------------\n");
errmsg = pex_run (pex,
((i + 1 == n_commands ? PEX_LAST : 0)
出力は下記のようになります。この例では、コンパイラはRISC-V 32bitベアメタル向けを使っています。
------------------------------ /home/katsuhiro/share/projects/oss/crosstool-builder-new/buildroot/libexec/gcc/riscv32-unknown-elf/8.3.0/cc1 -quiet a.c -quiet -dumpbase a.c -march=rv32gc -mabi=ilp32d -auxbase a -o /tmp/ccdd2F4Z.s ------------------------------
この情報があれば、コマンドラインから単独で起動できますし、GDBで追うこともできます。
$ gdb /home/katsuhiro/share/projects/oss/crosstool-builder-new/buildroot/libexec/gcc/riscv32-unknown-elf/8.3.0/cc1 (gdb) b main Breakpoint 1 at 0x4308a0: main. (2 locations) (gdb) r a.c -dumpbase a.c -march=rv32gc -mabi=ilp32d -auxbase a -g -O0 -Wall -fdump-tree-all-raw -fdump-rtl-all -o a.s Starting program: /home/katsuhiro/share/projects/oss/crosstool-builder-new/buildroot/libexec/gcc/riscv32-unknown-elf/8.3.0/cc1 a.c -dumpbase a.c -march=rv32gc -mabi=ilp32d -auxbase a -g -O0 -Wall -fdump-tree-all-raw -fdump-rtl-all -o a.s Breakpoint 1, main (argc=15, argv=0x7fffffffd3c8) at /home/katsuhiro/share/projects/oss/crosstool-builder-new/./gcc/gcc/main.c:36 36 toplev toplev (NULL, /* external_timer */
ブレークポイントなども仕掛けられますし、変数の値を表示することもできます。解析がかなり楽になるはずです……たぶん。
目次: ROCK64/ROCKPro64
最近はたくさんのARMのシングルボードコンピュータ(SBC)が市販されています。嬉しい時代になりました。これからのお買い物の参考としてリストアップしました。値段は変動するので参考です。
少し古い世代のSoCを採用したボード達です。
以前(2018年8月12日の日記参照)載せた情報も含んでいます。
目次: GCC
最近GCCのコードを書き換えたり、デバッガで追ったり、GCCとお友達になろうとしています。まだ仲良くなれていませんが、入り口に立つまでが色々大変だったのと、間違いなく数カ月後に手順を忘れるので、方法を書き残しておこうと思います。
GCCのコードを書き換えて、結果を反映させるには、何らかの方法でGCCをビルドする必要があります。クロスビルド用ツールチェーンの構築は、昔の日記(2019年4月28日の日記参照)に書いたとおりです。コンパイラを追うだけで、ルートファイルシステムが必要なければ、おそらくcrosstool-NGを使うのが無難です。差分ビルドがうまく行かないので、何か変更した後に再ビルドするのがちょっと面倒ですが、それ以外は簡単で便利です。
私は再ビルドが遅くてイライラしたのと、ビルドの仕組みにも興味があったので、以前の日記(2019年4月29日の日記参照)に書いたとおり、昔作ったクロスコンパイラをビルドするMakefile(GitHubへのリンク)を改造して使っています。ブランチはorigin/develop/separate-makefileです。もうこちらを本線にしても良い気がしてきたな。
これも使い方を忘れるのでメモしておきます。手動でビルドするのとあまり変わりません。
#### ビルド用ディレクトリ $ mkdir build_my_toolchain $ cd build_my_toolchain #### 環境構築用のリポジトリ $ git clone https://github.com/katsuster/crosstool-builder $ cd crosstool-builder $ git checkout -t origin/develop/separate-makefile $ cd ../ #### GCCだけリポジトリで取得する(git diffしたいから) $ git clone https://gcc.gnu.org/git/gcc.git ## GCC-8.3.0を使う、他のバージョンでもある程度ビルドできるはず $ cd gcc $ git checkout gcc-8_3_0-release $ cd ../ #### その他の依存モジュールはtarballを使用する $ mkdir tmp $ cd tmp $ wget https://mirrors.edge.kernel.org/pub/linux/kernel/v4.x/linux-4.19.1.tar.xz $ wget https://ftp.gnu.org/gnu/binutils/binutils-2.31.1.tar.bz2 $ wget https://ftp.gnu.org/gnu/glibc/glibc-2.28.tar.xz $ wget https://ftp.gnu.org/gnu/gmp/gmp-6.1.2.tar.lz $ wget https://ftp.gnu.org/gnu/mpc/mpc-1.1.0.tar.gz $ wget https://ftp.gnu.org/gnu/mpfr/mpfr-4.0.2.tar.xz $ cd ../ #### ツールチェーンに必要なモジュール $ tar xf tmp/linux-4.19.1.tar.xz $ tar xf tmp/binutils-2.31.1.tar.bz2 $ tar xf tmp/glibc-2.28.tar.xz $ ln -s linux-4.19.1 linux $ ln -s binutils-2.31.1 binutils $ ln -s glibc-2.28 glibc #### GCCに必要なモジュール $ tar xf tmp/gmp-6.1.2.tar.lz $ tar xf tmp/mpc-1.1.0.tar.gz $ tar xf tmp/mpfr-4.0.2.tar.xz $ cd gcc $ ln -s ../gmp-6.1.2 gmp $ ln -s ../mpc-1.1.0 mpc $ ln -s ../mpfr-4.0.2 mpfr $ cd ../
自分で書いていて面倒くさいなあと思いました。スクリプトにしたほうが良かったかもしれない。もしbinutilsも変更したりデバッグしたければ、tarballの代わりにリポジトリをチェックアウトしてくると良いです。
$ source crosstool-builder/env.sh $ cd crosstool-builder $ make -j4 install
デフォルトではRISC-V 64bit Linux向けのクロスコンパイラをビルドします。env.shを書き換えればAArch64やARM向けもビルド可能です。RISC-V 32bit向けはgcc-static(ベアメタル用コンパイラとして使用可能)までしかビルドできません。以降はglibcのビルドでエラーになりLinux用のクロスコンパイラはビルドできません。
$ cd crosstool-builder $ make -f gcc-static.mk -j4 install
GCCに何か修正を入れてビルドし直すときは、ビルドし直したい *.mkファイルを指定してmake します。
目次: ROCK64/ROCKPro64
ROCKPro64のPCIeが動かなくて、しばらく放置(2019年3月16日の日記参照)していたのですが、今日久しぶりに見てみたところ、意外とあっさり直せました。
PCIeが動かなかった理由は単純で、PERST# 信号を全く制御しておらず、PCIeカードのリセットを解除していなかったためでした。それは動かないわ。
不思議なことにlinux-nextではROCKPro64以外のRK3399搭載ボードはPCIeが使えるように対応が入っているのに、ROCKPro64だけハブられています。悲しいので、作ったパッチをLKMLにぶん投げておきました。誰かの役に立てば嬉しいですね。
ちなみにROCKPro64のPCIe PERST# 信号は、こんな経路で来ていました。
RK3399 GPIO2_D4 -> PCIE_PERST_L -> PCIE_PERST_3V3_L -> PERST#
我が家にはPCIeのカードが3つあります。あります、というか、わざわざROCKPro64のPCIe接続テストのために買ったという方が正しいです。
リセットを制御していない場合、基本的にはどのボードも動きません。しかしUSB拡張カードだけはたまに動きます。不思議な挙動です。カードがPERST# を無視しているのか、偶然か、深追いしていないのでわかりません。
PERST# の制御をするように直したところ、USB 3.0カードと、SATAカードはバッチリ認識するようになりました。PCIe - PCIブリッジカードは起動中になぜかROCKPro64にリセットが掛かってしまい、うまくいきませんでした。
ROCKPro64からの給電では足りないのかと疑って、外部からブリッジカードに電源を供給してみましたが、ダメでした。PCでも使えたり使えなかったりする、割と特殊なカードらしいので、ROCKPro64では動かないのかもしれません。
さらに調べるにせよ、何にせよ、また次の機会ですね。
メモ: 技術系の話はFacebookから転記しておくことにした。多少修正。
今更ですが、メモしていなかった気がするので、Tinker Board(Rockchip RK3288搭載)でHDMI Audioを有効にする方法です。
方法は簡単でLinuxのCONFIG_DRM_DW_HDMI_I2S_AUDIOを有効にすれば良いです。5/3時点のlinux-nextのツリーでは、make defconfigするとこのコンフィグはnで、ビルド対象外になっています。手動で下記の設定を有効にする必要があります。
$ make menuconfig Device Drivers ---> Graphics support ---> Display Interface Bridges ---> [*] Synopsys Designware I2S Audio interface
設定とビルドがうまく行くと、下記のようにi2s-i2s-hifiというちょっと変わった名前のオーディオデバイスが見えるようになるはずです。
# cat /proc/asound/pcm 00-00: USB Audio : USB Audio : playback 1 : capture 1 00-01: USB Audio : USB Audio #1 : playback 1 : capture 1 00-02: USB Audio : USB Audio #2 : playback 1 01-00: ff890000.i2s-i2s-hifi i2s-hifi-0 : : playback 1
HDMIは画像と音声が一緒に転送されますから、本来は画像側のドライバも合わせて有効にする必要があるはずです。が、画像側のドライバはdefconfigでyないしmになるようで、特殊なカーネルコンフィグを使っている人以外は気にしなくて良いでしょう。
どうして音声系のドライバだけdefconfigからハブられているのか?については謎です。私は画像側のドライバと音声側のドライバ両方ともdefconfigで有効にした方が良いのでは……と思いますが、何か理由があるのでしょう。
CONFIG_DRM_DW_HDMI_I2S_AUDIOはCODEC側なので、CPU側のコンフィグCONFIG_SND_SOC_ROCKCHIP_I2Sも紹介しておきます。とはいえdefconfigで有効になるようなので、これも通常は気にしなくて良いでしょう。
目次: 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が良さそうですけど。変更を反映して差分ビルドする方法ないのかな……??
< | 2019 | > | ||||
<< | < | 05 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | - | 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 | 31 | - |
合計:
本日:
管理者: Katsuhiro Suzuki(katsuhiro( a t )katsuster.net)
This is Simple Diary 1.0
Copyright(C) Katsuhiro Suzuki 2006-2023.
Powered by PHP 8.3.8.
using GD bundled (2.1.0 compatible)(png support.)