Minimální GUI v assembleru x86-64 s X11: optimalizace pro fasmg
Vývojáři píšící nízkoúrovňový kód často řeší minimalizaci velikosti spustitelných souborů při zachování funkčnosti. V tomto článku si ukážeme vytvoření minimálního GUI v assembleru x86-64 s využitím protokolu X11. Použijeme fasmg pro generování kompaktního binárního souboru bez linkeru, mmap pro dynamické přidělování paměti a makra pro zjednodušení systémových volání.
Cílem je GUI okno s textem o velikosti menší než původní implementace. Zaměříme se na čitelnost kódu pro středně pokročilé a senior vývojáře: struktury požadavků X11, kompatibilita ABI, optimalizace kopírování dat.
Příprava vývojového prostředí
Sestavení v VSCode s úlohami pro release a debug režimy. Release: DEBUG=0, debug: DEBUG=1 s generováním DWARF symbolů.
{
"label": "Vytvořit release spustitelný soubor",
"type": "shell",
"command": "chmod",
"args": ["+x", "${fileBasenameNoExtension}"],
"dependsOn": "Release sestavení s fasmg"
}
Ladění v Cutter s launch.json:
{
"name": "Spustit Cutter",
"type": "node",
"request": "launch",
"preLaunchTask": "Debug sestavení s fasmg",
"runtimeExecutable": "Cutter.AppImage",
"runtimeArgs": [
"${fileDirname}/${fileBasenameNoExtension}",
"--analysis", "2",
"--arch", "x86",
"--bits", "64"
]
}
Klávesa Ctrl+Shift+T pro debug sestavení (.asm soubory).
Makra pro ladění a logování
Připojíme libc dynamicky pouze v debug:
include 'dynamic/import64.inc'
if DEBUG
interpreter '/lib64/ld-linux-x86-64.so.2'
needed 'libc.so.6'
import printf
end if
Makra pro vararg printf s podporou %d, %f, %e, %g, %a. COUNT_ARGS_TO počítá argumenty, GET_VARARG_TO extrahuje podle indexu.
Konverze float/double do IEEE-754 přes virtuální paměť 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
Hlavní makro VARG_FUNC parsuje formátovací řetězec, rozděluje argumenty do registrů podle System V ABI (xmm0-xmm7 pro float, rsi/rdx/... pro integer). DEBUG_MSG je obálka pro logy.
Struktury X11 požadavků
Jednotná struktura FULL_LAYOUT obsahuje všechny potřebné požadavky:
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
Pole jsou uspořádána pro minimalizaci kódu kopírování. Rozložení v r12, sokety v r13+.
Univerzální makro systémových volání
MAKE_SYSCALL automatizuje nastavení registrů (rdi, rsi, rdx, r10, r8, r9) s podporou 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
; analogicky pro rsi, rdx, r10...
end iterate
; syscall scall
end macro
Optimalizace velikosti a výkonu
- mmap místo statických dat: 4KB stránka pro všechny struktury X11.
- movsb pro kopírování: seskupení polí minimalizuje volání.
- Registry pro konstanty: r12-r15 se nemění.
- Výchozí hodnoty v binárním souboru: makra generují pouze použité pole.
- Pevné písmo: X11 automaticky volí "fixed".
Výhody fasmg: kompaktní kód, makra, absence linkeru.
Co je důležité
- Struktury X11 požadavků jsou uspořádány pro optimální movsb kopírování.
- Vararg printf makro s IEEE-754 konverzí přes virtuální paměť.
- Univerzální syscall makro snižuje boilerplate o 70 %.
- mmap 4KB pokrývá všechny struktury bez statických dat v binárním souboru.
- Debug/release sestavení v VSCode + Cutter pro reverzní inženýrství.
— Editorial Team
Zatím žádné komentáře.