返回首页

汇编器 x86-64 GUI X11 fasmg

文章描述使用 fasmg 在 x86-64 汇编器上通过 X11 协议创建最小 GUI。讨论了 vararg printf、系统调用和 mmap 结构优化的宏。在 VSCode 中 debug/release 构建以及在 Cutter 中调试的细节。

汇编器上的最小 GUI:X11 + fasmg 优化
Advertisement 728x90

使用X11在x86-64汇编中实现最小化GUI:针对fasmg的优化

开发者在编写底层代码时,常面临在保持功能性的同时最小化可执行文件大小的挑战。本文探讨了如何使用X11协议在x86-64汇编中创建一个最小化的GUI。我们利用fasmg生成无需链接器的紧凑二进制文件,使用mmap进行动态内存分配,并通过宏简化系统调用。

目标是创建一个带文本的GUI窗口,比原始实现更小。重点在于为中高级开发者提供代码可读性:X11请求结构、ABI兼容性和数据复制优化。

设置开发环境

在VSCode中构建,包含发布和调试模式的任务。发布模式:DEBUG=0;调试模式:DEBUG=1,并生成DWARF符号。

Google AdInline article slot
{
    "label": "生成发布可执行文件",
    "type": "shell",
    "command": "chmod",
    "args": ["+x", "${fileBasenameNoExtension}"],
    "dependsOn": "使用fasmg进行发布构建"
}

在Cutter中调试,使用launch.json:

{
    "name": "启动Cutter",
    "type": "node",
    "request": "launch",
    "preLaunchTask": "使用fasmg进行调试构建",
    "runtimeExecutable": "Cutter.AppImage",
    "runtimeArgs": [
        "${fileDirname}/${fileBasenameNoExtension}",
        "--analysis", "2",
        "--arch", "x86",
        "--bits", "64"
    ]
}

按Ctrl+Shift+T进行调试构建(针对.asm文件)。

调试和日志宏

仅在调试模式下动态链接libc:

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

支持%d、%f、%e、%g、%a的变参printf宏。COUNT_ARGS_TO计算参数数量,GET_VARARG_TO按索引检索参数。

通过fasm虚拟内存将浮点/双精度转换为IEEE-754:

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

主VARG_FUNC宏解析格式字符串,根据System V ABI(浮点数使用xmm0-xmm7,整数使用rsi/rdx/...)将参数分配到寄存器。DEBUG_MSG是日志的包装器。

Google AdInline article slot

X11请求结构

统一的FULL_LAYOUT结构包含所有必要请求:

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

字段排序以最小化复制代码。布局在r12中,套接字在r13+中。

通用系统调用宏

MAKE_SYSCALL自动化设置寄存器(rdi、rsi、rdx、r10、r8、r9),支持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
        ; 类似处理rsi、rdx、r10...
    end iterate
    ; syscall scall
end macro

大小和性能优化

  • 使用mmap替代静态数据:4KB页面用于所有X11结构。
  • 使用movsb进行复制:分组字段以最小化调用。
  • 寄存器存储常量:r12-r15保持不变。
  • 二进制中的默认值:宏仅生成使用的字段。
  • 固定字体:X11自动选择“fixed”。

fasmg的优势:代码紧凑、宏支持、无需链接器。

关键要点

  • X11请求结构排序以实现最优movsb复制。
  • 通过虚拟内存进行IEEE-754转换的变参printf宏。
  • 通用系统调用宏减少70%的样板代码。
  • 4KB mmap覆盖所有结构,无需二进制中的静态数据。
  • VSCode + Cutter中的调试/发布构建,便于逆向工程。

— Editorial Team

Advertisement 728x90

继续阅读