大多数现代系统中堆栈增长的方向是什么?
我正在准备一些C语言培训材料,我希望我的示例能够适合典型的堆栈模型。
在Linux,Windows,Mac OSX(PPC和x86),Solaris和最新的Unix中,C堆栈的发展方向是什么?
堆栈增长通常不取决于操作系统本身,而是取决于运行的处理器。 例如,Solaris在x86和SPARC上运行。 Mac OSX(如您所述)在PPC和x86上运行。 Linux可以运行在我工作的大型系统z到小型的手表上 。
如果CPU提供了任何select,那么操作系统使用的ABI /调用约定指定了如果您希望代码调用其他人的代码时需要做出的select。
处理器和他们的方向是:
x86 down SPARC selectable. The standard ABI uses down. PPC down, I think. System z in a linked list, I kid you not. (but still down, at least for zLinux). ARM selectable, but Thumb2 has compact encodings only for down (LDMIA (increment after) / STMDB (decrement before)) Mostek6502 down (but only 256 bytes). RCA1802A any way you want, subject to SCRT implementation. PDP11 down.
显示我的年龄在最后几个,1802年是芯片用于控制早期的穿梭(感觉如果门是开放的,我怀疑,基于它的处理能力:-)和我的第二台计算机, COMX-35 (跟着我的ZX80 )。
PDP11的细节从这里收集。
SPARC架构使用滑动窗口寄存器模型。 体系结构上可见的细节还包括内部有效和caching的registry窗口的循环缓冲区,以及上/下溢时的陷阱。 详情请看这里 。 正如SPARCv8手册所解释的 ,SAVE和RESTORE指令就像ADD指令加上寄存器窗口旋转一样。 使用积极的常数,而不是通常的负面会给一个向上增长的堆栈。
上述的SCRT技术是另外一种 – 1802使用了一些或16个16位的SCRT(标准调用和返回技术)寄存器。 一个是程序计数器,你可以使用任何寄存器作为PC与SEP Rn
指令。 一个是堆栈指针,两个始终指向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个(SCRT 5个,DMA 2个,内存中断)。 啊,营销胜过现实的胜利。
System 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); } }
增长下降的好处是在较旧的系统中,堆栈通常位于内存的顶部。 程序通常从底部开始填充内存,因此这种内存pipe理最大限度地减less了测量的必要性,并将堆栈的底部放置在合理的地方。
堆栈在x86上增长(由体系结构定义,popup增量堆栈指针,推送递减)。
在MIPS中没有push
/拉指令。 所有的压入/popup都是通过相对于堆栈指针的加载/存储显式完成的,然后手动调整$sp
指针。 然而,由于所有寄存器( $0
除外)都是通用的,理论上任何寄存器都可以是堆栈指针,堆栈可以随程序员想要的任何方向增长。 MIPS ABI通常会向下发展。
在Intel 8051中,堆栈增长,可能是因为内存空间非常小(原始版本为128字节),没有堆,不需要将堆栈放在最前面,以便与堆堆分开从底部。
由于分配给程序的内存具有“永久数据”,即程序本身的代码在底部,然后是堆在中间的代码,所以它增长下来。 您需要另外一个固定点来引用堆栈,这样才能让您成为顶层。 这意味着堆栈向下生长,直到它可能与堆上的对象相邻。
在大多数系统上,堆栈增长缓慢,我在https://gist.github.com/cpq/8598782上的文章解释了为什么增长缓慢。; 原因是两个增长内存区域(堆栈)的最佳布局。