a rtesanías
in italiano in english
artículos descargas cursos
Un taller en desarrollo para la construcción de futuras aplicaciones para MenuetOS y la divulgación de la programación en lenguaje ensamblador.

PRIMEROS PASOS:

Bienvenidos a éste primer curso de programación en ensamblador. Nuestro objetivo será construir de manera simple algunas aplicaciones básicas usando elementos del sistema operativo Windows, pero nos concentraremos en aspectos generales, aplicables a otros sistemas operativos. Recordemos que nuestro objetivo es más amplio: desarrollar aplicaciones para un sistema operativo hecho completamente en lenguaje ensamblador.

¿Por qué escogimos Windows para el curso?
La razón fundamental es que tenemos a disposición una serie de herramientas que facilitarán nuestra labor.
Además es un sistema operativo conocido por un grán número de personas y por lo tanto presenta una mayor familiaridad. Windows nos permitirá entender los conceptos que más tarde podremos aplicar en la construcción de un sistema operativo completo.

Hablemos del paquete de entrenamiento del curso:

Paquete de entrenamiento tut01.zip (50 kB)

Ahora es un buen momento para descargarlo. Contiene solo lo estrictamente neceario para el presente curso, con el fin de evitar distracciones. Recuerda que iniciaremos desde cero, sin requerir ningún conocimiento previo.

Abril 17 de 2004



Si ya posees conocimientos en programación de computadores, lo que es muy probable, déjalos a un lado durante éste curso. Piensa en el curso como un repaso para que aproveches al máximo los conceptos. Éste curso pretende enseñar ensamblador, programación en Windows, estructuras de datos y el uso de las herramientas.
Todo de una vez y sin ningún conocimiento previo. Son muchos conceptos y es un gran reto para nosotros, por lo tanto te pedimos confianza y paciencia.

Hicimos un esfuerzo en dosificar los contenidos. Trata de no anticiparte a los acontecimientos para que puedas aprovecharlos al máximo.
Son temas muy extensos. Sea el lenguaje con su juego de instrucciones o el sistema operativo y sus librerías y funciones que las estructuras de datos, son objetos de especialización de muchos años. Nosotros solo podemos aspirar a pellizcarlos superficialmente con éstos cursos, pero queremos que al terminarlos estés en grado de poder profundizar el que más te interese.

Un pequeño paréntesis: Trata de usar el inglés en lo posible dentro del código, así podrás contar con mayor ayuda a la hora de hacer preguntas en los foros. Además le darás mayor uniformidad al código fuente, bien sea con el lenguaje de programación que con las librerías del sistema operativo.

Concepto fundamental
Como el procesador de tu computadora puede trabajar solo con unos y ceros, el secreto de la programación de computadores radica en interpretar la realidad con números. Cada uno o cada cero lo llamaremos bit, la mínima unidad de información.

Existen muchos trucos y artimañas para representar fracciones, texto, canciones o fotos como secuencias de unos y ceros. Cada día se desarrollan formas más eficientes o se mejoran las existentes. Con calma las iremos viendo a medida que las vamos necesitando.


Como prometimos, empezaremos inmediatamente con un ejemplo práctico. Nos interesa crear un archivo ejecutable que haga alguna función. Un EXE (ejecutable) en Windows es un archivo binario que contiene unas instrucciones que le dicen al sistema operativo que hacer cuando el usuario lanza el programa. El formato en el que las instrucciones están consignadas al interior del archivo es conocido como PE (Portable Ejecutable) y lo iremos analizando poco a poco.

¡Es hora de comenzar a ensamblar! Lanza el fasm para windows (fasmw.exe) que encuentras en el paquete de entrenamiento. A continuación pega en el editor el código que encuentras en el cuadro blanco.
Se trata quizá del programa más simple para producir una ventana en windows con el tradicional "Hola mundo".
Vamos primero a describir superficialmente el código parte por parte y luego podremos verlo en acción.

Listado de tut01en1.asm
format PE GUI


MB_OK              = 00h
MB_ICONEXCLAMATION = 30h


push MB_OK + MB_ICONEXCLAMATION
push _caption
push _message
push 0
call [MessageBox]


push 0
call [ExitProcess]


_caption db 'Ensamblando programas para Win32',0

_message db '¡Hola Mundo!',0


data import

dd 0,0,0,RVA kernel_name,RVA kernel_table
dd 0,0,0,RVA user_name,RVA user_table
dd 0,0,0,0,0


kernel_table:
ExitProcess dd RVA _ExitProcess
dd 0
user_table:
MessageBox dd RVA _MessageBoxA
dd 0


kernel_name db 'KERNEL32.DLL',0
user_name db 'USER32.DLL',0


_ExitProcess dw 0
db 'ExitProcess',0
_MessageBoxA dw 0
db 'MessageBoxA',0

end data

Pantallazo
Resultado
format

Ésta palabra es una directiva del fasm. Le indica al ensamblador que tipo de formato debe dar al archivo final, es decir al programa que queremos producir.
PE GUI

Los valores dados a la directiva format para producir un "Ejecutable Portátil" para la interfaz gráfica.
=

El signo "igual que" es otra directiva. Le dice a fasm que el nombre dado representa el valor numérico asociado.
Al momento de escribir el archivo, fasm sustituye cada aparición de "MB_OK" con un cero (0).
Los valores numéricos terminados en "h" son interpretados como hexadecimales, es decir, números que van de 0 a 15 en lugar de 0 a 9 usando las primeras 6 letras del alfabeto. Son tan utilizados que haremos una exposición más detallada luego. El número 030h corresponde al 48 decimal.
push

Es una instrucción del lenguaje ensamblador que viene convertida por fasm en código directamente ejecutado por el procesador. Es decir, es una orden directa para que el procesador haga una función determinada.

Push empuja el valor dado a continuación en una pila de valores. La pila almacena los valores en el orden en que llegan, con el último valor empujado de primero.

El resultado de la suma de 0+030h viene empujado en la pila.

Es decir, la pila tiene como primer valor el 030h
La instrucción siguiente empuja en la pila el valor del label o etiqueta "_caption" que es una dirección o posición de memoria. Éste es un concepto fundamental para el aprendizaje del lenguaje ensamblador.

Fasm conserva el valor de posición que corresponde al punto donde se define la etiqueta "_caption". Para definir una etiqueta hay tres opciones equivalentes:

1. Usar una directiva de datos, en el caso de _caption es db
2. Hacerlo seguir de dos puntos, como en el caso de kernel_table:

3. Usar la directiva label, que veremos en otro curso.
db

Es una directiva de datos que quiere decir Data Byte. Indica a fasm que debe convertir la información que sigue en secuencias de bytes para escribirlas en el archivo producido (nuestro programa).

El byte es una unidad de información correspondiente a 8 bits, o sea que puede representar un valor entre 0 y 255.

Cómo información podemos tener números y/o cadenas de texto separados por comas. La cadena de texto se convierte a bytes usando un código donde a cada símbolo corresponde un número (código ASCII).

call

Es otra instrucción del lenguaje ensamblador. Ésta se encarga de "llamar" una función, que puede ser interna o externa. Una función es una porción de instrucciones que hacen una tarea determinada y por lo tanto vienen agrupadas bajo una etiqueta. Recordemos que la etiqueta representa una dirección de memoria.

Llamar la función es decirle al procesador que ejecute las instrucciones cuando llamamos la etiqueta.
La función MessageBox es una función externa a nuestro programa. Pertenece al Windows y puede ser usada por cualquier programa. Ella será la que nos muestre la ventana en la pantalla y esperará a que pulsemos un botón.

Para trabajar, la función necesita saber que título y que mensaje mostrará, cuántos botones y de que tipo. Ésta información la obtiene de la pila directamente, por lo tanto nosotros debemos ponerla en orden y bien completa.
La función ExitProcess es otra función del Windows. Ella se encarga de terminar correctamente nuestro programa; un programa bien hecho en Windows termina siempre con ésta.

Notaste que le damos un valor de cero en la pila. Éste sirve para que nosotros le comuniquemos al Windows como terminó el programa. La convención indica que con un cero le decimos que todo salió bien.
Aquí termina efectivamente la ejecución de nuestro programa.

Quedaron faltando por analizar las últimas líneas del listado. Éstas líneas no se ejecutan. Sirven para el correcto funcionamiento del programa y cada una cumple con una función determinada. Aunque parecen bastante crípticas, en realidad no lo son tanto. Para explicarlas, necesitaremos unos conceptos adicionales que veremos al final de éste primer curso.


Por ahora no esperemos más. ¡Veamos nuestro programa en acción!

A continuación, grabaremos el código fuente en el disco, lo ensamblaremos y lo ejecutaremos. Desde el menú "Herramientas" en el editor, seleccionamos "Ejecutar" y fasm se encargará del resto. Te preguntará cómo y dónde guardarlo. Le das aceptar y casi inmediatamente te aparecerá un cuadro como el que ves aquí arriba.

Ya tenemos un programa funcionante. Trabaja muy poco, pero ya contiene los elementos esenciales para todo programa en Windows.
Iremos viendo cada elemento mientras el curso se desarrolla e iremos incrementando la complejidad del programa a medida que aprendemos más conceptos.

Nota:
Es posible que tu programa antivirus produzca una alerta.
No te preocupes, el problema en éste caso no es tu programa sino el antivirus.
- ¿cómo?
Simplemente se confunde por ser un programa tan pequeño e hipotiza que es un virus. Lo que pasa es que como los virus también son pequeños para poder pasar inobservados y replicarse fácilmente, el antivirus trata de defenderte de un ataque, en éste caso inexistente.
Un poco más adelante pondremos remedio a ésta situación y el antivirus no sospechará más de nosotros.

Mejoras...



Los archivos ejecutables PE vienen organizados en secciones según el tipo de información que necesiten. Así por ejemplo las instrucciones que se ejecutan van en una sección, los datos que no se ejecutan van en otra, las tablas con los nombres de las funciones de Windows se ponen en otra sección y así sucesivamente.

En nuestro caso tenemos todo junto y como no le dimos ninguna órden al respecto a nuestro ensamblador, fasm lo puso todo en una sección que llamó ".flat".
Para ser más ordenados y evitar sospechas de los antivirus, vamos a organizar nuestro programa en secciones.

Listado de tut01es2.asm
format PE GUI
MB_OK              = 00h
MB_YESNO           = 04h
MB_ICONEXCLAMATION = 30h


section '.code' code readable executable

push MB_YESNO + MB_ICONEXCLAMATION
push _caption
push _message
push 0
call [MessageBox]

push 0
call [ExitProcess]


section '.data' data readable writeable

_caption db 'Ensamblando programas para Win32',0

_message db '¿Te gusta fasm?',0


section '.idata' import data readable

dd 0,0,0,RVA kernel_name,RVA kernel_table
dd 0,0,0,RVA user_name,RVA user_table
dd 0,0,0,0,0

kernel_table:
ExitProcess dd RVA _ExitProcess
dd 0
user_table:
MessageBox dd RVA _MessageBoxA
dd 0

kernel_name db 'KERNEL32.DLL',0
user_name db 'USER32.DLL',0

_ExitProcess dw 0
db 'ExitProcess',0
_MessageBoxA dw 0
db 'MessageBoxA',0

Pantallazo
Resultado
Nuestro programa se mantiene prácticamente inalterado, lo que cambia es el resultado final, es decir, el ejecutable.
Las primeras líneas son idénticas. Vemos que las igualdades quedaron ántes de la sección. En realidad, éstas no afectan el resultado final, pues en ningún momento harán parte del ejecutable. Sirven para dar nombres especiales a ciertos números de tal forma que tengan significado claro y nuestro código se lea mejor.
section

Ésta directiva hace que fasm reserve espacio en el PE para una sección. El orden en el ejecutable será el mismo que la sección en el código.
Luego se indica un nombre que puede ser cualquier grupo de 8 caractéres, pero por estandarización cada sección tiene un nombre según el tipo de información que contiene.
La primera sección se llama ".code" y contiene las instrucciones que el procesador va a ejecutar. Conviene que el Windows lo sepa y por eso le decimos que es executable.
Por seguridad, el Windows debe saber si la sección es de solo lectura o lectura/escritura. En éste caso indicamos readable porque no pretendemos escribir en ella.
Una de las razones por las que los antivirus desconfían de la primera versión de nuestro programa es que una única sección con mezcla de datos y código es marcada cómo lectura/escritura, por lo tanto, podría tratarse de código mutante. En otras palabras, programas que se modifican ellos mismos como lo hacen muchos virus.
Nuestra segunda versión es la solución a éste problema.
La segunda sección ".data" indicada como data para que fasm sepa que las líneas que siguen son datos, es decir, que no producen instrucciones para el procesador. la marcamos como writeable aunque no escribiremos en ella. Nuestro programa es muy simple y lee los datos sin modificarlos. Un programa normal, necesita modificar ciertos valores y por lo tanto escribir en la sección de datos es lo común.
Finalmente, la tabla con los nombres de librerías y funciones de Windows la llamamos ".idata". la marcamos como import para indicar que tipo de datos contiene.
Una sección llega hasta el comienzo de otra o como en éste caso, hasta el final del código fuente.
Es una buena idea grabar ésta nueva versión con otro nombre para poder compararla con la precedente.
Después de compilarlo y ejecutarlo nos damos cuenta que el ejecutable es más grande.
El crecimiento es debido a la forma de organizar las secciones al interior del formato PE y podremos verlo más de cerca en el próximo curso.

Ahora hablemos un poco de las líneas finales de nuestro programa. Hemos especificado que el tipo de datos requerido para la sección es import y esto se hace con el fin de indicarle a Windows que queremos llamar funciones que no son nuestras sino externas a nuestro programa. Las queremos importar, en éste caso del sistema operativo.
¿Cómo se logra?
A través del formato PE, con una tabla precisa en donde Windows puede encontrar las etiquetas de las funciones requeridas por nuestro programa.

En Windows, las funciones del sistema operativo se encuentran coleccionadas en unos archivos con extensión DLL, llamados librerías de enlace dinámico. Cada una de éstas librerías contiene una o más funciones con sus etiquetas respectivas y listas para ser empleadas por nuestros programas. Lo único que tenemos que hacer es saber sus nombres correctos y construir la tabla estríctamente de acuerdo al formato PE.

La tabla debe contener la siguiente información:

Nombre de la librería: KERNEL32.DLL USER32.DLL
Nombre de las funciones requeridas: ExitProcess MessageBox

La clave para construir la tabla está aquí:
dd 0,0,0,RVA kernel_name,RVA kernel_table
dd 0,0,0,RVA user_name,RVA user_table
dd 0,0,0,0,0
La directiva de datos dd indica a fasm que debe convertir la secuencia de datos separados por comas en datos DWORD (double word) que son números de 4 bytes o sea los famosos 32 bits.
RVA es un operador del fasm que calcula el número de bytes desde el principio de la sección del PE hasta el punto en que se definió la etiqueta correspondiente, en éste caso "kernel_name".
RVA significa Relative Virtual Address (Dirección virtual relativa) y se usa porque Windows decide dónde poner las secciones en memoria cuando carga el programa. RVA es un concepto avanzado que trataremos en detalle en otro curso.

Windows encuentra la tabla, busca la dirección relativa en donde tenemos el nombre de la librería. Busca la librería entre ciertos directorios. En éste caso, busca dentro del directorio de sistema, comunmente C:\Windows\System32.
Una vez cargada la librería ubica las funciones con el nombre que le dimos, hace sus conexiones y listo. Nuestro programa funciona.

Un poco de teoría...


¿Para qué se crearon éstas librerías y que quiere decir que sean dinámicas?

Las librerías se crearon para evitar que cada programa que necesite hacer una tarea común como por ejemplo mostrar un mensaje lo hiciera a su manera y repitiendo el mismo código una y otra vez.
Son dinámicas porque entran a funcionar cuando el programa es ejecutado y no hacen parte de nuestro programa, es por eso que el programa es tán pequeño.
Cuando el programa es ejecutado, Windows lo carga en la memoria RAM, busca la tabla de import para saber que librerías debe cargar a su vez en la memoria y así poder buscar las funciones por su nombre o etiqueta.
Si una de las librerías o una de las funciones no es localizada o su nombre es incorrecto, Windows no deja que nuestro programa sea ejecutado


Vale la pena analizar un poco que quiere decir "cargar" en la memoria.
El procesador de tu computadora no puede ejecutar instrucciones o trabajar con datos que se encuentren almacenadas en discos. Necesita que sean leídos y almacenados en la memoria RAM. Ésto es lo que Windows hace cuando ejecutamos un programa.
El término procesador es una abreviatura de Microprocesador o CPU (Unidad Central de Proceso)

CONCEPTOS RELACIONADOS:
Éste es un buen momento para ampliar éstos conceptos:

Procesador (CPU)
Memoria RAM
Discos de almacenamiento

Conclusión



Esperamos que hayas disfrutado del curso y que te entusiasmes con el lenguaje ensamblador: el único que te da el control total sobre tu computador.
Hemos visto solo dos instrucciones del procesador, pero hemos avanzado sólidamente con el funcionamiento del sistema operativo.


Nuestro programa irá creciendo a medida que veamos las potencialidades del lenguaje, nuevas instrucciones y nuevas funciones del sistema operativo.

Sigue con el curso: TOMANDO CONFIANZA.


Retroalimentación:

Para nosotros es sumamente importante conocer sus preguntas y comentarios acerca de ésta página para poder mejorar los contenidos del curso. Responderemos y clasificaremos los comentarios con la mayor brevedad posible.

Gracias



Los programas distribuidos en éste sitio son gratuitos para cualquier uso.
Todos los derechos están reservados por sus respectivos autores. El material educativo y los artículos están portegidos por la
Licencia Artística Artesanal.
® 2004 Artisan Shop