1

I have created a sample code because I am trying to get myself into assembly. I declare and initalize an integer on the stack, and also do the same for one that is on the heap. When looking at the assembly code both of them produce pretty lookalike code:

mov dword ptr [ebp-8],0     ; this is on the stack
mov dword ptr [ebp-14h],0   ; this is on the stack

mov eax,dword ptr [ebp-20h] ; this is on the heap
mov dword ptr [eax],0       ; this is on the heap

Can you please shed some light on this what am I overlooking?

Relevant part of the disassembly can be found underneath:

    int x = 0;
00111848  mov         dword ptr [ebp-8],0  
    int y = 0;
0011184F  mov         dword ptr [ebp-14h],0  
    int* z = new int;
00111856  push        4  
00111858  call        00111325  
0011185D  add         esp,4  
00111860  mov         dword ptr [ebp+FFFFFF14h],eax  
00111866  mov         eax,dword ptr [ebp+FFFFFF14h]  
0011186C  mov         dword ptr [ebp-20h],eax  
    *z = 0;
0011186F  mov         eax,dword ptr [ebp-20h]  
00111872  mov         dword ptr [eax],0  
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
geo10
  • 366
  • 2
  • 11
  • 4
    Hint: Both places live in memory. – NathanOliver Jan 22 '20 at 21:04
  • 3
    Note that the pointer itself (i.e., `int* z`) is created on the stack as well. – JFMR Jan 22 '20 at 21:05
  • 1
    The compilers optimizer has *very* free hands to transform your code, as long as it behaves "as if" no optimizations have taken place as far as the C++ abstract machine is concerned. So, generated assembly for an *actual* machine can often be surprising. Why is this a concern to you? As long as the program executes according to the specification of the language, you shouldn't need to care how that result is accomplished. – Jesper Juhl Jan 22 '20 at 21:07
  • 1
    Please post the associated C++ source code. – Thomas Matthews Jan 22 '20 at 21:29
  • 2
    The code sequences aren't really the same. There's one more indirection with the assignment to `*z` than to `x` and than to `y`. (Also, `*z` is heap allocated by a library call, which the other two don't have at all.) – Erik Eidt Jan 22 '20 at 21:49
  • 3
    `mov dword ptr [ebp-14h],0` vs `mov eax,dword ptr [ebp-20h]; mov dword ptr [eax],0` does not look lookalike to me. There are even 2 assembly commands vs 1. Otherwise you can say that all assembly code is the same. – Slava Jan 22 '20 at 21:59
  • @ThomasMatthews: The C++ statements are there, interleaved with the disassembly. e.g. from `objdump -S -Mintel` after compiling with `g++ -m32 -O0 -g` un-optimized debug mode, with these statements in the body of any function. (It's un-optimized so surrounding context doesn't matter. Looks exactly like what you'd expect for those statements from `g++ -O0`. Or maybe MSVC; storing/reloading the return value of `new` to a temporary before finally storing it to `int *z` is a little weird.) – Peter Cordes Jan 23 '20 at 03:30
  • Not sure what compiler you're using, so I can't say for sure, but i'd bet that your compiler is making a lot of changes because it knows what's best. Most compilers will make changes to your code as a way of optimizing it. – Gabe Spound Jan 22 '20 at 21:09

2 Answers2

7

Both

int y = ....;

and

int* z = ....;

create an automatic variable (i.e. on stack). One is an integer and the other is a pointer.

First is initialised with a 0, and the other is initialised with new int. This creates the dynamic object, and results a call to the memory allocation function call 00111325.

eerorika
  • 232,697
  • 12
  • 197
  • 326
2

Both stack and heap are located in RAM, hence access to them looks similar.

On 32-bit x86, the stack pointer is in the esp register, and ebp is usually used as a "frame pointer". Function's local variables reside in memory just below ebp, since on x86 the stack grows downwards.

mov dword ptr [ebp-8], 0 means "write 4 zero bytes to memory at location [ebp-8]".

call 00111325 allocates a block on the heap and returns the address in eax.

mov dword ptr [ebp-20h], eax means to write eax at [ebp-20h] (that's where int *z is located on the stack).

mov dword ptr [eax], 0 then writes 0 at wherever address eax contains.

rustyx
  • 80,671
  • 25
  • 200
  • 267