Kenneth Brody wrote:
jacob navia wrote:
>santosh wrote:
>>Programs written to use the Windows API use Microsoft's "stdcall"
convention.
That was true under 32 bit windows. 64 bit windows uses "fastcall"
everywhere. It is a convention where 4 registers hold the
first 4 parameters of the function. With 64 bit wide registers
you can pass a long long in a register now.
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?)
If you're careful to distinguish between "parameter" and
"argument" the answer should be clear. An "argument" is a
value provided by the caller, and a "parameter" or "formal
parameter" is a function-local variable initialized from an
argument value. If a calling convention requires the first N
argument values to be passed in registers, that doesn't mean
the first N parameters need to reside in registers throughout
their lifetimes. (Turn it around: If the argument values arrive
on a stack, does that mean the optimizer can't put the parameters
in registers?)
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".)
SPARC has done this since it was first designed. The
first N argument values are passed in registers, even for
variadic functions. (Consequence: The <stdarg.hmachinery
is more involved than for memory-only calling conventions.)
Alpha uses registers to carry at least some arguments;
it's been a long time since I worked with Alpha machines and
I've forgotten the details.
It's my informal impression that most CPU designs less
than about two decades old pass at least some argument values
in registers; registers nowadays are a few decimal orders of
magnitude faster than memory (although that's not an entirely
fair comparison, what with store buffers and caches and all).
The CPUs that rely heavily on memory-resident arguments seem
to be those that have backward-compatibility issues with older
designs.
By the way, sometimes the "argument" value passed by the
calling convention isn't exactly the same as the "argument"
as seen in the C source. For example, some calling conventions
pass struct- and union-valued arguments by putting them in
unnamed memory-resident temporaries and passing pointers instead.
Some functions that return struct or union values are implemented
as if they were void functions with an extra, hidden argument
that points to a result location. What you see in the C may be
a little different than what you see in the debugger.
--
Er*********@sun.com