【发布时间】:2010-12-23 19:14:00
【问题描述】:
汇编程序中EDI和ESI寄存器的实际用途和用途是什么?
我知道它们用于一件事的字符串操作。
谁能举个例子?
【问题讨论】:
汇编程序中EDI和ESI寄存器的实际用途和用途是什么?
我知道它们用于一件事的字符串操作。
谁能举个例子?
【问题讨论】:
SI = 源索引DI = 目标索引
正如其他人所指出的,它们对字符串指令有特殊用途。对于实模式编程,ES 段寄存器必须与DI 和DS 与SI 一起使用,如
movsb es:di, ds:si
SI 和 DI 也可以用作通用索引寄存器。比如C源代码
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 的位置);地址周围的括号表示间接。
AX = 累加器DX = 双字累加器CX = 计数器BX = 基址寄存器
它们看起来像通用寄存器,但有许多指令(出乎意料?)使用其中的一个——但哪一个?——隐式使用。
【讨论】:
有一些操作只能使用 DI/SI(或它们的扩展对应物,如果您在 1985 年没有学习 ASM)。其中有
REP STOSB
REP MOVSB
REP SCASB
分别是重复(=大量)存储、加载和扫描的操作。您所做的是设置 SI 和/或 DI 指向一个或两个操作数,也许在 CX 中计数,然后让'er rip。这些是一次处理一堆字节的操作,它们使 CPU 处于自动状态。因为您没有显式地编写循环代码,所以它们的工作效率(通常)比手动编码的循环更有效。
以防万一您想知道:根据您设置操作的方式,重复存储可能很简单,例如将值 0 插入一个大的连续内存块;我认为,MOVSB 用于将数据从一个缓冲区(嗯,任何一串字节)复制到另一个缓冲区;并且 SCASB 用于查找与某些搜索条件匹配的字节(我不确定它是否仅在相等性上进行搜索,或者什么 - 你可以查一下 :))
这就是这些 regs 的大部分用途。
【讨论】:
像 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 指向的内存。
【讨论】:
除了用于批量操作的寄存器之外,它们还有助于通过 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 位调用约定不同,我不确定这些寄存器是否保留调用。
【讨论】: