我试图完全理解函数调用的堆栈增长机制,但我感到有些困惑。为了更好地理解,我编写了以下简单程序:

#include <stdio.h>
#include <stdint.h>

void callee(uint32_t* p)
{
    uint32_t tmp = 9;
    printf("callee - tmp is located at address location:%p and p is:%p \n", &tmp, p);
}

void caller()
{
    uint32_t tmp1 = 12;
    printf("caller - address of tmp1:%p \n", &tmp1);
    calle(&tmp1);
}

int main(int argc, char** argv)
{
    caller();
    return 0;
}
并使用 在线汇编器 转换器我得到以下汇编输出(我只留下了 callee 函数的代码):
.LC0:
    .string "callee - tmp is located at address location:%p and p is:%p \n"
calle:
    push    rbp
    mov     rbp, rsp
    sub     rsp, 32 // command 1
    mov     QWORD PTR [rbp-24], rdi
    mov     DWORD PTR [rbp-4], 9 // command 2
    mov     rdx, QWORD PTR [rbp-24]
    lea     rax, [rbp-4]
    mov     rsi, rax
    mov     edi, OFFSET FLAT:.LC0
    mov     eax, 0
    call    printf
    nop
    leave
    ret
据我了解,考虑到 命令 1 & 2 (如上所述),堆栈确实向低地址增长,并且当我使用命令 gcc myProg.c -o prog 编译它时,编译代码的(示例)输出如下:

可以看出,在 callee 函数中分配的局部变量确实位于比 caller 函数中的局部变量更低的内存地址中。到目前为止一切顺利。
然而 ,当我使用 -O2 选项(即: gcc -O2 myProg.c -o prog )编译程序时,编译代码的(示例)输出如下:

这一次,描述了在 callee 堆栈帧中分配的局部变量位于比 caller 函数中的局部变量更高的内存地址中。
所以我的问题是 - -O2 优化选项“最多”优化堆栈增长机制实际发生变化的情况,或者我在这里遗漏了什么......?gcc 版本:7.3
架构:x86_64
操作系统:Ubuntu 18.04。
感谢您的澄清。
伙计。

最佳答案

-O2 内联函数,此时编译器可以随意进行堆栈分配。

单独对象(如 tmptmp1 )之间的地址比较在 C 中在技术上是未定义的行为,因此 基于函数嵌套的地址之间的任何类型的 >< 关系都不是优化需要在遵循 as-如果规则 。编译器在内联函数时甚至不会尝试这样做。



将地址转换为 uintptr_t 之类的整数,或者将它们打印出来并在您的脑海中进行比较,不是 UB,但仍然无法根据任何内容保证结果。

关于关于 x86_64 Linux 上堆栈增长的困惑,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53035757/

10-11 22:07
查看更多