第11章 32位x86处理器编程架构
IA-32(INTEL Architecture, 32-bit):INTEL 32位处理器架构简称IA-3,以8086处理器为基础发展起来的。该章重点介绍了IA-32处理器的工作方式和相关技术。
IA-32架构的基本执行环境
寄存器的扩展
32位处理器通用寄存器:包含EAX、EBX、ECX、EDX、ESI、EDI、EBP、ESP,它们的在原先16位处理器的AX、BX、CX、DX、SI、DI、BP、SP上扩展而来,结构如下图:
EFLAGS:标志寄存器FLAGS也从16位扩展到了32位。
访存方式:32位处理器为了兼容16位处理器,保留了分段模型;但是提供一种变通方案平坦模型(Flat Mode),即段基地址为:0x00000000,段长度为4GB的分段方式。
32位工作模式:32位处理器有自己的32位工作模式,书籍内称呼这种32位模式为32位保护模式(Protected Mode)。与之对应的16位工作模式称为实模式(Real Mode)。
- 实模式:程序可以自由地访问不属于它的内存位置,不安全。
- 保护模式:处理器要求在加载程序时,先定义该程序所拥有的段,然后才允许使用这些段,还附加了段界限、特权级别、类型等属性。
段选择器:32位模式下,CS、SS、DS、ES,保存的不再是16位逻辑段地址,而是段的选择子,用于选择所要访问的段,因此,这一部分也叫作段选择器。
32位处理器增加了两个额外的段寄存器FS和GS,这两个寄存器到底有什么作用?书中后面也没有提到,于是我去查了下资料,只能大概了解其意思。
- FS(Flag Segment):标志段寄存器,指向当前活动线程的TEB结构。
- GS(Global Segment):全局段寄存器,可能被用作全局段的基址寄存器。
麻省理工的手册上,DS、ES、FS、GS都是标记为Data Segment,没有具体的区分。使用上各操作系统也有不同,具体可以参考底部的一些链接。
基本的工作模式
实模式(Real Mode):实质上就是8086模式,16位模式。
保护模式(Protected Mode):IA-32处理器的32位模式。
一些发展历史整理成表格看的更清楚一些:
线性地址和分页
逻辑地址:段地址和偏移地址称为逻辑地址,偏移地址叫作有效地址(Effective Address, EA),在指令中给出有效地址的方式叫作寻址方式(Addressing Mode)。比如:
inc word [bx+si+0x06]
段的管理是由处理器的段部件负责进行的。段部件将段地址和偏移地址相加,得到访问内存的地址。一般来说,段部件产生的地址就是物理地址。
多任务:IA-32处理器支持多任务,多任务在分配内存时会产生内存碎片的问题。
分页:IA-32处理器支持分页功能,分页功能将物理内存空间划分成逻辑上的页。页的大小一般为4KB,通过使用页,可以简化内存管理。
线性地址:当页功能开启时,段部件产生的地址就不再是物理地址了,而是线性地址(Linear Address),线性地址还要经页部件转换后,才是物理地址。
现代处理器的结构和特点
流水线
流水线(Pipe-Line)技术:把一条指令的执行过程分解成若干个细小的步骤,并分配给相应的单元来完成,各个单元的执行是独立的、并行的。
一条指令的执行过程分为取指令、译码和执行三个步骤:
高速缓存
为什么要高速缓存:处理器速度快,内存和硬盘相对较慢,处理器要等待内存和硬盘,便无法全速运行。
- CPU内寄存器纳秒(ns)级别;
- 内存一般是动态存储器(DRAM),几十纳秒级别;
- 硬盘,通常是毫秒级(ms)。
高速缓存(Cache):处理器与内存(DRAM)之间的一个静态存储器(SRAM),容量较小,但速度可以与处理器匹配。
缓存涉及到命中的问题:如果要访问的内容已经在高速缓存中,这称为命中(Hit);否则,称为不中(miss)。缓存不中,处理器需要重新装载高速缓存,该过程中所损失的时间称为不中惩罚(miss penalty)。
乱序执行
微操作(micro-operations):为了实现流水线技术,需要将指令拆分成更小的可独立执行部分。
一个微操作:有些指令非常简单,因此只需要一个微操作。
add eax,ebx
两个微操作:
add eax,[mem] ;拆分成两个微操作:
; 1.一个用于从内存中读取数据并保存到临时寄存器;
; 2.另一个用于将EAX寄存器和临时寄存器中的数值相加。
三个微操作:
add [mem],eax ;拆分成三个微操作:
; 1.一个从内存中读数据;
; 2.一个执行相加的动作;
; 3.一个用于将相加的结果写回到内存中。
乱序执行(Out-Of-Order Execution):一旦将指令拆分成微操作,处理器就可以在必要的时候乱序执行程序。
感觉乱序执行有点像并行,不相关的两个程序是可以并发执行的,从而提交效率。
寄存器重命名
寄存器重命名:在处理器内部,却有大量的临时寄存器可用,处理器可以重命名这些寄存器以代表一个逻辑寄存器,比如EAX。
寄存器重命名作用:为了提高指令的乱序执行,用临时寄存器代替原寄存器进行运算,等乱序执行完成后,再用临时寄存器内容替换原寄存器的内容,这个过程也叫做引退(Retirement)。
分支目标预测
清空(Flush)流水线:如果遇到一条转移指令,则后面那些已经进入流水线的指令就都无效了,就是要清空流水线。
流水线的问题:代码中经常存在分支,用哪个分支的代码填充流水线呢?用错误的分支填充流水线时,浪费的时间就越多。随着复杂架构下的流水线变得越来越长,程序分支带来的问题开始变得很大。让处理器的设计者不能接受,毕竟不中处罚的代价越来越高。
分支预测技术(Branch Prediction):分支预测的核心问题是,转移会发生还是不会发生。转移预测虽然很困难,但是可以通过统计学的方式分析概率。
比如下面这个例子:
xor si,si ;si清0
lops:
...
cmp si,20 ;si和20比较
jnz lops ;si<20,不为0,继续循环
jnz指令第一次执行时,转移一定会发生,处理器可以预测。
分支目标缓存器(Branch Target Buffer, BTB):在处理器内部,有一个小容量的高速缓存器。处理器执行了一条分支语句后,它会在BTB中记录当前指令的地址、分支目标的地址,以及本次分支预测的结果。
32位处理器的寻址方式
16位处理器的内存寻址:允许使用基址寄存器BX或者BP,同变址寄存器SI或者DI结合,再加上8位或者16位的位移来寻址内存操作数。
例如:
mov ax,[bx]
mov ax,[bx+di]
mov al,[bx+si+0x02]
32位处理器的内存寻址:全部的32位通用寄存器作为基址寄存器 + 除ESP外的32位通用寄存器作为变址寄存器 * 1、2、4、8比例因子 + 位或者32位的位移。
例如:
add eax,[0x2008] ; 有效地址是32位的(0x00002008)
sub eax,[eax+0x08] ; 有效地址是32位的
mov ecx,[eax+ebx*8+0x02] ; 有效地址是32位的