elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.


 


Tema destacado: Únete al Grupo Steam elhacker.NET


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación General (Moderador: Eleкtro)
| | |-+  Curso de ensamblador
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: Curso de ensamblador  (Leído 1,007 veces)
kaki

Desconectado Desconectado

Mensajes: 36



Ver Perfil
Curso de ensamblador
« en: 22 Agosto 2004, 14:12 »

Comencemos por los sistemas de numeraci¢n que m s utilizaremos al
 programar.

    El b sico va a ser el sistema hexadecimal, aunque debemos 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 "9", cambiar  a
 0 y sumar  uno a su 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,
 ‚ste n£mero binario cambiar  a "1". Sin embargo, si volvemos a a¤adirle
 otra unidad, ‚ste n£mero en formato binario ser  el "10" ( aumenta la
 cifra a la izquierda, que era 0, y la anterior toma el valor m¡nimo ).
 Sumemos ahora otra unidad: el aspecto del n£mero ser  "11" ( tres en
 decimal ). Y podr¡amos seguir:

Binario: 0 ; 1 ; 10 ; 11 ; 100 ; 101 ; 110; 111 ; 1000 ; 1001 ; 1010,...
Decimal: 0   1    2    3    4     5     6    7      8      9     10

    Esto nos permite establecer un sistema bastante sencillo de 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, aumentando el n£mero al que se eleva 2. Traduzcamos
 entonces el n£mero binario '10110111'

   2^7+ 0 +2^5+2^4+ 0 +2^2+2^1+2^0  = 128 + 0 + 32 + 16 + 4 + 2 + 1 = 183
    1   0   1   1   0   1   1   1

    De todos modos, ‚sta transformaci¢n la he puesto s¡mplemente para que se
 comprenda con m s claridad c¢mo funcionan los n£meros binarios. Es mucho
 m s aconsejable el uso de una calculadora cient¡fica que permita realizar
 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 activado ( 1 )
 o desactivado ( 0 ), aunque no detallar‚ ‚sto. Cada 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 )

    Ahora me paso al hexadecimal, muy utilizado 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 vemos, ‚ste sistema nos planteas bastantes problemas para la
 conversi¢n. Repito lo dicho, una calculadora cient¡fica nos ser  casi
 imprescindible para ‚sto.

    ¨ Por qu‚ utilizar ‚ste sistema ? Bien sencillo. Volvamos al byte, y
 traduzcamos su valor m s alto, "11111111". Resulta ser 256. Ahora pasemos
 ‚sta cifra al sistema hexadecimal, y nos resultar  "FF". Obtenemos un
 n£mero m s comprensible que el binario ( dif¡cil de recordar ), y ante todo
 mucho m s compacto, en el que dos cifras nos representar n cada byte.
    Podremos adem s traducir f cilmente el binario a hexadecimal con ‚sta
 tabla; cada cuatro cifras binarias pueden traducirse al hexadecimal:

            ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍËÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
            º     Binario       º    Hexadecimal   º
            ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ
                   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:

    1111001110101110

    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




                        ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
                        ³   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


       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

                  1.numero  2.numero  Resultado

                     1          1         1
                     1          0         0
                     0          1         0
                     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 complejos, queremos realizar un AND l¢gico entre
 dos bytes:

                11011000 AND 01101001

       Observemos lo que sucede:

                    11011000                                        216
           AND      01101001      En sistema decimal ser¡a:  AND    105
                    --------      (aunque en sistema decimal        ---
                    01001000       es m s lioso)                     72

       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" )


       OR
       --

    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 condones", 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 ).


      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,...


     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, quiero 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.

    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 utilizaremos 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.

    Y ahora, despu‚s de ‚stas cosillas, vamos con lo interesante,...
 segments y offsets:

    Resulta que 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 bien, por aqu¡ vienen los problemas ( y voy a intentar
 explicarlo lo m s mundanamente posible )

    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,...

    Necesitaremos para conocer una posici¢n de memoria pues cuatro bytes
 combinados de una curiosa manera.

    Imaginemos 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, llamaremos Offset a la direcci¢n
 indicada por ‚stos dos bytes.

    Ahora querremos m s memoria que 64 Kb, claro. Y para eso tenemos los
 otros dos bytes. Para formar la direcci¢n completa, se toman los 16 bits
 del registro de segmento y se situan en los 16 bits superiores de la
 direcci¢n de 20 bits, dejando los otros cuatro a cero. Vamos, como si
 a¤adi‚semos cuatro ceros a la derecha. Sumamos entonces a ‚ste valor de
 20 bits el Offset, resultando la direcci¢n real de memoria

    Voy a dar una explicaci¢n m s gr fica, porque creo que no me voy a
 enterar ni yo:

    Sea el valor de Segmento ( parezco un libro de matem ticas, j*der XD )
 0Ah ( o sea, 10 decimal o 1010b, binario ). Y el del Offset digamos 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 m s )
  +    0101 1111 0000 1010    ( el offset )
  ------------------------
  0000 0101 1111 1010 1010

    Y ‚sta ser¡a la direcci¢n *real* de memoria ( 05FAAh o 24490 Dec ). Como
 podr‚is 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 s¡mplemente 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-)




                         ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
                         ³  El juego de registros  ³
                         ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

    Quiz  alguno de vosotros se est‚ preguntando a ‚stas alturas: ¨ Y eso
 del Segment y Offset, d¢nde se guarda, que indica al ordenador esos sitios
 en memoria, qu‚ indica al ordenador en qu‚ punto de la memoria est  y qu‚
 tiene que ejecutar ? Pues bien, para ‚sto y mucho m s 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. sto 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 utilizados para
 por ejemplo mover datos en memoria, imprimir cadenas, bueno, un etc‚tera
 largu¡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 ‚sto lo explicar‚ m s adelante.

    Luego tenemos una serie de registros que utilizaremos m s comunmente:
 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 ‚stos cuatro registros son diferentes: 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.




                         ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
                         ³   ­­­ COMENZAMOS !!!   ³
                         ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

    Por fin vamos a empezar con ¢rdenes en ensamblador. Y comenzaremos con
 la m s sencilla, pero curiosamente la m s utilizada en ‚ste lenguaje:

    La orden MOV.
    ÄÄÄÄÄÄÄÄÄÄÄÄÄ

    La funci¢n de la orden MOV es, como su nombre da a entender, "mover" un
 valor. Pongamos un ejemplo:

    MOV AX,BX

    Esta ¢rden en lenguaje ensamblador, copiar  el contenido de BX en AX,
 conservando el valor de BX. He aqu¡ alg£n ejemplo m s:

    MOV AX,DS
    MOV ES,AX
    MOV DX,AX
    MOV AL,DH

    Como se v‚, no se puede realizar MOV AL,BX, ya que en AL no cabe BX
 ( sencillo, no ;) )
    Tambi‚n se puede introducir un valor dir‚ctamente en un registro. Ser¡a
 el caso de:

    MOV AX,0FEA2h
    MOV BL,255
    MOV DH,01110101b

    As¡ de paso pongo ejemplos de como se utiliza la numeraci¢n. El primero
 era un n£mero hexadecimal, el segundo decimal ( que no va acompa¤ado por
 nada para indicarlo ), y el tercero binario ( con la b al final ). A veces
 para representar un n£mero decimal se pone una 'd' al final ( p.ej, 10d )

    M s utilidades de MOV. Podemos transferir bytes que est‚n en memoria
 a un registro, o de un registro a memoria. Vayamos con los ejemplos:

    MOV AX,[BX]

    Y pongamos que en BX est  0EEEEh. En vez de transferir a AX el valor
 0EEEEh, le transferiremos el valor que haya en la posici¢n de memoria
 CS:BX, si CS por ejemplo vale 0134h y BX 03215h, transferir¡amos el byte
 que hay en 0134:03215h y el siguiente a AX.

    Se puede hacer tambi‚n al rev‚s;

    MOV [AX],CX

    Escribir¡amos en la direcci¢n de memoria CS:AX el valor de CX.
    Y tambi‚n podremos usar valores n£mericos:

    MOV AX,[2325h]    ( lo que hay en CS:2325h )
    MOV AX,DS:[2325h] ( el valor en DS:2325h )
    MOV AX,DS:DX      ( el valor en DS:DX )
    MOV DX,CS:CX      ( a DX, valor en CS:CX )
    MOV BX,CS:1241h   ( a BX, valor en CS:1241h )

    Muchas veces, se utiliza Word Ptr o Byte Ptr, que aclaran el tama¤o a
 transferir:

    MOV AL,BYTE PTR [BX+SI-30h]
    MOV AX,WORD PTR [BX+DI]

    Como acabamos de ver, es posible hacer "sumas" de valores al buscar
 una direcci¢n en memoria. Otros ejemplos ser¡an:

    MOV AX,[BX+3]
    MOV [BP+SI],AH


    Y para acabar ‚sta lecci¢n, aqu¡ ten‚is una tablilla de ejemplos sacada
 de un libro sobre MOVs que se pueden hacer:

  ÖÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÒÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ·
  º Formatos de la instrucci¢n MOV    º     Ejemplos                  º
  ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ×ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄĶ
  º MOV reg,reg                       º     MOV AX,BX                 º
  º MOV mem,reg                       º     MOV [BX],AL               º
  º MOV reg,mem                       º     MOV CH,[40FFh]            º
  º MOM mem,inmed                     º     MOV BYTE PTR [DI],0       º
  º MOV reg,inmed                     º     MOV BX,0FFFFh             º
  º MOV segreg,reg16                  º     MOV DS,AX                 º
  º MOV mem,segreg                    º     MOV [SI],ES               º
  º MOV segreg,mem                    º     MOV SS,[1234h]            º
  ÓÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÐÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄĽ
    reg: registro           mem:memoria         inmed:n£mero inmediato
    segreg: registro de segmento            reg16: registro de 16 bits


    Y vista la orden MOV, seguimos adelante,... sencillo, no ? ;)



                            ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
                            ³  Operaciones  ³
                            ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

    Las instrucciones INC y DEC:

    Son las m s b sicas a la hora de hacer operaciones con registros: INC,
 incrementa el valor de un registro ( o bueno, de cualquier posici¢n en
 memoria ) en una unidad, y DEC lo decrementa. Veamos:

    INC AX

    Incrementa en uno el valor de AX

    INC WORD PTR [BX+4]

    Incrementa la palabra situada en CS:[BX+4] en uno.

    DEC AX

    Decrementa AX, le resta uno.

    DEC WORD PTR [BX+4]

    Decrementa la palabra situada en CS:[BX+4] en una unidad.

    Estas dos instrucciones, equivalentes a por ejemplo a "a++" en C, nos
 servir n bastante como contadores ( para bucles ).



    Las instrucciones ADD y SUB
    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

    Se trata de dos operadores que contiene cualquier lenguaje de
 programaci¢n: la suma y la resta. Tienen dos operandos, uno de destino y
 otro fuente. Para la suma, se suman los dos operandos y se almacena en
 el primero (destino), y para la resta, se resta al primero el segundo,
 almacen ndose en destino, el primero. Aqu¡ est n algunos formatos de ‚stas
 instrucciones:

    ADD AX,BX               ; Sumar¡a AX y BX y lo guardar¡a en AX
    ADD [AX],BX             ; Suma el contenido de la direcci¢n de AX a BX,
                            ;y se almacena en la direcci¢n de AX
    ADD AX,[BX]             ; Se suman AX y el contenido de la direcci¢n de
                            ;BX, y se almacena ‚sta suma en AX
    ADD AX,3                ; Lo mismo pero utilizando un valor inmediato
                            ;en vez de la BX se¤alada anteriormente.
    SUB CL,DL               ; Resta de CL el valor de DL, y se almacena en CL
    SUB [CX],DX             ; Se resta al contenido de la direcci¢n de CX
                            ;el valor de DX, y se almacena en la dir. de CX
    SUB CX,23h              ; Se resta de CX el valor 23h, y queda en CX el
                            ;resultado

    Os habr‚is dado cuenta de una cosa, ¨ y si el resultado excede lo que
 puede contener el byte, o la palabra ?. sto se puede saber mediante los
 flags, que trataremos m s adelante.

    Tambi‚n os habr‚is fijado en que separ‚ con ; los comentarios. Bien,
 ‚sta es la manera en ensamblador de poner comentarios, como ser¡a en Basic
 la ¢rden "REM", o en C la convenci¢n "/* [...] */"


    NEG, NOT y operaciones l¢gicas
    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

    Neg, pone el registro o el lugar al que apunta en memoria en negativo
 seg£n la aritm‚tica de complemento a dos tal que : NEG AX o NEG [AX]

    Not es la que, como vimos, "invierte" los valores de los bits. Y el
 resto de operaciones l¢gicas tambi‚n las vimos anteriormente. Pondr‚ ahora
 tan s¢lo su sintaxis:

    NOT SI                      ; (o Not AX, etc,... o sea, con un registro)
    NOT Word ptr es:[ax]        ; Lo realiza sobre la palabra ( 2 bytes )
                                ;que se encuentra en es:[ax]
    AND AX,BX                   ; Efect£a un AND entre AX y BX, almacenando
                                ;el resultado en AX ( siempre en el primer
                                ;t‚rmino )
    AND [AX],BX                 ; Lo dicho, pero AX apunta a un lugar de
                                ;memoria
    AND AX,[BX]
    AND Byte ptr [15],3         ; Un AND en la direcci¢n :0015 con lo que
                                ;haya ah¡ y el valor "3"
    OR  AX,BX
    OR  [AX],BX
    OR  Byte ptr [15],3
    OR  DH,55h                  ;Tambi‚n podr¡a hacerse en el AND, se
                                ;confrontan DH y 55h en un OR.

               Y todo lo dicho para OR y AND vale para XOR, de tal manera
             que las operaciones son realizables entre:

             Registro y registro                  CX,DX
             Lugar de memoria y registro          [DX],BX
             Registro y lugar de memoria          AX,[SI]
             Lugar de memoria y n£mero            word ptr ES:[AX],0D533h
             Registro y n£mero                    AX,0CD32h


    Multiplicaci¢n y divisi¢n, MUL y DIV
    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ-

    Las pasar‚ algo r pido, ya que para nuestros objetivos no tienen una
 necesariedad excesiva, al menos a corto plazo.

    Estas operaciones multiplican al acumulador por el operando indicado.
 Si el operando es de 8 bits ( 1 byte ), el acumulador es AL. Si el
 operando es de 16 bits, el acumulador es AX. El resultado se almacena
 en AX o en el par DX-AX respectivamente, si el operando es de 8 bits o
 16 bits.

    Tambi‚n tendremos que diferenciar entre dos tipos de multiplicaciones
 y divisiones que entiende el procesador. Los que comienzan con una I
 operan con n£meros con signo ( ‚sto es, si queremos usar n£meros negativos
 y tal ), y los que no, con n£meros sin signo.

    Visto ‚sto, podremos decir que:

    MUL Byte Ptr [CX]

      Va a multiplicar el byte que hay en la direcci¢n que marca CX por el
 contenido que hay en AL, y una vez hecho ‚sto, va a almacenarlo en AX.

    MUL SI

      Multiplicar¡a SI por el contenido de AX, almacen ndose en el par AX-DX.
 La palabra superior ( de m s valor ), se devolver¡a en DX, y la inferior
 en AX.

    IMUL SI

      Esto y el ejemplo anterior ser¡a lo mismo, s¢lo que operando con
 n£meros con signo.


    Para la divisi¢n, el dividendo ha de estar en AX ( y ser 16 bits por
 tanto ). El divisor se indica en el operando, por ejemplo en DIV BL, ‚ste
 divisor estar¡a en BL. Se dividir¡a AX entre BL y el resultado quedar¡a en
 AL, quedando el resto en AH. Vamos a ver alg£n ejemplo que os veo muy
 perdidos:

    En la divisi¢n de un n£mero de diecis‚is bits entre otro de 8 bits, el
 cociente y resto ser n de 8 bits ( 1 byte ). El dividendo ha de estar en AX,
 y el divisor es el operando de la instrucci¢n, que puede ser un registro o
 un sitio en la memoria ( y se necesita poner lo de byte ptr )
    O sea, ser¡a tal que:
    DIV CL          o       IDIV    BYTE  PTR ES:[BP]

    El resultado se devuelve en AL, y el resto en AH. Si por ejemplo AX
 valiese 501d y cl valiese 2, a hacer el DIV CL, en AL quedar¡a 255 y en AH
 quedar¡a 1.

    Se puede dividir tambi‚n un n£mero de 32 bits ( 4 bytes ) entre otro de
 16 bits ( 2 bytes ), con lo que cociente y resto ser¡an de 16 bits. El
 dividendo estar¡a formado por el par DX/AX. Al hacer por ejemplo un:

    DIV SI

    Se dividir¡a DX-AX entre SI, almacen ndose el resultado en AX, y el resto
 en DX. Por ejemplo:

    Si en DX est  el valor 003Fh y en AX 5555h, el par ser¡a 3F5555h, con lo
 que al dividirlo por SI ( que pongamos que vale 0CCC4h ), se almacenar¡a en
 AX el resultado y en DX el resto.

    Y ahora pasamos a una parte en la que hay algo de teor¡a y tal,...



                               ÚÄÄÄÄÄÄÄÄÄ¿
                               ³  FLAGS  ³
                               ÀÄÄÄÄÄÄÄÄÄÙ

    La explicaci¢n de los "flags" viene a cuento de los saltos condicionales.
 Los que hay is visto un m¡nimo de otros lenguajes recordar‚is las sentencias
 FOR y NEXT ( en Basic ), o el IF/THEN/ELSE tambi‚n en estilo Basic pero
 encontrable en otros lenguajes. Pues bien, los flags y las instrucciones
 condicionales va a ser lo que os encontr‚is en ‚ste cap¡tulo del curso de
 Ensamblador.

    Vamos con el registro de flags.

    A las flags, "banderas", las agrupa un s¢lo registro de 16 bits, aunque
 ‚ste no est  utilizado por completo, ya que cada flag ocupa un s¢lo bit.
 Pero bueno, ¨ qu‚ son los flags a todo ‚sto ?

    Se trata de varios bits, que como siempre pueden valer uno o cero, y
 dependiendo de su valor indican varias cosas. El registro de flags es como
 sigue:

    ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
    ³ ± ³ ± ³ ± ³ ± ³ O ³ D ³ I ³ T ³ S ³ Z ³ ± ³ A ³ ± ³ P ³ ± ³ C ³
    ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ

    O: Overflow     D: Direcci¢n    I: Interrupciones rehabilitadas
    T: Trampa       S: Signo        Z: Cero
    A: Acarreo auxiliar     P: Paridad      C: Acarreo   ±: No utilizado


    Cada cuadrito representa un bit como es f cil adivinar. Tambi‚n os dar‚is
 cuenta de que cada bit que se utiliza tiene un nombre, y como ver‚is tambi‚n
 una utilidad. Aqu¡ explico el significado de cada uno, o al menos de los
 m s importantes:


    EL FLAG DE ACARREO
    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

    Hay veces en la operaciones en las que el n£mero se desborda, o sea, no
 cabe en el registro o en la posici¢n de memoria. Imaginemos que tenemos en
 AX el n£mero 0FFFFh y le sumamos 0CCCCh. Como es l¢gico, el resultado no nos
 cabr  en AX. Al realizar ‚sta suma, tenemos que tener en cuenta que el
 siguiente n£mero a 0FFFFh es 0000h, con lo que podremos ver el resultado.
 Igual pasar  si a 0000h le restamos por ejemplo 1 ( el resultado ser 
 0FFFFh ). Pero de alguna manera nos tenemos que DAR CUENTA de que ‚sto ha
 sucedido.

    Cuando se opera y hay acarreo en el £ltimo bit sobre el que se ha
 operado, el flag de acarreo se pone a uno. O sea, cuando ese n£mero se ha
 desbordado. Hay que recordar tambi‚n que las instrucciones INC y DEC no
 afectan a ‚ste flag. Veamos los efectos de ‚stas operaciones:

    MOV AX,0FFFFh
    INC AX              ; AX vale ahora 0, el flag de acarreo tambi‚n
    DEC AX              ; AX vale 0FFFFh, y el flag sigue inalterado
    ADD AX,1            ; AX vale 0, y el flag de acarreo est  a 1
    MOV BX,0000h
    ADD BX,50h          ; El flag de acarreo se pone a 0, no ha habido
                        ;acarreo en ‚sta operaci¢n
    SUB AX,1            ; Ahora AX vale otra vez 0FFFFh, y el flag de acarreo
                        ;se pone de nuevo a uno

    En resumen, se activa cuando tras una operaci¢n hay un paso del valor
 m ximo al m¡nimo o viceversa

    Este flag nos va a ser tambi‚n £til al comprobar errores, etc. Por
 ejemplo, si buscamos el primer archivo del directorio y no hay ninguno,
 ‚ste flag se activar , con lo que podremos usar los saltos condicionales,
 pero ‚sto ya se explica m s adelante.


    EL FLAG DE SIGNO
    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

    A veces interesa conocer cuando un n£mero con signo es negativo o positivo.
 Evidentemente, ‚sto s¢lo tiene efecto cuando EFECTIVAMENTE estamos tratando
 con n£meros enteros con signo, en complemento a dos. Indica cuando tras una
 operaci¢n aritm‚tica ( ADD, SUB, INC, DEC o NEG ) o l¢gica ( AND, OR o XOR )
 el resultado es un n£mero en complemento a dos. En realidad es la copia del
 bit de mayor peso del byte, el que indica cuando el n£mero es negativo.

    Por lo tanto, cuando vale 1 es que el n£mero es negativo y si vale 0 es
 que es positivo


    EL FLAG DE DESBORDAMIENTO  ("Overflow")
    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

    Se trata de un flag bastante parecido al de acarreo, pero que act£a con
 n£meros en complemento a dos y se activa cuando se pasa del mayor n£mero
 positivo ( 127 en un s¢lo byte ) al menor negativo ( -128 en tama¤o de un
 byte ).

    Este flag, al contrario que el de acarreo, SI es afectado por las
 instrucciones de decremento e incremento.


    EL FLAG DE CERO
    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

    De los m s sencillitos de comprender. S¡mplemente se activa cuando el
 resultado de una operaci¢n aritm‚tica o l¢gica es cero. A los avispados se
 os estar  ya ocurriendo la gran utilidad del flag,... tenemos por ejemplo
 dos registros, AX y CX, que queremos comparar para saber si son iguales.
 Para saberlo, no tendr¡amos m s que restar uno del otro, y si el resultado
 es cero ( o sea, si el flag de cero se pone en uno ), podremos hacer un
 salto condicional ( ‚sto lo explico en el pr¢ximo n£mero.

    O sea, de un

    SUB CX,AX

    Si son iguales, el flag de cero se pondr  a uno.


    EL FLAG DE PARIDAD
    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

    Se utiliza especialmente en la transmisi¢n de datos para la comprobaci¢n
 de errores, ya que comprueba si el resultado de la £ltima operaci¢n
 aritm‚tica o l¢gica realizada tiene un n£mero par o impar de bits puestos
 a uno. Se pondr  a uno cuando haya un n£mero par de bits, y a cero cuando
 sea impar.


    RESTO DE FLAGS
    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

    No describir‚ m s flags detalladamente, ya que su importancia es casi
 nula; por ejemplo est  el flag de interrupci¢n que cuando est  activado
 evita la posibilidad de interrupciones en secciones cr¡ticas de c¢digo, o
 el de trampa, que cuando est  activado provoca una INT 1h cada vez que se
 ejecuta otra instrucci¢n, pero creo que su inter‚s es escaso, al menos por
 el momento.


    INSTRUCCIONES DE COMPARACION
    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

    ­ No ibamos a terminar la lecci¢n sin ense¤ar nuevas instrucciones !
 Nos van a servir bastante para realizar las comparaciones, y son:

    CMP y TEST

    CMP compara dos registros, o un registro y una direcci¢n de memoria,...
 tiene el mismo formato que el SUB ( por ejemplo CMP AX,BX ), tan s¢lo que
 ninguno de los registros es alterado. Si por ejemplo son iguales, el flag
 de cero se pondr  en uno. Es en realidad un SUB del que no se almacena el
 resultado.

    TEST, comprobar, se puede realizar con el mismo formato de AND, ya que
 es equivalente a ella, tan s¢lo que no se guarda el resultado, aunque s¡ se
 modifican los flags.

    Y en el pr¢ximo cap¡tulo veremos como se aplican ‚stos flags, y como
 realizar los saltos comparativos.



                     ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
                     ³  LAS INSTRUCCIONES DE SALTO  ³
                     ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

    SALTOS INCONDICIONALES
    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

    Empecemos por el salto sin condiciones, con el que podremos cambiar
 el control a cualquier punto del programa. Ser¡a como el "Goto" del Basic,
 s¡mplemente transferir el control a otro punto del programa. La orden es
 JMP ( de Jump, salto )

    Si record is a ‚stas alturas los registros CS:IP, se podr  ver qu‚ es
 lo que hace realmente la instrucci¢n, y no es m s que incrementar o
 decrementar IP para llegar a la zona del programa a la que queremos
 transferir el control ( IP es el Offset que indica la zona de memoria
 que contiene la siguiente instrucci¢n a ejecutar, y CS el segmento )

    El formato m s sencillo para el salto ser¡a JMP 03424h, lo que saltar¡a
 a esa zona. Pero es digamos que "algo pesado" calcular en qu‚ direcci¢n
 va a estar esa instrucci¢n, con lo que utilizaremos etiquetas. Aqu¡ hay
 un ejemplo, en el que de paso se repasa un poco:


            MOV AX,0CC34h
            MOV CL,22h
            JMP PALANTE
VUELVE:     CMP BX,AX
            JMP FIN
PALANTE:    MOV BX,AX
            JMP VUELVE
FIN:        XOR CX,CX

    Ahora voy a comentar un poco el programa. Tras la primera instrucci¢n,
 AX vale 0CC34h, y tras la segunda, CL vale 22h. Despu‚s se realiza un salto
 a la instrucci¢n etiquetada con "PALANTE". La etiqueta ha de estar
 continuada por dos puntos ':', y puede ser llamada desde cualquier lugar del
 programa. Tambi‚n podremos hacer un MOV AX,[PALANTE], como hac¡amos antes
 con un MOV AX,[BX], pero asignando a AX el valor que haya en la direcci¢n
 en la que est  "PALANTE".
    El caso, que tras el salto a "PALANTE", se copia el valor del registro BX
 en AX, y se vuelve a "VUELVE". Se realiza una comparaci¢n entre AX y BX, que
 pondr  el flag de cero a 1 ( recordemos la anterior lecci¢n ), se saltar 
 a "FIN", donde tan s¢lo se realizar  la orden Xor CX,CX cuyo resultado, por
 cierto, es poner CX a cero tenga el valor que tenga ( y ‚sto se utilizar 
 bastante programando, por eso me ha dado por incluir la orden )

    Volvamos con la sintaxis del JMP con algunos ejemplos de como utilizarlo:

    JMP 100h

    Salta a la direcci¢n 100h. Un archivo .COM comienza normalmente en esa
 direcci¢n, as¡ que quiz  lo ve is en algunos virus.

    JMP 542Ah:100h

    Salta a la direcci¢n 100h pero del segmento 542Ah. ¨ Os acord is a£n
 de los Segments y Offsets ?. Se trata de un salto lejano.

    JMP SHORT 223Ah

    Salto corto a la direcci¢n 223Ah. Tranquilidad, ahora explico lo de salto
 corto, lejano,...

    JMP NEAR  55AAh

    Salto cercano, es diferente al corto

    JMP [100h]

    Salta a la direcci¢n contenida en 100h. Sin embargo es un error, ya que
 no se especif¡ca si es cercano, lejano, si se lee un s¢lo byte,... o sea,
 que ‚sta instrucci¢n no vale.

    JMP WORD PTR [BX]

    Ahora si vale ;). Salta a la direcci¢n contenida en la palabra ( dos
 bytes ) a la que apunta BX. O sea, si BX valiese 300h y en 300h los dos
 bytes fuesen 0CC33h, el JMP saltar¡a a ‚sta direcci¢n.

    JMP DWORD PTR [BX+SI+5]

    Dword son 32 bits, o sea, un salto lejano. Y saltar¡a al contenido en
 la direcci¢n de memoria a la que apuntan la suma de BX,SI y 5.


    Ahora voy a contar algo sobre los saltos lejanos, cercanos y cortos. El
 salto corto se realiza entre el punto en el que se est  y +127 o -128, o
 sea, que la cantidad que se puede contener en un byte con signo. A veces
 es necesario indicar que se trata de salto corto, cercano o lejano.

    El salto cercano se realiza contando como distancia el contenido de dos
 bytes, o sea, que el rango ser¡a desde 32767 a -32768 bytes de distancia.

    Y el lejano se realiza contando como distancia el contenido de cuatro
 bytes, y,... paso de calcular la distancia, pero es mucha X-)

    Por ejemplo, es incorrecto que haya en la direcci¢n 100h una instrucci¢n
 que diga JMP SHORT 500h, ya que la distancia no corresponde a un salto
 corto. Adem s, el salto dependiendo de que sea cercano, corto o largo se
 codifica de manera diferente en modo hexadecimal.


    SALTOS CONDICIONALES
    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

    ¨ Record is aquel IF-THEN-ELSE, o el FOR, o el WHILE-DO ?

    Bien, pues aqu¡ est  lo que suple a ‚stas instrucciones en lenguaje
 ensamblador. Se basan compl‚tamente en los flags, por ello el rollo de la
 anterior lecci¢n, pero est n simplificados de tal manera que no os har 
 falta sab‚roslos de memoria para poder hacerlos.

    Los saltos podr¡an resumirse en un modo "Basic" de la manera IF-THEN-GOTO
 de tal manera que cuando se cumple una condici¢n se salta a un sitio
 determinado.

    He aqu¡ los tipos de saltos condicionales ( las letras en may£sculas son
 las instrucciones ):

    JO: Jump if overflow. Salta si el flag de desbordamiento est  a uno
    JNO: Jump if not overflow. Salta si el flag de desbordamiento est  a
 cero.
    JC, JNAE, JB: Los tres sirven para lo mismo. Significan: Jump if Carry,
 Jump if Not Above or Equal y Jump if Below. Saltan por lo tanto si al
 haber una comparaci¢n el flag de acarreo se pone a 1, es entonces
 equivalente a < en una operaci¢n sin signo. Vamos, que si se compara as¡:
 CMP 13h,18h, saltar , ya que 13h es menor que 18h. Tambi‚n se suelen usar
 para detectar si hubo fallo en la operaci¢n, ya que muchas interrupciones
 al acabar en fallo encienden el carry flag.

    JNC, JAE, JNB: Otros tres que valen ex ctamente para lo mismo. Jump if
 not Carry, Jump if Above or Equal y Jump if Not Below. Saltan por tanto si
 al haber una comparaci¢n el flag de acarreo vale 0, o sea, es equivelente
 al operador >=. En la comparaci¢n CMP 0,0 o CMP 13h,12h saltar , ya que el
 segundo operando es MAYOR O IGUAL que el primero.

    JZ o JE: Jump if Zero o Jump if Equal. Salta si el flag de cero est  a
 1, o sea, si las dos instrucciones comparadas son iguales. Saltar¡a en el
 caso CMP 0,0

    JNZ o JNE: Jump if Not Zero o Jump if Not Equal. Salta si el flag de cero
 est  a 0, o sea, si las dos instrucciones comparadas no son iguales.

    JBE o JNA: Jump if Below or Equal o Jump if Not Above. Saltar¡a si en
 resultado de la comparaci¢n el primer miembro es menor o igual que el
 segundo ( <= )

    JA o JNBE: Jump if Above o Jump if Not Below of Equal. Justo lo contrario
 que la anterior, salta si en el resultado de la comparaci¢n el primer
 miembro es mayor al segundo.

    JS: Jump if Sign. Salta si el flag de signo est  a uno.

    JNS: Jump if Not Sign. Salta si el flag de signo est  a cero.

    JP, JPE: Jump if Parity o Jump if Parity Even. Salta si el flag de
 paridad est  a uno.

    JNP, JPO: Jump if Not Parity, Jump if Parity Odd. Salta si el flag de
 paridad est  a cero.

    JL, JNGE: Jump if Less, Jump if Not Greater of Equal. Salta si en el
 resultado de la comparaci¢n, el primer n£mero es inferior al segundo, pero
 con n£meros con signo.

    JGE, JNL: Jump if Greater or Equal, Jump if Not Less. Salta si en el
 resultado de la comparaci¢n, el primer n£mero es mayor o igual que el
 segundo, pero con n£meros con signo.

    JLE, JNG: Jump if Lower or Equal, Jump if Not Greater. Salta si en el
 resultado de la comparaci¢n, el primer n£mero es menor o igual que el
 segundo, pero con n£meros con signo.

    JG, JNLE: Jump if Greater, Jump if Not Lower or Equal. Salta si en el
 resultado de la comparaci¢n, el primer n£mero es mayor que el segundo, para
 n£meros con signo.

    Fiuuuuu !!! Menuda lista. Bueno, aconsejo que os qued‚is de cada
 parrafito con uno, aunque algunos se usen poco, pero como veis para una
 misma instrucci¢n hay varios,... y para gustos no hay nada escrito, lo mismo
 os da usar JG que JNLE por ejemplo.

    Vamos, que despu‚s de toda ‚sta aridez me temo que voy a tener que poner
 algunos ejemplos de los m s utilizados:

                MOV AX,1111h
                MOV BX,1112h
                CMP AX,BX       ; AX es menor que BX ( toma perogrullada )
                JB  tirapalante ; Saltar  a tirapalante
                HLT             ; Esta orden bloquea el ordenador, halt
tirapalante:    DEC BX          ; Ahora BX valdr  1111h
                CMP AX,BX       ; Ahora valen igual
                JNE Acaba       ; No saltar , ya que son iguales
                JE Continua     ; Esta vez si
Continua:       DEC BX          ; Ahora BX vale 1110h
                CMP AX,BX
                JE Acaba        ; No son iguales, por tanto no saltar 
                JB Acaba        ; No es menor, tampoco salta
                JG Acaba        ; Es mayor, ahora SI saltar 
Acaba:          XOR AX,AX
                XOR BX,BX       ; AX y BX valen ahora cero.

    Espero que con ‚sto haya aclarado un poco la utilidad de los saltos.
 Evidentemente, ahora al escribir sabemos cuando uno es menor o mayor, pero
 a veces mediante interrupciones sacaremos valores que no conoceremos al ir
 a programar, o quiz  lo hagamos de la memoria, y querremos comprobar si
 son iguales, etc‚tera.

    Por cierto, que en los saltos condicionales se puede hacer como en los
 incondicionales, o sea, formatos como:

    JE 0022h
    JNE 0030h
    JNO AL

    Sin embargo, estamos limitados a saltos cortos, o sea, de rango a 127
 bytes hacia adelante o 128 hacia atr s, no pudiendo superar ‚sta distancia.


    BUCLES
    ÄÄÄÄÄÄ

    He aqu¡ el equivalente al FOR-TO-NEXT en ensamblador, se trata de la
 orden LOOP. Lo que hace ‚sta orden es comparar CX con cero; si es igual,
 sigue adelante, si no lo es, vuelve al lugar que se indica en su operando
 decrementando CX en uno. Por lo tanto, CX ser  un contador de las veces
 que ha de repetirse el bucle. Vamos con un ejemplo:

        MOV CX,0005h
bucle:  INC DX
        CMP DX,0000h
        JE  Acaba
        LOOP bucle
Acaba:  ...

    Veamos como funciona ‚ste programa. Se mueve a CX el valor 5h, que van
 a ser las veces que se repita el bucle. Ahora, llegamos al cuerpo del bucle.
 Se incrementa DX y se compara con 0, cuando es igual salta a "Acaba". Si
 llega a la orden LOOP, CX se decrementar  y saltar  a bucle. Esto se
 repetir  cinco veces. En fin, que el programa acabar  en el grupo de
 instrucciones de "Acaba" cuando la comparaci¢n de un resultado positivo o
 cuando el bucle se haya repetido cinco veces.

    Tambi‚n tiene la limitaci¢n de que s¢lo realiza saltos cortos, y tambi‚n
 puede usarse como el JMP, de la forma:

    LOOP 0003h
    LOOP [AL]

    En resumen, la orden LOOP es la equivalente a CMP CX,0/JNZ par metro,
 donde par metro es el operando de LOOP.

    Y en fin, hemos terminado con los condicionales. Parece muy  rido, pero
 luego seguramente usar‚is poco m s que un JZ o JNZ al principio,... y el
 LOOP, claro. Ya no nos queda mucho. La explicaci¢n de la pila y las
 interrupciones, y ya podr‚is empezar a programar.



                                ÚÄÄÄÄÄÄÄÄÄÄÄ¿
                                ³  LA PILA  ³
                                ÀÄÄÄÄÄÄÄÄÄÄÄÙ

    Para explicar ‚sta parte, voy a hacerlo lo m s mundanamente posible y
 sin mucho t‚rmino complicado, porque las explicaciones muchas veces suelen
 liar m s sobre una cosa tan sencilla como es ‚sto.

    La pila es una especie de "almac‚n de variables" que se encuentra en una
 direcci¢n determinada de memoria, direcci¢n que viene indicada por SS:SP,
 como mencion‚ antes, registros que son SS de segmento de pila y SP de
 Offset de ‚sta.

    Entonces nos encontramos con dos ¢rdenes b sicas respecto a la pila, que
 son PUSH y POP. La ¢rden PUSH empuja una variable a la pila, y la ¢rden POP
 la saca. Sin embargo, no podemos sacar el que queramos, no podemos decir
 "quiero sacar el valor de DX que he metido antes y que fue el cuarto que
 met¡", por ejemplo.

    La estructura de la pila se denomina LIFO, siglas inglesas que indican
 'Last In First Out'. Esto significa que al hacer un POP, se sacar  el
 £ltimo valor introducido en la pila. Vamos con unos ejemplitos majos:

    PUSH    DX              ; Mete en la pila el contenido de DX
    PUSH    CX              ; Y ahora el contenido de CX
    POP     AX              ; Ahora saca el £ltimo valor introducido ( CX )
                            ;y lo coloca en AX.
    POP     BP              ; Y ahora saca en valor anterior introducido, que
                            ;es el contenido de DX cuando hicimos el PUSH DX
                            ;y se lo asigna a BP.

    Ahora, una rutina algo m s detallada:

    MOV     DX,0301h        ; DX vale ahora 0301 hexadecimal.
    PUSH    DX              ; Empuja DX a la pila. SP se decrementa en dos.
    MOV     DX,044C4h       ; Ahora DX vale 044C4h
    POP     CX              ; Y con ‚sto, CX vale 0301 hexadecimal, el valor
                            ;que hab¡amos introducido con anterioridad.

    Dije en la segunda l¡nea: SP se decrementa en dos. Cuando por ejemplo
 ejecutamos un .COM, SS es el segmento del programa ( o sea, igual que CS,
 y si no han sido modificados, DS y ES ), y SP apunta al final, a 0FFFFh.
 Cuando empujamos un valor a la pila, SP se decrementa en dos apuntando a
 0FFFDh, y en ‚sta direcci¢n queda el valor introducido. Cuando lo saquemos,
 se incrementar  de nuevo en dos el valor de SP, y el valor se sacar  de
 la pila.

    Se puede operar con ‚sta instrucci¢n con los registros AX, BX, CX, DX,
 SI, DI, BP, SP, CS, DS y ES, sin embargo no se puede hacer un POP CS, tan
 s¢lo empujarlo a la pila.

    He aqu¡ un ejemplo de lo que hace en realidad un POP en t‚rminos de MOVs,
 aunque sea un gasto in£til de c¢digo, tiene su aplicaci¢n por ejemplo para
 saltarse la heur¡stica en un antivirus, que busca un POP BP y SUB posterior,
 bueno, supongo que ya aprender‚is a aplicarlo cuando ve is el curso de
 virus/antivirus:

    Partamos de que hay cierto valor en la pila que queremos sacar.

    MOV     BP,SP       ; Ahora BP es igual al offset al que apunta SP
    MOV     BP,Word ptr [BP] ; Y ahora BP vale el contenido del offset al
                             ;que apunta, que al ser el offset al que apunta
                             ;el de pila, ser  el valor que sacar¡amos
                             ;haciendo un POP BP.
    ADD     SP,2            ; Para acabarlo, sumamos dos al valor de offset
                            ;de la pila.

    Y ‚sto es lo que hace un POP BP, s¡mplemente. Para ver lo que hace un PUSH
 no habr¡a m s que invertir el proceso, lo pongo aqu¡, pero ser¡a un buen
 ejercicio que lo intent rais hacer sin mirarlo y luego lo consult rais, por
 ejemplo introduciendo DX a la pila.

    SUB     SP,2
    MOV     BP,SP
    MOV     Word ptr[BP],DX

    Como £ltima recomendaci¢n, hay que tener bastante cuidado con los PUSH
 y POP, sacar tantos valores de la pila como se metan, y estar pendiente de
 que lo que se saca es lo que se tiene que sacar. La pila bien aprovechada
 es fundamental para hacer programas bien optimizados, ya que entre otras
 cosas las instrucciones PUSH y POP s¢lo ocupan un byte.

    Es por ejemplo mucho mejor usar un PUSH al principio y un POP al final
 en vez de dejar partes de c¢digo para almacenar variables, m s velocidad
 y menos tama¤o.

    Y finalmente, hay otras dos ¢rdenes interesantes respecto a la pila,
 PUSHF y POPF, que empujan el registro ( 16 bits ) de flags y lo sacan,
 respectivamente

                                LA ORDEN CALL
                                ÄÄÄÄÄÄÄÄÄÄÄÄ-

    Se trata de una ¢rden que se utiliza para llamar a subrutinas, y est 
 relacionada con la pila, por lo que la incluyo en ‚sta lecci¢n del curso.

    La sintaxis del Call es casi la de un Jmp, pudi‚ndose tambi‚n utilizar
 etiquetas, direcciones inmediatas o registros. Si compar semos un Jmp con
 un 'GOTO', el Call ser¡a el 'GOSUB'. Es una instrucci¢n que nos va a servir
 para llamar a subrutinas.

    Su forma de actuaci¢n es sencilla. Empuja a la pila los valores de CS e
 IP ( o sea, los del punto en el que est  en ese momento el programa ),
 aunque IP aumentado en el tama¤o del call para apuntar a la siguiente
 instrucci¢n, y hace un salto a la direcci¢n indicada. Cuando encuentre una
 instrucci¢n  RET, sacar  CS e IP de la pila, y as¡ retornar  al lugar de
 origen. Veamos un ejemplo:

         xor     ax,ax       ; Ax vale ahora 0
         Call    quebi‚n     ; Mete CS e IP a la pila y salta a quebi‚n
         Int     20h         ; sta ¢rden sale al dos, explicar‚ todo ‚sto
                             ;en el pr¢ximo cap¡tulo, s¢lo que sep is eso
quebi‚n: mov     ax,30h
         Ret                 ; Vuelve a la instrucci¢n siguiente al punto
                             ;de llamada, o sea, a la de "INT 20h"

    La ¢rden RET puede tener tambi‚n varios formatos: RETN o RETF, seg£n se
 retorne desde un sitio cercano ( RETN, near ) o lejano ( RETF, far ). No
 obstante, pr cticamente no lo usaremos, la mayor¡a de las veces se quedar 
 en RET y punto.

    Existe entonces la llamada directa cercana, en la que s¢lo se introduce
 IP ( l¢gicamente, apuntando a la ¢rden siguiente al Call ), y al retornar,
 lo hace en el mismo segmento, y la llamada directa lejana, en la que se
 introducen CS e IP ( y luego se sacan, claro ). A veces se podr¡an producir
 confusiones, con lo que quiz  pueda ser conveniente usar RETN y RETF
 respectivamente.

    Y el pr¢ximo cap¡tulo empezamos con interrupciones,... venga, que ya
 queda menos para poder programar ;-)



                           ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
                           ³   INTERRUPCIONES   ³
                           ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

    A ‚stas alturas del curso estar‚is diciendo: bueno, vale, he aprendido
 a mover registros, a meterlos en la pila, etc,... ¨ pero c¢mo act£o con
 el exterior ?. Porque por mucho registro que tenga no voy a escribir por
 ejemplo un car cter en la pantalla. Bieeeeeen, pues aqu¡ est , son las
 interrupciones.

    La primera cosa que tenemos que hacer es saber como funcionan las
 interrupciones. Son principalmente subrutinas de la BIOS o el DOS que
 pueden ser llamadas por un programa, por ejemplo la funci¢n 21h est 
 dedicada especialmente a tratamiento de archivos.

    Para utilizarlas, tendremos que poner los registros con un determinado
 valor para que se realice el prop¢sito que buscamos. Cada interrupci¢n
 tiene varias funciones, y podremos elegir cual ejecutamos seg£n el valor
 de AH.

    El formato de la ¢rden es INT X, donde X puede ir desde 1 a 255 ( aunque
 normalmente se escribe en formato hexadecimal ).

    Cuando se ejecuta una interrupci¢n, el ordenador empuja todos los flags
 a la pila, un 'PUSHF', y despu‚s mira en la tabla de vectores de
 interrupci¢n, de la que hablar‚ m s adelante, para transferir el control
 del programa al punto que indica esa tabla respecto a la interrupci¢n
 pedida mediante un 'CALL'. Cuando la interrupci¢n ha terminado, acabar  con
 un IRET, que es una combinaci¢n entre 'POPF' y 'RET'.

    La tabla de Vectores de Interrupci¢n es una tabla de direcciones para
 la direcci¢n a la que debe saltar cada interrupci¢n. Comienza en la
 direcci¢n de memoria 0000:0000 y acaba en la 0000:0400, siendo cada
 direcci¢n de 4 bytes de longitud. Para averiguar cual corresponde a cada
 interrupci¢n, no hay m s que multiplicar el n£mero de interrupci¢n por
 cuatro. Por ejemplo, la direcci¢n de memoria donde est  el punto al que
 salta una INT 21h, es 0000:21h*4. Ah¡ se contienen el CS e IP a los que
 saltar  el programa cuando se ejecute la interrupci¢n. Estos valores, son
 modificables, pero hay que tener mucho cuidado con ello.

    Y ahora voy a ponerme algo m s mundano, si no hab‚is entendido ‚sto al
 menos saber 'qu‚ hace', quiz  as¡ adem s los que os hay is perdido pod is
 retornar m s adelante. Vamos con un ejemplo de uso de una interrupci¢n:


                jmp mesaltomsg      ; Esto lo hago porque ejecutar el texto
                                    ;puede traer consecuencias imprevisibles

archivo:        db 'c:\command.com',0 ; el 0 que va despu‚s es necesario
                                    ; en operaciones con archivos, o no
                                    ; funcionar .

mesaltomsg:     mov ax,4100h        ; Al ir a llamar a la interrupci¢n, AH
                                    ;( que aqu¡ es 41h ), indica la funci¢n
                                    ;de dicha interrupci¢n que se quiere
                                    ;ejecutar. En ‚ste caso es la 41h, que
                                    ;significa borrar un fichero

                mov dx,OFFSET archivo   ; En dx cargamos la direcci¢n del
                                        ;offset con la etiqueta archivo,
                                        ;o sea, si la etiqueta archivo est 
                                        ;en :0014h, ese ser  ahora el valor
                                        ;de DX. Como vemos, no s¢lo basta
                                        ;con tener AX actualizado para poder
                                        ;usar la interrupci¢n.

                Int 21h                 ; Ejecutamos la interrupci¢n 21h en
                                        ;su funci¢n 41h, borrar un fichero.

    Voy a detallar un poco m s, ¨ por qu‚ en dx pongo la direcci¢n del offset
 de archivo ?. Porque la funci¢n de la Int21h que busco necesita par metros.
 Cuando AH vale 41h, funci¢n de borrar fichero, necesita ciertos par metros,
 y ‚sto es que en DS:DX se encuentre la cadena de caracteres que indica el
 fichero a buscar.

    Como DS vale lo mismo que CS si no lo hemos cambiado, tan s¢lo hace
 falta hacer que DX apunte al lugar donde est  la cadena de caracteres con
 el nombre del archivo.


    Vamos con otro ejemplo. Ahora, queremos cambiar el nombre de un fichero.
 La interrupci¢n para ello es la 21h, y la funci¢n que queremos es la 56h,
 con lo que en AH tendremos que poner ese valor.

    El par DS:DX, es la direcci¢n de la cadena que contiene la unidad, camino
 y nombre del fichero, tal y como suced¡a en el anterior ejemplo, y ES:DI
 la direcci¢n de la cadena que contiene la nueva unidad, camino y nombre.

    Vamos con el programa:

    Mov     ah,56h                  ; No hace falta inicializar al, como
                                    ;hicimos antes, no tiene ninguna
                                    ;importancia su contenido.
    Mov     dx,OFFSET anterior      ; Ds ya est  apuntando a ‚ste segmento,
                                    ;s¢lo tendremos que asignar Dx
    Mov     di,OFFSET posterior     ; Di apunta al nuevo nombre, Es no ha
                                    ;sido variado de ninguna manera.
    Int     21h                     ; Si en ‚ste directorio de haya el
                                    ;archivo de DS:DX, cambia su nombre al
                                    ;de ES:DI
    Int     20h                     ; Devuelve el control al Ms-dos.

anterior:       db  'berilio.com',0
posterior:      db  'magnesio.com',0


    En resumen, cambiar  el nombre del archivo berilio.com a magnesio.com
 si ‚ste se encuentra en el directorio.

    Hay innumerables cosas que se pueden hacer con las interrupciones:
 escribir textos, leer del teclado, cambiar modos de pantalla, escribir
 en archivos, leerlos, ejecutarlos,... demasiado para ponerlo aqu¡, aunque
 al final del curso os podr‚is encontrar m s ejemplos.

    Recomiendo tener a mano la lista de interrupciones de Ralf Brown, que
 es una aut‚ntica biblia de las interrupciones, o las gu¡as Norton. El caso
 es que es imposible sab‚rselas de memoria, y es mejor tener una buena
 obra de consulta al lado. La lista de interrupciones de Ralf Brown es
 f cil de encontrar, y ocupa cerca de un disco completo, con largos archivos
 de texto, y se actualiza de vez en cuando.

    Para dar una idea en general y que sep is c¢mo buscar lo que necesit is,
 aqu¡ est n las interrupciones que m s se usan y sus funciones en general,
 s¡mplemente para orientaros al buscar.


    Interrupci¢n 21h: Apuesto a que es la que m s utilizar‚is, con ella se
 consigue el acceso a la fecha y hora del sistema, gesti¢n de ficheros,
 funciones de dos referidas al disco, para la gesti¢n de directorios, y
 algunas de lectura/escritura en el teclado y pantalla, adem s de la gesti¢n
 de la memoria.

    Interrupci¢n 13h: Funciones de BIOS que se refieren al disco.

    Interrupci¢n 10h: Gesti¢n de la pantalla en modo alfanum‚rico, gesti¢n
 de la pantalla en modo gr fico.

    Interrupciones 25h y 26h: Funciones de dos de acceso directo al disco,
 escribir y leer sectores...

    Interrupci¢n 17h: Impresora.



                            ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
                            ³ Resto de ¢rdenes ³
                            ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

    Bueno, pues parece que nos vamos acercando al final,... ahora voy a
 contar con algo de detalle del resto de l


En línea

Espero que le sirva de algo
Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

Mensajes similares
Asunto Iniciado por Respuestas Vistas Último mensaje
curso ensamblador *-*
ASM
ByJørGe 1 910 Último mensaje 15 Diciembre 2015, 21:22
por fary
Curso ensamblador « 1 2 »
ASM
Poyoncio 13 3,569 Último mensaje 2 Febrero 2018, 11:19
por Borito30
Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines