trabajo de asembler
Short Description
Download trabajo de asembler...
Description
Manual de Lenguaje Ensamblador
TEMARIO Introducción. I.- Definiciones y conceptos preliminares. 1.- Conceptos básicos. 1.1.- El lenguaje de maquina y el lenguaje ensamblador. 1.2.- Interpretes, compiladores y ensambladores. 1.3.- El proceso de link, las rutinas de RUN-TIME y los servicios del sistema operativo. 2.- La arquitectura arquitectura de las computadoras computadoras personales personales IBM y Compatibles. 3.- La arquitectura de los microprocesadores Intel. 4.- El sistema operativo MS-DOS. 5.- Ensambladores y Macroensambladores. 6. Sistemas numéricos 7. Operaciones con bytes 7.1. AND 7.2. OR 7.3. XOR 7.4. NOT 8. El juego de registros. 9.- ¿Qué es....la BIOS? 9.1. Configuración avanzada y del chipset 9.2. Periféricos integrados 9.3. Administración de energía 9.4. Configuración de PNP y slots PCI 9.5. Autoconfiguración de la BIOS 9.6. Otras utilidades 9.7. Salir de la BIOS 9.8. Actualizar la BIOS 9.9. La BIOS y la pila 9.10. Cómo saltarse la password de la BIOS II.- El lenguaje ensamblador. 1.- Un ejemplo clásico. 2.- El formato del ensamblador. 3.- Directivas. 4.- Conjunto de instrucciones. 5.- Macros y procedimientos. 6.- Interrupciones. III.- Creación y depuración de programas en lenguaje ensamblador 1.- Edición. 2.- Ensamblado. 3.- Link.
Manual de Lenguaje Ensamblador
4.- Ejecución. 5.- Depuración. 5.1.- Uso de DEBUG de DOS I 5.2.- Uso de DEBUG II: Trazar un Programa 5.3.- Uso de DEBUG III: Escribir un Programa 5.4.- Observaciones 6.- La utilería utilería exe2bin y los archivos .exe y .com . Resumen del DEBUG Apéndice a.- Modelo de registros del 8086. Apéndice b.- Registros expandidos del 8087. Apéndice c.- Modelo de segmentación de memoria. Apéndice d.- Directivas del MASM. Apéndice e.- Juego de instrucciones del 8086, 8087, 80186, 80286 y 80287. Apéndice f.- Interrupciones. Apéndice g.- Ejemplos adicionales. Bibliografía.
Manual de Lenguaje Ensamblador
INTRODUCCION. El presente manual, es un documento que está orientado a la introducción a la programación en lenguaje Ensamblador, y principalmente, a aquellas personas que nunca han trabajado con este lenguaje y probablemente con ningún otro. Tal y como lo indica su título, está enfocado al lenguaje ensamblador de los microprocesadores Intel, particularmente el 8088, 8086, 80186, 80188 y 80286. Sin embargo, todos los programas generados para estos procesadores correrán en un 80386 ó 80486. Adicionalmente se proporciona el juego de instrucciones de los coprocesadores matemáticos 8087 y 80287, que es compatible con el de los microprocesadores ya citados, es decir, el manual se enfoca completamente hacia las computadoras que operan con procesadores de la familia x86 de Intel y, considerando que el ensamblador basa su funcionamiento en los recursos internos del procesador, los ejemplos descritos no son compatibles con ninguna otra arquitectura. Este documento trata de abarcar, de la forma más general, todo aquello que involucra el conocimiento y uso del lenguaje ensamblador. Así, ha sido organizado en tres partes. La primera describe los conocimientos básicos que deben poseerse para una mejor comprensión e interpretación de lo que es el lenguaje ensamblador y cómo debe ser usado. La segunda parte está dedicada por completo a lo que es el lenguaje ensamblador, las interrupciones del sistema operativo MS-DOS y el conjunto de instrucciones 8086-80286. La última parte se ha dedicado al proceso de ensamble, la depuración de programas en ensamblador, y algunas consideraciones sobre la creación de programas y su ejecución.
Manual de Lenguaje Ensamblador
Manual de Lenguaje Ensamblador
I.- DEFINICIONES Y CONCEPTOS PRELIMINARES. 1.- CONCEPTOS BASICOS. 1.1.- EL LENGUAJE DE MAQUINA Y EL LENGUAJE ENSAMBLADOR. Todo procesador, grande o pequeño, desde el de una calculadora hasta el de un supercomputador, ya sea de propósito general o específico, posee un lenguaje único que es capaz de reconocer y ejecutar. Por razones que resultan obvias, este lenguaje ha sido denominado Lenguaje de Máquina y más que ser propio de un computador pertenece a su microprocesador. El lenguaje de máquina está compuesto por una serie de instrucciones, que son las únicas que pueden ser reconocidas y ejecutadas por el microprocesador. Este lenguaje es un conjunto de números que representan las operaciones que realiza el microprocesador a través de su circuitería interna. Estas instrucciones, por decirlo así, están grabadas o "alambradas" en el hardware y no pueden ser cambiadas. El nivel más bajo al que podemos aspirar a llegar en el control de un microprocesador es precisamente el del lenguaje de máquina. Ahora bien, siendo el lenguaje de máquina un conjunto de números, ¿cómo es capaz el microprocesador de saber cuándo un número representa una instrucción y cuándo un dato? El secreto de esto reside en la dirección de inicio de un programa y en el estado del microprocesador. La dirección de inicio nos indica en qué localidad de memoria comienza un programa, y en consecuencia que datos deberemos considerar como instrucciones. El estado del microprocesador nos permite saber cuándo éste espera una instrucción y cuándo éste espera un dato. Obviamente, el lenguaje de máquina de un microprocesador no puede ser ejecutado por otro microprocesador de arquitectura distinta, a menos que haya cierto tipo de compatibilidad prevista. Por ejemplo, un 80486 es capaz de ejecutar lenguaje de máquina propio y soporta el código generado para microprocesadores anteriores de la misma serie (desde un 8086 hasta un 80386). Por otra parte, un PowerPC es capaz de ejecutar instrucciones de los microprocesadores Motorola 68xxx y de los Intel 80xx/80x86. En ambos casos, el diseño de los microprocesadores se hizo tratando de mantener cierto nivel de compatibilidad con los desarrollados anteriormente. En el segundo caso, este nivel de compatibilidad se extendió a los de otra marca. Sin embargo, un 8088 no puede ejecutar código de un 80186 o superiores, ya que los procesadores más avanzados poseen juegos de instrucciones y registros nuevos no contenidos por un 8088. Un caso similar es la serie 68xxx, pero de ninguna manera podemos esperar que un Intel ejecute código de un Motorola y viceversa. Y esto no tiene nada que ver con la compañía, ya que Intel desarrolla otros tipos de microprocesadores como el 80860 y el iWARP, los cuales no pueden compartir código ni entre ellos ni entre los 80xx/80xxx.
Manual de Lenguaje Ensamblador
Ahora bien, mientras que con el lenguaje de máquina, nosotros obtenemos un control total del microprocesador, la programación en este lenguaje resulta muy difícil y fácil para cometer errores. No tanto por el hecho de que las instrucciones son sólo números, sino porque se debe calcular y trabajar con las direcciones de memoria de los datos, los saltos y las direcciones de llamadas a subrutinas, además de que para poder hacer ejecutable un programa, se deben enlazar las rutinas de run-time y servicios del sistema operativo. Este proceso es al que se le denomina ensamblado de código. Para facilitar la elaboración de programas a este nivel, se desarrollaron los Ensambladores y el Lenguaje Ensamblador.
Existe una correspondencia 1 a 1 entre las instrucciones del lenguaje de máquina y las del lenguaje ensamblador. Cada uno de los valores numéricos del lenguaje de máquina tiene una representación simbólica de 3 a 5 letras como instrucción del lenguaje ensamblador. Adicionalmente, este lenguaje proporciona un conjunto de pseudo-operaciones (también conocidas como directivas del ensamblador) que sirven para definir datos, rutinas y todo tipo de información para que el programa ejecutable sea creado de determinada forma y en determinado lugar. 1.2- INTERPRETES, COMPILADORES Y ENSAMBLADORES. Aún cuando el lenguaje ensamblador fue diseñado para hacer más fácil la programación de bajo nivel, esta resulta todavía complicada y muy laboriosa. Por tal motivo se desarrollaron los lenguajes de alto nivel, para facilitar la programación de los computadores, minimizando la cantidad de instrucciones a especificar. Sin embargo, esto no quiere decir que el microprocesador ejecute dichos lenguajes. Cada una de las instrucciones de un lenguaje de alto nivel o de un nivel intermedio, equivalen a varias de lenguaje máquina o lenguaje ensamblador. La traducción de las instrucciones de nivel superior a las de bajo nivel la realizan determinados programas. Por una parte tenemos los intérpretes, como DBase, BASIC, APL, y Lisp. En estos, cada vez que se encuentra una instrucción, se llama una determinada rutina de lenguaje de máquina que se encarga de realizar las operaciones asociadas, pero en ningún momento se genera un código objeto y mucho menos un código ejecutable. Por otra parte, tenemos los compiladores, como los desarrollados para Fortran, Clipper, COBOL, Pascal o C, que en vez de llamar y ejecutar una rutina en lenguaje de máquina, éstos juntan esas rutinas para formar el código objeto que, después de enlazar las rutinas de run-time y llamadas a otros programas y servicios del sistema operativo, se transformará en el programa ejecutable. Finalmente, tenemos los ensambladores— como los descritos en este trabajo —que son como una versión reducida y elemental de un compilador (pero
Manual de Lenguaje Ensamblador
que de ninguna manera deben considerarse como tales), ya que lo único que tienen que hacer es cambiar toda referencia simbólica por la dirección correspondiente, calcular los saltos, resolver referencias y llamadas a otros programas, y realizar el proceso de enlace. Los ensambladores son programas destinados a realizar el ensamblado de un determinado código. 1.3.- EL PROCESO DE LIGA, LAS RUTINAS DE RUN-TIME Y LOS SERVICIOS DEL SISTEMA OPERATIVO. Para crear un programa ejecutable a partir de un código objeto se requiere que se resuelvan las llamadas a otros programas y a los servicios del sistema operativo, y agregar las rutinas o información de run-time para que el programa pueda ser cargado a memoria y ejecutado. Este proceso es lo que se conoce como Link o proceso de liga, y se realiza a través de un ligador o Linker que toma de entrada el código objeto y produce de salida el código ejecutable. Las rutinas de RUN-TIME son necesarias, puesto que el sistema operativo requiere tener control sobre el programa en cualquier momento, además de que la asignación de recursos y su acceso deben hacerse solamente a través del sistema operativo. Para los computadores personales, esto no es tan complejo como para otros computadores y sistemas operativos, pero es requerido.
2.- LA ARQUITECTURA IBM Y COMPATIBLES.
DE
LAS
COMPUTADORAS
PERSONALES
Los computadores PC están compuestos físicamente por: monitor, teclado, CPU, floppy drives, hard disk drives, periféricos y componentes adicionales. Lógicamente están compuestos por el BIOS (Basic Input-Output System) y el sistema operativo MS-DOS (MicroSoft Disk Operating System). El teclado se encuentra conectado a un puerto de entrada destinado específicamente para tal propósito. Este tiene asociado un área de memoria (buffer) al cual llegan los códigos de las teclas presionadas en el teclado. La CPU está compuesta por la memoria RAM, memoria ROM (donde reside el BIOS), los controladores de disco, la tarjeta de video, los puertos de entradasalida y el microprocesador. Los periféricos se encuentran conectados y asociados por el sistema operativo con un puerto en particular (una vez que el puerto ha sido abierto). Las tarjetas controladores de floppy y disco duro se encargan de intercambiar información entre memoria, procesador y unidades de disco. Para tal propósito se reservan en memoria áreas específicas, para servir de buffers en el intercambio de datos del computador con las unidades de disco. El monitor y la tarjeta de video están muy relacionados entre sí, ya que si bien el monitor se encarga de desplegar la información, no es éste quien la mantiene, sino la memoria designada a la tarjeta de video. Esta memoria es
Manual de Lenguaje Ensamblador
como cualquier otra, direccionable y modificable, y es en donde se guarda la información que aparece en pantalla. Debido al tipo de microprocesador empleado, la memoria de la PC se encuentra dividida en una serie de blocks denominados segmentos, de 64KB cada uno. La memoria es accesada especificando el segmento y el desplazamiento dentro del segmento (segmento: desplazamiento, para mayor detalle ver el apéndice C). Para las PC´s la memoria se clasifica en tres tipos: - Convencional: Es la memoria de tipo básico y que abarca las direcciones
de 0 a 640KB. En ésta es donde se cargan los programas de usuario y el sistema operativo, y es la que está disponible para equipo XT (8088,8086, 80186 y 80188). - Extendida: Esta memoria sólo está disponible para procesadores 80286 y mayores (equipo AT, 80386 y 80486). Muchos programas que usan la memoria convencional no pueden usar la memoria extendida porque las direcciones en memoria extendida están más allá de las que el programa puede reconocer. Únicamente las direcciones dentro de los 640KB pueden ser reconocidas por todos los programas. Para reconocer la memoria extendida se requiere de un manejador de memoria extendida, como HIMEM.SYS que provee MS-DOS. - Expandida: Esta es la memoria que se agrega al computador a través de una tarjeta de expansión, y que debe ser administrada por un programa especial, como el EMM386.EXE. A diferencia de la memoria convencional o extendida, la memoria expandida es dividida en bloques de 16K llamados páginas (pages). Cuando un programa solicita información de memoria expandida el manejador copia la página correspondiente en un área denominada page frame para poder ser accesada en la memoria extendida. Como se puede observar, el 8088, 8086, 80188 y 80186 son capaces de direccionar hasta 1 MB de memoria. Ya hemos indicado que la memoria convencional sólo abarca 640KB, así nos quedan 384KB libres. Esta parte de la memoria es denominada parte alta, y como no está disponible para muchos programas generalmente se usa para cargar drivers del sistema operativo, programas residentes y datos de hardware (ROM y páginas de video).
3.- LA ARQUITECTURA DE LOS MICROPROCESADORES INTEL. Sin importar de qué microprocesador se trate, los microprocesadores del 8088 al 80486 usan el modelo de registros del 8086. Los microprocesadores matemáticos 80287 al 80487 utilizan el modelo de registros expandidos del 8087. Para mayor detalle ver los apéndices A y B. Los microprocesadores matemáticos están diseñados exclusivamente para efectuar operaciones aritméticas de una manera más rápida y precisa bajo el
Manual de Lenguaje Ensamblador
control de otro procesador razón por la cual se denominan coprocesadores. Estos también poseen un juego de instrucciones de lenguaje de máquina propio. La diferencia entre los diversos microprocesadores de uso general y los coprocesadores reside en el nuevo conjunto de instrucciones, registros y señalizadores agregados con cada nueva liberación de un procesador superior. Estas adiciones se hicieron con el fin de agregar un mayor poder de cómputo sin alterar la estructura básica, para así mantener la compatibilidad con los desarrollos anteriores, tanto de software como de hardware. La diferencia entre los 8086 y 8088 con los 80186 y 80188 no es muy grande, ésta radica en un grupo de instrucciones que fueron agregadas al 80186 y al 80188. La diferencia entre el 8086 y el 8088, lo mismo que entre el 80186 y el 80188, es el modelo de memoria que usan ambos procesadores. El 8088 y el 80188 están diseñados como microprocesadores de 8 bits por lo que el modo de acceso a la memoria es ligeramente distinto pero compatible con el 8086 y el 80186. Esto se verá con más detalle en un tema posterior. 4.- EL SISTEMA OPERATIVO MS-DOS. Junto con todo lo visto anteriormente, y como se mencionó anteriormente, uno de los componentes que caracterizan los computadores personales es su sistema operativo. Una PC puede correr varios sistemas operativos: CP/M, CP/M86, XENIX, Windows, PC-DOS, y MS-DOS. Lo que los define es la forma en que están integrados sus servicios y la forma en que se accesa a ellos. Esto es precisamente lo que el linker debe enlazar y resolver. Aquí nos enfocaremos exclusivamente en el sistema operativo MS-DOS, y lo que se mencione aquí será valido para las versiones 3.0 y superiores. Este sistema operativo está organizado de la siguiente manera: Comandos Internos COMMAND.COM) Comandos Externos Utilerías y drivers Shell mayores) Servicios
(reconocidos
y
ejecutados
por
el
(.EXEs y .COMs) (programas de administración del sistema) (Interfaz amigable, sólo versiones 4.0 o (Interrupciones)
Los servicios, más conocidos como interrupciones o vectores de interrupción, es parte medular de lo que es MS-DOS, y no son más que rutinas definidas por MS-DOS y el BIOS, ubicadas a partir de una localidad de memoria específica. La manera de acceder a estas rutinas y a los servicios que ofrecen es mediante una instrucción que permite ejecutar una interrupción. MS-DOS proporciona dos módulos: IBMBIO.COM (provee una interfaz de bajo nivel para el BIOS) e IBMDOS.COM (contiene un manejador de archivos y servicios para manejo de registros). En equipos compatibles estos archivos tienen los nombres IO.SYS y MSDOS.SYS, respectivamente. El acceso a los servicios del computador se realiza de la siguiente manera:
Manual de Lenguaje Ensamblador
Programa DOS EXTERNO de usuario Alto nivel Petición de ‹—› IBMDOS.COM ‹—› Dispositivo I/O
DOS Bajo nivel ‹—› IBMBIO.COM
ROM ‹—›
BIOS
5.- ENSAMBLADORES Y MACROENSAMBLADORES. Existen varios ensambladores disponibles para ambiente MS-DOS: el IBM Macro Assembler, el Turbo Assembler de Borland, el Turbo Editassm de Speedware, por citar algunos. Una breve descripción de cada uno se proporciona a continuación. Macro Ensamblador IBM: Está integrado por un ensamblador y un
macroensamblador. En gran medida su funcionamiento y forma de invocarlo es sumamente similar al de Microsoft. Su forma de uso consiste en generar un archivo fuente en código ASCII, se procede a generar un programa objeto que es ligado y se genera un programa .EXE. Opcionalmente puede recubrirse a la utilería EXE2BIN de MS-DOS para transformarlo a .COM. Es capaz de generar un listado con información del proceso de ensamble y referencias cruzadas. Macro Ensamblador de Microsoft: Dependiendo de la versión, este
ensamblador es capaz de soportar el juego de instrucciones de distintos tipos de microprocesadores Intel de la serie 80xx/80x86. En su versión 4.0 este soporta desde el 8086 al 80286 y los coprocesadores 8087 y 80287. Requiere 128KB de memoria y sistema operativo MS-DOS v2.0 o superior. Trabaja con un archivo de código fuente creado a partir de un editor y grabado en formato ASCII. Este archivo es usado para el proceso de ensamble y generación de código objeto. Posteriormente, y con un ligador, es creado el código ejecutable en formato .EXE. Turbo Editassm: Este es desarrollado por Speddware, Inc., y consiste de
un ambiente integrado que incluye un editor y utilerías para el proceso de ensamble y depuración. Es capaz de realizar el ensamble línea a línea, conforme se introducen los mnemónicos, y permite revisar listas de referencias cruzadas y contenido de los registros. Este ensamblador trabaja con tablas en memoria, por lo que la generación del código ejecutable no implica la invocación explícita del ligador por parte del programador. Adicionalmente permite la generación de listados de mensajes e información de cada etapa del proceso y la capacidad de creación de archivos de código objeto. Turbo Assembler (De Borland Intl): es muy superior al Turbo Editassm.
Trabaja de la misma forma, pero proporciona una interfaz mucho más fácil de usar y un mayor conjunto de utilerías y servicios. En lo que se refiere a las presentes notas, nos enfocaremos al Microsoft Macro Assembler v4.0. Los programas ejemplo han sido desarrollados con éste y
Manual de Lenguaje Ensamblador
está está garanti garantizado zado su funcio funcionami namient ento. o. Estos Estos mismos mismos progra programas mas posibl posiblemen emente te funcionen con otros ensambladores sin cambios o con cambios mínimos cuando util utiliz izan an direc directi tivas vas o pseud pseudoi oins nstr truc ucci cion ones. es. Real Realmen mente te la dife diferen renci cia a entr entre e los los ensambladores radica en la forma de generar el código y en las directivas con que cuente, aunque estas diferencias son mínimas. El código ensamblador no cambia puesto que los microprocesadores microprocesadores con los que se va a trabajar son comunes. Así, todos los programas que se creen con un ensamblador en particular podrán ser ensamblados ensamblados en otro, cambiando cambiando las pseudo-operac pseudo-operaciones iones no reconocidas reconocidas por el equivalente indicado en el manual de referencia del paquete empleado. Los programas que componen el Macro Ensamblador Microsoft v4.0 son los siguientes: Programa MASM.EXE SYMDEB.EX E LINK.EXE MAPSYM.EX E CREF.EXE LIB.EXE MAKE.EXE EXEPACK.EX E EXEMOD.EX E COUNT.ASM README.DO C
Descripción Microsoft Macro Assembler Microsoft Symbolic Debuger Utility Microsoft 8086 object linker Microsoft Symbol File Generator Microsoft Cross-Reference Utility Microsoft Library Manager Microsoft Program Maintenance Utility Microsoft EXE File Compression Utility Microsoft EXE File Header Utility Sample source file for SYMDEB session Updated information obtained after the manua was printed.
El Micr Mi cro osoft soft Mac Macro Assem ssembl bler er v4.0 v4.0 crea rea códi código go ejec ejecut utab ablle para para procesadores 8086, 8088, 80186, 80188, 80286, 8087 y 80287. Además es capaz de aprovechar las instrucciones del 80286 en la creación de código protegido y no prot proteg egiido. do. El térmi érmino no mac macroen roensa samb mbllado ador es usad usado o para para indi indica carr que que el ensamblador en cuestión tiene la capacidad de poder ensamblar programas con facilidad facilidad de macro. Una macro es una pseudo-instr pseudo-instrucció ucción n que define un conjunto conjunto de instrucciones asociadas a un nombre simbólico. Por cada ocurrencia en el código de esta macro, el ensamblador se encarga de sustituir esa llamada por todas las instrucciones asociadas y, en caso de existir, se dejan los parámetros con los que se estaba llamando la macro y no con los que había sido definida. Es impo import rtan ante te seña señala larr que que no se deja deja una una llam llamad ada, a, como como a una una subr subrut utin ina a o procedimiento, sino que se incorporan todas las instrucciones que definen a la macro.1
Manual de Lenguaje Ensamblador
6. SISTEMAS NUMÉRICOS Comen Comence cemo moss por por los los sist sistem emas as de nume numerac ració ión n que que más más util utiliz izar aremo emoss al prog program ramar ar.. El bási básico co va a ser el sist sistema ema hexa hexadec decim imal al,, aunq aunque ue debem debemos os de explicar antes el binario, el sistema de numeración que utiliza el ordenador. Los números que conocemos están escritos en base 10. Esto significa que tenemos, desde el 0 hasta el 9, diez símbolos para representar cada cifra. Es decir, cada cifra ir de 0 a 9, y al superar el valor valor "9", cambiar cambiar a 0 y sumar uno a su su cifra cifra de la izquierda: 9+1: 10. El sistema binario utiliza tan sólo dos símbolos, el "0" y el "1". Imaginemos que tenemos el número binario "0". Al sumarle una unidad, este número binario cambiar cambiar a "1". Sin embargo, embargo, si volvemos volvemos a añadirle otra unidad, unidad, a este número en formato formato binari binario o ser el "10" (aumen (aumenta ta la cifra cifra a la izquie izquierda, rda, que que era 0, y la anterior toma el valor mínimo). Sumem Sumemos os ahora ahora otra unidad unidad:: el aspec aspecto to del número número ser decimal). Y podríamos seguir:
"11" "11" (tres (tres en
Binari Binario o : 0 ; 1 ; 10 ; 11 ; 100 ; 101 101 ; 110; 111 111 ; 1000 1000 ; 1001 ; 1010,... Decimal: 0 1 2 3 4 5 6 7 8 9 10 Esto nos permite establecer establecer un sistema sistema bastante bastante sencillo sencillo de conversión conversión del binario al decimal; He aquí los valores siendo n el valor de la cifra: Cifra menos significativa: n*2^0 = 1 si n=1 o 0 si n=0 Segunda cifra: n*2^1 = 2 si n=1 o 0 si n=0 Tercera cifra: n*2^2 = 4 si n=1 o 0 si n=0 Cuarta cifra: n*2^3 = 8 si n=1 o 0 si n=0 etc.,... Y así continuaríamos, aument entando el número ero al que se ele eleva 2. Traduzcamos entonces el número binario '10110111' 2^7+ 0 +2^5+2^4+ +2^5+2^4+ 0 +2^2+2^1+2^0 +2^2+2^1+2^0 = 128 + 0 + 32 32 + 16 + 4 + 2 + 1 = 183 1 0 1 1 0 1 1 1 De todos modos, esta transformación la he puesto simplemente para que se comprenda con más claridad cómo funcionan los números binarios. Es mucho
Manual de Lenguaje Ensamblador
más más acon aconsej sejabl able e el uso uso de una una calc calcul ulado adora ra cient científ ífic ica a que que permi permita ta real realiz izar ar conversiones entre decimales, hexadecimales y binarios. Se hace su uso ya casi imprescindible al programar. La razón del uso de los números binarios es sencilla. Es lo que entiende el ordenador, ya que interpreta diferencias de voltaje como acti activa vado do (1) o desa desact ctiivado vado (0) (0), aunq aunque ue no det detall allaré aré esto esto.. Cada ada byte byte de información está compuesto por ocho dígitos binarios, y a cada cifra se le llama bit. El número utilizado en el ejemplo, el 10110111, sería un byte, y cada una de sus ocho cifras, un bit. Y a partir de ahora, cuando escriba un número binario, lo haré con la notación usual, con una "b" al final del número (ej: 10010101b) La conversión a hexadecimal es muy utilizada en ensamblador, se trata de un sistema de numeración en base dieciséis. Por tanto, hay dieciséis símbolos para cada cifra, y en vez de inventarse para ello nuevos símbolos, se decidió adoptar las primeras letras del abecedario. Por lo tanto, tendremos ahora: Hex Dec 1 --> 1 2 --> 2 3 --> 3 4 --> 4 5 --> 5 6 --> 6 7 --> 7 8 --> 8 9 --> 9 A --> 10 B --> 11 C --> 12 D --> 13 E --> 14 F --> 15 10 --> 16 11 --> 17 Etc,... Como Como vemo vemos, s, este este sist sistema ema nos nos plan plante teas as bast bastant antes es prob proble lema mass para para la conversión, una calculadora científica será casi imprescindible para realizar esta operación. Por Por que que util utiliizar zar este este sist sistem ema? a? Bien Bien senc senciillo. lo. Volva olvamo moss al byt byte, y traduzcamos su valor más alto, "11111111". Resulta ser 256. Ahora pasemos esta cifra al sistema hexadecimal, y nos resultará "FF". Obtenemos un número más comp compre rens nsib ible le que que el bina binari rio o (dif (difíc ícil il de reco record rdar ar), ), y ante ante todo todo much mucho o más más compacto, en el que dos cifras nos representaran cada byte. Podremos además traducir fácilmente el binario a hexadecimal con esta tabla; cada cuatro cifras binarias pueden traducirse al hexadecimal:
Manual de Lenguaje Ensamblador
Binari Hexadecim o al 0000 0 0001 1 0010 2 0011 3 0100 4 0101 5 0110 6 0111 7 1000 8 1001 9 1010 A 1011 B 1100 C 1101 D 1110 E 1111 F Por ejemplo, el número binario: 1111 0011 1010 1110 En hexadecimal sería: 1111 0011 1010 1110 F 3 A E Para referirnos a un número hexadecimal sin especificarlo, usaremos la notación que se suele usar al programar, con un 0 al principio (necesario cuando hay letras) y una h al final, por ejemplo, el número anterior sería 0F3AEh
7. OPERACIONES CON BYTES Hay cuatro operaciones básicas que se pueden realizar con un número binario, y coinciden con operaciones de la lógica matemática, con lo que cualquiera que la haya estudiado tendrá cierta ventaja para entenderla. Para explicarlas, llamar‚ al valor 0 resultado "falso", y al valor 1 "verdadero". Las operaciones son AND, OR, XOR y NOT 7.1. AND Es un 'y' lógico. Se realiza entre dos cifras binarias confrontando cada cifra con su correspondiente, y el resultado será "1" si las dos son verdaderas (si las dos valen "1”), y "0" (falso) en el resto de los casos. AND 1er. numero 1 1 0 0
2do. numero 1 0 1 0
Resultad o 1 0 0 0
Vuelvo a la lógica para explicarlo más claramente: Imaginemos la frase: "El hombre es un mamífero y camina erguido". El hecho de que el hombre sea un mamífero es cierto (1), y el de que camine erguido, otro (1). Por lo tanto, al unirlos mediante una conjunción (‘y’ o ‘AND’), resulta que ya que se dan las dos, la oración es verdadera. Pongamos un ejemplo más complejo, queremos realizar un AND lógico entre dos bytes: 11011000 AND 01101001 Observemos lo que sucede: 11011000 01101001 En sistema decimal sería: AND 01001000 es mas lioso) 72
216 105
AND
(aunque en sistema decimal
Cuando coinciden dos valores de "verdad", el resultado es "verdad", si uno es falso, el resultado es "falso" (no es verdad que "El hombre es un mamífero y respira debajo del agua”), y si los dos son falsos, el resultado es falso (no es cierto que "El hombre es un ave y respira debajo del agua”) 7.2. OR
Manual de Lenguaje Ensamblador
El "o" lógico. El resultado es "verdadero" cuando al menos uno de los factores es verdadero. O sea, es "1" cuando al menos uno de los dos factores es "1". Sería como la frase "Voy a buscar el peine o la caja de bombones", donde que uno sea cierto no significa que el otro no lo sea; es cierta la frase, es verdadera mientras uno de los términos sean verdaderos.
Operemos con los números "10100110" y "01101100": 10100110
OR
01101100 --------
11101110
Como hemos visto, el valor 1 (verdadero) queda en las cifras de las que, confrontadas, al menos una es verdadera. Sólo resulta 0 (falso) si los dos números enfrentados son 0 (falsos). 7.3. XOR "OR" exclusivo. Se trata de una orden parecida al OR, tan sólo que la verdad de una excluye la de la otra. El resultado, por tanto, es "1" (verdad) cuando uno y sólo uno de los dos números es verdadero (y el otro falso, claro). Sería como la oración "O vivo o estoy muerto", para que sea cierta se tiene que dar una de las dos, pero nunca las dos o ninguna. 10111001
XOR 01011101
-------- 11100100
La orden XOR va a ser bastante útil en encriptación, pero eso ya es otra historia,... 7.4. NOT Esto se aplica sobre un sólo número, y en términos de lógica sería la negación de una oración, o sea, si el número al que se aplica es 1 el resultado es 0, y viceversa. En términos de lógica matemática aplicándolo a una oración, sería por ejemplo, " No es verdad que tenga ganas de estudiar y de no beber ", negando las otras dos que en caso contrario serían verdad: NOT 11100110
--------
00011001
Bytes, bits y demás Tan sólo, por si alguien no lo conoce, se quiere detallar el modo de almacenamiento del ordenador, incluyendo lo más temido por el iniciado en Ensamblador, y más engorroso para el programador, segments y offsets.
Manual de Lenguaje Ensamblador
La unidad mínima de información es el bit. Su estado, como vimos anteriormente, puede ser 1 o 0. Un conjunto de ocho bits, forman un byte. De ellos, el de la derecha es el menos significativo (su valor es menor), y el de m s a la izquierda el más significativo. Un Kbyte es un conjunto de 1024 (que no 1000) bytes. Igualmente, un MegaByte serán 1024 kbytes, o 1024*1024=1048576 bytes. Otro término que se utilizará a menudo, es palabra, o "word". Una "palabra", es un conjunto de dos bytes, y se utiliza por que a menudo se opera con ellas en lugar de bytes. Segments y offsets: Hubo un tiempo, cuando los dinosaurios dominaban la tierra, en el que a "alguien" se le ocurrió que con 640K debería de bastarnos para hacerlo todo. Y por aquí comienzan los problemas: El ancho de bus de direcciones, para localizar un punto en memoria, es de 20 bits. Por lo tanto, el número máximo de direcciones de memoria a las que podremos acceder ser 1 Mb. Pero como veremos, 20 bits no son ni 2 bytes ni 3, sino así como 2 y medio %-). El problema es ordenarlos para que el procesador conozca la dirección de memoria, y aquí llegan las cosillas,... Se Necesitará para conocer una posición de memoria de cuatro bytes combinados de una curiosa manera. Hay que imaginar los dos bytes inferiores. Su mayor valor puede ser 0FFFFh (poner un cero delante es una convención, para que lo entiendan los ensambladores, al igual que la h al final indicando que es un número hexadecimal). Esto nos da acceso a 64Kb de memoria, que se considera un bloque. También, a partir de ahora, se llamará Offset a la dirección indicada por estos dos bytes. Ahora se desea más memoria que 64 Kb, y para esto se poseen los otros dos bytes. Para formar la dirección completa, se toman los 16 bits del registro de segmento y se sitúan en los 16 bits superiores de la dirección de 20 bits, dejando los otros cuatro a cero. Vamos, como si se añade cuatro ceros a la derecha, y se suma a este valor de 20 bits, el Offset, da el resultado de la dirección real de memoria A continuación se presentará una demostración gráfica para el mejor entendimiento: Sea el valor de Segmento 0Ah (o decir, 10 decimal o 1010b, en binario). Y el del Offset que va a valer (en binario) 01011111 00001010. La suma para obtener la dirección de memoria sería tal que así: 0000 0000 0000 1010 0000 (segmento multiplicado*16, con 4 ceros mas) + 0101 1111 0000 1010 (el offset)
Manual de Lenguaje Ensamblador
-------------------------------------0000 0101 1111 1010 1010 Y esta sería la dirección *real* de memoria (05FAAh o 24490 Dec). Como puedes observar, y como curiosidad final, distintos segments y offsets especifican direcciones de memoria distintas; por ejemplo, los pares 0040h: 0000 (donde el primero es el Segment y el segundo el Offset, así lo tomaremos a partir de ahora), son iguales que 0000:0400h, y los dos se referirían a la misma posición de memoria física, la 0400h o 1024d. Espero que haya quedado claro, aunque sea simplemente tener una ligera idea. Lo próximo serán los registros, y (y ahora me pongo como los del Pcmanía cuando hablan de Windoze95) podremos empezar en serio con nuestro lenguaje favorito X-)
8. JUEGO DE REGISTROS Quizá alguno de vosotros se está preguntando a estas alturas: ¨ Y eso del Segment y Offset, dónde se guarda, que indica al ordenador esos sitios en memoria, que indica al ordenador en que punto de la memoria esta y que tiene que ejecutar? Pues bien, para esto y mucho mas sirven los registros. Se trata de una serie de "variables", que contienen información que puede ser cambiada. Comenzaré, al contrario que todos los libros, por los de segmento y offset actual: CS e IP. El registro CS es una variable de un tamaño de dos bytes. Contiene el Segmento actual en que se encuentra el programa. IP, es la variable, de dos bytes también, que contiene el Offset actual. Esto significa, el ordenador va interpretando las secuencias de bytes, pero necesita "algo" que le indique donde tiene que leer. La combinación CS: IP (tal y como me referí antes en lo de segments & Offsets) contiene la dirección en la que el ordenador est interpretando información *en el momento*. O sea, indica la dirección de la próxima instrucción que se va a ejecutar. El registro DS y el registro ES también sirven para guardar direcciones de Segmentos, y también son variables de dos bytes, ser n utilizada para por ejemplo mover datos en memoria, imprimir cadenas, bueno, un etcétera largísimo. Digamos que son "punteros", que apuntan a cierta zona de memoria (siempre combinado con otro que haga de Offset, claro). El registro SS apunta a la pila, y el SP es el que contiene el offset de la pila, pero esto lo explicaré mas adelante. Luego tenemos una serie de registros que utilizaremos mas comúnmente: AX, BX, CX y DX. Todas ocupan dos bytes, y se pueden utilizar divididas en dos partes de longitud un byte, cambiando de nombre. AX se divide en AH y AL, BX en BH y BL, CX en CH y CL y DX en DH y DL. La 'H' se refiere a High en inglés, alto (de mayor valor), y la 'l' a Low (de menor valor). Lo ilustro un poquillo: AX |-----------------------------| 11010110 10111000 AH AL Las funciones de estos cuatro registros son diferentes:
Manual de Lenguaje Ensamblador
AX se suele utilizar como propósito general, indica función a las interrupciones, etc., y es el más flexible, ya que ser el único que permita multiplicaciones y divisiones. Se denomina a veces acumulador. BX nos servirá mucho como "handler", para abrir/cerrar archivos, etc., y como registro de propósito general al igual que AX, CX y DX. CX se suele usar como contador. DX suele ser el puntero, señalando haciendo el papel de Offset lugares en memoria (suele combinarse con DS en la forma DS: DX). Y nos quedan ya sólo tres registros, BP, SI y DI, que son también punteros. SI y DI los utilizaremos a menudo para copiar bytes de un lado a otro, etc. Ni que decir que, como el resto de registros, contienen dos bytes. Igual sucede con BP, de otros dos bytes de tamaño. 9.- ¿QUÉ ES... LA BIOS? 9.1 CONFIGURACIÓN AVANZADA Y DEL CHIPSET Son parámetros que indican qué características del chipset deben habilitarse y cómo. Afecta habitualmente a la memoria RAM, a las caches (interna y externa) y a veces al micro, a los buses ISA, Vesa, PCI y AGP y a otros dispositivos como los puertos serie y paralelo. Este terreno puede ser algo peligroso, así que apunte todo antes de cambiar nada; lo más fácil es dejar las más opciones que pueda en Auto, aunque con eso puede que no saque el máximo de rendimiento. Y es que para ganar hay que sufrir...
Manual de Lenguaje Ensamblador •
•
•
Auto Configuración: pues eso, configuración automática; la tabla de salvación cuando no se consigue hacer a mano. Los valores que da tras una primera autoconfiguración pueden ser válidos como punto de partida, así que como siempre, apúntelos antes de modificarlos. ISA Bus Clock : la velocidad del bus ISA, que en teoría debe ser unos 8 MHz. A veces se introduce como una cifra en MHz y otras veces en función del bus del sistema (el PCLK), por ejemplo como 1/3 cuando éste es a 33 MHz, como en los 386 y 486 a 33 MHz o 486 a 66 y 100 (que van a 33 externamente). Cuanto más rápido sea el bus, mejor, pero no se pase: 10 ó 12 MHz ya está bien, más puede ser arriesgado y se supone que las tarjetas ISA no están preparadas para nada por encima de 8.
Velocidad de la RAM: en esto existen múltiples formas de proceder. Evidentemente, cuanto mayor le indiquemos que es la velocidad de la RAM más rápido irá el sistema, pero en muchas ocasiones la RAM no es tan rápida o de calidad como sería deseable y la estabilidad del sistema se resiente, sobre todo al cargarlo de trabajo. Los valores que indican esta velocidad son los ciclos de acceso a RAM, los ciclos de espera ( Clock Cycles o, a veces, Wait States) que el rápido microprocesador concede a la lenta RAM antes de mandarle o leer de ella la información. En casi todas las BIOS existen opciones para configurar automáticamente estos valores; en algunas BIOS basta con introducir la velocidad en nanosegundos de la memoria, así como su tipo (normal -FPM-, EDO o SDRAM); en otras se debe poner la cifra más baja en ciclos. Por ejemplo, una ráfaga habitual en lectura ( Read) puede ser 7-3-3-3, y se suele solicitar ese 3 como valor de DRAM Read Timing o DRAM Read Wait State (o Write para escritura). Para EDO o FPM rápida ese 3 puede ser un 2 y para SDRAM suele ser un 1. El 7 puede ser menor, incluso un 5 si tenemos un buen chipset y memoria rápida. Otras veces se indica la velocidad de la memoria simplemente describiéndola como Slowest, Slower, Faster y Fastest , de menos a más rápida. Así que mire los valores por defecto y vaya subiéndolos (o bajándolos, si son ciclos de espera) de uno en uno, tras lo cual reinicie y observe el
Manual de Lenguaje Ensamblador
•
•
•
•
rendimiento y la estabilidad del ordenador. Pruebe con Windows 9x, NT o similar, así como con algún juego exigente (mismamente Quake), no con el viejo DOS, que lo soporta casi todo. En cuanto note inestabilidad, vuelva al valor anterior y ya está. Ajustes de la caché: similares a los de la RAM. Algunos consisten en modificar los tiempos de acceso, otros en modificar la forma de acceder a la caché. De cualquier forma, esto depende enteramente de las capacidades de la caché misma, así que juegue poco con estos valores. Para los arriesgados o curiosos, el modo Write Back es mejor que el Write Thru (o Through ), aunque no puede usarse siempre. Vídeo y System Cacheable (Shadow): como se comentó en el apartado de opciones de la BIOS, copiar la BIOS de la tarjeta de vídeo o del sistema de la lenta ROM a la rápida RAM o, en este caso, usar la caché para lo mismo. Se supone que debería aumentar el rendimiento, pero puede dar problemas con sistemas operativos de 32 bits modernos. Manejo de dispositivos: hoy en día los chipsets deben manejar las controladoras de dispositivos tales como discos duros, puertos serie, etc., que suelen estar incorporadas a la placa base. No lo explicaremos por ahora, puesto que muchas veces existe un menú dedicado en exclusiva a este apartado, denominado generalmente Integrated Peripherals. Configuración por software de la CPU: en la actualidad, bastantes placas base han dejado de lado el método clásico para configurar la CPU y han optado por soluciones jumperless (literalmente, "sin jumpers"), autodetectando los valores correctos de velocidad de bus, multiplicador y voltaje y/o permitiendo que el usuario los seleccione mediante un sencillo menú en la BIOS. Como ejemplo tenemos el programa SoftMenu presente en las conocidas placas base Abit, entre ellas la BH6, que durante meses ha sido la placa de ensueño para los overclockers . Y es que aunque esta característica ahorra tiempo y complicaciones a cualquiera, donde se ve toda su potencia es cuando queremos ver hasta dónde podemos forzar nuestro micro... sin pasarnos y sabiendo que esto se supone que anula su garantía, ojo. 9.2. PERIFÉRICOS INTEGRADOS
Las placas base modernas (desde las de los últimos 486) suelen tener integrados los chips controladores del disco duro, y en muchas ocasiones manejan también las disqueteras, los puertos serie y el puerto paralelo. Por ello, las BIOS tienen diversos apartados para manejar estos dispositivos, entre ellos: •
•
Conexión o desconexión de dichas controladoras: de especial importancia en el caso del segundo canal IDE, que en ocasiones está deshabilitado por defecto, y que deberemos habilitar para conectar más de dos dispositivos IDE (o bien uno lento y uno rápido sin mezclarlos en el mismo canal, lo que baja el rendimiento). Modos de acceso a discos duros (PIO y/o UltraDMA): los discos modernos admiten 5 modos PIO, del más lento, el PIO-0 o no soporte de
Manual de Lenguaje Ensamblador
•
•
•
este tipo de acceso (en discos antiguos, de 100 MB o menos), hasta el más rápido, el modo PIO-4. Además, recientemente ha aparecido el modo UltraDMA, aún más rápido. Si la controladora está integrada en la placa base, aquí debe especificar esos datos. Búsquelos en el manual de su disco duro, en Internet en la página del fabricante o bien seleccione Auto y no se complique más. Direcciones e interrupciones (IRQs) de los puertos : bien sean los puertos serie o el paralelo. Resulta muy raro necesitar cambiar los valores por defecto, pero podría ser necesario para evitar conflictos con otros dispositivos que usen esos mismos valores. Tipo de puerto paralelo: el antiguo estándar de puerto paralelo se ha quedado un tanto anticuado hoy en día, sobre todo si lo que queremos conectar no es una impresora sino un escáner o una unidad Zip; por ello, se suele poder seleccionar otras posibilidades más avanzadas como ECP o EPP. Busque en el manual del periférico para saber qué modo debe escoger. Control del puerto de infrarrojos: aunque muy pocas placas base incluyen los adaptadores y cables necesarios, modernamente casi todas traen los conectores para instalar un puerto de infrarrojos en su sistema. Generalmente deberá habilitarse y seleccionar su tipo, dirección de memoria, IRQ y si debe redireccionar la información de COM2 a este puerto. 9.3. ADMINISTRACIÓN DE ENERGÍA
En este menú, relativamente reciente (no se implantó hasta bien entrada la época de los 486), es donde se configuran las características de ahorro de energía del ordenador. Esto puede ser algo totalmente superfluo, por ejemplo si vamos a usar el ordenador de forma continuada al máximo de potencia, o bien algo fundamental, como ocurre en ordenadores portátiles o sencillamente si tenemos la mala costumbre de encender el ordenador al llegar a la oficina y no apagarlo hasta la hora de salir, tanto si lo vamos a usar como si no. •
•
•
Power Management: literalmente, administración de energía. Es donde se selecciona si queremos habilitar el ahorro de energía y de qué forma; generalmente se ofrecen Disable (deshabilitado), User define (definido por el usuario) y algunas opciones predeterminadas para un ahorro mínimo o máximo. PM Control by APM: una opción muy importante; determina si el control de energía deberá hacerse según el estándar APM ( Advanced Power Management , administración avanzada de energía), lo que entre otras cosas permite que Windows sea capaz de suspender el equipo a voluntad o, si utilizamos una fuente ATX, que el sistema efectivamente se apague al pulsar "Apagar el sistema" en el menú Inicio. Video Off Method: ofrece diversas opciones para reducir el consumo del sistema de vídeo, de las cuales la más interesante es DPMS, aunque no
Manual de Lenguaje Ensamblador
todos los monitores y tarjetas gráficas la soportan; lea el manual de estos aparatos para estar seguro, aunque si son modernos y de cierta calidad es muy probable que la incorporen. La opción Blank Screen es simplemente un salvapantallas negro, lo que puede ser útil en DOS.
•
PM Timers: para controlar el tiempo que debe permanecer inactivo el ordenador ( System) o el disco duro ( HDD) antes de que se active el ahorro de energía. Existen 3 grados de ahorro de energía: Doze: reduce la velocidad de la CPU (el microprocesador). Standby: reduce la actividad de todo el ordenador. Suspend: reduce al mínimo la actividad del ordenador; sólo debe utilizarse con CPUs tipo SL, como son la mayoría de los 486 rápidos y superiores. PM Events: una larga serie de eventos o sucesos que deben ser controlados para saber si el ordenador está inactivo o trabajando. Es habitual no controlar ( Disable) la actividad de la IRQ8 (reloj de la BIOS), ya que rara vez se la puede considerar como totalmente inactiva. CPU Fan Off in Suspend: si el ventilador de la CPU va conectado a la placa base, lo apaga cuando el equipo está en suspenso, ya que en ese momento la CPU está prácticamente parada. Modem Wake Up: activa el equipo cuando se detecta una llamada entrante en el módem. Necesita que el módem soporte esta característica y que esté conectado a la placa base mediante un cable especial. LAN Wake Up: igual que la anterior, pero para la tarjeta de red. También necesita estar conectado a la placa base mediante un cable. o o o
•
•
•
•
9.4. Configuración de PNP y slots PCI
Manual de Lenguaje Ensamblador
Un menú lleno de opciones complicadas (en esta página pocas no lo son), de la clase que sería deseable no tener que alterar nunca; ése es mi consejo, escoja Auto todas las veces que pueda, pero si tiene algún conflicto entre dispositivos (misma IRQ, sobre todo)... Probablemente se pregunte qué tiene que ver PNP con PCI; pues bien, la gran mayoría de dispositivos PCI soportan PNP, a diferencia de las tarjetas ISA, mucho más problemáticas. Por eso, si su placa no tiene slots PCI (como las primeras para 486), no se extrañe si este menú no aparece. Ah, para el que no lo conozca, el Plug&Play , PNP o P&P, es una tecnología que facilita la conexión de dispositivos, ya que se supone que basta con enchufar y listo. Claro que no todos los dispositivos son PNP ni es una tecnología perfecta, si fuera así este menú no existiría... •
•
•
•
•
PNP OS Installed: informa al sistema de si hay un sistema operativo PNP instalado, es decir, uno que soporta Plug&Play , como Windows 95 (o eso dicen que hace...), en cuyo caso pasa a éste el control de los dispositivos PNP. De cualquier forma, muchas veces lo que esta casilla indique no afecta al correcto funcionamiento del sistema. Resources Controlled by: pues eso, recursos controlados bien manual, bien automáticamente. De nuevo, muchas veces es indiferente una u otra opción... siempre que no haya problemas, claro. IRQx/DMAx assigned to: una lista de las interrupciones (IRQs) y canales DMA que podemos asignar manualmente, bien a tarjetas PCI/ISA PnP (compatibles con PNP), bien a tarjetas Legacy ISA (tarjetas ISA no PNP, que son las más conflictivas). Necesitaremos conocer los valores de IRQ y/o DMA a reservar, que vendrán en la documentación del dispositivo problemático . PCI IDE IRQ Map to: algo que muy probablemente no necesite cambiar nunca, ya que sólo afecta a controladoras IDE no integradas en la placa base, sino en forma de tarjeta, que no sean PNP. Assign IRQ to USB: pues eso, si el puerto USB debe tener una interrupción asignada o no. Si no tiene ningún dispositivo USB conectado (¿y quién los tiene hoy en día?) puede liberar esa IRQ para otros usos; suele ser la misma interrupción que para uno de los slots PCI o ISA. 9.5. AUTOCONFIGURACIÓN DE LA BIOS
Este apartado comprende diversas opciones que se proporcionan para facilitar la configuración de la BIOS, de las cuales las más comunes son: •
•
LOAD BIOS DEFAULTS: carga una serie de valores por defecto con poca o nula optimización, generalmente útiles para volver a una posición de partida segura y resolver problemas observados al arrancar. LOAD SYSTEM DEFAULTS: una opción cuyos efectos varían de unas BIOS a otras. En unos casos carga unos valores por defecto seguros (como LOAD
Manual de Lenguaje Ensamblador BIOS DEFAULTS), en otros carga unos valores ya optimizados para
•
conseguir un rendimiento adecuado, o incluso puede servir para cargar la última serie de valores guardados por el usuario. LOAD TURBO DEFAULTS: carga los valores que estima óptimos para incrementar el rendimiento.
En cualquier caso, debe tenerse en cuenta que los cambios no suelen ser guardados automáticamente, sino que deben confirmarse al salir de la BIOS. 9.6 Otras utilidades Las BIOS pueden hacer todavía más cosas, dependiendo del modelo en concreto; algunas de las más usuales están a continuación.
Autodetección de discos duros IDE Esta opción permite detectar los discos duros que están conectados al sistema, así como su configuración. Resulta muy útil para simplificar la tarea de instalar un disco nuevo, así como cuando los datos del disco no están completos o no parecen funcionar en nuestra BIOS.
Su uso es sencillísimo: se entra en este menú y se va detectando cada uno de los cuatro posibles dispositivos IDE. Apunte las opciones que le aparezcan y pruebe a usarlas; recuerde usar el modo LBA para discos de más de 528 MB. Tenga en cuenta que muchas veces sólo por entrar en esta utilidad se alteran
Manual de Lenguaje Ensamblador
automáticamente los valores de configuración del disco, así que después de salir de ella compruebe si los cambios corresponden a los que quería realizar. Control por password Es decir, por una clave de acceso en forma de palabra secreta que sólo conozca usted. Tenga en cuenta que si la olvida se verá en graves problemas, hasta el punto de tener que borrar toda la BIOS para poder volver a usar el ordenador, así que apúntela en algún lugar seguro. Se suele poder seleccionar, bien en un menú específico o en las BIOS Features, entr entre e tene tenerr que que intr introd oduc ucir ir la clav clave e cada cada vez vez que que se arra arranc nca a el ordenador o sólo cuando se van a cambiar datos de la BIOS. Lo primero es el método ideal para seguridad, y además es gratis; lo segundo es útil cuando gente inexperta pero manazas tiene acceso al ordenador (por ejemplo, su sobrinito el tocalotodo). Formateo de disco duro a bajo nivel O, en inglés, HDD Low Level Format . Se trata de un formateo mucho más intenso que el normal; no sólo elimina los datos, sino que reorganiza la propia estr estruc uctu tura ra del del disc disco. o. Ge Gene nera ralm lmen ente te sólo sólo debe debe usar usarse se cuan cuando do el disc disco o está está fall fallan ando do muy muy a menu menudo do o ha sido sido infe infect ctad ado o por por un viru viruss trem tremen enda dame ment nte e resistente, y aun así no resulta recomendable. Si será duro, que realizarlo ¡suele ser motivo de pérdida de la garantía del disco duro! En fin, si se atreve, ármese con los datos de configuración del disco (cilindros, cabezas...) y rece por no tener que interrumpirlo por nada del mundo, cortes de luz incluidos. Antivirus No, no crea que con esta opción podrá ahorrarse el comprar uno de esos programas antivirus tan tristemente necesarios en los PC. En realidad, lo único que suele hacer esta opción (que en ocasiones tiene un menú propio y en otras se engloba bajo el Standard Setup , tal vez con el nombre de Virus Warning) Warning) es no permitir que se escriba sobre la tabla de particiones o el sector de arranque del del disc disco o duro duro,, bien bien sólo sólo dura durant nte e el arr arranqu anque e o en cual cualqu quie ierr mome moment nto, o, dependiendo del modelo concreto de BIOS. La idea es impedir que un virus destroce el disco duro sin darle oportunidad a cargar un disquete de arranque con un antivirus para desinfectar el sistema; no impedirá la infección, pero es una medida más de seguridad y gratis. Por cierto, puede ser necesario deshabilitar esta opción durante la instalación del sistema operativo o al formatear el disco duro, no sea que la BIOS crea que se trata de un ataque viral.
Manual de Lenguaje Ensamblador
9.7 SALIR DE LA BIOS Pues Pues es senc sencil illo lo,, pero pero revi revisé sémo mosl slo o para para los los que que no enti entien enda dan n ingl inglés és en absoluto. Generalmente existen dos opciones: •
•
Save and Exit Setup: Setup : o bien Write to CMOS and Exit o algo similar; pues eso, grabar los cambios y salir, con lo cual se reinicia el equipo. Debería pedirle confirmación, confirmación, en forma de " Y/N?" (Yes o No). Exit Without Saving: Saving : o Do Not Write to CMOS and Exit o Discard Chang Changes es and Exit Exit o simil similar; ar; lo contra contrari rio, o, salir salir sin grabar grabar los los cambio cambios. s. También debería pedir confirmación.
9.8. ACTUALIZAR LA BIOS La BIOS maneja temas tan críticos como el soporte de uno u otro microprocesador; además, como programa que es, no está exenta de fallos y se revisa periódicamente para eliminarlos o añadir nuevas funciones. Antiguamente, la única forma de actualizar una BIOS era extraer el chip de BIOS y sustituirlo por otro, lo cual no se lo recomiendo a nadie, tanto por las posibles incompatibilidades como por lo delicado y caro de la operación. Modernamente han aparecido BIOS que pueden modificarse con un simple prog progra rama ma soft softwa ware re;; se las las deno denomi mina na Flash-BIOS, Flash-BIOS, y no son un invento desdeñable. Lo que es más, la existencia de una de estas BIOS o no debería ser argumento de peso a la hora de comprar una placa base, al menos entre los inform rmát átic icos os.. Teng Tenga a en cuen cuenta ta que que mant manten ener er un regi regist stro ro de BIOS BIOS manitas info actualizadas es un servicio que sólo ofrecen los grandes fabricantes de placas base... y aun así no siempre se puede encontrar la necesaria actualización. actualización. Vaya a Actualizar la BIOS para conocer los pasos concretos a seguir; eso sí, le aviso de que deberá asegurarse de que la operación de actualización no se interrumpe por nada del mundo, así que nada de hacer multitarea, meterle prisa o tocar el teclado mientras se actualiza; son unos segundos, pero de importancia crítica. ¿Adivina qué día del año va a saltar la luz? Efectivamente, justo cuando esté actualizando su BIOS.
9.9 LA BIOS Y LA PILA Como dijimos, la pila conserva los datos de la BIOS cuando el ordenador está apagado. Dura mucho (unos tres años de media), pero al final se agota. Para cambiarla, apunte todos los datos de la BIOS, desconecte todo y sustitúyala por una igual, o bien por un paquete
Manual de Lenguaje Ensamblador
externo de baterías que se conectan a un jumper (un microinterruptor) de la placa base; ambas cosas las debería encontrar en tiendas de electrónica. Después conecte todo, arranque el ordenador, entre en la BIOS y reintroduzca todos los datos, ya que se habrán borrado. ¿Se imagina si no tuviera una copia escrita qué aventura? A mí me pasó hace años, y no me quedó más remedio que aprender sobre BIOS... bueno, no hay mal que por bien no venga. 9.10: CÓMO SALTARSE LA PASSWORD DE LA BIOS No, no se trata de hacer ilegalidades en ordenadores ajenos, se trata de saber qué hacer si sufre una repentina amnesia o si la BIOS trae una password ya intr introd oduc ucid ida; a; por por ejem ejempl plo, o, una una BIOS BIOS con con la que que luch luché é una una vez vez tení tenía a como como password por defecto "AMI", el nombre de su fabricante. Además, en ordenadores de segunda mano pasa no pocas veces. Los métodos son pocos; realmente sólo uno, y muy radical: borrar la BIOS entera. entera. Para ello existen tres formas: •
•
•
Por Por softwa software re tipo tipo "hacke "hacker" r":: algun algunos os progr programa amass se espec especial ializa izan n en destrozar BIOS, y si tiene suerte quizá incluso le digan cuál es la password sin tener que borrar la BIOS. Busque en los "bajos fondos" de Internet... ¡y tenga cuidado con estos programas y con los posibles virus! Mediante un jumper en la placa base : en algunas, no todas, existe un jumper que al cerrarse (al conectarse ambas patillas), y tras unos minutos de espera, permite borrar la BIOS limpiamente. Desconectando Desconectando la pila: pila: drástico, brutal, pero absolutamente efectivo.
En fin, sea como sea, recuerde tener su copia en papel de la BIOS y de la password para no tener que llegar a estos extremos.
Manual de Lenguaje Ensamblador
II.- EL LENGUAJE ENSAMBLADOR. 1.- UN EJEMPLO CLASICO. En esta parte se describe lo que es el lenguaje ensamblador, no al ensamblador o al proceso de ensamblado. Aquí se tratará todo lo concerniente con el lenguaje ensamblador y el conjunto de directivas del Microsoft Macro Assembler v4.0. Si bien esto puede resultar bastante extenso y complejo, aquí sólo se describirán las instrucciones y directivas básicas. Para comenzar veamos un pequeño ejemplo que ilustra el formato del programa fuente. Este ejemplo está completamente desarrollado en lenguaje ensamblador que usa servicios o funciones de MS-DOS (system calls) para imprimir el mensaje Hola mundo!! En pantalla. ; HOLA.ASM ; Programa clásico de ejemplo. Despliega una leyenda en pantalla. STACK SEGMENT STACK ; Segmento de pila DW 64 DUP (?) ; Define espacio en la pila STACK ENDS DATA SEGMENT ; Segmento de datos SALUDO DB "Hola mundo!!",13,10,"$" ; Cadena DATA ENDS CODE SEGMENT ; Segmento de Codigo ASSUME CS: CODE, DS: DATA, SS: STACK INICIO: ; Punto de entrada al programa MOV AX,DATA ; Pone direccion en AX MOV DS, AX ; Pone la direccion en los registros MOV DX, OFFSET SALUDO ; Obtiene direccion del mensaje MOV AH, 09H ; Funcion: Visualizar cadena INT 21H ; Servicio: Funciones alto nivel DOS MOV AH, 4CH ; Funcion: Terminar INT 21H CODE ENDS END INICIO ; Marca fin y define INICIO La descripción del programa es como sigue: 1.- Las declaraciones SEGMENT y ENDS definen los segmentos a usar. 2.- La variable SALUDO en el segmento DATA, define la cadena a ser desplegada. El signo del dólar al final de la cadena (denominado centinela) es requerido por la función de visualización de la cadena de MS-DOS. La cadena incluye los códigos para carriage-return y line-feed.
Manual de Lenguaje Ensamblador
3.- La etiqueta START en el segmento de código marca el inicio de las instrucciones del programa. 4.- La declaración DW en el segmento de pila define el espacio para ser usado por el stack del programa. 5.- La declaración ASSUME indica que registros de segmento se asociarán con las etiquetas declaradas en las definiciones de segmentos. 6.- Las primeras dos instrucciones cargan la dirección del segmento de datos en el registro DS. Estas instrucciones no son necesarias para los segmentos de código y stack puesto que la dirección del segmento de código siempre es cargada en el registro CS y la dirección de la declaración del stack segment es automáticamente cargada en el registro SS. 7.- Las últimas dos instrucciones del segmento CODE usa la función 4CH de MS-DOS para regresar el control al sistema operativo. Existen muchas otras formas de hacer esto, pero ésta es la más recomendada. 8.- La directiva END indica el final del código fuente y especifica a START como punto de arranque. 2.- EL FORMATO DEL ENSAMBLADOR. De acuerdo a las convenciones y notación seguidas en el manual del Microsoft Macro Assembler, y que usaremos nosotros también, tenemos: Notación
Significado
Negritas
Comandos, símbolos y parámetros a ser usados como se muestra. Todo aquello que debe ser reemplazado por el usuario Indican un parámetro opcional Denota un parámetros que puede repetirse varias veces Separa dos valores mutuamente excluyentes Usada para ejemplos. Código y lo que aparece en pantalla.
Itálicas
,,, ¦ letra chica
Cada programa en lenguaje ensamblador es creado a partir de un archivo fuente de código ensamblador. Estos son archivos de texto que contienen todas las declaraciones de datos e instrucciones que componen al programa y que se agrupan en áreas o secciones, cada una con un propósito especial. Las sentencias en ensamblador tienen la siguiente sintaxis:
Manual de Lenguaje Ensamblador
comentarios]
[Nombre] mnemónico [operandos] [;
En cuanto a la estructura, todos los archivos fuente tienen la misma forma: cero o más segmentos de programa seguidos por una directiva END. No hay una regla sobre la estructura u orden que deben seguir las diversas secciones o áreas en la creación del código fuente de un programa en ensamblador. Sin embargo la mayoría de los programas tiene un segmento de datos, un segmento de código y un segmento de stack, los cuales pueden ser puestos en cualquier lugar. Para la definición de datos y declaración de instrucciones y operandos el MASM reconoce el conjunto de caracteres formado por letras mayúsculas, letras minúsculas (excluyendo caracteres acentuados, ñ, Ñ), números, y los símbolos: ? @_$:.[]()‹›{}+-/*&%!´~¦ \ =# ˆ;,"‘ La declaración de números requiere tener presente ciertas consideraciones. En el MASM un entero se refiere a un número entero: combinación de dígitos hexadecimales, octales, decimales o binarios, más una raíz opcional. La raíz se especifica con B, Q u O, D, o H. El ensamblador usará siempre la raíz decimal por defecto, si se omite la especificación de la raíz (la cual se puede cambiar con la directiva .RADIX). Así nosotros podemos especificar un entero de la siguiente manera: dígitos, digitosB, digitosQ o digitosO, digitosD, digitosH. Si una D o B aparecen al final de un número, éstas siempre se considerarán un especificador de raíz, e.g. 11B será tratado como 11 2 (210), mientras que si se trata del número 11B16 debe introducirse como 11Bh. Para los números reales tenemos al designador R, que sólo puede ser usado con números hexadecimales de 8, 16, ó 20 dígitos de la forma digitosR. También puede usarse una de las directivas DD, DQ, y DT con el formato [+¦-] digitos.digitos [E [+¦-] dígitos]. Las cadenas de carácter y constantes alfanuméricas son formadas como ´caracteres´ o "caracteres”. Para referencias simbólicas se utilizan cadenas especiales denominadas nombres. Los nombres son cadenas de caracteres que no se entrecomillan y que deben comenzar con una A..Z ¦ a..z ¦ _ ¦ $ ¦ @ los caracteres restantes pueden ser cualquiera de los permitidos, y solamente los 31 primeros caracteres son reconocidos. 3.- DIRECTIVAS. El MASM posee un conjunto de instrucciones que no pertenecen al lenguaje ensamblador propiamente sino que son instrucciones que únicamente son reconocidas por el ensamblador y que han sido agregadas para facilitar la tarea de ensablamblado, tanto para el programador como para el programa que lo lleva a cabo. Dichas instrucciones son denominadas directivas. En general, las directivas son usadas para especificar la organización de memoria, realizar ensamblado condicional, definir macros, entrada, salida, control de archivos, listados, cross-reference, direcciones e información acerca de la estructura de un
Manual de Lenguaje Ensamblador
programa y las declaraciones de datos. El apéndice D proporciona una lista completa de estas directivas. Conjunto de instrucciones: Dentro de las directivas más importantes, tenemos las que establecen el conjunto de instrucciones a soportar para un microprocesador en especial: . 8086(def ault) . 8087(def ault) .186 .286c .289p .287
Activa las instrucciones para el 8086 y 8088 e inhibe las del 80186 y 80286. Activa instrucciones para el 8087 y desactiva las del 80287. Activa las instrucciones del 80186. Activa instrucciones del 80286 en modo no protegido. Activa instrucciones del 80286 en modo protegido y no protegido. Activa las instrucciones para el 80287
Declaración de segmentos: En lo que respecta a la estructura del programa tenemos las directivas SEGMENT y ENDS que marcan el inicio y final de un segmento del programa. Un segmento de programa es una colección de instrucciones y/o datos cuyas direcciones son todas relativas para el mismo registro de segmento. Su sintaxis es: Nombre SEGMENT [alineación] [combinación] [´clase´] Nombre ENDS El nombre del segmento es dado por nombre, y debe ser único. Segmentos con el mismo nombre se tratan como un mismo segmento. Las opciones alineación, combinación, y clase proporcionan información al LINK sobre cómo ajustar los segmentos. Para alineación tenemos los siguientes valores: byte (usa cualquier byte de dirección), word (usa cualquier palabra de dirección, 2 bytes/word), para (usa direcciones de párrafos, 16 bytes/parráfo, deafult), y page (usa direcciones de página, 256 bytes/page). Combinación define cómo se combinarán los segmentos con el mismo nombre. Puede asumir valores de: public (concatena todos los segmentos en uno solo), stack (igual al anterior, pero con direcciones relativas al registro SS, common (crea segmentos sobrepuestos colocando el inicio de todos en una misma dirección), memory (indica al LINK tratar los segmentos igual que MASM con public, at address (direccionamiento relativo a address). clase indica el tipo de segmento, señalados con cualquier nombre. Cabe señalar que en la definición está permitido el anidar segmentos, pero no se permite de ninguna manera el sobreponerlos.
Manual de Lenguaje Ensamblador
Fin de código fuente: Otra directiva importante es la que indica el final de un módulo. Al alcanzarla el ensamblador ignorará cualquier otra declaración que siga a ésta. Su sintaxis es: END [expresión] La opción expresión permite definir la dirección en la cual el programa iniciará. Asignación de segmentos: La directiva ASSUME permite indicar cuales serán los valores por default que asimilan los registros de segmento. Existen dos formas de hacer esto: ASSUME registrosegmento:nombre,,, ASSUME NOTHING NOTHING cancela valores previos. Etiquetas: Las etiquetas son declaradas Nombre: Donde nombre constituye una cadena de caracteres. regla
Declaración de datos: Estos se declaran según el tipo, mediante la [Nombre] directiva valor,,,
donde directiva puede ser DB (bytes), DW (palabras), DD (palabra doble), DQ (palabra cuádruplo), DT (diez bytes). También pueden usarse las directivas LABEL (crea etiquetas de instrucciones o datos), EQU (crea símbolos de igualdad), y el símbolo = (asigna absolutos) para declarar símbolos. Estos tienen la siguiente sintaxis: Nombre = expresión Nombre EQU expresión Nombre LABEL tipo FAR.
Donde tipo puede ser BYTE, WORD, DWORD, QWORD, TBYTE, NEAR,
Declaración de estructuras: Para la declaración de estructuras de datos se emplea la directiva STRUC. Su sintaxis es: Nombre STRUC campos Nombre ENDS
Manual de Lenguaje Ensamblador
4.- CONJUNTO DE INSTRUCCIONES. El juego completo de instrucciones reconocidas por los procesadores intel 8086 a 80286, junto con los coprocesadores 8087 y 80287, se enlistan en el apéndice E. Como puede verse en dicho apéndice, la mayoría de las instrucciones requieren algunos operandos o expresiones para trabajar, y lo cual es válido también para las directivas. Los operandos representan valores, registros o localidades de memoria a ser accesadas de alguna manera. Las expresiones combinan operandos y operadores aritméticos y lógicos para calcular en valor o la dirección a acceder. Los operandos permitidos se enlistan a continuación: Constantes: Pueden ser números, cadenas o expresiones que representan un valor fijo. Por ejemplo, para cargar un registro con valor constante usaríamos la instrucción MOV indicando el registro y el valor que cargaríamos dicho registro. mov ax,9 mov al,´c´ mov bx,65535/3 mov cx,count count sólo será válido si este fue declarado con la directiva EQU. Directos: Aquí se debe especificar la dirección de memoria a accesar en la forma segmento:offset. mov ax,ss:0031h mov al,data:0 mov bx,DGROUP:block Relocalizables: Por medio de un símbolo asociado a una dirección de memoria y que puede ser usado también para llamados. mov ax, value call main mov al,OFFSET dgroup:tabla mov bx, count count sólo será válido si fue declarado con la directiva DW. Contador de localización: Usado para indicar la actual localización en el actual segmento durante el ensamblado. Representado con el símbolo $ y también conocido como centinela. help DB ´OPCIONES´,13,10 F1 DB ´ F1 salva pantalla´,13,10 .
Manual de Lenguaje Ensamblador
. . F10 DB ´ F10 DISTANCIA = $-help
exit´,13,10,´$
Registros: Cuando se hace referencia a cualquiera de los registros de propósito general, apuntadores, índices, o de segmento. Basados: Un operador basado representa una dirección de memoria relativa a uno de los registros de base (BP o BX). Su sintaxis es: Desplazamiento[BP] Desplazamiento [BX] [Desplazamiento][BP] [BP+desplazamiento] [BP].desplazamiento [BP]+desplazamiento En cada caso la dirección efectiva es la suma del desplazamiento y el contenido del registro. mov ax,[BP] mov al,[bx] mov bx,12[bx] mov bx,fred[bp]
Indexado: Un operador indexado representa una dirección de memoria relativa a uno de los registros índice (SI o DI). Su sintaxis es: desplazamiento[DI] desplazamiento[SI] [desplazamiento][DI] [DI+desplazamiento] [DI].desplazamiento [DI]+desplazamiento En cada caso la dirección efectiva es la suma del desplazamiento y el contenido del registro. mov ax,[si] mov al,[di] mov bx,12[di] mov bx,fred[si] Base-indexados: Un operador base-indexado representa una dirección de memoria relativa a la combinación de los registros de base e índice. Su sintaxis es:
Manual de Lenguaje Ensamblador
desplazamiento[BP][SI] desplazamiento[BX][DI] desplazamiento[BX][SI] desplazamiento[BP][DI] [desplazamiento][BP][DI] [BP+DI+desplazamiento] [BP+DI].desplazamiento [DI]+desplazamiento+[BP] en cada caso la dirección efectiva es la suma del desplazamiento y el contenido del registro. mov ax,[BP][si] mov al,[bx+di] mov bx,12[bp+di] mov bx,fred[bx][si] Estructuras: Su sintaxis es variable.campo. Variable es el nombre con que se declaró la estructura, y campo es el nombre del campo dentro de la estructura. date STRUC mes DW ? dia DW ? aa DW ? date ENDS actual mov mov
date ‹´ja´,´01´,´84´› ax,actual.dia actual.aa, ´85´
Operadores y expresiones: Se cuenta con los siguientes operadores: Aritméticos:
expresión1 * expresión2 expresión1 / expresión2 expresión1 MOD expresión2 expresión1 + expresión2 expresión1 - expresión2 + expresión - expresión De corrimiento:
Manual de Lenguaje Ensamblador
expresión1 SHR contador expresión1 SHL contador Relacionales:
expresión1 expresión1 expresión1 expresión1 expresión1 expresión1
EQ expresión2 NE expresión2 LT expresión2 LE expresión2 GT expresión2 GE expresión2
De bit:
NOT expresión expresión1 AND expresión2 expresión1 OR expresión2 expresión1 XOR expresión2 De índice:
[expresión1] [expresión2]
ejemplos:
cx,dgroup:1
mov mov mov
al, string[3] string[last],al cx,dgroup:[1]
; igual a mov
De apuntador:
tipo PTR expresión tipo puede ser BYTE ó 1, WORD ó 2, DWORD ó 4, QWORD ó 8, TBYTE ó 10, NEAR ó 0FFFFh, FAR ó 0FFFEh. Ejemplos: call FAR PTR subrout3 mov BYTE ptr [array], 1 add al, BYTE ptr [full_word] De nombre de campo:
estructura.campo ejemplos:
inc month.day mov time.min,0
Manual de Lenguaje Ensamblador
mov [bx].dest De propósito especial:
OFFSET expresión: Regresa el desplazamiento del operando mov bx, OFFSET dgroup:array mov bx, offset subrout3 SHORT etiqueta: Para un salto de menos de 128 bytes jmp su tipo
SHORT loop
LENGTH variable: Regresa el número de elementos de variable según mov cx,length array SIZE variable: Regresa el tamaño en bytes alojados para variable. mov cx,size array SEG expresión: Regresa el valor del segmento para expresión mov ax, SEG saludo
5.- MACROS Y PROCEDIMIENTOS. La manera más fácil de construir el programa en módulos, es dividirlo en dos o más partes. Para esto, es necesario que datos, símbolos, y demás valores de un módulo sean reconocidos por el otro u otros módulos. Para este tipo de declaraciones globales existen dos directivas: PUBLIC nombre,,, que hace la variable, etiqueta o símbolo absoluto disponible para todos los programas. EXTRN nombre:tipo,,, que especifica una variable, etiqueta o símbolo externos identificados por nombre y tipo (que puede ser BYTE, WORD, DWORD, QWORD, TBYTE, NEAR, FAR, o ABS, éste último para números absolutos). El siguiente ejemplo ilustra el uso de las directivas. El primer listado corresponde al módulo principal, mientras que el segundo al módulo que contiene una rutina. Ambos módulos son archivos que se editan por separado, se ensamblan por separado, pero se ligan juntos. MODULO PRINCIPAL: MAIN.ASM
Manual de Lenguaje Ensamblador
NAME PUBLIC EXTRN stack
main exit print:near
stack
SEGMENT word stack 'STACK' DW 64 DUP(?) ENDS
data data
SEGMENT word public 'DATA' ENDS
code
SEGMENT byte public 'CODE' ASSUME cs:code, ds:data
start:
exit: code
mov ax,data mov ds,ax jmp print
; carga localizacion del segmento ; en el registro DS ; va a PRINT en el otro modulo
mov ah,4ch int 21h ENDS END start
SUBMODULO: TASK.ASM NAME task PUBLIC print EXTRN exit:near data entrada salida data
SEGMENT word public 'DATA' DB "Entrando a un submodulo....",13,10,"$" DB ".......saliendo del submodulo.",01,07,13,10,"$" ENDS
code
SEGMENT byte public 'CODE' ASSUME cs:code, ds:data
print:
mov mov mov mov mov mov int mov mov int
ah,06h ; Funcion para borrar pantalla al,0 ; todas las lineas cx,0 ; de 0,0 dh,24d dl,79d bh,0 ; atributo en lineas vacias 10h ; Servicio de e/s video dx, OFFSET entrada ah,09h 21h
Manual de Lenguaje Ensamblador
code
mov int jmp ENDS END
dx, OFFSET salida 21h exit ; Regresa al otro modulo
La declaración de macros se hace a través de las directivas MACRO y ENDM. Su sintaxis es: nombre MACRO [parámetros,,,] declaraciones ENDM Los parámetros son los valores que se substituirán en la macro cada vez que se haga referencia a ésta. Para la definición de procedimientos se emplean las directivas PROC y ENDP. Su sintaxis es: nombre PROC [distancia] sentencias nombre ENDP La distancia, que puede ser NEAR (default) o FAR permiten indicar el tipo de acciones a realizar en brincos y llamados a subrutinas. nombre se puede usar como dirección en llamados o brincos. 6.- INTERRUPCIONES. Como se mencionó anteriormente la PC esta constituida lógicamente por su BIOS y sistema operativo. La mayoría de las rutinas que controlan al computador están grabadas en el ROM del BIOS, aunque muchas rutinas son establecidas por el sistema operativo y se cargan en RAM al momento de encender al computador. Estas rutinas son denominadas interrupciones y son activadas mediante la instrucción: INT número. Una interrupción es una operación que invoca la ejecución de una rutina específica que suspende la ejecución del programa que la llamó, de tal manera que el sistema toma control del computador colocando en el stack el contenido de los registros CS e IP. El programa suspendido vuelve a activarse cuando termina la ejecución de la interrupción y son restablecidos los registros salvados. Existen dos razones para ejecutar una interrupción: (1) intencionalmente como petición para la entrada o salida de datos de un dispositivo, y (2) un error serio y no intencional, como sobreflujo o división por cero. El operando de una interrupción indica cúal es la rutina a activar. La dirección de la rutina es localizada por medio de una tabla que el sistema mantiene a partir de la dirección 0000:0000h. Existen 256 entradas de 4 bytes de longitud, y cada interrupción proporciona varias funciones. Las interrupciones de
Manual de Lenguaje Ensamblador
00h a 1Fh correponden al BIOS y de 20h a FFh son del DOS y BASIC. El apéndice F proporciona una lista de las interrupciones para equipo XT .
III.- CREACION Y DEPURACION DE PROGRAMAS EN LENGUAJE ENSAMBLADOR 1.- EDICION. Los archivos fuente de código ensamblador deben estar en formato ASCII standard. Para esto puede usarse cualquier editor que permita crear archivos sin formato, e.g. Edlin, Edit, Write, El editor del Turbo Pascal, Works, Word, WordStar, etcétera. Las declaraciones pueden ser introducidas en mayúsculas y/o minúsculas. Una buena práctica de programación es poner todas las palabras reservadas (directivas e instrucciones) en mayúsculas y todo lo del usuario en minúsculas para fines de facilidad de lectura del código. Las sentencias pueden comenzar en cualquier columna, no pueden tener más de 128 caracteres, no se permiten líneas múltiples ni códigos de control, y cada línea debe ser terminada con una combinación de line-feed y carriage-return. Los comentarios se declaran con ; y terminan al final de la línea. 2.- ENSAMBLADO. El ensamblado se lleva a cabo invocando al MASM. Este puede ser invocado, usando una línea de comando, de la siguiente manera:
Manual de Lenguaje Ensamblador
MASM archivo [,[objeto][,[listado][,[cross]]]]][opciones][;] donde: Archi Corresponde al programa fuente. Por default se toma la extensión .ASM. Objet Es el nombre para el archivo objeto. o Lista Nombre del archivo de listado de ensamblado. do Cross Es un archivo de referencias cruzadas. Opciones Pueden ser: /A: escribe los segmentos en orden alfabético /S: escribe los segmentos en orden del fuente /Bnum: fija buffer de tamaño num /C: especifica un archivo de referencias cruzadas /L: especifica un listado de ensamble /D: crea listado del paso 1 /Dsym: define un símbolo que puede usarse en el ensamble /Ipath: fija path para búscar archivos a incluir /ML: mantiene sensitividad de letras (mayús./minús) en nombres /MX: mantiene sensitividad en nombre publicos y externos /MU: convierte nombres a mayúsculas /N: suprime tablas en listados /P: checa por código impuro /R: crea código para instrucciones de punto flotante /E: crea código para emular instrucciones de punto flotante /T: suprime mensajes de ensable exitoso /V: despliega estadísticas adicionales en pantalla /X: incluir condicionales falsos en pantalla /Z: despliega líneas de error en pantalla si el ; al final se omite es necesario poner todas las comas que se indican. Si no se quiere poner algún valor basta con dejar la coma.
Manual de Lenguaje Ensamblador
La otra forma de invocar al ensamblador es sólo tecleando MASM y respondiendo a la información que se solicita. Para omitir algún valor sólo basta teclear ENTER si dar ningún valor. 3.- LINK. De la misma forma que el ensamblado, la fase de liga se lleva a cabo con el LINK. Este puede ser invocado de la misma forma que el MASM. Los parámetros que este requiere son: LINK objeto [,[ejecutable][,[mapa][,[librería]]]]][opciones][;] donde: objeto ejecutab le mapa librería
Es el nombre para el archivo .OBJ Nombre del archivo .EXE Nombre del archivo mapa Nombre del archivo biblioteca de rutinas
opciones → Pueden ser: /HELP /PAUSE /EXEPACK /MAP /LINENUMBERS /NOIGNORECASE
muestra lista de opciones pausa en el proceso empaca archivo ejecutable crea mapa se símbolos públicos copia número de lineas al mapa mantiene sensitividad en nombres
/ NODEFAULTLIBRARYS no usa bibliotecas por default EARCH /STACK:size fija el tamaño del stack a usar / fija alojación máxima de CPARMAXALLOC:núme espacio ro fija la dirección de carga más /HIGH alta /DSALLOCATE aloja grupo de datos
Manual de Lenguaje Ensamblador
/ ignora asociaciones para NOGROUPASSOCIATIO direcciones N / número a la INT OVERLAYINTERRUPT:n asigan nuevo03Fh úmero procesa un número de /SEGMENTS:número segmentos sigue la convención de orden /DOSSEG de DOS 4.- EJECUCION. Para la ejecución del programa simplemente basta teclear su nombre en el prompt de MS-DOS y teclear ENTER. Con esto el programa será cargado en memoria y el sistema procederá a ejecutarlo. El proceso completo para poder crear un programa ejecutable con el Microsoft Macro Assembler se muestra abajo. Edición del Archivo Creación de un archivo sin formato (ASCII)
.asm
Ensamble
.obj
MASM programa
Liga LINK programa
.exe
Ejecución
programa
y lo que se vería en pantalla sería lo siguiente: C:\DATA\PROGRAMS\ASM>masm main Microsoft (R) Macro Assembler Version 4.00 Copyright (C) Microsoft Corp 1981, 1983, 1984, 1985. All rights reserved. Object filename [main.OBJ]: Source listing [NUL.LST]: Cross-reference [NUL.CRF]: 50966 Bytes symbol space free 0 Warning Errors 0 Severe Errors C:\DATA\PROGRAMS\ASM>masm task Microsoft (R) Macro Assembler Version 4.00 Copyright (C) Microsoft Corp 1981, 1983, 1984, 1985. All rights reserved.
Manual de Lenguaje Ensamblador
Object filename [task.OBJ]: Source listing [NUL.LST]: Cross-reference [NUL.CRF]: 51034 Bytes symbol space free 0 Warning Errors 0 Severe Errors C:\DATA\PROGRAMS\ASM>link main+task Microsoft (R) 8086 Object Linker Version 3.05 Copyright (C) Microsoft Corp 1983, 1984, 1985. All rights reserved. Run File [MAIN.EXE]: List File [NUL.MAP]: Libraries [.LIB]: C:\DATA\PROGRAMS\ASM>main Entrando a un submodulo.... .......saliendo del submodulo. C:\DATA\PROGRAMS\ASM> 5.- DEPURACION. Para la depuración de un programa en ensamblador tenemos disponibles dos herramientas. Por un lado tenemos el debuger que nos proporciona MS-DOS (DEBUG.EXE) y por otro lado tenemos el que nos proporciona Microsoft (SYMDEB.EXE). Este último trabaja igual que el de MS-DOS pero nos proporciona muchas ventajas más. Una de ellas es la facilidad de desplegar el código fuente correspondiente a la instrucción que se esta ejecutando (si el programa ejecutable fue ensamblado o compilado con un ensamblador o compilador compatible), nos permite ejecutar comandos del S.O. y nos permite obtener información de las interrupciones de manera simbólica. 5.1.- Uso de DEBUG de DOS I DOS y la cónsola de Windows incluyen un programa llamado DEBUG. La palabra "debug" podríamos traducirla por depurador, aunque realmente ésta no sea su traducción literal. Supuestamente, un depurador está destinado a la eliminación de "bichos", cucarachas en nuestros programas. Es una especie de insecticida. En terminos de programación, podemos decir que se trata de un programa para la localización de errores que afectan sensiblemente el funcionamiento de nuestros programas.
Manual de Lenguaje Ensamblador
Con el depurador podemos revisar paso por paso la ejecución de nuestro programa, revisar como va modificándose el contenido de los registros hasta ubicar donde está el "bicho" y aplastarlo. Imagino que el nombre se debe a que los primeros desperfectos en las primeras máquinas de cómputo electrónicas se debía generalmente a la presencia de cucarachas u otros insectos en los circuitos de tubos. El debug de DOS permite, entre otras cosas, editar archivos ejecutables y hasta escribir programas en lenguaje ensamblador. 5.2.- Uso de DEBUG II: Trazar un Programa DEBUG, como muchos otros programas auxiliares de la programación, trabaja con el sistema hexadecimal. Para ejecutar DEBUG escribimos DEBUG en el puntero de DOS o en el cuadro de ejecución (Inicio-Ejecutar) de Windows. Aparecerá sólo un guión que es el apuntador del DEBUG. Las diversas operaciones del DEBUG se indican con letras: A: assemble (ensamblar) C: compare (comparar) D: display (desplegar) E: enter (ingresar) F: full (llenar) G: go (ir) H: Hexadecimal I: in (entrada) L: load (cargar) M: move (mover) N: name (nombrar) O: out (salida) P: proceed (proceder) Q: quit (quitar) R: register (registro) S: search (buscar) trace (trazar o T: rastrear) unassemble U: (desensamblar) W: write (escribir) Ahora no las usaremos todas. Antes de escribir un programa con DEBUG, primero revisemos el que escribimos al comienzo. Cargamos el programa en el DEBUG: C:\tasm\works\primer>DEBUG primer.exe
Manual de Lenguaje Ensamblador
Ahora ingresamos la orden T, y obtendremos: -t AX=0E00 BX=0000 CX=0020 DX=0000 SP=0040 BP=0000 SI=0000 DI=0000 DS=0DEF ES=0DEF SS=0E01 CS=0DFF IP=0003 NV UP EI PL NZ NA PO NC 0DFF:0003 8ED8 MOV DS,AX Se trata de la segunda instrucción de nuestro programa. La instrucción MOV es una instrucción de asignación, parecida al operador "=" de C. Lo que hace es mover el contenido del segundo operando, aquí AX, que para el momento tiene la dirección del segmento de datos, al primer operando, DS. Antes de la ejecución de la instrucción DS=0DEF y AX=0E00; son valores hexadecimales. Ingresemos de nuevo t: -t AX=0E00 BX=0000 CX=0020 DX=0000 SP=0040 BP=0000 SI=0000 DI=0000 DS=0E00 ES=0DEF SS=0E01 CS=0DFF IP=0005 NV UP EI PL NZ NA PO NC 0DFF:0005 BA0400 MOV DX,0004 Ahora DS=0E00. Se ha movido lo que estaba en AX a DS. La siguiente instrucción mueve a DX la dirección de nuestra cadena. Habíamos escrito "LEA DX, string"; DEBUG lo ha interpretado como "mover a DX lo que está 4 bytes por encima del inicio del segmento de datos". Si se quiere verificar escribimos: D DS:4, desplegar lo que está 4 bytes después del inicio del segmento de datos: -d ds:4 0E00:0000 48 6F 6C 61-20 67 65 6E 74 65 21 24 Hola gente!$ 0E00:0010 C7 06 0E 96 3E 2B 2E C7-06 10 96 3D 3B E8 83 09 ....>+.....=;... 0E00:0020 73 13 B8 FF FF 53 26 8B-1D 26 3A 0F 73 03 B8 02 s....S&..&:.s... En 0E00+4 vemos el código hexadecimal correspondiente a nuestra cadena, que en la columna derecha podemos ver en ASCII. Podemos ver que el
Manual de Lenguaje Ensamblador
símbolo "$", que originalmente habíamos introducido como 36, y que en la columna del medio aparece en hexadecimal: 24. Sigamos trazando: -t AX=0E00 BX=0000 CX=0020 DX=0004 SP=0040 BP=0000 SI=0000 DI=0000 DS=0E00 ES=0DEF SS=0E01 CS=0DFF IP=0008 NV UP EI PL NZ NA PO NC 0DFF:0008 B409 MOV AH,09 Ahora moveremos a la parte superior de AX un nueve: -t AX=0900 BX=0000 CX=0020 DX=0004 SP=0040 BP=0000 SI=0000 DI=0000 DS=0E00 ES=0DEF SS=0E01 CS=0DFF IP=000A NV UP EI PL NZ NA PO NC 0DFF:000A CD21 INT 21 Vemos ahora que "AX=0900", que confirma que hemos movido 9 a la parte alta de AX. Se va a ejecutar la interrupción 21h, servicio 9; recuérdese que anteriormente habíamos escrito "int 33". DEBUG trabaja en hexadecimal, así que despliega la versión hexadecimal de lo que escribamos. Para trazar por encima de la interrupción, no es bueno usar T, ya que esto nos llevará a la rutina de la interrupción. Así que mejor ejecutamos P: -p Hola gente! AX=0924 BX=0000 CX=0020 DX=0004 SP=0040 BP=0000 SI=0000 DI=0000 DS=0E00 ES=0DEF SS=0E01 CS=0DFF IP=000C NV UP EI PL NZ NA PO NC 0DFF:000C B410 MOV AH,10 Esto despliega nuestra cadena en la cónsola. Observa que todos los registros se han mantenido iguales después de la interrupción, excepto AX; vemos que en la parte baja de AX, que es AL, aparece un 24h. Se trata del caracter "$". Quiere decir que el servicio 9 de la interrupción 21h usa el registro AL para revisar la cadena. Ahora moveremos 16 a AH. DEBUG lo presenta como "MOV AH, 10"; 10h = 16 decimal.
Manual de Lenguaje Ensamblador
Hacemos T: AX=1024 BX=0000 CX=0020 DX=0004 SP=0040 BP=0000 SI=0000 DI=0000 DS=0E00 ES=0DEF SS=0E01 CS=0DFF IP=000E NV UP EI PL NZ NA PO NC 0DFF:000E CD16 INT 16 Se va a ejecutar el servicio 16 o 10h de la interrupción 22 o 16h. Lo que hace este servicio es esperar a que el usuario pulse un tecla, cuyo código devuelve en AH el código de rastreo y en AL el código de la tecla. Para teclas de función extendida (F1 - F12) más importante es el código de rastreo, ya que como código de tecla se pasará 00, para las teclas F1-F12, E0h para para otras teclas de control como Inicio o RePag. Hacemos P y se ejecuta nuestra pausa; pulsamos cualquier tecla, en mi caso "enter": -p AX=1C0D BX=0000 CX=0020 DX=0004 SP=0040 BP=0000 SI=0000 DI=0000 DS=0E00 ES=0DEF SS=0E01 CS=0DFF IP=0010 NV UP EI PL NZ NA PO NC 0DFF:0010 B80000 MOV AX,0000 Código de rastreo en AH=1Ch y código de tecla en AL=0Dh. Ahora vamos a salir. Devolvemos el valor FALSE (=0) en AX a DOS. Un simple gesto de educación. AX=0000 BX=0000 CX=0020 DX=0004 SP=0040 BP=0000 SI=0000 DI=0000 DS=0E00 ES=0DEF SS=0E01 CS=0DFF IP=0013 NV UP EI PL NZ NA PO NC 0DFF:0013 CB RETF Por último regresamos a DOS. La instrucción RETF es una operación ceroaria (sin operandos) que significa RETURN FAR, regresar lejos. Recordemos que hemos declarado nuestro procedimiento así: main
proc
far
"main" es el nombre del procedimiento; proc es una directiva que indica inicio de una rutina o función (en ensamblador se llaman procedimientos a las funciones) y far indica que el procedimiento puede ser accedido desde otros segmentos. La instrucción RETF nos saca del procedimiento a la línea de órdenes.
Manual de Lenguaje Ensamblador
Hay otras formas más limpias de salir de un programa, pero con esta basta por ahora. Nota también que a la derecha de cada instrucción aparece la dirección en memoria, en sistema hexadecimal, de la instrucción, y luego es seguida por otra cifra en hexadecimal. Ésta última es la versión en hexadecimal del código de operación de la instrucción. Si no fuera por el sistema hexadecimal, ahí aparecerían una serie de unos y ceros. Con DEBUG también podemos obtener el código fuente en ensamblador de un fichero ejecutable. Esto se hace cargando el fichero y ejecutando la orden U, seguida por la dirección a partir de la cual queremos que se inicie el desensamblado y el número de líneas a desensablar: -u cs:00 0CE2:0000 B8E30C MOV AX,0CE3 0CE2:0003 8ED8 MOV DS,AX 0CE2:0005 BA0400 MOV DX,0004 2:0008 B409 MOV AH,09 0CE2:000A CD21 0CE2:000C B410 0CE2:000E CD16 0CE2:0010 B80000 0CE2:0013 CB
INT 21 MOV AH,10 INT 16 MOV AX,0000 RETF
Tememos aquí un desensamblado de nuestro código. También podemos obtener este desensamblado en un archivo de texto aparte: DEBUG primer.exeprim.asm Esta orden volcará en prim.asm un desensablado de los primeros 20 (14h) bytes de primer.exe, que podemos revisar con un editor. Podríamos escribir un fichero disasm.bat: cls @echo off @echo U CS:00 13>t_$ @echo.>>t_$ @echo Q>>t_$ 2echo.>>t_$ @echo Desensamblando.... DEBUG %1.exe%1_.asm EDIT %1_.asm Luego ejecutamos: disasm primer
Manual de Lenguaje Ensamblador
y ya! Podríamos mejorarlo para que desensamble exactamente las instruccciones del segmento de código; e incluso hacer que nuestro .BAT cambie algunos valores hexadecimales en el .EXE, pero no es este el lugar para explicarlo. 5.3.- Uso de DEBUG III: Escribir un Programa Escribamos ahora un programa con el DEBUG. Antes una observación sobre el formato de los ejecutables en DOS. Existen dos formatos: .COM y .EXE. El primero, .COM, es el formato original. En este formato, todo, código y datos, es puesto en un único segmento cuyo tamaño no debe exeder los 64KB. En el formato .EXE, que es posterior, se reserva un segmento para datos, uno para código y uno para la pila. Nuestro programa fue escrito en formato .EXE. Con el DEBUG se pueden escribir programas en formato .COM, que son bastante más pequeños. El programa debe comenzar a ejecutarse en la dirección 256 [100h], ya que los ejecutables de DOS reservan los primeros 256 bytes para colocar ahí una estructura de datos conocida como PSP, cuando es cargado en la memoria. El PSP (Program Segment Prefije: Prefijo de Segmento del Programa) contine información que será utilizada por el cargador de DOS. Así que comenzamos escribiendo A 100 [enter] -a 100 0DAB:0100 jmp 108 0DAB:0102 db "hola$" 0DAB:0107 nop 0DAB:0108 mov dx,102 0DAB:010B mov ah,9 0DAB:010D int 21 0DAB:010F mov ah,10 0DAB:0111 int 16 0DAB:0113 int 20 0DAB:0115 La primera instrucción ,"jmp 108", es saltar a la localidad 108. Necesitamos un espacio para nuestra cadena. Como no sabemos el tamaño del programa y no podemos determinar al comienzo donde estará la cadena si la ponemos al final del programa, la ponemos al comienzo, y para evitar que el programa comience a ejecutarse en la cadena (lo que daría error) le pasamos por encima. La instrucción jmp 108 tiene dos bytes, reservamos 6 bytes para la cadena. Nos sobra un byte, así que escribimos "nop" en 107, un operador ceroario que significa No operación. Vemos que la dirección de la cadena es
Manual de Lenguaje Ensamblador
102, así que ponemos este valor en DX; luego llamamos al servicio 9 (mov ah, 9) de la interrupción 21h (int 21) para desplegar la cadena. Luego ejecutamos el servicio 10h de la interrupción 16h (que detiene la ejecución del programa) y por último regresamos a DOS con la interrupción 20h. Pulsamos dos veces enter para salir de la orden A. Podemos probar de inmediato nuestro programa con la orden G: -g hola Debes pulsar ENTER para salir del programa. Se desplegará: "El programa ha finalizado con normalidad" Ahora debemos escribir nuestro programa a un archivo .COM en disco. Para ello empleamos la orden W [write]. Para realizar esta escritura correctamente, primero elegimos un nombre para el programa, como pr.com. La extensión debe ser .COM, porque W no puede crear ejecutables con formato .EXE; la orden es: -n pr.com
También debemos especificar el tamaño de nuestro ejecutable. W creará un archivo con el tamaño indicado en el registro CX; así que deberíamos poner en CX el tamaño de nuestro ejecutable empleando la orden R: -r cx CX 0000 :15 Finalmente, escribimos el archivo en disco: -w Escribiendo 00015 bytes Eso es todo. Luego lo ejecutamos. Salimos de DEBUG: -q y ejectamos pr.com: hola
Manual de Lenguaje Ensamblador
¿Todo bien? Observa el tamaño del archivo: 21 bytes (15h = 21 decimal) 6.- LA UTILERIA EXE2BIN Y LOS ARCHIVOS .EXE Y .COM . Para MS-DOS sólo existen dos tipo de archivos ejecutables los .COM y .EXE. Ambos archivos difieren en algunas cosas. Primero, las ventajas de los .EXE son dobles, nos permiten tener archivos reubicables y el uso de hasta cuatro segmentos (STACK, DATA, EXTRA y CODE) de hasta 64KB cada uno. Un archivo .COM sólo puede tener un segmento de 64KB, en el que se tiene tanto código como pila, y datos. La desventaja de los .EXE es que agregan 512 bytes como cabecera con información para la reubicación del código. Un .COM no es reubicable, siempre inicia en la dirección 0100H. Si nuestro programa no es muy grande 64KB son mas que suficientes. Por lo que conviene crearlo como .COM, para esto se cuenta con la utilería EXE2BIN.EXE que nos proporciona el sistema operativo. y que nos permite crear .COM a partir de .EXE . Las restricciones para esto son las suguientes: el archivo a convertir no debe estar empacado, no debe tener segmento de stack, debe tener sólo segmento de código y su tamaño debe ser menor a 64KB. Resumen del DEBUG Uso del DEBUG. Ingreso: Tipeamos la instrucción que se menciona seguidamente desde el prompt. C: \ DEBUG
> Después de dar enter aparecerá un guión
C:\>debug Ya estamos posicionados en el DEBUG y éste está preparado para recibir instrucciones en ASSEMBLER. Ejemplo 1: Ver las instrucciones permitidas en el ASSEMBLER básico. Tipeamos lo siguiente: -?? Y nos mostrará la información que sigue. Tipee y compruebe Ensamblar Comparar Volcar
A [dirección] C dirección de intervalo D [intervalo]
Manual de Lenguaje Ensamblador
escribir llenar ir hex entrada cargar mover nombre salida proceder salir registrar buscar seguimiento desensamblar escribir asignar memoria expandida desasignar memoria expandida asignar páginas de memoria expandida mostrar estado de la memoria expandida -
E dirección [lista] F lista de intervalos G [=dirección] [direcciones] H valor1 valor2 I puerto L [dirección] [unidad] [primer_sector] [número] M dirección de intervalo N [nombre_ruta] [lista_argumentos] O byte de puerto P [=dirección] [número] Q R [registrar] S lista de intervalos T [=dirección] [valor] U [intervalo] W [dirección] [unidad] [primer_sector] [número] XA [#páginas] XD [identificador] XM [Lpágina] [Ppágina] [identificador] XS
Note que al terminar aparece el guión que nos indica que el DEBUG tiene nuevamente el control de las operaciones, con lo cual Uds. podrán ingresar más comandos Cada una de la instrucciones que se mostraron anteriormente se irán explicando a lo largo de este apunte, donde aplicaremos un ejercicio específico para cada una de ellas incrementando las posibilidades, desde las más simples hasta las más complejas, para perfeccionar nuestro dominio de la programación. Ejemplo 2: Ver los registros. Este ejercicio nos permite que miremos el valor de varios registros y del registro de estado de la ALU (STATUS REGISTER). Para eso tipeamos: -r
Manual de Lenguaje Ensamblador
Y no muestra lo que sigue:
NC
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0100 NV UP EI PL NZ NA PO
1987:0100 8936C7DE MOV [DEC7],SI DS:DEC7=0000 El significado de los diferentes registros se da en la tabla siguiente. RE F AX
Nombre
Que es lo que hace
Acumulador
BX
Registro Base
CX
Registro Contador
DX
Registro de Datos
DS
Registro segmento datos Segmento para datos
Almacena el resultado de operaciones matemáticas; lectura / escritura (I/O) dede/hacia los puertos que están conectados con los periféricos; almacena también un área de memoria temporal. Alacena direcciones o valores y puede interactuar con el Acumulador. Utilizados para la ejecución de LOOPS y puede ser incrementado o decrementado según la instrucción que sea necesaria De acuerdo a la estructura de computadores analizada por nosotros corresponde al MDR (MEMORY DATA RGISTER) y es el paso intermedio para el ingreso de datos. Es un puntero que nos indica la dirección donde se encuentran los datos. Igual que el anterior pero apuntando a una dirección mayor. Indica donde se encuentra el STACK. Indica donde esta almacenado el código para la ejecución del programa. Registro complementario para
ES SS CS BP
de de extra
Registro de segmento de pila Registro de segmento código Puntero
del
Manual de Lenguaje Ensamblador
SI DI SP
IP
STACK no modificar el SS. Registro de Indice Alacena una dirección que nos de segmento indica donde se encuentra el vector de datos. Indice destino Contiene una dirección donde se copiara el vector de datos indicado por SI. Puntero de Pila (STACK POINTER) Permite saber donde se encuentra el último dato almacenado en el STACK. Siempre debe ser mayor o igual al SS o BP Apuntador de la (INSTRUCTION POINTER) siguiente También llamado PROGRAM instrucción COUNTER. Tiene almacenada la dirección de la próxima instrucción a ser ejecutada.
Ahora pasemos al registro bandera o STATUS REGISTER, que nos da el resultado de la actuación de la ALU Señal
RE
Función
RE
Overflo w Directio n Interrup ts Sign Zero Auxiliary Carr y Parity Carry
NV
No hay
OV
Hay
UP
Hacia adelante
DN
Hacia atrás
DI
Desactivadas
EI
Desactivadas
PL NZ NA
Valor positivo No es cero No hay acarreo
NG ZR AC
Valor negativo Es cero Hay acarreo
PO NC
Paridad impar No hay acarreo
PE CY
Paridad Par Se produjo acarreo
F
F
Función
El comando r (registro) nos permite interactuar con los registros de la CPU, posibilitando modificar sus contenidos. Cuando tipeamos r sin ningún otro parámetro nos muestra todos los registros con sus respectivos contenidos, pero si agregamos un parámetro nos va a mostrar solo el contenido del registro que nosotros mencionamos:
Manual de Lenguaje Ensamblador
:
-r bx BX 0000
Como podemos observar no nos devuelve el signo – sino que ahora nos muestra : para que ingresemos el valor que queremos que sea almacenado en el registro BX.
En el ejemplo vemos que BX tiene un valor 0000. Si ingresamos 5555 en : tendremos: -r bx BX 0000 :5555 -r AX=0000 BX=5555 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0100 NV UP EI PL NZ NA PO NC 1987:0100 8936C7DE MOV [DEC7],SI DS:DEC7=0000 En negrilla vemos que el registro BX quedó modificado con el nuevo valor tipeado. Suma y Resta. Ejemplo S1: Se pide sumar dos valores (200 y FFF) . Vamos a ingresar las siguientes instrucciones en el orden como se dan. Los números indicados - a 100 XXXX: 0100 XXXX: 0103 XXXX: 0106 XXXX: 0108 XXXX: 010A -
Indica que se debe comenzar a ingresar datos a partir de la posición 100 MOV AX, 200 Mover 200 al acumulador (AX) MOV BX, FFF Mover FFF al Registro Base (BX) ADD AX, BX Sumar BX a AX INT 20 Dar enter Aparece el signo del DEBUG que tiene el control.
Manual de Lenguaje Ensamblador
-a 1987:0100 mov ax,200 1987:0103 mov bx,FFF 1987:0106 add ax,bx 1987:0108 int 20 1987:010A Ingresemos ahora el comando –r -u Este comando nos muestra nuestro programa compilado y muchas otras instrucciones que se encuentran en máquina pero que a nosotros no os interesan y que solo sirven para ensuciar nuestro razonamiento, por ello es preferible el comando –u XXXX XXXX (desde-hasta).
1987:0100 B80002 1987:0103 BBFF0F 1987:0106 01D8 1987:0108 CD20 1987:010A B2E8 1987:010C 7421 1987:010E A0C9DE 1987:0111 0AC9 1987:0113 7505 1987:0115 3A45FF 1987:0118 7401 1987:011A AA 1987:011B 8B34 1987:011D 007619
MOV MOV ADD INT MOV JZ MOV OR JNZ CMP JZ STOSB MOV ADD
AX,0200 BX,0FFF AX,BX 20 DL,E8 01,2F AL, [DEC9] CL,CL 011A AL,[DI01] 011B SI,[SI] [BP+19], DH
por ello es preferible el comando –u XXXX XXXX (desde-hasta). Si ingresamos el comando –u0100 0108 nos muestra el programa compilado. No tipeamos hasta 010A porque esta posición de memoria no la utilizamos y aparece instruccines que nosotros no hemos introducido en el sistema.
-u 0100 0108 1987:0100 B80002 1987:0103 BBFF0F
MOV MOV
AX,0200 BX,0FFF
Manual de Lenguaje Ensamblador
1987:0106 01D8 1987:0108 CD20 -
ADD AX,BX INT 20
Hagamos un alto y veamos como queda nuestro programa. En la primer columna tenemos las posición de nuestras instrucciones comenzando desde la posición 0100 (las 4 primeras indican también la posición pero a ellas no nos referiremos por el momento). En la segunda aparece la compilación. Aquí hay algo realmente curioso: B80002 – El primer byte es el código de operación. Fácil de entender. El segundo corresponde a los dos últimos dígitos del número que nosotros queremos cargar en el acumulador. El tercer byte tiene los dos primeros número del número que nosotros ingresamos. Es decir que 0200 se representa en memoria como 0020. Complicado pero así funciona el INTEL y no vamos ahora a entrar en detalle. En la tercera y cuarta las instrucciones que nosotros ingresamos en lenguaje simbólico.
Llegó el momento de analizar los diferentes tamaños de las instrucciones que utilizamos: La primera y segunda corresponden a la sentencia MOV (mover) y tienen un longitud de 3 (tres ) bytes. La tercera corresponde a una instrucción de suma y tiene solo dos. La cuarta también tiene dos. Ejemplo S2: Como queda en memoria almacenado nuestro programa. Para ver nuestro programa almacenado debemos tipear el comando: -d (DISPLAY) que nos muestra la memoria. Esta está dividida en dos partes: a. La comprendida por caracteres hexadecimales que nos permiten ver todo el contenido de la memoria porque la combinación de bits en un nibble (4 bits) siempre tiene representación en hexadecimal. b. En caracteres, en castellano o ingles, pero noten que es inentendible porque normalmente la configuración de memoria no tiene una estructura semántica y sintáctica que podamos comprender. En otros ejercicios veremos que si podemos leer desde la memoria caracteres comprensibles. c. El guión que separa en dos partes la memoria expresada en hexadecimal no indica el cambio de palabra. Hasta donde llega nuestro programa está subrayado. 1987:01 B8 00 02 BB FF 0F 01 D8 - CD 20 ......... ..t!.. 00 B2 E8 74 21 A0 C9 ...u.:E.t...4. 1987:01 DE 0A C9 75 05 3A 45 FF - 74 01 v.
Manual de Lenguaje Ensamblador
10 1987:01 20 1987:01 30 1987:01 40 1987:01 50 1987:01 60 1987:01 70 -
AA 8B 34 00 76 19 C0 75 FA BA B2 E8 C7 06 - 19 DF CA 83 E8 10 00 0A DB 74 04 9D F8 EB 02 9D - F9 5E 5F 5A 59 5B C3 51 52 57 56 9C 8B FA 8B F2 - E8 6B F4 A2 DB E2 BF 98 DE 0A C0 74 03 BF F3 E5 - B9 13 00 E8 1E F5 72 65 C7 06 CA DE 00 00 C6 06 - CC DE 00 80 3E DB E2 00 74 07 81 C6 04 01 E8 A8 - F5 E8 52 00 3B 06 CA DE
.u.............. . t.......^_ZY[ .Q RWV......k.. .... ...t..........re ...........>... t.........R.;...
El resto es basura que no nos pertenece. Si nosotros podemos leer esa basura, se pueden imaginar que importante puede ser todo esta que queda en la memoria para un HACKER.
Ejercicio 5: Se pide sumar dos direcciones. Para este ejercicio nos falta conocer como se informan las direcciones. La manera es simple, entre corchetes [ ]. Ingrese las instrucciones que se dan a continuación. -a 1987:0100 mov ax,[0200] 1987:0103 mov cx,[0FFF] 1987:0107 add ax,cx 1987:0109 int 20 1987:010B Ahora vamos a ejecutar el programa. Partimos del comando r para que nos muestre el estado de los registros y la primera instrucción del programa. -r AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0100 NV UP EI PL NZ NA PO NC 1987:0100 A10002 MOV AX,[0200] DS:0200=A708 Vemos que AX = 0000 que CX= 0000 y que la dirección [0200] = A708 que está indicada por el registro DS que se encuentra en la parte inferior derecha del
Manual de Lenguaje Ensamblador
ejemplo y en negrilla. Ahora vamos a usar el comando TRACE que se representa por la letra t. Este nos permite ver paso a paso que sucede en nuestro computador. -t AX=A708 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0103 NV UP EI PL NZ NA PO NC 1987:0103 8B0EFF0F MOV CX,[0FFF] DS:0FFF=DB52 Vemos que la primera instrucción modificó el contenido del registro AX con el valor de DS. Esto está bien, porque es lo que nosotros pedimos. Si volvemos a tipear t ejecutaremos la segunda instrucción. -t AX=A708 BX=0000 CX=DB52 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0107 NV UP EI PL NZ NA PO NC 1987:0107 01C8 ADD AX,CX Vemos que ahora no aparece el registro DS porque en la instrucción que se va a ejecutar no mencionamos direcciones. -t AX=825A BX=0000 CX=DB52 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0109 NV UP EI NG NZ NA PE CY 1987:0109 CD20 INT 20 Se ha realizado la suma de los dos registros y algunas cosas se han modificado. a) El registro AX se ha modificado pero notemos que el nuevo valor es inferior al que ya teníamos almacenado. ¿Porqué? La respuesta es simple porque se ha producido un acarreo. Se recomienda realizar la suma manualmente para comprobar que lo sucedido es cierto. b) Veamos que el STATUS REGISTER ha modificado su valor indicándonos que eso ha sucedido, para mayor claridad lo marcamos en negrilla y en color. c) Compárelo con el DISPLAY anterior.
Manual de Lenguaje Ensamblador
Por último ejecutemos INT 20. -t AX=825A BX=0000 CX=DB52 DX=0000 SP=FFE8 BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=00CA IP=0FA8 NV UP DI NG NZ NA PE CY 00CA:0FA8 90 NOP Observemos que la nueva instrucción que aparece es un NOP (NO OPERATION) indicándonos que el programa ha terminado. NOTA: Podemos ejecutar directamente (t) pero nos mostrará la segunda instrucción a ejecutarse y la primera ya ejecutada. Tipee q en la línea de comando, vuelva a tipear DEBUG y cargue nuevamente el programa, posteriormente empiece directamente con el TRACE.
Resolver e informar. Utilice el comando TRACE (t) para ejecutar el programa. Ejercicio 1. Sumar el contenido de una dirección y de una constante. Ejercicio 2: Reste dos números utilizando registros. El primero menor que el segundo. La instrucción para restar es SUB. Verifique el valor de los bits del STATUS REGISTER Ejercicio 3: Suma y resta. Sume dos números y reste otro. Utilice constantes, no direcciones. Verifique el valor de los bits del STATUS REGISTER Ejercicio 4: Sume dos números y reste una dirección. División del acumulador en dos partes. Si ejecutamos el comando r podemos ver el contenido del acumulador. -r AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0100 NV UP EI PL NZ NA PO NC 1987:0100 A10002 MOV AX,[0200] DS:0200=A708 Como vemos AX = 0000 si tipeamos el comando r ax nos permite modificar el el acumulador, como muestra el ejemplo.
Manual de Lenguaje Ensamblador
-rax AX 0000 :faf7 -r AX=FAF7 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0100 NV UP EI PL NZ NA PO NC 1987:0100 A10002 MOV AX,[0200] DS:0200=A708 Comprobamos que está modificado. Pero también podríamos hacerlo de otra manera. Como dice el título el registro AX lo podemos dividir en parte alta y parte baja siendo sus códigos de reconocimiento AH (ACUMULATOR HIGH) y AL (ACUMULATOR LOW). Entones podemos escribir lo siguiente: -a 0100 1987:0100 mov ah,03 1987:0102 int 20 1987:0104 y ejecutarlo como lo hacemos hasta el presente (con el TRACE). -r AX=FAF7 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0100 NV UP EI PL NZ NA PO NC 1987:0100 B403 MOV AH,03 Observemos que cuando se ejecutó la instrucción MOV AH,03 el registro AX quedo modificado en su parte superior por el valor (03) que ingresamos. -t AX=03F7 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0102 NV UP EI PL NZ NA PO NC 1987:0102 CD20 INT 20 -t AX=03F7 BX=0000 CX=0000 DX=0000 SP=FFE8 BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=00CA IP=0FA8 NV UP DI PL NZ NA PO NC
Manual de Lenguaje Ensamblador
00CA:0FA8 90 NOP Así terminamos de ejecutar esta parte. Hagamos lo mismo con la parte inferior. -a100 1987:0100 mov al,bb 1987:0102 int 20 1987:0104 -r AX=03FF BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0100 NV UP EI PL NZ NA PO NC 1987:0100 B0BB MOV AL,BB -t AX=03BB BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0102 NV UP EI PL NZ NA PO NC 1987:0102 CD20 INT 20 -t AX=03BB BX=0000 CX=0000 DX=0000 SP=FFE8 BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=00CA IP=0FA8 NV UP DI PL NZ NA PO NC 00CA:0FA8 90 NOP Ahora vamos a sumar las dos partes que componen el acumulador (AX). Para eso hacemos el siguiente programa. -a100 00CA:0100 add ah,al 00CA:0102 int 20 00CA:0104 y lo ejecutamos. -r AX=03BB BX=0000 CX=0000 DX=0000 SP=FFE8 BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=00CA IP=0100 NV UP DI PL NZ NA PO NC 00CA:0100 00C4 ADD AH,AL -t
Manual de Lenguaje Ensamblador
AX=BEBB BX=0000 CX=0000 DX=0000 SP=FFE8 BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=00CA IP=0102 NV UP DI NG NZ NA PE NC 00CA:0102 CD20 INT 20 Podemos realizar la comprobación del resultado muy fácilmente. Multiplicación y división. En lo referente a la multiplicación podemos determinar dos tipos de instrucciones: MUL multiplica valores sin signo. IMUL multiplica valores con signo. Aquí tenemos algunas variantes que no se observaron el la suma y en la resta. Podemos multiplicar entidades de 8 bites y de 16 bits (una palabra) o 16 y 32 o... dependiendo del tamaño de la palabra y del procesador que estamos utilizando. Independientemente si queremos multiplicar por media palabra el valor debe estar en la parte baja del registro que vamo a utilizar, por ejemplo en AL y si queremos multiplicar por la palabra deberá ocupar todo el registro, es decir que deberá estar en AX por ejemplo. Ejemplo M1: Multiplicar valores de 8 bits sin signo Ingresamos el programa: C:\>debug -a 1987:0100 mov al,4 1987:0102 mov cl,5 1987:0104 mul al,cl 1987:0106 int 20 1987:0108 -g106 AX=0010 BX=0000 CX=0005 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0106 NV UP EI PL NZ NA PO NC 1987:0106 CD20 INT 20 Dos cosas importantes. La primera es que el programa se ha ejecutado y vemos el resultado en AX y podemos comprobar que está correcto y la segunda es que estamos usando un nuevo comando que es g que nos permite ejecutar
Manual de Lenguaje Ensamblador
completamente el programa que nosotros cargamos y nos muestra el resultado. Este tiene dos opciones: En el ejemplo M1 hemos ejecutado el programa parcialmente puesto que apuntamos hasta la instrucción almacenada en 0106 que es int 20, pero podemos ejecutar el programa hasta la 108 o 0108 ysucedería esto: -g108 El programa ha finalizado con normalidad -r AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0100 NV UP EI PL NZ NA PO NC 1987:0100 B004 MOV AL,04 Se ejecutó el programa totalmente y nos informa su correcta terminación pero no se muestran las variaciones de los registros. Ejecicio M2: Multiplicación de valores que provoquen un desbordamiento. En este caso vamos a utilizar dos valores que multiplicados superen la capacidad de almacenamiento de la parte baja del registro. -a 1987:0100 mov al,bb 1987:0102 mov cl,aa 1987:0104 mul al,cl 1987:0106 int 20 1987:0108 -g108 El programa ha finalizado con normalidad -r AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0100 NV UP EI PL NZ NA PO NC 1987:0100 B0BB MOV AL,BB En este caso no nos sirve de mucho, porque no nos deja ver nada, no muestra los resultados y solo podemos saber que el programa hace algo y que no da error, pero nada más. Por lo tanto siempres es preferible ingresar por el TRACE (t) para ver paso a paso que sucede. -r AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0100 NV UP EI PL NZ NA PO NC
Manual de Lenguaje Ensamblador
1987:0100 B0BB MOV AL,BB -t AX=00BB BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0102 NV UP EI PL NZ NA PO NC 1987:0102 B1AA MOV CL,AA -t AX=00BB BX=0000 CX=00AA DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0104 NV UP EI PL NZ NA PO NC 1987:0104 F6E0 MUL AL -t AX=8899 BX=0000 CX=00AA DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0106 OV UP EI PL NZ NA PO CY 1987:0106 CD20 INT 20 Realicen el cálculo de la multiplicación manualmente y observen que es lo que sucedió y porduzcan un informe con ello. Ejercicio M3: Multiplicación de valores con signo. -a 1987:0100 mov al,8 1987:0102 mov cl,-2 1987:0104 imul cl 1987:0106 int 20 1987:0108 -u 0100 0108 1987:0100 B008 MOV AL,08 1987:0102 B1FE MOV CL,FE es igual que decir mul ax,cl 1987:0104 F6E9 IMUL CL 1987:0106 CD20 INT 20 1987:0108 CC INT 3 Observemos que ya hay modificaciones . ¿Determine cuales y que es lo que sucedió y porqué? Ejecutamos el programa paso a paso. -r AX=0000 BX=0000 CX=0000 DX=0000 SP=FFE2 BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0100 NV UP DI PL NZ NA PO NC 1987:0100 B008 MOV AL,08 -t
Manual de Lenguaje Ensamblador
AX=0008 BX=0000 CX=0000 DX=0000 SP=FFE2 BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0102 NV UP DI PL NZ NA PO NC 1987:0102 B1FE MOV CL,FE -t AX=0008 BX=0000 CX=00FE DX=0000 SP=FFE2 BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0104 NV UP DI PL NZ NA PO NC 1987:0104 F6E9 IMUL CL -t AX=FFF0 BX=0000 CX=00FE DX=0000 SP=FFE2 BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0106 NV UP DI PL NZ NA PO NC 1987:0106 CD20 INT 20 Analicen que sucedió. ¿Qué pasa si tomamos AX en lugar de AL? ¿Qué sucedió con los bits de bandera? ¿Están correctos o hay errores en ellos? Realicen el informe correspondiente. Realice el mismo programa con la diferencia de la siguiente instrucción e informe el análisis particular y Mov cl,-1 comparativo
Realizados los ejemplos anteriores y convenientemente analizados podemos pasar a realizar ejercicios con registros completos. Informe cada uno de los ejercicios. Ejercicio M1: Multiplique dos números. Ejercicio M2: Multiplique un número positivo por un número negativo a) Con valores pequeños. b) Con valores grandes. Ejercicio M3: Multiplique dos números con signo negativo. Ejercicio M4: Ingrese el siguiente programa y analice los resultados -a 100 1987:0100 mov bx,ffff 1987:0103 mov cx,-1 1987:0106 imul cx 1987:0108 imul bx 1987:010A int 20 1987:010C -
Manual de Lenguaje Ensamblador
División. También está compuesta por dos instrucciones: DIV que divide dos valores sin signo. IDIV que divide dos valores con signo. En una división de valores enteros vamos a suponer que el dividendo siempre será mayor que el divisor, por lo menos para esta primera parte de nuestro estudio. De acuerdo a lo expresado pasemos a realizar nuestro primer ejemplo. Ejemplo D1: Dividir dos número enteros. Aclaraciones: Para un divisor de 8 bits el dividendo será de 16 bits, por lo tanto el dividendo lo ubicaremos en AX (16 bits) y el divisor en CL (8bits) El programa es: -a 1987:0100 mov ax,8 1987:0103 mov cl,4 1987:0105 div cl 1987:0107 int 20 1987:0109 -t
Daría lo mismo escribir div ax,cl
AX=0008 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0103 NV UP EI PL NZ NA PO NC 1987:0103 B104 MOV CL,04 -t AX=0008 BX=0000 CX=0004 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0105 NV UP EI PL NZ NA PO NC 1987:0105 F6F1 DIV CL -t AX=0002 BX=0000 CX=0004 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0107 NV UP EI NG NZ AC PE CY 1987:0107 CD20 INT 20 -
Manual de Lenguaje Ensamblador
Ejercicio D1: Realicen un programa utilizando dos números que no sean múltiplos y analaice el registro AX. Ejercicio D2: Realice un programa cuyo divisor sea cero e informe que sucede y porqué. Ejercicio D3: Realice un programa que permita dividir los siguientes valores FFFF y 2, pero en ste caso el divisor será BX. Observe todos los registros e informe. Ejercicio D4: Realice un programa que permita la diviidr FFFF por – 1 y analice.
Manual de Lenguaje Ensamblador
Bifurcaciones condicionales, incondicionales y repeticiones. Cuando hacemos un programa seguramente tendremos ue realizar en algún momento una pregunta que nos permita testear un registro, variable, archivo, etc., y optar por realizar tal o cual cosa dependiendo de que resultado nos devuelva el dato consultado. Por otro lado también existe la psibilidad de que después de ejecutar una serie de instrucciones debamos continuar el programa por otro lado saltando un montón de instrucciones, en este caso estamos utilizando un salto inconsicional , no hay ninguna condición previa , y por último podemos realizar una serie de repeticiones o iteraciones o LOOPS dentro de nuestro programa. Esto sucede enla mayoría de los programas y es por eso que esta nueva sección investiga las tres posibilidades. Ejemplo B1: Realizar un programa con un salto condicional. Para visualizar mejor las posibilidades de Verdadero y Falso que se pueden presentar utilizaremos dos variables alfabéticas. El programa -a 1987:0100 jmp 0113 1987:0102 -e 102 "Saltamos varias instrucciones verdad " 0d 0a "$" -a 113 1987:0113 mov dx,102 1987:0116 mov ah,9 1987:0118 int 21 1987:011A int 20 1987:011C -g Saltamos varias instrucciones verdad El programa ha finalizado con normalidad Para analizar las instrucciones que saltamos debemos hacer: -u 100 011a 1987:0100 EB11 1987:0102 53 1987:0103 61 1987:0104 6C 1987:0105 7461 1987:0107 6D 1987:0108 6F 1987:0109 7320 1987:010B 7661 1987:010D 7269
JMP 0113 PUSH BX DB 61 DB 6C JZ 0168 DB 6D DB 6F JNB 012B JBE 016E JB 0178
Manual de Lenguaje Ensamblador
1987:010F 61 DB 61 1987:0110 7320 JNB 0132 1987:0112 69 DB 69 1987:0113 BA0201 MOV DX,0102 1987:0116 B409 MOV AH,09 1987:0118 CD21 INT 21 1987:011A CD20 INT 20 En negrilla todas las instrucciones que saltamos, que por supuesto no son de nuestro programa. Otra manera de ver la ejecución de nuestro programa es utilizando el comando p. En este caso aconsejamos hacerlo indicando además la instrucción desde donde debe comenzar como en la secuencia que sigue. -p 100 AX=0000 BX=0000 CX=0000 DX=0102 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0116 NV UP EI PL NZ NA PO NC 1987:0116 B409 MOV AH,09 AX=0900 BX=0000 CX=0000 DX=0102 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0118 NV UP EI PL NZ NA PO NC 1987:0118 CD21 INT 21 HEMOS SALTADO VAR¦ ¦ -!¦ UCCIONES VERDAD AX=0924 BX=0000 CX=0000 DX=0102 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=011A NV UP EI PL NZ NA PO NC 1987:011A CD20 INT 20 El programa ha finalizado con normalidad -
Manual de Lenguaje Ensamblador
Pasaje de datos entre registros. Para realizar este ejercicio vamos a utilizar una nueva intrucción que es XCHG, que realiza el pasaje del contenido entre dos registros. No importa la manera en que de especifiquen los registros en la instrucción. Para ello damos el siguiente ejemplo: C:\>debug -a 100 1987:0100 mov ax,333 1987:0103 mov bx,222 1987:0106 xchg bx,ax 1987:0107 int 20 1987:0109 -t 3 AX=0333 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0103 NV UP EI PL NZ NA PO NC 1987:0103 BB2202 MOV BX,0222 AX=0333 BX=0222 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0106 NV UP EI PL NZ NA PO NC 1987:0106 93 XCHG BX,AX AX=0222 BX=0333 DI=0000 DS=1987 ES=1987 NC 1987:0107 CD20 o bien IP 0108 :100 -u100 108 1987:0100 B83303 1987:0103 BB2202 1987:0106 87C3 1987:0108 CD20 -r AX=0222 BX=0333 DI=0000 DS=1987 ES=1987 NC 1987:0100 B83303
CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 SS=1987 CS=1987 IP=0107 NV UP EI PL NZ NA PO INT
20
MOV AX,0333 MOV BX,0222 XCHG AX,BX INT 20 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 SS=1987 CS=1987 IP=0100 NV UP EI PL NZ NA PO MOV
AX,0333
Manual de Lenguaje Ensamblador
-t3 AX=0333 BX=0333 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0103 NV UP EI PL NZ NA PO NC 1987:0103 BB2202 MOV BX,0222 AX=0333 BX=0222 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0106 NV UP EI PL NZ NA PO NC 1987:0106 87C3 XCHG AX,BX AX=0222 BX=0333 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=1987 ES=1987 SS=1987 CS=1987 IP=0108 NV UP EI PL NZ NA PO NC 1987:0108 CD20 INT 20 Como podemos observar lo dicho anteriormente se cumple. Manejo de Disco con el DEBUGER Para comenzar vamos a formatear un diskette de la manera tradicional. El comando para realizar el formateo, para los que no lo recuerdan, es: FORMAT A:/S. C:\>format a:/s Inserte un nuevo disco en la unidad A: y presione Entrar cuando esté listo... Comprobando el formato del disco. Comprobando 1,44 MB Formato completado. Sistema transferido ¿Nombre del volumen? (11 caracteres, Entrar para ninguno)? PRUEBA1 1.457.664 bytes de espacio total en disco 389.632 bytes utilizados por el sistema 1.068.032 bytes disponibles en disco 512 bytes en cada unidad de asignación. 2.086 unidades de asignación libres en disco. El número de serie del volumen es 0A1B-1ED8
Manual de Lenguaje Ensamblador
¿Desea formatear otro disco (S/N)?N Bueno ya lo tenemos formateado. Ahora vamos a verificar la información que tenemos en el diskette. Para ello entramos en el DEBUG Como lo hacemos habitualmente. Una vez en el DEBUG vamos a utilizar el comando D (DUMP) indicándole la dirección desde la cual queremos empezar. Y mostrará lo siguiente:
Manual de Lenguaje Ensamblador
do
Coman ?? a g r t
Significado Permite ver el set de instrucciones básico del Assembler Abre el DEBUG para ingresar sentencias Permite la ejecutar un programa en forma completa o parcial Permite ver el estados de los registros Muestra paso a paso la ejecución. Corresponde al comando TRACE.
Manual de Lenguaje Ensamblador
APENDICE A.- MODELO DE REGISTROS DEL 8086
Bit 15
Bit 1
Bit 7
Bit 0Bit 7
Bit 0
AH
AL
AX (Acumulador)
BH
BL
BX (Base)
CH
CL
CX (Contador)
DH
DL
DX (Datos)
SP (Apuntador de pila) BP (Apuntador de base) SI (Indice a fuente) DI (Indice de destino)
Manual de Lenguaje Ensamblador APENDICE B.- REGISTROS EXPANDIDOS DEL 8087.
Manual de Lenguaje Ensamblador
Manual de Lenguaje Ensamblador
Manual de Lenguaje Ensamblador APENDICE C.- MODELO DE SEGMENTACION DE MEMORIA.
Manual de Lenguaje Ensamblador APENDICE D.- DIRECTIVAS DEL MASM. .186
Permite reconocer instrucciones microprocesadores 8086 y 80186.
.286c
Permite ensamblar instrucciones 80286 en modo no protegido, 8086 y 80186.
.286p
Activa el ensamble de instrucciones 80286 en modo protegido, 80186, 8086.
.287
Ensamblar instrucciones 80287 y 8087.
.8086
Modo por defecto. Activa el ensamble de instrucciones 8086 (idénticas para el 8088).
.8087
Activa el ensamble de instrucciones 8087. Modo por defecto.
nombre=expresión
Asigna el valor de expresión a nombre.
ASSUME segmentregister :segmentname...
para
Selecciona segmentregister que sea el segmento por defecto para todos los símbolos en el segmento o grupo nombrados. Si segmentname es NOTHING, ningún registro es seleccionado.
COMMENT delimitador texto delimitador
Trata como un comentario a todo texto dado entre delimitador y delimitador.
.CREF
Restablece el listado de referencia cruzada de símbolos.
[nombre] DB valor... [nombre] DW valor... [nombre] DD valor... [nombre] DQ valor... [nombre] DT valor... Aloja e inicializa un byte ( DB), una palabra (DW, 2 bytes), una palabra doble (DD), una palabra cuádruple (DQ), y 10 bytes ( (DT) de almacenamiento para cada valor . ELSE
Señala el inicio de un bloque alterno dentro de un bloque condicional.
Manual de Lenguaje Ensamblador END [expresión]
Señala el fin de un bloque y, opcionalmente, fija el punto de entrada a expresión.
ENDIF
Termina un bloque condicional.
ENDM
Termina una macro.
nombre ENDP
Marca el final procedimiento
nombre ENDS
Marca el final de la definición de una estructura o segmento
nombre EQU expresión
Asigna expresión a nombre.
.ERR
Genera error.
.ERR1
Genera error en el paso 1 únicamente.
.ERR2
Genera error en el paso 2 únicamente.
.ERRB
Genera error si argumento es blanco.
.ERRDEF nombre
Genera error si nombre ya ha sido definido.
.ERRDIF ,
Genera error si los nombres son diferentes.
.ERRE expresión
Genera error si expresión es falsa (o)
.ERRIDN ,
Genera error si las cadenas son idénticas.
.ERRNB
Genera error si el argumento no es blanco.
.ERRNDEF nombre
Genera error si nombre no se ha definido.
.ERRNZ expresión
Genera error (verdadera).
EVEN
Si es necesario, incrementa el contador de localidad a un número par y genera una instrucción NOP.
EXITM
Termina la expansión del bloque de repetición o macro y comienza a ensamblar la siguiente declaración fuera del bloque.
EXTRN nombre:tipo...
Declaración de símbolo externo.
de
si
la
definición
expresión
una
no
variable,
de
es
un
cero
etiqueta
o
Manual de Lenguaje Ensamblador nombre GROUP segmentname...
Asocia el nombre de un grupo con uno o más segmentos.
IF expresión
Permite el ensamble verdadera (no cero).
IF1
Ensambla sólo en el paso 1.
IF2
Ensambla sólo en el paso 2.
IFB
Ensambla si argumento es blanco.
IFDEF nombre
Ensambla si nombre ya ha sido definido.
IFDIF ,
Ensambla sólo diferentes.
IFE expresión
Ensambla si expresión es falsa (0).
IFIDN ,
Ensambla si los argumentos son idénticos.
IFNB
Ensambla si el argumento no es blanco.
IFNDEF nombre
Si nombre no ha sido definido permite el ensamble
INCLUDE filename
Inserta código indicado
IRP nombre,
Marca el inicio de un bloque de código que será repetido tantas veces como parámetros existan y en cada repetición nombre será reemplazado por cada parámetro.
IRPC nombre,
Marca el inicio de un bloque de código que será repetido tantas veces como caracteres tenga la cadena indicada y en cada repetición será substituido nombre por cada carácter.
nombre ETIQUETA tipo
Crea una nueva variable o etiqueta asignando el valor actual del contador de localidades y el tipo dado a nombre.
.LALL
Lista todas las declaraciones en una macro.
si
los
fuente
si
es
expresión
argumentos
desde
el
son
archivo
Manual de Lenguaje Ensamblador .LFCOND
Restablece el condicionales.
.LIST
Restablece el listado de declaraciones en el listado del programa.
LOCAL nombre...
Declara nombre dentro de una macro para que sea reemplazado por el nombre actual, cuando la macro sea expandida
nombre MACRO parámetro...
Marca el inicio de la macro nombre y establece cada parámetro para ser substituido por los respectivos parámetros cuando la macro sea llamada.
NAME módulo
Fija el nombre del módulo.
PURGE macro...
Borra las macros indicadas.
ORG expresión
Fija el contador de localidades expresión.
%OUT texto
Despliega texto en pantalla.
nombre PROC tipo
Señala el inicio de un procedimiento de determinado tipo.
PAGE longitud ,ancho
Fija los márgenes para el listado el programa (en caracteres).
PAGE+
Incrementa la numeración de página.
PAGE
Genera un corte de página en el listado.
PUBLIC nombre...
Hace que cada variable, nombre, etiqueta o símbolo absoluto declarado esté disponible para el resto de módulos en el programa.
.RADIX expresión
Fija la base a expresión para la introdución de números.
nombre RECORD campo:ancho[=expresión]..
REPT expresión
listado
de
bloques
Define una estructura para un registro de 8 ó 16 bits que contiene uno o más campos. Marca el incio de un bloque será repetido el número de veces indicado por expresión.
Manual de Lenguaje Ensamblador .SAL
nombre SEGMENT [alineación][combine]['clase']
Suprime el listado de las expansiones de macros.
Marca el inicio de un segmento del programa llamado nombre y que posee los atributos indicados.
.SFCOND
Suprime el listado de cualquier bloque condicional subsecuente cuya condición IF sea falsa.
nombre STRUC
Marca el comienzo en la definción de una estructura.
SUBTTL [texto]
Define un subtítulo para el listado.
.TFCOND
Fija por defecto condicionales.
TITLE texto
Títulos para los listados de los programas.
.XALL
Lista sólo aquellas macros que generen código o datos.
.XCREF [nombre...]
Suprime el cruzadas.
.XLIST
Suprime el listado de las líneas que sigan.
el
listado
listar
de
las
los
bloques
referencias
Manual de Lenguaje Ensamblador APENDICE E.- JUEGO DE INSTRUCCIONES DEL 8086, 8087, 80186, 80286 Y 80287. En la siguiente lista de instrucciones, para la descripción y su sintaxis se recurre a las siguientes abreviaturas: acum. reg segreg r/m inmed mem etiqueta src dest
Uno de los acumuladores: AX o AL. Cualquiera de los registros Uno de los registros de regmento Uno de los operandos generales: registro, memoria, basado, indexado o basado-indexado Constante o símbolo de 8 o 16 bits Un operando de memoria: símbolo, etiqueta, variable. Etiqueta de instrucciones. Fuente en operaciones de cadena Destino en operaciones de cadena.
Para el 8086/8088 AAA AAD AAM AAS ADC acum, inmed r/m,inmed r/m, reg reg, r/m ADD acum,inmed r/m,inmed r/m, reg reg, r/m AND acum,inmed r/m,inmed r/m, reg reg, r/m CALL etiqueta r/m CBW CLC CLD
Ajuste ASCII para adición. Ajuste ASCII para división. Ajuste ASCII para multiplicación. Ajuste ASCII para división.
Suma con acarreo.
Suma.
Operación AND a nivel bit.
Llamado. Convierte byte a palabra. Limpia bandera de acarreo. Limpia bandera de dirección.
Manual de Lenguaje Ensamblador CLI CMC CMP acum,inmed r/m,inmed r/m, reg reg, r/m CMPS src,dest CMPSB CMPSW CWD DAA DAS DEC r/m reg DIV r/m ESC inmed, r/m HLT IDIV r/m IMUL r/m IN accum,inmed acum, DX INC r/m reg INT 3 INT inmed INTO IRET
JMP etiqueta r/m
LAHF
Limpia bandera de interrupción. Complementa bandera de acarreo.
Comparación
Comparación de cadenas. Compara cadenas byte por byte. Compara cadenas palabra por palabra. Convierte palabra a palabra doble. Ajuste decimal para adición. Ajuste decimal para substracción. Decremento. División. Escape con 6 bits. Alto. División entera. Mutiplicación entera. Entrada desde puerto. Incremento. Interrupcion 3 codificada como un byte. Interrupción 0-255. Interrupción en overflow. Retorno de interrupción. Brinco incondicional. J(condición) etiqueta Brinca de acuerdo a las condiciones: A (arriba), AE (arriba o igual), B (siguiente), BE (siguiente o igual), C (acarreo), CXZ (CX en cero), E (igual), G (mayor), GE (mayor o igual), L (menor), LE (menor o igual), NA (no anterior), NAE (no anterior o igual), NB (no siguiente), NBE (no siguiente o igual), NC (no acarreo), NE (no igual), NG (no mayor), NGE (no mayor o igual), NL (no menor), NLE (no menor o igual), NO (no sobreflujo), NP (no paridad), NS (no signo), NZ (no cero), O (sobreflujo), P (paridad), PE (paridad par), PO (paridad impar), S (signo), Z (cero). Carga AH con las banderas.
Manual de Lenguaje Ensamblador LDS r/m LEA r/m LES r/m LOCK LODS src LODSB LODSW LOOP etiqueta LOOPE etiqueta LOOPNE etiqueta LOOPNZ etiqueta LOOPZ etiqueta MOV acum,mem r/m,inmed mem, acum r/m, reg r/m,segreg reg, inmed reg,r/m segreg,r/m MOVS dest, src MOVSB MOVSW MUL r/m NEG r/m NOP NOT r/m OR acum, inmed r/m,inmed r/m, reg reg,r/m OUT DX, accum inmed, acum POP r/m reg segreg POPF
Carga DS. Carga la dirección. Carga ES. Cierra bus. Carga cadena. Carga byte de cadena en AL. Carga palabra de la cadena en AX. Ciclo. Ciclo mientras igual. Ciclo mientras no igual. Ciclo mientras no cero. Ciclo mientras cero.
Mueve un valor del segundo al primer operando
Mueve cadena. Mueve cadena byte por byte. Mueve cadena palabra por palabra. Multiplicación. Niega (complemento a 2). Operación ociosa. Invierte valores de bits (complemento a1).
Operación OR a nivel de bit.
Salida por el puerto dado por el primer operando (inmediato de 8 bits). Recupera valor de la pila. Recupera banderas.
Manual de Lenguaje Ensamblador PUSH r/m reg segreg PUSHF RCL r/m,1 r/m,CL RCR r/m, 1 r/m, CL REP REPE REPNE REPNZ REPZ RET [inmed] ROL r/m,1 r/m, CL ROR r/m,1 r/m, CL SAHF SAL r/m, 1 r/m, CL SAR r/m, 1 r/m, CL SBB acum, inmed r/m,inmed r/m, reg reg,r/m SCAS dest SCASB SCASW SHL r/m, 1 r/m, CL SHR r/m, 1 r/m, CL STC STD STI STOS dest STOSB STOSW
Guarda valor en la pila. Guarda banderas. Rotación a la izquierda con acarreo. Rotación a la derecha con acarreo. Repite. Repite si igual. Repite si no igual. Repite si no cero. Repite si cero. Regresa después de recuperar bytes de la pila. Rotación a la izquierda. Rotación a la derecha. Carga banderas con el valor de AH. Desplazamiento aritmético a la izquierda. Desplazamiento aritmético a la derecha.
Substracción con acarreo.
Explora cadena. Explora cadena para el byte en AL. Explora cadena por la palabra en AX. Desplazamiento a la izquierda. Desplazamiento a la derecha. Fija bandera de acarreo. Fija bandera de dirección. Fija bandera de interrupción. Guarda cadena. Guarda byte en AL en la cadena. Guarda palabra en AX en la cadena.
Manual de Lenguaje Ensamblador SUB accum, inmed r/m,inmed r/m, reg reg,r/m TEST acum, inmed r/m,inmed r/m, reg reg,r/m WAIT XCHG acum, reg r/m,inmed r/m, reg reg,r/m XLAT XOR acum, reg r/m,inmed r/m, reg reg,r/m
Substracción.
Comparación.
Aguarda. Intercambio. Traduce.
Operación XOR a nivel bit.
Para el 8087 F2XM1 FABS FADD mem FADD ST, ST(i) FADD ST(i), ST FADDP ST(i), ST FBLD mem FBSTP mem FCHS FCLEX FCOM FCOM ST FCOM ST(i) FCOMP FCOMP ST FCOMP ST(i) FCOMPP FDECSTP FDISI
Calcula 2x-1. Toma valor absoluto del tope de la pila. Suma real. Suma real desde la pila. Suma real a la pila. Suma real y saca de pila. Carga un decimal empacado de 10 bytes en la pila. Almacena un decimal empacado de 10 bytes y saca de pila. Cambia signo del valor en el tope de la pila. Borra las excepciones después de un WAIT. Compara real. Compara real con el tope de la pila. Compara real con la pila. Compara real y saca de pila. Compara real con el tope de la pila y saca de pila. Compara real con el tope de la pila y saca. Compara real y saca dos valores de la pila. Decrementa el apuntador de la pila. Deshabilita las interrupciones depués de un WAIT.
Manual de Lenguaje Ensamblador
FLDL2E
División real. División real desde la pila. División real en la pila. División real sacando valor de la pila. División real invertida. División real invertida desde memoria. División real invertida desde la pila. División real invertida desde la pila. División con un real invertido y sacando valor de la pila. Habilita interrupciones después de un WAIT. Libera elemento de la pila. Suma entera de un número de 2 ó 4 bytes. Compara enteros de 2 ó 4 bytes y saca de la pila. Compara entero de 2 ó 4 bytes y saca de pila. División entera. División entera invertida. Carga un entero de 2, 4 u 8 bytes en la pila. Multiplicación entera de 2 ó 4 bytes. Incrementa el apuntador de la pila. Inicializa el procesador después de WAIT. Almacena entero de 2 ó 4 bytes. Almacena entero de 2, 4 u 8 bytes y saca de la pila. Resta entero de 2 ó 4 bytes. Resta entera de 2 ó 4 bytes invertida. Carga real de 4, 8 ó 10 bytes en la pila. Pone +1.0 en el tope de la pila. Carga la palabra de control. Carga entorno 8087 (14 bytes). Carga log 2 e en el tope de la pila.
FLDL2T
Carga log2 10 en el tope de la pila.
FLDLG2
Carga log10 2 en el tope de la pila.
FLDLN2
Carga log e 2 en el tope de la pila.
FLDPI FLDZ FMUL MUL mem FMUL ST, ST(i) FMUL ST(i), ST FMULP ST, ST(i) FNCLEX
Carga π en el tope de la pila. Carga +0.0 en el tope de la pila. Multiplicación real. Multiplicación real desde memoria. Multiplica real desde pila. Multiplica real a la pila. Multiplica real y saca de la pila. Borra excepciones sin WAIT.
FDIV mem FDIV ST, ST(i) FDIV ST(i), ST FDIVP ST(i), ST FDIVR FDIVR mem FDIVR ST, ST(i) FDIVR ST(i), ST FDIVRP ST(i), ST FENI FFREE FIADD mem FICOM mem FICOMP mem FIDIV mem FDIVR mem FILD mem FIMUL mem FINCSTP FINIT FIST mem FISTP mem FISUB mem FISUBR mem FLD mem FLD1 FLDCW mem FLDENV mem
Manual de Lenguaje Ensamblador FNDISI FNENI FNINIT FNOP FNSAVE mem FNSTCW mem FNSTENV mem FNSTSW mem FPATAN FPREM FPTAN FRNDINT FRSTOR mem FSAVE mem FSCALE FSQRT FST FST ST FST ST(i) FSTCW mem FSTENV mem FSTP mem FSTSW mem FSUB FSUB mem FSUB ST, ST(i) FSUB ST(i), ST FSUBP ST, ST(i) FSUBR FSUBR mem FSUBR ST, ST(i) FSUBR ST(i), ST FSUBRP ST(i), ST FTST FWAIT FXAM FXCH FFREE ST FREE ST(i)
Inhabilita interrupciones sin WAIT. Habilita interrupciones sin WAIT. Inicializa procesador sin WAIT. Operación nula. Salva estado 8087 (94 bytes) sin WAIT. Almacena la palabra de control sin WAIT. Guarda el entorno 8087 sin WAIT. Almacena el estado 8087 sin WAIT. Función arcotangente parcial. Residuo parcial. Función tangente parcial. Redondea a entero Restablece estado 8087 (94 bytes) Conserva el estado 8087 (94 bytes). Escala Raíz cuadrada Almacena real. Almacena real desde el tope de la pila. Almacena real desde la pila. Almacena palabra de control con WAIT. Guarda el entorno 8087 después de WAIT. Guarda real de 4, 8 ó 10 bytes y saca de la pila. Almacena la palabra de estado depués de WAIT. Substrae real. Substrae real desde memora. Substrae real desde la pila. Substrae real a la pila. Substrae real y saca de pila. Substracción real invertida. Substracción real invertida desde memoria. Substracción real invertida desde la pila. Substracción real invertida a la pila. Substracción real invertida a la pila y saca. Prueba el tope de la pila. Aguarda que la última operación 8087 termine. Examina el elemento del tope de la pila. Intercambia contenido de los elementos de la pila. Intercambia el elemento del tope de la pila. Intercambia el elemento del tope de la pila y el i-ésimo elemento.
Manual de Lenguaje Ensamblador FYL2X
Extrae el exponente y significando. Calcula Y log 2 X.
FYL2PI
Calcula Y log 2 (x+1)
FXTRACT
Para el 80186/80188/80286 (modo no protegido) BOUND reg, mem ENTER inmed16, inmed8 IMUL reg, inmed reg, r/m, inmed INS mem, DX INSB mem,DX INSW mem DX LEAVE OUTS DX, mem OUTSB DX, mem OUTSW DX, mem POPA PUSH inmed PUSHA RCL r/m, inmed RCR r/m, inmed ROL r/m, inmed ROR r/m, inmed SAL r/m, inmed SAR r/m, inmed SHL r/m, inmed SHR r/m, inmed
Detecta valor fuera de rango. Hace elemento en la pila para llamada a procedimiento. Multiplicación entera. Entrada de cadena desde el puerto DX. Entrada de cadena de bytes desde el puerto DX. Entrada de cadena de palabras desde el puerto DX. Deja procedimeinto. Salida de cadena de bytes o palabras al puerto DX. Salida de cadena de bytes al puerto DX. Salida de cadena de palabras al puerto DX. Saca todos los registros de la pila. Introduce a la pila Introduce todos los registros. Rotación a la izquierda con acarreo Rotación a la derecha con acarreo. Rotación a la izquierda. Rotación a la derecha. Desplazamiento aritmético a la izquierda. Desplazamiento aritmético a la derecha. Desplazamiento a la izquierda. Desplazamiento a la derecha.
Para el 80286 (modo protegido) ARPL mem, reg CLTS LAR reg, mem LGDT mem LIDT mem LLDT mem LMSW mem LSL reg, mem LTR mem SGDT mem
Ajusta petición de nivel de privilegio. Limpia bandera de conmutación de tareas. Carga derechos de acceso. Carga la tabla de descriptores globales (8 bytes). Carga tabla de descriptores de interrupciones (8 bytes). Carga la tabla de descriptores locales. Carga la palabra de estado. Carga el límite del segmento. Carga registro de tareas. Guarda la tabla de descriptores locales (8 bytes).
Manual de Lenguaje Ensamblador SIDT mem SMSW mem STR mem VERR mem VERW mem
Guarda tabla de descriptores de interrupciones (8 bytes). Guarda la palabra de estado. Guarda registro de tareas. Verifica acceso de lectura. Verifica acceso de escritura.
Para el 80287 FSETPM FSTSW AX FNSTSW AX
Fija modo protegido. Almacena palabra de estado en AX (aguarda). Almacena palabra de estado en AX (no aguarda).
Manual de Lenguaje Ensamblador APENDICE F.- INTERRUPCIONES. Dirección (Hex) 0-3 4-7 8-B C-F 10-13 14-17 18-1F 20-23 24-27 28-37 38-3B 3C-3F 40-43 44-47 48-4B 4C-4F 50-53 54-57 58-5B 5C-5F 60-63 64-67 68-6B 6C-6F 70-73 74-77 78-7B 7C-7F 80-83 84-87 88-8B 90-93 94-97 98-9B 9C-9F A0-FF 100-1FF
Interrupción (Hex) 0 1 2 3 4 5 6,7 8 9 A,B,C,D E F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 24 25 26 27 28-3F 40-7F
Función Division by zero Single step trace Nonmaskable interrupt Breakpoint instruction Overflow Print screen Reserved Timer Keyboard interrupt Reserved Diskette interrupt Reserved Video screen I/O Equipment check Memory size check Diskette I/O Communication I/O Cassete I/O Keyboard input Printer Output ROM Basic entry code Bootstrap loader Time of day Get control on keyboard break Get control on timer interrupt Pointer to video initialization table Pointer to diskette parameter table Pointer to table for graphicscharacters ASCII 128-255 DOS program terminate DOS function call DOS terminate address DOS fatal error vector DOS absolute disk read DOS absolute disk write DOS terminate, fix in storage Reserved for DOS Not used
Manual de Lenguaje Ensamblador 200-217 218-3C3 3C4-3FF
80-85 86-F0 F1-FF
Reserved by BASIC Used by BASIC interpreter Not Used
View more...
Comments