美文网首页
汇编语言_06

汇编语言_06

作者: 番薯大佬 | 来源:发表于2017-07-17 15:53 被阅读21次


    • 栈:是一种具有特殊的访问方式的存储空间(后进先出, Last In Out Firt,LIFO)
    • 8086会将CS作为代码段的段地址,将CS:IP指向的指令作为下一条需要取出执行的指令
    • 8086会将DS作为数据段的段地址,mov ax,[address]就是取出DS:address的内存数据放到ax寄存器中
    • 8086会将SS作为栈段的段地址,任意时刻,SS:SP指向栈顶元素
    • 8086提供了PUSH(入栈)和POP(出栈)指令来操作栈段的数据
      • 比如push ax是将 ax的数据入栈,pop ax是将栈顶的数据送入ax

    push ax


    push ax 的执行由以下两个步骤完成

    • SP = SP - 2,SS:SP 指向当前栈顶前面的单元,以当前栈顶前面的单元为新的栈顶;
    • 将ax中的内容送入 SS:SP 指向的内存单元处,SS:SP此时指向新栈顶

    pop ax


    pop ax的执行过程和push ax刚好相反,由以下两步完成

    • 将SS:SP指向的内存单元处的数据送入ax中;
    • SP=SP+2,SS:SP 指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶

    思考
    如果将10000H 到 1000FH 这段空间当做栈,初始状态栈是空的,此时,SS=1000H,SP=?思考后看分析。


    栈空,SS:SP执行栈控件最高地址单元的下一个单元


    结果

    栈顶超界
    push


    pop


    上面描述了执行push、pop指令时,发生的栈顶超界问题。可以看到,当栈满的时候再使用push指令入栈,或栈空的时候再使用pop指令出栈,都将发生栈顶超界问题。

    栈顶超界是危险的,因为我们既然将一段空间安排为栈,那么在栈空间之外的空间里
    很可能存放了具有其他用途的数据、代码等,这些数据、代码可能是我们自己程序中的,也可能是别的程序中的(毕竟一个计算机系统中并不是只有我们自己的程序在运行)。但是由于我们在入栈、出栈时的不小心,而将这些数据、代码意外地改写,将会引发一连串的错误。

    我们当然希望CPU可以帮我们解决这个问题,比如说在CPU中有记录栈顶上限和栈底的寄存器,我们可以通过填写这些寄存器来指定栈空间的范围,然后,CPU在执行push指令的时候靠检测栈顶上限寄存器,在执行pop指令的时候靠检测栈底寄存器保证不会超界。

    不过,对于8086CPU,这只是我们的一个设想(我们当然可以这样设想,如果CPU是我们设计的话,这也就不仅仅是一个设想)。实际 的情况是,8086CPU中并没有这样的寄存器。

    8086CPU不保证我们对栈的操作不会超界。这也就是说,8086CPU只知道栈顶在何处(由SS:SP指示),而不知道我们安排的栈空间有多大。这点好像CPU只知道当前要执行的指令在何处(由CS:IP指示),而不知道要执行的指令是多少。从这两点上我们可以看出8086CPU的工作机理,它只考虑当前的情况:当前的栈顶在何处,当前要执行的指令是哪一条。

    我们在编程的时候要自己操作栈顶超界的问题,要根据可能用到的最大栈空间,来安排栈的大小,防止入栈的数据太多而导致的超界;执行出栈操作的时候也要注意,以防止栈空的时候继续出栈而导致的超界。

    push&pop汇编
    push 和 pop 指令的格式可以是如下形式

    指令 说明
    push 寄存器 将一个寄存器的数据入栈
    pop 寄存器 出栈,用一个寄存器接收出栈的数据
    push 段寄存器 将一个段寄存器中的数据入栈
    pop 段寄存器 出栈,用一个段寄存器接收出栈的数据
    push 内存单元 将一个内存字单元处的字入栈
    pop 内存单元 出栈,用一个内存字单元接收出栈的数据
    mov ax,1000H mov ds,ax 内存单元的段地址要放在ds中
    push [0] 将1000:0处的字压入栈中
    pop [2] 出栈,出栈的数据送入1000:2处

    注意

    • 栈操作都是以字为单位
    • 在8086中,push、pop操作的数据都是2个字节的

    编程练习

    • 将10000H到1000FH 这段空间当做栈,初始状态栈是空的;
    • 设置AX=001AH,BX=001BH;
    • 利用栈,交换AX和BX中的数据。
    mov ax,1000H
    mov ss,ax
    mov sp,0010H
    
    mov ax,001AH
    mov bx,001BH
    
    push ax
    push bx
    pop ax
    pop bx
    

    栈段

    • 对于8086来说,在编程时,可以根据需要,将一组内存单元定义为一个段
    • 我们可以将一组长度为N(N<=64KB)、地址连续、起始地址为16倍数的内存单元,当做栈空间来使用,称为栈段。比如用10010H1001FH这段内存空间当做栈来使用,我们就可以认为10010H1001FH是一个栈段,它的段地址为1001H,长度为16字节
    • 如何使用push、pop等栈操作指令访问我们定义的栈段?
      • 用SS存放栈段的段地址,用SP存放栈顶的偏移地址

    段总结

    • 我们可以用一个段存放数据,将它定义为"数据段"
    • 我们可以用一个段存放代码,将它定义为"代码段"
    • 我们可以用一个段当作栈,将它定义为"栈段"

    对于数据段,将它的段地址放在DS中,用mov、add、sub等访问内存单元的指令时,CPU就将我们定义的数据段中的内容当作数据来访问;
    对于代码段,将它的段地址放在CS中,将段中第一条指令的偏移地址放在IP中,这样CPU就将执行我们定义的代码段中的指令;
    对于栈段,将它的段地址放在SS中,将栈顶单元的偏移地址放在SP中,这样CPU在需要进行栈操作的时候,比如执行push、pop指令等,就将我们定义的栈段当作栈空间来用。

    练习


    练习1
    练习1-答案
    练习2
    练习2-答案

    相关文章

      网友评论

          本文标题:汇编语言_06

          本文链接:https://www.haomeiwen.com/subject/pwkfkxtx.html