|
发表于 2012-11-13 23:36:33
|
显示全部楼层
我也是刚走到这里,上网找到的笔记,自己也在理解
学习笔记:第三章 寄存器(内存访问)
1.字在内存中存储时,要用两个地址连续的内存单元来存放。字的低位字节存放在低地址单元中,高位字节存放在高地址单元中。我们将起始地址为n的字单元为n地址单元。
2.[address]表示一个偏移地址为address的内存单元。
用mov指令要存放内存单元时,可以在mov指令中只给出单元的偏移地址,此时,段地址默认在ds寄存器中。
同样的,在debug中使用d命令和e命令(处理内存数据),只需给出单元的偏移地址,段地址默认在ds寄存器中;使用a命令,u命令和t命令(处理指令),只需给出单元的偏移地址,段地址默认在cs寄存器中;
3.传送指令MOV(Move Instruction):
传送指令是使用最频繁的指令,它相对于高级语言里的赋值语句。
指令格式: MOV dest, src
指令功能:把一个字节或字的操作数从源地址src传送至目的地址dest。指令执行后,目的操作数的值被改变,而源操作数的值不变。在存储单元是该指令的一个操作数时,该操作数的寻址方式可以是任意一种存储单元寻址方式。
MOV指令是采用寻址方式最多的指令,用我们约定的符号可以表达如下:
MOV reg/mem,imm ;立即数送寄存器或主存
MOV reg/mem/seg,reg ;寄存器送寄存器(包括段寄存器)或主存
MOV reg/seg,mem ;主存送寄存器(包括段寄存器)
MOV reg/mem,seg ;段寄存器送主存或寄存器
对MOV指令有以下几条具体规定,其中有些规定对其它指令也同样有效。
(1)两个操作数的数据类型要相同,要同为8位、16位或32位;如:MOV BL, AX等是不正确的;
(2)在内存和寄存器之间传送字类型数据时,高地址单元和高8位寄存器,低地址单元和低8位寄存器相对应;
(3)两个操作数不能同时为段寄存器,如:MOV ES, DS等;
(4)两个操作数不能同时为存储单元,如:MOV VARA, VARB等,其中VARA和VARB是同数据类型的内存变量;
(5)代码段寄存器CS不能为目的操作数,但可作为源操作数,如:指令MOV CS, AX等不正确,但指令MOV AX, CS等是正确的;
(6)指令指针IP,不能作为MOV指令的操作数;
(7)立即数不能直接传给段寄存器,如:MOV DS, 100H等;
(8)立即数不能作为目的操作数,如:MOV 100H, AX等;
(9)由于指定的寄存器有明确的字节或字类型,所以对应的立即数也必须分别是字节或字;但在涉及存储器单元时,指令中给出的立即数可以理解为字,也可以理解为字节,此时必须显式指明。为了区别是字节传送还是字传送,可用汇编操作符byte ptr(字节)和word ptr(字)指定;
(10)对于不能直接传送的数据,如(2)(3)(6),可以使用通用寄存器作为中转站;不能用传送指令MOV修改寄存器CS和IP,可使用转移指令JMP设置它们的值。
4.堆栈:
堆栈是一个“先进后出”的主存区域,位于堆栈段中,使用SS段寄存器记录其段地址。堆栈只有一个出口,即当前栈顶。栈顶是地址较小的一端(低端),它用堆栈指针寄存器SP指定。
堆栈有两种基本操作,对应有两条基本指令:进栈指令PUSH和出栈指令POP。
任意时刻,SS:SP指向栈顶元素。PUSH指令和POP指令执行时,CPU从SS和SP中得到栈顶的地址。
用栈来暂存以后需要恢复的寄存器的内容时,寄存器出栈的顺序和入栈时相反。
PUSH,POP实质上就是一种内存传送指令,可以在寄存器和内存之间传送数据,与MOV指令不同的是,PUSH和POP指令访问的内存单元的地址不是在指令中给出的而是有SS:SP指出的。同时,PUSH 和POP指令还要改变SP中的内容。
5.进栈指令:
指令格式: PUSH src
指令功能:把一个字操作数存入堆栈顶部,同时使堆栈指针SP减2。
执行顺序:SP的值先减1,操作数的高位字节送入当前SP所指内存单元中;然后SP的值再减1,操作数的低位字节送入当前SP所指内存单元中。
说明:(1)PUSH入栈指令可以使用的源操作数src有:寄存器(通用寄存器,地址指针,变址寄存器,段寄存器),存储器。只有立即数不允许入栈。
(2)堆栈操作的对象只能是字操作数,进栈时,低字节存放于低地址,高字节存放在高地址,SP相应向低地址移动两个字节单元。
(3)栈为空时,SS:SP指向栈空间最高地址单元的下一个单元。如我们将10000H-1000FH这段空间当作栈。初始状态栈是空的,此时,SS = 1000H,SP = 0010H。
理解方式有两种:一是我们可以假设栈中有只有一个元素,则SP = 000EH。现在将这个元素出栈,则 SP = SP + 2,变成SP = 0010H。二是因为当栈为空时,栈中没有元素,也就不存在栈顶元素,所以SS:SP只能指向栈的最底部字单元下面的单元,该单元的偏移地址为栈最底部的字单元的偏移地址+2。栈的最底部字单元的地址为1000:000E,所以当栈空时,SP = 0010H。
6.标志进栈指令:
指令格式:PUSHF
指令功能:把标志寄存器PSW中的内容存入堆栈顶部,同时使堆栈指针SP的值减2。
执行顺序:SP的值先减1,PSW的高位字节送入当前SP所指内存单元中;然后SP的值再减1,操作数的低位字节送入当前SP所指内存单元中。
说明:默认规定了标志寄存器和和当前堆栈栈顶空间。
7.出栈指令:
指令格式: POP DST栈顶的一个字传送至指定的目的操作数,然后堆栈指针SP加2。目的操作数应为字操作数,
指令功能:把当前SP所指向堆栈顶部的一个字弹出送入指定的目的操作数,同时使堆栈指针SP加2。
执行顺序:先将SP所指的栈顶单元内容送入DST低位字节单元,SP的值加1;然后将当前SP所指的栈顶单元内容送入DST高位字节单元,SP的值再加1。
说明:(1)PUSH入栈指令可以使用的目的操作数dest有:寄存器(通用寄存器,地址指针,变址寄存器,段寄存器),存储器。立即数和段寄存器CS不允许作为目的操作数。
(2)堆栈操作的对象只能是字操作数,字从栈顶弹出时,低地址字节送低字节,高地址字节送高字节,SP相应向高地址移动两个字节单元。
(3)出栈后,SS:SP指向新的栈顶。POP操作前的栈顶元素依然存在,但是,它已经不在栈中,当再次执行PUSH等入栈指令后,新的指令将其覆盖。
8.标志出栈指令:
指令格式:POPF
指令功能:从堆栈顶部弹出两个字节送到标志寄存器PSW中,同时使堆栈指针SP的值加2。
执行顺序:先将SP所指的栈顶单元内容送入PSW的低位字节单元,SP的值加1;然后将当前SP所指的栈顶单元内容送入PSW的高位字节单元,SP的值再加1。
说明:默认规定了标志寄存器和和当前堆栈栈顶空间。
9.栈顶超界的问题:
当栈满的时候再使用PUSH指令入栈,或栈空的时候再使用POP指令出栈,都会发生栈顶超界的问题。
8086CPU不保证我们对栈的操作不会超界。所以我们在编程的时候要自己操心栈顶超界的问题,要根据可能用到的最大栈空间,来安排栈的大小,防止入栈的数据太多而导致的超界;执行出栈操作时也要注意,以防止栈空的时候继续出栈而导致的超界。
PUSH,POP等栈操作指令,修改的只是SP。因为逻辑段的最大容量为64KB,所以栈顶的变化范围最大为0-FFFFH。从栈空的时候SP=0,一直入栈,直到栈满使SP=0;如果再次入栈,栈顶将环绕,覆盖了原来栈中的内容。所以一个栈段的容量最大为64KB。
10.段的综述:
一段内存,可以既是代码的存储空间,又是数据的存储空间,还可以是栈空间,也可以什么都不是。关键在于CPU中寄存器的设置,即当CS:IP指向该处时,CPU将其视为代码;当SS;SP指向该处时,CPU将其视为栈;当DS指向该处时,CPU将其视为普通数据。
Debug的T命令在执行修改段寄存器SS的指令时,下一条指令也紧接着被执行。
11.检测点3.2
(1)补全下面的程序,使其可以将10000H-1000FH中的8个字,逆序拷贝到20000H-2000FH中。
mov ax, 1000H
mov ds, ax
( mov ax, 2000H )
( mov ss, ax )
( mov sp, 0010H );此时栈空
push [0]
push [2]
push [4]
push [6]
push [8]
push [A]
push [C]
push [E]
(2)补全下面的程序,使其可以将10000H-1000FH中的8个字,逆序拷贝到20000H-2000FH中。
mov ax, 2000H
mov ds, ax
( mov ax, 1000H )
( mov ss, ax )
( mov sp, 0000H );此时栈满
pop [E]
pop [C]
pop [A]
pop [8]
pop [6]
pop [4]
pop [2]
pop [0] |
|