【汇编教程】再谈栈
前言
两年前,我写过一篇《【汇编学习随记】汇编中栈的定义》,当时是初次接触汇编语言,对于栈的理解仅限于理解这是一种数据结构,自己却没有理解怎么用栈。当时确实是肤浅了。两年后的今天,我总算是搞清楚了汇编中栈究竟是什么,写下来分享给大家。
栈是什么
数据结构上理解栈,我想不必过多解释了,本质就是一块具有特定进出规则的内存空间,在这块空间内遵循数据先进后出的原则。
但我们作为汇编学习者,仅有这些理解是不够的,让我们从8086CPU的角度看看栈。在8086CPU中,提供了一对段寄存器SS和寄存器SP,用于指向栈顶,CPU对栈的两个操作push(入栈)和pop(出栈)都取决于这两个(段)寄存器,但却没有寄存器能用于标识栈底,这意味着如果我们不提前计算好哪些内存单元是栈空间,栈空间到哪里,那么就很容易出现栈顶超界的问题,可能影响到其他内存空间的数据,从而导致程序异常。(这里也体现了汇编语言和高级语言的不同:汇编语言要求你手动把内存空间抠的很细,但是用高级语言编程时肯定不用考虑这些,因为操作系统已经代为安排好了。想想C++ STL库里的那个栈,根本不用想栈顶是否超界对吧)。对此,我们只能在设计程序时就预留好栈。
因为这一特点,通常情况下,我们不会把栈和代码放在一个段里,而是给栈单独开一个段。
化学上常说,性质决定用途。由于栈这一独特的结构,(至少在汇编中)栈通常用于多层循环时,进入内层循环前暂存外层循环的数据,内层循环结束了再将这些数据恢复出来。这是一个编程时的惯例。
实际应用
上一篇文章中的双层循环就是一个不错的例子,这里就不新出题目了,直接搬过来,要求用栈暂存数据~
编程,将datasg段中每个单词改成小写字母(用栈)
assume cs:codesg,ds:datasg,ss:stacksg
stacksg segment
stacksg ends
datasg segment
db 'Far '
db 'You '
db 'HJC '
db 'BBS '
datasg ends
codesg segment
start:
codesg ends
ends start直接上答案:
assume cs:codesg,ds:datasg,ss:stacksg;三个段寄存器cs、ds、ss分别关联三个段:代码段、数据段、栈段
stacksg segment
dw 0,0,0,0,0,0,0,0;定义出16个位,刚刚
stacksg ends
datasg segment
db 'Far '
db 'You '
db 'HJC '
db 'BBS '
datasg ends
codesg segment
start:mov bx,0
mov cx,4
mov sp,0;标记当前栈底
s0:push cx;进入内层循环前,cx入栈
mov si,0
mov cx,3;重置cx,进内层循环
s:mov al,[bx+si]
or al,00100000b
mov [bx+si],al
inc si
loop s
add bx,16
pop cx
loop s0
mov ax,4c00h
int 21h
codesg ends
end start结语
汇编中的栈和高级语言的栈还是有差别的,虽然是同一种数据结构,但汇编的栈直接由底层硬件(电路)提供支持,而高级语言中的栈其实是用程序模拟的。我是faryou,下期见!