Saltar a contenido

x86-64 Assembly Language (64-bit)

"Clase de la hoja"

########################################################################################################################################################################################################################################################## Copiar todos los comandos
########################################################################################################################################################################################################################################################## Generar PDF seleccionado/button

■/div titulada

El lenguaje de montaje x86-64 representa el pináculo evolutivo de la familia de arquitectura x86, ampliando la instrucción fundamental de 32 bits x86 establecida en la era de computación de 64 bits, manteniendo al mismo tiempo la compatibilidad integral atrasada e introduciendo poderosas nuevas capacidades que definen la computación moderna. También conocido como AMD64 (desarrollado por AMD) o Intel 64 (Intel's implementation), esta arquitectura se ha convertido en la plataforma dominante para computadoras de escritorio, infraestructura de servidor y aplicaciones informáticas de alto rendimiento en todo el mundo. La transición de la computación de 32 bits a 64 bits trajo cambios fundamentales que se extienden mucho más allá de la simple expansión espacial, la introducción de nuevos registros, la mejora de la codificación de instrucciones, la mejora de las convenciones de llamadas y las características arquitectónicas que permiten un rendimiento y escalabilidad sin precedentes. Comprender el lenguaje de montaje x86-64 es esencial para los programadores de sistemas, investigadores de seguridad, ingenieros de rendimiento y desarrolladores que trabajan en aplicaciones que exigen la máxima eficiencia, control de hardware directo o integración de sistemas profundos. Esta referencia integral proporciona una cobertura detallada de la programación de montaje x86-64, desde las mejoras arquitectónicas de más de 32 bits x86 a técnicas avanzadas de optimización que aprovechan las capacidades completas de los procesadores modernos de 64 bits.

Evolución arquitectónica y mejoras de 64 bits

Objetivos históricos de Contexto y Diseño

El desarrollo de la arquitectura x86-64 surgió del reconocimiento de que las limitaciones de computación de 32 bits eventualmente limitarían el crecimiento de las aplicaciones informáticas, en particular en áreas que requieren grandes espacios de memoria, computación de alto rendimiento y aplicaciones servidor que manejan conjuntos de datos masivos. La introducción de la arquitectura AMD64 en 2003 marcó un momento crucial en la historia de la computación, proporcionando un camino de evolución limpio de 32 bits x86, al tiempo que introdujo mejoras arquitectónicas que abordaron las limitaciones de larga data del diseño x86. El éxito de la arquitectura llevó a una adopción generalizada en toda la industria, con Intel implementando extensiones compatibles en su arquitectura Intel 64, estableciendo x86-64 como el estándar para plataformas de computación modernas.

La filosofía de diseño detrás de x86-64 hizo hincapié en mantener la compatibilidad completa atrasada con el código x86 existente de 32 bits al tiempo que introducir mejoras que permitirían futuras escalabilidad y mejoras de rendimiento. Este enfoque garantizaba que se pudieran conservar las inversiones de software existentes, mientras que las nuevas aplicaciones podían aprovechar las capacidades de 64 bits. La arquitectura introduce varios modos operativos, incluyendo el modo legado (compatibilidad de 32 bits), el modo de compatibilidad (aplicaciones de 32 bits dentro de sistemas operativos de 64 bits), y el modo de 64 bits (operación nativa de 64 bits), proporcionando flexibilidad para entornos de computación mixtos durante el período de transición.

Regístrate Arquitectura Mejoras

La mejora más visible inmediata en x86-64 es la dramática expansión del conjunto de registro, duplicando el número de registros de uso general de ocho a dieciséis y ampliando todos los registros a 64 bits de ancho. Esta expansión aborda una de las limitaciones más significativas de la programación x86 de 32 bits, donde la presión del registro a menudo forzó el acceso frecuente a la memoria y oportunidades limitadas de optimización. El nuevo conjunto de registro incluye los ocho registros originales (RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP) extendidos a 64 bits, más ocho registros adicionales (R8 a R15) que proporcionan recursos computacionales adicionales.

; 64-bit register usage examples
mov rax, 0123456789ABCDEFh ; Load 64-bit immediate value
mov r8, rax                ; Copy to new register R8
mov r9d, eax               ; 32-bit operation clears upper 32 bits
mov r10w, ax               ; 16-bit operation preserves upper bits
mov r11b, al               ; 8-bit operation preserves upper bits

; Register naming conventions
; 64-bit: RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP, R8-R15
; 32-bit: EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP, R8D-R15D
; 16-bit: AX, BX, CX, DX, SI, DI, BP, SP, R8W-R15W
; 8-bit:  AL, BL, CL, DL, SIL, DIL, BPL, SPL, R8B-R15B

La convención de nombres de registro sigue un patrón sistemático que mantiene la compatibilidad con código de 32 bits al tiempo que proporciona una clara identificación de tamaños de operación. Una característica arquitectónica importante es que las operaciones de 32 bits en registros de 64 bits limpian automáticamente los 32 bits superiores, proporcionando un semántico limpio para operaciones de tamaño mixto y eliminando posibles vulnerabilidades de seguridad de los contenidos de registro no inicializados.

Modelo de memoria y espacio de dirección

x86-64 ofrece un amplio espacio de dirección que apoya teóricamente el abordaje de 64 bits, aunque las implementaciones actuales suelen soportar direcciones virtuales de 48 bits y direcciones físicas de 40-52 bits. Esta expansión desde el límite de 4 GB de sistemas de 32 bits a múltiples terabytes de memoria direccional permite aplicaciones que anteriormente eran imposibles, incluyendo bases de datos a gran escala, aplicaciones de computación científica y cargas de trabajo de servidores de gran densidad de memoria.

; 64-bit memory addressing
mov rax, [rbx]              ; 64-bit memory load
mov [rcx+rdx*8], rax        ; 64-bit store with scaling
lea rsi, [rdi+r8*4+100]     ; Load effective address calculation

; RIP-relative addressing (64-bit mode only)
mov rax, [rip+variable]     ; PC-relative data access
call [rip+function_ptr]     ; PC-relative function call

La introducción del abordaje relativo RIP representa una mejora arquitectónica significativa que permite la generación de código independiente de la posición y simplifica la vinculación dinámica. Este modo de dirección calcula las direcciones de memoria relativas al puntero de instrucción actual, eliminando la necesidad de un tratamiento absoluto en muchos escenarios y mejorando la portabilidad del código.

Conjunto de instrucciones mejorado y codificación

REX Prefijo e Instrucción

x86-64 introduce el byte prefijo REX que permite el acceso a registros extendidos y tamaños de 64 bits de operando manteniendo la compatibilidad con la codificación de instrucciones existente. El prefijo REX aparece antes del opcode de instrucción y contiene campos que especifican el modo de operación de 64 bits, el acceso al registro ampliado y las capacidades adicionales de tratamiento. Comprender el uso de prefijo REX es crucial para los programadores de montaje que trabajan con el conjunto de registro ampliado y las operaciones de 64 bits.

; REX prefix examples (shown conceptually)
mov rax, rbx        ; REX.W + MOV (64-bit operation)
mov r8, r9          ; REX.W + REX.R + REX.B + MOV (extended registers)
mov eax, r8d        ; REX.B + MOV (32-bit with extended register)

; Instruction encoding considerations
add rax, 1          ; Can use shorter encoding than immediate
add rax, 128        ; Requires longer immediate encoding
add rax, r8         ; Uses REX prefix for extended register

El prefijo REX permite varias capacidades importantes, incluyendo el acceso a los registros R8-R15, especificación de tamaño de 64 bits y modos de abordaje ampliados. El prefijo es generado automáticamente por los ensambladores cuando sea necesario, pero entender su función ayuda a optimizar la selección de instrucciones y entender las implicaciones del tamaño del código.

Nuevas instrucciones y capacidades

x86-64 introduce varias nuevas instrucciones y mejora las instrucciones existentes para aprovechar las capacidades de 64 bits. Estas mejoras incluyen nuevos modos de tratamiento, soporte de valor inmediato ampliado e instrucciones optimizadas para el funcionamiento de 64 bits. La arquitectura también elimina algunas instrucciones heredadas que son incompatibles con el funcionamiento de 64 bits y añade nuevas capacidades que mejoran el rendimiento y la funcionalidad.

; 64-bit specific instructions
movsxd rax, eax     ; Sign-extend 32-bit to 64-bit
cdqe                ; Convert doubleword to quadword (RAX)
cqo                 ; Convert quadword to octword (RDX:RAX)

; Enhanced immediate support
mov rax, 0FFFFFFFFFFFFFFFFh ; 64-bit immediate (limited cases)
mov r8, 7FFFFFFFh           ; 32-bit immediate sign-extended

; Improved string operations
movsq               ; Move quadword string
stosq               ; Store quadword string
scasq               ; Scan quadword string

La instrucción MOVSXD proporciona una eficiente expresión de signos de 32 bits a 64 bits, abordando un requisito común en la programación de 64 bits. Las instrucciones de cadena mejoradas funcionan en cantidades de 64 bits, lo que permite mejorar el rendimiento de las operaciones de datos a granel en datos alineados de 64 bits.

Calling Conventions and ABI

Sistema V ABI (Unix/Linux)

La interfaz binaria de aplicación del sistema V define la convención de llamadas estándar para sistemas similares a Unix que se ejecutan en x86-64, estableciendo protocolos consistentes de paso del parámetro, uso del registro y gestión de pilas. Este ABI aprovecha el conjunto de registro ampliado para pasar los parámetros de función en los registros en lugar de en la pila, mejorando significativamente el rendimiento de las llamadas de función en comparación con las convenciones de 32 bits.

; System V ABI parameter passing
; Integer/pointer parameters: RDI, RSI, RDX, RCX, R8, R9
; Floating-point parameters: XMM0-XMM7
; Return values: RAX (integer), XMM0 (floating-point)

function_call_example:
    ; Prepare parameters
    mov rdi, param1     ; First parameter
    mov rsi, param2     ; Second parameter
    mov rdx, param3     ; Third parameter
    mov rcx, param4     ; Fourth parameter
    mov r8, param5      ; Fifth parameter
    mov r9, param6      ; Sixth parameter
    ; Additional parameters go on stack

    call target_function
    ; Return value in RAX

; Function prologue/epilogue
target_function:
    push rbp            ; Save frame pointer
    mov rbp, rsp        ; Establish frame pointer
    sub rsp, 32         ; Allocate local storage (16-byte aligned)

    ; Function body
    mov rax, rdi        ; Access first parameter
    add rax, rsi        ; Add second parameter

    ; Function epilogue
    mov rsp, rbp        ; Restore stack pointer
    pop rbp             ; Restore frame pointer
    ret                 ; Return to caller

El sistema V ABI requiere alineación de pilas de 16 bytes en los límites de llamadas de función, garantizando un rendimiento óptimo para las operaciones SIMD y manteniendo la compatibilidad con el código generado por el compilador. El ABI también define los registros salveados por calle (RBX, RBP, R12-R15) que deben ser preservados a través de llamadas de función, y los registros guardados por llamadas que pueden ser modificados por las funciones llamadas.

Microsoft x64 ABI (Windows)

La convención de llamadas Microsoft x64 difiere de System V ABI de varias maneras importantes, reflejando diferentes prioridades de diseño y requisitos de compatibilidad. Comprender estas diferencias es crucial para el desarrollo multiplataforma y cuando se interfacing con APIs del sistema de Windows.

; Microsoft x64 ABI parameter passing
; Integer/pointer parameters: RCX, RDX, R8, R9
; Floating-point parameters: XMM0-XMM3
; Return values: RAX (integer), XMM0 (floating-point)

windows_function_call:
    ; Prepare parameters
    mov rcx, param1     ; First parameter
    mov rdx, param2     ; Second parameter
    mov r8, param3      ; Third parameter
    mov r9, param4      ; Fourth parameter
    ; Additional parameters go on stack

    sub rsp, 32         ; Allocate shadow space
    call target_function
    add rsp, 32         ; Clean up shadow space
    ; Return value in RAX

; Windows function structure
windows_function:
    ; Shadow space automatically allocated by caller
    mov [rsp+8], rcx    ; Can spill parameters to shadow space
    mov [rsp+16], rdx
    mov [rsp+24], r8
    mov [rsp+32], r9

    ; Function body
    mov rax, rcx        ; Access first parameter
    add rax, rdx        ; Add second parameter

    ret                 ; Return to caller

El Microsoft ABI requiere la asignación de espacio de sombra para los primeros cuatro parámetros, incluso cuando se pasan en registros. Este espacio de sombra proporciona almacenamiento para los parámetros de registro si la función llamada necesita derramarlos a la memoria, simplificando la implementación de funciones y depurando.

Gestión avanzada de memoria

Memoria Virtual y Paging

x86-64 implementa un sofisticado sistema de memoria virtual que soporta múltiples tamaños de página y funciones avanzadas de gestión de memoria. La arquitectura utiliza una estructura de tabla de páginas de cuatro niveles (en la mayoría de las implementaciones) que permite una traducción eficiente de direcciones virtuales a direcciones físicas mientras apoya el espacio de dirección ampliado.

; Page table manipulation (system-level programming)
mov cr3, rax            ; Load page directory base
mov rax, cr3            ; Read current page directory

; TLB management
invlpg [memory_address] ; Invalidate specific page in TLB
mov rax, cr4            ; Read control register 4
or rax, 80h             ; Set PGE bit (Page Global Enable)
mov cr4, rax            ; Enable global pages

; Memory type and caching control
mov rcx, 277h           ; IA32_PAT MSR
rdmsr                   ; Read Page Attribute Table
; Modify EAX/EDX for memory type configuration
wrmsr                   ; Write modified PAT

Comprender la gestión de memoria virtual es crucial para la programación a nivel de sistema, controladores de dispositivos y aplicaciones que requieren un control preciso sobre el comportamiento de la memoria. La unidad de gestión de memoria x86-64 proporciona características para la protección de memoria, control de caché y optimización de rendimiento que pueden afectar significativamente el comportamiento de aplicación.

Soporte de página grande

x86-64 admite múltiples tamaños de página incluyendo las páginas estándar 4KB, 2MB páginas grandes y 1GB páginas enormes. Gran soporte de página puede proporcionar beneficios significativos para aplicaciones con grandes huellas de memoria reduciendo la presión TLB y mejorando la eficiencia del acceso a la memoria.

; Large page allocation (conceptual - typically done through OS APIs)
; 2MB page allocation
mov rax, 200000h        ; 2MB page size
mov rbx, page_address   ; Must be 2MB aligned

; Huge page allocation
mov rax, 40000000h      ; 1GB page size
mov rbx, huge_page_addr ; Must be 1GB aligned

; Page size detection
cpuid                   ; Check processor capabilities
test edx, 8             ; Test PSE bit (Page Size Extension)
jnz large_pages_supported

El uso de páginas grandes requiere una cuidadosa consideración de la alineación de la memoria, estrategias de asignación y soporte del sistema operativo. Las aplicaciones que pueden utilizar páginas grandes suelen ver mejoras significativas en el rendimiento de las cargas de trabajo intensivas en la memoria.

SIMD y procesamiento vectorial

SSE/AVX Integración

Los procesadores x86-64 incluyen capacidades integrales de SIMD (Instrucción única, datos múltiples) a través de conjuntos de instrucciones SSE, AVX y AVX-512. Estas extensiones permiten el procesamiento paralelo de múltiples elementos de datos en una sola instrucción, proporcionando importantes beneficios de rendimiento para aplicaciones multimedia, informática científica y criptográficas.

; SSE operations (128-bit vectors)
movaps xmm0, [source]   ; Load 4 packed single-precision floats
addps xmm0, xmm1        ; Add 4 floats in parallel
movaps [dest], xmm0     ; Store result

; AVX operations (256-bit vectors)
vmovaps ymm0, [source]  ; Load 8 packed single-precision floats
vaddps ymm0, ymm0, ymm1 ; Add 8 floats in parallel
vmovaps [dest], ymm0    ; Store result

; Integer SIMD operations
movdqa xmm0, [int_array] ; Load 4 packed 32-bit integers
paddd xmm0, xmm1        ; Add 4 integers in parallel
movdqa [result], xmm0   ; Store result

La programación SIMD requiere comprensión de los requisitos de alineación de datos, selección de instrucciones y estrategias de vectorización. El uso eficaz de las instrucciones SIMD puede proporcionar mejoras de rendimiento 4x, 8x o incluso 16x para algoritmos adecuados.

Advanced Vector Extensions

AVX y AVX-512 proporcionan una mayor capacidad de procesamiento de vectores con registros más amplios y operaciones más sofisticadas. Estas extensiones incluyen soporte para operaciones enmascaradas, instrucciones de recogida/scatter y funciones especializadas para dominios de aplicaciones específicos.

; AVX-512 operations (512-bit vectors)
vmovaps zmm0, [source]  ; Load 16 packed single-precision floats
vaddps zmm0, zmm0, zmm1 ; Add 16 floats in parallel
vmovaps [dest], zmm0    ; Store result

; Masked operations
kmovw k1, eax           ; Load mask register
vaddps zmm0\\\\{k1\\\\}, zmm1, zmm2 ; Conditional addition based on mask

; Gather operations
vgatherdps zmm0\\\\{k1\\\\}, [rsi+zmm1*4] ; Gather floats using index vector

La programación AVX-512 requiere una cuidadosa atención al soporte de procesador, consideraciones térmicas y efectos de escalado de frecuencia que pueden afectar el rendimiento general del sistema.

Programación de sistemas y seguridad

Registros de control y Estado del sistema

x86-64 ofrece amplias capacidades de control del sistema mediante registros de control, registros específicos de modelo e instrucciones del sistema. Estas características permiten la aplicación del sistema operativo, la aplicación de la seguridad y la vigilancia del desempeño.

; Control register access
mov rax, cr0            ; Read control register 0
or rax, 1               ; Set PE bit (Protection Enable)
mov cr0, rax            ; Enable protected mode

mov rax, cr4            ; Read control register 4
or rax, 200h            ; Set OSFXSR bit (OS FXSAVE/FXRSTOR support)
mov cr4, rax            ; Enable SSE support

; Model-specific register access
mov rcx, 1Bh            ; IA32_APIC_BASE MSR
rdmsr                   ; Read MSR (result in EDX:EAX)
or eax, 800h            ; Set APIC Global Enable
wrmsr                   ; Write MSR

La programación del sistema requiere entender los niveles de privilegios, los mecanismos de protección de la memoria y las interfaces de hardware que forman la base de la funcionalidad del sistema operativo.

Características de seguridad y mitigación

Los procesadores modernos x86-64 incluyen funciones de seguridad de hardware diseñadas para mitigar diversos vectores de ataque, incluyendo flujos de amortiguación, programación orientada hacia el retorno y ataques de canal lateral.

; Control Flow Integrity (Intel CET)
endbr64                 ; End branch instruction (indirect branch target)
wrss rax, [rbx]         ; Write to shadow stack
rdsspq rax              ; Read shadow stack pointer

; Memory Protection Keys (Intel MPK)
mov eax, 0              ; Protection key 0
mov ecx, 0              ; Access rights
wrpkru                  ; Write protection key rights

; Pointer Authentication (future/ARM-inspired)
; Conceptual - not yet in x86-64
; pacia rax, rbx        ; Sign pointer in RAX with key in RBX
; autia rax, rbx        ; Authenticate pointer

La utilización de las funciones de seguridad requiere coordinación entre las capacidades de hardware, el apoyo al sistema operativo y el diseño de aplicaciones para proporcionar una protección eficaz contra las técnicas modernas de ataque.

Técnicas de optimización del rendimiento

Selección de instrucciones y programación

Optimizar el código de montaje x86-64 requiere comprensión de la microarquitectura del procesador, los retrasos de la instrucción y las capacidades de unidad de ejecución. Los procesadores modernos x86-64 utilizan sofisticados motores de ejecución fuera de orden que pueden ocultar muchos detalles de optimización, pero una cuidadosa selección de instrucciones y programación todavía pueden proporcionar beneficios de rendimiento significativos.

; Optimized instruction selection
lea rax, [rbx+rcx]      ; Faster than mov+add for address calculation
shl rax, 3              ; Faster than imul rax, 8 for power-of-2 multiply
test rax, rax           ; Faster than cmp rax, 0 for zero test

; Loop optimization
align 16                ; Align loop entry point
loop_start:
    ; Unroll loop body for better throughput
    mov rax, [rsi]      ; Load first element
    add rax, [rsi+8]    ; Add second element
    mov [rdi], rax      ; Store result
    mov rax, [rsi+16]   ; Load third element
    add rax, [rsi+24]   ; Add fourth element
    mov [rdi+8], rax    ; Store result

    add rsi, 32         ; Advance source pointer
    add rdi, 16         ; Advance destination pointer
    sub rcx, 4          ; Decrement counter by 4
    jnz loop_start      ; Continue if not zero

Desarrollar, reordenar instrucciones y asignar un registro cuidadoso puede mejorar significativamente el rendimiento de las secciones de código computacionalmente intensivo.

Pautas de optimización y acceso a la memoria

Comprender la jerarquía de caché y los patrones de acceso a la memoria es crucial para lograr un rendimiento óptimo en aplicaciones x86-64. El sistema de caché del procesador incluye múltiples niveles con diferentes características que afectan el rendimiento del acceso a la memoria.

; Cache-friendly memory access
; Sequential access pattern (cache-friendly)
mov rsi, array_start
mov rcx, element_count
sequential_loop:
    mov rax, [rsi]      ; Load element
    ; Process element
    add rsi, 8          ; Move to next element
    dec rcx
    jnz sequential_loop

; Prefetch instructions for cache optimization
prefetcht0 [rsi+64]     ; Prefetch to L1 cache
prefetcht1 [rsi+128]    ; Prefetch to L2 cache
prefetcht2 [rsi+256]    ; Prefetch to L3 cache
prefetchnta [rsi+512]   ; Prefetch non-temporal (bypass cache)

La utilización eficaz de caché requiere comprensión de los tamaños de la línea de caché, estrategias prefetch y patrones de acceso a la memoria que minimizan las faltas de caché y maximizan la utilización del ancho de banda de memoria.

El lenguaje de montaje x86-64 proporciona una plataforma completa y potente para aplicaciones informáticas modernas, combinando el rico conjunto de instrucciones patrimonio de x86 con las capacidades mejoradas necesarias para la computación de 64 bits. Su conjunto de registro ampliado, mejores convenciones de llamadas, funciones avanzadas de gestión de memoria y amplias capacidades SIMD permiten a los desarrolladores crear aplicaciones de alto rendimiento que utilicen plenamente las capacidades de procesador modernos. La maestría de la programación de montaje x86-64 es esencial para el desarrollo a nivel de sistema, las aplicaciones críticas de rendimiento, la investigación de seguridad y cualquier dominio que requiera el control directo del hardware y la utilización óptima de los recursos. La evolución continua de la arquitectura a través de nuevas extensiones de conjunto de instrucciones y funciones de seguridad asegura su relevancia para futuros retos de cálculo al tiempo que mantiene la compatibilidad y ventajas de los ecosistemas que han hecho x86-64 la plataforma de computación dominante.