Kenneth said:
Just curious...
How does one take the address of one of the first 4 parameters? (I
suppose the compiler would have to do something such as store it on
the stack temporarily and then take that address?)
Exactly.
Before calling a function you should subtract 32 bytes from the stack
pointer. The called procedure can (if it wants) store in that space
the values it received in the registers. Lcc-win64 does that in
a debug setting so that the debugger can figure out where the values
of the parameters are...
Note that I have seen implementations (long ago, I forget which
platform) which did exactly as you state -- the first N parameters to
non-varadic functions were passed in registers. (Yet another case of
"no prototype in scope for varadic function == UB".)
Variadic functions are QUITE difficult in this setting, and I
had a LOT of bugs in the code generation. Basically, I store all
the registers that could possibly carry an argument (rcx, rdx,
r8,r9,xmm0,xmm1,xmm2,xmm3) into a continuous stack area and
maintain a pointer to the integer or pointer part, and another
pointer to the floating point part. Up to 4 floating point values
could be passed in xmm0-xmm3. Since the procedure doesn't know
at the start what values are being passed to it, it must save
all of them and va_arg() will pull the corresponding value
from either
o the integer or pointer stack, or
o from the floating point stack
o or from the actual stack where values are passed like
structures or long doubles.
This is relatively easy. MUCH more complex are the linux 64 conventions
(a nightmare).