Para mi reporte sobre mi tarea intro, decidi hacer un programa que muestra el promedio de n cantidad de numeros.
Codigo en C
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
main(){ | |
int num,i,suma=0,cantidad; /*declarar variables*/ | |
printf("Cuantos numero quieres calcular su promedio: "); | |
scanf("%d",&num); | |
for(i=1;i<=num;i++) | |
{ | |
printf("Numero: "); | |
scanf("%d",&cantidad); | |
suma=suma+cantidad;} | |
suma=suma/num; | |
printf("Su promedio es : %d",suma); | |
printf("\n"); | |
return 0; | |
} |
Después se compila mediante la siguiente instrucción para asi obtener el código ensamblador
gcc -S factorial.c
Este es el resultado:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.file "prom.c" ; nombre del archivo | |
.section .rodata ; coloca variables globales en una seccion separada o alamcena la constante en cadena | |
.align 4 ; | |
.LC0: ; etiqueta del segmento de codigo | |
.string "Cuantos numero quieres calcular su promedio: " ; cadena almacenada en este segmento | |
.LC1: ; etiqueta de segmento de codigo | |
.string "%d" ; cadena almacenada en este segmento | |
.LC2: ; etiqueta de segmento de codigo | |
.string "Numero: " ; cadena alamacenada en este segmento | |
.LC3: ; etiqueta de segmento de codigo | |
.string "Su promedio es : %d" ; cadena almacenada | |
.LC4: ;etiqueta de segmento de codigo | |
.string "PAUSE" ; cadena alamacenada | |
.text ; inicia las instrucciones | |
.globl main ; declaracion de main como simbolo global | |
.type main, @function ; main es una funcion | |
main: ; etiqueta de la funcion main(principio) | |
pushl %ebp ; prologo respalda %ebp anterior | |
movl %esp, %ebp ; %esp apunta a %ebp | |
andl $-16, %esp ; alinea la pila | |
subl $48, %esp ; reservamos 48 bytes | |
movl $0, 36(%esp) ; | |
movl $.LC0, %eax ; movemos la cadena de $.LC0 a %eax | |
movl %eax, (%esp) ; mover la direccion de eax al valor al cual apunta %esp (tope de pila) | |
call printf ; manda llamar a printf | |
movl $.LC1, %eax ; movemos la cadena almacenad en $.LC1 a %eax | |
leal 44(%esp), %edx ; movemos el valor de %esp+44 a %edx que es un registro de entrada y salida | |
movl %edx, 4(%esp) ; movemos la direccion de %edx al registro %esp+4 | |
movl %eax, (%esp) ; movemos la direccion de %eax al valor que apunta %esp(tope de pila) | |
movl $1, 40(%esp) ; asignamos 1 a la variable %esp+40('resultado') | |
jmp .L2 ; salto de linea a .L2 | |
.L3: | |
movl $.LC2, %eax ; movemos la cadena de $.LC2 a %eax | |
movl %eax, (%esp) ; mover la direccion de %eax al valor al cual apunta %esp(tope de pila) | |
call printf ; manda llamar a printf | |
movl $.LC1, %eax ; movemos la cadena de $.LC1 a %eax | |
leal 32(%esp), %edx ; movemos el valor de %esp+32 a %edx (registro de entrada y salida) | |
movl %edx, 4(%esp) ; movemos la direccion de %edx al registro %esp+4 | |
movl %eax, (%esp) ; mover la direccion de %eax al valor al que apunta %esp(tope de pila) | |
call __isoc99_scanf ; | |
movl 32(%esp), %eax ; la variable %esp+32 la asignamos al registro %eax | |
addl %eax, 36(%esp) ; asignamos el valor de %eax al registro de %esp+36 | |
addl $1, 40(%esp) ; | |
.L2: | |
movl 44(%esp), %eax ; la variable %esp+44 la asignamos al registro %eax | |
cmpl %eax, 40(%esp) ; al registro de %esp+40 | |
jle .L3 ; salto cuando es menor que .L3 | |
movl 44(%esp), %eax ; la variable %esp+44 la asignamos al registro de %eax | |
movl %eax, 28(%esp) ; Desplazamiento de el valor de %eax al registro de %eax+36 | |
movl 36(%esp), %eax ; la variable %esp+36 la asignamos al registro %eax | |
movl %eax, %edx ; | |
sarl $31, %edx ; | |
idivl 28(%esp) ; | |
movl %eax, 36(%esp) ; el registro %eax lo movemos a la variable %esp+36 | |
movl $.LC3, %eax ; mover la cadena $.LC3 a %eax | |
movl 36(%esp), %edx ; movemos el valor de %esp+36 a %edx (registro de entrada y salida) | |
movl %edx, 4(%esp) ; movemos la direccion de %edx al registro %esp+4 | |
movl %eax, (%esp) ; mover la direccion de %eax al valor al cual apunta %esp(tope de pila) | |
call printf ; llama a printf | |
movl $10, (%esp) ; | |
call putchar ; | |
movl $.LC4, (%esp) ; movemos la cadena $.LC4 a %esp | |
call system ; llamamos a system | |
movl $0, %eax ; | |
leave ; | |
ret ; termina el programa | |
.size main, .-main ; | |
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3" | |
.section .note.GNU-stack,"",@progbits |
Código Optimizado
Optimizar el codigo realiza modificaciones sobre el código intermedio para mejorar la eficiencia en velocidad y tamaño. En mi caso solo quite intrucciones que me parecierón extras como movimientos de memoria innecesarios y el siguiente es el código optimizado.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.file "prom.c" | |
.LC0: | |
.string "Cuantos numero quieres calcular su promedio: " | |
.LC1: | |
.string "%d" | |
.LC2: | |
.string "Numero: " | |
.LC3: | |
.string "Su promedio es : %d" | |
.LC4: | |
.string "PAUSE" | |
.text | |
.globl main | |
.type main, @function | |
main: | |
pushl %ebp | |
movl %esp, %ebp | |
andl $-16, %esp | |
subl $48, %esp | |
movl $0, 36(%esp) | |
movl $.LC0, %eax | |
movl %eax, (%esp) | |
call printf | |
movl $.LC1, %eax | |
leal 44(%esp), %edx | |
movl %edx, 4(%esp) | |
movl $1, 40(%esp) | |
jmp .L2 | |
.L3: | |
movl $.LC2, %eax | |
movl %eax, (%esp) | |
call printf | |
leal 32(%esp), %edx | |
movl %edx, 4(%esp) | |
call __isoc99_scanf | |
movl 32(%esp), %eax | |
addl %eax, 36(%esp) | |
addl $1, 40(%esp) | |
.L2: | |
movl 44(%esp), %eax | |
cmpl %eax, 40(%esp) | |
jle .L3 | |
movl %eax, 28(%esp) | |
movl 36(%esp), %eax | |
movl %eax, %edx | |
sarl $31, %edx | |
idivl 28(%esp) | |
movl %eax, 36(%esp) | |
movl $.LC3, %eax | |
movl %edx, 4(%esp) | |
movl %eax, (%esp) | |
call printf | |
movl $10, (%esp) | |
movl $.LC4, (%esp) | |
movl $0, %eax | |
leave | |
ret | |
.size main, .-main |
Cuando recién compilamos aparecerán muchas líneas, algunas etiquetas como .file, .type, tambien fueron algunas que elimine. Decidi comentarizar las lineas para localizar y entender cada parte de lo que realizaba el programa en este lenguaje.
Aun me faltaron algunas lineas e instrucciones de identificar porque aun no comprendia lo que realizaban pero aqui las explico.
leal 44(%esp), %edx -> Transfiere la dirección de eax para el registro edx
cmpl %eax, 40(%esp) -> Resta fuente de destino y actualiza las banderas
leave -> Libera las variables locales creando por la anterior
idivl -> La instrucción IDIV divide el contenido del 64 bits sin signo "edx":
"eax" (construido mediante la visualización "edx" como los más significativos cuatro
bytes y "eax" (como los menos significativos cuatro bytes) por el valor de operando
especificado. El resultado cociente de la división se almacena en "eax", mientras que
el resto se coloca en "edx".
Después realice la prueba con el código optimizado de la siguiente manera
Referencia :
También tome de base la publicación de mi compañero Juan Carlos para comprender más algunas lineas de código.