C堆栈变量是否反向存储?

Are C stack variables stored in reverse?

我想了解 C 如何在堆栈上分配内存。我一直认为堆栈上的变量可以描述为结构成员变量,它们在堆栈中占据连续的、连续的字节块。为了帮助说明我在某处发现的这个问题,我创建了这个重现该现象的小程序。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void function(int  *i) {
    int *_prev_int =  (int *) ((long unsigned int) i -  sizeof(int))  ;
    printf("%d\n", *_prev_int );    
}

void main(void) 
{
    int x = 152;
    int y = 234;
    function(&y);
}

看到我在做什么了吗?假设 sizeof(int) 是 4:我正在寻找传递的指针后面的 4 个字节,因为这将读取 调用者的 堆栈中 int y 之前的 4 个字节。

它没有打印出 152。奇怪的是,当我看接下来的 4 个字节时:

int *_prev_int =  (int *) ((long unsigned int) i +  sizeof(int))  ;

现在它可以工作了,打印调用者堆栈中 x 中的任何内容。为什么 x 的地址比 y 低?堆栈变量是否倒置存储?

堆栈组织完全未指定并且特定于实现。实际上,它取决于很多编译器(甚至是它的版本)和优化标志。

有些变量甚至不在堆栈上(例如,因为它们只是保存在某些寄存器中,或者因为编译器优化了它们 - 例如,通过内联、常量折叠等)。

顺便说一句,你可以有一些不使用任何堆栈的假设 C 实现(即使我不能说出这样的实现)。

要了解有关堆栈的更多信息:

遗憾的是,我不知道可以在语言级别访问调用堆栈的低级语言(如 C、D、Rust、C++、Go 等)。这就是为什么为 C 编写垃圾收集器很困难(因为 GC-s 需要扫描调用堆栈指针)...但是请参阅 Boehm's conservative GC 以获得非常实用和务实的解决方案。

现在几乎所有的处理器架构都支持堆栈操作指令(例如ARM中的LDM、STM指令)。编译器在这些实现堆栈的帮助下。在大多数情况下,当数据被压入堆栈时,堆栈指针会递减(向下增长)并在数据从堆栈弹出时递增。

所以这取决于处理器架构和编译器如何实现堆栈。

取决于编译器和平台。同样的事情可以用不止一种方式完成,只要它由一个程序一致地完成(在这种情况下,编译器翻译成汇编,即机器代码)并且平台支持它(好的编译器会尝试优化汇编以获得“最”)。

免费书籍 初学者逆向工程(理解汇编语言) 深入了解 c 语言幕后的内容、编译程序时发生的情况以及它们发生的原因的一个很好的来源。 =16=],丹尼斯·尤里切夫,the latest version can be found at his site