Programa 18: Contar frecuencia de caracteres en una cadena en Asembly ARM64 - Alejandro Suarez
by pepinisillo
GNU/Linux
•
xterm
•
bash
84 views
📌 Demostración: Contar frecuencia de caracteres en una cadena en ARM64 Assembly
💻 Lenguajes de Interfaz en TECNM Campus ITT
👨💻 Autor: Alejandro Suarez Sandoval
📅 Fecha: 2025/04/08
🎯 Descripción
Este programa cuenta la frecuencia de cada carácter de una cadena dada.
La implementación se realiza en:
✅ Assembly ARM64 para RaspbianOS en Raspberry Pi
🔧 Compilación en Raspberry Pi (ARM64)
as frecuencia_caracter.s -o frecuencia_caracter.o
ld frecuencia_caracter.o -o frecuencia_caracter
▶️ Ejecución
./frecuencia_caracter
👀 Código fuente
🔗 Código fuente en Gist: Programa 18 Contador de Frecuencia de Caracteres 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/08 |
| • Descripción: Programa que cuenta la frecuencia de caracteres en |
| una cadena en Rust y Assembly ARM64 para RaspbianOS. |
| • Demostración: |
| https://asciinema.org/a/713375 |
| • Compilación (Raspberry Pi ARM64): |
| as frecuencia_caracter.s -o frecuencia_caracter.o |
| ld frecuencia_caracter.o -o frecuencia_caracter |
| • Ejecución: ./frecuencia_caracter |
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂ ⠂⠄⠄⠂☆
═════════•°• Demostración Código en lenguaje Rust •°•═══════
use std::collections::HashMap;
fn main() {
let input_text = "A mi me gusta mucho jugar overwatch y escuchar a the boyz.\n";
println!("Analizando frecuencia de caracteres en el texto:");
println!("{}", input_text);
let mut char_counts = HashMap::new();
for c in input_text.chars() {
if c.is_ascii() {
*char_counts.entry(c).or_insert(0) += 1;
}
}
println!("\nResultados (mostrando caracteres con frecuencia > 0):");
let mut sorted_chars: Vec<_> = char_counts.keys().collect();
sorted_chars.sort();
for &c in sorted_chars {
let count = char_counts.get(&c).unwrap();
println!("Carácter '{}': {}", c, count);
}
}
════════════════════•°• ☆ •°•══════════════════════════════
/*
/* ⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂ ⠂⠄⠄⠂☆
═════════════•°• Código en ARM64 Assembly •°•═════════════ */
.global _start // Punto de entrada global
.data
// Texto para analizar
input_text:
.ascii "A mi me gusta mucho jugar overwatch y escuchar a the boyz.\n"
text_length = . - input_text
// Mensajes
msg_intro:
.ascii "Analizando frecuencia de caracteres en el texto:\n"
msg_intro_len = . - msg_intro
msg_results:
.ascii "\nResultados (mostrando caracteres con frecuencia > 0):\n"
msg_results_len = . - msg_results
msg_char:
.ascii "Carácter '"
msg_char_len = . - msg_char
msg_freq:
.ascii "': "
msg_freq_len = . - msg_freq
newline:
.ascii "\n"
newline_len = . - newline
// Arreglo para contar la frecuencia (128 posiciones para cubrir ASCII)
.align 4 // Asegurar alineamiento adecuado
char_counts:
.skip 128 * 4 // 4 bytes por contador (word)
// Búfer para convertir números a texto
buffer:
.skip 20
.text
_start:
// Mostrar mensaje de introducción
mov x0, #1
adr x1, msg_intro
mov x2, #msg_intro_len
mov x8, #64
svc #0
// Mostrar el texto a analizar
mov x0, #1
adr x1, input_text
mov x2, #text_length
mov x8, #64
svc #0
// Inicializar el array de conteo a cero
adr x19, char_counts // Dirección del array de contadores
mov x20, #0 // Índice para inicialización
init_counts:
cmp x20, #128
b.ge count_chars
// Poner a cero cada contador
str wzr, [x19, x20, lsl #2] // char_counts[i] = 0
add x20, x20, #1
b init_counts
count_chars:
adr x19, input_text // Dirección del texto
mov x20, #0 // Índice para recorrer el texto
adr x21, char_counts // Dirección del array de contadores
count_loop:
// Comprobar si hemos llegado al final del texto
cmp x20, #text_length
b.ge show_results
// Cargar el carácter actual
ldrb w22, [x19, x20] // w22 = carácter actual
// Si es ASCII válido (< 128), incrementar su contador
cmp w22, #128
b.ge next_char
// Incrementar el contador para este carácter
lsl x23, x22, #2 // x23 = índice * 4 (tamaño de word)
ldr w24, [x21, x23] // w24 = valor actual del contador
add w24, w24, #1 // w24 = w24 + 1
str w24, [x21, x23] // Guardar valor incrementado
next_char:
add x20, x20, #1 // Incrementar índice
b count_loop
show_results:
// Mostrar mensaje de resultados
mov x0, #1
adr x1, msg_results
mov x2, #msg_results_len
mov x8, #64
svc #0
// Recorrer el array de contadores para mostrar resultados
mov x20, #32 // Empezar por espacio (ASCII 32)
mov x25, #127 // Terminar en DEL (ASCII 127)
show_loop:
// Verificar si hemos llegado al final
cmp x20, x25
b.gt exit_program
// Obtener la frecuencia para este carácter
lsl x23, x20, #2 // x23 = índice * 4
ldr w24, [x21, x23] // w24 = frecuencia
// Si la frecuencia es 0, pasar al siguiente carácter
cbz w24, next_result
// Mostrar: "Carácter 'X': "
mov x0, #1
adr x1, msg_char
mov x2, #msg_char_len
mov x8, #64
svc #0
// Reservar espacio en la pila y alinear
sub sp, sp, #16
// Guardar el carácter en la pila
strb w20, [sp]
// Mostrar el carácter
mov x0, #1
mov x1, sp // Dirección del carácter en la pila
mov x2, #1 // Longitud: 1 carácter
mov x8, #64
svc #0
// Restaurar pila
add sp, sp, #16
// Mostrar ": "
mov x0, #1
adr x1, msg_freq
mov x2, #msg_freq_len
mov x8, #64
svc #0
// Mostrar la frecuencia
mov x25, x24 // Copiar frecuencia para convertir
bl num_to_ascii
// Mostrar nueva línea
mov x0, #1
adr x1, newline
mov x2, #newline_len
mov x8, #64
svc #0
// Restaurar límite superior para el bucle
mov x25, #127
next_result:
add x20, x20, #1 // Incrementar al siguiente carácter
b show_loop
exit_program:
// Salir del programa
mov x0, #0
mov x8, #93
svc #0
// Subrutina para convertir número a ASCII y mostrarlo
num_to_ascii:
// Preparar para convertir el número a texto
mov x24, x25 // Copiar número a x24
adr x26, buffer // x26 = puntero al búfer
add x26, x26, #19 // Empezar desde el final del búfer
mov x27, #10 // x27 = base 10 para división
// Caso especial si el número es 0
cbnz x24, convert_loop
mov w28, '0' // Carácter ASCII '0'
strb w28, [x26]
sub x26, x26, #1
b end_convert
convert_loop:
// Comprobar si el número es 0
cbz x24, end_convert
// Obtener el último dígito (número % 10)
udiv x28, x24, x27 // x28 = x24 / 10
msub x29, x28, x27, x24 // x29 = x24 - (x28 * 10) = x24 % 10
// Convertir dígito a ASCII y guardarlo
add w29, w29, #'0' // Convertir a carácter ASCII
strb w29, [x26] // Guardar en búfer
sub x26, x26, #1 // Mover puntero
// Actualizar número para siguiente iteración
mov x24, x28 // Número = número / 10
b convert_loop
end_convert:
// Calcular longitud de la cadena resultante
add x26, x26, #1 // Ajustar puntero al primer dígito
adr x25, buffer
add x25, x25, #20
sub x2, x25, x26 // x2 = longitud de la cadena
// Imprimir número
mov x0, #1 // File descriptor: 1 para stdout
mov x1, x26 // Dirección del búfer
mov x8, #64 // Syscall número 64: write
svc #0 // Llamada al sistema
ret