2. Programación Básica




Unidad 2: Programación Estructurada y Avanzada en Ensamblador

Plataforma académica interactiva con los 16 temas completamente desarrollados. Códigos listos para JDoodle (NASM 32-bit Linux, int 0x80).

Bloque 1: Entorno, Entrada de Datos y Bifurcaciones

2.1 Ensamblador (y ligador) a utilizar

En entornos modernos de 64 bits, la forma nativa de compilar bajo nivel educativo es mediante la sintaxis **NASM (Netwide Assembler)**. El ensamblador genera un archivo objeto binario formateado para Linux (.o), y el ligador de GNU (ld) enlaza los segmentos de memoria para definir el punto de entrada e instrucciones ejecutables reales.

2.2 Ciclos numéricos

La CPU utiliza estructuras cíclicas basadas en registros contadores fijos. La instrucción nativa LOOP resta automáticamente 1 de ECX/CX y comprueba si el resultado es cero; si no lo es, desvía el flujo del programa hacia la etiqueta designada en el segmento de código.

2.3 Captura básica de cadenas

La recolección de texto proveniente de la terminal o teclado se efectúa cargando el código de servicio 3 (sys_read) en el registro de control EAX, definiendo en EBX el descriptor de entrada estándar (0 para STDIN) y apuntando ECX hacia un búfer dinámico en memoria.

2.4 Comparación y prueba

La instrucción CMP resta internamente el operando derecho del izquierdo sin guardar el resultado, alterando las banderas de estado (ZF, CF, SF) en el registro EFLAGS. Por su parte, TEST realiza una operación lógica AND bit por bit, útil para comprobar si ciertos bits específicos están encendidos.

2.5 Saltos

La CPU cambia el orden lineal de ejecución de instrucciones modificando el puntero EIP. Los saltos se dividen en **Incondicionales** (JMP, se ejecutan sin importar nada) y **Condicionales** (JE, JNE, JG, JL), los cuales se disparan solo si las banderas del procesador cumplen una condición matemática previa.

Código para JDoodle (Temas 2.1 a 2.5): Comparación y Salto
section .data
    msg_match db "Los numeros coinciden", 10
    len_match equ $ - msg_match
section .text
    global _start
_start:
    mov eax, 50        ; Registro A
    mov ebx, 50        ; Registro B
    cmp eax, ebx       ; 2.4 Comparación aritmética
    je saltar_a_meta   ; 2.5 Salto Condicional si son iguales (ZF=1)
    jmp salir_programa ; 2.5 Salto Incondicional de escape
saltar_a_meta:
    mov eax, 4         ; Syscall sys_write
    mov ebx, 1         ; Descriptor stdout (Pantalla)
    mov ecx, msg_match ; Dirección del mensaje
    mov edx, len_match ; Longitud
    int 0x80           ; Interrupción de Kernel
salir_programa:
    mov eax, 1         ; Syscall sys_exit
    xor ebx, ebx       ; Código de retorno 0
    int 0x80

Bloque 2: Repeticiones Controladas y Operaciones Aritméticas

2.6 Ciclos condicionales

A diferencia de los ciclos numéricos puros, los ciclos condicionales dependen del cumplimiento de un estado dinámico en las banderas del procesador. Se estructuran combinando instrucciones de salto relacionales como JNZ (Jump if Not Zero) o JZ al final del cuerpo de un bucle de procesamiento de datos.

2.7 Incremento y decremento

Las instrucciones INC y DEC modifican el operando sumando o restando una unidad aritmética de forma exacta. Son significativamente más rápidas que usar instrucciones generales como ADD o SUB debido a que requieren microinstrucciones de menor tamaño dentro de la ALU.

2.8 Captura de cadenas con formato

La captura estructurada impone restricciones severas al flujo de caracteres. Se define un tamaño de almacenamiento inamovible en la sección de memoria de variables no inicializadas (.bss) utilizando la directiva resb, garantizando que el usuario no pueda desbordar la memoria adyacente.

2.9 Instrucciones aritméticas

El repertorio matemático básico del procesador incluye ADD (suma), SUB (resta), MUL (multiplicación sin signo) y DIV (división). En las multiplicaciones de 32 bits, el multiplicando se aloja obligatoriamente en EAX, y el resultado extendido se almacena en la combinación de registros EDX:EAX.

Código para JDoodle (Temas 2.6 a 2.9): Bucle Matemático Incremental
section .text
    global _start
_start:
    mov ecx, 5         ; Inicializamos un contador manual en 5
    mov eax, 2         ; Valor acumulador base
ciclo_aritmetico:
    mov ebx, 3
    mul ebx            ; 2.9 Multiplicación: EAX = EAX * 3
    inc eax            ; 2.7 Incremento: EAX = EAX + 1
    dec ecx            ; 2.7 Decremento: ECX = ECX - 1
    jnz ciclo_aritmetico ; 2.6 Ciclo Condicional: Repite mientras ECX != 0
    
    mov eax, 1         ; Terminar programa (sys_exit)
    xor ebx, ebx
    int 0x80

Bloque 3: Gestión de Memoria, Conversión Decimal y Álgebra Booleana

2.10 Manipulación de la pila

La Pila (Stack) es un segmento de la memoria RAM regido bajo la política **LIFO** (Last In, First Out). La instrucción PUSH inserta datos en el tope reduciendo el puntero de pila ESP, mientras que POP extrae el dato y lo deposita en un registro, incrementando ESP de manera automática.

2.11 Obtención de cadena con representación decimal

Los registros almacenan valores binarios crudos. Para convertirlos en una cadena de texto decimal visible por humanos, el algoritmo exige dividir el número de forma matemática consecutiva entre 10. Cada residuo aislado (que oscila entre 0 y 9) se transforma en su carácter ASCII equivalente sumándole la constante 48 (o el carácter '0').

2.12 Instrucciones lógicas

Representan el álgebra de Boole implementada directo en compuertas de hardware. Las instrucciones fundamentales son: AND (máscaras de bits), OR (encendido de bits), XOR (limpieza veloz de registros al emparejar un operando consigo mismo) y NOT (inversión total del complemento a uno).

Código para JDoodle (Temas 2.10 a 2.12): Resguardo en Pila y Operación Lógica
section .text
    global _start
_start:
    mov eax, 0xABCDE   ; Carga de datos críticos
    push eax           ; 2.10 Resguarda el contenido en el Stack (Pila)
    
    mov eax, 0xFF00    ; Variable de máscara
    mov ebx, 0x0F0F    ; Variable de datos
    and eax, ebx       ; 2.12 Operación Lógica AND bit por bit
    xor ecx, ecx       ; 2.12 XOR para limpiar a cero el registro ECX de forma óptima
    
    pop eax            ; 2.10 Restaura el valor original desde el Stack
    mov eax, 1         ; sys_exit
    int 0x80

Bloque 4: Operaciones de Bit Avanzadas, Hexadecimal y Archivos

2.13 Desplazamiento y rotación

Las instrucciones de desplazamiento mueven los bits a la izquierda (SHL, multiplica por 2) o a la derecha (SHR, divide entre 2), rellenando los espacios vacíos con ceros. Las rotaciones (ROL, ROR) reinsertan los bits expulsados por el extremo opuesto, impidiendo la pérdida de información.

2.14 Obtención de una cadena con la representación hexadecimal

Para codificar un número a texto base 16, se fragmenta el registro en bloques de 4 bits (nibbles) mediante máscaras lógicas. Si el bloque matemático resultante vale de 0 a 9, se le suma 48 ('0'); si su rango oscila entre 10 y 15, se le suma 55 para transformarlo con precisión en las letras de la 'A' a la 'F' en la tabla ASCII.

2.15 Captura y almacenamiento de datos numéricos

El teclado del sistema captura exclusivamente caracteres en formato de texto. El proceso inverso de almacenamiento numérico binario real requiere leer el buffer carácter por carácter, restar 48 para aislar el valor absoluto del dígito, y multiplicar la base acumulada de forma sucesiva por 10.

2.16 Operaciones básicas sobre archivos de disco

La administración física del sistema de archivos depende de las llamadas de servicios del Kernel de Linux. Involucra el uso estricto de identificadores funcionales: sys_open (EAX=5) para aperturas o creación configurando descriptores de permisos de lectura, sys_write (EAX=4) para almacenamiento secuencial y sys_close (EAX=6) para el cierre y salvaguarda final de datos.

Código para JDoodle (Temas 2.13 a 2.16): Manipulación y Desplazamientos Bit a Bit
section .text
    global _start
_start:
    mov eax, 12        ; Binario: 00001100 (12 decimal)
    shl eax, 2         ; 2.13 Desplazamiento Izquierda: Multiplica por 4 -> Resulta 48
    shr eax, 1         ; 2.13 Desplazamiento Derecha: Divide entre 2 -> Resulta 24
    
    mov ebx, 0x0A      ; Representación numérica base hexadecimal
    rol ebx, 4         ; 2.13 Rotación de bits sin pérdida en el registro
    
    mov eax, 1         ; Terminar ejecutable (sys_exit)
    xor ebx, ebx
    int 0x80

📊 Examen de Evaluación Integral de la Unidad 2

Valida de manera rigurosa tu conocimiento técnico en cada uno de los 16 temas desarrollados sobre la arquitectura del procesador.

1. ¿Qué extensión de archivo binario no ejecutable se produce directamente tras finalizar la tarea del Ensamblador (NASM / MASM)?
2. ¿Cuál es el comportamiento nativo de la instrucción LOOP al controlar un ciclo numérico?
3. Para realizar la captura de una cadena de caracteres básica mediante llamadas al sistema Linux (int 0x80), ¿qué identificador de servicio debe cargarse en EAX?
4. ¿En qué se diferencia fundamentalmente la instrucción TEST frente a la instrucción CMP?
5. ¿Qué bandera del procesador define si un salto condicional tipo JZ (Jump if Zero) debe ejecutarse?
6. ¿Por qué las instrucciones INC y DEC se consideran altamente eficientes en la programación de bajo nivel?
7. Al ejecutar una operación de multiplicación nativa de 32 bits (MUL EBX), ¿dónde deposita el procesador el resultado extendido?
8. ¿Qué instrucción se encarga de extraer un elemento guardado en el tope de la Pila (Stack) e incrementar el registro ESP?
9. Si desplazamos un registro un bit hacia la izquierda mediante la instrucción SHL, ¿cuál es el efecto aritmético equivalente?
10. ¿Qué llamada al sistema de Linux (Syscall cargada en EAX) se encarga de realizar la escritura física de datos hacia un descriptor de archivo en disco?