汇编程序中 EDI 和 ESI 寄存器的实际用途和用途是什么?
我知道它们是用来做字符串运算的。
有人能举个例子吗?
有一些操作可以用 DI/SI (或者它们的扩展对应物,如果你没有在1985年学过 ASM 的话)进行 只有。其中包括
REP STOSB REP MOVSB REP SCASB
它们分别是用于重复(= 块)存储、加载和扫描的操作。你要做的就是设置 SI 和/或 DI 指向一个或两个操作数,也许在 CX 中放一个计数器,然后让它开裂。这些操作一次只能处理一堆字节,它们让 CPU 处于自动化状态。因为您没有显式地编码循环,所以它们比手工编码的循环更有效率(通常)。
以防你想知道: 根据你设置的操作,重复存储可以是一些简单的事情,比如把值0打到一个大的连续内存块中; 我认为,MOVSB 用于从一个缓冲区(好吧,任何一组字节)复制数据到另一个缓冲区; SCASB 用于寻找符合某些搜索条件的字节(我不确定它是否只搜索相等,或什么 & nash; 你可以查找它:)
这就是那些规定的大部分作用。
像 MOVSB 和 MOVSW 这样的操作码可以有效地将数据从 ESI 指向的存储器复制到 EDI 指向的存储器。因此,
mov esi, source_address mov edi, destination_address mov ecx, byte_count cld rep movsb ; fast!
除了在其他答案中提到的字符串运算(MOVS/INS/STOS/CMPS/SCASB/W/D/Q 等) ,我想补充的是,还有更多的“现代”x86汇编指令隐含地使用了至少 EDI/RDI:
SSE2 MASKMOVDQU(以及即将发布的 AVX VMASKMOVDQU)指令有选择地将 XMM 寄存器中的字节写入 EDI/RDI 指向的内存。
MASKMOVDQU
VMASKMOVDQU
SI = 源索引 DI = 目的地索引
SI
DI
正如其他人所指出的,它们对字符串指令有特殊的用途。对于实模式编程,ES段寄存器必须与 DI一起使用,而 DS必须与 SI一起使用
ES
DS
movsb es:di, ds:si
SI 和 DI 也可以用作通用的索引寄存器
srcp [srcidx++] = argv [j];
编译成
8B550C mov edx,[ebp+0C] 8B0C9A mov ecx,[edx+4*ebx] 894CBDAC mov [ebp+4*edi-54],ecx 47 inc edi
其中 ebp+12包含 argv,ebx是 j,edi包含 srcidx。注意,第三条指令使用 edi乘以4,并将 ebp偏移量加上0x54(srcp的位置) ; 地址周围的括号表示间接。
ebp+12
argv
ebx
j
edi
srcidx
ebp
srcp
AX = 蓄电池 双字累加器 CX = 计数器 基寄存器
AX
CX
它们看起来像通用寄存器,但是有许多指令(意外地?)含蓄地使用其中之一,但是使用哪一个呢。
除了用于大规模操作的寄存器之外,它们对于通过32位调用约定中的函数调用(调用保存)来保存寄存器的属性也很有用。ESI、 EDI、 EBX、 EBP、 ESP 是被调用保留的,而 EAX、 ECX 和 EDX 是不被调用保留的。调用保留的寄存器受到 C 库函数的尊重,它们的值通过 C 库函数调用保留。
Jeff Duntemann 在他的汇编语言书中有一个打印命令行参数的汇编代码示例。代码使用 esi 和 edi 来存储计数器,因为它们将被 C 库函数 printf 保持不变。对于 eax、 ecx、 edx 等其他寄存器,不能保证它们不被 C 库函数使用。
Https://www.amazon.com/assembly-language-step-step-programming/dp/0470497025
参见第12.8节 C 如何看待命令行参数。
请注意,64位调用约定不同于32位调用约定,我不确定这些寄存器是否被调用保留。