You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Linux下用NASM x64新建窗口并绘制像素?

在Linux x64 NASM中实现X11窗口绘制像素

核心思路

Linux桌面环境依赖X11窗口系统,直接通过汇编调用X11动态库函数,结合Linux系统调用读取文件,就能实现无C/C++依赖的窗口像素绘制。以下是完整实现步骤和代码示例:

实现步骤与代码

1. 汇编代码(pixel_drawer.asm)

section .data
    ; X11相关常量
    display_name    db  0   ; 使用默认显示(:0)
    window_title    db  "Pixel Image Viewer", 0
    ; 文件路径(替换成你的0/1数据文件)
    file_path       db  "image_data.txt", 0
    ; 错误提示
    err_open        db  "Failed to open file", 10, 0
    err_read        db  "Failed to read file", 10, 0
    err_x11_init    db  "Failed to initialize X11", 10, 0

    ; 图像参数(可根据文件内容调整,或从文件头读取)
    img_width       equ 64
    img_height      equ 64
    pixel_size      equ 8   ; 每个逻辑像素放大8倍,避免太小看不清

section .bss
    display         resq 1
    window          resq 1
    gc              resq 1
    file_fd         resq 1
    file_buffer     resb img_width * img_height  ; 存储读取的0/1数据

section .text
    global _start

; 打印错误信息并退出
print_error:
    mov rsi, rdi
    call str_len
    mov rdx, rax
    mov rsi, rdi
    mov rdi, 1
    mov rax, 1
    syscall
    mov rdi, 1
    mov rax, 60
    syscall

; 计算字符串长度
str_len:
    mov rax, 0
.loop:
    cmp byte [rsi + rax], 0
    je .done
    inc rax
    jmp .loop
.done:
    ret

_start:
    ; 1. 打开文件
    mov rax, 2                  ; sys_open
    mov rdi, file_path
    mov rsi, 0                  ; O_RDONLY
    mov rdx, 0
    syscall
    cmp rax, 0
    jl print_error              ; 打开失败,打印错误
    mov [file_fd], rax

    ; 2. 读取文件内容
    mov rax, 0                  ; sys_read
    mov rdi, [file_fd]
    mov rsi, file_buffer
    mov rdx, img_width * img_height
    syscall
    cmp rax, img_width * img_height
    jne print_error             ; 读取长度不符,报错
    ; 关闭文件
    mov rax, 3                  ; sys_close
    mov rdi, [file_fd]
    syscall

    ; 3. 初始化X11连接
    extern XOpenDisplay
    mov rdi, display_name
    call XOpenDisplay
    cmp rax, 0
    je print_error
    mov [display], rax

    ; 获取默认屏幕
    extern XDefaultScreen
    mov rdi, [display]
    call XDefaultScreen
    mov rsi, rax                ; 屏幕号存到rsi,后续用

    ; 创建窗口
    extern XCreateSimpleWindow
    mov rdi, [display]
    mov rdx, 0                  ; x坐标
    mov rcx, 0                  ; y坐标
    mov r8, img_width * pixel_size  ; 窗口宽度
    mov r9, img_height * pixel_size ; 窗口高度
    push 1                      ; 边框宽度
    push 0                      ; 边框颜色(黑色)
    push 0xffffff               ; 背景颜色(白色)
    call XCreateSimpleWindow
    mov [window], rax

    ; 设置窗口标题
    extern XStoreName
    mov rdi, [display]
    mov rsi, [window]
    mov rdx, window_title
    call XStoreName

    ; 创建绘图上下文(GC)
    extern XCreateGC
    mov rdi, [display]
    mov rsi, [window]
    mov rdx, 0
    mov rcx, 0
    call XCreateGC
    mov [gc], rax

    ; 显示窗口
    extern XMapWindow
    mov rdi, [display]
    mov rsi, [window]
    call XMapWindow

    ; 刷新显示
    extern XFlush
    mov rdi, [display]
    call XFlush

    ; 4. 绘制像素
    mov rbx, 0                  ; 当前数据索引
    mov rcx, 0                  ; y坐标(逻辑像素)
.draw_y_loop:
    cmp rcx, img_height
    je .draw_done
    mov rdx, 0                  ; x坐标(逻辑像素)
.draw_x_loop:
    cmp rdx, img_width
    je .next_y

    ; 获取当前像素值(0或1)
    mov al, byte [file_buffer + rbx]
    cmp al, '1'
    jne .skip_pixel

    ; 绘制放大后的像素块(pixel_size x pixel_size)
    mov r8, rdx
    imul r8, pixel_size
    mov r9, rcx
    imul r9, pixel_size
    mov r10, 0
.fill_x:
    cmp r10, pixel_size
    je .fill_y_done
    mov r11, 0
.fill_y:
    cmp r11, pixel_size
    je .next_fill_x

    ; 调用XDrawPoint绘制单个点
    extern XDrawPoint
    mov rdi, [display]
    mov rsi, [window]
    mov rdx, [gc]
    mov rcx, r8 + r10
    mov r8, r9 + r11
    call XDrawPoint

    inc r11
    jmp .fill_y
.next_fill_x:
    inc r10
    jmp .fill_x
.fill_y_done:

.skip_pixel:
    inc rbx
    inc rdx
    jmp .draw_x_loop
.next_y:
    inc rcx
    jmp .draw_y_loop
.draw_done:

    ; 5. 等待窗口关闭事件
    extern XNextEvent
    stack_alloc equ 32          ; XEvent结构体大小至少32字节,栈对齐
    sub rsp, stack_alloc
.event_loop:
    mov rdi, [display]
    mov rsi, rsp
    call XNextEvent
    ; 检查是否是关闭事件(DestroyNotify)
    mov ax, word [rsp]          ; event.type
    cmp ax, 17                  ; DestroyNotify的类型值
    jne .event_loop

    ; 6. 清理资源
    extern XFreeGC
    mov rdi, [display]
    mov rsi, [gc]
    call XFreeGC

    extern XDestroyWindow
    mov rdi, [display]
    mov rsi, [window]
    call XDestroyWindow

    extern XCloseDisplay
    mov rdi, [display]
    call XCloseDisplay

    ; 退出程序
    mov rax, 60
    mov rdi, 0
    syscall

2. 编译与运行

  • 编译汇编文件:
    nasm -f elf64 pixel_drawer.asm -o pixel_drawer.o
    
  • 链接(需要链接X11库):
    ld -o pixel_drawer pixel_drawer.o -lX11
    
  • 准备image_data.txt文件,内容为连续的0和1,长度等于img_width * img_height(比如64x64就是4096个字符),示例片段:
    0000000000000000000000000000000000000000000000000000000000000000
    0111111001111110011111100111111001111110011111100111111001111110
    ...
    
  • 运行程序:
    ./pixel_drawer
    

关键细节说明

  • X11函数调用:通过extern声明X11库中的函数,链接时指定-lX11动态链接,无需依赖C标准库。
  • System V AMD64调用约定:参数按rdi, rsi, rdx, rcx, r8, r9顺序传递,超过6个的参数压栈,栈需保持16字节对齐。
  • 像素放大:直接绘制单个点会太小,这里用pixel_size将每个逻辑像素放大成方块,便于观察。
  • 事件处理:通过XNextEvent等待窗口关闭事件,确保程序正常退出并清理资源。

内容的提问来源于stack exchange,提问作者IsmellBeans

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 04:05:25