内联汇编
介绍
本文档介绍了 Wave 语言提供的内联汇编功能。 内联汇编是 Wave 提供的功能之一,其语法设计保持了高级语言的便利性和结构性,同时允许直接访问低级硬件控制。
这使得一般 Wave 代码难以表达的寄存器操作、内存地址级访问、特定 CPU 指令执行等工作成为可能,并在性能优化重要或需要强烈依赖硬件和架构的代码情况下得到利用。 通过这个功能,Wave 不仅限于高级语言,还可以覆盖系统编程领域。
基本语法
内联汇编是通过 asm { ... } 块来编写的。
这个块中定义了将实际执行的汇编指令以及用于连接 Wave 变量和 CPU 寄存器的输入输出映射。
asm {
"汇编指令" // 实际汇编代码 (每行一条指令)
...
in("寄存器") 值 // 输入寄存器映射
out("寄存器") 变量 // 输出寄存器映射
}
汇编指令是以字符串形式编写的,直接描述在实际 CPU 上执行的低级指令。 可以写成多行,原则上每行只写一条指令。
例如,可以采用如下形式。
"mov rax, 1"
"syscall"
in("寄存器") 值语句用于将 Wave 变量或表达式的值加载到指定的 CPU 寄存器中。
通过这种方式,汇编代码可以将该寄存器用作输入值。
下面的例子是将变量s的值传递到x86-64约定中的第一个syscall参数寄存器rdi。
in("rdi") s
相反,out("寄存器") 变量语句用于将指定寄存器中的值取到 Wave 变量中。
当需要在 Wave 代码中使用汇编执行结果时,使用此方法。
下面的例子是将syscall调用后的返回值存储在rax寄存器中的值存储到变量ret中。
out("rax") ret
简单例子
下面的例子是在 Linux x86-64 环境下使用 syscall 将字符串输出到标准输出的简单代码。
fun main() {
var msg_ptr: ptr<i8> = "Hello from syscall!\n";
var ret_val: i64;
asm {
"mov rax, 1"
"syscall"
in("rdi") 1
in("rsi") msg_ptr
in("rdx") 20
out("rax") ret_val
}
}
在这个例子中,Wave 代码直接将字符串的指针和长度设置到寄存器中,并调用系统调用来进行输出操作。
系统调用的返回值通过rax寄存器传递,并通过out语句重新获取到Wave变量中。
注意事项
内联汇编是故意绕过 Wave 的类型稳定性和抽象功能。 如果使用错误的命令或出现寄存器设置错误,程序可能会异常终止或发生未定义的行为。
通过 in 和 out 的寄存器映射本身在编译时进行验证,但不保证汇编指令的语义有效性或执行结果。
因此,使用内联汇编时,必须准确理解目标架构、调用约定以及指令的操作。