文章目录
处理器的功能结构
处理器的基本结构
低端处理器一般由算术逻辑单元、寄存器和指令处理单元等几部分组成,典型的8位处理器的基本结构如下图所示
- 算术逻辑单元(Arithmetic Logic Unit,ALU)
计算机的运算器,负责处理器所能进行的各种运算,主要就是算术运算和逻辑运算
基本的ALU由加法器电路构成,操作的数据来自通用寄存器或主存,运算结果返回寄存器或主存。
累加器(Accumulator) 结构的处理器,
累加器提供一个操作数,暂存器提供另一个操作数,运算后,累加器保存运算结果。
标志(Flag)寄存器,也称为程序状态字(PSW)
反映运算结果的辅助信息(eg.有无进错位、是否为0、是否为负)
例如:有无进借位、是否为零、是否为负等 - 寄存器(Register)
处理器内部需要高速存储单元,用于暂时存放程序执行过程中的代码和数据
*从应用角度可以将寄存器分为:透明寄存器和可编程寄存器
透明寄存器 对应用人员不可见、不能直接控制的寄存器
可编程(Programmable)寄存器 具有引用名称、供编程使用
*可编程寄存器可进一步分为通用寄存器和专用寄存器
通用寄存器 数量较多、使用频度较高,具有多种用途(eg.存放指令需要的操作数据、存放地址以便在主存或I/O接口中指定操作数据的位置)
专用寄存器 只用于特定目的(eg.程序计数器[Program Counter,PC]用于记录将要执行指令的主存地址) - 指令处理单元
处理器的控制单元,它控制指令的执行和信息的传输
指令执行的过程
取指:指令处理单元将指令从主存取出,并通过总线传输到处理器内部的指令寄存器
译码:指令处理单元通过指令译码电路获得该指令的功能
执行:指令处理单元的时序和控制逻辑按一定的时间顺序发出和接收相应信号,完成指令所要求的操作
8086的功能
- 总线接口单元(Bus Interface Unit,BIU)和执行单元(Execution Unit,EU)
总线接口单元
由6个字节的指令队列(即指令寄存器)、指令指针IP(等同于程序计数器PC的功能)、段寄存器(CS、DS、SS和ES)、地址加法器和总线控制逻辑等构成,管理着8086与系统总线的接口,负责处理器对存储器和外设访问。8086引脚由16位双向数据总线、20位地址总线和若干控制总线组成。8086所有的对外操作必须通过BIU和这些总线进行。eg.从主存中读取指令、从主存或外设读取数据、向主存或外设写出数据
执行单元
由ALU、通用寄存器、标志寄存器和控制电路构成,负责指令译码、数据运算和指令执行。
指令执行的两个主要阶段:取指和执行
取指:从主存取出指令代码进入指令队列。在8086处理器中,指令在存储器中的地址由代码段寄存器CS和指令指针IP共同提供,再由地址加法器得到20位存储器地址。BIU负责从存储器取出这个指令代码,送入指令队列。
执行:译码指令、并发出有关控制信号实现指令功能。在8086处理器中,执行单元EU从指令队列中获得预先取出的指令代码,在EU控制电路中进行译码,然后发出控制信号由算术逻辑单元进行数据运算、数据传送等操作。指令执行过程需要的操作数据来自处理器内部的寄存器,有些则来自指令队列、自存储器和外设。 - 指令预取(Prefetch)
*8086处理器维护着长度为6个字节的指令队列
EU单元译码、执行指令,同时BIU单元读取后续指令
*BIU和EU两个单元相互独立,可以并行操作,即在EU单元对一个指令进行译码执行时,BIU单元可以同时对后续指令进行读取。所以:8086处理器的指令读取,实际上是指令预取
*由于要译码执行的指令已经预取到处理器内部的指令队列,所以8086不需要等待取指操作就可以从指令队列获得指令进行译码执行。
*最简单的指令流水线技术
*节省许多取指时间,提高了工作效率
*程序转移将使预取指令作废,降低了流水线效率
80386的功能结构
总线接口单元:为处理器提供同外部的接口
指令预取单元:先行读取指令
指令译码单元:从预取队列中取来指令,译码成微指令代码
执行单元:ALU、乘法器、除法器和移位器等
分段单元:逻辑地址变换成线性地址
分页单元:将线性地址变换成物理地址
各功能部件可以并行工作,进行流水线处理
Pentium的结构
- 超标量流水线:2条指令流水线
- 分离Cache:指令Cache和数据Cache
- 动态分支预测:预测程序执行顺序
- 其他
性能增强的浮点处理单元FPU
常用指令固化
改进复杂指令的微代码算法
节能特性
电源电压:3.3V
寄存器
寄存器就是暂时存放数据的地方
通过编写程序、由处理器执行指令控制直接寄存器
IA-32处理器通用指令(整数处理指令)基本执行环境:8个32位通用寄存器、6个16位段寄存器、32位标志寄存器、32位指令指针
对应用人员(程序员)来说,
处理器被抽象为可编程寄存器
👇图为IA-32常用寄存器(图中31、15、7、0等依次表达二进制位)
通用寄存器(General-Purpose Register)
处理器最常使用的整数通用寄存器,可用于保存整数数据、地址等
8个32位通用寄存器(E(Extended)表达扩展含义)
EAX,EBX,ECX,EDX,ESI,EDI,EBP,ESP
8个16位通用寄存器,分别表示相应32位通用寄存器低16位部分
AX,BX,CX,DX,SI,DI,BP,SP
8个8位通用寄存器
AH,AL,BH,BL,CH,CL,DH,DL
存取16位寄存器,高16位不受影响
存取8位寄存器,16/32位寄存器其他位不受影响
通用寄存器的名称
EAX:累加器(Accumulator),使用频度最高,用于算术运算、逻辑运算乙级与外设传送信息
EBX:基址寄存器(Base),常用来存放存储器地址,以方便指向变量或数组中的元素
ECX:计数器(Counter),作为循环操作等指令中的计数器。
EDX:数据寄存器(Data),用来存放数据,其中低16位DX常用来存放外设端口地址
ESI:源变址寄存器(Source Index),用于指向字符串或数组的源操作数。源操作数是指被传送或参与运算的操作数
EDI:目的变址寄存器(Destination Index),用于指向字符串或数组的目的操作数。目的操作数是指保存传送结果或运算结果的操作数。
EBP:基址指针寄存器(Base Pointer),默认情况下指向程序堆栈区域的数据,主要用于在子程序中访问通过堆栈传递的参数和局部变量
ESP:堆栈指针(Stack Pointer),专用于指向程序堆栈区域顶部的数据,在涉及堆栈操作的指令中会自动增加或减少。
堆栈Stack是一个特殊的存储区域,(FILO)。调用子程序,用于暂存数据、传递参数、存放局部变量、临时保存数据。堆栈指针会随着处理器执行有关指令自动增大/减少,所以ESP(SP)应该作为专用寄存器对待;但是ESP又可以像其他通用寄存器一样灵活地改变。
标志寄存器EFLAGS
标志(Flag)
反映指令执行结果或控制指令执行形式。
处理器中用一个或多个二进制位表示一种标志,0或1的不同组合表达标志的不同状态,8086支持16位标志寄存器FLAGS,IA-32处理器形成32位EFLAGS标志寄存器。
状态标志:记录指令执行结果的辅助信息,加减运算和逻辑运算指令是主要设置状态标志的指令。有6个,处理器主要使用其中5个构成各种条件,分支指令判断这些条件实现程序分支。
它们从低位到高位:进位标志(Carry Flag,CF)、奇偶标志(Parity Flag,PF)、调整标志(Adjust Flag,AF)、零标志(Zero Flag,ZF)、符号标志(Sign Flag,SF)、溢出标志(Overflow Flag,OF)
控制标志:方向标志(Direction Flag,DF),仅用于串操作指令,控制地址的变化方向。处理器执行CLD指令设置DF=0,每次串操作后的存储器地址自动增加,从低地址像高地址处理;执行STD则反之。
系统标志:控制操作系统或核心管理程序的操作方式
中断允许标志IF(Interrupt-enable Flag)或简称中断标志,用于控制外部可屏蔽中断是否可以被处理器响应。执行STI指令,IF=1允许中断;执行CLI指令则反之。
陷阱标志(Trap Flag,TF)也常称作单步标志,用于控制处理器是否进入单步操作。TF=1执行,处理器在每条指令执行结束时便产生一个内部中断,单步调试。
I/O特权层标志IOPL(I/O Privilege Level)
任务嵌套标志NT
虚拟8086方式标志VM
恢复标志RF
对齐检测标志AC
CPU识别标志ID(Identification Flag)
虚拟中断标志VIF
虚拟中断挂起标志VIP
专用寄存器
专用寄存器往往只用于特定指令或场合
- 指令指针寄存器EIP
保存将要执行的指令在主存的地址,这个位置用存储器地址表示,存储器地址保存在程序计数器PC中。 - 段寄存器
段是安排相关代码或数据的主存区域
段寄存器表明段在主存中的位置
6个16位段寄存器:代码段寄存器【存放程序中指令代码的代码块】(Code Segment,CS) 堆栈段寄存器【存放当前运行程序所用的数据的数据段】( Data Segment,DS) 数据段寄存器【指明程序使用的堆栈区域的堆栈块】(Stack Segment,SS) 附加段寄存器 ES FS GS - 其他寄存器
浮点寄存器、多媒体寄存器
系统专用寄存器
存储器组织
物理地址(Physical Address):物理存储器以字节为基本存储单位,每个存储单元被分配一个唯一的地址
物理地址空间从0开始顺序编排,直到处理器支持的最大存储单元
8086处理器支持1MB存储器:00000H~FFFFFH(0-2的20次方-1)
IA-32处理器支持4GB存储器:00000000H~FFFFFFFFH(0-2的32次方-1)
操作系统利用存储管理单元进行存储管理,程序并不直接寻址物理存储器
IA-32处理器提供3种存储模型,用于程序访问存储器
存储模型
操作系统利用存储单元进行存储管理,程序并不直接寻址物理存储器。IA-32处理器提供了3种存储模型(Memory Model)用于程序访问存储器
- 平展存储模型(Flat memory model)
存储器是一个连续的地址空间--线性地址空间
IA-32处理器支持4GB(0-2的32次方-1)容量线性地址空间 - 段式存储模型(Segmented memory model)
存储器由一组独立的地址空间--段(Segment)组成
每个段都可以达到4GB容量
在处理器内部,所有的段都被映射到线性地址空间
通常,代码、数据和堆栈位于分开的段中,程序利用逻辑地址寻址段中的每个字节单元。 - 实地址存储模型(Real-address Mode memory model)
8086处理器的存储模型
段式存储模型的特例
线性地址空间最大为1MB容量,段最大为64KB
工作方式
- 保护方式(Protected mode)
IA-32处理器固有的工作状态
具有强大的段页式存储管理和特权与保护能力
使用全部32条地址总线,可寻址4GB物理存储器
使用平展或段式存储模型
利用虚拟8086方式支持实地址8086软件 - 实地址方式(Real-address mode)
可以进行32位处理的快速8086
只能寻址1MB物理存储器空间,每个段不超过64KB
可以使用32位寄存器、32位操作数和32位寻址方式
只能支持实地址存储模型 - 系统管理方式(System Management mode)
实现节能和系统安全管理
逻辑地址
在处理器内部、程序员编程时采用的地址
逻辑地址=段基地址∶偏移地址(Offset)
段基地址=在主存中的起始地址
偏移地址=距离段基地址的位移量
某个存储单元可以有多个逻辑地址,但只有一个唯一的物理地址
- 基本段
编写应用程序时,涉及三类基本段:
代码段(Code Segment):存放指令代码
程序的指令代码必须安排在代码段段基地址:代码段寄存器CS指示
程序的数据默认存放在数据段,数据也可放在其他段
偏移地址:指令指针寄存器EIP保存
数据段(Data Segment):存放数据
段基地址:数据段寄存器DS指示
有时也用附加段寄存器ES,段寄存器FS和GS指示
偏移地址:各种存储器寻址方式计算出来
堆栈段(Stack Segment):堆栈区域
程序使用的堆栈一定在堆栈段
基本段的逻辑地址SS:ESP
段基地址:堆栈段寄存器SS指示
偏移地址:堆栈指针寄存器ESP保存 - 段选择器
16位段寄存器保存16位段选择器(Segment Selector)
段选择器指向64位段描述符(Descriptor),段描述符包括段基地址
平展存储模型:指向地址0位置
段式存储模型:指向线性地址空间不同的段
实地址存储模型:保存段基地址的高16位
- 保护方式的地址转换
平展存储模型
段基地址为0,偏移地址等于线性地址
段式存储管理
段基地址和偏移地址都是32位
段基地址加上偏移地址形成线性地址
线性地址映射到物理地址
不使用分页机制:线性地址与物理地址对应
使用分页机制:硬件支持下由操作系统或核心程序管理,构成虚拟存储器,转换成物理地址
4.实地址方式的地址转换
主存空间1MB(=220 B):00000H~FFFFFH
程序设计时分段管理,但有两个限制:
每个段最大为64KB(2的16次方字节)
段只能开始于低4位地址全为0的物理地址处
逻辑地址=段地址∶偏移地址
16位段寄存器保存20位段起始地址的高16位
偏移地址也用16位数据表示
物理地址=段地址×16👇+偏移地址
汇编语言基础
汇编语言以助记符形式表示计算机指令
助记符(mnemonic)是便于人们记忆、并能描述指令功能和指令操作数的符号
助记符是表明指令功能的英语单词或其缩写
汇编格式指令以及使用它们编写程序的规则就形成汇编语言(Assembly Language)
汇编语言程序:用汇编语言书写的程序
汇编程序:将汇编语言程序“汇编”成机器代码目标模块的程序
汇编语言程序与汇编程序是两个概念
指令代码格式(Instruction format)/机器代码格式
IA-32处理器采用可变长度指令格式
操作码
可选的指令前缀(用于扩展指令功能)
1~3字节的主要操作码
操作数(地址码)
可选的寻址方式域(包括ModR/M和SIB字段)
可选的位移量
可选的立即数
指令代码示例
数据传送指令MOV(取自Move)
将数据从一个位置传送到另一个位置,类似高级语言的赋值语句
mov dest,src
;源操作数src:被传送的数据或数据所在的位置
;目的操作数dest:数据将要传送到的位置
mov eax,ebx ; 机器代码:8B C3
mov eax,[ebx] ; 机器代码:8B 03
mov eax,[ebx+esi*4+80h] ; 机器代码:8B 84 B3 80 00 00 00
语句格式
程序由语句组成
一个语句常占一行(MASM有续行符“\”)
一个语句不超过132个字符,4个部分
执行性语句:表达处理器指令(硬指令)
标号: 硬指令助记符 操作数,操作数 ;注释
说明性语句:表达伪指令,控制汇编方式
名字 伪指令助记符 参数,参数,…… ;注释
- 标号与名字
标号:执行性语句中
冒号分隔;表示处理器指令在主存中的逻辑地址;指示分支、循环等程序的目的地址
名字:说明性语句中
空格或制表符分隔;变量名、段名、子程序名等;反映变量、段和子程序等的逻辑地址
标识符(Identifier)
最多由31个字母、数字及规定的特殊符号(如 _、$、?、@)组成,不能以数字开头
一个源程序中,用户定义的每个标识符必须唯一
不能是汇编程序采用的保留字
保留字(Reserved Word)
是编程语言本身需要使用的各种具有特定含义的标识符、也称为关键字
硬指令助记符: MOV
伪指令助记符: BYTE
操作符: OFFSET
寄存器名: EAX
取名原则类似高级语言,默认不区别大小写字母
“ OPTION CASEMAP:NONE ” 伪指令,告知MASM 区别用户定义标识符的大小写 - 助听器
助记符:帮助记忆指令功能的符号
硬指令助记符对应处理器指令,表示一种处理器操作,伪指令助记符表达一个汇编命令
处理器指令示例:传送指令 MOV
伪指令示例:字节变量定义
助记符:BYTE (或DB)
功能:在主存中占用若干的存储空间,用于保存变量值,该变量以字节为单位存取 - 操作数和参数
处理器指令的操作数:表示参与操作的对象
具体的常量;保存在寄存器的数据;保存在存储器中的变量;逗号前常是目的操作数,逗号后常是源操作数
伪指令的参数:
常量、变量名、表达式等;可以有多个,参数之间用逗号分隔 - 注释
语句的4个组成部分要用分隔符分开
标号后的冒号;注释前的分号;操作数间和参数间的逗号;分隔其他部分采用一个或多个空格或制表符
源程序框架
; eg0000.asm in Windows Console
include io32.inc ; 包含32位输入输出文件
.data ; 定义数据段
…… ; 数据定义(数据待填)
.code ; 定义代码段
start: ; 程序执行起始位置
…… ; 主程序(指令待填)
exit 0 ; 程序正常执行结束
…… ; 子程序(指令待填)
end start ; 汇编结束
- 包含伪指令INCLUDE
将常用的常量定义、过程说明、共享的子程序库等内容进行声明(相当于C和C++语言中,包含头文件的作用)
IO32.INC是配合本书的包含文件
前3个语句:
.686 ; 32位指令
.model flat,stdcall
; 选择平展模型,标准调用规范
option casemap:none
;告知MASM区分用户定义标识符的大小写
- 段的简化定义
数据段定义伪指令.DATA创建一个数据段
代码段定义伪指令.CODE创建一个代码段
堆栈段由Windows维护,用户不必设置
程序开始执行的位置
应用一个标号(例如:START)
汇编结束END指令的参数
应用程序执行结束
语句“EXIT 0”将控制权交还操作系统
提供给操作系统一个返回代码
通常用0表示执行正确
源程序汇编结束END语句
执行结束≠汇编结束
eg.信息显示程序
在数据段给出这个字符串形式的信息:
; 数据段
msg byte 'Hello, Assembly!',13,10,0
; 定义要显示的字符串
在代码段编写显示字符串的程序:
; 代码段
mov eax,offset msg
; 指定字符串的偏移地址
call dispmsg
; 调用I/O子程序显示信息
; eg0201.asm
include io32.inc
.data ; 数据段
msg byte 'Hello, Assembly!',13,10,0 .code ; 代码段
start: ; 程序执行起始位置
mov eax,offset msg
call dispmsg
exit 0 ; 程序正常执行结束
end start ; 汇编结束
;c语言程序
;#include <stdio.h>
;int main()
;{
; printf("Hello, world !\n");
; exit(0);
;}
- 输入输出子程序库
键盘输入和显示器输出的I/O子程序
含IO32.INC和IO32.LIB,需要包含文件声明
源程序文件开始使用包含命令声明
INCLUDE IO32.INC
子程序调用方法
MOV EAX,入口参数
CALL 子程序名
宏调用方法
宏名 入口参数
*常用输出子程序
*常用输入子程序
开发过程
数据寻址的方式
指令有两部分:操作码和操作数
操作码:处理器要执行哪种操作,不可缺少,用助记符表示
操作数:指令执行的参与者,各种操作的对象,需要通过地址指示
数据寻址方式:通过地址查找数据(操作数)
立即数寻址:数据与指令操作码一起,用常量表达
寄存器寻址:数据在寄存器中,用寄存器名表示
存储器寻址:数据在主存中,用存储器地址代表
立即数寻址方式
操作数紧跟操作码,是机器代码的一部分
操作数从指令代码中立即得到,即立即数(Immediate),用常量形式直接表达
立即数寻址方式只用于源操作数,常用来给寄存器和存储单元赋值
例如:MOV EAX,33221100H
机器代码:B8 00 11 22 33
操作码:B8
立即数:33221100
寄存器寻址方式
操作数存放在处理器的内部寄存器中
用寄存器名表示它的内容
绝大多数指令采用通用寄存器寻址
部分指令支持专用寄存器,例如段寄存器
寄存器寻址方式简单快捷,最常使用
例如:MOV EBX,EAX
32位通用寄存器:EAX EBX ECX EDX ……
16位通用寄存器:AX BX CX DX ……
8位通用寄存器:AH AL BH BL ……
存储器寻址的方式
操作数在主存中,通过存储器地址指示
编程时,存储器地址使用包含段选择器和偏移地址的逻辑地址
*段选择器(段寄存器)指示段基地址
默认规定:数据在DS指向的数据段;EBP或ESP作为基地址,数据在SS指向的堆栈段
显式说明:使用段超越指令前缀,段寄存器名后跟英文冒号
*偏移地址由各种寻址方式计算,常被称为有效地址EA(Effective Address)
- 段寄存器的默认和超越
主存操作数常通过变量形式引用,一般不需要使用段超越前缀指令 - 偏移地址的组成
32位有效地址 = 基址寄存器+(变址寄存器×比例)+位移量
基址寄存器:任何8个32位通用寄存器之一
变址寄存器:除ESP之外的任何32位通用寄存器之一
比例:1,2,4或8
位移量:8或32位有符号值
16位有效地址 = 基址寄存器+变址寄存器+位移量
基址寄存器:BX或BP
变址寄存器:SI或DI
位移量:8或16位有符号值
多种主存寻址方式 - 直接寻址
有效地址只有位移量部分,直接包含在指令代码中
常用于存取变量
例如:
MOV ECX,COUNT ;COUNT是变量
MOV ECX, DS:[405000H]
指令代码:8B 0D 00 50 40 00
操作码和寻址方式:8B 0D
操作数:有效地址 00405000H
4. 寄存器间接寻址
有效地址存放在寄存器中(寄存器内容=偏移地址)
MASM用中括号括起寄存器
可以方便地对数组的元素或字符串的字符进行操作
寄存器间接寻址没有说明存储单元类型
例如:
mov edx,[ebx]
mov [esi],ecx
- 寄存器相对寻址
有效地址是寄存器内容与位移量之和
也可以方便地对数组的元素或字符串的字符进行操作
例如:
mov esi,[ebx+4] ;位移量:4
mov edi,[ebp-08h] ;位移量:-08H
mov esi,count[ebx] ;位移量:COUNT
主存以字节为可寻址单位,地址的加减是以字节为单位
6. 变址寻址
使用变址寄存器寻址操作数
便于支持两维数组等数据结构
例如:
mov edi,[ebx+esi]
mov edi,[ebx][esi]
; 基址变址寻址,功能:EDI=DS:[EBX+ESI]
mov eax,[ebx+edx+80h]
mov eax,80h[ebx+edx]
mov eax,80h[ebx][edx]
;相对基址变址寻址
功能:EAX=DS:[EBX+EDX+80H]
- 带比例的变址寻址
变址寄存器内容乘以比例1(可省略),2,4或8的变址寻址
比例1、2、4和8对应8、16、32和64位数据的字节个数,便于以数组元素为单位寻址相应数据
例如:
mov eax,[ebx*4] ; 带比例的变址寻址
mov eax,[esi*2+80h] ; 带比例的相对变址寻址
mov eax,[ebx+esi*4] ; 带比例的基址变址寻址
mov eax,[ebx+esi*8-80h] ; 带比例的相对基址变址寻址
各种数据寻址方式的总结
立即数 imm
通用寄存器 reg
存储器操作数 mem