早期的计算机很不灵活,每个设备要执行的步骤都作为机器的一部分内置在控制单元中了。为了提高灵活性,一些早期的电子计算机将CPU设计为可以方便地重新布线。这种灵活性是通过插拔装置体现的,类似于老式电话交换台,跳线的端子插到接线孔中。
意识到程序可以像数据一样编码并存储到主存中,这是一个重大的突破。如果控制单元被设计为从存储器中获取程序,解码指令并执行指令,那么只要更改计算机主存的内容,就可以改变计算机运行的程序,而不需要重写CPU。
将计算机程序存入主存的想法被称为存储程序概念(Stored-Program Concept)。
为了应用存储程序概念,CPU被设计为可以识别编码成位模式的指令。这组指令及相应的编码系统被称为机器语言(Machine Language)。用机器语言表达的指令就叫作机器级指令,或机器指令(Machine Instruction)。
CPU所能完成的操作是由其执行的指令决定的,这些指令称为机器指令。CPU能执行的所有机器指令的集合称为该CPU的指令系统。指令系统设计的好坏、功能的强弱,会对整个计算机产生很大的影响,指令系统是计算机中硬件与软件之间的接口。
1 指令系统指令格式
指令是指挥计算机完成各种操作的基本命令,一般来说,一条指令包括两个基本组成部分:操作码和地址码。
操作码说明指令的功能及操作性质。地址码用来指出指令的操作对象,它指出操作数或操作数的地址及指令执行结果的地址,类似于C语言的表达式及赋值语句。
按照指令中地址码的数量,指令格式分为以下几种:
三地址指令格式:OP A B C
A OP B → C
二地址指令格式:OP A B
A OP B → A
一地址指令格式:OP A
OP A → A
零地址指令格式:OP
2 寻址方式
如何对指令中的地址字段进行解释,以获得操作数的方法或转移地址的方法,操作数的位置可能在指令中、寄存器中、存储器中或I/O端口中,常用的寻址方式有立即数寻址、直接寻址、寄存器寻址、寄存器间接寻址等。
2.1 立即数寻址方式
操作数作为指令的一部分而直接写在指令中,这种操作数称为立即数,这种寻址方式也就称为立即数寻址方式。
立即数可以是8位、16位或32位,该数值紧跟在操作码之后。
在汇编语言中,规定:立即数不能作为指令中的第二操作数。该规定与高级语言中“赋值语句的左边不能是常量”的规定相一致。
立即数寻址方式通常用于对通用寄存器或内存单元赋初值。
如:MOV AX,2346H ;将16位立即数2346H送入寄存器AX。
2.2 寄存器寻址方式
指令所要的操作数已存储在某寄存器中,或把目标操作数存入寄存器。把在指令中指出所使用寄存器(即:寄存器的助忆符)的寻址方式称为寄存器寻址方式。
指令中可以引用的寄存器及其符号名称如下:
8位寄存器有:AH、AL、BH、BL、CH、CL、DH和DL等;
16位寄存器有:AX、BX、CX、DX、SI、DI、SP、BP和段寄存器等;
32位寄存器有:EAX、EBX、ECX、EDX、ESI、EDI、ESP和EBP等。
寄存器寻址方式是一种简单快捷的寻址方式,源和目的操作数都可以是寄存器。
2.3 直接寻址方式
直接寻址方式是指操作数在存储器中,操作数的有效地址(16位偏移量)直接包含在指令中。
2.4 寄存器间接寻址方式
寄存器间接寻址是将指定的寄存器内容为地址,由该地址所指定的单元内容作为操作数。
例如,设将内部RAM的65H单元内容(47H)送A,可执行指令:MOV A,@R0,其中R0内容为65H。
指令的执行过程为:当程序执行到本指令时,就以指令中所指定的工作寄存器R0的内容(65H)为指针,将内部数据存储器65H单元的内容(47H)送累加器A。
2.5 寄存器相对寻址方式
该寻址方式是以指定的寄存器内容,加上指令中给出的位移量(8位或16位),并以一个段寄存器为基准,作为操作数的地址。指定的寄存器一般是一个基址寄存器或变址寄存器。
假设指令:MOV BX, [SI+100H],在执行它时,(DS)=1000H,(SI)=2345H,内存单元12445H的内容为2715H。
根据寄存器相对寻址方式的规则,在执行本例指令时,源操作数的有效地址EA为:
EA=(SI)+100H=2345H+100H=2445H
该操作数的物理地址应由DS和EA的值形成,即:
PA=(DS)*16+EA=1000H*16+2445H=12445H。
所以,该指令的执行效果是:把从物理地址为12445H开始的一个字的值传送给BX。
2.6 基址加变址寻址方式
基址加变址寻址方式是指将寄存器(该寄存器一般指基址寄存器)的内容与指令中给出的地址偏移量相加,从而得到一个操作数的有效地址。
假设指令:MOV BX, [BX+SI],在执行时,(DS)=1000H,(BX)=2100H,(SI)=0011H,内存单元12111H的内容为1234H。
根据基址加变址寻址方式的规则,在执行本例指令时,源操作数的有效地址EA为:
EA=(BX)+(SI)=2100H+0011H=2111H
该操作数的物理地址应由DS和EA的值形成,即:
PA=(DS)*16+EA=1000H*16+2111H=12111H
所以,该指令的执行效果是:把从物理地址为12111H开始的一个字的值传送给BX。
2.7 相对基址加变址寻址方式
在相对基址变址寻址方式中,通常把BX和BP看作是基址寄存器,把SI和DI看作变址寄存器。它是把一个基址寄存器BX或BP的内容,加上变址寄存器SI或DI的内容,再加上指令中给定的8位或16位位移量,并以一个段寄存器作为地址基准,作为操作数的地址。
假设指令:MOV AX, [BX+SI+200H],在执行时,(DS)=1000H,(BX)=2100H,(SI)=0010H,内存单元12310H的内容为1234H。
根据相对基址加变址寻址方式的规则,在执行本例指令时,源操作数的有效地址EA为:
EA=(BX)+(SI)+200H=2100H+0010H+200H=2310H
该操作数的物理地址应由DS和EA的值形成,即:
PA=(DS)*16+EA=1000H*16+2310H=12310H
所以,该指令的执行效果是:把从物理地址为12310H开始的一个字的值传送给AX。
3 指令种类
3.1 数据传送指令
这是一种常用的指令,用以实现寄存器与寄存器,寄存器与存储单元以及存储器单元与存储器单元之间的数据传送,对于存储器来说,数据传送包括对数据的读(相当于取数指令)和写(相当于存数指令)操作。
通用数据传送指令 MOV
条件传送指令 CMOVcc
交换指令 XCHG/XLAT/BSWAP
地址或段描述符选择子传送指令 LEA/LDS/LES/LFS/LGS/LSS等
3.2 算术运算指令
计算机指令系统一般都设有二进制数加、减、比较和求补等最基本的指令,此外还设置了乘、除法运算指令、浮点运算指令以有十进制动算指令等。
加法指令 ADD/ADC
减法指令 SUB/SBB
加一指令 INC
减一指令 DEC
比较操作指令 CMP
乘法指令 MUL/IMUL
除法指令 DIV/IDIV
符号扩展指令 CBW/CWDE/CDQE
十进制调整指令 DAA/DAS/AAA/AAS
3.3 逻辑运算指令
一般计算机都具有与、或、非(求反)、异或(按位加)和测试等逻辑运算指令。
逻辑运算指令 NOT/AND/OR/XOR/TEST等。
3.4 移位操作指令
移位操作指令分为算术移位、逻辑移位和循环移位三种,可以实现对操作数左移或右移一位或若干位。
逻辑左移指令 SHL
逻辑右移指令 SHR
算术左移指令 SAL
算术右移指令 SAR
循环左移指令 ROL
循环右移指令 ROR等。
位测试指令 BT 位测试并置位指令 BTS 位测试并复位指令 BTR 位测试并取反指令 BTC 位向前扫描指令 BSF 位向后扫描指令 BSR等。
3.5 程序控制(转移)类指令
主要有以下类别:
无条件转移指令 JMP; 条件转移指令 Jcc/JCXZ; 循环指令 LOOP/LOOPE/LOOPNE; 过程调用指令 CALL; 子过程返回指令 RET; 中断指令 INTn、INT3、INTO、IRET等。
3.6 输入输出(I/O)指令。
计算机本身是数据处理和管理机构,不能产生原始数据,也不能长期保存数据。所处理的一切原始数据均来自输入设备,所得的处理结果必须通过外总设备输出。
指令的功能是从I/O端口输入(读)数据到微处理器的累加器中,OUT指令的功能是将微处理器的累加器中的数据输出(写)到I/O端口中。
端口输入指令 IN/INS
端口输出指令 OUT/OUTS。
3.7 堆栈操作指令
堆栈是由若干个连续存储单元组成的先进后出(FILO)存储区,第一个送入堆栈中的数据存放在栈底,最后送入堆栈中的数据存放在栈顶。栈底是固定不变的,而栈顶却是随着数据的入栈和出栈在不断变化。
堆栈指针sp总是指向已经存入数据的栈顶(不是空单元),所以PUSH指令是将(SP)减2,后将内容压栈(即先修改SP是指指向空单元,后压入数据),而POP是先从栈顶弹出一个字,后将堆栈指针SP加2。
堆栈操作指令 PUSH/PUSHA/PUSHAD/POP/POPA/POPAD
3.8 字符串处理指令
字符串处理指令就是一种非数值处理指令,一般包括字符串传送,字符串转换(把一种编码的字符串转换成另一种编码的字符串),字符串比较,字符串查找(查找字符串中某一子串),字符串匹配,字符串的抽取(提取某一子串)和替换(把某一字符串用另一字符串替换)等。
串传送指令 MOVS
串比较指令 CMPS
串扫描指令 SCANS
串加载指令 LODS
串保存指令 STOS
这些指令可以有选择地使用REP/REPE/REPZ/REPNE和REPNZ的前缀以连续操作。
3.9 其它指令
如处理机控制类指令、数据转换类指令。
4 C代码与汇编指令
可以在代码中设置断点进行调试然后查看调试窗口(Alt+8),即可看到C语言与汇编代码的对照。
1: #include <iostream>
2: using namespace std;
3: int max(int a,int b)
4: {
00401550 push ebp
00401551 mov ebp,esp
00401553 sub esp,40h
00401556 push ebx
00401557 push esi
00401558 push edi
00401559 lea edi,[ebp-40h]
0040155C mov ecx,10h
00401561 mov eax,0CCCCCCCCh
00401566 rep stos dword ptr [edi]
5: if(a>=b)
00401568 mov eax,dword ptr [ebp+8]
0040156B cmp eax,dword ptr [ebp+0Ch]
0040156E jl max+25h (00401575)
6: return a;
00401570 mov eax,dword ptr [ebp+8]
00401573 jmp max+28h (00401578)
7: else
8: return b;
00401575 mov eax,dword ptr [ebp+0Ch]
9: }
00401578 pop edi
00401579 pop esi
0040157A pop ebx
0040157B mov esp,ebp
0040157D pop ebp
0040157E ret
10: void main()
11: {
00401590 push ebp
00401591 mov ebp,esp
00401593 sub esp,44h
00401596 push ebx
00401597 push esi
00401598 push edi
00401599 lea edi,[ebp-44h]
0040159C mov ecx,11h
004015A1 mov eax,0CCCCCCCCh
004015A6 rep stos dword ptr [edi]
12: int i = 0;
004015A8 mov dword ptr [ebp-4],0
13: i=max(3,4);
004015AF push 4
004015B1 push 3
004015B3 call @ILT+500(max) (004011f9)
004015B8 add esp,8
004015BB mov dword ptr [ebp-4],eax
14: cout<<i;
004015BE mov eax,dword ptr [ebp-4]
004015C1 push eax
004015C2 mov ecx,offset std::cout (0047be90)
004015C7 call @ILT+245(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004010fa)
15:
16: }
004015CC pop edi
004015CD pop esi
004015CE pop ebx
004015CF add esp,44h
004015D2 cmp ebp,esp
004015D4 call __chkesp (00420310)
004015D9 mov esp,ebp
004015DB pop ebp
004015DC ret
-End-