"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.
#includeint 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.cCon 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