Parameter passing and calling conventions

Parameters are passed to functions on the parameter stack. In general, parameters are pushed from left to right, so the rightmost parameter is the last one pushed (and therefore the one at the lowest position on the parameter stack). Provided that there are no local variables, the last parameter is at offset zero on the parameter stack.

Parameter passing in presence of a prototype

In presence of a prototype, parameters are pushed as their respective types. This does especially mean that characters are pushed as such and are not promoted to integers.

Parameter passing without a prototype

If no prototype is available, the default promotions are applied before pushing parameters. This means that characters are promoted to integer before pushing them.

Variable argument lists

Parameters in variable argument lists (ellipsis, ) are treated the same as if there were no prototype.

The ''fastcall'' calling convention

If a function is declared as __fastcall__ (or fastcall), the last (rightmost) parameter is not passed on the stack, but passed in the primary register to the called function. This is A in case of an eight bit value, A/X in case of a 16 bit value, and A/X/sreg in case of a 32 bit value.

If the called function is a C function, its first instruction will be a call to one of the push functions to push the passed value onto the stack. This means that for C functions fastcall doesn't make the code really faster. Assembler functions however, can take advantage of the values passed in registers.

Although fastcall doesn't help making C functions faster it usually helps making the whole program somewhat smaller as all the callers of a fastcall function can omit one call to a push function.

Callee cleans up the stack

Contrary to most other C compilers, the callee is responsible for cleaning up the stack (dropping stack space used for parameters) before returning. This is done in order to generate smaller code, since dropping parameters can in many places be combined with dropping local variables.


The following example assume that there are no local variables. Presence of local variables would change the stack offset of the parameters in the function.


void foo (unsigned bar, unsigned char baz);

Stack layout within the function:

           | High byte of bar |
Offset 2 ->+------------------+
           | Low byte of bar  |
Offset 1 ->+------------------+
           | baz              |
Offset 0 ->+------------------+

Example code for accessing bar. The variable is in A/X after the code snippet:

        ldy     #2              ; Offset of high byte of bar
        lda     (sp),y          ; High byte now in A
        tax                     ; High byte now in X
        dey                     ; Offset of low byte of bar
        lda     (sp),y          ; Low byte now in A
cc65/parameter_passing_and_calling_conventions.txt · Last modified: 2010-05-30 18:44 by uz
Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki