1. 数组的存储与遍历
1.1 编写数组数据写入内存
- 首先选中某部分地址编辑数据,这里以x64架构的 " long "类型数组为例,即每个元素占据8字节(qword)。
类比如图
- 构造数组元素如下图:
- 易知,数组结构如下表
Index | Address | Data |
0 | 0x7FF68FE80050 | 0x11 |
1 | 0x7FF68FE80058 | 0x22 |
2 | 0x7FF68FE80060 | 0x33 |
3 | 0x7FF68FE80068 | 0x44 |
4 | 0x7FF68FE80070 | 0x55 |
1.2 汇编循环遍历数组元素
mov rbx,0x7FF68FE80050 //将数组基地址(首地址)赋给 rbx寄存器保存 mov rcx,0 // 将 rcx寄存器作为index loop_start: //循环体 mov rax,qword ptr[rbx+rcx*8] // 取出数组元素放入rax寄存器 inc rcx //索引值自增 cmp rcx,5 //跳出循环判断 jl loop_start // 如果 rcx < 5 ,则执行跳转
- 执行结果如下:
3. Lea指令
lea
(Load Effective Address)指令用于计算内存地址而不进行内存访问。它将地址表达式的结果加载到寄存器中。比如:
lea rax, [rbx + 4*rcx]
- 这条指令计算
(rbx + 4*rcx)
的地址,并将结果存储到rax
寄存器中。lea
可以用来进行地址计算、实现指针算术或调整寄存器值,但不会访问内存中的数据。
示例:
lea rdx, [rbx+rcx*8] mov r9, qword ptr [rdx]
- 执行前状态
- 执行结果
lea 指令也可以作为计算器存储计算结果
如:仅使用 lea rax, [rbx+rdx * 3] 指令将会把 rbx+rdx*3 式子的结果存储到 rbx寄存器。
4. mul指令与imul指令
mul
和 imul
指令用于执行乘法操作,但它们在处理有符号数和无符号数、以及结果存储方面有所不同。
4.1 mul 指令
mul
指令用于执行无符号乘法。它有不同的操作数形式和结果存储方式:
8位操作数:
mul al ; AL 寄存器中的值与操作数(AL)相乘,结果存储在 AX 中。
- 操作数:AL(8位寄存器)
- 结果:AX(16位寄存器)
AX
=AL
* 操作数- 如果结果超过16位,则
AX
中高字节的值将反映结果的高位部分。
- 16位操作数:
mul ax ; AX 寄存器中的值与操作数(AX)相乘,结果存储在 DX:AX 中。
- 操作数:AX(16位寄存器)
- 结果:DX:AX(32位结果)
DX:AX
=AX
* 操作数- 如果结果超过16位,则
DX
中的高16位包含结果的高位部分,AX
中的低16位包含结果的低位部分。
- 32位操作数:
mul eax ; EAX 寄存器中的值与操作数(EAX)相乘,结果存储在 EDX:EAX 中。
- 操作数:EAX(32位寄存器)
- 结果:EDX:EAX(64位结果)
EDX:EAX
=EAX
* 操作数- 如果结果超过32位,则
EDX
中的高32位包含结果的高位部分,EAX
中的低32位包含结果的低位部分。
mul
指令的特点:
mul
指令始终是无符号乘法。- 结果存储在特定的寄存器对中,以便捕获可能的溢出。
- 操作数通常是寄存器中的值,但也可以是内存中的值。
4.2 imul 指令
imul
指令用于执行有符号乘法。它有几种不同的操作数形式:
- 单操作数形式:
imul ax ; AX 寄存器中的值与操作数(AX)相乘,结果存储在 AX 中。
- 操作数:AX(16位寄存器)
- 结果:AX(16位寄存器)
AX
=AX
* 操作数- 如果结果溢出,结果会被截断,只保留低位部分。
2.双操作数形式:
imul eax, ebx ; EAX 寄存器中的值与 EBX 寄存器中的值相乘,结果存储在 EAX 中。
- 操作数:EAX(32位寄存器)、EBX(32位寄存器)
- 结果:EAX(32位寄存器)
EAX
=EAX
*EBX
- 如果结果超出32位范围,则结果会被截断,只保留低32位部分。
3.三操作数形式:
imul eax, ebx, 5 ; EAX 寄存器中的值与 EBX 寄存器中的值和 5 相乘,结果存储在 EAX 中。
- 操作数:EAX(32位寄存器)、EBX(32位寄存器)、5(立即数)
- 结果:EAX(32位寄存器)
EAX
=EBX
* 5- 这里,
EBX
乘以 5,结果存储在EAX
中。
imul
指令的特点:
imul
指令是有符号乘法。imul
的结果是有符号的,考虑了符号位。- 当使用多操作数形式时,
imul
可以用来进行更复杂的乘法计算。
总结
mul
进行无符号乘法,结果存储在特定的寄存器对中(例如,DX:AX
或EDX:EAX
)。imul
进行有符号乘法,支持多种形式,包括单操作数、双操作数和三操作数形式。结果存储在目的寄存器中。mul
和imul
都会根据操作数的大小选择适当的寄存器对来存储结果,以处理可能的溢出。
5. div指令
div
指令用于执行无符号除法操作。与 mul
和 imul
指令不同,div
指令用于将一个数除以另一个数,并计算商和余数。它的操作方式根据操作数的大小和类型有所不同。
5.1 div 指令的基本原理
div
指令会根据被除数和除数的大小来选择不同的寄存器对,以存储商和余数。操作数是无符号的,所以结果也会是无符号的。
5.2 8 位除法
语法:
div byte [memory] ; 除数在内存中 div al ; 除数在 AL 寄存器中
- 被除数:
AX
寄存器 - 除数:8 位操作数(如
AL
寄存器中的值或内存中的值) - 商:
AL
寄存器 - 余数:
AH
寄存器
计算:
AX / 除数 = 商 (AL) AX % 除数 = 余数 (AH)
AX
寄存器的高字节AH
和低字节AL
共同存储被除数。div
指令将AL
除以操作数,结果存储在AL
中,余数存储在AH
中。
示例代码:
mov al, 20 ; 被除数 mov bl, 4 ; 除数 div bl ; AL = AL / BL, AH = AL % BL ; 结果:AL = 5, AH = 0
5.3 16 位除法
语法:
div word [memory] ; 除数在内存中 div ax ; 除数在 AX 寄存器中
- 被除数:
DX:AX
寄存器对 - 除数:16 位操作数(如
AX
寄存器中的值或内存中的值) - 商:
AX
寄存器 - 余数:
DX
寄存器
计算:
DX:AX / 除数 = 商 (AX) DX:AX % 除数 = 余数 (DX)
DX
寄存器存储被除数的高16位,AX
寄存器存储低16位。div
指令将DX:AX
除以操作数,结果存储在AX
中,余数存储在DX
中。
示例代码:
mov ax, 1000 ; 被除数 mov bx, 25 ; 除数 div bx ; DX:AX = AX / BX, DX = AX % BX ; 结果:AX = 40, DX = 0
5.3 32 位除法
语法:
div dword [memory] ; 除数在内存中 div eax ; 除数在 EAX 寄存器中
- 被除数:
EDX:EAX
寄存器对 - 除数:32 位操作数(如
EAX
寄存器中的值或内存中的值) - 商:
EAX
寄存器 - 余数:
EDX
寄存器
计算:
EDX:EAX / 除数 = 商 (EAX) EDX:EAX % 除数 = 余数 (EDX)
EDX
寄存器存储被除数的高32位,EAX
寄存器存储低32位。div
指令将EDX:EAX
除以操作数,结果存储在EAX
中,余数存储在EDX
中。
示例代码:
mov eax, 100000 ; 被除数 mov ebx, 200 ; 除数 div ebx ; EDX:EAX = EAX / EBX, EDX = EAX % EBX ; 结果:EAX = 500, EDX = 0
特点和要求
1.被除数和除数的大小:
div 指令要求被除数必须通过寄存器对来存储,以适应可能的结果范围(AX 对于8位操作数,DX:AX 对于16位操作数,EDX:EAX 对于32位操作数)。
除数的大小必须与被除数的大小相匹配。
2.除数不能为零:
如果除数为零,div 指令会引发除零异常,这是一个运行时错误。
3.结果存储:
商和余数分别存储在特定的寄存器中。如果结果超出寄存器的大小,div 指令会在商寄存器中存储结果的低位部分,而高位部分存储在余数寄存器中。
4.标志位:
div 指令不会影响标志寄存器的标志位(如 ZF、OF、CF、SF)
在使用 div
指令时,请确保被除数的大小和除数匹配,并且除数不能为零,以避免程序异常。