汇编实验二 用机器指令和汇编指令编程
Skyen Lv4

实验任务

(1)使用Debug,将下面的程序段写入内存,逐条执行,根据指令执行后的实际运行情况填空。

书上实验内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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;修改的内存单元的地址是220FE,内容是C0FC
push bx ;sp= 00FC;修改的内存单元的地址是220FC,内容是6021
pop ax ;sp= 00FE;ax= 6021
pop bx ;sp= 0100;bx= C0FC

push [4] ;sp= 00FE;修改的内存单元的地址是220FE,内容是30F0
push [6] ;sp= 00FC;修改的内存单元的地址是220FC,内容是2F31

运行结果:

可爱的图一

淘气的图二

程序分析:

  • 首先,我使用的是Mac 系统下 DOSBox 的debug 环境。

    不同的系统运行结果是不是一样呢?有可能吧~ 主要考虑他的原理。

  • 逐步分析:
    首先,前两行代码将ds指向了FFFF段内存,也就是数据段是ffffH:00开始的内存单元了。
    然后,建立一个栈结构,ss指向2200H段的内存,初始化栈顶指针是100H,ss:sp指向栈底后面第一个单元(目前栈结构是空);也就是说这个栈结构栈底后面第一个单元地址是2200:100H(物理地址:22100H)

1
2
3
4
mov ax,[0]        //ax=C0EA;
add ax,[2] //ax=ax+[2]=C0EA+0012=C0FC
mov bx,[4] //bx=30F0;
add bx,[6] //bx=bx+[6]=31F0+2F30=6120
1
2
3
4
5
6
7
8
9
10
11
12
13
14
push ax          //将ax=C0FC压入栈中;sp=sp-2=0100-2=00FE;
修改的内存单元的地址是220FE,内容是C0FC

push bx //将bx=6120压入栈中;sp=sp-2=00FE-2=00FC
修改的内存单元的地址是220FC,内容是6021

pop ax //将ax=C0FC推出栈;sp=sp+2=00FE;ax=6021
pop bx //将ax=C0FC推出栈;sp=sp+2=0100;bx=C0FC

push [4] //将DS:0004压入栈中;sp=sp-2=00FE;
修改的内存单元的地址是220FE,内容是30F0

push [6] //将DS:0006压入栈中;sp=sp-2=00FC;
修改的内存单元的地址是220FC,内容是2F31

对比实验:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
mov ax,2100
mov ds,ax

mov ax,2200
mov ss,ax

mov sp,0100

mov ax,[0] ;ax= 3130
add ax,[2] ;ax= 6462
mov bx,[4] ;bx= 3534
add bx,[6] ;bx= 6C6A


push ax ;sp= 00FE
;修改的内存单元的地址是2200:FE到FF, 内容为:62 64
push bx ;sp= 00FC
;修改的内存单元的地址是2200:FC到FD, 内容为:6A 6C
pop ax ;sp=00FE ;ax= 6C6A
pop bx ;sp=0100 ;bx= 6462

push [4] ;sp= 00FE
;修改的内存单元的地址是2200:FE到FF, 内容为:34 35
push [6] ;sp= 00FC
;修改的内存单元的地址是2200:FC到FD, 内容为:36 37


  • 可以看出尽管修改了数据,但是基本的原理都还相同。

  • 程序理解:
    【1】创建了一个栈的结构,它的实质就是一段连续的内存空间,只不过访问内存的方式不像我们原来的CPU寻址方式,使用push和pop访问。
    【2】栈使用的实际空间是随着sp指针的指向而发生改变的,它和最大使用空间是有区别的。栈空,sp=100H,栈满,sp=0。
    【3】栈操作的对象基本单位是字单元(2个字节),对应的内存就是2个内存单元。

(2) 仔细观察图中的实验过程,然后分析:为什么2000:0~2000:f中的内容会发生改变。

可能要再做些实验才能发现其中的规律。如果你在这里就正确回答了这个问题,那么要恭喜你,因为你有很好的悟性。大多数的学习者对这个问题还是比较迷惑的,不过不要紧,因为随着课程的进行,这个问题的答案将逐渐变得显而易见。
  1. 在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 前三行指令的功能为:
  1. 将2000进入ax寄存器中

  2. 将ax中的值赋值给ss

  3. 将sp的值改为0010。

  • 变化的原因为:
    在用t指令进行调试时,会产生中断。cpu将先把标志寄存器进栈,再把当前的cs的值进栈,IP的值最后进栈。

总结体会:

初始没有执行这段代码时,使用d命令观察2000:00内存,都是00,怎么创建栈结构指向这段内存时,我们发现有些数据了。这些数据是什么?

发现呢这里面有cs值、ip值、ax值(这个容易看出来),还有bp值(00 00),还有那个一排英文字符。

了解一下之后呢,发现:t命令实际是引发了单步中断,执行中断例程时,CPU会将一些中断例程使用的的寄存器变量自动压栈到栈中,此例中就包括了上述的寄存器变量的值。

注意:由于t命令必须保存寄存器变量的值(这个是中断程序定义的。)它也占用一定的空间。可能我们定义的栈空间比较小;频繁的使用push指令,为了避免栈顶超界,我们尽量使栈空间大些,就像此程序,设定栈空间是100H。