I'm wondering how a struct is returned in something like:
typedef struct number {
uint64_t a, b, c, d;
}number;
number get_number(){
number res = {0,0,0,0};
return res;
}
which disassembles to
0000000000001149 <get_number>:
1149: 55 push rbp
114a: 48 89 e5 mov rbp,rsp
114d: 48 89 7d d8 mov QWORD PTR [rbp-0x28],rdi
1151: 48 c7 45 e0 00 00 00 mov QWORD PTR [rbp-0x20],0x0
1158: 00
1159: 48 c7 45 e8 00 00 00 mov QWORD PTR [rbp-0x18],0x0
1160: 00
1161: 48 c7 45 f0 00 00 00 mov QWORD PTR [rbp-0x10],0x0
1168: 00
1169: 48 c7 45 f8 00 00 00 mov QWORD PTR [rbp-0x8],0x0
1170: 00
1171: 48 8b 4d d8 mov rcx,QWORD PTR [rbp-0x28]
1175: 48 8b 45 e0 mov rax,QWORD PTR [rbp-0x20]
1179: 48 8b 55 e8 mov rdx,QWORD PTR [rbp-0x18]
117d: 48 89 01 mov QWORD PTR [rcx],rax
1180: 48 89 51 08 mov QWORD PTR [rcx+0x8],rdx
1184: 48 8b 45 f0 mov rax,QWORD PTR [rbp-0x10]
1188: 48 8b 55 f8 mov rdx,QWORD PTR [rbp-0x8]
118c: 48 89 41 10 mov QWORD PTR [rcx+0x10],rax
1190: 48 89 51 18 mov QWORD PTR [rcx+0x18],rdx
1194: 48 8b 45 d8 mov rax,QWORD PTR [rbp-0x28]
1198: 5d pop rbp
1199: c3 ret
From the disassembly it looks like before calling the function the required space is allocated on the stack and the function fills in those values.
But in the second part it looks like rdi
is treated as pointer to a number
struct where the values are also saved. What is that about?
And when using a C function in assembler how do I know where the result is?
A calling convention typically does not specifically dictate any code or code sequences, it dictates only state — such as registers and memory, which goes to parameter passing and the stack: where parameters and return values go, what state must be preserved by the call (i.e. some registers and allocated stack memory), and what is scratch (i.e. some registers, and memory below the current stack pointer). It may also dictate things like stack alignment requirements.
The calling convention speaks to state as per above: but only at very specific points in time, namely at the exact boundary when control is transferred from caller to callee, and again when control is transferred back from callee to caller. Thus, the callee has an expectation that the caller has setup all the parameters as expected before its first instruction runs. The caller has the expectation that the callee has setup all the return values (and preserved what ever it must preserve) before the first instruction of its resumption from the call.
For these purposes, the calling convention does not dictate machine code instructions or even sequences of instructions; it only establishes expectation of values and locations at the points of transfer.