Introducción a la Programación de Sistemas.

83
Revisión 2011 Software de Sistemas | Varios Autores INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

description

Materia: Software de Sistemas. INFORMÀTICA ADMINISTRATIVA.

Transcript of Introducción a la Programación de Sistemas.

Page 1: Introducción a la Programación de Sistemas.

Revisión 2011

Software de Sistemas | Varios Autores

INTRODUCCIÓN A LA PROGRAMACIÓN DE

SISTEMAS

Page 2: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

2

La informática es la ciencia que se encarga de la automatización del manejo de la información. La informática, por su rapidez de crecimiento y expansión, Ha venido transformando rápidamente las sociedades actuales. La computadora, a diferencia de otras herramientas que en general apoyan el esfuerzo físico de los Humanos, fue inventada para facilitar el trabajo intelectual. El lenguaje de programación es el medio de comunicación entre el Hombre y la máquina. Sistema de símbolos y reglas que permite la construcción de programas con los que la computadora puede operar así como resolver problemas de manera eficaz. Estos contienen un conjunto de instrucciones que nos permiten realizar operaciones de entrada/salida, calculo, manipulación de textos, lógica/comparación y almacenamiento/recuperación. La programación tiene como objetivo el tratamiento de la información correctamente, con lo que se espera que un programa de el resultado correcto y no uno erróneo. Así que cada aplicación debe funcionar según lo esperado en términos de programación, esta pretende que sus programas sean útiles y eficientes. Un sistema es un conjunto de componentes que interaccionan entre sí para lograr un objetivo común. Las personas se comunican con el lenguaje, que es un sistema muy desarrollado formado por palabras y símbolos que tienen significado que tienen significado para el que Habla y para quienes lo escuchan, lo mismo es para las computadoras las cuales tienen sistemas y se comunican por medio de computadoras. La programación es el proceso de convertir las especificaciones a grandes rasgos de los sistemas en instrucciones de máquina que produzcan los resultados deseados. Por lo tanto la Programación de Sistemas se refiere a la creación de programas cuya finalidad es servir a otros programas (software) ejemplos; Ensambladores, Cargadores y Ligadores, Compiladores, intérpretes. El Software es un conjunto de programas, documentos, procedimientos, y rutinas asociados con la operación le un sistema de computo. Distinguiéndose de los componentes físicos llamados hardware. El hardware por sí solo no puede hacer nada, pues es necesario que exista el software.

Page 3: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

3

Índice 1. ESTRUCTURA DE LA COMPUTADORA. ....................................................................................... 4

2. ENSAMBLADORES. ............................................................................................................... 20

3. CARGADOR – LIGADOR. ........................................................................................................... 49

4. MACROPROCESADORES. ......................................................................................................... 68

5. GLOSARIO. ............................................................................................................................... 76

6. ANEXOS. .................................................................................................................................. 80

El software de manera general, podemos clasificarlo en:

• Software de sistema: en algunas ocasiones también denominado software de base, consiste en un software que sirve para controlar e interactuar con el sistema, proporcionando control sobre el hardware y dando soporte a otros programas.

• Software de aplicación: El software de hoja de cálculo, de diseño

asistido por computadoras (CAD), de procesamiento de texto, de manejo de Bases de Datos, pertenece a esta categoría.

• Software de uso general: este ofrece la estructura para un gran número de aplicaciones empresariales, científicas y personales. La mayoría de software para uso general se vende como paquete; es decir, con software y documentación orientada a los usuarios (manuales de referencia, plantillas de teclado y demás).

El trabajo de un programador de sistemas es seleccionar, modificar y mantener el complejo software del sistema operativo. Por lo tanto, los programadores de sistemas desempeñan una función de apoyo al mantener el ambiente de software del sistema operativo en el que trabajan los programadores de aplicaciones y los operadores de las computadoras. También participan en las decisiones relativas a reducciones o ampliaciones de hardware y/o software. Programación de Sistemas Conceptos y Aplicaciones Se entiende por programación de sistemas el conjunto de programas necesario para que una computadora de una imagen coherente y monolítica ante sus usuarios. Es un área especializada dentro de las ciencias de la computación. Así, mediante la programación de sistemas, no solo se manejan las computadoras por

Page 4: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

4

medio del lenguaje maquina (0 y 1) sino por otros sistemas operativos, sin lo cual sería muy difícil la interacción con la maquina.

1. ESTRUCTURA DE LA COMPUTADORA. Objetivo: Entender con detalle los procesos lógicos que suceden en una computadora para que pueda ejecutar un programa en lenguaje máquina de una plataforma que en particular se define al iniciar el curso. 1.1 Arquitectura de Von Neumann. Cuando se describe una computadora se debe distinguir entre arquitectura y organización. • La arquitectura de computadoras que se refiere a los atributos de un sistema que son visibles a un programador, es decir aquellos atributos que tienen un impacto directo en la ejecución lógica de un programa. Ejemplos de atributos arquitectónicos: conjunto de instrucciones, número de bits usados para representar datos, mecanismos de entrada salida y técnicas de direccionamiento de memoria. También suele definirse como la forma de seleccionar e interconectar componentes de hardware para crear computadoras según los requerimientos de funcionalidad, rendimiento y costo. • La organización de computadoras que se refiere a las unidades funcionales y sus interconexiones, que materializan especificaciones arquitectónicas. Ejemplos de atributos de organización: son los detalles del hardware transparentes para el programador, tales como señales de control, interfaces entre la computadora y los periféricos y la tecnología de memoria utilizada. Por poner un ejemplo, una cuestión de arquitectura es si la computadora tendrá la instrucción de multiplicar. Una cuestión de organización es si esa instrucción será implementada por una unidad especializada en multiplicar o por un mecanismo que haga un uso iterativo de la unidad de suma del sistema. La unidad central de procesamiento, CPU (por sus siglas del inglés Central Processing Unit), o, simplemente, el procesador, es el componente en una computadora digital que interpreta las instrucciones y procesa los datos contenidos en los programas de computadora. La CPU proporciona la característica fundamental de la computadora digital: la programabilidad, es uno de los componentes necesarios encontrados en las computadoras

Page 5: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

5

de cualquier tiempo, junto con el almacenamiento primario y los dispositivos de entrada/salida. Desde mediados de los años 1970, los microprocesadores de un solo chip han reemplazado casi totalmente todos los tipos de CPU, y hoy en día, el término "CPU" es aplicado usualmente a todos los microprocesadores. Las funciones básicas que una computadora puede llevar a cabo son: Procesamiento de datos, Almacenamiento de datos, Transferencia de datos, Control. La computadora es una entidad que interactúa de alguna manera con su entorno externo. En general, todas sus conexiones con el exterior pueden ser clasificadas como dispositivos periféricos o líneas de comunicación. Hay cuatro componentes estructurales principales: Unidad de Procesamiento Central (CPU): controla el funcionamiento

de la computadora y lleva a cabo las funciones de procesamiento de datos. Frecuentemente se le llama procesador.

Memoria Principal: es el dispositivo en el cual se almacenan datos. E/S: transfiere datos entre la computadora y el exterior. Sistema de /interconexión (Bus del sistema): es un mecanismo que

proporciona la comunicación entre la CPU, la memoria y E/S. 1.1.1 CPU.

Unidad de Control: controla el funcionamiento de la CPU y por tanto de la computadora.

Unidad Aritmética y Lógica (ALU): lleva a cabo las funciones de procesamiento de datos.

Registros: proporciona almacenamiento interno para la CPU. interconexión interna de la CPU: son mecanismos que proporcionan

comunicación entre la unidad de control, ALU y registros.

La ENIAC (Electronic Numerical Integrator And Computer) fue la primera computadora electrónica de uso general en el mundo. Uno de los inconvenientes más grandes de la ENIAC era que tenía que ser programada manualmente mediante conmutadores y conectando y desconectando cables. El proceso de programación podría ser más fácil si el programa se representará en una forma adecuada para ser guardado en la memoria junto con los datos. Entonces, la computadora conseguiría sus instrucciones leyéndolas de la memoria, y se podría hacer o modificar un programa escribiendo en una zona de memoria. John Von Neumann en imagen.

Page 6: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

6

La idea central del modelo de computación propuesto por John Von Neumann es almacenar las instrucciones del programa de una computadora en su propia memoria, logrando con ello que la máquina siga los pasos definidos por su programa almacenado. 1.1.2 Memoria.

La memoria se puede definir como los circuitos que permiten almacenar y recuperar la información. En un sentido más amplio, puede referirse también a sistemas externos de almacenamiento, como las unidades de disco o de cinta. Para nuestros propósitos, la memoria será un conjunto de celdas (o casillas) con las siguientes características: 1. cada celda puede contener un valor numérico John von Neumann (28 dic. 1903 - 8 feb. 1957) matemático húngaro-estadounidense, de ascendencia judía, realizó contribuciones importantes en física cuántica, análisis funcional, teoría de conjuntos, informática, economía, análisis numérico, hidrodinámica (de explosiones), estadística y muchos otros campos de la matemática. Recibió su doctorado en matemáticas de la Universidad de Budapest a los 23 años. 2. cada celda tiene la propiedad de ser direccionable, es decir, se puede distinguir una de otra por medio de un número unívoco que es su dirección. 3. Las celdas de memoria están organizadas en forma de vector, que no es más que un conjunto de celdas numerado secuencialmente. Como se dijo, se puede hacer referencia a una celda por medio de su dirección. Se usará un apuntador para dirigirse a alguna celda cualquiera. Una memoria para efectuar una lectura se deposita en el bus de direcciones la dirección de la palabra de memoria que se desea leer y entonces se activa la señal de lectura; después de cierto tiempo (retardo), en el bus de datos aparecerá el contenido de la dirección buscada. Por otra parte, para realizar una escritura se deposita en el bus de datos la información que se desea escribir y en el bus de direcciones la dirección donde deseamos escribirla, entonces se activa la señal de escritura (escritura), pasado el tiempo de retardo, la memoria escribirá la

Page 7: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

7

información en la dirección deseada. Internamente la memoria tiene un registro de dirección (MAR, memory address register), un registro buffer de memoria o registro de datos (MB, memory buffer, o MDR, memory data register) y, un decodificador como se ve en la figura. Esta forma de estructurar la memoria se llama organización lineal o de una dimensión. El bus se puede definir como un conjunto de líneas conductoras de hardware utilizadas para la transmisión de datos entre los componentes de un sistema informático. Un bus es en esencia una ruta compartida que conecta diferentes partes del sistema, como el microprocesador, la controladora de unidad de disco, la memoria y los puertos de entrada/salida (E/S), para permitir la transmisión de información. En el bus se encuentran dos pistas separadas, el bus de datos y el bus de direcciones (aquí está la diferencia entre la Arquitectura de Neumann con la de Harvard). La CPU escribe la dirección de la posición deseada de la memoria en el bus de direcciones accediendo a la memoria, teniendo cada una de las líneas carácter binario. Es decir solo pueden representar 0 o 1 y de esta manera forman conjuntamente el número de la posición dentro de la memoria (es decir: la dirección). Cuantas más líneas haya disponibles, mayor es la dirección máxima y mayor es la memoria a la cual puede dirigirse de esta forma (es decir si es un dispositivo programable de 1,2 o 3 bytes). Esto que en le teoría parece tan fácil es bastante más complicado en la práctica, ya que aparte de los bus de datos y de direcciones existen también casi dos docenas más de líneas de señal en la comunicación entre la CPU y la memoria, a las cuales también se acude. Todas las tarjetas del bus escuchan, y se tendrá que encontrar en primer lugar una tarjeta que mediante el envío de una señal adecuada indique a la CPU que es responsable de la dirección que se ha introducido. Las demás tarjetas se despreocupan del resto de la comunicación y quedan a la espera del próximo ciclo. Ejemplo en INTEL: Estructuras de interconexión Existen dos organizaciones físicas de operaciones E/S que tienen que ver con los buses que son:

o Bus único: La primera gran diferencia entre estas dos tipos de estructuras es que el bus único no permite un controlador DMA

Page 8: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

8

(todo se controla desde la CPU), mientras que el bus dedicado sí que soporta este controlados

o Bus dedicado: este trata a la memoria de manera distinta que a los periféricos (utiliza un bus especial) al contrario que el bus único que los considera a ambos como posiciones de memoria (incluso equipara las Operaciones E/S con las de lectura/escritura en memoria). Este bus especial que utiliza el bus dedicado tiene 4 componentes fundamentales:

Datos: Intercambio de información entre la CPU y los periféricos. Control: Lleva información referente al estado de los periféricos

(petición de interrupciones). Direcciones: Identifica el periférico referido. Sincronización: Temporiza las señales de reloj.

La mayor ventaja del bus único es su simplicidad de estructura que le hace ser más económico, pero no permite que se realice a la vez transferencia de información entre la memoria y el procesador y entre los periféricos y el procesador. Por otro lado el bus dedicado es mucho más flexible y permite transferencias simultáneas. Por contra su estructura es más compleja y por tanto sus costes son mayores 1.2. Estructura lógica del procesador.

La ALU contiene localidades de almacenamiento llamadas registros, definidos de la siguiente manera: Registro Temporal de Memoria "Buffer" (MBR): Contiene una

palabra que debe ser almacenada en memoria, o recibe una palabra procedente de la memoria.

Registro de Dirección de Memoria (MAR): Especifica la dirección de memoria de la palabra que va a ser escrita o leída en MBR.

Registro de /instrucción (IR): Contiene el código de operación de la instrucción que se va a ejecutar.

Registro Temporal de /instrucción (IBR): Almacena temporalmente la instrucción contenida en la parte derecha de una palabra.

Contador de Programa (PC): Contiene la dirección de la siguiente pareja de instrucciones que se traerán de memoria.

Acumulador (AC) Multiplicador Cociente (MQ): Se emplean para almacenar temporalmente operandos y resultados de operaciones de la ALU.

Page 9: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

9

Virtualmente todas las computadoras se han diseñado basándose en los conceptos desarrollados por von Neumann. Tal diseño se conoce como Arquitectura de von Neumann y se basa en tres conceptos clave: Los datos y las instrucciones se almacenan en una sola memoria de

lectura - escritura. Los contenidos de esta memoria se direccionan indicando su

posición, sin considerar el tipo de dato contenido en la misma. La ejecución se produce siguiendo una secuencia de instrucción tras

instrucción (a no ser que dicha instrucción se modifique explícitamente).

Ciclo maquina La función básica de una computadora es ejecutar programas, el cual está compuesto de un conjunto de instrucciones almacenadas en memoria. La CPU es la encargada de ejecutar las instrucciones específicas del programa. Para comprender esta función debe considerarse el detalle del proceso de ejecución del programa. Desde el punto de vista más simple, se considera el procesamiento de una instrucción en dos etapas: la CPU lee (busca, trae; fetch en inglés) la instrucción de memoria y la ejecuta. La ejecución del programa consiste en la repetición del proceso de traer y ejecutar la instrucción. Buscar una instrucción es una operación común a todas las instrucciones, y consiste en la lectura de la instrucción de una localidad de memoria. La ejecución de la instrucción puede suponer varias operaciones y depende de la naturaleza de la instrucción. El procesamiento de una instrucción se denomina ciclo de instrucción. Los dos pasos se denotan como ciclo de búsqueda y ciclo de ejecución. La ejecución del programa se detiene sólo si la computadora se desconecta, se produce algún error o se encuentra una instrucción que detiene la computadora. Al principio de cada ciclo de instrucción, la CPU busca o trae una instrucción de memoria. En una CPU típica, se utiliza un registro llamado contador de programa (PC program counter) para apuntar a la instrucción que debe traerse a continuación. A no ser que se indique otra cosa, la CPU siempre incrementa el PC después de traer una instrucción para

Page 10: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

10

determinar de dónde traer la siguiente instrucción de la secuencia (siguiente dirección de memoria). La instrucción traída se almacena en un registro de la CPU conocido como registro de instrucción (IR instruction register). La CPU interpreta la instrucción y realiza la acción requerida. En general, ésta puede ser de cuatro tipos:

• CPU - Memoria: Deben transferirse datos desde la CPU a la memoria o viceversa.

• CPU - E/S: Deben transferirse datos a o desde el exterior mediante el módulo de E/S.

• Procesamiento de datos: La CPU realizará alguna operación aritmética o lógica con los datos.

• Control: Una instrucción puede especificar que la secuencia de ejecución se altere por lo que la CPU debe poner el contador de programa al valor adecuado.

El ciclo de ejecución de una instrucción puede ocasionar más de una referencia a memoria, o en su lugar, puede especificar una operación de E/S. Con estas consideraciones en mente, la figura 5 proporciona una visión más detallada el ciclo de instrucción. Para un ciclo de instrucción dado, algunos estados pueden no darse y otros pueden visitarse más de una vez. Los estados del ciclo maquina ocasionan intercambio entre la CPU y la memoria o módulo E/S. Los circuitos micro programables son sistemas digitales, lo que significa que trabajan con dos únicos niveles de tensión. Dichos niveles, por abstracción, se simbolizan con el cero, 0, y el uno, 1, por eso el lenguaje de máquina sólo utiliza dichos signos. Esto permite el empleo de las teorías del álgebra booleana y del sistema binario en el diseño de este tipo de circuitos y en su programación. Una visión típica de la arquitectura de computadores como una serie de capas de abstracción: hardware, firmware, ensamblador, kernel, sistema operativo y aplicaciones. Claude Elwood Shannon, en su Analysis of Relay and Switching Circuits, y con sus experiencias en redes de conmutación, sentó las bases para la aplicación del álgebra de Boole a las redes de conmutación.

Page 11: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

11

Un lenguaje de programación de bajo nivel es el que proporciona poca o ninguna abstracción del microprocesador de un ordenador. Consecuentemente es fácilmente trasladado a lenguaje de máquina. La palabra "bajo" no implica que el lenguaje sea inferior a un lenguaje de alto nivel; se refiere a la reducida abstracción entre el lenguaje y el hardware. En general se utiliza este tipo de lenguaje para programar controladores (drivers). Se trabaja a nivel de instrucciones, es decir, su programación es al más fino detalle. Está orientado a la máquina. Primera generación El lenguaje de programación de primera

generación (por sus siglas en inglés, 1GL), es el lenguaje de código máquina. Es el único lenguaje que un microprocesador entiende de forma nativa. El lenguaje máquina no puede ser escrito o leído usando un editor de texto, y por lo tanto es raro que una persona lo use directamente.

Segunda generación El lenguaje de programación de segunda generación (por sus siglas en inglés, 2GL), es el lenguaje ensamblador. Se considera de segunda generación porque, aunque no es lenguaje nativo del microprocesador, un programador de lenguaje ensamblador debe conocer la arquitectura del microprocesador (como por ejemplo las particularidades de sus registros o su conjunto de instrucciones).

Entonces recapitulemos: Lenguajes Las instrucciones deben darse en un lenguaje de programación, es decir, en una determinada configuración de información digital binaria. En las primeras computadoras, la programación era una tarea difícil y laboriosa ya que los conmutadores ON-OFF de las válvulas de vacío debían configurarse a mano. Programar tareas tan sencillas como ordenar una lista de nombres requería varios días de trabajo de equipos de programadores. Desde entonces se han inventado varios lenguajes informáticos, algunos orientados hacia funciones específicas y otros centrados en la facilidad de uso. Lenguaje máquina El lenguaje propio del ordenador, basado en el sistema binario, o código máquina, resulta difícil de utilizar para las personas. El programador debe introducir todos y cada uno de los comandos y datos en forma binaria, y una operación sencilla como comparar el contenido de un registro con los

Page 12: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

12

datos situados en una ubicación del chip de memoria puede tener el siguiente formato: 11001010 00010111 11110101 00101011. La programación en lenguaje máquina es una tarea tan tediosa y consume tanto tiempo que muy raras veces lo que se ahorra en la ejecución del programa justifica los días o semanas que se han necesitado para escribir el mismo. Lenguaje ensamblador Al asignar un código mnemotécnico (por lo general de tres letras) a cada comando en lenguaje máquina, es posible escribir y depurar o eliminar los errores lógicos y de datos en los programas escritos en lenguaje ensamblador, empleando para ello sólo una fracción del tiempo necesario para programar en lenguaje máquina. En el lenguaje ensamblador, cada comando mnemotécnico y sus operadores simbólicos equivalen a una instrucción de máquina. Un programa ensamblador traduce el código fuente, una lista de códigos de operación mnemotécnicos y de operadores simbólicos, a código objeto (es decir, a lenguaje máquina) y, a continuación, ejecuta el programa. Sin embargo, el lenguaje ensamblador puede utilizarse con un solo tipo de chip de CPU o microprocesador. Los programadores, que dedicaron tanto tiempo y esfuerzo al aprendizaje de la programación de un ordenador, se veían obligados a aprender un nuevo estilo de programación cada vez que trabajaban con otra máquina. Lo que se necesitaba era un método abreviado en el que un enunciado simbólico pudiera representar una secuencia de numerosas instrucciones en lenguaje máquina, y un método que permitiera que el mismo programa pudiera ejecutarse en varios tipos de máquinas. Estas necesidades llevaron al desarrollo de lenguajes de alto nivel. Intérpretes y compiladores La traducción de una serie de instrucciones en lenguaje ensamblador (el código fuente) a un código máquina (o código objeto) no es un proceso muy complicado y se realiza normalmente por un programa especial llamado compilador. La traducción de un código fuente de alto nivel a un código máquina también se realiza con un compilador, en este caso más complejo, o mediante un intérprete. Un compilador crea una lista de instrucciones de código máquina, el código objeto, basándose en un código fuente. El código objeto resultante es un programa rápido y listo para funcionar, pero que puede hacer que falle el ordenador si no está

Page 13: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

13

bien diseñado. Los intérpretes, por otro lado, son más lentos que los compiladores ya que no producen un código objeto, sino que recorren el código fuente una línea cada vez. Cada línea se traduce a código máquina y se ejecuta. Cuando la línea se lee por segunda vez, como en el caso de los programas en que se reutilizan partes del código, debe compilarse de nuevo. Aunque este proceso es más lento, es menos susceptible de provocar fallos en la computadora. El uso de microprocesadores requiere el dominio de los sistemas numéricos decimal, hexadecimal y binario. Todo sistema numérico parte del 0 y tiene tantos dígitos como su sistema lo marque. Tomando en cuenta esto, tenemos que el sistema binario empieza con 0 y contiene solo 2 (binario) dígitos por lo tanto el siguiente dígito es 1. El sistema decimal igual empieza de 0 y termina en 9 (sumando así 10 dígitos) y así sucesivamente. Es importante que considere que "micro" (la maquina) identifica el numero negativo con "bits de estatus" que veremos en el siguiente punto (1.4), y que el símbolo negativo (-) es solo una representación para el usuario final. 1.4.1 Conceptos de modelo de programación. La arquitectura de un microprocesador o de cualquier procesador de computadora, se define por su conjunto de instrucciones y por el modo en como éstas acceden a los datos en memoria para su procesamiento. Las instrucciones que obedece un microprocesador están codificadas como dígitos binarios en su sistema de memoria. Cada instrucción puede dividirse en uno o más campos de bits. Todas las instrucciones tienen un campo de código de operación (COP), que define el propósito de la instrucción. Además, la instrucción completa puede tener campos para operandos o direcciones de memoria que especifican en donde están almacenados los datos. Lo anterior delimita el concepto de "formato de instrucción".

Page 14: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

14

Las instrucciones por su complejidad pueden ser sencillas o compuestas. Los microprocesadores que ejecutan instrucciones sencillas son los llamados RISC (Reduced Instruction Set Computer), como por ejemplo el PIC16C84 de MicroChip o el propio Sparc de SUN y el PPC604 de Motorola. Por otra parte tenemos a los microprocesadores con instrucciones compuestas, los CISC ( Complex Instruction Set Computer ), como el 6809 de Motorola, SIC/XE y la serie 80X86 de Intel. Existen algunos procesadores híbridos muy eficientes como los famosos K6, K6-II y K6-III de AMD. En este punto se ve de acuerdo al manual de referencia del dispositivo a tratar. Para nuestro curso el microprocesador a ver será el HC12. El modelo de programación representa la estructura de manipulación de datos que soporta el conjunto de instrucciones, usualmente compuesta por: • Unidad aritmética y lógica Los registros de trabajo El registro de condiciones La memoria de datos. El modelo de programación del HC12 se muestra en la gráfica siguiente: A B Acumulador A y B D 0 doble acumulador D IX Registro indexado X IY Registro indexado Y SP Stack pointer PC Contador de programa El CPU tiene 2 registros de propósito general (A,B) que pueden ser concatenados a uno solo de 16 bits (D). Tiene 2 tipos de registros indexados (X, Y), el stack pointer, el contador de programa y los códigos de condición de registros. Las instrucciones por su operatividad pueden estudiarse en tres clases. De asignación y transferencia de datos (LDAA, LEAS, STAA, MOVB,

etc.). De aritmética y lógica (ABA, ADCA, ADDD, SBA, DEC, ANDA,... etc.). De control de programa (JSR, JMP, RTS, JSR,... etc.).

Mientras que los registros son clasificados de acuerdo a su función: registro de datos registros de segmentos bandera de registro registros indexados

Page 15: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

15

Modo de direccionamiento: Por la manera en como las instrucciones acceden a los datos en memoria o en los registros, éstas se pueden clasificar en los siguientes direccionamientos (para el HC12): SIMPLES: Inherente, inmediato, directo, extendido; NO SIMPLES: relativo, indexado (diferentes tipos), múltiples, otros. El campo de operación de una instrucción especifica la operación que se debe realizar. Esta debe ser ejecutada sobre algunos datos almacenados en registros del computador o en palabras de memoria, es decir, sobre los operandos. El modo de direccionamiento especifica la forma de interpretar la información contenida en cada campo de operando para localizar, en base a esta información, el operando. Al usuario que tiene poca experiencia, la variedad de modos de direccionamiento en una computadora le Debe parecer excesivamente complicada. Sin embargo, la disponibilidad de diferentes esquemas de direccionamiento le da al programador experimentado flexibilidad para escribir programas que son más eficientes en cuanto a número de instrucciones y tiempo de ejecución. Es tal la importancia de los modos de direccionamiento que la potencia de una máquina se mide tanto por su repertorio de instrucciones como por la variedad de modos de direccionamiento que es capaz de admitir. Los modos de direccionamiento de un ordenador son las diferentes formas de transformación del campo de operando de la instrucción en la dirección del operando. En esta definición el término dirección debe interpretarse en su sentido más general de localización del operando, en cualquier lugar, y no en el sentido más estricto de dirección de memoria. A la dirección obtenida de las transformaciones anteriores la llamaremos dirección efectiva. Esta dirección, en el caso de tratarse de una dirección de memoria, es la que se cargará en el M.A.R. o registro de dirección de memoria. La especificación del modo de direccionamiento puede ir en el código de operación o en el campo de cada operando. La CPU ofrece varios métodos para calcular direcciones de memoria. Los accesos a memoria se pueden: categorizar como accesos para obtener la

Page 16: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

16

siguiente instrucción a ejecutarse, o para obtener algún dato específico. En cuanto a conseguir la siguiente instrucción por ejecutarse, la CPU utiliza la combinación de los registros CS e IP, los rúales dan la dirección deseada. Antes de entrar en detalles sobre las diferentes modalidades de direccionamiento de la memoria para obtener algún dato específico, vale la pena aclarar algunos conceptos acerca de lo que es un segmento, así como de la manera que se forma una dirección. Una instrucción es un código binario con un significado ya establecido de antemano. Para no tener que memorizar estos códigos y facilitar de esta manera la tarea del programador, a cada instrucción se le asigna una abreviatura que dé una idea de la acción que realiza. Así por ejemplo si se pretende cargar un dato en el acumulador se emplea una instrucción cuyo mnemónico es LDA abreviatura de LoaD Accumulator. Pero además hay que indicar en la instrucción cual es el dato o donde se encuentra el dato con el que hay que operar. Así por ejemplo la instrucción LDA (Cargar el acumulador) da lugar a los nueve códigos de operación que se indican en la tabla de su manual de referencia, que tienen como denominador común que todas las instrucciones cargan en el acumulador un dato, pero difieren en la forma de obtener ese dato. Por lo tanto el MODO DE DIRECCIONAMIENTO DETERMINA COMO LA UNIDAD CENTRAL DE PROCESO (CPU) ACCEDE A LAS LOCALIDADES DE MEMORIA PARA OPERAR. Los modos de direccionamiento son parte implícita del conjunto de instrucciones del dispositivo. Ver apéndices del manual de referencia de dicho micro. Las instrucciones que usan más de un modo de direccionamiento se verán como modos de direccionamiento múltiple. CADA MODO DE DIRECCIONAMIENTO GENERA UNA DIRECCIÓN EFECTIVA DE 16 BITS QUE ES USADA DURANTE PORCIÓN DE REFERENCIA DE LA INSTRUCCIÓN. LA DIRECCIÓN EFECTIVA NO REQUIERE EJECUCIÓN DE CICLOS EXTRA. Los micros utilizan técnicas de direccionamiento con los siguientes fines: Dar versatilidad de programación al usuario proporcionando facilidades tales como índices, direccionamientos indirectos, etc., esta versatilidad

Page 17: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

17

nos servirá para manejar estructuras de datos complejas como vectores, matrices, etc. Reducir el número de bits del campo de operando. Esto permite al usuario flexibilidad para escribir programas que son más eficientes en cuanto a número de instrucciones y tiempo de ejecución. Es tal la importancia de los modos de direccionamiento que la potencia de una máquina se mide tanto por su repertorio de instrucciones como por la variedad de modos de direccionamiento que es capaz de admitir. Los modos de direccionamiento de un micro son las diferentes formas de transformación del campo de operando de la instrucción en la dirección del operando. En esta definición el término dirección debe interpretarse en su sentido más general de localización del operando, en cualquier lugar, y no en el sentido más estricto de dirección de memoria. A la dirección obtenida de las transformaciones anteriores la llamaremos dirección efectiva. Esta dirección, en el caso de tratarse de una dirección de memoria, es la que se cargará en el M.A.R. o registro de dirección de memoria. 1.4.2 Direccionamientos simples. (Inherente, Inmediato, Directo y Extendido).

Inherente: Instrucciones que usan este método de direccionamiento no tienen operando externos (solo el mnemónico o instrucción), o si los tiene son registros, estos son registros internos del CPU. En cualquier caso el CPU no accesa a ninguna localidad de memoria para completar la instrucción. EJEMPLOS: NOP; esta instrucción, no tiene operando INX; esta instrucción tiene operando del CPU. Inmediato: El símbolo de (#) es usado para indicar un operando en modo de direccionamiento inmediato. Un error común de programación es el omitir accidentalmente el símbolo #. Esto causa que el ensamblador malinterprete la expresión que sigue como una dirección. Es decir: LDA #$55 significa un cargo al acumulador A del valor 55, mientras que LDA $55, que significa que al acumulador A se le carga el valor del contenido de la dirección $0055. Sin el símbolo #, la instrucción cambia.

Page 18: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

18

Nota, que el símbolo de "#" es el identificador del modo de direccionamiento aplicado, el siguiente símbolo, si es que lo tiene, identifica el sistema de numeración. Para el usuario final (el programador en lenguaje ensamblador) las bases de numeración tienen mucha importancia ya que la señal de salida se puede interpretar de acuerdo al dispositivo utilizado. Directo: Este modo es llamado algunas veces "direccionamiento de PAGINA CERO" porque opera en un rango de $0000 hasta $00FF. En ambos casos la localidad de memoria $0055 (IVE 2 BYTES) es a la que accesa el CPU para poder extraer el dato. El byte más significativo deberá ser 0. Operacionalmente hablando mientras que en el modo de direccionamiento inmediato el valor del operador modifica el estado del dato (operación), en el modo de direccionamiento directo, es la búsqueda de una localidad de memoria representada por 1 byte. Extendido: En este modo, los 16 bits de memoria son ocupados, es decir la localidad de memoria accesada en ambos casos es de 0100, o sea 2 bytes. Este modo de direccionamiento es utilizado exclusivamente por las instrucciones de salto condicional (branch). La dirección de memoria a la que se transfiere el control del programa se obtiene sumando el valor del contador de programa al segundo byte de la instrucción, denominado "offset". Este offset es un número en complemento a-2, con lo que se pueden efectuar saltos de hasta 127 posiciones hacia adelante o 128 hacia atrás. Para este modo de direccionamiento es importante utilizar la variable CONLOCT, que es el contador de localidades, por lo tanto para los modos de direccionamiento relativo (8, 9 y 16).

Page 19: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

19

1.4.4 Direccionamiento Relativo de 16 bits.

Este al igual que el anterior corresponde a las instrucciones (mnemónicos) de salto condicional (control de programa), con la diferencia de rango -32k a +32k lo que da 2 bytes completos de desplazamiento. 1.4.5 Direccionamiento Indexado.

En este, los registros internos indexados son el segundo operador, lo que hace que: El operando se encuentra en memoria. Registro índice: se modifica a menudo en la ejecución del programa. Al igual que todos y cada uno de los modos de direccionamiento cada estructura, representa una acción diferente. Para llevar a cabo la traducción correcta se presenta la siguiente figura, que es una tabla de modos de direccionamiento indexado (formas fuente). Para saber que formula se utilizara, debemos determinar: 1. que la línea de programa está utilizando modo de direccionamiento indexado. 2. la forma fuente del modo de indexado (n,r). 3. formula aplicar, de acuerdo al rango. Se tienen 6 formulas. Chequemos por puntos: El operando se encuentra en memoria. La instrucción contiene una dirección que se emplea para leer en memoria una dirección intermedia que será la verdadera dirección del objeto buscado ver punto anterior. 1.4.7 Otros direccionamientos. 1.4.7.1 Relativo de 9 Bits.

Este al igual que los anteriores corresponde a las instrucciones (mnemónicos) de salto condicional (control de programa), con la diferencia de rango -/+ 1 byte y con el siguiente formato. Que igual que los relativos anteriores se verán a detalle en el siguiente modulo.

Page 20: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

20

2. ENSAMBLADORES. Objetivo: Entender y manejar los diferentes esquemas de ensamblado. Diseñar un ensamblador de dos pasos. 2.1 Relación Arquitectura de máquinas y ensamblador.

La evolución de los sistemas comienza con un ensamblador, se sigue con los CARGADORES que es el modulo 3 para nuestro caso de estudio, MACROPROCESADORES que es el modulo 4, COMPILADORES y SISTEMAS OPERATIVOS. Al inicio de los tiempos, el programador tenía que interpretar el fundamento de la instrucción, se escribían una serie de unos y ceros (lenguaje maquina) y se grababan en la memoria del dispositivo, entonces el dispositivo interpretaba como esto como una instrucción. Los programadores encontraban esta tarea (leer o escribir en la memoria) muy lenta, así que se introdujo el concepto de MNEMONICO, que sustituye al conjunto de UNOS y CEROS, y al conjunto de estos mnemónicos LENGUAJE ENSAMBLADOR. La entrada de dicho programa se le llama PROGRAMA FUENTE y a la salida PROGRAMA OBJETO (que es la traducción de dichas instrucciones a lenguaje maquina. Los ensambladores son programas que procesan los enunciados del programa origen en lenguaje ensamblador y los traducen en archivos en lenguaje máquina que son ejecutados por un microprocesador o un micro controlador, estos permiten que los programas origen se escriban y se editen en una computadora para generar un código ejecutable en otra computadora. El archivo en lenguaje objeto ejecutable resultante se carga (CARGADOR) y se ejecuta en el sistema destino. Lenguaje ensamblador es el lenguaje simbólico que se utiliza para codificar los programas origen que se procesan por el ensamblador es llamado lenguaje ensamblador. Este lenguaje es una colección de símbolos mnemónicos que representan: operaciones (mnemónicos de instrucciones para la máquina o de directrices para el ensamblador), nombres simbólicos, operadores y símbolos especiales. El lenguaje ensamblador proporciona códigos de operación de los mnemónicos para

Page 21: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

21

todas las instrucciones de la máquina contenidas en la lista de instrucciones. Los fabricantes de microprocesadores y micro controladores ofrecen una gran variedad de herramientas de soporte para los diseñadores, tales programas se incluyen con los sistemas de desarrollo. Los programas almacenados en ROM ofrecen un medio de comunicación con la PC, los cuales descargan el programa de aplicación del usuario en memoria RAM, para luego ser interpretado por el micro, la versatilidad, que ofrecen estos sistemas disminuye la posibilidad de error de los diseñadores. EL micro recibe las instrucciones de una memoria interna o externa en forma de 1 o 0, a esto se le denomina instrucción de código de máquina, la cual controla las operaciones que realiza el micro. Para el usuario le queda escribir el programa en una serie de instrucciones propias llamados mnemónicos, que describe una instrucción de código de máquina también conocido como código operativo. El programa escrito en mnemónicos es ensamblado en un ambiente o software que se ejecuta en una PC. Introduciendo así un listado en código hexadecimal llamado código fuente, que es en realidad el listado de instrucciones de código de máquina o códigos operativos. El ensamblador es propio del fabricante. Los depuradores son sistemas en los que nos permiten evaluar un programa en tiempo real, es decir, sobre el micro, teniendo interacción en un ambiente gráfico sobre una pe, también reciben el nombre de emuladores (hardware y software). Los simuladores son ambientes totalmente de programación (software) que nos permiten evaluar programas los cuales se pueden visualizar el comportamiento o estado de "acumuladores, registros de memoria del programa, contenido de memoria, etc. Un mnemónico es una instrucción en bajo nivel, el cual está escrito de manera de abreviación del idioma ingles. Ejemplo: nop (not operation), Idaa (load accumulator a), rola (rótate left accumulator) etc. Una pseudo-instruccion es una instrucción al ensamblador (no al micro), por lo tanto esta no tiene código objeto (hexadecimal) algunas de las pseudo-instrucciones más usadas son: equ, org, end, etc. Un ensamblador es un programa que traduce las instrucciones a lenguaje maquina, estos deben ser escritos conforme a las especificaciones del ensamblador. Un programa consiste en declaraciones (llamadas línea código) línea por línea. Su sintaxis es la siguiente: nombre del campo, operación del campo, operando del campo, sintaxis del campo, ejemplo:

Page 22: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

22

Campo de Etiquetas: Una etiqueta puede aparecer por si sola en una línea. El ensamblador interpreta esto como "establece el valor de la etiqueta igual al valor actual del contador de programa ( PC )". El campo de etiquetas aparece como el primer campo dentro de un enunciado origen. El campo de etiquetas puede adoptar cualquiera de las siguientes formas:

o Un asterisco (*) como el primer carácter en el campo de etiquetas indica que el resto del enunciado origen es un comentario. Los comentarios son ignorados por el ensamblador e impresos en el listado origen solamente como información de programación, o Un espacio de carácter en blanco (TAB o espacio) como primer carácter indica que el campo de etiquetas se encuentra vacío. La línea no tiene una etiqueta y no es un comentario, o Un símbolo como primer carácter indica que la línea tiene etiqueta. Estos símbolos son las letras mayúsculas y minúsculas (a - z), los dígitos (0 - 9) y caracteres especiales como punto (.), signo de pesos ($) y subrayado (). Estos símbolos consisten de uno a quince caracteres, el primero de los cuales debe ser alfabético o un carácter especial punto o subrayado. Todos los caracteres son significantes y las mayúsculas y minúsculas son distintas. Etc.

o Campo de Operaciones: El campo de operaciones aparece después del campo de etiquetas y debe de estar precedido por al menos un espacio en blanco.

o El campo de operaciones debe de contener el mnemónico de un código de operación legal o una directriz del ensamblador.

o En este campo, los caracteres en mayúsculas son convertidos en minúsculas antes de ser revisados como un mnemónico legal, o Debido a esto " nop "," NOP " y " NoP 11 son reconocidos como el mismo mnemónico. o Los símbolos que aparecen en este campo pueden ser de uno de dos tipos.

o Código de Operación: Estos símbolos corresponden directamente a instrucciones de máquina. El código de operación incluye a cualquier nombre e registro asociado con la instrucción.

o Estos nombres de registros no deben de estar separados del código de operación por ningún espacio en blanco.

o De esta forma, “clra” significa “limpia (poner en ceros) el acumulador (A)”, pero 11 Ir a significa “limpia la localidad de memoria identificada por la etiqueta A”.

Page 23: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

23

o Directiva /Pseudoinstruccion: Estos son códigos de operación especiales conocidos por el ensamblador, los cuales más bien controlan el proceso de ensamblado en vez de ser traducidos a instrucciones máquina.

o Campo de Operandos: La interpretación del campo de operandos depende del contenido del campo de operaciones.

o El campo de operandos, si se requiere, debe de seguir al campo de operaciones y debe de estar precedido por al menos un espacio en blanco.

o El campo de operandos puede contener un símbolo, una expresión o una combinación de símbolos y expresiones separados por comas, o El campo de operandos de una instrucción máquina es utilizada para especificar el modo de direccionamiento de la instrucción, así como el operando de la instrucción, o La siguiente tabla resume los diferentes formatos del campo de operandos para la familia HC11.

o Símbolos: Cada símbolo se encuentra asociado con un valor entero de 16 bits, el cual es utilizado en lugar del símbolo durante la evaluación de la expresión.

o El asterisco (*) utilizado en una expresión como símbolo representa el valor actual del contador de localidades (el primer byte de una instrucción de varios bytes).

o Constantes: Las constantes representan cantidades de información que no varían en su valor durante la ejecución del programa.

o Las constantes pueden ser presentadas al ensamblador en uno de cinco posibles formatos: decimal, hexadecimal, binario, octal o ASCII, o El programador le indica al ensamblador el formato del número con los siguientes prefijos: Las constantes sin prefijo son interpretadas como

decimal. o El ensamblador convierte todas las constantes a código máquina

binaria y son desplegadas en el listado del ensamblado como valores hexadecimales.

o Campo de Comentarios: El último campo de un enunciado origen del ensamblador es el campo de comentarios.

o Este campo es opcional y solamente es impreso en el listado origen con propósitos de documentación.

Page 24: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

24

o El campo de comentarios es separado del campo de los operandos (o del campo de operaciones sino se requiere operando) por al menos un espacio en blanco, o El campo de comentarios puede contener cualquier carácter imprimible ASCII.

Esto se cumple dependiendo del mnemónico y del direccionamiento (como se muestra en los ejemplos de arriba). Una vez que hemos visto la evolución de los lenguajes, cabe preguntarse: ¿En estos tiempos "modernos", qué quiero del Lenguaje Ensamblador?, he aquí algunas ventajas y desventajas. Ventajas: • Velocidad: El proceso de traducción que realizan los intérpretes, implica un proceso de cómputo adicional al que el programador quiere realizar. Por ello, nos encontraremos con que un intérprete es siempre más lento que realizar la misma acción en Lenguaje Ensamblador, simplemente porque tiene el costo adicional de estar traduciendo el programa, cada vez que lo ejecutamos. De ahí nacieron los compiladores, que son mucho más rápidos que los intérpretes, pues hacen la traducción una vez y dejan el código objeto, que ya es Lenguaje de D máquina, y se puede ejecutar muy rápidamente. Aunque el proceso de traducción es más complejo y costoso que el de ensamblar un programa, normalmente podemos despreciarlo, contra las ventajas de codificar el programa más rápidamente. Sin embargo, la mayor parte de las veces, el código generado por un compilador es menos eficiente que el código equivalente que un programador escribiría. La razón es que el compilador no tiene tanta inteligencia, y requiere ser capaz de crear código genérico, que sirva tanto para un programa como para otro; en cambio, un programador humano puede aprovechar las características específicas del problema, reduciendo la generalidad pero al mismo tiempo, no desperdicia ninguna instrucción, no hace ningún proceso que no sea necesario. • Eficiencia en el tamaño: Por las mismas razones que vimos en el aspecto de velocidad, los compiladores e intérpretes generan más código máquina del necesario; por ello, el programa ejecutable crece. Así, cuando es importante reducir

Page 25: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

25

el tamaño del ejecutable, mejorando el uso de la memoria y teniendo también beneficios en velocidad, puede convenir usar el lenguaje Ensamblador. Entre los programas que es crítico el uso mínimo de memoria, tenemos a los virus y manejadores de dispositivos (drivers). Muchos de ellos, por supuesto, están escritos en lenguaje Ensamblador. • Flexibilidad: Las razones anteriores son cuestión de grado: podemos hacer las cosas en otro lenguaje, pero queremos hacerlas más eficientemente. Pero todos los lenguajes de alto nivel tienen limitantes en el control; al hacer abstracciones, limitan su propia capacidad. Es decir, existen tareas que la máquina puede hacer, pero que un lenguaje de alto nivel no permite. Por ejemplo, en Visual Basic no es posible cambiar la resolución del monitor a medio programa; es una limitante, impuesta por la abstracción del GUI Windows. En cambio, en ensamblador es sumamente sencillo, pues tenemos el acceso directo al hardware del monitor. Desventajas: • Tiempo de programación: Al ser de bajo nivel, el Lenguaje Ensamblador requiere más instrucciones para realizar el mismo proceso, en comparación con un lenguaje de alto nivel. Por otro lado, requiere de más cuidado por parte del programador, pues es propenso a que los errores de lógica se reflejen más fuertemente en la ejecución. Por todo esto, es más lento el desarrollo de programas comparables en Lenguaje Ensamblador que en un lenguaje de alto nivel, pues el programador goza de una menor abstracción. • Programas fuentes grandes: Por las mismas razones que aumenta el tiempo, crecen los programas fuentes; simplemente, requerimos más instrucciones primitivas para describir procesos equivalentes. Esto es una desventaja porque dificulta el mantenimiento de los programas, y nuevamente reduce la productividad de los programadores. • Peligro de afectar recursos inesperadamente: Tenemos la ventaja de que todo lo que se puede hacer en la máquina, se puede hacer con el Lenguaje Ensamblador (flexibilidad). El problema es

Page 26: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

26

que todo error que podamos cometer, o todo riesgo que podamos tener, podemos tenerlo también en este Lenguaje. En ciertos casos extremos, puede llegarse a sobrescribir información del CMOS de la máquina. • Falta de portabilidad: Como ya se mencionó, existe un lenguaje ensamblador para cada máquina; por ello, evidentemente no es una selección apropiada de lenguaje cuando deseamos codificar en una máquina y luego llevar los programas a otros sistemas operativos o modelos de computadoras. Si bien esto es un problema general a todos los lenguajes, es mucho más notorio en ensamblador: yo puedo reutilizar un 90% o más del código que desarrollo en "C", en una PC, al llevarlo a una RS/6000 con UNIX, y lo mismo si después lo llevo a una Macintosh, siempre y cuando esté bien hecho y siga los estándares de "C", y los principios de la programación estructurada. En cambio, si escribimos el programa en Ensamblador de la PC, por bien que lo desarrollemos y muchos estándares que sigamos, tendremos prácticamente que reescribir el 100 % del código al llevarlo a UNIX, y otra vez lo mismo al llevarlo a Mac. 2.1.1 Características Dependientes de la Maquina.

El ensamblador de dos pasos puede ser muy eficiente para la administración de la memoria que ocupa durante su ejecución, pues el primero y segundo paso no tiene necesidad de estar cargados en memoria al mismo tiempo pues: las tareas respectivas en lo fundamental son distintas. Cuyas características son las siguientes: • Dependientes de la máquina. • Independientes de la máquina. Son características dependientes del procesador, desde luego el conjunto de instrucciones, los modos de direccionamiento, la generación de código y sin faltar la interfaz con la plataforma en la cual corre el ensamblador, un aspecto importante que no se nos debe pasar por alto, es que los ensambladores pueden tener una clasificación en virtud de su generación de código.

o COP: código de operación, pues si bien el código 8605 significa para el HC12 cargar al Acumulador A un 5, para el HC08 de la misma familia de Motorola es otra cosa muy diferente (el código correspondiente para dicha acción es 9605.

Page 27: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

27

o MODO DE DIRECCIONAMIENTO: aunque existen "E" modos de direccionamientos, no todos son aplicables a los micros.

o MNEMONICO: las instrucciones aunque en concepto podrían ser las mismas, se enuncian de diferente manera.

o REGISTROS INTERNOS: como parte de la arquitectura de cada micro y así podríamos seguir enumerando encontrando las características que hacen exclusivo al micro.

2.1.2 Características Independientes de la maquina.

Las características independientes de la máquina son aquellas relacionadas más bien con el tipo de implementación del programa y sus estructuras de datos que con la máquina objeto.

o DIRECTIVAS: también existen las llamadas DIRECTIVAS o PSEUDOINSTRUCCIONES, las cuales especifican acciones auxiliares que se llevan a cabo por el ensamblador.

o PERIFÉRICOS: todo dispositivo que será controlado por el micro o ARCHIVOS AUXILIARES: *.LST, *.OBJ, *.S19, *.TABSIM, etc.,

dependiendo del algoritmo con que se trabaje.... De igual manera podríamos seguir numerando características globales para los micros

2.2 Modalidades de ensamblado Al considerar que un segmento es un área especial en un programa que inicia en un límite de un párrafo, esto es, en una localidad de regularmente divisible entre 16, o 10 hexadecimal. Aunque un segmento puede estar ubicado casi en cualquier lugar de la memoria y, en modo real, puede ser hasta de 64K, solo necesita tanto espacio como el programa requiera para su ejecución. Un segmento en modo real puede ser de hasta 64K. Se puede tener cualquier número de segmentos; para direccionar un segmento en particular basta cambiar la dirección en el registro del segmento apropiado. Los tres segmentos principales son los segmentos de código, de datos y de la pila. Segmento de código:

El segmento de código (CS) contiene las instrucciones de máquina que son ejecutadas por lo común la primera instrucción ejecutable esta en el inicio

Page 28: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

28

del segmento, y el sistema operativo enlaza a esa localidad para iniciar la ejecución del programa. Como su nombre indica, el registro del CS direcciona el segmento de código. Si su área de código requiere más de 64K, su programa puede necesitar definir más de un segmento de código. Segmento de datos:

El segmento de datos (DS) contiene datos, constantes y áreas de trabajo definidos por el programa. El registro DS direcciona el segmento de datos. Si su área de datos requiere más de 64K, su programa puede necesitar definir más de un segmento de datos. Segmento de pila:

En términos sencillos, la pila contiene los datos y direcciones que usted necesita guardar temporalmente o para uso de sus "llamadas" subrutinas. El registro de segmento de la pila (SS) direcciona el segmento de la pila. Limites de los segmentos:

Los registros de segmentos contienen la dirección inicial de cada segmento. La siguiente figura presenta un esquema de los registros CS, DS y SS; los registros y segmentos no necesariamente están en el orden mostrado. Otros registros de segmentos son el ES (segmento extra) y, en los procesadores 80386 y posteriores, los registros FS y GS, que contienen usos especializados. Un segmento inicia en un límite de párrafo, que es una dirección por lo común divisible entre el 16 decimal o 10 hexadecimal. Ejemplo: un segmento de datos inicia en la localidad de memoria 045F0H. Ya que en este y todos los demás casos el ultimo dígito hexadecimal de la derecha es cero, los diseñadores de computadora decidieron que sería innecesario almacenar el dígito cero en el registro del segmento. Así, 045F0H se almacena como 045F, con el cero de la extrema derecha sobrentendido. En donde sea apropiado, el texto indica al cero de la derecha con corchetes, como 045F [0]. Desplazamiento: En un programa, todas las localidades de memoria están referidas a una dirección inicial de segmento. La distancia en bytes desde la dirección del segmento se define como el desplazamiento (offset). Un desplazamiento de dos bytes (16 bits) puede estar en el rango de 0000H hasta FFFFH, o bien, desde cero hasta 65, 535. Así el primer byte del segmento de código tiene un desplazamiento 00, el segundo byte tiene un desplazamiento 01,

Page 29: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

29

etc. hasta el desplazamiento 65, 535. Para referir cualquier dirección de memoria en un segmento, el procesador combina la dirección del segmento en un registro de segmento con un valor de desplazamiento. En el ejemplo siguiente, el registro DS contiene la dirección de segmento del segmento de datos en 045F[0]H y una instrucción hace referencia a una localidad con un desplazamiento de 0032H bytes dentro del segmento de datos. Por lo tanto, la localidad real de memoria del byte referido por la instrucción es 04622H; Dirección del segmento DS: 045F0H Desplazamiento: +0032H Dirección real: 04622H. Note que un programa tiene uno o más segmentos, los cuales pueden iniciar casi en cualquier lugar de memoria, variar en tamaño y estar en cualquier orden. Como hemos visto un ensamblador es un programa de sistema que acepta un programa de lenguaje simbólico (texto usualmente) y produce un lenguaje de código objeto o de lenguaje máquina. El programa de entrada es llamado programa fuente y está guardado comúnmente en un archivo de texto; la salida es la traducción del "fuente" en un archivo de código objeto, que puede ser ejecutable por el microprocesador. El ensamblador puede generar código objeto en un sólo paso o en varios. La principal limitación del ensamblador de un paso es que no puede resolver referencias delanteras (por ejemplo... saltos hacia adelante con referencias simbólicas). Por ese motivo en el presente curso se prefiere implementar un ensamblador de dos pasos, pues pueden resolverse referencias adelantadas... además de un mejor manejo de los símbolos. En definitiva, el ensamblador empleado dependerá de que en las instrucciones se emplee uno o varios operando, de que existan uno o varios tipos de direccionamiento, etc. La potencia de un ensamblador se mide por las pseudo instrucciones que contenga. Aunque todos los ensambladores realizan básicamente las mismas tareas, podemos clasificarlos de acuerdo a características. Ensambladores básicos: Son de muy bajo nivel, y su tarea consiste

básicamente en ofrecer nombres simbólicos a las distintas instrucciones, parámetros y cosas tales como los modos de

Page 30: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

30

direccionamiento. Además, reconoce una serie de directivas (o meta instrucciones) que indican ciertos parámetros de funcionamiento del ensamblador.

Ensambladores modulares, o macro ensambladores: Descendientes de los ensambladores básicos, fueron muy populares en las décadas de los 50 y los 60, antes de la generalización de los lenguajes de alto nivel. Hacen todo lo que puede hacer un ensamblador, y además proporcionan una serie de directivas para definir e invocar macroinstrucciones (o simplemente, macros).

Ensambladores modulares 32-bits o de alto nivel: Son ensambladores que aparecieron como respuesta a una nueva arquitectura de procesadores de 32 bits, muchos de ellos teniendo compatibilidad hacia atrás pudiendo trabajar con programas con estructuras de 16 bits. Además de realizar la misma tarea que los anteriores, permitiendo también el uso de macros, permiten utilizar estructuras de programación más complejas propias de los lenguajes de alto nivel.

Ensambladores Cruzados (Cross-Assembler): Se denominan así los ensambladores que se utilizan en una computadora que posee un procesador diferente al que tendrán las computadoras donde va a ejecutarse el programa objeto producido. El empleo de este tipo de traductores permite aprovechar el soporte de medios físicos (discos, impresoras, pantallas, etc.), y de programación que ofrecen las máquinas potentes para desarrollar programas que luego los van a ejecutar sistemas muy especializados en determinados tipos de tareas.

Ensambladores Residentes: Son aquellos que permanecen en la memoria principal de la computadora y cargan, para su ejecución, al programa objeto producido. Este tipo de ensamblador tiene la ventaja de que se puede comprobar inmediatamente el programa sin necesidad de transportarlo de un lugar a otro, como se hacía en cross-assembler, y sin necesidad de programas simuladores. Sin embargo, puede presentar problemas de espacio de memoria, ya que el traductor ocupa espacio que no puede ser utilizado por el programador. Asimismo, también ocupará memoria el programa fuente y el programa objeto. Esto obliga a tener un espacio de memoria relativamente amplio. Es el indicado para desarrollos de pequeños sistemas de control y sencillos automatismo empleando microprocesadores. La ventaja de estos ensambladores es que permiten ejecutar inmediatamente el programa; la desventaja es

Page 31: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

31

que deben mantenerse en la memoria principal tanto el ensamblador como el programa fuente y el programa objeto.

Microensambladores: Generalmente, los procesadores utilizados en las computadoras tienen un repertorio fijo de instrucciones, es decir, que el intérprete de las mismas interpretaba de igual forma un determinado código de operación. El programa que indica al intérprete de instrucciones de la UCP cómo debe actuar se denomina microprograma. El programa que ayuda a realizar este microprograma se llama microensamblador. Existen procesadores que permiten la modificación de sus microprogramas, para lo cual se utilizan microensambladores.

Macroensambladores: Son ensambladores que permiten el uso de macroinstrucciones (macros). Debido a su potencia, normalmente son programas robustos que no permanecen en memoria una vez generado el programa objeto. Puede variar la complejidad de los mismos, dependiendo de las posibilidades de definición y manipulación de las macroinstrucciones, pero normalmente son programas bastantes complejos, por lo que suelen ser ensambladores residentes.

Macro Ensamblador: IBM Está integrado por un ensamblador y un macroensamblador. En gran medida su funcionamiento y forma de invocarlo es sumamente similar al de Microsoft. Su forma de uso consiste en generar un archivo fuente en código ASCII, se procede a generar un programa objeto que es ligado y se genera un programa .EXE. Opcionalmente puede recurrirse a la utilería EXE2BIN de MS-DOS para transformarlo a .COM. Es capaz de generar un listado con información del proceso de ensamble y referencias cruzadas.

Macro Ensamblador de Microsoft: Dependiendo de la versión, este ensamblador es capaz de soportar el juego de instrucciones de distintos tipos de microprocesadores Intel de la serie 80xx/80x86. En su versión 4.0 este soporta desde el 8086 al 80286 y los coprocesadores 8087 y 80287. Requiere 128KB de memoria y sistema operativo MS-DOS v2.0 o superior. Trabaja con un archivo de código fuente creado a partir de un editor y grabado en formato ASCII. Este archivo es usado para el proceso de ensamble y generación de código objeto. Posteriormente, y con un ligador, es creado el código ejecutable en formato .EXE.

Turbo Editassm: Este es desarrollado por Speddware, Inc., y consiste de un ambiente integrado que incluye un editor y utilerías para el proceso de ensamble y depuración. Es capaz de realizar el ensamble

Page 32: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

32

línea a línea, conforme se introducen los mnemónicos, y permite revisar listas de referencias cruzadas y contenido de los registros. Este ensamblador trabaja con tablas en memoria, por lo que la generación del código ejecutable no implica la invocación explícita del ligador por parte del programador. Adicionalmente permite la generación de listados de mensajes e información de cada etapa del proceso y la capacidad de creación de archivos de código objeto.

Turbo Assembler: De Borland Intl., es muy superior al Turbo Editassm. Trabaja de la misma forma, pero proporciona una interfaz mucho más fácil de usar y un mayor conjunto de utilerías y servicios.

Ensambladores de una fase: Estos ensambladores leen una línea del programa fuente y la traducen directamente para producir una instrucción en lenguaje máquina o la ejecuta si se trata de una pseudoinstrucción. También va construyendo la tabla de símbolos a medida que van apareciendo las definiciones de variables, etiquetas, etc. Debido a su forma de traducción, estos ensambladores obligan a definir los símbolos antes de ser empleados para que, cuando aparezca una referencia a un determinado símbolo en una instrucción, se conozca la dirección de dicho símbolo y se pueda traducir de forma correcta. Estos ensambladores son sencillos, baratos y ocupan poco espacio, pero tiene el inconveniente indicado de no resolver referencias adelantadas.

Ensambladores de dos fases: Los ensambladores de dos fases se denominan así debido a que realizan la traducción en dos etapas. En la primera fase, leen el programa fuente y construyen una tabla de símbolos; de esta manera, en la segunda fase, vuelven a leer el programa fuente y pueden ir traduciendo totalmente, puesto que conocen la totalidad de los símbolos utilizados y las posiciones que se les ha asignado. Estos ensambladores son los más utilizados en la actualidad.

La tabla de símbolos es un conjunto de pares ordenados (Si, Ti) en los que el primer elemento Si es un símbolo y el segundo Ti el valor asociado, es decir la traducción correspondiente. Se puede considerar una tabla de símbolos posibles, en un conjunto T, de los códigos de operación y direcciones binarias. En general, en las tablas de símbolos llevan un número fijo de caracteres, que se completan con

Page 33: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

33

espacios en blanco si es necesario. Como es natural, las técnicas de construcción y consultas de tablas tienen que ser diferentes en cada caso. 2.3 Técnicas de ensamblado.

Como se vio en la sección anterior, existen ensambladores que realizan su tarea en una o más fases o pasos. El proceso de ensamble de un paso consiste en leer una línea de programa fuente y traducirla a lenguaje máquina cuando se trata de una instrucción, o se ejecuta si es una pseudoinstrucción (directiva). La tabla de símbolos se va construyendo a medida que se avanza en la lectura de las líneas del programa fuente. Para que el ensamble de un paso funciones, todos los símbolos deben estar definidos antes de emplearse. Esto debido a que, para traducir correctamente cada instrucción, se debe conocer la dirección de cada uno de los símbolos que intervienen en ella. En otras palabras, no pueden quedar referencias pendientes porque ya no habrá otra oportunidad de resolverlas. Tampoco podrán hacerse saltos hacia líneas posteriores. No es posible saltar hacia una línea cuya etiqueta todavía no ha sido definida. Para resolver el problema que presenta el proceso de ensamble de un paso, se utiliza el proceso de ensamble de dos pasos o fases. En la primera fase, se lee el programa fuente y se construye la tabla de símbolos. En la segunda fase, se vuelve a leer el programa fuente y se traduce totalmente ya que se conoce la totalidad de los símbolos utilizados (incluyendo las etiquetas) y las posiciones de memoria que se les han asignado. Como ya se conocen las direcciones de las etiquetas utilizadas, pueden realizarse saltos hacia adelante. Se pueden hacer varios tipos de ensambladores, con las anteriores características básicas, según el tipo de máquina y de la potencia del lenguaje ensamblador deseado. En definitiva, el ensamblador empleado dependerá de que en las instrucciones se emplee uno o varios operandos, de que existan uno o varios tipos de direccionamiento, etc. La potencia de un ensamblador se mide por las pseudo instrucciones que contenga. Aunque todos los ensambladores realizan básicamente las mismas tareas, podemos clasificarlos de acuerdo a sus características.

Page 34: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

34

Los lenguajes de alto nivel fueron diseñados para eliminar las particularidades de una computadora específica, mientras que un lenguaje ensamblador está diseñado para una computadora específica, o, de manera más correcta, para una familia especifica de microprocesadores. Para el aprendizaje de lenguaje ensamblador no es necesario conocimiento previo de un lenguaje de programación, aunque tenerlo puede ayudarle a comprender algunos conceptos de programación más rápido, no es necesario conocimiento previo de electrónica o circuitería. Empecemos a dar una descripción general de las funciones de los 2 pasos del ensamblador simple propuesto. 2.3.1 Ensamblador de un paso.

La evolución de la programación ha ido variando la estructura de los ensambladores haciéndolos cada vez más complejos. Los más sencillos son los llamados en inglés load-and-go, que se puede traducir por ensambladores sobre la marcha, ya que aceptan un programa en forma simbólica; y en cuanto entra, lo ensambla en binario en la memoria, generalmente, mediante una exploración (sean) del programa fuente. En este caso se obtienen los ensambladores de un paso. Los ensambladores de un paso pueden ser de dos tipos diferentes, según que la salida generada esté en binario o en simbólico-binario. Los ensambladores que generan una salida en binario, llamados en

la ingles de tipo load and go, suelen ser utilizados para programas pequeños (que son frecuentemente modificados) o para máquinas pequeñas sin memorias auxiliares, en los cuales el hecho de leer dos veces el programa por cinta de papel o por máquina de escribir supondría una gran pérdida de tiempo. El principal problema de estos ensambladores es la necesidad de usar los símbolos antes de definirlos. Se utiliza, por ello, una técnica parecida a la del editor de encadenamiento: Si a un símbolo se le menciona, pero no está definido, se le introduce en una tabla que almacena todas las presencias del símbolo. En el momento en que se define, se vuelve atrás y se rellenan todas las referencias con el valor correspondiente. El resto de la técnica es análoga a la de los ensambladores de dos pasos.

En los ensambladores que producen una salida simbólico-binaria, suele requerirle que todos los nombres de datos se definan en

Page 35: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

35

cabeza, por lo que sólo queda el problema de símbolos no definidos para las instrucciones de bifurcación. El resto es análogo a los del tipo load and go, aunque la salida no es procesable directamente, sino que necesita un cargador. La mayor dificultad de este tipo de ensambladores aparece cuando hay operandos cuyos símbolos son expresiones aritméticas, en las que todavía no se han definido sus símbolos constituyentes. En las bifurcaciones hacia adelante debe dejar una indicación de que el cargador ha de completar estas instrucciones. Se crea una tabla de referencia hacia adelante.

2.3.2 Ensamblador de dos o más pasos.

Las ventajas de dividir un programa en subprogramas son grandes. A parte de poder trabajar con unidades independientes, cuando hay que cambiar o corregir un programa basta con reprogramar y ensamblar de nuevo los subprogramas o rutinas afectados por el cambio. Este método aumenta la eficacia del ensamblador, ya que el tiempo de proceso de las referencias cruzadas o parámetros de ensamblaje es prácticamente proporcional al cuadrado del número de instrucciones del programa; por consiguiente, al dividir el programa en partes, se consigue una reducción Importante en el tiempo de ensamblaje. A los ensambladores que pueden realizar la incorporación automática de subrutinas de bibliotecas y el enlazamiento de las diversas partes de un programa se les denomina ensambladores de rutinas o de subprogramas. Este tipo de ensambladores suele trabajar en dos pasos, es decir, haciendo dos exploraciones del programa fuente: En el primer paso, construyen la tabla de símbolos y acumulan todas las definiciones de símbolos que se encuentran en la rutina para efectuar la traducción en el segundo paso. Las rutinas ensambladas se suelen almacenar en un medio externo (cinta magnética, discos, tarjetas, etc.). 2.3.2.1 Primer paso (crear tabla de símbolos).

Durante el primer paso, la principal tarea del ensamblador es extraer del programa fuente todas las definiciones de símbolos y crear las correspondientes tablas. Para ello, como ya se ha visto, procede a analizar las cadenas de entrada para convertirlas en un conjunto de campos y buscarlos o añadirlos a la tabla correspondiente. En esta fase se suele efectuar un análisis sintáctico de las sentencias del programa fuente, con el fin de poder detectar posibles errores. Este análisis lo realiza una subrutina cuya estructura es muy variable, puesto que las sentencias de

Page 36: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

36

entrada, que dependen del lenguaje de que se trate, tienen muy diversas estructuras: formato y longitud fijos, formato variable y longitud fija o formato y longitud variable, aparte de que el número de operandos y expresiones permitidas varían desde un mínimo de dos campos a cuatro o cinco por término medio. Algoritmo para el primer paso: En el caso de la pseudo-instrucción se bifurca a la subrutina correspondiente para efectuar las acciones de control que sean adecuadas a cada caso; en particular, cuando se detecta la de fin de programa, el efecto es inicializar la rutina de post-análisis, completar las tablas de símbolos y dar paso a la segunda fase. La definición de los símbolos depende del tipo de instrucción en la que aparezcan. La más sencilla se manifiesta cuando se define por una etiqueta, pues automáticamente el contador de direcciones refleja la dirección relativa del símbolo. En las tablas se almacena el símbolo, el valor - si se puede determinar en ese momento- y un identificador de tipo del símbolo cuya utilidad se comprenderá a estudiar el fin del paso 1. El primer paso de un ensamblador tiene por misión principal la del análisis de las sentencias o instrucciones. Un esquema de las etapas del primer paso es el siguiente:

o Leer sentencia o instrucción. Analizar sentencia o instrucción. o Tratamiento de etiquetas. o Buscar en tabla de símbolos (si no está, pasar al siguiente paso). o Insertar en tabla de símbolos. o Tratamiento de código de operación. o Buscar en tabla de código de operación y actualizar campo de

dirección. o Escribir código de operación. o Buscar en tabla de pseudo- instrucciones y hacer el tratamiento de

la pseudo-instrucción. o Análisis del operando (en caso de la creación de un código

intermedio). o Almacenar en tabla de símbolos. o Buscar en tabla de símbolos. o Sustituir por dirección en tabla de símbolos.

Al finalizar el paso uno, entra en juego una subrutina post analizadora que, según el tipo de indicador asociado e cada símbolo en las tablas,

Page 37: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

37

completa los valores. Así, si este indicador era de definición por etiqueta, respeta el. Valor almacenado; si era definición por pseudo-instrucción, evalúa las correspondientes cadenas de equivalencia; o si era de indefinición, le da una dirección que haya quedado libre de acuerdo con la estrategia del ensamblador, siempre que no se trate de una variable externa. En resumen el primer paso se asignan direcciones a todas las proposiciones del programa, se guardan los valores direcciones) asignados a todas las etiquetas para usarse en el paso 2 y se realizan algún procesamiento de las instrucciones para el ensamblador. (Esto incluye el procesamiento que-afecta a la asignación de direcciones, como la determinación de la longitud de las áreas de datos definidas por BYTE, RESP, etc.). 2.3.2.2 Segundo paso (formato de salida).

Los ensambladores de dos fases se denominan así debido a que realizan la traducción en dos etapas. En la primera fase, leen el programa fuente y construyen una tabla de símbolos; de esta manera, en la segunda fase, vuelven a leer el programa fuente y pueden ir traduciendo totalmente, puesto que conocen la totalidad de los símbolos utilizados y las posiciones que se les ha asignado. Estos ensambladores son los más utilizados en la actualidad. El objetivo de este paso es obtener una visión semi-compilada (simbólica-binaria del programa o rutina que se está ensamblando), además de las tablas de uso para el cargador y la información necesaria para la localización de as variables. Para ello vuelve a leer el programa fuente, bien de un medio exterior (cinta de papel, tarjetas) o, lo más usual, de una cinta o disco magnético. Al leer una instrucción, ignora la etiqueta que ya fue completamente procesada en el primer paso. El código de operación es traducido de acuerdo con la tabla correspondiente o se genera la bifurcación a la subrutina correspondiente, sí se trataba de un código de pseudo-instrucción. Determina si las cantidades y direcciones se encuentran en modo absoluto, localizable o todavía indeterminada (variables externas), efectuando los cálculos o evaluaciones necesarios y generando los valores

Page 38: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

38

binarios correspondientes, con indicación para la posterior localización si fuese necesaria. La salida de esta fase y, por consiguiente, del ensamblaje depende del editor de encadenamiento, aunque un formato típico es el siguiente:

o Nombre de la rutina, subprograma o programa. o Sección binaria con el programa en forma semicompilada y con la

información necesaria para la localización. o Tabla de definición, con los símbolos globales definidos en la rutina. o Tabla de uso, que detalla el uso de los símbolos globales.

Esta última tabla es muy compleja, puesto que registra todas las apariciones de los símbolos externos, al depender de las posibilidades del ensamblador correspondiente. Si se permite la multiplicación de estos símbolos globales, hay que generar también una tabla de uso para el producto. Las tablas de uso son necesarias para la fase siguiente del encadenamiento de las diversas rutinas. En el caso más sencillo, que es cuando se canalizan todas las variables globales a través de un área común se almacena en la tabla, para cada símbolo, el lugar o lugares de la rutina en que ha sido usada. Cuando el valor del símbolo es determinado, el editor de encadenamiento puede colocarlo en sus lugares correctos. Al acabar el ensamblaje simultáneamente a él en otros casos se produce un listado con el programa fuente, incluidos: Los comentarios, el programa objeto, las tablas de símbolos con sus valores y los errores detectados con sus diagnósticos. El formato y características particulares de este listado dependen del lenguaje utilizado. SEGUNDO PASO. Lectura del programa de memoria secundaria.

o Tratamiento de sentencias o instrucciones. En el primer paso sólo se analizaban las sentencias para ver si eran correctas.

o Tratamiento del código de operación (SEGUNDO PASO). En el primer paso el código de operación se trataba Simplemente para ver si era correcto o no.

o Buscaren tabla de código de operación. Obtener código de máquina y su longitud.

o Actualizar contador de direcciones.

Page 39: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

39

o Buscar tabla de pseudo-instrucción (si es símbolo). Tratar la pseudoinstrucción.

o Tratamiento del operando. o Buscaren tabla de símbolo (si es símbolo). Obtener la dirección. o Obtener valor (si no es símbolo se obtiene la dirección

directamente). o Escribir código objeto.

2.4 Gestión de memoria en el ensamblador.

La gestión de memoria se refiere a como un ensamblador puede manejar los ficheros objeto obtenidos del archivo fuente hacia la maquina que habrá de ejecutarlo, ya sea que el procesador al que controla pertenezca al mismo equipo en donde fue diseñado (ensamblador nativo) o que maneje la memoria del procesador de algún otro equipo (ensamblador cruzado).

o Un proceso necesita memoria para ejecutar programas o Código del programa o Datos estáticos y dinámicos.

o El Gestor de Memoria pretende optimizar el uso de la o memoria principal disponible o Sistema operativo residente o Memoria principal disponible para ejecutar procesos.

o El rendimiento global del sistema mejora si se pueden ejecutar varios procesos concurrentemente.

o El método a utilizar depende principalmente del hardware disponible.

ENSAMBLADORES NATIVOS O RESIDENTES. El ensamblador residente se ejecuta sobre una maquina que contiene el mismo procesador que el destinatario del código ensamblado. Un ensamblador residente ofrece al programador la ventaja de utilizar una única máquina para crear, probar, y depurar código, los ensambladores residentes sobre los primeros microprocesadores fueron algo lentos y restrictivos en características debido al alto costo de memoria y la lentitud del microprocesador, con la disponibilidad de memoria de bajo costo (y consecuentemente grandes memorias disponibles en la mayor parte de los sistemas) y la posibilidad del procesador de direccionar directamente grandes cantidades de memoria, así como de realizar funciones más rápidas, los ensambladores residentes proporcionan ahora una variedad de características y velocidad de ensamblaje que anteriormente solo se

Page 40: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

40

encontraban en ensambladores cruzados sobre grandes computadores y microcomputadores. En el Ensamblador Nativo, como otros ensambladores, permite que el resto del ensamblador reparta solamente en instrucciones de máquina simbólicas (en nuestro caso, son más como "instrucciones de máquina procesales"). Las mnemónicas elegidas están cerca de las mnemónicas estándares de SPARC; la única diferencia es que los procedimientos del ensamblador requieren la especificación de si el segundo operando sea un registro o un inmediato. Las optimizaciones además de crear el código automático para las instrucciones y de resolver blancos de la rama y otras expresiones, el ensamblador nativo realiza una cantidad limitada de optimización. Actualmente, llena la rama retrasa ranuras usando un algoritmo simple: si la blanco del rama es una instrucción que puede entrar en retrasa la ranura, después inserta la instrucción de la blanco en retrasa la ranura e incremente el rama compensado por 4. Uno más sofisticado retrasa algoritmo que llena de la ranura es deseable, porque el algoritmo antedicho no disminuye tamaño de código solamente hace un rama tomado levemente más rápido. Un algoritmo mejor trabajaría por lo menos en bloques básicos e intentaría mover instrucciones a través de ramas, en la ranura que sigue la rama, siempre que sea posible. No sería duro poner esto en ejecución eficientemente. El ensamblador nativo podría también realizar la instrucción programar, pero eso es poco probable pagar apagado mucho hasta que conseguimos librados de la mayoría del tipo dinámico cheques. ENSAMBLADORES CRUZADOS. Un ensamblador cruzado es el polo opuesto del ensamblador nativo. El ensamblador cruzado es aquel que se ejecuta sobre un computador con un procesador diferente de aquel para el que se ensambla el código. OS ensambladores cruzados permiten a un programador desarrollar programas para diferentes sistemas sobre un computador. Sin embargo, excepto en el caso de minicomputadores y grandes computadores que pueden ofrecer un simulador de microprocesador destinatario real, no se puede normalmente probar y depurar el código creado por un ensamblador cruzado sin ejecutarse sobre una maquina real que utilice este procesador. En cualquier caso, siempre se debe utilizar la sintaxis

Page 41: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

41

correcta, esto es, códigos OP, operandos, y así sucesivamente, para el microprocesador para el que el ensamblador cruzado está diseñado. De hecho, la cosa más interesante sobre los Ensambladores cruzados son los motivos para de su existencia, entre las principales se encuentran:

• Los primeros miniordenadores eran lentos y tenían dispositivos aún más lentos. Esto tuvo sentido al ensamblar un programa sobre una unidad central, donde tanto el redactor como el ensamblador cruzado podrían usar cintas magnéticas o discos, y luego transferir el archivo objeto, sobre la cinta de papel, al miniordenador para la ejecución.

• Algunos de aquellos primeros miniordenadores fueron diseñados para pequeños programas de uso. Ellos tenían pequeñas memorias o conjuntos de instrucción limitados que hicieron poco práctico para controlar un ensamblador. Para tales ordenadores, CA era una solución práctica.

Los problemas principales en la puesta en práctica del Ensamblador Cruzado son:

• Si el ensamblador cruzado es de un paso, no puede cargar el programa objeto directamente en la memoria del ordenador objetivo. Esto tiene que cargarlo en la memoria del ordenador de la fuente, resolver todas las referencias avanzadas, y generar un archivo objeto absoluto. El archivo objeto tarde o temprano es descargado al ordenador objetivo.

• La diferencia en el tamaño de palabra entre los ordenadores de la fuente y objetivo presenta un problema ya que Ensamblador cruzado tiene que generar instrucciones y constantes para el ordenador objetivo, pero esto sólo puede usar instalaciones disponibles sobre el ordenador de la fuente. El resultado puede ser un empleo extenso de instrucciones que manipulando bits para funcionar sobre las partes de palabras.

El ensamblador cruzado carece de la ayuda para las instrucciones del coprocesador de matemáticas, las constantes de la secuencia, y las macros. Se apoyan los directorios siguientes del ensamblador: END, ORG, EQU, SET, REG, DC. (Constante definida), BCD (bloque constante definido), y DS (almacenaje definido).

Page 42: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

42

META ENSAMBLADOR. También conocido como ensamblador universal, es un ensamblador que puede ensamblar código de un Diferente número de computadoras. Un ensamblador convencional que solo puede manejar código fuente y objeto de una computadora, está técnica a la misma computadora. En contraste, un meta ensamblador trabajando en una computadora "K" quizás sería capaz de ensamblar código de las computadoras "K","L","M" Y algunas más. Por esto, un meta ensamblador es por lo tanto, un ensamblador cruzado. Hay dos tipos de meta ensamblador:

• Restringido, este solo puede ensamblar código de un número limitado de computadores, normalmente los miembros de una familia de computadoras. La información sobre conjunto de instrucciones es construirla en la meta ensamblador y entonces sólo falta darle el nombre de un ordenador, seguido por el archivo de origen.

• General en principio, manejar código de cada computadora. Esto no

tiene ninguna instrucción, y tiene que ser entregado, con cada archivo De origen, una descripción completa de instrucciones, de objeto y la fuente.

Y hay dos maneras de diseñar una meta ensamblador:

• Generativo (puede ser restringido o general). se le da el nombre de cualquier ordenador de una descripción de un conjunto de instrucciones, y genera un ensamblador dedicado. Este ensamblador es controlado normalmente, traduciendo archivos de origen en los archivos de objeto.

• Adaptable. Si sigue una generación restringida un meta ensamblador se forma de varios ensambladores su único trabajo es decidir cual ensamblador se necesita y generar una copia.

Un ensamblador general adaptarlo, es un programa general, disponible para adaptarse en sus salidas para diferentes situaciones, y es potencialmente útil. El principal problema en usarlo como un metaensamblador es diseñar la entrada. La entrada debería incluir una descripción del conjunto de

Page 43: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

43

instrucciones de la computadora objetivo, pero no debería ser tan largo ni muy complejo. Una característica interesante de meta ensambladores, es que ellos pueden ensamblar programas para muchas computadoras pero los programas fuentes deben conformarse con la sintaxis de los meta ensambladores. En otras palabras, en uno puede tomar simplemente un programa escrito en un ensamblador existente y ensamblarlo en un metaensamblador sin hacerle cambios. El metaensamblador Y puede ensamblar programas para una computadora X (y otras computadoras). Un programa fuente que corre en X puede no ser válido para Y, desde que Y puede requerir la fuente para estar en un formato correcto y para contener comandos especiales. 2.4.1 Jerarquía de memorias.

Recordando el ciclo maquina 1. Se busca la instrucción en memoria principal. 2. Se decodifica la instrucción y se buscan en memoria los operandos. 3. Se ejecuta la instrucción. 4. Se almacena el resultado en memoria principal. Código absoluto. La asignación no se puede cambiar nunca. Ejemplo: programas .COM en MS-DOS, asignación de direcciones en

tiempo de carga. Código generado por el montador o el cargador. La asignación se hace en el momento de lanzar el programa. Código reubicable.

2.4.4 Asignación de dirección en tiempo de ejecución.

El código no tiene direcciones definitivas incluso después de la carga La asignación se resuelve en cada acceso a memoria. Permite mover el programa durante la ejecución. Necesita hardware especial.

Page 44: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

44

2.4.5 Espacios de memoria lógicos y físicos.

• Dirección lógica o La generada por la CPU durante la ejecución del programa. o Llamada también dirección virtual.

• Dirección física o La usada realmente en el Registro de Direcciones de Memoria.

• Carga dinámica o Se trata de no perder tiempo cargando código que luego no se

ejecuta. o Al empezar solo se carga el programa principal. o Las subrutinas no se cargan hasta que son llamadas. o Solo hace falta tener una tabla de rutinas cargadas y una forma

especial de llamarlas o No hace falta un SO especial, solo un cargador reubicable. o El espacio en memoria está reservado para el proceso, pero no

se utiliza siempre. • Enlace dinámico

o Se trata de no reservar espacio para las subrutinas hasta el momento de la ejecución.

o Cada llamada lleva asociada un código para localizar la dirección de la rutina en memoria.

o Ese código se sustituye por la dirección de la rutina una vez cargada.

o Consume menos memoria y menos disco. o Solo hay una copia de la biblioteca en memoria o El código del programa no incluye el de las bibliotecas o Se pueden tener varias versiones de la misma biblioteca o

Bibliotecas Compartidas o Necesita que el SO compruebe que no se vulnera la protección

de memoria. • Solapamientos (overlays)

o Técnica que permite ejecutar un programa que sea mayor que la memoria principal disponible.

o Se basa en mantener en memoria solo las instrucciones y Tatos que se necesita en cada momento.

o No hace falta soporte Tel SO. o Hace falta programar el traductor y el montador ® Hace falta un

programador experto

Page 45: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

45

o para agrupar instrucciones y datos en conjuntos adecuados ® Solo se usa con hardware limitado (micros 86, 286).

o En otros casos, técnicas automáticas de memoria virtual Un ensamblador en dos pasos 2.5 Diseño y programación del ensamblador de dos pasos.

Un algoritmo es una serie de pasos lógicos para realizar una acción, programa o tarea ya que es el primer paso para realizar un programa. Los algoritmos se pueden expresar por fórmulas, diagramas de flujo, y pseudocódigos. Los algoritmos tienen ciertas características que son:

• Preciso: Esto quiere decir que debe indicar el orden en cada paso. • Definido: Es decir, si se sigue dos veces, obtiene el mismo resultado

cada vez. • Finito: Que tiene fin, o sea un número definido de pasos.

Analizando en detalle el proceso de compilación, se divide en dos grandes fases, una de Análisis y la otra de Síntesis. Fase de Análisis:

• En el llamado análisis lexicográfico o léxico, el compilador revisa y controla que las "palabras" estén bien escritas y pertenezcan a algún tipo de token (cadena) definido dentro del lenguaje, como por ejemplo que sea algún tipo de palabra reservada, o si es el nombre de una variable que este escrita de acuerdo a las pautas de definición del lenguaje. En esta etapa se crea la tabla de símbolos, la cual contiene las variables y el tipo de dato al que pertenece, las constantes literales, el nombre de funciones y los argumentos que reciben etc.

• En el análisis sintáctico como su nombre lo indica se encarga de

revisar que los tokens estén ubicados y agrupados de acuerdo a la definición del lenguaje. Dicho de otra manera, que los tokens pertenezcan a frases gramaticales validas, que el compilador utiliza para sintetizar la salida. Por lo general las frases gramaticales son representadas por estructuras jerárquicas, por medio de árboles de análisis sintáctico. En esta etapa se completa la tabla de símbolos

Page 46: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

46

con la dimensión de los identificadores y los atributos necesarios etc.

• El análisis semántico se encarga de revisar que cada agrupación o

conjunto de token tenga sentido, y no sea un absurdo. En esta etapa se reúne la información sobre los tipos para la fase posterior, en esta etapa se utiliza la estructura jerárquica de la etapa anterior y así poder determinar los operadores, y operandos de expresiones y preposiciones.

Fase de Síntesis:

• Etapa de generación de código intermedio, aunque algunos compiladores no la tienen, es bueno saber de su existencia, en esta etapa se lleva el código del programa fuente a un código interno para poder trabajar más fácilmente sobre él. Esta representación interna debe tener dos propiedades, primero debe ser fácil de representar y segundo debe ser fácil de traducir al código objeto.

• En la etapa de optimización de código, se busca obtener el código

más corto y rápido posible, utilizando distintos algoritmos de optimización.

• Etapa de generación de código, se lleva el código intermedio final a

código maquina o código objeto, que por lo general consiste en un código maquina relocalizable o código ensamblador. Se selecciona las posiciones de memoria para los datos (variables) y se traduce cada una de las instrucciones intermedias a una secuencia de instrucciones de maquina puro.

• La tabla de símbolos no es una etapa del proceso de compilación,

sino que una tarea, una función que debe realizar el proceso de compilación. En ella se almacenan los identificadores que aparecen en el código fuente puro, como así también los atributos de los mismos, su tipo, su ámbito y en el caso de los procedimientos el número de argumentos el tipo del mismo etc. En otras palabras una tabla de símbolos es una estructura de datos, que contiene un registro por cada identificado y sus atributos. La tabla de símbolo es accedida tanto para escritura como parar lectura por todas las etapas. Detector de errores o manejador de errores, al igual que la tabla de símbolos no es una etapa del proceso de compilación, si no

Page 47: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

47

que es una función, muy importante, pues al ocurrir un error esta función debe tratar de alguna forma el error para así seguir con el proceso de compilación (la mayoría de errores son detectados en las etapas de análisis léxico, análisis sintáctico, análisis semántico).

Algoritmo de programación del paso 1. Se puede dar una descripción general de las funciones de los 2 pasos del ensamblador simple propuesto. 1 (define los símbolos): 1. Asignar direcciones a todas las proposiciones del programa. 2. Guardar los valores (direcciones) asignados a todas las etiquetas para usarse en el paso 2. 3. Realizar algún procesamiento de las instrucciones para el ensamblador. (Esto incluye el procesamiento que afecta a la asignación de direcciones, como la determinación de la longitud de las áreas de datos definidas por BYTE, RESP, etc.). 2.5.2 Algoritmo de programación del paso 2.

Paso 2 (ensambla instrucciones y genera el programa objeto): 1. Ensamblar instrucciones (traducción de los códigos de operación y examen de las direcciones). 2. Generar los valores de datos definidos por BYTE, P ORD, etc. 3. Realizar el procedimiento no realizado en el paso 1 de las instrucciones del ensamblador. 4. Escribir el programa objeto y el listado de ensamblado. 5. Generar S19. 2.5.3 Formato de Archivo objeto.

Un archivo de salida de Motorola es un archivo tipo ASCII, Motorola maneja 3 tipos:

• S19 para direccionamiento de 16 bits. • S2 para direccionamiento de 24 bits. • S3 para direccionamiento de 32 bits

Page 48: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

48

Estos archivos son una opcional tabla de información, con datos específicos para ser cargados en memoria: Modulo de registro este es opcional, contiene el nombre del modulo. Registro de símbolos en caso de ser necesario un símbolo re-calculable. Registro de encabezado SO Registro de dato SI (2 bytes) dato S2 (3 bytes) dato S3 (4 bytes) dato

Registro de término S7 archivo de 32 bits de dirección S8 archivo de 24 bits de dirección S9 archivo de 16 bits de dirección

Recordemos que este es solo un formato para el cargador del simulador, para facilitar la vida del programador, lo único exacto y sin varianza deberá ser el COP resultante. Para nuestro caso del HC12 de Motorola el formato de salida será un S19 con las siguientes características:

Page 49: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

49

3. CARGADOR – LIGADOR.

Objetivo: Entender el funcionamiento de los esquemas más importantes de la carga y liga de módulos objeto. 3.1 Clases de cargador.

En informática, un cargador es la parte de un sistema operativo que es responsable de cargar programas en memoria desde los ejecutables (por ejemplo, archivos ejecutables). El cargador es usualmente una parte del núcleo del sistema operativo y es cargado al iniciar el sistema y permanece en memoria hasta que el sistema es reiniciado o apagado. Algunos sistemas operativos que tienen un núcleo paginable pueden tener el cargador en una parte paginable de la memoria, entonces a veces el cargador intercambia de memoria (swapping). Todos los sistemas operativos que soportan la carga de programas tienen cargadores. Algunos sistemas operativos empotrados de computadoras altamente especializadas corren un único programa y no existen capacidades de carga de programas, por lo tanto no usan cargadores. Ejemplos de estos sistemas embebidos se encuentran en equipos de audio para automóviles. En los sistemas Unix, el cargador es el manejador para la llamada del sistema execue(). Algunas computadoras necesitan cargadores relocalizables, los cuales ajustan direcciones de memoria (punteros) en un ejecutable para compensar las variaciones en la cual la memoria disponible de la aplicación empieza. Las computadoras que necesitan de los cargadores relocalizables son aquellos en los cuales los punteros son direcciones absolutas en vez de compensaciones de direcciones base del programa. Un ejemplo muy conocido está en los mainframes IMB Sistema 360 y sus descendientes, incluyendo la serie de los sistemas Z9. Los ligadores dinámicos son otro tipo de cargador que carga y liga librerías dinámicas (como dll's). 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.

Page 50: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

50

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. CARGADOR LIGADOR. Un cargador es un programa del sistema que realiza la accción de carga. Algunos sistemas tienen un ligador para realizar las operaciones de enlace, y un cargador separado para manejar la relocalización y la carga. El cargador es normalmente un programa pequeño que permite al usuario entrar directamente las palabras de instrucción y datos a direcciones concretas de la memoria, mediante un teclado o una cinta magnética. El cargador consiste en un juego de instrucciones que permiten al dispositivo de entrada (teclado o unidad distinta) asignar la dirección de inicio de la memoria y asegurar que el computador leerá el programa y lo largará byte a byte. La ligadura de tales recursos puede ser de naturaleza estática o dinámica. Esto nos lleva al siguiente proceso:

• Carga: lleva el programa objeto a la memoria para su ejecución. • Relocalización: modifica el programa objeto de forma que puede

cargarse en una dirección. • Diferente de la localidad especificada originalmente. • Ligado: combina 2 o más programas. • Objeto independientes y proporciona la información necesaria para

realizar referencias entre ellos. El ligador realiza la operación de enlazar programas objetos independientes. Los editores de ligado pueden efectuar varias funciones ultimas además de la simple preparación de un programa objeto para su

Page 51: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

51

ejecución estos también se pueden utilizar para construir paquetes de subrutinas u otras secciones de control que suelen utilizar juntas. Estos pueden ser útiles al tratar con bibliotecas de subrutinas que manejan lenguajes de programación de alto nivel. Comparados con los cargadores de ligadores los editores de ligado en general tienden a ofrecer mayor flexibilidad y control con el correspondiente incremento en complejidad y sobrecarga. La tarea primaria del enlazador es resolver referencias externas lleva acabo la siguiente etapa del proceso de traducción enlazado los módulos ensambladores y los acervos para formar un programa completo. En algunos sistemas el cargador simplemente copia el programa ejecutable a las posiciones de memorias apropiadas. Sus funciones son:

• Enlazar código intermedio compilado independiente en un solo modulo de cara resolviendo las diferencias entre Tokens. Incorporada las denominadas rutinas de librería en caso de solicitarlas el propio programa.

• Reunir procedimientos traducidos por separado y enlazarlos para que se ejecuten como una unidad llamada programa binario ejecutable.

Con la maquina vacía e inactiva, no hay necesidad recolección de programación, tan solo se puede especificar la dirección especifica del programa que se carga en primer lugar. En la mayoría de los casos este programa es el sistema operativo, que ocupa un lugar en la memoria. Esto significa para realizar las funciones. 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 incomodo y propenso a errores para hacer una buena solución del problema. Ofrece algunas ventajas sobre los otros tipos de ligado. Proporciona la posibilidad de cargare las rutinas solo cuando y si se necesitan. Si las subrutinas son grandes o tiene muchas referencias externas se pueden conseguir ahorros considerables de tiempo y espacio de memoria. El programa cargador una vez, situado en la memoria del computador, cargará el programa de aplicación y los datos. Pero, previamente, se ha

Page 52: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

52

debido cargar el cargador en la memoria. Y esto se puede realizar por los siguientes métodos: Entrada manual: Mediante el teclado el usuario teclea el cargador BOOTSTRAP. Después de esto, el cargador se carga así mismo en la memoria del computador. Entrada por ROM: Es posible tener las instrucciones de inicialización almacenados permanentemente en alguna porción de la ROM, en lugar de introducirlas manualmente por teclado o por panel frontal. Cuando se requiere el programa de bootstrap, el operador simplemente dirige al computador, mediante los conmutadores del panel, a ejecutar las instrucciones memorizadas en ROM: al estar el programa almacenado en ROM se elimina también la posibilidad de borrados accidentales. Indican a la computadora la forma de poner, dentro de la memoria principal unos datos que están guardados en un periférico de memoria externa (cinta, disco, etc.). Sirven para cargar en la memoria pequeños programas que inician el funcionamiento de una computadora. Algunas computadoras de carácter general no tienen en memoria ningún programa de forma permanente y cuando se desconectan pierden toda la información de su memoria interna. Al volverlos a conectar no son capaces de controlar ningún periférico. Se hace así para que sea el usuario el que ponga los programas que le interese ejecutar. En ocasiones un mismo programa necesita ejecutarse en diferentes posiciones de memoria. Para esto la traducción debe estar realizada en forma adecuada, es decir no utilizando referencias absolutas a direcciones en memoria, sino referencias a una dirección especial llamada de reubicación. Cargadores absolutos: El programa cargador pone en memoria las instrucciones guardadas en sistemas externos. Independientemente de que sea un cargador inicial, o no sin dichas instrucciones se almacenan siempre en el mismo espacio de memoria (cada vez que se ejecuta el programa cargador) se dice que es un cargador absoluto.

Page 53: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

53

Montar un programa consiste en añadir al programa objeto obtenido a la traducción las rutinas externas a las que hace referencia dicho programa. El ensamblador debe permitir dichas referencias y las rutinas deben estar a su vez en lenguaje máquina guardadas en algún elemento accesible por el montador. Generalmente, dichas rutinas se encuentran guardadas en un fichero especial al que suele denominarse librería porque están almacenadas todas las rutinas externas susceptibles de ser utilizadas por los diferentes programas del usuario. Allí va el programa ligador cuando está realizando el montaje de un programa a buscarlas y las adjunta al programa objeto. Diferencia fundamental entre un editor de ligado y un cargador ligador: Un cargador tiene como función principal la de subir un programa objeto que se encuentra en almacenamiento secundario a la memoria para que pueda ser ejecutado; durante el proceso de carga, si el programa que se va a ejecutar requiere o tiene definidas algunas referencias externas que pueden ser partes de programas o programas en sí, entonces es cuando entra el proceso de liga. El proceso de carga puede ser absoluto o relocalizable. El proceso de liga puede ser estático o dinámico. Primero, ensambla o compila el programa fuente, produciendo un programa objeto (que puede contener varias secciones de control diferentes). Una 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 modulo de carga ó 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. 3.1.1 Ligado dinámico.

El ligado dinámico, consiste en enlazar en tiempo de ejecución los módulos que contienen a las subrutinas, este ofrece algunas ventajas sobre los tipos de ligado. Proporciona la posibilidad de cargar las rutinas sólo cuando si se necesitan. Si las subrutinas son grandes ó tienen muchas

Page 54: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

54

referencias externas se pueden conseguir ahorros considerables de tiempo y espacio en memoria. El ligado dinámico evita la necesidad de cargar la biblioteca completa para cada ejecución. 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. En el método que se utilice aquí las rutinas que se carguen dinámicamente deben llamarse por medio de una solicitud del 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 dirección real y el nombre simbólico de la rutina llamada no se hace hasta que se ejecuta la proposición llamada. 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 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. Los editores de ligado 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 resuelven por búsqueda automática en biblioteca. Tablas y lógica de un cargador ligador:

• Ahora ya se puede presentar un algoritmo de un cargador ligador y relocalizador, se utilizan registros de modificación para que las funciones de relocalización y ligado se realicen por medio de este mecanismo.

• El algoritmo de un cargador-ligador es mucho más complicado que el del cargador absoluto, la entrada de este cargador consta de un conjunto de programas objeto o secciones de control que se van a ligar. Una sección puede (y es común que lo haga) hacer una referencia externa a un símbolo cuya definición aparece más adelante en este flujo de entrada. En este caso, la operación de

Page 55: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

55

ligado requerida no se puede realizar hasta haber asignado una dirección al símbolo externo implicado.

• La principal estructura de datos necesaria para el cargador ligador

es una tabla de símbolos externos TABSE (análoga TABSIM), se usa para almacenar el nombre y la dirección de los símbolos externos en el conjunto se secciones de control que se está cargando, la tabla también suele indicar en qué sección de control se define el símbolo, entre otras variables importantes podemos encontrar a DIRPROG (dirección y carga del programa) que es la dirección inicial de la memoria donde se va a cargar el programa ligado, y DIRSC (dirección de la sección de control) que contiene la dirección inicial asignada a la sección de control que está examinando el cargador.

3.1.2 Ejemplo de cargador CYBER.

Los programas CYBER suelen contener mucho mas 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. 1. Sin relocalización. 2. Valor relocalizable solo en la mitad superior de la palabra. 3. Valor relocalizable solo en la mitad inferior de la palabra. 4. valores relocalizables en las mitades superior e inferior de la palabra. 5. 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 4 bits asociado a cada palabra de código objeto. Esos 4 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 3 niveles. Cada segmento está identificado por un par ordenado de enteros, y un segmento solamente puede tener un punto de entrada.

Page 56: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

56

Cada segmento, excepto la raíz, debe cargarse por medio de una solicitud explícita; 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 3 niveles, y cada segmento puede tener varios puntos de entrada. 3.1.3 Ejemplo de editor de ligado 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. 3.1.4 Ejemplo de editor de ligado 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

Page 57: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

57

que se está creando y realizar operaciones con valores de pila. El lenguaje de mandatos ofrece una gran diversidad de posibilidades: hay más de 50 códigos de mandatos posibles. El ligador VAX realiza las funciones usuales de ligado y relocalización. Además hace parte del trabajo que en otros sistemas realizan el ensamblador o compilador. 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. 3.2 Relación Cargador- Sistema Operativo.

Un sistema operativo es un programa que actúa como intermediario entre el usuario y el hardware de un computador y su propósito es proporcionar un entorno en el cual el usuario que pueda ejecutar programas. El objetivo principal de un sistema operativo es, entonces, lograr que el sistema de computación se use de manera cómoda, y el objetivo secundario es que el hardware del computador se emplee de manera eficiente. Un sistema operativo es una parte importante de casi cualquier sistema de computación. Un sistema de computación puede dividirse en cuatro componentes: el hardware, el sistema operativo, los programas de aplicación y los usuarios. El Principal objetivo de un sistema operativo es proporcionar una interfaz entre el equipo y los programas. Para lograr este objetivo, el sistema operativo debe administrar los recursos del sistema de cómputo, de manera tal que su utilización sea lo más sencilla y eficiente posible. Ahora, recordando que un cargador s un programa que coloca en la memoria para su ejecución, el programa guardado en algún dispositivo de almacenamiento secundario. Un cargador es un programa del sistema que realiza la "'unción de carga, pero muchos cargadores también incluyen relocalización y ligado. Algunos sistemas tienen un ligador para realizar las operaciones de enlace y un cargador separado para manejar la relocalización y la carga. Un programa montado sin errores se puede ejecutar; antes de eso, el programa está en un fichero de almacenamiento secundario, ¿como lo

Page 58: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

58

hace? El núcleo del sistema operativo trae el programa a memoria y empieza a ejecutarlo. Para empezar el programa, el sistema operativo realiza los siguientes pasos:

• Lee la cabecera del archivo ejecutable para determinar el tamaño de los segmentos de texto y datos.

• Crea un espacio de direcciones nuevo para el programa. Este espacio de direcciones es suficientemente grande para albergar los segmentos de texto y de datos, junto con el segmento de pila.

• Copia instrucciones y datos del fichero ejecutable en el nuevo espacio de direcciones.

• Copia los argumentos pasados al programa en la pila. • Inicia los registros de la maquina, por lo general todos los registros

se ponen a cero, pero al puntero de la pila hay que asignarle la dirección de la primera posición libre de la pila.

• Salta a la rutina de inicio que copia los argumentos del programa de la pila a registros y llama a la rutina main del programa, si la rutina main retorna, la rutina de inicio termina el programa con la llamada al sistema de salida.

El hardware (unidad central de proceso (CPU), memoria y dispositivos de entrada y salida (E/S) proporciona los recursos de computación básica básicos. Los programas de aplicación (compiladores, sistemas de bases de datos, juegos de vídeo y programas para negocios) definen la forma en que estos recursos se emplean para resolver los problemas de computación de los usuarios. Puede haber distintos usuarios (personas, máquinas, otros computadores) que intentan resolver problemas diferentes; por consiguiente, es posible que haya diferentes programas de aplicación. El sistema operativo controla y coordina el uso del hardware entre los diversos programas de aplicación de los distintos usuarios. Los sistemas operativos son ante todo administradores de recursos; el principal recurso que administran es el hardware del computador: Los procesadores, los medios de almacenamiento, los dispositivos de entrada/salida, los dispositivos de comunicación y los datos. Los sistemas operativos realizan muchas funciones, como proporcionar la interfaz con el usuario, permitir que los usuarios compartan entre sí el hardware y los datos, evitar que los usuarios interfieran recíprocamente, planificar la distribución de los recursos, facilitar la entrada y salida, recuperarse de los errores, contabilizar el uso de los recursos, facilitar las operaciones en

Page 59: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

59

paralelo, organizar los datos para lograr un acceso rápido y seguro, y manejar las comunicaciones en red. No existe una definición universal aceptada de qué forma parte de un sistema operativo y qué no. Una perspectiva sencilla considera como tal todo lo que envía un vendedor cuando se ordena la adquisición del "sistema operativo". Sin embargo, los requisitos de memoria y las características incluidas varían en forma considerable de un sistema a otro. Algunos requieren menos de un megabyte de espacio e incluso carecen de un editor de pantalla, mientras que otros necesitan cientos de megabytes de espacio e incluyen revisores ortográficos y sistemas de ventanas. Una definición más común es que el sistema operativo es el programa que se ejecuta todo el tiempo en el computador (conocido usualmente como núcleo), siendo programas de aplicación todos los demás. La segunda definición es la más común y es la que utilizamos en general. La necesidad de un cargador relocalizador es una consecuencia de la rápida evolución de las computadoras, más poderosas y con más memoria, de tal manera que puede alojar no uno sino varios programas y entonces el sistema operativo (según la política de gestión de procesos) puede hacer que se ejecuten varias tareas. Pero desde luego primero se tiene que cargar el sistema operativo, por lo tanto necesitamos un cargador que desde el inicio o arranque de la computadora, aloje memoria para el S.O. Tal cargador es el llamado "Cargador de Arranque" o Bootstrap, el cual comúnmente es un cargador absoluto. Ese cargador aloja memoria para el cargador relativo del sistema operativo y una parte de éste, el conmutador de tareas, finalmente se carga todo el sistema operativo y el control de carga se pasa al cargador relativo incluido en éste. El arrancador Bootstrap, se encuentra en una memoria de sólo lectura (ROM), la cual tiene decodificadas direcciones fijas, lo que define al cargador absoluto. En dicha memoria ROM, se encuentran además otras rutinas pertinentes al arranque en frío de la computadora Aquí sería bueno que usted, explicara ¿qué pasa en otras plataformas? UNIX, MAC, etc.

Page 60: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

60

3.3 Funciones del editor de enlace.

La mayor parte de los programas se componen de más de un procedimiento. Los compiladores y ensambladores suelen traducir un procedimiento a la vez y guardan en memoria secundaria el resultado de esta Traducción. Antes de que pueda ejecutarse el programa, todos los procedimientos traducidos deben recuperarse y darse correctamente. Si no se dispone de memoria virtual, el programa enlazado debe cargarse explícitamente en memoria. Los programas que realizan estas funciones reciben varios nombres, como cargador (loader), cargador montado (linking loader) y editor de enlaces (linkage editor). La traducción completa de un programa fuente se efectúa en dos pasos: • Compilación o ensamblaje de los procedimientos fuente • Encadenamiento (linking) o montaje de los módulos objeto. Un enlazador (en inglés, linker) es un programa que toma los ficheros de código objeto generado en los primeros pasos del proceso de compilación, la información de todos los recursos necesarios (biblioteca), quita aquellos recursos que no necesita, y enlaza el código objeto con su(s) biblioteca con lo que finalmente produce un fichero ejecutable o una biblioteca. En el caso de los programas enlazados dinámicamente, el enlace entre el programa ejecutable y las bibliotecas se realiza en tiempo de carga o ejecución del programa. • La generación de un módulo ejecutable a partir de una colección de procedimientos traducidos independientemente requiere un ligador. • El ensamblador asiste al ligador suministrándole una tabla de símbolos o rótulos y referencias no resueltas. La tarea principal del enlazador es resolver las referencias externas, o sea establecer la correspondencia entre símbolos definidos en un archivo objeto y su empleo en otro archivo de la misma naturaleza. El enlazador debe combinar varios archivos objeto con su acervo respectivo de datos en un solo archivo ejecutable.

Page 61: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

61

Existen algunos pasos necesarios para ejecutar el editor de enlace, los que finalmente dependen de las directrices de importación-exportación de objetos:

1. Probar directrices, el micro tiene 2 sentencias en el lenguaje ensamblador: directivas e instrucciones,

2. Referencias externas, crear tabla de símbolos: Establecer la correspondencia entre símbolos definidos en un archivo objeto y su empleo en otro archivo de la misma naturaleza. El enlazador debe combinar varios archivos objeto con su acervo respectivo de datos en un archivo ejecutable.

3. Abrir archivos objeto y formatear datos. 4. Combinar archivos objeto. 5. Enlazar código intermedio compilado. 6. Incorpora rutinas de librerías en caso de solicitarlas el propio

programa. 7. Su función es reducir procedimientos traducidos por separado y

enlazarlos para que se ejecuten como una unidad llamada programa binario ejecutable.

Los editores de ligado en general tienden a ofrecer una gran flexibilidad y control con el correspondiente incremento de complejidad y sobrecarga. 3.3.1 Ligadura de una subrutina.

El editor de ligado 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. El enlace de una subrutina es la estructura con que se comparte la información del involucrado. El involucrado proporciona la dirección como parte del enlace de subrutina. Las subrutinas se encuentran guardadas en algún elemento accesible por el que se suele denominarse librería porque ahí están almacenados todas las rutinas externas susceptibles de ser utilizadas por los diferentes programas del usuario ahí va el programa ligado cuando está realizando el montaje de un programa al buscarlas y las adjunta al programa objeto a este proceso se le llama ligadura de rutinas y subrutinas.

Page 62: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

62

3.3.2 Razones de porque dividir un programa en subprogramas.

• Vincular entre lenguajes; es decir combinar el poder computacional de un lenguaje de alto nivel con el eficiente procesamiento del lenguaje ensamblador.

• Facilitar el desarrollo de proyectos largos en los cuales equipos diferentes proceden sus módulos separadamente.

• Incrustar partes de un programa durante su ejecución a causa del gran tamaño del programa.

Cuando se utilizan subrutinas en unos programas, el código ejecutable de cada una de ellas debe encontrarse en memoria al tiempo de ejecución. Para esto antes de cargar un programa debe ligarse su código objeto de cada una de las subrutinas involucradas por el obtenido así por un programa ejecutable que tiene tanto el código del modulo involucrado como el código de los módulos involucrados. 3.4 Problema de ligas de objetos y métodos de solución.

Uno de los objetivos alternativos del cargador es pegar o unir otros recursos al código objeto para que éste realice por completo sus funciones específicas desde el intérprete de órdenes del sistema operativo. Estos recursos pueden ser bloques de memoria de datos o de código, dispositivos de entrada y salida, inclusive otros archivos ejecutables, y esta ligadura puede ser de forma estática o dinámica. En el proceso de ligado que lleva a cabo el cargador se combinan 2 o más programas objeto independientes y proporciona la información necesaria para realizar referencias entre ellos y de esta manera puedan interactuar. La problemática que suele presentarse en el cargador es que se haga una referencia a un símbolo de un módulo externo cuya definición aparece más adelante en el flujo de entrada. En tal caso, la operación de ligado no se puede hacer hasta haber asignado una dirección al símbolo externo implicado en la liga. A este problema se le llama: problema de liga de referencias adelantadas externas y su para su solución es necesario considerar tres pasos descritos a continuación: Combinación de bloques de memoria de código y de datos: Esto significa que en la memoria estarán intercalados bloques tanto de datos como de

Page 63: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

63

código lo que implica que entre el código estarán estén implícitos los datos necesarios para realizar las tareas específicas. Construcción de una tabla de Símbolos (Acervo): A lo que nos referimos con esto es, que será necesario contar con una tabla que contenga todos los símbolos requeridos para la ejecución de un programa de manera que se sepa de antemano lo que puede solicitarse por parte del código. Lista de partes exportables públicas y privadas incluyendo su desplazamiento: Con esto nos referimos a que se realizará una lista en la que se especifiquen que partes de un módulo podrán exportarse y que partes son públicas y privadas incluido el desplazamiento que se les hará para la ejecución de programa. El enlazado permite al programador y al propio sistema operativo dividir un programa en varios archivos llamados módulos, que pueden ensamblarse por separado y enlazarse en una ocasión posterior, el enlace puede ser de naturaleza estática o dinámica. El enlace estático da como resultado, un archivo ejecutable con todos los símbolos y módulos respectivos incluidos en dicho archivo. Por otra parte sistemas operativos como el, win 95/nt, y el OS/2 se puede preferir una liga dinámica, solo mientras se está en ejecución el programa ejecutable, así los módulos que están invocados en el tiempo de ejecución, denotan la librería de enlace dinámico o DLL. 3.4.1 Cargador dinámico.

Un cargador dinámico es útil cuando no es posible asignar en memoria un programa completo. Utiliza 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, aunque, este enfoque suele implicar más operaciones que el cargador ligador. Se trata de esquema que pospone la función de ligado hasta el momento de la ejecución: una subrutina se carga y liga al resto del programa al llamarla por primera vez.

Page 64: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

64

El programa contiene subrutinas que corrigen o diagnostican errores en los datos de entrada durante la ejecución. Si esos errores son poco comunes, las rutinas de corrección y diagnóstico pueden no ser utilizadas durante la mayoría de las ejecuciones del programa. Sin embargo, si el programa estuviera totalmente ligado antes de la ejecución, habría que cargar y ligar esas rutinas cada vez que se ejecuta el programa. El ligado dinámico proporciona la posibilidad de cargar las rutinas sólo cuando se necesiten. 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 solo pocas de una gran cantidad de subrutinas posibles, pero el número exacto de rutinas necesarias no puede predecirse hasta que el programa examine la entrada. Esta situación podría presentarse, por ejemplo, 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 sólo se usarían unas cuantas. 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. El programa hace una solicitud de servicio de carga y llamada al sistema operativo. El parámetro de esta solicitud es el nombre simbólico de la rutina llamada. El sistema operativo examina sus tablas internas para determinar si la rutina ya se ha cargado o no; en caso necesario, la rutina se carga desde la biblioteca de usuario o desde el sistema especificado. Entonces el control pasa del sistema operativo a la rutina llamada. Cuando se completa el procesamiento de la subrutina llamada, vuelve a quien la llamó (es decir, a la rutina del sistema operativo que maneja la solicitud de servicio de carga y llamada). Entonces el sistema operativo devuelve el control al programa que hizo la solicitud. Es importante devolver el control

Page 65: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

65

de esta forma, para que el sistema operativo sepa cuándo la rutina llamada terminó su ejecución. Una vez terminada la subrutina, puede ser C dinámico. Algunas veces es conveniente retener la rutina en la memoria para algún uso posterior, siempre y cuando no se necesite el espacio de almacenamiento para otro proceso. Si una subrutina sigue en la memoria, una segunda llamada a ella puede no necesitar otra operación de carga. El control puede pasarse del cargador dinámico a la rutina llamada. 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 de llamada. Otra forma de escribir esto es decir que el ligamiento del nombre a una dirección real se retrasa del tiempo de carga al tiempo de ejecución. Como ya se había expuesto, este ligamiento retardado da como resultado una mayor flexibilidad, y también requiere mayor sobrecarga, ya que el sistema operativo debe intervenir en el proceso de llamada. 3.5 Diseño y programación de un Cargador Algoritmo de cargador.

1. colocar un programa objeto en la memoria. 2. Iniciar su ejecución. 3. Si tenemos un cargador que no necesita realizar las funciones de ligado y relocalización de programas, su operación es simple pues todas las funciones se realizan en un solo paso. 4. Se revisa el registro de encabezamiento para comprobar si se ha presentado el programa correcto para la carga (entrando en la memoria disponible). 5. A medida que lee cada registro de texto, el código objeto que contiene pasa a dirección de la memoria indicada. 6. Cuando se encuentra el registro de fin, el cargador salta a la dirección especificada para iniciar la ejecución del programa cargado.

Page 66: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

66

3.5.1 Cargador absoluto (ejemplo) Hay dos aspectos del programa cargador que requieren una mayor explicación: la variable dirbyte y el campo dirini. El proceso de carga absoluta del siguiente cargador es: La variable dir_byte que se declara como apuntador a un carácter o sea es la dirección de un carácter. Es razonable suponer que se almacena un carácter usando un byte de memoria y que, por consiguiente, la variable dirbyte contiene la dirección de un byte de memoria. Inicialmente, esta .variable se asigna igual a la constante DIR_CARGA.En cada iteración del lazo while, a la posición de memoria identificada por dir_byte se le asigna el siguiente byte del archivo ejecutable; después se incrementa en uno el valor de dirbyte. De esta manera, el contenido del archivo ejecutable se copia a posiciones consecutivas de la memoria a cárter de DIRCARGA. 3.5.2 Cargador re localizable (ejemplo).

Para analizar el proceso de relocalización introduciremos dos términos: el espacio lógico de direcciones y el espacio físico de direcciones. Un espacio lógico de direcciones representa el espacio desde la perspectiva del programa, los únicos objetos que necesitan direcciones son aquellos a los cuales hace referencia el programa. E I ensamblador y el enlazador usan el espacio lógico de direcciones para completar sus etapas del proceso de traducción. El espacio físico de direcciones representa la perspectiva de la memoria en la maquina. Cada posición de memoria tiene una dirección. El cargador completa el proceso de traducción estableciendo la correspondencia de las direcciones del programa entre el espacio lógico de direcciones y el espacio físico. Se pueden emplear dos técnicas para asegurar que la ejecución del programa sea correcta después de moverlos: la relocalización estática y la relocalización dinámica. El termino estática en relocalización estática se refiere al hecho de que los programas solo se pueden refocilara antes de iniciar su ejecución. Cuando se usa la relocalización dinámica los programas se pueden relocalizar en cualquier momento incluso después de haber iniciado su ejecución, a esto se debe el nombre de relocalización dinámica.

Page 67: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

67

Para la relocalización estática se requiere que el enlazador proporcione información de relocalización adicional en el archivo ejecutable esta información de relocalización consiste en una lista de parches que indican al cargador cuales son las posiciones del programa que tienen que modificarse al mover el programa. La relocalización dinámica es más rápida y flexible que la estática, pero requiere hardware de correspondencia de direcciones. Si no se proporciona este tipo de hardware, será necesario emplear la relocalización estática. La relocalización dinámica se establece la correspondencia entre las direcciones usadas en el programa y direcciones físicas cada vez que se utilizan durante la ejecución del programa. Las direcciones lógicas generadas por el ensamblador y el enlazador no se alteran durante la carga en posiciones contiguas de la memoria. En la fig. de la parte de abajo representa un cargador sencillo que puede usarse con la relocalización dinámica. En este caso el cargador lee el encabezado del archivo ejecutable y determina la cantidad de espacio necesaria para el programa. Después asigna espacio suficiente para el programa y copia el archivo ejecutable a memoria. Cuando se carga el programa en la memoria, el cargador establece la correspondencia necesaria para el programa, pasando la dirección de carga y el tamaño del programa a una rutina llamada establecer correspondencia. Al leer este código, observe que la función de cargar devuelve un entero sin signo en lugar de un apuntador. Esto refleja el hecho de que la dirección inicial es una dirección lógica y no una dirección física. Relocalización. Los cargadores que permiten la relocalización de programas se denominan cargadores relocalizadores o cargadores relativos. Existen dos métodos para la relocalización. El primer método utiliza un registro de modificación para describir cada parte del código que se ha de cambiar al relocalizar el programa. La necesidad de relocalizar los programas es una consecuencia directa del cambio a computadoras más grandes y potente. La forma de efectuar la relocalización en un cargador también depende de las características de la máquina.

Page 68: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

68

4. MACROPROCESADORES.

Objetivo: Entender el funcionamiento de las diversas modalidades del macro procesamiento. Con el fin de evitar al programador la tediosa repetición de partes idénticas de un programa, los ensambladores y compiladores cuentan con macro procesadores que permiten definir una abreviatura para representar una parte de un programa y utilizar esa abreviatura cuantas veces sea necesario. Para utilizar una macro, primero hay que declararla. En la declaración se establece el nombre que se le dará a la macro y el conjunto de instrucciones que representará. El programador escribirá el nombre de la macro en cada uno de los lugares donde se requiera la aplicación de las instrucciones por ella representadas. La declaración se realiza una sola vez, pero la utilización o invocación a la macro (macrollamada) puede hacerse cuantas veces sea necesario. La utilización de macros posibilita la reducción del tamaño del código fuente, aunque el código objeto tiende a ser mayor que cuando se utilizan funciones. Es tan común el empleo de macroinstrucciones se les considera como una extensión de los lenguajes. De manera similar se considera al procesador de macroinstrucciones o macro procesador como una extensión del ensamblador o compilador utilizado. El macro procesador se encarga, en una primera pasada, de registrar todas las declaraciones de macros y de rastrear el programa fuente para detectar todas las macro llamadas. En cada lugar donde encuentre una macro llamada, el macro procesador hará la sustitución por las instrucciones correspondientes. A este proceso de sustitución se le denomina expansión de la macro. El macro procesador elabora dos tablas para el manejo de las macros: Una tabla de macro nombres que consiste de los nombres de las macros y un índice que le permite localizar la definición de la macro en otra tabla llamada tabla de macro definiciones. Como su nombre lo indica, la tabla de macro definiciones contiene las definiciones de todas las macros a utilizar en el programa. En ocasiones es

Page 69: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

69

conveniente agrupar macros, de acuerdo a las tareas que realizan, y almacenarlas en archivos que se constituyen en bibliotecas de macros. De esta manera, cuando se requiera la utilización de alguna macro en particular, se incluye en el programa fuente el archivo de la biblioteca de macros correspondiente. Macroinstrucción es una pseudo operación o un conjunto de instrucciones a la cual se le asigna un nombre para ser llamada y después utilizar su código. Estas permiten escribir una versión abreviada de un programa. Dejando que el macro procesador maneje los detalles internos, su característica principal es sustitución de líneas de código por una referencia. Ejemplo: En este ejemplo el nombre de la macro es DELAY, cuando se encuentra en un programa DELAY, el ensamblador toma el cuerpo de esta macro del macro procesador y lo pasa al código fuente donde encontró DELAY. La estructura de una macroinstrucción es la siguiente: La tabla de nombres de macros es donde se almacenan las referencias de las macroinstrucciones, la de códigos es donde se almacenan los códigos de cada macro y la de argumentos los parámetros de cada macro. Usos su uso más común es en el lenguaje ensamblador, debido a la complejidad de los mnemónicos, pero la macro también puede ser un guión o puede tener un uso en aplicaciones finales (Word, Excel) o para perfilar compiladores como visual basic. Rutina vs macro Una rutina es un procedimiento (en este caso un conjunto de código) que es usado cada vez que se le llame. Una rutina al ser llamada dentro de un programa hace que el código principal y se dirija a ejecutar el código de la rutina, en cambio cuando se llama a una macro, el ensamblador llama al código de la macro y lo implanta donde fue llamado, aumentando así el código fuente y por consiguiente el objeto. La idea aquí es que se incorpore un procesador de macros en su ensamblador de dos pasos.

Page 70: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

70

Considere que su ensamblador es de dos pasos, por lo tanto ya tiene un procedimiento de inserción y búsqueda de símbolos en la famosa estructura de datos llamada "tabla de símbolos". Le sugiero que la tabla de símbolos sea creada por adelantado y con un cuarto campo en sus registros, este campo adicional es en realidad una liga a una lista de elementos (una lista vinculada), que contiene la información de las tres tablas empleadas por el reconocedor de macros, el cual es un procedimiento muy sencillo de implantar al inicio del ensamblador. Acto seguido, implemente las funciones básicas de un procesador de macros en el propio ensamblador. De esta manera al escribir el código de su ensamblador se ahorrará mucho trabajo y tiempo. 4.1 importancia teórica de macro-expresiones y usos de un macro-procesador Un macroinstrucción (abreviado frecuentemente como macro), no es más que una conveniencia notacional para el programador. Una macro representa un grupo de proposiciones utilizadas comúnmente en el lenguaje de programación fuente, para el caso, ensamblador. El procesador de macros reemplaza cada macroinstrucción con el grupo correspondiente de proposiciones del lenguaje fuente, lo que se denomina expansión de macros. Por todo lo anterior, las macroinstrucciones permiten al programador escribir una versión abreviada de un programa, dejando que el procesador de macros maneje los detalles internos. Las funciones básicas de un procesador de macros son:

• Sustitución de líneas de código por una referencia simbólica. • Calcular las direcciones efectivas de las referencias. • Expansión de las referencias en un archivo intermedio.

El procesador de macros, como puede verse, no intenta ningún análisis ni traducción a código objeto del programa fuente, más bien parece que el procesador hace que aumente el tamaño de éste. Esto es un elemento clave para el programador, pues el uso indiscriminado de macros puede hacer que el tamaño del código objeto sea enorme y poco práctico, al contrario de las llamadas a subrutinas.

Page 71: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

71

Claro que también se paga un precio alto por el empleo de las llamadas, pues se pierde tiempo importante en la gestión de la pila, donde usualmente se pasan los parámetros. El macroprocesador requiere tres estructuras de datos para su exitosa operación.

• La tabla de nombres de macros (TABNOM). • La tabla de código de macros (TABDEF). • La tabla de argumentos (TABARG).

Ahí se guarda toda la información pertinente a las macros, mientras el ensamblador analiza la expansión y hace la traducción a código objeto. A veces hay confusión entre macros y subrutinas. Subrutinas son rutinas comunes en el programa se accede a ellas haciendo llamados a estas, son normalmente usadas para rutinas más complejas donde el retorno de llamada tolerada. Macros es comúnmente usado para rutinas más simples o donde la velocidad de en código de linea es requerida. Para poder utilizar una macro esta debe ser definida dentro del programa fuente. La macrodefinicion consta de 3 partes estas son:

• La macro cabecera que especifica el macro nombre y su lista de parámetro.

• El macro cuerpo que es la parte que es insertada actualmente dentro el programa de fuente.

• El macro terminador. La cabecera se tiene de la siguiente forma: name MACRO <parameter list> El nombre del campo contiene un símbolo único que el usado para identificar la macro. Siempre que el símbolo es encontrado en el programa fuente, se insertara la macro en el programa fuente donde se apunta. El campo MACRO del encabezado de la macro contiene la llave de esta y esta le dice al ensamblador donde comienza la definición de la misma. El campo <parameter list> lista de 0 a 16 parámetros que serán usados en el cuerpo de la macro y que son definidos por el tiempo del ensamblador. Los símbolos usados en la lista de parámetros solo son usados por el ensamblador durante el tiempo de carga de la macro. El macro cuerpo puede contener instrucciones, directivas, declaraciones de ensamble condicional o de control.

Page 72: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

72

Ejemplos: MULT_BY_16 MACRO (no parameters) DIRECTADD MACRO DESTINATION,SOURCE (two parameters) Tenemos 2 definiciones de terminación de macros: ENDM y EXITM, toda definición de macro debe tener un ENDM para notificar al ensamblador que la definición de macro ha terminado, EXITM es alternativa para usos de final de macros que son usadas con ensambles condicionales, cuando EXITM es encontrado en un programa las declaraciones de ENDM son ignoradas. Esta sección se trata de varias situaciones que surgen en el uso de macros y como a manejarlas. Primero la macro definición es listada, entonces el programa fuente invoca la macro y finalmente como la macro era expandida por el ensamblador. El uso más común de los procesadores de macros es en la programación de lenguaje ensamblador. Para ilustrar los conceptos del uso de las macros, se van a emplear ejemplos de la máquina SIC/XE, NeMiSyS y 80x86 con el TASM 2.0. Si podemos aceptar que una macro también puede ser un guión, entonces las macros también tienen su uso en aplicaciones finales... por ejemplo EXCEL, WORD... etc. por mencionar algunos. Pero también existen guiones para perfilar compiladores como DELPHI y como VISUALBASIC. A continuación unos ejemplos. Se definen 4 operadores especiales para el uso de macros: “%”, Cuando aparece este símbolo en la lista de parámetros el valor es pasado al cuerpo del macro en vez del símbolo mismo. “c”, Cuando este símbolo precede a un carácter este es tomado como una literal y pasa al cuerpo de la macro sin este es útil cuando es necesario delimitar el cuerpo del macro. Por ejemplo en la lista de parámetro siguiente, el parámetro segundo pasa a la macro seria una COMA (,): GENERAR INST 75, STK_VALOR. & Los símbolos de ambos lados se concatenan y el símbolo es removido.

Page 73: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

73

Cuando estos símbolos son usados, el comentario precedente NO será grabado y por lo tanto NO será invocado en una macro. 4.1.1 Conceptos clave.

Expansión: Cuando el ensamblador se encuentra con una cabecera de MACRO, lo que hace es almacenarla con su cuerpo correspondiente en una tabla. Posteriormente, cuando en el programa se utilice la cabecera o el nombre de esa MACRO, el ensamblador accederá a la tabla mencionada y sustituirá, en el programa, ese nombre de MACRO por el cuerpo de la misma. A la operación de búsqueda en la tabla de macros se le conoce como "Llamada a la MACRO", y a la sustitución del nombre de la MACRO por el cuerpo de la misma se denomina "Expansión de la MACRO". En otras palabras, El ensamblador sustituye cada vez que aparezca la macro. No es como los procedimientos, que se "llaman" pero no repiten el código. Una macro puede llamar a otra o a sí misma: Es posible una expansión de macros recursiva, siempre y cuando aseguremos una posición definida de los símbolos que se van a emplear dentro de la macro. Por ejemplo para el SIC/XE, dicha tarea es un poco difícil, aunque si se programa el expansor de macros como una máquina de pila es posible la implementación. Un tipo recursivo es aquel cuyos valores son compuestos de valores del mismo tipo. Es aquel que está definido en términos del mismo. Recursividad: La ventaja de la directiva LOCAL: En general, el conjunto de valores de un tipo recursivo T, puede ser definido por un conjunto de ecuaciones recursivas de la forma: T=T. El conjunto de ecuaciones recursivas puede tener muchas soluciones. Si una macro es recursiva, es decir, si se llama a sí misma, deberá pasarse a sí misma un parámetro que se modificará en cada expansión, y la macro deberá probar el parámetro y terminar la recursión cuando llegue a cierto valor. En caso contrario, el ensamblador podría ingresar en un ciclo infinito. Si esto sucede, el usuario deberá suspender explícitamente el ensamblador.

Page 74: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

74

Por otra parte está la solución de Intel, la cual nos dice que los símbolos internos de las macros los deberemos marcar como "LOCAL", para que la reubicación de los mismos sea factible en la segunda pasada del ensamblador. Directiva que le indica al ensamblador que dentro de la macro van a existir una serie de etiquetas que deben de ser identificadas de una forma especial al realizar la expansión de la macro y siempre considerando la relación que existe con la tabla de símbolos. Con ello se evita las definiciones múltiples de estas etiquetas. El formato es el siguiente: LOCAL etiquetas (separadas por comas), Esta directiva debe situarse, en el caso de que exista después de la cabecera de la macro. Etiquetas en macros: se tienen 2 alternativas para especificar etiquetas en el cuerpo de una macro: una etiqueta puede ser un parámetro o puede ser generada dentro del cuerpo de la macro. 4.2 Microprocesadores con argumentos y Microprocesadores recursivos.

Las macros de la página anterior, más o menos tienen la misma pauta. El prototipo de una macro comienza con la palabra clave MACRO, el nombre de la macro y opcionalmente una línea con argumentos, que son los parámetros de la macro. En el caso de las macros de Intel, con el TASM 2.0 o el MASM de IBM, primero se empieza con el nombre de la macro y después con la palabra clave MACRO. También se cuenta con línea de argumentos. Es posible una expansión de macros recursiva, siempre y cuando aseguremos una posición definida de los símbolos que se van a emplear dentro de la macro. Por ejemplo para el SIC/XE, dicha tarea es un poco difícil, aunque si se programa el expansor de macros como una máquina de pila es posible la implementación. Por otra parte está la solución de Intel, la cual nos dice que los símbolos internos de las macros los deberemos marcar como "LOCAL", para que la reubicación de los mismos se factible en la segunda pasada del ensamblador.

Page 75: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

75

• TIPOS RECURSIVOS EN GENERAL: Un tipo recursivo es aquel cuyos valores son compuestos de valores del mismo tipo. Es aquel que está definido en términos del mismo. En general, el conjunto de valores de un tipo recursivo T, puede ser definido por un conjunto de ecuaciones recursivas de la forma: T=T. El conjunto de ecuaciones recursivas puede tener muchas soluciones. STRING Una String es una secuencia de caracteres. Las strings son soportadas por todos los lenguajes de programación moderna. Pero no se tiene consenso en su clasificación: ¿Una string puede ser primitiva o compuesta? ¿Qué tipo de operación debe tener?, Una string como un tipo primitivo, con valores que son strings de cualquier longitud. Ejemplo. ML. Una string como una array de caracteres: Pascal y Ada. Una string como una lista de caracteres: Miranda y Prolog. 4.3 Incorporación del procesador de macros al ensamblador.

La idea aquí es que se incorpore un procesador de macros en su ensamblador de dos pasos. Tomando en cuenta que el ensamblador es de dos pasos, por lo tanto ya tiene un procedimiento de inserción y búsqueda de símbolos en la famosa estructura de datos llamada "tabla de símbolos", se sugiere que la tabla de símbolos sea creada por adelantado y con un cuarto campo en sus registros, este campo adicional es en realidad una liga a una lista de elementos (una lista vinculada), que contiene la información de las tres tablas empleadas por el reconocedor de macros, el cual es un procedimiento muy sencillo de implantar al inicio del ensamblador. Acto seguido, implemente las funciones básicas de un procesador de macros en el propio ensamblador. Ventajas: • Grupos pequeños Repetidos de instrucciones reemplazadas por 1 macro. • Errores en macros son fijos solo una vez, en la Duplicación. • Por definición el esfuerzo es reducido. • En efecto, instrucciones de nivel más alto nuevo puede ser creado. • Programa es hecho más fácil, error menos boca abajo. • Generalmente más rápido en ejecución que subrutinas.

Page 76: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

76

Desventajas: • En programas grandes, el tamaño de código de producto es mayor que el de los procedimientos. Cuando usar macros: • Para reemplazar grupos pequeños de instrucciones no merecedor de subrutinas. • Para crear un conjunto de instrucción más alta para aplicaciones especificas. • Para crear compatibilidad con otros ordenadores. • Para reemplazar porciones de código que es repetido a menudo por todo. Macros es expandido cuando el programa es reunido. Este medio que cada suceso del macro nombre (aparte desde la definición) es reemplazado por las declaraciones en la macro definición.

5. GLOSARIO. Cargador Es una rutina que lee un programa ejecutable y lo almacena en la memoria principal antes de su ejecución. Código maquina Representación de instrucciones y datos de un programa ejecutables directamente por una computadora. Compilador Programa traductor de un lenguaje de alto nivel a su código de máquina absoluto o reubicable equivalente. La traducción se realiza de tal forma que una sentencia fuente se convierte en varias instrucciones máquina, efectuando además un control previo de errores de todo el programa. Si existen errores, la traducción se interrumpe. Compilador Cruzado Programa traductor de lenguaje de alto nivel a lenguaje de máquina que se ejecuta en una computadora, generando el código para ser ejecutado en otra distinta.

Page 77: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

77

Depurador Es un programa de ayuda que permite ejecutar un programa fuente paso a paso investigando la imagen del mismo, que se va creando en la memoria con el fin de analizarlo: y corregir posibles errores. Editor Los sistemas operativos para la construcción de programas suelen además contar con las siguientes utilidades o utilitarios: Editor, Editor de Enlace, Cargador, Depuradora Este es un programa que permite escribir o corregir archivos de texto, generalmente programas fuente. Editor de enlace También denominado montador, es un programa para crear un código ejecutable a partir) de uno o más módulos objeto resolviendo las referencias existentes entre los mismos y asignando direcciones definitivas a los elementos reubicables. También extraen las rutinas necesarias de las librerías para incluirlas en el programa ejecutable final. Ejecución Proceso de llevar a efecto las instrucciones de un programa ejecutable previamente cargado en la memoria principal. Ensamblador En la traducción de un programa fuente a código máquina se utilizan diversos programas que forman parte del sistema operativo. Estos programas traductores pueden ser: Ensamblador, Ensamblador Cruzado, Compilador, Compilador cruzado, Intérprete. Programa Utilizado para traducir un programa escrito en lenguaje ensamblador a lenguaje de máquina de tal forma que la traducción se realiza convirtiendo cada sentencia fuente en una instrucción de máquina. En la traducción se sustituyen las direcciones simbólicas por direcciones absolutas. Ensamblador Cruzado Programa traductor de lenguaje ensamblador a lenguaje de máquina que se ejecuta en una computadora y traduce para ejecutar en otro distinto. Instrucción o sentencia Línea o líneas de un programa donde se da la orden de realización de un operación o conjunto de operaciones particulares. Además del término general, distinguiremos dos tipos de instrucciones.

Page 78: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

78

Instrucción privilegiada Es aquella que para ser ejecutada necesita que el programa o usuario tengan ciertos privilegios. Interprete Programa traductor de lenguaje de alto nivel a código máquina, de tal forma que una sentencia fuente se convierte en varias instrucciones máquina y tras la traducción de cada una de ellas se ejecutan sin esperar a traducir la siguiente. Librería de Programas Archivo que contiene una colección organizada de programas. Librería del Sistema Colección controlada de software perteneciente al sistema y que puede ser incorporado a un programa de igual forma que una rutina de librería objeto. Librería Objeto Archivo compuesto de una colección de rutinas que pueden ser solicitadas e incorporadas por los distintos programas al hacer referencia a las mismas. Macroinstrucción Instrucción en el lenguaje fuente que es reemplazada por una secuencia definida de instrucciones en el mismo lenguaje fuente, todas las macroinstrucciones son expandidas por el compilador o ensamblador al conjunto de instrucciones que representan. Módulo Unidad de programa que puede ser compilada y unida a otros módulos para formar un programa completo, también lo podemos definir como una parte separable de un programa. Los programas o módulos, según el proceso de conversión a código máquina, pueden ser Programa Fuente y Programa Objeto o Programa Ejecutable. Módulo Objeto Es un módulo fuente ensamblado o compilado que está listo para ser unido a otros para formar un programa ejecutable. Si se trata de todo un programa (un solo módulo) se denomina programa objeto.

Page 79: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

79

Proceso Se utiliza este término para hacer referencia a un programa en ejecución. Programa Secuencia de instrucciones que representan la resolución de un algoritmo y que pueden ser ensambladas, compiladas o interpretadas con el fin de obtener un programa ejecutable en código máquina para realizar un trabajo útil para el usuario. Programa Ejecutable Programa construido por el editor de enlace o montador (linker) a partir de uno o más módulos objeto y de rutinas de librería. Este programa puede ser cargado en memoria y ejecutado. En el proceso de traducción o conversión de un programa fuente a ejecutable entran en juego unos archivos cuya composición es un conjunto de módulos que puede-ser reclamados por los distintos elementos a traducir, denominados librerías. Pueden ser tres clases: Librería de Programas, Librería Objeto, Librerías del Sistema. Programa Fuente Programa escrito en ensamblador o lenguaje de alto nivel (FORTRAN, COBOL, PASCAL, C, etc.) que debe ser ensamblado, compilado o interpretado antes de ejecutarse en la computadora. Normalmente son editados por el usuario o programador por medio de un editor.

Page 80: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

80

6. ANEXOS.

6.1 CÓDIGO ASCII.

El código ASCII (acrónimo inglés de American Standard Code for Information Interchange. Código Estadounidense Estándar para el Intercambio de información), pronunciado generalmente [áski], es un código de caracteres basado en el alfabeto latino tal como se usa en inglés moderno y en otras lenguas occidentales. Fue creado en 1963 por el Comité Estadounidense de Estándares (ASA, conocido desde 1969 como el Instituto Estadounidense de Estándares Nacionales, o ANSÍ) como una refundición o evolución de los conjuntos de códigos utilizados entonces en telegrafía. Más tarde, en 1967, se incluyeron las minúsculas, y se redefinieron algunos códigos de control para formar el código conocido como US-ASCII. Casi todos los sistemas informáticos actuales utilizan el código ASCII o una extensión compatible para representar textos y para el control de dispositivos que manejan texto. El código ASCII define una relación entre caracteres específicos y secuencias de bits; además de reservar unos cuantos códigos de control para el procesador de textos, y no define ningún mecanismo para describir la estructura o la apariencia del texto en un documento; estos asuntos están especificados por otros lenguajes como los lenguajes de etiquetas. 6.2 SECCIONES DEL MANUAL DE REFERENCIA DEL HC12.

6.2.1 MODELO DE PROGRAMACIÓN.

El modelo de programación de cualquier dispositivo lo obtenemos del mismo proveedor, quien nos lo hace saber por medio de su manual de referencia. Jerarquía de memoria En una computadora hay una jerarquía de memorias atendiendo al tiempo de acceso y a la capacidad que normalmente son factores contrapuestos

Page 81: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

81

por razones económicas y en muchos casos también físicas. Comenzando desde el procesador al exterior, es decir en orden creciente de tiempo de acceso y capacidad, se puede establecer la siguiente jerarquía: Registros de procesador: Estos registros interaccionan continuamente con la CPU (porque forman parte de ella). Los registros tienen un tiempo de acceso muy pequeño y una capacidad mínima, normalmente igual a la palabra del procesador (1 a 8 bytes). Registros intermedios: Constituyen un paso intermedio entre el procesador y la memoria, tienen un tiempo de acceso muy breve y muy poca capacidad. Memorias caché: Son memorias de pequeña capacidad. Normalmente una pequeña fracción de la memoria principal, y pequeño tiempo de acceso. Dentro de la memoria caché puede haber, a su vez, dos niveles denominados caché on chip, memoria caché dentro del circuito integrado, y caché on board, memoria caché en la placa de circuito impreso pero fuera del circuito integrado, evidentemente, por razones físicas, la primera es mucho más rápida que la segunda. Existe también una técnica, denominada Arquitectura Harvard, en cierto modo contrapuesta a la idea de Von Newmann, que utiliza memorias caché separadas para código y datos. Esto tiene algunas ventajas como se verá en este capítulo. Memoria central o principal: En este nivel residen los programas y los datos. La CPU lee y escribe datos en él aunque con menos frecuencia que en los niveles anteriores. Tiene un tiempo de acceso relativamente rápido y gran capacidad. Extensiones de memoria central: Son memorias de la misma naturaleza que la memoria central que amplían su capacidad de forma modular. El tiempo de similar, a lo sumo un poco mayor, al de la memoria central y su capacidad puede ser algunas veces mayor. Memorias de masas o auxiliares: Son memorias que residen en dispositivos externos al ordenador, en ellas se archivan programas y datos para su uso posterior, también se usan estas memorias para apoyo de la memoria central en caso de que ésta sea insuficiente (memoria virtual). Estas memorias suelen tener gran capacidad pero pueden llegar a tener

Page 82: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

82

un tiempo de acceso muy lento. Dentro de ellas también se pueden establecer varios niveles de jerarquía. Clasificación de memorias semiconductoras de acceso aleatorio. Las memorias se clasifican, por la tecnología empleada y, además según la forma en que se puede modificar su contenido, A este respecto, las memorias se clasifican en dos grandes grupos: • Memorias RAM: Son memorias en las que se puede leer y escribir, si bien su nombre (Random access memory) no representa correctamente este hecho. Por su tecnología pueden ser de ferritas (ya en desuso) o electrónicas. Dentro de éstas últimas hay memorias estáticas (SRAM, static RAM), cuya célula de memoria está basada en un biestable, y memorias dinámicas (DRAM, dinamic RAM, en las que la célula de memoria es un pequeño condensador cuya carga representa la información almacenada. Las memorias dinámicas necesitan circuitos adicionales de refresco ya que los condensadores tienen muy poca capacidad y, a través de las fugas, la información puede perderse, por otra parte, son de lectura destructiva. • Memorias ROM (Read Only Memory): Son memorias en las que sólo se puede leer. Pueden ser:

o ROM programadas por máscara, cuya información se graba en fábrica y no se puede modificar, PROM, o ROM programable una sola vez.

o EPROM (erasable PROM) o RPROM (reprogramable ROM), cuyo contenido puede borrarse mediante rayos ultravioletas para regrabarlas.

o EAROM (electrically alterable ROM) o EEROM (electrically erasable ROM), que son memorias que está en la frontera entre las RAM y las ROM ya que su contenido puede regrabarse por medios eléctricos, estas se diferencian de las RAM en que no son volátiles.

En ocasiones a este tipo de memorias también se las denomina NYRAM (no volátil RAM), o Memoria FLASH, denominada así por la velocidad con la que puede reprogramarse, utilizan tecnología de borrado eléctrico al igual que las EEPROM. Las memorias flash pueden borrarse enteras en unos cuantos segundos, mucho más rápido que las EPROM.

Page 83: Introducción a la Programación de Sistemas.

INTRODUCCIÓN A LA PROGRAMACIÓN DE SISTEMAS

83

Básicamente las memorias ROM se basan en una matriz de diodos cuya unión se puede destruir aplicando sobre ella una sobretensión (usualmente comprendida entre -12.5 y -40 v.). De fábrica la memoria sale con 1's en todas sus nosiciones, para grabarla se rompen las uniones en que se quieran poner 0's. Esta forma de realizar la grabación se denomina técnica de los fusibles.