- Opciones del
cargador - Programas de
superposiciones - Opciones de diseño del
cargador - Editores de
ligado - Ligado
dinámico - Cargadores de
arranque - Ejemplos de cargadores y ligadores
reales - Ligador del sistema
vax - Cargador de
cyber
Muchos cargadores permiten al usuario especificar
opciones que modificar el procesamiento estándar descrito.
Muchos cargadores tienen un lenguaje
especial de mandatos que se utiliza para especificar opciones.
Algunas veces existe un archivo
independiente de entrada al cargador que contiene esas
proposiciones de control. En
ocasiones esas mismas proposiciones también pueden estar
intercaladas en el flujo primario de entrada entre los programas objeto.
En ciertos sistemas el
programador puede incluso introducir proposiciones de control del
cargador en el programa fuente,
y el ensamblador o
el compilador retienen esos mandatos como parte del programa
objeto.
Una opción típica del cargador permite la
selección de fuentes
alternativas de entrada, por ejemplo el mandato INCLUDE, puede
indicar al cargador que lea el programa objeto designado en una
biblioteca y que
lo trate como si fuera parte de la entrada primaria del cargador.
Otros mandatos permiten al usuario eliminar símbolos
externos o secciones de control completas. También es
posible cambiar referencias externas dentro del programa que se
está cargando y ligando. Por ejemplo, el mandato DELETE,
puede indicar al cargador que elimine la sección de
control nombrada del conjunto de programas que se está
cargando. El mandato CHANGE puede hacer que el símbolo
externo nombre1 se cambie a nombre2 siempre que aparezca en los
programas objeto. Otra opción común para el
cargador implica la inclusión automática de rutinas
de biblioteca para satisfacer referencias externas. La
mayoría de los cargadores permiten al usuario especificar
bibliotecas
alternativas para búsqueda, por medio de una
proposición del tipo LIBRARY MILIB. Suele buscar en esas
bibliotecas especificadas por el usuario antes que en las
bibliotecas estándar del sistema. Esto
permite al usuario utilizar versiones especiales de esas rutinas
estándar.
Los cargadores que realizan la búsqueda
automática en bibliotecas para satisfacer referencias
externas, a menudo permiten al usuario especificar que no se
resuelvan de esa forma algunas referencias. Si se sabe que el
análisis estadístico no se va a
realizar en una ejecución determinada de este programa, el
usuario puede incluir un mandato como NOCALL DEVSTD,PLOT,CORREL
para indicar al cargador que no se resuelvan esas referencias
externas, evitando así el trabajo
extra de cargar y ligar rutinas innecesarias, con el consiguiente
ahorro del
espacio de memoria que se
requeriría.
También se puede especificar que no se resuelva
ninguna referencia externa por búsqueda en biblioteca,
aunque eso daría como resultado un error si el programa
intenta hacer esa referencia externa durante la ejecución.
Esta opción es más útil cuando se van a
ligar programas, pero no se van a ejecutar de inmediato. En tales
casos suele ser conveniente posponer la resolución de
referencias externas.
Los cargadores a menudo incluyen otras opciones. Una de
las tales opciones es la posibilidad de especificar la localidad
donde se inicia la ejecución. Otra es la posibilidad de
controlar si el cargador debe intentar o no la ejecución
del programa si se detectaran errores durante la
carga.
2. Programas de
superposiciones
Muchos sistemas que manejan programas de
superposición requieren que este proceso sea
una estructura de
árbol, los nodos de la estructura se denominan segmentos:
el segmento raíz se carga cuando comienza la
ejecución del programa, y permanece en la memoria
hasta que termina el programa. Los otros segmentos se cargan a
medida que se llaman.
Puesto que los segmentos del mismo nivel sólo
pueden ser llamados desde el nivel superior, no se pueden
requerir al mismo tiempo, de modo
que se pueden asignar a las mismas localidades de la memoria. Si
se carga un segmento debido a una transferencia de control, se
superpone a cualquier segmento del mismo nivel que puede estar en
memoria. De esta forma, se puede ejecutar todo el programa en una
cantidad total menor de memoria, que es la razón principal
de utilizar estructuras de
superposiciones. En el resto de esta sección se examina
con más detalle del proceso de superposiciones por el
cargador.
El cargador puede asignar una dirección real o inicial a todos los
segmentos del programa de superposiciones una vez que se dispone
de la dirección inicial de carga, con lo que se conocen
las direcciones para todos los símbolos externos. Esto
significa que todas las operaciones de
relocalización y ligado se pueden realizar de la forma
usual, con una excepción: la transferencia de control del
padre a un segmento debe admitir la posibilidad de que el
segmento llamado no esté en la memoria. El segmento
raíz puede cargarse directamente en la memoria; los otros
segmentos se escriben en un archivo de trabajo especial ARCHSEG
creado por el cargador.
El proceso de superposiciones en si, esto es, la carga
de un segmento cuando se le transfiere el control, se puede
manejar de varias formas distintas.
3. Opciones de diseño
del cargador
Los cargadores ligadores realizan el ligado y la
relocalización en el momento de la carga. Se analizan dos
opciones: los editores de ligado, que realizan el ligado antes
del momento de la carga, y el ligado dinámico, en el cual
la función de ligado se realiza en el momento de la
ejecución.
Un editor de ligado realiza el ligado y algo de
relocalización; sin embargo, el programa ligado se escribe
en un archivo o biblioteca, en lugar de cargarse inmediatamente
en la memoria. Este enfoque reduce las operaciones adicionales al
ejecutar el programa. Lo único que se necesita en el
momento de la carga es una forma muy simple de
relocalización.
El ligado dinámico, que utilizan los dispositivos
del sistema operativo
para cargar subprogramas en el momento en que se llaman por
primera vez. Al retardar el proceso de ligado de esta forma, se
puede lograr flexibilidad adicional. Sin embargo, este enfoque
suele implicar más operaciones que el del cargador
ligador.
Los cargadores de arranque que se pueden utilizar para
ejecutar programas autónomos, independientes del sistema
operativo o del cargador del sistema. También se pueden
utilizar para cargar el sistema operativo o el cargador mismo en
la memoria.
La diferencia fundamental entre un editor de ligado y un
cargador ligador es: Primero se ensambla o compila el programa
fuente, produciendo un programa objeto (que puede contener varias
secciones de control diferentes). Un cargador ligador realiza
todas las operaciones de ligado y relocalización,
incluyendo búsqueda automática en bibliotecas, si
se específica, y carga el programa ligado directamente en
la memoria para su ejecución. Por otro lado, un editor de
ligado produce una versión ligada del programa (llamada a
menudo módulo de carga o imagen
ejecutable), que se escribe en un archivo o biblioteca para su
ejecución posterior.
Cuando el usuario está listo para ejecutar el
programa ligado, se puede utilizar un cargador relocalizador
simple para cargar el programa en la memoria. La única
modificación necesaria al código objeto es la suma
de una dirección de carga real a los valores
relativos del programa. El editor de ligado realiza la
relocalización de todas las secciones de control relativas
al inicio del programa ligado. De esta forma, todos los elementos
que necesitan modificarse en el momento de la carga tienen
valores
relativos al inicio del programa ligado; esto significa que el
cargado se puede realizar en un paso, sin necesidad de una tabla
de símbolos externos, lo que, a su vez, supone muchas
menos operaciones que la utilización de un cargador
ligador.
Si un programa se va a ejecutar muchas veces sin ser
reensamblado, el uso del editor de ligado reduce de manera
considerable la sobrecarga requerida. La resolución de
referencias externas y la búsqueda en biblioteca se
realizan una sola vez (cuando el programa está ligado).
Por el contrario, un cargador ligador busca en bibliotecas y
resuelve referencias externas cada vez que se ejecuta el
programa.
Sin embargo, algunas veces un programa se reensambla en
casi todas las ejecuciones. Esta situación puede
presentarse en un ambiente de
desarrollo y
prueba de programas (por ejemplo, programas de estudiantes).
También se presenta cuando un programa se usa tan poco que
no tiene objeto almacenar una versión ensamblada en una
biblioteca. En tales casos, es más eficiente usar un
cargador ligador, que evita los pasos de escribir y leer el
programa ligado.
El programa ligado producido por el editor de ligado
generalmente está en forma adecuada para ser procesado por
el cargador relocalizador. Se resuelven todas las referencias
externas, y se indica la relocalización con algún
mecanismo, como registros de
modificación o máscaras de bits. Aunque se haya
realizado todo el ligado, a menudo se retiene la información concerniente a las referencias
externas en el programa ligado. Esto permite religar
posteriormente el programa para reemplazar secciones de control,
modificar referencias externas, etc. Si no se conserva esta
información; el editor de ligado no puede reprocesar el
programa de ligado; sólo puede cargarlo y
ejecutarlo.
Si se conoce de antemano la dirección real en la
que se cargará el programa, el editor de ligado puede
realizar toda la relocalización necesaria. El resultado es
un programa ligado que es la imagen exacta de la forma en que
aparecerá el programa en la memoria durante la
ejecución; el contenido y procesamiento de esa imagen son
iguales que para un programa objeto absoluto. Sin embargo, la
flexibilidad adicional de poder cargar
un programa en cualquier localidad suele compensar la ligera
sobrecarga adicional que supone realizar la relocalización
en el momento de la carga.
Los editores de ligado pueden realizar varias funciones
útiles, además de la simple preparación de
un programa objeto para su ejecución.
Los editores de ligado también se pueden utilizar
para construir paquetes de subrutinas u otras secciones de
control que se suelen utilizar juntas. Esto puede ser útil
al tratar con bibliotecas de subrutinas que manejan lenguajes de
programación de alto nivel. A veces permiten al
usuario especificar que las referencias externas no se resuelvan
por búsqueda automática en biblioteca. A menudo
incluyen otras opciones y mandatos como los analizados para los
cargadores ligadores. Comparados con los cargadores ligadores,
los editores de ligado en general tienden a ofrecer mayor
flexibilidad y control, con el correspondiente incremento en
complejidad y sobrecarga.
El ligado dinámico ofrece algunas ventajas sobre
los otros tipos de ligado. Proporciona la posibilidad de cargar
las rutinas sólo cuando y si se necesitan. SI las
subrutinas son grandes o tienen muchas referencias externas, se
pueden conseguir ahorros considerables de tiempo y espacio de
memoria.
De forma similar, supóngase que en cualquier
ejecución un programa usa sólo pocas de una gran
cantidad de subrutinas posibles, pero el número exacto de
rutinas necesarias no puede predecirse hasta que el programa
examina su entrada. Esta situación podría
presentarse, con un programa que permita al usuario llamar
interactivamente a cualquiera de las subrutinas de una gran
biblioteca matemática
y estadística. El usuario podría
suministrar la entrada de datos desde un
terminal de tiempo compartido, y los resultados podrían
exhibirse en el terminal. En este caso podrían ser
necesarias todas las subrutinas de la biblioteca, pero en
cualquier sesión de terminal solo se usarían unas
cuantas. El ligado dinámico evita la necesidad de cargar
la biblioteca completa para cada ejecución. El ligado
dinámico puede incluso hacer innecesario que el programa
conozca el conjunto de subrutinas que se podría utilizar.
El nombre de la subrutina se trataría simplemente como
otro elemento de entrada.
Para realizar la carga de ligado de una subrutina
llamada se puede utilizar varios mecanismos distintos. En el
método que
se analiza aquí, las rutinas que se carguen
dinámicamente deben llamarse por medio de una solicitud de
servicio al
sistema operativo. Este método también
podría considerarse como una solicitud a una parte del
cargador que se mantiene en la memoria durante la
ejecución del programa.
Cuando se utiliza ligado dinámico, la
asociación de una dirección real y el nombre
simbólico de la rutina llamada no se hace hasta que se
ejecuta la proposición llamada.
Con la máquina vacía e inactiva, no hay
necesidad de hacer relocalización de programas, tan solo
se puede especificar la dirección absoluta del programa
que se cargue en primer lugar. En la mayoría de los casos,
este programa es el sistema operativo, que ocupa un lugar
predefinido en la memoria. Esto significa que se necesitan
algunos medios para
realizar las funciones de un cargador absoluto. Una opción
es que el operador introduzca en la memoria el código
objeto de un cargador absoluto, utilizando los interruptores en
la consola del computador.
Algunos computadores requerían que el operador hiciera
exactamente eso. Sin embargo, este proceso es demasiado
incómodo y propenso a errores para ser una buena
solución del problema.
Otra posibilidad es que el programa del cargador
absoluto resida permanentemente en una memoria sólo de
lectura (ROM).
Cuando se produce una señal de hardware, la máquina
empieza a ejecutar este programa de la ROM. En algunos
computadores, el programa se ejecuta directamente en la ROM; en
otros, el programa se copia de la ROM a la memoria principal y se
ejecuta allí. Sin embargo, algunas máquinas no
tienen ese almacenamiento
sólo de lectura. Además, puede no ser conveniente
cambiar un programa en ROM si es necesario hacer modificaciones
en el cargador absoluto.
Una solución inmediata es tener una
función de hardware incorporada que lea un registro de
longitud fija de algún dispositivo en una localidad fija
de la memoria; el dispositivo que se utilice puede seleccionarse
mediante interruptores de la consola. Una vez completa la
operación de lectura, el control se pasa
automáticamente a la dirección de la memoria donde
se almacenó el registro. Este registro contiene
instrucciones de máquina que cargan el programa absoluto
que sigue.
Si el proceso de carga requiere más instrucciones
de las que pueden leerse en un solo registro, el primer registro
causa la lectura de
otros y estos, a su vez, pueden originar la lectura aún de
mas registros; de ahí el término arranque. El
primer registro suele denominarse cargador de arranque, y se
coloca al inicio de todos los programas objeto que se van a
cargar en un sistema vacío o inactivo. Esto incluye, por
ejemplo, al propio sistema operativo y a todos los programas
independientes que se ejecutan sin sistema operativo.
7. Ejemplos de cargadores y
ligadores reales
Editor de ligado del sistema/370.
El formato de los programas objeto manejado por el
editor de ligado del Sistema/370 es muy parecido al analizado
para SIC/XE. La técnica de referencia a un número,
se usa para mejorar la eficiencia. El
programa de salida del editor de ligado se llama módulo de
carga, y puede cargarse en la memoria para su ejecución, y
suele contener suficiente información para permitir que el
editor de ligado los reprocese. El usuario tiene la posibilidad
de especificar que un módulo de carga sea "no editable",
en cuyo caso puede omitirse gran parte de la información
de control, para producir un módulo de carga más
pequeño.
El editor de ligado del Sistema 370 puede realizar todas
las funciones estándar analizadas, las secciones de
control pueden ser eliminadas, reemplazadas o reordenadas. Los
símbolos utilizados en referencias externas se pueden
cambiar o eliminar. Para facilitar la edición, el editor
de ligado se encarga del reemplazo automático de secciones
de control. Si se están procesando dos o más
secciones de control que tienen el mismo nombre, solo se incluye
la primera en el módulo de carga; las otras se eliminan
sin ser consideradas como errores. El editor de ligado busca
automáticamente en las bibliotecas del sistema o en las
especificadas por el usuario para resolver referencias externas.
Sin embargo, el usuario puede suprimir la búsqueda de
algunas o de todas las referencias externas.
El editor de ligado también almacena otro tipo de
información con el módulo de carga, que incluye el
traductor de lenguaje empleada para cada sección de
control y la fecha de ensamblado o compilación. El editor
de ligado también proporciona fechas de edición y
modificación para mantener una historia del procesamiento.
Cuando se coloca un módulo de carga en una biblioteca, el
editor de ligado hace una entrada en el directoria de esa
biblioteca que especifica si el módulo puede ser
reprocesado por el editor de ligado, si es un programa de
superposiciones, si es reutilizable o compartible, y muchos otros
atributos, algunos de estos los especifica el usuario, y otros
son generados por el editor de ligado a partir de la
información reunida durante el procesamiento.
Los programas superposiciones del Sistema/370 se pueden
dividir en varias regiones para mejorar la utilización del
almacenamiento. Cada región contiene una
superposición con estructura de árbol; dentro de
una región, se aplican las reglas usuales de referencias
entre segmentos; sin embargo, las regiones son independientes
entre si. Un segmento de una región es libre de llamar a
cualquier segmento de otra región.
La mayoría de los sistemas 370 disponen de un
cargador ligador, así como de un editor de ligado. El
cargador ofrece menos opciones y posibilidades que las que
presenta el editor de ligado. Por ejemplo, el cargador no maneja
programas de superposiciones ni produce módulos de carga
para almacenarlos en una biblioteca de programas. Sin embargo,
debido a su poca complejidad, y como evita la creación de
un módulo de carga, el cargador puede reducir el tiempo de
edición y carga casi la mitad. Su no se necesitan las
funciones especializadas del editor de ligado, por razones de
eficiencia se recomienda utilizar el cargador.
El ligador VAX es un editor de ligado que realiza las
mismas funciones básicas alcanzadas con anterioridad. La
acción del ligador en la creación de las secciones
de imagen está controlada por el ensamblador o compilador
por medio de una secuencia de mandatos que forman parte del
programa objeto. El ligador usa una pila interna como
almacenamiento de trabajo. Los mandatos del programa objeto
pueden especificar el apilamiento de valores a partir de diversas
fuentes, guardar valores de la pila en la imagen que se
está creando y realizar operaciones con valores de pila.
El lenguaje de
mandatos ofrece una gran diversidad de posibilidades: hay mas de
50 códigos de mandatos posibles.
El ligador VAX puede generar tres tipos de imágenes.
Una imagen ejecutable es aquella adecuada para la carga y
ejecución; sin embargo, el ligador no puede reprocesar
este tipo de imagen. Una imagen compartible no es ejecutable,
pero el ligador puede reprocesarla, y se puede utilizar, por
ejemplo, como etapa intermedia en el ligado de un programa muy
grande. Las imágenes compartibles también hace
posible que diferentes programas compartan la misma copia de
ciertas instrucciones o área de datos. En el disco, o
cargada en la memoria, sólo se mantiene una copia de la
imagen compartible. Esta copia es compartida por todos los
programas de aplicación que la requieren. De esta forma,
el uso de imágenes compartibles puede dar como resultado
ahorros de memoria, espacio en disco y paginación
E/S.
El tercer tipo de imagen que puede crear el ligado es
una imagen de sistema, concebida para ser ejecutada directamente
en la máquina VAX, sin los servicios del
sistema operativo. Este tipo de imagen solo se utiliza en
circunstancias especiales. La estructura y contenido de una
imagen de sistema son más sencillo que en cualquiera de
los otros dos tipos.
El ligador de VAX realiza las funciones usuales de
ligado y relocalización. Además, hace parte del
trabajo que en otros sistemas realizan el ensamblador o el
compilador.
El ligador de VAX no utiliza programas de
superposiciones, debido en parte a la gran memoria
virtual que dispone VAX. Los diseñadores del sistema
consideraron que el tamaño de esta memoria virtual, junto
con los algoritmos
para la administración de la memoria, hacían
innecesaria la utilización de las
superposiciones.
Los programas CYBER suelen contener mucho más
valores relocalizables que los programas de VAX o del sistema
/370.
Una palabra de CYBER puede contener más de una
instrucción, por lo que no es posible usar un solo bit de
relocalización por palabra. A causa de que en CYBER
sólo las instrucciones de 30 bits pueden contener
direcciones de memoria, existen cinco posibles de valores
relocalizables dentro de una palabra.
- Sin relocalización.
- Valor relocalizable sólo en la mitad superior
de la palabra. - Valor relocalizable sólo en la mitad inferior
de la palabra. - Valores relocalizables en las mitades superior e
inferior de la palabra. - Valor relocalizable en la mitad de los 30 bits de la
palabra.
Cuando se usa la técnica de la máscara de
bits, hay un campo de cuatro bits asociado a cada palabra de
código objeto. Esos cuatro bits se utilizan para codificar
las posibles antes listadas, y también para especificar si
la dirección base del programa se suma o resta a cada
valor
relocalizable.
El cargador de CYBER puede utilizar programas de
superposiciones de un tipo más restringido que el
descrito. Una estructura de superposiciones está limitada
a un máximo de tres niveles. Cada segmento está
identificado por un par ordenado de enteros, y un segmento
solamente puede tener un punto de entrada.
Cada segmento, excepto el raíz, debe cargarse por
medio de una solicitud explicita; no existe la carga
automática de segmentos. El programa de aplicación
puede solicitar la carga de un segmento por medio de una llamada
de servicio al sistema operativo. Como alternativa, en el
segmento raíz puede haber un pequeño cargador
residente para manejar el proceso de
superposición.
Hay también una opción más poderosa
que las superposiciones: la segmentación. Un programa
segmentado también usa una estructura de árbol; sin
embargo, puede haber más de tres niveles, y cada segmento
puede tener varios puntos de entrada.
Palabras claves:
Opciones del cargador, programas de superposiciones,
opciones de diseño del cargador, editores de ligado,
Ligado dinámico, Cargadores de arranque, ejemplos de
cargadores y ligadores,
Trabajo enviado y realizado por:
Leopoldo de la Fuente Silva
Estudiante del Instituto Tecnológico de Cd.
Victoria