Question on calling conventions for syscalls/functions
Posted: Thu Jan 21, 2021 11:07 am
So, I know of the various calling conventions that x86 has (safecall, stdcall, vectorcall, ...). I also know that other architectures (RISC-V, ARM, ...) have dedicated registers for passing arguments to functions (e.g.: RISC-V has a0-A6). My question is mainly out of curiosity: vectorcall, for example, passes arguments in rcx, rdx, r8, r9, and then vector arguments in xmm0-xmm5. However, these register allocations seem arbitrary to me. X86 has 32 vector registers (and 96 if you have the full vector instruction set -- SSE all the way up to AVX-512). What I'm wondering is this:
1. Why don't we put all integer arguments in RAX, RBX, RCX, RDX, R8, R9, R10, ..., or use R8-R15 for arguments and RAX/RBX/RCX/RDX/RSI/... for return values?
2. For system calls, I've noticed that -- for example -- Linux uses EAX, EBX, ECX, and EDX fro arguments, but this is very different on x64. Why is this the case? Shouldn't it use the 64-bit RAX/RBX/... registers on x64 like it does on x86?
3. For vector arguments, vectorcall uses only XMM0-XMM5. So what happens to XMM6-XMM31, and why are they unused? Similarly, what about YMM/ZMM0-31?
4. Would it be okay for my OS to use the above (logical) calling convention, or would it break a lot, and how much effort would it require for me to add that to compilers/interpreters?
I know that this is primarily an x86-specific set of questions, but I'm just trying to understand why we don't use register arguments for parameter passing and return values as much as possible for all OSes, and use the stack for register spilling, whereas on other architectures registers seem to be used as much as possible before spilling onto the stack arguments that exceed the register count.
1. Why don't we put all integer arguments in RAX, RBX, RCX, RDX, R8, R9, R10, ..., or use R8-R15 for arguments and RAX/RBX/RCX/RDX/RSI/... for return values?
2. For system calls, I've noticed that -- for example -- Linux uses EAX, EBX, ECX, and EDX fro arguments, but this is very different on x64. Why is this the case? Shouldn't it use the 64-bit RAX/RBX/... registers on x64 like it does on x86?
3. For vector arguments, vectorcall uses only XMM0-XMM5. So what happens to XMM6-XMM31, and why are they unused? Similarly, what about YMM/ZMM0-31?
4. Would it be okay for my OS to use the above (logical) calling convention, or would it break a lot, and how much effort would it require for me to add that to compilers/interpreters?
I know that this is primarily an x86-specific set of questions, but I'm just trying to understand why we don't use register arguments for parameter passing and return values as much as possible for all OSes, and use the stack for register spilling, whereas on other architectures registers seem to be used as much as possible before spilling onto the stack arguments that exceed the register count.