LLVM JIT trouble with static function.

by syoyo

さらに追記: JIT シェーダエンジンがうまく動かない件、どうもこちら側のプログラムにメモリリークがあったから、が原因で LLVM 側に問題があるということではありませんでした. また、正しく動くプログラムで確認したところ、シンボル解決もモジュール内のシンボルがルックアップされます(下で書いてあるのは間違い).

追記: JIT シェーダエンジンがうまく動かない件、どうも下記が原因のようではないようです. こちらのプログラムでどこかでメモリリークが生じているからかもしれません. 原因はいまのところ不明.

LLVM JIT シェーダエンジンを書いていて, 半日くらいはまった LLVM のバグ? らしきものについて記録として残しておきます.

おかしくなる例はこんな感じ.

ここで、main.c は LLVM の JIT エンジンのコードが含まれたバイナリを構成するソースです.
JIT エンジンは muda.c の内容を(clang などで .c -> .bc としたあとに .bc を読み込み)JIT コンパイルし, muda.c:dora() を呼び出すものとします.

muda.c:dora() は muda.c 内で static 関数である func() を呼びます.
同様の名前の関数は main.c(JIT エンジンがリンクされているバイナリ側)にもあるとします.

このとき、muda.c モジュールの JIT コンパイル時では、dora() 内で呼んでいる func() は muda.c:func() ではなくて、main.c:func() であると間違って(?)シンボル解決してしまいます. そして dora() は main.c:func() を呼び出すわけではなく, seg fault してプログラムが終了してしまいます.

LLVM JIT エンジンは実は結構よくできていて、JIT コンパイルするモジュール内で解決できないシンボルがあると、デフォルト動作では JIT エンジンが含まれているバイナリ側のシンボルからマッチするものが無いか探すようになっているようです.
もしかしたらこの動作が悪く影響しているのかもしれません.

が、static で宣言されている関数であれば、なるべくモジュール内で定義されている関数(シンボル)を優先的に採用するのが期待されるような動作の気がします.

まあこれが LLVM のバグなのかどうか、単に C か elf バイナリの仕様では曖昧なので LLVM のバグではないのか、ちょっと llvm-dev にでも聞いてみますかね.

いずれにせよ、LLVM を使って JIT コンパイルするときは、なるべくファイルスコープを外れても被らないような関数名をつけるのが良いと言うことで.

Advertisements