Search code examples
assemblyvisual-c++x86alloca

Trying to understand the Assembly implementation of the alloca() function on x86


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.


Solution

  • 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.