|
Cursos y Tutoriales Estructura de un programa en Ensamblador: Para entrar directamente en materia, veamos un listado en lenguaje ensamblador de un programa corriente: se trata de un programa que muestra la cadena "Primer Programa" en el monitor y retorna al Sistema Operativo. PILA SEGMENT STACK 'STACK' ; Abre el segmento de PILA. DW 100h DUP (?) ; Reserva 100 palabras para la PILA. PILA ENDS ; Cierra el segmento de PILA. DATOS SEGMENT 'DATA' ; Abre el segmento de DATOS. mensaje DB "Primer Programa", '$' ; Mensaje a escribir. DATOS ENDS ; Cierra el segmento de DATOS. CODIGO SEGMENT 'CODE' ; Abre el segmento de CODIGO. ASSUME CS:CODIGO, DS:DATOS, SS:PILA ENTRADA: MOV ax, DATOS ; Valor de segmento para DATOS. MOV ds, ax ; Para acceder a "mensaje". MOV dx, OFFSET mensaje ; Para la interrupción 21h, función 09. MOV ah, 09 ; Especifica el servicio o función 09. INT 21h ; Invoca el servicio 09: Imprimir Cadena. MOV ax, 4C00h ; Servicio (Función) 4Ch, con valor de retorno 0. INT 21h ; Invoca servicio 4Ch: Retorno al DOS. CODIGO ENDS ; Cierra el segmento de CODIGO. END ENTRADA ; Final del modulo fuente y primera instrucción ; desde donde debe empezarse a ejecutar el programa. Veamos primero el formato de SEGMENT: ........... nombre ENDS Sirve para indicarle al ensamblador que la información que venga a continuación, y hasta que no encuentre una directiva de fin de segmento (ENDS), corresponde al mismo segmento. - nombre: Indica el nombre del segmento que vamos a utilizar. El "nombre" indicado en SEGMENT y el "nombre" indicado en ENDS deben ser el mismo. - alineamiento: En "alineamiento" vamos a situar una información que le dirá al ensamblador las características que debe tener la dirección de memoria que elija para realizar la carga de ese segmento. Los valores que le podemos dar son: BYTE: Puede colocar el segmento en cualquier dirección. WORD: Debe colocar el segmento en una dirección múltiplo de 2. DWORD: Debe colocar el segmento en una dirección múltiplo de 4. PARA: Debe colocar el segmento en una dirección múltiplo de 16. Es el alineamiento por defecto. - READONLY: Informa al ensamblador de un error producido cuando alguna instrucción del segmento que contiene la sentencia READONLY es modificada. - combinación: La combinación nos dirá una serie de informaciones para el montador (LINKER). Le podemos situar las posibilidades: PUBLIC: Le dice al montador (LINKER) que este segmento y todos los que tengan el mismo nombre en 'clase' se concatenarán en un mismo segmento. STACK: Indica que estamos tratando con un segmento de pila. Esta identificación es obligatoria en el caso de que el segmento contenga la pila. Al menos dabe haber un segmento de pila para crear un módulo ejecutable con el montador (LINKER). AT expresión: Sirve para indicarle al montador en que dirección de memoria deberá situar la información correspondiente a éste segmento. La dirección de memoria viene especificada en el parámetro "expresión". COMMON: Indica que este segmento y todos los del mismo nombre ("clase") que procese el montador empezarán en la misma dirección, solapándose entre sí. La longitud asignada por el montador es la longitud máxima de todos los segmentos COMMON procesados. MEMORY: EL segmento se ubicará en una dirección de memoria superior a la de otros que aparecerán durante el montaje (LINK) del programa. Se puede aplicar, por ejemplo, para utilizar la memoria más allá de los límites del programa. Sólo puede haber un segmento de este tipo. Si existieran varios, solo se procesará el primero como tal, y el resto se procesará como COMMON.
- use (sólo 80386/486): Determina el tamaño del segmento. USE16 indica que el desplazamiento es de 16 bits de ancho, y USE32 indica que el desplazamiento es de 32 bits de ancho. - 'clase': La 'clase' es un nombre que sirve para que el montador pueda unificar todos los segmentos que tengan asociados dicho nombre, si es que le damos la posibilidad de ello. Volvamos al programa. PILA SEGMENT STACK 'STACK'. Esta línea lleva la directiva SEGMENT, que hace que el ensamblador incluya una entrada en el fichero objeto para este segmento. PILA es el nombre con el que nos referimos a éste segmento dentro del listado fuente, mientras que 'STACK' incluida entre comillas simples es utilizada por el enlazador (LINKER). La palabra STACK sin comillas indica tanto al ensamblador como al enlazador (LINKER) que este segmento se utilizará como espacio de pila en ejecución. Cada línea SEGMENT debe tener su una correspondiente ENDS (Fin de segmento). DW 100h DUP (?) ; esta línea lleva la directiva DW (definir palabra). Esta directiva permite fijar directamente los valores incluidos en el módulo al tamaño, en este caso, de una palabra, el uso de DUP nos permite fijar un número determinado de palabras (100h = 256 en este caso) a un mismo valor. El valor se indica entre paréntesis; en esta línea es un interrogante, con lo que indicamos al ensamblador que no son importantes los contenidos iniciales de esta 256 palabras. El enlazador puede intentar reducir el tamaño del ejecutable gracias a que no nos interesan lon contenidos iniciales de esta posiciones de memoria. La instrucción DUP se utiliza para definir arrays (vectores). El formato sería: El valor de "contador" nos dice el número de veces que se repite lo que hay en "valor_inicial". El "valor_inicial" debe definirse siempre entre parétesis. El "valor_inicial" suele se o un "?" que nos indica que no nos interesa el contenido inicial del vector o un número, que nos indicará el contenido de cada posición del vector. Ejemplos: baray BYTE 5 DUP (1) ; En este cado tenemos un vector de 5 posiciones, y cada posición ocupa un BYTE y tiene un valor inicial de 1 (cada posición). array DWORD 10 DUP (1) ; En este caso tenemos un vector de 10 posiciones, y cada posición ocupa una Doble Palabra (DWORD) y tiene un valor inicial de 1. buffer BYTE 256 DUP (?) ; Vector de 256 posiciones, y cada posición ocupa un BYTE y tiene un valor inicial que no nos interesa. También se puede definir un "array" de la siguiente forma: warray WORD 2, 4, 6, 8, 10 La forma de acceder a alguno de estos elementos dentro del código de segmento sería: DATOS SEGMENT 'DATA' btabla BYTE 12 DUP (?) DATOS ENDS CODIGO SEGMENT 'CODE' ASSUME CS:CODIGO, DS:DATOS UNO: MOV ax, DATOS MOV ds, ax XOR al, al ; Ponemos lo que vamos a meter en "btabla" a 0 MOV si,0 ; colocamos el puntero de "btabla" (SI) a 0 (el primer elemento de la matriz o el array empieza en la posición cero) MOV cx, 12 ; contador a 12. DOS: MOV btabla[si], al ; Movemos un valor de un BYTE (AL), (ya que hemos definido "btabla" de tipo BYTE) a "btabla". También podemos poner esta instrucción como: MOV btabla + SI, AL INC si ; Al tratarse de elementos de un BYTE el puntero sólo se debe incrementar en una unidad. LOOP DOS XOR ax, ax MOV si; 0 ; Ponemos el índice del array a cero MOV xc, 5 TRES: MOV ax, warray[si] ; Movemos el valor que indica el puntero (SI) dentro de "warray” a AX (Ya que hemos definido "warray" de tipo PALABRA). ; También podemos poner esta instrucción ; como: MOV AX, warray + SI ADD si, 2 ; Incrementamos SI en 2 unidades debido a que "warray" esta definido con PALABRAS. LOOP TRES CODIGO ENDS END UNO (ELEMENTO - 1) * TIPO Donde: ELEMENTO es el elemento a buscar y TIPO es el tamaño con el que hemos definido el array (1 - BYTE, 2 - WORD (2 bytes), 4 - DWORD (4 bytes), etc). En el caso de matrices, ésta nos presenta un almacemaniento que ocupa posiciones consecutivas y que lo debemos tratar como un vector. Para tratar dicho vector se necesita conocer el número de filas y el número de columnas. El algoritmo para acceder a un elemento, a partir de la dirección de comienzo, sería: (FILA - 1) * Nº COL * TIPO + (COL - 1) * TIPO Donde: FILA es la posición de la fila a buscar, Nº COL es el número de columnas que tiene cada fila. TIPO es lo mismo que en los vectores. COL es la posición de la columna a buscar. Por ejemplo: En una matriz de 4 filas por 3 columnas tipo BYTE, queremos ver el contenido de la posición (3, 2). (3 - 1) * 3 * 1 + (2 - 1) * 1 PILA ENDS Cierra el segmento de pila. Esta directiva (ENDS) cierra el segmento abierto pos la directiva PILA SEGMENT. El identificador que antecede a ENDS debe ser el mismo que el que antecede a la directiva SEGMENT correspondiente, recordando que no son importantes las mayúsculas o minúsculas. DATOS SEGMENT 'DATA' Abre el segmento de datos. Esta directiva abre otro segmento. Este segmento lo utilizaremos para los datos del programa. Mensaje DB "Primer Programa", '$' Mensaje a escribir. (También lo podemos ver definido como: 'Primer Programa$,' o como: "Primer Programa","$", etc.). Esta directiva sirve para reservar memoria para la variable mensaje. DB quiere decir "definir byte". En éste caso, se reservan 16 bytes (15 del mensaje y uno del $). El carácter $ se utiliza como delimitador del texto a escribir. Es decir, cuando vayamos a escribir mensaje por pantalla se escribirán todos los caracteres hasta encontrar el carácter $. También podemos encontrar, por ejemplo, el mensaje: "Pimer Programa", 13, 10, "$" que nos indicaría que, después de escribir el texto, ejecutaría el carácter 13 (retorno de carro) y luego el carácter 10 (salto de línea). En cuanto al tamaño de los datos, éste puede ser: TAMAÑO RANGO BYTE, DB Valor de 0 a 225 (1 Byte). SBYTE Valor entre: -128 y +127 (1 Byte). WORD, DW Valor de 0 a 65.535 (2 Bytes). SWORD Valor entre: -32.768 t +32.767 (2 Byte). DWORD, DD Valor de 0 a 4 Megabytes (4.294.967.259) (4 bytes). SDWORD Valor entre: -2.147.438.648 y +2.147.438.647 (4 bytes) QWORD, DQ Tamaño de 8 Bytes. TBYTE, DT Tamaño de 10 Bytes. En cuanto a número reales en "coma flotante": TIPO DE DATO BITS DIGITOS SIGNIF. RANGO APROXIMADO REAL4 32 6 - 7 De: ±1.18x10-38 a ±3.40x1038 REAL8 64 15 - 16 De: ±2.23x10-308 a ±1.79x10308 REAL10 80 19 De: ±3.37x10-4932 a ±1.18x104932 Para expresar un número real se utiliza este formato: [+/-] entero. [fracción] [E] [[+/-] exponente] Ejemplos: corto REAL4 25.23 ; 25,23 doble REAL8 2.523E1 ; 2.523x101 = 25,23 diezbytes REAL10 -2523.0E-2 ; = -2523x10-2 = -25,23 Seguimos con el programa. DATOS ENDS Cierra el segmento de datos. CODIGO SEGMENT 'CODE' Abre el segmento de código. Abre el segmento de código, donde incluímos el código del programa. Ni el nombre CODIGO, ni la clase 'CODE' son tratados de forma especial por el ensamblador o el enlazador. ASSUME CS:CODIGO, DS:DATOS, SS:PILA Esta línea informa al ensamblador de los segmentos a los que apuntarán durante la ejecución los diferentes registros de segmento. De este modo, si intentamos acceder a la etiqueta 'mensaje' definida en el segmento "DATOS", el ensamblador sabrá que puede acceder a ella por medio del registro DS. El registro CS se asocia con el segmento de CODIGO y el registro SS con el segmentos de PILA. MOV AX, DATOS Valor de segmento para "DATOS" (AX=dirección del segmento de DATOS). Almacena la componente segmento del segmento DATOS sobre el registro AX. Como el registro DS apunta al comienzo del PSP (Prefijo de Segmento de Programa; antes de que el procesador de comandos (COMAND.COM) del DOS pase el control al programa, construye un bloque de 256=100h bytes a partir de la primera posición de memoria disponible. El PSP contine campos como la dirección de retorno al DOS cuando acabe de ejecutarse el programa, la dirección del código si se pulsa Ctrl-Break, la dirección de la rutina del tratamiento de errores críticos, la cantidad de memoria disponible para el programa y los parámetros, etc.), es necesario cambiarlo para que se pueda acceder a los datos (en el segmento de datos) mediante el registro DS. La instrucción MOV no permite mover directamente a DS, por lo que se utiliza el registro AX como registro intermedio. MOV DS, AX Al segmento de código no hace falta direccionarlo con CS, pues lo hace el sistema operativo MS-DOS. Tampoco hace falta direccionar el registro SS para acceder a la pila, pues el DOS lo inicializa también. En éste programa no existe segmento extra. MOV DX, offset “mensaje” Esta instrucción carga en el registro DX el desplazamiento de la etiqueta "mensaje", dentro del segmento donde ha sido definida. Podemos utilizar la expresión OFFSET etiqueta para obtener el desplazamiento dentro de un segmento de una etiqueta cualquiera (DS:DX = dirección del texto). MOV AH, 09 Especifica la Función 09. INT 21h Invoca el servicio (interrupción) 21h. imprimir cadena. Esta dos instrucciones invocan la función 09 de la interrupción 21h. correspondiente al MS-DOS. Este servicio envía a la salida estándar del programa (habitualmente la pantalla) la cadena de caracteres apuntada por DS:DX. MOV AX, 4C00h Servicio 4Ch; valor de retorno 0. INT 21h Invoca el servicio 4Ch de la interrupción 21h, que retorna al sistema operativo con el ERRORLEVEL, indicando en el registro AL, en éste cado cero. CODIGO ENDS Cierra el segmento "CODIGO". END ENTRADA Fin de programa; indica punto de entrada al programa. La directiva END marca el ensamblador el final del código fuente. El símbolo a continuación de END indica al ensamblador en qué punto debe comenzar la ejecución del programa. El ensamblador parará la información al enlazador, que incluirá esta información en la cabecera del EXE. Si se quieren utilizar esta directivas, es necesario primero incluir una línea con la directiva .MODEL. El formato de esta directiva es el siguiente: .MODEL modelo de memoria [,opciones] Los modelos de memoria pueden ser: TINY: Tipo de puntero del Segmento de Código: NEAR, tipo de puntero del Segmento de datos: NEAR; permite combunar el Segmento de Código y el Segmento de Datos. SMALL: Tipo de puntero del Segmento de Código: NEAR, tipo de puntero del Segmento de datos: NEAR. MEDIUM: Tipo de puntero del Segmento de Código: FAR, tipo de puntero del Segmento de datos: NEAR. COMPACT: Tipo de puntero del Segmento de Código: NEAR, tipo de puntero del Segmento de datos: FAR. LARGE: Tipo de puntero del Segmento de Código: FAR, tipo de puntero del Segmento de datos: FAR. HUGE: Tipo de puntero del Segmento de Código: FAR, tipo de puntero del Segmento de datos: FAR. FLAT: Tipo de puntero del Segmento de Código: NEAR, tipo de puntero del Segmento de datos: NEAR; permite combinar el Segmento de Código y el segmento de Datos, pero se utiliza, exclusivamente, con el sistema operativo OS/2 2.x. Las opciones pueden ser: - Sistema Operativos: Pueden tomar los valores: OS_OS2 o OS_DOS. - Tamaño de la Pila: Pueden tomar los valores: NEARSTACK (Cuando el Segmento de Pila y el Segmento de Datos comparten el mismo segmento físico (SS=DS)) y FARSTACK (Cuando el Segmento de Pila y el Segmento de datos no comparten el mismo segmento físico (SSDS)). Por ahora utilizaremos el modelo SMALL para la generación de programas EXE que utilicen un sólo segmento para código y otro para datos, y el modelo TINY para programa de tipo COM. Cuando el ensamblador procesa la directiva .MODEL, prepara la definición de algunos segmentos por defecto par el código, los datos y la pila. Los nombres, alineamiento, combinación y clase de estos segmentos vienen fijados apropiadamente por el modelo especificado, por lo que no necesitamos preocuparnos de ellos. El modelo SMALL soporta un Segmento de Código y un Segmento de Datos. El modelo MEDIUM soporta varios Segmentos de Código y un Segmento de Datos. El modelo COMPACT soporta un Segmento de Código y varios Segmento de Datos. Los modelos LARGE y HUGE son equivalentes, soportan varios Segmentos de Códigos y Varios Segmentos de Datos. Para activar el tipo de procesador con el que vamos a trabajar y las instrucciones disponibles para ese tipo de procesador, se utilizan las sentencias: .186, .286., .386 y .486 Después de esto, el ensamblador reconoce algunas directivas especiales para abrir segmentos: .CODE para abrir el Segmento de Código. .DATA para abrir el Segmento de Datos. .STACK para fijar el tamaño del Segmento de Pila. Estas directivas, además de abrir el segmento asociado, cierran el último segmento abierto, por lo que no es necesaria la directiva ENDS. La directiva .CODE, además de abrir el Segmento de Código, genera el ASSUME adecuado para el modelo especificado. La directiva .STACK lleva un parámetro opcional que fija el tamaño de la pila en bytes. En su defecto, el ensamblador asume un tamaño de 1024 bytes. El ensamblador y el enlazador tratan siempre de forma especial el segmento de pila, de manera que los datos del segmento de pila no aparecen en el fichero ejecutable, reduciendo por tanto el tamaño de éste y haciendo el tamaño del EXE independiente del tamaño de la pila. La directiva END, además de las funcione vistas, cierra el último segmento abierto. Es probable que se necesite inicializar registros de segmento del mismo modo que en la forma de codificación normal, como MOV ax, datos pero la directiva simplificada de segemto no permite ver el nombre de los segmentos generados. Para solucionar este problema, el ensamblador le permite usar los símbolos : @CODE y @DATA en lugar del nombre de los segmento de Código y Datos, respectivamente. .MODEL SMALL ; Modelo de memoria SMALL: Usamos un Segmento de Código y un de Datos. .STACK 200h ; Tamaño de la pila 200h=512 bytes. En el otro programa eran: DW 100h, es decir, 256 palabras, es decir, 512 bytes. .DATA ; Abre el Segmento de Datos mensaje DB "Primer Programa","$" ; Mensaje a imprimir .CODE ; Cierra el Segmento de Datos, abre el de Código y genera el ; ASSUME ENTRADA: MOV ax, @DATA ; Valor del segmento para ".DATA". MOV ds, ax ; Para acceder a "mensaje". MOV dx, OFFSET mensaje ; Todo lo de abajo es igual. MOV ah, 09 INT 21h MOV ax, 4C00h INT 21h END ENTRADA ; Fin del programa. Cierra el segmento de Código e indica el punto de entrada al programa. MACROS. Una macro consiste en una serie de lineas a la que se asocia un nombre y que se puede repetir en cualquier punto del listado sin más que dar su nombre. Toda macro debe tener dos partes: 1) La cabezera de la macro: Aquí se especifica el nombre de identificación de la misma, es decir, al grupo de instruciones que engloba esa macro : Nombre-Macro MACRO parámetro [, parámetro, ...] 2) Texto o cuerpo de la macro: Aquí se situan las instrucciones (sentencias). 3) Fin de macro (ENDM). El formato a utilizar sería: Nombre_Macro MACRO parámetro [, parámetro,...] sentencias ENDM La cabecera y el fin de la MACRO, siempre vienen dados por pseudoinstrucciones o directivas,. El cuerpo de la MACRO, viene dado por instrucciones normales de ensamblador. 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". Según lo comentado, si nos fijamos en un programa codificado en ensamblador, tenemos dos versiones de programa. Una de ellas escrita directamente y otra mediante macros, con lo que nos podíamos encontrar que después de la expansión de las macros las dos versiones de programa son iguales. El empleo de macros no debemos confundirlo con el empleo de procedimientos, ya que una llamada a una macro sustituye su nombre por el cuerpo de la misma, en cambio, una llamada a procedimientos lo único que realiza es un enlace con otro programa. Las macros se suelen incluir todas dentro de ficheros específicos. En cada uno de los ficheros situaremos las macros que tengan alguna relación entre sí. Nos podemos encontrar con macros que en la realización de una tarea puedan utilizar datos distintos. Para no tener que definir una macro para cada dato distinto que tengamos que utilizar, se debe permitir la utilización de "Parámetro Formales", entendiéndose que estos datos serían los nombres que utilizaremos en el cuerpo de la MACRO cuando la definiésemos por primera vez. Estos parámetros van situados en la cabecera de la definición de la macro. En la llamada a la macro sería donde situaríamos los "Parámetros Reales", con los que va a trabajar la macro. Cuando se hace una expansión de la macro los parámetros formales se sustituyen por los parámetros reales. Estas instrucciones se sustituyen justamente en la posición en la que se encuentra la directiva. Dicha directiva se usa dentro de cualquiera de los segmentos, pero su utilización corriente es dentro del Segmento de Código. Se suele utilizar para poder incluir dentro de un programa los ficheros de MACROS. Su formato es: INCLUDE Nombre_Fichero Si el Fichero a incluir en el programa (Nombre_Fichero), no se encuentra en el mismo directorio del programa o en la misma unidad, habrá que indicarle en la instrucción, el camino de acceso para encontrar ese Fichero. Ejemplo: En un disco tenemos un fichero con una serie de MACROS y que se llama: MACROS.ASM: Listado de MACROS.ASM retorno MACRO MOV ah, 4ch INT 21h ENDM display MACRO cadena MOV dx, OFFSET cadena MOV ah, 09h INT 21h ENDM leer_teclado MACRO MOV ah, 08h INT 21h En nuestro ordenador estamos realizando nuestro programa: PILA SEGMENT STACK 'STACK' dw 100h dup (?) PILA ENDS DATOS SEGMENT 'DATA' paso db "MIOOO" control db 5 dup (?) men1 db "Clave de acceso:".13,10,"$" men2 db "Bienvenido","$" DATOS ENDS CODIGO SEGMENT 'CODE' ASSUME CS: CODIGO, DS: DATOS, SS: PILA EMPEZAR: MOV ax, DATOS MOV ds, ax INCLUDE A:\ MACROS,ASM ; Aquí le decimos al programa que incluya las macros del porgrama que se encuentra en el fichero MACROS:ASM que se encuentra en un disco en la unidad A de nuestro ordenador. DOS: MOV si, 0 display men1 ; "display" es una MACRO que tiene parámetro. MOV cx, 5 UNO: leer teclado ; Otra MACRO. Esta macro no tiene parámetros. MOV control[SI], al INC si LOOP UNO MOV si, 0 MOV cx, 5 TRES: CMP al, paso[SI] JNE DOS INC SI LOOP TRES display men2 ; Otra MACRO retorno ; Otra MACRO sin parámetros CODIGO ENDS ENDS EMPEZAR Con las directivas simplificadas las macros funcionan igual. LOCAL: 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. Ejemplo: esperar MACRO numero LOCAL SEGUIR MOV cx, numero seguir: LOOP seguir ENDM Otra cosa aconsejable que se puede hacer en referencia a las macros es guardar previamente en la pila el valor de los registros que vayamos a usar dentro de la macro y después, cuando acaben las instruciones de la macro, volver a retornárselos. Ejemplo: display MACRO cadena PUSH dx PUSH ax MOV dx, offset cadena MOV ax, 09h INT 21h POP ax POP dx ENDM Ejercicios: 1.- Disponemos de una matriz almacenada en una serie de bytes en memoria. Dicha matriz está estructurada mediante 4 filas y 3 columnas. Realizar la suma de los elementos de esta matriz recorriéndola fila a fila. 2.- Disponemos de una matriz de 4 filas y 3 columnas ocupando cada elemento de la matriz un byte. Calcular la suma de los elementos de esta matriz columna a columna, 3.- Disponemos de una matriz almacenada en palabras de memoria cuya estructura de 4 filas y 4 columnas. Se pide realizar la suma de sus dos diagonales. 4.- Disponemos de una matriz almacenada en palabras de memoria que posee una estructura de 4 filas y 3 columnas. Sumar los elementos que ocupen posiciones impares, a continuación, sumar los que ocupen posiciones pares, y la suma de elementos impares es mayor que la de los pares, efectuar la resta "impares - pares", y si no es así, efectuar la resta "pares - impares". 5.- Se trata de teclear un máximo de 40 caracteres que irán apareciendo en pantalla. Si durante el tecleo no deseamos seguir con el mismo, podemos romper la secuencia pulsando el ENTER. Una vez tecleados los 40 caracteres, aparecerá en pantalla un literal que nos indicará que introduzcamos una palabra a localizar dentro de la secuencia inicial tecleada. Una vez localizada la palabra se nos deberá indicar cuantas veces aparece esta palabra dentro del texto inicial tecleado. PROCEDIMIENTOS. El uso de los procedimientos va a estar marcado por elementos principales: CALL: (Llamada a un procedimiento). Esta instrucción transfiere el control a otro punto de la memoria, cargado IP (cuando el procedimiento llamado está dentro del mismo segmento (NEAR)), y eventualmente CS (cuando el procedimiento llamado está en otro segmento (FAR)), con nuevos valores. La dirección actual (CS:IP o solamente IP, en función de si la instrucción altera CS o no) se introduce en la pila para permitir un posterior retorno. El destino del salto puede estar indicado tras el código de operación de la instrucción o puede obtenerse indirectamente de un registro o posición de memoria especificada en la instrucción. Hay varios tipos de llamadas (a etiquetas, a variables, etc), nosotros vamos a tratar las llamadas a etiquetas. Formato: CALL [tipo_salto] destino "tipo_salto" indica si la llamada es a un procedimiento cercano (entoces su valor es NEAR) o lejano (su valor es FAR), y "destino" es el nombre del procedimiento al que vamos a llamar. PROC: Indica el comienzo de un procedimiento (un procedimiento es un bloque de instrucciones que sirven para realizar una tarea determinada y que pueden invocarse desde varios puntos del programa. Puede considerarse como una subrutina). Formato: sentencias RET Nombre_Procedimiento ENDP El "atributo" puede ser NEAR o FAR dependiendo de si el salto es dentro del mismo segmento (NEAR) o no (FAR). Los valores de IP (NEAR) o CS:IP (FAR) se guardan en la pila cuando se produce una llamada a un procedimiento. Para que estos valores puedan ser restaurados después de la ejecución del procedimiento y elñ programa sigua con su ejecución normal se ejecuta la instricción RET (retornar valores). Ejemplo: PILA SEGMENT STACK 'STACK' dw 100h dup (?) PILA ENDS DATOS SEGMENT 'DATA' mensaje db "Primer Programa:","$" DATOS ENDS CODIGO SEGMENT 'CODE' ASSUME CS: CODIGO, DS: DATOS, SS: PILA INCLUDE MACROS.ASM ENTRADA: MOV ax, DATOS MOV ds, ax display mensaje retorno ; ; **** Procedimientos **** ; retorno PROC PUSH ax MOV ax, 4C00h INT 21h POP ax RET retorno ENDP CODIGO ENDS END ENTRADA (Fichero MACROS.ASM) display MACRO mem PUSH dx PUSH ax MOV dx, offset mem MOV ah, 09h INT 21h POP ax POP dx ENDM COMPILACION. Para conseguir un programa ejecutable, el programa fuente escrito en lenguaje ensamblador, entre otras tareas, habrá que ensamblarlo y linkarlo (LINKER). Para ello el MASM 6.0 nos suministra una instrucción que nos realiza estas dos funciones: ML. ML es el ensamblador que nos suministra MASM 6.0 y se encuentra (normalmente) en el subdirectorio: \MASM\BIN. El ensamblaje de un programa fuente escrito en ensamblador se realiza de la siguiente forma: ML [\opción] Nombre_Programa.ASM Si el fichero no se encuentra en el mismo directorio que el ensamblador, hay que poner el PATH donde se encuentra el fichero fuente. Para visualizar las opciones con las que cuenta el ensamblador basta con ejecutar: ML /? Algunas de estas opciones son: - /AT: Habilita el modelo TINY (para ficheros .COM). - /c: Ensambla sin Linkar (LINK). - /Zi: Añade información simbólica para el BEBUG. - /Zm: Habilita la compatibilidad con MASM 5.10. Si se quiere ejecutar el MASM 6.0 desde un entorno gráfico, se puede ejecutar un programa que hay en el directorio \MASM\BIN y que se llama PWB. Si fuera necesario la ejecución de LINK este se encuentra en el directorio \MASM\BINB. |
|
|