【发布时间】:2016-04-28 12:28:36
【问题描述】:
我目前正在研究汇编和反汇编一些代码(x86),并尝试从中重新创建 C 代码。我至少知道寄存器和编程的基础知识。但是在以下情况下我无法理解 ESI 的用法:
mov esi, [esp+10h]
lea esi, [esi+0]
我不确定在这种情况下esp+10h 是什么,但我认为这并不重要,因为它应该只是一些随机的 32 位值,对吧?
据我所知,mov esi, [esp+10h] 将从地址esp+10h 复制数据(实际值)并将其存储在 ESI 中。所以esi 现在应该是某种数据。但随后lea esi, [esi+0] 出现并将esi+0(即数据)解释为地址并将其写入esi。
在我读到的stackoverflow 上的另一个线程中,lea esi, [esi+0] 实际上是nop(What is the meaning of lea 0x0(%esi),%esi)。这是有道理的,因为它不应该修改地址。但是当esi 是使用数据时,这就令人困惑了。所以我的 C 代码看起来像这样:
int esi = *(esp + 0x10); //move data from esp+10h to esi
int* esi = &esi; //write the address of esi+0 to esi which is
//actually an int and not int*
所以我的问题是,寄存器级别的数据和地址之间是否有任何区别,或者它是否只是因为看起来相同(32 位寄存器)而被解释为原样。我的另一个问题是这段代码现在实际上做了什么,最后 ESI 是什么? mov 是否总是复制数据? lea 总是复制地址不重要吗?
您现在可能已经猜到了,我很困惑,也许我想得太远了。请怜悯我:D
【问题讨论】:
-
mov esi, [esp+10h]获取(假定)函数的第四个(DWORD/4 字节)参数并将其复制到ESI。lea esi, [esi+0]确实是 NOP,类似于mov esi, esi。 -
@zx485 :您假设堆栈在返回地址之后没有放置任何东西。也许代码有序言/尾声代码?问题中实际上没有足够的信息来说明
esp+10h的内容,除非 OP 用他们正在查看的其余代码更新了问题。 -
第二条语句应为
esi = esi + 0;。第一个有点不对,不是esp + 0x10而是esp + 0x10 / sizeof(*esp);也就是说,汇编程序的位移以字节/字符为单位,但在 C 中,位移/索引以元素的数量为单位。lea的含义是,如果给mov操作码提供相同类型的操作数,它可以用来计算将使用的地址。 -
这只是一个猜测,但通常像
lea esi, [esi+0]这样的 nop 表示编译器可能会出于性能目的尝试将一段代码与边界对齐。通常,您会在循环顶部之前看到什么都不做指令,以将其对齐到特定边界(通常为 16 字节)。如果您向我们展示了您正在转换的所有代码,我们将能够更准确地确定代码实际在做什么。 -
对于 CPU,在 ESI 中具有地址或值没有区别,两者都是整数。对于
lea,需要注意的是,虽然指令本身是“加载有效地址”的缩写,但它实际上只是计算地址,而不是获取实际值。这就是为什么可以将其用作 NOP 的原因。如果它达到实际内存值,您将面临因非法地址访问而崩溃的风险(因为 ESI 的值未确定并且可能指向无效的内存区域)。