GNU/Linux xterm bash 93 views

📌 Demostración: Calcula una potencia dada de una base dadas por un usuario en ARM64 Assembly

💻 Lenguajes de Interfaz en TECNM Campus ITT
👨‍💻 Autor: Alejandro Suarez Sandoval
📅 Fecha: 2025/04/10

🎯 Descripción

Este programa calcula la potencia de una base, dadas por un usuario mostrando el resultado en la terminal.
La implementación se realiza en:

Assembly ARM64 para RaspbianOS en Raspberry Pi

🔧 Compilación en Raspberry Pi (ARM64)

as potencia.s -o potencia.o  
ld potencia.o -o potencia

▶️ Ejecución

./potencia

👀 Código fuente

🔗 Código fuente en Gist: Programa 36 Potencia de un número, ingresando la base y la potencia por el usuario, mostrando resultado en terminal Código Assembly ARM64 para RaspbianOS

/*
 ______  ____               ____  __ __      
/\  _  \/\  _`\   /'\_/`\  /'___\/\ \\ \     
\ \ \L\ \ \ \L\ \/\      \/\ \__/\ \ \\ \    
 \ \  __ \ \ ,  /\ \ \__\ \ \  _``\ \ \\ \_  
  \ \ \/\ \ \ \\ \\ \ \_/\ \ \ \L\ \ \__ ,__\
   \ \_\ \_\ \_\ \_\ \_\\ \_\ \____/\/_/\_\_/
    \/_/\/_/\/_/\/ /\/_/ \/_/\/___/    \/_/  
                                             
♡ ∩_∩ 
(„• ֊ •„)♡
| ̄U U ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄| 
| • Lenguajes de Interfaz en TECNM Campus ITT                                 |   
| • Autor: Alejandro Suarez Sandoval                                          | 
| • Fecha: 2025/04/10                                                         | 
| • Descripción: Programa que calcula una potencia dada de una base dada      | 
|   por el usuario en C y Assembly ARM64 para RaspbianOS.                     | 
| • Demostración:                                                             |
|   https://asciinema.org/a/714611                                            |
| • Compilación (Raspberry Pi ARM64):                                         |  
|     as potencia.s -o potencia.o                                             |  
|     ld potencia.o -o potencia                                               |  
| • Ejecución: ./potencia                                                     |  
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄                                       

⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂ ⠂⠄⠄⠂☆
═════════•°• Demostración Código en lenguaje C •°•═══════

#include <stdio.h>
#include <math.h>

int main() {
    double base, exponente;

    printf("Ingrese la base: ");
    scanf("%lf", &base);

    printf("Ingrese el exponente: ");
    scanf("%lf", &exponente);

    double resultado = pow(base, exponente);
    printf("Resultado: %.0f\n", resultado);

    return 0;
}

════════════════════•°• ☆ •°•══════════════════════════════
/*

/* ⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂ ⠂⠄⠄⠂☆
═════════════•°• Código en ARM64 Assembly •°•═════════════ */

// Calculadora de Potencias en ARM64 Assembly para Linux
// Este programa calcula base^exponente, con ambos valores ingresados por el usuario

.global _start

// Garantizar alineamiento para los datos
.align 4
.section .rodata
    prompt_base:     .ascii "Ingrese la base: "
    .equ prompt_base_len, . - prompt_base
    
    prompt_exp:      .ascii "Ingrese el exponente: "
    .equ prompt_exp_len, . - prompt_exp
    
    result_msg:      .ascii "Resultado: "
    .equ result_msg_len, . - result_msg
    
    newline:         .ascii "\n"

.align 4
.section .bss
    .align 4
    buffer:          .space 20      // Buffer para entrada de usuario
    .align 3
    base:            .quad 0        // Almacena la base
    .align 3
    exponent:        .quad 0        // Almacena el exponente
    .align 3
    result:          .quad 0        // Almacena el resultado
    .align 4
    result_buffer:   .space 20      // Buffer para convertir resultado a ASCII

.align 4
.section .text
_start:
    // Mostrar prompt para la base
    mov x0, #1                      // fd = STDOUT
    ldr x1, =prompt_base            // buffer = prompt_base
    mov x2, prompt_base_len         // length 
    mov x8, #64                     // syscall = sys_write
    svc #0

    // Leer la base del usuario
    mov x0, #0                      // fd = STDIN
    ldr x1, =buffer                 // buffer donde almacenar la entrada
    mov x2, #20                     // count = tamaño máximo del buffer
    mov x8, #63                     // syscall = sys_read
    svc #0
    
    // Convertir el string de la base a número
    ldr x1, =buffer
    bl string_to_int                // Convertir entrada a entero
    
    // Guardar la base
    ldr x1, =base
    str x0, [x1]
    
    // Mostrar prompt para el exponente
    mov x0, #1                      // fd = STDOUT
    ldr x1, =prompt_exp             // buffer = prompt_exp
    mov x2, prompt_exp_len          // length
    mov x8, #64                     // syscall = sys_write
    svc #0

    // Leer el exponente del usuario
    mov x0, #0                      // fd = STDIN
    ldr x1, =buffer                 // buffer donde almacenar la entrada
    mov x2, #20                     // count = tamaño máximo del buffer
    mov x8, #63                     // syscall = sys_read
    svc #0
    
    // Convertir el string del exponente a número
    ldr x1, =buffer
    bl string_to_int                // Convertir entrada a entero
    
    // Guardar el exponente
    ldr x1, =exponent
    str x0, [x1]
    
    // Calcular la potencia
    ldr x0, =base
    ldr x0, [x0]                    // x0 = base
    ldr x1, =exponent
    ldr x1, [x1]                    // x1 = exponente
    bl calculate_power              // Calcula base^exponente
    
    // Guardar el resultado
    ldr x1, =result
    str x0, [x1]
    
    // Mostrar mensaje de resultado
    mov x0, #1                      // fd = STDOUT
    ldr x1, =result_msg             // buffer = result_msg
    mov x2, result_msg_len          // length
    mov x8, #64                     // syscall = sys_write
    svc #0
    
    // Convertir resultado a string
    ldr x0, =result
    ldr x0, [x0]                    // x0 = resultado
    ldr x1, =result_buffer          // buffer para string
    bl int_to_string                // Convertir resultado a string
    mov x2, x0                      // x2 = longitud del string
    
    // Mostrar el resultado
    mov x0, #1                      // fd = STDOUT
    ldr x1, =result_buffer          // buffer = result_buffer
    mov x8, #64                     // syscall = sys_write
    svc #0
    
    // Mostrar salto de línea
    mov x0, #1                      // fd = STDOUT
    ldr x1, =newline                // buffer = newline
    mov x2, #1                      // length = 1
    mov x8, #64                     // syscall = sys_write
    svc #0
    
    // Salir del programa
    mov x0, #0                      // código de salida = 0
    mov x8, #93                     // syscall = sys_exit
    svc #0

// Función para calcular base^exponente
// x0 = base, x1 = exponente
// Retorna: x0 = resultado
calculate_power:
    // Guardar registros en la pila
    stp x29, x30, [sp, #-16]!
    stp x19, x20, [sp, #-16]!
    
    // Guardar parámetros en registros no volátiles
    mov x19, x0                     // x19 = base
    mov x20, x1                     // x20 = exponente
    
    // Casos especiales
    cmp x20, #0                     // Si exponente = 0
    b.ne not_zero_exp
    mov x0, #1                      // Retornar 1
    b power_done
    
not_zero_exp:
    mov x0, #1                      // Inicializar resultado = 1
    
power_loop:
    cmp x20, #0                     // Mientras exponente > 0
    b.le power_done
    
    mul x0, x0, x19                 // resultado = resultado * base
    sub x20, x20, #1                // exponente--
    b power_loop
    
power_done:
    // Restaurar registros
    ldp x19, x20, [sp], #16
    ldp x29, x30, [sp], #16
    ret

// Función para convertir string a entero
// x1 = puntero al buffer con el string
// Retorna: x0 = valor entero
string_to_int:
    // Guardar registros
    stp x29, x30, [sp, #-16]!
    
    mov x0, #0                      // Inicializar resultado = 0
    mov x2, #0                      // Índice = 0
    
str_to_int_loop:
    ldrb w3, [x1, x2]               // Cargar byte: w3 = buffer[i]
    
    // Verificar fin de línea o entrada
    cmp w3, #10                     // Si es '\n'
    b.eq str_to_int_done
    cmp w3, #0                      // Si es '\0'
    b.eq str_to_int_done
    
    // Verificar que sea un dígito
    cmp w3, #'0'
    b.lt str_to_int_next            // Si < '0', ignorar
    cmp w3, #'9'
    b.gt str_to_int_next            // Si > '9', ignorar
    
    // Convertir ASCII a dígito
    sub w3, w3, #'0'                // w3 = valor numérico
    
    // result = result * 10 + digit
    mov x4, #10
    mul x0, x0, x4                  // result *= 10
    add x0, x0, x3                  // result += digit
    
str_to_int_next:
    add x2, x2, #1                  // i++
    b str_to_int_loop
    
str_to_int_done:
    // Restaurar registros
    ldp x29, x30, [sp], #16
    ret

// Función para convertir entero a string
// x0 = valor entero a convertir
// x1 = puntero al buffer donde almacenar el string
// Retorna: x0 = longitud del string
int_to_string:
    // Guardar registros
    stp x29, x30, [sp, #-16]!
    stp x19, x20, [sp, #-16]!
    
    mov x19, x0                     // Guardar valor original
    mov x20, x1                     // Guardar puntero al buffer
    
    // Caso especial: valor = 0
    cmp x19, #0
    b.ne not_zero
    
    mov w2, #'0'                    // Carácter '0'
    strb w2, [x20]                  // buffer[0] = '0'
    mov w2, #0                      // Fin de string
    strb w2, [x20, #1]              // buffer[1] = '\0'
    mov x0, #1                      // Longitud = 1
    b int_to_string_done
    
not_zero:
    mov x2, #0                      // Contador de dígitos
    mov x3, x20                     // Puntero temporal al buffer
    
    // Convertir dígitos (en orden inverso)
int_to_string_loop:
    cmp x19, #0
    b.eq int_to_string_reverse
    
    mov x4, #10
    udiv x5, x19, x4                // x5 = valor / 10
    msub x6, x5, x4, x19            // x6 = valor % 10 (remainder)
    
    add w6, w6, #'0'                // Convertir a ASCII
    strb w6, [x3], #1               // Almacenar en buffer y avanzar
    
    mov x19, x5                     // valor = valor / 10
    add x2, x2, #1                  // contador++
    b int_to_string_loop
    
    // Invertir el string (ya que los dígitos están al revés)
int_to_string_reverse:
    mov x0, x2                      // Guardar longitud en x0
    mov w4, #0
    strb w4, [x3]                   // Terminar string con '\0'
    
    // Si longitud <= 1, no necesitamos invertir
    cmp x2, #1
    b.le int_to_string_done
    
    // Preparar para invertir: i=0, j=len-1
    mov x3, #0                      // i = 0
    sub x4, x2, #1                  // j = len - 1
    
reverse_loop:
    cmp x3, x4                      // mientras i < j
    b.ge int_to_string_done
    
    // Intercambiar buffer[i] y buffer[j]
    ldrb w5, [x20, x3]              // w5 = buffer[i]
    ldrb w6, [x20, x4]              // w6 = buffer[j]
    strb w6, [x20, x3]              // buffer[i] = w6
    strb w5, [x20, x4]              // buffer[j] = w5
    
    add x3, x3, #1                  // i++
    sub x4, x4, #1                  // j--
    b reverse_loop
    
int_to_string_done:
    // Restaurar registros
    ldp x19, x20, [sp], #16
    ldp x29, x30, [sp], #16
    ret