¿Cada región en el diagrama es un segmento?
Estos son 2 usos casi totalmente diferentes de la palabra "segmento"
- Segmentación x86 / registros de segmento: los sistemas operativos x86 modernos utilizan un modelo de memoria plana donde todos los segmentos tienen la misma base = 0 y límite = máximo en el modo de 32 bits, lo mismo que el hardware impone que en el modo de 64 bits , lo que hace que la segmentación sea un vestigio . (Excepto FS o GS, utilizado para almacenamiento local de subprocesos incluso en modo de 64 bits).
- Vinculador / cargador de programas secciones / segmentos. ( ¿Cuál es la diferencia de sección y segmento en formato de archivo ELF )
Los usos tienen un origen común: si estaba utilizando un modelo de memoria segmentada (especialmente sin memoria virtual paginada), es posible que los datos y las direcciones BSS sean relativos a la base del segmento DS, la pila relativa a la base SS y el código relativo a la Dirección base de CS.
Por lo tanto, se pueden cargar múltiples programas diferentes en diferentes direcciones lineales, o incluso moverlos después de comenzar, sin cambiar los desplazamientos de 16 o 32 bits en relación con las bases de segmento.
Pero luego debe saber a qué segmento se refiere un puntero, por lo que tiene "punteros lejanos" y así sucesivamente. (Los programas x86 de 16 bits reales a menudo no necesitaban acceder a su código como datos, por lo que podrían usar un segmento de código de 64k en algún lugar, y tal vez otro bloque de 64k con DS = SS, con la pila creciendo desde grandes compensaciones y datos en la parte inferior, o un pequeño modelo de código con todas las bases de segmentos iguales).
Cómo interactúa la segmentación x86 con la paginación
La asignación de direcciones en modo de 32/64 bits es:
- segmento: desplazamiento (base de segmento implicada por el registro que contiene el desplazamiento, o anulado con un prefijo de instrucción)
- Dirección virtual lineal de 32 o 64 bits = base + desplazamiento. (En un modelo de memoria plana como el que usa Linux, punteros / desplazamientos = direcciones lineales también. Excepto cuando se accede a TLS en relación con FS o GS).
Las tablas de páginas (almacenadas en caché por TLB) se asignan linealmente a 32 (modo heredado), 36 (PAE heredado) o dirección física de 52 bits (x86-64). ( /programming/46509152/why-in-64bit-the-virtual-address-are-4-bits-short-48bit-long-compared-with-the ).
Este paso es opcional: la paginación debe habilitarse durante el arranque configurando un bit en un registro de control. Sin paginación, las direcciones lineales son direcciones físicas.
Tenga en cuenta que la segmentación no le permite usar más de 32 o 64 bits de espacio de direcciones virtuales en un solo proceso (o subproceso) , porque el espacio de direcciones plano (lineal) en el que se asigna todo solo tiene el mismo número de bits que los propios desplazamientos. (Este no fue el caso para x86 de 16 bits, donde la segmentación fue realmente útil para usar más de 64k de memoria con registros y compensaciones en su mayoría de 16 bits).
La CPU almacena en caché los descriptores de segmento cargados desde el GDT (o LDT), incluida la base del segmento. Cuando desreferencia un puntero, según el registro en el que se encuentre, el valor predeterminado es DS o SS como segmento. El valor del registro (puntero) se trata como un desplazamiento desde la base del segmento.
Como la base del segmento es normalmente cero, las CPU hacen esto en casos especiales. O desde otro punto de vista, si hacer una base de segmento distinto de cero, las cargas tienen una latencia adicional porque el caso (normal) "especial" de pasar por la adición de la dirección de base no se aplica.
Cómo Linux configura los registros de segmento x86:
La base y el límite de CS / DS / ES / SS son todos 0 / -1 en modo de 32 y 64 bits. Esto se denomina modelo de memoria plana porque todos los punteros apuntan al mismo espacio de direcciones.
(Los arquitectos de CPU de AMD neutralizaron la segmentación al aplicar un modelo de memoria plana para el modo de 64 bits porque los sistemas operativos principales no lo usaban de todos modos, excepto por la protección no ejecutiva que se proporcionó de una manera mucho mejor al paginar con el PAE o x86- Formato de tabla de 64 páginas).
TLS (Thread Local Storage): FS y GS no están fijos en base = 0 en modo largo. (Eran nuevos con 386, y no fueron utilizados implícitamente por ninguna instrucción, ni siquiera las rep
instrucciones de cadena que usan ES). x86-64 Linux establece la dirección base FS para cada subproceso en la dirección del bloque TLS.
Por ejemplo, mov eax, [fs: 16]
carga un valor de 32 bits de 16 bytes en el bloque TLS para este hilo.
el descriptor de segmento CS elige en qué modo se encuentra la CPU (modo protegido de 16/32/64 bits / modo largo). Linux usa una sola entrada GDT para todos los procesos de espacio de usuario de 64 bits y otra entrada GDT para todos los procesos de espacio de usuario de 32 bits. (Para que la CPU funcione correctamente, DS / ES también debe establecerse en entradas válidas, y también lo hace SS). También elige el nivel de privilegio (kernel (anillo 0) vs. usuario (anillo 3)), por lo que incluso al regresar al espacio de usuario de 64 bits, el núcleo todavía tiene que organizar el cambio de CS, usando iret
o en sysret
lugar de un normal instrucción de salto o ret.
En x86-64, el syscall
punto de entrada usa swapgs
para voltear GS del GS del espacio de usuario al kernel, que usa para encontrar la pila de kernel para este hilo. (Un caso especializado de almacenamiento local de subprocesos). La syscall
instrucción no cambia el puntero de la pila para apuntar a la pila del núcleo; todavía apunta a la pila de usuarios cuando el núcleo alcanza el punto de entrada 1 .
DS / ES / SS también debe establecerse en descriptores de segmento válidos para que la CPU funcione en modo protegido / modo largo, aunque la base / límite de esos descriptores se ignore en modo largo.
Básicamente, la segmentación x86 se usa para TLS y para el material osdev x86 obligatorio que el hardware requiere que haga.
Nota al pie 1: Historia divertida: hay archivos de listas de correo de mensajes entre desarrolladores de kernel y arquitectos de AMD de un par de años antes del lanzamiento del silicio AMD64, lo que da como resultado ajustes en el diseño de syscall
modo que sea utilizable. Vea los enlaces en esta respuesta para más detalles.