miércoles, 20 de noviembre de 2019

Generador de código objeto

 
Generación de código objeto

 El generador de código objeto como lo menciona (Urbina, 2011) transforma el código Intermedio optimizado en código objeto de bajo nivel. Toma código intermedio y genera Código objeto para la máquina considerada Es la parte más próxima a la arquitectura de la Máquina. Habitualmente, se escriben ``a mano´´ desarrollo a medida´ para cada máquina Específica.




REGISTROS

¿Qué son?

Los registros son la memoria principal de la computadora. Existen diversos registros de propósito general y otros de uso exclusivo. Algunos registros de propósito general son utilizados para cierto tipo de funciones. Existen registros acumuladores, puntero de instrucción, de pila, etc.

Los registros son espacios físicos dentro del microprocesador con capacidad de 4 bits hasta 64 bits dependiendo del microprocesador que se emplee.

¿Quiénes lo utilizan?


Antes de nada, para el desarrollo de esta parte hablaremos indistintamente de registros de activación o de marcos de pila. Esto se debe a que en la documentación encontrada sobre el manejo de los registros ebp y esp se hace mención a dicho concepto de marco de   pila.   Puesto   que   el   lenguaje   permite   recursividad,   los   registros   de   activación   se asignan dinámica mente. 




Distribución

La UCP o CPU tiene 14 registros internos, cada uno de ellos de 16 bits (una palabra). Los bits están enumerados de derecha a izquierda, de tal modo que el bit menos significativo es el bit 0.
Los registros se pueden clasificar de la siguiente forma: 

Registros de datos:

AX: Registro acumulador. Es el principal empleado en las operaciones aritméticas.
BX: Registro base. Se usa para indicar un desplazamiento.
CX: Registro contador. Se usa como contador en los bucles.
DX: Registro de datos.

Estos registros son de uso general y también pueden ser utilizados como registros de 8 bits, para utilizarlos como tales es necesario referirse a ellos como por ejemplo: AH y AL, que son los bytes alto (high) y bajo (low) del registro AX. Esta nomenclatura es aplicable también a los registros BX, CX y DX. 

Registros de segmentos: 

CS: Registro de segmento de código. Contiene la dirección de las instrucciones del programa. 
DS: Registro segmento de datos. Contiene la dirección del área de memoria donde se encuentran los datos del programa.
SS: Registro segmento de pila. Contiene la dirección del segmento de pila. La pila es un espacio de memoria temporal que se usa para almacenar valores de 16 bits (palabras).
ES: Registro segmento extra. Contiene la dirección del segmento extra. Se trata de un segmento de datos adicional que se utiliza para superar la limitación de los 64Kb del segmento de datos y para hacer transferencias de datos entre segmentos.

Registros punteros de pila:

SP: Puntero de la pila. Contiene la dirección relativa al segmento de la pila.
BP: Puntero base. Se utiliza para fijar el puntero de pila y así poder acceder a los elementos de la pila.

Registros índices:

 SI: Índice fuente.
 DI: Índice destino.


¿Cuales su aplicación en la generación de códigos?

1. usar el registro de y si está en un registro que no tiene otra variable, y además y no
está viva ni tiene uso posterior. Si no:
2. usar un registro vacío si hay. Si no:
3. usar un registro ocupado si op requiere que x esté en un registro o si x tiene uso
Posterior. Actualizar el descriptor de registro. Si no:
4. usar la posición de memoria de x

Ensambladores





Son los encargados de traducir los programas escritos en lenguaje ensamblador a lenguaje máquina.

Compiladores

Son programas que leen el código fuente y lo traducen o convierten a otro lenguaje. Estos programas te muestran los errores existentes en el código fuente.





Etapas del proceso de compilación:


Edición. Esta fase consiste en escribir el programa empleando algún lenguaje y un editor. Como resultado nos dará el código fuente de nuestro programa.
Compilación. En esta fase se traduce el código fuente obtenido en la fase anterior a código máquina. Si no se produce ningún error se obtiene el código objeto.
En caso de errores el compilador los mostraría para ayudarnos a corregirlos y se procedería a su compilación de nuevo, una vez corregidos.
Linkado. Esta fase consiste en unir el archivo generado en la fase dos con determinadas rutinas internas del lenguaje, obteniendo el programa ejecutable.
Existen dos tipos de linkados:


linkado estático: Los binarios de las librerías se añaden a nuestros binarios compilados generando el archivo ejecutable.
Linkado dinámico: no se añaden las librerías a nuestro binario sino que hará que se carguen en memoria las librerías que en ese momento se necesiten.
Una vez traducido, compilado y linkado el archivo esta listo para su ejecución donde también podrán surgir problemas y fallos, para los cuales tendríamos que volver a realizar todo el proceso anteriormente citado, de modo que puedan ser corregidos.

Por este motivo es importante realizar numerosas pruebas en tiempo de ejecución antes de presentar el programa al cliente.

Otro sistema para la ejecución de nuestro código fuente es mediante el uso de intérpretes (estos no se encontrarían dentro de los traductores).

Intérpretes

Los intérpretes realizan la traducción y ejecución de forma simultanea, es decir, un intérprete lee el código fuente y lo va ejecutando al mismo tiempo.

Las diferencias entre un compilador y un intérprete básicamente son:


Un programa compilado puede funcionar por si solo mientras que un código traducido por un intérprete no puede funcionar sin éste.
Un programa traducido por un intérprete puede ser ejecutado en cualquier máquina ya que, cada vez que se ejecuta el intérprete, tiene que compilarlo.
Un archivo compilado es mucho más rápido que uno interpretado.




lunes, 21 de octubre de 2019

Glosario tecnico- Nemotecnia Lenguaje ensamblador


Conceptos básicos.
Lenguaje de alto nivel: es aquel que se aproxima más al lenguaje natural humano que al lenguaje binario de las computadoras. Su función principal radica en que a partir de su desarrollo, existe la posibilidad de que se pueda utilizar el mismo programa en distintas máquinas, es decir que es independiente de un hardware determinado. La única condición es que la PC tenga un programa conocido como traductor o compilador, que lo traduce al lenguaje específico de cada máquina. Entre estos lenguajes figuran ejemplos como PASCAL, BASIC, FORTRAN y C++. (Lanzillotta, 2004).
•Lenguaje de bajo nivel: también llamado lenguaje ensamblador, permite al programador escribir instrucciones de un programa usando abreviaturas del inglés, también llamadas palabras nemotécnicas, tales como: ADD, DIV, SUB, etc. Un programa escrito en un lenguaje ensamblador tiene el inconveniente de que no es comprensible para la computadora, ya que, no está compuesto por ceros y unos. Para traducir las instrucciones de un programa escrito en un lenguaje ensamblador a instrucciones de un lenguaje máquina hay que utilizar un programa llamado ensamblador. (Pes, 2009).
  Lenguaje ensamblador: es un tipo de lenguaje de bajo nivel utilizado para escribir programas informáticos, y constituye la representación más directa del código máquina específico para cada arquitectura de computadoras legible por un programador. (Wikipedia, 2009).
• Lenguaje máquina: El lenguaje máquina es el único que entiende la computadora digital, es su "lenguaje natural". En él sólo se pueden utilizar dos símbolos: el cero (0) y el uno (1). Por ello, al lenguaje máquina también se le denomina lenguaje binario. (Pes, 2009).
  Compilador: los compiladores son programas o herramientas encargadas de compilar. Un compilador toma un texto (código fuente) escrito en un lenguaje de alto nivel y lo traduce a un lenguaje comprensible por las computadoras (código objeto).


Clasificación de los ensambladores.
 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.
 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.
 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 generados 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.
 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.
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.
Instrucciones simbólicas
Una instrucción en ensamblador consta de códigos de operación, operaciones, operandos y comentarios.
La etiqueta, es el símbolo que añadido a una instrucción permite que se pueda referenciar simbólicamente en el programa.
El código de operación, es generalmente un símbolo, aunque en algunos sistemas es un entero octal, hexadecimal o decimal que indica la operación que se quiere realizar.
El campo operando, es un campo de dirección de datos que puede estar dividido en varios subcampos de acuerdo con la constitución interna de la computadora correspondiente.
El comentario, que no es obligatorio, no es procesado por el ensamblador. Nos dice que las instrucciones pueden ser de formato fijo, formato libre y formato mixto.

CONJUNTO DE INSTRUCCIONES (Microprocesadores 8086/8088)
Se pueden clasificar en los siguientes grupos:
Instrucciones de Transferencia de Datos
Estas instrucciones mueven datos de una parte a otra del sistema; desde y hacia la memoria principal, de y a los registros de datos, puertos de E/S y registros de segmentación.
Las instrucciones de transferencia de datos son las siguientes:
MOV                  transfiere
XCHG                intercambia
IN                      entrada
OUT                  salida
XLAT                 traduce usando una tabla
LEA                   carga la dirección efectiva
LDS                   carga el segmento de datos
LES                   carga el segmento extra
LAHF                carga los indicadores en AH
SAHF                guarda AH en los indicadores
PUSH FUENTE (sp) ←←fuente
POP DESTINO  destino←←(sp)
Control de Bucles (instrucciones simples)

Éstas posibilitan el grupo de control más elemental de nuestros programas. Un bucle es un bloque de código que se ejecuta varias veces. Hay 4 tipos de bucles básicos:
• Bucles sin fin
• Bucles por conteo
• Bucles hasta
• Bucles mientras

Las instrucciones de control de bucles son las siguientes:
• INC    incrementar
• DEC  decrementar
• LOOP realizar un bucle
• LOOPZ, LOOPE realizar un bucle si es cero
• LOOPNZ, LOOPNE realizar un bucle si no es cero
• JCXZ salta si CX es cero

Instrucciones de Prueba, Comparación y Saltos.
Este grupo es una continuación del anterior, incluye las siguientes instrucciones:
TEST   verifica
CMP   compara
JMP   salta
JE, JZ   salta si es igual a cero
JNE, JNZ  salta si no igual a cero
JS   salta si signo negativo
JNS   salta si signo no negativo
JP, JPE  salta si paridad par
JNP, JOP  salta si paridad impar
JO   salta si hay capacidad excedida
JNO   salta si no hay capacidad excedida
JB, JNAE  salta si por abajo (no encima o igual)
JNB, JAE  salta si no está por abajo (encima o igual)
JBE, JNA  salta si por abajo o igual (no encima)
JNBE, JA  salta si no por abajo o igual (encima)
JL, JNGE  salta si menor que (no mayor o igual)
JNL, JGE  salta si no menor que (mayor o igual)
JLE, JNG  salta si menor que o igual (no mayor)
JNLE, JG  salta si no menor que o igual (mayor)
Instrucciones de Llamado y Retorno de Subrutinas.

Para que los programas resulten eficientes y legibles tanto en lenguaje ensamblador como en lenguaje de alto nivel, resultan indispensables las subrutinas:

CALL   llamada a subrutina
RET   retorno al programa o subrutina que llamó
Instrucciones Aritméticas.
Estas instrucciones son las que realiza directamente el 8086/8088

a. Grupo de adición:
ADD   suma
ADC   suma con acarreo
AAA   ajuste ASCII para la suma
DAA   ajuste decimal para la suma

b. Grupo de sustracción:
SUB  resta
SBB  resta con acarreo negativo
AAS  ajuste ASCII para la resta
DAS  ajuste decimal para la resta

c. Grupo de multiplicación:
MUL   multiplicación
IMUL   multiplicación entera
AAM   ajuste ASCII para la multiplicación

d. Grupo de división:
DIV   división
IDIV   división entera
AAD   ajuste ASCII para la división

e. Conversiones:
CBW   pasar octeto a palabra
CWD   pasar palabra a doble palabra
NEG   negación

f. Tratamiento de cadenas:
Permiten el movimiento, comparación o búsqueda rápida en bloques de datos:
MOVC   transferir carácter de una cadena
MOVW   transferir palabra de una cadena
CMPC   comparar carácter de una cadena
CMPW   comparar palabra de una cadena
SCAC   buscar carácter de una cadena
SCAW   buscar palabra de una cadena
LODC   cargar carácter de una cadena
LODW   cargar palabra de una cadena
STOC   guardar carácter de una cadena
STOW   guardar palabra de una cadena
REP   repetir
CLD   poner a 0 el indicador de dirección
STD   poner a 1 el indicador de dirección

Instrucciones Lógicas.

Son operaciones bit a bit que trabajan sobre octetos o palabras completas:
NOT   negación
AND   producto lógico
OR   suma lógica
XOR   suma lógica exclusiva

Instrucciones de Desplazamiento, Rotación y Adeudos.
Básicamente permiten multiplicar y dividir por potencias de 2
SHL, SAL  desplazar a la izquierda (desplazamiento aritmético)
SHR   desplazar a la derecha
SAR   desplazamiento aritmético a la derecha
ROL   rotación a la izquierda
ROR   rotación a la derecha
RCL   rotación con acarreo a la izquierda
RCR   rotación con acarreo a la derecha
CLC   borrar acarreo
STC   poner acarreo a 1

Instrucciones de Pila.
Una de las funciones de la pila del sistema es la de salvaguardar (conservar) datos (la otra es la de salvaguardar las direcciones de retorno de las llamadas a subrutinas):
PUSH   introducir
POP   extraer
PUSHF   introducir indicadores
POPF   extraer indicadores

Instrucciones de Control del microprocesador.
Hay varias instrucciones para el control de la CPU, ya sea a ella sola, o en
conjunción con otros procesadores:
NOP   no operación
HLT   parada
WAIT   espera
LOCK   bloquea
ESC   escape

Instrucciones de Interrupción.
STI   poner a 1 el indicador de interrupción
CLI   borrar el indicador de interrupción
INT   interrupción
INTO   interrupción por capacidad excedida (desbordamiento)
IRET   retorno de interrupción