如何调用Rust内部装配功能



我知道rust内调用C函数的一种方法是使用类似的东西:

extern "C" {
    fn abs(input: i32) -> i32;
}
fn main() {
    unsafe {
        println!("abs(-3) = {}", abs(-3));
    }
}

但是如何在锈谱中调用某些汇编功能(位于与其他Rust文件相同的目录中的.s文件中)?

示例

这是使用C X86_64在MacOS上调用约定的汇编功能。它不是segfault,所以必须是正确的: - )

cargo.toml

[build-dependencies]
cc = "1.0"

build.rs

fn main() {
    cc::Build::new()
        .file("add.S")
        .compile("my-asm-lib");
}

add.s

.text
.globl _my_adder
_my_adder:
        addq %rdi, %rsi
        movq %rsi, %rax
        ret

src/main.rs

extern "C" {
    fn my_adder(a: u64, b: u64) -> u64;
}
fn main() {
    let sum = unsafe { my_adder(1, 2) };
    println!("{}", sum);
}

说明

要利用汇编功能,有两个主要部分:

  1. 编译和链接函数
  2. 调用该功能

编译和链接

Rust并未固有地提供编译汇编文件的方法。相反,您必须使用已经存在于机器上的C编译器对它们进行编译。最常见的方法是在构建脚本中使用CC板条。

构建脚本将您的汇编文件编译到静态库中,并指示货物链接到库。

您必须确保您的汇编语法对所使用的C编译器有效。例如,MSVC和GCC使用不同的装配样式。您可能需要拥有同一组件功能的多个副本来处理不同的平台。

呼叫

调用该函数高度依赖于调用约定。主要的调用约定是 C调用约定,用extern "C"或仅表示extern。您可能还需要使用#[link_name = "..."]#[no_mangle]属性。

您还可以使用#[naked]函数创建自己的自定义呼叫约定(请参阅RFC 1201)。然后,您将根据呼叫约定在呼叫之前/之后的呼叫者侧使用汇编代码。这在稳定的Rust 中不可用。

Rust 1.21.1支持的其他许多呼叫约定:

完成其他答案:

如果您使用夜间生锈,则可以避免使用global_asm使用自定义构建脚本!宏。

看起来像这样的简单用法:

#[feature(global_asm)]
...
global_asm!(include_str!("something_neato.s"));

最新更新