Assembly 在void函数中的一个空return语句之后%rax会发生什么情况?

Assembly 在void函数中的一个空return语句之后%rax会发生什么情况?,assembly,x86-64,calling-convention,Assembly,X86 64,Calling Convention,我的理解是,如果执行void函数时没有返回语句,那么%rax仍将存储从以前的非void函数返回的任何内容 即,如果: int a(int param){ return param; } void b(){ } int main(){ a(5); b(); return 1; } 然后在main完成执行后但返回之前,%rax中存储的值将为5 我的问题是,如果b有一个空的返回语句,会发生什么? 就是 void b(){ return; } 这是否清除了

我的理解是,如果执行void函数时没有返回语句,那么%rax仍将存储从以前的非void函数返回的任何内容

即,如果:

int a(int param){
    return param;
}

void b(){
}

int main(){
    a(5);
    b();
    return 1;
}
然后在main完成执行后但返回之前,%rax中存储的值将为5

我的问题是,如果b有一个空的返回语句,会发生什么? 就是

void b(){
    return;
}
这是否清除了%rax?或者%rax是否仍保留其以前的值

然后%rax仍将存储从上一个非void函数返回的任何内容

不,你的理解是错误的

当RAX不持有返回值(void或FP函数)时,它是一个调用阻塞寄存器,例如RCX或RSI。阅读调用约定文档或查看编译器输出

顺便说一句,显式的
返回
语句与到达底部的
}
语句是完全无关的。(除了从非
void
函数末尾掉下来的是UB,一些编译器会将其编译为
ud2
非法指令。)

然后在main完成执行后但返回之前,%rax中存储的值将为5


即100%的实施细节;编译器可以对函数中的寄存器执行任何操作,比如使用RAX计算非函数调用表达式。调用约定只确定了函数之间的边界。

没有必要为无效返回清除
%rax
,因为没有人应该查看它。也不知道它以前的值是什么,因为编译后的代码可以使用它做任何事情。这是一个人为的例子,当然,但我记得有一次遇到一个bug,因为int函数中的一个分支没有return语句,返回的值实际上错误地来自先前调用的函数。那么,为了健壮性,我们是否应该尽可能地清除%rax以避免类似的错误?不,为健壮性清除此寄存器不是我们想要的。我们想要的是由于未能返回值而导致的编译时错误,因此我们可以实现并修复该错误。我相信现代的C编译器会做到这一点。如果调用方使用返回值,则从非void函数中脱落只是未定义的行为(参见ISO/IEC 9899:2011§6.9.1¨12)。@fuz:谢谢。在CLAN(IILC)中,<代码> UD2<代码>可能只有C++。我很确定我在函数本身中看到了一个
ud2
。我经常在C++模式中使用GORD。(这个问题没有标注C或C++,所以我们不知道哪个应用。)