sábado, 4 de febrero de 2012

C to assembler


Bueno en esta entrada les mostrare un código convertido de lenguaje C a lenguaje ensamblador y que significan las lineas de código .
Primero se hizo la prueba con un hola mundo y después con un programa que tuviera algunas sentencias como un if o un for para observar los cambios que ocurren y que podría quitarse de el código para optimizarlo.
Empezemos un programa sencillo como un hola mundo  que en c seria asi


#include


int main(void){
printf("Hola Mundo");
}


Genera un codigo en lenguaje ensamblador asi :



.file "hola.c"
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
        LC0:
.ascii "Hola Mundo\0"
.text
        .globl _main
.def _main; .scl 2; .type 32; .endef
         _main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
andl $-16, %esp
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
call __alloca
call ___main
movl $LC0, (%esp)
call _printf
movl $0, %eax
leave
ret
.def _printf; .scl 2; .type 32; .endef

Se puede observar  varias sentencias que quedarían mas o menos claras como .file " hola.c" que seria el nombre de el archivo , bueno ahora veamos un código sencillo pero con un poco mas de cosas como por ejemplo condiciones  y alguna función . 

#include
#define PI 3.1416

int main() 

       { 
        Cabecera();
SeleccionDatos();
}
Cabecera(){
      printf("\t\t===============================\n");
    printf("\t\t| AREAS DE FIGURAS GEOMETRICAS|\n");
       printf("\t\t===============================\n\n");

        printf("Ingresa por favor la opcion que desees ->\n\n\n");
        printf("\t1.- Cuadrado\n");
        printf("\t2.- Circulo\n");
           
        }

SeleccionDatos(){
    int opcion = 0;
    int areaCuadrado = 0;
    int lado = 0;
    int radio=0;
    float area = 0.0;
    
    scanf("%d",&opcion);  
    
    if(opcion >= 3){
              printf("Por favor ingresa un numero correcto ->");
              scanf("%d", &opcion);
              }
    
    switch(opcion){
case 1: 
     printf("Elegiste cuadrado\n");      
         printf("Ingresa el tamano de el lado del cuadrado -> \n\n");           
         scanf("%d", &lado);
         areaCuadrado = lado*lado;    
         printf("El area de el cuadrado es %d ", areaCuadrado);
     break;
    case 2:
         printf("Elegiste circulo\n");      
         printf("Ingresa el tamano de el radio-> \n\n"); 
         scanf("%d", &radio);
         while(radio < 1){
           printf("Porfavor ingresa un numero mayor a 0 ->");
           scanf("%d", &radio);
         }
            area = (PI *(radio*radio))/2;   
            printf( "El area de circulo de radio %d es -> %f", radio, area);
         break;
     }
    
    getche();
    getche();
    return 0;
    }

Bueno vemos que es un programa que contiene un while un switch un if asi como los case ademas de 2 funciones llamadas Cabecera()  y SeleccionDatos() mandadas llamar en el main, ahora observemos el codigo ensamblador generado 

  .file "ctoassembler.c"                                                     // indica el nombre de el archivo y su extensión 
.def ___main; .scl 2; .type 32; .endef
.text                                                                                  //Comienza el código 
  .globl _main                                                                    // define main como global
.def _main; .scl 2; .type 32; .endef
        _main:
pushl %ebp                                          // instrucciones de pila permiten el uso de la pila para almacenar y extraer datos
movl %esp, %ebp       // Instrucciones de transferencia Son utilizadas para mover los contenidos de los operandos. 
subl $8, %esp          // Proposito Sustraccion  y su sintaxis es sub destino, fuente Resta el operando fuente del destino.                        
                                  //$8 = $8- %esp
andl $-16, %esp  // Realiza la conjunción de los operandos bit por bit. Sintaxis: AND destino, fuente operación "y" 
                                         lógica de los dos operandos:
movl $0, %eax                 
addl $15, %eax   //Adición de los operandos.Sintaxis: ADD destino, fuente Suma los dos operandos y guarda el
                                    // resultado en el operando destino.      
                                     // $15 = $15 + %eax                                        
addl $15, %eax   
shrl $4, %eax
sall $4, %eax
movl %eax, -4(%ebp)                               //almacena -4(%ebp) en %eax 
movl -4(%ebp), %eax
call __alloca
call ___main
call _Cabecera
call _SeleccionDatos // Los Call son llamadas a subrutinas ejemplo llamada a SeleccionDatos()
leave
ret                                  // Termina el programa
.section .rdata,"dr"
.align 4
LC0:
.ascii "\11\11===============================\12\0"
.align 4
LC1:
.ascii "\11\11| AREAS DE FIGURAS GEOMETRICAS|\12\0"
.align 4
LC2:
.ascii "\11\11===============================\12\12\0"
.align 4
LC3:
.ascii "Ingresa por favor la opcion que desees ->\12\12\12\0"
LC4:
.ascii "\11"
.ascii "1.- Cuadrado\12\0"
LC5:
.ascii "\11"
.ascii "2.- Circulo\12\0"
.text
.globl _Cabecera
.def _Cabecera; .scl 2; .type 32; .endef
_Cabecera:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl $LC0, (%esp)
call _printf                    // Todos los CALL son llamadas a subrutinas 
movl $LC1, (%esp)
call _printf
movl $LC2, (%esp)
call _printf
movl $LC3, (%esp)
call _printf
movl $LC4, (%esp)
call _printf
movl $LC5, (%esp)
call _printf
leave
ret
.section .rdata,"dr"
LC7:
.ascii "%d\0"
.align 4
LC8:
.ascii "Por favor ingresa un numero correcot ->\0"
LC9:
.ascii "Elegiste cuadrado\12\0"
.align 4
LC10:
.ascii "Ingresa el tamano de el lado del cuadrado -> \12\12\0"
LC11:
.ascii "El area de el cuadrado es %d \0"
LC12:
.ascii "Elegiste circulo\12\0"
.align 4
LC13:
.ascii "Ingresa el tamano de el radio-> \12\12\0"
.align 4
LC14:
.ascii "Porfavor ingresa un numero mayor a 0 ->\0"
.align 4
LC17:
.ascii "El area de circulo de radio %d es -> %f\0"
.align 8
LC15:
.long 776530087
.long 1074340351
.align 8
LC16:
.long 0
.long 1073741824
.text
.globl _SeleccionDatos
.def _SeleccionDatos; .scl 2; .type 32; .endef
_SeleccionDatos:
pushl %ebp
movl %esp, %ebp
subl $56, %esp
movl $0, -4(%ebp)
movl $0, -8(%ebp)
movl $0, -12(%ebp)
movl $0, -16(%ebp)
movl $0x00000000, %eax
movl %eax, -20(%ebp)
leal -4(%ebp), %eax
movl %eax, 4(%esp)
movl $LC7, (%esp)
call _scanf
cmpl $2, -4(%ebp)
jle L4        //Propósito: salto condicional, se toma en cuenta el signo.  Sintaxis: JLE etiqueta Salta si es
                      menor o igual o salta si no es más grande
movl $LC8, (%esp)
call _printf 
leal -4(%ebp), %eax
movl %eax, 4(%esp)
movl $LC7, (%esp)
call _scanf
L4:
movl -4(%ebp), %eax
movl %eax, -28(%ebp)
cmpl $1, -28(%ebp)
je L6       //salto condicional Sintaxis: JE etiqueta Salta si es igual o salta si es cero. El salto se realiza si ZF está                                                                         
                     activada
cmpl     $2, -28(%ebp) // Propósito: Comparar los operandos. Sintaxis: CMP destino, fuente. Esta instrucción resta el     //operando fuente al operando destino pero sin que éste almacene el resultado de la operación, solo se afecta el         //estado de las banderas
je L7
jmp L5        // Propósito: Salto incondicional Sintaxis: JMP destino. Esta instrucción se utiliza para desviar el flujo de  
//un programa sin tomar en cuenta las condiciones actuales de las banderas ni de los datos.
L6:
movl $LC9, (%esp)
call _printf
movl $LC10, (%esp)
call _printf
leal -12(%ebp), %eax
movl %eax, 4(%esp)
movl $LC7, (%esp)
call _scanf
movl -12(%ebp), %eax
imull -12(%ebp), %eax
movl %eax, -8(%ebp)
movl -8(%ebp), %eax
movl %eax, 4(%esp)
movl $LC11, (%esp)
call _printf
jmp L5
L7:
movl $LC12, (%esp)
call _printf
movl $LC13, (%esp)
call _printf
leal -16(%ebp), %eax
movl %eax, 4(%esp)
movl $LC7, (%esp)
call _scanf
L8:
cmpl $0, -16(%ebp)
jg L9            // Propósito: salto condicional, se toma en cuenta el signo. Sintaxis: JG etiqueta. Salta si es más grande o salta si no es menor o igual. El salto ocurre si ZF = 0 u OF = SF.
movl $LC14, (%esp)
call _printf
leal -16(%ebp), %eax 
movl %eax, 4(%esp)
movl $LC7, (%esp)
call _scanf
jmp L8
L9:
movl -16(%ebp), %eax
imull -16(%ebp), %eax // Propósito: Multiplicación de dos enteros con signo.Sintaxis:IMUL fuente , toma en //cuenta los signos de las cantidades que se multiplican. 
pushl %eax
fildl (%esp)
leal 4(%esp), %esp
fldl LC15
fmulp %st, %st(1)
fldl LC16
fdivrp %st, %st(1)
fstps -20(%ebp)
flds -20(%ebp)
fstpl 8(%esp)
movl -16(%ebp), %eax
movl %eax, 4(%esp)
movl $LC17, (%esp)
call _printf
L5:
call _getche
call _getche
movl $0, %eax
leave
ret
.def _getche; .scl 2; .type 32; .endef
.def _scanf; .scl 2; .type 32; .endef
.def _printf; .scl 2; .type 32; .endef
.def _SeleccionDatos; .scl 2; .type 32; .endef
.def _Cabecera; .scl 2; .type 32; .endef

Podemos observar que se hace mucho mas grande entonces arriba con comentarios se podrá apreciar el significado . 

1 comentario: