Vous êtes sur la page 1sur 16

Por fin me mande a escribir algo sobre esto, quiero agradecerles especialmente a Ariel Nardelli Mauricio Taslik Gastn

Sanchez Eduardo Arias Luis Mamud Pablo Rotzyld Federico Joselevich Diego Paz Nicolai Kuzminski Fernando Bardelli Juan Esteva Fabin Benavidez

Por haberse prendido de entrada en esta idea, y por haber hecho sugerencias, y por haberme hecho decidirme. !!!

Bueno, Mmmm... Vamos a empezar por algo que quizs muchos ya sepan, pero como es indispensable, igual se lo tengo que contar: La Memoria de Las PC: Como ya sabrn, de haber escuchado por ah, hay varios tipos de memoria, la Memoria Base, la Memoria Expandida (EMS), Memoria Extendida (XMS), Upper Memory Blocks (UMB), High Memory Area (HMA) y un montn mas de referencias a distintos tipos de memoria, lo que les voy a contar es que direccin de memoria le corresponde a un Byte dentro del primer MegaByte, es decir, dentro de la memoria base (0-640K) y en la zona donde estn las plaquetas de expansin, Monitor, BIOS ROM, rea de la controladora de Disco, etc... Tratemos de acostumbrarnos a ver los nmeros en Hexadecimal (base 16). Los dgitos que pueden formar un numero en esta base, son: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E y F, tomando valores en ese mismo orden, el 0 vale 0 y la F vale 15. De esta forma un numero, por ejemplo 0FA3h (la 'h' final indica que esta en 'Hexa'), expresado en decimal valdra (3)+(Ah*16)+(Fh*16*16)+(0*16*16*16), o lo que es lo mismo 3+160+3840+0=4003, pongmonos de acuerdo que cuando un nmero lo escribimos en Haxa le ponemos la 'h' al final, y si comienza con una letra, le agregamos un '0' adelante para no confundirnos con un nombre de variable. Esto fue una breve pero necesaria introduccin al sistema Hexadecimal de numeracin. Ahora si, veamos como se direcciona la memoria de una PC. Tengamos en cuenta que si queremos direccionar 1 Mb nos hacen falta 5 dgitos hexadecimales, es decir, poder escribir, de alguna forma 0FFFFFh o 100000h-1 que es 1*16^5=1 Mb (1 que se resta, corresponde al byte #0). Como los 80x86 tienen registros de 16 bits (8 bits = 1 Byte, 16 bits=1 Word) o 4 dgitos hexa, solo podramos llegar a direccionar 0FFFFh bytes, lo que significan 64 Kb solamente (de aqu la limitacin de los .COMs). Lo que se

hace es utilizar dos registros a la vez para apuntar a un solo byte, lo que nos amplia el campo a poder diferenciar 0FFFFh:0FFFFh bytes o 1 Mg de Mb muchsimo! Entonces, Que pasa que no se puede tener tanta memoria sin hacer cosas extraas? Claro, lo que pasa es que para direccionar se usan dos registros, pero no ubicados uno al lado del otro, sino desplazados un dgito. Que? Si, ya se que esta confuso, ahora te cuento: En un Registro, digamos que se llama DS, esta 0040h, y en otro, digamos BS, hay 006Ch. La direccin a la que apunta DS:BS (as se escribe) es 0040:006C, pero esta direccin, en nmeros de 5 cifras se escribe 0046C, la conversin es simplsima, lo que hay que hacer es sumar los registros de la siguiente forma:
BS -> 006C DS -> + 0040 --------------DS:BS -> 0046Ch

De esta suma, uno se puede dar cuenta que para referirse a una misma posicin de memoria puede haber muchas formas distintas. Por ejemplo, para referirse a 0046C, se puede hacer:
000C 046C +0046 +0000 ------- -------0046C = 0046:000C 0046C=0000:046C 023C 005C +0023 +003F -------- -------0046C = 0023:023C 0046C = 003F:005C

Es decir, puede haber muchas formas de nombrar el mismo byte, y tenemos que tratar de acostumbrarnos a darnos cuenta que, por ejemplo, 0F000:1234 y 0F123:0004 son equivalentes. Tenemos que una direccin de memoria se separa en dos partes, la de la izquierda del ':' es el famoso SEGMENT o segmento y lo de la derecha es el OFFSET o desplazamiento, de una direccin.

Conclusin: Para referirnos a cualquier Posicin de Memoria es necesario conocer su Segment y su Offset, ya que sabiendo uno solo, nos podemos estar refiriendo a muchos bytes distintos. Algunas Posiciones de Memoria tiles: de 0000:0000 a 0040:0000 la tabla de punteros de interrupciones. Cada puntero toma dos Words (un DWord) el primero para el Offset y el segundo para el Segment. en 0040:0000 Word El numero de Port correspondiente al COM1 en 0040:0002 Word El numero de Port correspondiente al COM2 en 0040:0004 Word El numero de Port correspondiente al COM3

en 0040:0006 Word El numero de Port correspondiente al COM4 en 0040:0027 Byte Status de las teclas especiales. en 0040:0049 Byte El modo actual de video. en 0040:006C DWord La hora actual, primero el word menos significativo y luego, en 40:(6C+2) el mas significativo. El numero es 18.2 veces la hora. a partir de B000:0000 La memoria de video de la Hrcules (Texto & Grficos) a partir de B800:0000 La memoria de video de las otras (Texto & Algunos Grficos) Muchas mas posiciones de memoria se pueden sacar de varios lugares, donde yo siempre busco es en ASM.NG (Norton Guide de Assembler) y en 2MchNfo2, (- Too Much Info Two -) como no poda ser de otra manera. :) Nota: Si un DWord es YYYYXXXX, el Word menos significativo es XXXX, y el mas significativo es YYYY. Si un Word es YYXX, el Byte mas significativo es YY y el menos significativo es XX. Para probar las posiciones de memoria, desde pascal pueden hacer: If Mem[$0040:$0049]=7 Then { Modo Texto } para leer un byte (el '$' significa Hexa) Mem[$B800:(Columna+File*80)*2]:='A' Para la letra Mem[$B800:(Columna+File*80)*2+1]:=White; Para el atributo MemW[$0040:0000] (o MemW[$40:0]) para un Word MemL[$40:$6C] para un LongInt (o DWord Signado) Desde C: if (peekb(0x0040,0x0017)==7) { /*Modo Texto*/ } para un byte (o char) pokeb(0xB800,(Columna+File*80)*2,'A') Para la letra pokeb[0xB800,(Columna+File*80)*2+1,WHITE) Para el atributo peek(0x40,2) y poke(0x40,2) para un int (Word Signado) y para un DWord hay que hacer un #define porque el C no trae: #define peekpokel(seg,ofs) (*(unsigned long far *)(MK_FP(seg,ofs))) ahora si: if (peekpokel(0x40,0x6C)==0x0F0342034) {} y peekpokel(0x40,0x6C)=0 para un DWord Muy bien, ahora ya sabemos que la mquina tiene memoria y tambin sabemos como apuntar a una posicin en esta memoria, pero bueno, este curso es de Assembler, no de memorias, por lo tanto, lo interesante y apropiado sera que les comentara, as como si de pasada fuera, como se hace en Assembler para cargar o grabar algo desde o hacia la memoria. Pero, primero hay que saber otras cositas... No es tan

fcil la cosa... Al "hablar" en Assembler, estamos dicindole a la mquina en lo mas cercano a su idioma posible (ya que su verdadero idioma es de "1" y "0" totalmente) lo que tiene que hacer. Estamos hablando directamente, nosotros mismos, sin la ayuda de un traductor (compilador), con el cerebro propiamente dicho de la mquina. Estamos hablando con el vendito 80x86. Entonces para decirle algo tenemos que conocerlo un poco mas. Como es muy probable que muchos tengan 8086/88 o 80286 vamos a ver especialmente, la estructura interna de estos "micros" (microprocesadores), por arriba, solo lo necesario para programar en assembler, obviamente tambin sirve para los iluminados que tengan 386 o 486, o quizs 586 o P-5. Internamente todos los micros (entiendo que todos), tiene unas pocas variables, llamadas REGISTROS que son en donde se procesan los datos, se hacen operaciones; son por las cuales se puede acceder a memoria, etc. Sirven para todo. Pero no todas sirven para lo mismo, y aunque muchas si sean intercambiables, todas estn destinadas para algo en especial, y tienen una que otra funcin propia. Los registros de la familia 80x86 son: AX BX CX DX SI DI BP SP IP CS DS ES SS Acumulator Register Base Index Register Counter Register Data Register Source Index Destination Index Base Pointer Stack Pointer Instruction Pointer Current Segment Data Segment Extra Segment Stack Segment Acumulador Indice Base Contador Dato Indice de Origen Indice de Destino Puntero Base Puntero de Pila Puntero de Instrucciones Segmento Actual del Programa Segmento de Datos Segmento Extra Segmento de Pila

Flags Sealizadores de Estado: Todos estos registros son de 16 bits, es decir de un Word. Pero los registros que terminan en X (AX, BX, CX, DX) pueden ser manejados, tambin, como si fueran dos Bytes (Que lo son), por separado, sus nombres son, AH para el Byte mas significativo de AX y AL para el menos significativo, BH y BL para BX, CH y CL para CX y DH y DL para DX (la H y la L hacen referencia a "Hi" y "Lo", es decir Alto y Bajo, alto es sinnimo de mas significativo y bajo de menos. Si por ejemplo: AX = 437Ah Entonces AH = 43h y AL = 7Ah BX = 0145h BH = 01h y BL = 45h CX = 0AABBh CH = 0AAh y CL = 0BBh DX = 1h DH = 00h y DL = 01h De igual manera, si:

AL = 10h y AH = 32h AX = 3210h BL = 08h y BH = 0CAh BX = 0CA08h CL = 1h y CH=1h CX = 0101h DL = 00 y DX=00 DX = 0000h Estos cuatro son los nicos segmentos que se pueden separar en byte alto y byte bajo. Funciones especificas: AX, Acumulator: Sirve para hacer todas las operaciones aritmticas, y algunas, como Multiplicar y Dividir, le son exclusivas. AX (y AL por su versin de un solo byte) son los nicos registros que pueden ser multiplicados y divididos por otro registro. La resta de AX y AL, por ejemplo, ocupan un byte menos que la de cualquier otro registro, pero esto no es para preocuparse, un byte, realmente no es nada, por mas que se acumule. BX, Base Index: Sirve para ser usado como registro de base para un ndice o array, es decir, una posicin de memoria puede ser apuntada por BX (su offset), igualmente tambin se lo puede usar para hacer sumas restas y todo tipo de operaciones lgicas. AX, CX y DX no sirven para apuntar a memoria. CX, Counter: Es el registro reservado para contar, como su nombre lo indica. Para este propsito hay rdenes especiales que lo decrementan o incrementan y hacen algo segn el resultado. Tambin hay ciertas rdenes repetitivas que necesitan saber cuanto repetirse, por medio de CX (o CL en su versin Byte) se les indica. DX, Data: Este registro no tiene definido un uso, en general es utilizado para pasar ciertos parmetros, pero si cumple una funcin, por ejemplo en la multiplicacin, si se multiplica AX=1000h (un Word) por, simplemente 10h (un Byte) el resultado es 00010000h (Un DWord), entonces, el Word Alto del resultado de la multiplicacin se deposita en DX, y el Bajo en AX. SI, Source Index: Puede ser utilizado como ndice a posiciones de memoria, es decir se puede poner un nmero en SI (Offset) y leer el dato de esta posicin. Pero a la vez tiene una funcin especfica, la de Registro Fuente para las rdenes de tratamiento de cadenas. Hay ciertas rdenes en Assembler que son para, por ejemplo mover toda una cadena de bytes, de un lugar a otro, la direccin de la cual se leen los bytes se pone en SI antes de decir que lea. DI, Destination Index: Como SI, puede ser usado como ndice. Pero su funcin especfica es la de Registro de Destino para las operaciones de cadena, lo que se lee de el contenido de SI (no de SI mismo, sino de la posicin de memoria a la que apunta SI) es depositado en la posicin de memoria a la que apunta DI, expresada por [DI]. Al la vez, igual que con SI, se pueden hacer operaciones aritmticas simples (suma y resta), y tambin todo tipo de operaciones lgicas (AND, OR, XOR). BP, Base Pointer: Puntero a una posicin de memoria, muy parecido a BX,

pero generalmente usado para facilitar el pasaje de parmetros en funciones hechas con lenguajes de alto nivel, por una caracterstica propia que ya voy a explicar. SP, Stack Pointer: Puntero que indica en que Offset termina el Stack, o pila. El Stack, es un rea de la memoria principal de la mquina, (no esta dentro del Micro, ni tampoco es fija) que sirve para preservar cosas, la estructura del Stack, que ya explicare mas a fondo, es simple, esta estructura es llamada LIFO (Last In First Out) o lo que es lo mismo, lo ltimo que entra, es lo primero que sale, es como si tuviramos una pila de cosas, lo ltimo que apoyamos arriba va a ser lo primero que podamos sacar despus. Si no esta claro, no se preocupen, ya voy a explicarlo bien, y voy a decir para que se usa, y cuando. IP, Instruction Pointer: El puntero de instruccin es el que le indica al Micro cual va a ser la prxima instruccin que debe ejecutar (Solo el Offset). El programa en Assembler tiene una estructura lgica, la cual se puede seguir. IP comienza al principio del programa (la prxima orden que se debe ejecutar es la primera del programa), se ejecuta esa orden e IP es incrementado tanto como Bytes ocupe la orden recin ejecutada (no todas las rdenes ocupan un byte) luego sigue con la prxima y as sucesivamente. Si pudiramos de alguna forma cambiar el contenido de IP lo que estaramos haciendo seria una desviacin, o un Jump (salto) a otro lado del programa, y efectivamente se puede hacer esto, pero no diciendo IP = 1234h, sino haciendo un salto, que es equivalente a esto ltimo: JMP 1234h. Ya lo voy a explicar, esto tambin. Se habrn dado cuenta, que siempre que dije que apuntaba a una posicin de memoria, hice notar que solo era el Offset lo que estaba comprendido, por ejemplo en DI o SI, BX o SP. Pero entonces, como es posible que con solamente el offset alcance para identificar una posicin de memoria? si yo mismo dije: "Para referirnos a cualquier posicin de memoria es necesario conocer su Segment y su Offset, ya que sabiendo uno solo, nos podemos estar refiriendo a muchos bytes distintos." Bueno, ac esta la cuestin: CS, Current Segment: Es el Segmento actual de ejecucin, juntos CS:IP apuntan a la prxima orden que el Micro debe leer para ejecutar. Veamos algo: CS:IP = 1000:FFFA hay una orden entonces IP se incrementa: CS:IP = 1000:FFFE Que pasa si ahora hay otra orden, e IP se incrementa de nuevo? Fcil: FFFE+1 = FFFF pero FFFF+1 = 10000 !!! Que pasa en este caso? CS no se incrementa, e IP no puede contener un numero de 5 cifras! Lo que pasa es que IP vuelve a 0000 y el programa sigue en CS:IP o sea 1000:0000, lo que es una posicin 64k mas baja de memoria, o sea cualquier lado... Este es el problema por lo que los .COMs no pueden tener

mas de 64k de largo sin hacer nada raro (cambiar CS cuando sea necesario). DS, Data Segment: Es el segmento destinado a ser usado junto con BX, SI y DI para apuntar a una direccin de memoria. Tambin puede ser usado con BP y SP, pero hace falta expresarlo concretamente. (Mas adelante aclaro esto) ES, Extra Segment: Es un segmento Extra para ser utilizado cuando haga falta. Tambin tiene una funcin propia: Junto con DI indican el destino en las "rdenes de cadena" (el dato ledo de DS:SI es puesto en ES:DI, en las ordenes de movimiento). SS, Stack Segment: El segmento de Stack; junto con SP apuntan a la ltima posicin que fue utilizada para "depositar" datos en el Stack. Por ultimo: Flags: Es un registro especial en el cual se guardan los resultados de la ltima operacin matemtica o de comparacin. No se guardan los resultados numricos, solo los de estado, es decir: CF PF AF ZF SF TF IF DF OF IOPL NT RF VM Carry Flag Parity Flag Auxiliary Flag Zero Flag Sign Flag Trap Flag Interrupt Flag Direction Flag Overflow Flag I/O Privilege Level Nested Task Flag Resume Flag Virtual Mode Flag Bandera de por Acarreo Bandera de por Paridad Bandera Auxiliar Bandera por Cero Bandera de Signo Bandera de Paso Simple Bandera de Interrupcin Bandera de Direccin Bandera por Sobre flujo Solo en 286 o superior Solo en 286 o superior Solo en 386 o superior Solo en 386 o superior

Hasta aqu la explicacin de los registros internos del Micro. Para apuntar a una posicin, hace falta indicar su Offset y su Segment, esto se hace mediante un registro de segmento (DS, CS, SS, ES) y un Offset, que puede ser un nmero o un registro como BS, SI, DI, BP, SP: DS:[3304h] Apunta al Segment DS y al offset 3304h. Los corchetes indican que lo que se quiere es el contenido de esa posicin, no la posicin en si. ES:[BX] Indica a la posicin que esta en el Segmento DS y el Offset BX. SS:[SP] Indica la posicin de arriba de todo del Stack, apuntada por el Segmento SS y el Offset SP.

No siempre hace falta indicar el Segment al que se apunta. Como el segment DS es el destinado para poner los datos, la gente de Intel decidi que si no se especifica segmento para un offset absoluto (un nmero como el primer caso), o para los registros BS, SI y DI, se asume DS. Para los registros SP y BP, se asume SS como Segmento por defecto. Entonces: [1304h] Indica el contenido de DS:[1304h] [BX] Apunta a DS:[BX], pero ES:[BX] Apunta a ES:[BX], porque se especifica ES ES:[0017h] -> a ES:[0017h] [SP] -> a SS:[SP] CS:[SP] -> a CS:[SP] CS:[DI] -> a CS:[DI] SS:[SI] -> a SS:[SI] [SI] -> a DS:[SI] [DI] -> a DS:[DI] [BP] -> a SS:[BP] ES:[BP] -> a ES:[BP] Es decir, cualquier combinacin de Segmento y Registro ndice o Base o Offset Absoluto puede ser formada, pero no siempre hace falta aclarar el Segmento. Hasta ahora vimos que en los microprocesadores hay variables llamadas REGISTROS, que cada uno esta destinado a una funcin especial, pero que en general se dividen en dos grandes grupos, los registros de uso general, por decirles de alguna forma, y los exclusivamente para ser usados como segmentos. Vamos a ver como es un programa en Assembler, pero antes, quiero aclarar que es un Assembler. Assembler, propiamente dicho, es el programa (TASM, MASM, A86, etc.) que se ocupa de transformar lo que nosotros escribimos, en palabras, se podra decir, a nmero, que es lo que realmente entiende la mquina. En realidad, lo convierte, actualmente, en un cdigo objeto, .OBJ, que es una herramienta que se creo para poder unir o Linkear varias rutinas hechas en distintos momentos y/o lenguajes. Lo que completa el proceso es el Linker, TLINK, LINK, OPTLINK, BLINKER, etc. Lo que yo uso, particularmente, son el Assembler y Linker de Borland, el TASM y el TLINK, pero bueno, si alguien quiere usar alguno mas, es cosa de darse maa, o preguntar que hay que cambiar. Primero, para comenzar por algo fcil, y para que por fin, de una vez por todas, puedan comenzar a hacer algo, vamos a hacer un .COM, es lo mas simple, mas rpido, y mas fcil de recordar. En TASM, hacer un .COM se simplifica mucho, se limita a poner al principio del programa:
EJEMPLO.ASM: .MODEL SMALL ; Tipo .COM, este modelo de memoria ; significa que SS, DS, ES y CS son iguales al ; comenzar el programa. Y que los datos y el stack

; estn sobre el mismo segmento pero claro, en ; distinto offset. .CODE ; Para decirle al Assembler que aqu ; comienza el cdigo. En otros modelos, como .HUGE ; hay que definir la parte de datos, con .DATA y ; la parte de Stack, con .STACK. ORG 100h ; Esta orden, para el compilador tambin ; le dice que comience el programa en el offset ; 100h. Todos los .COMs deben comenzar en el ; offset 100h. Mas adelante voy a explicar bien el ; funcionamiento de esta orden. ; Y luego completar el programa con lo que sea. EJEMPLO: ; Esta es una etiqueta, es un nombre que ; se le da a una posicin para, luego, poder ; referirnos a ella por su nombre. Esta es una ; ayuda que nos da el Assembler para no tener que ; referirnos a nmeros todo el tiempo. Ac hace ; falta para que el compilador sepa que todo ; comienza all. No es necesario que sea el nombre ; del programa, puede ser cualquier otra cosa pero ; yo acostumbro esto. ; La orden MOV (MOVE), lleva dos parmetros. Lo ; que hace es copiar el contenido del segundo ; parmetro al primero mov di,offset mensaje ; Esta orden, significa poner en DI el offset de ; la posicin que representa mensaje. (mirar mas ; abajo para ver mensaje). ; DI = Offset Mensaje Repetir: ; Pongo un 'label' o etiqueta, para ; usarlo luego. mov al,byte ptr [di] ; Pongo en AL el contenido de la posicin que ; indica [DI]. ; Recordemos que [DI] solo, significa DS:[DI], ; porque el segmento por omisin para DI es DS. ; Con 'byte ptr' indico que DS:[DI] es un ; puntero a un BYTE. AL = DS:[DI] add al,40h ; le sumo a AL 40h. ; AL+=40h (AL=AL+40h) mov byte ptr [di],al ; Pongo en DS:[DI] (lo que apunta DS:DI) el ; contenido de AL. DS:[DI]=AL inc di ; Incrementa DI en 1. ; DI++ (DI=DI+1) cmp al,'$' ; !!! Compara AL con '$', es decir ; con el valor ASCII de '$'. El resultado de la ; comparacin es guardado en los flags del micro. ; AL??'$' jne Repetir ; Salta si el resultado de la ltima

; ; ; ;

comparacin fue que son iguales. Jump if Not Equal. Si no eran iguales salta a Repetir, el label que habamos puesto al principio. AL=='$' ? Go Repetir

mov ah,09h ; Pongo en AH un 09h ; AH=09h mov dx,offset mensaje ; DX = Offset Mensaje int 21h ; !!! Ejecuto la Interrupcin 21h mov ax,4c00h ; AX=4C00h int 21h ; INT 21h Mensaje db 08h, 2Fh, 2Ch, 21h, 0E1h, 0E1h, 0E1h ; Aca estoy definiendo una lista de nmeros, ; cada uno es un byte. (DB = Define Byte). El ; primer byte de la lista esta bajo el nombre ; mensaje. Tambin podra haber puesto: ; Mensaje db 'El da esta lindo!' ; Se toma cada caracter como un byte. db 0CDh, 0CAh, 0E4h ; Esta lnea es la continuacin de la anterior. ; Es necesario volver a poner DB. END EJEMPLO ; assembler ; El nombre ; mismo del ; Con esta orden, le digo al que mi programa termina ac. despus de END tiene que ser el principio.

Dentro de este cdigo hay, fundamentalmente, dos tipos de rdenes: Las ordenes propiamente de Assembler. (MOV, CMP, JNE, INT, ADD, INC) Y las rdenes al compilador, que le dicen como tratar el archivo. (.MODEL, .CODE, END) Por otro lado, estn las variables y labels, que son ayudas que nos da el compilador. Si esto no existiera tendramos que recordar, en vez del nombre de una variable, su posicin, y adems tendramos que calcularla a mano. De todo esto se ocupa el compilador (ensamblador). Este programa, funciona y hace algo, pero, claro, no todo es tan simple. Traten de analizarlo antes de ejecutarlo, para eso van a necesitar una lista de interrupciones. Si no la tienen, vayan consiguindola, casi todo programa en assembler se aprovecha de las interrupciones. Tengan en cuenta que en un .COM, al comienzo, DS, ES, CS y SS tienen el mismo valor, y claro que lo conservan a nos ser que se lo cambiemos nosotros. Con estos bsicos conocimientos ya se pueden ir dando maa para hacer otras cosas, traten de ver si les sale algo. Piensen que quieren hacer y como, si hay algo que no se les ocurre, traten otra vez, que esa es la mejor forma de aprender, tratar hasta que salga, si no les sale, pregunten, que por esta vez puede pasar... :)

Ac esta lo que van a necesitar, sobre las interrupciones que usa el programa. INT 21 - DOS 1+ - WRITE STRING TO STANDARD OUTPUT AH = 09h DS:DX -> '$'-terminated string _______________________________________________________ INT 21 - DOS 2+ - "EXIT" - TERMINATE WITH RETURN CODE AH = 4Ch AL = return code _______________________________________________________ Interprtenlo como les parezca, para que se vayan acostumbrando, vio? Anteriormente hicimos un COM. En Assembler, entre hacer un COM o un EXE, casi no hay diferencia, ya que todo lo tenemos que hacer nosotros explcitamente, el compilador se ocupa solamente de lo bsico. Les dije que para hacer un .COM (siempre en TASM), lo mas fcil es poner:
.MODEL TINY .CODE ORG 100h NomProg: END NomProg

Entre el Label "NomProg:" y el fin del archivo "END NomProg", hay que poner todo el cdigo del programa en si. Mas adelante vamos a ver que significa cada una de estas cosas, y como cambiarlas para crear EXEs de distintos tipos, por ahora, recurdenlas para poder probar sus cositas. Como en todo lenguaje, adems de saber como programar hay que saber las rdenes, para poder decirle que hacer a la mquina. Yo voy a ir explicando de a poco todas las rdenes que se me ocurran, pero como buena gua de consulta sugiero la Norton Guide de Assembler, (Sali una versin nueva que esta en Kansas City). Esta NG es una buena gua y explica bastante bien que hace cada orden, igualmente, me ofrezco para que si alguien quiere hacer algo en Assembler, y le surge alguna duda, me lo pregunte; ahora tenemos el rea Assembler. Formato general de una orden: mnemnico [Param1 [,Param2]] Donde: Mnemnico es la orden en si misma, es llamada mnemnico porque se utilizan estas letras, para no tener que recordar el nmero de la orden. Son letras que parecen no tener significado, pero si lo tienen, y una vez que se lo conoce, no solo se recuerdan, tambin se aciertan algunos que no se conocan antes...

Param1, no siempre se utiliza, hay Mnemnicos que no requieren parmetros. Este parmetro, cuando una orden lleva dos [parmetros], es llamado Destination, es donde se guardan los resultados de las operaciones, claro que puede no hacer falta, pero, digamos, que como siempre, estas son las excepciones a las reglas... Param2, muchas veces, este parmetro no existe, pero normalmente, cuando es necesario, es llamado Source, y es el origen de las operaciones en las que interviene. Otra vez, tenemos que decir, que hay excepciones a esta regla... Ahora si, algunas rdenes concretas: MOV Param1,Param2 Esta orden, MOVe, mueve, o mejor dicho, copia el contenido de Param2 a Param1. Por ejemplo, MOV AX,BX es el equivalente a decir AX=BX, el valor de BX no cambia, y el de AX se transforma en el de BX. Param1, puede ser tanto, un registro como una posicin de memoria. Param2 puede ser una constante, un registro o una posicin de memoria. Pero hay ciertas restricciones, a una posicin de memoria no se le puede asignar el contenido de otra posicin de memoria, es decir MOV DS:[1200],ES:[3020] NO es una orden valida. Si se desea hacer esto, hay que desdoblarlo en dos ordenes: MOV AX,ES:[3020] MOV DS:[1200],AX Si lo que se quera mover era un word. O cambiando por AL (en vez de AX) si se quera mover un byte. (AX y AL son ejemplos, podra haber sido cualquier registro). Hay otras formas de hacerlo sin destruir el contenido de AX, ya lo vamos a ver. Hay otra limitacin mas, a un registro de segmento, no se le puede asignar directamente un valor, slo esta permitido asignarle el contenido de otro registro, pero que tampoco sea de segmento, es decir, para hacer: DS=CS hay que hacer, otra vez: MOV AX,CS MOV DS,AX Y otra vez hay mas formas, y tambin, ya las vamos a ver. Otra orden muy utilizada, es la orden: INT IntNum

Esta orden llama a una interrupcin, es decir, busca en el rea de memoria donde estn los punteros a las subrutinas de interrupciones (ISR), y llama a donde apunta el nmero de interrupcin especificado. (Un puntero, es una direccin de memoria, que apunta a algo, en este caso a la posicin donde comienza cada ISR. Las interrupciones son rutinas que estn a disposicin nuestra, para que las utilicemos cuando nos sean necesarias. Son rutinas que nos facilitan mucho la tarea de programar. Hay varios tipos de interrupciones: Interrupciones de BIOS: estas interrupciones son las que instalan las Plaquetas que ponemos en el motherboard, tambin esta el BIOS propio de la mquina. Los BIOS, son ejecutados al encenderse la computadora, primero se ejecuta el BIOS propio del mother (son, normalmente dos chips con etiquetas, que se pueden ver al abrir la mquina), este BIOS "principal" se ocupa de instalar sus interrupciones y de verificar si hay otros BIOS agregados en plaquetas, si los hay, los ejecuta y ellos se encargan de instalar sus propias interrupciones. Las interrupciones de BIOS, son las que nos facilitan el acceso a los distintos perifricos, ya que se encargan de "hablar" directamente con el HardWare, cosa bastante pesada de hacer, y que por otro lado, puede cambiar de Hard en Hard. Gracias al BIOS, podemos acceder al monitor sin que nos importe la marca ni el modelo, solamente llamamos a las interrupciones necesarias. Las Interrupciones de DOS, son el sistema operativo en si, una mquina es completamente funcional sin BIOS, pero claro, tendramos que estar hacindonos nosotros las rutinas necesarias para que nuestros programas funcionen en todas las mquinas (serian todos enormes!!!), bueno, el sistema operativo, es la interfase entre el usuario y el BIOS, el sistema operativo es el que nos da la facilidad de manejar archivos, de reservar memoria, en fin, de administrar los recursos de la mquina, de una forma que no cree conflictos entre los programas de distintos programadores. Es el que pone las reglas de como utilizar la mquina. No es complicado, si pesado, manejar archivos sin DOS, de hecho varios programas, como el DiskExplorer de Norton, lo hacen, pero, otra vez, que sentido tiene tener que poner un sistema operativo en cada programa que hacemos...* Entonces, las interrupciones de DOS, son las que nos permiten manejar los distintos recursos de la mquina, es decir, los archivos, los directorios. La memoria y el flujo de programas en si. Es el que nos facilita la entrada de teclado o disco (hacindola indistinguible), etc. Luego estn las IRQ (Interrupt Request), estas interrupciones son interrupciones propiamente dichas, no son normalmente llamadas por un programa. Estas IRQs son llamadas directamente por el HardWare, para indicar alguna situacin especial. Por ejemplo, el Mouse llama a una IRQ para avisar que surgi algn cambio de estado en el propio Mouse. El Teclado, llama a una IRQ para decir que hay algn mensaje proveniente de el hacia la CPU, etc. Normalmente, lo que se hace con las IRQs es reemplazar la rutina a la que apunta la tabla de punteros y entonces cuando sucede una IRQ, nuestra rutina es llamada directamente por el microprocesador, desde all se lee el Mouse o el Teclado, o lo que corresponda. Muy extraamente, por estas razones, nuestro programa llama a una IRQ.

Bueno, entonces tenemos que las Interrupciones son rutinas que nos facilitan la programacin, son rutinas ya instaladas en la mquina, que hacen tareas complejas por nosotros. Y como tales rutinas, llevan parmetros, pero donde? si la orden es: INT IntNum Las Interrupciones toman los parmetros de los registros, y su resultado tambin vuelve en registros... Las Interrupciones BIOS, por ejemplo son las 13h, 10h, 11h, 12h, 16h, 17h, 19h, etc... Las DOS, son las 20h, 22h, 23h, 24h, 25h, 26h, 27h, 28h, 29h. Pero la fundamental es la INT 21h, por medio de ella es posible hacer casi todo lo necesario para llevar un programa a la marcha... Pero como puede ser que con una sola INT sea posible hacer tantas cosas? Muy simple, muchas INTs tienen funciones y sub-funciones, las cuales se identifican segn el valor de los registros, normalmente AX o AH son utilizados para decir a que nmero de funcin/sub-funcin queremos acceder. As, por ejemplo, la INT 21h si AH = 09h, sirve para mostrar un String en pantalla, pero si AH = 39h sirve para hacer un directorio. Como ven, la utilidad de una INT no solo esta limitada a una funcin, si no que puede tener mltiples usos. Algo fundamental en la utilizacin de un Assembler, es la posibilidad que nos da de ponerle nombres a las posiciones de memoria, es decir, podemos poner una cadena en memoria, y asignarle un nombre, tal como si fuera una variable, y de hecho, lo es. La forma de reservar lugar para una variable, dentro de un programa, no es complicada: Nombre XX Valor Nombre es el nombre con el que nos vamos a referir, mas tarde a esa posicin de memoria, es el nombre de la variable. XX, es la definicin del tipo de la variable: DB DW DD DQ DT Para definir un byte, dice que la variable es un byte, o un array de Bytes, es decir, un byte atras de otro. Para definir un Word o un array de Word. Para definir un DWord, o un array de DWord. Para definir un QWord (QuadWord, u ocho bytes). Para definir Ten Bytes (diez).

Valor es el valor inicial, no puede faltar nunca, claro que si no se le quiere dar ningn valor inicial, es factible poner, en el lugar del valor, u '?', que significa que reserve espacio sin importar que valor le de. Definiciones validas, podran ser: Letra_A DB 'A' ; Un caracter ** Number_1 DW 1 ; Un Numero 1, pero Word. Pointer DD 0B000h:8000h; Puntero a la pantalla de video. String DB 'Hola, Como estas!'

; Cadena definida como array ; de bytes. Array DB 1,2,4,8,16,32,64,128 ; Array de Bytes... etc... La vez pasada me pase con el programa, quizs era un poco complicado, pero era para que tengan una idea de como es un programa en Assembler, quizs muchos le encontraron la vuelta y animaron a largarse a programar. Sugiero, que traten de entender programitas en Assembler, no es ninguna ciencia este lenguaje, es uno de los mas simples, pero lleva su tiempo encontrarle la vuelta... Ac va otro programita, tambin rebuscado, pero, yo se que si no entienden van a preguntar... O no? (:
.model tiny .code org 100h Ejemplo_2: jmp Comienzo ; Salteo el rea de datos, si se ; ejecutara (no hay diferencia entre datos y ; programas) seria una colgada mas... Matching DB '*.*',0 ; Array: Una cadena mas un nmero. Comienzo: mov ah,4eh mov cx,0 mov dx,offset Matching ; DX = Offset de Matching ; DS, al entrar a un .COM es igual a CS. int 21h ; Que hace? jc Error ; Si esta prendido el Carry Flag, salto mov ah,2fh int 21h ; Y esta? mov byte ptr es:[bx+1eh+13],'$' ; Byte ptr para decirle que a lo que apunta ; [bx+13] es un byte, podra ser un word ptr, o ; un dword ptr. El '$' es el fin de una cadena ; a imprimir por el DOS. mov dx,es mov ds,dx lea dx,[bx+1eh] ; Pone en DX el Offset al que apunta ; BX+13, es decir DX = BX+13 mov ah,9 int 21h ; Imprime una cadena. Error: mov ax,4c00h int 21h END Ejemplo_2

* Fuera de tema, pero interesante quizs, es el hecho de ampliar cada vez mas este concepto de reutilizacin de cdigo hasta llegar al Windows, donde ningn programa trae las rutinas para hacer mens, botones o ventanas, pero todos las utilizan. Tambin crearon las DLL (Dinamic Link Libraries) que pueden ser reutilizadas por varios programas, pero claro, hay que saber aprovecharlo...

** Desde el ';' hasta el final de la lnea, es considerado comentario por el compilador. Bueno, espero que entiendan algo, porque la verdad, que aunque lo le varias veces, tengo mis dudas, todava... A continuacin la ltima entrega de interrupciones tiles... -------------------------------------------------------------------------INT 21 / AH=4Eh Find First Matching File Entrada: AH = 4Eh CX = Attributo a buscar. DS:DX -> puntero a un ASCIIZ (Cadena terminada en 0) con el nombre a buscar, wildcards permitidos. Devuelve: AX = Codigo de Error, si El Carry Flag (CF) esta en uno. DTA = Contiene la informacion de retorno. -------------------------------------------------------------------------DTA = Offset Tamao Significado 00 Byte Atributo de la bsqueda [...] 1E 13 bytes ASCIIZ del nombre del archivo encontrado. -------------------------------------------------------------------------INT 21 / AH=2Fh Get Disk Transfer Address (DTA) Entrada: AH=2Fh Devuelve: ES:BX -> Puntero con la direccin de la DTA actual. --------------------------------------------------------------------------