Rust传递结构体采用何种ABI?x86_64下与C的差异解析
Rust x86_64下结构体返回的ABI规则解析
在x86_64系统中,通用调用约定为:当返回值大小≤16字节时,通过寄存器RAX和RDX传递;当返回值大小>16字节时,通过第一个
sret参数传递。但Rust的表现似乎和这一规则不符。
C语言示例及表现
代码实现
struct test_struct { int a; int b; int c; }; struct test_struct foo() { struct test_struct a = {1,2,3}; return a; }
对应LLVM IR
define dso_local { i64, i32 } @foo()
该结构体大小为12字节(≤16字节),可见返回值通过寄存器传递,符合x86_64通用约定。
Rust语言示例及表现
代码实现
pub struct test_struct { a: i32, b: i32, c: i32, } pub fn foo() -> test_struct { let data = test_struct { a: 0, b: 1, c: 2, }; data }
对应LLVM IR
define void @_ZN7example3foo17hd5941535b576c335E(ptr sret(%test_struct) %0) unnamed_addr
同样是12字节的结构体,却使用sret参数传递返回值,和C的表现不一致。
Rust的结构体返回ABI规则
Rust默认使用Rust专用ABI,而非C的System V ABI,该ABI设计更侧重编译器优化与语言内存安全需求,和C的约定存在明显差异:
- 几乎所有结构体返回都会通过
sret参数传递(调用者预先分配内存,函数将结果写入该地址),无论结构体大小是否≤16字节。 - 仅当结构体是可拆分为整数类型的简单标量组合(如单个i32、两个i64组成的结构体等),编译器才可能优化为寄存器传递,且依赖编译优化级别。
- 若需让Rust函数遵循C的System V ABI,只需给函数添加
#[no_mangle]和extern "C"注解,此时结构体返回行为会和C一致。
示例修改后的Rust代码:
#[no_mangle] pub extern "C" fn foo() -> test_struct { let data = test_struct { a: 0, b: 1, c: 2, }; data }
对应的LLVM IR会和C版本类似,采用寄存器传递返回值。
内容的提问来源于stack exchange,提问作者super_jh
相关产品推荐
相关产品推荐

