viernes, 27 de abril de 2012

Tarea Intro. Lenguaje Ensamblador

"El lenguaje ensamblador es un lenguaje de programación de bajo nivel para los computadores, microprocesadores, microcontroladores, y otros circuitos integrados programables."


Un programa ensamblador se utiliza para traducir sentencias de lenguaje ensamblador a código máquina de un computador. El ensamblador realiza una traducción desde las sentencias mnemónicas a las instrucciones y datos de máquina.


Mnemónico es un código de operación (lenguaje de máquina) con el que es más facil la programación. Por ejemplo la instrucción MOV, que indica al microprocesador que debe mover datos de un lugar a otro. El microprocesador entiende números binarios por lo que se necesita la traducción del término mnemónico a código objeto.

Ventajas de lenguaje ensamblador
  • Velocidad
  • Eficiencia de tamaño
  • Flexibilidad
Un programa en ensamblador requiere menos memoria, así como menos tiempo de ejecución que un programa escrito en C, C++, Java, etc. 

El lenguaje ensamblador te permite realizar tareas que serían difíciles o hasta imposibles con un lenguaje de alto nivel. 

Conociendo el lenguaje ensamblador se puede entender la arquitectura de la máquina, lo cual ningún lenguaje de alto nivel proporciona. 


Desventajas de lenguaje ensamblador
  • Tiempo de programación
  • Programa fuente grande
  • Peligro de afectar recursos inesperadamente
  • Falta de portabilidad

Realicé un programa en lenguaje C que calcula el área y perímetro de ciertas figuras, utilizando un switch para elegir la figura de la que desea sacar el área y perímetro. Las figuras que puedes seleccionar son cuadrado, rectángulo y círculo. 

#include 

int main ()
{
  int opcion;
  float ladosqrt, baserect, alturarect, radio, area =0, perimetro = 0;
 

  printf("-------------------------------------------------\n");
  printf("Elige una figura: \n");
  printf("1.Cuadrado\t\t\t2.Rectangulo\n");
  printf("3.Circulo\t\t\n");
  printf("----> ");
  scanf("%d", &opcion);


  if (opcion == 1 == 2 == 3)
    {
      printf("El numero que ingresaste no es valido");
    }

  switch(opcion)
    {
    case 1:
      printf("\n\nHaz elegido cuadrado");
      printf("\nDame la medida de un lado: ");
      scanf("%f", &ladosqrt);
      area = ladosqrt*ladosqrt;
      perimetro = ladosqrt*4;
      printf("\nArea: %.2f\t\tPerimetro: %.2f\n", area, perimetro);
      break;

    case 2:
      printf("\n\nHaz elegido rectangulo");
      printf("\nDame la medida de la base: ");
      scanf("%f", &baserect);
      printf("Dame la medida de la altura: ");
      scanf("%f", &alturarect);
      area = baserect*alturarect;
      perimetro = (baserect*2)+(alturarect*2);
      printf("\nArea: %.2f\t\tPerimetro: %.2f\n", area, perimetro);
      break;

    case 3:
      printf("\n\nHaz elegido circulo");
      printf("\nDame el radio: ");
      scanf("%f", &radio);
      area = 3.1416*radio*radio;
      perimetro = 3.1416*radio*2;
      printf("\nArea: %.2f\t\tPerimetro: %.2f\n", area, perimetro);
      break;

    default:
      break;
      
    }


  return 0;
}


Para generar el código  en ensamblador  con gcc se utiliza

gcc -S area.c
Con esto se genera un archivo area.s el cual muestro a continuación. El archivo que se generó cuenta con 186 líneas de código.
 .file "area.c"
 .section .rodata
 .align 4
.LC1:
 .string "-------------------------------------------------"
.LC2:
 .string "Elige una figura: "
.LC3:
 .string "1.Cuadrado\t\t\t2.Rectangulo"
.LC4:
 .string "3.Circulo\t\t"
.LC5:
 .string "----> "
.LC6:
 .string "%d"
.LC7:
 .string "\n\nHaz elegido cuadrado"
.LC8:
 .string "\nDame la medida de un lado: "
.LC9:
 .string "%f"
.LC11:
 .string "\nArea: %.2f\t\tPerimetro: %.2f\n"
.LC12:
 .string "\n\nHaz elegido rectangulo"
.LC13:
 .string "\nDame la medida de la base: "
.LC14:
 .string "Dame la medida de la altura: "
.LC15:
 .string "\n\nHaz elegido circulo"
.LC16:
 .string "\nDame el radio: "
 .text
.globl main
 .type main, @function
main:
 pushl %ebp
 movl %esp, %ebp
 andl $-16, %esp
 subl $80, %esp
 movl $0x00000000, %eax
 movl %eax, 76(%esp)
 movl $0x00000000, %eax
 movl %eax, 72(%esp)
 movl $.LC1, (%esp)
 call puts
 movl $.LC2, (%esp)
 call puts
 movl $.LC3, (%esp)
 call puts
 movl $.LC4, (%esp)
 call puts
 movl $.LC5, %eax
 movl %eax, (%esp)
 call printf
 movl $.LC6, %eax
 leal 68(%esp), %edx
 movl %edx, 4(%esp)
 movl %eax, (%esp)
 call __isoc99_scanf
 movl 68(%esp), %eax
 cmpl $2, %eax
 je .L4
 cmpl $3, %eax
 je .L5
 cmpl $1, %eax
 jne .L7
.L3:
 movl $.LC7, %eax
 movl %eax, (%esp)
 call printf
 movl $.LC8, %eax
 movl %eax, (%esp)
 call printf
 movl $.LC9, %eax
 leal 64(%esp), %edx
 movl %edx, 4(%esp)
 movl %eax, (%esp)
 call __isoc99_scanf
 flds 64(%esp)
 flds 64(%esp)
 fmulp %st, %st(1)
 fstps 76(%esp)
 flds 64(%esp)
 flds .LC10
 fmulp %st, %st(1)
 fstps 72(%esp)
 flds 72(%esp)
 flds 76(%esp)
 fxch %st(1)
 movl $.LC11, %eax
 fstpl 12(%esp)
 fstpl 4(%esp)
 movl %eax, (%esp)
 call printf
 jmp .L6
.L4:
 movl $.LC12, %eax
 movl %eax, (%esp)
 call printf
 movl $.LC13, %eax
 movl %eax, (%esp)
 call printf
 movl $.LC9, %eax
 leal 60(%esp), %edx
 movl %edx, 4(%esp)
 movl %eax, (%esp)
 call __isoc99_scanf
 movl $.LC14, %eax
 movl %eax, (%esp)
 call printf
 movl $.LC9, %eax
 leal 56(%esp), %edx
 movl %edx, 4(%esp)
 movl %eax, (%esp)
 call __isoc99_scanf
 flds 60(%esp)
 flds 56(%esp)
 fmulp %st, %st(1)
 fstps 76(%esp)
 flds 60(%esp)
 fld %st(0)
 faddp %st, %st(1)
 flds 56(%esp)
 fadd %st(0), %st
 faddp %st, %st(1)
 fstps 72(%esp)
 flds 72(%esp)
 flds 76(%esp)
 fxch %st(1)
 movl $.LC11, %eax
 fstpl 12(%esp)
 fstpl 4(%esp)
 movl %eax, (%esp)
 call printf
 jmp .L6
.L5:
 movl $.LC15, %eax
 movl %eax, (%esp)
 call printf
 movl $.LC16, %eax
 movl %eax, (%esp)
 call printf
 movl $.LC9, %eax
 leal 52(%esp), %edx
 movl %edx, 4(%esp)
 movl %eax, (%esp)
 call __isoc99_scanf
 flds 52(%esp)
 fldl .LC17
 fmulp %st, %st(1)
 flds 52(%esp)
 fmulp %st, %st(1)
 fstps 76(%esp)
 flds 52(%esp)
 fldl .LC17
 fmulp %st, %st(1)
 fadd %st(0), %st
 fstps 72(%esp)
 flds 72(%esp)
 flds 76(%esp)
 fxch %st(1)
 movl $.LC11, %eax
 fstpl 12(%esp)
 fstpl 4(%esp)
 movl %eax, (%esp)
 call printf
 jmp .L6
.L7:
 nop
.L6:
 movl $0, %eax
 leave
 ret
 .size main, .-main
 .section .rodata
 .align 4
.LC10:
 .long 1082130432
 .align 8
.LC17:
 .long 776530087
 .long 1074340351
 .ident "GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2"
 .section .note.GNU-stack,"",@progbits


Al crear el archivo en ensamblador, gcc agrega líneas de más que son innecesarias por lo cual hay que optimizar el código de manera que se eliminen esas líneas que no se necesitan para que el programa siga funcionando. Aquí esta el resultado el cual contiene 165 líneas de código. En este programa agregue comentarios para que se entienda más facilmente que es lo que hace cada comando, en las últimas líneas donde ya no agregue comentarios es por que se vuelve a hacer lo mismo que en las anteriores líneas.




.LC1:  #etiquetas
 .string "-------------------------------------------------"  #cadena
.LC2:
 .string "Elige una figura: "
.LC3:
 .string "1.Cuadrado\t\t\t2.Rectangulo"
.LC4:
 .string "3.Circulo\t\t"
.LC5:
 .string "----> "
.LC6:
 .string "%d"
.LC7:
 .string "\n\nHaz elegido cuadrado"
.LC8:
 .string "\nDame la medida de un lado: "
.LC9:
 .string "%f"
.LC11:
 .string "\nArea: %.2f\t\tPerimetro: %.2f\n"
.LC12:
 .string "\n\nHaz elegido rectangulo"
.LC13:
 .string "\nDame la medida de la base: "
.LC14:
 .string "Dame la medida de la altura: "
.LC15:
 .string "\n\nHaz elegido circulo"
.LC16:
 .string "\nDame el radio: "
.globl main
main:
 pushl %ebp            #coloca el registro en la pila
 movl %esp, %ebp       #se mueve %ebp a %esp
 subl $80, %esp        #se reserva espacio en %esp
 movl $.LC1, (%esp)    #se mueve el contenido de la pila
 movl $.LC3, (%esp)
 call puts             #se hace una llamada a la funcion puts
 movl $.LC4, (%esp)  
 call puts
 movl $.LC5, %eax
 movl %eax, (%esp)     #se mueve encima de la pila para imprimir
 call printf           #se llama a la funcion de imprimir
 movl $.LC6, %eax
 leal 68(%esp), %edx   #se actualiza el registro de %edx con la direccion de %esp
 movl %edx, 4(%esp)  
 movl %eax, (%esp)
 call __isoc99_scanf   #se hace una llamada a la funcion para recibir un valor
 movl 68(%esp), %eax
 cmpl $2, %eax         #se comparan los valores
 je .L4                #saltar a .L4 si es igual 
 cmpl $3, %eax         #se comparan los valores
 je .L5                #saltar a .L5 si es igual
 cmpl $1, %eax         #se comparan los valores
 jne .L7               #saltar a .L7 si no es igual
.L3:
 movl $.LC7, %eax      #se mueve %eax a .LC7
 movl %eax, (%esp)     #se mueve encima de la pila para imprimir
 call printf           #llamada a la funcion de imprimir
 movl $.LC8, %eax      #se mueve %eax a .LC8
 movl %eax, (%esp)     #se mueve encima de la pila para imprimir
 call printf           #llamada a la funcion para imprimir
 movl $.LC9, %eax      #se mueve %eax a .LC9
 leal 64(%esp), %edx  
 movl %edx, 4(%esp)
 movl %eax, (%esp)     #se mueve encima de la pila para recibir valor
 call __isoc99_scanf   #llamada a la funcion para recibir un valor
 flds 64(%esp)         #cargar un float de la memoria
 flds 64(%esp)         #cargar un float
 fmulp %st, %st(1)     #multiplicar valores 
 fstps 76(%esp)  
 flds 64(%esp)         #cargar un float 
 flds .LC10   
 fmulp %st, %st(1)     #multiplicar valores
 fstps 72(%esp)
 flds 72(%esp) 
 flds 76(%esp)
 fxch %st(1)           #intercambia el valor de la parte superior de la pila con una de otro registro
 movl $.LC11, %eax
 fstpl 12(%esp)        #quita el valor de la pila FPU y lo pone a mero arriba de la pila del programa usando %esp
 fstpl 4(%esp)
 movl %eax, (%esp)     #se mueve encima de la pila para imprimir
 call printf   #se hace la llamada a la funcion de imprimir
 jmp .L6   #salta a .L6 
.L4:
 movl $.LC12, %eax  
 movl %eax, (%esp)
 call printf
 movl $.LC13, %eax
 movl %eax, (%esp)
 call printf
 movl $.LC9, %eax
 leal 60(%esp), %edx
 movl %edx, 4(%esp)
 movl %eax, (%esp)
 call __isoc99_scanf
 movl $.LC14, %eax
 movl %eax, (%esp)
 call printf
 movl $.LC9, %eax
 leal 56(%esp), %edx
 movl %edx, 4(%esp)
 movl %eax, (%esp)
 call __isoc99_scanf
 flds 60(%esp)
 flds 56(%esp)
 fmulp %st, %st(1)
 fstps 76(%esp)
 flds 60(%esp)
 fld %st(0)
 faddp %st, %st(1)
 flds 56(%esp)
 fadd %st(0), %st        #se suman los valores
 faddp %st, %st(1)
 fstps 72(%esp)
 flds 72(%esp)
 flds 76(%esp)
 fxch %st(1)
 movl $.LC11, %eax
 fstpl 12(%esp)
 fstpl 4(%esp)
 movl %eax, (%esp)
 call printf
 jmp .L6
.L5:
 movl $.LC15, %eax
 movl %eax, (%esp)
 call printf
 movl $.LC16, %eax
 movl %eax, (%esp)
 call printf
 movl $.LC9, %eax
 leal 52(%esp), %edx
 movl %edx, 4(%esp)
 movl %eax, (%esp)
 call __isoc99_scanf
 flds 52(%esp)
 fldl .LC17
 fmulp %st, %st(1)
 flds 52(%esp)
 fmulp %st, %st(1)
 fstps 76(%esp)
 flds 52(%esp)
 fldl .LC17
 fmulp %st, %st(1)
 fadd %st(0), %st
 fstps 72(%esp)
 flds 72(%esp)
 flds 76(%esp)
 fxch %st(1)
 movl $.LC11, %eax
 fstpl 12(%esp)
 fstpl 4(%esp)
 movl %eax, (%esp)
 call printf
 jmp .L6
.L7:
.L6:
 leave                  #termina
 .section .rodata 
.LC10:
 .long 1082130432
.LC17:
 .long 776530087
 .long 1074340351

Ahora se crea el archivo ejecutable con el siguiente comando:
gcc -o area.exe area.s

Después ejecutamos el archivo con el siguiente comando:
./area.exe


Y aquí esta el programa ejecutándose en terminal






Referencias:
Intel Assembler

1 comentario: