Retour à l'accueil

Assembleur x86-64 GUI X11 fasmg

L'article décrit la création d'une GUI minimale en assembleur x86-64 avec le protocole X11 en utilisant fasmg. Macros pour vararg printf, appels système et optimisation de structures pour mmap sont discutés. Détails sur la construction debug/release dans VSCode et le débogage dans Cutter.

GUI minimale en assembleur : X11 + optimisation fasmg
Advertisement 728x90

Interface graphique minimale en assembleur x86-64 avec X11 : Optimisation pour fasmg

Les développeurs de code bas niveau sont souvent confrontés au défi de minimiser la taille des fichiers exécutables tout en conservant les fonctionnalités. Cet article explore la création d'une interface graphique minimale en assembleur x86-64 en utilisant le protocole X11. Nous utilisons fasmg pour générer un binaire compact sans éditeur de liens, mmap pour l'allocation dynamique de mémoire et des macros pour simplifier les appels système.

L'objectif est une fenêtre graphique avec du texte, plus petite que les implémentations originales. L'accent est mis sur la lisibilité du code pour les développeurs de niveau intermédiaire à senior : structures de requêtes X11, compatibilité ABI et optimisation de la copie des données.

Configuration de l'environnement de développement

Compilation dans VSCode avec des tâches pour les modes release et debug. Release : DEBUG=0, debug : DEBUG=1 avec génération de symboles DWARF.

Google AdInline article slot
{
    "label": "Créer l'exécutable de release",
    "type": "shell",
    "command": "chmod",
    "args": ["+x", "${fileBasenameNoExtension}"],
    "dependsOn": "Compilation release avec fasmg"
}

Débogage dans Cutter avec launch.json :

{
    "name": "Lancer Cutter",
    "type": "node",
    "request": "launch",
    "preLaunchTask": "Compilation debug avec fasmg",
    "runtimeExecutable": "Cutter.AppImage",
    "runtimeArgs": [
        "${fileDirname}/${fileBasenameNoExtension}",
        "--analysis", "2",
        "--arch", "x86",
        "--bits", "64"
    ]
}

Appuyez sur Ctrl+Maj+T pour les compilations debug (fichiers .asm).

Macros pour le débogage et la journalisation

Liaison dynamique avec libc uniquement en mode debug :

Google AdInline article slot
include 'dynamic/import64.inc'
if DEBUG
    interpreter '/lib64/ld-linux-x86-64.so.2'
    needed 'libc.so.6'
    import printf
end if

Macros pour printf à arguments variables avec support de %d, %f, %e, %g, %a. COUNT_ARGS_TO compte les arguments, GET_VARARG_TO les récupère par index.

Conversion float/double en IEEE-754 via la mémoire virtuelle de fasm :

macro MOVQ_IMM reg, val
    local bits
    virtual at 0
        dq val
        load bits qword from 0
    end virtual
    mov rax, bits
    movq reg, rax
end macro

La macro principale VARG_FUNC analyse la chaîne de format, distribuant les arguments aux registres selon l'ABI System V (xmm0-xmm7 pour les flottants, rsi/rdx/... pour les entiers). DEBUG_MSG est un wrapper pour les logs.

Google AdInline article slot

Structures de requêtes X11

Une structure FULL_LAYOUT unifiée contient toutes les requêtes nécessaires :

struct FULL_LAYOUT
    ridBase             dd  0
    ridMask             dd  0
    windowRootId        dd  0
    rootVisualId        dd  0
    gcId                dd  0
    exposed             db  0
    create_window_req   X11_CREATE_WINDOW
    draw_string_req     STRING_TO_DRAW
    handshake           X11_HANDSHAKE
    gc_request          X11_CREATE_GC
    addr_un             SOCKADDR_UN
    map_window_req      X11_MAP_WINDOW
    union
        free    rb     HEAP_SIZE - ($ - create_window_req)
        setup   X11_SETUP
        pollfd  POLLFD
    endu
ends

Les champs sont ordonnés pour minimiser le code de copie. Layout dans r12, sockets dans r13+.

Macro universelle d'appel système

MAKE_SYSCALL automatise la configuration des registres (rdi, rsi, rdx, r10, r8, r9) avec support pour ptr [c], [c], 0 :

macro MAKE_SYSCALL scall, args&
    iterate arg, args
        if % = 1
            match =ptr [c], arg
                lea    rdi, [c]
            else match [c], arg
                mov     rdi, [c]
            else match =0, arg
                xor    rdi, rdi
            else
                mov    rdi, arg
            end match
        ; similaire pour rsi, rdx, r10...
    end iterate
    ; syscall scall
end macro

Optimisations de taille et de performance

  • mmap au lieu de données statiques : page de 4 Ko pour toutes les structures X11.
  • movsb pour la copie : regrouper les champs minimise les appels.
  • Registres pour les constantes : r12-r15 restent inchangés.
  • Valeurs par défaut dans le binaire : les macros génèrent uniquement les champs utilisés.
  • Police fixe : X11 sélectionne automatiquement "fixed".

Avantages de fasmg : code compact, macros, pas d'éditeur de liens.

Points clés à retenir

  • Les structures de requêtes X11 sont ordonnées pour une copie movsb optimale.
  • Macro printf à arguments variables avec conversion IEEE-754 via mémoire virtuelle.
  • Macro d'appel système universelle réduit le code répétitif de 70 %.
  • mmap 4 Ko couvre toutes les structures sans données statiques dans le binaire.
  • Compilations debug/release dans VSCode + Cutter pour le reverse engineering.

— Editorial Team

Advertisement 728x90

Lire ensuite