[Intel汇编-MASM]栈

1. CPU的栈操作的支持:

    1) 现代CPU都提供栈的功能,即提供栈的访问功能,指令有push和pop等;

    2) 8086CPU对栈的操作(push、pop等)都是以字为单位的,即16位,因此不得在栈操作中使用非16位的寄存器,如AL等,否则将会报错;


2. 用SS:SP定义一个内存栈:

     1) 和前面利用DS寄存器定义一个数据段一样,栈同样也是存在于用户的内存区的(即当前程序的内存区);

     2) 栈段段基由SS寄存器定义(即Stack Segment),而SP这个偏移指针则用来指示栈顶,因为栈是后进先出的,因此初始化时SP大于SS,并且入栈是SP变小出栈SP变大,因此栈是一个反向扩增的内存区域,栈顶是低地址,栈底是高地址;

     3) 定义栈(即对SS:SP进行初始化):初始化时设SS = N, SP = M,则栈底 = M - 2,栈顶 = N,总共可以放(M - N) / 2个字(注意!栈操作的单位是字);

!注意:栈也只是内存空间中的一部分,只不过它具有特殊的访问方式而已(通过push和pop方式访问);


3. push和pop的执行过程(举例的形式):

    1) 对于push ax:先sp -= 2再将ax压入ss:sp处,从图形上看就是sp先往下退两格再塞ax(向下地址变小);

    2) 对于pop ax:先将ss:sp处的字赋给ax,然后sp += 2,从图形上看就是先取值然后sp往上进两格(栈底在上面,栈顶在下面,栈是一个反向扩充的内存区);

!注意:弹栈并不意味着弹掉的空间清零,只是不去管它(即不维护了),将来可能会被覆盖掉;


4. 越界问题:

     1) CPU在硬件层面上并没有提供任何越界警告的机制,即当用于多次push和pop之后sp超出上面所述的N ~ M - 2的范围;

     2) 越界的危害,越界后可能访问到其它正在执行的程序或者操作系统的内核,如果不小心对其中的数据进行修改则后果不堪设想,可能会造成死机崩溃;

     3) 越界攻击:是一种黑客常用的手段,比如一般用户的敏感信息如密码等不得直接访问,黑客就会在密码段旁边的空间设定一个栈,然后不停pop(pop不会修改数据,而push会修改数据,因此就用pop),越界到密码段,然后获取密码,这当然只是一个例子,越界攻击还可以做其它意想不到的事;


5. push和pop指令的具体使用:

    1) 同样,这里只介绍操作对象是寄存器的情况,当操作对象是内存单元时比较麻烦,这里的规则并不适用;

    2) 对于push,除了ip不能push以外其它所有寄存器都可以push,意思就是把push后面寄存器中的内容压栈;

    3) 对于pop,除了cs和ip不能作为操作数以外其余寄存器都可以,意思就是将栈顶的元素弹至pop后面指定的寄存器中保存;

    4) 示例:

; 定义一个栈
mov		ax, 1000H
mov		ss, ax
mov		sp, 10H

; 对ax和bx初始化
mov		ax, 1AH
mov		bx, 2BH

; 备份ax和bx到栈中
push	ax
push	bx

; 破坏(清空)ax和bx
sub		ax, ax
sub		bx, bx

; 从栈中恢复数据(注意后进先出的顺序)
pop		bx
pop		ax

; 顺序弄错就成交换ax和bx的值了
pop		ax
pop		bx
!注意,可以直接对sp使用传送指令!


6. 关于Debug的T命令中断问题的介绍:

       a. 在使用命令D、U、E、A时,其中的段基地址可以直接使用寄存器来代替,这使得调试更加方便和快捷;

       b. 例如:D DS:1000、A CS:00等;

当用用T命令执行修改SS寄存器(必须是SS寄存器)的命令时将会一次性执行两条指令,即包修改SS寄存器的下一条指令也同时执行了,因此将会看不见Debug停留在修改SS寄存器指令的下一条指令,如下图所示:

       

!这是因为当T遇到修改SS寄存器的指令时会产生中断,当然现在可以先不管这个问题,这个问题会在以后解释,但不过在用Debug调试的时候一定会因为遇到这个问题而感到非常郁闷;

**同样这种中断也会使栈中出现意想不到的数据:

   

     当2000:0~10的范围设为栈,但是由于T命令遇到修改ss而产生中断而使栈中的内容不为0,这就说明了中断处理过程中使用了ss:sp定义的栈并产生了数据,这点要非常注意,虽然中断返回后ss:sp被重新设成了初值(这就意味着这并不影响中断返回后栈的使用),但有些情况下需要避免这种情况,特别是在操作系统初始化的时候就需要内核栈不被任何数据占用,这就意味着内核初始化时不得调用任何函数(函数会产生中断),因此所有函数都必须使用内联或宏替换进行代码嵌入!(貌似扯远了。。。)

你可能感兴趣的:(栈,masm,intel汇编)