我试图完全理解函数调用的堆栈增长机制,但我感到有些困惑。为了更好地理解,我编写了以下简单程序:
#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
内联函数,此时编译器可以随意进行堆栈分配。
单独对象(如 tmp
和 tmp1
)之间的地址比较在 C 中在技术上是未定义的行为,因此 基于函数嵌套的地址之间的任何类型的 >
或 <
关系都不是优化需要在遵循 as-如果规则 。编译器在内联函数时甚至不会尝试这样做。
将地址转换为 uintptr_t
之类的整数,或者将它们打印出来并在您的脑海中进行比较,不是 UB,但仍然无法根据任何内容保证结果。
关于关于 x86_64 Linux 上堆栈增长的困惑,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53035757/