《汇编语言》 学习笔记
《汇编语言》 学习笔记
第一章 基础知识
1.1 机器语言
每一种微处理器,由于硬件设计和内部结构的不同,就需要不同的点评脉冲来控制,使他工作。所以每一种微处理器都有自己的机器指令级,也就是机器语言。
1.2 汇编语言的产生
此后,程序员使用汇编指令编写源程序,这时候就需要使用编译器,将汇编指令转成机器指令的编译程序。
1.3 汇编语言的组成
汇编语言发展至今,有以下三类指令组成
-
汇编指令:机器码的助记符,有对应的机器码
-
伪指令:没有对应的机器码,由编译器执行,计算机并不执行。
-
其他符号:如
+,-,*,、\
等,由编译器识别,没有对应的机器码。汇编语言的核心是汇编指令,它决定了汇编语言的特性。
1.4 存储器
存储器中存储CPU需要的指令与数据,也就是平时所说的内存。
1.5 指令与数据
在内存或磁盘上,指令与数据没有任何区别,都是二进制信息。
CPU在工作时才会赋予不同意义,使其发挥不同的作用。
1.6 存储单元
存储器被划分成若干个存储单元,每个存储单元从0开始顺序编号,例如一个存储器有128个存储单元,编号从0~127,如下图所示
这些编号可以看作存储单元在存储器中的地址
计算机最小的信息单元为bit(音译为比特),也就是一个二进制位
8个bit组成一个Byte,也就是一个字节
微型机存储器:每个存储单元可以存储一个Byte即8个二进制位,一个存储器有128个存储单元,它可以存储128个Byte,即1024个二进制位。微机存储器的容量是以字节为最小单位。
大容量存储器:一般用以下单位计量容量(以下B代表Byte)
- 1KB = 1024B
- 1MB = 1024KB
- 1GB = 1024MB
- 1TB = 1024GB
1.7 CPU对存储器的读写
CPU要从内存中读数据,首先要指定存储单元的地址。
在微机中,不只有存储器这一种期间,所以CPU在读写数据的时候还要指明,它要对那个器件进行操作,进行那种操作,从中读取数据,还是向里面写入数据。
可见,CPU要进行数据读写,必须和外部器件,进行下面3类的信息交互
- 地址信息:存储单元的地址
- 控制信息:器件的选择,读或写的命令
- 数据信息:读或写的数据
电子计算机能处理、传输的信号都是电信号,要是用导线传送。在计算机中专门有连接CPU和其他芯片的导线,通称为总线。
总线根据传送信息的不同,从逻辑上分为3类,地址总线、控制总线和数据总线。
CPU从3号单元读取数据的过程如下:
- CPU通过地址线将地址信息
3
发出 - CPU通过控制线发出内存读命令,选中存储器芯片,并通知它,将要从中读取数据
- 存储器将3号单元中的数据
8
通过数据线送入CPU
要让一个计算机或者危机处理器工作,影响他输入能够驱动他进行工作的电平信息(机器码)
对于8086CPU,下面的代码能实现从3号单元读取数据
机器码:10100001 00000011 00000000
汇编指令:MOV AX,[3]
含义:传送3
号单元的内容入寄存器AX
1.8 地址总线
地址总线上能够传多少个不同信息,CPU就能对多少个存储单元进行寻址。
地址总线的宽度决定了CPU的寻址能力。
在电子计算机中,一根导线可以传送的稳定状态只有两种,高电平或是低电平,用二进制表示就是1或者0,10跟导线可以传送10位二进制数据,10位二进制数据可以表示2的10次方个不同的数据,最小为0最大为1023。
一个CPU有N跟地址线,则可以说这个CPU的地址总线宽度为N,这样的CPU最多可以寻找2的N次方个内存地址(Byte)
下图展示了一个具有10跟地址线的CPU向内存发出地址信息11时10跟地址总线上传送的二进制信息
若访问地址为12时,地址总线上穿得内容就是12的二进制数据即000000 1100
访问地址13时,地址总线数据为000000 1101
访问地址14时,地址总线数据为000000 1110
1.9 数据总线
CPU与内存或其他器件之间的数据传送是通过数据总线进行的。
数据总线的宽度决定了CPU与外界的数据传送速度。
8跟数据总线一次可以传一个8位二进制数据(即一个字节),16根数据总线一次可传送两个字节。
1.10 控制总线
CPU对外部器件的控制是通过控制总线进行的,控制总线是个总称,是一些不同的控制线的集合。有多少跟控制总线,就意味着CPU提供了对外器件的多少种控制
所以,控制总线的宽度决定了CPU对外部器件的控制能力。
前面所讲的内存读或写是由几根控制总线综合发出的,其中一个称为“读信号输出”的控制线负责由CPU向外传送读信号,CPU向该控制线上输出低电压表示将要读取数据;有一个称为“写信号输出”的控制总线负责传送写信号。
1.11 内存地址空间(概述)
系统中的所有存储器中的存储单元都处于一个统一的逻辑存储器中,它的容量受CPU寻址能力的限制,这个逻辑存储器即使我们所说的内存地址空间。
1.12 主板
主板上有核心器件和一些主要器件,这些器件通过总线(地址总线、数据总线、控制总线)相连。这些器件有CPU、存储器、外围芯片组、扩展插槽等。扩展插槽上一般插有RAM内存条和各类接口卡。
1.13 接口卡
CPU对外部设备无法直接控制,如显示器、音响、打印机等。直接控制这些设备进行工作的是插在拓展插槽上的接口卡。拓展插槽通过总线和CPU相连,所以接口也通过总线同CPU相连。
总的来说,CPU通过总线向接口卡发送命令,接口卡根据CPU的命令控制外设进行工作。
1.14 各类存储器芯片
这些存储器芯片从物理连接上看是独立的、不同的器件。从读写属性上看分为两类:
- 随机存储器(RAM):可读可写,关机后存储内容丢失
- 只读存储器(ROM):只能读取不能写入,关机后其中内容不丢失
从功能和连接上看可分为三类:
-
随机存储器:
用于存放供CPU使用的绝大部分程序和数据,主随机存储器一般由两个位置上的RAM组成,装在主板上的RAM和装在拓展插槽上的RAM。
-
装有BIOS(Basic Input/output System,基本输入/输出系统)的ROM
BIOS是由主板和各类接口卡(如显卡、网卡等)厂商提供的软件系统,可以通过它利用该硬件设备进行最基本的输入输出。在主板和某些接口上插有存储相应的BIOS的ROM。
-
接口卡上的RAM
某些接口卡需要对大批量输出、输出输出的数据进行展示存储,在其上装有RAM。最典型的就是显卡上的RAM,一般称为显存。
1.15 内存地址空间
CPU在操控存储器的时候,把存储器都当作内存来对待,把他们总的看作一个由若干存储单元组成的逻辑存储器,这个逻辑存储器就是我们所说的内存地址空间。
CPU向显存地址空间中,然后会被显卡输出到显示器上
CPU向显卡BIOS ROM写入数据,写入的单元内容不会改变
内存地址空间的大小受CPU地址总线宽度的限制
8086CPU地址总线宽度为20,可以传送2^20
个不同的地址信息(大小从0至2^20-1),则8086PC的内存地址空间的大小为1MB。同理80386CPU的总线宽度为32,内存空间的最大为4MB
我们基于计算机硬件系统编程的时候,必须知道这个系统的内存中的内存地址空间分配情况。当我们想在某类存储器中读写数据的时候,必须知道它的第一个单元的地址和最后一个单元的地址,才能保证读写操作是在预期的存储器中进行。
不同的内存地址空间分配情况不同,下图是8086PC机内存储地址空间分配的进本情况
向地址C0000~FFFF
的内存单元写入数据的操作是无效的,因此这等于改写制度存储器中的内容。
第二章 寄存器
在CPU中
-
运算器进行信息处理
-
寄存器进行信息存储
-
控制器控制各种器件进行工作
-
内部总线连接各种器件,在他们之间进行数据的传送
对于一个汇编程序员来说,CPU中的主要部件是寄存器。寄存器是CPU中程序可以用指令读写的部件。程序员通过各种寄存器中的内容来实现对CPU的控制。
不同的CPU寄存器的个数、结构是不同的
2.1 通用寄存器
8086CPU的所有寄存器都是16
位的,可以存放两字节
AX、BX、CX、DX这4个寄存器通常用来存放一般性的数据,被称为通用寄存器。
以AX为例,寄存器的逻辑结构如图所示
一个16位寄存器所能存储的数据的最大值约为两字节
8086CPU上一代CPU中的存储器都是8位的,为了保证兼容性,需要使得AX、BX、CX、DX这四个寄存器都可分为两个独立使用的8位寄存器使用。见下图
一个16位寄存器可以存储一个16位的数据,数据在寄存器中的存放情况如下图所示
2.2 字在寄存器中的存储
8086CPU可以一次处理一下两种尺寸的数据
- 字节:记为BYTE,一个字节由8个bit组成,可以存放在8位寄存器中
- 字:记为word,一个字由两个字节组成,这两个字节分别成为这个字的高位字节和低位字节。
一个字可以存放在一个16位寄存器中,这个字的高位字节和低位字节自然存在这个寄存器的高8位寄存器和低8位寄存器中
2.3 几条汇编指令
汇编指令 | 控制CPU完成的操作 | 高级语言描述 |
---|---|---|
mov ax,18 | 将18送入寄存器AX | AX=18 |
mov ah,78 | 将78送入寄存器AH | AH=78 |
add ax,8 | 将寄存器AX中的值加上8 | AX=AX+8 |
mov ax,bx | 将寄存器BX中的数据送入寄存器AX | AX=BX |
add ax,bx | 将AX和BX的值相加,结果存在AX中 | AX=AX+BX |
汇编指令不区分大小写
程序段中的指令 | 指令执行后AX中的数据 | 指令执行后BX中的数据 |
---|---|---|
MOV AX,4E20H | 4E20H | 0000H |
ADD AX,1406H | 6226H | 0000H |
MOV BX,2000H | 6226H | 2000H |
ADD AX,BX | 8226H | 2000H |
MOV BX,AX | 8226H | 8226H |
ADD AX,BX | 044CH | 8226H |
由于ax
寄存器是16位寄存器只能存放4位十六进制的数据,但是在执行add ax,bx
指令后ax
为1033C
,超出了ax寄存器的上限,所以1044C
中的最高位1
不能存放在ax
寄存器中,最终ax
寄存器中的数据为044CH
再看一段程序的执行情况
程序段中的指令 | AX | BX |
---|---|---|
MOV AX,001AH | 001AH | 0000H |
MOV BX,0026H | 001AH | 0026H |
ADD AL,BL | 0040H | 0026H |
ADD AH,BL | 2640H | 0026H |
ADD BH,AL | 2640H | 4026H |
MOV AH,0 | 0040H | 4026H |
ADD AL,85H | 00C5H | 4026H |
ADD AL,93H | 0058H | 4026H |
程序的最后一条指令mov al,93h
在执行前,al
中的值为C5H
,相加后为158H
,但是由于al
为8位寄存器,只能存放两位十六进制数据,所以最高位1丢失,ax
中的值位0058h
此时,al
是作为一个独立的8位寄存器使用,和ah
没有关系
若执行的是add ax,93h
低8位的进位会存储在ah
中,CPU再执行指令时,只认为有1个16位寄存器ax
进行的是16位计算,执行完这条指令后,ax
中的值变为0158h
使用的寄存器是16位寄存器ax
相当于00C5H
加上0093H
错误指令:
mov ax,bx ;在8位寄存器和16位寄存器之间传送数据
mov bh,ax ;在16位寄存器和8位寄存器之间传送数据
mov al,20000 ;8位寄存器最大可存放值为255的数据
add al,100h ;将一个高于8位的数据加到一个8位寄存器中
检测
只能使用目前学过的汇编指令,最多使用四条指令,编程计算2的4次方
mov ax,2
add ax,ax
add ax,ax
add ax,ax
2.4 物理地址
CPU在在访问内存单元时,要给出内存单元的地址。所有的内存单元构成的存储空间是一个一维的线性空间,每一个内存单元在这个空间中都有唯一的地址,我们将这个唯一的地址称为物理地址。
CPU通过地址总线送入存储器的,必须是一个内存单元的物理地址。在CPU向地址总线上发出物理地址之前,必须要先在内部形成这个物理地址。
2.5 16位结构的CPU
概括的说,16位结构(16位机,字长为16位)描述了一个CPU具有下面几方面的结构特性。
-
运算器一次最多可以处理16位的数据
-
寄存器最大的宽度位16位
-
寄存器和运算器之间的通路为16位
在十六位结构的CPU内部,能过一次性处理、传输、暂时存储的信息最大长度是16位的
2.6 8086CPU给出物理地址的方法
8086CPU采用一种在内部用两个16位地址合成的方法来形成一个20位的物理地址
如图所示,当8086CPU要读写内存时:
-
cpu中的相关部件提供两个16位地址,一个段地址,另一个时偏移地址
-
段地址和偏移地址通过内部总线送入一个称为地址加法器的部件
-
地址加法器将两个16位地址合成一个20位的物理地址
-
地址加法器通过内部总线将20位物理地址送入输入输出控制电路
-
输入输出控制电路将20位物理地址送上地址总线
-
20位物理地址被地址总线送到存储器
其中,地址加法器采用物理地址=段地址*16+偏移地址的方法用段地址合成物理地址
2.7 段地址*16+偏移地址的本质含义
CPU在访问内存时,用一个基础地址(段地址*16)和一个相对于基础地址的偏移地址相加,给出内存单元的物理地址。
8086CPU中,段地址*16可看作基础地址(起始地址)
2.8 段的概念
内存并没有分段,段的含义来自于CPU
以后在编程的时候可以根据需要,将若干连续的内存单元看作一个段,用段地址*16定位段的起始地址(及地址)用偏移地址定位段中的内存单元。
有两点需要注意:段地址*16必然是16的倍数,所以一个段的起始地址也一定是16的倍数;偏移地址为16位,16位的地址寻址能力为64KB,所以一个段的长度最大为64KB。
CPU可以用不同的段地址和偏移地址形成同一个物理地址
如果给定一个段地址,仅通过变化偏移地址来进行寻址,最多可以定位64KB个内存单元,因为偏移地址16位,变化范围为0~FFFFH。
2.9 段寄存器
段地址在8086CPU的段寄存器中存放,8086CPU有四个段寄存器,CS、DS、SS、ES。当8086CPU要访问内存时由这四个段寄存器提供内存单元的段地址
2.9 CS和IP
CS和IP时8086CPU中两个最为关键的寄存器,他们指示了CPU当前要读取地址的地址。
CS为段寄存器,IP为指令寄存器
在8086PC中任意时刻,设CS中的内容为M,IP中的内容为N,8086CPU将从内存M*16+N单元开始,读取一条指令并执行
也可以这样表述,任意时刻,CPU将CS:IP指向的内容当作指令执行
8086CPU的工作过程可以简要描述如下
- 从CS:IP所指向的内存单元读取指令,读取的指令进入指令缓冲区
- IP=IP+所读取指令的长度,从而指向下一条指令
- 执行命令。转到步骤1,重复这个过程
在8086CPU加点启动或复位后(即CPU刚开始工作时),CS和IP被设置为CS=FFFFH,IP=0000H,即在刚启动时候,CPU从内存单元FFFF0H端元读取指令执行,FFFF0H单元中的指令是8086PC机开机后执行的第一条指令
CPU将CS:IP指向的内存单元中的内容看作指令,因为,在任何时候,CPU将CS、IP中的内容当作指令的段地址偏移地址,用他们合成指令的物理地址,到内存中读取指令码。
2.11 修改CS、IP的指令
mov
指令不能设置CS、IP的值,需要使用jmp
指令进行修改
若想修改CS、IP的内容,可以用形如"JMP 段地址:偏移地址"的指令完成,如
jmp 2AE3:3
;执行后:CS=2AE3H IP=0003H,CPU将从2AE33H处读取指令
jmp 3:0B16
;执行后:CS=0003H IP=0B16H,CPU将从00B46H处读取指令
"JMP 段地址:偏移地址"的功能是:用指令中给出的段地址修改CS,偏移地址(IP)
jmp ax
在含以上等同于 mov IP,ax
jmp 3:01B6
含以上等同于mov CS,3 mov ax,01B6
设CPU初始状态CS=2000H,IP=0000H,请写出指令执行序列
- 当CS=2000H,IP=0000H时,CPU从
2000h*16+0h=20000h
处读取指令,读入的指令是:B8 22 66(MOV AX,6622H),读入后IP=IP+3=0003h
- 指令执行后,CS=2000H(未变),IP=0003h,则CPU从内存
2000h*16+0003h=20003
处读取指令,读入的指令是EA 03 00 00 10(JMP 1000:0003),读入后IP=IP+5=0008H
- 指令执行后,CS=1000H,IP=0003H,则CPU从内存
1000h*16+0003h=10003h
处读取指令,读入的指令是B8 00 00(MOV AX,0000)读入后IP=IP+3=0006H
- ......
分析后可知指令序列为
mov ax,6622h
jmp 100:3
mov ax,0000
mov bx,ax
jmp bx
mov ax,0123h
转到第三步执行
2.12 代码段
将一段内存单元定义为一个段,将长度N(N<=64KB)的一簇代码,存在一组地址连续、起始地址是16倍数的内存单元中
例如
mov ax,0000 (B8 00 00)
add ax,0123h (05 23 01)
mov bx,ax (8B D8)
jmp bx (FF E3)
这段长度为10个字节的指令,存放在123B0H123B9H的一组内存单元中,我们可以认为,123B0H123B9H这段内存是用来存放代码的,是一个代码段,段地址为123BH,长度为10个字节。
为了执行上面的代码段,需要使CS=123BH、IP=0000H
实验1 查看CPU和内存,用机器指令和汇编指令编程
DEBUG基础指令
- R 查看、改变CPU寄存器中的内容
- D 查看内存中的内容
- E 改写内存中的内容
- U 将内存中的机器指令翻译成汇编指令
- T 执行一条机器指令
- A 以汇编指令的格式在内存中写入一条机器指令
alt+enter 将dos窗口切换为全屏模式
R 查看、改写寄存器中的值