堆栈是一种LIFO(后进先出-压入堆栈的最后一个条目是弹出时返回的第一个条目)数据结构,通常用于保存堆栈帧(属于堆栈的位) 当前功能)。
这包括但不限于:
寄信人地址。
返回值的地方。
传递的参数。
局部变量。
您将项目推入堆栈并弹出。 在微处理器中,堆栈可用于用户数据(例如局部变量和传递的参数)和CPU数据(例如调用子例程时的返回地址)。
堆栈的实际实现取决于微处理器体系结构。 它可以在内存中增长或下降,并且可以在推/弹出操作之前或之后移动。
通常会影响堆栈的操作是:
子程序调用和返回。
中断调用并返回。
代码显式推入和弹出条目。
直接操作SP寄存器。
以我的(虚构的)汇编语言考虑以下程序:
Addr Opcodes Instructions ; Comments
---- -------- -------------- ----------
; 1: pc
0000 01 00 07 load r0,7 ; 2: pc
0003 02 00 push r0 ; 3: pc
0005 03 00 00 call 000b ; 4: pc
0008 04 00 pop r0 ; 7: pc
000a 05 halt ; 8: pc
000b 06 01 02 load r1,[sp+2] ; 5: pc
000e 07 ret ; 6: pc
现在让我们跟随执行,描述上面注释中显示的步骤:
这是程序计数器为零且堆栈指针为8000(所有这些数字均为十六进制)的开始条件。
这将简单地将立即数r7加载到寄存器r0中,然后进行下一步(除非另有说明,否则我将假定默认行为是将其移至下一步)。
通过将堆栈指针减少2,然后将寄存器的值存储到该位置,将r0压入堆栈。
这将调用一个子例程。 在上一步中,程序计数器将以类似于r0的方式被推入堆栈,然后程序计数器被设置为其新值。 这与用户级别的推送没有什么不同,除了它实际上是作为系统级别的事情完成的。
这将从堆栈指针计算出的内存位置加载r1-它显示了一种将参数传递给函数的方法。
return语句从堆栈指针指向的位置提取值,并将其加载到程序计数器中,同时向上调整堆栈指针。 这就像系统级弹出窗口(请参阅下一步)。
从堆栈弹出r0涉及从堆栈指针指向的位置提取值,然后向上调整该堆栈指针。
暂停指令只是将程序计数器留在原处,是一个无限循环。
希望从该描述中将变得清楚。 底线是:堆栈对于以LIFO方式存储状态很有用,这通常是大多数微处理器进行子例程调用的方式的理想选择。
除非您当然是SPARC,否则在这种情况下,请为堆栈使用循环缓冲区:-)
更新:只是为了阐明在上述示例(无论是显式还是通过调用/返回)中推入和弹出值时所采取的步骤,请参见以下示例:
LOAD R0,7
PUSH R0
Adjust sp Store val
sp-> +--------+ +--------+ +--------+
| xxxx | sp->| xxxx | sp->| 0007 |
| | | | | |
| | | | | |
| | | | | |
+--------+ +--------+ +--------+
POP R0
Get value Adjust sp
+--------+ +--------+ sp->+--------+
sp-> | 0007 | sp->| 0007 | | 0007 |
| | | | | |
| | | | | |
| | | | | |
+--------+ +--------+ +--------+