应用程序二进制接口 (ABI)

本节介绍影响 crate 编译输出的 ABI 的特性。

有关指定导出函数的 ABI 的信息,请参阅 extern 函数。有关指定链接外部库的 ABI 的信息,请参阅 外部块

used 属性

used 属性 只能应用于 static。即使变量在 crate 中的任何其他项中未使用或未被引用,此 属性 也会强制编译器将变量保留在输出对象文件(.o、.rlib 等,不包括最终二进制文件)中。但是,链接器仍然可以自由地删除此类项。

下面是一个示例,展示了在什么条件下编译器会将 static 项保留在输出对象文件中。

#![allow(unused)]
fn main() {
// foo.rs

// This is kept because of `#[used]`:
#[used]
static FOO: u32 = 0;

// This is removable because it is unused:
#[allow(dead_code)]
static BAR: u32 = 0;

// This is kept because it is publicly reachable:
pub static BAZ: u32 = 0;

// This is kept because it is referenced by a public, reachable function:
static QUUX: u32 = 0;

pub fn quux() -> &'static u32 {
    &QUUX
}

// This is removable because it is referenced by a private, unused (dead) function:
static CORGE: u32 = 0;

#[allow(dead_code)]
fn corge() -> &'static u32 {
    &CORGE
}
}
$ rustc -O --emit=obj --crate-type=rlib foo.rs

$ nm -C foo.o
0000000000000000 R foo::BAZ
0000000000000000 r foo::FOO
0000000000000000 R foo::QUUX
0000000000000000 T foo::quux

no_mangle 属性

no_mangle 属性 可以用于任何 ,以禁用标准符号名称修饰。该项的符号将是该项名称的标识符。

此外,该项将从生成的库或对象文件中公开导出,类似于 used 属性

此属性是不安全的,因为未修饰的符号可能与另一个同名符号(或与一个众所周知的符号)冲突,从而导致未定义的行为。

#![allow(unused)]
fn main() {
#[unsafe(no_mangle)]
extern "C" fn foo() {}
}

版本差异:在 2024 版本之前,允许在没有 unsafe 限定符的情况下使用 no_mangle 属性。

link_section 属性 指定 函数静态 内容将被放置到的对象文件的节。它使用 MetaNameValueStr 语法来指定节名称。

此属性是不安全的,因为它允许用户将数据和代码放置到不期望它们的内存节中,例如将可变数据放置到只读区域中。

#![allow(unused)]
fn main() {
#[unsafe(no_mangle)]
#[unsafe(link_section = ".example_section")]
pub static VAR1: u32 = 1;
}

版本差异:在 2024 版本之前,允许在没有 unsafe 限定符的情况下使用 link_section 属性。

export_name 属性

export_name 属性 指定将在 函数静态 上导出的符号的名称。它使用 MetaNameValueStr 语法来指定符号名称。

此属性是不安全的,因为具有自定义名称的符号可能与另一个同名符号(或与一个众所周知的符号)冲突,从而导致未定义的行为。

#![allow(unused)]
fn main() {
#[unsafe(export_name = "exported_symbol_name")]
pub fn name_in_rust() { }
}

版本差异:在 2024 版本之前,允许在没有 unsafe 限定符的情况下使用 export_name 属性。