• 对 栈 的理解

    一,初始

    栈是一种具有特殊访问方式的储存空间。它的特殊性就在于,最后进入这个空间的数据,最先出去。

    • 可以用一个盒子和3本书描述img

    可以想象一下,如果这三本书是一行行代码,那么,它的解释入栈和出栈原理就是和图中所示的大概一样。

    二、栈的操作

    • 入栈:将一个新的元素放到栈顶
    • 出栈:从栈顶取出一个元素

    栈顶的元素总是最后入栈,需要出栈时,又总是最先被从栈中取出

    这种操作规则:LIFO(Last in First out,后进先出)

    一般来说,在汇编中,入栈和出栈的指令是最基本的,push(入栈),pop(出栈)

    如:

    push ax将寄存器ax中的数据送入栈中

    pop ax从栈顶取出数据放到ax寄存器中

    8086CPU的入栈和出栈方式都是以字(16位)为单位进行的

    三、举例理解

    如果将10000H~1000FH这段内存当做栈来使用,理解以下指令

    1
    2
    3
    4
    5
    6
    7
    8
    9
    mov ax,0123H
    push ax
    mov bx,2266H
    push bx
    mov cx,1122H
    push cx
    pop ax
    pop bx
    pop cx

    分解指令理解

    • 初始栈的模型

      image-20211218142551845

    • mov ax,0123Hpush ax

      0123H放入ax中,然后将ax中的数据push 进栈

      image-20211218142851085

    • 同理, mov bx,2266Hpush bx

      2266H放入bx寄存器中,再将bx中的数据push进栈

      image-20211218143350528

    • 同理,mov cx,1122Hpush cx

      image-20211218143631913

    • pop ax

      pop指令是将栈顶的元素取出,放入ax中,由于这时栈顶的元素数据是1122H,所以将其取出

      image-20211218144052750

    • pop bx

      同理,这时pop取出栈顶的元素2266H,并放入bx中

      image-20211218144721558

    • pop cx

      这时取出0123H,将其放入cx中

      image-20211218145729752

    由此,一个程序执行完毕,栈就恢复了原始状态

    注意:字形数据用两个单元存放,高地址放高8位,低地址放低8位

    四、CPU如何知道指令位置

    通过了一个例子的执行,可能有个问题,CPU是如何知道要执行指令的位置

    答案是,寄存器CSIP中存放着当前指令的段地址和偏移地址,并且,在任意时刻,SS:SP都指向栈顶的元素。

    • 段寄存器SS: 存放栈顶的段地址

    • 寄存器SP:存放栈顶的偏移地址

      push深刻理解

    push ax事实上执行了两步操作,

    1. SP=SP-2

    2. 将ax中的内容送入SS:SP指向的内存单元处,SS:SP指向新的栈顶

    image-20211218151824132

    pop深刻理解

    pop与push是逆运算,pop ax同样也需要执行两步操作

    1. SS:SP指向的单元中的数据取出,放到ax中
    2. SP=SP+2,这时SS:SP指向了新的单元

    image-20211218153457919

    由上面两步可以看出,所谓 ’取出‘ 数据,其实,并只取出了数据,并没有删除内存中的数据,而是将SS:IP的指向改变了,原来存入的数据还在,若想要删除,只能用新的数据覆盖

    五、栈的大小

    因为SS:SP只记录了栈顶的地址,依靠SS和SP可以保证入栈和出栈时找到栈顶,如何保证在入栈和出栈时,栈顶不会超出栈空间?

    即是

    • 当栈满的时候再使用push指令入栈
    • 当栈空的时候再使用pop指令出栈

    这就会导致栈顶超界问题,非常危险

    1. 栈顶超界

      img

    2. 栈底超界

      img

    以上演示图片说明,栈顶超界是危险的

    因为我们既然将一段空间安排为栈,那么在栈空间之外的空间里很可能存放了具有其它用途的数据、代码,可能是我们自己程序中的,也可能是别的程序中的,毕竟在计算机中并不是只有我们自己的程序在运行。

    这就是所谓的栈溢出,从黑客角度,就是溢出攻击

    六、设置栈

    如果将10000H~1000FH这段空间当做栈,初始状态是空的,如何将AX,BX,DS中的数据入栈?

    1
    2
    3
    4
    5
    6
    mov ax,1000H
    mov ss,ax ;设置栈的段地址,SS=1000H,不能直接向SS送入数据,用AX中转
    mov sp,0010H ;设置栈顶的偏移地址,因为栈为空,所以SP=0010H
    push ax
    push bx
    push ds

    栈的意义就在于暂时储存以后需要恢复的寄存器内容

    七、参考链接

    小甲鱼汇编入门:

    https://www.bilibili.com/video/BV1zW411n79C

    阮一峰-汇编入门教程:

    https://www.ruanyifeng.com/blog/2018/01/assembly-language-primer.html

    上一篇:
    android 嵌入python 互交
    下一篇:
    Base64 的算法原理
    本文目录
    本文目录