PROGRAMA SUMA RICHI CHINGON ES UNA VRGA
section .bss
Esto le dice al programa:
➡️ “Voy a definir variables sin valor inicial. Solo reserva espacio en memoria.”
.bss significa Block Started by Symbol, una sección para reservar memoria que
estará vacía al inicio.
a resb 2
Aquí estás diciendo:
➡️ “Reserva 2 bytes de memoria para una variable llamada a.”
¿Por qué 2 bytes? Porque cuando el usuario escribe un número y presiona ENTER, se
registran dos caracteres: el número (ej. '4') y el ENTER ('\n' o 0x0A en ASCII).
b resb 2
Igual que con a, reservas 2 bytes para guardar lo que escriba el usuario como
segundo número.
r resb 1
Ahora reservas 1 solo byte para la variable r, donde se va a guardar el resultado de la
suma (en forma de carácter).
section .text
Le estás diciendo al ensamblador:
➡️ “A partir de aquí viene el código que se va a ejecutar.”
Es la sección donde empieza la acción real del programa.
global _start
Le estás diciendo:
➡️ “Este es el punto de inicio del programa.”
Cuando Linux arranque tu programa, va a empezar desde donde diga _start:.
_start:
Es una etiqueta (como un punto de referencia).
No hace nada por sí sola, pero marca el lugar exacto donde empieza a ejecutarse el
código.
mov eax, 3
Esto es una instrucción para el sistema operativo. Le estás diciendo:
➡️ “Quiero usar la función número 3 del sistema Linux, que sirve para leer del
teclado (entrada estándar).”
EAX es un registro del procesador que guarda qué función vas a usar.
mov ebx, 0
EBX es otro registro. Al ponerle 0, estás diciendo:
➡️ “Quiero leer desde el teclado (stdin, entrada estándar).”
En Linux:
• 0 = teclado
• 1 = pantalla
• 2 = errores
mov ecx, a
ECX es el registro que le dice al sistema:
➡️ “Guarda lo que el usuario escriba en la dirección de memoria de la variable a.”
mov edx, 2
EDX dice:
➡️ “Quiero leer 2 bytes.” Uno será el número, y el otro el ENTER que el usuario va a
presionar.
int 0x80
Este es el momento mágico.
➡️ “Ejecuta todo lo que pedí arriba.”
El sistema operativo ve que quieres usar la función 3, con origen 0, destino a, y
longitud 2. Entonces espera que el usuario escriba algo y guarda eso en la variable
a.
mov eax, 3
Otra vez estás diciendo:
➡️ “Quiero leer otro dato del teclado.”
mov ebx, 0
Otra vez:
➡️ “La entrada vendrá del teclado (stdin).”
mov ecx, b
➡️ “Guarda lo que escriba el usuario en la variable b.”
mov edx, 2
➡️ “Voy a leer 2 bytes de nuevo (número + ENTER).”
int 0x80
➡️ “Hazlo.”
El sistema espera que escribas el segundo número, y lo guarda en b.
mov al, [a]
Aquí sacas de memoria lo que estaba guardado en a (el primer número que
escribiste) y lo guardas en el registro AL.
AL es la parte baja del registro EAX. Solo guarda 1 byte. Usamos AL porque cada
número es solo un carácter.
sub al, '0'
Aquí estás haciendo algo clave:
➡️ “Convierte el carácter a número real.”
Por ejemplo:
• '4' en ASCII = 52
• '0' en ASCII = 48
• 52 - 48 = 4
Así conviertes '4' → 4 para que puedas sumarlo como número.
mov bl, [b]
Lo mismo, pero con el segundo número. Lo sacas de la variable b y lo metes en BL
(parte baja de EBX).
sub bl, '0'
Otra conversión de carácter a número.
Si escribiste '5', se convierte en 5 restándole '0'.
add al, bl
Ahora sí:
➡️ “Suma el primer número con el segundo.”
Ambos están ya convertidos a números reales, así que puedes sumarlos
directamente.
add al, '0'
Ahora conviertes el número resultado de nuevo a carácter.
Si la suma fue 9, haces 9 + 48 = 57, que es el carácter '9'.
Esto es porque solo puedes mostrar caracteres en pantalla, no números crudos.
mov [r], al
Guarda el carácter del resultado (por ejemplo '9') en la variable r.
mov eax, 4
➡️ “Quiero usar la función número 4 del sistema: escribir en pantalla (stdout).”
mov ebx, 1
➡️ “Escribe en la pantalla (stdout = 1).”
mov ecx, r
➡️ “Lo que quiero mostrar está en la variable r.”
mov edx, 1
➡️ “Muestra solo 1 byte (un carácter).”
int 0x80
➡️ “Hazlo.”
El carácter que representa la suma se muestra en la pantalla.
mov eax, 1
➡️ “Quiero usar la función número 1: salir del programa.”
xor ebx, ebx
Esto pone el registro EBX en 0.
El valor 0 significa que el programa terminó sin errores.
Se usa xor ebx, ebx en vez de mov ebx, 0 porque es un poco más eficiente en
ensamblador.
int 0x80
➡️ “Finaliza el programa.”
El sistema operativo cierra tu programa y todo terminó.
section .bss
a resb 2
b resb 2
r resb 1
section .text
global _start
_start:
mov eax, 3
mov ebx, 0
mov ecx, a
mov edx, 2
int 0x80
mov eax, 3
mov ebx, 0
mov ecx, b
mov edx, 2
int 0x80
mov al, [a]
sub al, '0'
mov bl, [b]
sub bl, '0'
add al, bl
add al, '0'
mov [r], al
mov eax, 4
mov ebx, 1
mov ecx, r
mov edx, 1
int 0x80
mov eax, 1
xor ebx, ebx
int 0x80
CODIGO MULTIPLICACION RICHI NO LE SABE A ESTE
section .data
Esta sección contiene datos definidos desde el inicio, es decir, variables con valores
fijos.
X dd 3
Define una variable llamada X y le asigna el valor 3.
dd = define double word (4 bytes = 32 bits). Este es el multiplicando.
Y dd 2
Define Y con el valor 2 (multiplicador).
También usa 4 bytes para poder hacer desplazamientos sin errores.
msg_result db "El resultado es: ", 0
Aquí guardas un texto que vas a mostrar antes de imprimir el número.
El , 0 al final es un terminador null (\0) para fines de seguridad (aunque no obligatorio
aquí).
len_result equ $ - msg_result
Calcula cuántos bytes tiene el texto "El resultado es: " automáticamente.
$ representa la posición actual y msg_result la inicial → la resta da la longitud.
newline db 10
El valor 10 en decimal es el salto de línea (\n en ASCII).
Se usará para bajar de línea al final.
section .bss
Sección para variables sin valor inicial, pero que vamos a usar más adelante.
P resd 1
Reserva 4 bytes (1 dword) para la variable P, que va a guardar el resultado de la
multiplicación.
ascii_buf resb 10
Reserva 10 bytes para el buffer de conversión a texto.
Ahí se va a ir armando el número carácter por carácter (máximo 10 dígitos en base
10).
section .text
Empieza la sección donde se escribe el código real que se va a ejecutar.
global _start
Declara el punto de entrada del programa.
Linux sabrá que el programa comienza en _start.
_start:
Etiqueta que marca el inicio del programa.
mov ecx, 8
ECX se usará como contador del ciclo de multiplicación.
Vamos a revisar 8 bits del multiplicador (Y), de derecha a izquierda.
multiplicar:
Etiqueta para el inicio del bucle de multiplicación binaria.
mov eax, [Y]
Carga el valor actual del multiplicador en EAX.
and eax, 1
Hace una operación lógica AND con el bit menos significativo (el de la derecha).
Sirve para saber si el bit actual de Y es 1 o 0.
jz no_sumar
Si el bit es 0, salta a la parte donde no se suma.
jz = Jump if Zero (si el resultado anterior fue 0).
mov eax, [X]
Si no se brincó, significa que el bit era 1.
Entonces carga el multiplicando X en EAX.
add [P], eax
Suma EAX (el multiplicando) al acumulador P, que guarda el resultado final.
no_sumar:
Etiqueta a la que se salta si el bit de Y era 0 (y por lo tanto no se hace suma en esta
vuelta).
mov eax, [X]
Vuelve a cargar el valor actual de X en EAX.
shl eax, 1
Hace un corrimiento a la izquierda: multiplica X por 2.
Esto equivale a avanzar una posición binaria para el siguiente bit.
mov [X], eax
Guarda el nuevo valor de X en la variable original.
Ahora X está duplicado y listo para la próxima iteración.
mov eax, [Y]
Carga de nuevo el valor del multiplicador.
shr eax, 1
Hace un corrimiento a la derecha: divide Y entre 2.
Esto elimina el bit que ya revisamos y avanza al siguiente.
mov [Y], eax
Guarda el nuevo valor de Y actualizado en su variable.
dec ecx
Resta 1 al contador del ciclo.
jnz multiplicar
Si ECX todavía no es 0, salta de nuevo a multiplicar: para repetir el proceso.
mov eax, [P]
Ya terminó el ciclo. Ahora P tiene el resultado de la multiplicación.
Se lo carga en EAX para comenzar la conversión a texto.
lea edi, [ascii_buf + 9]
EDI será un puntero que apunta al final del buffer.
Vamos a construir el número de derecha a izquierda.
mov byte [edi], 0
Pone un terminador null (\0) al final de la cadena para seguridad (aunque en este caso
no es necesario, es buena práctica).
mov ebx, 10
Queremos dividir en base 10 (para convertir a texto), así que ponemos el número 10
en EBX.
convertir:
Etiqueta para el inicio del bucle de conversión numérica a caracteres ASCII.
dec edi
Retrocede 1 byte en el buffer. Vamos a poner el próximo carácter ahí.
xor edx, edx
Pone EDX en cero para que no interfiera con la división.
En divisiones de 32 bits: EDX:EAX / EBX → por eso hay que asegurarse de que EDX = 0.
div ebx
Divide EAX entre 10 (que está en EBX).
• El cociente queda en EAX
• El residuo queda en EDX
add dl, '0'
Convierte el residuo (resto de la división) a carácter ASCII.
Ejemplo: 8 → 56 ('8' en ASCII)
mov [edi], dl
Guarda ese carácter en el buffer en la posición actual.
test eax, eax
Verifica si EAX (el cociente) llegó a cero.
jnz convertir
Si no es cero todavía, vuelve a dividir el número siguiente (sigue convirtiendo).
mov eax, 4
Función del sistema para escribir (sys_write).
mov ebx, 1
1 = salida estándar → la pantalla.
mov ecx, msg_result
ECX apunta al texto "El resultado es: ".
mov edx, len_result
EDX indica cuántos caracteres se van a mostrar del mensaje.
int 0x80
Ejecuta la instrucción de escribir el mensaje en pantalla.
mov eax, 4
Otra vez, función para escribir.
mov ebx, 1
Salida: pantalla.
mov ecx, edi
ECX apunta a la parte del buffer donde está el primer dígito del número
convertido.
mov edx, ascii_buf + 10
EDX se llena con la dirección final del buffer.
sub edx, edi
Calcula la cantidad de caracteres reales que tiene el número convertido.
int 0x80
Imprime el número como texto.
mov eax, 4
Otra vez, llamada a sys_write.
mov ebx, 1
Pantalla.
mov ecx, newline
ECX apunta a un carácter de salto de línea.
mov edx, 1
Se va a escribir solo 1 byte.
int 0x80
Escribe un salto de línea en pantalla.
mov eax, 1
Función del sistema para terminar el programa (sys_exit).
xor ebx, ebx
Código de salida = 0 (todo bien).
int 0x80
Termina el programa.
section .data
X dd 3 ; Multiplicando (15 = 0x0F)
Y dd 2 ; Multiplicador (11 = 0x0B)
msg_result db "El resultado es: ", 0
len_result equ $ - msg_result
newline db 10
section .bss
P resd 1 ; Producto (32 bits)
ascii_buf resb 10 ; Buffer para conversión ASCII
section .text
global _start
_start:
mov ecx, 8
multiplicar:
mov eax, [Y]
and eax, 1
jz no_sumar
mov eax, [X]
add [P], eax
no_sumar:
mov eax, [X]
shl eax, 1
mov [X], eax
mov eax, [Y]
shr eax, 1
mov [Y], eax
dec ecx
jnz multiplicar
mov eax, [P]
lea edi, [ascii_buf + 9] ; Apuntar al final del buffer
mov byte [edi], 0 ; Null-terminator
mov ebx, 10 ; Base 10
convertir:
dec edi
xor edx, edx
div ebx ; eax/10 -> eax (cociente), edx (resto)
add dl, '0' ; Convertir resto a ASCII
mov [edi], dl
test eax, eax
jnz convertir
mov eax, 4 ; sys_write
mov ebx, 1 ; stdout
mov ecx, msg_result
mov edx, len_result
int 0x80
mov eax, 4
mov ebx, 1
mov ecx, edi ; Puntero al inicio del número ASCII
mov edx, ascii_buf + 10 ; Longitud máxima
sub edx, edi ; Calcular longitud real
int 0x80
mov eax, 4
mov ebx, 1
mov ecx, newline
mov edx, 1
int 0x80
mov eax, 1 ; sys_exit
xor ebx, ebx ; Código 0
int 0x80