1

I've been disassembling some executable files to learn assembly language. I compiled a very simple program with GCC and Visual Studio, and noticed a strange difference in passing arguments.

(cdecl) int some_function(int, int)

VS:

mov eax, [ebp+8]
push eax
mov ecx, [ebp+4]
push ecx
call some_function

GCC:

mov eax, [ebp+8]
mov [esp+4], eax
mov eax, [ebp+4]
mov [esp], eax
call some_function

Why does GCC use mov instead of push?

EDIT: This is the original program for reference.

int some_function(int a, int b) {
    return a + b;
}

int main(void) {
    int a = 1, b = 2;

    printf("string %d\n", some_function(a, b));
}
konsolas
  • 1,041
  • 11
  • 24
  • 2
    You will get a lot of noise if you don't turn on optimizations (without optimizations you usually see a lot of extra loads and stores). Without seeing the rest of the assembly code it could be the use of `mov` is related to maintaining some sort of alignment before making the call. Hard to say. Even seeing the original simple program you wrote may help. – Michael Petch Aug 30 '16 at 17:01
  • I've added the source code for the original program. – konsolas Aug 30 '16 at 17:26
  • I think the point here is trying to understand those loads and stores. With optimization this question and that understanding may be lost. – old_timer Aug 30 '16 at 17:55
  • 1
    I don't agree, you can tell the compiler not to inline when doing optimizations. Once you get rid of the noise you can take a look at what remains. After reviewing the GCC code it is clear the reason they are not using push is because the code is trying to guarantee the stack is 16-byte aligned prior to call to `some_function`. They pre-allocate the space (including call parameter space) so that `esp` remain 16-byte aligned just prior to the call. Using `push` would misalign it again. GCC's 32-bit ABI requires such alignment even on Windows. – Michael Petch Aug 30 '16 at 17:59
  • A description of the 32-bit ABI that GCC uses can be found [here](https://01.org/sites/default/files/file_attach/intel386-psabi-1.0.pdf) . In particular _Section 2.2.2 The Stack Frame_ says _"The end of the input argument area shall be aligned on a 16 (32, if __m256 is passed on stack) byte boundary. In other words, the value (%esp + 4) is always a multiple of 16 (32) when control is transferred to the function entry point. "_ – Michael Petch Aug 30 '16 at 18:15
  • I also suspect that the GCC compiler being used is circa 4.9 somewhere. Later versions of GCC may maintain the alignment but do so using push if it can. – Michael Petch Aug 30 '16 at 18:33

2 Answers2

0

Because this version of gcc allocates the memory on the stack for local variables and for parameters to be passed to a callee in the function prologue.

The Visual C compiler does so only for local variables and pushes callee's arguments onto the stack instead.

This is a language implementation dependent behavior. The gcc's approach allows better optimisation while evaluating the callee's parameters: the compiler may reorder evaluation without keeping in mind that the space for particular callee parameter is not allocated yet.

Serge
  • 6,088
  • 17
  • 27
0

Some compilers use esp as a base pointer.
If it were to use push esp would change. A changing base pointer would complicate it's use; esp. in loops.

By using mov [esp+x],reg instead of push the compiler can still 'push' arguments whilst keeping esp available as a base pointer.

It comes at a cost though. Modern CPU's have a stack engine.
By not using push the compiler circumvents the stack engine and its benefits.

Johan
  • 74,508
  • 24
  • 191
  • 319