スレッド情報ブロック( TIB ) またはスレッド環境ブロック( TEB ) は、x86上のWin32のデータ構造で、現在実行中のスレッドに関する情報を保存します。これはOS/2の同様の構造から派生したもので、32 ビット システムでは下位互換性があります。[1]
TIB はWindows 9xでは公式には文書化されていません。Windows NTシリーズのDDK (およびMinGW / ReactOSNT_TIB実装) には、サブシステムに依存しない部分を文書化する構造体が含まれていますwinnt.h。TIB が効果的に文書化される前から、多くのアプリケーションが既にそのフィールドを使い始めており、それらは事実上APIの一部となっています。特に、 SEHフレームを含む最初のフィールドは、Microsoft 独自のコンパイラによって生成されたコードによって直接参照されます。[1] TEB の Win32 サブシステム固有の部分は文書化されていませんが、Wineには に TEB 定義が含まれていますwinternl.h。[2]
TIB を使用すると、Win32 API を呼び出さずにプロセスに関する多くの情報を取得できます。例としてはGetLastError()、、のエミュレーションが挙げられます。PEBGetVersion()へのポインターを通じて、インポート テーブル (IAT)、プロセス起動引数、イメージ名などにアクセスできます。32ビット Windows では
FSセグメント レジスタから、64 ビット Windows では GS からアクセスします。
Windows 上の TIB の内容
この表はWineによるMicrosoft Windows内部の作業に基づいています。[2]
FS (32 ビットの場合) または GS (64 ビットの場合) は、TDB (スレッド データベース) と呼ばれるデータ ブロックに埋め込まれた TIB にマップされます。TIB には、スレッド固有の例外処理チェーンと TLS (スレッド ローカル ストレージ) へのポインターが含まれています。スレッド ローカル ストレージは、C ローカル ストレージと同じではありません。
TIBに保存されるスタック情報
プロセスは、TIB に格納されている情報を適宜更新する限り、スレッドのスタックを自由に移動できる必要があります。この問題で重要なフィールドは、スタック ベース、スタック制限、割り当て解除スタック、保証スタック バイトです。これらはそれぞれ、 64 ビットのオフセット0x8、0x10、0x1478に格納されます。さまざまな Windowsカーネル関数がこれらの値を読み書きしますが、これは特に、スタック オーバーフローを他の読み取り/書き込みページ フォールトと区別するためです (保証スタック バイト内のスタック制限内で保護されているページへの読み取りまたは書き込みは、アクセス違反ではなくスタック オーバーフロー例外を生成します)。割り当て解除スタックが重要なのは、Windows API で保護されているページの量を変更できるためです。関数では、現在のスペースの読み取りと拡張の両方が可能です。読み取るには、フィールドを読み取り、拡張するには、スタック ページをアンコミットするために を使用します。スタック制限を設定せずに を設定すると、で異常な動作が発生する可能性があります。たとえば、スタック制限が間違った値に上書きされます。 を呼び出すライブラリはさまざまです。たとえば、.NET CLR では、スレッドのスタックを設定するために を使用します。
0x1748SetThreadStackGuaranteeGuaranteedStackBytesDeallocationStackSetThreadStackGuaranteeSetThreadStackGuarantee
TIBへのアクセス
現在のスレッドの TIB には、セグメントレジスタFS (x86) または GS (x64)のオフセットとしてアクセスできます。
FS:[0]TIB フィールドには、 からのオフセットでアクセスするのではなく、まず に格納されている TIB フィールドへの線形自己参照ポインターを取得するのが一般的です。そのポインターは、ポインター演算で使用することも、構造体ポインターFS:[18h]にキャストすることもできます。
Microsoft Windows SDKなどを使用すると、プログラマーはwinnt.hnamedで定義されたインライン関数を使用してNtCurrentTeb、現在のスレッド情報ブロックのアドレスをとして返すことができますNT_TIB *。[4]
IA-32アーキテクチャの代替アクセス方法は次のとおりです。
// gcc (AT&T スタイルのインライン アセンブリ)。void
* getTIB ( void ) { register void * pTIB ; #if defined(__x86_64__) || defined(__amd64__) __asm__ ( "movq %%gs:0x30, %0" : "=r" ( pTIB )); #elif defined(__i386__) __asm__ ( "movl %%fs:0x18, %0" : "=r" ( pTIB )); #else #error サポートされていないアーキテクチャ#endif return pTIB ; }
// gcc (名前付きアドレス空間、-O1 または -ftree-ter のインライン アセンブリ バージョンと同じ)。void
* getTIB ( void ) { #if defined(__x86_64__) || defined(__amd64__) #ifndef __SEG_GS #error サポートされていない GCC バージョン#endif return * ( void * __seg_gs * ) 0x30 ; #elif defined( __ i386__) #ifndef __SEG_FS #error サポートされていない GCC バージョン#endif return * ( void * __seg_fs * ) 0x18 ; #else #error サポートされていないアーキテクチャ#endif }
// Microsoft C
__declspec ( naked )
void * getTIB () { __asm mov EAX , FS : [ 18 h ] __asm ret }
// インライン アセンブリの代わりに Microsoft の組み込み関数を使用する (X86 と X64 の両方のアーキテクチャで動作)
void * getTIB () { #ifdef _M_IX86 return ( void * ) __readfsdword ( 0x18 ); #elif _M_AMD64 return ( void * ) __readgsqword ( 0x30 ); #else #error サポートされていないアーキテクチャ#endif }
参照
参考文献
- ^ ab Pietrek, Matt (1996 年 5 月)。「Under The Hood」。Microsoft Systems Journal。2009年 6 月 14 日時点のオリジナルよりアーカイブ。2010年 7 月 7 日閲覧。
- ^ abcd "wine winternl.h: typedef struct _TEB". GitHub . wine-mirror. 2019年10月29日.
- ^ チャペル、ジェフ。「TEB」。
- ^ 「NtCurrentTeb 関数」 。Microsoft Docs。2019年11 月 20 日閲覧。
さらに読む
- Pietrek, Matt (1996 年 3 月)。Windows 95 プログラミングの秘密 (pdf)。IDG。pp. 136–138。ISBN 978-1-56884-318-6. 2010年7月17日閲覧。
外部リンク
- NTinternals.net の TEB レイアウト
- 構造化例外処理とTIB
- TIBの最初のスロットの説明
- TEB の分野ごとの説明
- さまざまな Windows バージョンの TEB 定義
