1. El problema: reubicar y proteger
Cuando varios programas comparten la RAM, hay que resolver dos cosas (tema 1):
- Reubicación: el programa se compila para usar direcciones a partir de 0, pero se carga en una posición cualquiera de la RAM. Hay que traducir cada dirección.
- Protección: un programa no debe poder acceder a la memoria de otro ni del núcleo.
La solución más simple es tratar el proceso como un bloque contiguo en la RAM y usar dos registros: uno con la dirección donde empieza el bloque (base) y otro con su tamaño (límite).
2. La idea: base y límite
El proceso se carga en un bloque contiguo de memoria física, entre la dirección base y base + límite. El procesador tiene dos registros especiales:
- Registro base: la dirección física donde empieza el proceso.
- Registro límite: el tamaño del espacio del proceso (en bytes o en palabras).
El programa sigue usando direcciones lógicas a partir de 0. En cada acceso, el hardware suma la base y comprueba el límite. Es la forma más sencilla de reubicación y protección.
Registros base y límite son dos registros del procesador que definen el rango de memoria física asignado a un proceso: base es la dirección de inicio, límite es el tamaño. En cada acceso se traduce la dirección lógica sumando la base y se comprueba que no supere el límite.
3. Traducción y comprobación
Para cada acceso a memoria con dirección lógica d:
- Comprobar: si
d ≥ límite, el acceso es ilegal → excepción (protección). - Traducir: dirección física =
base + d. - Acceder: la RAM responde con el byte en esa posición física.
Todo esto ocurre en hardware, en cada acceso, sin intervención del sistema operativo. El SO solo carga los registros base y límite al cambiar de proceso (context switch).
4. Registros en el hardware
En arquitecturas clásicas (y en algunos sistemas embebidos actuales), los registros base y límite son parte del procesador:
- Se cargan por el sistema operativo al cambiar de proceso.
- Están protegidos: el programa de usuario no puede modificarlos.
- La comprobación se hace en cada acceso, sin costo adicional perceptible.
En x86 moderno no se usan registros base y límite puros para la memoria principal: se usa segmentación (tema 15) y paginación (tema 18). Pero el concepto sigue presente en sistemas embebidos y en la memoria de E/S mapeada.
5. Ejemplo numérico
Un proceso se carga en la RAM a partir de la dirección física 0x10000 y ocupa 0x5000 bytes (20 KiB). Entonces:
| Dirección lógica | ¿Dentro del límite? | Dirección física | Resultado |
|---|---|---|---|
| 0x0000 | Sí (0 < 0x5000) | 0x10000 | Acceso válido |
| 0x1000 | Sí | 0x11000 | Acceso válido |
| 0x4FFF | Sí (último byte) | 0x14FFF | Acceso válido |
| 0x5000 | No (igual al límite) | — | Excepción de protección |
| 0xFFFF | No | — | Excepción de protección |
El límite es exclusivo: las direcciones válidas son 0 a límite-1.
6. Ventajas
- Simplicidad: solo dos registros y una suma/comparación por acceso.
- Reubicación sin recompilar: el mismo binario se carga en cualquier posición; basta con cambiar la base.
- Protección efectiva: un proceso no puede salir de su rango.
- Sin fragmentación interna: el bloque se asigna exactamente del tamaño pedido.
7. Limitaciones
- Asignación contigua: el proceso debe ocupar un bloque contiguo en la RAM. Si no hay un hueco suficientemente grande, no se puede cargar.
- Fragmentación externa: al cargar y descargar procesos, quedan huecos que no se pueden usar para procesos grandes (tema 12).
- Sin compartición: no se puede compartir código entre procesos (cada uno necesita su propio bloque).
- Sin memoria virtual: el proceso no puede ser mayor que la RAM libre.
- Sin páginas: no se puede cargar solo una parte del proceso.
Estas limitaciones motivaron la segmentación (tema 15) y la paginación (tema 18).
8. Experimento en C
El programa siguiente simula en software la traducción con base y límite:
#include <stdio.h>
#include <stdlib.h>
typedef struct { unsigned long base; unsigned long limite; } Contexto;
static unsigned long traducir(Contexto *c, unsigned long logica, int *ok)
{
if (logica >= c->limite) { *ok = 0; return 0; }
*ok = 1;
return c->base + logica;
}
int main(void)
{
Contexto c = { .base = 0x10000, .limite = 0x5000 };
unsigned long direcciones[] = { 0x0000, 0x1000, 0x4FFF, 0x5000, 0xFFFF };
for (int i = 0; i < 5; i++) {
int ok;
unsigned long f = traducir(&c, direcciones[i], &ok);
printf("logica 0x%04lx -> %s 0x%04lx\n",
direcciones[i], ok ? "fisica" : "EXCEPCION", f);
}
return 0;
}
$ gcc -std=c17 -Wall -Wextra -o base_limite base_limite.c
$ ./base_limite
logica 0x0000 -> fisica 0x10000
logica 0x1000 -> fisica 0x11000
logica 0x4fff -> fisica 0x14fff
logica 0x5000 -> EXCEPCION
logica 0xffff -> EXCEPCIONlogica 0xffff -> EXCEPCION
9. Probar con un simulador
Este simulador traduce direcciones lógicas a físicas usando base y límite. Cambia la base, el límite y la dirección lógica, y observa si el acceso es válido y cuál es la dirección física resultante.
Simulador · base y límite
| Campo | Valor |
|---|---|
| ¿Dentro del límite? | |
| Dirección física | |
| Rango válido |
10. En Linux hoy
Linux no usa registros base y límite puros para la memoria principal: usa paginación. Pero el concepto sigue presente en:
- Segmentación x86: los segmentos (CS, DS, SS) tienen base y límite, aunque en modo 64 bits se usan de forma plana (base 0, límite máximo).
- Memoria de E/S mapeada: los dispositivos se mapean en rangos de direcciones con permisos.
- Contenedores y virtualización: la idea de "un proceso = un rango" se mantiene a nivel lógico.
11. Resumen
- Los registros base y límite son la forma más simple de reubicación y protección.
- La dirección física se calcula como base + dirección lógica, tras comprobar que la lógica sea menor que el límite.
- Si la dirección lógica supera el límite, se lanza una excepción de protección.
- Ventajas: simplicidad, reubicación sin recompilar, protección efectiva.
- Limitaciones: asignación contigua, fragmentación externa, sin compartición ni memoria virtual.
12. Preguntas de repaso
Intenta responder cada una antes de abrir la respuesta.
1. ¿Qué hace el registro base?
Se suma a la dirección lógica para obtener la dirección física. Define dónde empieza el proceso en la RAM.
2. ¿Qué hace el registro límite?
Define el tamaño del espacio del proceso. Si la dirección lógica es mayor o igual al límite, el acceso es ilegal.
3. ¿Cuál es la fórmula de traducción?
Dirección física = base + dirección lógica, siempre que dirección lógica < límite.
4. ¿Qué ocurre si una dirección lógica supera el límite?
Se lanza una excepción de protección (trap), y el sistema operativo puede terminar el proceso.
5. ¿Por qué base y límite no permiten memoria virtual?
Porque el proceso debe caber entero en un bloque contiguo de RAM; no se puede cargar solo una parte ni usar el disco.
6. ¿Qué es la fragmentación externa?
Los huecos libres que quedan entre procesos cargados y que no son suficientemente grandes para un proceso nuevo, aunque la memoria libre total sea suficiente.
7. ¿Los registros base y límite se usan en x86-64 moderno?
No para la memoria principal (se usa paginación), pero el concepto sigue en la segmentación y en sistemas embebidos.
8. ¿Quién carga los registros base y límite?
El sistema operativo, al cambiar de proceso (context switch). El programa de usuario no puede modificarlos.
Para practicar
- Modifica
base_limite.cpara aceptar base, límite y dirección como argumentos de línea de comandos. - Calcula a mano la dirección física para base=0x20000, límite=0x8000, dirección lógica=0x7FFF. ¿Es válida?
- ¿Qué dirección lógica máxima es válida para límite=0x1000? ¿Y la mínima inválida?
- Implementa en C una función que simule base y límite para un array de accesos y cuente los válidos e inválidos.
- Investiga qué registros de segmentación usa x86 (CS, DS, SS, ES, FS, GS) y qué base/límite tienen en modo 64 bits.
- Explica con tus palabras por qué base y límite no permiten compartir código entre procesos.
- Compara base y límite con la paginación: ¿qué problema resuelve la paginación que base y límite no?