从内联汇编和调用约定中调用 Rust 函数

问题描述 投票:0回答:1

我正在编写一些已在我的 Rust 项目中进行汇编的代码。我和一位同事正在讨论调用约定,但我一直无法为此找到明确的资源。

据我了解,Rust 调用约定是未定义的。因此,在调用程序集时,我应该使用 C 调用约定来了解一些已知信息。

我在三个职能之间工作:

unsafe extern "C" fn f(a) -> b
是一个裸函数,仅从 Rust 调用。它完全是汇编,并假设参数和返回值按照 C 中的方式完成(在堆栈上并放入 %eax)。 因为它被标记为 C 并从 Rust 调用,所以编译器将确保无论在哪里调用它,都将使用 C 调用约定。

unsafe extern "C" fn g()
也是一个裸函数。 Rust 从未调用过它。只是有时
f
会返回到这个函数(即
ret
f
会弹出
g
的地址)。 虽然这不是一个真正的 C 函数(我知道它是从
f
调用的,并且立即使用寄存器而不是
f
中的左值),但它总是会回调到 Rust 函数。本质上,这一切都是将参数压入堆栈,然后将
call
推送到
h
(通过使用
sym h
)。

unsafe fn h
是这里的最后一个函数。它只能在内联汇编中通过
g
sym
调用。 因此,
h
应该期望使用 C 约定进行调用,但可以使用 Rust 约定返回(事实上
h
永远不会返回)。

我的问题是:

是否使用我的 C 函数 g 中的

call
sym h
,提醒 Rust 编译器在
h
中一致使用 C 调用约定?

我之前已将

h
标记为
extern "C"
,尽管它是纯 Rust 代码。在我看来,这将确保编译器尊重
h
的参数是 C 风格。但是,该代码似乎是双向的。如果将来 Rust 决定以不同的方式(并且错误地)优化对
h
的调用,我不希望这一点发生改变。

c rust calling-convention
1个回答
0
投票

在内联汇编中使用

call
并不能保证该函数将使用 C 调用约定(事实上,编译器根本不了解内联汇编)。您确实需要使用
extern "C"
。使用 Rust 调用约定可以看起来可以工作(有时调用约定是等效的),但不能保证。

如果将函数指针传递给

h()
,它们也需要是
extern "C"
,即使它们不是从汇编中调用的。据我所知,Rust 调用约定函数的 ABI 无法保证,因此您甚至无法传递它们,这就是编译器向您发出警告的原因。

如果

h()
没有返回,您可以将其标记为具有返回类型
!
,这将使编译器验证它确实没有返回(如果从 Rust 调用,也将允许它利用此信息)。

© www.soinside.com 2019 - 2024. All rights reserved.