x86汇编语言学习记录
## x86汇编语言学习记录
0x00 前置知识
有一定编程基础(会点C,java,C++,python等)。理解信息在不同地方,意义可能不同(同一段信息,我们可能将其看成数据,也有可能看成指令)。
0x01 学习教材及其他资源推荐

《汇编语言》王爽著,清华大学出版社出版书籍。该书通俗易懂,理论和实践紧密结合,编者也十分幽默风趣。
现在win10已把debug调试程序移除了,因此我们需要自己安装debug,在此推荐博客园的一篇教程[win10环境下如何运行debug](win10环境下如何运行debug - wuliMax - 博客园 (cnblogs.com))。
0x02 正式学习
1 基础知识
一些符号约定
进制书写:
1. 通用:任意进制表示,**数值(进制)**,如十进制数89(10),二进制数1010(2)。
2. 常用:
1. 二进制:在后面加B表示,其中B是英文二进制Binary的首字母。如二进制数1010B。
2. 十进制:对于十进制数可以不加标注,或加后缀D,其中D是英文十进制Decimal的首字母D。
3. 八进制:数据后面加O表示。如256O。
4. 十六进制:数据后面加H表示,或者加上0x前缀。如1AH,0x1A。
机器语言
机器语言是机器指令的集合。电子计算机的机器指令是一串串的二进制数码,计算机可以通过读入机器指令,将其转化为高低电平,从而实现基本运算,存储等操作。
现在PC机通过CPU(central processing unit,简称CPU)芯片,来实现以上功能。不同CPU,因为设计和结构的不同,所以控制指令就有所不同,即不同CPU都有自己的机器语言。
早期程序员为了解决机器语言的使用困难,从而开发了汇编语言。
汇编语言组成
- 汇编指令(机器码的助记符)【核心】如mov。
- 伪指令(由编译器执行)如结束符end。
- 其他符号(由编译器识别)如+、-、*、/。
存储器
电脑中的存储器大致可划分为两大类:一类是主存,即内存;一类是辅存,即外存。二者的重要区别之一,就在于他们与CPU之间的物理连接方法不同。与CPU地址线直接相连的存储器就是内存,而通过接口与CPU间接相连的存储器就是外存。

PC机中的内存条

PC机中的硬盘(外存)

CPU、内存和硬盘关系
因为CPU直接连接内存,因此如果我们想让CPU工作,就需要将数据和指令存放在内存中。
存储器计量单位
计算机存储信息的最小单位,称之为位(bit,又称比特)。
存储器中所包含存储单元的数量称为存储容量,其计量基本单位是字节(Byte,简称B),8个二进制位称为1个字节,此外还有KB、MB、GB、TB等,它们之间的换算关系是1Byte=8bit,1KB=1024B,1MB=1024KB,1GB=1024MB,1TB=1024GB。
在Intel 8086这一16位CPU中,我们常用字节、字(两个字节)为计量单位。
CPU与内存通信

CPU和内存通信
上图中,MAR和MDR是寄存器。前者是地址寄存器(用来储存地址),后者是数据寄存器(用来储存数据)。CPU将内存中的数据读出后,先要放入到CPU流水线的寄存器中,再对数据进行运算处理。
同时,从上图我们可以得知CPU和内存之间有三条总线(抽象),即数据总线、控制总线、地址总线。
CPU和内存通信可以简单分成三步:
1. CPU通过地址总线将地址信息传出给存储器芯片,明确操作的存储单元。
2. CPU通过控制总线发出控制命令(读 、写等)。
3. 存储器和CPU通过数据总线传输数据。
总线
三种总线都有自己的宽度(物理层面可以简单理解成每一种总线都由很多根电线组成)。一根线,可以传输一个高/低电平,因此可以代表一比特。例如,8086CPU数据总线有16根数据线,则8086CPU的数据总线宽度为16位,一次性可以传输1个字(两个字节)的数据量。
如上所述,数据总线的宽度决定了数据传输速度。而以此类推,地址总线宽度决定了CPU的寻址能力(CPU最大能控制的内存大小),控制总线决定了CPU的控制能力(如读、写等)。
2 寄存器
寄存器简介
寄存器是CPU的主要部件。可以用于暂时存放参与运算的数据和运算结果。同时,我们也可以通过改变寄存器的内容实现对CPU的控制。
8086CPU有14个寄存器,每个寄存器都有自己的名称。这14个寄存器为:AX(accumulator)、BX(base)、CX(count)、DX(data)、SP(Stack Pointer)、BP(Base Pointer)、SI(Source Index)、DI(Destination Index)、IP(Instruction Pointer)、CS(Code Segment)、DS(Data Segment)、SS(Stack Segment)、ES(Extra Segment)、FLAG
通用寄存器
8086CPU的寄存器均为16位。AX、BX、CX、DX这四个寄存器通常用来存储一般性的数据,被称为通用寄存器。(注意是通常,因为它们还有其他功能)
而这些16位通用寄存器又可分为两个独立的8位的寄存器。
-
AX可分为AH和AL;
-
BX可分为BH和BL;
-
CX可分为CH和CL;
-
DX可分为DH和DL;

左边为高位,右边为低位
地址
内存单元构成的存储空间是一维线性的(可以理解成一维数组)。每一个内存空间都有唯一的物理地址。CPU如果想访问一个内存单元,就必须知道这个内存单元的物理地址。
8086CPU是16位结构CPU,一次只能处理16位,也就是2个字节的数据。
结构特性:
1.运算器一次最多可以处理16位数据;
2.寄存器的最大宽度为16位;
3.寄存器和运算器之间的通路为16位。
而8086CPU有20位的地址总线,从前文可知,理论上8086CPU拥有1MB(220Byte)的寻址能力。但是8086CPU为16位结构,如果只用单纯的一个寄存器处理,那么最大只能使用到16位的地址总线。
因此,8086CPU采用了两个16位合成一个20位的方法,实现CPU获取物理地址。

物理地址=段地址*16+偏移地址
段地址和偏移地址均为16位,将段地址左移4位(即乘以16),得到20位地址(此时末尾4位为0),再加上偏移地址,即可获得完整的20位地址。一般表示为段地址:偏移地址,如2000H:1000H。
但是由于两个16位的数据本来可以表示一个32位的数据(一对一),但是此处只用来表示了20位的数据,因此会出现一个物理地址可以用多种段地址和偏移地址表示。
同时我们可以计算出在段地址固定,只改变偏移地址的情况下,最大寻址大小为64KB。
段寄存器
8086CPU有4个段寄存器:CS、DS、SS、ES。
CS和IP
CS(Code Segment)是代码段寄存器,IP(Instruction Pointer)是指令指针寄存器(相当于偏移地址)。在8086机中,任意时刻,CPU将CS:IP指向的内容当作指令来执行。

CPU读取、执行一条指令的动态过程[1]
未完待续
几条基本的汇编语句
-
mov reg(注意段寄存器除外),idata(常量) 汇编指令和寄存器名称大小写不敏感
- 如mov ax,10H合法,即ax=10H
- mov cs,10H非法
-
mov reg(寄存器),reg(寄存器)
- 如 mov ax,bx,即ax=bx
-
add reg(寄存器),reg(寄存器)
- 如add ax,bx,即ax=ax+bx;
-
add reg(寄存器),idata(常量)
-
如add ax,8H,即ax=ax+8H;
未完待续
-
浙公网安备 33010602011771号