我对汇编很陌生,我目前正在阅读一本名为《逆向工程初学者》的书,我进入了讨论堆栈内存分配的部分。我理解(我认为)堆栈分配的概念,但在示例中有些东西我不理解,如果有人能提供帮助,我会很高兴。
书中以这个函数为例:
#ifdef __GNUC__
#include <alloca.h> // GCC
#else
#include <malloc.h> // MSVC
#endif
#include <stdio.h>
void f()
{
char *buf=(char*)alloca (600);
#ifdef __GNUC__
snprintf (buf, 600, "hi! %d, %d, %d\n", 1, 2, 3); // GCC
#else
_snprintf (buf, 600, "hi! %d, %d, %d\n", 1, 2, 3); // MSVC
#endif
puts (buf);
};
我了解 C 函数的作用。它在堆栈上分配 600 字节的内存,然后将字符串“hi!”写入该空间。使用该_snprintf
功能。然后函数打印它。
目前一切都很好。之后,本书给出了 MSVC 编译器生成的汇编实现,代码如下所示:
mov eax, 600 ; 00000258H
call __alloca_probe_16
mov esi, esp
push 3
push 2
push 1
push OFFSET $SG2672
push 600 ; 00000258H
push esi
call __snprintf
push esi
call _puts
add esp, 28
在这里,我知道EAX
寄存器将包含__alloca_probe_16
函数的参数。但现在有些东西对我来说没有意义。据我了解,该函数基本上只是减去from__alloca_probe_16
值中的字节数。EAX
ESP
例如,如果ESP
指向 1000 现在它指向 400。然后我们将 400 存储到ESI
并开始将参数压_snprintf
入堆栈,并ESI
指向函数需要开始写入数据的位置。所以我的问题是,如果ESP
和ESI
寄存器都指向 400 并且我从 1000-400(600 字节)分配内存,并且我开始将东西压入堆栈,它们不会进入从 400 开始的位置并减少? 我的意思是,如果不使用它们,为什么要减去 600 字节?在我看来,这就是堆栈在行后的样子push esi
。
| 400 |
| 600 |
| adrr of string |
| 1 |
| 2 |
| 3 | 400 , ESP , ESI
| | ...
|_______________________| 1000
我知道我可能错了并且没有理解正确的东西,因为我认为这本书没有错,如果有人能帮助我理解这段汇编代码中发生的事情,我会很高兴。