3.11.2 Calling Conventions

GNAT follows standard calling sequence conventions and will interface to any other language that also follows these conventions. The following Convention identifiers are recognized by GNAT:

Ada

This indicates that the standard Ada calling sequence is used and all Ada data items may be passed without any limitations in the case where GNAT is used to generate both the caller and callee. You can also mix GNAT generated code and code generated by another Ada compiler. In this case, you should restrict the data types to simple cases, including primitive types. Whether complex data types can be passed depends on the situation. It is probably safe to pass simple arrays, such as arrays of integers or floats. Records may or may not work, depending on whether both compilers lay them out identically. Complex structures involving variant records, access parameters, tasks, or protected types, are unlikely to be able to be passed.

If output from two different compilers is mixed, you are responsible for dealing with elaboration issues. Probably the safest approach is to write the main program in the version of Ada other than GNAT, so it takes care of its own elaboration requirements, and call the GNAT-generated adainit procedure to ensure elaboration of the GNAT components. Consult the documentation of the other Ada compiler for further details on elaboration.

Assembler

Specifies assembler as the convention. In practice this has the same effect as convention Ada (but is not equivalent in the sense of being considered the same convention).

Asm

Equivalent to Assembler.

COBOL

Data is passed according to the conventions described in section B.4 of the Ada Reference Manual.

C

Data is passed according to the conventions described in section B.3 of the Ada Reference Manual.

A note on interfacing to a C ‘varargs’ function:

In C, varargs allows a function to take a variable number of arguments. There is no direct equivalent in this to Ada. One approach that you can use is to create a C wrapper for each different profile and then interface to this C wrapper. For example, to print an int value using printf, create a C function printfi that takes two arguments, a pointer to a string and an int, and calls printf. Then in the Ada program, use pragma Import to interface to printfi.

It may work on some platforms to directly interface to a varargs function by providing a specific Ada profile for a particular call. However, this does not work on all platforms since there is no guarantee that the calling sequence for a two-argument normal C function is the same as for calling a varargs C function with the same two arguments.

Default

Equivalent to C.

External

Equivalent to C.

C_Plus_Plus (or CPP)

This stands for C++. For most purposes, this is identical to C. See the separate description of the specialized GNAT pragmas relating to C++ interfacing for further details.

Fortran

Data is passed according to the conventions described in section B.5 of the Ada Reference Manual.

Intrinsic

This applies to an intrinsic operation, as defined in the Ada Reference Manual. If a pragma Import (Intrinsic) applies to a subprogram, it means the body of the subprogram is provided by the compiler itself, usually by means of an efficient code sequence, and that you don’t supply an explicit body for it. In an application program, the pragma may be applied to the following sets of names:

  • Rotate_Left, Rotate_Right, Shift_Left, Shift_Right, Shift_Right_Arithmetic. The corresponding subprogram declaration must have two formal parameters. The first must be a signed integer type or a modular type with a binary modulus and the second parameter must be of type Natural. The return type must be the same as the type of the first argument. The size of this type can only be 8, 16, 32, or 64.
  • Binary arithmetic operators: ‘+’, ‘-’, ‘*’, ‘/’. The corresponding operator declaration must have parameters and result type that have the same root numeric type (for example, all three are long_float types). This simplifies the definition of operations that use type checking to perform dimensional checks:
    type Distance is new Long_Float;
    type Time     is new Long_Float;
    type Velocity is new Long_Float;
    function "/" (D : Distance; T : Time)
      return Velocity;
    pragma Import (Intrinsic, "/");
    

    You often program this common idiom with a generic definition and an explicit body. The pragma makes it simpler to introduce such declarations. It incurs no overhead in compilation time or code size because it is implemented as a single machine instruction.

  • General subprogram entities. This is used to bind an Ada subprogram declaration to a compiler builtin by name with back ends where such interfaces are available. A typical example is the set of __builtin functions exposed by the gcc back end, as in the following example:
    function builtin_sqrt (F : Float) return Float;
    pragma Import (Intrinsic, builtin_sqrt, "__builtin_sqrtf");
    

    Most of the gcc builtins are accessible this way, and as for other import conventions (e.g. C), it is the user’s responsibility to ensure that the Ada subprogram profile matches the underlying builtin expectations.

Stdcall

This is relevant only to Windows implementations of GNAT and specifies that the Stdcall calling sequence is used, as defined by the NT API. To simplify building cross-platform bindings, this convention is handled as a C calling convention on non-Windows platforms.

DLL

This is equivalent to Stdcall.

Win32

This is equivalent to Stdcall.

Stubbed

This is a special convention that indicates that the compiler should provide a stub body that raises Program_Error.

GNAT additionally provides a useful pragma Convention_Identifier that you can use to parameterize conventions and allow additional synonyms. For example, if you have legacy code in which the convention identifier Fortran77 was used for Fortran, you can use the configuration pragma:

pragma Convention_Identifier (Fortran77, Fortran);

And from now on, you can use the identifier Fortran77 as a convention identifier (for example in an Import pragma) with the same meaning as Fortran.