Consider a compiled call sum = add(left, right). The source expresses a function call, but the machine-level contract is defined by the target architecture's application binary interface (ABI). Register choices and stack details differ by platform and compiler.
1. Evaluate and place arguments
The caller evaluates each argument. The ABI assigns some arguments to registers and any remaining arguments to stack locations, with rules for alignment and preserved registers. The compiler may keep values in registers or optimize the call away entirely when it can prove an equivalent result.
2. Transfer control
The call instruction records where execution should resume and branches to the callee. Some instruction sets place the return address in a link register; others push it or use another convention. This is why a universal “every call pushes a return address” explanation is inaccurate.
3. Build the callee's working state
If needed, the function adjusts the stack pointer, saves registers it must preserve, and reserves space for local values. A small leaf function may use no stack frame. The compiler can also inline the body, leaving no call boundary at runtime.
4. Return to the caller
The callee places the result in the ABI-defined location, restores preserved state, and executes a return sequence. The caller resumes after the call and reads the result. Debug symbols can map these machine instructions back to source locations; the source function itself is not necessarily a separate runtime object.
Inspect generated assembly for a specific target before generalizing. ABI rules are platform contracts, not properties of the C syntax alone.