I have been following the excellent book Programming Ground Up, wanting to learn assembly. Although not in the book at this point, I wanted to call my assembly function from C. on a 32 bit machine, this works as is when working from the book.
What I do here is storing the first argument in %ebx
and the second in %ecx
.
.type power, @function
.globl power
power:
pushq %ebp
movl %esp, %ebp
subl $4, %esp
movl 8(%ebp), %ebx
movl 12(%ebp), %ecx
I compile this (and the rest of the function) into an object file, create a main.c, where I prototype the function and call it, something like this:
int power(int b, int x);
int a = power(2, 1);
However, when I compile this on a 64 bit machine, I get some very unexpected results. I modified the obvious, like the fact that %esp
and %ebp
needs to be replaced with %rsp
and %rbp
, but digging with GDB reveals that the arguments are nowhere to be found on the stack!
Checking out what happens by using the -S
option to GCC I can see that instead of pushing the variables on the stack, GCC stores the arguments in registers.
movl $1, %esi
movl $2, %edi
call power
On the 32 bit machine, it does what I expect and push the arguments on the stack:
movl $1, 4(%esp)
movl $2, (%esp)
call power
Now what is going on here? Why does GCC pass the arguments in registers on 64 bit and on the stack on 32 bit? This is very confusing! And I can't find any mention on this anywhere. Is there anyone who can enlighten me on this situation?
There are three major calling conventions that are used with the C language on 32-bit x86 processors: STDCALL, CDECL, and FASTCALL. In addition, there is another calling convention typically used with C++: THISCALL. There are other calling conventions as well, including PASCAL and FORTRAN conventions, among others.
Calling convention defaults The x64 Application Binary Interface (ABI) uses a four-register fast-call calling convention by default. Space is allocated on the call stack as a shadow store for callees to save those registers.
In Linux, GCC sets the de facto standard for calling conventions. Since GCC version 4.5, the stack must be aligned to a 16-byte boundary when calling a function (previous versions only required a 4-byte alignment). A version of cdecl is described in System V ABI for i386 systems.
A calling convention is a scheme for how functions receive parameters from their caller and how they return a result. The calling conventions can differ in where parameters and return values are placed (in registers; on the call stack; a mix of both), the order they are placed.
64-bit C calling convention is: %rdi, %rsi, %rdx, %rcx, %r8 and %r9
See full description here: "System V Application Binary Interface: AMD64 Architecture Processor Supplement" http://www.x86-64.org/documentation/abi.pdf
3.2 Function Calling Sequence
When I learned the same topic, I made small C programs with required functions, compiled them in 64 bit compiler and read the Assembly code produced by C compiler. C/C++ compiler can be used like kind of Assembly reference.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With