Chapter Contents

Previous

Next
Communication with Assembler Programs

Calling Conventions for C Functions

The following sections discuss calling conventions for C functions.


C Parameter Lists

Generally, C passes arguments by value rather than by reference. This means that the parameter list contains the actual argument values instead of pointers to the arguments. Suppose that the extern function f is called with the following arguments:

int i;
char c;
short s;
double d;
char *p;
f(i, c, s, d, p);

The parameter list generated by the compiler in this case would be mapped in assembler language as follows:


Typical C Parameter List
PARMBLOK DS 0D DS F value of i DS F value of c (promoted to int) DS F value of s (promoted to int) DS F uninitialized padding bytes DS D value of d DS A value of p

Note that c has been placed in byte 3 of a word, s has been placed in the second halfword of a word, and d is aligned on a doubleword boundary. The parameter list itself is always aligned on a doubleword boundary.

Many assembler routines expect their arguments to be passed by reference instead of by value. In some cases, this type of parameter list can be generated by simply applying the ampersand ( & ) operator to each argument. However, this solution is insufficient for function calls using arguments that are not lvalues, such as constants or expressions. To support such function arguments, the compiler accepts the (nonstandard) at-sign ( @ ) operator. The @ operator can be applied only to function arguments. When applied to an lvalue, the @ operator has the same effect as the & operator. When applied to a function argument that is not an lvalue (such as a constant), the @ operator returns a pointer to a temporary copy of the value. (See The @ operator. Note that the @ operator can be used only in conjunction with the at compiler option.)

Also, many assembler routines accept varying-length parameter lists. These routines typically expect that the last parameter has the high-order bit (the VL-bit) set to indicate that it is the final parameter. The compiler can be made to create this sort of parameter list by using the _ _asm keyword in the function declaration.

To show how the @ operator and the _ _asm keyword can be used, suppose the function f in the previous example is called as follows:

_ _asm void f();
char c;
short s;
char *p;
f(@(2+3), @c, @s, @1.0, @p);

Then the compiler creates a parameter list, as shown in C Parameter List Using Keyword _ _asm and the @ Operator.


C Parameter List Using Keyword _ _asm and the @ Operator
PARMBLOK DS 0D DS A pointer to a temporary 5 DS A pointer to c DS A pointer to s DS A pointer to a temporary 1.0 DS A pointer, with VL-bit set, to p

An OMD listing may be extremely helpful in determining the exact format of any parameter block.


_ _asm, _ _ref, and _ _ibmos Keywords

The _ _asm , _ _ref , and _ _ibmos keywords are used to declare functions and pointers to functions written in assembler language that expect a parameter list in OS format.

If the _ _asm keyword is used in a declaration of a function or function pointer, the compiler creates a VL-format parameter list for the function. The compiler uses the following conditions to create a VL-format parameter list:

The following declaration causes the compiler to create a VL-format parameter list for asm_func :

_ _asm int asm_func(void *, void *);

If the _ _asm keyword is used in the declaration of a function pointer, the function pointer is assumed to be local unless the _ _remote keyword is explicitly used. The following declaration causes the compiler to create a VL-format parameter list for the function called via asm_fp :

_ _asm int (*asm_fp)(void *, void *);

The _ _asm keyword does not cause the compiler to generate a call-by-reference parameter list; that is done by the _ _ref keyword, described below. You can also use the @ (at sign) operator to pass individual parameters by reference. Refer to The @ operator for more information on this operator.

The _ _ref keyword can be used in function declarations and function pointer declarations. This keyword specifies that the called function is an assembler language function expecting a call-by-reference parameter list in VL format. The effect of using the _ _ref keyword is similar to using the _ _asm keyword and the @ operator together, with the @ operator implied for all non-pointer arguments.

The parameter list created for functions declared with the _ _ref keyword, or called via a function pointer declared with the _ _ref keyword, contains only pointers. In general, if the argument is already a pointer type, such as char * , the argument is used directly without further indirection. If the argument is not a pointer type, the compiler places a pointer to the argument in the parameter list. The parameter list is in VL format as described above.

If the function is declared with a prototype, all arguments are converted to the type specified by the prototype. If the argument must be converted to match the type specified in the prototype, the compiler creates a temporary variable, assigns it the value of the argument, and passes a pointer to the temporary variable. For example, consider the declaration and call shown here:

_ _ref void myfunc(short);
int i;
i = 2;
myfunc(i);

The compiler creates a temporary short variable, assigns it the value of i , and places a pointer to the temporary variable in the parameter list.

Since the compiler passes a pointer to a temporary copy of the argument instead of to the argument itself, the called function cannot change the value of the argument. If changes to the argument by the called function must be reflected in the calling function, be sure to use an argument of the same type.

If the argument already has the type specified in the prototype, or if the argument is an int or long type and the prototype specifies a type that differs only in sign, no conversion is performed. For example, if the prototype specifies unsigned int and the argument is signed int , no conversion is performed and a pointer to the argument is placed in the parameter list.

Like _ _asm , if the _ _ref keyword is used in the declaration of a function pointer, the function pointer is assumed to be local unless the _ _remote keyword is explicitly used. See Remote Function Pointers for more information.

Using the _ _ibmos keyword in a declaration is the same as specifying the name of the function or function pointer in a #pragma linkage (,OS) statement. Refer to The #pragma linkage statement for more information. You may find it easier to use the _ _ibmos keyword to declare function pointers in certain situations, such as in the declaration of aggregate types. For example:

struct XYZ {
   /* other structure members */
   _ _ibmos int (*fp)(int, int);
   /* other structure members */
};

Function pointers declared with the _ _ibmos keyword are always local. Specification of both _ _ibmos and _ _remote results in an error.

The _ _asm , _ _ref , and _ _ibmos keywords may not be used in a declaration with any ILC function keywords, such as _ _pascal . Unless there is an attempt to convert a local function pointer to a remote function pointer, _ _asm , _ _ref , and _ _ibmos function pointers may be freely converted to each other.


Linkage Conventions

The compiler uses standard linkage when calling a function. For example, the function f is called with the following instructions:

L 15,=V(F)    R15 addresses the function.
LA 1,PARMBLOK R1 addresses the function arguments.
BALR 14,15    R14 contains the return address.

Also, R13 points to an 18-word save area.

The register conventions illustrated above are summarized in Register Conventions for Function Calls.

Register Conventions for Function Calls
General Register Contents on Entry to the Function
1 addresses parameter list
13 18-word save area
14 return address
15 entry point address

The called function is expected to restore general registers 2 through 13 before returning. Restoring other general registers is optional. The compiler generates code when necessary to save floating-point registers before calling the function and restores them on return.

If an assembler language routine uses the access registers, and any calling routine was compiled with the armode compiler option, it is the responsibility of the assembler code to save the access registers on entry and restore them on exit. Note that any function called from C is called in primary address space mode.

Note:    armode is not supported for C++ code in Release 7.00  [cautionend]


Returning Values from Assembler Routines

If f returns a scalar value, the compiler expects the value to be in general register 15 unless the value is a double , long double , or float , in which case the value is expected to be in floating-point register 0. For example, suppose f is declared as a function returning int ; given the call

val = f(i, c, s, d, p);

the compiler may then generate the following code sequence:

L     15,=V(F)
LA    1,PARMBLOK
BALR  14,15       Call f.
ST    15,VAL      Store return value in val.

Or, if f is declared as returning double , the compiler may generate the following:

L     15,=V(F)
LA    1,PARMBLOK
BALR  14,15       Call f.
STD   0,VAL       Store return value in val.

If function f returns a structure or union value, the linkage is a little more complicated. In this case, a pointer to an area in which the return value should be stored is located 4 bytes before the parameter list. This pointer may be 0 if the function result is discarded as the result of being cast to void . In addition to copying the return value to the area addressed by the return value pointer, the function must also clear the pointer before returning, or a later call whose return value is discarded may cause overlay of the previous return value.

This is an example of generated code for a call to a function S returning a structure:

LA    2,SRET           Address return code.
ST    2,PARMBLOK-4     Store before parameter list.
L     15,=V(S)
LA    1,PARMBLOK
BALR  14,15

This is an example of generated code in S to return a structure value:

L     2,DSAPARMS          Locate incoming parameter list.
        S     2,=F'4'             Back up one word.
        ICM   3,B'1111',0(2)      Test for void return.
        BZ    NOVAL
        MVC   0(slen,3),SRET      Copy return value.
        MVC   0(4,2),CRABZERO     Zero return value address.
NOVAL   DS    0H

When a function returning a far pointer is called, the compiler expects its value to be returned in access register 15 and general register 15. An example of compiler-generated code to call a routine returning a far pointer follows:

   L    15,=V(F)
   LA   1,PARMBLOK
   BALR 14,15        Call f.
   STAM 15,15,VAL    Store returned ALET in val word 1.
   ST   15,VAL+4     Store returned pointer in val word 2.

When a function returns a long long (or unsigned long long value), the result is returned in registers 15 and 0. Register 15 contains the high-order 4 bytes, and register 0 the low-order 4 bytes.


Chapter Contents

Previous

Next

Top of Page

Copyright © 2001 by SAS Institute Inc., Cary, NC, USA. All rights reserved.