繁体   English   中英

在C和C ++中调用函数时EAX寄存器的初始化差异

[英]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版本使用0xorl %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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM