MMU y segmentación
🎯 Al terminar podrás
- Distinguir dirección lógica y física, y decir cuándo coinciden según el momento del binding.
- Traducir con base y límite: física = base + offset, solo si offset < límite.
- Partir una dirección en (segmento, offset) según los bits de cada parte, y detectar el segmentation fault (offset ≥ límite o s ≥ STLR).
- Comparar segmentación y paginación: quién divide el programa, qué fragmentación tiene cada una y si la traducción suma o concatena.
Antes necesitas: Binario y hexadecimal (agrupar de a 4 bits)
- Visual mira el diagrama o la tabla y explica qué cambia en cada paso
- Laboratorio sube la escalera: resuelto → completa → solo → variante
- Simulador predice el estado antes de pulsar el paso siguiente
Dirección lógica vs física
Sección titulada «Dirección lógica vs física»- Lógica (virtual): la genera la CPU; es lo que ve el programa.
- Física: la que ve la unidad de memoria.
- Son iguales con binding en tiempo de compilación o carga, y distintas con binding en tiempo de ejecución.
Cada proceso (y el kernel) tiene su propio espacio de direcciones. La MMU traduce de la vista de la CPU a la vista de la memoria. Con traducción, la protección es fácil: si A ni siquiera puede nombrar los datos de B, no puede dañarlos. Además, todos los programas pueden enlazarse en la misma región virtual.
MMU con registro de relocalización
Sección titulada «MMU con registro de relocalización»El esquema más simple es un registro base (llamado registro de relocalización), que se suma a cada dirección, más un registro límite para la protección:
Si no se cumple, se genera una trampa al SO. MS-DOS en 8086 usaba 4 registros de este tipo (CS, DS, SS y ES). En un cambio de contexto, el SO carga la base y el límite del nuevo proceso, que forman parte del PCB.
Segmentación
Sección titulada «Segmentación»El programa se ve como un conjunto de segmentos lógicos de tamaño variable (código, datos, stack, compartido…). Cada dirección es un par (segmento, offset) y hay una tabla de segmentos con (base, límite, permisos) por entrada.
- ✔ Refleja la estructura modular del programa, así que protección y compartición salen por segmento.
- ✘ Los segmentos son de tamaño variable, así que hay fragmentación externa, como en las particiones dinámicas.
Arquitectura de la segmentación (diapositivas)
Sección titulada «Arquitectura de la segmentación (diapositivas)»1. Cómo traduce el hardware una dirección
Sección titulada «1. Cómo traduce el hardware una dirección»Se usa el ejemplo de arriba, (1, 50). El hardware hace dos controles antes de sumar. Primero mira si el segmento existe (s < STLR). Luego, en la entrada de la tabla, mira si es válida y si el permiso alcanza, y si el offset cabe (d < límite). Si algo falla, hay trampa al SO. Si todo pasa, física = base + d.
- La dirección lógica es el par ⟨número de segmento s, offset d⟩.
- STLR (Segment-Table Length Register) dice cuántos segmentos hay. STBR (Segment-Table Base Register) dice dónde está la tabla en la RAM. La entrada de s se encuentra en STBR + s.
- Cada entrada guarda la base (dónde empieza el segmento en la RAM), el límite (cuánto mide), un bit de validez V (0 = segmento ilegal) y permisos R/W/X.
2. Lo que ve el programa vs dónde queda en la RAM
Sección titulada «2. Lo que ve el programa vs dónde queda en la RAM»Para el programa, cada segmento empieza en 0. En la RAM, los segmentos quedan donde haya espacio, en cualquier orden y sin estar juntos. Como miden distinto, ubicarlos es un problema de asignación dinámica (first-fit, best-fit…), igual que en las particiones dinámicas, y entre ellos quedan huecos.
3. Protección y compartición por segmento
Sección titulada «3. Protección y compartición por segmento»Dos procesos que usan el mismo editor apuntan su segmento de código a la misma base (4000). El código se carga una sola vez. Cada uno tiene sus datos propios. Como el permiso va por segmento, el código queda R-X (nadie lo puede modificar) y los datos RW-.
4. El caso real: x86 (80386)
Sección titulada «4. El caso real: x86 (80386)»En x86, el segmento no sale de los bits de la dirección: lo nombra la instrucción, mediante un registro de segmento. El registro guarda un selector, que elige un descriptor de la GDT (global) o de la LDT (local del proceso). El descriptor aporta la base y el límite, y base + offset da la dirección lineal, que después pasa por la paginación.
- En las diapositivas, el mapa de segmentos vive en el procesador. El segmento sale de los bits altos de la dirección, o de la propia instrucción (
mov [es:bx], ax). - Las entradas marcadas N (no válidas) en el mapa disparan un error de acceso, como la fila V = 0 del diagrama 1.
- En CS, el campo RPL del selector es el nivel de privilegio actual (CPL: 0 = kernel, 3 = usuario).
Ventajas para el programador (Stallings §8.1):
- Maneja estructuras que crecen: el SO agranda el segmento (o lo mueve o hace swap).
- Permite recompilar y enlazar módulos por separado.
- Facilita compartir (una utilidad o una tabla en su propio segmento).
- Facilita proteger (permisos por segmento).
La segmentación elimina la fragmentación interna y conserva la externa, aunque menor que en las particiones, porque los segmentos son más chicos que un proceso entero. Sí es visible para el programador o el compilador, que conocen el tamaño máximo de segmento.
Ejemplo de Stallings (fig. 7.11b): direcciones de 16 bits, con 4 bits de segmento y 12 de offset (segmentos de hasta 4096 B). 0001 001011110000 es el segmento 1, offset 752. Si la base del segmento 1 es 0010000000100000 (8224), la dirección física es 8224 + 752 = 8976 = 0010001100010000. Aquí sí hay una suma (en paginación basta concatenar) y se compara offset < largo.
El mapa del ejemplo de clase: el código queda en 0x4000–0x47FF, los datos en 0x4800–0x5BFF, el segmento compartido en 0xF000–0xFFFF (compartido con otras aplicaciones) y el stack en 0x0000–0x2FFF. El resto de la memoria física queda para otras aplicaciones.
Traducción con segmentación (dirección de 16 bits)
Los 2 bits altos eligen el segmento y los 14 bajos son el offset. La MMU comprueba offset < limit y calcula física = base + offset. Es la tabla de la diapositiva 37.
| Seg | Nombre | Base | Límite |
|---|---|---|---|
| 0 | code | 0x4000 | 0x0800 |
| 1 | data | 0x4800 | 0x1400 |
| 2 | shared | 0xF000 | 0x1000 |
| 3 | stack | 0x0000 | 0x3000 |
Tabla de la diapositiva 37 (direcciones de 16 bits: 2 bits de segmento | 14 bits de offset):
| Seg. | Uso | Base | Límite |
|---|---|---|---|
| 0 | código | 0x4000 | 0x0800 |
| 1 | datos | 0x4800 | 0x1400 |
| 2 | compartido | 0xF000 | 0x1000 |
| 3 | stack | 0x0000 | 0x3000 |
Peldaño 1 · Resueltolee cada paso y su porqué
Resuelto: 0x8010
- Partir:
0x8010=10 | 00 0000 0001 0000. Segmento 2, offset0x0010. - Validar: ¿2 < STLR = 4? Sí. ¿
0x10< límite0x1000? Sí. - Sumar:
0xF000 + 0x10=0xF010.
Peldaño 2 · Complétalofaltan pasos clave: llénalos tú
Complétalo: 0x5000
El paso 1 ya está: 0x5000 = 01 | 01 0000 0000 0000, así que es el segmento 1. Completa: ¿cuál es el offset? ¿Pasa la validación? ¿Qué dirección física da?
Comparar
Offset = 01 0000 0000 0000 = 0x1000. Como 0x1000 < 0x1400, es válido. Física = 0x4800 + 0x1000 = 0x5800.
Peldaño 3 · Solosin ayuda; luego compara
Solo: 0xC100, 0x9200 y 0x47FF
Comparar (verificado con un script)
| Virtual | Seg. | Offset | ¿Válido? | Física |
|---|---|---|---|---|
0xC100 | 3 | 0x0100 | 0x100 < 0x3000 | 0x0100 |
0x9200 | 2 | 0x1200 | 0x1200 ≥ 0x1000 | segmentation fault |
0x47FF | 1 | 0x07FF | 0x7FF < 0x1400 | 0x4FFF |
0x47FF es la trampa: «parece» una dirección de código porque cae cerca de 0x4000, pero los 2 bits altos son 01 y por eso pertenece a datos. Nunca confundas una dirección virtual con una física.
Peldaño 4 · Variantecambia una condición: ¿sigue valiendo lo anterior?
Variante: la misma 0x5000, con 4 bits de segmento y 12 de offset (como en Stallings) y STLR = 4
Comparar
0x5000 = 0101 | 0000 0000 0000, así que ahora es el segmento 5, con offset 0. Como 5 ≥ STLR = 4, el segmento no existe y hay segmentation fault antes de mirar el offset. Lección: la misma dirección significa otra cosa si cambia cómo se reparten los bits. El primer paso siempre es fijar cuántos bits tiene cada campo.
Traza de la diapositiva 38 (PC = 0x0240)
Sección titulada «Traza de la diapositiva 38 (PC = 0x0240)»- Fetch
0x0240(0000 0010 0100 0000): segmento 0, offset0x240→ física0x4000 + 0x240 = 0x4240→la $a0, varx→$a0 = 0x4050. - Fetch
0x0244→0x4244→jal strlen→$ra = 0x0248y PC =0x0360. - Fetch
0x0360→0x4360→li $v0, 0. - Fetch
0x0364→0x4364→lb $t0, ($a0): carga desde0x4050(0100 0000 0101 0000), que es el segmento 1, offset0x50→ física0x4800 + 0x50 = 0x4850.
Observa que la misma dirección 0x4050 es un dato virtual y no la física 0x4050, que caería dentro del segmento de código.
Segmentación en procesadores modernos
Sección titulada «Segmentación en procesadores modernos»- Modo real (8086): direcciones
segmento:offset, segmentación intensiva. - Modo protegido (x86 de 32 bits): descriptores de segmento en la GDT/LDT (código, datos, stack…).
- Modo largo (x86-64): la segmentación está prácticamente deshabilitada; base y límite se ignoran para código y datos. Solo FS y GS conservan significado:
- FS: thread-local storage en espacio de usuario (glibc).
- GS: variables per-CPU del kernel.
- Linux ignora la segmentación y usa paginación como mecanismo principal, porque da aislamiento, memoria virtual y demand paging, cosas que la segmentación sola no maneja bien.
Autoevaluación
0/5 correctas · 0 respondidas📈 ¿Qué tan bien lo dominas?
Elige pensando en lo que hiciste, no en lo que leíste. Para marcar 3 tienes que haber resuelto un ejercicio nuevo sin pistas y haberlo justificado. Si solo lo leíste y sientes que «ya entendí», todavía es un 1.
Fuente ·for_partial/pending_themes/Sem06_06-OST-Memory.pdf (diap. 8–10, 24–40) · Stallings cap. 7 · Love, Linux Kernel Development