【知识总结】 第四章-指令系统

2025-05-22 19:51:46 | 世界杯的规则

基本概念

程序:由一系列有序的指令构成

指令:指示计算机硬件完成指定的基本操作的命令

指令系统

又叫指令集,是一台计算机所有指令的集合

位于软件硬件交界面上

计算机的主要属性,指出计算机有哪些基本的硬件功能

指令系统应具备的特征

完备性:功能齐全

高效性:编写的程序占据空间小,执行速度快

规整性

对称性:所有寄存器和存储单元可同等对待;所有指令可使用各种寻址方式

匀齐性:可以支持各自数据类型

一致性:指令格式和数据格式一致

兼容性:系列机各种机型有相同的基本机构和共同的基本指令集

指令格式

基本格式

操作码+地址码

操作码指出操作的类型

地址码给出被操作的信息的地址

指令长度指的是一条指令的二进制代码长度

取决于操作码长度、地址码长度、地址码个数

可能大于、等于或小于机器字长,如双字长指令、字长指令、半字长指令

指令系统的所有指令长度相等,称为定长指令字结构,执行快,结构简单

指令系统的指令长度随指令而异,称为变长指令字结构,一般是字节的整数倍(考虑主存按字节编址)

根据操作数地址码的个数,指令分为

零地址指令

不需要操作数的指令。如空指令、停机指令、关中断指令

涉及堆栈的运算指令。

一地址指令:

单操作数指令。如自增、自减、求反、求补,形式为

隐含的双操作数指令。一般另一个操作数由ACC(累加器)提供,运算结果也存到ACC中,形式为

二地址指令:比如常用的逻辑运算,算术运算,形式为

三地址指令:比如常用的逻辑运算,算术运算,形式为

四地址指令:形式为,是下一条指令的地址

定长操作码指令格式

在指令高位分配固定长度的若干位表示操作码

位操作码字段可以表示个指令

定长操作码简化计算机硬件设计,提高指令译码识别速度,当计算机字节为32位和更长时,这是常规用法

拓展操作码指令格式

当指令字长有限时,为了丰富指令种类,可以采用可变长度操作码

拓展操作码是最常用的可变长操作码,操作码长度根据地址码的减少而增加

一般全1留作拓展操作码使用

比如0000 - 1110是4位操作码;11110000 -

11111110是8位操作码;111111110000 - 111111111110是12位操作码

除了拓展操作码,还有其他的拓展方法,比如哈夫曼编码的思想,给高频指令短的操作码

拓展编码必须是前缀码,即不存在短码是长码的前缀,且各指令操作码不重复

指令的操作类型

数据传送

寄存器之间的传送 MOV

从内存读数据到CPU寄存器 LOAD

从CPU寄存器写数据到内存 STORE

算术和逻辑运算

算术运算:ADD(加)、SUB(减)、CMP(比较)、MUL(乘)、DIV(除)、INC(自增1)、DEC(自减1)

逻辑运算:AND(与)、OR(或)、NOT(非)、XOR(异或)

移位操作

算术移位

逻辑移位

循环移位

转移操作

无条件转移 JMP:任意条件都会转移

条件转移 BRANCH:满足条件才会转移

调用

CALL:调用指令需要保存下一条指令的地址,方便调用结束后返回。

返回 RET:完成调用后根据之前保存的地址返回

陷阱 TRAP

输入输出操作:用于CPU和外部设备交换数据、传送控制命令和状态信息

寻址方式

有效地址的概念

指令中的地址码字段并不代表操作数真实地址,而是形式地址

形式地址需要结合寻址方式,算出操作数在存储器中的真实地址,即有效地址EA

若考虑虚拟存储机制,有效地址本质上是段内偏移量,即线性地址等于段基地址加有效地址。

本章内容除非特殊说明,默认先不考虑虚拟存储,即段基地址从0开始,且不采用分页机制,此时有效地址就是真实的物理地址

指令寻址和数据寻址

指令寻址

含义:寻找下一条需要执行的指令地址

分为

顺序寻址:程序计数器PC加1

跳跃寻址:通过本条转移指令算出下一条指令地址,可能跳跃到绝对地址(根据标记符),也可能跳跃到相对地址(距当前的指令偏移量),算出后修改程序计数器PC

数据寻址

含义:根据指令中操作数的形式地址得到其有效地址

数据寻址方式很多,通常在指令中设置一个字段(即寻址特征),用以指明寻址方式的类型

指令的格式为:操作码、寻址特征、形式地址A

常见寻址方式

隐含寻址

不显式给出所有操作数地址,指令中隐含操作数的地址

比如累加器ACC作为第二个操作数的地址,结果也存放到ACC中

优点是缩短指令长度;缺点是需要增加存储隐含地址的硬件

访存0次

立即(数)寻址

地址字段指出的是操作数本身,称为立即数

数据用补码形式存放

优点是不需要访问内存;缺点是立即数的位数收到指令长度限制

访存0次

直接寻址

地址字段就是操作数的真实地址

优点是寻址简单,只需要访问一次内存;缺点是寻址范围受指令位数限制,地址也不容易修改

访存1次

间接寻址

指令中给出操作数真实地址所存放位置的真实地址

间接寻址可以是一次,也可以是多次

如果内存寻址得到的内容第一位是1,表示多次间接寻址,需要继续寻址

如果内存寻址得到的内容第一位是0,表示得到的就是操作数的地址

优点是扩大了寻址范围,EA位数大于A的位数;缺点是需要多次访存(至少2次)

这种寻址方式不常用,通常使用寄存器间接寻址扩大寻址范围

访存至少2次

寄存器寻址

指令中给出操作数所在的寄存器编号

优点是不访问主存,且地址码很短(因为寄存器不多);缺点是寄存器价格贵,个数有限

访存0次

寄存器间接寻址

指令中给出操作数真实地址所存放的寄存器编号

特点是比间接寻址快,但仍需要访问主存

访存1次

相对寻址

指令中给出的是偏移地址(可正可负),基地址在PC中

操作数地址不是固定的,广泛应用于转移指令

注意

转移指令取出后,PC会立刻更新到下一行指令的位置,此后再计算相对偏移量。

比如转移指令2个字节,转移指令地址为X,则执行完后,

访存1次

基址寻址

指令给出偏移地址,基地址在基址寄存器BR中

面向操作系统的寻址方式,基址寄存器由操作系统管理,用户程序运行时通常BR不可变

该寻址方法扩大了寻址范围,用户不需要考虑编程的地址范围;缺点是偏移量的位数短

访存1次

变址寻址

指令给出基地址,偏移地址在变址寄存器IX中

面向用户的寻址方式,变址寄存器用户可以更改,指令中的A一般不变

该寻址方法扩大了寻址范围,常用于数组(A为数组地址,IX存放元素偏移量)、循环;缺点是偏移量的位数短

访存1次

堆栈寻址

堆栈是存储器(或专用寄存器组)中特定的按后进先出原则管理的存储区

该存储的读写一般通过栈顶指针寄存器SP

分为

硬堆栈:寄存器堆栈,成本高,不适合大容量堆栈

软堆栈:主存中划分一块区域作为堆栈,划算且常用

本寻址方式一般指令中都无操作数,操作数隐含在堆栈中,在读写堆栈的单元前后会相应对SP内容进行增减

x86汇编指令入门

相关寄存器

8个32位的通用寄存器,分别为

EAX 累加器(Accumulator)

EBX 基地址寄存器(Base Register)

ECX 计数寄存器(Count Register)

EDX 数据寄存器(Data Register)

ESI、EDI 变址寄存器(Index Register)

EBP 堆栈基指针(Base Pointer)

ESP 堆栈顶指针(Stack Pointer)

功能上作为程序计数器PC的寄存器:IP或EIP,只能使用控制指令修改

字母表示可以大写也可以小写,第一个字母E表示Extended(拓展的)

为了兼容性,EAX、EBX、ECX、EDX的低两个字节可以单独使用,以EAX为例

EAX低2字节称为AX

AX的高字节和低字节分别称为AH和AL

除了EBP和ESP,其他寄存器的使用实际上是任意的

寻址模式

如果是两个地址参数,第一个为目的地址,第二个为源地址

中括号内是地址,整体表示取括号中地址对应的存储空间

计算地址最多只能用2个32位寄存器和1个32位有符号常数相加

内存分配

汇编语言中声明内存大小,显示的使用

DB:Data Byte,单字节

DW:Data Word,双字节

DD:Double Word,四字节

对于常数的分配空间大小,可以使用标识符

BYTE PTR:常数以单字节形式

WORD PTR:常数以双字节形式

DWORD PTR:常数以四字节形式

指令可以有后缀指明空间大小,以传送指令mov为例

movb:传送单字节

movw:传送双字节

movl:传送四字节

movq:传送八字节

常用指令

分别表示操作数为寄存器、内存、常数的情况。如果reg和con后带数字则表示指定了位数。

数据传送指令

mov指令:将第二个操作数复制到第一个操作数。要求目的操作数不为常数,且不能从内存到内存

mov ,

mov ,

mov ,

mov ,

mov ,

push指令:ESP值减4后把操作数压入栈中,可以看出栈增长方向是从大地址到小地址

push

push

push

pop指令:把操作数弹出栈后ESP加4

pop

pop

算术和逻辑计算指令

add/sub指令:第一个操作数加上/减去第二个操作数,结果保存在第一个操作数位置

add/sub ,

add/sub ,

add/sub ,

add/sub ,

add/sub ,

inc/dec指令:操作数自增1/自减1

inc/dec

inc/dec

imul指令:带符号整数乘法指令。第一个(目的)操作数必须是寄存器;可以有一个或两个源操作数;一个源操作数时不使用常数,其与目的操作数的积放到目的操作数;两个源操作数时使用常数,把积放到目的操作数;如果溢出则OF=1

imul ,

imul ,

imul ,,

imul ,,

idiv指令:带符号除法指令。一个操作数表示除数。被除数为EDX:EAX。结果商存入EAX,余数存入EDX。

idiv

idiv

and/or/xor指令:逻辑与/或/异或,结果放在第一个操作数

and/or/xor ,

and/or/xor ,

and/or/xor ,

and/or/xor ,

and/or/xor ,

not指令:取反(位翻转)指令

not

not

neg指令:取负指令

neg

neg

shl/shr指令:逻辑移位指令,结果存放在第一个操作数,第二个操作数为移位的位数

shl/shr ,

shl/shr ,

shl/shr ,

shl/shr ,

控制流指令

jmp指令:控制IP转移到label指示的地址执行

jmp

cmp指令:第一个操作数和第二个操作数比较,根据结果设置处理机状态字条件码

cmp ,

cmp ,

cmp ,

cmp ,

jcondition指令:根据处理机状态字进行条件转移

je

jne

jz

jg

jge

jl

jle

ja

jae

jb

jbe

call/ret指令:用于函数的调用和返回。call把当前指令地址入栈后,无条件转移到标签处;ret从栈中弹出之前保存的地址,无条件转移回之前的地址位置

call

ret

数据对齐和大小端存放

详见第二章笔记中,“数据的存储和排列”小节

CISC和RISC的基本概念

复杂指令系统计算机(CISC)

增强原有指令的功能,设置更复杂的新指令,使软件功能硬件化实现

比如X86架构计算机

精简指令系统计算机(RISC)

减少指令的种类、简化指令的功能,使指令的速度提高

比如ARM、MIPS架构计算机

复杂指令系统计算机

CISC的特点如下:

指令系统:复杂庞大

指令数目:一般在200条以上

指令字长:不固定。指令格式多,寻址方式多

可访存的指令:不受限制

各指令使用频度:差别大,遵循28定律(20%的指令使用频率80%,80%的指令很少使用)

各指令执行时间:差别大,大部分需要多个时钟周期

CPU中通用寄存器数量:较少

控制器控制方式:大多数采用微程序控制。有些指令很复杂,无法用硬连线控制。

目标代码优化:难以用优化编译生成高效的目标代码程序

指令流水线技术:可以通过一定方式实现

软件兼容性:比较好,高档机可保护低档机全部指令并加以扩充

精简指令系统计算机

RISC的特点如下:

指令系统:选取使用频率高的简单指令,复杂的指令由简单指令组合实现

指令数目:一般在100条以下

指令字长:固定。指令格式少,寻址方式少

可访存的指令:只有LOAD/STORE(取数存数)允许访存。其余指令的操作在寄存器之间进行

各指令使用频度:都经常使用

各指令执行时间:大部分指令在一个时钟周期内完成

CPU中通用寄存器数量:非常多

控制器控制方式:以硬布线控制(组合逻辑控制)为主,基本不用微程序控制

目标代码优化:特别重视编译优化工作,以减少程序执行时间

指令流水线技术:一定采用

软件兼容性:大多数RISC不能和老机器兼容,但因为实用性强,是未来的发展方向

高级语言程序与机器代码之间的对应

编译器、汇编器和链接器的基本概念

详见第一章笔记“高级语言程序与机器语言程序转换”小节

过程(函数)调用的机器级表示

假设P调用Q,则步骤如下

P保存现场:当需要保留调用者保存寄存器(包括EAX、ECX、EDX)的值,进行此步骤

P压参数:把调用参数按从右到左的顺序压入栈中(如果寄存器数量充足,也可能把部分参数用寄存器保存)

P执行CALL指令

存旧PC:把返回地址(调用指令后一条指令的位置)压栈

更新PC:修改PC至跳转处,此后Q过程开始执行

Q准备阶段

存原栈底:将EBP(P的栈底)压栈(此时ESP为栈顶,所指位置存放P的栈底)

更新栈底:更新EBP为ESP位置(即Q的栈底中存放P的栈底)

更新栈顶:修改ESP,为自己分配栈空间(一般减去大小为16字节的倍数,以便对齐)

保存现场:如果需要用被调用者保存寄存器(包括EBX、ESI、EDI),进行此步骤

Q过程体阶段

局部变量空间分配:一般按低地址到高地址的顺序使用栈空间(和栈增长方向相反)

通常按小端存放,考虑对齐

结束时设置返回值(通常是放到EAX寄存器中)

Q结束阶段

Q恢复P的现场

Q执行leave指令

恢复栈顶:修改ESP等于EBP,以释放Q的栈空间

恢复栈底:弹出Q的EBP所指向P的EBP的值给EBP,即恢复P的栈空间

Q执行ret指令

恢复PC:弹出此时ESP所指向的返回地址给PC,以返回P执行

P恢复现场

P继续执行CALL指令的下一条指令

注:关于一个过程P的栈帧 +

P栈帧头:P过程EBP指向空间(存放P过程的调用者的旧EBP) +

P栈帧尾:下一个过程Q的EBP指向空间(存放的是P的EBP)的前一个空间(存放的是P的返回地址)

+ 栈帧是周期性的,P的栈帧尾后面就是Q的栈帧头

选择结构语句的机器级表示

条件码

即标志位寄存器,包括

CF 进位标志:用于无符号数

ZF 零标志:最近运算是否为0

SF 符号标志:最近运算结果的符号

OF 溢出标志:用于带符号数

cmp和sub对条件码的行为一致

test和and对条件码行为一致

jcondition指令结合条件码的ZF和SF可以实现跳转

if语句

可以利用if-goto语句分析从高级语言到汇编的过程

如果if条件不满足,则goto跳转

然后把if-goto转换到对应的汇编中,使用cmp/test、jcondition

Label的方式

switch语句

相比于if语句多次条件判断来跳转,switch是多路选择,一次直接跳到某个条件处的语句执行

需要用到跳转表

段属性为只读,即.section .rodata

跳转地址在4字节边界上,即align 4

跳转表的头设置一个标记Label,头之后的每一行(项)都是一个标签Labeli,i=0,1,...,7

给出一个例子

设switch输入10、12、14、15、17分别对应情况L2、L3、L4、L1、L3,其他输入对应情况L5

跳转表Label标签后面的每一行分别表示情况10、11、12、...、17需要跳到的标记Labeli,即L2、L5、L3、L5、L4、L1、L5、L3

汇编代码中,首先把判断的输入减10,记为t。

比较t和7的关系(条件码设置按无符号减法)。

如果大于7(根据无符号数运算,这里包括t是负数的情况),跳转到L5

否则根据t作为索引查跳转表对应表项标签Labelt,跳转到跳转表此项对应的标签位置执行即可

循环结构语句的机器级表示

高级语言转汇编可以借助if-goto作为中间代码,方便分析转换

循环结构有三种情况

do-while循环:一次goto即可

while循环:相当于在do-while前先判断条件一次。需要两个goto

for循环:相当于while语句前先做一个初始化语句,可以先转成while循环。需要两个goto。

最后把if-goto转换到对应的汇编中,使用cmp/test、jcondition

Label的方式