Invoking a callable service from C/C++

Many of the Compiler-Writer Interfaces (CWIs) do not exist as a STUB and there is no C interface. However, there are two methods for invoking this service from C or C++; in either case, a C prototype for the callable service must be defined. Note that most of the Callable Services use OS linkage.

  1. Build a STUB in assembler and link-edit that stub with the application.
  2. Construct C mappings of the Common Anchor Area (CAA) and the library vector where the address of the Callable Service is stored, and use C declarations to access the routine. This is identical to how the C Run Time Library accesses Vendor Interface functions.
Figure 1 shows an example of calling the CEETBCK callable service from C. In the example, the function caa() is a macro that addresses the CAA using the _gtca builtin. The typedefs for some parameters (used with Language Environment® interfaces) are declared in <leawi.h>. The CAA contains the offsets where the Language Environment library vectors (CEECAACELV and CEECAALEOV) are located. It also documents the offset from the start of the specific library vector (in this case CEECAALEOV) to the address of the CEETBCK callable service. For information about the CAA, see Language Environment common anchor area. For information about CEETBCK, see z/OS Language Environment Programming Reference.
Figure 1. Example: calling CEETBCK from C
#ifndef __gtca
#define __gtca() _gtca()
#ifdef  __cplusplus
extern "builtin"
#else
#pragma linkage(_gtca,builtin)
#endif
const void* _gtca(void);
#endif

#ifndef caa
#define caa() ( (struct caa *)__gtca() )
#endif
struct caa
{	
char foo[816];	
void *ceecaaleov;
};					

struct ceeleov
{		
char foo[304];	
void *CEELEOVTBCK;
};

typedef struct ceeleov CEELEOV;
typedef void ceetbck_cwi_func
( void **, int *, void **, int *, char *, int *,
int *, int *, char *, int *, int *, int *,
void **, int *, int *, char *, int *, void **,
int *, _FEEDBACK *);

#define CEETBCK_CWI
((ceetbck_cwi_func *)(((CEELEOV *)
(caa()->ceecaaleov))->CEELEOVTBCK))

ceektbck_cwi_func *tbkfn_ptr =
(ceektbck_cwi_func *)CEETBCK_CWI;

(*tbkfn_ptr)(arg1, arg2, arg3, ...);  /* call CEETBCK */
If you want to call a Language Environment callable service from DLL-compiled C code (or from C++ code), you need to compile with the CALLBACKANY suboption of the DLL compiler option. This is because the library vector is an array of addresses, and DLL-compiled code needs to make calls through function descriptors. Additionally, you must turn off the high-order bit of the address in the library vector. If the high-order bit is on, then the code that makes the CALLBACKANY call acts as though there are no passed parameters. To do this, the call looks like:
ceektbck_cwi_func *tbkfn_ptr =
(ceektbck_cwi_func *)((long)CEETBCK_CWI & 0x7FFFFFFF);

(*tbkfn_ptr)(arg1, arg2, arg3, ...);  /* call CEETBCK */