Answers:
堆栈的增长通常不取决于操作系统本身,而是取决于运行的处理器。例如,Solaris在x86和SPARC上运行。如前所述,Mac OSX在PPC和x86上运行。Linux可以运行在从我的大型honkin System z到微不足道的小手表等所有东西上。
如果CPU提供任何选择,则操作系统要使用的ABI /调用约定指定了您希望代码调用所有人的代码时需要做出的选择。
处理器及其方向是:
为了显示我的年龄,1802是用来控制早期航天飞机的芯片(基于它的处理能力,我怀疑门是否打开了:-)和第二台计算机COMX-35(按照我的ZX80)。
SPARC体系结构使用滑动窗口寄存器模型。架构上可见的详细信息还包括寄存器窗口的循环缓冲区,该缓冲区有效并在内部缓存,并且在上溢/下溢时会出现陷阱。有关详细信息,请参见此处。如SPARCv8手册所述,SAVE和RESTORE指令类似于ADD指令加上寄存器窗口旋转。使用正常数而不是通常的负将产生向上增长的堆栈。
前面提到的SCRT技术是另一种技术-1802使用了一部分或16个16位寄存器用于SCRT(标准调用和返回技术)。一个是程序计数器,您可以将任何寄存器与SEP Rn
指令一起用作PC 。一个是堆栈指针,两个始终设置为指向SCRT代码地址,一个用于调用,一个用于返回。没有对寄存器进行特殊处理。请记住,这些细节来自内存,它们可能并不完全正确。
例如,如果R3是PC,R4是SCRT调用地址,R5是SCRT返回地址,R2是“堆栈”(引用是在软件中实现的),SEP R4
则将R4设置为PC并开始运行SCRT通话代码。
然后它将R3存储在R2“堆栈”上(我认为R6用于临时存储),向上或向下进行调整,获取R3之后的两个字节,将它们加载到 R3中,然后SEP R3
在新地址处运行。
要返回,它将SEP R5
从R2堆栈中拉出旧地址,向其中添加两个(跳过调用的地址字节),将其加载到R3中并SEP R3
开始运行先前的代码。
最初,在完成所有基于6502/6809 / z80堆栈的代码之后,很难把头缠起来,但是仍然以一种“碰头撞墙”的方式保持优雅。该芯片的最大卖点之一是全套的16个16位寄存器,尽管事实上您立即丢失了其中的7个(5个用于SCRT,两个用于DMA和内存中断)。啊,营销胜过现实:-)
系统z实际上非常相似,使用其R14和R15寄存器进行呼叫/返回。
在C ++(适用于C)stack.cc中:
static int
find_stack_direction ()
{
static char *addr = 0;
auto char dummy;
if (addr == 0)
{
addr = &dummy;
return find_stack_direction ();
}
else
{
return ((&dummy > addr) ? 1 : -1);
}
}
static
。相反,您可以将地址作为参数传递给递归调用。
static
,如果您多次调用此命令,则后续调用可能会失败...
在MIPS和许多现代的RISC体系结构(如PowerPC上,RISC-V,SPARC ...)有没有push
和pop
说明。这些操作是通过手动调整堆栈指针,然后相对于调整后的指针加载/存储值来明确完成的。所有寄存器(零寄存器除外)都是通用的,因此理论上任何寄存器都可以是堆栈指针,并且堆栈可以按程序员希望的任何方向增长
就是说,在大多数体系结构上,堆栈通常会变小,这可能是为了避免堆栈和程序数据或堆数据变大并相互冲突的情况。sh-的答案中也提到了很多解决原因。一些示例:MIPS ABI向下增长并使用$29
(AKA $sp
)作为堆栈指针,RISC-V ABI也向下增长并使用x2作为堆栈指针
在Intel 8051中,堆栈长大了,可能是因为内存空间非常小(原始版本中为128字节)以至于没有堆,而且您无需将堆栈放在顶部,以便将其与堆长分开从下往上
您可以在https://en.wikipedia.org/wiki/Calling_convention中找到有关各种体系结构中堆栈使用情况的更多信息。
也可以看看
仅是其他答案的一小部分,据我所知,这还没有涉及到这一点:
使堆栈向下生长会使堆栈内的所有地址相对于堆栈指针具有正偏移。不需要负偏移,因为它们只会指向未使用的堆栈空间。当处理器支持相对于堆栈指针的寻址时,这简化了对堆栈位置的访问。
许多处理器的指令允许相对于某些寄存器仅以正偏移量进行访问。这些建筑包括许多现代建筑以及一些旧建筑。例如,ARM Thumb ABI通过在单个16位指令字中编码的正偏移量来提供相对于堆栈指针的访问。
如果堆栈向上增长,则相对于堆栈指针的所有有用偏移都将为负,这将使直观性和便利性降低。与寄存器相对寻址的其他应用程序(例如用于访问结构的字段)的应用程序也不一致。
在大多数系统上,堆栈会减少,而我在https://gist.github.com/cpq/8598782上的文章解释了为什么堆栈会减少。很简单:如何在固定的内存块中布局两个增长的内存块(堆和堆栈)?最好的解决方案是将它们放在相反的一端,让彼此靠近。