跳到主要内容

汇编语言的关键字

关于《汇编语言》中的关键字,专业名词

一、基础知识

1、什么是机器语言呢?
机器语言就是机器指令的集合。机器指令指的是一列二进制数字。计算机可以将机器指令转变成一列高低电平,以使计算机的电子器件受到驱动,进行运算。

2、什么是计算机呢?
可以执行机器指令,进行运算的机器。

3、 mov ax,bx 表示把寄存器 BX 的内容送到 AX 中。

4、什么是寄存器呢?
寄存器就是 CPU 中可以存储数据的器件,一个 CPU 可以有多个寄存器,AX,BX 只是寄存器的代号。

5、什么是编译器呢?
编译器就是能够将汇编指令转换成机器指令的翻译程序。

6、汇编指令就是机器指令的助记符,同机器指令一一对应。

7、指令和数据在存储器(内存)中存放。
CPU 想要工作,就必须向他提供指令和数据。而指令和数据又存放在存储器(内存)中。磁盘不同于内存,磁盘上的数据或程序如果不读到内存中,就无法被
CPU 使用。

8、指令和数据只是应用上的概念,在内存和磁盘中,它们是没有区别的,都是二进制信息。

9、电子计算机的最小信息单位是 bit (一个二进制位)。8 bit 组成一个 byte (字节)。 **微机存储器的容量是以字节(byte)为最小单位来计算的。
**

10、CPU 是如何对存储器进行读取的呢?
首先,我们知道存储器的存储单元是有序号的,并且一个计算机中,可以有多个存储器。
CPU 想要进行数据的读写需要与外部器件进行下面 3 类信息的交互

- 存储单元的地址(地址信息)
- 器件的选择,读或写的命令(命令信息)
- 读或写的数据(数据信息)

11、在计算机中专门有连接 CPU 和其他芯片的导线,通常称为总线。根据传送信息的不同分为 3 类,地址总线、控制总线、数据总线。

12、MOV AX,[3] 传送 3 号单元的内容入 AX

13、CPU 通过地址总线来指定存储器单元的。地址总线上能传送多少个不同的信息,CPU 就可以对多少个存储单元进行寻址。

14、CPU 与内存或其他器件之间的数据传送是通过数据总线来进行的。数据总线的宽度决定了 CPU 和外界的数据传送速度。

15、CPU 对外部器件的控制是通过控制总线来进行的。控制总线是一些不同控制线的集合。控制总线的宽度决定了 CPU 对外部器件的控制能力。

16、每一种 CPU 都有自己的汇编指令集。

17、每一个 CPU 芯片都有许多管脚,这些管脚和总线相连。

18、什么是内存地址空间?
一个 CPU 有 10 根地址总线,那么它可以寻址 1024 个内存单元,这 1024 个可以寻到的内存单元就构成这个 CPU 的内存地址空间。

19、CPU 对外部设备都不能直接控制。直接控制这些设备进行工作的是插在扩展插槽上的接口卡。扩展插槽通过总线与 CPU 相连,所以接口卡通过总线同
CPU 相连。
CPU 通过总线向接口卡发送命令,接口卡根据 CPU 的命令控制外设进行工作。

20、从读写属性上可以将存储器分为两类:随机存储器(RAM)和自读存储器(ROM)。
随机存储器可读可写,但必须带电存储,关机后存储的内容丢失。
只读存储器只能读取不能写入,关机之后其中的内容不丢失。

21、从功能和连接上又分为以下几类

- 随机存储器:用于存放供 CPU 使用的绝大部分程序和数据,主随机存储器一般由两个位置上的 RAM 组成,装在主板上 RAM 和插在扩展插槽上的
RAM。
- 装有 BIOS(Basic Input/Oupur System) 的 ROM:BISO 是由主板和各类接口卡(显卡、网卡等)厂商提供的软件系统,可以通过它利用该硬件设备进行最基本的输入输出。在主板和某些接口卡上插有存储相应
BIOS 的 ROM。
- 接口卡上的 RAM:某些接口卡需要对大批量输入输出数据进行暂时存储,其上装有 RAM。最典型的就是显卡上的 RAM。

22、CPU 会将存储器们总的看作成一个由若干存储单元组成的逻辑存储器。这个逻辑存储器就是我们所说的内存地址空间。每个物理存储器在这个逻辑存储器中占有一个地址段,即一段地址空间。CPU
在这段地址空间中读写数据,实际上就是在相对应的物理存储器中读写数据。

## 二、寄存器

1、CPU 由运算器、控制器、寄存器等器件构成。

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

2、8086 有 14 个寄存器 AX BX CX DX SI DI SP BP IP CS SS DS ES PSW

3、8086CPU 的寄存器都是 16 位的,可以存放两个字节。

4、AX BX CX DX 这 4 个寄存器通常用来存放一般性的数据,被称为通用寄存器。

5、为了向上兼容,AX BX CX DX 都可以分为两个独立使用的 8 位寄存器来使用。
AH(高8位) AL(低8位)
BH BL
CH CL
DH DL

6、几条汇编指令
mov ax,18 ax = 18
mov ah,78 ah = 78
add ax,8 ax = ax + 8
mov ax,bx ax = bx
add ax,bx ax = ax + bx

7、在进行数据传送或运算时,要注意指令的两个操作对象的位数应当是一致的。

8、CPU 访问内存单元时,要给出内存单元的地址。所有的内存单元构成存储空间是一个一维的线性空间,每一个内存单元在这个空间中都有唯一的地址,我们将这个唯一的地址称为物理地址。

9、16 位 CPU 表示

- 运算器一次最多可以处理 16 位数据
- 寄存器的最大宽度为 16 位
- 寄存器和运算器之间的通路为 16 位

10、段地址 × 16 + 偏移地址 = 物理地址 的本质含义
CPU 在访问内存时,用一个基础地址(段地址 × 16)和一个相对于基础地址的偏移地址相加,给出内存单元的物理地址。
基础地址 + 偏移地址 = 物理地址

11、段的概念
内存并没有分段,段的划分来自于 CPU。
段地址 SA 和偏移地址 EA 满足 SA × 16 + EA = 物理地址

12、4 个段寄存器 CS DS SS ES

13、CS 和 IP 是 8086CPU 中两个最关键的寄存器,它们指示了 CPU 当前要读取指令的地址。CS 为代码段寄存器,IP 为指令指针寄存器。

14、在任意时刻,设 CS 中的内容为 M,IP 中的内容为 N,8086CPU 将从内存 M × 16 + N 单元开始,读取一条指令并执行。
8086 机中,任意时刻,CPU 将 CS:IP 指向的内容当作指令执行。

15、8086CPU 的工作过程
(1)从 CS:IP 指向的内存单元读取指令,读取的指令进入指令缓冲器
(2)IP = IP + 所读取指令的长度,从而指向下一条指令
(3)执行指令。转到步骤(1),重复这个过程。

16、CPU 根据什么将内存中的信息看作指令?
CPU 将 CS:IP 指向的内存单元中的内容看做指令,因为,在任何时候,CPU 将 CS、IP 中的内容当作指令的段地址和偏移地址,用它们合成指令的物理地址,到内存中渎职指令码。

17、MOV 指令不用用于设置 CS、IP 的值。JMP 指令可以修改 CS、IP 的指令。
同时修改CS、IP 的内容。jmp 段地址:偏移地址 JMP 2000H:0001H **“等同于”** MOV CS,2000H MOV IP,0001H
仅修改 IP 的内容 jmp 某一合法寄存器 JMP AX **“等同于”** MOV IP,AX

18、CPU 在加电启动或复位后,CS、IP 被设置为 FFFFH、0000H。
46

19、8086CPU 的工作过程

- 从 CS:IP 指向的内存单元读取指令,读取的指令进入指令缓冲器
- IP 指向下一条指令
- 执行指令。(转到步骤一,重复这个过程)

20、Debug 的使用 (安装教程地址:https://blog.csdn.net/qq_45382733/article/details/112597079)
R 查看、改变 CPU 寄存器的内容
r
r ax

D 查看内存中的内容
d 端地址:偏移地址 会显示出 128 个内存单元的内容

E 改写内存中的内容
e 端地址:偏移地址 数据 数据 数据 .....
e 1000:0 0 1 2 3 4 5 6 7 8 9

e 端地址:偏移地址 回车键
debug 程序会显示起始地址和第一单元的原始内容,在 "." 后面输入想要写入 的数据,通过空格键写入内存。通过回车键结束 e 命令。

U 将内存中的机器指令翻译成汇编指令
u 端地址:偏移地址

T 执行一条机器指令
> `t #指向 CS:IP 所指向的指令`

A 以汇编指令的格式在内存中写入一条机器指令

## 三、寄存器(内存访问)

1、在内存中存储时,由于内存单元是字节单元(一个单元存放一个字节),则一个字要用两个地址连续的内存单元来存放,这个字的低位字节存放在低地址单元中,高位字节存放在高地址单元中。

2、**字单元**:存放一个字型数据的内存单元,由两个地址连续的内存单元组成。

3、DS 寄存器,通常用来存放要访问数据的段地址
MOV BX,1000H
MOV DS,BX
MOV AL,[0]
上面的 3 条指令将 10000H(1000:0)中的数据读到 al 中

3、mov 指令

- 将数据直接送入寄存器
- 将一个寄存器中的内容送入另一个寄存器

4、[...] 表示一个内存单元,[] 里面的数据是指偏移地址,段地址会直接去 ds 寄存器中取

5、8086CPU 不支持直接将数据写入段寄存器,想要把数据写入 ds 寄存器,需要先将数据写入一般寄存器(例如 AX)然后 通过 mov ds,ax
命令将数据写入 ds 寄存器

6、mov
mov 寄存器,数据 mov ax,8
mov 寄存器,寄存器 mov ax,bx
mov 寄存器,内存单元 mox ax,[0]
mov 内存单元,寄存器 mov [0],ax
mov 段寄存器,寄存器 mov ds,ax
mov 寄存器,段寄存器 mov ax,ds

7、[address]表示一个偏移地址为 address 的内存单元

8、mov、add、sub 是具有两个操作对象的指令。jmp 是具有一个操作对象的指令。

9、0000:0010 = 0001:0000

10、栈是一种具有特殊的访问方式的存储空间。它的特殊性在于,最后进入这个空间的数据,最先出去。

11、PUSH入栈、POP出栈 8086CPU 的入栈和出栈都是以字为单位进行的。

12、段寄存器 SS 和寄存器 SP,栈顶的段地址存放在 SS 中,偏移地址存放在 SP 中。**在任意时刻,SS:SP 指向栈顶元素**。push 指令和
pop 指令执行时,CPU 从 SS 和 SP中得到栈顶的地址。

13、push ax 的执行过程

- SP=SP-2,SS:SP 指向当前栈顶前面的单元,以当前栈顶前面的单元为新的栈顶
- 将 ax 中的内容送入 SS:SP 指向的内存单元处,SS:SP 此时指向新栈顶。

14、pop ax 的执行过程

- 将 SS:SP 指向的内存单元处的数据送入 ax 中
- SP=SP+2,SS:SP 指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶

15、将 ax 寄存器清零

- mov ax,0 ;占 3 个机器码
- sub ax,ax ;占 2 个机器码

16、push、pop 实质上就是一种内存传送指令,可以在寄存器和内存之间传送数据。

17、ds、cs、ip、ss、sp

- 对于数据段,将它的段地址放在 ds 中,用 mov、ad的、sub 等访问内存单元的指令时,CPU 就将我们定义的数据段中的内容当做数据来访问;
- 对于代码段,将它的段地址放在 CS 中,将段中的第一条指令的偏移地址放在 IP 中,这样 CPU 就将执行我们定义的代码段中的指令;
- 对于栈段,将它的段地址放在 SS 中,将栈顶单元的偏移地址放在 SP 中,这样 CPU 在需要进行栈操作的时候,比如 push、pop
指令等,就将我们定义的栈段当作栈空间来用。

18、**debug 的 T 命令在执行修改寄存器 SS 的指令时,下一条指令也紧接着被执行。**

## 四、第一个程序

1、一个汇编语言从写出到最终执行的过程

- 编写汇编源程序
- 对源程序进行编译连接(先编译,生成目标文件,再连接,生成可执行文件)
- 执行可执行文件中的程序

2、一个简单的汇编代码

assume cs:abc

abc segment

mov ax,2
add ax,ax
add ax,ax

mov ax,4c00h
int 21H ; 这两条命令的作用是使程序返回。

abs ends

end

3、一个程序结束后,将 CPU 的控制权交还给使它得以运行的程序,我们称这个过程为:**程序返回**

4、伪指令:由编译器来执行的指令。

- XXX segment ... XXX ends ; segment 表示开始 ends 表示结束
- end ; end 是一个汇编程序结束的标记。
- assume ;将有特定用途的段和相关的段寄存器关联起来

5、标号
XXX 在 segment 的前面,作为一个段的名称,这个段的名称最终将被编译、连接程序处理为一个段的段地址。

6、汇编程序编译连接过程

- 编译
(1)编写源程序(代码),保存为 xx.asm
(2)运行 masm.exe 程序
(3)输入源程序的文件名
(4)输入编译出的目标文件的名称(.obj)
(5)按回车,忽略编译器将源程序编译为目标文件的过程中产生的中间结果(.lst)
(6)按回车,不生成交叉引用文件(.crf) cross-refrence
(7)此时就生成了中间文件 xxx.obj
- 连接
(1)运行 link.exe 程序
(2)输入目标文件名
(3)输入要生成的可执行文件的名称
(4)按回车,不生成映像文件
(5)输入库文件的名称
(6)此时就生成了可执行文件 xxx.exe

7、连接程序的作用

- 当源程序很大时,可以分开编译,通过连接程序将目标文件连接在一起,生成一个可执行文件
- 程序中调用了某个库文件中的子程序,需要将这个库文件和该程序生成的目标文件连接在一起,生成一个可执行文件
- 将目标文件处理成可执行文件

8、简洁方式

- 编译过程 masm 1; 在源程序文件后加上分号,可以直接忽略中间文件的生成
- 连接过程 link 1; 在目标文件后加上分号,可直接忽略中间文件的生成

9、可执行程序的调试
debug 1.exe **注意:要带上 .exe**

## 五、[BX] 和 loop 指令

1、[bx] 表示一个内存单元,它的偏移地址在 bx 中,段地址在 ds 中

2、() 中的内存单元的地址为物理地址

- 寄存器名
- 段寄存器名
- 内存单元的物理地址

3、inc bx 等同于 add bx,1 将 bx 中的内容加 1

4、**在汇编中,数据不能以字母开头。**
0a000h,0a0001h, .... ,0ffffh

5、int 21 命令要通过 p 命令来执行,而不是 t 命令

6、debug 程序的 g 命令
g 0012 表示使 debug 从当前的 CS:IP 指向的指向执行,一直到 (IP)=0012h 为止
0012 可通过 u 命令查看到loop 命令接着的参数

7、debug 程序的 p 命令
p 命令可以循环一次执行完 (cx)=0

8、段前缀
mov ax,ds:[bx]
mov ax,cs:[bx]
mov ax,ss:[bx]
mov ax,es:[bx]

9、一段安全的空间
0:200h - 0:2ffh 一共 256 个字节

## 六、包含多个段的程序

1、程序获取内存空间的方法有两种

- 加载程序的时候为程序分配(通过在源程序中定义段来进行内存空间的获取)
- 程序在执行的过程中向系统申请

2、dw,define word,定义字型数据。(2 个字节)

3、程序运行的时候,CS 中存放代码段的段地址

4、end 的作用

- 通知编译器程序结束
- 通知编译器程序的入口在什么地方

5、可执行文件中程序执行过程

- 由其他的程序(Debug、command 或其他程序)将可执行文件中的程序加载入内存
- 设置 CS:IP 指向程序的第一条要执行的指令(即程序的入口,根据end关键字可以知道程序的入口是哪里,程序加载之后,会将 CS:IP
指向程序开始的地址),从而使程序得以运行
- 程序运行结束后,返回到加载者

6、在代码段中使用数据
assume cs:code

code segment
...
数据
...
start:
...
代码
...
code ends
end start

7、为什么要把数据、栈和代码放到不同段中?

- 把它们放到一个段中使程序显得混乱
- 如果数据、栈和代码需要的空间超过 64KB,就不能放在一个段中(这个是 8086CPU 的限制,并不是所有的处理器都这样)

## 七、更灵活的定位内存地址的方法

1、and 和 or 指令

- and
mov al,01100011b
and al,00111011b
- or
mov al,01100011b
or al,00111011b

2、关于 ASCII 码
db define bytye

3、以字符形式给出的数据,用单引号(') 括起来。例如 db 'UNIX'

```assembly
assume cs:code,ds:data
data segment
db 'unIX'
db 'foRK'
data ends
code segment
start:
mov al,'a'
mov bl,'b'

mov ax,4c00h
int 21h
code ends
end start

4、大小写转换的问题

字母转大写 and 11011111B 字母转小写 or 0010000B

assume cs:code,ds:data
data segment
db 'BaSiC'
db 'iNfOrMaTiOn'
data ends
code segment
start:
mov ax,data
mov ds,ax
mov bx,0
mov cx,5
s:
mov al,[bx]
and al,11011111b
mov [bx],al
inc bx
loop s

mov bx,5
mov cx,11
s1:
mov al,[bx]
or al,0010000b
mov [bx],al
inc bx
loop s1

mov ax,4c00h
int 21h
code ends
end start

5、[bx+idata] 表示一个偏移地址为(bx) + idata 内存单元 mov ax,[bx+200] 等同于 (ax) = ((ds)*16 + (bx) +200) 偏移地址为 bx 的数值加上 200,段地址在 ds 中 可以写成下面格式

  • mov ax,[bx+200]
  • mov ax,200[bx]
  • mov ax,[bx].200

6、用[bx+idata]的方式进行数组的处理

7、SI 和 DI si 和 di 不能够分成两个 8 位寄存器来使用

assume cs:code,ds:data
data segment
db 'welcome to masm!'
db '................'
data ends
code segment
start:
mov ax,data
mov ds,ax
mov si,0
mov di,16
mov cx,8
s: mov ax,[si]
mov [di],ax
add si,2
add di,2
loop s

mov ax,4c00h
int 21h
code ends
end start

8、[bx+si] 和 [bx+di]
[bx+si] 表示一个内存单元,他的偏移地址为(bx)+(si) 即 bx 中的数值加上 si 中的数值
mov ax,[bx+si] <==> (ax) = ((ds)*16 + (bx) + (si))
<==> mov ax,[bx][si]

9、[bx+si+idata] 和 [bx+di+idata]
mov ax,[bx+si+idata] <==> (ax) = ((ds)*16 + (bx) + (si) + idata)
mov ax,[bx+200+si]
mov ax,[20o+bx+si]
mov ax,200[bx][si]
mov ax,[bx].200[si]
mov ax,[bx][si].200

10、不同的寻址方式的灵活应用

- [idata] 用一个常量来表示地址,可用于直接定位一个内存单元
- [bx] 用一个变量来表示内存地址,可用于间接定位一个内存单元
- [bx+idata] 用一个变量和常量表示地址,可在一个起始地址的基础上用变量间接定位一个内存单元
- [bx+si] 用两个变量表示地址
- [bx+si+idata] 用两个变量和一个常量表示地址

## 八、数据处理的两个基本问题

1、在 8086CPU 中,只有 bx、si、di、bp 四个寄存器可以用在"[...]"中进行内存单元的寻址。这四个寄存器可以任意组合。只要在[...]中使用
bp,而指令中没有显性地给出段地址,段地址就默认在 ss 中。

2、汇编中数据位置的表达

- 立即数 idata,直接包含在机器指令中的数据
- 寄存器,指令要处理的数据在寄存器中
- 段地址 SA 和偏移地址 EA,指令要处理的数据在内存中,在汇编指令中可用[X]的格式给出 EA,SA 在某个段寄存器中

3、寻址方式

- [idata]
- [bx]
- [si]
- [di]
- [bp]
- [bx+idata]
- [si+idata]
- [di+idata]
- [bp+idata]
- [bx+si]
- [bx+di]

4、指令要处理的数据有多长

- 通过寄存器名指明要处理的数据的尺寸
- 在没有寄存器名存在的情况下,用操作符 Xptr 指明内存单元的长度
mov word ptr ds:[0],1
inc word ptr [bx]
inc word ptr ds:[0]
add word ptr [bx],2

mov byte ptr ds:[0],1
inc byte ptr [bx]
inc byte ptr ds:[0]
add byte ptr [bx],2

5、综合应用

mov ax,seg
mov ds,ax
mov bx,60h

mov word ptr [bx+0ch],38
mov word ptr [bx+0eh],70

mov si,0
mov byte ptr [bx+10h+si] ,'V'
inc si
mov byte ptr [bx+10h+si] ,'A'
inc si
mov byte ptr [bx+10h+si] ,'X'

struct company{
char cn[3];
char hn[9];
int pm;
int sr;
char cp[3];
};

struct company dec = {"DEC","Ken Plsen",137,40,"PDP"};
main(){
int i;
dec.pm = 38;
dec.sr = dec.sr + 70;
i = 0;
dec.cp[i] = 'V'
i++;
dec.cp[i] = 'A'
i++;
dec.cp[i] = 'X'
return 0;
}

6、div 是除法指令

- 除数:8 或 16 位
- 被除数:默认在 AX 或 DX 和 AX 中。
除数为 8 位 ,被除数在 AX 中,16位
除数为 16 位,被除数在 DX 和 AX 中,32 位,DX 放高 16 位,AX 放低 16 位
- 结果
除数为 8 位,AL 存商,AH 存余数
除数为 16 为,AX 存商,DX 存余数
div byte ptr ds:[0]
(al)=(ax)/((ds)*16+0) 的商
(ah)=(ax)/((ds)*16+0) 的余数

7、伪指令dd (double word),定制双字型数据

data segment
db 1 ;1 字节
dw 1 ;2 字节
dd 1 ;4 字节
data ends

8、dup 和 db、dw、dd 等数据定义伪指令配合使用的,用来进行数据的重复
db 3 dip (0) <==> db 0,0,0
db 3 dup (0,1,2) <==> db 0,1,2,0,1,2,0,1,2
db 重复的次数 dup (重复的字节型数据)
dw 重复的次数 dup (重复的字型数据)
dd 重复的次数 dup (重复的双字型数据)

## 九、转移指令的原理

1、可以修改 IP 或同时修改 CS 和 IP 的指令统称为转移指令。

2、转移行为

- 只修改 IP,称为段内转移
- 短转移 -128~127
- 近转移 -32768~32767
- 同时修改 CS 和 IP,称为段间转移

3、转移指令分类

- 无条件转移
- 条件转移
- 循环
- 过程
- 中断

4、操作符 offset ,取得标号的偏移地址。

5、jmp 指令,jmp 为无条件指令,可以只修改 IP,也可以同时修改 CS 和 IP。
(1)转移的目的地址
(2)转移的距离(段间转移、段内短转移、段内近转移)**这一点很重要,是转移的距离,并不是转移到标号处**

6、“jmp short 标号” 指令所对应的及其码中,并不包含转移的目的地址,而包含的是转移的位移。
复习下 CPU 执行指令的过程

- 从 CS:IP 指向的内存单元读取指令,读取的指令进入指令缓冲区
- (IP)=(IP) + 所读取指令的长度,从而指向下一条指令
- 执行指令。转到步骤1

7、`jmp short 标号` => `(IP) = (IP) + 8 位位移`
`jmp near ptr 标号` => `(IP) = (IP) + 16 位位移`
`jmp far ptr 标号` => `(CS)=标号所在段的段地址;(IP)=标号在段中的偏移地址`
`jmp 16位reg` => `(IP)=(16位reg)`
`jmp word ptr 内存单元地址(段内转移)` => `转移到偏移地址为内存单元地址处存放的数据上 (IP)=(内存单元地址)`
`jmp dword ptr 内存单元地址(段间转移)` => `(CS)=(内存单元地址+2) 高地址为段地址 ;(IP)=(内存单元地址) 低地址为偏移地址`
位移由编译程序在编译的时候计算出。

8、jxcz 指令为有条件转移指令,所有的有条件指令都是短转移,在对应的机器码中包含转移的位移,而不是目的地址。
if((cx)=0) jmp short 标号

9、loop 指令为循环指令,所有的循环指令都是短转移,在对应的机器码中包含转移的位移,而不是目的地址。
(cx)--;
if((cx)≠0)jmp short 标号