
AI-摘要
PrideLzh GPT
AI初始化中...
介绍自己 🙈
生成本文简介 👋
推荐相关文章 📖
前往主页 🏠
前往爱发电购买
4-段寄存器&寻址方式
pridelizihao一、段寄存器及使用
1、存储器分段
(1)物理地址相关
内存(逻辑存储器):CPU能通过CPU总线直接寻址访问的存储器
物理地址:
内存(逻辑存储器)
每一个字节单元有一个唯一的地址,称为物理地址。- 这个物理地址就是各存储器在CPU总线上的地址,利用它CPU可以直接访问到对应的存储空间
- CPU的地址线数量决定可产生的最大物理地址,n根地址线—>最大地址2^n-1,32位CPU通常有32根地址线,因此32位CPU的电脑最大只能装4G的内存条
物理地址空间:所有可形成的
物理地址
的集合- 物理地址空间大小不等于实际安装物理内存大小
- Intel8086有20根地址线,物理地址的范围是0到FFFFF
Intel80386有32根地址线,物理地址的范围是0到FFFFFFFF
(2)存储器分段
为了有效地管理存储器,常常把
- 线性的物理地址空间划分为若干逻辑段
- 存储空间被划分为若干存储段
可以认为逻辑段和存储段是对应的。
通常,运行的程序把不同的数据存储于存储器中的不同存储段,包括
代码
:要执行的指令序列(存储于代码段
)数据
:要处理加工的内容(存储数据段
)堆栈
:按先进后出规则存取的区域(存储于堆栈段
)
2、逻辑地址
(1)逻辑地址
- 分段后,程序中使用的某个存储单元总是属于某个段,所以可以
某某段
某某单元
方式表示存储单元 逻辑地址
:程序中用于表示存储单元的地址- 由于采用分段存储管理方式,程序中使用的逻辑地址是二维的,第一维给出某某段,第二维给出段内的某某单元。
- 二维的逻辑地址可以表示为:
段号∶段内地址
(段内)偏移
:存储单元的物理地址与所在段起始地址的差值。这个差值恰好是段内地址,因此二维的逻辑地址又可以表示为:段号∶偏移
- 实方式下,段号是
段值
保护方式下,段号是段选择子
有效地址/偏移地址
:逻辑地址中的偏移称作有效地址或偏移地址,汇编程序中,不同的数据往往固定存放在不同的段,有唯一对应的段寄存器,因而这个地址用的最多。比如指示代码的EIP、指示堆栈位置的ESP、EBP等都是存储的有效地址
(2)逻辑地址转为物理地址
物理地址 = 段起始地址 + 偏移
获得物理地址的过程:
- 由段号得到段起始地址
- 加上偏移
对于IA32
- 保护方式下:物理地址32位,段起始地址32位,偏移32位
- 实方式下:物理地址20位,段起始地址20位,偏移16位
- 可以参考:我理解的逻辑地址、线性地址、物理地址和虚拟地址(补充完整了)
对于8086:
- 只有实方式:物理地址20位,段起始地址20位,偏移16位
- 可以参考:逻辑地址、线性地址和物理地址之间的转换
如果整个程序只有一个段,则二维逻辑地址退化为一维。段起始地址完全相同,偏移决定一切。如果用VS2010来编写嵌入汇编程序,那么就是这种情况,只考虑偏移即可
(3)三种地址小结
地址 | 说明 |
---|---|
物理地址 | 各存储器在CPU总线上的地址,是实际上可以直接访问到存储器的地址 |
逻辑地址 | 段号∶偏移 方式描述的地址,需要进行一些计算才能转换为物理地址 |
有效地址 | 就是逻辑地址中的偏移量 |
3、段寄存器
- 作用:段寄存器存放着当前使用的逻辑地址中的段号(段值/段选择子),用于获得段起始地址。
- 段寄存器是16位的,在实方式下存储16位段值;在保护方式下存储16位段选择子
- 若代码段、堆栈段、数据段在同一个存储段,则CS、DS、SS给出相同的段起始地址
- 若段寄存器给出的段起始地址为0,则偏移相当于物理地址
二、寻址方式
寻址方式
:表示指令中操作数所在的方法- CPU常用的三种寻址方式:
立即寻址
、寄存器寻址
、存储器寻址
,此外还有固定寻址和I/O端口寻址 - 以上三种方式都是对于偏移地址的不同描述,对于段基址:
- 基址寄存器是EBP或ESP时,默认的段寄存器是SS
- 否则,默认的段寄存器是DS
1、立即寻址
立即寻址方式
:操作数本身就包含在指令中,直接作为指令的一部分给出,这样的操作数称为立即数
注意:
- 只有源操作数可以使用立即寻址方式
- 如果立即数由多个字节构成,么在作为指令的一部分存储时,也采用“高高低低”规则。
由于立即寻址方式的操作数是立即数,包含在指令中,所以执行指令时,不需要再到存储器中去取该操作数了。
- 立即寻址,会自动配合目的操作数尺寸,不需要dword ptr等参数
示例:
1 | //以下源操作数使用立即寻址方式 |
2、寄存器寻址
寄存器寻址方式
:操作数存在CPU内部寄存器,指令指定寄存器适用范围:
- 8个32位寄存器:
EAX
,EBX
,ECX
,EDX
,ESI
,EDI
,EBP
,ESP
- 8个16位寄存器:
AX
,BX
,CX
,DX
,BP
,SI
,DI
,SP
- 8个8位寄存器:
AH
,AL
,BH
,BL
,CH
,CL
,DH
,DL
- 8个32位寄存器:
操作数在寄存器中,不需要访问存储器取得操作数,这样指令执行速度较快
示例:
1 | MOV EBP, ESP //把ESP之值送到EBP |
3、32位的存储器寻址方式
存储器寻址方式
:给出存储单元偏移的寻址方式(在某个段内,给出存储单元的偏移即可找到它)存储器操作数
:在指令中[xxx]
意味着从xxx
地址取数据,称这个[xxx]
为存储器操作数。有效地址
:要访问的存储单元的段内偏移。在32位的存储器寻址方式下,存储单元有效地址可达32位- 采用32位的存储器寻址方式,能够给出32位的偏移
- 有多种存储器寻址方式
- 直接寻址
- 寄存器间接
- 寄存器相对
- 基址加变址
- 通用方法
- 说明:
- 存储器操作数尺寸是字节/字/双字
- 默认指令中的寄存器操作数的尺寸决定了存储器操作数的尺寸;但也可以显式指定存储器操作数尺寸
修饰符 | 功能 |
---|---|
WORD PTR | 指定尺寸为“字” |
BYTE PTR | 指定尺寸为“字节” |
DWORD PTR | 指定尺寸为“双字” |
(1)直接寻址方式
直接寻址方式
:操作数在存储器中,指令直接包含操作数所在的存储单元的有效地址。- 示例:
1 | MOV ECX, [95480H] //源操作数采用直接寻址 |
即寻址和直接寻址的区别:
- 直接寻址中十六进制数表示地址,要到此地址取出操作数;立即寻址中表示操作数
- 直接寻址的地址要写在方括号
[]
中
注意:
- 直接寻址时,
[]
给出的是被取出数据的最低地址 - 按 “高高低低” 规则取出数据
- 直接寻址时,
(2)寄存器间接寻址方式
寄存器间接寻址
:操作数在存储器中,由八个32位通用寄存器之一给出操作数所在存储单元有效地址。寄存器间接寻址和寄存器寻址的区别:
- 寄存器间接的Reg名称出现在方括号
[]
中 - 寄存器间的Reg中存储的是操作数所在地址;寄存器寻址的Reg存储的是操作数
- 寄存器间接的Reg名称出现在方括号
注意:
- 操作数地址必须来自八个32位通用寄存器之一
示例:
1 | MOV EAX, [ESI] //源操作数寄存器间接寻址,ESI给出有效地址 |
(3)通用方式
存储单元的有效地址可以由三部分内容相加构成
- 一个32位基地址寄存器
- 一个可乘上比例因子
1/2/4/8
的32位变址寄存器 - 一个8/16/32位位移量
PS:可省去任意两部分
注意:
- 变址寄存器乘上的比例因子取值只能是
1/2/4/8
之一 - 三部分中可以任意省略。省略后的寻址方式又有不同名称,但都属于通用方式,前面提到的直接寻址方式和寄存器间接寻址方式也是属于通用方式
- 变址寄存器乘上的比例因子取值只能是
示意图:
示例:
寄存器相对寻址方式
:[寄存器名+偏移]
1
2
3MOV EAX, [EBX+12H] ;源操作数有效地址是EBX值加上12H
MOV [ESI-4], AL ;目的操作数有效地址是ESI值减去4
ADD DX, [ECX+5328H] ;源操作数有效地址是ECX值加上5328H基址+变址寻址
:[寄存器名+寄存器名]
1 | MOV EAX, [EBX+ESI] ;源操作数有效地址是EBX值加上ESI值 |
3. `基址+带放大因子的变址寻址`:`[寄存器名+寄存器名*放大因子+偏移]`
1 | MOV EAX, [ECX+EBX*4] ;EBX作为变址寄存器,放大因子是4 |
(4)补充
用 [address] 这样的方法从内存取值
- address是地址尾,也就是取出值的最低字节地址
- 存入寄存器时,低地址对应寄存器低位;高地址对应高位(“高高低低”规则)
- 初始化好的全局变量,占用内存空间是连续的
使用尺寸修饰符的示例:
关于存储器寻址的说明
- 缺省段寄存器
(1)如果基址寄存器不是EBP/ESP,缺省引用的段寄存器为DS
(2)如果基址寄存器是EBP/ESP,缺省引用的段寄存器为SS
(3)如果EBP作为变址寄存器(ESP不能做变址寄存器),缺省引用的段寄存器为DS - 有效地址
(1)无论存储器寻址方式具体是哪种,如果基址寄存器、变址 寄存器、比例因子、位移量这些算出来超过32位,只有低32位有效
- 缺省段寄存器
三、取有效地址指令LEA
名称 | LEA(取有效地址指令) |
---|---|
格式 | LEA REG,OPRD |
动作 | 把操作数OPRD的有效地址传送到REG |
合法值 | OPRD:存储器操作数; |
REG:16/32位通用寄存器 | |
注意 | 此指令不影响标志寄存器 |
此指令是取地址,和mov有本质区别 |
- 示例1:基本操作
1 | MOV EDI, 51234H //EDI=00051234H |
- 示例2:指针的实现
1 |
|
- 示例三:取一个double数据
1 |
|
- 示例四:妙用LEA和存储器取值,进行多项式计算
1 | //待翻译的c函数 |
评论
匿名评论隐私政策
TwikooValine
✅ 你无需删除空行,直接评论以获取最佳展示效果