カーネル読書会 第0x40回

↓ これに行ってきた。
http://mkosaki.blog46.fc2.com/blog-entry-166.html
http://d.hatena.ne.jp/hyoshiok/20060609#p1

CPUIDの結果から、より適切なコードバイトが使えるCPUなら、起動時にコードを書き換える仕組み。
Pentium4 対応カーネルってどうなってんのかな、と思っていたのだけど、こういう仕組みなら、古いマシンで立ち上げても動くのかな。

kosakiさんのサンプルコードにて。

  誰か: この57ってなんですか?
  kosaki: (マジックナンバーとして)素数を使うと、(自分で埋め込んだという印になるから)探しやすいです。
  私: 3で割れますが…。

思わずツッコミを入れてしまいました。

皆さん、低レベルな話が大好きですね。10時過ぎまでというのは、かなり盛り上がったほうだと思います。kosakiさんありがとうございました。
よしおかさんの『「薄い話」とわざわざ言う奴ほど濃い話をするという法則』は見事的中。
次回はldsoとちらっとおっしゃっていましたので期待しています。

ちなみにapply_alternatives()で使用する7バイトのNOPは、

#define GENERIC_NOP7 ".byte 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00\n"

となっている。Intel風に書くと

  lea esi, [esi + 0]

つまり mov esi, esi なのでNOPということのようだ。(参照
prefixをつけるのかと思っていたら、そうではなく。たぶんprefixは特別な作用(で遅くなる可能性)があるので避けているのかなと。

思ったのは、add [esp + 0], 0 みたいに、メモリの読み出しを発生させる(かもしれない)NOPと、本当に何もしないNOPがあるなと。
(その辺が実際はどうなのかは、実装者にしかわからないというのが、よしおかさんの話にもあった)
lea esi, [esi + 0]も、mov esi, esiに変換されて、さらに何もしないNOPになるかもしれないし、esi + 0をALUに計算させるかもしれない。
add [eax + ebx + 0], 0みたいな方が長いんだけど、採用されていないのはその辺の理由なのだろう。
あと、AMDサポートを入れたときには8バイトNOPがサポートされるというのを聞いて、それだとIntel CPUで動かなくなるんじゃないのかと思ったんだけど、そこは微妙。

#define K8_NOP4 ".byte 0x66,0x66,0x66,0x90\n" 
#define K8_NOP8 K8_NOP4 K8_NOP4

とかになってる。なんじゃこりゃ。
0x66は32bit prefixで、0x90はNOP。たぶんAMD系は同じprefixを繰り返してもオッケーで、ペナルティが無視できるくらい小さいのだろう。

そういえばx86は、命令長が1バイトから?バイトくらいまである超変態命令セット。そんな「異端児」が何年も改良され続けているのがすごい。
で、最大何バイトだっけか、と思ったら、よくわからない。

1〜15バイト説
http://www.atmarkit.co.jp/fpc/rensai/zunouhoudan001/pentium3vsathlon.html

100バイト以上説
http://www2.nsknet.or.jp/~azuma/nu/nu0025.htm

15バイトに、prefixをいくらでもつけられるから、100バイトを超える、という理解でいいのかな。