15-栈和栈的初始化

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35733751/article/details/85234590

计算机工程师们为了设计出更高效,更易于控制管理的程序,把内存分成一些不同的区域(详细见4-计算机的启动过程中的图3),其中有一块区域就是“栈”,本质上栈是一段内存空间,在计算机里领域里代表:数据临时存储的地方。

同时栈也是一种数据存储结构,这对于学过数据结构这门课的同学来说并不难理解,我们知道“栈”在程序设计中是经常使用的,在早期,设计8086处理器的计算机工程师为了更方便的管理“栈”这段内存,设计了“三个”专门负责管理“栈”的寄存器。

和代码段,数据段一样,栈也被定义成一个内存段,叫做栈段(Stack Segement),由段寄存器SS指向栈的段地址。针对栈的操作主要有压栈(push)和出栈(pop),进栈和出栈只能在一端进行,因此需要使用栈指针寄存器SP指向栈顶的地址,表示下一个数据应该压入栈的位置或者从哪里出栈。而栈指针寄存器BP则用于指向栈底的地址。

 

在定义栈的时候,需要从内存中找到一块可用的区域,我们再来回忆一下8086的内存分布图(不记得同学赶快复习一下:4-计算机的启动过程)。首先,0xF0000-0xFFFFF区域的内存和0xB8000-0xB8FFF区域的内存已经固定了不可用,因此我们可以选择区域就是0x00000-0x9FFFF区域了,那么这里我们把栈的段地址定为0x0000,偏移地址为0xFFFF。

 

下面给出汇编代码:

mov ax,0x0000
mov ss,ax		;指定栈的段地址为0x0000

mov bp,0xFFFF		;指定栈底的地址
mov sp,0xFFFF		;指定栈顶的地址

;定义数据
mov ax,0x1234
mov bx,0x2345
mov cx,0x3456
mov dx,0x4567

;通过push指令依次把数据入栈
push ax
push bx
push cx
push dx

End:
jmp near End

times 510-($-$$) db 0x00
db 0x55,0xAA 

 

启动虚拟机调试,执行结果如下:

 

在初始化栈时,寄存器SP和BP都指向了0xFFFF地址(栈底),从栈的内存区域来看,数据入栈是从0xFFFE地址开始存储数据的,当数据全部入栈完毕,我们知道最后一个数据肯定是在栈顶的,而寄存器SP正好就指向了0xFFF7(栈顶地址),当然在数据入栈的过程中,寄存器SP的值是一直在不断变化的,大家可以每执行一次push指令时,观察寄存器SP的变化。

ESP和EBP两个寄存器是针对32位的,SP和BP寄存器是16位的。

 

前面说过寄存器SP也表示下一个要入栈的数据的位置,那么有的小伙伴肯定很好奇push指令是怎么把数据入栈的?

以push ax为例,我们可以理解为push指令做了这些事情:

sub sp,2			;将寄存器sp的值减2
mov word[ss:sp],ax	        ;然后把寄存器ax的值存到寄存器sp指向的地址,完成数据入栈

当然,以上这些只是为了方便理解push指令,实际上在汇编程序中这样写是不会编译通过的。

对于出栈,x86汇编提供了pop指令来完成出栈操作,如果你理解了push指令,那么pop指令对你来说,就很容易理解了。

 

汇编代码如下:

mov ax,0x0000
mov ss,ax		;指定栈的段地址为0x0000

mov bp,0xFFFF		;指定栈底的地址
mov sp,0xFFFF		;指定栈顶的地址

;定义数据
mov ax,0x1234
mov bx,0x2345
mov cx,0x3456
mov dx,0x4567

;把数据依次入栈
push ax
push bx
push cx
push dx

;依次出栈
pop dx
pop cx
pop bx
pop ax

End:
jmp near End

times 510-($-$$) db 0x00
db 0x55,0xAA 

 

程序执行结果:

注意观察栈的内存区域,寄存器SP和BP的变化。出栈的时候要遵守先进后出,后进先出的原则,当然你也可以不遵守,按ax,bx,cx,dx的顺序出栈,但是这样可能会导致程序的最终执行结果并不是你想要的。因为我们现在所写的程序已经是没有了操作系统的限制,所以你想做怎么都可以,如果是基于操作系统上这样写程序是肯定不行的,普通用户程序无法直接访问内存,必须借助操作系统才能访问。

 

总结:

栈其实是计算机工程师们在内存的某块区域抽象虚拟出来的一个“箱子”,这个箱子的上端是开口,可以依次往存放东西,但是要遵守先进后出,后进先出的原则。所以不要把栈想象的有多神秘,在汇编语言中就是用ss,sp,bp,以及push和pop指令来管理控制,读写的一块内存区域而已(说白了,栈就是从内存抽象出来的)。

猜你喜欢

转载自blog.csdn.net/qq_35733751/article/details/85234590