汇编语言
作者:互联网
汇编语言
基础知识
机器语言与汇编语言
-
机器语言:一列二进制数,计算机将其变为一列高低电平,驱动计算机的电子器件。
-
汇编语言:机器语言难以辨别和记忆,便产生了便于记忆的机器指令的书写格式
\(e.g.:\)
graph LR 汇编指令--编译器-->机器码操作:把寄存器BX中的内容送到AX中
机器指令:
1000100111011000
汇编指令:
mov ax, bx
汇编语言的组成
-
汇编指令:机器码的助记符,有对应得到机器码
-
伪指令:没有对应的机器码,由编译器执行,计算机不执行
-
其它符号:没有对应的机器码,有编译器识别,\(e.g.+、-、*、/\)
计算机原理补充
-
指令和数据:都是二进制信息,在内存或磁盘上几乎没有区别,\(e.g.\)对于
1000100111011000
,既可以把它看作89D8H
,也可以看作mov ax, bx
指令来执行 -
CPU对存储器的读写:CPU要从内存中读数据,先要指定存储单元的地址,对哪个器件操作,执行什么操作...
-
信息交互:存储单元的地址(地址信息)、器件的选择,读或写的命令(控制信息)、读或写的数据(数据信息)
-
总线:连接CPU和其它芯片的导线,根据传送信息的不同,分为地址总线、控制总线、数据总线
-
地址总线:CPU与通过地址总线指定存储器单元。例如一个具有10根地址总线的CPU可以传递10位二进制数据,表示\(2^{10}\)种不同的数据。
-
数据总线:内存与其他器件之间通过数据总线进行数据传送,数据总线的宽度决定数据传送速度。
-
控制总线:控制总线的宽度决定CPU对外部器件的控制能力。
-
-
CPU从内存中读取数据的过程如上图
-
CPU通过地址总线将地址信息
3
发出; -
CPU通过控制总线发出内存读命令,选中存储器芯片,通知它将要从中读取数据;
-
存储器将
3
号单元中的数据8
通过数据总线送入CPU中;
写入数据过程类似。
寄存器
CPU主要由运算器、控制器、寄存器构成,在CPU中:
-
运算器进行信息处理
-
寄存器进行信息存储
-
控制器控制各种期间工作
-
内部总线连接各器件并进行数据传送
-
\(8086CPU\)中有14个寄存器,分别为:
AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、PSW
几条简单的汇编指令(不区分大小写):
mov ax, 18——将18送入AX
mov ah, 78——将78送入AH
add ax, 8——将寄存器AX中的数值加8
mov ax, bx——将寄存器BX中的数据送入AX中
add ax, bx——将AX与BX中的数据相加并将结果存储在AX中
通用寄存器
在\(8086CPU\)中寄存器为16位,存放两个字节。寄存器AX、BX、CX、DX
通常用来存放一半性的数据,称为通用寄存器。而且它们都可以氛围两个独立使用的8位寄存器使用。
-
AX分为AH和AL
-
BX分为BH和BL
-
……
如上图,数据20000
的二进制为100111000100000
,存储在AX
中,将16位的AX分为两个8位寄存器,即AX的低八位(07)构成AL,表示78;高八位(815)构成AH,表示32
字在寄存器中的存储:一个字有两个字节组成,它的高位字节和低位字节分别存储在寄存器的高八位和低八位寄存器中。
段寄存器
物理地址
所有的内存单元构成的存储空间是一个一维空间,每个内存单元在这个空间中有唯一的地址,这个地址称为物理地址。
8086CPU有20位地址总线,可以传送20位地址,达到1MB寻址能力。但是8086CPU是16位结构,在内部一次性处理、传输、暂时存储的地址为16位。如果只是将地址从内部简单发出,那么它只能送出16位的地址,表现出的寻址能力只有64KB。
如图,8086CPU在内部用两个16位地址合成一个20位的物理地址。
-
CPU中的相关部件提供一个16位的地址,一个称为段地址,另一个称为偏移地址;
-
段地址和偏移地址通过内部总线送入一个称为地址加法器的部件;
-
地址加法器将2个16位的地址合成为一个20位的地址;
物理地址=段地址*16+偏移地址
-
地址加法器再通过内部总线将20位的物理地址送入输入输出控制电路;
-
输入输出控制电路将20位的物理地址送上地址总线;
-
20位的物理地址被地址总线传送到存储器;
$e.g.段地址:0X1230,偏移地址:0X00C8,物理地址= 0X1230*16+0X00C8 = 123C8 $
解读物理地址的生成过程
物理地址=段地址*16(基础地址)+偏移地址
段的划分:段的划分来自于CPU而不是内存,假设我们认为\(10000H\)到\(100FFH\)为一个段,段的起始地址为\(10000H\),大小为\(100H\);我们也可以把\(10000H~1007FH\)、\(10080H~100FFH\)认为是两个段,起始地址分别为\(10000H\)和\(10080H\),大小都为\(80H\)。
段的长度:基础地址=段地址*16,则段的起始地址为16的倍数;偏移地址为16位,则一个段的最大长度为\(64KB\)
寄存器CS、IP
CS和IP指示了CPU当前要读取指令的地址,其中CS为代码段寄存器,IP为指令指针寄存器。
在8086PC机中,CPU将从M*16+N开始读取一条指令并执行,如下动图
(8086CPU当前状态:CS2000H,IP0000H;内存20000H~20009H中存放可执行机器码)
-
初始状态:CS:2000H,IP:0000H;
-
CS、IP中的内容送入加法器得到物理地址;
-
地址加法器将物理地址送入输入输出控制电路;
-
输入输出控制电路将20000H送上地址总线;
-
从内存单元20000H中得到机器指令
B8 23 01
,通过数据总线送入CPU; -
输入输出控制电路将机器指令送入指令缓冲器;
-
执行指令
mov ax, 0123H
,IP的值增加
执行下一段重复上述过程。
修改CS、IP中的指令
程序员你呢沟通过修改寄存器中的内容实现对CPU的控制,而CPU从何处执行指令是由CS、IP中的内容决定的,因此,改变CS、IP的内容可以控制CPU执行目标指令。
;同时修改CS、IP的内容
jmp 段地址;偏移地址
;仅修改IP的内容
jmp 合法寄存器
\(e.g.\)
jmp 2AE3: 3
,执行后CS=2AE3H,IP=0003H
;
jmp ax
,执行前ax=1000H,CS=2000H,IP=0003H
;执行后ax=1000H,CS=2000H,IP=1000H
注:mov IP, ax不合法
段寄存器DS和[address]
在\(8086CPU\)中,DS寄存器通常用来存放要访问的段地址
\(e.g.\)将10000H(1000:0)
中的数据读取到al
中
mov bx, 1000H
mov ds, bx
mov al. [0] ; […]表示一个内存单元
注:
DS
是段寄存器,mov ds, 1000H
非法。例如,要将AL
中的数据/指令送入DS
中,指令为:mov ax, 1000H mov ds, ax mov [0], al
mov、add、sub指令
mov 寄存器, 数据 mov ax, 8
mov 寄存器,寄存器 mov ax, bx
mov 寄存器, 内存单元 mov ax, [0]
mov 内存单元, 寄存器 mov [0], ax
mov 段寄存器, 寄存器 mov ds, ax
寄存器SS、SP
CPU的栈机制
在基于\(8086CPU\)编程时,可以将一段内存当作栈使用。最基本的两个指令PUSH
实现入栈,POP
实现出栈。如下图将10000H~1000FH
这段内存用作栈使用
push ax / push […] ; 将寄存器AX/[内存单元]中的数据送入栈中
pop ax / pop […] ; 将栈顶数据去除送入AX/[内存单元]中
SS、SP
在\(8086CPU\)中,段寄存器SS
存放栈顶地址,SP
存放偏移地址。任意时刻,SS:SP
指向栈顶元素
下图描述了\(8086CPU\)对push
指令的执行过程,pop过程相反
注:入栈时,栈顶从高地址向低地址方向增长
当栈为空时,按照
SS:SP
指向栈顶的原则,SS:SP
指向栈最底部单元下面的单元若栈顶超界,可能会覆盖原本存放的数据,会引发一系列的错误
第一个程序
程序从写出到执行
graph LR test.asm--编译masm-->test.obj--连接link-->test.exe--加载command-->内存中的程序-
编写汇编源程序;
-
对源程序编译连接;
-
使用编译程序对源程序进行编译,生成目标文件;
-
用连接程序对目标文件进行连接,生成可执行文件;
-
可执行程序
程序(机器码)和数据(源程序定义的数据)
相关的描述信息(大小。占的内存空间)
- 执行可执行文件中的程序;
操作系统按照可执行文件的描述信息,将可执行文件的机器码和数据载入内存,进行相关的初始化(设置CS:IP指向),然后由CPU执行程序。
源程序
assume cs:codesg
codesg segment ; 定义一个段,段的名称为"codesg",段从此开始
; 标号:codesg指代一个地址,最终被编译、连接程序处理为一个段的段地址
mov ax, 0123H
mov bx, 0456H
add ax, bx
add ax, ax
mov ax, 4c00H
int 21H
codesg ends ; 名称为"condesg"的段结束
end
下面对程序进行说明
伪指令:
没有对应的机器指令,不被CPU执行,由编译器执行
segment
和end
是一对伪指令,用来定义一个段,XXX
是段的名称;每个程序至少有一个段;end
是汇编语言的结束标记,编译器在编译汇编程序过程中,遇到end则结束对源程序的编译;assume
将具有特殊用途的段与相关的段寄存器相关联汇编指令程序;
汇编指令
源程序中的汇编指令组成了最终由计算机执行的程序,这里的程序是源程序中最终由计算机执行、处理的指令或数据,程序最先以汇编指令的形式存在源程序中,经编译、连接后转为机器码,存储在可执行文件中。
[BX]和loop指令
[bx]和内存单元
要完整地描述一个内存单元,需要内存单元的地址和内存单元的长度
-
用[0]表示内存单元,
0
表示单元的偏移地址 -
用[bx]表示内存单元,偏移地址在
bx
中
段前缀
在指令mov ax, [bx]
中,偏移地址又bx
给出,段地址在ds
中;我们也可以显式地给出段地址所在的寄存器,例如mov ax, es:[bx]
"ds:"、"cs:"、"ss:"、"es:"被称为段前缀
loop
定义“( )”表示寄存器、段寄存器或内存单元中的内容,(al)、(bl)等为字节型,(ds)、(ax)为字型例如
(ax)=0010H
表示ax中的内容为0010H
(21000H) = 0010H
表示2000:1000处的内容为0010H
(ax) = ((ds)*16+2)
表示mov ax, [2]
(ax) = (ax)+2
表示add ax, 2
(sp) = (sp)-2
表示push ax
(ax) = ((ss)*16+(sp)) \\ (sp) = (sp)+2
表示pop ax
loop指令:用于实现循环功能,cx
中存放循环次数
loop 标号
CPU执行loop
指令时,进行两步操作
-
(cx) = (cx)-1
-
判断(cx)是否为0
-
\((cx) = 0\)向下执行程序
-
\((cx) \not= 0\)转至标号处执行程序
-
《汇编语言》(第三版)王爽 著
链接:https://pan.baidu.com/s/1adqH6znzDA1pAqkK7xDt3w?pwd=1226
提取码:1226
标签:汇编语言,mov,地址,内存,寄存器,ax,CPU 来源: https://www.cnblogs.com/Euler-0525/p/16313494.html