El bloque de información de subprocesos ( TIB ) o el bloque de entorno de subprocesos ( TEB ) es una estructura de datos en Win32 en x86 que almacena información sobre el subproceso que se está ejecutando actualmente . Desciende de, y es compatible con versiones anteriores, sistemas de 32 bits con una estructura similar en OS/2 . [1]
El TIB no está oficialmente documentado para Windows 9x . El DDK de la serie Windows NT (así como la implementación MinGW / ReactOS ) incluye una estructura que documenta la parte independiente del subsistema. Incluso antes de que TIB se documentara efectivamente, muchas aplicaciones ya habían comenzado a usar sus campos y son efectivamente parte de la API . El primer campo que contiene el marco SEH , en particular, está directamente referenciado por el código producido por el propio compilador de Microsoft. [1] La parte del TEB específica del subsistema Win32 no está documentada, pero Wine incluye una definición de TEB en . [2]NT_TIB
winnt.h
winternl.h
El TIB se puede utilizar para obtener mucha información sobre el proceso sin llamar a la API Win32. Los ejemplos incluyen emular GetLastError()
, GetVersion()
. A través del puntero al PEB se puede obtener acceso a las tablas de importación (IAT), argumentos de inicio del proceso, nombre de la imagen, etc. Se accede desde el registro del segmento FS en Windows de 32 bits y GS en Windows de 64 bits.
Esta tabla se basa en el trabajo de Wine en los componentes internos de Microsoft Windows . [2]
FS (para 32 bits) o GS (para 64 bits) se asigna a un TIB que está integrado en un bloque de datos conocido como TDB (base de datos de subprocesos). El TIB contiene la cadena de manejo de excepciones específica del subproceso y un puntero al TLS (almacenamiento local del subproceso). El almacenamiento local del subproceso no es lo mismo que el almacenamiento local de C.
Un proceso debería tener libertad para mover la pila de sus subprocesos siempre que actualice la información almacenada en el TIB en consecuencia. Algunos campos son clave para este asunto: base de pila, límite de pila, pila de desasignación y bytes de pila garantizados, almacenados respectivamente en desplazamientos 0x8
, 0x10
y 0x1478
en 0x1748
64 bits. Diferentes funciones del kernel de Windows leen y escriben estos valores, especialmente para distinguir los desbordamientos de pila de otras fallas de lectura/escritura de páginas (una lectura o escritura en una página protegida entre los límites de la pila en bytes de pila garantizados generará una excepción de desbordamiento de pila en lugar de un acceso). violación). La pila de desasignación es importante porque la API de Windows permite cambiar la cantidad de páginas protegidas: la función SetThreadStackGuarantee
permite tanto leer el espacio actual como aumentarlo. Para leerlo, lee el GuaranteedStackBytes
campo y, para hacerlo crecer, utiliza las páginas de la pila para descomprimir. Establecer límites de pila sin configurar DeallocationStack
probablemente provocará un comportamiento extraño en archivos SetThreadStackGuarantee
. Por ejemplo, sobrescribirá los límites de la pila con valores incorrectos. Diferentes bibliotecas llaman a SetThreadStackGuarantee
, por ejemplo, .NET CLR lo usa para configurar la pila de sus subprocesos.
Se puede acceder al TIB del hilo actual como un desplazamiento del registro de segmento FS (x86) o GS (x64).
No es común acceder a los campos TIB mediante un desplazamiento desde FS:[0]
, sino obtener primero un puntero lineal de autorreferencia almacenado en FS:[18h]
. Ese puntero se puede usar con aritmética de punteros o convertirse en un puntero de estructura .
Usando el SDK de Microsoft Windows o similar, un programador podría usar una función en línea definida en winnt.h
nombrado NtCurrentTeb
que devuelve la dirección del bloque de información del subproceso actual como NT_TIB *
. [4]
Los métodos alternativos de acceso para arquitecturas IA-32 son los siguientes:
// gcc (ensamblaje en línea estilo AT&T). vacío * getTIB ( vacío ) { registro vacío * pTIB ; #si está definido(__x86_64__) || definido(__amd64__) __asm__ ( "movq %%gs:0x30, %0" : "=r" ( pTIB )); #elif definido(__i386__) __asm__ ( "movl %%fs:0x18, %0" : "=r" ( pTIB )); #else #error arquitectura no compatible #endif return pTIB ; }
// gcc (espacios de direcciones con nombre, igual que la versión ensamblada en línea en -O1 o -ftree-ter). vacío * getTIB ( vacío ) { #si está definido (__x86_64__) || definido(__amd64__) #ifndef __SEG_GS #error versión GCC no compatible #endif return * ( void * __seg_gs * ) 0x30 ; #elif definido(__i386__) #ifndef __SEG_FS #error versión GCC no compatible #endif return * ( void * __seg_fs * ) 0x18 ; #else #error arquitectura no compatible #endif }
// Microsoft C __declspec ( desnudo ) void * getTIB () { __asm mov EAX , FS : [ 18 h ] __asm ret }
// Usando los elementos intrínsecos de Microsoft en lugar del ensamblaje en línea (funciona para arquitecturas X86 y X64) void * getTIB () { #ifdef _M_IX86 return ( void * ) __readfsdword ( 0x18 ); #elif _M_AMD64 return ( void * ) __readgsqword ( 0x30 ); #else #error arquitectura no compatible #endif }