lunes, 14 de enero de 2008

Ensamblador (Entrega 3)

El lenguaje ensamblador y las interrupciones

Al estudiar la estructura de la unidad central de procesos CPU, los alumnos aprenden el concepto de interrupción relacionado con el procesador, esta interrupción es de “hardware”, se trata de una señal eléctrica que recibe el procesador a través del bus de la PC (o una conexión directa en el caso de los microcontroladores).

Hay otro tipo de interrupciones, denominadas “de software” que en realidad son rutinas programadas y almacenadas en la memoria de la computadora. Para comprender esto, pensemos en un estado inicial en el que el procesador ejecuta un programa, al ocurrir una interrupción, el procesador abandona la tarea que lo ocupa y pasa a ejecutar otra.

Sintéticamente, lo que ocurre es lo siguiente:

1) El procesador almacena ciertos datos, tales como el contador de programa (que señala la dirección de memoria que está ejecutando)
2) Carga la dirección de memoria de la rutina de interrupción ISR correspondiente
3) Ejecuta la rutina de interrupción ISR y retorna de la interrupción.
4) Restablece los datos.

Una vez que el procesador completa su servicio al acontecimiento que originó la interrupción, retorna a la ejecución del programa en el punto en el que lo abandonara.

El lenguaje ensamblador dispone de una instrucción específica para “llamar” las interrupciones, se denomina INT. Int se utiliza para llamar a rutinas que realizar tareas genéricas y que vienen como servicios en el BIOS y en el DOS por lo que el programador no necesita programarlas por si mismo. Por ejemplo, para abrir un archivo el programador usará una rutina de interrupción de DOS, para establecer el modo de pantalla, mover el cursor y otras tareas similares, usará una rutina de BIOS. En general, la subrutina que se utilizará se especifica en AH (la porción alta del registro AX).

Por ejemplo, para imprimir un mensaje en la pantalla, se usará el servicio 9 de la interrupción 21. Si contáramos con un programa ensamblador simbólico, tal como el MASM, podríamos escribir algo así:

MSG DB 'CADENA$'
MOV DX, OFFSET MSG
MOV AH, 9
INT 21

En este caso, MSG es una variable, es decir, representa una posición de memoria. Este tipos de opciones facilitan mucho la tarea del programador. Sin embargo, con debug no contamos con esos lujos y debemos hacer estas cosas “a mano”, como vemos en el siguiente ejemplo:




Fig. 1 Ejemplo del uso del servicio 9 de la interrupción 21


El procedimiento que ejecuta el procesador para atender una interrupción se denomina ISR (Interrupt Service Routine en inglés) o rutina de servicio de interrupción. Esta rutina, es simplemente un programa que fué diseñado especialmente para atender el tipo de interrupción de que se trate. El vector de interrupción permite establecer la dirección que tendrá esta rutina.

El disparador de una interrupción puede tener origen en el hardware o en el software. Los vectores de interrupción de hardware se denominan IRQ. Las interrupciones de software se generan mediante la instrucción INT. El vector de interrupción se indica mediante un operando que sigue a la instrucción y puede tener un valor entre 0 y FF (0 y 255).

La computadora personal, al arrancar, carga un conjunto de rutinas de servicio de interrupción en la memoria. El primer programa en cargar rutinas es el BIOS que, como ya señalamos, está grabada en una memoria ROM (ROM-BIOS).

Además, los sistemas operativos disponible en el ambiente de la computadora personal tales como el DOS y OS/2, instalan rutinas de servicio de interrupción. De esta forma, el programador de lenguaje ensamblador dispone de un conjunto de servicios listos para ser utilizados. Uno de los servicios de interrupción típicos de BIOS es INT 10 que ofrece numerosos servicios de video. El DOS dispone de una interrupción muy versátil INT 21.

Generar un archivo .COM con Debug

El siguiente ejemplo muestra como se genera una interrupción de software. En este caso, utilizaremos el servicio 2 de la interrupción 21 de DOS. Para realizar este ejemplo, cree un archivo con el nombre EJ1.TXT utilizando un procesador de textos que genere código ASCII (EDIT de DOS o NOTEPAD de Windows). Luego, ingrese el conjunto de instrucciones tal como figuran en el ejemplo, sin cambiar nada.

Nej1.com
A
MOV AH,02
MOV DL,53
INT 21
MOV AX,004C
INT 21

RCX
B
W
Q

Recuerden que todos los números con los que trabaja el programa DEBUG son hexadecimales.

Explicación

Mediante el comando N le indicamos a DEBUG que cree un archivo con el nombre “ej1.com”. Luego, mediante el comando A le ordenamos que convierta las instrucciones que siguen (a dicho comando) en código de máquina (binario), luego de las instrucciones escritas en lenguaje ensamblador, hay una línea en blanco. Esta línea debe estar en blanco. Luego, está el comando RCX que permite cargar un valor en el registro CX, en este caso B hexadecimal (11 decimal). Luego, el comando W ordena a DEBUG grabar en el archivo ej1.com la cantidad de bytes que se indicaron en el registro CX, en nuestro caso B bytes. Finalmente el comando Q le orden a DEBUG salir.


Uso del programa

Para ensamblar el programa usaremos el comando debug seguido por el signo "<" y luego el nombre del archivo que creamos previamente, es decir ej1.txt. Observe la Fig. 2 en la cual se muestra la ejecución de este paso, y el despliegue en pantalla que realiza debug.

Fig. 2 Proceso de ensamblado y prueba del programa ej1

El caracter "<" simplemente redirecciona la entrada, en lugar de tomar datos desde el teclado, toma los datos del archivo de textos.

Para probar el "programa" ej1.com que acaba de crear, en la carpeta de trabajo en que se encuentra (C:\DOCUME~1\NUEVA>) teclee el nombre ej1 INTRO y el programa mostrará una S por la pantalla.

Análisis detallado del ejemplo

Pasaremos ahora a analizar el ejemplo anterior, paso a paso, para comprender algunos conceptos de programación en lenguaje ensamblador así como también, la forma en la que trabaja el programa DEBUG.

Preste suma atención a las líneas que exponemos a continuación:

- Línea 1: Nej1.com

El comando N instruye a DEBUG para que cree un archivo con el nombre que aparece a continuación del propio comando N. En nuestro caso, el nombre del archivo es “ej1.com” (es decir, un programa ejecutable).

- Línea 2: A

El comando A ordena a DEBUG convertir a lenguaje de máquina las instrucciones mnemotécnicas propias del lenguaje ensamblador (Ver figura Esquema del proceso de ensamble).

Recordemos que las instrucciones de lenguaje ensamblador se denominan mnemotécnicas por el hecho de que son fáciles de memorizar debido a la similitud que tienen con términos del idioma inglés. Por ejemplo, la instrucción MOV que permite “mover” un valor hacia un registro de la CPU, es claramente reconocible como MOVE (mover en inglés).

- Línea 3: MOV AH,02

Esta es la primera instrucción en lenguaje ensamblador, es decir es una instrucción para el procesador y no para DEBUG. Como previamente debug recibió la instrucción A, al leer el código de la línea 3, si es un código válido, lo convertirá a lenguaje de máquina y lo guardará en memoria.

El procesador de la computadora personal, dispone de un conjunto de registros que utiliza para almacenar, en forma temporal, los datos que procesa. Todos los programas, desde el humilde manejador del ratón hasta Windows Vista terminan convertidos en instrucciones de máquina y valores en los registros del procesador. Los registros disponibles son los siguientes: AX, BX, CX y DX. Estos son registros de 16 bits, que corresponde a 2 bytes o también a 4 números hexadecimales (recuerde que un número hexadecimal corresponde a 4 bits, o sea 1/2 byte).

El procesador, permite además acceder a registros 1 byte que en realidad corresponden al desdoblamiento de los registros de 16 bits que mencionamos antes. Así, el registro AX puede ser manejado también mediante los registros AH y AL. La H de AH indica que el byte es de orden superior; por su parte, la L de AL señala que el byte es de orden inferior. Para entender esto, veamos el siguiente ejemplo: Luego de realizar la instrucción MOV BX,7F5C, tenemos BX=7F5C, entonces BH=7F y BL=5C.

- Línea 4: MOV DL,53

En este caso, la instrucción (a la CPU) indica mover el valor 53 hexadecimal (83 decimal) al registro DL. Incidentalmente, el valor 53 hexadecimal corresponde al carácter S (de Sergio) en código ASCII.

- Línea 5: INT 21

Esta es la instrucción que realiza la interrupción de software. INT 21 es una interrupción de DOS que tiene múltiples aplicaciones o servicios, estos servicios, dependen de los valores contenidos en el registro AH. Veamos los servicios que presta la interrupción para los siguientes valores de AH:

Si AH=0

El sistema ingresa un carácter por el teclado, lo pone en el registro AL y lo muestra por la pantalla.

Si AH=1

Muestra por pantalla el carácter que está en el registro DL. En nuestro ejemplo, DL=53, 83 decimal es decir, la letra S.

- Línea 6: MOV AX,004C

Aquí tenemos un ejemplo del uso de un registro de 16 bits. Observe que lo cargamos con el valor 004C.

- Línea 7: INT 21

Nuevamente la interrupción 21 de DOS, en este caso, el servicio es AX= 004C que sirve para terminar el programa y hacerle saber a DOS que finalizó en forma exitosa. Esta línea y la anterior deberían incluirse siempre en los programas con la excepción de los programas residentes que utilizan un procedimiento diferente.

- Línea 8:

Esta línea se dejó en blanco intencionalmente ya que sirve para sacar a DEBUG del comando A (ensamblar), el cual debe concluir ya que la última línea para ensamblar fue la línea 7.

- Línea 9: RCX


El comando R le indica a debug preparar el registro, en este caso el registro CX para ingresarle un valor. DEBUG utiliza el registro CX para guardar un valor que sirva, en este caso, para indicar la cantidad de bytes en lenguaje de máquina (esta cantidad tuvo que determinarla el autor).

- Línea 10: B

Este es el valor que se cargará en CX. El valor B hexadecimal es igual a 11 decimal y corresponde a la cantidad de bytes que DEBUG grabará como código en lenguaje de máquina (que está en la memoria) en el archivo ej1.com.

- Línea 11: W

El comando W ordena a DEBUG a escribir la cantidad de bytes que indica el registro CX y cerrar el archivo.

- Línea 12: Q

El comando Q ordena a debug termnar su operación y retornar a DOS.

Realicen los ejemplos y en próximas entregas veremos cómo crear nuestros propios servicios de interrupción y cómo dejar programas “residentes” en memoria.

Hasta la próxima entrega,

Sergio Otaño

2 comentarios:

Inti dijo...

buen aporte viejo....

Inti dijo...

buen aporte viejo...