为何MSVC成员函数从不通过RAX寄存器返回结构体?
Windows x64 ABI中自由函数与成员函数返回结构体的差异及设计原因
我在MSVC代码生成过程中发现一个现象:满足x64 API中通过RAX寄存器返回条件的结构体,在自由函数和成员函数中的处理逻辑存在明显差异。
示例代码如下:
struct Result { uint64_t value; }; Result makeResult(uint64_t value) { return { value }; } struct ResultFactory { NOINLINE Result MakeResult(uint64_t value) const { return { value }; } };
上述Result结构体完全符合x64 API中通过RAX寄存器返回的要求,自由函数的汇编代码也确实遵循了这一逻辑:
value$ = 8 Result makeResult(unsigned __int64) PROC ; makeResult, COMDAT mov rax, rcx ret 0 Result makeResult(unsigned __int64) ENDP ; makeResult
但成员函数的汇编代码却采用了不同的处理方式:
Result ResultFactory::MakeResult(unsigned __int64)const PROC ; ResultFactory::MakeResult, COMDAT mov QWORD PTR [rdx], r8 mov rax, rdx ret 0 Result ResultFactory::MakeResult(unsigned __int64)const ENDP ; ResultFactory::MakeResult
编译器要求成员函数通过RDX寄存器传递Result的引用(MSVC成员函数中当无法用RAX返回时会使用第二个寄存器)。这种设计会无端降低代码生成效率,导致非内联场景下成员函数与自由函数出现性能差异,甚至有时返回原生类型再通过bit_cast转换反而更快。而Clang/GCC的处理逻辑则符合预期——直接用RAX返回该结构体。
最初我不确定这是MSVC的特性还是x64 Windows调用约定的要求(MSDN并未明确说明相关C++细节),后来经@Turtlefight指出这是Windows ABI的规定。现在我的疑问是:Windows ABI为何要做出这种区分?这似乎只会降低代码生成效率,还增加了全局函数与成员函数处理的复杂度,想了解背后的设计原因。
内容的提问来源于stack exchange,提问作者Juliean
相关产品推荐
相关产品推荐

