First of all, you have to understand that there is a specification for all these things. These specifications differ from one assembly language to another and from one operating system to the other.
These global specification are called Application Binary Interface (ABI) and define, among other things, what we call the 'calling conventions' of functions. IDAPro seems to have found that your program is following the cdecl
convention but I doubt it is correct, I think that the calling convention used here is fastcall
within the amd64
SystemV ABI (see the wikipedia page about calling conventions). My guess is that you are using Linux...
So, the manipulation of rpb
and rsp
are just here to save the previous state of the stack-frame in order to restore it when you leave the function (you stack the content of rbp
on the stack with the hope that you will be able to restore it when you leave the function at the end). But, you already understood this.
The space allocation (sub rsp, 10h
) come from the fact that you have to store one int
(argc
) of 4 bytes and one pointer to a char*
(argv
) of 8 bytes. I know, when added it is only 12 bytes and not 16 bytes (10h
). But, the access in memory for the CPU have been optimized when they are aligned (meaning that they start at an address which is a power of 2, or, if you consider hexadecimal representation, the address must end with a 0
). So, the compiler decided to round-up the memory needed to align the data and be more efficient fetching it.
Then, you have the memory space available on the stack, now lets go fetch the data. So, for that you have to know what does the caller function before starting the function we are currently looking at.
In fact, the previous function, before calling the function we are in, has stored the arguments of our function in some registers. Here, it is important to agree that all the function (caller and callee) will use the same set of registers to pass the arguments from the caller to the callee.
So, usually, the first integer argument is stored in rdi
and the second in rsi
(the full list of registers is listed here. Here, as the first argument is argc
an int
, a 32-bit register is enough (4 bytes), so we use edi
in place of rdi
. And, as the second argument is a pointer (argv
), we need the full 64-bit register rsi
(8 bytes).
What do we do with this? Well, we store preciously argc
and argv
within our stack-frame in the memory we just allocated before.
Note that the address stored in rbp
will not change all along the life of the current stack-frame (as we need it at the end to perform a leave
and restore the address of the rbp
of the previous stack-frame). So, most of the compilers will use rbp
as point of reference to call the variables which are local to the current stack-frame. Thus, rbp+var_4
refer to argc
and rbp+var_10
refer to argv
from now.
Well, that is about all you really need to know about the fastcall
convention in Linux. Now, the program should be more understandble to you.
Hope this helped!