Programación en Lenguaje Ensamblador

-El Verdadero Lenguaje de las Máquinas-

Arreglos y Estructuras en Ensamblador

–Como darle forma a los datos en la memoria–

arreglo y estructura

Uno de los temas mas revoltosos a la hora de programar en ensamblador es el de las estructuras de datos. Para los que son lo suficientemente afortunados y no han programado en otros lenguajes, las estructuras de datos son secciones lineales dentro de la memoria que representan un conjunto de datos. Para explicarlo de un modo sencillo es como el mapa de un pais que se divide en estados y estos a su vez en ciudades. Las ciudades y los estados pueden tener cualquier forma y tamaño pero en la realidad no son mas que una misma masa de tierra. La división de esa masa está solo en las fronteras fijadas por la gente y los gobiernos.

Una estructura de datos a nivel ensamblador es exactamente igual. Se trata de una zona continua de la memoria que contiene datos. Y al igual que el mapa no hay una verdadera división que defina realmente donde comienza uno y termina otro. Ni siquiera el programa sabe realmente donde se marcan estas divisiones porque todo esto es determinado por el compilador.

El caso de los arreglos, que por cierto no existe en español ninguna palabra que sea traducción directa de ARRAY se trata de un tipo especial de estructura donde todos los elementos son del mismo tipo y ancho. Y aunque esto es cierto desde el punto de vista de alguien que programa en lenguajes normales en el caso del ensamblador los arrays son especialente amistosos y es posible aplicarles unas optimizaciones tremendas que sería imposible aplicarle a una estructura de datos tradicional.

Ahora veamos. ¿Qué ventajas nos otorgan las estructuras? Estructurar datos nos sirve para acomodar toda la información de alguna entidad de manera entendible para el usuario. Pero como veremos mas adelante esto no necesariamente es lo mejor para la computadora. Por ejemplo, si los datos de un sprite son sus coordenadas X,Y, ancho y altura podemos crear una estructura llamada SPRITE que contenga cuatro valores enteros consecutivos donde cada uno de estos representa alguno de los cuatro datos anteriores. En este caso los 4 valores son de tipo entero y ancho de 32 bits pero en el caso de las estructuras la regla es tener datos de diferentes tipos y anchos. Esto es especialmente peligroso cuando se manejan cadenas de texto, pues estas pueden tener longitudes impredecibles pero eso se arregla guardandolas todas en una sección específica (y muy grande) de la memoria y dejando en la estructura solamente la posición de memoria donde esta cadena inicia.

Ahora viene lo interesante: ¿Como manejamos estructuras en ensamblador? La mayoría de los ensambladores con capacidad de manejar macros cuentan con una que se encarga de manejar estructuras. Como esto es diferente en cada compilador y en sus manuales hay mucha información sobre como invocarlas no voy a profundizar demasiado en el tema. Pero normalmente se trata de una etiqueta a la que le siguen un par de llaves { } entre las que se insertan los nombres y tipos de datos de los elementos de la estrucutura. A partir de ese punto la definición de estructura nos permite declarar instancias de esta de la misma manera que lo hacemos con los tipos de datos de siempre. Cuando queremos hacer referencia a un elemento de la estructura solo escribimos el nombre de esa instancia seguido de un punto y el nombre del elemento de esta y lo manejamos como si fuera una variable cualquiera. Intermanente el sistema de macros convierte estas complicadas construcciones en simples valores enteros que representan localidades de memoria. Y todo se reduce a simples operaciones con valores inmediatos y desplazamientos directos.

Veamos un ejemplo ‘sencillo’ de esto, supongamos que queremos declarar una estructura de datos llamada SPRITE para manejar los gráficos del juego. Es una estructura que consta de 5 enteros de 32 bits: La posición de memoria donde se almacenan los pixeles, el ancho, la altura, coordenada X y coordenada Y donde va a aparecer. En el caso del FASM existe una macro llamada STRUCT que si la usáramos este proceso sería mas o menos así:

struct SPRITE
{
.puntero_a_imagen    dd    ?
.ancho            dd    ?
.altura            dd    ?
.coordenada_x        dd    ?
.coordenada_y        dd    ?
}

Si luego quisiéramos declarar un sprite que por ejemplo se llamara Monstruo haríamos esto

Monstruo SPRITE

Y por ejemplo para asignar a este monstruo una determinada imagen previamente cargada en la memoria solo tendríamos que escribir en el primer elemento de la estructura la posición de esa imagen.

Mov eax, [sprite_monstruo]
mov [monstruo.puntero_a_imagen], eax

El sistema de macros convertiría la última instrucción en algo como esto:

mov [401e8c], eax

Bueno, hasta ahora pareciera que esta macro es la solución al problema de las estructuras en ensamblador. Sin embargo el problema es cuando necesitamos muchas estructuras del mismo tipo. Pues al menos hasta la última vez que revisé la documentación del FASM no había una macro capaz de manejar arreglos de estructuras. Este caso es muy necesario en juegos como los de estrategia que en un momento dado pueden tener a mil unidades en una misma batalla. Ahora, aunque fuera posible tener una macro o una funcionalidad que permitiera manejar en ensamblador los arreglos de estructuras como se hace en lenguajes como C/C++ esto no sería lo que se dice eficiente y a nivel interno requeriría de muchas instrucciones adicionales del procesador tan solo para poder leer y escribir todas estas estrucutras. La solución a este problema va a venir en una nota posterior, por ahora esta nota y la que siguen se van a concentrar en los males que presenta el manejo ‘intuitivo’ de estructuras a la hora de programar en ensamblador.

Los peligros de las estructuras en ensamblador.

En cierto manual de ensamblador leí que el manejo de estructuras de datos era lo mejor que le había pasado a los programadores desde que se implementó el uso de mnemónicos en lugar de escribir directo en lenguaje máquina. Esto puede ser cierto en el caso de estrucutras individuales y aisladas pero en el caso de tener muchas miles de estructuras (que es lo que siempre sucede) no solo se complica la programación sino que disminuye mucho el rendimiento del sistema. Para empezar el compilador convierte las operaciones con macros de estructuras en desplazamientos inmediatos. En el caso de los procesadores de Intel esto genera códigos de operación muy largos que requieren de mayor cantidad de ciclos de reloj para traducir las direcciones inmediatas de memoria incluidas en el propio OpCode. Además existen ciertos procesadores que no admiten valores inmediatos dentro de los propios códigos de operación y la solución a esto casi siempre implica el uso de ‘literal pools’ que son secciones de memoria que almacenan constantes en el propio código y harían crecer el código fuente de manera inecesaria. Otra desventaja de abusar de estrucutras cuyos elementos no son del mismo ancho es que al hacer esto se desalinean los elementos respecto a la posición de memoria y para que el CPU pueda leer un valor a la máxima velocidad posible este debe de estar en una localidad de memoria cuya posición sea divisible entre su longitud. Por ejemplo un valor de 32 bits debe de estar en posiciones que terminen en 0, 4, 8, C en hexadecimal. El tema de la alineación de memoria o Memory Alignment merece una nota completa. Otra desventaja con manejar demasiadas estructuras es el de no poder acceder al mismo elemento común en todas ellas, cosa que sucede normalmente en programas que tienen que actualizar un dato determinado en cientas, miles o hasta millones de estructuras. En fin, podría estar escribiendo por un buen rato sobre los males de los arreglos de estructuras en ASM pero eso mejor lo dejo para la nota que sigue.

Anuncios

agosto 28, 2010 - Posted by | Uncategorized | ,

2 comentarios »

  1. Todo un as en el paint

    Comentario por b1ackpig | septiembre 3, 2010 | Responder

    • Espero que no te haya faltado una “s” en eso de AS.

      Ahora voy a tratar de hacer esos dibujitos como en los tiempos de las computadoras con monitores EGA. La verdad es que eso que ahora llaman pixelart me parece un insulto al esfuerzo hecho por los grafistas de la decada de los ochenta.

      Comentario por asm86 | septiembre 3, 2010 | 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: