如何在Rust中调用汇编函数?

typ*_*pos 0 assembly rust

我知道在Rust中调用C函数的一种方法是使用这样的东西:

extern "C" {
    fn abs(input: i32) -> i32;
}

fn main() {
    unsafe {
        println!("abs(-3) = {}", abs(-3));
    }
}
Run Code Online (Sandbox Code Playgroud)

但是如何.s在Rust代码中调用一些汇编函数(位于与其他Rust文件相同的目录中的文件内)?

Mat*_* M. 6

这是在macOS上使用C x86_64调用约定的汇编函数.它不是段错误,所以一定是对的:-)

Cargo.toml

[build-dependencies]
cc = "1.0.3"
Run Code Online (Sandbox Code Playgroud)

build.rs

extern crate cc;

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

add.S

.text
.globl _my_adder
_my_adder:
        addq %rdi, %rsi
        movq %rsi, %rax
        ret
Run Code Online (Sandbox Code Playgroud)

SRC/main.rs

extern "C" {
    fn my_adder(a: u64, b: u64) -> u64;
}

fn main() {
    let sum = unsafe { my_adder(1, 2) };
    println!("{}", sum);
}
Run Code Online (Sandbox Code Playgroud)

说明

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

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

编译和链接

Rust本身并不提供编译程序集文件的方法.相反,您必须使用计算机上已存在的C编译器来编译它们.最常见的做法是在构建脚本中使用cc crate.

构建脚本会将汇编文件编译为静态库,并指示Cargo链接到库.

您必须确保您的汇编语法对您正在使用的C编译器有效.例如,MSVC和GCC使用不同的装配样式.您可能需要具有相同组装功能的多个副本才能处理不同的平台.

调用

调用该函数在很大程度上取决于调用约定.主要调用约定是C调用约定,用extern "C"或者只用plain表示extern.您可能也想使用#[link_name = "..."]#[no_mangle]属性.

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

Rust 1.21.1支持许多其他调用约定:

cdecl,stdcall,fastcall,vectorcall,thiscall,aapcs,win64,sysv64,ptx-kernel,msp430-interrupt,x86-interrupt,Rust,C,system,rust-intrinsic,rust-call,platform-intrinsic,unadjusted

  • @fuz:没有具体说明.Rust不会对任何目标提交任何特定的调用约定.在实践中,*目前*,它通常恰好符合C约定; 但它可能在将来的任何时候发生变化,例如,如果在特定架构上找到更快的调用约定. (2认同)