比例因子寻址:
比例因子寻址(也称为比例缩放索引寻址或基址加变址加比例因子寻址)是一种复杂的内存寻址方式,常用于数组和指针操作。它允许通过一个基址寄存器、一个变址寄存器和一个比例因子来计算内存地址。
语法
比例因子寻址的通用格式为:
[base + index * scale + displacement]
-
base:基址。
-
index:变址寄存器(如
ESI
、EDI
等)。 -
scale:比例因子,可以是 1、2、4、8(根据数组元素数据类型决定)。
-
displacement:位移量,可以是一个立即数(常数)。
示例:使用循环来操作一个字节数组
.586
.model flat,stdcall
option casemap:none
.data
byte_arr db 13,23,14,25 ;定义数组
.code
main proc
xor ebx,ebx ;xor异或指令;将 EBX 寄存器清零。
mov eax,offset byte_arr
loop_a:
mov [eax + ebx * 1],bl ;[eax + ebx * 1] 可以获取到字节数组每个元素的地址(ebx可以自加)
;若是字数组:[eax + ebx * 2],双字数组:[eax + ebx * 4]..根据数组元素类型选择数字(字节)
inc bl
cmp ebx,4
jl loop_a
main endp
end
代码执行过程
-
初始化
EBX
为 0 和EAX
为byte_arr
的地址。 -
进入循环,
[eax + ebx * 1]
依次访问byte_arr
的每个字节,将BL
寄存器的值(从 0 开始递增)存储到数组的每个元素中。 -
循环结束后,
byte_arr
的所有元素将被替换为[0, 1, 2, 3]
。
代码段解释:
-
xor ebx,ebx
将EBX
寄存器清零,即EBX = 0
。 -
mov eax,offset byte_arr
将byte_arr
的地址加载到EAX
寄存器。 -
loop_a:
是标签,表示循环的起始位置。 -
mov [eax + ebx * 1],bl
将BL
寄存器的值存储到byte_arr
数组中的相应位置。具体来说,[eax + ebx * 1]
计算数组byte_arr
中的当前元素地址,并将BL
的值存储到该位置。因为EBX
从 0 开始,因此这将依次操作byte_arr
的每个字节。(EBX
位32
位寄存器,但是由于此时数组元素为1字节,8位数据;所以次数若是将ebx
中的数据mov
至数组元素中会造成数据溢出,所以只能movBL
) -
inc bl
将BL
寄存器的值加 1。 -
cmp ebx,4
将EBX
寄存器的值与 4 进行比较。 -
jl loop_a
如果EBX
的值小于 4,则跳转到loop_a
,继续循环。
代码执行效果
byte_arr
将从原来的 [13, 23, 14, 25]
被修改为 [0, 1, 2, 3]
执行前数组内的数据:
执行后数组内的数据:
取数据
通过比例因子寻址取到地址后就可以使用LODS
系列指令取数据。
LODS
(Load String)指令是一条字符串操作指令,用于从数据段加载一个字节、一个字(16位),或者一个双字(32位)到累加器寄存器(AL
, AX
, EAX
)。它使用源索引寄存器 ESI
来指示要加载的数据的地址,并根据方向标志位(DF
)来决定 ESI
的增减。
语法
-
LODSB
:从[ESI]
加载一个字节到AL
,并根据DF
更新ESI
。 -
LODSW
:从[ESI]
加载一个字到AX
,并根据DF
更新ESI
。 -
LODSD
:从[ESI]
加载一个双字到EAX
,并根据DF
更新ESI
。
方向标志位(DF)
-
如果
DF
为 0(使用CLD
清除),ESI
递增。 -
如果
DF
为 1(使用STD
设置),ESI
递减。
示例:
使用 LODSB
指令从数组中逐字节加载数据。
.586
.model flat,stdcall
option casemap:none
.data
byte_arr db 13,23,14,25
.code
main proc
;取数据代码
xor eax,eax ;将 EAX 寄存器清零。
mov esi,offset byte_arr
mov ecx,4
lods_a:
lodsb ;根据ESI中的数组基地址,将数据加载至AL寄存器中
loop lods_a
main endp
end
xor eax,eax
:将 EAX
寄存器清零。
mov esi,offset byte_arr
:将数组 byte_arr
的地址加载到 ESI
寄存器。
mov ecx,4
:将 ECX
寄存器设置为 4,表示要处理的字节数。
lods_a:
:标签,表示循环的起始位置。
lodsb
:从 ESI
指向的地址加载一个字节到 AL
寄存器,并根据方向标志(DF
)更新 ESI
。默认情况下,ESI
会递增。
loop lods_a
:将 ECX
寄存器的值减 1;如果 ECX
的值不为 0,则跳转到 lods_a
,继续循环。
内存中的数组:
取出数据: