这个指令做了什么(REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:)?

时间:2014-05-20 22:17:20

标签: assembly

我正在查看Intel-x86程序跟踪并遇到了这条指令

REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:

我知道

REP MOVS

导致MOV指令运行多次由ECX寄存器中的值指定,在我的情况下为0x2b。

我知道

BYTE PTR

确定信息的大小,在这种情况下只是一个字节。

我知道

ES:[EDI]

告诉将BYTE PTR DS中的任何内容移动到EDI指向的地址。

我不知道的是逗号之后的部分是什么。

BYTE PTR DS:

问题:

为什么PTR指令会这样做?为什么不呢

REP MOVS BYTE ES:[EDI]. BYTE DS:

什么是ES和DS对应?

由于

2 个答案:

答案 0 :(得分:4)

看起来教学并没有结束。我今天刚刚在OllyDBG中遇到了这个指令,我可以调整指令列的大小来显示指令的其余部分。

00499B3A  |. F3:A4          |REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]

既然我们知道完整的指令,但我仍然不知道这条指令的作用。所以我从here中提取了英特尔指令集参考手册,并搜索了操作码F3:A4

在手册中,它描述了这个操作码如下:

  

从DS移动(E)CX字节:[(E)SI]到ES:[(E)DI]。

答案 1 :(得分:4)

汇编程序别名

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等标准操作系统下运行,则不应修改或以任何方式关注它们。只有在下列情况下才需要段寄存器:

  1. 您正在编写16位模式的程序,如MS-DOS 16位实模式或MS-DOS 16位保护模式(在80286上可用)。
  2. 您正在为新操作系统编写内核/管理程序,或者您的应用程序在没有任何操作系统的裸机硬件上运行。
  3. 在16位模式下,在8086到80286的Intel CPU上,有以下段寄存器: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寄存器并且指向同一个存储器,你可以忽略它们。 / p>

    关于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个周期。