啥都不会 发表于 2022-4-17 23:29

8086汇编-汇编环境搭建

本帖最后由 啥都不会 于 2022-4-18 20:39 编辑

> 本帖最后由 啥都不会 于 2022-4-18 14:50 编辑

> 本帖最后由 啥都不会 于 2022-4-18 14:44 编辑

> 本帖最后由 啥都不会 于 2022-4-18 14:33 编辑

> 本帖最后由 啥都不会 于 2022-4-18 14:27 编辑

> 本帖最后由 啥都不会 于 2022-4-17 23:57 编辑

> 本帖最后由 啥都不会 于 2022-4-17 23:37 编辑

# 运行环境:

WIN10

# 涉及工具:

DosBox

# 编程语言:

汇编语言

# 以下为主题内容:

这篇笔记部分参考了 "王爽《汇编语言》"

# 汇编学习环境搭建

1. ([https://pan.baidu.com/s/1XgMfM9VeUYV7Xb_n3JfbbQ?pwd=9emc](https://pan.baidu.com/s/1XgMfM9VeUYV7Xb_n3JfbbQ?pwd=9emc))
2. 安装配置DOSBox虚拟机
   
   ![](https://user-images.githubusercontent.com/25861639/160359821-6fa2dcaa-bc95-4f83-91d5-18507deef6e2.jpg)
3. 将 masm 目录放到自定义的目录中
   
   ![](https://user-images.githubusercontent.com/25861639/160360093-9df486e7-8581-4a5c-a9a6-0a5bda37502f.jpg)
4. 进入 DOSBox 安装目录,双击 DOSBox 0.74 Options.bat 文件,此时会自动打开配置文件 dosbox-0.74.conf 文件
   
   ![](https://user-images.githubusercontent.com/25861639/160360193-0fbc7c9a-dad3-408d-9d0a-3b20fc67e214.jpg)
5. 在配置文件末尾添加如下命令:

```masm
mount C "masm目录"
c:
```

如下图所示:

![](https://user-images.githubusercontent.com/25861639/160360294-f368f32a-a7c1-44ae-a17d-696dee5d5e49.jpg)

# 汇编语言程序设计编程调试过程

1. 编写 .asm 源程序
2. 使用 masm 汇编源程序
3. 使用 link 连接目标程序
4. 调试 exe 可执行程序

![](https://user-images.githubusercontent.com/25861639/160360365-3d5c77c1-702f-4649-b5e1-1ae5abeb81ad.jpg)

- 编辑器:编写汇编代码的工具,记事本、nodepad++、vscode等等
- 汇编-编译器:将汇编代码按照汇编语法解析成机器指令。汇编成功后生成 obj 文件。
- 链接器:将一个或多个 obj 文件链接在一起,生成二进制可执行文件。
- 调试器:调试生成的二进制文件

范例:

![](https://user-images.githubusercontent.com/25861639/160360556-803eb075-03e6-46f5-ada8-f170b807c27b.jpg)

![](https://user-images.githubusercontent.com/25861639/160360549-33a683c6-8dc3-46bd-ae45-e9849ac4c353.jpg)

![](https://user-images.githubusercontent.com/25861639/160360554-03d262a4-689b-493a-90dd-d8dbce7f7ebd.jpg)

# Debug调试程序

debug 命令

![](https://user-images.githubusercontent.com/25861639/163718043-03ec6166-e17e-476a-99e1-a3472d546b7f.png)

## 调试 hello.exe

1. 调试程序:debug 程序名
   
   ![](https://user-images.githubusercontent.com/25861639/160361083-63a01464-9363-4f30-8caa-2e35400110e0.jpg)
2. 指令 R 显示当前寄存器的值
   
   ![](https://user-images.githubusercontent.com/25861639/163717400-e39e8b1b-15f9-46da-9b1c-ed5dca4fae94.png)

> 在寄存器值的下一行,显示程序将要执行得指令

3. 单步调试
   指令 t,对程序进行单步调试(执行一条汇编指令)
   
   ![](https://user-images.githubusercontent.com/25861639/160361294-f41fcc68-8b82-49cb-b480-4fbe32531acb.jpg)

> 执行完第一条指令后,AX寄存器得值改变了

4. 查看程序汇编指令
   指令 u,查看程序运行时得汇编指令
   
   ![](https://user-images.githubusercontent.com/25861639/160361300-81f89057-977d-40b2-8c14-fa4d45158853.jpg)
5. 修改汇编指令
   指令 a,修改汇编指令(默认是从 cs:0 的位置处修改指令)
   
   ![](https://user-images.githubusercontent.com/25861639/160361307-ad767035-cd35-4063-915b-2b72cff565a6.jpg)
   输入 "a 物理地址",修改指定位置的指令
   
   ![](https://user-images.githubusercontent.com/25861639/160361662-43f5c005-5ee3-476b-b345-b2006518434a.jpg)

> 在逻辑地址处,再次输入 enter 结束a功能

6. 退出调试器
   输入 q 退出 debug 调试器
   
   ![](https://user-images.githubusercontent.com/25861639/160361667-73403a93-040e-49e4-a21d-3e80a0b792c6.jpg)

> 其他指令不常用,后面调试大一点的程序会用到 p 和 g 指令,后面等用到再说,其它指令不常用,就不再演示了。

# 寄存器

CPU 是由运算器、控制器、寄存器等器件构成,这些器件都是靠内部总线相连。之前所说的总线,相对于 CPU 来说是外部总线。内部总线实现 CPU 内部各个器件之间的联系,外部总线实现 CPU 和主板上其他器件(内存条、硬盘、显卡等等)的联系。

CPU 内部器件功能描述:

- 运算器进行的信息处理;
- 寄存器进行的信息存储;
- 控制器控制各器件进行工作;
- 内部总线连接各种器件,在它们之间进行数据传送。

CPU 就是使用运算器处理寄存器中的数据,再将结果传给寄存器。

不同的 CPU 寄存器的个数、结构是不相同的。8086 CPU 有 14 个寄存器,每个寄存器有一个名称。这些寄存器是:AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、flag。

![](https://user-images.githubusercontent.com/25861639/160361931-eeecdfa9-ecc3-41de-8816-5c951a39958b.png)

![](https://user-images.githubusercontent.com/25861639/160362079-2ae6d043-2352-4ad1-becc-c5854c52df5c.jpg)

"数据寄存器" 和 "变址寄存器" 后面的功能描述,指的是在特定环境下通用寄存器的用途。一般情况下你可以用其中任一寄存器传输数据。数据寄存器 BX 也可用作变址寄存器,因为 8086 存储指针的寄存器不够用,所以拓展了 bx 寄存器的功能(现在不理解没关系,后面写代码写多了就懂了)。

指针寄存器:SP(永远指向栈顶指针)和 BP(永远指向栈底指针)是堆栈中使用的寄存器,一般涉及到堆栈时才会使用。

> 变址寄存器和指针寄存器都是用来存储内存地址的。它们之间的唯一区别就是,指针寄存器用在堆栈数据传送和存储中,而变址寄存器用在一般数据传送和存储中。

IP指令指针:表示将要执行哪个地址的指令。每次执行完当前指令,IP 会自动加 1 指向下一条指令,这也就是计算机能实现自动化的原因。

段寄存器:段寄存器用来存储相应段的段值。比如
DS 存储数据段段值,CS 存储代码段段值,SS 存储堆栈段的断值,ES 存储扩展段段值(因为在8086中段寄存器不够用,所以加了 ES
作为备用段寄存器)。段寄存器主要是为了解决 8086 计算机寻址空间不足的问题,这个后续会进行解释。

flags(标志寄存器或程序状态字PSW寄存器)寄存器:包含状态标志位和控制标志位。状态标志位用来表示逻辑运算结果,而控制标志位就是用来控制计算机运行的。

## 数据寄存器

8086 CPU 的所有寄存器都是 16 位的,可以存放两个字节。AX、BX、CX、DX 这 4 个寄存器通常用来存放一般性的数据,被称为数据寄存器。

以 AX 为例,寄存器的逻辑结构图如下:

![](https://i.loli.net/2020/06/23/QxLK5Sfn4EN8iBw.png)

一个 16 位寄存器可以存储一个 16 位的数据,数据在寄存器中的存放情况如下:

![](https://i.loli.net/2020/06/23/kZlJmRBAsLt3VzG.png)

8086 CPU 上一代中的寄存器都是 8 位的,为了保证兼容,让原来基于上一代 CPU 编写的程序可以稍加修改就能在 8086 上。因此 8086 CPU 的 AX、BX、CX、DX 这 4 个寄存器都可以分为两个独立的 8 位寄存器来用:

- AX 可分为两个独立的寄存器 AH 和 AL
- BX 可分为两个独立的寄存器 BH 和 BL
- CX 可分为两个独立的寄存器 CH 和 CL
- DX 可分为两个独立的寄存器 DH 和 DL。

以 AX 为例,8086 CPU 的 16 位寄存器分为两个 8 位寄存器的情况如下:

![](https://i.loli.net/2020/06/23/Rve9dZ3bOaQLrFj.png)

AX 的低 8 位(0位~7位)构成了 AL 寄存器,高 8 位(8位~15位)构成了 AH 寄存器。AH 和 AL 寄存器是可以独立使用的 8 位寄存器。下图展示了 16 位寄存器及 它所分成的两个 8 位寄存器的数据存储情况。

![](https://i.loli.net/2020/06/23/dMuCAzYZLvong68.png)

![](https://user-images.githubusercontent.com/25861639/160362293-e2bc963d-6bda-4723-a3bd-485fa1fcd740.jpg)

**示例:**
通过汇编指令控制 CPU 进行工作,如下入的几条指令

![](https://i.loli.net/2020/06/23/iGuB7aRPoltbcrq.png)

![](https://user-images.githubusercontent.com/25861639/160362312-ee0938c8-5e1c-40bf-96cd-523cd606f0b7.jpg)

下图 CPU 执行表中所列的程序段中的每条指令后,对寄存器中的数据进行的改变。

![](https://i.loli.net/2020/06/23/eRLrETstDPSfQm3.png)

![](https://i.loli.net/2020/06/23/UrBLS2TDXgzuiyJ.png)

![](https://user-images.githubusercontent.com/25861639/160362484-b1f9c921-3923-4dff-ab82-d6955828b7b5.jpg)

![](https://user-images.githubusercontent.com/25861639/160362491-6cc8c776-769f-4c87-b02c-f16fc34b58d7.jpg)

上图中的最后一条指令 add ax,bx的 AX 数据为:8226H+8226H=1044CH,但是 AX 是16 位寄存器只能存储 4 位 16 进制数据,所以最高位 1 不能在 ax 中保存,ax 中的数据为:044CH

一个 16 位寄存器被分为两个 8 位寄存器使用的时候,独立出来的 8 位寄存器与原来的 16 位寄存器无关。如果使用 AH 或 AL 时,当数据超过 8 位时多出来的数据会被丢弃。

下图所列的是一段程序的执行情况:

![](https://i.loli.net/2020/06/23/JrxzeZuonGwXd5c.png)

![](https://user-images.githubusercontent.com/25861639/160362634-edc9a9c0-57b6-4f0d-9f23-464521f01d32.jpg)

![](https://user-images.githubusercontent.com/25861639/160362639-f0bf93ea-c2e5-42f1-a6ee-7480fdaf8e11.jpg)

上图中的最后一条指令 add al,93H ,在执行前,al中的数据为 C5H,相加后所得的值为:C5+93=158H,但是 al 为 8 位寄存器,只能存储两位 16 进制的数据,所以最高位的 1 丢失,ax 中的数据为:0058H

## 变址和基址寄存器

变址和指针寄存器主要用于存放某个存储单元地址的偏移,或某组存储器单元开始地址的偏移,作为存储器(短)指针使用。

作为寄存器,可以保存16位算数逻辑运算中的操作数和运算结果,有时运算结果就是需要的存储单元地址的偏移。**区别:**不可以分解成8位寄存器使用。

主要作用是实现多种存储器操作数的寻址,从而方便的实现对多种类型数据的操作。

SI和DI寄存器称为变址寄存器。在字符串操作中,规定由SI给出源指针,由DI给出目的指针,所以SI也称为源变址寄存器,DI也称为目的变址寄存器。SI和DI也可以作为一般存储器使用。

举例:

```masm
mov si,0
mov ax,

mov di,0
mov ax,

mov si,offset mess
mov di,offset mess
```

BP和SP寄存器称为指针寄存器。BP主要用于给出堆栈中数据区基址的偏移,从而方便地实现直接存取堆栈中地数据,所以BP也称为基指针寄存器。正常情况下,SP也只作为堆栈指针使用,即保存堆栈栈顶地址的偏移。堆栈就是一块内存用来存储数据的,只不过存储数据的方法不一样,具体内容后面会详细解释。

举例:

```masm
mov ax,stack
mov ss,ax
mov sp,16

push bp
mov bp,sp
```

tzxM48 发表于 2022-4-17 23:29

谢谢分享

啥都不会 发表于 2022-4-17 23:30

图片格式问题

gEL1730 发表于 2022-4-17 23:30

谢谢分享

aVksWF94 发表于 2022-4-17 23:38

感谢楼主

pJXAafK 发表于 2022-4-17 23:38

谢谢分享

evz8 发表于 2022-4-17 23:52

感谢楼主

pUcvSEeV58 发表于 2022-4-17 23:57

谢谢分享

zXuEQvVk480 发表于 2022-4-18 00:17

谢谢分享

EQJjHBgCr 发表于 2022-4-18 00:25

感谢楼主
页: [1] 2 3 4 5 6 7 8
查看完整版本: 8086汇编-汇编环境搭建