3.1内存中字的存储
一个字 = 2个字节。由于内存单元是字节单元(一个单元存放一个字节),存放字需要两个连续的内存单元,这个字的低位字节放在低地址单元,高位字节放在高地址单元
3.2 DS和[address] 对内存单元的读写
8086CPU中,内存地址由段地址和偏移地址组成,DS寄存器存放要访问的数据的段地址。如果将DS设置为1000H,不能直接 mov ds,1000H, 而是:mov ax,1000H mov ds,ax 。(8086CPU不支持直接将数据(立即数)送入段寄存器的操作)
问题3.2
将al中的数据送入内存单元10000H中。
mov bx,1000H
mov ds,bx
mov [0],al ;;al低8位字节,所以送入8bit数据。操作的数据的长短跟据使用的寄存器的大小确定
sub和add等运算操作符不能操作段寄存器
检测点3.1:
(1) 在Debug中,用d 0:0 1F 查看内存,结果如下:
0000:0000 70 80 F0 30 EF 60 30 E2-00 80 80 12 66 20 22 60
0000:0010 62 26 E6 D6 CC 2E 3C 3B-AB BA 00 00 26 06 66 68
下面的程序执行前,AX=0,BX=0,写出每条汇编指令执行完成后相关寄存器中的值
mov ax,1
mov ds,ax
mov ax,[0000] AX= 8070H <---x ds设置为了0001,所以全部错了。。。 ---> 2662
mov bx,[0001] BX= F080H <---x E626
mov ax,bx AX= F080H <---x E626
mov ax,[0000] AX= 8070H <---x 2662
mov bx,[0002] BX= 30F0H <---x D6E6
add ax,bx AX= B160H <---x FD48
add ax,[0004] AX= 124FH <---x 2C14
mov ax,0 AX= 0000H <---x 0000
mov al,[0002] AX= 00F0H <---x 00E6
mov bx,0 BX= 0000H <---x 0000
mov bl,[000C] BX= 0066H <---x 0026
add al,bl AX= 0156H <---x 010C取低地址数据 000C
(2)内存中的情况如图,各寄存器的初始值: CS= 2000H, IP= 0, DS= 1000H, AX= 0, BX= 0;
.写出CPU执行的指令序列(用汇编指令写出)
.写出CPU执行每条指令后,CS,IP和相关寄存器中的值
.数据和代码在内存中有区别吗?如何确定内存中哪些信息是数据,哪些是程序?
CS=2000H, IP=0, DS=1000H, AX=0, BX=0
mov ax,6622H 指令执行前:CS=2000H, IP=3, DS=1000H, AX=0, BX=0 执行后:CS=2000H, IP=3, DS=1000H, AX=6622H, BX=0
jmp 0ff0:0100 指令执行前:CS=2000H, IP=8, DS=1000H, AX=6622H, BX=0 执行后:CS=0ff0H, IP=0100H, DS=1000H, AX=6622H, BX=0 等价于CS=1000H, IP=0
mov ax,2000H 指令执行前:CS=1000H, IP=3, DS=1000H, AX=6622H, BX=0 执行后:CS=1000H, IP=3, DS=1000H, AX=2000H, BX=0
mov ds,ax 指令执行前:CS=1000H, IP=5, DS=1000H, AX=2000H, BX=0 执行后:CS=1000H, IP=5, DS=2000H, AX=2000H, BX=0
mov ax,[0008] 指令执行前:CS= 1000H, IP=8, DS=2000H, AX=2000H, BX=0 执行后:CS=1000H, IP=8, DS=2000H, AX=0C389H, BX=0
mov ax,[0002] 指令执行前:CS=1000H, IP=0B, DS=2000H, AX=0C389H, BX=0 执行后:CS=1000H, IP=0B, DS=2000H, AX=0EA66H, BX=0
程序根据CS:IP和DS:偏移地址 来确定内存中的信息是指令还是数据。
jmp 段地址:偏移地址 -》mov cs,段地址 mov ip,偏移地址
jmp ax -》mov ip,ax(不是说真有这条指令,是指功能类似这样)
3.6 栈
一种具有特殊访问方式的存储空间LIFO:数据遵循先进后出的规则
问题3.6
如果将10000H~1000FH这段空间当作栈,初始状态栈是空的,此时,SS=1000H,SP=?
push数据时,sp = sp - 2,所以栈是由高地址到低地址。栈为空时,栈顶指针指向栈空间的最高地址的下一个单元
栈的最高地址为SS=1000, IP=000F,所以栈顶的下一个单元为0010,IP=0010
3.7 CPU提供的栈机制
8086CPU提供入栈和出栈的指令,最基本的两个指令是PUSH(如栈),POP(出栈),8086CPU的入栈和出栈都是以字(2byte)为单位进行
CPU怎么知道栈顶位置-》任意时刻,SS:SP 指向栈顶元素
数据入栈(push)时 SP=SP - 2,出栈(pop)时 SP=SP + 2; TIPS:栈有大小(最大=2的16次方个字节,CPU在内存上操作的最小单元为字节byte),8086CPU中栈的大小范围:0~64KB(地址连续,起始地址为16的倍数的内存单元),栈顶的最大变化范围:0~FFFFH。8086CPU不保证栈的超界问题,由程序员自己确定。
问题3.7
编程 将10000H~1000FH这段空间当作栈,初始状态栈是空的,将AX,BX,DS中的数据入栈。
mov cx,1000H
mov ss,cx ;设置栈的段地址
mov sp,0010H ;设置栈的偏移地址
push ax
push bx
push ds
问题3.8
编程:
(1) 将10000H~1000FH这段空间当作栈,初始状态栈是空的;
(2) 设置AX=001AH,BX=001BH;
(3) 将AX,BX中的数据入栈;
(4) 然后将AX,BX清零;
(5) 从栈中恢复AX,BX原来的内容
mov ax,1000H
mov ss,ax ;设置栈的段地址
mov sp,0010H ;设置栈顶
mov ax,001AH
mov bx,001BH
push ax
push bx
mov ax,0 ;sub ax,ax 用sub更好,sub指令的机器码为2个字节,mov为3个字节
mov bx,0
pop bx
pop ax
问题3.9
编程:
(1)将10000H~1000FH这段空间当作栈,初始状态栈是空的
(2)设置AX=001AH,BX=001BH
(3)利用栈,交换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
问题3.10
如果要在10000H处写入字型数据,可以用以下的代码完成:
mov ax,1000H
mov ds,ax
mov ax,2266H
mov [0],ax
补全下面的代码,使它能够完成同样的功能:
要求:不能使用"mov 内存单元,寄存器"这类指令
mov ax,1000H
mov ss,ax
mov sp,2 ;将1000:0当作栈,10002作栈顶
mov ax,2266H
push ax ;入栈 先将sp-2,使得ss:sp指向新的内存单元,然后再将数据送入ss:sp指向的新的栈顶单元。记住栈的地址是由高到低的。入栈或出栈操作的内存单元都是sp指向的内存单元,所以出栈时,先将数据取出,再sp+2
问题3.11
如果将10000H~1FFFFH这段空间当作栈段,初始状态栈是空的,此时,SS=1000H,sp=?
sp=0000H
检测点3.2
(1)补全下面的程序,使其可以将10000H~1000FH中的8个字,逆序复制到20000H~2000FH中。(以字为单位复制)
mov ax,1000H
mov ds,ax
mov bx,2000H
mov ss,bx
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 bx,1000H
mov ss,bx
mov sp,0010H
pop [E]
pop [C]
pop [A]
pop [8]
pop [6]
pop [4]
pop [2]
pop [0]
实验2 用机器指令和汇编指令编程
2.实验任务
(1)使用Debug将下面的程序段写入内存,逐条执行,根据指令执行后的实际运行情况填空。
FFFF:0000处的数据
mov ax,ffff
mov ds,ax ;设置数据段地址
mov ax,2200
mov ss,ax
mov sp,0100 ;设置栈段
mov ax,[0] ;ax=C0EA
add ax,[2] ;ax=C0FC
mov bx,[4] ;bx=30F0
add bx[6] ;bx=6021
push ax ;sp=00FE,修改的内存单元的地址是 2200:00FE和2200:00FF 对应地址的内容为FC C0
push bx ;sp=00FC,修改的内存单元的地址是 2200:00FC和2200:00FD 对应的地址的内容为21 60
pop ax ;sp=00FE,ax=6021
pop bx ;sp=0100,bx=C0FC
push [4] ;sp=00FE,修改的内存单元的地址是 2200:00FE和2200:00FF 内容为 F0 30
push [6] ;sp=00FC ,修改的内存单元的地址是 2200:00FD和2200:00FC 内容为 31 2F
(2)分析为什么2000:0~2000:f中的内容会发生改变?
初始没有执行这段代码时,我们使用d命令观察2000:00内存,都是00,怎么创建栈结构指向这段内存时,我们发现有些数据了。这些数据是什么?
我们发现这里面有cs值、ip值、ax值(这个容易看出来),还有bp值(00 00),还有flag的值(这个我用肉眼是看不出来了。呵呵,就是那个一排英文字符)。
为什么,在讲内中断这章时,你就明白了。t命令实际是引发了单步中断,执行中断例程时,CPU会将一些中断例程使用的的寄存器变量自动压栈到栈中,此例中就包括了上述的寄存器变量的值。
我们可以不必理会这些寄存器的变量,我们只关心sp就可以了。有它指示,我们就可以对栈进行操作了。而此时的sp是正确的,
注意:这个栈和我们创建的栈是同一个栈结构(为什么,ss=2000H了),由于t命令必须保存寄存器变量的值(这个是中断程序定义的。)它也占用一定的空间。可能我们定义的栈空间比较小;频繁的使用push指令,为了避免栈顶超界,我们尽量使栈空间大些,就像此程序,设定栈空间是100H。 此问题答案copy自:https://www.cnblogs.com/Base-Of-Practice/articles/6883882.html