汇编语言(三)—— 寻址方式
数据寻址
指令由操作码和操作数两部分组成。操作码用助记符表示处理器要执行的操作;操作数是指令执行的参与者,需要通过地址指示。
数据或指令通过地址访问。
寻址方式:寻找有效地址的方法。
- 数据寻址:寻找指令执行过程中访问所需要的操作数地址;
① 数据保存在指令代码中:立即数寻址,用常量表达。
② 操作数来自寄存器:寄存器寻址,用寄存器名表示。
③ 数据来自主存储器:存储器寻址,用存储器地址代表。
存储器寻址分为三类:直接寻址;寄存器间接寻址;寄存器相对寻址。
④ 操作数来自外设(接口):外设I / / /O地址表示,用I / / /O地址代表。
外设I / / /O寻址分为两类:直接寻址;间接寻址。 - 指令寻址:一条指令执行后确定执行的下一条指令的位置。
立即数寻址
数据已经保存在指令代码中。
-
操作数紧跟操作码,是机器代码的一部分,称为立即数(Immediate)。
mov eax, 33221100H ; 机器代码: B8 00 11 22 33 ; 操作码: B8 ; 立即数: 33221100 EAX: 32 位寄存器
-
立即数形式:
① 十六进制常数;
② 字符(ASCII码值);
③ 十进制负数(补码);
④ 符号常量;
⑤ 常量表达式;
⑥ 变量的偏移地址(offset 变量名);
⑦ 标号的偏移地址(语句标号:代码段使用标号名代表其偏移地址)。 -
立即数的类型:由对应的寄存器或变量类型决定,本身没有类型。
-
立即数寻址方式只用于源操作数,常用来给寄存器和存储单元赋值,用常量形式直接表达。
-
立即数符号表示:i8, i16, i32, imm.
寄存器寻址
数据来自CPU内部的寄存器。
-
操作数存放在处理器的内部寄存器,用寄存器名表示它的内容。
-
32位通用寄存器:EAX、EBX、ECX、EDX、ESI、EDI、EBP、ESP
-
16位通用寄存器:AX、BX、CX、DX、SI、DI、BP、SP
-
8位通用寄存器:AH、AL、BH、BL、CH、CL、DH、DL
mov ebx, eax ; 目的操作数和源操作数均采用寄存器寻址 ; 源操作数在寄存器EAX中,目的操作数在寄存器EBX中。
-
寄存器的类型:
① 8位寄存器的类型是字节型;
② 16位寄存器的类型是字型;
③ 32位寄存器的类型是双字型。mov al, ah ; 源操作数与目的操作数均是寄存器寻址 mov bx, ax mov ebx, eax mov dx, ds ; ds 为数据段寄存器,16位(专用寄存器) mov es, dx ; es 为数据段寄存器,16位(专用寄存器) mov al, 12 ; 目的操作数是寄存器地址 mov bx, 12 mov bvar, cl ; 源操作数是寄存器地址 , 字节类型 mov wvar, cx ; 字类型 mov dvar, ecx ; 双字类型
-
目的操作数和源操作数类型需要匹配,即一条语句中,两个操作数的类型必须一致。
-
寄存器符号表示:r8, r16, r32, reg.
存储器寻址
数据来自主存储器。
- 数据在主存中,通过存储器地址指示。
- 指令代码表达形式地址,由形式地址结合规则经过计算得到\有效地址EA(Effective Address)(偏移地址),处理器将有效地址转换为物理地址(通过物理地址总线)访问存储单元。
- 存储器地址使用逻辑地址(逻辑地址 = 段基地址 : 偏移地址)
段寄存器指示段基地址(绝大部分情况使用默认规定,段超越时需要显式说明);
偏移地址由各种存储器寻址方式计算(有效地址EA)。 - 段寄存器指示段基地址:
① 默认规定:读取指令一定是代码段(CS),堆栈操作针对堆栈段(SS),读写数据默认在数据段(DS)。
② 显示说明(段超越):使用段超越指令前缀(段寄存器后面跟冒号,如CS: DS: SS: ES: FS: GS:)
- 段存储器的默认和超越:
① 不可超越:
读取指令默认CS段,偏移地址为EIP;
堆栈操作默认SS段,偏移地址为ESP;
串指令的目的操作数默认ES段,偏移地址为EDI。
②\可超越:
一般的数据访问默认DS段,可超越(CS, ES, SS, FS, GS),偏移地址为有效地址;
EBP / / /ESP基址的数据访问默认SS段,可超越(CS, ES,DS, FS, GS),偏移地址为有效地址;
串指令的源操作数默认DS段,可超越(CS. ES, SS, FS, GS),偏移地址为ESI。 - 32位有效地址的组成:基址寄存器 + 变址寄存器
×
\times
× 比例 + 位移量
基址寄存器:任何8个32位通用寄存器之一。
变址寄存器:除ESP外的任何32位通用寄存器之一。
比例:1,2,4,8。
位移量:8或32位有符号数。
e.g. EBX + ESI * 4 + 80H - 16位有效地址的组成:基址寄存器 + 变址寄存器 + 位移量
基址寄存器:BX或BP寄存器。
变址寄存器:SI或DI寄存器。
位移量:8或16位有符号数。
e.g. BX + SI + 80H - 存储器单元符号表示:m8, m16, m32, mem.
存储器的直接寻址
有效地址只有位移量部分,直接包含在指令代码中,用变量名(或加中括号)表示偏移地址。
mov ecx, count ; count :数据段 405000H
mov ecx, [count]
mov ecx, DS:[405000H]
; 指令代码: 8B 0D 00 50 40 00
; 操作码: 8B 0D
; 操作数:有效地址 00405000H
存储器的代码段存储操作数在数据段的偏移地址,存储器的数据段存储数据。
-
主存操作数常通过变量形式引用,一般不需要使用段超越前缀指令。
-
表达形式:① 变量名;② 变量名 ± \pm ± n;③ [变量名] 变量名[n]
地址的加减以主存的字节单元为单位。mov cl, bvar ; 源操作数是变量名 mov edx, dvar mov bvar + 1, dh ; 目的操作数是变量名 mov word ptr dvar + 2, dx ; ptr 将 dx 中的操作数送到 dvar+2 所指单元开始的连续两个字节 mov dvar, 87654321H
-
源操作数和目的操作数均可使采用存储器操作数,但不能同时使用。即两个操作数不允许同时都是内存单元的数。如果想要将一个内存单元的数据传给另一个单内存单元需要利用通用寄存器,使用一条指令不能完成。
存储器的寄存器间接寻址
有效地址只有基址寄存器部分。有效地址存放在寄存器中,寄存器内容 = 偏移地址 = 有效地址,用中括号括起寄存器表达。
mov edx, [ebx] ; 双字量传送,将 ebx 所存地址处存储单元的数据送到 edx
mov cx, [esi] ; 字量传送
mov [edi], al ; 字节量传送,将 al 的数据送到 edi 所存地址处的存储单元
-
寄存器间接寻址未说明数据类型,数据由另一个操作数的寄存器或变量类型决定,指令只有一个操作数时必须指定类型(PTR)。
地址的加减以主存的字节单元为单位。; 立即数无类型,需要显示说明 mov [ebx], 100 ; 错误代码,数据类型不明确 mov byte ptr [ebx], 100 ; byte ptr 说明数据类型为字节
-
方便对数组元素或字符串的字符进行操作:数组(字符串)的首(尾)地址赋值给寄存器,可以通过增减寄存器值指向不同的元素(字符)。
存储器的寄存器相对寻址
有效地址由寄存器内容与位移量之和,寄存器要用中括号括起。
mov esi, [ebx + 4] ; 位移量: 4 ,无类型
mov esi, 4[ebx]
mov esi, [4][ebx]
mov edi, [ebp - 08H] ; 位移量: -08H,无类型
mov edi, [-8H][ebp]
mov edi, -8H[ebp]
mov eax, count[esi] ; 位移量: count , count 定义的类型
mov eax, [esi + count] ; count 变量所在的偏移地址作为相对寻址的位移量
mov eax, [count][esi]
- 寄存器相对寻址未说明数据类型,数据由另一个操作数的寄存器或变量类型}决定,指令只有一个操作数时必须指定类型(PTR)。
地址的加减以主存的字节单元为单位。 - 方便对数组元素或字符串的字符进行操作:数组(字符串)的首地址作为位移量,寄存器赋值0或元素(字符)个数,通过增减寄存器值指向不同的元素(字符)。
指令寻址
指令寻址:① 顺序寻址;② 跳}寻址(相对寻址、直接寻址、间接寻址(寄存器间接寻址、存储器间接寻址));
顺序寻址
EIP自动增量指向下一条指令,顺序执行接着的下一条指令。
跳转寻址
控制流程跳转到指定指令位置,实现程序分支、循环、调用等结构。
指令的相对寻址
提供目标地址相对于当前指令指针EIP的位移量(指令形式:操作码 位移量)。
目标地址(目的地址或转移地址)= 当前EIP + 位移量。
相对寻址都是段内转移,最常用、最灵活。
指令的直接寻址
直接提供目标地址(指令形式:操作码 目标地址)。
目标地址 = 指令操作数。
理论上可以支持段内或段间转移,IA-32只支持段间的直接转移。
指令的间接寻址
指示寄存器或存储单元,目标地址来自寄存器或存储单元,间接获得。
① 寄存器间接寻址:用寄存器保存目标地址(指令形式:操作码 寄存器地址)。
② 存储器间接寻址:用存储单元保存目标地址(指令形式:操作码 存储器地址)。