【发布时间】:2016-04-13 01:31:09
【问题描述】:
这可能是一个菜鸟问题,因为我才刚刚开始深入研究 c++ 代码的反汇编,以检查编译器最终为我做了什么。基本上我有一些 c++ 代码(这是一个玩具示例):
const int SIZE = 10000000;
for(auto i = 0; i < SIZE; i++)
{
giantVector[i] = giantVector[i] * giantVector[i];
}
这最终编译为(在优化的发布版本中,减去 mmx 指令):
00021088 mov esi,dword ptr [giantVector] //move a pointer to giantVector into esi
0002108B xor eax,eax //clear out eax
000210C4 mov ecx,dword ptr [esi+eax*4] //move int from vector into ecx
000210C7 imul ecx,ecx //multiply ecx by itself
/* Move the result back into vector. This instruction uses esi as the base pointer
to the first element in the vector then adds eax(loop counter) * 4(sizeof(int))
to determine where to stick it. */
000210CA mov dword ptr [esi+eax*4],ecx //move result back into vector
000210CD inc eax //increment the loop counter in eax
000210CE cmp eax,989680h //compare with SIZE constant
000210D3 jl main+0C4h (0210C4h) //If less, jump back into loop, otherwise fall through
我在这里的 cmets 只是我对事物的理解,我正在逐步了解以更好地处理事物。
我的问题是.. 000210CA 的指令是如何工作的? esi + eax * 4 本身不是计算吗?为什么该指令本身不需要其他指令来计算?或者这就是真正发生的事情?这些指令在地址空间中对我来说似乎是连续的。
如果它有帮助的话,这是由 Visual Studio 2015 编译的,并且此代码是从反汇编调试窗口中提取的。
【问题讨论】:
-
参见this answer,它解释了 x86 寻址模式。是的,
[base + index*scale]是一种有效的寻址模式,可以在任何允许有效地址作为其操作数之一的指令中使用。另请参阅x86 tag wiki 中的链接。 -
还要注意
mov esi,dword ptr [giantVector]是一个负载。std::vector存储一个指向动态分配内存的指针。您将更容易理解 C 的 asm 输出,或避免 STL 并仅使用数组的类 C 的 C++。通常 STL 的东西编译成什么都没有,就像这里一样,但它会导致非常大量的 asm。 -
@aqez 这是关于您在已删除答案中的问题:LEA 指令(加载有效地址)通常用于使用 x86 寻址执行一般整数数学运算。举个简单的例子,
eax *= 5可以用LEA eax, [eax + eax*2]完成。 LEA 让您无需实际访问内存即可计算“地址”。