Llegamos a la última frontera en larebelion.com. Si has sobrevivido a la programación en C, a la gestión de memoria y a los Sockets, es hora de hablar directamente con el procesador. Bienvenidos a Arquitectura de Computadores.
En las universidades españolas, normalmente se enseña Ensamblador usando MIPS (con simuladores como MARS o SPIM) o x86 (usando NASM en Linux). En este post, hemos recopilado 10 ejercicios de exámenes de ambos mundos para que domines los registros, los saltos condicionales y las llamadas al sistema (syscalls).
1. MIPS: Suma de dos enteros (UPM)
Enunciado: Escribe un programa en ensamblador MIPS que cargue dos números enteros en registros, los sume y guarde el resultado en un tercer registro.
.globl main
main:
li $t0, 15 # Cargar el valor inmediato 15 en $t0
li $t1, 20 # Cargar el valor inmediato 20 en $t1
add $t2, $t0, $t1 # $t2 = $t0 + $t1 (15 + 20 = 35)
# Terminar el programa limpiamente
li $v0, 10 # Syscall 10 = exit
syscall
2. x86 (NASM): Imprimir "Hola Mundo" (UPC)
Enunciado: Crea el clásico "Hola Mundo" en ensamblador x86 de 32 bits para Linux, usando interrupciones de sistema (int 0x80).
msg db 'Hola Mundo', 0xA ; Mensaje con salto de línea
len equ $ - msg ; Longitud del mensaje
section .text
global _start
_start:
mov eax, 4 ; Syscall 4 = sys_write
mov ebx, 1 ; File descriptor 1 = stdout
mov ecx, msg ; Puntero a la cadena
mov edx, len ; Tamaño de la cadena
int 0x80 ; Llamada al kernel de Linux
mov eax, 1 ; Syscall 1 = sys_exit
int 0x80
3. MIPS: Condicional IF-ELSE (UCM)
Enunciado: Dado un valor en $t0, si es mayor o igual a 5, almacena un 1 en $t1 (aprobado), si no, almacena un 0 (suspenso).
main:
li $t0, 4 # Nota del alumno
bge $t0, 5, aprobado # Branch if Greater or Equal to 5
suspenso:
li $t1, 0 # Cargar 0 (suspenso)
j fin # Salto incondicional a 'fin'
aprobado:
li $t1, 1 # Cargar 1 (aprobado)
fin:
li $v0, 10
syscall
4. x86 (NASM): Bucle FOR simple (UGR)
Enunciado: Escribe un bucle en ensamblador x86 que simule un for(int i=5; i>0; i--) utilizando la instrucción loop y el registro ecx.
global _start
_start:
mov ecx, 5 ; ecx es el contador del bucle
mov eax, 0 ; eax será el acumulador
mi_bucle:
add eax, 1 ; Operación interna del bucle
loop mi_bucle ; Decrementa ecx y salta si ecx != 0
mov eax, 1
int 0x80
5. MIPS: Recorrer un Array (US)
Enunciado: Tienes un array de 3 enteros en memoria. Escribe el código MIPS para sumar todos sus elementos y guardar el total en $t2.
array: .word 10, 20, 30
.text
main:
la $t0, array # Cargar dirección base del array
li $t2, 0 # Inicializar suma total a 0
lw $t1, 0($t0) # Leer primer elemento
add $t2, $t2, $t1
lw $t1, 4($t0) # Leer segundo elemento (+4 bytes)
add $t2, $t2, $t1
lw $t1, 8($t0) # Leer tercer elemento (+8 bytes)
add $t2, $t2, $t1
li $v0, 10
syscall
6. x86 (NASM): Operaciones a nivel de Bits (UV)
Enunciado: Usa máscaras y operaciones bit a bit (AND, OR, XOR) para poner a cero el registro eax, encender su bit menos significativo y luego invertirlo.
global _start
_start:
xor eax, eax ; Forma eficiente de poner eax a 0
or eax, 1 ; Enciende el bit menos significativo (eax = 1)
not eax ; Invierte todos los bits (Complemento a 1)
mov eax, 1
int 0x80
7. MIPS: Leer entero por teclado (UC3M)
Enunciado: Escribe un programa que pida al usuario por teclado su edad y la guarde en un registro utilizando las Syscalls de SPIM/MARS.
main:
# Syscall 5 = Read Integer
li $v0, 5
syscall
# El entero leído queda guardado en $v0
move $t0, $v0 # Lo movemos a $t0 para protegerlo
li $v0, 10
syscall
8. x86 (NASM): Longitud de una Cadena (UAM)
Enunciado: Implementa el equivalente a strlen() de C en ensamblador x86, iterando hasta encontrar el byte nulo (0x00).
cadena db "Ingenieria", 0
section .text
global _start
_start:
mov esi, cadena ; Puntero al inicio de la cadena
xor ecx, ecx ; ecx = 0 (Contador)
contar:
cmp byte [esi], 0 ; ¿Es el fin de cadena (\0)?
je fin_conteo ; Si es cero, salta a fin
inc esi ; Avanza al siguiente carácter
inc ecx ; Incrementa el contador
jmp contar
fin_conteo:
; En ecx queda almacenada la longitud (10)
mov eax, 1
int 0x80
9. MIPS: Pila (Stack) y Funciones (UMA)
Enunciado: Muestra cómo guardar el registro de retorno $ra en la pila antes de hacer una llamada a una subrutina anidada, y cómo restaurarlo después.
mi_funcion:
# Prólogo: Reservar espacio en la pila y guardar $ra
addi $sp, $sp, -4
sw $ra, 0($sp)
# [Cuerpo de la función aquí]
# Epílogo: Restaurar $ra y liberar pila
lw $ra, 0($sp)
addi $sp, $sp, 4
jr $ra # Jump Register (Retorno)
10. x86 (NASM): Multiplicación (UNED)
Enunciado: Multiplica el valor 10 por 5 usando la instrucción mul y guarda el resultado en una variable de memoria.
resultado resb 4 ; Reserva 4 bytes para el resultado
section .text
global _start
_start:
mov eax, 10 ; eax siempre es uno de los operandos en mul
mov ebx, 5
mul ebx ; Multiplica eax por ebx. Resultado en edx:eax
mov [resultado], eax ; Guarda los 32 bits bajos en la variable
mov eax, 1
int 0x80
No hay comentarios:
Publicar un comentario