自分でC文字列ライブラリを実装しようとすると、glibcとLinuxカーネルでは一部の関数を実装する方法が異なることがわかりました。たとえば、 glibc memchr および glibc strchr は、関数を高速化するためにいくつかのトリックを使用しますが、 カーネルmemchr および カーネルstrchr しないでください。 Linuxカーネル機能がglibcのように最適化されないのはなぜですか?
カーネルはこれらの関数のいくつかの最適化されたバージョンをArch固有のディレクトリに持っています。例えば memchr
のx86実装 を参照してください( all memchr
definition および all strchr
定義 )。見つかったバージョンは、代替の汎用バージョンです。保護チェック、memchr
の場合は#ifndef __HAVE_Arch_MEMCHR
、strchr
の場合は#ifndef __HAVE_Arch_STRCHR
を探すことで、これらを見つけることができます。
Cライブラリの最適化されたバージョンは、より洗練されたコードを使用する傾向があります。そのため、上記では、カーネルが高速化するためにそれほど長い時間を費やさない理由を説明していません。これらの関数のいずれかのより最適化されたバージョンからカーネルが恩恵を受けるシナリオを見つけることができる場合、パッチが歓迎されると思います(適切な裏付けがあり、最適化された関数がまだ理解可能である限り、 memcpy
)に関するこの古い議論。しかし、これらの関数をカーネルで使用しても、価値があるとは言えません。たとえば、memcpy
および関連する関数は、カーネル内の小さなバッファーで使用される傾向があります。そして、キャッシュに収まるかインライン化できる短い関数からの速度向上を決して軽視しないでください...
さらに、 Iwillnotexist Idonotexist 、 MMXおよびSSEはカーネルで簡単に使用できない 、および多くの最適化されたバージョンで言及されていますメモリ検索またはコピー機能はこれらに依存しています。
多くの場合、使用されるバージョンはとにかく コンパイラの組み込みバージョン であり、これらは大幅に最適化されており、Cライブラリの場合よりもはるかに最適化されています(たとえば、memcpy
は多くの場合、レジスタのロードとストア、または定数ストアに変換されます)。
mkisofs
以外で作成されたISO-9660 + Rock Ridgeファイルシステムでトリガーされた、2006年のSolarisのカーネルコアダンプバグを修正する必要があったことを覚えています。
そのISOフォーマットソフトウェアは、ISO -9660ディレクトリエントリの中央に(mkisofs
によって行われるように)Rock Ridgeファイル名を含めず、ISO-9660ディレクトリエントリの末尾に含めました。次に、Rock Ridgeのファイル名がnullバイトで終了していないことを知る必要があります...
何が起こったのかというと、Solarisカーネルの(当時はあまりにも最適化された)文字列ルーチンが1つオーバーシュートし、Rock Ridgeファイル名が2kセクターの最後で正確に終わり、そのセクターがちょうど最後で終わった場合です。 4kカーネルメモリページの場合、このオーバーシュートアクセスにより、不正なメモリアクセスが原因でカーネルパニックが発生しました。
将来このカーネルパニックを防ぐために、アクセスコードを非常に保守的なものに書き直す必要がありました。
ご覧のように、カーネルの安全なコードを書くのははるかに難しい場合があり、そのようなコードは、カーネルパニックを回避するためだけに、場合によっては少し遅くなります。
ところで:MMUの終わりに到達する可能性がある場合、リンカーのセグメントの後に数バイトを追加させることで、ユーザー空間プログラムのCPUからの潜在的に予測不可能なプリフェッチの問題を処理できます。 =ページこれは、マッピング領域に依存するカーネルでは機能しません。