Introducción al Lenguaje Ensamblador x86

Conceptos, estructura, modos de direccionamiento, control de flujo, instrucciones y ejercicios prácticos en ensamblador x86.

⚙️ Introducción a la Arquitectura x86 y Lenguaje Ensamblador

¿Qué es el lenguaje ensamblador?

El lenguaje ensamblador es un lenguaje de bajo nivel, muy cercano al hardware. Utiliza mnemotécnicos (MOV, ADD, INT) para representar instrucciones que se traducen directamente a código de máquina y es específico de cada arquitectura (x86, ARM, etc.).

  • Usa mnemotécnicos para instrucciones.
  • Traducción directa a binario.
  • Específico de cada arquitectura.

Evolución de la arquitectura x86

ProcesadorAñoBitsDescripción
Intel 8086/8088197816Primeros procesadores x86
Intel 80386198532Extensión a 32 bits (IA-32)
AMD64200364AMD introduce x86-64, luego adoptado por Intel

¿Por qué aprender ensamblador x86?

  • Base de sistemas operativos (Windows, Linux)
  • Usado en drivers, firmware y sistemas embebidos
  • Permite entender el funcionamiento real de la CPU

🏗️ Estructura de un Programa en Ensamblador

Segmentos en Ensamblador

SegmentoFunciónEjemplo
.DATAVariables y constantesmsg DB 'Hola$'
.CODEInstrucciones del programaMOV AX, 5
.STACKMemoria temporal (pila).STACK 100h

Modelos de memoria

  • TINY: Todo en un solo segmento (programas pequeños)
  • SMALL: Un segmento para código y otro para datos
  • LARGE: Múltiples segmentos para código y datos

Ejemplo básico: Hola Mundo

.MODEL SMALL
.STACK 100h
.DATA
    msg DB 'Hola Mundo$'
.CODE
    MOV AX, @DATA
    MOV DS, AX       ; Inicializa segmento de datos
    LEA DX, msg      ; Carga dirección del mensaje
    MOV AH, 09h      ; Función para imprimir
    INT 21h          ; Llama al sistema operativo
    MOV AH, 4Ch      ; Terminar programa
    INT 21h

📍 Modos de Direccionamiento

ModoEjemploExplicación
InmediatoMOV AX, 10El dato está en la instrucción
DirectoMOV AX, [1000h]La dirección del dato está en la instrucción
Por registroMOV AX, BXUsa un registro del CPU
IndexadoMOV AX, [BX+SI]Combina registros y desplazamientos

Los modos de direccionamiento determinan cómo se accede a la memoria y afectan el rendimiento del programa.

🔄 Estructuras de Control de Flujo

Secuenciales

Las instrucciones se ejecutan en orden, una tras otra.

Condicionales

Permiten tomar decisiones:

IF-ELSE

CMP AX, BX      ; Compara AX y BX
JE iguales       ; Salta si son iguales
; Código si no son iguales
JMP fin
iguales:
; Código si son iguales
fin:

SWITCH-CASE

Se simula con saltos condicionales (JMP, JE, JNE).

Iterativas (Bucles)

FOR

MOV CX, 10   ; Repetir 10 veces
ciclo:
    ; Código del bucle
    LOOP ciclo

WHILE

inicio_while:
    CMP AX, BX
    JNE fin_while
    ; Código del bucle
    JMP inicio_while
fin_while:

🛠️ Instrucciones Básicas en Ensamblador

InstrucciónEjemploDescripción
MOVMOV AX, BXCopia el valor de BX a AX
ADDADD AX, 5Suma 5 a AX
SUBSUB AX, BXResta BX de AX
INTINT 21hLlama a una función del sistema
CMPCMP AX, BXCompara AX y BX (para condicionales)
JMPJMP etiquetaSalta a una etiqueta

Interrupciones importantes (INT 21h)

  • AH = 09h: Imprimir cadena
  • AH = 01h: Leer un carácter
  • AH = 4Ch: Terminar programa

📝 Ejercicios Prácticos

1. Suma de dos números

section .text
global _start

_start:
    mov al, 4          ; primer número
    add al, 9          ; segundo número (4+9=13)

    mov ah, 0          ; limpiar AH antes de dividir
    mov bl, 10
    div bl             ; divide AX por BL: AL = cociente(decena), AH = resto(unidad)

    ; Convertir cociente (decena) y resto (unidad) a ASCII
    add al, '0'
    mov [decena], al

    add ah, '0'
    mov [unidad], ah

    ; Mostrar decena si no es cero
    cmp byte [decena], '0'
    je mostrar_unidad

    mov eax, 4         ; syscall sys_write
    mov ebx, 1         ; stdout
    mov ecx, decena
    mov edx, 1
    int 0x80

mostrar_unidad:
    mov eax, 4
    mov ebx, 1
    mov ecx, unidad
    mov edx, 1
    int 0x80

    ; Salir
    mov eax, 1
    mov ebx, 0
    int 0x80

section .bss
decena resb 1
unidad resb 1

2. Contar dígitos de un número

section .data
num db '123456789$', 0

section .bss
decena resb 1
unidad resb 1

section .text
global _start

_start:
    mov esi, num      ; puntero a la cadena
    mov cx, 0         ; contador

contar:
    mov al, [esi]
    cmp al, '$'
    je convertir
    inc cx
    inc esi
    jmp contar

convertir:
    mov ax, cx
    mov bl, 10
    xor dx, dx
    div bl            ; AX / 10, AL = cociente(decena), AH= resto(unidad)

    add al, '0'       ; convertir decena a ASCII
    mov [decena], al

    add ah, '0'       ; convertir unidad a ASCII
    mov [unidad], ah

    ; Mostrar decena si no es '0'
    cmp byte [decena], '0'
    je mostrar_unidad

    mov eax, 4        ; sys_write
    mov ebx, 1        ; stdout
    mov ecx, decena
    mov edx, 1
    int 0x80

mostrar_unidad:
    mov eax, 4        ; sys_write
    mov ebx, 1
    mov ecx, unidad
    mov edx, 1
    int 0x80

    ; Salir
    mov eax, 1        ; sys_exit
    xor ebx, ebx
    int 0x80

Simulador interactivo de código ensamblador x86

Puedes escribir y ejecutar código ensamblador x86 directamente en el simulador de arriba. Es ideal para probar ejemplos como los de esta guía.

🏁 Conclusión

  • El ensamblador x86 es fundamental para entender cómo funcionan las computadoras.
  • Se usa en sistemas operativos, drivers y aplicaciones de bajo nivel.
  • Aunque es complejo, dominarlo permite optimizar código y entender la arquitectura de la CPU.