lunes, 6 de febrero de 2012

Tarea intro: Lenguaje Ensamblador

Para realizar, el reporte introductorio de la materia de cómputo integrado, sobre lenguaje ensamblador, realicé una serie de pruebas mediante programas utilizando el lenguaje C y generé código ensamblador mediante el compilador, que como lo hemos visto en unidades anteriores, es un lenguaje de programación de bajo nivel que representa simbólicamente códigos máquina ocupándose del trabajo útil.

Para verificar esto, hice diferentes pruebas y ver que pasaba con el código que el compilador generaba en ensamblador. 

Para empezar realicé un código solamente un printf y con un return, para analizarlo.

#include <stdio.h>
int main(int argc, char** args){
printf("Roberto\n");
return;
}
view raw gistfile1.c hosted with ❤ by GitHub
Para generar este tipo de código se utiliza el siguiente comando: 
    gcc -S ejemplo.c      
Lo cual genera un ejemplo.s.
.file "ejemplo.c" #debug
.section .rodata
.LC0:
.string "Roberto"
.text # inicio de una seccion de codigo
.globl main #La etiqueta main es global
.type main, @function #es una funcion
main: #etiqueta del incio del codigo.
pushl %ebp #prologo
movl %esp, %ebp #prologo
andl $-16, %esp #alinea la pila
subl $16, %esp #resta 16 bytes
movl $.LC0, (%esp) # Mueve la cadena a la parte superior de la pila
call puts #llama a puts
leave #epilogo termina la rutina
ret #return
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2"
.section .note.GNU-stack,"",@progbits
view raw gistfile1.asm hosted with ❤ by GitHub
Las líneas que tienen inicio con puntos, como por ejemplo ".file", ".text" ".glob" son pseudo-operaciones los cuales llevan el nombre de directivas de ensamblador, son comandos que indican a el ensamblador cómo va a armar el archivo. 

Las líneas que comienzan con un texto, luego de dos puntos como "main:", son etiquetas

 Las demás son instrucciones ensamblador. En este código podemos diferenciar en las líneas 9 y 10 el prólogo de la función y en la línea 15 el epílogo de la función, los cuales expliqué anteriormente. 

 La línea 16 alinea la pila hasta un límite de 16 bytes, al reducir a cero la parte inferior a 4 bits de %esp, la cual luego de experimentar, me doy cuenta que no es necesaria. 

 La línea 12 resta 16 bytes desde el apuntador de la pila, lo que da como resultado 16 bytes de espacio para main, la cual luego de experimentar, me doy cuenta que reserva memoria, la cual no sabemos cuanto es. 

Para este reporte, decidí analizar un programa en C que te imprime las tablas de multiplicar de 1 al 10.
#include <stdio.h>
int main(int argc, char** args){
multi(2);
return 0;
}
int multi(int x){
int y;
y = 1;
while(y <= 10){
printf("%d * %d = %d\n", x, y, x*y);
y++;
}
return 0;
}
view raw gistfile1.c hosted with ❤ by GitHub
Lo cual genera:
.file "multi.c" #debug (referencia)
.text #inicio de una seccion de codigo
.globl main #la etiqueta main es global
.type main, @function #main es una funcion
main: #etiqueta de inicio de codigo
pushl %ebp #prologo
movl %esp, %ebp #prologo
andl $-16, %esp #alinea la pila
subl $16, %esp #resta 16 bytes lo cual reserva 16 bytes a main
movl $2, (%esp) #Mueve el 2 a la parte superior
call multi #llamada a multi
movl $0, %eax #le pone el 0 (el del return)
leave #epilogo
ret #epilogo
.size main, .-main
.section .rodata
.LC0:
.string "%d * %d = %d\n" #cadena de impresion
.text #inicio de una seccion de codigo
.globl multi #la etiqueta multi es global
.type multi, @function #multi es una funcion
multi: #etiqueta de multi
pushl %ebp #prologo
movl %esp, %ebp #prologo
subl $40, %esp #reserva 40 bytes
movl $1, -12(%ebp) #le asigna a y uno y = 1
jmp .L3 #"salta" a .L3, inicia la instruccion dentro del while
.L4:
movl 8(%ebp), %eax #carga la variable "x" de pila en EAX (registro acumulador)
movl %eax, %edx #mueve el registro acumulador a registro datos(EDX)
imull -12(%ebp), %edx #multiplica al y = (-12(%ebp)) con x
movl $.LC0, %eax #pone en la pila a la cadena
movl %edx, 12(%esp) #mueve la multiplicacion a el registro
movl -12(%ebp), %edx #pone la y en EDX
movl %edx, 8(%esp) #el EDX lo pone en el registro de la pila
movl 8(%ebp), %edx #la variable x lo pone en EDX
movl %edx, 4(%esp) #EDX lo pone en el registro de la pila
movl %eax, (%esp) #prepara la cadena ponendolo en el incio
call printf #llama al printf
addl $1, -12(%ebp) #contador
.L3: #etiqueta que incia la intruccion del while
cmpl $10, -12(%ebp) #instruccion generica que permite comparar
jle .L4 #salta si es menor o igual
movl $0, %eax #le pone el 0 (el del return)
leave #epilogo
ret #epilogo
.size multi, .-multi
.ident "GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2"
.section .note.GNU-stack,"",@progbits
view raw gistfile1.asm hosted with ❤ by GitHub
El cual he optimizado:

.globl main #etiquetas son globales.
.globl multi
main: #etiqueta de inicio de codigo
pushl %ebp #prologo
movl %esp, %ebp
movl $2, (%esp) #Mueve el 2 a la parte superior
call multi #llama a multi
leave #epilogo
ret
multi: #etiqueta de inicio de multi
pushl %ebp #prologo
movl %esp, %ebp
subl $28, %esp #reserva 28 bytes
movl $1, -12(%ebp) #pone un 1 en y
jmp .L3 #salta a condicion while
.L4:
movl 8(%ebp), %edx #Carga la variable x en EAX
imull -12(%ebp), %edx #Multiplica al y con x
movl %edx, 12(%esp) #mueve la multiplicacion a registro
movl -12(%ebp), %edx #pone la y en EDX (datos)
movl %edx, 8(%esp) #lo mueve a registro
movl 8(%ebp), %edx #pone la x en EDX
movl %edx, 4(%esp) #lo mueve a registro
movl $.LC0, (%esp) #mueve la cadena al espacio de memoria de registros
call printf #llama a printf
addl $1, -12(%ebp) #aumenta 1 a y
.L3:
cmpl $10, -12(%ebp) #intruccion generica compara
jle .L4 #salta si es menor o igual
leave #epilogo de multi
ret
.LC0:
.string "%d * %d = %d\n" #etiqueta con string
view raw gistfile1.asm hosted with ❤ by GitHub
Para una mejor compresión de los códigos, adjunto las diapositivas que he puesto en clase, junto con su explicación.
Tarea-ensamblador



Referencias. 

No hay comentarios:

Publicar un comentario