从没有返回的函数中返回一个值

时间:2021-04-06 20:29:57

标签: c assembly gcc undefined-behavior

我想我发现 gcc 编译器处理函数的方式有问题。

我不知道这是一个错误,还是我多年来一直忽略的事情。 实际上,通过声明一个函数并定义后者具有返回值,编译器将在函数范围内分配的第一个变量的值存储在EAX寄存器中,然后依次将其存储在变量中。示例:

#include<stdio.h>

int add(int a, int b)
{
    int c = a + b;

    ;there isn't return
}

int main(void)
{
    int res = add(3, 2);

    return 0;
}

这是输出:

5

这是具有 intel 语法的 x86-64 程序集:

函数添加:

push   rbp
mov    rbp, rsp
mov    DWORD PTR[rbp-0x14], edi  ;store first
mov    DWORD PTR[rbp-0x18], esi  ;store second
mov    edx, DWORD PTR[rbp-0x14]
mov    eax, DWORD PTR[rbp-0x18]
add    eax, esx
mov    DWORD PTR[rbp-0x4], eax
nop
pop    rbp
ret

函数主:

push   rbp
mov    rbp, rsp
sub    rsp, 0x10
mov    esi, 0x2    ;first parameter
mov    edi, 0x3    ;second parameter
call   0x1129 <add>

;WHAT??? eax = a + b, why store it?
mov    DWORD PTR[rbp-0x4], eax 
mov    eax, 0x0
leave
ret

如您所见,它为我保存了变量 a 中参数 bc 的总和,但随后它将我保存在了变量 res 中eax 寄存器包含它们的总和,就像函数返回值一样。

这样做是因为函数定义了返回值吗?

2 个答案:

答案 0 :(得分:6)

您所做的是通过未能从函数返回值然后尝试使用该返回值来触发 undefined behavior

这在 C standard 的 6.9.1p12 节中有记录:

<块引用>

如果到达终止函数的 },并且调用者使用了函数调用的值,则行为未定义。

正如您所见,未定义行为表现出来的一种方式是程序似乎正常工作。但是,如果您添加了一些不相关的代码或使用不同的优化设置进行编译,则无法保证它会继续工作。

答案 1 :(得分:2)

eax 是用于返回值的寄存器,在本例中是因为它应该返回 int。所以调用者会得到该寄存器中发生的任何事情。但是,您至少应该得到一个警告,即没有 return 语句。

因为您的函数非常小并且编译器决定使用 eax 寄存器进行计算,所以它似乎可以工作。

如果开启优化或提供更复杂的功能,结果会大不相同。

相关问题