【问题标题】:What's the point of LEA EAX, [EAX]?LEA EAX,[EAX] 有什么意义?
【发布时间】:2011-02-11 19:15:17
【问题描述】:
LEA EAX, [EAX]

我在使用 Microsoft C 编译器编译的二进制文件中遇到了这条指令。它显然不能改变 EAX 的值。那为什么会出现呢?

【问题讨论】:

  • @Potatoswatter:是的,这是二进制的发布版本,所以应该进行优化。另外,我正在使用 ollydbg 进行反汇编。
  • 你有这个gem对应的C语句吗?
  • @Wikser:不。这不是一次性的案例。我在同一个二进制文件中看到过一两个像 LEA EBX、[EBX] 这样的人。事实上,我现在正在看屏幕上的最后一个。 Ollydbg 将这个(LEA EBX,[EBX] 即)的操作码显示为“8D9B 00000000”
  • 如果是 64 位二进制,那么它只是前 32 位中的一个零

标签: c assembly x86 instruction-set


【解决方案1】:

这是一个NOP

以下通常用作NOP。它们都做同样的事情,但它们会产生不同长度的机器码。根据对齐要求,选择其中之一:

xchg eax, eax         = 90
mov eax, eax          = 89 C0 
lea eax, [eax + 0x00] = 8D 40 00 

【讨论】:

  • 其实严格意义上来说并不是NOP,因为它引入了对EAX的数据依赖。现代 CPU 将此特定模式检测为 NOP 并忽略数据依赖性,但一些较旧的 CPU 可能不会。
  • 其实nop的操作码是0x90,和xchg eax, eax是一样的
  • 好吧,“现代 cpu 将这种特定模式检测为 NOP”是错误的,他们仍然引入 false 数据依赖链。只有一些真正的 NOP,其中解码器不引入任何数据依赖性。
  • @Quonux 和 multi-byte NOPs 很久以前就已经正式发布了。 This answer 也列出了 Intel 官方的 NOPs 从 2 到 9 个字节
【解决方案2】:

来自this文章:

这个技巧被 MSVC++ 编译器使用 发出 NOP 指令 不同的长度(用于填充之前 跳跃目标)。例如,MSVC++ 如果它生成以下代码 需要 4 字节和 6 字节填充:

8d6424 00 lea [ebx+00],ebx ; 4 字节填充 8d9b 00000000
lea [esp+00000000],esp ; 6字节 填充

第一行标记为“npad 4” 在由 编译器,第二个是“npad 6”。 可以选择寄存器(ebx,esp) 从很少使用的避免 代码中的错误依赖项。

所以这只是一种 NOP,出现在 jmp 指令的目标之前以对齐它们。

有趣的是,您可以根据此类指令的特征来识别编译器。

【讨论】:

  • 说它是NOP 只是答案的一半(然而,奇怪的是,选择了一个)。解释你为什么要做这些NOPs 是完整的答案。干得好。
  • 我在使用 MSVC++ 编译器时也遇到过这种情况。
【解决方案3】:
LEA EAX, [EAX]

确实不会改变 EAX 的值。据我了解,它的功能与以下内容相同:

MOV EAX, EAX

您是在优化代码还是未优化代码中看到它?

【讨论】:

  • 代码优化好了。但这如何证明/解释这个 LEA?
  • @Frederick:如果它没有经过优化,我想如果编译器使用 LEA 进行某种计算并且特殊情况生成了这个冗余语句(这发生在未优化的代码中)会是有意义的跨度>
  • 这是我公司向客户发布的二进制文件。所以它必须是优化版本。
  • “所以它必须是优化版本”。不必要。如果他们忘记打开/O2怎么办?
  • LEA 指令在 Pentium 4 上的执行速度可能比 MOV 指令快(今天使用 LEA 的计算速度仍然很快)所以我认为这是 LEA 的一个原因。
猜你喜欢
  • 2022-01-15
  • 2011-10-12
  • 1970-01-01
  • 1970-01-01
  • 2017-01-26
  • 2012-08-08
相关资源
最近更新 更多