Descarga la aplicación para disfrutar aún más
Esta es una vista previa del archivo. Inicie sesión para ver el archivo original
laboratorio/Prácticas/Práctica DEBUG.pdf LABORATORIO DE PROGRAMACIÓN EN LENGUAJE ENSAMBLADOR x86-16bits Programa DEBUG: ensamblado y trazado de instrucciones Objetivo El primer objetivo de esta práctica es familiarizarse con el potente programa DEBUG. Entre las numerosas facilidades que nos ofrece esta aplicación se encuentra la de ensamblar una secuencia de instrucciones y la posibilidad de ejecutar dicha secuencia paso a paso permitiéndonos examinar todo el contexto (registros, banderas de estado y memoria) en cada parada. El segundo objetivo es comprender la diferencia entre un programa y una secuencia de instrucciones ensamblada. Efectivamente, el código máquina de una secuencia de instrucciones no constituye por sí solo una imagen válida de un ejecutable. El programa DEBUG El programa DEBUG es un depurador, una herramienta destinada a facilitarnos encontrar errores o ayudarnos a mejorar el funcionamiento de una aplicación durante su desarrollo. Para ello, un depurador muestra el contenido de la memoria y de los registros en cualquier instante de la ejecución de un programa. Además, nos permite modificar el contenido de secciones completas de memoria o dar valor a variables o registros. El depurador DEBUG cuenta con la capacidad adicional de permitirnos ensamblar secuencias de instrucciones. Luego, ese código ensamblado, podemos depurarlo, ejecutarlo e incluso salvarlo en un fichero. Las funciones que puede realizar DEBUG se enumeran a continuación: cargar la imagen de un ejecutable mostrar el código fuente de un programa junto con su código máquina y la dirección de cada instrucción mostrar el contenido de los registros y las banderas de estado ejecutar o trazar paso a paso programas o secuencias de instrucciones introducir valores en memoria o en registros buscar valores binarios o ASCII en memoria mover bloques de memoria de un lugar a otro rellenar bloques de memoria acceder en lectura y escritura tanto a ficheros como a sectores de disco ensamblar secuencias de instrucciones admite scripts Depuración de un programa Para depurar un programa existente, invocamos DEBUG pasándole como argumento el nombre del programa: C:>debug programa.exe Hay que indicar que DEBUG es un depurador a nivel de ensamblador. Esto significa que el código fuente que muestra es siempre lenguaje ensamblador independientemente del lenguaje con el que se haya escrito el código fuente original. Es decir, lo que hace es desensamblar el código de la imagen del ejecutable. Para ver la memoria y los registros del procesador o para ensamblar una secuencia de instrucciones, invocamos DEBUG sin argumentos. C:>debug PROGRAMA DEBUG: ENSAMBLADO Y TRAZADO DE INSTRUCCIONES Comando ? El comando ? (ayuda) muestra el listado completo de comandos disponibles y un recordatorio de los argumentos que admiten tal y como se puede ver a continuación. -? assemble A [dirección] compare C intervalo de direcciones dump D [intervalo] enter E dirección [lista] fill F lista de rango go G [=dirección] [direcciones] hex H valor1 valor2 input I puerto load L [dirección] [unidad] [primer sector] [número] move M intervalo de direcciones name N [ruta] [lista de argumentos] output O byte de puerto proceed P [=dirección] [número] quit Q register R [registro] search S lista de rango trace T [=dirección] [valor] unassemble U [intervalo] write W [dirección] [unidad] [primer sector] [número] allocate expanded memory XA [N.páginas] deallocate expanded memory XD [identificador] map expanded memory pages XM [páginaL] [páginaP] [identificador] display expanded memory status XS Seguidamente, veremos algunos de ellos con más detalle. Comando Q El comando Q (quit) cierra el depurador DEBUG y devuelve el control al DOS. Comando A El comando A (assemble) sirve para ensamblar las instrucciones que se le pasen seguidamente. Opcionalmente se le puede pasar una dirección como argumento. La dirección se puede pasar como una base y un desplazamiento explícitos, un registro de segmento y un desplazamiento o sólo un desplazamiento que tomará como base implícita el valor de CS. Para dejar de ensamblar hay que pulsar ‘enter’ en una línea vacía. Ejemplos: -A ensambla a partir de la posición actual -A 100 ensambla a partir de CS:0100h -A DS:500 ensambla a partir de DS:0500h -A 05FB:0100 ensambla a partir de 05FB:0100h 05FB:0100 mov ax, 10 05FB:0103 mov bx, 20 05FB:0106 add ax, bx 05FB:0108 - Comando D El comando D (dump) presenta el contenido de la memoria. Muestra los bytes de cada posición tanto en hexadecimal como en ASCII. La base por defecto, usada cuando no se especifica explicitamente, es DS. Ejemplos: -D muestra a partir de la posición actual o DS:0 si es la primera vez -D 100 muestra a partir de DS:0100h -D ES:500 muestra a partir de ES:0500h -D 05FB:0100 muestra a partir de 05FB:0100h -D 100 110 muestra desde DS:0100h hasta DS:0110h (rango) -D 100 L 20 muestra 20h bytes desde DS:0100h (lista) 2 LABORATORIO DE PROGRAMACIÓN EN ENSAMBLADOR X86-16BITS Comando F El comando F (fill) rellena un rango de memoria con un valor o con una lista de valores. Ejemplos: -F 100 400, 0 rellena el rango entre 100 y 400 con ‘0’ -F 100 110, CF rellena el rango entre 100 y 110 con 0CFh -F 100 L20 ‘A’ rellena 20 bytes a partir de 100 con el carácter ‘A’ -F 100 110 ‘AB’ rellena el rango entre 100 y 110 con ‘AB’ Comando G El comando G (go) ejecuta el programa que se está depurando o bien ejecuta lo que hay en memoria a partir de una posición dada. También se pueden insertar hasta 10 puntos de ruptura. Ejemplos: -G ejecuta el programa desde la posición en curso hasta el final -G 200 ejecuta desde la posición en curso hasta la de desplazamiento 200 -G=100 ejecuta desde la posición CS:100 -G=100 400 ejecuta desde la posición CS:100 hasta la de desplazamiento 400 Comando L El comando L (load) carga un fichero si ha sido declarado con el comando N o sectores del disco en caso contrario, en la posición de memoria indicada. Si no se indica dirección, se asume la CS:100. El número total de bytes leídos se expresa en BX:CX. Ejemplos: -L carga el fichero declarado con N en la posición CS:100 -L DS:100 carga el fichero declarado con N en la posición DS:100 -L 300 2 A 4 carga 4 sectores del disco C (2) a partir del 0Ah en la posición CS:300 Comando N El comando N (name) declara el fichero que se va a utilizar en combinación con los comandos L y W. Ejemplos: -N c:\codigo.bin declara el fichero de la ruta indicada Comando R El comando R (register) muestra el contenido de los registros así como la siguiente instrucción a ejecutar. También puede mostrar el contenido de un registro individual y, en ese caso, permite cambiar su valor. Ejemplos: -R muestra el contenido de todos los registros -R BX muestra el contenido del registro BX y espera por un nuevo valor -R IP muestra el contenido del registro IP y espera por un nuevo valor -R F muestra el contenido de los flags y espera por un nuevo valor La tabla siguiente muestra los códigos nominales que identifican los valores que adoptan los flags. flag a 1 flag a 0 OV = desbordamiento NV = no desbordamiento DN = dirección decreciente UP = dirección creciente EI = interrupción habilitada DI = interrupción deshabilitada NG = signo negativo PL = signo positivo ZR = cero NZ = no cero AC = acarreo auxiliar NA = no acarreo auxiliar PO = paridad impar PE = paridad par CY = acarreo NC = no acarreo 3 PROGRAMA DEBUG: ENSAMBLADO Y TRAZADO DE INSTRUCCIONES Comando T El comando T (trace) ejecuta las instrucciones en modo paso a paso mostrando en pantalla el contenido de los registros después de la ejecución de cada una. A partir de la dirección en curso, puede ejecutar una sola instrucción o un conjunto de ellas. Ejemplos: -T ejecuta la siguiente instrucción -T 10 ejecuta las 16 instrucciones siguientes -T=200 10 ejecuta las 16 instrucciones que se encuentran a partir de CS:200 Comando U El comando U (unassemble) desensambla el contenido de memoria escribiendo los mnemónicos correspondientes. Si no se le pasa ninguna dirección, comienza en CS:100 o en la última posición en la que se usó. Ejemplos: -U desensambla a partir de CS:100 (si es la primera vez que se invoca) -U 500 desensambla a partir de CS:500 -U 200 500 desensambla entre CS:200 y CS:500 Comando W El comando W (write) escribe un bloque de memoria en un fichero si ha sido declarado con el comando N o en sectores del disco en caso contrario. El tamaño del bloque de memoria se ha de expresar en BX:CX. La dirección de comienzo es CS:100 si no se expresa explícitamente. Ejemplos: -N c:\codigo.bin declara “codigo.bin” como fichero por defecto -R BX (0) -R CX (100) establece como tamaño 256 bytes (BX:CX=0:100h) -W escribe en “c:\codigo.bin” los 256 bytes a partir de CS:100 -W 300 2 A 4 escribe 4 sectores del disco C (2) a partir del sector 0Ah con el contenido de la memoria a partir de la posición CS:300 La escritura directa en sectores es extremadamente peligrosa si no se hace cuidadosamente ya que podría borrar el disco completo. Procesando scripts El programa DEBUG admite secuencias de comandos escritos en ficheros de texto (ficheros de script) que se le pasan mediante comandos de redireccionamiento (<). Por ejemplo, supongamos que queremos ensamblar a partir de la dirección CS:100 una serie de instrucciones. Escribiríamos el fichero de script miscript.txt de esta manera: A 100 mov ax, 10 mov bx, 20 add ax, bx Q Obsérvese como finalizamos la secuencia de comandos con el comando Q (quit) para devolver el control al DOS. Véase también como, tras la serie de instrucciones, se añade un retorno de carro para que finalice el ensamblado. Para pasar el script al DEBUG haremos lo siguiente: C:>debug < miscript.txt 4 LABORATORIO DE PROGRAMACIÓN EN ENSAMBLADOR X86-16BITS Prácticas A) Creación de una secuencia de código con DEBUG Utilizando el depurador DEBUG vamos a crear una secuencia de código. La secuencia de código dispondrá de una pequeña área de datos en la cabecera (posiciones bajas de memoria) y ejecutará algunas operaciones de proceso y de transferencia. La secuencia se salvará como un fichero de nombre ‘codigo.bin’. Hay que recordar que ese fichero no es un ejecutable ya que no cuenta con una cabecera reconocible por parte del sistema operativo. Realizaremos las siguientes tareas: Comenzamos invocando el comando R y observando el estado de los registros. -R Declaramos un fichero por defecto para las transferencias con el sistema de ficheros utilizando el comando N -N c:\codigo.bin Volcamos el contenido de 16 bytes de memoria a partir de DS:100 invocando el comando D. -D 100 L 10 Rellenamos los 16 bytes de memoria a partir de DS:100 con 0 invocando el comando F. Estos 16 bytes serán la cabecera de la secuencia de código. -F 100 L 10 0 Comprobamos que la memoria se ha rellenado como queríamos usando el comando D de nuevo. -D 100 L 10 Ensamblamos con el comando A el siguiente código a partir de CS:110: -A 110 CS:0110 mov ax, cs 1 CS:0112 add ax, 10 CS:0115 mov ds, ax CS:0117 mov al, 11 CS:0119 mov bl, 22 CS:011B xchg bh, bl CS:011D add ax, bx CS:011F mov [0000], al CS:0122 mov [0001], ax CS:0125 neg cx CS:0127 sub cx, [0003] CS:012B push cx CS:012C pop dx CS:012D mov si, 4 CS:0130 inc si CS:0131 mov [si], ch CS:0133 dec dx CS:0134 mov di, 6161 CS:0137 mov [si+1], di CS:013A dec si CS:013B mov ax, [si] CS:013D Cargamos BX con 0 usando el comando R. -R BX BX 0000 :0 Cargamos CX con 3D (tamaño del código y la cabecera de datos) usando el comando R. -R CX CX 0000 :3D Escribimos el bloque de memoria definido como secuencia de código en el fichero ‘codigo.bin’ utilizando el comando W. El comando sin argumentos toma como comienzo CS:100. -W 1 El comando A presenta en cada línea la dirección CS:desplazamiento con los valores que tenga en cada caso. 5 PROGRAMA DEBUG: ENSAMBLADO Y TRAZADO DE INSTRUCCIONES Desensamblamos el contenido de memoria a partir de CS:100 y a partir de CS:110 con el comando U. Veremos que el área de código, rellena con 0, también admite una interpretación como código. -U 100 … -U 110 La secuencia de comandos se puede escribir en un fichero de script para pasársela a DEBUG posteriormente. La salida del depurador se puede salvar en un fichero de texto. Este sistema puede ser más cómodo que usar DEBUG directamente ya que, en caso de error, no hay que volver a empezar el ensamblado completo del código. B) Trazado de la secuencia de código generada Utilizando nuevamente DEBUG, se pide trazar la secuencia de código generada anteriormente. Entendemos por trazar el hecho de ejecutar paso a paso una serie de instrucciones teniendo acceso en cada detención a los registros del procesador, a su estado y a la memoria del proceso. La ejecución paso a paso nos permite depurar los programas así como alcanzar una comprensión más profunda del funcionamiento de una determinada tarea con el objetivo, por ejemplo, de conseguir un mayor rendimiento del código. Para trazar el código con DEBUG utilizaremos el comando T. Cargaremos, primero, la secuencia de código utilizando los comandos N y L. Una vez en memoria, pasaremos a ejecutarla paso a paso observando cada vez las modificaciones que se hayan llevado a cabo en registros, estado y memoria. -N c:\codigo.bin -L -R IP IP 0100 :0110 -R AX=0000 BX=0000 CX=003D DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=0CB8 ES=0CB8 SS=0CB8 CS=0CB8 IP=0110 NV UP EI PL NZ NA PO NC 0CB8:0110 8CC8 MOV AX,CS -T 6 Hago que IP apunte a la primera instrucción de la secuencia de código. laboratorio/Prácticas/Práctica DEL PROGRAMA AL PROCESO_v3.pdf LABORATORIO DE PROGRAMACIÓN EN LENGUAJE ENSAMBLADOR x86-16bits De la creación del programa al proceso en ejecución Objetivo El objetivo de esta práctica es conocer y diferenciar los conceptos de programa y proceso. Aprenderemos a desarrollar un programa en ensamblador y qué secciones lo componen. Programa Un programa no es un conjunto de instrucciones solamente. Un programa es un espacio de memoria organizado en secciones bien diferenciadas entre las que no pueden faltar la sección de código, la sección de datos y la sección de pila. El programa compilado se guarda en un fichero que tiene dos partes: el binario y una cabecera con información para el sistema operativo. Las secciones de un programa Un programa requiere de varias secciones de memoria. Evidentemente, una de ellas es la que contiene las instrucciones a ejecutar. Sin embargo, también necesitamos una sección que almacene los datos y una sección para la pila. Las secciones más habituales son: Sección de código La sección de código, sección de texto o simplemente texto, es la que contiene la secuencia de instrucciones a ejecutar. Normalmente es una sección de sólo lectura aunque algunos programas se automodifican o reservan pequeños espacios para datos en esta sección. Esta sección requiere de un puntero especial (puntero de instrucción o contador de programa) que señala la posición de la siguiente instrucción a ejecutar. Sección de datos La sección de datos contiene las variables globales (aquellas accesibles desde todo el programa) y las estáticas (su tiempo de vida abarca todo el tiempo de ejecución del programa) que contienen datos iniciales (inicializadas por el programador). Es una sección de lectura y escritura aunque si una variable se declara como constante se puede alojar en una zona de solo lectura. Sección de bss La sección bss (Block Started by Symbol) contiene variables estáticas no inicializadas, es decir, cuyo valor inicial es 0. Normalmente esta sección no se almacena en el fichero imagen del ejecutable sino que es el cargador del sistema operativo quien realiza la reserva de espacio en memoria principal y el relleno con 0. Sección de heap La sección heap se usa para hacer reservas dinámicas de memoria en tiempo de ejecución. La reserva de un bloque de memoria puede liberarse o incrementarse en tiempo de ejecución. Es una sección que puede crecer y, por tanto, no debe estar limitada por otras secciones. No aparece en el fichero imagen del ejecutable. Sección de pila La sección pila implementa un área de memoria con un tipo de acceso LIFO (Last Input First Output) utilizada en el manejo de procedimientos (subrutinas) que sirve para almacenar temporalmente los argumentos y variables locales. Esta sección requiere de un puntero especial (puntero de pila) que indica la posición de memoria de la cima de la pila. Adicionalmente, se suele utilizar otro puntero especial (puntero de marco de pila) que sirve para referenciar los argumentos y variables locales propios del procedimiento (subrutina) en curso. Es habitual que la sección de pila y la sección de heap crezcan la una contra la otra de manera que, si el programa no ha sido bien diseñado, una sección puede llegar a sobrescribir los datos de la otra. DE LA CREACIÓN DEL PROGRAMA AL PROCESO EN EJECUCIÓN La cabecera de un programa La cabecera almacena información para el cargador del sistema operativo. Algunos de los datos que proporciona esta cabecera son: tamaño de la cabecera tamaño del fichero binario tabla de direcciones de memoria absolutas máxima y mínima cantidades de memoria requeridas valores iniciales de los punteros de instrucción y de pila ¿Qué es la tabla de direcciones de memoria absolutas? La imagen de un ejecutable se implementa en forma de fichero reubicable, es decir, que ha de funcionar igual sea cual sea el rango de posiciones de memoria principal que se le asignen. Todas aquellas referencias a posiciones de memoria relativas a la posición en curso no tienen problema de ambigüedad. En cambio, todas aquellas referencias absolutas son desconocidas a priori. Por ejemplo, el comienzo de la sección de datos puede ubicarse en cualquier posición de memoria principal y no se conocerá con precisión hasta que el sistema operativo no asigne un mapa de memoria al proceso. Para solucionar este problema, lo que hacemos es referenciar las posiciones absolutas respecto al comienzo de la imagen del ejecutable y confeccionar una tabla con todas las posiciones de memoria absolutas que han de corregirse. Dicha tabla se guarda en la cabecera de la imagen del ejecutable. Una vez que el cargador conoce el rango del mapa de memoria asignado al proceso, modifica todos los valores de las direcciones absolutas de memoria sumando la posición de memoria inicial del proceso con la posición relativa que aparece en la imagen del ejecutable. Veamos un ejemplo. Supongamos que la sección de datos comienza en la posición 1.024B respecto al comienzo de la imagen del ejecutable y supongamos que dicha imagen se va a cargar en la posición de memoria principal 3.456B. En consecuencia, la sección de datos comienza en la posición 3.456B + 1.024B = 4.480B Lo mismo sucede con los punteros de instrucción y de pila. El cargador del sistema operativo calculará los valores efectivos de ambos punteros una vez se conoce el mapa de memoria asignado. Formatos de cabeceras Existen diferentes formatos para las cabeceras de las imágenes de los ejecutables. A continuación se presentan los más importantes: a.out (assembler output): formato original utilizado en entornos UNIX; obsoleto, evolucionó a COFF COFF (Common Object File Format): formato para ejecutables, código objeto y librerías compartidas en entorno UNIX; reemplazado UNIX por ELF sirvió de base para formatos del entorno Windows ELF (Executable & Linkable Format): formato para ejecutables, código objeto, librerías compartidas y volcado de memoria en entorno UNIX; admite una gran variedad de secciones en los ejecutables MZ (Mark Zbikowski): utilizado en el entorno DOS; evolucionó dando lugar a varias extensiones PE (Portable Executable): formato para ejecutables, código objeto, librerías compartidas (DLL), archivos de fuentes y otros usos en entorno Windows; es una evolución de COFF Proceso Un proceso es un programa en ejecución, es decir, una secuencia de instrucciones con una serie de recursos asociados y un estado. Los recursos asociados son el contador de programa, los datos de memoria, la pila y su puntero, los registros y operadores de la ruta de datos y los recursos de E/S (puertos, descriptores de ficheros, etc.). El estado guarda información del punto de ejecución, situación de procesamiento, propietario, privilegios, comunicaciones, mecanismo de devolución del control al sistema operativo, etc. El estado se almacena de diferentes maneras dependiendo de la arquitectura. Creación de un proceso El sistema operativo toma la imagen de un ejecutable, actualiza sus direcciones absolutas e inicializa los datos que lo requieran, copia la imagen actualizada en memoria principal, asigna recursos y transfiere el control a la primera instrucción. 2 LABORATORIO DE PROGRAMACIÓN EN ENSAMBLADOR X86-16BITS Finalización de un proceso Un proceso puede terminar de manera normal devolviendo el control al sistema, puede ser abortado por otro proceso o puede finalizar por error. Estados de un proceso Un proceso puede estar en ejecución, bloqueado (a la espera de algún evento externo) o listo (esperando a disponer de los recursos de ejecución del procesador). Desarrollo de programas en ensamblador x86-16bits Los ficheros ejecutables tienen extensión .EXE y se ajustan al formato MZ, es decir, la cabecera del fichero se ajusta a dicho formato MZ. El binario representa todos los segmentos declarados incluyendo la pila. Dependiendo del tipo de declaración, los segmentos pueden estar solapados parcial o totalmente o no estar solapados en absoluto. El tamaño del ejecutable no está limitado a 64KB. El desarrollo de un programa .EXE parte de un fichero de código fuente en ensamblador (programa.asm) que se ensambla con masm5.1 dando lugar a un fichero de módulo objeto (programa.obj) que finalmente se enalza (linka) con link generando el fichero ejecutable (programa.exe). programa.asm programa.obj programa.exe MASM programa.asm LINK programa.obj Diseño de secciones en ensamblador x86-16bits El desarrollo de programas con lenguajes de alto nivel confía al compilador el diseño de las secciones de un programa. Por el contrario, el desarrollo de programas en ensamblador x86-16bits permite controlar totalmente este diseño si se considera necesario (definición completa de segmentos) o bien permitir que el programa ensamblador realice ese diseño de una manera transparente al programador (definición simplificada de segmentos). Definición completa de segmentos A continuación se muestra el “esqueleto” de varios programas que siguen la definición completa de segmentos. Se comenta cada uno de ellos al margen. 3 DE LA CREACIÓN DEL PROGRAMA AL PROCESO EN EJECUCIÓN 1 Definición completa de segmentos Segmentos separados Salida mediante INT 21h – servicio 4Ch ASSUME CS:codigo, DS:datos, SS:pila ;-------------------------------------------- ; segmento de datos datos SEGMENT // DECLARACIÓN DE DATOS // datos ENDS ;-------------------------------------------- ; segmento de pila pila SEGMENT STACK // DECLARACIÓN DEL TAMAÑO DE LA PILA // DB 256 DUP(?) ; pila de 256 bytes pila ENDS ;-------------------------------------------- ; segmento de código codigo SEGMENT inicio: MOV AX, DATOS ;inicializamos el MOV DS, AX ;segmento de datos // CÓDIGO DEL PROGRAMA // MOV AX, 4C00h ;devolver el control INT 21h ;al MS-DOS codigo ENDS ;-------------------------------------------- ; indicamos al programa ensamblador dónde ; comienza el código del programa ; sirve para dar valor a CS:IP END inicio Se declara el comienzo de cada segmento mediante una etiqueta y la directiva SEGMENT. Se declara el final con la misma etiqueta seguida de ENDS. El orden en el que se declaren será el orden en el que aparezcan en la imagen del ejecutable. Siempre tiene que haber un segmento STACK (directiva SEGMENT seguida del operando STACK). En caso contrario el linker emitirá un error. La directiva ASSUME indica qué registro de segmento sirve para direccionar cada segmento. El de código necesariamente debe usar CS. El código fuente finaliza con la directiva END seguida de la etiqueta que marca el comienzo del código (inicio en este ejemplo). Esto sirve para que CS:IP apunte a la dirección de arranque. El segmento de código contiene la secuencia de instrucciones. Es muy importante que comience asignando valor al segmento de datos ya que si no se hace, no podrán referenciarse los datos. Existen otras maneras de realizar la declaración completa de segmentos, por ejemplo, solapando los segmentos con el fin de minimizar el tamaño de los ejecutables. 4 LABORATORIO DE PROGRAMACIÓN EN ENSAMBLADOR X86-16BITS Definición simplificada de segmentos La definición simplificada de segmentos deja al programa ensamblador la tarea de diseño de los segmentos. Se invoca con la directiva DOSSEG. Los segmentos se declaran con las directivas .DATA, .CODE, .STACK (seguido del tamaño), etc. 1 Definición simplificada de segmentos 2 Definición simplificada de segmentos Sin segmento de datos (datos en código) dosseg .model small .stack 100h .data // DECLARACIÓN DE DATOS // .code inicio: mov ax, @data mov ds, ax // CÓDIGO DEL PROGRAMA // mov ah, 4Ch int 21h end inicio dosseg .model small .stack 100h .code inicio: jmp ppio // DECLARACIÓN DE DATOS // ppio: mov ax, @code ;ojo, no @data mov ds, ax // CÓDIGO DEL PROGRAMA // mov ah, 4Ch int 21h end inicio Carga y finalización del proceso bajo MS-DOS Para que el programa se convierta en proceso es necesario que el sistema operativo tome la imagen ejecutable, calcule y escriba las direcciones absolutas (tabla de realocación en el entorno MS-DOS), asigne recursos y transfiera el control al proceso. El estado del proceso de salva en un área de memoria contigua al binario conocida como PSP (Program Segment Prefix). El PSP tiene un tamaño de 256B = 100hB. Como se ha indicado, para cargar los ficheros .EXE el sistema operativo debe actualizar las direcciones absolutas anotadas en la tabla de realocación sumando a cada valor de la tabla la dirección de comienzo del proceso. En el momento en el que el sistema transfiere el control del proceso, los punteros adoptan estos valores: DS y ES apuntan al PSP CS e IP toman el valor especificado por la directiva END SS apunta al segmento de pila SP toma el valor del tamaño de la pila Puesto que el sistema operativo asigna a DS y ES el puntero del PSP, es responsabilidad del programador comenzar el código asignando a DS (y ES si se usa) el valor correcto. Para finalizar el proceso se utiliza el servicio 4Ch de la interrupción 21h, tal y como podemos observar en los ejemplos de declaración de segmentos. cargador rango de memoria libre disponible PSP programa memoria en cabecera .EXE .COM 5 DE LA CREACIÓN DEL PROGRAMA AL PROCESO EN EJECUCIÓN Prácticas A) Creación de un ejecutable .EXE siguiendo la definición completa de segmentos. Queremos crear un ejecutable que contenga la sencilla secuencia de operaciones aritméticas que se propone a continuación: xor ax, ax mov al, operando1 add al, operando2 mov resultado, ax La declaración de datos será la mostrada a continuación. Se declaran tres variables. Dos de tamaño byte para los operandos y una de tamaño word para el resultado. operando1 DB 10h operando2 DB 20h resultado DW 0000h Crea un programa que incorporen este código usando el “esqueleto” propuesto en esta práctica para desarrollar ejecutables usando la definición completa de segmentos. Una vez creado, pásaselo a DEBUG y comprueba que realiza las tareas correctamente trazando la ejecución del código. B) Creación de un ejecutable .EXE siguiendo la definición simplificada de segmentos. Crea 2 programas usando los dos “esqueletos” propuestos en esta práctica para desarrollar ejecutables usando la definición simplificada de segmentos. La tarea que vamos a programar es la escritura de un mensaje en la pantalla. Para ello declaramos los datos siguientes: mensaje DB "Hola a todos",13,10 ;Mensaje a escribir longitud EQU $ - mensaje ;No es declaración; es etiqueta de nº entero El código invocará al sistema operativo de la siguiente manera: MOV CX, longitud MOV DX, OFFSET mensaje MOV BX, 1 MOV AH, 40h INT 21h 6 laboratorio/Prácticas/Práctica SERVICIOS INT 21h - E-S CARACTERES.pdf LABORATORIO DE PROGRAMACIÓN EN LENGUAJE ENSAMBLADOR x86-16bits Interrupciones del sistema. Servicios de entrada/salida de caracteres (INT 21h) Objetivo El objetivo de esta práctica es conocer y aprender a utilizar los servicios de entrada/salida de caracteres que ofrece la interrupción del sistema operativo INT 21h. Estos servicios toman como entrada el teclado y como salida la pantalla. Existen servicios diferenciados para trabajar sobre caracteres individuales o sobre cadenas de caracteres. Funciones de entrada de caracteres de la INT 21h La entrada se realiza desde el teclado. Disponemos de varios servicios para hacer la lectura de un carácter. Se diferencian en función de si la entrada es bloqueante o no y de si se atiende o no la combinación de teclas Ctrl-Break. Entrada bloqueante Una entrada/salida es bloqueante si el proceso principal se detiene hasta que se satisfaga alguna condición (normalmente hasta que los datos se hayan leído o escrito). Será no bloqueante si el proceso principal no se detiene. En el caso que nos ocupa, un servicio de lectura de carácter es bloqueante si espera hasta que se lea algún carácter. Será no bloqueante si lee el buffer de teclado devolviendo o un código de carácter o 0 si no hay carácter. El uso de un servicio bloqueante o no bloqueante depende de lo que necesite el programador en cada caso. En ocasiones será conveniente detener la ejecución del programa en tanto no haya un carácter de entrada mientras que en otros momentos bastará con comprobar si hay o no un carácter disponible. Combinación Ctrl-Break La combinación de teclas Ctrl-Break (Ctrl-C) se puede usar para invocar una interrupción especial conocida como break de teclado (interrupción BIOS INT 1Bh) que sirve para terminar el proceso en curso. La rutina de atención a la INT 1Bh por defecto sólo contiene una instrucción IRET, es decir, que no realiza ninguna tarea. Sin embargo, se puede cambiar dicha rutina para que realice otra tarea. Existen servicios de entrada de carácter que atienden la interrupción de break de teclado y otros que no. Servicio 01h – entrada bloqueante con eco y atención a Ctrl-Break El servicio 01h de la INT 21h espera a que se pulse una tecla y la escribe en la pantalla (lectura con eco) comprobando si es Ctrl-Break en cuyo caso dispara la interrupción de break de teclado que suele finalizar el programa en curso. El código ASCII del carácter se devuelve en el registro AL. argumentos: ah = 01h valores devueltos: al = código ASCII leído Servicio 06h – DL = FFH – entrada no bloqueante sin eco y omisión de Ctrl-Break El servicio 06h de la INT 21h puede ser de entrada o salida. Si DL es igual a FFh, lee un carácter del buffer del teclado sin eco y omitiendo un posible Ctrl-Break. argumentos valores devueltos ah = 06h dl = FFh (lectura de consola) zf = 0 si hay carácter y 1 si no hay carácter disponible al = código ASCII leído Servicio 07h – entrada bloqueante sin eco y omisión de Ctrl-Break El servicio 07h de la INT 21h espera a que se pulse una tecla sin eco y omitiendo un posible Ctrl-Break. El código ASCII del carácter se devuelve en el registro AL. argumentos: ah = 07h valores devueltos: al = código ASCII leído Servicio 08h – entrada bloqueante sin eco y atención a Ctrl-Break El servicio 08h de la INT 21h espera a que se pulse una tecla sin eco y comprobando si es Ctrl-Break en cuyo caso dispara la interrupción de break de teclado. El código ASCII del carácter se devuelve en el registro AL. argumentos: ah = 08h valores devueltos: al = código ASCII leído INTERRUPCIONES DEL SISTEMA. SERVICIOS DE ENTRADA/SALIDA DE CARACTERES (INT 21H) 2 Servicio 0Bh – lee el estado del teclado con atención a Ctrl-Break El servicio 0Bh lee el estado del teclado con atención a Ctrl-Break. El registro AL devuelve el estado. argumentos: ah = 0Bh valores devueltos: al = FFh si hay carácter; 0 en caso contrario Servicio 0Ch – borra el buffer del teclado e invoca un servicio de entrada de carácter El servicio 0Ch de la INT 21h borra el buffer del teclado e invoca un servicio de entrada de carácter de los explicados más arriba (01h, 06h, 07h, 08h) o de entrada de cadenas que se verá seguidamente (0Ah). El registro AL se utiliza para seleccionar el servicio a invocar y devuelve el valor propio de dicho servicio. argumentos valores devueltos ah = 0Ch al = número de servicio a invocar al = valor devuelto por el servicio invocado Funciones de salida de caracteres de la INT 21h Como hemos indicado, la salida se realiza sobre la pantalla. Disponemos de un único servicio para escribir un carácter en la pantalla con la INT 21h. Es el siguiente: Servicio 02h – salida de carácter El servicio 02h presenta un carácter en pantalla. El registro DL contiene el ASCII del carácter a escribir: argumentos valores devueltos ah = 02h dl = código ASCII del carácter a escribir al = código ASCII escrito Servicio 06h – DL ≠≠≠≠ FFH – salida de carácter Este servicio puede ser de entrada o salida. Si DL es distinto de FFh, escribe el carácter codificado en DL. argumentos valores devueltos ah = 06h dl = código ASCII del carácter a escribir (≠FFh) al = código ASCII escrito Funciones de entrada/salida de cadenas de caracteres de la INT 21h Una cadena de caracteres (string en inglés) es una secuencia ordenada de longitud arbitraria de códigos alfanuméricos. El sistema de codificación puede ser ASCII, EBCDIC o UNICODE. Físicamente las cadenas se pueden almacenar colocando cada código en posiciones consecutivas de memoria o enlazando carácter a carácter. El primer sistema es el más habitual y eficiente. Para diferenciar una cadena de otra, podemos reservar espacio en memoria de tamaño fijo, pero este método es ineficiente ya que desaprovecha espacio de almacenamiento. Habitualmente, lo más eficiente es manejar espacios de almacenamiento de longitud variable utilizando alguno de estos métodos: • indicando el comienzo y final de cada cadena mediante un carácter separador • indicando la longitud de la cadena antes de la misma • indicando el final de la cadena mediante un carácter terminador En el caso de los servicios de entrada/salida de cadenas de la interrupción del sistema operativo INT 21h se utiliza el almacenamiento consecutivo en memoria de los códigos alfanuméricos y se permite la longitud arbitraria de la cadena gracias al carácter terminador ‘enter’ para entrada de cadena y ‘$’ para salida de cadena. Servicio 0Ah – entrada de cadena de caracteres El servicio 0Ah de la INT 21h lee una secuencia de caracteres desde el teclado y los almacena en memoria hasta que se pulse la tecla ‘enter’. El área de memoria es una estructura de datos con 3 campos: el primer byte es el tamaño máximo permitido de la cadena incluido el código de la tecla ‘enter’, el segundo byte recibirá el número de caracteres leídos sin contar el ‘enter’ y el tercer campo es el buffer de memoria en el que se almacenará la cadena incluyendo el ‘enter’. Evidentemente, el tamaño del buffer deberá coincidir con el valor del primer campo. El puntero del área de memoria se pasa como parámetro en DS:DX. LABORATORIO DE PROGRAMACIÓN EN ENSAMBLADOR X86-16BITS 3 argumentos valores devueltos ah = 0Ah ds:dx = puntero del área de memoria - número de caracteres leídos - cadena Ejemplo: .data cadena DB 11,?,11 DUP(?) ;reserva para una cadena de 10 caracteres .code mov ax, @DATA mov ds, ax lea dx, cadena mov ah, 0Ah int 21h Servicio 09h – salida de cadena de caracteres El servicio 09h de la INT 21h escribe en la pantalla una cadena de caracteres almacenada en memoria y finalizada con el carácter ‘$’. El puntero del área de memoria se pasa como parámetro en DS:DX. argumentos valores devueltos ah = 09h ds:dx = puntero de la cadena al = 24h Ejemplo: .data cadena DB ‘Hola mundo$’ .code mov ax, @DATA mov ds, ax lea dx, cadena mov ah, 09h int 21h Funciones de entrada/salida de dispositivos de la INT 21h El sistema operativo proporciona una serie de servicios a través de la INT 21h para hacer transferencias de caracteres con dispositivos que bien pueden ser ficheros o la consola. Por consola entendemos la entrada y salida estándar, es decir, la entrada por teclado o stdin y la salida por pantalla o stdout. Estos servicios permiten crear, borrar, abrir, cerrar, leer, escribir y realizar otras acciones, sobre ficheros. En este momento sólo estamos interesados en la entrada/salida por consola: • leer fichero o consola: servicio 3Fh • escribir fichero o consola: servicio 40h Estos servicios representan una alternativa a los de entrada/salida de cadenas ya que no utilizan carácter terminador en las cadenas sino que trabajan con el número de caracteres a transferir como argumento. Servicio 3Fh – lectura de dispositivo El servicio 3Fh de la INT 21h lee caracteres de un dispositivo. Si el dispositivo es un fichero, se le pasa el manejador del fichero (handler) y el número de caracteres a leer. Si el dispositivo es la consola, el número de manejador es el 1 y se lee el teclado hasta que aparezca el carácter CR (Carriage Return) al pulsar la tecla ‘enter’. argumentos valores devueltos ah = 3Fh bx = manejador del dispositivo (1 si consola) cx = número de caracteres a leer ds:dx = puntero del área de memoria cf = 0 si no hay error y 1 si se produce error ax = número de caracteres leídos o código de error en su caso INTERRUPCIONES DEL SISTEMA. SERVICIOS DE ENTRADA/SALIDA DE CARACTERES (INT 21H) 4 Servicio 40h – escritura en dispositivo El servicio 40h de la INT 21h escribe un número de caracteres especificado como argumento en un dispositivo. Si el dispositivo es la consola, el número de manejador es el 1 y se escribe en pantalla. El puntero del área de memoria se pasa como parámetro en DS:DX. argumentos valores devueltos ah = 40h bx = manejador del dispositivo (1 si consola) cx = número de caracteres a escribir ds:dx = puntero del área de memoria cf = 0 si no hay error y 1 si se produce error ax = número de caracteres escritos o código de error en su caso Prácticas A) Realiza un programa que capture 4 caracteres numéricos y almacene el valor numérico en una variable de tipo word. Los caracteres numéricos del 0 al 9 se codifican en ASCII del 30h al 39h (véase tabla ASCII más abajo). Esto hace que sea muy sencillo su detección y conversión a entero. Cada vez que no se introduzca un carácter numérico, el programa emitirá un mensaje de error y volverá a comenzar. Para calcular el valor numérico, acumularemos los resultados parciales sobre el registro DX inicialmente a cero. Por cada carácter, multiplicamos DX por 10 y le sumamos la nueva cifra. Una vez finalizado la captura de las 4 cifras ABCD, tendremos: DX = ((((DX * 10 + A) *10 + B) * 10) + C *10) + D B) Realiza un programa que emita un mensaje por pantalla en función de la tecla que se pulse. Programa un bucle que emita un mensaje en pantalla de manera indefinida. El mensaje cambiará en función de la tecla que se pulse. Si se pulsa ‘F’ el programa finaliza. La lectura del teclado será no bloqueante. C) Realiza un programa lea 2 caracteres hexadecimales y almacene su valor entero en una variable de tipo byte. Sólo se hará eco de los caracteres hexadecimales. La entrada se programará sin eco. Una vez validado el carácter leído, se hará eco. Si no corresponde a un carácter hexadecimal se seguirá esperando un nuevo carácter. Una vez almacenada la variable, se mostrará en pantalla tomándola como ASCII. Son caracteres hexadecimales: ‘0’ – ‘9’, ‘a’ – ‘f’ y ‘A’ – ‘F’. Para obtener el valor numérico de un carácter hexadecimal codificado en mayúsculas ASCII basta con restar ‘A’ – 10, es decir, restarle su código ASCII y sumar su valor numérico en decimal. D) Realiza un programa que pida una cadena de un máximo de 10 caracteres, convierta las mayúsculas a minúsculas y viceversa, y presente la nueva cadena en pantalla. En la tabla ASCII vemos que los caracteres de las mayúsculas y de las minúsculas sólo se diferencias en el bit del peso 25. Basta con complementar dicho bit para que el carácter cambie de tamaño. Usaremos el servicio 0Ah para leer la cadena y el servicio 09h o el 40h para presentar la nueva cadena. laboratorio/Teoría de laboratorio/01 - Arquitectura software x86-16bits.pdf 1 Arquitectura software x86-16bits 1/47© R af ae l R ic o Ló pe z Índice 1. Organización interna 2. Segmentación de memoria 3. Modos de direccionamiento 4. Formato de instrucciones Arquitectura software x86-16bits 2/47© R af ae l R ic o Ló pe z ¿Qué es arquitectura software? • Es el conjunto de atributos que ve el programador � …o que ve el compilador, como generador automático de código • Es el “contrato” entre en fabricante del procesador y el programador • No requiere correspondencia real con la capa física • La arquitectura software x86-16bits data de 1978 � Típico repertorio CISC 2 Arquitectura software x86-16bits 3/47© R af ae l R ic o Ló pe z 1. Organización interna PROPÓSITO GENERAL015 Puntero a la cima de la pilaSPPuntero de pila Destino en manejo de cadenasDIÍndice destino Fuente en manejo de cadenasSIÍndice fuente Puntero a dirección base (pila)BPPuntero base Producto, división y E/SDLDHDatos Contador de bucles, desplazamientos, rotaciones y repetición de cadenasCLCHContador Puntero a dirección base (datos)BLBHBase Producto, división, E/S y transferencias optimizadasALAHAcumulador AX BX CX DX Arquitectura software x86-16bits 4/47© R af ae l R ic o Ló pe z 1. Organización interna Registros de propósito general: • Almacenamiento temporal de datos • Algunos se acceden como palabra (16 bits) o como byte � Registro X � Registro L y H • Usos dedicados y limitaciones • Modelo híbrido (acumulador y banco de registros) � Heredado de arquitecturas anteriores 3 Arquitectura software x86-16bits 5/47© R af ae l R ic o Ló pe z 1. Organización interna REGISTROS DE SEGMENTO015 ESSegmento extra (datos) SSSegmento de pila DSSegmento de datos CSSegmento de código • Los programas manejan diferentes áreas de memoria: �Código (texto) �Datos �Pila �Heap • Estos registros apuntan a dichas áreas de memoria Arquitectura software x86-16bits 6/47© R af ae l R ic o Ló pe z 1. Organización interna Registros de segmento: • Todas las direcciones son relativas a alguno de los registros de segmento (por defecto) • CS: la memoria de este segmento contiene instrucciones • DS: datos declarados por el programa • SS: es la pila • ES: datos extra; datos de cadenas 4 Arquitectura software x86-16bits 7/47© R af ae l R ic o Ló pe z 1. Organización interna OTROS REGISTROS015 IPPuntero de instrucción FlagsEstado Arquitectura software x86-16bits 8/47© R af ae l R ic o Ló pe z 1. Organización interna 15 paridad acarreo REGISTRO DE ESTADO acarreo auxiliar cero signo trap (paso a paso) interrupción dirección desbordamiento CPAZSTIDO 0 5 Arquitectura software x86-16bits 9/47© R af ae l R ic o Ló pe z 1. Organización interna • Acarreo: � Es 1 si el resultado de una operación genera acarreo • Paridad: � Es 1 si el resultado contiene un número par de bits a 1 • Acarreo auxiliar: � Es 1 si el resultado genera un acarreo en los 4 bits de menor peso. Se usa en aritmética BCD • Cero: � Es 1 si el resultado es cero • Signo: � Copia el bit de mayor peso del resultado �(independientemente de la interpretación del resultado) Arquitectura software x86-16bits 10/47© R af ae l R ic o Ló pe z 1. Organización interna • Trap: � Si es 1 el procesador genera una interrupción de paso a paso después de ejecutar cada instrucción • Interrupción: � Si es 1 las interrupciones serán reconocidas • Dirección: � Si es 1 las operaciones con cadenas se realizan de las posiciones altas a las bajas 6 Arquitectura software x86-16bits 11/47© R af ae l R ic o Ló pe z 1. Organización interna • Desbordamiento: � Es 1 si el resultado es demasiado grande (o pequeño) para los límites de representación con signo (en C-2) 21 −− ⊕= nn ccOF Arquitectura software x86-16bits 12/47© R af ae l R ic o Ló pe z 1. Organización interna • Flags de estado � Acarreo, paridad, acarreo auxiliar, cero, signo y desbordamiento �Describen el resultado �Se aplican a operaciones de tamaño byte (n=8) –ya sea la parte alta o la baja– o palabra (n=16) �Proporcionan códigos de condición por separado o en conjunto • Flags de control � Trap, interrupción y dirección �Afectan al modo de funcionamiento del procesador 7 Arquitectura software x86-16bits 13/47© R af ae l R ic o Ló pe z 1. Organización interna Arquitectura software x86-16bits 14/47© R af ae l R ic o Ló pe z 2. Segmentación de memoria • El mapa de memoria que “ve” el x86-16bits NO es “plano” • Los registros de 16 bits sólo pueden direccionar 216 posiciones de memoria (65.636 posiciones = 64K) • ¿Cómo alcanzar un espacio de direcciones mayor? • El acceso a memoria se realiza en segmentos de 64K 8 Arquitectura software x86-16bits 15/47© R af ae l R ic o Ló pe z 2. Segmentación de memoria • La memoria está organizada en bytes (B) • La capacidad de direccionamiento es de 1MB (220 B) • La dirección completa se consigue mediante la combinación de dos punteros: base y desplazamiento (offset): base:desplazamiento • La dirección física se calcula: base x 16 + desplazamiento Arquitectura software x86-16bits 16/47© R af ae l R ic o Ló pe z 2. Segmentación de memoria Ejemplos: • La dirección 53C2:107A es: 53C20 h x16 (x10 h) +107A h 54C9A h dirección física • La dirección B100:046C es: B1000 h x16 (x10 h) +046C h B146C h dirección física 9 Arquitectura software x86-16bits 17/47© R af ae l R ic o Ló pe z 2. Segmentación de memoria • La misma dirección física puede ser accedida con diferentes combinaciones base:desplazamiento Ejemplo: • La dirección física 7A26B h puede ser: �7A26:000B �7A00:026B �751C:50AB • Problemas de seguridad • La base (segmento) apunta a párrafos (de 16 posiciones) Arquitectura software x86-16bits 18/47© R af ae l R ic o Ló pe z 2. Segmentación de memoria • En ensamblador no se representan las direcciones como base:desplazamiento aunque si lo admiten los depuradores • Los desplazamientos llevan asociada una base por defecto • Cuando es necesario especificar la base se hace de manera simbólica (usando el nombre del registro de segmento como prefijo de la instrucción) 10 Arquitectura software x86-16bits 19/47© R af ae l R ic o Ló pe z por defectopor defectoprefijoprefijoDI SI BX BP SP IP base offset prefijopor defectoprefijoprefijo prefijopor defectoprefijoprefijo prefijoprefijopor defectoprefijo nonosíno nononosí ESDSSSCS 2. Segmentación de memoria Arquitectura software x86-16bits 20/47© R af ae l R ic o Ló pe z 2. Segmentación de memoria • Las direcciones pueden ser: � Near � Far • Near : sólo el desplazamiento; la base toma el valor en curso de la dada por defecto • Far : se requiere la especificación de la base y del desplazamiento 11 Arquitectura software x86-16bits 21/47© R af ae l R ic o Ló pe z 2. Segmentación de memoria Arquitectura software x86-16bits 22/47© R af ae l R ic o Ló pe z 2. Segmentación de memoria 12 Arquitectura software x86-16bits 23/47© R af ae l R ic o Ló pe z 3. Modos de direccionamiento • Determinan la ubicación de los operandos • Tres posibles ubicaciones: �Inmediatos (en la propia instrucción) �En registros �En memoria �(Implícitos) � no se identifican, son sobreentendidos Arquitectura software x86-16bits 24/47© R af ae l R ic o Ló pe z 3. Modos de direccionamiento • Momento en el que se actualiza el modo de direccionamiento: �Inmediatos � tiempo de ensamblado �En registros � tiempo de programación o compilación �En memoria • Absolutos � tiempo de carga • Relativos � tiempo de ejecución interviene el SO 13 Arquitectura software x86-16bits 25/47© R af ae l R ic o Ló pe z 3. Modos de direccionamiento • Clasificación de estructura de computadores: a registro base + desplazamiento base + índice + desplazamiento contador de programa puntero de pila relativo implícito indirecto a registro a memoria a página base absolutodirecto inmediato Arquitectura software x86-16bits 26/47© R af ae l R ic o Ló pe z 3. Modos de direccionamiento 3.1. Inmediato � Ejemplo: MOV AL,15h 8088/86 IP CS SS ES DS AX BX CX DX SI DI BP SP MEMORIA INSTRUCCIÓNDIRECCIÓN siguiente instrucciónXX Antes de ejecutar la instrucción 0000 0100 XX 80 15 MOV AL,15h01000 01001 01002 01003 8088/86 IP CS SS ES DS AX BX CX DX SI DI BP SP MEMORIA INSTRUCCIÓNDIRECCIÓN siguiente instrucciónXX Después de ejecutar la instrucción 0002 0100 01000 01001 01002 01003 80 15 MOV AL,15h 15 14 Arquitectura software x86-16bits 27/47© R af ae l R ic o Ló pe z 3. Modos de direccionamiento 3.2. Directo absoluto a registro � Ejemplo: MOV AX,BX 8088/86 IP CS SS ES DS AX BX CX DX SI DI BP SP MEMORIA INSTRUCCIÓNDIRECCIÓN siguiente instrucciónXX Antes de ejecutar la instrucción 0000 0100 XXXX 8B C3 MOV AX,BX01000 01001 01002 01003 7FA6 8088/86 IP CS SS ES DS AX BX CX DX SI DI BP SP MEMORIA INSTRUCCIÓNDIRECCIÓN siguiente instrucciónXX Después de ejecutar la instrucción 0002 0100 01000 01001 01002 01003 8B C3 MOV AX,BX 7FA6 7FA6 Arquitectura software x86-16bits 28/47© R af ae l R ic o Ló pe z 3. Modos de direccionamiento 3.3. Directo absoluto a memoria (nombre INTEL: directo a memoria) � Ejemplo: MOV CX,ETIQUETA 8088/86 IP CS SS ES DS AX BX CX DX SI DI BP SP MEMORIA INSTRUCCIÓNDIRECCIÓN siguiente instrucciónXX Antes de ejecutar la instrucción 0000 0100 XXXX 8B 0E MOV CX,ETIQUETA01000 01001 01002 01003 0200 01004 03234 03235 34 12 (ETIQUETA = 1234h) ED BE operando fuente 8088/86 IP CS SS ES DS AX BX CX DX SI DI BP SP MEMORIA INSTRUCCIÓNDIRECCIÓN Después de ejecutar la instrucción 0004 0100 siguiente instrucciónXX 8B 0E MOV CX,ETIQUETA01000 01001 01002 01003 01004 03234 03235 34 12 ED BE 0200 BEED 15 Arquitectura software x86-16bits 29/47© R af ae l R ic o Ló pe z 3. Modos de direccionamiento 3.4. Directo relativo a registro (nombre INTEL: indirecto a memoria) � Ejemplo: MOV[BX]+ARTICULO,AL registro base 8086/88 IP CS SS ES DS AX BX CX DX SI DI BP SP MEMORIA INSTRUCCIÓNDIRECCIÓN siguiente instrucciónXX Antes de ejecutar la instrucción 0000 0100 1000 88 87 MOV [BX]+ARTICULO, AL01000 01001 01002 01003 0500 01004 0B000 0B001 00 50 (ARTICULO = 5000h) XX operando destino XX FC XX 8086/88 IP CS SS ES DS AX BX CX DX SI DI BP SP MEMORIA INSTRUCCIÓNDIRECCIÓN Después de ejecutar la instrucción 0004 0100 siguiente instrucciónXX 88 87 01000 01001 01002 01003 01004 0B000 00 50 FC 0500 MOV [BX]+ARTICULO, AL 1000 XX XX0B001 FC Arquitectura software x86-16bits 30/47© R af ae l R ic o Ló pe z 3. Modos de direccionamiento 3.4. Directo relativo a registro (nombre INTEL: indirecto a memoria) � Ejemplo: MOV DL,VECTOR[SI] registro índice 8086/88 IP CS SS ES DS AX BX CX DX SI DI BP SP MEMORIA INSTRUCCIÓNDIRECCIÓN siguiente instrucciónXX Antes de ejecutar la instrucción 0000 0100 8A 94 MOV DL,VECTOR[SI]01000 01001 01002 01003 B000 01004 BA000 00 A0 (VECTOR = A000h) ED operando fuente XX XX 0000 8086/88 IP CS SS ES DS AX BX CX DX SI DI BP SP MEMORIA INSTRUCCIÓNDIRECCIÓN Después de ejecutar la instrucción 0004 0100 siguiente instrucciónXX 8A 94 01000 01001 01002 01003 01004 BA000 00 A0 ED B000 MOV DL,VECTOR[SI] EDXX 0000 16 Arquitectura software x86-16bits 31/47© R af ae l R ic o Ló pe z 3. Modos de direccionamiento 3.4. Directo relativo a registro (nombre INTEL: indirecto a memoria) � Ejemplo: MOV AH,[BX][SI]+ARRAY 8088/86 IP CS SS ES DS AX BX CX DX SI DI BP SP MEMORIA INSTRUCCIÓNDIRECCIÓN siguiente instrucciónXX Antes de ejecutar la instrucción 0000 0100 1000 8A 20 MOV AH,[BX][SI]+ARRAY01000 01001 01002 01003 0200 01004 06234 06235 34 12 (ARRAY = 1234h) ED XX operando fuente XX XX 2000 8088/86 IP CS SS ES DS AX BX CX DX SI DI BP SP MEMORIA INSTRUCCIÓNDIRECCIÓN j Después de ejecutar la instrucción 0004 0100 siguiente instrucciónXX 8A 20 01000 01001 01002 01003 01004 06234 34 12 ED 0200 MOV AH,[BX][SI]+ARRAY 1000 ED XX 2000 registro índice y base Arquitectura software x86-16bits 32/47© R af ae l R ic o Ló pe z 4. Formato de instrucciones • Es la codificación binaria de las instrucciones • Debe proporcionar información acerca de: � Operación a realizar � Operandos y resultado � Siguiente instrucción (secuencia implícita) • El x86-16bits cuenta con dos formatos: � Formato general � Formato especial (campo de extensión y/o prefijo) • Está diseñado para minimizar el espacio de representación 17 Arquitectura software x86-16bits 33/47© R af ae l R ic o Ló pe z 4. Formato de instrucciones 4.1. Formato general d w mod reg r/m desplazamiento o dato inmediato especifica un operando registro especifica un operando registro o memori determina el tamaño de los operandos determina el operando fuente y destino código de operación código byte 1 byte 2 byte 4byte 3 Arquitectura software x86-16bits 34/47© R af ae l R ic o Ló pe z 4. Formato de instrucciones 4.1. Formato general • El primer byte contiene 3 clases de información: � Código de operación: los 6 primeros bits contienen el código de la operación a realizar � El bit de dirección de registro (D): especifica si el operando dado por el campo de registro operando REG en el segundo byte es el operando fuente o destino: • si D = 1 tengo que REG = operando destino • si D = 0 tengo que REG = operando fuente � El bit de tamaño del dato (W): especifica si la operación será realizada sobre datos de 8 o de 16 bits: • si w = 0 los datos son de 8 bits • si w = 1 los datos son de 16 bits 18 Arquitectura software x86-16bits 35/47© R af ae l R ic o Ló pe z 4. Formato de instrucciones 4.1. Formato general • El segundo byte contiene los operandos: � Uno siempre es un registro �Viene dado por REG � El otro puede ser registro o memoria �Viene dado por MOD y R/M � NO se admiten las operaciones entre dos operandos ubicados en memoria Arquitectura software x86-16bits 36/47© R af ae l R ic o Ló pe z 4. Formato de instrucciones 4.1. Formato general • Campo REG: DIBH111 SIDH110 BPCH101 SPAH100 BXBL011 DXDL010 CXCL001 AXAL000 w = 1w = 0REG 19 Arquitectura software x86-16bits 37/47© R af ae l R ic o Ló pe z 4. Formato de instrucciones 4.1. Formato general • Campo MOD y R/M: MOD = 11 Cálculo de la dirección efectiva [BX]+D16 [BP]+D16 [DI]+D16 [SI]+D16 [BP]+[DI]+D16 [BP]+[SI]+D16 [BX]+[DI]+D16 [BX]+[SI]+D16 MOD = 10 [BX]+D8 [BP]+D8 [DI]+D8 [SI]+D8 [BP]+[DI]+D8 [BP]+[SI]+D8 [BX]+[DI]+D8 [BX]+[SI]+D8 MOD = 01 [BX] dirección [DI] [SI] [BP]+[DI] [BP]+[SI] [BX]+[DI] [BX]+[SI] MOD = 00 DIBH111 SIDH110 BPCH101 SPAH100 BXBL011 DXDL010 CXCL001 AXAL000 w = 1w = 0R/M Arquitectura software x86-16bits 38/47© R af ae l R ic o Ló pe z 4. Formato de instrucciones 4.1. Formato general � Registros implicados en el cálculo de direcciones (se incluye el registro de segmento por defecto): DS SS DS SS DS Reg. de segmento DSx16+[BX]111 SSx16+[BP]110 DSx16+[DI]101 DSx16+[SI]100 SSx16+[BP]+[DI]011 SSx16+[BP]+[SI]010 DSx16+[BX]+[DI]001 DSx16+[BX]+[SI]000 Dirección efectivaR/M 20 Arquitectura software x86-16bits 39/47© R af ae l R ic o Ló pe z 4. Formato de instrucciones 4. 1. F or m at o ge ne ra l Arquitectura software x86-16bits 40/47© R af ae l R ic o Ló pe z 4. Formato de instrucciones 4. 1. F or m at o ge ne ra l 21 Arquitectura software x86-16bits 41/47© R af ae l R ic o Ló pe z 4. Formato de instrucciones • Leyenda: � reg8, reg16: registros de tamaño byte o palabra � inm8, inm16: inmediatos de tamaño byte o palabra � r/m: operando registro o memoria � m: operando memoria � d8, d16: desplazamiento � b: base � b:d16 es una dirección completa de memoria � ‘→→→→’: se escribe � ‘:’: no se escribe Arquitectura software x86-16bits 42/47© R af ae l R ic o Ló pe z 4. Formato de instrucciones 4.2. Formato especial con campo de extensión • Se necesitan 2 bytes para determinar la operación no determina la operación desplazamiento y/o dato inmediato (determina la operación)campo de extensión byte 1 byte 2 byte 4byte 3 byte 6byte 5 operando registro o memoria código de operación 22 Arquitectura software x86-16bits 43/47© R af ae l R ic o Ló pe z 4. Formato de instrucciones 4.2. Formato especial con campo de extensión � Los campos MOD y R/M dan lugar al operando � El campo REG da el código de operación completando el campo de extensión Grupo IIFE, FF Grupo IF6, F7 DesplazamientosD0, D1, D2, D3 Inmediatos80, 81, 82, 83 GRUPOCAMPO DE EXTENSIÓN Arquitectura software x86-16bits 44/47© R af ae l R ic o Ló pe z 4. Formato de instrucciones 4.3. Formato especial con prefijo byte 1 byte 2byte 0 prefijo Sincronización con coprocesadorLOCK REPNZ/REPNE REPZ/REPE Repetición de instrucción de cadena REP ES SS DS Modifican la base por defecto CS EfectoPrefijo 23 Arquitectura software x86-16bits 45/47© R af ae l R ic o Ló pe z 4. Formato de instrucciones • Ejemplo: � MOV AX,[BX][SI] �DSx16+[BX][SI] � CS:MOV AX,[BX][SI] �CSx16+[BX][SI] Arquitectura software x86-16bits 46/47© R af ae l R ic o Ló pe z 4. Formato de instrucciones • EJEMPLO: La instrucción MOV BL,AL mueve el byte contenido en el registro fuente AL al registro destino BL. ¿Cuál es el código máquina de la instrucción sabiendo que el código de operación es 1000102? � SOLUCION: En el primer byte los primeros 6 bits especifican la operación y deben ser: CODIGO DE OPERACION = 1000102 � El bit D indica si el registro que señala el campo REG del 2º byte es el operando fuente o el destino. Codificaremos el registro AL en el campo REG y, por tanto, D será 0 � El bit W será 0 para indicar una operación de tamaño byte � PRIMER BYTE = 1000 10002 = 88h 24 Arquitectura software x86-16bits 47/47© R af ae l R ic o Ló pe z 4. Formato de instrucciones � En el segundo byte, REG indica el operando fuente que es AL. Su código es: REG = 000 � Como el segundo operando es también un registro, MOD debe valer 11. El campo R/M debe especificar que el registro destino es BL y su códificación es 011. Esto da: MOD = 11 R/M = 011 � SEGUNDO BYTE = 1100 00112 = C3h � Y el código hexadecimal completo para la instrucción es: MOV BL,AL = 88 C3h laboratorio/Teoría de laboratorio/02 - Repertorio de instrucciones x86-16bits.pdf 1 Repertorio de instrucciones x86-16bits 1/145© R af ae l R ic o Ló pe z Índice 1. Generalidades 2. Instrucciones de transferencia 3. Instrucciones de proceso 4. Instrucciones de bifurcación 5. Otras instrucciones Repertorio de instrucciones x86-16bits 2/145© R af ae l R ic o Ló pe z 1. Generalidades • No se pueden realizar operaciones donde ambos operandos residan en memoria • Las instrucciones de transferencia NO ACCEDEN al registro de estado • Las instrucciones de proceso ESCRIBEN el registro de estado • Las instrucciones de salto LEEN el registro de estado 2 Repertorio de instrucciones x86-16bits 3/145© R af ae l R ic o Ló pe z 1. Generalidades • Existen 2 tipos de sintaxis � INTEL � ATT • Nosotros usaremos la sintaxis INTEL � El primer operando es el DESTINO � El segundo operando es el FUENTE • En las operaciones de proceso, el operando DESTINO pierde su valor inicial siendo reemplazado por el resultado Repertorio de instrucciones x86-16bits 4/145© R af ae l R ic o Ló pe z 2. Instrucciones de transferencia 2. Instrucciones de transferencia Índice 1. Movimiento de datos 2. Extensión de signo 3. Transfiriendo punteros 4. Transferencias con la pila 5. Entrada/salida 3 Repertorio de instrucciones x86-16bits 5/145© R af ae l R ic o Ló pe z 2.1. Movimiento de datos MOV {reg/mem},{reg/mem/inmediato} • Trasfiere un byte o una palabra desde el operando fuente al destino op. destino ←←←← op. fuente • El operando fuente no se destruye • Ambos operandos deben ser del mismo tamaño Repertorio de instrucciones x86-16bits 6/145© R af ae l R ic o Ló pe z 2.1. Movimiento de datos • Ejemplo: MOV AX,FFFF ; AX = FFFF h MOV BX,1234 ; BX = 1234 h MOV AX,BX ; AX = 1234 h ; BX = 1234 h 4 Repertorio de instrucciones x86-16bits 7/145© R af ae l R ic o Ló pe z 2.1. Movimiento de datos • Restricciones: � No se pueden mover datos entre dos elementos de memoria; hay que utilizar un registro intermedio MOV AX, mem1 MOV mem2, AX � No se puede mover un inmediato a un registro de segmento; hay que usar un registro intermedio MOV AX, 1234h ; AX = 1234h MOV DS, AX ; DS = 1234h � El registro de segmento CS no puede ser destino Repertorio de instrucciones x86-16bits 8/145© R af ae l R ic o Ló pe z 2.1. Movimiento de datos XCHG {reg/mem},{reg/mem} • Intercambia el contenido de los operandos • Es útil para evitar el uso de una variable temporal • Ejemplo: MOV AX,FFFF ; AX = FFFF h MOV BX,0 ; BX = 0000 h XCHG AX,BX ; AX = 0000 h ; BX = FFFF h 5 Repertorio de instrucciones x86-16bits 9/145© R af ae l R ic o Ló pe z 2.1. Movimiento de datos XLAT memoria • Memoria es un desplazamiento sobre DS. El puntero a memoria será: DS:memoria prefijo: XLAT memoria • Ahora el segmento viene dado por el prefijo. El puntero a memoria será: prefijo:memoria Repertorio de instrucciones x86-16bits 10/145© R af ae l R ic o Ló pe z 2.1. Movimiento de datos • La instrucción XLAT carga en AL el valor de una tabla de memoria • Es útil para traducir entre sistemas de codificación • La tabla debe ser de bytes y no puede tener más de 256 bytes; el primero tiene desplazamiento 0 • La base de la tabla se coloca en BX y el puntero en AL AL ←←←← [BX+AL] 6 Repertorio de instrucciones x86-16bits 11/145© R af ae l R ic o Ló pe z 2.1. Movimiento de datos • Ejemplo: .DATA TABLA DB 1,2,3,4,5,6,7 ;declaración .CODE MOV BX,OFFSET TABLA ;carga BX MOV AL,4 ;5º valor XLAT TABLA ;AL = 5 • Esto es equivalente a: MOV AL,TABLA[4] Repertorio de instrucciones x86-16bits 12/145© R af ae l R ic o Ló pe z 2.1. Movimiento de datos • Ejemplo: � Esta tabla permite traducir códigos ASCII a EBCDIC � El código ASCII sirve de índice �Por ejemplo, el índice 32 apunta al “2” en EBCDIC F5TABLA[35] F4TABLA[34] F3TABLA[33] F2TABLA[32] F1TABLA[31] F0TABLA[30] XXTABLA[1] XXTABLA[0] valordirección 7 Repertorio de instrucciones x86-16bits 13/145© R af ae l R ic o Ló pe z 2.1. Movimiento de datos LAHF • Carga los 8 bits más bajos del registro de estado (banderas de estado) en AH AH ←←←← banderas de estado (bits 0, 2, 4, 6, 7) SAHF • Recupera las banderas de estado desde AH banderas de estado ←←←← AH Repertorio de instrucciones x86-16bits 14/145© R af ae l R ic o Ló pe z 2.1. Movimiento de datos • Las instrucciones de transferencia de las banderas de estado se suelen usar para mover el estado entre coprocesadores • Para manejar el conjunto completo del registro de estado se deben usar instrucciones de transferencia con la pila �PUSHF �POPF 8 Repertorio de instrucciones x86-16bits 15/145© R af ae l R ic o Ló pe z 2.2. Extensión de signo • Antes de poder mover datos de diferente tamaño es necesario extender adecuadamente el signo • El procedimiento es distinto si el número es considerado con signo o sin él, pero es el programador el que debe tenerlo en cuenta ya que la máquina no advierte la diferencia � Cuando el valor tiene signo se usa CBW o CWD � Cuando el valor es sin signo se rellena con ceros Repertorio de instrucciones x86-16bits 16/145© R af ae l R ic o Ló pe z 2.2. Extensión de signo CBW • Convertir byte en palabra • Copia el bit 7 del registro AL en todo el registro AH CWD • Convertir palabra en doble palabra • Copia el bit 15 del registro AX en el registro DX � Doble palabra ���� DX:AX 9 Repertorio de instrucciones x86-16bits 17/145© R af ae l R ic o Ló pe z 2.2. Extensión de signo • Ejemplo con signo: .DATA mem8 DB –5 ;declaración mem16 DW –5 ;declaración .CODE MOV AL, mem8 ;carga AL = FBh CBW ;AX = FFFBh (-5) MOV AX, mem16 ;carga AX = FFFBh CWD ;DX = FFFFh ;DX:AX = (-5) Repertorio de instrucciones x86-16bits 18/145© R af ae l R ic o Ló pe z 2.2. Extensión de signo • Ejemplo sin signo: .DATA mem8 DB 251 ;declaración (FBh) mem16 DW 65531 ;declaración (FFFBh) .CODE MOV AL, mem8 ;carga AL = FBh(251) XOR AH, AH ;AX = 00FBh (251) MOV AX, mem16 ;carga AX = FFFBh XOR DX, DX ;DX:AX = 0000 FFFBh 10 Repertorio de instrucciones x86-16bits 19/145© R af ae l R ic o Ló pe z 2.3. Transfiriendo punteros • Instrucciones para cargar punteros en registros • Los punteros pueden ser � Near ���� dentro de un segmento; no exceden los 64KB • LEA � Far ���� entre segmentos; exceden los límites del segmento y se requiere una base y un desplazamiento • LES • LDS Repertorio de instrucciones x86-16bits 20/145© R af ae l R ic o Ló pe z 2.3. Transfiriendo punteros LEA {reg},{mem} • Carga un puntero near en un registro; el puntero es la dirección efectiva de la posición de memoria especificada en el operando fuente � El operando destino puede ser cualquier registro de propósito general � No están permitidos los registros de segmento � El operando fuente es una posición de memoria especificada por cualquier modo de direccionamiento 11 Repertorio de instrucciones x86-16bits 21/145© R af ae l R ic o Ló pe z 2.3. Transfiriendo punteros • Ejemplo: • Transfiere el desplazamiento del operando fuente al registro destino LEA AX, 1234[SI] ;si SI = 1000h ;AX = 1234 + 1000 ;AX = 2234h Repertorio de instrucciones x86-16bits 22/145© R af ae l R ic o Ló pe z 2.3. Transfiriendo punteros • Advertencias respecto a LEA: LEA DX,cadena MOV DX,OFFSET cadena • Dan el mismo resultado pero es más rápida la segunda ya que la posición de cadena en el área de datos es conocida en tiempo de ensamblado • Usaremos LEA cuando queramos transferir un desplazamiento no conocido en tiempo de diseño: LEA DX,cadena[SI] MOV DX,OFFSET cadena[SI] ;no funciona 12 Repertorio de instrucciones x86-16bits 23/145© R af ae l R ic o Ló pe z 2.3. Transfiriendo punteros LES {reg},{mem} • Copia un puntero far (32 bits) guardado en el operando fuente al registro especificado en el operando destino y al registro ES �ES ���� salva la base � Registro destino ���� salva el desplazamiento (no se aceptan los registros de segmento) • El operando fuente es una posición de memoria de tamaño doble palabra (32 bits) Repertorio de instrucciones x86-16bits 24/145© R af ae l R ic o Ló pe z 2.3. Transfiriendo punteros • Los punteros en memoria se salvan por este orden � Palabra de menor peso ���� desplazamiento � Palabra de mayor peso ���� base • Ejemplo: PTR ���� 1234:5678 LES DI,PTR ;DI = 5678h ;ES = 1234h 12PTR[3] 34PTR[2] 56PTR[1] 78PTR[0] valordirección 13 Repertorio de instrucciones x86-16bits 25/145© R af ae l R ic o Ló pe z 2.3. Transfiriendo punteros LDS {reg},{mem} • Copia un puntero far (32 bits) guardado en el operando fuente al registro especificado en el operando destino y al registro DS � DS ���� salva la base � Registro destino ���� salva el desplazamiento (no se aceptan los registros de segmento) • El operando fuente es una posición de memoria de tamaño doble palabra (32 bits) Repertorio de instrucciones x86-16bits 26/145© R af ae l R ic o Ló pe z 2.3. Transfiriendo punteros • Ejemplo: PTR ���� 1234:5678 LDS SI,PTR ;SI = 5678h ;DS = 1234h 12PTR[3] 34PTR[2] 56PTR[1] 78PTR[0] valordirección 14 Repertorio de instrucciones x86-16bits 27/145© R af ae l R ic o Ló pe z 2.3. Transfiriendo punteros • Ejemplo: .DATA cadena DB “Hola mundo” ;cadena pcadena DD cadena ;salvo el puntero array DB 100 DUP(?) ;reservo array parray DD array .CODE LES DI,pcadena ;ES:DI����cadena LDS SI,parray ;DS:SI����array Repertorio de instrucciones x86-16bits 28/145© R af ae l R ic o Ló pe z 2.4. Transferencias con la pila • La pila es un área de memoria de acceso secuencial tipo LIFO gobernada por el puntero SP y usada para almacenar datos temporalmente: � Paso de parámetros a procedimientos � Variables locales a procedimientos � Salvaguarda de registros cuando deben ser utilizados por otra variable • En el x86-16bits el SP comienza en las posiciones más altas y avanza hacia las más bajas 15 Repertorio de instrucciones x86-16bits 29/145© R af ae l R ic o Ló pe z 2.4. Transferencias con la pila • Las instrucciones que trabajan con la pila sólo especifican un operando ya que el otro es implícito (la cima de la pila referenciada por SP) • Estas instrucciones también actúan de manera implícita sobre el puntero de pila (SP) � Decrementándolo cuando introducen datos � Incrementándolo cuando sacan datos • Las transferencias son de tamaño palabra (16 bits) � El SP se actualiza de 2 en 2 Repertorio de instrucciones x86-16bits 30/145© R af ae l R ic o Ló pe z 2.4. Transferencias con la pila PUSH {reg/mem} • Poner palabra en la pila • Decrementa el SP en 2 y coloca el operando en la pila � El operando nunca puede ser CS SP ←←←← SP – 2 SS:SP ←←←← operando bajas posiciones altas AL ←←←← SPAH ←←←← SP después de PUSH AX antes de PUSH AX 16 Repertorio de instrucciones x86-16bits 31/145© R af ae l R ic o Ló pe z 2.4. Transferencias con la pila • Ejemplo: PUSH AX ;pone AX en la cima de la pila • Es equivalente a: SUB SP,2 ; SP ←←←← SP - 2 MOV [SP],AX ; SS:SP ←←←← AX Repertorio de instrucciones x86-16bits 32/145© R af ae l R ic o Ló pe z 2.4. Transferencias con la pila POP {reg/mem} • Sacar palabra de la pila • Copia el dato de la pila en el operando especificado e incrementa el SP en 2 � El operando nunca puede ser CS operando ←←←← SS:SP SP ←←←← SP + 2 bajas posiciones altas Byte L ←←←← SPByte H ←←←← SP después de POP AX antes de POP AX 17 Repertorio de instrucciones x86-16bits 33/145© R af ae l R ic o Ló pe z 2.4. Transferencias con la pila • Ejemplo: POP AX ;AX ���� valor cima de la pila • Es equivalente a: MOV AX,[SP] ; AX ←←←← SS:SP ADD SP,2 ; SP ←←←← SP + 2 Repertorio de instrucciones x86-16bits 34/145© R af ae l R ic o Ló pe z 2.4. Transferencias con la pila PUSHF • Transfiere el registro de estado completo a la pila SP ←←←← SP - 2 SS:SP ←←←← reg. estado POPF • Carga el registro de estado completo con el contenido de la cima de la pila reg. estado ←←←← SS:SP SP ←←←← SP + 2 18 Repertorio de instrucciones x86-16bits 35/145© R af ae l R ic o Ló pe z 2.5. Entrada/salida • Los mapas de memoria y de entrada/salida en máquinas x86-16bits son disjuntos • Cuando se emite una dirección en el bus de direcciones es necesario especificar si es de memoria o de E/S • Por esto contamos con instrucciones específicas de E/S �IN ���� señal IO/M = 1 ���� señal RD activa �OUT ���� señal IO/M = 1 ���� señal WR activa También tenemos INS y OUTS que mueven áreas de memoria Repertorio de instrucciones x86-16bits 36/145© R af ae l R ic o Ló pe z 2.5. Entrada/salida IN Acc,{puerto/DX} • Carga el acumulador con un valor leído en un puerto de E/S especificado por el operando fuente � El puerto puede ser un inmediato de tamaño byte (puertos 0 – 255) � Por encima de este puerto hay que darlo como DX • El tamaño de la transferencia viene dado por Acc: � Si es AX ���� tamaño palabra � Si es AL ���� tamaño byte 19 Repertorio de instrucciones x86-16bits 37/145© R af ae l R ic o Ló pe z 2.5. Entrada/salida OUT {puerto/DX},Acc • Escribe el contenido del acumulador en el puerto especificado � El puerto puede ser un inmediato de tamaño byte (puertos 0 – 255) � Por encima de este puerto hay que darlo como DX • El tamaño de la transferencia viene dado por Acc: � Si es AX ���� tamaño palabra � Si es AL ���� tamaño byte Repertorio de instrucciones x86-16bits 38/145© R af ae l R ic o Ló pe z 2.5. Entrada/salida • Normalmente las E/S se realizan mediante llamadas al S.O. (que a su vez realiza llamadas al BIOS) � INT 21h ���� bajo D.O.S. � API ���� bajo Windows • Sin embargo, las instrucciones de E/S proporcionan un método para hacer E/S directamente � ¡OJO! pueden provocar problemas de portabilidad 20 Repertorio de instrucciones x86-16bits 39/145© R af ae l R ic o Ló pe z 3. Instrucciones de proceso 3. Instrucciones de proceso Índice 1. Operaciones lógicas 2. Desplazamientos y rotaciones 3. Suma 4. Resta 5. Multiplicación 6. División 7. Operaciones en BCD Repertorio de instrucciones x86-16bits 40/145© R af ae l R ic o Ló pe z 3.1. Operaciones lógicas • Las instrucciones lógicas realizan operaciones booleanas sobre bits individuales � Cada resultado en el bit i-ésimo sólo depende de los bits i-ésimos de los operandos de entrada �Son las más rápidas � No conllevan propagaciones de acarreos, etc. �No son función del peso (≠f(peso)) 21 Repertorio de instrucciones x86-16bits 41/145© R af ae l R ic o Ló pe z 3.1. Operaciones lógicas • El repertorio del x86-16bits da soporte a las operaciones lógicas AND, OR, XOR entre dos operandos (diádicas) y a la NOT de un operando (monádica) 001111 011001 111010 100000 NOT XX XOR YX OR YX AND YYX monádicadiádicas Repertorio de instrucciones x86-16bits 42/145© R af ae l R ic o Ló pe z 3.1. Operaciones lógicas • Se suelen usar combinando un operando con una “máscara” � La “máscara” tiene diferentes formas dependiendo de la operación � Se utiliza para modificar o extraer información de unos bits y obviar la de otros • Las instrucciones no han de confundirse con los operadores � Las primeras operan en tiempo de ejecución � Los segundos son órdenes para el ensamblador � Se distinguen por el contexto 22 Repertorio de instrucciones x86-16bits 43/145© R af ae l R ic o Ló pe z 3.1. Operaciones lógicas AND {reg/mem},{reg/mem/inmediato} • Realiza la operación lógica AND • Se puede usar para poner a cero un bit independientemente de su valor actual � La máscara contendrá un 0 allá donde queramos colocar un cero y un 1 donde queremos dejar intacto el bit original Repertorio de instrucciones x86-16bits 44/145© R af ae l R ic o Ló pe z 3.1. Operaciones lógicas • Ejemplo: MOV AL, 035h ; 0011 0101 AND AL, 0FBh ;and 1111 1011 ; 0011 0001 ; 0011 0001 AND AL, 0F8h ;and 1111 1000 ; 0011 0000 MOV AH, 7 ;servicio 7 de INT 21h INT 21h ;entrada carácter sin eco AND AL, 1101 1111b ;convierte a Mayúsculas CMP AL, ‘Y’ ;¿es ‘Y’? JE YES ;si es ‘Y’ salta a la rutina ;si no es ‘Y’ continúa YES: : : : ;rutina 23 Repertorio de instrucciones x86-16bits 45/145© R af ae l R ic o Ló pe z 3.1. Operaciones lógicas OR {reg/mem}, {reg/mem/inmediato} • Realiza la operación lógica OR • Se puede usar para poner a uno un bit independientemente de su valor actual � La máscara contendrá un 1 allá donde queramos colocar un 1 y un 0 donde queremos dejar intacto el bit original • También se usa para comparar con 0 Repertorio de instrucciones x86-16bits 46/145© R af ae l R ic o Ló pe z 3.1. Operaciones lógicas • Ejemplo: MOV AL, 035h ; 0011 0101 OR AL, 08h ;or 0000 1000 ; 0011 1101 ; 0011 1101 OR AL, 07h ;or 0000 0111 ; 0011 1111 OR BX, BX ;¿es BX=0? ;ocupa 2B tarda 2 ciclos JG ;BX positivo JL ;BX negativo ;BX cero CMP BX, 0 ;¿es BX=0? ;ocupa 3B tarda 3 ciclos es una resta que no salva el resultado 24 Repertorio de instrucciones x86-16bits 47/145© R af ae l R ic o Ló pe z 3.1. Operaciones lógicas XOR {reg/mem},{reg/mem/inmediato} • Realiza la operación lógica XOR • Se puede usar para conmutar el valor de bits específicos � La máscara tendrá 1 allá donde quieras conmutar • También se usa para poner a cero un registro Repertorio de instrucciones x86-16bits 48/145© R af ae l R ic o Ló pe z 3.1. Operaciones lógicas • Ejemplo: MOV AL, 035h ; 0011 0101 XOR AL, 08h ;xor 0000 1000 ; 0011 1101 ; 0011 1101 XOR AL, 07h ;or 0000 0111 ; 0011 1010 XOR CX, CX ;ocupa 2B tarda 3 ciclos ;actualiza el estado MOV CX, 0 ;ocupa 3B tarda 4 ciclos ;NO actualiza el estado SUB CX, CX ;ocupa 2B tarda 3 ciclos ;actualiza el estado 25 Repertorio de instrucciones x86-16bits 49/145© R af ae l R ic o Ló pe z 3.1. Operaciones lógicas NOT {reg/mem} • Complementa todos los bits del operando
Compartir