2010-01-10 463 views
75

我知道在架构我个人熟悉(86,6502,等),堆栈一般生长向下(即每个项目推送到堆栈上的结果在一个递减SP,而不是增加1)。为什么堆栈通常会向下生长?

我想了解一下这个历史的理由。我知道在一个统一的地址空间中,在数据段的另一端(比如说)启动堆栈很方便,所以如果双方在中间相互碰撞只会有问题。但为什么堆栈传统上得到最高的部分?特别是考虑到这与“概念”模型相反吗?

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

回答

36

作为历史悠久的理由,我不能肯定地说(因为我没有设计他们)。我的想法在这件事情上是早期的CPUs得到他们的原始程序计数器设置为0,这是一个自然的愿望,在另一端启动堆栈并向下增长,因为他们的代码自然增长。

顺便说一句,请注意,上电复位程序计数器为0,这个设置并不适合所有的CPU的情况。例如,Motorola 6809将从地址0xfffe/f中获取程序计数器,以便您可以开始在任意位置运行,具体取决于该地址提供的内容(通常但不限于ROM)。

一些历史系统会做的第一件事就是从顶部扫描存储器,直到它找到一个位置读回相同的写入值,以便它知道安装的实际RAM(例如,具有64K地址空间的z80不一定具有64K或RAM,事实上,在我的早期,64K应该是海量的)。一旦找到最高实际地址,它就会正确设置堆栈指针,然后可以开始调用子程序。这种扫描通常由CPU在ROM中作为启动的一部分运行代码完成。

关于栈增长,而不是所有的人都向下生长,见this answer了解详情。

+1

我喜欢Z80 RAM检测策略故事。有些人认为,文本段的布局正在向上发展 - 昔日的程序员与处理堆栈的含义有直接的接触。感谢paxdiablo。指向这组堆栈实现的替代形式的指针也非常有趣。 – 2010-01-10 19:26:01

+0

不是早期的记忆有办法通知它的大小,我们必须手动计算它吗? – 2015-09-28 15:46:21

+1

@LưuVĩnhPhúc,我必须假设你是我身后的一代人(或两人)。我仍然记得TRS-80模型3的方法是在开机时获取日期和时间*以询问用户。有一个内存扫描器来设置内存的上限被认为是当天最新的技术:-)你能想象如果Windows每次问你的时间,或者你有多少内存,每次启动时会发生什么? – paxdiablo 2015-09-29 02:49:44

3

IIRC堆栈向下,因为增长堆向上生长。它可能是相反的。

+3

在某些情况下,向上增长的堆允许有效的重新分配,但是向下增长的堆几乎从未做过。 – 2016-12-09 05:28:58

15

一个很好的解释,我听到的是,在过去的一些机器只能有未签名的偏移量,所以你要在堆栈中,而不必失去了额外的指令,以假负增长向下,所以你可以打你的当地人抵消。

4

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

+1

计算机不减;他们加上2的赞美。任何通过减法完成的事情都是通过添加完成的。考虑一下,电脑有加法器,而不是减法器。 – jww 2018-02-12 08:01:58

2

我相信这完全是一个设计决定。并非所有这些都在向下发展 - 请参阅this SO thread关于不同架构上堆栈增长方向的一些好的讨论。

0

我不能肯定,但我做了一些编程的VAX/VMS在天回。我似乎记得内存(堆)的一部分上升,堆栈下降。当两人见面时,你的记忆就已经消失了。

+1

这是真的,但为什么堆向上而不是相反? – 2015-04-22 15:11:25

1

我认为该协议始于IBM 704及其臭名昭着的“减量寄存器”。现代语言会将其称为指令的偏移字段,但重点是他们去了down不是up

0

只是2C更多:

除了提到的所有历史悠久的理由,我相当肯定,我们没有理由这是现代处理器有效。所有处理器都可以采用带符号偏移量,并且自从我们开始处理多个线程以来,最大化堆/堆栈距离是相当有限的。

我个人认为这是一个安全设计缺陷。比方说,如果x64架构的设计者会颠倒堆栈增长的方向,堆栈缓冲区溢出就会被淘汰 - 这是一件大事。