//
xiaoaoaode
Published on 2023-10-24 / 47 Visits
0

Zig内联汇编

官方文档内联汇编规则

翻译自https://ziglang.org/documentation/master/#toc-Assembly

pub fn syscall1(number: usize, arg1: usize) usize {
    // 内联汇编是一个有返回值的表达式。
    // 这个表达式以`asm`开始
    return asm
    // volatile是一个可选的修饰符,告诉Zig该内联汇编表达式有副作用
    // 无volatile的情况下,如果返回值未被使用,Zig将可能会删除该内联汇编
    volatile (
    // 下一项是用来表示汇编的编译期字符串
    // 在这个字符串里,在这个字符串中,可以使用 %[ret]、%[number] 或 %[arg1] 来代表寄存器,
    // 以指定在使用寄存器约束字符串时 Zig 用于参数或返回值的寄存器。
	// 不过本示例代码并没有这个用法
    // %字符串可以通过双倍的百分号%%来获得。
	// 通常在这部分会使用多行字符串语法。
    \\syscall
    // 下一项是输出部分。在未来,Zig 可能会支持多个输出,这取决于
    // https://github.com/ziglang/zig/issues/215 如何解决。
    // 同时也允许无输出。在这种情况下,这个冒号后面直接接着输入部分的冒号。
        :
    // 这指定了上面汇编字符串中使用的 %[ret] 语法中的名称。
	// 本示例中没有使用它,但语法是强制性的。(不太理解是哪方面的强制性)
        [ret]
    // 下一项是输出约束字符串。在 Zig 中,这个特性是不稳定的,
	// 因此必须使用 LLVM/GCC 文档来理解语义。
	// 详见 https://llvm.org/docs/LangRef.html#inline-asm-constraint-string
	// https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
    // 本示例中,约束字符串表示:内联汇编指令的结果值是 $rax 中的任意值。
        "={rax}"
    // 下一项是一个值绑定,或者 -> 后跟一个类型。
	// 类型是内联汇编表达式的结果类型。如果是一个值绑定,
	// 那么可以在汇编字符串使用 %[ret] 语法来引用与该值绑定的寄存器。
        (-> usize),
    // 下一项是输入列表。这些输入的约束意味着,
	// “当执行汇编代码时,$rax 必须具有 number 的值,$rdi 必须具有 arg1 的值”。
	// 允许任意数量的输入参数。
        : [number] "{rax}" (number),
            [arg1] "{rdi}" (arg1),
    // 下一项是破坏列表。这部分声明一组寄存器,其值在执行此汇编代码时不会被保留。
	// 这不包括输出或输入寄存器。
	// 特殊的破坏值 "memory" 意味着汇编写入未声明的任意内存位置,不仅限于已声明的间接输出所指向的内存。
	// 本示例中,我们列出了 $rcx 和 $r11,因为已知内核系统调用不保留这些寄存器的值。
        : "rcx", "r11"
    );
}

传递参数

  1. X86_64传递参数的顺序

    1. 整数寄存器:RDI、RSI、RDX、RCX、R8、R9、栈。

    2. 浮点寄存器:XMM0、XMM1、XMM2、XMM3、XMM4、XMM5。

    3. 当参数数量超过六个时,额外的参数会被推送到栈上,从右往左依次排列。这意味着第七个参数会出现在较高的地址上,以此类推。

    4. 参数从右到左在栈上入栈,但在调用函数之前,栈会被对齐到16字节的边界。这意味着如果参数总数是奇数,会填充一个额外的8字节以保持栈的对齐。

  2. Windows下参数传递

    1. 整数寄存器:RCX、RDX、R8、R9、栈。

    2. 浮点寄存器:XMM0、XMM1、XMM2、XMM3。

    3. 当参数数量超过四个时,额外的参数会被推送到栈上,从右往左依次排列。这意味着第五个参数会出现在较高的地址上,以此类推。

    4. 参数从左到右在栈上入栈,但在调用函数之前,栈会被对齐到16字节的边界。这意味着如果参数总数是奇数,会填充一个额外的8字节以保持栈的对齐。

Arm与Arm64

  1. Linux下

    1. Arm32

      • 整数寄存器: r0​​、r1​​、r2​​ 、 r3​​ 、栈。

      • 浮点寄存器: s0​​、s1​​、s2​​ 、 s3​​ 、栈。

    2. Arm64

      • 整数寄存器: x0​​ 到 x7​​ 、栈。

      • 浮点寄存器: d0​​ 到 d7​​ 、栈。

  2. Windows下

    1. 整数寄存器: x0、x1、x2、x3、栈。

      • 整数寄存器:d0​​ 到 d7​​、栈。

内联asm约束字符串

LLVM Language Reference Manual — LLVM 18.0.0git documentation --- LLVM 语言参考手册 — LLVM 18.0.0git 文档

objdump查看汇编

# 指定Intel汇编(默认AT&T汇编)
llvm-objdump -S -M intel xxx.exe