我刚刚学习ASM / x86,所以请耐心等待。
我在我正在检查的程序中注意到以下内容,我认为它正在将一个参数传递给被调用的函数:
mov [ebp-04],00000005
call <some function call here>
据我所知,这似乎是将堆栈顶部的第二个字节设置为值5
。
这是否有效地将参数5传递给函数?
它是否与C
中的以下内容类似:
void someFunction(int num); //function declaration
someFunction(5); //In some context
如果将单个参数5传递给函数,为什么将其设置为第二个字节(-04),而不是堆栈的顶部?什么是堆栈的顶部?我解释这一切都错了吗?
修改
函数的顶部是ebp
设置的位置:
push ebp
mov ebp,esp
push -01
push 184
mov eax,fs:[00000000]
... //bunch more pushes and movs with eax and ecx into [ebp-offset]
... //a couple of jump if equals
... //some more push and movs
lea ecx,[ebp-1C]
mov [ebp-04],00000005
call <some function>
这是被调用的函数:
mov edx,[ecx]
mov eax,[ecx+08]
sub eax,edx
test edx,edx
je <label1>
cmp eax,00000080
jna <label2>
push edx
call <another function>
add esp,04
ret
label2:
push eax
push edx
call <yet another function>
add esp,08
label1:
ret
答案 0 :(得分:2)
您显示的示例不是向函数传递值。至少它不是一个典型的电话。
使用fs
寄存器通常是try / catch设置。
如果这确实是函数的整个序列(特别是被调用的函数)那么
...这里可能只设置了一些局部变量。
mov [ebp-04],00000005
...这里似乎是一个要在ECX寄存器中传递的参数器
lea ecx,[ebp-1C]
大多数编译的程序使用ebp
寄存器作为堆栈上局部变量的基指针。然后使用[ebp-X]
对各个变量进行寻址,其中X是每个变量的偏移量。例如,如果您有两个本地int变量,那么当这两个变量被解决时,您会看到[ebp-4]
和[ebp-8]
。
答案 1 :(得分:1)
ebp
不是堆栈指针,即esp
。 ebp
通常用作帧指针,因此根据它的设置方式,它可能确实将5
作为参数传递。或者它可能只是将其存储在局部变量中。
此外,如果不知道函数本身,可能无法判断它是本地参数还是函数参数:
int x = 5;
foo();
可能生成与foo(5);
帧指针用于指向当前函数的堆栈区域的开头,并且必须由序言中的函数本身设置。参数高于它(正偏移)本地低于它(负偏移)。请注意,在32位和64位模式下(在x86上),您并不真正需要它,因为您可以直接相对于堆栈指针esp
进行寻址。但在某些情况下,它可能很有用,例如用于调试目的。
答案 2 :(得分:1)
通常通过将参数放入寄存器或将它们推入堆栈,然后调用目标子例程来传递参数。
EBP通常包含指向堆栈帧的指针,而不是堆栈顶部。所以你的例子似乎很奇怪,至少它看起来不太可能是一个传递操作的参数。它可能是与正在进行呼叫的功能相关的一些其他动作。
是编译器生成的代码吗?如果是这样,编译器可能知道ESP和EBP之间的关系(通常在将函数ESP复制到ESP中时)并且可能正在利用该知识。你需要弄清楚之前设置EBP值的位置;显示代码会很有帮助。