ESI和EDI寄存器的目的是什么?

153

EDI和ESI寄存器在汇编语言中的实际用途是什么?

我知道它们可以用于字符串操作。

能否给出一个例子?


14
看这个链接:http://www.swansontec.com/sregisters.html。 - Jeffpowrs
5个回答

118

SI = 源索引
DI = 目的地索引

正如其他人所指出的那样,它们在字符串指令中有特殊用途。对于实模式编程,必须使用ES段寄存器与DI配合使用,并使用DSSI配合使用,例如:

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

第三个指令使用了 edi 乘以4并加上 ebp 偏移0x54(srcp的位置);地址周围的括号表示间接寻址。


尽管我记不清我在哪里看到的,但这里证实了大部分内容,而这里(第17页幻灯片)则提供了其它信息:

AX = 累加器
DX = 双字累加器
CX = 计数器
BX = 基地址寄存器

它们看起来像是通用寄存器,但有许多指令出乎意料地隐式地使用其中之一,但是用哪一个呢?


85

你只能使用DI/SI(或其扩展版本,如果你没有在1985年学习过ASM)执行一些操作。其中包括:

REP STOSB
REP MOVSB
REP SCASB

这些分别是用于重复(=批量)存储、加载和扫描的操作。您需要设置SI和/或DI指向一个或两个操作数,也许将计数放在CX中,然后开始执行操作。这些操作可以一次处理许多字节,并使CPU自动化。由于您不需要显式编码循环,它们通常比手动编码的循环更有效率。

以防您想知道:根据您如何设置操作,重复存储可以是将值0打入大块连续内存的简单操作; 我认为MOVSB用于将数据从一个缓冲区(或任何一组字节)复制到另一个缓冲区;而SCASB用于查找与某个搜索条件匹配的字节(我不确定它是否只在相等性上搜索,或者是什么-您可以查看)。这就是这些寄存器的大部分作用。


7
过去的优化技巧:在手动优化16位x86汇编代码时,rep stoswrep stosb快得多,所以如果复制两个字节符合您要做的事情,请改用它。 - Alexander

39

像MOVSB和MOVSW这样的操作码可以高效地将由ESI指向的内存中的数据复制到由EDI指向的内存中。因此,

mov esi, source_address
mov edi, destination_address
mov ecx, byte_count
cld
rep movsb ; fast!

13
除了其他答案提到的字符串操作(如MOVS/INS/STOS/CMPS/SCASB/W/D/Q等),我想补充一下还有一些更“现代”的x86汇编指令,其隐式地至少使用EDI/RDI寄存器:
SSE2的MASKMOVDQU指令(以及即将推出的AVX VMASKMOVDQU指令)可以选择性地将XMM寄存器中的字节写入由EDI/RDI指向的内存。

10

除了寄存器用于大规模操作之外,它们的一个特点是在32位调用约定中通过函数调用来保留(call-preserved)。其中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位调用约定不同,我不确定这些寄存器是否被保留。


我从未听说过“神圣”一词用于描述大多数人所称的“易失性”/“非易失性”,或者“被调用者保存”与“调用者保存”。我喜欢“调用保留”/“调用破坏”,因为它并不意味着它们实际上被保存在任何地方。无论如何,在x86-64 System V ABI中,ESI/RSI和EDI/RDI都不是调用保留的。 - Peter Cordes
此外,在常见的32位调用约定中,您忘记将EBP和ESP列为保留调用者寄存器。 - Peter Cordes
1
无论如何,这是一个非常好的观点。在实际代码中,你更可能基于调用约定的原因选择EDI/ESI,而不是因为它们对任何指令都很特殊。 - Peter Cordes
我喜欢call-preserved。我已经更新了答案。感谢您的审阅。 - Jay Rajput

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接