swapgs命令
x64で追加された命令のひとつにswapgs(Swap GS Base Register)がある。この命令は、
現在の GS ベースレジスタ値を、MSR アドレス C0000102H(MSR_KERNELGSbase)に格納された値と交換する。
――インテル® エクステンデッド・メモリ 64 テクノロジ・ソフトウェア・デベロッパーズ・ガイド 第 2巻(全 2巻)
特権命令で、Windowsカーネルにおいてもよく利用されている。しかし、なぜこんなチープな命令が新設されたか疑問に思ったので調べてみると、どうやら、x86のsysenterに相当するx64のsyscall命令がRSPの値を更新しないため、なんらかの方法でRSPをカーネル用に設定する必要にせまられ、その対応としてできた命令らしい。
SWAPGSは、KernelGSbase MSRのCPL 0データポインタをGSベースレジスタと交換する。するとカーネルは、通常のメモリ参照でGS プリフィックスを使用してカーネルデータ構造体にアクセスできるようになる。
ここでいうカーネル構造体は、Windowsでは KPCR 構造体である。以下は Win7 x64 における割り込み関連関数のひとつで、swapgsのあとに gs 経由で rsp の値を更新している。
nt!KiSystemCall64: fffff800`0307df40 0f01f8 swapgs fffff800`0307df43 654889242510000000 mov qword ptr gs:[10h],rsp fffff800`0307df4c 65488b2425a8010000 mov rsp,qword ptr gs:[1A8h] ...
1: kd> dt nt!_kpcr -r1 +0x000 NtTib : _NT_TIB +0x000 GdtBase : Ptr64 _KGDTENTRY64 +0x008 TssBase : Ptr64 _KTSS64 +0x010 UserRsp : Uint8B +0x018 Self : Ptr64 _KPCR +0x020 CurrentPrcb : Ptr64 _KPRCB ... +0x118 PcrAlign1 : [24] Uint4B +0x180 Prcb : _KPRCB +0x000 MxCsr : Uint4B +0x004 LegacyNumber : UChar +0x005 ReservedMustBeZero : UChar +0x006 InterruptRequest : UChar +0x007 IdleHalt : UChar +0x008 CurrentThread : Ptr64 _KTHREAD +0x010 NextThread : Ptr64 _KTHREAD +0x018 IdleThread : Ptr64 _KTHREAD +0x020 NestingLevel : UChar +0x021 PrcbPad00 : [3] UChar +0x024 Number : Uint4B +0x028 RspBase : Uint8B ...
いろいろ調べごとをしているが、x64は私にとってかなり未知な部分が多くて面白い。