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
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
argc) of 4 bytes and one pointer to a
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
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
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
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!