我目前正在调查程序集并反汇编一些代码(x86),并尝试从中重新创建C代码。我至少知道寄存器和编程的基础知识。但在以下情况下,我无法理解ESI的使用情况:
mov esi, [esp+10h]
lea esi, [esi+0]
我不确定esp+10h
在这种情况下是什么,但我认为这不重要,因为它应该只是一些随机的32位值,对吧? / p>
据我所知,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
答案 0 :(得分:3)
CPU没有像高级语言那样的数据类型。对于CPU,所有数据都只是位;将这些位解释为整数/位掩码/地址/浮点数只存在于程序员的脑海中。程序员有责任知道“这个32位值表示字符数组的地址,所以我只应该用它在那个上下文中有意义的事情”。但如果你做一些不太明智的事情,比如移动一个地址,机器就不会阻止你。
第一条指令取esp
寄存器中的值(通常包含堆栈顶部的地址),添加10h
,取32位来自该地址的值,并将其加载到esi
寄存器中。此地址的值可能是局部变量或函数参数,并且正在加载到esi
中以准备进一步的计算。
第二条指令获取esi
寄存器中的值,加0,并将值加载到esi
。 (注意它不会从内存中获取任何内容,尽管指令的“间接”外观;这是lea
指令的一个奇怪之处,它基本上计算一个地址,但不会取消引用它。你可以想到它有点像C的一元&
。)正如你所说,这是一个无操作;是的,esi
中有数据,但它自己被“替换”了。
请注意,机器中只有一个esi
寄存器,因此将其声明为两个不同变量的代码会产生误导。将esi
视为全局变量。
由于C确实有数据类型,要在C中获得类似的效果,您必须在整个地方进行类型转换。我会像这样表达代码:
int esi, esp;
esi = *(int *)(esp + 0x10);
esi = (int)&*(int *)esi; // does nothing
(您必须假设您可以将整数转换为指针并返回而不更改其值。)