I am very new to assembly and I am currently reading a book called Reverse Engineering for Beginners and I got to the part that talks about memory allocation on the stack. I understand (I think) the concept of stack allocation but in the example there was something that I didn't understood and I'll be happy if anyone here can help.
The book give this function as an example:
#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);
};
I understand what the C function does. It allocates 600 bytes of memory on the stack and than writes to that space the string "hi!" using the _snprintf
function. Then the function prints it.
All good for now. After that the book gives the assembly implementation that the MSVC compiler produced and the code looks like this:
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
Here I understand that the EAX
register will contain the argument for the __alloca_probe_16
function.
but now something doesn't make sence to me. From what I understand the function __alloca_probe_16
basically just subtracts the number of bytes that is in the value of EAX
from ESP
.
So for example if ESP
points to 1000 now it points to 400. Then we store the 400 into ESI
and start pushing arguments of _snprintf
to the stack and ESI
is pointing to the location of where the function needs to start writing data to.
So my problem is this, if both the ESP
and ESI
registers point to 400 and I allocated memory from 1000-400 (600 bytes), and I start pushing things onto the stack, won't they go in to the position starting from 400 and decreasing? I mean, why did it subtract 600 byte if it is not using them?
In my eyes this is how the stack looks like after the push esi
line.
| 400 |
| 600 |
| adrr of string |
| 1 |
| 2 |
| 3 | 400 , ESP , ESI
| | ...
|_______________________| 1000
I know that I am probably wrong and didn't understand something right because I don't think the book is wrong, I'll be happy if someone can help me to understand what is happening in this assembly code.
so for example if the ESP points to 1000 now it points to 400. then we store the 400 into ESI and start pushing arguments of the _snprintf to the stack and ESI is pointing to the location of where the function needs to start writing data to.
Right.
So my problem is this, if both the ESP and ESI registers point to 400 and I allocated memory from 1000-400 (600 bytes), and I start pushing thing into the stack, won't they go in to the position starting from 400 and decreasing?
Yes, certainly they will.
I mean , we did I subtracted 600 byte if i am not using them?
You haven't used that space yet, but you've made it available so that snprintf
has a place to write the string it produces, and you passed it address 400 (which was in ESI) to tell it to do so. When snprintf
returns, the string "hi! 1, 2, 3 \n"
will be stored starting at address 400.
Of course you didn't really need 600 bytes for such a short string; that's just an example for illustration. You could make it smaller if you want.