汇编器别名
REP MOVS DWORD PTR ES:[EDI], DWORD PTR [ESI]
是REP MOVSD的同义词
和
REP MOVS BYTE PTR ES:[EDI], BYTE PTR[ESI]
是
的同义词
REP MOVSB
您可以使用这种方式编写代码以“提高”代码的可读性。这个想法可能是这样的:“如果有人忘记了 MOVSB 从 ESI 转移到 EDI,那么这种更长的语法将有助于使事情变得更清晰”。这绝不会影响编译的二进制形式。区别仅在于文本源代码。
如您所知,根据数据大小,有以下 MOVS 命令:
- MOVSB(字节,8 位)
- MOVSW(字,16 位)
- MOVSD(双字,32 位)
- MOVSQ(qword,64 位)- 仅在 64 位模式下可用
这个指令有什么作用
MOVS 命令将数据从 DS:SI(ESI/RSI) 复制到 ES:DI(EDI/RDI) -- SI/DI 寄存器的大小取决于您当前的模式 - 16 位、32 位或64 位。它还增加(减少)SI和DI寄存器(根据D标志,设置CLD增加寄存器)。
MOVS 命令不能使用除 DS:SI/ES:DI 以外的其他寄存器,因此无需指定它们。在我看来,设置它们甚至是多余的,并且可读性没有提高反而变差了。
关于段寄存器 ES 和 DS
DS 和 ES 是“段”寄存器。正如我之前所写,MOVS 仅使用 SI/DI 作为索引寄存器和 DS/ES 作为段寄存器。您不能修改 MOVS 命令使用的寄存器。
但是您不必担心段寄存器,因为它们通常已经正确设置,如果您的程序在 Linux、Windows 等标准操作系统下运行,您不应该修改或担心它们。这些段寄存器可能仅在以下情况下才需要:
- 您正在为 16 位模式编写程序,例如 MS-DOS 16 位实模式或 MS-DOS 16 位保护模式(在 80286 上可用)。
- 您正在为新操作系统编写内核/主管,或者您的应用程序在没有任何操作系统的裸机硬件上运行。
在 16 位模式下,在 Intel CPU 从 8086 到 80286 上,有以下段寄存器:CS DS ES SS。
在实模式下,16 位段寄存器被解释为线性 20 位地址的最高有效 16 位(因此 CPU 实际上确实将段寄存器的值乘以 16 以获得基地址段)。例如,如果将 1 移至 DS,将 2 移至 SI,则“byte ptr DS:[SI]”将表示 1*16+2 = 18(从内存空间开始的第 18 个字节)。
在保护模式(80286 及更高版本)下,段寄存器不再保存 16 位整数值。它们现在包含指向包含 24 位基地址的段描述符表的索引。
在 Intel 80386 及更高版本中,32 位保护模式保留了 80286 保护模式的分段机制。尽管如此,还是添加了一个分页单元作为分段单元和物理总线之间的第二层地址转换。此外,每个段描述符中的段基也是 32 位(而不是 24 位)。此外,还添加了两个新的段寄存器:FS 和 GS。
64 位架构不使用分段。其中四个段寄存器:CS、SS、DS 和 ES 被强制为 0,并且限制为 264。段寄存器 FS 和 GS 仍然可以具有非零基地址。这允许操作系统将这些段用于特定目的。
一个值得注意的事实是,386 和更高版本的 Intel x86 CPU 仍然使用 16 位大小的段寄存器,因为它们只保存段描述符表的索引。
因为,正如我之前写的,在标准操作系统中,无论是 32 位还是 64 位,段寄存器都是已经预先配置的 DS 和 ES 寄存器,并且指向相同的内存,所以您可以忽略它们。
您可以在英特尔® 64 位和 IA-32 架构软件开发人员手册(组合卷:1、2A、2B、2C、2D、3A、3B、3C、 3D 和 4)。引用:
这些指令对字符串中的单个元素进行操作,
可以是字节、字或双字。要操作的字符串元素
on 用 ESI(源字符串元素)和 EDI 标识
(目标字符串元素)寄存器。这两个寄存器
包含指向 a 的绝对地址(段的偏移量)
字符串元素。默认情况下,ESI 寄存器寻址段
用 DS 段寄存器标识。段覆盖前缀
允许 ESI 寄存器与 CS、SS、ES、FS 或
GS 段寄存器。 EDI 寄存器寻址识别的段
与 ES 段寄存器;不允许段覆盖
EDI 注册。在字符串中使用两个不同的段寄存器
指令允许对位于
不同的细分市场。或者通过将 ESI 寄存器与 ES 相关联
段寄存器,源字符串和目标字符串都可以
位于同一段。 (后一种情况也可以是
通过加载相同的 DS 和 ES 段寄存器来实现
段选择器并允许 ESI 寄存器默认为 DS
寄存器。)MOVS 指令移动由 寻址的字符串元素
ESI 寄存器到 EDI 寄存器寻址的位置。这
汇编器识别该指令的三种“短形式”,即
指定要移动的字符串的大小:MOVSB(移动字节字符串),
MOVSW(移动字串)和MOVSD(移动双字串)。
关于MOVS指令的性能
自从 1993 年生产出第一颗奔腾 CPU 以来,英特尔开始让简单的命令更快,而复杂的命令(如 REP MOVS)则更慢。
因此,REP MOVS 变得非常缓慢,没有更多实际理由使用它。
2013 年,英特尔决定重新审视 REP MOVS。如果 CPU(2013 年之后生产)具有 CPUID ERMSB(增强型 REP MOVSB)位,则 REP MOVSB 和 REP STOSB 命令的执行方式与旧处理器不同,并且应该很快。在实践中,它只对大块,256 字节及更大,并且仅在满足某些条件时才快速:
- 源地址和目标地址都必须与 16 字节边界对齐;
- 源区域不应与目标区域重叠;
- 长度必须是 64 的倍数才能产生更高的性能;
- 方向必须是正向 (CLD)。
请参阅英特尔优化手册,第 3.7.6 节增强型 REP MOVSB 和 STOSB 操作 (ERMSB) http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf
由于启动成本非常高(大约 35 个周期),它们在小块上非常慢。