Programación en Lenguaje Ensamblador

-El Verdadero Lenguaje de las Máquinas-

Como funciona el Gameloop de un Videojuego en Windows

–PeekMessage, Gameloop y Sincronización–

Esta vez no voy a perder tiempo con mis nuevos lectores no comprometidos con la programación en ensamblador y me voy a concentrar en explicar el Gameloop con PeekMessage, total. Por este tiempo voy a estar muy ocupado programando. Ya dejaremos las discusiones para pasado marzo cuando los números de VG Chartz nos den un enfoque objetivo de lo que realmente pasa en “la industria”. No vayan a pensar que porque mi actividad en otros foros baje es que estoy tramando algún plan siniestro, a menos que consideren peligroso el minijuego en ASM en el que me estoy concentrando en este momento. Bien, ahora a programar.

toma externa

En esta imagen vemos un diagrama de flujo o flowchart de un ciclo de mensajes. Al igual que en el anterior, las rutinas en azul son procesos del Windows y las grises son rutinas del usuario. Para quienes no han leido sobre programación mas que lo que les obligan a leer en la escuela, los rectángulos con dos rayas verticales a los lados son subrutinas que están definidas en otro lugar y que devuelven el control al programa principal cuando terminan. Subrutina, función, procedimiento, método, en este caso significa lo mismo. Entonces comencemos con PeekMessage

PeekMessage, a diferencia de GetMessage no se sienta a esperar a que el sistema operativo le envíe un mensaje. En lugar de eso lo que hace es echar un rápido vistazo (que es lo que en inglés significa el verbo “peek”) a la entrada de mensajes del mismo modo que uno hace cuando se asoma a ver si el cartero le ha dejado una carta en el buzón. Una vez echada esta rápida mirada regresa en el acumulador un cero en caso de no encontrar un mensaje y un valor diferente de cero en caso contrario para luego seguir su camino. PeekMessage tiene casi los mismos argumentos que GetMessage pero incluye uno extra que le dice que debe de hacer en caso de encontrar un mensaje, en el caso de un juego debe de enviarse en este argumento la constante PM_REMOVE para que tome el mensaje si lo encuenta y lo copie en la estructura de mensajes que le tenemos reservada en la sección de datos. Luego procesamos el mensaje con TranslateMessage y DispatchMessage como en el ciclo tradicional.

Y es justo a partir de este punto cuando interviene el Gameloop. Independientemente de si se procesó un mensaje o no, en cada iteración debe hacerse el intento de entrar al Gameloop. Mas adelante veremos el detalle de como se sincroniza este último con el ciclo de mensajes. Inmediatamente luego de ejecutar una iteració del gameloop se revisa el contenido de una bandera que nos indica si debemos de terminar el prorama. En este caso le puse el elegante nombre de fuck_off que podría traducirse al castellano como “irnos al demonio”. Si la bandera está puesta a cero entonces volvemos a ejecutar otra iteración del ciclo de mensajes y si es falsa salimos del ciclo, ejecutamos la rutina para cerrar el juego y terminamos el programa.


Sincronización del MessageLoop y el Gameloop

Con esta programacion, en cada iteración se va a ejecutar una vez el ciclo de mensajes y una vez el ciclo del gameloop. Pero esto puede ser demasiado rápido para la acción del juego, sobre todo en computadoras muy poderosas. Si no se mantiene la velocidad del Gameloop a un nivel constante el juego puede volverse incontrolable. En los viejos tiempos de los sistemas monotarea bastaba con revisar el reloj interno del sistema, checar la hora de entrada del ciclo y sumarle a esta una constante para calcular la hora de salida y luego entrar a un ciclo y no salir de él hasta que el reloj interno marcara la hora de salida. Aunque esto es posible en Windows, si lo hacemos podemos dejar colgada la aplicación o en el menor de los casos obtendríamos una velocidad de respuesta del sistema muy pero muy pobre. Pues pasaríamos demasiado tiempo congelados en el Gameloop y no podríamos recibir y procesar los mensajes del sistema. Entonces
¿Cual es la solución?

El ciclo de mensajes y el Gameloop pueden estar en las siguientes circunstancias uno frente al otro: En la primera el ciclo de mensajes va mucho mas rápido que el del juego y en la segunda ambos ciclos van a la misma velocidad. Bajo ninguna circunstancia el ciclo Gameloop debe de ir mas rápido que el de los mensajes o el sistema va a dejar de responder a las entradas del usuario. Pues una vez que se ha entrado a la iteración del gameloop no hay manera de procesar los mensajes. Por lo que es en la rutina de procesamiento de mensajes o Window Procedure donde las rutinas de respuesta deben de determinar que es lo que va a pasar en la siguiente iteración del juego. Ahora veamos como se evita que el juego corra mas rápido de lo deseado.

A diferencia de los sistemas antiguos, nosotros no podemos paralizar la aplicación dentro de la iteración del Gameloop, pero podemos dejar que el CPU pase mas tiempo en la sección de los mensajes. La manera de hacer esto no es muy diferente a como se hacía en la antiguedad. La idea es esta: Si tenemos un tiempo fijo de 1/60 segundos para cada iteración del gameloop necesitamos que este solo se ejecute sesenta veces por segundo. Para eso antes de entrar a la primera iteración tomamos la hora del sistema y le sumamos 1/60 segundos. Esa es la hora de entrada del gameloop y no puede entrar antes. De modo que al llamar a Gameloop lo primero que se hace es tomar la hora actual del sistema y compararla con esa hora de entrada, si la hora actual es mayor a la hora de entrada el ciclo se ejecuta y se determina la siguiente hora de entrada sumándole a la hora actual 1/60 segundos; de lo contrario se termina el gameloop sin haber hecho nada. El Gameloop puede y debe de ejecutarse en menos de 1/60 segundos pero el CPU va a pasar todo el tiempo que le sobre esperando y procesando mensajes hasta que sea de nuevo hora de entrar al gameloop. Con esto se obtiene un juego rápido, jugable y que a la vez tenga buena respuesta de las entradas del usuario.

Ya para terminar, solo nos faltan dos cosas para terminar el asunto del Gameloop, una rutina para medir su velocidad y por supuesto una manera de salir de él, pues de no hacerlo estaríamos atorados en un ciclo infinito. Ese tema lo discutiremos en la siguiente entrada donde se va a hablar de como demonios se procesan los mensajes del sistema dentro de un juego.

enero 29, 2011 Publicado por | Uncategorized | , , , | Deja un comentario

Gameloop, GetMessage y Trolls

–Los que vengan por el ASM, brínquense hasta la segunda imagen–

Como ya se habrán dado cuenta, mi malvadísima conspiración para destruir a “la industria” latinoamericana de juegos de video ha sido finalmente descubierta. Ahora mismo los grandes capitanes de empresa contemplan este mismo blog en sus computadoras equipadas con doble pantalla y multiples tarjetas aceleradoras mientras dan instrucciones a su personal de recursos humanos de ir al cuarto donde guardan todas las solicitudes de empleo que les llegan y arrojar por el WC todas aquellas que sospechen que han sido enviadas por mi. De hecho algunos tienen la extraña fantasía de que alguna vez fui a tocar a su puerta y ellos con toda la pena del mundo me dijeron que no me podían contratar. Ahórrense la molestia de buscar porque yo nunca he enviado ni un solo currículum a ninguna empresa y mucho menos a una desarrolladora (o maquiladora en algunos casos) de videojuegos de latinoamérica y lo mas cerca que he estado de una de estas empresas ha sido como publico en una conferencia que dieron dos de sus empleados.

occvideojuegos

Es mas, si realmente me importara ser un buen empleado no hubiera invertido media vida aprendiendo cosas como la programación gráfica y las matemáticas relacionadas con esta, y en lugar de ensamblador me hubiera puesto a estudiar alguno de esos paquetes que se ponen de moda cada seis meses y ya tendría mas certificaciones en manejo de paquetes que bots dandome follow en Twitter haciéndose pasar por mujeres. Me habría esforzado por estudiar becado en una escuela privada para titularme “de lo que fuera” mientras pago el resto de la beca-credito bailando trabajando de noche en algun bar de mala muerte y por supuesto iría al gimnasio todos los dias y he habría hecho algunas cirugías estéticas para al final leer una buena cantidad de esos libros donde dicen como vestirse y actuar en una entrevista de trabajo para salir bien librado de los juegos mentales que el personal de reclusos humanos suele aplicar a los pobres diablos que van a arrodillarse ante ellos buscando comida.

No señor, en el remoto caso de que en un futuro caiga en la miseria y tenga la necesidad de mantener a una familia. Esto último algo verdaderamente dificil porque soy un Forever Alone, puede que vaya a pedir empleo como cualquier otro ciudadano responsable pero si eso llega a pasar de lo único que estoy seguro es que va a ser un empleo que no tenga nada que ver ni con programación ni con videojuegos porque no podría vivir con la deshonra de haber fracasado en ese ambicioso proyecto de vida. Ahora que si alguien quiere trabajar conmigo y me da un trato de igual a igual puede que si acepte ofrecer mis servicios a alguno de los nuevos estudios que comienzan a surgir de modo aislado en diferentes partes de México, sobre todo del norte. Pues muchos de estos ya tienen conciencia de eso que en este blog me refiero como “la industria” y ponen requisitos tan divertidos como el de la captura de pantalla que acompaña este párrafo. Me pregunto si para llenar ese requisito de “no haber trabajado en algún estudio” tengo que tramitar algún documento por el estilo de la carta de no antecedentes criminales.

De acuerdo, para que mis nuevos lectores de este blog entre los que se cuentan varias personas que no están leyendo esto porque les guste el ASM. Ya pueden dejar de leer y regresarse a hacer scripts y ponerle gloss a esos íconos porque al menos en esta entrada ya no voy a hablar mas de ustedes. En cambio voy a tratar un tema de ensamblador que no les interesa ni creo que sean capaces de entenderlo.


GetMessage vs Peek Message en un Gameloop

getmessageflowchart

De acuerdo, en un programa de Windows sencillo pero ligeramente mas complejo que un simple MessageBox, se tienen tres partes principales: La inicialización, el ciclo de mensajes y el procedimiento de ventana. La inicialización es donde el programa toma y carga la información necesaria para funcionar, el ciclo de mensajes es una estructura cíclica que se encarga de procesar todos los mensajes que el sistema operativo le envía al programa y el último es el proceso de ventana o Window Procedure que es el mas extraño, pues se trata de una función que el propio Windows se encarga de llamar por nosotros y es en donde le decimos que es lo que debe de hacer con los mensajes que le llegan. De momento voy a pasarme por alto la fase de inicialización y voy a explicar como funciona un ciclo de mensajes sencillo con GetMessage.

Un programa puede tener mas de un ciclo de mensajes pero tradicionalmente este se escribe al final del Winmain, que es el módulo principal del programa, inmediatamente después de la inicialización. Puede encontrarse porque a su inicio hay una etiqueta que indica el ciclo. En la imagen de la izquierda puede verse un diagrama de flujo de un ciclo de mensajes de Windows con GetMessage. Los cuadros en azul son funciones del Windows y los grises son rutinas del usuario. El ciclo primero llama a la función GetMessage, cuando esta es llamada se queda esperando hasta que Windows le envía un mensaje. Este mensaje queda almacenado en una estructura de mensajes que hemos definido en la etapa de inicialización. Sin embargo hay un mensaje en especial que lanza una señal diferente a los demás, el mensaje de salida. Cuando Windows le ordena a la aplicación cerrarse, GetMessage regresa en el acumulador el valor de cero, entonces lo primero que debemos hacer es probar si luego de llamar a GetMessage tenemos un cero en EAX, de ser así saltamos fuera del ciclo de mensajes y terminamos el programa. De lo contrario a TranslateMessage y DispatchMessage en sucesión con la posición de la estructura de mensajes como único argumento. Este ciclo tan simple puede volverse muy complicado por la manera de efectuar los saltos del ensamblador. Lo común es usar un salto incondicional luego de DispatchMessage que caiga poco antes de GetMessage y usar un salto condicional (o una combinación de salto condicional con incondicional si el código es demasiado grande) para salir del ciclo en caso de que GetMessage retorne un cero en el acumulador. Ahora vamos a ver las ventajas e inconvenientes de este modo de procesar los mensajes.

Cuando procesamos los mensajes con GetMessage, la aplicación se sienta a esperar a que el sistema operativo le envíe un mensaje y mientras esto no sucede no puede hacerse nada mas, esto es bueno en ambientes multitarea porque el CPU puede dedicarle tiempo de procesamiento a otras aplicaciones que corran de manera simultanea. Pero en el caso de un juego, (a menos que se trate de un juego basado en turnos) esto es malo. Pues la acción se paralizaría hasta que no llegara un mensaje y volvería a detenerse cuando este acabara de ser procesado. En un juego de acción rápida existe un ciclo que debe de ejecutarse en una frecuencia tan rápida como la taza de actualización de la pantalla y si es posible hasta mas rápido. Si usáramos un Gameloop basado en GetMessage este no sería lo bastante rápido para mantener un juego de mucha velocidad y la mayor parte del tiempo estaría congelado sin hacer nada. El primer problema que hay que resolver con un Gameloop es el de procesarse lo suficientemente rápido. El segundo problema que debe de resolver un Gameloop es el de mantener una frecuencia constante sin importar en que máquina se ejecute el juego o lo que esta esté haciendo en segundo plano. En la siguiente entrada discutiremos como se usa PeekMessage para sincronizar un Gameloop y un poco sobre como mantenerlo a una frecuencia constante, porque por ahora por insultar esta nota ya me quedó muy tl;dr.

enero 29, 2011 Publicado por | Uncategorized | , , , | 1 Comentario

Primera Etapa de Desarrollo del Minijuego

–No es lo mismo conocer el camino que recorrerlo–

En esta ocasión, voy a desfogar un poco de mi ira mientras muestro avances del minijuego que aunque ya tiene partes ejecutables aún está bastante lejos de ser jugable. Apenas si acabo de terminar las rutinas de autodepuración y estoy trabajando en el ciclo principal o gameloop. Como ya lo había dicho lo dificil es sincronizar el gameloop con el loop de mensajes del propio Windows.

iniciodev

En esta captura de pantalla que aparentemente no muestra la gran cosa, si acaso una caja de texto, algunas lineas de ensamblador en la parte baja y una carpeta de proyecto con mas de un archivo. Aquí es donde entra el famoso include. Pues bien usado permite un buen control sobre archivos muy grandes, aunque para el compilador no haya diferencia entre 100 archivos separados de 100 lineas cada uno que un solo source gigantesco de 10,000 lineas (quien piense que estos números son exagerados es porque nunca ha programado en ensamblador). Para un programa que apenas empieza aconsejo que se separe en archivos separados secciones del código como por ejemplo la de datos inicializados e importaciones, y puede que también la de funciones que no van directo en el flujo principal del programa como por ejemplo las de autodepuración. De momento este enfoque me está funcionando bastante bien. Por cierto, hay otra cosa de la que quiero hablarles antes de pasar a las pedradas. Se trata de mi muy particular mapa de desarrollo.

La verdad no se ni me importa si esto ya existe o si no me estoy apegando a los protocolos de administración definidos internacionalmente, pero a mi me funciona bastante bien. Lo llamo mapa de desarrollo y es remotamente parecido a un diagrama de PERT. En este mapa cada cuadro remarcado es una actividad relativamente sencilla para poder definirse con unas pocas palabras. El orden de las flechas define el orden de precedencia, de modo que si la actividad B está antes de la C hay que terminar B primero. Algunas actividades tienen como requisito varias mas y es necesario terminar todas estas antes de proceder. Las áreas coloreadas son las actividades que ya se han completado. No hay que esforzarse demasiado para darse cuenta que las actividades en las que se puede trabajar en un momento dado son aquellas que están separadas de las grises por una sola flecha. Personalmente este tipo de mapas me gusta por un razón, que a diferencia de las gráficas de gantt que tipicamente se encuentran en las paredes de las oficinas, este tipo de gráfica se presta mas para desarrollos llevados a cabo por una sola persona que no tiene un tiempo límite (mínimo) para terminarlos. Si acaso se pueden ordenar por niveles de dificultad y con una buena estructura se puede trabajar en varias actividades simultaneas y así evitar la posibilidad de estancarse en una sola.

mapadev

Según este mapa, ya tengo el documento donde se representan las llamadas a API de Windows desde ensamblador, se terminaron las rutinas básicas de debug que actualmente pueden desplegar tanto números y cadenas sin formato hasta el contenido de registros generales y secciones reducidas de memoria a partir de una dirección offset en formato hexadecimal. Actualmente estoy investigando como hacer el gameloop de manera eficiente, aunque desde este punto bien podría ponerme a investigar de una vez el manejo de archivos e incluso comenzar a armar el documento de llamadas a DirectX desde ensamblador, pero creo que de momento lo mas sano es crear de una vez ese gameloop. Por cierto, otro documento importante pero del que no tengo de momento una imagen para mostrar es un mapa de precedencia de las funciones. Pues ya me he visto en problemas cuando modifico una función de la cual dependen varias mas. Si no mal recuerdo había una regla sobre guias de seguridad a la hora de programar en ensamblador que hacía referencia a este problema al que hasta ahora no me había enfrentado pero por lo menos ahora tengo manera de detectar este tipo de situaciones y hacer algo para remediarlas, o por lo menos sacar ventaja de estas.


Entonces soy la viva imagen de porqué la industria no progresa…

(El título de esta subnota es una actualización de última hora que voy a explicar otro dia porque de momento no puedo teclear de la risa)

Ya para completar mi límite de 1000 palabras por entrada solo quiero comentar algunas cosas que ya no se en que tono escribir. Al comenzar esta nota esperaba destilar bastante veneno contra “la industria” pero ahora que los veo con tan malas ventas y problemas para conseguir vedadera mano de obra calificada dados sus propios prejuicios comienzo a tenerles un poco de lástima. De momento solo digamos que luego de insultar a los desarrolladores independientes, sobre todo a los autodidactas ya algunos de estos grupos están teniendo problemas para conseguir gente de buen nivel que trabaje con ellos. Yo mismo al ver este tipo de situaciones comienzo a plantearme seriamente mi conducta con algunos de estos grupos, pues de los dos mas importantes con uno estoy en abierta hostilidad y el otro ya comienza a tocarme las narices con sus game designers con título de comunicación, especialistas en retoque de botones de interfaces y servicios de outsourcing para juegos extraños que no valen ni 500 DSi points. Creo que es hora de que deje de ser tan condesciendiente con ellos y mejor me concentre en los desarrolladores que comienzan a organizarse en el norte de México que son los que tengo mas cerca y que hasta ahora me he llevado bastante bien. Confío que si logro hacer equipo con la gente clave entre todos podemos hacer un poder equivalente al de los grupos del sur. De momento solo digamos que hay una pequeña empresa, un grupo de estudiantes organizados a nivel interuniversitario y otros creadores independientes con los que podría colaborar. Si hago mi parte y meto algo de actividad a ese grupo de aficionados puede que ocurra un milagro y todas las fuerzas que rondan alrededor de ese grupo se concentren y se logre algo bueno, de momento mejor dejo de trollear en la comunidad de game dev de siempre y mejor me concentro en programar que luego de dias como este me queda cada vez mas claro que el siguiente encuentro que tenga con esa segunda empresa tan importante de “la industria” no va a ser tan feliz como a todos nos hubiera gustado.

enero 24, 2011 Publicado por | Uncategorized | , , , | 4 comentarios

Poor Programmer Episodio Doble

–Esto ya camina… ¡Ahora a correr!–

Esta vez les traigo dos episodios seguidos de la serie Poor Programmer. En el primero de estos dos se habla por fin de la manera de conseguir y manejar las constantes que normalmente no son parte del compilador. Como ya mencioné antes es importante conocer el valor numérico de las constantes simbólicas que tanto API’s como sistema operativo utilizan pero también es peligroso caer en los famosos números mágicos. Aquí se resuelve este asunto de una vez por todas.

En este otro video se muestra como usar una inofensiva hoja de cálculo para mantener el control del programa. Al principio parece sencillo mantener en la cabeza todos los símbolos de un programa. Pero en el caso del ensamblador, cuando el programa supera las 1000 lineas la cantidad de símbolos es inmanejable y este video muestra como echar mano de este recurso a la hora de programar. Para mas detalles sobre esta técnica lean la nota llamada “el programador en su laberinto”.

Por cierto, acabo de cambiar la manera de nombrar los videos porque los títulos anteriores no decían nada sobre el contenido del video. Ahora se incluye un título mas o menos descriptivo. Lo que se encuentra en los paréntesis cuadrádos es el número de reto y de episodio. Por ejemplo en lugar de escribir Poor Programmer Reto 1 parte 12 ahora se escribe Poor Programmer [r01p12] “Cazadores de Constantes”. De ese modo es posible describir de lo que se trata el episodio y a la vez tener algo que nos de idea de continuidad.

¿Qué sigue? Supongo que acelerar el desarrollo ahora que voy a tener un poco mas de tiempo. Hay tanto por hacer y tan poco tiempo. Pues cada que pasa el tiempo me parece que estoy perdiendo mi toque, o por lo menos mi capacidad para programar como antes lo hacía. A pesar de que por ahora las circunstancias parezcan tan favorables.

julio 4, 2010 Publicado por | Uncategorized | , , , , , | 2 comentarios

Poor Programmer Reto 1 Episodio 10

–Comentarios y otros consejos–

En este video se habla de la mejor manera de usar los comentarios en un programa en ensamblador y se dan algunos consejos para que el programa sea mucho mas legible.

Por cierto, tengo una duda respecto a estos videos, pues si bien la nueva manera de hacerlos me permite entregar puntualmente uno cada semana, la verdad es que a esa velocidad terminar el primer reto me tomaría todo lo que resta del año. Y si sacara todos los videos en cuanto salen algunas semanas subiría 10 videos y luego pasaría un mes sin que publicara ninguno. Creo que voy a continuar como hasta ahora y cuando se acumulen un cierto número de videos listos para publicar subiré mas de uno por semana.

Me pregunto que es lo que piensa la gente que ve estos videos. Por lo que se ve estos últimos que solo son capturas de pantalla han tenido buena aceptación pero no estoy seguro de quienes los ven. No creo que la gente con gran experiencia en programación les interesen aún, puede que haya varios principiantes interesados en FASM. De lo que si estoy seguro es que este proyecto del Poor Programmer va a dividirse en algunos varios cientos de videos.

junio 21, 2010 Publicado por | Uncategorized | , , , , | 2 comentarios

Poor Programmer Reto 1 Episodio 9

–Como llamar a las DLL’s de Windows en FASM–

¿Qué esperaban? ¿Que mi próximo video saliera hasta dentro de un mes y no mostrara nada de código? Pues se equivocaron. Tengo suficiente material para sacar un video cada semana durante el próximo mes y dada la buena respuesta que tuvo el último video voy a seguir con este nuevo formato.

Aún recuerdo hace ya años cuando aprendí a programar en ensamblador para Windows por medio de la aplicación de la Ingeniería inversa que la parte mas dificil de todas fue sin duda (en ese entonces) la de lograr que una aplicación lograra interactuar con el sistema operativo sin problemas. Esto que en apariencia es sencillo no era tan evidente en un entorno multitarea y mucho menos sin un SDK adecuado. En este video que es la continuación del anterior se detalla toda la sección de importaciones. Recuerden que este programa no contiene ni una sola macro.

Para los que ponen en su perfil de las comunidades de desarrollo de juegos que saben ensamblador nada mas porque en su escuela copiaron el mismo viejo ejemplo de 16 bits que comienza con MOV AX, @DATA tengo que decirles que las llamadas al sistema operativo en Windows son completamente diferentes a las del viejo DOS. En Windows existen grupos de procesos que pueden ser llamados por cualquier programa. Por ahora no voy a dar una explicación muy detallada de lo que es una DLL o Dynamic Link Library pero en este video van a ver porqué se les llama bibliotecas de enlace dinámico. Porque los programas se enlazan a estas en el momento de su carga e incluso pueden hacerlo a media ejecución con algunas llamadas especiales al sistema operativo.

Por ahora solo tienen que saber que si quieren llamar a servicios del sistema operativo deben de saber llamar a las DLL’s (o en algunos casos a las COM). Ya verán como este programita que comenzó desde cero poco a poco se va a convertir en un juego de verdad.

junio 14, 2010 Publicado por | Uncategorized | , , , , , | 1 Comentario

Constantes y Valores Inmediatos en ASM

–El Problema de los Números Mágicos–

algunas constantes

Antes de exponer el problema de las constantes a la hora de programar en ASM hay que dejar claro que es una constante. El simple sentido común nos dice que una constante es algo que no cambia, que siempre permanece igual como el lugar donde se encuentra el mar o el comportamiento de la gente en internet. Para los matemáticos una constante es una cantidad que no cambia, aunque ellos las separan en constantes absolutas y relativas. Las constantes absolutas mantienen su valor en todas partes en las que aparecen como es el caso de PI = 3.1415927… o e = 2.71828 o el valor de la velocidad de la luz a traves del vacío. Las constantes relativas toman un valor para ese cálculo en particular pero no cambian a traves de este como es el caso del coeficiente constante en una función polinomial para los de arte digital que no me entendieron un coeficiente constante es el número grande que está a la izquierda de la letra equis, el número chiquito que está a la derecha arriba se llama exponente y si está abajo es un subíndice.

Ahora vamos a la programación. En computación una constante es también una cantidad que no cambia. Sin embargo hay dos clases diferentes de constantes que normalmente pueden encontrarse en programas computacionales de cualquier lenguaje: Las Constantes Congeladas y los Valores Inmediatos.

Constantes Congeladas

No es realmente el nombre técnico pero así es como les llamo. Como ya han de saber a estas alturas, y si no lean el blog desde el principio, la computadora almacena valores en celdas de 8 bits llamadas bytes que pueden almacenar cantidades entre 0 y 255. Para valores mayores se combinan estas celdas o se usan registros de CPU de mayor ancho. Estas celdas pueden cambiar el valor que almacenan si se los ordenamos con las instrucciones de transferencia y manipulación de datos como por ejemplo MOV. Algunos compiladores tienen la directiva CONST que impide que las celdas que han sido declaradas constantes cambien su contenido luego de haber sido inicializadas mandando un mensaje de error. Hasta ahora solo he visto esta clase de directivas en compiladores de C y no en ASM. No se exactamente el porqué un programador querría declarar como de solo lectura una localidad de memoria pudiendo recurrir a los valores inmediatos.

Valores Inmediatos

Este término es muy de ensamblador, pero es visto ampliamente en todos los lenguajes. Normalmente un CPU toma los valores que procesa de las celdas de memoria, puertos de entrada y salida o de otros de sus propios registros de procesador en una especie de intercambio similar al que las manos de un artesano llevan a cabo con los materiales y herramientas regadas por su mesa de trabajo. Sin embargo, a veces esos datos pueden ser parte de las instrucciones. Por ejemplo, en la instruccón MOV EAX, 1 movemos el valor de uno al acumulador. Y ese uno es parte del propio opcode (se encuentra en los ultimos 4 bytes del opcode). El uso de los valores inmediatos tiene sus ventajas y desventajas pero una cosa es segura con ellos: LOS VALORES INMEDIATOS NO CAMBIAN NUNCA.

Por razones que sería una tontería explicar, un valor inmediato puede ser el operando origen en una operación de ensamblador pero nunca el operando destino. Por ejemplo, tiene sentido mover el número uno al acumulador pero no tiene sentido mover el contenido del acumulador al número uno. Por lo mismo, un valor inmediato no se guarda en las celdas de memoria que contienen los datos, sino en las que contienen el código y modificar valores en esta sección aunque es posible (se llama Código Auto-Modificable) no solo es dificil y peligroso sino que está prohibido por la seguridad de los sistemas operativos mas modernos.

Otro pariente cercano del código automodificable es la Ejecución de Datos que es escribir código ejecutable en una sección del programa reservada para los datos y luego dirigir el flujo del programa hacia ese segmento. Pero como pueden ver en esta captura de pantalla, ya existe la Data Execution Protection o DEP que por seguridad no nos va a permitir hacer este tipo de cosas.

De acuerdo, tanto las constantes congeladas como los valores inmediatos se consideran valores constantes. Ahora pasemos a los Números Mágicos

Números Mágicos

En esta imagen tenemos dos rutinas en ASM que hacen exactamente lo mismo, de hecho si las ensamblamos incluso generan el mismo código máquina.

MOV      EAX, [EBX + 14H]
CMP      EAX, 4
SETNS    EDX
MOV      [EBX + 10H], EDX

MOV      EAX, [EBX + PUNTOS_DE_VIDA]
CMP      EAX, VALOR_DE_ATAQUE
SETS     EDX
MOV      [EBX + PERSONAJE_MUERE]

En ambos códigos primero leemos un valor de una estructura que contiene los datos de un personaje y extraemos el valor de sus puntos de vida, luego los comparamos con el valor de ataque recibido que es en este caso 4 y si el resultado de restarle ese 4 al total de puntos de vida la bandera que indica si el personaje se muere o no se muere. En este caso si el personaje tiene menos de 4 puntos de vida va a perder. Como puede verse no solo la rutina de abajo es mucho mas entendible ¡Y ni siquiera tiene comentarios! Sino que es mas mantenible a largo plazo. Por ejemplo si mas adelante queremos cambiar el valor de ataque o el orden de los datos dentro de la estructura solo es necesario ir al punto donde se define el valor de la constante y todas las referencias a esta serán automáticamente actualizadas. Que si nos ponemos a buscar todos los cuatros a lo largo del código nos tomará bastante mas tiempo.

Supongo que ya se han de imaginar porqué se les llama números mágicos a los números que aparecen como parte de las instrucciones y los operandos. Porque como todo lo que es mágico su funcionamiento se nos oculta y como programadores debemos escribir código que sea entendible ya no para otros sino para nosotros mismos, pues cuando un programa pasa de las 10,000 lineas se vuelve verderamente dificil de mantener si no hemos organizado el código de manera adecuada.

Trabajando con constantes inmediatas

Bueno, ya se habló de las maravillas del uso de constantes y como estas pueden mejorar la manejabilidad del código sin afectar la eficiencia del programa en los mas mínimo. Ahora veamos como hacemos nuestras propias constantes.

Declarar una constante en FASM es tan sencillo como escribir el nombre de la constante y el valor numérico separados por un signo de igual. Por ejemplo si queremos que la constante MALA_SUERTE tenga el valor de trece, solo tenemos que hacer esto:

MALA_SUERTE = 13

A partir de esa linea, cada que el compilador encuentre MALA_SUERTE va a sustituirla con el número 13. Por cierto, aunque no es obligatorio existe la convención de escribir los nombres de las constantes en MAYUSCULAS separando las palabras con el signo de subrayado _ (underscore bar _ ) no solo para que sean facilmente identificables sino para que no se confundan con el código normal que bien pueden llamarse igual. Por lo menos el FASM hace distinción entre letras mayúsculas y minúsculas. Por cierto, el sistema de definición de constantes no solo sirve para declarar constantes numéricas, usado con precaución puede usarse para modificar las instrucciones y estructura del propio compilador pues puede sustituir palabras o frases enteras.

Ahora bien, las constantes tienen un pequeñisimo problema sobre todo para los principiantes que aprenden leyendo código escrito por otros programadores. Y es que si el valor de una constante no ha sido definida por el programador el compilador no va a saber como manejarla y va a marcar un error de sintaxis. La mayor parte del tiempo cuando intenten programar para una nueva API en ensamblador se las van a ver con este problema. Por lo que deben de aprender a localizar, organizar y reutilizar dichas constantes en sus propios programas. Este proceso, al que yo llamo “Cacería de Constantes” es bastante entretenido y hace reflexionar sobre el verdadero significado de la palabra “hacking”. Pero de este asunto hablaremos en otra nota con mayor profundidad.

junio 10, 2010 Publicado por | Uncategorized | , , , | 1 Comentario

Poor Programmer Reto 1 Episodio 8

–Ahora si a programar desde cero–

La verdad es que eso de hacer videos se me había complicado demasiado, ahora en lugar de hacer episodios aislados como antes voy a hacer grabaciones mas o menos extensas sobre algún proyecto y luego voy a rebanarlas y envolverlas cual si fueran caramelos para distribuirlas de manera continua a lo largo de las semanas. En esta ocasión me puse a escribir el programa correspondiente al reto uno absolutamente desde cero, este código no contiene ni una sola de esas horribles macros ni tan siquiera constantes externas o source code escrito por nadie mas.

Si acaso lo único externo son las llamadas a la API de windows que ya de por si son llamadas creando una sección de importaciones mas o menos RAW. Esta sección de importaciones es sin duda la parte mas interesante de este video.

En si el video no tiene gran valor para los programadores mas avanzados pero al menos este y los 3 episodios que siguen sin duda serán apreciados por quienes apenas se inician en el ASM, ya que en este se dan varios consejos sobre como escribir código en ensamblador que sea legible y sencillo de mantener. Cosa que es indispensable al programar en un leguaje tan cercano a la máquina como lo es este. En esta parte se describen las directivas principales de un programa en ASM para Windows, la manera de llamar funciones de la API del sistema operativo y una breve explicación de lo que son las cadenas ASCII-Z.

Por cierto, en esta serie cometí un pequeño error en la sección de importaciones que luego del tercer episodio se va a resolver. La sección de importaciones ‘.idata’ tiene como argumentos import data readable writeable. Otra interesante diferencia con los videos anteriores es que este es el primero que tiene música de fondo. En realidad solo puse ese fondo musical (que se supone que es de uso libre) para disimular los pertubadores ruidos ambientales que pueden escucharse en todo momento. Bueno, espero que le den buen uso a estos videos y que se recupere un poco la antigua reputación de este blog.

junio 7, 2010 Publicado por | Uncategorized | , , , , , | 2 comentarios

Poor Programmer Reto 1 Episodio 5

–Llamadas COM o ¿Va a querer papas con su orden?–

Este en realidad es la segunda parte del episodio cuatro. Aquí se deja en claro la diferencia entre una llamada tradicional a la API de windows y una de modelo de objeto componente. También se analiza un poco o mejor dicho se disecciona la macro COMINVK o el INVOKE para COM. Una llamada a una función COM tiene 2 diferencias principales respecto a las funciones tradicionales que simplemente reciben sus argumentos con el stack y luego ejecutamos la instrucción CALL del procesador.

Para que sea mas facil de entender esto funciona de la misma manera en que se toman las órdenes de un restaurante. Cuando uno entra a comer en un restaurante pide su platillo; además del platillo damos ciertas indicaciones por ejemplo pedimos una hamburguesa, que sea doble carne, que tenga queso, papas grandes y refresco sin hielo. Al hacerlo la mesera va a tomar la orden en su libreta y va a apuntar en ella que queremos una hamburguesa con tales o cuales complementos; pero también va a anotar la mesa donde estamos. Luego va a llevar a la cocina esa orden y luego de un rato ya cuando la hamburguesa esté servida con todo y sus complementos nos lo llevará a la mesa.

Las llamadas a COM trabajan de esa misma manera. No solo reciben los argumentos que en este caso serían los complementos. El platillo sería la función que queremos llamar y la mesa a la que han de ser entregados es el objeto que “da la orden”. Para seguir con la burla el ejemplo del restaurante en este caso la tabla de funciones sería igual al menú. Cada menú tiene una serie de entradas donde cada una corresponde a un platillo que el comensal puede ordenar. Igualmente podemos cambiar la preparacion de los platillos siempre y cuando el menú siempre se respete. Y a la hora de tomar la orden internamente lo que se pasa es la posición del platillo dentro del menú. Sus complementos(en este caso los argumentos de la funcion) y la mesa a la que se va a servir. El modelo COM trabaja exactamente de esa manera.

También se muestra en el video lo que en este caso sería la mesa que es la interfaz al objeto creado. No se va a detallar por ahora como trabaja internamente sino como se comunica la aplicación que tenemos con este tipo de objetos. Lo que es un gran avance y optimización si lo comparamos con la llamada tradicional a una típica función DLL.

En el siguiente capítulo utilizaremos toda la información obtenida en los capítulos anteriores ahora si para generar una aplicación sencilla. Aunque no será muy vistosa si nos dirá si el sistema nos obedece o no. A partir de ahí el resto será sencillo. Simplemente jugar con las constantes, argumentos y funciones para obtener diferentes efectos. Parece que el reto uno va a terminar mucho antes de lo que tenía esperado pero no tan rápido como me gustaría.

abril 5, 2010 Publicado por | Uncategorized | , , , | 3 comentarios

Poor Programmer Reto 1 Episodio 4

–Los OpCodes Nunca Mienten–

Ahora si comienza lo bueno. En este video se muestra el análisis de un programa de directx de windows abierto con ollydbg. Para quien nunca ha visto como funciona intermanente una llamada a windows esta es la mejor oportunidad para verlo de cerca.

Y aunque en este video en particular no se habla mucho sobre como funciona la inicialización de ventanas y el manejo de mensajes si se ve en detalle el proceso de inicialización de un objeto COM y su posterior finalización. Para los principiantes o para cualquiera que todavía no está muy adentrado en lo que es el ensamblador para windows este video tiene un valor adicional pues muestra como demonios funciona internamente la macro invoke. Se muestra la macro con todas sus horribles constantes y luego como esta es desenrrollada en el ejecutable, en el debugger se muestra como se pasan los argumentos y como esa macro se convierte en los opcodes PUSH y CALL. También se habla del problema con las constantes. Que son y como manejarlas cuando estas no están definidas y que hacer cuando no conocemos el verdadero valor. Así como su utilidad para evitar el problema de los números mágicos y el código duro. El proceso de análisis te tuvo que dividir en 2 partes puesto que el video era de casi media hora. En la segunda parte del video se muestra la diferencia entre una llamada tradicional a la API de windows y una de COM que es la base tecnológica en la que directx trabaja.

Para los que ya tienen experiencia programando en directx por otros lenguajes mas “para humanos” aquí se muestra internamente como se maneja la creación de objetos COM y como estos objetos llamar a diferentes funciones. Pero todos esos detalles se mostrarán en el siguiente capítulo. Por ahora lo mejor es detallar y dejar en claro como funcionan las llamadas a sistema al interior de la máquina y como esa horrible macro INVOKE puede fastidiar a quienes van empezando a programar en ensamblador.

abril 5, 2010 Publicado por | Uncategorized | , , , , | Deja un comentario

DirectX en Ensamblador

–Como Llamar al DirectX desde un programa en ASM–

Pues ya ha sido un año de decir cosas sin sentido en este blog. Conforme pasa el tiempo la gente que viene a este sitio comienza a preguntar cosas mas interesantes y no todos son simples estudiantes en busca de alguien que les haga la tarea. Sobre todo en las últmas fechas viene mas gente preguntandome como hacer cosas interesantes. Y ya que los 5 o 6 seguidores mas fieles de estos escritos ya están en capacidad de entender los temas mas avanzados es hora de comenzar con el tema de la programación gráfica en Ensamblador. Y el tema de hoy es el de DirectX en ASM.

Antes de que los programadores mas hardcore me agarren a tomatazos quiero explicar primero como es este asunto. Primero si uno quiere programar el hardware directamente en una computadora casera tiene 2 caminos, el primero es hacer su propio sistema operativo (yo ya lo intenté) y el segundo es mediante algunas funciones mas o menos ocultas del DirectX que casi ningún Game Developer “Profesional” (odio esa palabra) utiliza. Si optan por hacer su propio OS puede que tengan éxito pero en general la gente no le interesa demasiado desinstalar su fiel Windows cada vez que quieran correr un juego.

Lo interesante de la historia del DirectX es que al menos en su origen parece haber sido desarrollado con la programación en Ensamblador en mente. Pues las funciones mas primitivas casi no hacen nada por si mismas. De hecho el DirectDraw lo único que hace es devolver información muy general sobre el hardware de video y manipulación de esta memoria a nivel muy pero muy elemental. Las únicas funciones que se ven mas o menos sofisticadas son aquellas que transfieren bloques de bits (BitBlT como dicen en “La industria”) y son suceptibles a ser aceleradas por hardware. Pues esta es una de las funciones de aceleración de video por hardware mas antiguas que se conocen. Aunque no me extrañaría que transferir bloques de memoria con MOVSD fuera mas rápido. Actualmente DirectX se ocupa casi por completo del rendering de una escena y el desarrollador solo tiene que asegurarse de que los parámetros de las funciones cumplan con ciertas condiciones para garantizar compatibilidad. Aunque el nuevo DirectCompute de Dx11 se ve bastante prometedor para la programación de verdad. Pero de esto último hablaré muy pero muy en el futuro.

Supongo que cualquier aficionado a las computadoras sabe que es el DirectX y no voy a dedicar una entrada entera para explicarlo. Lo primero que debemos tener en cuenta es que el DirectX funciona bajo el Modelo Objeto Componente, abreviado COM. Esta tecnología es una de las mejores cosas que Bill Gates ha hecho por la programación en Ensamblador desde tiempos del MASM. Pues permite que las llamadas a los Objetos COM (en este caso DirectX es un objeto COM) no dependan del lenguaje de programación usado. Es pocas palabras, esto es lo que permite que podamos recurrir a los servicios de DirectX sin importar que lenguaje usemos, bien puede tratarse de C, C++, C# o incluso ASM. No menciono otros lenguajes para no comenzar peleas pero construir una interfaz COM desde un lenguaje cualquiera es casi tan sencillo como hacer un arreglo de enteros de 32 bits.No hacen falta directivas raras de compilación, descargas de SDK’s (al menos no en ASM) ni mucho menos bibliotecas de enlace de esas que tantos problemas les dan a quienes tratan de iniciarse en esto de la programación de videojuegos.

La mejor parte del COM es que no hace falta una sección de importaciones tan grande y complicada para su manejo como en el caso de las tradicionales llamadas a la API de Windows. Sin embargo, un típico COM es bastante mas complicado de inicializar que una típica llamada a una función de la API. Afortunadamente para nosotros, DirectX tiene un sistema de inicialización semi automática que nos evita eso. Por ahora, nuestro primer programa va a usar la versión mas antigua que existe del DirectDraw, lo va a inicializar y luego lo va a desactivar, para decepción de los lamers este demo no va a mostrar otra cosa mas que una simple ventana con un mensaje que va a decir si se pudo o no inicializar.

Ahora Vamos con el Source Code

Primero el programa inicializa una ventana casi como cualquier otra. Ya saben, primero se obtiene el Module Handle, la posición de la linea de comando, se llama a Winmain, se declaran las respectivas estructuras de mensaje y parámetros de ventana, se da de alta la clase de ventana con RegisterClassEx y se crea la ventana con CreateWindowEx. El resto ya lo saben y si no lean las notas de inicios del 2009 de este mismo blog. Bueno, la parte que nos interesa es esta:

                        push	     0
			lea         eax, [directdraw]
			push       eax
			push	     0
			call	     [DirectDrawCreate]
		    ;inicializar directdraw

			mov	    eax, [directdraw]
			push	   eax
			mov	    eax, [eax]
			call	   dword [eax + 8]
		    ;directdraw::release()

Esto es lo mismo que hacer hResult =DirectDrawCreate(NULL, iDirectDraw,NULL); en C++. Y esto es la parte mas interesante de esta entrada, pues mientras que para usuarios de otros lenguajes casi no hay diferencia entre una llamada a la API de Windows y una llamada a uno objeto COM nosotros los programadores de ASM podemos ver la enorme diferencia entre un estilo de llamada y otra.

Lo que este programa hace es lo siguiente:

  • Inicializa DirectDraw y obtiene la “Interfaz” al objeto DirectDraw recién creado
  • Llama a la función DirectDraw::Release(); para liberar el objeto COM
  • Irnos al demonio del modo usual.

Obsérvese la enorme diferencia que hay entre la llamada a DirectDrawCreate, que es una simple llamada a la API de Windows y a DirectDraw::Release(); que es una llamada a una función miembro del objeto DirectDraw.

Este método es muy parecido a como trabajan los equipos de sonido de carátula removible de algunos automóviles. Cada uno de los botones de esta carátula activan un interruptor que controla las funciones del equipo. Para mi este modelo es muy complicado de explicar.

interfazcom

Otro simil podría ser esos intercomunicadores de los departamentos en los que uno oprime un botón para comunicarse con cada uno de los cuartos. Lo importante de este modelo es que no solo se logra independencia del COM con la aplicación que la llama, sino que es posible modificar el COM sin necesidad de cambiar la aplicación que usa sus servicios. Mas adelante hablaré sobre las maravillas del COM. Por ahora voy a seguir explicando como llamar a DirectX desde Ensamblador.

Desde el punto de vista de un programador de Ensamblador, una interfaz COM no es mas que un entero de 32 bits que representa una localidad de memoria. En ese lugar hay una estructura con información de dicho objeto, la parte mas importante es su tabla de funciones. El primer DWORD de esa estructura es a su vez otra posición de memoria que indica donde se encuentra esta tabla. Todos los objetos pertenecientes a una misma clase hacen las mismas cosas y para no desperdiciar espacio todos tienen un apuntador a una misma tabla de funciones. Esta tabla es un array de enteros de 32 bits donde cada uno a su vez es una posición de memoria a las funciones que nos interesan. El proceso para hacer una llamada a una función de un objeto COM desde Ensamblador es el siguiente:

  • Empujar los argumentos al Stack como si se tratara de una llamada a funcion como cualquier otra com PUSH
  • Empujar como último de los parámetros la “interfaz” que es el DWORD que representa al Objeto COM
  • Obtener la posición de la tabla de funciones asociada a ese objeto, este es el primer DWORD de la definición del objeto. En el ejemplo, se carga en EAX la interfaz primero y luego se hace un MOV EAX, [EAX]
  • Finalmente se hace una llamada Base mas desplazamiento. Donde la base es un registro general que contiene la posición de la tabla de procesos de ese objeto COM y el desplazamiento es el número de función multiplicado por 4 (por ser DWORDS).

Por ahora aquí le dejo, mas adelante vamos a ver mas sobre el manejo del COM. Sin embargo, esta entrada es mas que suficiente para aquellos que quieran programar sus juegos en Ensamblador para Windows. Solo necesitan una poca mas de información sobre el COM y el archivo de ayuda que incluye el DirectX SDK. Recuerden que es importante hacer ingeniería inversa con los desensambladores a este y todos los ejemplos ejecutables que les de en este blog o en la comunidad virtual.

diciembre 25, 2009 Publicado por | Uncategorized | , , , , , , | 1 Comentario

Como Imprimir un Entero de 32 Bits en ASM

printf(“Imprimir en ASM no es tan facil como tu crees”);

El semestre en las universidades termina y con ello baja la cantidad de visitantes, dejando solo aquellos que vienen por gusto o porque realmente les interesa el ASM. Esta vez traigo un programita que convierte un valor binario de 32 bits en una cadena ASCII-Z.

entero en messagebox

Ya se lo que se han de estar preguntando los que no estan muy familiarizados con la programación en ensamblador: ¿Porque este desperdicia espacio en una tontería como esta? O peor aún ¿Y que este idiota no sabe que los números son diferentes a los “strings”?

Mientras mas avanzo en esto del Ensamblador mas me doy cuenta del daño que causa a a los programadores principiantes el empezar su aprendizaje con lenguajes de “alto nivel” (como me fastida ese término). Por todos es bien conocido el daño que hace iniciarse a programar con BASIC y todos sus descendientes y tal parece que cada nueva versión de BASIC tiene nuevas y mas novedosas maneras de echar a perder a los programadores mas jóvenes. No cabe duda de que el daño hecho por iniciarse en este tipo de lenguajes es muy dificil de remediar. Si me pusiera a enumerar todos necesitaría otras 3 entradas nada mas para el puro BASIC, pero en este caso creo que voy a blasfemar un poco.

Todos saben que como radical que soy, tengo muy poco respeto por la mayoría de los lenguajes autodenominados de “alto nivel”. Excepto por el viejo C que es el que mas se acerca al ASM. Sin embargo, para quienes se inician programando en C o alguno de sus derivados mas amistosos topan con piedra a la hora de comenzar a programar en ASM. Pues cosas que son relativamente sencillas en estos lenguajes son completamente diferentes, cuando no imposibles en ensamblador. Esta lista merece su entrada a parte pero el asunto a discutir ahora es la modesta función printf( );

printf(“La suma de %d + %d es igual a %d”,numero1, numero2, resultado);

Veamos los parámetros: el primero es una cadena de texto con signos de control que son remplazados por el contenido de las variables numéricas llamadas numero1, numero2 y resultado. Pero este proceso no es directo, primero la función debe de procesar por medio de un aceptor la secuencia de signos que se encuentran entre las comillas dobles e interpretar los signos de control como instrucciones. ¡En realidad esta sencilla cadena de caracteres puede considerarse un programa completo!. Y lo que dice es: Toma los 3 números cuyos valores te envío por el Stack, conviertelos en strings decimales e intégralos con el resto del string y luego le dices al sistema operativo que los despliegue. Eso sin mencionar la comprobación exhaustiva de tipos de las variables ni los formatos numéricos en los que debe de ser mostrado. De hecho, la leyenda de que una sola instrucción de C se convierte en cientas o miles de instrucciones en ASM es cierta sobre todo por instrucciones como printf(); y scanf();

Bueno, ahora que ya saben que un printf no es tan sencillo como parece vamos con el código:

;BIN2ASC.ASM
;Escrito por Mario Salazar el 11 de diciembre del 2009
;https://asm86.wordpress.com
;http://itzasm.ning.com
;Programita que despliega un numero de 32 bits en hexadecimal
;por medio de MessageBox. Para compilarlo con FASM solo presione
;la tecla F9. El numero solo puede ser cambiado en el codigo
;Lean el archivo bin2asc.xls para una referencia de las variables

format PE GUI
entry start

section '.code' code readable executable

  start:

			mov [eax_bin], 1234abcdh
		   ;cambia el 1234abcdh por el numero que quieras entre 0 y 2^32

			call bin2asc
		   ;llamada a la funcion que convierte ese numero en cadena ascii-z

			push	0
			push	debug_caption
			push	eax_ascii
			push	0
			call	[MessageBoxA]
		   ;mostrar una MessageBox que despliegue el numero

			push	0
			call	[ExitProcess]
		   ;terminar el programa

bin2asc:
			pusha
		    ;guardar los registros generales en el stack

			xor	eax, eax	 ;prepararse para el ciclo y
			mov	ecx, 8		 ;cargar valor binario en edx
			mov	edx,[eax_bin]
    lee_binario:
			mov	ebx, 0fh	 ;extraer los 4 bits mas bajos
			and	ebx, edx	 ;con una mascara de bits
			mov	al,  [ebx + digitos]
			push	eax		 ;usar esos 4 bits como indice
			shr	edx, 4		 ;a la tabla digitos
			loop	lee_binario	 ;por cada 8 numeros
		    ;obtener 8 simbolos ascii y guardarlos en el stack

			mov	ecx, 8
			mov	edi, eax_ascii	 ;apuntar edi a la cadena ascii
    escribe_binario:
			pop	eax
			mov	[edi], al
			inc	edi
			loop	escribe_binario
		    ;sacar los simbolos ascii del stack y
		    ;guardarlos en la cadena ascii

			popa
			ret
		    ;restablecer los registros generales y terminar proceso

section '.data' data readable writeable

	eax_bin 	  dd	   0			      ;valor binario a convertir
	debug_caption	  db	   'Hex de 32 bits:',0	;nombre de la ventana
	eax_ascii	  db	   '00000000',0 	      ;cadena de salida
	digitos 	  db	   '0123456789ABCDEF'	      ;arreglo de simbolos hexadecimales

section '.idata' import data readable writeable

  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:
    MessageBoxA 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

section '.reloc' fixups data readable discardable

En realidad la mayor parte del source pertenece al viejo PEDEMO.EXE del FASM. Pero no he “encapsulado” este “método” para que fuera mas sencillo de entender y a la vez mas dificil de lamear. Para compilarlo solo cárguen este programa en el IDE del FASMW y opriman F9. Pueden cambiar el número 1234abcdh por el que ustedes quieran ¡Incluso si lo dan en formato decimal o como una palabra de 4 letras!. Si hacen lo de las palabras con 4 letras (muchas de las cuales suelo gritarle a los lamers todo el tiempo) no olviden ponerla entre comillas dobles. No se asusten si de pronto alguna aparece al reves, se debe a algo llamado Little Endian que explicaré (de nuevo) otro día.

El programa tiene 3 elementos de datos:

eax_bin.- Es un espacio en memoria de 32 bits donde se va a guardar el dato a desplegar

eax_ascii.- Array de 9 bytes. Ocho son para los digitos y el ultimo en un cero binario que indica el fin de la cadena ASCII-Z

digitos.- Este es el mas importante. Es un array de bytes donde cada uno representa uno de los 16 digitos ascii que serán usados para formar la cadena de texto.

Ahora vamos con las instrucciones:

Antes y después de la función se guardan y restauran los valores de los registros generales con PUSHA Y POPA. Luego de guardarlos se escribe el entero de 32 bits en el registro EDX y en ECX se escribe un 8 en preparación para el ciclo de lectura que ha de repetirse 8 veces.

Hay un ciclo que lee el valor de 32 bits en porciones de 4 bits cada una, este ciclo está entre la etiqueta lee_binario: y la instrucción loop lee_binario. Para extraer los 4 bits mas bajos del registro EDX se hace un AND entre este y EBX que poco antes fue cargado con el valor 0Fh (quince decimal y 00001111 en binario) El resultado de este AND deja en EBX los 4 bits mas bajos del registro EDX y el resto los pone a cero. Esto es lo que los programadores de ASM llamamos “máscara de bits”.

Ahora viene lo interesante: Para convertir esos 4 bits en un dígito ASCII con una sola instrucción de lenguaje Ensamblador usamos EBX como offset del arreglo digitos. De modo que estos 4 bits (que solo pueden tomar valores entre 0 y 15) nos den la posición de memoria de su correspondiente dígito ASCII una vez que se sumen a la posición de memoria indicada por la etiqueta digitos. La instrucción que hace esto y guarda el resultado en la parte baja del acumulador EAX es MOV AL, [EBX + digitos]

Luego de esto, el acumulador completo se guarda en el stack con push y luego se hace un desplazamiento binario hacia la derecha de 4 bits en EDX con SHR EDX, 4. Con esto ahora los 4 bits mas bajos en EDX corresponden al siguiente dígito hexadecimal a transformar. Esto se repite 8 veces hasta que se obtienen todos los valores ASCII para formar la cadena hexadecimal de 32 bits.

La siguiente es bastante sencilla, primero se carga en ECX otro 8 para escribir los 8 digitos del hexadecimal de 32 bits. A continuación se carga en el registro EDI (Extended Destination Index) la posición de memoria de la zona donde vamos a escribir la cadena ASCII. Entonces, por cada ciclo vamos a ir sacando valores de la pila con POP EAX y escribimos los 8 bits mas bajos en la posición guardada por edi con MOV [EDI], AL e incrementamos el ‘puntero’ EDI con INC EDI para ir avanzando en la cadena.

Luego de estos 2 ciclos restauramos los registros generales con POPA y devolvemos el control al llamador con RET. Es importante siempre restaurar los registros generales en Windows, sobre todo EBX, ESI y EDI antes de que el Windows vaya a hacer cualquier cosa, de lo contario podemos desatar su ira y nos echará abajo la aplicación.

Una cosa mas, por si no lo han notado en el primer ciclo los digitos de 4 bits se leen comenzando por el menos significativo pero a la hora de escribir se comienza por el digito mas significativo. Esto es posible porque usamos el Stack. Y como todos saben de la clase de ensamblador con Solis el primer elemento en entrar a estas estructuras es también el último en salir.

Ya para terminar, es importante poder convertir enteros binarios en cadenas ASCII porque la mayor parte de los sistemas operativos (o en este caso la API del Windows) no pueden representar números binarios facilmente. Además de que un mismo número binario puede ser representado en muchas formas diferentes dependiendo del sistema numérico (decimal, hexadecimal, fraccionario, etc.) mas adelante veremos como desplegar un número binario en formato decimal. En realidad solo basta con agregar 2 instrucciones y un dato de 1 byte a este mismo código. Les aconsejo que sean organizados con sus viejos códigos y los reutilicen tanto como les sea posible porque los programas escritos en ASM pueden llegar a ser enormes en source aunque su ejecutable tan solo mida unos pocos kilobytes.

diciembre 16, 2009 Publicado por | Uncategorized | , , , , , , , | 9 comentarios

Revancha de 32 Bits

–Y el Retorno de los Programadores de Ensamblador–

Esta es la cuarta y última parte de la Saga de 32 Bits. Donde se muestra como luego de ser desterrados por los lamers, los programadores de Ensamblador regresamos a reclamar nuestro lugar en los PC’s actuales basadas en Windows con CPU de Intel. Aunque algunos parece que aún no se han dado cuenta y en pleno siglo XXI siguen programando para los procesadores de 16 bits como el 8086.

peheader

Luego de escribir las tres notas anteriores revisé una vieja bitácora que comencé a escribir mas o menos por el otoño del 2000. Encontré una referencia de la primavera del 2004 en la que se menciona un primer intento por programar en ensamblador para Windows. Lo interesante de esta primera aproximación fue que en lugar de comenzar a programar como con cualquier otro lenguaje. Buscando tutoriales, libros y hablando con ‘profesionales de la industria’ lo que hicimos fue irnos directo contra el formato binario de los archivos ejecutables. Ya teníamos algo de experiencia estudiando código ejecutable de tiempos del DOS con sus famosos archivos de formato MZ. No puedo describirles la sensación que uno tiene cuando por primera vez abre un programa ejecutable en un editor hexadecimal y entiende lo que significan cada uno de esos números. Y mas aún cuando puedes manipular un archivo binario sin mas herramienta que un editor hexadecimal y ver como la aplicación cambia su conducta. En el caso del Windows este formato era conocido como PE (Portable Executable) y hasta tiene un encabezado compatible con MS-DOS que despliega un mensaje que dice “Este programa no puede ser ejecutado en DOS”.

Sin embargo, aún no éramos tan buenos como para programar 100% en lenguaje máquina a velocidad mas o menos razonable, y ahí comenzó la aventura de buscar programación de Windows en ASM. En ese entonces el FASM tenía muy poco soporte y no nos hallábamos con sus terribles Macros. Existían sin embargo otros 2 caminos: MASM y NASM.

nasmlogo

El Netwide Assembler, mejor conocido como NASM era un ensamblador “popular” en el mundo de Linux (y escribo popular entre comillas porque en realidad a la gente de Linux no le interesa mucho el ASM) Su sintaxis era muy buena comparada con otros ensambladores de Linux y podía hacer código para DOS y Windows. Por un tiempo usamos este ensamblador, y aunque era excelente para programar nuestras viejas computadoras 486 con DOS, programar en Windows era demasiado complicado, pues necesitaba de un enlazador externo sumamente revoltoso de usar llamado ALINK para hacer programas compatibles con Win32. Eso sin mencionar que el NASM era sumamente ineficiente, era posible contar en segundos el tiempo que se tardaba en compilar un sencillo “hola mundo” y su ejecutable medía casi un mega completo. Además de que había demasiados pasos intermedios que no quedaba claro que hacían. Pero sobre todo, una cosa muy rara era el hecho de que un programa ensamblador tuviera su source code en C. Me imagino que como el C es el lenguaje de programación oficial de UNIX y todos sus descendientes lo hacían para mentener cierta compatibilidad. Al final decidimos abandonar el NASM porque a diferencia de otros proyectos de GNU Linux este estaba relativamente abandonado y sus contríbutors no parecía interesarles demasiado la programación en ASM, como a la mayoría de la gente que trabaja con Linux.

cajadelmasm

En cuanto al MASM o Microsoft Macro Assembler este en realidad casi no lo usamos. Sin embargo era necesario conocerlo muy bien porque la inmensa mayoría de los códigos de Ensamblador para Windows que encontramos estaban programador en él. Los tutoriales de Iczelion, los del Test Department, un Tetris en DirectX (del que hablaré dentro de poco) y la mayor parte de los códigos de las comunidades de Ensamblador para Windows fueron ensamblados con MASM. Lo siniestro del asunto es que Microsoft abandonó MASM desde mediados de los noventa y desde entonces ha sido mantenido con vida artificial por hábiles programadores de diversas partes del mundo. De hecho hay un programador conocido solo como Hutch que ha hecho mucho por mantener este viejo ensamblador funcionando en estos últimos años. Puede que lo que lo ha mantenido con vida haya sido su capacidad para generar viejo código máquina de 32 bits para los 486 pero de ahí en delante, el MASM no pasaba de ser un modelo antiguo con grandes remodelaciones de aficionados.

Al final solo quedaba el FASM, pero como ya se dijo los programas en Ensamblador para Windows eran muy pocos y casi todos estaban plagados de esas horribles macros que tanto fastidian a los principiantes. Por lo que en aquellos años la programación en ASM para Windows pasó a segundo plano para dar paso al desarrollo de software para la consola coreana de videojuegos mencionada en la entrada anterior.

De Vagabundo a Estudihambre

Y así pasaron un par de años hasta que mi familia me obligó a retomar mis estudios. En realidad no me interesaba estudiar y solo lo hice porque mi madre dijo que no se iba a morir hasta no verme titulado como el resto de mis hermanos, el si podría vivir o no de lo que estudiara le importaba, como se dice en México, 3 cacahuates. Y como tal, busqué una escuela cuya colegiatura me costara solo 3 cacahuates, donde nadie me conociera y sobre todo que al graduarme tuviera un título de ingeniero. Por obra y gracia de los dioses del tercer mundo encontré un lugar donde podía estudiar una carrera profesional por menos de 100 dólares americanos el semestre.

De esta escuela les hablaré otro día, lo que importa ahora es que a 3 semestres de haber entrado ahí el trabajo con los coreanos se fue por el retrete y sin jalarle. Por lo que furioso y con menos dinero decidí retomar la programación en ASM para Windows con todos los inconvenientes ya mencionados. Aún recuerdo como imprimí los tutoriales de Iczelion y el Space-Tris (Un Tetris en Ensamblador para Windows que usaba DirectX) y me encerré con lo que quedaba de mi antigua Pentium 100mhz de en ese entonces casi 10 años de antiguedad. Y como ambas fuentes de información estaban en MASM y yo programaba en FASM hizo falta de muchas horas con el BIEW y el OllyDbg mas documentos sobre el formato PE de Windows para lograr obtener toda la información que necesitaba y echar a andar los primeros códigos. Por desgracia ya era la segunda mitad de la primera década de este siglo y todo eso no me servía para mucho. En ese tiempo aprendí mucho de lo que actualmente se sobre como programar en ASM para Windows.

El Reto Final de los Vagabundos

Sin embargo la controversia seguía. Pues aunque ya era capaz de hacer las típicas aplicaciones GUI con Ensamblador aún faltaba el poder hacer verdaderos juegos, por lo que esa sensación de inferioridad no acababa de irse. Recuerdo especialmente una plática que tuve con el Julio en una época que habíamos considerado participar en un evento de animación y videojuegos llamado Creánimax. El decía que si queríamos participar íbamos que dejar momentaneamente el Ensamblador y programar en C++. Yo por supuesto como buen fundamentalista de la programación en ASM me opuse terminantemente a rebajarme a usar un lenguaje “para humanos”. Ahí fue cuando el Julio diera uno de sus discursos célebres:

–“Ya se que el ensamblador es como un Ferrari y que el C/C++ es un auto de calle como un Chevy (elijan el modelo que quieran) pero por ahora solo tenemos las llantas del Ferrari y no lo vamos a terminar de construir en un buen tiempo. Sin embargo ya tenemos completo el Chevy y puede llevarnos a donde queramos si arrancamos ahora mismo.”–

Palabras mas, palabras menos una semana después apareció con un modesto programa hecho en el tan odiado Visual Studio que escribía unos cuantos pixeles en la memoria de video y por una temporada estuvo haciendo algunas rutinas para manejo de sprites. Ahora que lo veo de lejos creo que si por lo menos hubiera hecho eso mismo con Code::Blocks y el MINGW (un derivado de GCC para hacer programas de Windows) lo hubiera aceptado un poco mas.

No estoy seguro de cuanto tiempo pasó entre eso y el momento en que yo por mi cuenta lograra hacer eso mismo programando completamente en Ensamblador; pero fue el suficiente para que el asunto de la participación en el Creánimax quedara olvidada. Finalmente, durante el verano del 2008 fue que logré hacer trabajar juntos al Windows Vista, los nuevos CPU’s multinucleo, el DirectX y al Ensamblador de manera verdaderamente eficiente de modo que podría tomar lo que mas me conviniera (abstracción de hardware de DirectX o programación directa de las Streaming SIMD Extensions) según considerara necesario. Luego de este evento tan trascendente en mi vida, ya no hubo mas necesidad de subestimar al Ensamblador a la hora de hacer proyectos serios. Sin embargo, apenas había aprendido a flotar en las orillas del océano y para ganar era necesario cruzar este a nado limpio. Aunque una de las cosas mas extrañas de esta aventura de programar en Ensamblador para Windows fue que los libros que mas me ayudaron a lograrlo no eran precisamente libros de Ensamblador, ¡Sino de Programación en C!. Por supuesto que estos solo me sirvieron para saber que era lo que estaban haciendo esos OpCodes porque al final donde los programadores de C veían esa horrible notación húngara yo solo veía agradables enteros de 32 bits y una que otra cadena ASCII-Z o Unicode.

Y como prueba aquí les dejo una captura de pantalla de una escritura en ensamblador directo a la memoria de video. El modo es el humilde 800 por 600 a 32 bits de colores. Cada uno de los renglones tiene una intensidad de color azul (256 intensidades). Los números a la izquierda son valores de 32 bits de una zona de la memoria. Para pintar estas lineas se usaron las instrucciones REP y STOSD de ensamblador. De modo que con esto se demuestra que no solo es posible programar en Ensamblador para Windows, sino que es posible obtener optimizaciones tan buenas como en la vieja época de los DOS Extenders. Y me haría falta esto y mas para poder manejar lo que estaba por ocurrir…

vramasm

Nota al margen: Esta foto la tuve que tomar con una camara digital porque no hay manera de capturar la pantalla con PrintScreen al escribir directo a memoria. Es necesario copiarla manualmente a un archivo de imagen.

Por cierto, y nada mas para insultar. Hasta ahora casi no he encontrado juegos que aprovechen las nuevas arquitecturas de nucleo múltiple a toda su capacidad. Muchos de los juegos actuales no serían capaces de desplegar sus famosas gráficas sin la ayuda de costosas tarjetas aceleradoras de video y la verdad es esa misma calidad de imagen sin el uso de las GPU’s ya era posible desde la época del Pentium 4 (si las hubieran programado en Ensamblador por supuesto). Por cierto, a finales del 2008 y principios del 2009 fue que logré escribir directo al sistema de video en ensamblador para Windows Vista. Y nada mas para seguir insultando, no tuve ninguno de esos problemas de los que tanto se quejan los lamers del .NET y plataformas similares. Y aunque usé algunos antiguos servicios del DirectX para evitar problemas con la protección de memoria, no tuve necesidad ni siquiera de descargar e instalar el SDK ni mucho menos ninguna de esas bibliotecas Wrappers (que ocultan las llamadas a DirectX) que tan de moda se han puesto hasta entre los autodenominados profesionales de la industria.

Y este es el punto donde se queda esta historia. Si todo va bien, para dentro de uno o dos años voy a tener con que darle a esto de los juegos. O antes si alguno de entre los que leen este blog quiere unirse para participar y llevarse su parte es bienvenido. Hay que recuperar todo el tiempo y dinero perdido. Y hay que moverse rápido porque los CPU’s de 64 bits ya llevan algún tiempo en el mercado y aunque los sistemas caseros de 64 bits actuales son bastante inestables, ya comienzan a ser aceptados por los consumidores. Parece que la barrera de los 4 gigabytes de memoria está por romperse. Y no puedo esperar por programar una computadora con 16 Exabytes (lo que mediria una memoria de 64 bits). Seguro en 20 años, pues igual de lejanos se escuchaban los 4 Gigabytes en 1985.

Y este es el fin de estas 4 historias sobre la programación en Ensamblador de 32 bits. Al final la única moraleja que puedo dejarles a ustedes es la siguiente:

–Si no puedes contra el enemigo…  ¡Desensámblalo!–

diciembre 13, 2009 Publicado por | Uncategorized | , , , , , | 2 comentarios

Vagabundos de 32 Bits

¿Era ese el final de los Programadores de Ensamblador?

Esta historia es continuación de la nota anterior llamada “Desterrados de 32 Bits” que a su vez es continuación de “Revolución de 32 Bits” y cuenta uno de los episodios mas deprimentes en la historia de la programación en Ensamblador de principos de este siglo.

artedeprogramador

En la última entrada se cuenta como de la noche a la mañana, se volvió casi imposible programar en Ensamblador para computadoras con Windows basados en tecnología NT (como el 2000, ME y XP) y como muchos tuvieron que dejar de lado la programación en Ensamblador y rebajarse a manejar bases de datos para poder sobrevivir. Y de como mis compañeros programadores y yo decidimos hacerle frente a este destierro sin obtener lo que se dice los mejores resultados en el proceso. Sin mas, aquí está la historia:

El asunto no podía quedarse así, por lo que en ese entonces reuní a lo que entonces era mi pequeña banda de forajidos computacionales y en una junta tomamos una de las decisiones que, aunque tuvo muchas cosas buenas retrasó nuestro avance en el desarrollo de videojuegos por al menos nueve años. Ahí, frente a unos demos de DirectX, recuerdo especialmente uno de una calabaza de halloween que desplegaba un Framerate de 120 FPS, nos preguntamos:

¿Continuamos con la programación directa del hardware o nos metemos con DirectX?

¡Demonios! Si pudiera regresar el tiempo justo a ese instante me abofetearía a mi mismo hasta que solo me funcionaran el sentido del oido y el sentido común y me gritaría a mi mismo:

¡No seas 9*n3+@5! ¡Es perfectamente posible programar para Windows en Ensamblador!

Pero en ese entonces tenía un concepto muy equivocado sobre lo que era programar para Windows. Creía que la única manera de desarrollar para las versiones mas avanzadas de este sistema operativo era con herramientas como el Visual Studio y similares. Las cuales en ese entonces (o sus equivalentes de ese entonces) aunque eran buenas resultaban muy caras, extremadamente difíciles de conseguir, con infomación casi nula y aún bien dominadas el rendimiento del producto final no se comparaba con el de una aplicación programada completamente en Ensamblador. Por lo que, confiados en nuestra habilidad para programar en ASM tomamos una decisión tan valiente como ingenua: ¡Nuestros juegos debían de ser capaces de ejecutarse sin sistema operativo!

Hoy en día es mas o menos conocido el concepto de Live CD entre los aficionados a Linux. Y para los que no saben, un live CD es un disco que uno pone en una computadora y que es capaz de correr una aplicación completa sin necesidad de alterar en lo mas mínimo el sistema operativo instalado, y se usa para versiones de prueba de sistemas operativos. Nuestro plan era hacer juegos que funcionaran de la misma manera. Durante ese tiempo, que abarcó mas o menos 2 años aprendimos muchísimo sobre como hacer un sistema operativo y, al igual que cuando intentamos hacer un compilador propio y nos topamos con FASM, esta vez nos topamos con MenuetOS. Un interesante sistema operativo de Europa Oriental programado completamente en Ensamblador. Aprendimos mucho de esa experiencia, aunque mas hubiéramos aprendido de haber sabido hablar ruso. Algunas de las hazañas que conseguimos en ese entonces fueron:

  • Arrancar una PC sin sistema operativo por medio de un Bootloader en Floppy y CD
  • Hacer controladores de discos y periféricos para ese bootloader.
  • Entrar al modo protegido desde ese bootloader
  • Tomar control sobre el misterioso BIOS de 32 bits.
  • Manipular el BUS PCI y todos lo periféricos conectados al mismo.
  • Manipular las tarjetas de video de aquel entonces compatibles con el estandar VESA 2.0 y superior.
  • Mover grandes cantidades de datos con el DMA de 32 bits.
  • Y muchas cosas igual o mas impresionantes que al final no nos sirvieron para mucho.

menuetos

Al final, ya cuando teníamos la capacidad de desarrollar software mas o menos decente que corriera desde un live CD (por cierto, en esa época las grabadoras caseras de CD eran tan caras como una computadora de escritorio) nos topamos de narices con que la gente no aceptaba ningun software que no corriera en Windows. Era una ironía que aún teniéndo la capacidad de desarrollar un sistema operativo completo si hubiéramos querido eramos incapaces de programar unos humildes juegos.

A partir de entonces no ocurrió nada bueno, salvo el haber levantado una pequeña oficina en un local que había permanecido abandonado durante cuarenta años. Y que a pesar de tener serias carencias nos sirvió bien para continuar nuestras investigaciones por los primeros 2 años de este siglo XXI. En ese corto espacio jugamos a ser una empresa de 3 (5 si contamos al Samuel y a Aldape) programadores sin documentos ni ganancias. Pero que logramos uificar todo lo que hasta entonces habíamos desarrollado.

Sin embargo, al pasar el tiempo y no lograr avances que fueran redituables el grupo se fue debilitando. Ya no éramos mas los programadores capaces de trabajar en un demo por 3 días seguidos de campamento en la oficina, algunos se vieron obligados a trabajar por hambre y necesidad. Eso sin mencionar que en ese entonces fue cuando me expulsaron de la universidad cuando ya iba en mi penúltimo semestre. El juicio fue algo traumático pero mas traumáticos fueron los meses antes y después del mismo. Y como ya comenté, no podré poner un pie en mi antigua facultad hasta bien entrado el 2024. Pero si regreso no va a ser como estudiante. Por cierto, mas o menos a la mitad del siguiente año fue cuando nuestro grupo de desarrollo acabó de desmoronarse por completo. Aunque aun nos veíamos ocasionalmente para planear estrategias que nunca llevábamos a cabo. Y aunque habíamos caído, aun no estábamos muertos.

Y aun estaba por venir lo peor…

Los siguientes dos años fueron los peores, no tiene caso que comente mis tragedias personales pero solo voy a decirles que en ese entonces fue cuando comenzó mi odio contra los lamers, pues en ese tiempo no encontraba trabajo ni como barrendero y el ver como todos los empleos en computación se los llevaban gentes cuyas únicas habilidades eran copiar querys, escribir documentos html (y no precisamente con un editor de texto), hacer clientes con editores de Visual Basic y trabajar con hojas de cálculo era algo que me enfurecía mas allá de los límites del razonamiento humano. Aún recuerdo como disimulé el asco al saludar de mano a un jefe de recursos humanos que tenía unas horribles manchas en la piel.

Y así pasé ese tiempo hasta que un día me llegó el chisme de que al otro lado del mundo alguien estaba desarrollando una nuevo consola de videojuegos y que no encontraba programadores. Esa pequeña aventura fue lo que me mantuvo vivo durante esos años negros y aunque no terminó como me hubiera gustado,si me hizo sentirme mejor conmigo mismo y me ayudó a reconstruir parte de mi antiguo equipo de desarrollo. Dicho aparato era conocido como GP32 de una empresa de Corea del Sur llamada Gamepark ubicada en Seoul. Espero poder escribir sobre ese asunto un día de estos. Pero supe que lo peor había pasado cuando, durante una sesión de programación con esta consola portatil, el buen Julio dijera:

–Te ves mucho mas repuesto que como te veías en los años de universidad… ¡En especial el último!

En fin, en el tiempo en que tuve esa consola coreana en mis manos recuperé mucho de lo que había perdido en años anteriores y si no fuera porque mi familia me obligó a rehacer mis estudios muy probablemente estaría escribiendo este blog desde algún lugar de Corea del Sur. Sin embargo, a pesar de esta gran victoria semipersonal (pues el Julio también colaboró muy de cerca) la programación para sistemas Windows había quedado abandonada durante siete años y dudo que en los 2 próximos años pueda hacerse algo que valga la pena vender. Apenas hace un año y luego de meses de ingeniería inversa y otras artes oscuras que no se si sea seguro mencionar en público es que logré hacer funcionar el ensamblador en una computadora con CPU de nucleo múltiple en Windows Vista. Y es ahora cuando realmente puedo retomar todo lo que dejé pendiente hace ya tanto tiempo.

Derrotados pero no muertos

Como se dijo en la nota anterior, este regreso a la programación en Ensamblador para Windows se debe en gran parte a los esfuerzos de grandes programadores como Iczelion, el autor del FASM Thomasz Grysztar, gente de sitios como asmcommunity.net y otros muchos mas que a partir de mucha investigación lograron devolverle su merecido lugar a la programación en ASM. En la siguiente entrada se hablará de este feliz regreso. Sin embargo, apenas se había descubierto el camino a seguir. El recorrerlo y llegar hasta el final era un esfuerzo de proporciones épicas, mismas que se detallarán en la siguiente nota donde además de eso se contará como los programadores de Ensamblador regresamos al territorio del que alguna vez fuimos cruelmente expulsados.

diciembre 6, 2009 Publicado por | Uncategorized | , , , | 9 comentarios

Destierro de 32 Bits

C:\>RUN\DOS\RUN>

Esta es la continuación de la entrada anterior titulada “Revolución de 32 Bits”.

La última nota trató sobre el como las PC’s equipadas con procesadores 386 y superiores abandonaron lentamente la programación en 16 bits para dar paso a aplicaciones mas avanzadas de 32 bits. Y como el mundo tuvo que esperar casi 10 años para ver juegos que realmente aprovecharan el hardware de estos entonces poderosos equipos. En esta parte de la historia se cuentan unos años horribles en los que llegué a pensar que era el fin de la programación en Ensamblador para computadora personales.

Corrían los últimos años del siglo veinte, poco a poco las conexiones de tipo Dial Up se volvían inoperantes y los primeros monitores LCD (de esos que si uno no estaba parado directamente de frente a ellos no se veían) comenzaban a aparecer. Esa era una época maravillosa en la que el DOS y el Windows 95 cohabitaban en la misma computadora y existía la controversia de que tanto uno dependía del otro. Tiempos en que el Windows NT solo existía en equipos empresariales y aunque era muy estable no servía para jugar. En ese tiempo aún había juegos que para jugarlos adecuadamente había que salirse del Windows. Pues correrlos desde dentro de este sistema, aunque era posible disminuían severamente su desempeño. La razón de esto era el Modo Virtual 86

Modo Virtual 86

DOS agonizante

Las computadoras de 32 bits (no recuerdo de momento a partir de que CPU) tenían una modalidad interesante de operación llamada Virtual 86 Mode, en que podían imitar no solo uno, sino a una multitud de sistemas de 16 bits y ejecutarlos como una subtarea independiente. De este modo era posible correr al mismo tiempo varias instancias del DOS con sus respectivas aplicaciones sin por ello salirse del Modo Protegido. Esto le dio mucha vida artificial a estas viejas aplicaciones aún a pesar de que hacía mucho tiempo que los CPU’s 8086 habían dejado de fabricarse. Sin embargo, cuando una aplicación de Modo Real trataba de inicializar el Modo Protegido desde el Modo Virtual 86 pasaban errores muy feos, como el Famosísimo Fallo de protección General, Ejecución de instrucciones privilegiadas, fallos de página y otras cosas peores cuya única solución casi siempre era un reset de la computadora completa. Eso sin mencionar que aunque esto no ocurrirera, uno solo tenía acceso a una minúscula fracción del poder de procesamiento y memoria del sistema. Por lo que las aplicaciones de 16 bits ejecutadas en el Modo Virtual 86 rara vez daban buenos resultados. Aunque siempre estaba la opción de reiniciar la computadora en modo MS-DOS.

¿Qué estaba haciendo Bill Gates mientras tanto?

Resulta que en su diseño original, Windows no estaba preparado para suministrar lo necesario para hacer buenos juegos. Su GDI (Graphics Device Interface) estaba pensada con la seguridad en mente y no en el alto desempeño que los juegos requieren. Por lo que, y esto lo leí en viejos libros de historia, intentaron hacer una biblioteca de funciones de 32 bits desde al menos el windows 3.1. Dicha mejora era conocida como WinG pero no tuvo la aceptación esperada y los buenos juegos siguieron corriendo en Modo Protegido desde MS-DOS con ayuda de los Dos Extenders. Sin embargo, un poco mas adelante, Bill Gates finalmente aceptó que la única manera de lograr que los buenos juegos fueran desarrollados para Windows era dándo un acceso mucho mas DIRECT-o al hardware.

Inicios del DirectX.

dxlogo

Antes de entrar en detalle, hay que explicar primero el concepto de Overhead. Como en su origen las computadoras personales tenían muy pocos componentes realmente estandar aparte de un CPU Intel o compatible, era muy común crear capaz de delegación intermedia para facilitar la comunicación entre los dispositivos mas dispares sin cambiar los códigos originales. Por ejemplo, en tiempos del DOS, si uno quería escribir un pixel en pantalla primero tenía que llamar una función de la biblioteca de gráficos de C llamaba BGI(o cualquier otra biblioteca de gráficos) llamada putpixel(); que recibía las coordenadas X, Y y el color. Esta a su vez llamaba al sistema operativo para dar la órden de pintar el pixel, luego el sistema operativo llamaba al BIOS que ejecutaba la interrupción 10h y luego de hacer una complicada y tardada serie de validaciones al fin escribía el mentado puntito de color en la pantalla. Este proceso era tan lento que uno podía hacer un ciclo anidado para pintar la pantalla y podía ver como esta cambiaba de color lentamente. ¡Y pintar una pantalla completa de 320 por 200 tardaba casi un minuto!. Sin embargo, con ensamblador bastaba con conocer la posición de la RAM de Video y escribir un pixel era tan rápido como mover un byte a una posición de memoria. Eso sin contar que existían muchos recursos para manejar la tarjeta de video para hacer animaciones rápidas (de momento recuerdo por lo menos tres). El asunto era como dar acceso a los programadores a esta velocidad sin necesidad de salir del Windows. Y fue así como nació DirectX

Como su nombre lo indica, la idea original tras el DirectX era darle a los programadores el acceso mas directo posible al Hardware sin comprometer la protección de memoria del propio Windows. Mientras que intentaban ahogar los problemas de compatibilidad de hardware con capas de abstracción y emulación de hardware. Al principio DirectX fue un fracaso, pero no tanto porque fuera una mala idea, sino porque la mayor parte de los recursos del sistema estaban siendo usadas por el resto de las aplicaciones. No fue sino hasta la aparición del DirectX 5 que se empezaron a ver juegos para Windows mas o menos decentes. En ese entonces, los juegos de 32 bits soportados en los DOS Extenders ya comenzaban a oler a muerto.

C:\RUN\DOS\RUN>

Los vaqueros del viejo oeste solían decir que no había mejor indio que el indio muerto, y yo digo que el mejor de todos los Windows fue el Windows 98 SE, pues permitía explotar un sistema Pentium III a plena capacidad con todo y sus puertos USB en menos de 30 megas. Además de ser muy estable y ser el último que tenía la opción de reiniciar en Modo MS-DOS. Con un sistema como este fue que mi grupo de desarrolladores renegados aprendimos una buena cantidad de cosas sobre computación. Sin embargo. Sin embargo, con la llegada del temido Windows NT y sus derivados a las computadoras caseras, esta maravillosa era terminó. No mas juegos de 32 bits que tomaban el control absoluto del sistema. De hecho, en esa época, mientras jugaba el juego Hexen en una PC Pentium III con Windows ME apareció una pantalla sobre un error en algo llamado WinOldAp. De acuerdo con una poca de investigación, Winoldap era un servicio del sistema operativo que permitía correr aplicaciones de la época descrita en la entrada anterior “Revolución de 32 Bits” en este caso me enteré de que estaba muerto hasta que el mismo Windows me lo había informado.

…llegó un momento en que llegamos a creer que ese era el fin de la programación en Ensamblador para computadoras caseras…

Por cierto, y hablando del Windows ME, fue a partir de esta versión del sistema operativo de Micro$oft que la feliz armonía entre el Windows y los programadores de juegos que usaban Dos Extenders (o que entraban al modo protegido por su cuenta) se acabó. A partir del Windows 2000 y el ME ya no había manera de salirse del Windows y tomar el control absoluto del sistema como antes. Recuerdo que hubo una pequeña guerra entre mi grupo de amigos programadores por que sistema instalar en nuestras computadoras. Pues un sistema posterior al Windows 98 no nos permitía programar como lo habíamos hecho hasta entonces. Y la peor parte es que todas las herramientas para desarrollo en Windows eran inadmisibles dados nuestros métodos de trabajo. Llegó un momento en que llegamos a creer que ese era el fin de la programación en Ensamblador para computadoras caseras por lo que, como abandonar la programación en ASM no era una opción decidimos hacer lo mejor que se nos ocurrió: ¡Programar en Ensamblador para otras plataformas! Aunque eso significara crear la nuestra propia.

Y en ese entonces fue cuando se dio nuestro destierro de la programación en Ensamblador para computadoras caseras. Aunque en ese tiempo hicimos muchos avances en otras áreas relacionadas con el Ensamblador que se mencionarán en la siguiente entrada. Pero eso no nos salvó de experiencias terribles que poco a poco fueron debilitando al equipo aunque sin llegar a acabar con él por completo.

En la siguiente entrada se contará de que fue de la programación en Ensamblador (o al menos la parte que me tocó vivir) durante los primeros años del presente siglo y como gracias a los esfuerzos de grandes hackers como Iczelion y otros cuyos seudónimos no alcanzo a recordar los programadores de Ensamblador pudimos regresar a la escena de la computación casera de la que alguna vez nos sentimos desterrados. Pero entre ese tiempo, muchos de nosotros nos convertimos en poco menos que vagabundos y esos oscuros años son los que se narrarán mas adelante.

diciembre 6, 2009 Publicado por | Uncategorized | , , , | Deja un comentario

Modo Protegido

–O el Hotel de los OpCodes Rotos–

 

Una de las cosas mas importantes que tienen los nuevos sistemas operativos respecto a los antiguos es la capacidad de hacer que muchas aplicaciones trabajen de manera simultanea en computadoras que tienen un solo CPU. En otra nota hablaré sobre como demonios hace el sistema para hacer esto; pero ahora quiero responder a una pregunta mucho mas interesante: ¿Como demonios le hace el sistema para que miles de programas corran de manera simultanea sin hacerse porquería unos a otros? La respuesta es precisamente en lo que Intel ha dado en llamar el Modo Protegido.

¿Y que demonios es el Modo Protegido? Se trata de un mecanismo de seguridad jerárquica mas o menos complejo implementado en el propio CPU. Gracias a él es no solo es posible correr muchos programas simultaneamente, sino además de que se logra que cada uno se comporte como si tuviera toda la computadora para él solo. Este sistema se basa en cuatro niveles de prioridad que a menudo se representan como anillos concéntricos donde quien está mas al centro tiene poder sobre los que están mas a la periferia. Pero como esto me parece muy complejo y aburrido como para explicarse en este blog voy a hacer una analogía mas comprensible para (muy pocos de) ustedes: Un Hotel

Un hotel es el perfecto simil de un sistema operativo que corre en Modo Protegido como lo hacen Windows y Linux en su versión x86. Pues en ambos se tiene a un montón de gente (los programas) cohabitando en un mismo espacio mas o menos grande. En el lugar mas bajo de la jerarquía tenemos las habitaciones de los huéspedes. Se supone que cada huesped puede usar una habitación por la cual pagó y nadie puede entrar a una habitación que no sea la suya, al menos no sin el consentimiento de quien está adentro. Cuando la habitación se desocupa esta puede ser usada por alguien mas sin afectar por ello la vida en el resto del hotel. En un sistema en Modo Protegido, una aplicación que es cargada recibe un espacio dentro de la memoria y tiene acceso (o eso es lo que ella cree) a muchos recursos comenzando por un espacio de memoria exclusivo que ninguna otra de las aplicaciones puede leer o escribir (salvo por un error en la función VirtualProtectEx pero eso es otro show). En caso de que una de estas aplicaciones termine su ejecución o peor aún falle y deje de funcionar el sistema no se ve afectado por ello.

En el siguiente nivel de esta jerarquía están los servicios comunes como el comedor, la piscina (eso si la piscina no está cerrada),el gimnasio o cualquier otra area similar. Los huéspedes pueden hacer uso de estos recursos ya sea turnándose o reservando un lugar con anticipación. De este modo, aunque se tenga únicamente una piscina (y si no está cerrada) todos pueden ir a nadar sin temor a que nadie se apodere de esta para él solo. En el Modo Protegido es igual. Todas las aplicaciones pueden hacer uso de los recursos del hardware como discos, pantalla, puertos de comunicaciones o archivos pero para hacerlo tienen que pedir permiso al sistema. Ninguna aplicación puede acceder de manera directa a estos recursos sin desencadenar el temible Fallo de Protección General. Pero puede hacer uso de los servicios de los controladores o Drivers para beneficiarse de esos recursos. Pasando de nuevo a la analogía del hotel, los empleados que dan acceso a estas instalaciones son los controladores de dispositivo.

El segundo nivel mas alto de la jerarquía dentro del hotel lo tiene el personal e instalaciones de mantenimiento. Inmediatamente arriba del personal que da acceso a las instalaciones comunes tenemos al resto del personal del hotel. Entre los que destacan el personal de limpieza, los que asignan las habitaciones a los nuevos huéspedes, los encargados de hacer reparaciones cuando algo se descompone y en general todos aquellos que mantienen el hotel de una sola pieza. Como ya se sabe el personal de mantenimiento tiene acceso a casi todas las areas del hotel como por ejemplo las habitaciones de los huéspedes a los que entran para limpiarlas de vez en cuando. Sin embargo los huéspedes no pueden entrar a instalaciones tales como las oficinas administrativas, las áreas tras los mostradores, la cocina del hotel o al cuarto de máquinas de la piscina (en el caso de que la piscina no esté cerrada). En el Modo Protegido este nivel corresponde a los mas importantes servicios de sistema como por ejemplo el control de la Memoria Virtual, la asignación de espacios dentro de la memoria física, la conectividad de red, el control de ejecución y cambios en el modo de operación, o el manejo de errores y excepciones. Dependiendo de la complejidad del sistema esta parte puede corresponder al nucleo del sistema operativo o estar fuera pero trabajar de modo estrecho con este.

En el nivel mas alto de la jerarquía está el dueño del hotel, el típico gordo sudoroso y sin camisa que se pasa el día espiando a los huéspedes a traves de un complejo sistema de cámaras ocultas tras los espejos de los baños y en las lámparas de techo. Este ser maneja el hotel completo desde su silla mantecosa y decide (dependiendo de lo que ve con sus cámaras) cosas como por ejemplo quién se queda o se va del hotel, se encarga de vigilar de las instalaciones funcionen correctamente y de no ser así mandar al personal de mantenimiento a arreglar las cosas. Por ejemplo, si la piscina tiene SIDA, mandar cerrarla. O evitar de que un grupo de huéspedes con cabello afro la cierren. En pocas palabras, el dueño del hotel es quien tiene control absoluto sobre todo y sobre todos. Supongo que no tengo que explicar demasiado su equivalente en el Modo Protegido. En el anillo de protección de mayor jerarquía, también conocido como el Anillo Cero o “Ring 0” es donde se encuentra el nucleo del sistema. Este nucleo se encuentra en lo mas alto del poder respecto al resto del sistema, sino que tiene acceso directo a muchos servicios privilegiados de la propia computadora que solo desde este anillo de protección es posible manejar sin desencadenar un Fallo de Protección General.

Y bien solo queda por contestar una pregunta: ¿Y que pasa si alguien desobedece estas leyes de protección? La respuesta es el temible General Protection Fault.

General Protection Fault (Fallo de Protección General)

Uno de los errores mas comunes en la era del Windows 95 esa el famosísimo General Protection Fault. Este ocurría cuando una aplicación intentaba invadir un espacio de memoria que no era el suyo o cuando ejecutaba una instrucción de CPU que estaba por encima de su nivel de privilegios. Cuando el Procesador detectaba esta situación generaba la “Exception 0D General Protection Fault”. No se si será coincidencia pero a esta excepción le corresponde el número de mala suerte por excelencia en el mundo occidental, el 13. A grandes rasgos, una “Exception” es un código que se dispara cuando el CPU detecta una condicón peligrosa determinada de antemano. Se supone que en un sistema bien hecho una excepción es como una alarma contra incendios que detecta el fuego y activa los aspersores automáticos para apagarlo y una vez hecho esto regresar a la ejecución normal. Pero en los tiempos del viejo Windows 95 la única manera de salir de una General Protection Exception era reiniciando la computadora.

Otra nota curiosa es la de porqué son exactamente 4 niveles de protección dentro del Modo Protegido. Al parecer 4 era la potencia de 2 mas cercana al 3, pues como todo jefe sabe para manejar a la burocracia se necesitan cuando menos 3 niveles en la jerarquía, donde el mal alto corresponde al jefe y el mas bajo a los que hacen el trabajo manual. El nivel intermedio existe para delegar responsabilidades y encontrar culpables cuando algo falla. De hecho se dice, aunque no lo he comprobado por flojera, que las primeras versiones de Windows de 32 bits solo usaban 2 niveles de seguridad, el mas alto para el nucleo del sistema operativo y el mas bajo para las aplicaciones y que además usaban todos los descriptores de segmento inicializados en la posición cero de la memoria y con un límite de 4 Gb.¡En una época en la que las computadoras mas costosas no pasaban de los 64 megabytes en RAM.! Este diseño hacía que se produjeran muchos fallos de protección general, porque los segmentos de código de los diferentes programas en realidad quedaban unos sobre otros. La explicación de lo que es un descriptor de memoria vendrá en otra nota pero antes quiero dejarlos con algo para pensar:

Todos sabemos que los hoteles no solo se usan para hospedar parejitas, sino que a veces se alquilan para eventos especiales como convenciones, presentaciones de productos nuevos, viajes de negocios (este es el uso mas cercano al original) y algunos eventos deportivos o culturales. De hecho, la inmensa mayoría de las personas que leen este blog por gusto, las mas de las veces hemos han estado en un hotel por cuestiones de trabajo las mas de las veces. Bueno, hay quien hace de lo otro un trabajo pero eso ya no es programación. Ahora la pregunta es ¿Qué tal si para alguno de estos eventos se necesita reservar una instalación completa? Como por ejemplo, cerrar la piscina para organizar una competencia de natación, u organizar un banquete exclusivo en el restaurante del hotel o quizas llevar a cabo un concierto o baile en los jardines. O cualquier otra situación donde se necesite acceso DIRECTo a una determinada instalación.

Les dejo de tarea pensar en esto, pues esa es la clave para programar buenos videojuegos en Windows.

noviembre 18, 2009 Publicado por | Uncategorized | , , , | 1 Comentario

El León Enjaulado

–Y el Circo de los Programadores–

huele a leon

Un día un avión se estrelló en el centro de la selva africana, pasaron los días y nadie los rescataba hasta que se les acabó la comida. Enmedio de la desesperación, un valiente se ofreció a internarse en la peligrosa selva en busca de alimento para todos. Pasaron las horas y aquél no regresaba. De pronto se escucha un grito:

–¡Rápido! ¡Abran la puerta!–

Cuando ven por la ventana, descubren al pasajero que salió por comida huir a toda prisa de un enorme león que le pisaba los talones, pero justo cuando abrieron la puerta, el perseguido se agacha y la bestia salta al interior del avión. Entre el pánico, quienes se quedaron encerrados con la bestia alcanzan a escuchar:

–Ahí les dejo este para que lo descueren. ¡Voy por otro!

No encontraba una mejor manera de describir como me siento luego de haber hecho lo que creía que sería un gesto de buena voluntad. Pues si son seguidores de este blog saben de mis peleas con ciertas personalidades de la ‘industria’ nacional del desarrollo de videojuegos. Este caso en particular se relaciona con lo descrito en la nota anterior titulada “Ya estás muerto”, específicamente la llamada “Primer videojuego”. Que trataba de un grupo de aficionados que querían desarrollar un juego “sencillo” para probar su habilidad. Resulta que me dio lástima ver lo mal que la habían pasado y quise ayudarlos un poco. Pero lo que ocurrió no era lo que esperaba.

No hace falta que les diga que la ayuda que les ofrecí no tiene nada que ver con el todopoderoso Lenguaje Ensamblador, y aunque me averguence decirlo, me rebajé a usar un lenguaje “de humanos” como el C++ con la versión mas reciente de DirectX. ¿Puede haber una manera mas sencilla de hacer un juego de video? Inclusive, hasta les busqué algunas herramientas libres de desarrollo y hasta les dije como descargarlas, configurarlas y usarlas (hasta con dibujitos y videos del Youtube). Pero aún así algunos consideraban que eso era demasiado dificil.

La idea era desarrollar un juego mas o menos sencillo que pudiera ser programado por cualquier quinceañero con una computadora con acceso a Internet. Sin embargo, algunos afirmaban que manejar el DirectX era “demasiado dificil” (deja vu) y que preferían usar bibliotecas como Allegro y SDL. Personalmente he jugado con ese tipo de bibliotecas, no me preocupa tanto que sean wrappers al DirectX, que su overhead las vuelva lentas como tortugas reumaticas  ni que pongan en una caja negra las llamadas al sistema, lo que no pude soportar es que no daban control sobre nada. Por ejemplo ¡SDL no da acceso directo al Frame Buffer! Creo que esta simple declaración deja en claro lo que pienso de él.

El que un principiante se asuste con el formato de llamada de DirectX y tema perderse en las confusas macros en notación húngara inventadas por Micro$oft puedo mas o menos entenderlo, ¡¿Pero asustarse con la función CallBack de Windows?! De hecho, una de las cosas a las que recurren mucho los desarrolladores aficionados es a los famosos “Manejadores de eventos” que son rutinas que hacen parecer que responden a ciertos eventos del sistema, cuando en realidad no es así. Eso me hizo recordar la época en que herramientas lamers como el Visual Basic se pusieron de moda. En realidad generaban código común y corriente pero nadie se atrevía a tocar una linea del código generado. En verdad, para alguién que tuviera un mínimo de conocimientos informáticos, el escuchar a estos lamers hablar de “Programación de Eventos” era similar a oir a un padre contarle a sus hijos sobre como los trajo la cigueña.

Volviendo al proyecto del “Primer videojuego”, lo siguiente a definir fueron las herramientas. Al final decidimos (o debería decir que les impuse) usar el compilador Mingw con Code::Blocks. Pasé mas tiempo buscando como configurarlo para que aceptara la última versión de DirectX que escribiendo mis primeros programas. Por cierto, Code::Blocks tiene una función que genera una aplicación “de prueba” de manera automática al hacer click en el icono del proyecto/sources. Así que todo lo que tenían que hacer para crear su primer programa en DirectX era dar click en sources, generar automáticamente el Main.CPP y oprimir el botón de compilación. Por alguna razón, luego de llegar a este punto la comunidad guardó silencio. Todos cambiaron de tema y nadie ha posteado en el grupo de “Primer Videojuego” desde entonces.

Dicen los japoneses que la diversión del karaoke(canto de aficionados) termina cuando sube alguien que si sabe cantar. Aunque en esa comunidad hay varios profesionales de “la industria” de los videojuegos nunca he visto que uno de ellos publique ya no digamos un juego completo, sino tan siquiera un demo jugable hecho por ellos. Me pregunto porqué entonces los autodenominados profesionales rondan estas comunidades. Es como alguien que presume de ser muy bueno para pelear y frecuenta las arenas de boxeo y lucha libre ¡Pero que nunca pelea! Me pregunto cual es el propósito de esta gente, lo único que sé es que si quieren medirse con alguien aquí estoy yo para que demuesten su valor si es que se atreven.

La pregunta que ustedes estarán haciéndose es ¿Y que tiene que ver esta historia absurda con la programación en Ensamblador? Bueno, la verdad es que estoy pensando hacer una DLL que pueda ser llamada desde los programas hechos en C++, esto no parece la gran cosa hasta que tomamos en cuenta que la DLL está codificada 100% en ensamblador y se llama de manera directa por el programa en C++. Espero que de esta manera quienes no conocen este lenguje y hasta le temen puedan contemplar su verdadera capacidad sin dejar la relativa seguridad de un lenguje ‘de humanos’ como C++. Mas o menos como un niño contemplaría desde lejos a un león enjaulado en un paseo por el circo. Poco a poco le iría perdiendo el miedo hasta que se acercara poco a poco a la jaula, meta sus manitas entre los barrotes y le de a probar al gran felino un poco de su algodón de azucar.

¿Y ahora que sigue? Supongo que jugaré con estos aficionados con sus propios juguetes y ya cuando llegue el momento sacaré los mios, lo interesante de este proyecto (cuya verdadera finalidad es la de mostrar como combinar el Ensamblador con otros lenguajes) es que no solo voy a hacer una ‘buena obra’ sino que de paso podré fastidiar un poco a ciertos lamers “profesionales”que han convertido a los integrantes de estas comunidades en sus groupies de tiempo completo.

agosto 24, 2009 Publicado por | Uncategorized | , , , , | 7 comentarios

Darwin Digital

–Evolución y Extinción Tecnológica–

Alguna vez alguien me dijo que los mas poderosos sistemas de computación solo existen al interior de las grandes empresas de desarrollo de software y algunos centros de investigación y que lejos de ser estáticos cambian y evolucionan con el paso del tiempo. Esto se relaciona con una interesante y blasfema discusión sobre la evolución de las especies.

Hay extremistas que dicen que los seres vivos actuales fueron creados tal y como los conocemos. Esta teoría se conoce como la “Teoría del Mínimo Absoluto” y dice que si retrocedemos en la evolución, quitándole cosas, llega un momento en que una entidad deja de existir como tal. Esto aunque parece tener algo de lógica, no tiene nada que ver con la realidad, pues precisamente la evolución consiste en el cambio constante de las especies. Donde pequeños y constantes cambios (microevolución) son las piezas de los cambios mas grandes (macroevolución). Con el tiempo el cambio es tan grande que el ejemplar final ya no tiene nada que ver con lo que alguna vez fue.

Pero bueno, este es un blog sobre lenguaje Ensamblador, no de biología y mucho menos de religión. De lo que quiero hablar en esta entrada es sobre la evolución del software en la computadora de un programador. A diferencia de los usuarios que se limitan a descargar y usar paquetes que tienen que ser reinstalados, a veces con todo y computadora, cada cierto tiempo; los programadores hacen herramientas pequeñas y funcionales que modifican conforme los requerimientos a los que se enfrentan cambian. Estos cambios pueden parecer insignificantes pero con el tiempo llegan a ser tantos y tan frecuentes que el software original cambia por completo y al paso de los años es tan grande, complejo y poderoso que parece haber sido creado por los mismísimos dioses o al menos por algún tipo de genio loco de la computación.

En este caso, quiero hacer la prueba para ver si esto es cierto y quiero aplicarlo al desarrollo de una herramienta que permita mantener bajo control el desarrollo de programas muy grandes (y del que ya hablé en una nota hace meses). Por ahora apenas codifiqué una pequeña aplicación que toma el contenido de un archivo de texto llamado ‘input.txt’ y lo copia a otro llamado ‘output.txt‘. El programa, aunque está hecho en Ensamblador para Windows de 32 bits no tiene interfaz gráfica (aunque puede adaptársele una). En pocas horas, este programita será capaz de leer un texto cualquiera y decir que palabras diferentes contiene y en que renglón se encuentran. Esto es lo bastante sencillo para ser codificado en un fin de semana.

Si alguno de ustedes lee el código y no nada mas lo copia a la IDE del FASM verá una estructura muy rara llamada “aceptor” un aceptor es un maldito ciclo con una o mas condiciones de parada enmedio que sirve para detectar patrones en secuencias lineales de entrada, como lo son las palabras en un texto. Los aceptores merecen una o dos notas aparte para explicarlos pero por ahora no son mas que un ciclo con uno o dos saltos. No quiero adelantar nada sin haberlo programado primero, pero algo tan elemental como ver que palabras contiene un texto y donde están es muy util a la hora de programar, pues puedes llevar mejor control de tus variables y estructuras sin tener que moverte a traves del mar de instrucciones en que se convierte un programa en Ensamblador. Aquí les dejo lo que llevo del código, que por supuesto funciona (copia el contenido de un texto llamado input.txt a otro llamado output.txt).


;Se supone que este programa debe de evolucionar para
;convertirse en una herramienta de desarrollo y control de
;codigos complejos. No tengo idea de como va a ser pero
;por ahora lo unico que hace es copiar el contenido de un
;archivo de texto llamado 'input.txt' y escribirlo en otro
;archivo llamado 'output.txt'. Solo compilalo y haz doble click
;para ejecutarlo.
;
;para ver como sigue la evolucion entra a:
;
; https://asm86.wordpress.com
format PE GUI
entry start

section '.code' code readable executable

  start:

;;      AQUI EMPIEZA EL SHOW

                        call abrir_archivo_fuente
                        call medir_archivo_fuente
                        call leer_archivo_fuente

                        call procesar_archivo_fuente

                        call crear_archivo_salida
                        call escribir_archivo_salida

                        call cerrar_handles_archivos
;;      AQUI ACABA EL SHOW
        push    0
        push    _caption
        push    buffer_provisional
        push    0
        call    [MessageBoxA]

        push    0
        call    [ExitProcess]
    ;fin de la ejecucion

;aqui comienzan los procesos propios
abrir_archivo_fuente:

                       push    0
                       push    20h; archivo
                       push    3; abrir existente OPEN_EXISTING
                       push    0;seguridad
                       push    3;lectura y escritura compartida
                       push    0c0000000h;lectura y escritura generica
                       push    input_file_name
                       call    [CreateFile]
                       mov     [input_handle], eax
                    ;abrir archivo fuente a analizar

                        ret
medir_archivo_fuente:
                        push 0          ;posicion del dword mas alto en caso de que el archivo supere los 4gbytes
                        push [input_handle];handle del archivo abierto
                        call [GetFileSize]
                        mov  [input_size], eax
                    ;tomarle la medida al archivo

                        ret

leer_archivo_fuente:

                        push    0                 ;no overlap
                        push    indice            ;# de bytes leidos
                        push    [input_size]           ;leer n bites
                        push    buffer_provisional ;guardar aqui
                        push    [input_handle]               ;handle de archivo
                        call    [ReadFile]
                    ;leer del archivo para su analisis

                        ret

crear_archivo_salida:
                       push    0
                       push    20h; archivo
                       push    2;crear nuevo
                       push    0;seguridad
                       push    3;lectura y escritura compartida
                       push    0c0000000h;lectura y escritura generica
                       push    output_file_name
                       call    [CreateFile]
                       mov     [output_handle],eax
                    ;crear archivo de salida, si ya esta,
                    ;crearlo de todos modos

                        ret
escribir_archivo_salida:
                        push    0      ;no overlapped
                        push    indice ;posicion de numero de bytes transferidos
                        push    [input_size]  ;cantidad de bytes a transferir
                        push    buffer_provisional;posicion de buffer
                        push    [output_handle]    ;handle de archivo
                        call    [WriteFile]
                    ;escribir al archivo
                    ;#copiar 20 bytes a un archivo de texto

                        ret

cerrar_handles_archivos:
                       push     [output_handle]
                       call     [CloseHandle]
                       push     [input_handle]
                       call     [CloseHandle]
                   ;aqui se cierra el acceso a ambos archivos
                       ret
;procesar_archivo_fuente(char *cadena, aceptor *aceptor);
;toma como parametros la posicion de inicio de la cadena y la
;de la estructura del aceptor, seria bueno que tambien recibiera la
;longitud de la cadena
procesar_archivo_fuente:

                        ret

;/// fin de los procedimientos propios

section '.data' data readable writeable

  output_handle dd      0
  input_handle  dd      0
  input_size    dd      0       ;longitud del archivo a leer

  indice        dd      0

  _caption db 'Buffer de texto:',0
  _message db 'hello world!',0

input_file_name   db 'input.txt',0
output_file_name  db 'output.txt',0

;////aqui empieza el aceptor ascii
;es una matriz cuadrada de valores de 8 bits,
;que mide 128 por la cantidad de estados
;la entrada es el indice y compone los bits mas
;bajos del indice. Los bits mas altos indican el estado presente
;a cada estado corresponde la ejecucion de un proceso y
aceptor:
.entradas db 80h ;entradas admitidas
.estados  db 2   ;posibles estados del aceptor
.proc_array dd 0 ;posicion del arreglo de funciones asociadas
.numero_de_procesos dd 0; cantidad de funciones asociadas
aceptor_matrix: times 80h db 0    ;

;### SECCION DE DEBUG, INICIO

        ;simbolos ascii

buffer_provisional:times 10000 db 0;darle cran a esto con virtualalloc

buffer_de_palabra: times 100h db 0; aqui se guarda una palabra individual

section '.idata' import data readable writeable

  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
    CreateFile  dd RVA _CreateFileA
    CloseHandle dd RVA _CloseHandle
    ReadFile    dd RVA _ReadFile
    WriteFile   dd RVA _WriteFile
    GetFileSize dd RVA _GetFileSize

    dd 0

  user_table:
    MessageBoxA 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

  _CreateFileA  dw      0
                db      'CreateFileA',0

  _CloseHandle  dw      0
                db      'CloseHandle',0

  _ReadFile     dw      0
                db      'ReadFile',0

  _WriteFile    dw      0
                db      'WriteFile',0

  _GetFileSize  dw      0
                db      'GetFileSize',0

section '.reloc' fixups data readable discardable

Por ahora sigue terminar el aceptor y averiguar una manera de construir una estructura que permita representar en forma de red las interacciones entre los símbolos. Pero eso ya se verá cuando este programa evolucione un poco mas.

Lo interesante de este tipo de evolución es que no depende del tiempo real sino de las horas que los programadores le invierten y de los retos o depredadores a los que el programa se tiene que enfrentar. Lo mas interesante de este sistema es la parte de la reproducción, pues luego de que un software ha evolucionado a cierto nivel puede heredarle algunas de sus nuevas capacidades a sus descendientes. Por ejemplo, hace mucho mientras investigaba como programar en Windows hice unas funcioncitas que desplegaban el contenido de los registros generales y de secciones de memoria que hasta la fecha les implanto a los programas mas nuevos para encontrar los errores mas rápido. En este caso, por simplicidad quité estas rutinas pero el ejemplo es perfectamente funcional sin ellas.

El siguiente paso es reconocer y ubicar cada palabra en un texto y mas adelante que distinga exactamente que es cada símbolo (instrucciones, macros, variables, etc.)No se como lo voy a hacer, lo único que importa ahora es que la evolución no se detenga porque eso significaría la extinción tanto del programa como mía. Aunque creo que va a llegar un momento en que este sistema deba de ser capaz de aprender. Pero eso solo la evolución, o la extinción lo dirán. Por cierto, para que cuente como evolución, el software debe de tener una utilidad real, por insignificante que esta sea, en todas sus etapas.

julio 25, 2009 Publicado por | Uncategorized | , , | 2 comentarios

Tierra de Indios

–Predicando el Ensamblador en la Tribu Linux–

Existe una expresión que dice “Hablar de Dios en tierra de indios”. Significa que hay ciertos temas que pueden desatar la ira de determinadas comunidades. Y una de las comunidades que mas odia el Ensamblador es la de Linux. No entiendo exactamente porqué pero hasta ahora de todos los grupos de usuarios de linux que he conocido no he encontrado a un solo programador que no mire al Ensamblador con desprecio, y algunas veces hasta con odio. En otra nota les contaré mis encontronazos con un cierto grupo de usuarios de Linux de mi pueblo. Por ahora solo comentaré que dos de los personajes de este grupo con los que mas me peleaba eran “El Enano” y “El Maricotas”.

pinguino apache

Bueno, no es necesario explicar que en lo referente a leguajes de programacion, el dios de los linuxeros es el lenguaje C. Asi que es obvio que se enfurezcan cuando alguien les habla sobre el Ensamblador. De hecho este tema es excelente si quieren buscarle pelea a un linuxero. El asunto es que a pesar de esta diferencia de opiniones hubo alguien en Europa Oriental que se le ocurrió juntar ambas cosas: Linux y Ensamblador. Y asi fue como nació el sitio linuxassembly.org. Sitio del que por cierto ya hay un link en la barra de enlaces de este blog.

Este sitio es relativamente viejo y no se mueve mucho, parece que su antiguo administrador no pudo seguir manteniéndolo por motivos de trabajo. Asi que en su desesperación lanzó un grito de auxilio a todos los aficionados al ensamblador (no muchos) para ayudarle con su sitio. No se cuantos se acercaron pero yo le envié un correo diciéndole que quería colaborar con su página. Una semana despues me llegó un correo diciéndome que si podía hacer tutoriales solo tenía que mandárselos cuando los terminara.

Antes de ponerme a presumir de gran desarrollador de software libre y compararme con ese hippie apestoso al que los linuxeros le besan sus micóticos pies (los linuxeros saben bien de cual de sus profetas hablo) es oportuno decir que mi experiencia con linux ha sido mas mala que buena. Para empezar esa gente odia al ensamblador, tienen unas costumbres rarísimas como recompilar el nucleo de su sistema operativo cada noche de luna llena, usar editores de texto cuyos comandos van junto con el texto que escriben, adorar a un anciano de barba larga que le toca la flauta a las mariposas, y se dice que algunos hasta hacen Drivers(ellos les llaman módulos) sin usar nada de Ensamblador. Supongo que este último párrafo va a conseguirme algunos enemigos en el mundo de Linux, aunque no mas de los que ya tengo por el solo hecho de programar el Ensamblador.

Veamos, hace algún tiempo saqué de un bote de basura una computadora usada y le puse Ubuntu Linux. Funcionaba bastante bien tomando en cuenta el mal estado del hardware. El problema es que no estaba habituado a la forma de hacer las cosas en Linux y apenas pude programar algunos ejemplos con la linea de comando. Luego intenté conectar una PC con Windows a la máquina Linux para desarrollar estilo Cross Assembler. Pero tuve serios problemas a la hora de compilar los ejecutables y enviarlos, pues mis mejores herramientas de programación en Ensamblador corren en Windows. Ahora estoy considerando instalar una versión virtualizada de Linux en mi laptop. Según investigué hay una versión de Linux especial para correr dentro de Windows. No haciendo particiones como todos esos lamers/Posers que instalan linux en una partición para no utilizarlo nunca. Esta versión es conocida como CoLinux.

copinguino

No lo he instalado aún pero el FAQ dice que es una versión completa de Linux que puede correr como si fuera una simple aplicación de Windows usando la Virtualización. Esta opción me parece la mejor en cuanto a costo de hardware, tiempos y recursos. Mas adelante les diré como me fue en este asunto.

Hasta donde se, hay algunos ensambladores capaces de trabajar en Linux, como el NASM, GAS, etc. Sin embargo, FASM no solo es capaz de hacer programas para Linux, sino que puede hacerlos sin necesidad de ser ejecutado dentro de Linux. Es decir, que es posible escribir código para linux en una PC con Windows. Esto me ahorrará algo de tiempo mientras aprendo la exagarada complejidad de la mayoría de los editores de texto de Linux. Me pregunto porqué casi no tienen editores tan sencillos como el viejo EDIT del DOS.

¿Cual es el plan? Primero tengo que despejar mi disco duro porque ya me queda muy poco espacio. Luego experimentaré con ese asunto de la Virtualización de Linux y en cuanto pueda mover archivos entre un sistema y otro comenzaré a programar. Hasta entonces es mejor documentarse bien para entender las creencias tribales de esta comunidad que no deja de parecerme extraña. Pues hará falta valor para predicar el Ensamblador en Tierra de Linux.

junio 27, 2009 Publicado por | Uncategorized | , , , , | 8 comentarios

¡Quiero Ver Mas Allá de lo Evidente!

–Crackeando tutorial de Iczelion con OllyDbg–

En esta nota procesaremos el primero de los tutoriales de Iczelion, aunque en realidad vamos a comenzar por el segundo porque la primera parte de lo único que habla es de como funciona el MASM. Y como hay mas gente que habla inglés de la que sabe ensamblador, mejor pasamos a los códigos.

Para esta parte, la mayoría de ustedes ya leyeron la parte teórica, asi que no voy a volver a explicar cosas como para que sirve el .386 (no es la entrada al Modo Protegido) ni lo del modelo flat y stdcall ni los includes ni lo de optioncasemap. Además de que nada de esto nos va a servir. La parte de la sección de datos que tiene 2 cadenas ascii no es la gran cosa y si han seguido este blog desde el principio ya han de saber lo que es una cadena ASCII-Z. Lo único que nos interesa son estas 2 lineas:

invoke MessageBox, NULL,addr MsgBoxText, addr MsgCaption, MB_OK

invoke ExitProcess,NULL

¿Parece sencillo? ¡No lo es! Lo mismo dijeron muchos que intentaron descifrar los tutoriales de Iczelion y ahora viven de hacer querys de SQL. Ese invoke no es una operación de CPU sino una horrible macro, y el primer renglón en realidad se “desenrolla” en 5 instrucciones que en su totalidad miden 18 bytes. Sin contar que a su vez tiene dos llamadas a otra macro anidada llamada ‘addr’ Esta última puede convertirse en 3 o 4 instrucciones mas cada vez que aparece dependiendo de la complejidad de los operandos.

El segundo invoke se desenrolla en solo 2 instrucciones que en total miden solo 7 bytes.

Bueno, los 2 invokes es lo último que ven muchos programadores antes de frustrarse e irse de DBA’s. Pero nosotros tenemos el depurador OllyDbg y al comando de:

OllyDbg, ¡Quiero ver mas allá de lo Evidente!

Obtenemos esta vista del demo de Iczelion en lenguaje máquina:


debug

	00401000 >/$ 6A 00          PUSH 0                                   ; /Style = MB_OK|MB_APPLMODAL
	00401002  |. 68 00304000    PUSH msgbox.00403000                     ; |Title = "Iczelion's tutorial no.2"
	00401007  |. 68 19304000    PUSH msgbox.00403019                     ; |Text = "Win32 Assembly is Great!"
	0040100C  |. 6A 00          PUSH 0                                   ; |hOwner = NULL
	0040100E  |. E8 0D000000    CALL            ; \MessageBoxA
	00401013  |. 6A 00          PUSH 0                                   ; /ExitCode = 0
	00401015  \. E8 00000000    CALL          ; \ExitProcess
	0040101A   .-FF25 00204000  JMP DWORD PTR DS:[<&KERNEL32.ExitProcess>;  kernel32.ExitProcess
	00401020   $-FF25 08204000  JMP DWORD PTR DS:[<&USER32.MessageBoxA>] ;  USER32.MessageBoxA

Como pueden ver, y si no pueden mas abajo lo reescribí en texto para que sea mas sencillo de lamear, las macros se desenrollaron y se convirtieron en instrucciones de ensamblador, las constantes se convirtieron en simples números y además podemos ver las posiciones de memoria del programa.

Para los que ven por primera vez algo como esto, la primera columna indica las posiciones dentro de la memoria virtual, la segunda son los OpCodes en Lenguaje Máquina y la columna que parece código es en realidad código desensamblado. Hasta donde puede, OllyDbg intenta averiguar lo que el programa está haciendo y escribe comentarios en el extremo derecho del código. En este caso, supo que estábamos llamando a MessageBox y Exit Process e incluso identificó plenamente los parámetros. Ahora veamos paso por paso lo que el programa está haciendo:

6A 00 PUSH 0

Aquí están empujando un cero de 32 bits al stack. Esta es la constante MB_OK que le dice a MessageBox el estilo de caja.

68 00304000 PUSH msgbox.00403000

En esta linea están empujando al stack la posición de memoria de la cadena ASCII-Z que dice “Iczelion’s tutorial no.2”. Esta posición es 403000. Pero en el source se usa la etiqueta MsgCaption. La macro addr en este caso no hizo nada porque 403000 es una posición de memoria absoluta. Cuando se usan direcciones relativas como esp + 123h o ebx + edi, addr convierte estas posiciones relativas en absolutas con el uso de la instrucción LEA (esta será motivo de otra entrada)


debug

En esta captura de pantalla se ve el segmento de memoria en ascii y hexadecimal. Si conocen de memoria el código ASCII pueden leer las cadenas directamente. Noten el cero binario con el que terminan y la posición de memoria a la que hacen referencia las funciones que usan texto.

00401007 |. 68 19304000 PUSH msgbox.00403019

Esta linea hace lo mismo que la anterior pero manda al stack la posición de la cadena ascii que dice: “Win32 Assembly is Great!”

0040100C |. 6A 00 PUSH 0 ; |hOwner = NULL

En esta linea se empuja otro cero al stack que le dice a MessageBox que la ventana no tiene padres, pues hOwner indica el handler del Pwner Owner o dueño de la ventana. Este cero indica que aparece en el centro del escritorio. Pero eso ya es cosa de la API de Windows


0040100E |. E8 0D000000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA

Aquí se llama a MessageBoxA. Nótese la A mayúscula que va al final. Para Windows hay diferencias entre funciones ascii y unicode. En este caso llamamos a MessageBox versión ASCII. Otra de las cosas importantes que nos ocultan las macros.

00401013 |. 6A 00 PUSH 0 ; /ExitCode = 0

Esta ya es parte del segundo Invoke, aquí se empuja un cero al stack que es el único parámetro de la función ExitProcess que termina el programa. La constante NULL se transforma en cero, parece que NULL es mas sencillo de leer en un código que el propio cero.

0040101A .-FF25 00204000 JMP DWORD PTR DS:[<&KERNEL32.ExitProcess>; kernel32.ExitProcess

Finalmente se llama a la función API de windows ExitProcess y se termina el programa. La linea que sigue pertenece un sistema de llamado de funciones conocido como JUMP TABLE o trampolín. Que permite que un programa pueda llamar funciones externas y cambiantes sin necesidad de reprogramación. En esta tabla se colocan los verdaderos llamados a función y cuando hacemos un CALL para ejecutar una función API lo que en realidad hacemos es saltar a esta tabla. Este es un mecanismo interesante pero no hay urgencia de verlo porque FASM no lo usa. De hecho, este programa hace exactamente lo mismo que el PEDEMO.ASM que viene en los ejemplos del fasm y en este mismo blog en la nota llamada “¡Al fin un código!”

Hasta ahora, apenas hemos entendido lo que realmente ocurre tras esos inocentes invokes, y ya tienen una idea de lo peligrosas que pueden ser las macros para los principiantes, es mejor que las guarden para cuando tengan artritis y no puedan teclear sus programas los suficientemente rápido. O por lo menos hasta que realmente sepan lo que están haciendo y lo confirmen con el depurador de códigos en la primera oportunidad.

Para recapitular, hoy aprendimos todo esto:

1.- Se necesita un depurador para entender los tutoriales de Iczelion.

2.- Una macro puede desenrollarse en muchísimas instrucciones de Ensamblador

3.- Los argumentos de una función se introducen por el STACK en orden inverso a como quedan dentro del stack frame.

4.- Las constantes como MB_OK, hOwner, etc. Se convierten en simples números enteros casi siempre de 32 bits

5.- La macro ADDR convierte una referencia a memoria de tipo relativa a una posición de memoria absoluta usando la instrucción LEA.

6.- En este caso se usa una JUMP TABLE para hacer las llamadas a la API de Windows, pero FASM no trabaja asi.

Por ahora me regreso a donde estaba, estoy desarrollando una trampa para lamers muy divertida, aunque va a estar lista para la siguiente temporada de caza y esta es hasta el final del otoño. Por ahora traten de leer y analizar los tutoriales de Iczelion ustedes solos a ver que mas se encuentran, recuerden que hay un link a la web de Iczelion a la derecha de este blog.

junio 9, 2009 Publicado por | Uncategorized | , , , , , | 15 comentarios

Seguir

Recibe cada nueva publicación en tu buzón de correo electrónico.

Únete a otros 42 seguidores