couse83_lab1计算机基础知识

1. 字长与寄存器

学习汇编语言以 Intel 8086 CPU 为基础会更容易掌握。

要知道,微型计算机的字长与微处理器的寄存器位数有关。

  • 以 Intel 80X86 系列微处理器为例,CPU 是 8086/8088、80286 的字长是 16 位(二进制位 bit),那么它们的寄存器的位数一定是 16 位的;

  • 32 位字长的微机 CPU 是 80386/80486 或者 Pentium 系列,它们的寄存器的位数则是 32 位的。

学习汇编语言我们会用到十六进制(H)的数据形式,要使自己尽快习惯用十六进制来思维。

在汇编语言中,数值后面分别用字母B、H、D代表二进制(Binary)、十六进制(Hexadecimal)、十进制数(Decimal)(十进制数可以省略 D)。

在计算机中还规定采用字节、字、双字等单位来表示数据。

  • 字节(Byte):8 位二进制数。如 00000101B 或表示成 05H10000101B 或表示成 85H
  • 字(Word):16 位二进制数,等于 2 字节。如 1100010111010110B 或表示成 C5D6H
  • 双字(Double Word):32 位二进制数,又称为双精度数,等于 4 字节。如 23456789H

2. 8086 寄存器

8086 寄存器都是 16 位的寄存器,根据用途可分为 4 种类型。分别是数据寄存器、地址寄存器、段寄存器和控制寄存器。

如图所示:
在这里插入图片描述

2.1 数据寄存器

数据寄存器中每个寄存器又可以分为 2 个 8 位的寄存器。分别为 AH、AL,BH、BL,CH、CL,DH、DL。H 表示高字节(高 8 位)寄存器、L 表示低字节(低 8 位)寄存器。

例如:用 AX 寄存器存放一个字 1234H,表示为 (AX)=1234H,即高字节 12 放在 AH,低字节 34 放在 AL 中。

2.2 地址寄存器

地址寄存器包括指针和变址寄存器 SP、BP、SI、DI 四个 16 位寄存器。

顾名思义,它们可用来存放存储器操作数的偏移地址。另外,它们也可以作为通用寄存器用。

2.3 段寄存器

8086CPU 有 4 个 16 位的段寄存器,分别是 CS 代码段寄存器、DS 数据段寄存器、ES 附加段寄存器、SS 堆栈段寄存器。

2.4 控制寄存器

控制寄存器包括 IP 和 FLAGS(又称为 PSW 程序状态字)两个 16 位寄存器,用于控制程序的执行。

IP 指令指针寄存器,用来存放代码段中的偏移地址,指出当前正在执行指令的下一条指令所在单元的偏移地址。

FLAGS 标志寄存器中的某位代表 CPU 的 1 个标志,表示出 CPU 的某种执行状态。最低位为 D0,最高位为 D15。8086CPU 的标志寄存器共有 9 个标志,分别为 6 个条件码标志和 3 个控制标志。如图:

在这里插入图片描述

条件码标志:

  • CF 进位标志。当指令执行结果的最高位向前有进位时,CF=1,否则 CF=0。
  • SF 符号标志。当指令执行结果的最高位(符号位)为负时,SF=1,否则 SF=0。
  • ZF 零标志。当指令执行结果为 0 时,ZF=1,结果不为 0 时,ZF=0。
  • OF 溢出标志。当指令执行结果有溢出(超出了数的表示范围)时,OF=1,否则 OF=0。
  • AF 辅助进位标志。当指令执行结果的第 3 位(半字节)向前有进位时,AF=1,否则 AF=0。
  • PF 奇偶标志。当指令执行结果中 1 的个数为偶数个时,PF=1,否则 PF=0。

控制标志:

  • DF 方向标志。执行串处理指令时,若设置 DF=0,存储单元的地址寄存器的值自动增加,若设置 DF=1,存储单元的地址寄存器的值自动减小。
  • IF 中断标志。设置 IF=1,允许 CPU 响应可屏蔽中断,IF=0 则不响应。
  • TF 陷阱标志。在 DEBUG 调试时,TF=1,采用单步执行方式,即进入陷阱;TF=0,正常执行程序。

两个二进制数相加运算,有关标志位自动发生变化。

在这里插入图片描述

根据计算结果可知 CPU 会自动地把标志位设为:CF=0,SF=1,ZF=0,OF=0,PF=0,即无进位,结果为负数,结果不为 0,没有溢出,奇数个 1。

对溢出的判断也可以从简单的角度理解,因为进行运算的二进制数是补码,可看出本题是一个负数和一个正数相加,结果为负数,不溢出。若两个正数相加,结果为负数,或者两个负数相加,结果为正数,那都是溢出了,说明 8 位补码已经表示不了该结果。

2.5 DEBUG 下的标志位表示

在 DEBUG 调试环境下以字母缩写的形式表示各个标志位的状态。

进入 DEBUG 后,用 R 命令查看寄存器状态时,可以看到除了陷阱标志以外的标志位的状态。

在这里插入图片描述

2.6 数的补码运算

在计算机中,对带符号数可用真值和机器数两个概念表示。

真值,就是带有“+”、“-”号的实际数值;所谓机器数,则是把“+”、“-”符号数值化(0、1)后所得到的计算机实际能表示的数。

机器数有三种码表示,分别是原码、反码和补码。汇编语言中,数都是以补码的形式表示的,因此必须掌握数的补码表示和补码的运算。这三种码的定义如下:

  • 原码。原码将最高位作为符号位,正数为 0,负数为 1,其余 7 位作为数值位。
  • 反码。正数的反码与正数的原码一样。而求负数的反码时,符号位为 1,数值位在原码的基础上求反。
  • 补码。正数的补码与正数的原码一样。求负数的补码时,符号位为 1,数值位在原码的基础上求反加 1

十进制数 +5 和 -5 分别表示成二进制数原码、反码和补码。

[+5]= [+5]= [+5]= 00000101B  
[-5]= 10000101B  
[-5]= 11111010B  
[-5]= 11111011B  

3. 内存

在汇编语言中,内存是非常重要的学习内容。我们先要对内存地址和存储单元的概念进行学习。

对存储单元的标识可以用物理地址或逻辑地址表示。

3.1 物理地址

物理地址是内存单元的真实地址,存储单元的物理地址是唯一的。

Intel 8086 CPU 有 20 根地址线,因此其存储空间可达 2 的 20 次方 = 1 M 个字节单元(1MB)。

地址都是从 0 开始的,在 20 位地址线的存储空间中采用十六进制表示的物理地址范围是 00000H ~ FFFFFH

3.2 逻辑地址

逻辑地址是用户编程时使用的地址,分为段地址和偏移地址两部分。

在 8086 汇编语言中,把内存地址空间划分为若干逻辑段,每段由一些存储单元构成,每段最大为 65536 个字节单元(0 号单元~65535 号单元 0000H~FFFFH

用段地址指出是哪一段,偏移地址标明是该段中的哪个单元。
段地址和偏移地址都是 16 位二进制数。

逻辑地址的形式:段地址:偏移地址

在这里插入图片描述

在上图中,内存划分出了若干段。0 号段,1 号段,…,每一段都有 0 号单元、1 号单元、2 号单元,…。每段的长度可以不一样,如 0 号段从 0 号单元到 0FH 号单元共 16 个字节单元,1 号段从 0 号单元到 0139H 号单元共 314 个字节单元。

用段地址表示段号,偏移地址代表每一段中的单元号,比如 0000:0002H 代表 0 号段的 2 号单元,0001:0002H 代表 1 号段的 2 号单元,以此类推。因此,偏移地址的通俗含义是在该段内,相对于段地址偏移了多少个单元。

3.3 逻辑地址转换为物理地址

用户编程时采用的逻辑地址在 CPU 执行程序时都要转换成实际的物理地址,这个转换过程是由 CPU 中的地址加法器自动完成的。

转换时先将 16 位的段地址左移 4 位,相当于乘以 16 或十六进制的 10H,再和偏移地址相加。转换公式为:

物理地址 = 段地址 × 10H + 偏移地址

例:若某单元的逻辑地址为 0001:0002H,其物理地址 = 0001H × 10H + 0002H = 00012H;另一单元的逻辑地址为 3020:055AH,其物理地址 = 3020H × 10H + 055AH = 3075AH。

存储器逻辑分段类型如下:

  • 代码段:用于存放指令,段地址存放在段寄存器 CS。
  • 数据段:用于存放数据,段地址存放在段寄存器 DS。
  • 附加段:用于辅助存放数据,段地址存放在段寄存器 ES。
  • 堆栈段:是重要的数据结构,可用来保存数据、地址和系统参数,段地址存放在段寄存器 SS。

存储单元中的数据称为存储单元内容,一个实际的存储单元只能存放一个字节(8 位二进制)的数据。存储单元的地址和内容的表示形式为用括号将地址括起来以代表单元的内容。

如(3075AH)=12H,表示 3075AH 号单元中的内容是 12 H,称为字节单元;

若(37692H)=5678H,表示 37692H 单元和 37693H 单元一起存放 5678H,该单元是字单元。字单元在存储的时候,高字节放在高地址单元,低字节放在低地址单元,即 56H 放在 37693H 单元,78H 放在 37692H 单元。

如图:

在这里插入图片描述

有关 CPU 和存储单元的概念我们已经了解了,那么如何观察实际机器内部的情况呢?能不能看到具体的寄存器、标志、存储单元的内容呢?可不可以修改和控制它们呢?

这一系列的疑问我们可以在调试工具软件 DEBUG 的支持下得到解答。通过上机实验,可加强相关理论概念的理解;而掌握了 DEBUG 这个有力工具,就可以深入到机器内部进行观察了。

4. Debug

在 DOS 操作系统和 Windows 操作系统中,都提供了调试工具 DEBUG。

DEBUG 是为汇编语言设计的一种调试工具,它通过单步、设置断点等方式为程序员提供了非常有效的调试手段。利用它可以观察和修改 CPU 的寄存器、内存单元;可以跟踪程序的运行,发现程序的错误。

实验楼环境中采用 dosemu 来模拟 DOS 环境,进入 DOS 环境中可以直接启动 DEBUG 程序。

DEBUG 命令有 20 多个,我们主要学习最常用的命令。

R ——查看和修改寄存器
D ——查看内存单元
E ——修改内存单元
U ——反汇编,将机器指令变为汇编指令
T / P ——单步执行
G ——连续执行程序
A ——输入汇编指令
Q ——退出

注意:DOS 和 DEBUG 命令都支持不区分大小写。

  • cd\ ——首先要用 cd\ 退回到根目录 C> 下
  • dir ——显示文件列表
  • md hb ——建立 hb 子目录
  • cd hb ——进入 hb 子目录
  • copy d:\dos\masm.exe c:\hb ——将 D 盘 dos 目录下的 masm.exe 拷贝到 C 盘 hb 目录下
  • copy d:\dos\link.exe c:\hb ——将 D 盘 dos 目录下的 link.exe 拷贝到 C 盘 hb 目录下
  • cd .. ——退回到上一级目录
  • del \hb\masm.exe ——删除 hb 子目录中的某文件
  • rd hb ——删除 hb 子目录(子目录中的所有文件必须先删除)
  • e: ——进入 e 盘
  • cls ——清屏
  • type ——显示文本文件内容(如 type c:\hb\abc.asm)

4.1 R - 查看和修改CPU中寄存器的内容

R 命令有两种用法:

  1. 直接键入 R —— 将显示 CPU 所有的寄存器和标志位;

  2. 修改寄存器 —— 在 R 后跟写寄存器名(比如 R AX),回车后先显示寄存器的内容,在冒号后键入新的值;再用 R 命令就可看到修改后的内容了。

如图所示,使用 R AX 将 AX 寄存器的值改为 1234H。
在这里插入图片描述
观察上图,由于此时 DEBUG 进入的是操作系统环境,R 命令显示的是系统下的寄存器的值。可看出,AX、BX、CX、DX 均为 0,如果将 AX 寄存器的值修改为 1234H,执行 R AX 之后在冒号后输入 1234 即可。注意,DEBUG 下的数据都是十六进制数。

再来看四个段寄存器 DS、ES、SS、CS 的值都是 07BEH,说明现在系统处在同一个逻辑段中(不同的系统环境下,段寄存器的值可能不一样,dosemu 虚拟机中为 07BEH)。操作系统根据内存的情况为各段分配段地址,因此每台机器或每次运行时段地址值可能会不一样。IP 指令指针寄存器的值是 0100H,表示将要执行的指令在代码段的 0100H 单元中。该指令单元的逻辑地址应该由 CS:IP 构成,即 07BE:0100H。

在这里插入图片描述

我们来看在寄存器的下面那一行的表示。该行显示的是代码段的一条指令的反汇编。所谓反汇编,指的是将二进制的机器指令显示成汇编指令。由三部分构成:最左边 07BE:0100 表示该指令所在单元的逻辑地址,中间 F60000 表示该指令的机器码,第 3 列显示为汇编指令 TEST BYTEPTR [BX+SI],00,该指令为 TEST 测试指令。

通过 DEBUG,我们就可知道一条汇编指令翻译成机器代码是什么值了;反之也一样,对一条机器指令也可得知它代表什么汇编指令。

在图的最右边显示的是 CPU 标志寄存器各标志位的状态,可对照表 2-1 观察一下现在系统的状态。

在这里插入图片描述

4.2 d - 查看内存中的内容

前面我们学到,内存每 16 个字节单元为一小段,逻辑段必须从小段的首址开始。用 D 命令可以查看存储单元的地址和内容。

D 命令格式为:

D  段地址:起始偏移地址 [结尾偏移地址] [L范围]

例如:

D DS:0      查看数据段,从 0 号单元开始
D ES:0        查看附加段,从 0 号单元开始
D DS:100    查看数据段,从 100H 号单元开始
D 0200:5 15     查看 0200H 段的 5 号单元到 15H 号单元(在虚拟机上该命令不能执行)
D 0200:5 L 11   用 L 选择范围。查看 0200H 段的 5 号单元到 15H 号单元共 17 个单元

D 命令的执行情况如下图所示。(由于 D 0200:5 15 无法在虚拟机中执行,因此我们给大家提供了一张非环境中的图片,用来展示效果)

在这里插入图片描述
其中左边一列为逻辑地址,中间部分为存储单元的内容。

每行为 16 个字节单元,中间的小横线用于区分前 8 个单元和后 8 个单元。在逻辑地址中只给出每行第一个单元的偏移地址,其余 15 个单元的偏移地址没有标出。可以推断出图中第一行单元的偏移地址从 0000H 到 000FH,第二行单元的偏移地址为 0010H~001FH,以此类推。右边部分显示出内存单元中的 ASCII 码表示的字符,无法显示时用小点代替。

  • 图中第一条 D 命令: d ds:0 显示的是数据段存储单元的内容,可以看到数据段的段地址为 DS,其值 0B05H。

    0 号单元的内容为 CDH,1 号单元为 20H ,…,第 15 号单元的内容为 03H;第二行 0010H 号(16 号)单元的内容为 69H,它是小写字母 i 的 ASCII 码,因此右边区域中显示了 i ,表示该单元的值 69H 可以看成 ASCII 码。

  • 第二条 D 命令: d 0200:0 显示 0200H 段中的内容,也是从 0 号单元开始。

  • 第三条 D 命令: d 0200:5 15从 0200H 段的 5 号单元开始显示直到 15H 号单元。

如果在 D 后面直接写出偏移地址,则显示当前数据段下偏移地址开始的内存单元,如:

D 10        从数据段10H号单元开始显示
D100    从数据段100H号单元开始显示

注意:多次键入 D,可连续显示后面的单元内容。

4.3 E - 修改内存的中内容

用 E 命令可以改写多个存储单元的内容。格式为:E 起始地址 修改值 修改值...

例如:将数据段中的 DS:3~DS:5 三个单元的内容修改为 14、15、16。命令为

E DS:3 14 15 16

如下图所示。(由于 D DS:0 20 无法在虚拟机中执行,因此我们给大家提供了一张非环境中的图片,用来展示效果)

在这里插入图片描述

用 D DS:0 命令显示后,可以看到,这三个单元的值由原来的 9F 00 9A 修改为 14 15 16。

如果 E 后面直接跟偏移地址,则修改当前数据段下偏移地址所指单元值;还可以用 E 命令修改其它段的存储单元内容。

E 10        修改当前数据段10H号单元内容
E ES:100    修改附加段100H号单元内容
D ES:100      查看一下100H单元的内容是否修改了

4.4 u - 将内存中的机器指令翻译成汇编指令

u -反汇编
程序员编写的汇编语言源程序经过汇编(编译)后生成了二进制的机器指令代码,而 U 命令可将二进制的机器指令变为助记符形式的汇编指令,因此称之为“反汇编”。通过 U 命令,我们可以得到机器指令与汇编指令的对照,了解机器指令的存储情况,如图所示。

在这里插入图片描述
左边为代码段中存储单元的逻辑地址,段地址 CS 的值为 0AFEH,偏移地址从 0100H 开始。紧靠偏移地址的一列为机器指令代码,右边部分是机器指令对应的汇编指令。

例如第一行中,机器指令为 7419H,它对应的汇编指令为 JZ 011B,该指令是条件转移指令,表示当结果为 0 时跳转到偏移地址 011BH 单元中的指令继续执行。而 0AFE:011BH 单元的指令为 MOV BX,0034,是一条传送指令。(dosemu 虚拟机中是另一组不同的指令)。

U 后跟偏移地址,则从该地址开始反汇编。如:

U 0       从代码段0号单元开始反汇编
U100     从代码段100H号单元开始反汇编

需要注意的是,图 2-22 中显示的程序代码并不是用户编写的程序,因为在输入 DEBUG 命令时没有写用户程序名.EXE。

  • 这段程序代码是系统代码段中保存的内容,有可能是系统程序,也有可能是无效的代码。

4.5 A命令- 输入汇编指令

在 DEBUG 中,使用 A 命令可以输入汇编指令,系统自动地将键入的汇编指令翻译成机器代码,并相继地存放在从指定地址开始的存储区中。

由于 DEBUG 下的数值默认为十六进制数,因此先要将十进制数转换成十六进制数。

第 1 章提到的计算 Z = 35 + 27 的汇编指令为:

MOV  AX,23H
ADD  AX,1BH
MOV  [0000],AX

例如,第 1 章提到的计算 Z = 35 + 27 的汇编指令为:

MOV  AX,23H
ADD  AX,1BH
MOV  [0000],AX

加法的结果 Z=62=3EH。变量 Z 用存储单元[0000]表示。这三条指令可在 DEBUG 下用 A 命令直接输入。输入 A 命令后,系统自动地给出逻辑地址为 0AEE:0100(CS:偏移地址),在其后输入汇编指令,回车后可输入下一条指令,直接回车则退出输入。

操作过程如下:
在这里插入图片描述
也可以在 A 命令后给出指令的存放地址,如 A CS:0000,表示从代码段的 0 号单元开始存放输入的指令。

4.6 T/P 命令——单步执行

本次执行前,先用 R 命令查看指令指针寄存器 IP 的值是否为 0100,如果不是,用 R IP 命令修改为 0100。表示现在要从 CS:0100 单元开始执行指令。T 命令每执行一次,都要显示当前寄存器的状况,我们可以随时了解指令的执行情况。计算 Z = 35 + 27 的汇编指令的执行过程如下图所示。

输入完指令后,应该执行它。T 命令可以一条一条地执行指令。P 命令的作用与 T 命令相同,当遇到中断指令 INT n 和调用指令CALL时,应该使用 P 命令,以确保程序正常执行。这是因为INT n指令和 CALL 指令都要转移到子程序去执行,T 命令进入子程序后可能无法返回;而 P 命令则直接执行该指令,并将结果带回。遇到循环指令 LOOP 时也应该使用 P 命令,可以使循环快速结束。

在这里插入图片描述
查看执行结果:

  • 第一次执行 T 命令后,AX 寄存器的值改为 0023,
  • 第二次执行后,AX 的值变成 003E 了,说明已经执行完加法 ADD 指令了,
  • 第三次执行 T 后,寄存器的值并未发生变化,说明第三条指令没有对寄存器操作。

第三条指令 MOV [0000],AX 是把结果保存到数据段的存储单元 0 号字单元中,用 D DS:0 命令查看该单元的值已经为 003EH 了(两个字节单元为一个字单元)。

T 命令还可以连续执行多条指令。如上例中连续执行 3 条指令,可用如下 T 命令:

-T 3

T 命令也可以设置开始地址和执行条数。如上例中从 0100H 开始连续执行 3 条指令,可用如下 T 命令:

-T =0100  3

4.7 G 命令——连续执行程序

有关连续执行命令 G 的用法我们放到后面章节中学习

4.8 Q 命令 ——退出 DEBUG

键入 Q,回车后退出 DEBUG,返回到 DOS 下。

猜你喜欢

转载自blog.csdn.net/chumingqian/article/details/124996750
今日推荐