8086汇编(16位汇编)学习笔记01.汇编基础和debug使用
本帖最后由 大理寺少卿 于 2024-12-15 18:32 编辑### 为什么学习16位汇编?
16位操作指令最多能够操作两个字节,且更能够体现出与硬件的交互。16位下的指令和32位汇编的指令差不多。16位汇编的指令在32位一样使用.要学好汇编必须要了解一点点硬件知识,16汇编是直接操作硬件,32位汇编指令跟硬件隔离了
### 硬件运行机制
#### 1. 为什么计算机的操作数据的单位是二进制?
字节是内存操作的最小单位,但是
**位**才是计算机操作的最小单位
•电子器件二极管
•正向加电则通,反向加电则不同
!(./notesimg/1651839511904-7fede3d3-589c-42e9-88c2-edef42132514.png)
•门电路
!(./notesimg/1651839733379-ff9fd706-6933-4a06-b1b0-99b7a9940fea.png)!(./notesimg/1651839773278-abe95de1-a5f7-4ca0-a079-16baf8a1b56b.png)
!(./notesimg/1651839836688-b9d805af-d263-44a6-85af-89d4b4110b35.png)
####
- 因为二进制是最简单的计算,所以二进制的计算非常快,CPU的处理是通过算术/逻辑 单元 **ALU** 来处理数据的。
例如:
- \+ 可以通过位于运算获取结果。
!(./notesimg/1651840885827-b0435fa1-df1e-4cac-99c0-c58be0cf734f.png)
**用法:**
!(./notesimg/1651840904799-d55f0422-41bd-4580-a9fb-86a93ad6f73b.png)
算术运算的结果是通过位运算得到得
##### 加法
结果 进位
0 + 1 = 1 0
0 + 0 = 0 0
1 + 0 = 1 0
1 + 1 = 0 1
结果 - 异或
进位 - 位与
##### 减法
加补码
##### 乘法
3 * 5 = 3 * (4 + 1) = 3*4 + 3*1 = 3 <<2 + 3
##### 除法
情况比较复杂
机器码 助记符
7f+12 000111111100010010 add7f,12
45&36 10 0100010100110110 and 45,36
#### 2. 算术/逻辑 单元(ALU)
所有的数学运算都可以由位运算组成。那么更高级的数学运算也可以通过简单的位运算计算。所以将常用运算封装成一个器件,称之为单元。
#### 3. 机器码
**类似于1111110000010101010B,可以用来控制硬件的二进制数据,叫做机器码、**
#### 4. 助记符
**二进制值难记,每种功能的二进制控制码取一个容易记住的名字,叫做助记符,也称之为指令。**
**00B - add + 加法**
**01B - sub - 减法**
**10B - and & 与运算**
**11B - xor ^ 异或运算**
#### 5. 汇编
**助记符硬件不能识别,需要将其转换成对应的的机器码,这个过程叫做汇编。(助记符转机器码)**
### 微机系统硬件组成
#### 概述
##### 1. 一个硬件系统都有什么?
● 一个系统不可能由一个硬件单独完成,所以划分处多个硬件模块,然后由一个模块居中调度。称作CPU。
##### 2. CPU如何与其他硬件做交互?
● I/O桥 所有的硬件模块连接到I/O桥,由I/O桥负责辅助cpu与哪一个硬件模块连接。
● 总线
##### 3. cpu如何去选择不同的硬件模块?
● 位多路复用器
!(./notesimg/1651841977362-1fb931aa-e950-4554-b791-6c93118e83db.png)
**CPU**:一个系统不可能由一个硬件单独完成,所以划分多个硬件模块,然后由一个硬件模块居中调度
**cpu的主要工作**:1.算术运算;2.读写,即从一个硬件中读写至另一个硬件中。
!(./notesimg/1651841714304-8742af7f-9b46-4bda-ad61-27c58f2f5633.png)
•总线 cpu有8位数据/地址线,ram是个256byte的存储器。
!(./notesimg/1651842157543-6fe4029c-a4f8-4fca-aa8c-000dfcffad50.png)
控制线用来表明操作类型 00设置地址 01读 10写 11 保留
例如:将 45 写入 地址7f
1. 在控制线上 加00(设置地址),并将7f 设置到数据地址线
2. ram收到指令将地址调到7f
3. 在控制线上 加 10 (写),并将 45 设置到数据地址线
4. ram收到指令将 45 设置到之前写的地址上
读跟写差不多,但是如果要改地址,必须重新开始
#### 8086逻辑图
!(./notesimg/1651842893564-78f27e67-48f1-45bb-b474-def9a5ec4dd9.png)
引脚复用:引脚用来当地址用,又用来当数据用,AD引脚数决定是多少位cpu
A address地址 寻址范围 (0-2^20 1M)
D data 数据 传输数据(16位2个字节1个字)
#### 余量
### 计算机系统组成
!(./notesimg/1651843332242-2482490a-be10-4684-84eb-109ea6e6660a.png)
从编写完以下代码到屏幕显示字符中间发生了什么?
```cpp
#include <stdio.h>
int main()
{
printf(“hello world\n”);
}
```
##### •编译
!(./notesimg/1651843377779-c3602741-fab8-4bdc-9048-7afa421fe832.png)
##### •加载可执行文件
!(./notesimg/1651843400484-37e9438f-7378-42e4-b8d1-4ad059462e45.png)
##### •执行
!(./notesimg/1651843421914-887b66cd-ad87-4bee-b83b-191ab8bc383a.png)
### 8086cpu组织结构
!(./notesimg/1651843486354-3a3ca357-0814-44d2-9127-690d35865d01.png)
#### 8086cpu内部有2个模块组成
##### •EU部件
执行部件(excution unit)
译码
执行指令
##### •BIU部件
总线接口部件(bus interface unit)
取指令
读取数据
写入数据
#### 8086cpu将指令的执行分成多个模块,有什么好处?
目的: 让硬件的利用率最大
•流水线: 可以多个部件同时工作,提高硬件的利用率,从而提高效率。
1.取指令
2.译码
3.取数据
4.执行
5.存储结果
1,2,4是必须的。
!(./notesimg/1651843887360-0e9e2fe8-0bb4-4cb5-a21b-9e6d7e639604.png)
流水线并不是越深越好,否则一旦出现分支转移,其后果将会很恶劣
#### 寄存器
cpu的“局部变量”
!(./notesimg/1651843741908-2b732521-5def-424a-a8c7-90d11eb7c45c.png)
### debug的使用
#### 配置环境
\1. XP系统
2.dosbox(推荐) [https://www.dosbox.com](https://www.dosbox.com/)
3.msdos player
4.dosbox-x (推荐) [https://dosbox-x.com](https://dosbox-x.com/)
##### 使用 vscode
!(./notesimg/1651861169574-5c353722-b489-4a06-a281-f3f59db71b03.png)
!(./notesimg/1651861364349-401d6dc5-4046-40da-bab7-3b2071fa37b3.png)
!(./notesimg/1651861402258-48dd72fb-ff4d-448e-9a1f-005906b5c410.png)
!(./notesimg/1651861590101-5488da0a-dda1-4069-ab2d-4077357d8c0c.png)
!(./notesimg/1651861755071-b87e32db-9899-4319-a6f5-9081d6f41915.png)
注意:选择使用的汇编工具必须是MASM , TASM 是 linux 的 语言,dos环境建议使用 dosbox-x
dosbox-x 也可以直接在官网下载
!(./notesimg/1651862262389-f1d5923b-d339-40e4-b40b-d57ca7ece76f.png)
因为这个是模拟的,所以无法访问本地磁盘,可以映射某个文件夹让他当c盘去用
!(./notesimg/1651862534213-04033df2-45b9-4dbc-b17e-ff80222ed3dc.png)
!(./notesimg/1651862694610-a1e9b056-a77b-4378-91c1-43d3734cb699.png)
##### 使用dosbox-x
没改动配置文件的情况下:
粘贴和复制: shif + f6
挂载:
!(./notesimg/1651954924641-0eec838a-89fa-40af-ad0b-6bab22f69f8f.png)
改动配置文件的情况: dosbox-x.conf
取消粘贴的修饰符:
!(./notesimg/1651955026982-372adb95-46a6-4645-8ed4-e156bc799050.png)
挂载:
```cpp
mount C: G:\asm16
C:
```
#### 使用方法
!(./notesimg/1651863699243-17ac61a9-454d-4e0b-9984-b676c24fd58e.png)
##### 基本DOS命令:
```cpp
#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)
```
##### DosBox常用指令
** = 或者 **
| 指令 | 作用 | 用法 |
| -------------------------- | ---------------------------------- | ---------------------------------------------------------------------------- |
| **?** | **帮助文档** | **-?** |
| **U** | **反汇编(把机器码变成助记符)** | **-u,-u****** |
| **A** | **输入汇编指令** | **a ** |
| **R** | **查看和修改寄存器** | **r ** |
| **D** | **查看内存单元** | **d ** |
| **E** | **修改内存单元** | **e addr** |
| **G** | **直接运行** | **相当于 F5** |
| **T** | **单步步入** | **相当于 F11** |
| **P** | **单步步过** | **相当于 F10** |
| **写入文件(n,cx,w)** | **将内存数据保存到文件** | **-n "文件名"****-rcx 20 (字节数)****-w 开始地址(没有默认为100)** |
| **Q** | **退出** | |
!(./notesimg/1651863936713-a35449fd-1f6e-4681-8d5f-e3ed0db9ea58.png)
!(./notesimg/1651864588002-a4c3d88b-cc37-4f9c-8512-b61f2fe7ec6a.png)
a 后面如果跟地址,代表从该地址开始写汇编代码,不跟则默认从ip地址开始写,写完一行按回车确认,全部写完空行回车
!(./notesimg/1651864778985-0d72cd4c-1095-4760-a590-bab01410f095.png)
R 后面跟寄存器代表可以修改寄存器的值
!(./notesimg/1651864924090-0173dae2-13e5-4218-a7a1-ec49b1e26f9e.png)
!(./notesimg/1651865025904-db429166-b6cb-49dc-9f0c-c486cf3aa7a5.png)
e后面跟地址代表修改该处内存的值,按空格 表示 继续修改后面的,按回车表示修改结束
e addr
!(./notesimg/1651865318640-59aef5dc-8d45-4006-8ddc-8ebeafe9741a.png)
e addr "字符串"
!(./notesimg/1651865476791-23fcb364-1c37-4498-b482-060f5ca590f9.png)
!(./notesimg/1651865755190-3a846534-dafe-43ad-823b-f4faa14059bc.png)
!(./notesimg/1651865867474-6cf13c36-9ec7-40cf-8f7e-44a119727d68.png)
!(./notesimg/1651867005362-17ab315e-8253-43b8-bfa3-d04a3f980e56.png)
注意: 保存数据是从 地址 100 开始的,跟ip地址的值无关,如果要向指定开始位置,w 后面加 开始地址
!(./notesimg/1651867252388-72a78d85-c497-4f98-9860-b6c0f27aaf72.png)
### 标志寄存器
常用的是 ZF和DF
!(./notesimg/1631847954912-d71fb7dd-520a-4904-a09a-f58a4892f05e.png)
#### 条件标志:
- **CF 进位标志:**用于反映运算是否产生进位或借位。如果运算结果的最高位产生一个进位或借位,则CF置1,否则置0。运算结果的最高位包括字操作的第15位和字节操作的第7位。移位指令也会将操作数的最高位或最低位移入CF。
- **PF 奇偶标志:**用于反映运算结果低8位中“1”的个数。“1”的个数为偶数,则PF置1,否则置0。
- **AF** **辅助进位标志****:**算数操作结果的第三位(从0开始计数)如果产生了进位或者借位则将其置为1,否则置为0,常在BCD(binary-codedecimal)算术运算中被使用。
- **ZF 零标志:**用于判断结果是否为0。运算结果0,ZF置1,否则置0。
- **SF 符号标志:**用于反映运算结果的符号,运算结果为负,SF置1,否则置0。因为有符号数采用补码的形式表示,所以SF与运算结果的最高位相同。
- **OF 溢出标志:**反映有符号数加减运算是否溢出。如果运算结果超过了8位或者16位有符号数的表示范围,则OF置1,否则置0。
#### 控制标志:
- **TF 跟踪标志:**当TF被设置为1时,CPU进入单步模式,所谓单步模式就是CPU在每执行一步指令后都产生一个单步中断。主要用于程序的调试。8086/8088中没有专门用来置位和清零TF的命令,需要用其他办法。
- **IF 中断标志:**决定CPU是否响应外部可屏蔽中断请求。IF为1时,CPU允许响应外部的可屏蔽中断请求。
- **DF 方向标志:**决定串操作指令执行时有关指针寄存器调整方向。当DF为1时,串操作指令按递减方式改变有关存储器指针值,每次操作后使SI、DI递减。
#### CF 进位标志
```cpp
当运算结果的最高有效位有进位(加法)或借位(减法)时设置。
进位标志置1,即CF = 1;否则CF = 0
用途:用于表示两个无符号数高低。
举例:
3AH + 7CH=B6H, 没有进位:CF = 0 NC
AAH + 7CH=(1)26H,有进位:CF = 1 CY
```
!(./notesimg/1651869047425-c9d0cd06-774e-4b9a-9a84-5805534141e6.png)
!(./notesimg/1651869660147-54de3559-386a-4063-951c-982b99a6273b.png)
#### 零标志ZF
```cpp
若运算结果为0则ZF=1,否则ZF=0。
用途:用于表示两个无符号数高低。
举例:
3AH + 7CH=B6H,结果不是零: ZF = 0 ZR
84H + 7CH=(1)00H, 结果是零:ZF = 1 NZ
```
!(./notesimg/1651869814916-85d894ee-4ee3-4fcc-b2f7-a8cb7b398b4d.png)
!(./notesimg/1651869977252-2baf7ec1-3ff7-405b-99c7-ae1c76b1ab74.png)
#### 溢出标志OF
溢出只发生在正数+正数 负数+负数 负数- 正数 正数-负数的情况
```cpp
使用该标志位判断运算结果是否溢出。(当将操作数作为有符号数时)
加法:若同符号数相加,结果的符号与之相反则OF=1,否则OF置0。
减法:被减数与减数异号,而结果的符号与减数相同则OF=1,否则置0。
发生了溢出,说明了运算结果不可信。
3AH + 7CH=B6H, 产生溢出:OF = 1 OV
AAH + 7CH=(1)26H, 没有溢出:OF = 0 NV
```
!(./notesimg/1651870719132-3e06fb2b-54d2-437e-9127-4ee1da1f7b90.png)
!(./notesimg/1651870912936-909b3f39-58bd-4716-bb9e-c22fd79e2b20.png)
##### 进位和溢出
```cpp
进位CF 针对的是无符号数运算,溢出OF 针对的是有符号数运算。
当看成无符号数,则关注CF标志,看成有符号数,则关注OF标志。
cpu运算时,不管数据是有符号还是无符号,它运算完,会当作有符号数设置 CF 位,也会当作无符号数设置 of 位,即2个操作位都会设置, 至于最后看哪个位要根据我们的业务逻辑自己去选择
```
#### 符号标志SF
```cpp
运算结果最高位为1,SF为1,否则为0。
有符号数据用最高有效位表示数据的符号,最高有效位是符号标志的状态。
举例:
3AH + 7CH=B6H, 最高位D7=1: SF = 1 NG
84H + 7CH=(1)00H, 最高位D7=0: SF = 0 PL
```
!(./notesimg/1651871956916-8537c927-35e0-43e2-b11b-ab0641fe32b3.png)
!(./notesimg/1651872109828-b1141dc2-d5c3-4759-96fd-35e83b509f39.png)
#### 奇偶标志位PF
```cpp
当运算结果(指低8位)中1的个数为偶数时,PF置1,否则置0。
作用:该标志位主要用于检测数据在传输过程中的错误。
举例:
3AH + 7CH=B6H=10110110B
结果中有5个1,是奇数:PF = 0 PO
3AH + 7AH=B6H=10110100B
结果中有4个1,是偶数:PF = 1 PE
```
!(./notesimg/1651872308411-1896fdc5-712f-4b30-bb87-9400932e3420.png)
!(./notesimg/1651872511799-b0d2a4d0-7857-43f6-b328-f9d3461ab5d3.png)
#### 辅助进位标志位AF
```cpp
表示一个字节的低4位是否有进位和借位。运算时D3位(低半字节)有进位或借位时,AF = 1;否则AF = 0。
处理器内部使用,用于十进制算术运算调整指令中,用户一般不必关心
3AH + 7CH=B6H,D3有进位:AF = 1 AC
31H + 71H=A2H,D3无进位:AF = 0 NA
```
!(./notesimg/1651872847728-41c34943-79dd-48b7-a422-91cb5c5daf48.png)
!(./notesimg/1651872950494-8106206e-2861-4d5b-ac55-45640c130d7f.png)
#### 标志位状态总结
| **.标志位** | **标志名称** | **FLASE** | **TURE** |
| ------------- | ------------------ | ----------- | ---------- |
| **OF** | **溢出标志** | **NV** | **OV** |
| **DF** | **方向标志** | **UP** | **DN** |
| **IF** | **中断标志** | **DI** | **EI** |
| **SF** | **符号标志** | **PL** | **NG** |
| **ZF** | **零标志** | **NZ** | **ZR** |
| **AF** | **辅助进位标志** | **NA** | **AC** |
| **PF** | **奇偶标志** | **PO** | **PE** |
| **CF** | **进位标志** | **NC** | **CY** |
!(./notesimg/1652098077921-a1092bea-3907-4064-9ea3-8cdacbc233fd.png)
在 debug中顺序
!(./notesimg/1651874265884-b45d2630-ea0c-41ea-bdb6-35544f596a4a.png)
OF[溢出 ] DF[方向] IF[中断] SF[符号] ZF[零] AF[辅助进位] PF[奇偶] CF[进位]
页:
[1]