Programación en Lenguaje Ensamblador

-El Verdadero Lenguaje de las Máquinas-

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.

Anuncios

diciembre 25, 2009 - Posted by | Uncategorized | , , , , , ,

1 comentario »

  1. Re loco programar con ASM, yo estoy aprendiendo para escribir shellcodes para los exploit je.

    Comentario por jinny | enero 24, 2011 | Responder


Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: