[英]Differences in the initialization of the EAX register when calling a function in C and C++
当编译为C程序或C ++程序(对于Linux x86-64)时,小程序的程序集之间存在一个奇怪的差异。
有问题的代码:
int fun();
int main(){
return fun();
}
将其编译为C程序(使用gcc -O2
)可得出:
main:
xorl %eax, %eax
jmp fun
但是将其编译为C ++程序(带g++ -02
)会得到:
main:
jmp _Z3funv
我感到困惑的是,C版本使用0
( xorl %eax, %eax
)初始化了主函数的返回值。
C语言的哪个功能导致了这种必要性?
编辑:的确,对于int fun(void);
没有初始化eax寄存器。
如果根本没有fun
原型,即:
int main(){
return fun();
}
然后,C编译器再次将eax寄存器清零。
在C int fun();
可以接受任意数量的参数,因此它甚至可以是varargs函数。 但是在C ++中,这意味着它不接受任何参数。
x86-64 sysv abi约定要求在调用varargs函数时,寄存器AL
必须包含使用的SSE寄存器数。 您当然不传递任何参数,因此将其置零。 为了方便起见,编译器决定将整个eax
归零。 将原型声明为int fun(void);
xor
将消失。
显然,这是一种防御措施,设计用于以下情况:无原型的fun
功能恰好是可变函数,如@Jester的回答所解释。
但是请注意,从标准C语言的角度来看,这种解释没有任何用处。
自标准化时间(C89 / 90)开始以来,C语言明确要求所有可变参数函数必须在调用点之前用原型声明。 调用非原型可变参数函数会触发标准C中的未定义行为。因此,从形式上讲,编译器不必适应可变参数的fun
-如果是这样,则无论如何该行为都是不确定的。
此外,正如@John Bollinger在评论中指出的那样,根据C标准,非原型的int fun()
声明实际上排除了fun
其他可变参数原型声明。 即可变参数函数不能合法地预先声明为()
函数。 这就是上述非原型声明足以使编译器认为fun
不可能是可变参数的另一个原因。
实际上,这可能是一项遗留功能,旨在支持标准C代码,而无需使用原型预先声明可变参数函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.