Você está na página 1de 6

Sintáxis AT&T(GAS)

Como previo a la tarea introductoria, decidí investigar un poco sobre la sintaxis que utiliza
el GNU Assembler, al pasar el código de C a ensamblador. Esta sintaxis es llamada AT&T
y su ventaja es la compatibilidad con GCC para generare el código ensamblador de un
determinado código en lenguaje C.

Para entender un poco del mismo, empezaré con un simple hola mundo, para comprender
las operaciones con el stack y demás, y luego explicaré como funcionan los ciclos for y
while, además de las condiciones en lenguaje ensamblador usando como ejemplo un
programa sencillo para imprimir números pares.

Información General:

 At&T tiene la forma instruccion orígen, destino. Como por ejemplo movl $1,
%28(esp). La instrucción mueve el número uno, al offset 28 del stack pointer.

 $ es usado para valores literales, % para registros.

 Los sufijos al final de las instrucciones para designar el tamaño del operando que se
manipulará:
o b = byte (8 bit)
o s = short (16 bit entero) o un solo (32-bit punto flotante)
o w = word (16 bit)
o l = long (32 bit entero or 64-bit punto flotante)
o q = quad (64 bit)
o t = ten bytes (80-bit punto flotante)

Hola Mundo
Que mejor forma de empezar en un nuevo lenguaje que con un hola mundo. Primero que
nada lo haremos en C, y lo pasaremos a ensamblador usando el comando gcc -S
nombrearchivo.c. El código en C, y su compilación-ejecución, es el siguiente:

Código:
Compilación y Ejecución:

Como se puede ver, todo funciona correctamente, ahora podemos pasarlo a ensamblador
usando el siguiente comando:

Esto nos generará un archivo ".s"(en mi caso llamado hello.s), el cual podemos abrir para ver
el código equivalente en lenguaje ensamblador. El código del hola mundo en ensamblador es
el siguiente:

La información inicial, es agregada por el compilador gcc al generar el archivo .s, pero esta
no afecta realmente el desempeño de nuestro programa, así que puede ser omitida. Después
podemos encontrar la etiqueta .LC0, que declara un string llamado "Hola Mundo", que será
utilizado más adelante para imprimirlo.
Como etiqueta podemos usar prácticamente cualquier combinación alfanumérica, precedida
por un punto, en este caso LC0 es el nombre por default que agrega el compilador gcc.

Después se declara la etiqueta main como global, para que todos puedan acceder a ella, y
decimos que main es una función. Dentro de la etiqueta main es donde encontramos la parte
importante. Las primeras cuatro líneas son típicas en una surutina, lo que hacen es guardar
espacio para las variables locales.

Después, se mueve el string guardado en la etiqueta .LC0 hacia al inicio del stack, y lo
imprimimos. En este caso gcc cambio la función printf del código en C, por la función puts,
pero la aplicación es similar. Al final, guardamos 0 en eax, como nuestro valor del
return(guardar valores de retorno en eax es algo común). Al final la instrucción "leave" libera
la memoria del stack y retorna el control.

Ciclos y Condiciones
Para entender un poco más sobre ensamblador y los ciclos en este lenguaje, hice un simple
programa que imprime los numeros pares entre el 1 y el 10(para hacerlo corto), y lo pase a
lenguaje ensamblador para ver como se comportan. Los códigos en lenguaje C son los
siguientes;

No tienen nada fuera de lo común, un simple main con una sola variable, un ciclo que se
repite hasta el 10, y una condición que decide si el contador será par o no para poder
imprimirlo si es par. Para pasarlos a ensamblador es el mismo procedimiento que en el hola
mundo.

Los códigos en ensamblador de los códigos pasados, son los siguientes:

while for
Mi primera impresión fue que los códigos eran muy parecidos, excepto que el código del for
tenía una etiqueta más separada, explicaré por qué.

Ciclo For

Como se mencionó anteriormente las líneas que se ven de rojo son etiquetas, básicamente
sirven para controlar el flujo del programa y moverse a ellas a determinadas condiciones y
puntos en el programa. Al inicio de la etiqueta main, igual que en el hola mundo , empezamos
con las mismas primeras cuatro líneas para reservar espacio para las variables locales. En
este caso se reservan 32 bytes en el stack. La siguiente línea del main, mueve el valor 1, a la
posición 28(%esp), esto ya que es un entero, y ocupara 4 bits(32-4 = 28). Si desearamos
agregar alguna otra variable entera, e inicializarla sería simplemente agregar una línea como
esta: movl $0, 24(%esp), restando cada vez 4 por entero.

Después se usa la instrucción jump para brincar desde main, a la etiqueta .L2, donde lo
primero que hacemos es comparar si el valor guardado en la posición 28(%esp), que sería
nuestra variable "i", es menor o igual a 10, si esto es así se manda el control del flujo a .L4.

Aqui se harán los contenidos del for, donde inicialmente movemos el valor de 28(%esp) a
eax, y le aplicamos una operación AND, al este valor, y el valor 1. Esto es usado para saber
si el número es par o impar, luego comparamos eax, consigo mismo, esto es para saber si es
0 o no, si no es 0, es decir no es par, se dará un brinco a .L3, donde se le sumará uno al valor
guardado en la posición 28(%esp). Si es igual a 0, se continua en .L4, omitiendo la instrucción
jne.

Las siguientes líneas son usadas para imprimir el número par. Primero, movemos el
contenido de la etiqueta .LC0(el string "%d\n") hacia eax, después movemos el valor
guardado en la posición 28(%esp) a edx. Movemos edx(ahora la variable "i"), a la posición
4(%esp), y después eax(el string) a la posición %esp. Esto podemos visualizarlo como
posiciones en memoria conjuntas, ya que ponemos el string al inicio del stack, y justo después
colocamos la variable que el string va a imprimir. Entonces llamamos printf para imprimir
esos valores.

Ciclo While

En el ciclo while, se realiza prácticamente lo mismo, pero a diferencia del for, no agrega una
etiqueta para realizar la suma al contador, y el brinco que se hace al comparar el número de
repeticiones y el contador, se hace con jne, lo que significa que brinca cuando no sea igual a
10.

Al terminar, disminuyendo algunas lineas de código para el for, quite una etiqueta, y ajuste
algunas lineas para que funcionara igualmente, y se redució un poco el código. Para terminar
como el siguiente:

Comparaciones

De esta manera, el código del while y del for es prácticamente lo mismo, la única diferencia
es la condición para brincar a la etiqueta que se repetirá(L3).

 En el for, el brinco es jle, que significa, que se hará un brinco, si la condición anterior
es menor o igual. En el código esto significa que si el valor del registro "28(%esp)"
(que sería nuestra variable "i"), es menor o igual a 10, será mandado a la etiqueta L3.

 En el while, el brinco es jn, que significa que se hará un brinco cuando la condición
no sea igual. En el código esto significa que si el valor del registro "28(%esp)", no es
igual a 10, brincará a la etiqueta L3.