Chapter Contents

Previous

Next
Code Generation Conventions

Function Pointers

SAS/C software allows two types of function pointers, remote and local. Function pointers of each type may be declared using the nonstandard keywords _ _remote and _ _local . Function pointers are remote by default. Normally, you do not need to be concerned with the details of function-pointer implementation. If all of your programs are in C, the compiler takes care of setting up the pointer and calling a function through the pointer. This section provides information for users who have to build or use C function pointers in assembler language routines, who have to map between function pointers and data pointers, or who need to know the details of function-pointer implementation for some other purpose.


Remote Function Pointers

By default, all function pointers are remote. You can also explicitly declare a remote function pointer using the positional type qualifier keyword _ _remote . For example:

int _ _remote (*remote_fp)(void);

Remote function pointers are 4 bytes long and are aligned on a fullword boundary. They are indirect, that is, they do not point directly to executable code. Remote function pointers can call a function in another load module which has a different pseudoregister vector. A remote function pointer must define both the address of the called function and the new pseudoregister vector. An indirect implementation makes it possible for remote function pointers to contain both pieces of data. A remote function pointer points to an object containing two 4-byte addresses. The first address is the address of the function, the second is the address of the pseudoregister vector for the load module containing the function. For more information, refer to External Variables.

Use the following procedure to call a function through a remote function pointer in assembler language:

  1. Load the function pointer into general register 15.

  2. Save the value in CRABPRV in a general register.

  3. Copy the second fullword addressed by general register 15 (the new pseudoregister vector address) into CRABPRV. If the called function is in the same load module as the calling function, the new address will be the same as the old address, but it is quicker to move it than it is to check.

  4. Load the address in the first fullword (the called function address) into general register 15 and call the function with a standard BALR 14,15.

  5. When the called function returns, restore the old value of CRABPRV from the general register in which it was saved.

CRABPRV is a field containing the address of the pseudoregister vector for the currently executing load module. During program execution, this field is always located at offset decimal 12 from the address in general register 12.

The following example illustrates this procedure:


Sample Assembler Language Routine for Calling a Function with a Remote Function Pointer
L R15,FUNCPTR Load function pointer into R15. L RX,12(,R12) Save current pseudoregister vector address. This assumes that R12 has the CRAB address. MVC 12(4,R12),4(R15) Copy new pseudoregister vector address into CRABPRV. L R15,0(,R15) Load function address into R15. BALR R14,R15 Call the function. ST RX,12(,R12) Restore old pseudoregister vector address. . . . FUNCPTR DS A

If you are using the norent compiler option, the format of a remote function pointer that has not yet been used to call a function is slightly different. A function pointer in this state addresses an object containing three addresses. The first is the address of a library routine (L$CFNAD), the second addresses the object itself, and the third addresses the entry point of the function. The procedure for calling a function through a function pointer in this format is no different from that outlined above. Steps 2, 3, and 5 (the psuedoregister vector address swap) must be performed. You can identify a function pointer in this format by testing bit 0 of the second address. If the bit is set to 1, the function pointer is in this format.


Local Function Pointers

Local function pointers are 4 bytes long and aligned on a fullword boundary. A local function pointer points directly to the entry point of the function.

To declare a local function pointer, specify the keyword _ _local preceding the open parenthesis of the function pointer declaration, as in the following example:

int _ _local (*local_fp)(void);

Earlier versions of SAS/C documentation showed the keyword _ _local preceding the return type. That syntax is ambiguous, but the compiler attempts to honor it in simple cases. The following example is a correct declaration of a local function pointer that returns a remote function pointer.

int _ _remote (*_ _local(*local_fp)(void))(int);

The above declaration could not be specified using the previously documented syntax without use of a typedef. Nevertheless, in practice, a typedef would be recommended for clarity.

The pflocal compiler option can be used to specify that all function pointers in a program are local except for those specifically declared with the _ _remote keyword. For more information on the pflocal option, see Compiler Options.

In assembler language terminology, the pointer can be thought of as a V-type address constant. To call a function through a local function pointer in assembler language, load the value of the function pointer into the appropriate general register, usually general register 15, and call the function with the instruction sequence expected by the function. Sample Assembler Routine for Calling a Function with a __local Function Pointer illustrates the standard calling sequence.


Sample Assembler Routine for Calling a Function with a __local Function Pointer
L R15,FUNCPTR Load __local function pointer into R15. BALR R14,R15 Call the function. ST R15,RETVAL Save function return value. . . . FUNCPTR DS A

Function pointers declared using the _ _asm , _ _ref , or _ _ibmos keyword are local by default. You can, however, use the _ _local keyword in such a declaration without causing an error.

Conversions

It is possible to convert a remote function pointer to a local function pointer by assignment or with a cast. This can be used to obtain the entry point address of a C function or to pass the entry point address to an assembler language routine. For instance, the code in Conversion of a Remote Function Pointer to a Local Function Pointer passes the actual entry point address of vdefexit to ISPLINK .


Conversion of a Remote Function Pointer to a Local Function Pointer
#include <stddef.h> extern int cuserxt(); extern __asm int ISPLINK(); /* Declare ISPLINK as an */ /* assembler language function. */ void main() { struct { _ _local int (*exit)(); char *data; } udata; char name[41] ; . . . /* Assign the cuserexit function pointer */ /* to the _ _local function */ /* pointer udata.exit. */ udata.exit = cuserxt; udata.data = NULL; /* Define an ISPF variable as using a user exit. */ (void) ISPLINK("VDEFINE ", "NAME ", name, "USER ", @40, " ", @udata); . . . }

Since local function pointers do not contain a pseudoregister address, conversion from local to remote is not possible. You can frequently use the buildm function to create a remote function pointer from a local function pointer. For more information on the buildm function, see Chapter 1, "Dynamic-Loading Functions," in SAS/C Library Reference, Volume 2 .

Note:    Never attempt to use a function pointer to modify the code of a function. In addition to the reentrancy implications, note that a _ _remote function pointer does not address the function's code directly, and using it to store new data will produce unpredictable results.  [cautionend]

For more information about using assembler language routines in C programs, see Communication with Assembler Programs. For more information about the _ _remote and _ _local keywords, refer to Source Code Conventions.


Chapter Contents

Previous

Next

Top of Page

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