汇编 (Assembly)

Zig 允许直接在 Zig 源代码中嵌入汇编代码。这使得可以进行低级优化和硬件交互。

内联汇编 (Inline Assembly)

使用 asm 关键字可以插入汇编指令。

const std = @import("std");

pub fn add_two_numbers(a: i32, b: i32) i32 {
    var result: i32 = undefined;
    asm volatile ("add %[res], %[a], %[b]"
        : [res] "=r" (result) // 输出:将结果写入 %res 对应的寄存器
        : [a] "r" (a), [b] "r" (b) // 输入:%a, %b 对应的寄存器分别从 a, b 获取值
        : // 没有 clobbers
    );
    return result;
}

test "add with asm" {
    try std.testing.expect(add_two_numbers(5, 7) == 12);
}

输出约束 (Output Constraints)

输出约束指定了汇编代码如何将结果写入 Zig 变量,通常与寄存器或内存位置绑定。

  • "=r": 写入通用寄存器。
  • "=m": 写入内存。

输入约束 (Input Constraints)

输入约束指定了 Zig 变量如何提供给汇编代码。

  • "r": 从通用寄存器读取。
  • "m": 从内存读取。
  • "0": 与第 0 个输出操作数使用相同的寄存器。

破坏列表 (Clobbers)

破坏列表(Clobbers)指定了汇编代码会修改但未作为显式输出列出的寄存器。编译器需要知道这些信息以正确生成代码。

全局汇编 (Global Assembly)

使用 pub extern "asm" fn 可以定义一个纯汇编函数,其整个函数体由汇编代码组成。

pub extern "asm" fn _start() noreturn {
    asm volatile (
        \  mov $0x0, %rbp
        \  mov $0x0, %rsp
        \  call main
        \  mov $0x3c, %rax  # syscall number for exit
        \  xor %rdi, %rdi   # exit code 0
        \  syscall
    );
}

另请参阅: