进程的堆栈布局

为什么输出44而不是12,&x,eip,ebp和j应该是下面给出的代码的堆栈布局我猜,如果是这样那么它必须有12作为输出,但我得到它44? 所以帮助我理解这个概念,即使每个执行瞬间重新定位基指针,相对必须保持不变,不应该是12?

int main() { int x = 9; // printf("%p is the address of x\n",&x); fun(&x ); printf("%x is the address of x\n", (&x)); x = 3; printf("%dx is \n",x); return 0; } int fun(unsigned int *ptr) { int j; printf("the difference is %u\n",((unsigned int)ptr -(unsigned int) &j)); printf("the address of j is %x\n",&j); return 0; } 

您假设编译器已经打包了所有内容(而不是将内容放在特定的对齐边界上),并且您还假设编译器没有内联函数,或进行任何其他优化或转换。

总之,您不能对此类事物做任何假设,也不能依赖任何特定行为。

不,它不应该是12.它不应该是任何东西。 ISO标准对于如何在堆栈上排列事物几乎没有什么可说的。 实现在移动事物和插入填充以提高效率方面有很大的余地。

如果你通过编译器传递它来生成汇编程序代码(例如使用gcc -S ),那么这里会发生什么变得明显。

 fun: pushl %ebp movl %esp, %ebp subl $40, %esp ;; this is quite large (see below). movl 8(%ebp), %edx leal -12(%ebp), %eax movl %edx, %ecx subl %eax, %ecx movl %ecx, %eax movl %eax, 4(%esp) movl $.LC2, (%esp) call printf leal -12(%ebp), %eax movl %eax, 4(%esp) movl $.LC3, (%esp) call printf movl $0, %eax leave ret 

似乎gcc正在预先生成下一个堆栈帧(下一个打印到printf )作为fun函数的序言的一部分。 就是这种情况。 您的编译器可能正在做一些完全不同的事 但最重要的是:只要不违反标准,实施就可以做到它想做的事情。

顺便提一下,这是来自优化级别0的代码,它给出了48的差异。当我使用gcc的疯狂优化级别3时,我得到了4的差异。再次,完全可以接受,gcc通常会做一些相当令人印象深刻的优化水平。