La Tabla de descriptores globales ( GDT ) es una estructura de datos utilizada por los procesadores de la familia Intel x86 que comienzan con el 80286 para definir las características de las diversas áreas de memoria utilizadas durante la ejecución del programa, incluida la dirección base, el tamaño y los privilegios de acceso como ejecutabilidad y capacidad de escritura. Estas áreas de memoria se denominan segmentos en la terminología de Intel.
Tabla de descriptores globales
El GDT también puede contener otros elementos además de los descriptores de segmento . Cada entrada de 8 bytes en el GDT es un descriptor, pero estos descriptores pueden ser referencias no solo a segmentos de memoria sino también a segmentos de estado de tarea (TSS), tabla de descriptores locales (LDT) o estructuras de puerta de llamada en la memoria. Los últimos, Call Gates, son particularmente importantes para transferir el control entre niveles de privilegios x86, aunque este mecanismo no se utiliza en la mayoría de los sistemas operativos modernos.
También hay una tabla de descriptores locales (LDT). Se pueden definir múltiples LDT en el GDT, pero solo uno está actualizado a la vez: generalmente asociado con la Tarea actual. Mientras que el LDT contiene segmentos de memoria que son privados para un programa específico, el GDT contiene segmentos globales. Los procesadores x86 tienen funciones para cambiar automáticamente el LDT actual en eventos específicos de la máquina, pero no tienen facilidades para cambiar automáticamente el GDT.
Cada acceso a la memoria que puede realizar un programa siempre pasa por un segmento. En el procesador 80386 y posteriores, debido a las compensaciones y límites de segmentos de 32 bits , es posible hacer que los segmentos cubran toda la memoria direccionable, lo que hace que el direccionamiento relativo al segmento sea transparente para el usuario.
Para hacer referencia a un segmento, un programa debe usar su índice dentro de la GDT o la LDT. Dicho índice se denomina selector de segmento (o selector). Por lo general, el selector debe cargarse en un registro de segmento para su uso. Aparte de las instrucciones de la máquina que permiten establecer / obtener la posición del GDT y de la Tabla de descriptores de interrupciones (IDT), en la memoria, cada instrucción de la máquina que hace referencia a la memoria tiene un Registro de segmento implícito, ocasionalmente dos. La mayoría de las veces, este registro de segmento se puede anular agregando un prefijo de segmento antes de la instrucción.
La carga de un selector en un registro de segmento lee automáticamente el GDT o el LDT y almacena las propiedades del segmento dentro del propio procesador. Las modificaciones posteriores al GDT o LDT no serán efectivas a menos que se vuelva a cargar el registro de segmento.
Ejemplo de GDT
A continuación se muestra una implementación de ensamblaje de un GDT que abre los 4 GB de memoria disponible:
- base = 0x00000000, límite de segmento = 0xffffffff
; Desplazamiento 0x0 . Descriptor nulo : dq 0; compensado 0x8 .code: ; cs debe apuntar a este descriptor dw 0xffff ; límite de segmento primero 0-15 bits dw 0 ; base primero 0-15 bits db 0 ; base 16-23 bits db 0x9a ; byte de acceso db 11001111 b ; alto 4 bits (banderas) bajo 4 bits (límite 4 últimos bits) (el límite es de 20 bits de ancho) db 0 ; base 24-31 bits; desplazamiento 0x10 .data: ; ds, ss, es, fs y gs deben apuntar a este descriptor dw 0xffff ; límite de segmento primero 0-15 bits dw 0 ; base primero 0-15 bits db 0 ; base 16-23 bits db 0x92 ; byte de acceso db 11001111 b ; alto 4 bits (banderas) bajo 4 bits (límite 4 últimos bits) (el límite es de 20 bits de ancho) db 0 ; base 24-31 bits
GDT en 64 bits
El GDT todavía está presente en el modo de 64 bits; se debe definir un GDT, pero generalmente nunca se cambia ni se usa para la segmentación. El tamaño del registro se ha ampliado de 48 a 80 bits, y los selectores de 64 bits son siempre "planos" (por lo tanto, de 0x0000000000000000 a 0xFFFFFFFFFFFFFFFF). Sin embargo, la base de FS y GS no está restringida a 0, y continúan utilizándose como indicadores del desplazamiento de elementos como el bloque del entorno del proceso y el bloque de información del hilo.
Si se borra el bit del sistema (cuarto bit del campo de acceso), el tamaño del descriptor es de 16 bytes en lugar de 8. Esto se debe a que, aunque se ignoran los segmentos de código / datos, los TSS no lo son, pero el puntero de TSS se puede cambiar. 64 bits de longitud y, por lo tanto, el descriptor necesita más espacio para insertar la dword más alta del puntero TSS.
64-bit versiones de Windows prohíben enganche de la GDT; intentar hacerlo hará que la máquina realice una comprobación de errores . [1]
Tabla de descriptores locales
Una tabla de descriptores locales ( LDT ) es una tabla de memoria utilizada en la arquitectura x86 en modo protegido y que contiene descriptores de segmentos de memoria , al igual que GDT: inicio de dirección en memoria lineal, tamaño, capacidad de ejecución, capacidad de escritura, privilegio de acceso, presencia real en memoria, etc.
Los LDT son hermanos de la Tabla de descriptores globales (GDT) y cada uno define hasta 8192 segmentos de memoria accesibles a los programas; tenga en cuenta que, a diferencia del GDT, la entrada cero es una entrada válida y se puede utilizar como cualquier otra entrada LDT. También tenga en cuenta que a diferencia del GDT, la LDT no se puede utilizar para almacenar ciertas entradas del sistema: DST o LDT. Sin embargo, las puertas de llamada y las puertas de tareas están bien.
Historia
En los procesadores x86 que no tienen funciones de paginación, como el Intel 80286 , el LDT es esencial para implementar espacios de direcciones separados para múltiples procesos. En general, habrá una LDT por proceso de usuario, que describirá la memoria privada, mientras que la memoria compartida y la memoria del núcleo serán descritas por la GDT. El sistema operativo cambiará el LDT actual cuando programe un nuevo proceso, use la instrucción de máquina LLDT o cuando use un TSS . Por el contrario, el GDT generalmente no se cambia (aunque esto puede suceder si los monitores de máquinas virtuales como VMware se están ejecutando en la computadora).
La falta de simetría entre ambas tablas se subraya por el hecho de que el LDT actual se puede activar automáticamente en ciertos eventos, especialmente si se utiliza la multitarea basada en TSS , mientras que esto no es posible para el GDT. El LDT tampoco puede almacenar ciertos tipos de segmentos de memoria privilegiados (por ejemplo, TSSes). Finalmente, el LDT se define en realidad mediante un descriptor dentro del GDT, mientras que el GDT se define directamente mediante una dirección lineal.
La creación de memoria compartida a través de GDT tiene algunos inconvenientes. Cabe destacar que dicha memoria es visible para todos los procesos y con los mismos derechos. Para restringir la visibilidad y diferenciar la protección de la memoria compartida, por ejemplo para permitir solo el acceso de solo lectura para algunos procesos, se pueden usar entradas LDT separadas, apuntadas a las mismas áreas de memoria física y solo creadas en las LDT de los procesos que han solicitado acceso a un área de memoria compartida determinada.
Las entradas LDT (y GDT) que apuntan a áreas de memoria idénticas se denominan alias . Los alias también se crean normalmente para obtener acceso de escritura a segmentos de código: no se puede usar un selector ejecutable para escribir. (Los programas en modo protegido construidos en el llamado modelo de memoria diminuta , donde todo está ubicado en el mismo segmento de memoria, deben usar selectores separados para código y datos / pila, haciendo que ambos selectores también sean técnicamente "alias"). GDT, también se crean alias para obtener acceso a segmentos del sistema como los TSSes.
Los segmentos tienen una bandera "Presente" en sus descriptores, lo que les permite ser eliminados de la memoria si surge la necesidad. Por ejemplo, los segmentos de código o los segmentos de datos no modificados se pueden desechar y los segmentos de datos modificados se pueden intercambiar en el disco. Sin embargo, debido a que es necesario operar segmentos enteros como una unidad, es necesario limitar su tamaño para garantizar que el intercambio se realice de manera oportuna. Sin embargo, el uso de segmentos más pequeños y fáciles de intercambiar significa que los registros de segmento deben recargarse con más frecuencia, lo que en sí mismo es una operación que requiere mucho tiempo.
Uso moderno
El microprocesador Intel 80386 introdujo la paginación , que asigna páginas de memoria física separadas (en sí mismas unidades muy pequeñas de memoria) en las mismas direcciones virtuales, con la ventaja de que la paginación de disco es mucho más rápida y eficiente que el intercambio de segmentos. Por lo tanto, los sistemas operativos x86 modernos de 32 bits utilizan muy poco LDT, principalmente para ejecutar código heredado de 16 bits .
Si el código de 16 bits necesita ejecutarse en un entorno de 32 bits mientras se comparte memoria (esto sucede, por ejemplo, cuando se ejecutan programas OS / 2 1.x en OS / 2 2.0 y posteriores), el LDT debe escribirse de tal manera que cada La dirección plana (paginada) también tiene un selector en el LDT (por lo general, esto da como resultado que el LDT se llene con entradas de 64 KiB). Esta técnica a veces se denomina mosaico LDT . El tamaño limitado del LDT significa que el espacio virtual de direcciones planas debe limitarse a 512 megabytes (8191 veces 64 KiB); esto es lo que sucede en OS / 2, aunque esta limitación se corrigió en la versión 4.5. También es necesario asegurarse de que los objetos asignados en el entorno de 32 bits no crucen los límites de 64 KiB; esto genera algo de desperdicio de espacio de direcciones.
Si el código de 32 bits no tiene que pasar objetos de memoria arbitrarios a código de 16 bits, por ejemplo, presumiblemente en la emulación OS / 2 1.x presente en Windows NT o en la capa de emulación de Windows 3.1 , no es necesario limitar artificialmente la tamaño del espacio de direcciones de 32 bits.
Referencias
- ^ "Política de parcheo para sistemas basados en x64" .
Si el sistema operativo detecta una de estas modificaciones o cualquier otro parche no autorizado, generará una verificación de errores y apagará el sistema.