Answers:
至于历史的基本原理,我不能确定地说(因为我没有设计它们)。我对此的想法是,早期的CPU会将其原始程序计数器设置为0,并且很自然地希望在另一端启动堆栈并向下扩展,因为它们的代码自然会向上扩展。
顺便说一句,请注意,并非所有早期的CPU 都在复位时将程序计数器设置为0 。例如,Motorola 6809将从地址中读取程序计数器,
0xfffe/f
以便您可以在任意位置开始运行,具体取决于该地址提供的内容(通常但绝不限于ROM)。
一些历史系统将要做的第一件事是从顶部开始扫描内存,直到找到一个位置,该位置将回读相同的写入值,以便它知道实际安装的RAM(例如,具有64K地址空间的z80不一定有64K或RAM,实际上,在我早期的时候64K就已经很大了)。一旦找到最上面的实际地址,它将适当地设置堆栈指针,然后可以开始调用子例程。作为启动的一部分,此扫描通常由ROM中的CPU运行代码完成。
关于堆栈的增长,并非所有堆栈都向下增长,有关详细信息,请参见此答案。
Stanley Mazor(4004和8080架构师)解释了如何在“英特尔微处理器:8008至8086”中为8080(并最终为8086)选择了堆栈增长方向:
选择堆栈指针运行是“下坡”(堆栈朝着较低的内存方向移动),以简化从用户程序到堆栈的索引编制(正索引),并简化从前面板显示堆栈的内容。
一种可能的原因可能是它简化了对齐。如果将局部变量放在必须放在4字节边界上的堆栈上,则可以简单地从堆栈指针中减去对象的大小,然后将两个低位清零以获得正确对齐的地址。如果堆栈向上生长,则确保对齐变得有些棘手。
我相信这纯粹是设计决定。并非所有人都向下增长-有关不同体系结构上堆栈增长方向的一些很好的讨论,请参见此SO线程。
再加2分:
除了提到的所有历史依据外,我敢肯定,没有理由在现代处理器中是有效的。所有处理器都可以采用带符号的偏移量,并且自从我们开始处理多个线程以来,最大程度地提高堆/堆栈的距离就显得毫无意义。
我个人认为这是安全设计缺陷。如果说x64体系结构的设计者会改变堆栈的增长方向,那么大多数堆栈缓冲区溢出将被消除-这是很大的事情。(因为琴弦向上生长)。
我不确定,但是过去我为VAX / VMS做过一些编程。我似乎还记得一部分内存(堆??)上升而堆栈下降。当两个人见面时,您就没内存了。