sábado, 7 de marzo de 2026

10 Ejercicios Resueltos de Ensamblador (x86 y MIPS): Arquitectura de Computadores

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.

.text
.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).

section .data
    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).

.text
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.

section .text
    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.

.data
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.

section .text
    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.

.text
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).

section .data
    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.

.text
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.

section .bss
    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