The only difference in X64 ABI (Application binary interface) for standard and varargs is that floating point arguments are passed in XMM registers and standard registers, all other characteristics are the same:
1. The first 4 parameters are passed in registers as FASTCALL. Parameters in excess of 4 are passed on the stack.
2. The parameters from 8 up to 64 bits are passed in registers
right justified. Means that a char parameter will occupy the lower 8 bits of the register, a widechar the lower 16 bits, an int the lower 32bits and an I64 the whole register. The same system is used for parameters on the stack that has always a dimension of 64bits, menaing that each push or pop is 64bits wide (this is also an HW requirement when the CPU is in x64 mode). Please see
MSDN documentation[
^]:
Quote:
The first four integer arguments are passed in registers. Integer values are passed (in order left to right) in RCX, RDX, R8, and R9. Arguments five and higher are passed on the stack. All arguments are right-justified in registers. This is done so the callee can ignore the upper bits of the register if need be and can access only the portion of the register necessary.
3. Other size in excess of 64 bits, i.e. __m128, are passed only by reference. The compiler creates an hidden local copy of the variable then pass the pointer to such hidden copy.
All information are available on the MS site
here[
^]. Reading carefully you'll get all you need.
EDIT to add explanation due to answer upgrade.
The way used by compiler for the
right justify are compiler specific, so it could be a simple byte move, a sign extended move to a 16, 32 or 64bits. In your case the first four instructions depends on the cast you applied.
Please refer to the code:
char ch1 = 'A';
wprintf(L"%c %d %ld %lld", ch1, (short)ch1, (__int32)ch1, (__int64)ch1);