以前、hdk神からLinuxカーネルは最適化を有効にしないとコンパイルできないという話を聞いたのですが、詳解Linuxカーネルをパラパラと読んでいたら理由が書いてありました。
この不思議な現象を生み出す原因はfix_to_virt関数にあります。どのアーキテクチャにもあると思います。ざっと確認した限りではmips, sh, x86_64, sparc, i386, umに同様の関数が定義されていました(ファイル名はasm/fixmap.h)。
例えばmipsのコードを見ると、以下のようになっています。
static inline unsigned long fix_to_virt(const unsigned int idx)
{
/*
* this branch gets completely eliminated after inlining,
* except when someone tries to use fixaddr indices in an
* illegal way. (such as mixing up address types or using
* out-of-range indices).
*
* If it doesn't get removed, the linker will complain
* loudly with a reasonably clear error message..
*/
if (idx >= __end_of_fixed_addresses)
__this_fixmap_does_not_exist();
return __fix_to_virt(idx);
}
引数idxには必ず __end_of_fixed_addresses未満の定数を渡します。するとこのコードが最適化される際にifの条件が評価され、if文が常に成立しないことがわかります。コンパイラはifブロックを全て消しさってから、呼び出し元の関数に埋め込み(インライン展開)ます。
__end_of_fixed_addressesってのは、各アーキテクチャの固定メモリマップのアドレスを定義するfixed_addresses列挙型の最後に置かれる定数です。値そのものより「どの固定メモリマップアドレスよりも大きい」ことが重要です。この値を越えたアドレスへのアクセスは不正なアクセスなのです。
mipsでは以下のような列挙型で定義されています。
enum fixed_addresses {
#define FIX_N_COLOURS 8
FIX_CMAP_BEGIN,
#ifdef CONFIG_MIPS_MT_SMTC
FIX_CMAP_END = FIX_CMAP_BEGIN + (FIX_N_COLOURS * NR_CPUS),
#else
FIX_CMAP_END = FIX_CMAP_BEGIN + FIX_N_COLOURS,
#endif
#ifdef CONFIG_HIGHMEM
/* reserved pte's for temporary kernel mappings */
FIX_KMAP_BEGIN = FIX_CMAP_END + 1,
FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
#endif
__end_of_fixed_addresses
};
正しくない引数(変数や __end_of_fixed_addresses以上の定数)を渡す呼び出しがあると、if文が消去できず __this_fixmap_does_not_exist関数の呼び出しが残ります。しかしこの関数はどこにも定義されていないため、リンク時にエラーになるのです。
つまりこのif文は、最適化によって消去されることを前提に作ってあります。逆に言うと、最適化しなければ正しい呼び出しでも __this_fixmap_does_not_exist関数の呼び出しが残ってしまってコンパイルが通らないことを意味しています。
こうすることで実行時のチェックを省略できて速くなるのでしょうけど、gccの挙動にべったり依存しています。この技を使わずとも実現できる何か良い方法は無かったのかなあ…。
< | 2008 | > | ||||
<< | < | 03 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | - | - | - | - | 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 | - | - | - | - | - |
合計:
本日: