Assembly 在void函数中的一个空return语句之后%rax会发生什么情况?
我的理解是,如果执行void函数时没有返回语句,那么%rax仍将存储从以前的非void函数返回的任何内容 即,如果: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; } 这是否清除了
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++,所以我们不知道哪个应用。)