Aller au contenu

x86-64 Langue d'assemblage (64 bits)

Copier toutes les commandes Générer PDF

Le langage d'assemblage x86-64 représente le pinacle évolutif de la famille d'architecture x86, étendant l'instruction fondamentale 32-bit x86 installée dans l'ère de l'informatique 64-bit tout en maintenant une compatibilité vers l'arrière complète et en introduisant de puissantes nouvelles capacités qui définissent l'informatique moderne. Également connu sous le nom d'AMD64 (développé par AMD) ou Intel 64 (implémentation d'Intel), cette architecture est devenue la plate-forme dominante pour l'informatique de bureau, l'infrastructure serveur et les applications informatiques de haute performance dans le monde entier. La transition de l'informatique 32 bits à l'informatique 64 bits a apporté des changements fondamentaux qui vont bien au-delà de l'expansion de l'espace d'adresse simple, en introduisant de nouveaux registres, un codage d'instruction amélioré, des conventions d'appel améliorées et des caractéristiques architecturales qui permettent des performances et une évolutivité sans précédent. Comprendre le langage d'assemblage x86-64 est essentiel pour les programmeurs de systèmes, les chercheurs en sécurité, les ingénieurs de performance et les développeurs travaillant sur des applications qui exigent une efficacité maximale, un contrôle matériel direct ou une intégration profonde du système. Cette référence complète offre une couverture détaillée de la programmation d'assemblage x86-64, des améliorations architecturales sur 32 bits x86 aux techniques d'optimisation avancées qui tirent parti de toutes les capacités des processeurs modernes 64 bits.

Evolution architecturale et améliorations de 64 bits

Contexte historique et objectifs de conception

Le développement de l'architecture x86-64 est ressorti de la reconnaissance que les limitations informatiques 32 bits finiraient par freiner la croissance des applications informatiques, en particulier dans les domaines nécessitant de grands espaces de mémoire, de l'informatique haute performance et des applications serveur qui manipulent des ensembles de données massifs. L'introduction par AMD de l'architecture AMD64 en 2003 a marqué un moment crucial dans l'histoire de l'informatique, fournissant un chemin d'évolution propre à partir de 32 bits x86 tout en introduisant des améliorations architecturales qui répondaient aux limites de longue date de la conception x86. Le succès de l'architecture a conduit à une large adoption dans l'ensemble de l'industrie, avec Intel implémentant des extensions compatibles dans leur architecture Intel 64, établissant x86-64 comme la norme pour les plates-formes informatiques modernes.

La philosophie de conception derrière x86-64 a mis l'accent sur le maintien d'une compatibilité arrière complète avec le code existant de x86 32 bits tout en introduisant des améliorations qui permettraient d'améliorer l'évolutivité et les performances futures. Cette approche a permis de préserver les investissements logiciels existants et de tirer parti des nouvelles applications 64 bits. L'architecture introduit plusieurs modes d'exploitation, dont le mode ancien (compatibilité 32 bits), le mode de compatibilité (applications 32 bits dans les systèmes d'exploitation 64 bits) et le mode 64 bits (opération 64 bits native), offrant une flexibilité pour les environnements informatiques mixtes pendant la période de transition.

Améliorations de l'architecture du registre

L'amélioration la plus visible en x86-64 est l'expansion spectaculaire du jeu de registres, qui double le nombre de registres à usage général de huit à seize et étend tous les registres à une largeur de 64 bits. Cette extension répond à l'une des limites les plus importantes de la programmation 32 bits x86, où la pression d'enregistrement a souvent forcé l'accès fréquent à la mémoire et des possibilités d'optimisation limitées. Le nouvel ensemble de registres comprend les huit registres originaux (RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP) étendus à 64 bits, plus huit registres supplémentaires (R8 à R15) qui fournissent des ressources de calcul supplémentaires.

; 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 convention de désignation des registres suit un schéma systématique qui maintient la compatibilité avec le code 32 bits tout en fournissant une identification claire des tailles d'exploitation. Une caractéristique architecturale importante est que les opérations 32 bits sur les registres 64 bits éliminent automatiquement les 32 bits supérieurs, fournissant une sémantique propre pour les opérations de taille mixte et éliminant les vulnérabilités de sécurité potentielles du contenu non initialisé des registres.

Modèle de mémoire et espace d'adresse

x86-64 fournit un espace d'adressage largement élargi qui supporte théoriquement l'adressage 64 bits, bien que les implémentations actuelles prennent généralement en charge les adresses virtuelles 48 bits et les adresses physiques 40-52 bits. Cette extension de la limite de 4 Go de systèmes 32 bits à plusieurs téraoctets de mémoire adressable permet des applications qui étaient auparavant impossibles, y compris des bases de données à grande échelle, des applications informatiques scientifiques et des charges de travail de serveurs à forte intensité de mémoire.

; 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
```_

L'introduction de l'adressage RIP-relative représente une amélioration architecturale significative qui permet la génération de code indépendant de position et simplifie la liaison dynamique. Ce mode d'adressage calcule les adresses de mémoire par rapport au pointeur d'instruction actuel, éliminant la nécessité d'une adresse absolue dans de nombreux scénarios et améliorant la portabilité du code.

## Ensemble d'instructions amélioré et codage

### Préfixe REX et codage des instructions

x86-64 introduit l'octet de préfixe REX qui permet l'accès à des registres étendus et des tailles d'opérandes 64 bits tout en maintenant la compatibilité avec l'encodage des instructions existantes. Le préfixe REX apparaît avant l'opcode d'instruction et contient des champs qui spécifient le mode d'opération 64 bits, l'accès étendu au registre et des fonctions d'adressage supplémentaires. Comprendre l'utilisation du préfixe REX est crucial pour les programmeurs d'assemblage travaillant avec le jeu de registres étendu et les opérations 64 bits.

```asm
; 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
```_

Le préfixe REX permet plusieurs fonctionnalités importantes, dont l'accès aux registres R8-R15, la spécification de taille d'opérande 64 bits et les modes d'adressage étendus. Le préfixe est automatiquement généré par les assembleurs au besoin, mais la compréhension de sa fonction aide à optimiser la sélection des instructions et la compréhension des implications de la taille du code.

### Nouvelles instructions et capacités

x86-64 introduit plusieurs nouvelles instructions et améliore les instructions existantes pour profiter des capacités 64 bits. Ces améliorations comprennent de nouveaux modes d'adressage, un support de valeur immédiat étendu et des instructions optimisées pour le fonctionnement 64 bits. L'architecture supprime également certaines instructions qui sont incompatibles avec le fonctionnement 64 bits tout en ajoutant de nouvelles fonctionnalités qui améliorent les performances et les fonctionnalités.

```asm
; 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

L'instruction MOVSXD fournit une extension de signal efficace de 32 bits à 64 bits, répondant à une exigence commune dans la programmation 64 bits. Les instructions de chaînes améliorées fonctionnent sur des quantités de 64 bits, ce qui améliore les performances des opérations de données en vrac sur des données alignées de 64 bits.

Conventions d'appel et ABI

Système V ABI (Unix/Linux)

L'interface binaire d'application System V définit la convention d'appel standard pour les systèmes de type Unix fonctionnant sur x86-64, établissant des protocoles cohérents de passage des paramètres, d'utilisation des registres et de gestion des piles. Cet ABI profite de l'ensemble élargi de registres pour passer les paramètres de fonction dans les registres plutôt que sur la pile, améliorant sensiblement la performance des appels de fonction par rapport aux conventions 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

Le système V ABI nécessite un alignement de la pile à 16 octets aux limites des appels de fonction, assurant une performance optimale pour les opérations SIMD et maintenant la compatibilité avec le code généré par le compilateur. L'ABI définit également les registres sauvegardés par les appelants (RBX, RBP, R12-R15) qui doivent être conservés dans les appels de fonctions et les registres sauvegardés par les appelants qui peuvent être modifiés par des fonctions appelées.

Microsoft x64 ABI (Windows)

La convention d'appel Microsoft x64 diffère du système V ABI de plusieurs façons importantes, reflétant différentes priorités de conception et exigences de compatibilité. Comprendre ces différences est crucial pour le développement de plates-formes croisées et lors de l'interface avec les API système 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

L'ABI de Microsoft nécessite une allocation d'espace d'ombre pour les quatre premiers paramètres, même lorsqu'ils sont passés dans des registres. Cet espace d'ombre fournit un stockage pour les paramètres de registre si la fonction appelée doit les déverser dans la mémoire, simplifiant l'implémentation de la fonction et le débogage.

Gestion avancée de la mémoire

Mémoire virtuelle et pagination

x86-64 implémente un système de mémoire virtuelle sophistiqué qui prend en charge plusieurs tailles de pages et des fonctionnalités avancées de gestion de la mémoire. L'architecture utilise une structure de table de quatre niveaux (dans la plupart des implémentations) qui permet une traduction efficace des adresses virtuelles aux adresses physiques tout en prenant en charge l'espace d'adresse élargi.

; 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

Comprendre la gestion de la mémoire virtuelle est crucial pour la programmation au niveau du système, les pilotes de périphériques et les applications qui nécessitent un contrôle précis sur le comportement de la mémoire. L'unité de gestion de la mémoire x86-64 fournit des fonctionnalités pour la protection de la mémoire, le contrôle de cache et l'optimisation des performances qui peuvent avoir un impact significatif sur le comportement de l'application.

Support de grande page

x86-64 prend en charge plusieurs tailles de pages, y compris les pages standard 4KB, 2MB grandes pages, et 1 Go grandes pages. Une grande prise en charge des pages peut offrir d'importants avantages en termes de performances pour les applications ayant une grande empreinte mémoire en réduisant la pression TLB et en améliorant l'efficacité d'accès à la mémoire.

; 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

L'utilisation d'une grande page nécessite un examen attentif de l'alignement de la mémoire, des stratégies d'allocation et du support du système d'exploitation. Les applications qui peuvent utiliser efficacement de grandes pages voient souvent des améliorations importantes de la performance dans les charges de travail à forte intensité de mémoire.

SIMD et traitement vectoriel

SSE/AVX Intégration

Les processeurs x86-64 comprennent des fonctions SIMD complètes (instruction unique, données multiples) grâce aux ensembles d'instructions SSE, AVX et AVX-512. Ces extensions permettent le traitement parallèle de plusieurs éléments de données dans une seule instruction, offrant des avantages de performance importants pour les applications multimédia, l'informatique scientifique et cryptographique.

; 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 programmation SIMD exige une compréhension des exigences d'alignement des données, de la sélection des instructions et des stratégies de vectorisation. Utilisation efficace des instructions SIMD peut fournir 4x, 8x, ou même 16x des améliorations de performance pour les algorithmes appropriés.

Extensions vectorielles avancées

AVX et AVX-512 offrent des capacités de traitement vectoriel améliorées avec des registres plus larges et des opérations plus sophistiquées. Ces extensions comprennent le support pour les opérations masquées, les instructions de collecte/diffusion et les fonctions spécialisées pour des domaines d'application spécifiques.

; 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 programmation AVX-512 nécessite une attention particulière au support du processeur, aux considérations thermiques et aux effets d'échelle de fréquence qui peuvent avoir une incidence sur la performance globale du système.

Programmation et sécurité du système

Registres de contrôle et État du système

x86-64 offre de vastes capacités de contrôle du système grâce à des registres de contrôle, des registres spécifiques à un modèle et des instructions de système. Ces caractéristiques permettent la mise en oeuvre du système d'exploitation, l'application de la sécurité et la surveillance du rendement.

; 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 programmation du système nécessite la compréhension des niveaux de privilèges, des mécanismes de protection de la mémoire et des interfaces matérielles qui constituent la base de la fonctionnalité du système d'exploitation.

Caractéristiques de sécurité et mesures d'atténuation

Les processeurs modernes x86-64 comprennent des fonctions de sécurité du matériel conçues pour atténuer divers vecteurs d'attaque, y compris les débordements de tampon, la programmation orientée retour et les attaques de canaux latéraux.

; 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

L'utilisation des fonctions de sécurité nécessite une coordination entre les capacités matérielles, le soutien du système d'exploitation et la conception d'applications pour assurer une protection efficace contre les techniques d'attaque modernes.

Techniques d'optimisation des performances

Sélection et calendrier des instructions

L'optimisation du code d'assemblage x86-64 nécessite une compréhension des capacités de microarchitecture du processeur, des latences d'instruction et des unités d'exécution. Les processeurs modernes x86-64 utilisent des moteurs d'exécution hors-commande sophistiqués qui peuvent masquer de nombreux détails d'optimisation, mais une sélection et un calendrier d'instructions soignés peuvent tout de même fournir des avantages de performance importants.

; 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

Le déroulement des boucles, la réorganisation des instructions et l'attribution prudente des registres peuvent améliorer considérablement les performances des sections de code à forte intensité de calcul.

Optimisation des caches et modèles d'accès à la mémoire

Comprendre la hiérarchie du cache et les modèles d'accès à la mémoire est crucial pour obtenir des performances optimales dans les applications x86-64. Le système cache du processeur comprend plusieurs niveaux avec différentes caractéristiques qui affectent les performances d'accès à la mémoire.

; 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)

L'utilisation efficace du cache nécessite une compréhension de la taille des lignes de cache, des stratégies préfettch et des modèles d'accès à la mémoire qui minimisent les lacunes du cache et maximisent l'utilisation de la bande passante de la mémoire.

Le langage d'assemblage x86-64 offre une plate-forme complète et puissante pour les applications informatiques modernes, combinant le riche patrimoine de l'ensemble d'instructions de x86 avec les capacités améliorées requises pour l'informatique 64 bits. Son ensemble de registres élargi, ses conventions d'appel améliorées, ses fonctions avancées de gestion de mémoire et ses vastes capacités SIMD permettent aux développeurs de créer des applications performantes qui utilisent pleinement les capacités de processeur modernes. La maîtrise de la programmation d'assemblage x86-64 est essentielle pour le développement au niveau du système, les applications critiques pour la performance, la recherche sur la sécurité et tout domaine nécessitant un contrôle matériel direct et une utilisation optimale des ressources. L'évolution continue de l'architecture grâce aux nouvelles extensions et aux nouvelles fonctions de sécurité des ensembles d'instructions assure sa pertinence pour les défis informatiques futurs tout en maintenant la compatibilité et les avantages écosystémiques qui ont fait de x86-64 la plateforme informatique dominante.