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
第三个指令使用了 edi
乘以4并加上 ebp
偏移0x54(srcp
的位置);地址周围的括号表示间接寻址。
AX
= 累加器DX
= 双字累加器CX
= 计数器BX
= 基地址寄存器
它们看起来像是通用寄存器,但有许多指令出乎意料地隐式地使用其中之一,但是用哪一个呢?
你只能使用DI/SI(或其扩展版本,如果你没有在1985年学习过ASM)执行一些操作。其中包括:
REP STOSB
REP MOVSB
REP SCASB
这些分别是用于重复(=批量)存储、加载和扫描的操作。您需要设置SI和/或DI指向一个或两个操作数,也许将计数放在CX中,然后开始执行操作。这些操作可以一次处理许多字节,并使CPU自动化。由于您不需要显式编码循环,它们通常比手动编码的循环更有效率。
以防您想知道:根据您如何设置操作,重复存储可以是将值0打入大块连续内存的简单操作; 我认为MOVSB用于将数据从一个缓冲区(或任何一组字节)复制到另一个缓冲区;而SCASB用于查找与某个搜索条件匹配的字节(我不确定它是否只在相等性上搜索,或者是什么-您可以查看)。这就是这些寄存器的大部分作用。
像MOVSB和MOVSW这样的操作码可以高效地将由ESI指向的内存中的数据复制到由EDI指向的内存中。因此,
mov esi, source_address
mov edi, destination_address
mov ecx, byte_count
cld
rep movsb ; fast!
除了寄存器用于大规模操作之外,它们的一个特点是在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位调用约定不同,我不确定这些寄存器是否被保留。