【问题标题】:What does this instruction do ( REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS: )?该指令有什么作用( REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS: )?
【发布时间】:2014-07-09 08:52:57
【问题描述】:

我正在查看 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分别对应什么?

谢谢

【问题讨论】:

  • 这不只是你的汇编语言的问题吗?
  • 问题是,我正在分析恶意软件的踪迹。因此,我无权访问源代码,也没有编译或汇编程序。我拿了二进制文件并运行了一个反汇编程序。不知道我是否理解你的问题。
  • 请查阅您的反汇编手册,了解它使用什么语言?每个供应商选择略有不同的语法来表达汇编代码。
  • 这是 REP MOVSB 的尴尬版本。相当典型的反汇编程序。
  • 这就是我的想法。我在同一跟踪的其他地方看到了 REP MOVSB 指令。为什么不直接放 REP MOVSB?

标签: assembly x86 instructions


【解决方案1】:

似乎指令并没有就此结束。我今天刚在 OllyDBG 中看到这条指令,我可以调整指令列的大小以显示指令的其余部分。

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

现在我们知道完整的指令是什么,但我仍然不知道这条指令的作用。于是我从here翻出Intel指令集参考手册,搜索操作码F3:A4

手册中对这个操作码的描述如下:

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

【讨论】:

  • 英特尔当前版本的手册条目 (felixcloutier.com/x86/movs:movsb:movsw:movsd:movsq) 描述了您可以将其写为 rep movsb 的事实,或者使用操作数来暗示使用这种详细反汇编输出的大小。 “显式操作数”形式和“无操作数”形式
【解决方案2】:

汇编器别名

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. 您正在为新操作系统编写内核/主管,或者您的应用程序在没有任何操作系统的裸机硬件上运行。

在 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 个周期),它们在小块上非常慢。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-01-21
    • 2012-08-21
    • 2015-01-25
    • 2010-10-05
    • 1970-01-01
    • 2021-05-11
    • 2011-03-14
    相关资源
    最近更新 更多