第三章 寄存器(内存访问)

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

原文地址:https://www.cnblogs.com/linxisuo/p/13177133.html