Multi-Processor版とUni-processor版のKernelの違い
Windows NT 以降の OSは Multi CPUに対応しているため、一部のバイナリが Multi-Processor版とUni-processor版(単一CPU版) に分かれています。
代表的なのが、Kernel32.dll と ntdll.dll なのですが、この2つのファイルの場合、違いは Multi Processor版の 0xf0 命令が Uni Processor版では 0x90 に置き換わっています。
ntdllでは RtlTryEnterCriticalSection / RtlLeaveCriticalSection / RtlEnterCriticalSection などの関数群。
KERNEL32 では、
InterlockedIncrement / InterlockedExchange / InterlockedDecrement / InterlockedCompareExchange / InterlockedExchangeAdd の関数が使用しています。
0xf0 は何かというと lock prefix と呼ばれる命令で 他のプロセッサからのメモリアクセスを禁止するためにバスロックします。
参考までに、 add, adc, and, bt, btc, btr, bts, cmpxchg, cmpxchg8b, dec, inc, neg, not, or, sbb, sub, xchg, xor, xadd などの命令の前にくっつくことができます。
0x90 は nop 命令として使われますが、インストラクションとしては、 xchg eax, eax が使われています
|・ω・)ノ 知ってた?
関連サイト:
マルチプロセッサ用リアルタイムOSの解説 » ロックの実現方法
ロックおよびアトミック操作に関連する組み込み関数
あと、NTOSKRNL(or HAL)のスピンロックもユニプロセッサ版だとなにもしないコードになってたりしますよね。
以前、ユニプロセッサ版のカーネルで入れ子のスピンロックのコードを書いてしまっていて、マルチプロセッサ版の(シングルプロセッサに制限した)カーネルで動かしたらハングして「ウヴァー」ってなったのを思い出しました^^;
ありゃ、ユニプロセッサ版でスピンロックコードかけたらどうなるのか試したことはなかったんですが、アセンブラのマニュアル見ると、他プロセッサのバスアクセスをロックするって書いてますが、1CPUだと、実質自分でデッドロックかけちゃうのと等価になっちゃうんですね。