COHERENT manpages

This page displays the COHERENT manpage for calling conventions [Definition].

List of available manpages
Index


calling conventions -- Definition

The following presents the calling conventions for COHERENT.

The calling conventions of C take into account machine architecture and the
fact that the number of arguments  passed to a function may vary, as in the
functions printf() and scanf().

For example, consider the following C program, called foo.c:

    short a;
    long b;
    char c;

    foo()
    {
        example(a, b, c);
    }

Compiling this program with the command

    cc -S foo.c

generates the assembly-language code (with added comments):

     .alignoff
     .comm  a,      2    / a, b, and c are commons in the .bss
     .comm  b,      4
     .comm  c,      1

foo:
     .text
     .globl foo

foo:
     push   %ebp
     movl   %ebp, %esp
     movsxb %eax, c      / move c to %eax with sign extend
     push   %eax         / pass c
     push   b            / pass b
     movsxw %eax, a      / move a to %eax with sign extend
     push   %eax         / pass a
     call   example

     leave               / epilog code for foo
     ret
     .align 4

Note the following points:

-> Parameters are  pushed in reverse order.  You should  not depend on this
   feature, as the ANSI standard says that parameters may be calculated and
   pushed in any order.

-> The stack is reset by the caller, not the callee.  Only the caller knows
   the number of parameters pushed.

-> All parameters  become int or  double when passed  under Kernighan &
   Ritchie C.  This changes under ANSI C.

Now consider the module example.c, which gives the receiving end:

    double
    example(x, y, z)
    short x;
    long y;
    char z;
    {
        int tmp;

        tmp = x * y;
        return (tmp + z);
    }

The command

    cc -S example.c
generates the code:

     .alignoff

     .text
     .globl example

example:
     enter  $4, $0       / 4 bytes of local variables
     push   %edi
     movl   %eax, 12(%ebp)/ x * y
     imull  8(%ebp)      / 8 == 4 + sizeof(int)
     movl   -4(%ebp), %eax/ save into tmp
     movl   %edi, 16(%ebp)/ tmp + z
     addl   %edi, %eax   / return double in EDX:EAX
     movl   %eax, %edi
     call   _dicvt
     pop    %edi

     leave               / leave with result in %eax:%edx
     ret
     .align 4

After the prologue code, the stack always looks like

    =========================   <- High addresses
    | passed parameters     |
    =========================   4(%ebp)
    | return address        |
    =========================   <- %ebp
    | saved %ebp            |
    =========================   -4(%ebp)
    | local variables       |
    =========================
    | other saved registers |
    | may include %esi,     |
    | %edi and %ebx         |
    =========================   <- %esp

Notice that parameters start at

    [4 + first parm size](%ebp)

and go to higher addresses, whereas local variables start at

    -4(%ebp)

and  go to  lower addresses.   Therefore,  if you  have a  local array  and
overwrite it  in the forward direction, you clobber  your caller's %ebp; if
you  overwrite it  in  the backward  direction, you  clobber your  caller's
register variables  (although if the caller has  no register variable, it's
harmless).

On the 80386, the stack starts  at 0x80000000 and grows down being expanded
by  the system  as it  is  needed.  Reasonable  programs should  never have
stack-overflow problems, as they did under COHERENT 286.

Note  that  the  convention  for  returning floating-point  numbers  differ
depending upon whether a program uses software floating-point emulation, or
hardware floating-point  code as invoked  by the cc  option -VNDP. Programs
that use hardware floating point return double in the NDP stack top $st0.

See Also

C language,
Programming COHERENT,