The great thing about calling conventions on the x86
platform is that there are so many to choose from! In the 16-bit world, part of the calling convention was fixed by the instruction set: The BP
register defaults to the SS
selector, whereas the other registers default to the DS
selector. So the BP
register was necessarily the register used for accessing stack-based parameters.
The registers for return values were also chosen automatically by the instruction set. The AX
register acted as the accumulator and therefore was the obvious choice for passing the return value. The 8086 instruction set also has special instructions which treat the DX:AX
pair as a single 32-bit value, so that was the obvious choice to be the register pair used to return 32-bit values. That left SI
, DI
, BX
and CX
. (Terminology note: Registers that do not need to be preserved across a function call are often called “scratch”.)
When deciding which registers should be preserved by a calling convention, you need to balance the needs of the caller against the needs of the callee. The caller would prefer that all registers be preserved, since that removes the need for the caller to worry about saving/restoring the value across a call. The callee would prefer that no registers be preserved, since that removes the need to save the value on entry and restore it on exit.
If you require too few registers to be preserved, then callers become filled with register save/restore code. But if you require too many registers to be preserved, then callees become obligated to save and restore registers that the caller might not have really cared about. This is particularly important for leaf functions (functions that do not call any other functions).
The non-uniformity of the x86
instruction set was also a contributing factor. The CX
register could not be used to access memory, so you wanted to have some register other than CX
be scratch, so that a leaf function can at least access memory without having to preserve any registers. So BX
was chosen to be scratch, leaving SI
and DI
as preserved.
Blogpost series by Raymond Chen:
Additional links: