I'm exploring variadic functions, particularly the assembly it gets compiled to. Let's imagine we have a variadic function which calls a function from within it. With reference to the example file below,
#include <stdio.h>
void foo(int arg1, int arg2) {}
void sum(int num_args, ...) {
foo(69, 420);
}
int main(int argc, const char **argv) { sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); }
I then this with the gcc -S flag and saw that the argument registers %rdi through r9 (values 1 through 6 passed to sum) were pushed onto the stack at specific offsets (%rbp - 180, 168, 160, 152, 144, 136, respectively).
My questions are:
- Why does
rdiget 12 bytes when it's at most 8 bytes? Or is that an incorrect assumption? - Why these arbitrary addresses instead of simple push operations? Is this something I can know a priori without having to tinker/dig into the gcc source?
Thanks
For context, I'm trying to implement an interface for variadic argument management similar to stdarg.h to explore what's going on under the hood and practice writing x86. Not being able to know where the compiler stores the variadic caller's arguments before making calls to functions such as va_start etc. makes it quite difficult to achieve. Ideally I'd want a portable way to know where the arguments are being stored (well, as portable as an x86 routine can be)