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.
Para generar este tipo de código se utiliza el siguiente comando:
This file contains 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> | |
int main(int argc, char** args){ | |
printf("Roberto\n"); | |
return; | |
} |
gcc -S ejemplo.c
Lo cual genera un ejemplo.s.
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.
This file contains 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 "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 |
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.
Lo cual genera:
El cual he optimizado:
This file contains 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> | |
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; | |
} |
This file contains 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 "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 |
This file contains 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
.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 |
Tarea-ensamblador
Referencias.
- Sistemas de tiempo real - Universidad de Extremadura.
- x86 Assembly Programming - University of Science and Technology of China.
- C Internals - Avabodh.
- Stackoverflow - question.
No hay comentarios:
Publicar un comentario