Assembly
Introduction à l'assembleur

Introduction à l'assembleur

Registres sBPF et modèle de mémoire

Lorsque votre programme sBPF s'exécute, il fonctionne avec deux mécanismes de stockage principaux : 11 registres haute vitesse intégrés au processeur et des régions de mémoire organisées qui contiennent tout le reste.

Registers

Les registres sont comme 11 emplacements de stockage numérotés (r0 à r10) intégrés directement dans le processeur. Chacun contient une seule valeur de 64 bits et offre un accès instantané sans délais. Lorsque vous exécutez add64 r1, r2, le processeur récupère immédiatement les valeurs des deux registres et effectue le calcul.

Le compromis est simple : vous n'avez que 11 cases au total, vous devez donc les utiliser stratégiquement pour les valeurs avec lesquelles vous travaillez activement.

sBPF attribue des rôles spécifiques à chaque registre :

RegistreRôleSauvegardé par l'appelé ?Notes d'utilisation
r0Valeur de retourNonRésultats de fonction, valeurs de retour des appels système
r1Pointeur de tampon d'entréeNonPointe vers 0x400000000 à l'entrée
r2-r5Brouillon/argumentsNonArguments de fonction auxiliaire, valeurs temporaires
r6-r9Usage généralOuiDoit être préservé entre les appels
r10Pointeur de trameOui, lecture seuleBase de la pile, ne peut pas être modifié directement

Les registres r6 à r9 sont sauvegardés par l'appelé, ce qui signifie que leurs valeurs persistent entre les appels de fonction. Utilisez-les pour les données importantes qui doivent survivre aux invocations de fonction.

Les registres restants (r0-r5) sont écrasés pendant les appels système et les appels de fonction.

Le registre r10 est « spécial » car il sert de pointeur de trame, pointant vers la base de votre espace de pile et restant en lecture seule. Vous accédez aux variables de la pile en utilisant des décalages négatifs comme [r10 - 8] et [r10 - 16].

Mémoire

Alors que les registres contiennent les valeurs activement utilisées, la mémoire stocke tout le reste. sBPF organise la mémoire en régions fixes avec des dispositions identiques dans tous les programmes :

RégionAdresse de départObjectifTaille/Notes
Texte0x100000000Code et données en lecture seuleProgramme binaire
Pile0x200000000Variables locales4 Kio par cadre de pile, avec une profondeur d'appel maximale de 64
Tas0x300000000Allocation dynamique32 Kio
Entrée0x400000000Paramètres du programmeComptes sérialisés et données d'instruction
  • La région de texte contient votre code exécutable et les données en lecture seule comme les constantes de chaîne. Les données définies avec des directives .quad résident généralement ici.

  • La région de pile héberge les variables locales. Avec r10 pointant vers la base de la pile, vous accédez aux variables locales en utilisant des décalages négatifs : [r10 - 16], [r10 - 24], etc.

  • La région d'entrée contient les paramètres de votre programme. À l'entrée, r1 pointe vers cette région (0x400000000), vous permettant de lire les données de compte sérialisées et les paramètres d'instruction transmis à votre programme.

Cette disposition fixe offre trois avantages clés : la sécurité grâce à l'isolation de la mémoire entre les programmes, le déterminisme avec des adresses identiques sur tous les validateurs, et la performance grâce aux optimisations du compilateur pour des emplacements connus.

Toute tentative d'accès à des adresses non mappées déclenche une violation d'accès et la transaction échoue.

Utilisation des registres et de la mémoire

Voici comment les registres et la mémoire fonctionnent ensemble en pratique :

sbpf
.globl entrypoint
entrypoint:
    // On entry: r1 points to input data at 0x400000000
    
    ldxdw r0, [r1 + 0]      // Load first 8 bytes from input into r0
    mov64 r2, 42            // Put 42 in register r2
    add64 r0, r2            // Add them: r0 = r0 + r2
    
    stxdw [r10 - 8], r0     // Store result on stack
    mov64 r0, 0             // Return success
    exit

Ce programme démontre le modèle typique :

  • Utilise le registre r1 (pointeur d'entrée) pour lire depuis la mémoire

  • Utilise les registres r0 et r2 pour les calculs

  • Utilise le registre r10 (pointeur de cadre) pour accéder à la mémoire de la pile

  • Renvoie le résultat dans le registre r0

Le flux de travail suit un modèle cohérent : charger les données de la mémoire dans les registres, effectuer des calculs avec les registres, puis stocker les résultats en mémoire lorsque nécessaire.

Utilisation de la pile

La pile fonctionne avec r10 comme pointeur de trame, pointant vers la base de votre trame de pile actuelle (l'adresse la plus élevée). Les variables locales utilisent des décalages négatifs :

sbpf
// Store a value on the stack
mov64 r0, 42
stxdw [r10 - 8], r0         // Store at first stack slot

// Load it back
ldxdw r1, [r10 - 8]         // Load from first stack slot

Les emplacements de pile font généralement 8 octets de large, donc les variables consécutives utilisent des décalages comme [r10 - 8], [r10 - 16], [r10 - 24], et ainsi de suite.

Entrée et sortie du programme

L'exécution de votre programme commence au symbole marqué avec .globl (généralement entrypoint). L'état initial des registres est minimal et prévisible :

sbpf
.globl entrypoint
entrypoint:
    // On entry:
    // r1 = 0x400000000 (input buffer pointer)
    // r10 = 0x200001000 (0x200000000 stack start + 0x1000 4KiB frame size)
    // r0, r2-r9 = 0 (all other registers zeroed)

    // Your program logic here

    mov64 r0, 0     // Success code (0 = SUCCESS)
    exit            // Return to runtime

Le comportement de sortie dépend de la profondeur d'appel :

  • À la profondeur d'appel 0, la sortie termine le programme avec r0 comme code de résultat.

  • À des niveaux d'appel plus profonds, la sortie agit comme une instruction return, restaurant les registres sauvegardés par l'appelant (r6-r9) et le pointeur de trame de l'appelant (r10) avant de poursuivre l'exécution à l'adresse de retour.

Le runtime gère automatiquement la configuration et le nettoyage grâce à un code implicite de prologue et d'épilogue, y compris la configuration de l'état initial des registres et le traitement final du retour.

Blueshift © 2025Commit: e573eab