amd64 sysv calling convention

char size 1 | align 1
8-bytes:
#0 INTEGER
short size 2 | align 2
8-bytes:
#0 INTEGER
int size 4 | align 4
8-bytes:
#0 INTEGER
long size 8 | align 8
8-bytes:
#0 INTEGER
float size 4 | align 4
8-bytes:
#0 SSE
double size 8 | align 8
8-bytes:
#0 SSE

void foo( );

Allocated registers:

Notes

(from the AMD64 SysV ABI)

Arguments are first classified into classes that have corresponding amd64 registers.

These are:

INTEGER - types that fit into general purpose registers
SSE - types that fit into vector registers
SSEUP - types that fit into the upper bytes of vector registers
MEMORY - types to be passed on the stack

(n.b. there are more classes for more complex unimplemented types)

Classification:

Arguments are rounded up to 8 bytes (8-bytes from now on).

Scalars are assigned the following classes:

  • char, short, int, long, long long and pointers are classified as INTEGER
  • float and double are classified as SSE

Classification of aggregate types:

  1. If the object is larger than four 8-bytes, or if it contains unaligned fields it is classified as MEMORY.
  2. If the size of the object is larger than a single 8-byte then each 8-byte gets classified individually. The initial class of each 8-byte is set to NO_CLASS.
  3. The class of an 8-byte is determined by recursively combining the classes of the fields of an object that overlap this 8-byte.
    1. If both classes are equal, this is the resulting class.
    2. If one class is NO_CLASS, the result is the other class.
    3. If one class is MEMORY, the result is MEMORY.
    4. If one class is INTEGER, the result is INTEGER.
    5. Otherwise the class is SSE.

Post-processing for aggregate types:

  • If one of the classes is MEMORY then the entire argument is passed in memory.
  • If the size of the object is larger than two 8-bytes and the first 8-byte isn't SSE and if any other 8-byte isn't SSEUP then the whole object is passed in memory.
  • If SSEUP is not preceded by SSE or SSEUP, it is converted to SSE.

After classification arguments are assigned their registers in order.

  • If the class is MEMORY, pass it on the stack.
  • If the class is INTEGER, pick the next available register from the list:
    • %rdi, %rsi, %rdx, %rcx, %r8, %r9,
  • If the class is SSE, pick the next available register from %xmm0 to %xmm7
  • If the class is SSEUP, pick the next available 8-byte in the last used vector register.
  • If there are no more registers available for any 8-byte of an object, pass the entire object in memory. Previous register assignments are discarded.

After registers are assigned, the arguments passed in memory get pushed onto the stack in reverse order.

*** This is how I understood the ABI. Not necessarily correct.