为什么堆栈通常会向下增长?

时间:2010-01-10 00:35:05

标签: architecture stack history

我知道在我个人熟悉的架构(x86,6502等)中,堆栈通常向下增长(即,推入堆栈的每个项目都会导致递减的SP,而不是递增的SP)。

我想知道这个的历史原因。我知道在一个统一的地址空间中,在数据段的另一端(例如)开始堆栈很方便,所以如果双方在中间碰撞,那么只会出现问题。但是为什么堆栈传统上是最重要的?特别是考虑到这与“概念”模型的对立方式如何?

(请注意,在6502架构中,堆栈也向下增长,即使它被限制在一个256字节的页面上,这种方向选择似乎是任意的。)

11 个答案:

答案 0 :(得分:43)

至于历史原因,我不能肯定地说(因为我没有设计它们)。关于此事的想法是早期的CPU将其原始程序计数器设置为0,并且自然希望在另一端启动堆栈并向下扩展,因为它们的代码自然会向上增长。 / p>

  

另外,请注意,所有早期CPU不会在重置时将程序计数器的此设置设置为0。例如,摩托罗拉6809将从地址0xfffe/f获取程序计数器,因此您可以开始在任意位置运行,具体取决于该地址提供的内容(通常,但不限于ROM)。 / p>

某些历史系统最先做的事情之一就是从顶部扫描内存,直到找到一个可以读回写入的相同值的位置,这样就可以知道安装的实际RAM(例如,z80与64K地址空间不一定有64K或RAM,事实上64K在我早期就已经大量了。一旦找到顶部实际地址,它将适当地设置堆栈指针,然后可以开始调用子例程。这种扫描通常由CPU在ROM中运行代码来完成,作为启动的一部分。

关于堆栈增长,并非所有堆栈都向下增长,有关详细信息,请参阅this answer

答案 1 :(得分:20)

我听到的一个很好的解释是,过去的某些机器只能有无符号的偏移量,所以你希望堆栈向下增长,这样你就可以击中当地人,而不必丢失额外的指令来伪造负偏移

答案 2 :(得分:6)

一个可能的原因可能是它简化了对齐。如果在堆栈上放置一个必须放在4字节边界上的局部变量,则可以简单地从堆栈指针中减去对象的大小,然后将两个较低位置零以获得正确对齐的地址。如果堆栈向上增长,确保对齐变得有点棘手。

答案 3 :(得分:4)

IIRC堆栈向下增长,因为堆向上增长。它可能是另一种方式。

答案 4 :(得分:3)

Stanley Mazor(4004和8080架构师)介绍了如何在"Intel Microprocessors: 8008 to 8086"中为8080(最终是8086)选择了堆栈增长方向:

  

选择将堆栈指针运行为“下坡”(堆栈向低内存方向前进)以简化从用户程序到堆栈的索引编制(正索引编制)并简化从前面板显示堆栈的内容。

答案 5 :(得分:2)

我认为这纯粹是一个设计决定。并非所有这些都向下增长 - 请参阅this SO thread,以便就不同架构的堆栈增长方向进行一些讨论。

答案 6 :(得分:1)

我认为会议始于IBM 704及其臭名昭着的“减量登记册”。现代语音将其称为指令的偏移字段,但关键是它们向下 向上

答案 7 :(得分:1)

因为 POP 使用的寻址模式与通常用于扫描字符串和数组的寻址模式相同

从堆栈中弹出一个值的指令需要做两件事:从内存中读取值,并调整堆栈指针。此操作有四种可能的设计选择:

  1. 预增栈指针,然后读取值。这意味着堆栈将“向下”增长(朝向较低的内存地址)。

  2. 先递减栈指针,然后读取值。这意味着堆栈将“向上”增长(朝向更高的内存地址)。

  3. 先读取值,然后后增量堆栈指针。这意味着堆栈将向下增长。

  4. 先读取值,然后后递减堆栈指针。这意味着堆栈将向上增长。


在许多计算机语言(尤其是 C)中,字符串和数组作为指向其第一个元素的指针传递给函数。一个非常常见的操作是按顺序读取字符串或数组的元素,从第一个元素开始。这样的操作只需要上述的后增量寻址模式。

此外,读取字符串或数组的元素比写入元素更常见。实际上,有许多标准库函数根本不执行写入操作(例如 strlen()strchr()strcmp())!


因此,如果您的指令集设计中的寻址模式数量有限,那么最有用的寻址模式将是后增量读取。这不仅会导致最有用的字符串和数组操作,还会导致POP 指令向下增长堆栈

第二个最有用的寻址模式是后递减写入,可用于匹配的 PUSH 指令。

确实,PDP-11 had postincrement and predecrement 寻址模式产生了向下增长的堆栈。甚至 VAX 也没有 preincrement 或 postdecrement。

答案 8 :(得分:0)

我不确定,但是在那些日子里我为VAX / VMS做了一些编程。我似乎记得内存的一部分(堆??)上升,堆栈下降。当两人相遇时,你就失去了记忆。

答案 9 :(得分:0)

再多2c:

除了提到的所有历史原理之外,我很确定没有理由在现代处理器中有效。所有处理器都可以采用有符号的偏移量,自从我们开始处理多个线程以来,最大化堆/堆栈距离是没有用的。

我个人认为这是一个安全设计缺陷。例如,如果x64体系结构的设计者会颠倒堆栈增长方向,那么堆栈缓冲区溢出就会被消除 - 这是一个大问题。

答案 10 :(得分:0)

在最小的嵌入式系统中,堆栈增长下降的一个优点是可以将单个RAM块冗余地映射到页面O和页面1中,从而允许从0x000开始分配零页面变量,并且堆栈从0x1FF开始向下增长,从而在覆盖变量之前最大程度地增加了增长量。

6502的最初设计目标之一是可以与例如6530结合使用,从而形成具有1 KB程序ROM,计时器,I / O和64字节的两芯片微控制器系统。堆栈和页面零变量之间共享的RAM数量。相比之下,当时基于8080或6800的最小嵌入式系统将是四或五个芯片。