2018年09月20日

GCC 7以前のAArch64ターゲットでlibgccをビルドする時に-fomit-frame-pointerを付けるとC++例外が正しく動かなくなる問題

タイトルが本記事の内容のほぼ全てです。自分で libgcc をビルドするという奇特(誤用)な人以外には関係無い話ですが(※)、まあこんなこともあるんだなと。

おそらく Linux (aarch64-linux-gnu) ターゲット等でも共通だと思うのですが、現象を確認したのはベアメタル (aarch64-elf) ターゲットで、GCC 5.1/6.3 です。7.2 では発生しませんでした。(4 系でも発生すると思いますが、そもそも AArch64 のサポートが 4.8 からなので、枯れてるとは言い難い 4 系の使用自体が現在では非推奨だと思います。)



この問題は、半年ほど前、弊社の製品である exeGCC の開発中に発覚しました。それまで GCC 7.2 で順調に開発していたのですが、様々な理由により GCC のバージョンを 6.3 に下げたとたんに、C++ の例外が簡単なサンプルすら動作しなくなってしまったのです。

一つ一つ条件を地道に絞り込んで行き、libgcc の問題であること、全く同じソース、設定で、cc1(コンパイラ本体)のみを GCC 7 のものと差し替えてビルドした場合は動くこと、しかし生成アセンブラコードはほとんど同じで、違いは __builtin_eh_return() の実行時の挙動のみであること、などがわかってきて、最終的には以下の既知の問題であることがわかりました。

[AArch64] PR71951: Fix unwinding with -fomit-frame-pointer

このパッチは libgcc をビルドする時に強制的に -fno-omit-frame-pointer を付けて最適化を無効にするという非常にシンプルなものだったので、とりあえず問題自体はこのパッチをバックポートすることで解決しました。

他にも GCC 6.3 には、以下の気になる修正が入ってないので、最終的には GCC 6.4 + 上記パッチで落ち着きました。

Bug 77455 - [AArch64] eh_return implementation fails

ちょっと気になるのは、この強制 -fno-omit-frame-pointer パッチは GCC 7.3 から入ってるのですが、なぜか 7.2 では問題が発生しなかったことです。(これ自体は、コンパイラ以外の、例えばスタートアップやリンカスクリプトの設定不備の疑いを潰すのに非常に役立ち、ありがたかったのですが。もし 7.2 で動かなかったら、さらに多くの時間がかかったと思われます。)問題は解決したので、これ以上の深追いはしてないのですが。



自前で AArch64 GCC の libgcc をビルドする人はほとんどいないと思いますが、他に仕事中に見つかるような Tips はもっとはるかに特殊な条件がたくさん付き一般性が無いものばかりなので、これでもギリギリ blog のネタになるかなという。一応仕事の一環なのにブログ放置しすぎですみません。

GCC の 6 系は広く使われているので、詳しくないですが例えば Gentoo Linux や BSD みたいにユーザが独自の最適化オプションを追加して全体を make world できるような環境で、-fomit-frame-pointer -O2 なんてのは一番ポピュラーな設定ですし、大問題になったりしないのかな?とか思いますが、コンパイラなんていう最重要システムツールは特別扱いかもしれませんし、そもそも AArch64 の時点で極少数派なのかもしれませんね……。

kmckk at 16:20コメント(0)GCC | 若槻 

コメントする

名前
 
  絵文字
 
 
記事検索
最新コメント
アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

QRコード
QRコード