IA-32处理器基本功能2

  


IA-32处理器基本功能 


  


2.4 段寄存器 
2.4.1 存储器分段 
2.4.2 逻辑地址 
2.4.3 段寄存器  
  


2.4.1 存储器分段 
.CPU能够通过其总线直接寻址访问的存储器被称为内存 
.每一个字节存储单元有一个唯一的地址,称之为物理地址 
.CPU的地址线数量决定了可产生的最大物理地址 




 n根地址线,可形成的最大物理地址是2n-1 


.所有可形成的物理地址的集合被称为物理地址空间 
Intel8086有20根地址线,物理地址的范围是0到FFFFF 
Intel80386有32根地址线,物理地址的范围是0到FFFFFFFF 




.物理地址空间 




物理地址空间大小不等于实际安装的物理内存大小 
物理地址空间大小不等于实际安装的物理内存大小  
  


2.4.1 存储器分段 


把地址空间划分为若干逻
辑段
对应存储空间被划分为若干存储段
其一是代码
其二是数据
其三是堆栈
. 为了有效地管理存储器,常常把地址空间划分为若干逻
辑段。对应存储空间被划分为若干存储段。逻辑段和存储
段是一致的。 
.一般说来,运行着的程序在存储器中映像有三部分组成: 
其一是代码,代码是要执行的指令序列 
其二是数据,数据是要处理加工的内容 
其三是堆栈,堆栈是按“先进后出”规则存取的区域 
.通常,代码、数据和堆栈分别占用不同的存储器段,相
应的段也就被称为代码段、数据段和堆栈段。 




.存储器分段 




 
  


2.4.1 存储器分段 
.可以按需要进行段的
划分。逻辑段与逻辑
段可以相连,也可以
不相连,还可以部分
重叠。 
.代码、数据和堆栈可
以在同一个逻辑段内,
占用不同区域。 




段E
段D
段C
段BXXXX0HXXXX0HXXXX0HXXXX0H
段AXXXX0H
.存储器分段 




 
  


2.4.2 逻辑地址 
某某段
某某单元
逻辑地址是二
维的

第一维给出某某段

第二维给出段内的某某单元
.在分段之后,程序中使用的某个存储单元总是属于某个段。
所以,可以采用某某段某某单元的方式来表示存储单元。 
.在程序中用于表示存储单元的地址被称为逻辑地址。 
.由于采用分段存储管理方式,程序中使用的逻辑地址是二
维的,第一维给出某某段,第二维给出段内的某某单元。 




.逻辑地址 




如何表示某某段?如何表示段内的某某单元? 
如何表示某某段?如何表示段内的某某单元?  
  


2.4.2 逻辑地址 
段号

段内地址 
段内地址就是段内偏移
段号

偏移 
.二维的逻辑地址可以表示为: 
段号∶段内地址 
.存储单元的物理地址与所在段的起始地址的差值被称为
段内偏移,简称为偏移。段内地址就是段内偏移,也就
是偏移。于是,二维的逻辑地址可以表示为: 
段号∶偏移 




.逻辑地址 




 
  


2.4.2 逻辑地址 
段号

偏移 
段值
段选择子
.二维的逻辑地址: 
段号∶偏移 
.在实方式和保护方式下,都通过偏移指定段内的某某单
元。在实方式下,段号是段值;在保护方式下,段号则
是段选择子。 




.逻辑地址 




 
在第6章介绍段值 
在第9章介绍段选择子  
  


2.4.2 逻辑地址 
物理地址 

段起始地址 
+ 
偏移 
由段号可
以得到段起始地址
由段号得到段起始地址

再加上偏移
.获得物理地址 
物理地址 = 段起始地址 + 偏移 
.在实方式下,由段值可以得到段起始地址;在保护方式
下,根据选择子可以得到段起始地址。总之,由段号可
以得到段起始地址。二维的逻辑地址可以转换成一维的
物理地址。逻辑地址转换为物理地址的过程可归纳为:
由段号得到段起始地址,再加上偏移。 




.转换成物理地址 




 
保护方式下,物理地址是32位,段起始地址是32位,偏移是32位; 
在实方式下,物理地址是20位,段起始地址是20位,偏移是16位。  
  


2.4.2 逻辑地址 
物理地址 

段起始地址 
+ 
偏移 
.
如果整个程序只有一个段

则二维的逻辑地址退化成一


由于段起始地址完全相同

偏移就决定一切
。 
.获得物理地址 
物理地址 = 段起始地址 + 偏移 
.如果整个程序只有一个段,则二维的逻辑地址退化成一
维。由于段起始地址完全相同,偏移就决定一切。 




.转换成物理地址 




VC2010
环境中就是这样。 
某种意义上,嵌入汇编只考虑偏移。 
VC2010环境中就是这样。 
某种意义上,嵌入汇编只考虑偏移。  
  


2.4.3 段寄存器 
只需通过偏移便可指定要访问的
存储单元
当前使用段的段号存放在段寄存器
.在一个已确定的段内,只需通过偏移便可指定要访问的
存储单元。程序中绝大部分涉及存储器访问的指令都只给
出偏移。 
.逻辑地址中的段号(段值或者段选择子)存放在哪里呢?
答案是,当前使用段的段号存放在段寄存器(Segment 
Registers)中。 
.段寄存器是16位的。在实方式下,用于存放16位的段
值;在保护方式下,用于存放16位的段选择子。 




.段寄存器 




 
  


2.4.3 段寄存器 
指定当前代码段,
指定当前堆栈段 
.
一般情况下,
指定当前数据段 
.Intel 8086处理器有四个段寄存器 
CS: 代码段(Code Segment)寄存器 
SS: 堆栈段(Stack Segment)寄存器 
DS: 数据段(Data Segment)寄存器 
ES: 附加段(Extra Segment)寄存器 
.从80386处理器开始,增加了两个段寄存器 




 FS: 附加段寄存器 


 GS: 附加段寄存器 


.CS指定当前代码段,SS指定当前堆栈段 
.一般情况下,DS指定当前数据段 
.附加段寄存器ES、FS、GS也可用于指定数据段 




.段寄存器 




 
  


2.4.3 段寄存器 
.
如果由段寄存器给出的段起始地址是
0
,那么偏移就相
当于物理地址。 
.在访问存储单元时,CPU先根据对应的段寄存器得到段
起始地址,再加上相应的偏移,形成存储单元的物理地址。 
.如果程序的代码段、数据段、堆栈段占用同一个存储段,
那么代码段寄存器CS、数据段寄存器DS和堆栈段寄存器
SS等指定同一个存储段,给出相同的段起始地址。 
.如果由段寄存器给出的段起始地址是0,那么偏移就相
当于物理地址。 




.段寄存器 




 
  


2.5 寻址方式 
立即寻址、寄存器
寻址和存储器寻址
.把表示指令中操作数所在的方法称为寻址方式 
.CPU常用的寻址方式可分为三大类:立即寻址、寄存器
寻址和存储器寻址,此外还有固定寻址和I/O端口寻址等 




 
  


2.5 寻址方式 
2.5.1 立即寻址方式和寄存器寻址方式 
2.5.2 32位的存储器寻址方式 
2.5.3 取有效地址指令  
  


2.5.1 立即寻址方式和寄存器寻址方式 
.操作数本身就包含在指令中,直接作为指令的一部分给
出。把这种寻址方式称为立即寻址方式。 
.把这样的操作数称为立即数。 




.立即寻址方式 




MOV EAX, 
12345678

;

EAX
寄存器赋初值 
ADD BX, 
1234
H ;

BX
寄存器加上值
1234H 
SUB CL, 

;

CL
寄存器减去值

MOV EDX, 

;
源操作数是
32
位 
MOV DX, 

;
源操作数是
16
位 
MOV DL, 

;
源操作数是
8
位 
MOV EAX, 12345678H ;给EAX寄存器赋初值 
ADD BX, 1234H ;给BX寄存器加上值1234H 
SUB CL, 2 ;从CL寄存器减去值2 
MOV EDX, 1 ;源操作数是32位 
MOV DX, 1 ;源操作数是16位 
MOV DL, 1 ;源操作数是8位  
  


2.5.1 立即寻址方式和寄存器寻址方式 
采用

高高低低

目的操作数不能
采用立即寻址方式
。 
立即寻址方式
不需要再到存储器中去取该操作数
.立即数作为指令的一部分,跟在操作码后存放在代码段。 
.如果立即数由多个字节构成,那么在作为指令的一部分
存储时,也采用“高高低低”规则。 
.只有源操作数才可采用立即寻址方式,目的操作数不能
采用立即寻址方式。 
.由于立即寻址方式的操作数是立即数,包含在指令中,
所以执行指令时,不需要再到存储器中去取该操作数了。 




.立即寻址方式 




 
  


2.5.1 立即寻址方式和寄存器寻址方式 
.操作数在CPU内部的寄存器中,指令中指定寄存器。
把这种寻址方式称为寄存器寻址方式。 
.可以是8个32位的通用寄存器 
.可以是8个16位的通用寄存器 
.可以是8个8位的通用寄存器 




.寄存器寻址方式 




EBP
ESP
EAX
EDX
DI
BX
AH
DH 
MOV EBP, ESP ;把ESP之值送到EBP 
ADD EAX, EDX ;把EAX之值与EDX之值相加,结果送到EAX 
SUB DI, BX ;把DI之值减去BX之值,结果送到DI 
XCHG AH, DH ;交换AH与DH之值  
  


2.5.1 立即寻址方式和寄存器寻址方式 
采用寄存器寻址方式的指令执行速度较快 
.由于操作数在寄存器中,不需要通过访问存储器来取得
操作数,所以采用寄存器寻址方式的指令执行速度较快 




.寄存器寻址方式 




 
  


2.5.2 32位的存储器寻址方式 
.
采用
32
位的存储器寻址方式

能够给出
32
位的偏移
.当指令的操作数在存储单元时,指定存储单元就指定了
操作数。 
.在某个段内,通过偏移就能够指定存储单元。一般情况
下访问存储单元的指令只需要给出存储单元的偏移。 
.存储器寻址方式指,给出存储单元偏移的方式。 
.采用32位的存储器寻址方式,能够给出32位的偏移。 
.常常把要访问的存储单元的段内偏移称为有效地址
EA(Effective Address)。在32位存储器寻址方式下,存储
单元的有效地址可达32位。 




.32位的存储器寻址方式 




 
  


2.5.2 32位的存储器寻址方式 
有多种存储器寻
址方式
.为了灵活方便地访问存储器,IA-32系列CPU提供了多
种表示存储单元偏移的方式。换句话说,有多种存储器寻
址方式。 
.直接寻址 
.寄存器间接 
.寄存器相对 
.基址加变址 
.通用 








.32位的存储器寻址方式 




 
  


2.5.2 32位的存储器寻址方式 
.操作数在存储器中,指令直接包含操作数所在存储单元
的有效地址。把这种寻址方式称为直接寻址方式。 




.直接寻址方式 




MOV ECX, 
[95480H] 
;
源操作数采用直接寻址 
MOV 
[9547CH]
, DX ;
目的操作数采用直接寻址 
ADD BL, 
[95478H] 
;
源操作数采用直接寻址 
MOV ECX, [95480H] ;源操作数采用直接寻址 
MOV [9547CH], DX ;目的操作数采用直接寻址 
ADD BL, [95478H] ;源操作数采用直接寻址 
立即寻址和直接寻址有本质区别! 
直接寻址的地址要放在方括号中,在源程序中,往往用变量名表示。  
  


2.5.2 32位的存储器寻址方式 
.示例 
假设数据段和代码段重叠, 
段起始地址都是0。 
有效地址为01234567H的 
双字存储单元中内容是 
4F5A9687H。 




.直接寻址方式 




..
op67..
96DSEAX
存储器
..
..
0123456701234567012345675A
数据段
代码段+
AHAL45230187965A4F874F0000000000000000MOV EAX

[01234567H] 
MOV EAX,[01234567H]  
  


2.5.2 32位的存储器寻址方式 
.操作数在存储器中,由八个32位的通用寄存器之一给出
操作数所在存储单元的有效地址。把这种通过寄存器间接
给出存储单元有效地址的方式称为寄存器间接寻址方式。 




.寄存器间接寻址方式 




MOV EAX, 
[ESI] 
;
源操作数寄存器间接寻址,
ESI
给出有效地址 
MOV 
[EDI]
, CL ;
目的操作数寄存器间接寻址,
EDI
给出有效地
址 
SUB DX, 
[EBX] 
;
源操作数寄存器间接寻址,
EBX
给出有效地址 
MOV EAX, [ESI] ;源操作数寄存器间接寻址,ESI给出有效地址 
MOV [EDI], CL ;目的操作数寄存器间接寻址,EDI给出有效地
址 
SUB DX, [EBX] ;源操作数寄存器间接寻址,EBX给出有效地址  
  


2.5.2 32位的存储器寻址方式 
.寄存器间接寻址方式 




[ESI]
EAX
ESI
EAX
MOV [ESI], EAX ;目的操作数采用寄存器间接寻址方式 


MOV ESI, EAX ;目的操作数采用寄存器寻址方式 


寄存器间接寻址与寄存器寻址有本质区别! 
寄存器间接寻址的寄存器出现在方括号中。 
寄存器间接寻址方式中,给出操作数所在存储单元有效地址的寄
存器,相当于
C
语言中的指针变量,它含有要访问存储单元的地址 
寄存器间接寻址方式中,给出操作数所在存储单元有效地址的寄
存器,相当于C语言中的指针变量,它含有要访问存储单元的地址。  
  


2.5.2 32位的存储器寻址方式 
基地址
寄存器 
变址寄存器 
位移
量 
.存储单元的有效地址可以由三部分内容相加构成: 
.一个32位的基地址寄存器 
.一个可乘上比例因子1、2、4或8的32位变址寄存器 
.一个8位、16位或32位的位移量 
.这三部分可省去任意的两部分 








.32位存储器寻址方式的通用表示 




基址
EAXEBXECXEDXESPEBPESIEDI+
EAXEBXECXEDXEBPESIEDI1248X

8位
16位
32位
+
变址比例位移量
EA = 
  


2.5.2 32位的存储器寻址方式 
.支持灵活的32位有效地址的存储器寻址方式 




.32位存储器寻址方式的通用表示 




基址寄存器
变址寄存器
8个32位通用寄存器都可以作为基址寄存器; 
除ESP寄存器外,其他7个通用寄存器都可以作为变址寄存器。 
补码表示, 
如8位或16位, 
计算时被扩展成32位  
  


2.5.2 32位的存储器寻址方式 
.示例 




.32位存储器寻址方式的通用表示 




MOV EAX, 
[EBX+12H] 
;
源操作数有效地址是
EBX
值加上
12H 
MOV 
[ESI
-
4]
, AL ;
目的操作数有效地址是
ESI
值减去

ADD DX, 
[ECX+5328H] 
;
源操作数有效地址是
ECX
值加上
5328H 
MOV EAX, [EBX+12H] ;源操作数有效地址是EBX值加上12H 
MOV [ESI-4], AL ;目的操作数有效地址是ESI值减去4 
ADD DX, [ECX+5328H] ;源操作数有效地址是ECX值加上5328H 
寄存器相对寻址方式  
  


2.5.2 32位的存储器寻址方式 
.示例 




.32位存储器寻址方式的通用表示 




MOV EAX, 
[EBX+ESI] 
;
源操作数有效地址是
EBX
值加上
ESI
值 
SUB 
[ECX+EDI]

AL ;
目的操作数有效地址是
ECX
值加上
EDI
值 
XCHG 
[EBX+ESI]
, DX ;
目的操作数有效地址是
EBX
值加上
ESI
值 
MOV EAX, [EBX+ESI] ;源操作数有效地址是EBX值加上ESI值 
SUB [ECX+EDI], AL ;目的操作数有效地址是ECX值加上EDI值 
XCHG [EBX+ESI], DX ;目的操作数有效地址是EBX值加上ESI值 
基址加变址寻址方式  
  


2.5.2 32位的存储器寻址方式 
.示例 




.32位存储器寻址方式的通用表示 




MOV EAX, 
[ECX+EBX*4] 
;EBX
作为变址寄存器,放大因子是

MOV 
[EAX+ECX*2]
, DL ;ECX
作为变址寄存器,放大因子是

ADD EAX, 
[EBX+ESI*8] 
;ESI
作为变址寄存器,放大因子是

SUB ECX, 
[EDX+EAX
-
4] 
;EAX
作为变址寄存器,放大因子是

MOV EBX, 
[EDI+EAX*4+300H] 
;EAX
作为变址寄存器,放大因子是

MOV EAX, [ECX+EBX*4] ;EBX作为变址寄存器,放大因子是4 
MOV [EAX+ECX*2], DL ;ECX作为变址寄存器,放大因子是2 
ADD EAX, [EBX+ESI*8] ;ESI作为变址寄存器,放大因子是8 
SUB ECX, [EDX+EAX-4] ;EAX作为变址寄存器,放大因子是1 
MOV EBX, [EDI+EAX*4+300H] ;EAX作为变址寄存器,放大因子是4 
基址加带放大因子的变址寻址方式  
  


2.5.2 32位的存储器寻址方式 


.示例 
假设由DS得段起始地址是0,
寄存器EDI的内容是
51234H,寄存器EAX的内
容是6,并且有效地址为
0005154CH的双字存储单
元的内容是44434241H。 




MOV EBX

[EDI+EAX*4+300H] 
MOV EBX,[EDI+EAX*4+300H] 
.32位存储器寻址方式的通用表示 




41..
4100000000EBX
存储器
..
..
42BH..
EDI =00051234EAX*4 = 000000180005154CBL+ 000003004243444443 
  


2.5.2 32位的存储器寻址方式 


.演示程序dp27 




#include <
stdio.h

int 
vari 
= 0x12345678; //
定义整型变量。设有效地址为

char buff[] = "ABCDE"; //
定义字符数组。设首元素有效地址为

int 
main( ) 

int 
dv1, dv2, dv3, dv4; //
定义
4
个整型变量 
_
asm 

//
嵌入汇编 
。。。。。。 

printf
("dv1=%08XH
\
n",dv1); //
显示为
dv1=12345678H 
printf
("dv2=%08XH
\
n",dv2); //
显示为
dv2=41123456H 
printf
("dv3=%08XH
\
n",dv3); //
显示为
dv3=41121234H 
printf
("dv4=%08XH
\
n",dv4); //
显示为
dv4=41121244H 
return 0; 

#include <stdio.h> 
int vari = 0x12345678; //定义整型变量。设有效地址为x 
char buff[] = "ABCDE"; //定义字符数组。设首元素有效地址为y 
int main( ) 
{ int dv1, dv2, dv3, dv4; //定义4个整型变量 
_asm { //嵌入汇编 
。。。。。。 

printf("dv1=%08XH\n",dv1); //显示为dv1=12345678H 
printf("dv2=%08XH\n",dv2); //显示为dv2=41123456H 
printf("dv3=%08XH\n",dv3); //显示为dv3=41121234H 
printf("dv4=%08XH\n",dv4); //显示为dv4=41121244H 
return 0; 

演示32位存储器寻址方式使用, 
演示字节存储单元与双字存储单元关系  
  


2.5.2 32位的存储器寻址方式 


.演示程序dp27 




_
asm 

LEA EBX, 
vari 
//
把变量
vari
的有效地址
x
送到
EBX 
MOV EAX, [EBX] //
把有效地址为
x
的双字
(12345678H)
送到
EAX 
MOV dv1, EAX 
MOV EAX, [EBX+1] //
把有效地址
x+1
的双字
(41123456H)
送到
EAX 
MOV dv2, EAX 

MOV ECX, 2 
MOV AX, [EBX+ECX] //
把有效地址为
x+2
的字
(1234H)
送到
AX 
MOV dv3, EAX 

MOV AL, [EBX+ECX*2+3] //
把有效地址为
x+7
的字节
(44H)
送到
AL 
MOV dv4, EAX 

_asm { 
LEA EBX, vari //把变量vari的有效地址x送到EBX 
MOV EAX, [EBX] //把有效地址为x的双字(12345678H)送到EAX 
MOV dv1, EAX 
MOV EAX, [EBX+1] //把有效地址x+1的双字(41123456H)送到EAX 
MOV dv2, EAX 

MOV ECX, 2 
MOV AX, [EBX+ECX] //把有效地址为x+2的字(1234H)送到AX 
MOV dv3, EAX 

MOV AL, [EBX+ECX*2+3] //把有效地址为x+7的字节(44H)送到AL 
MOV dv4, EAX 

演示32位存储器寻址方式使用, 
演示字节存储单元与双字存储单元关系  
  


2.5.2 32位的存储器寻址方式 


.演示程序dp27 




_
asm 

LEA EBX, 
vari 
MOV EAX, [EBX] 
MOV dv1, EAX 
MOV EAX, [EBX+1] 
MOV dv2, EAX 

MOV ECX, 2 
MOV AX, [EBX+ECX] 
MOV dv3, EAX 

MOV AL, [EBX+ECX*2+3] 
MOV dv4, EAX 

_asm { 
LEA EBX, vari 
MOV EAX, [EBX] 
MOV dv1, EAX 
MOV EAX, [EBX+1] 
MOV dv2, EAX 

MOV ECX, 2 
MOV AX, [EBX+ECX] 
MOV dv3, EAX 

MOV AL, [EBX+ECX*2+3] 
MOV dv4, EAX 

424100000000
存储器
..
12x43444534785600..
yx+1x+2y+3, x+7y+1, x+5y+4, x+8x+3y+2, x+6varibuff[ ] 
  


2.5.2 32位的存储器寻址方式 


.
存储器
操作数的尺寸可以是字节

字或者双字
指令中的寄存器操作数的尺寸就决定了存储器
操作数的尺寸
少数情况下

需要显式地指定存储器操
作数的尺寸
.如果指令的操作数允许是存储器操作数,那么各种存储
器寻址方式都适用。 
.存储器操作数的尺寸可以是字节、字或者双字。 
.在某条具体的指令中,如果有存储器操作数,那么其尺
寸是确定的。在大多数情况下,存储器操作数的尺寸是一
目了然的,因为通常要求一条指令中的多个操作数的尺寸
一致,所以指令中的寄存器操作数的尺寸就决定了存储器
操作数的尺寸。在少数情况下,需要显式地指定存储器操
作数的尺寸。 




.关于存储器寻址方式的说明 




 
  


2.5.2 32位的存储器寻址方式 
.演示程序dp28 




#include <
stdio.h

int 
var1 = 0x33333333, var2 = 0x44444444, var3 = 0x55555555; 
int 
bufi
[3] = {0x66666666, 0x77777777, 0x88888888}; 
int 
main() 

_
asm 
{ //
嵌入汇编代码 
MOV var1, 9 //
双字
存储单元 
MOV 
WORD PTR 
var2, 9 //

存储单元 
MOV 
BYTE PTR 
var3, 9 //
字节
存储单元 

printf
("%08XH
\
n",var1); //
显示为
00000009H 
printf
("%08XH
\
n",var2); //
显示为
44440009H 
printf
("%08XH
\
n",var3); //
显示为
55555509H 

#include <stdio.h> 
int var1 = 0x33333333, var2 = 0x44444444, var3 = 0x55555555; 
int bufi[3] = {0x66666666, 0x77777777, 0x88888888}; 
int main() 

_asm { //嵌入汇编代码 
MOV var1, 9 //双字存储单元 
MOV WORD PTR var2, 9 //字存储单元 
MOV BYTE PTR var3, 9 //字节存储单元 

printf("%08XH\n",var1); //显示为00000009H 
printf("%08XH\n",var2); //显示为44440009H 
printf("%08XH\n",var3); //显示为55555509H 

演示显式地标明存储器操作数的尺寸  
  


2.5.2 32位的存储器寻址方式 


.演示程序dp28 




 
_
asm 
{ //
嵌入汇编代码 
LEA EBX, 
bufi 
//

bufi
的有效地址送到
EBX 
MOV 
DWORD PTR 
[EBX], 5 //
双字
存储单元 
MOV 
WORD PTR 
[EBX+4], 5 //

存储单元 
MOV 
BYTE PTR 
[EBX+8], 5 //
字节
存储单元 

printf
("%08XH
\
n", 
bufi
[0]); //
显示为
00000005H 
printf
("%08XH
\
n", 
bufi
[1]); //
显示为
77770005H 
printf
("%08XH
\
n", 
bufi
[2]); //
显示为
88888805H 
return 0; 

_asm { //嵌入汇编代码 
LEA EBX, bufi //把bufi的有效地址送到EBX 
MOV DWORD PTR [EBX], 5 //双字存储单元 
MOV WORD PTR [EBX+4], 5 //字存储单元 
MOV BYTE PTR [EBX+8], 5 //字节存储单元 

printf("%08XH\n", bufi[0]); //显示为00000005H 
printf("%08XH\n", bufi[1]); //显示为77770005H 
printf("%08XH\n", bufi[2]); //显示为88888805H 
return 0; 

演示显式地标明存储器操作数的尺寸  
  


2.5.2 32位的存储器寻址方式 


.如果基址寄存器不是EBP或者ESP,那么缺省引用的段
寄存器是DS;如果基址寄存器是EBP或者ESP,那么缺省
引用的段寄存器是SS。当EBP作为变址寄存器使用(ESP
不能作为变址寄存器使用)时,缺省引用的段寄存器仍然
是DS。 
.无论存储器寻址方式简单或者复杂,如果由基址寄存器、
带比例因子的变址寄存器和位移量这三部分相加所得超过
32位,那么有效地址仅为低32位。 




.关于存储器寻址方式的说明 




 
  


2.5.3 取有效地址指令 
.取有效地址指令 
.取有效地址指令的应用 




 
  


2.5.3 取有效地址指令 


.取有效地址指令 




.该指令把操作数OPRD的有效地址传送到寄存器REG。 




.取有效地址(Load Effective Address)指令的一般格式 




LEA REG,OPRD 


注意: 
源操作数
OPRD
必须是一个存储器操作数, 
目的操作数
REG
必须是一个
16
位或者
32
位的通用寄存器。 
注意: 
源操作数OPRD必须是一个存储器操作数, 
目的操作数REG必须是一个16位或者32位的通用寄存器。  
  


2.5.3 取有效地址指令 
.取有效地址指令 




 
MOV EDI, 51234H ;EDI=00051234H 
MOV EAX, 6 ;EAX=00000006H 
LEA ESI, [EDI+EAX] ;ESI=0005123AH 
LEA ECX, [EAX*4] ;ECX=00000018H 
LEA EBX, [EDI+EAX*4+300H] ;EBX=0005154CH 
MOV EDI, 51234H ;EDI=00051234H 
MOV EAX, 6 ;EAX=00000006H 
LEA ESI, [EDI+EAX] ;ESI=0005123AH 
LEA ECX, [EAX*4] ;ECX=00000018H 
LEA EBX, [EDI+EAX*4+300H] ;EBX=0005154CH 
.使用举例 




LEA
指令与
MOV
指令有本质上的区别! 
LEA指令与MOV指令有本质上的区别!  
  


.演示程序dp29 




#include <
stdio.h

char 
chx

chy
; //
全局字符变量 
int 
main( ) 

char 
*
p1, 
*
p2; //
两字符型指针变量 
//
嵌入汇编代码之一 
_
asm 

LEA EAX, 
chx 
//
取变量
chx
的存储单元有效地址 
MOV p1, EAX //
送到指针变量
p1 
LEA EAX, 
chy 
//
取变量
chy
的存储单元有效地址 
MOV p2, EAX //
送到指针变量
p2 

#include <stdio.h> 
char chx, chy; //全局字符变量 
int main( ) 

char *p1, *p2; //两字符型指针变量 
//嵌入汇编代码之一 
_asm { 
LEA EAX, chx //取变量chx的存储单元有效地址 
MOV p1, EAX //送到指针变量p1 
LEA EAX, chy //取变量chy的存储单元有效地址 
MOV p2, EAX //送到指针变量p2 

p1 = &
chx

p2 = &
chy

高级语言中的指针本质 
p1 = &chx; 
p2 = &chy; 
2.5.3 取有效地址指令  
  


.演示程序dp29 




 
printf
("Input:"); //
提示 
scanf
("%c", p1); //
键盘输入一个字符 
//
嵌入汇编代码之二 
_
asm 

MOV ESI, p1 //
取回变量
chx
的有效地址 
MOV EDI, p2 //
取回变量
chy
的有效地址 
MOV AL, [
ESI
] //
取变量
chx
之值 
MOV [
EDI
], AL //
送到变量
chy
中 

printf
("ASCII:%02XH
\
n", *p2); //
显示之 
return 0; 

printf("Input:"); //提示 


 scanf("%c", p1); //键盘输入一个字符 


 //嵌入汇编代码之二 


 _asm { 


 MOV ESI, p1 //取回变量chx的有效地址 


 MOV EDI, p2 //取回变量chy的有效地址 


 MOV AL, [ESI] //取变量chx之值 


 MOV [EDI], AL //送到变量chy中 


 } 


 printf("ASCII:%02XH\n", *p2); //显示之 


 return 0; 





2.5.3 取有效地址指令 
寄存器作为指针 
寄存器作为指针 temp = *p1; 
*p2 = temp; 
temp = *p1; 
*p2 = temp;  
  


.演示程序dp210 




#include <
stdio.h

int 
iarr
[5] = {55, 87, 
-
23, 89, 126}; //
整型数组 
double 
darr
[5] = {9.8, 2.77, 3.1415926, 1.414, 1.73278}; 
//
双精度浮点数组 
int 
main( ) 

int 
ival
; //
整型变量 
double 
dval
; //
双精度浮点 
//
嵌入汇编 
_
asm 

。。。。。。 

printf
("
iVAL
=%d
\
n",
ival
); //
显示为
iVAL
=89 
printf
("
dVAL
=%.8f
\
n",
dval
); //
显示为
dVAL
=3.14159260 
return 0; 

#include <stdio.h> 
int iarr[5] = {55, 87, -23, 89, 126}; //整型数组 
double darr[5] = {9.8, 2.77, 3.1415926, 1.414, 1.73278}; 
//双精度浮点数组 
int main( ) 
{ int ival; //整型变量 
double dval; //双精度浮点 
//嵌入汇编 
_asm { 
。。。。。。 

printf("iVAL=%d\n",ival); //显示为iVAL=89 
printf("dVAL=%.8f\n",dval); //显示为dVAL=3.14159260 
return 0; 

2.5.3 取有效地址指令 


演示32位寻址方式 
演示取有效地址指令  
  


.演示程序dp210 




 
_
asm 

LEA EBX, 
iarr 
//
把整型数组首元素的有效地址送
EBX 
MOV ECX, 3 
MOV EDX, [EBX+ECX*4] //
取出
iarr
的第
4
个元素 
MOV 
ival
, EDX 

LEA ESI, 
darr 
//
把浮点数组首元素的有效地址送
ESI 
LEA EDI, 
dval 
//
把变量
dval
的有效地址送
EDI 
MOV ECX, 2 
MOV EAX, [ESI+ECX*8] //

darr
的第
3
个元素的低双字 
MOV EDX, [ESI+ECX*8+4] //

darr
的第
3
个元素的高双字 
MOV [EDI], EAX //
保存低双字 
MOV [EDI+4], EDX //
保存高双字 

_asm { 
LEA EBX, iarr //把整型数组首元素的有效地址送EBX 
MOV ECX, 3 
MOV EDX, [EBX+ECX*4] //取出iarr的第4个元素 
MOV ival, EDX 

LEA ESI, darr //把浮点数组首元素的有效地址送ESI 
LEA EDI, dval //把变量dval的有效地址送EDI 
MOV ECX, 2 
MOV EAX, [ESI+ECX*8] //取darr的第3个元素的低双字 
MOV EDX, [ESI+ECX*8+4] //取darr的第3个元素的高双字 
MOV [EDI], EAX //保存低双字 
MOV [EDI+4], EDX //保存高双字 

2.5.3 取有效地址指令 
演示32位寻址方式 
演示取有效地址指令  
  


2.5.3 取有效地址指令 


.取有效地址指令的应用 




int 
_
fastcall 
cf211(
int 
x, 
int 
y) //
由寄存器传参数 

return ( 2 * x + 5 * y + 100 ); 

int _fastcall cf211(int x, int y) //由寄存器传参数 





 return ( 2 * x + 5 * y + 100 ); 





编译器生成的目标代码 
(速度最大化) 
编译器生成的目标代码 
(速度最大化) 
ECX
传递

EDX
传递

ECX传递x 
EDX传递y 
通过高级语言源程序的目标代码来说明
LEA
指令的妙用。 
通过高级语言源程序的目标代码来说明LEA指令的妙用。 
;
函数
cf211
目标代码(使速度最大化) 
lea 
eax
, DWORD PTR [
edx+edx
*4+100] ;DWORD PTR
表示双字存储单元 
lea 
eax
, DWORD PTR [
eax+ecx
*2] 
ret 
;函数cf211目标代码(使速度最大化) 


 lea eax, DWORD PTR [edx+edx*4+100] ;DWORD PTR表示双字存储单元 


 lea eax, DWORD PTR [eax+ecx*2] 


 ret 


 
  


2.5.3 取有效地址指令 


.取有效地址指令的应用 




int 
_
fastcall 
cf212(
int 
x, 
int 
y) //
由寄存器传参数 

return ( 3 * x + 7 * y + 200 ); 

int _fastcall cf212(int x, int y) //由寄存器传参数 





 return ( 3 * x + 7 * y + 200 ); 





编译器生成的目标代码 
(速度最大化) 
编译器生成的目标代码 
(速度最大化) 
ECX
传递

EDX
传递

ECX传递x 
EDX传递y 
通过高级语言源程序的目标代码来说明
LEA
指令的妙用。 
通过高级语言源程序的目标代码来说明LEA指令的妙用。 
;
函数
cf212
目标代码(使速度最大化) 
lea 
eax
, DWORD PTR [
ecx+ecx
*2] ; 
eax
=3*x 
lea 
ecx
, DWORD PTR [
edx
*8] ; 
ecx
=8*y 
sub 
ecx

edx 

ecx
=7*y 
lea 
eax
, DWORD PTR [eax+ecx+200] ; 
eax
=3*x+7*y+200 
ret 
;函数cf212目标代码(使速度最大化) 


 lea eax, DWORD PTR [ecx+ecx*2] ; eax=3*x 


 lea ecx, DWORD PTR [edx*8] ; ecx=8*y 


 sub ecx, edx ; ecx=7*y 


 lea eax, DWORD PTR [eax+ecx+200] ; eax=3*x+7*y+200 


 ret 


 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值