fetch() — Get a load module

Standards

Standards / Extensions C or C++ Dependencies
Language Environment C  

Format

#include <stdlib.h>

void (*fetch(const char *name))();

General description

Dynamically loads the load module specified by name into memory. The load module can then be invoked from a z/OS® XL C program. The name or the alias by which the fetchable load module is identified in the load module library must appear in a fetch() library function call.

To avoid infringing on the user's name space, this nonstandard function has two names. One name, the external entry point name, is prefixed with two underscore characters, and the other name is not. The name without the prefix underscore characters is exposed only when you use LANGLVL(EXTENDED).

To use this function, you must either invoke the function using its external entry point name (that is, the name that begins with two underscore characters __fetch()) or compile with LANGLVL(EXTENDED). When you use LANGLVL(EXTENDED), any relevant information in the header is also exposed.

You cannot fetch a module that contains a main(). If you do, fetch() will not return a usable pointer. Use of the pointer will result in undefined behavior. To call these types of modules, use the system() library function. Alternatively, when creating the module, you can reset the entry point so that the linkage is provided by z/OS XL C.

When non-reentrant modules have been fetched multiple times, you should release them in the reverse order; otherwise the load modules may not be deleted immediately.

You can fetch modules written in C and C++. For C modules, the source of the fetched module must, in general, contain #pragma linkage(…, fetchable) (the exception is described below). To fetch a C++ module, the routine must be declared extern “C”, and must be declared in a #pragma linkage(…, fetchable) directive. See also fetchep() — Share writable static for more information about the need for #pragma linkage.

Note: For C or C++ modules that are compiled with the XPLINK option and are to be fetched, #pragma linkage(..., fetchable) is required. They cannot use the technique of resetting the entry point. If an application tries to fetch() an XPLINK routine that did not specify FETCHABLE, then an error will be returned.

XPLINK programs can fetch non-XPLINK programs, and vice versa. The function descriptor returned by fetch() will contain glue code to support a stack swap and parameter list conversion if necessary. Calls to a fetched routine that do not cross an XPLINK linkage boundary will not incur any glue code overhead.

If the fetched module is compiled as a DLL it can import variables and functions from other DLL modules, but it cannot export variables or functions.

Nested fetching is supported. That is, a fetched module can also invoke the fetch() library function to dynamically load a separate fetchable module.

Multiple fetching is also supported. Fetching a module more than once will result in separate fetch pointers. If the module is marked “reentrant”, multiple fetches will not reload the module into storage. Under MVS™, you can place the reentrant module into the Extended Link Pack Area or the Link Pack Area (ELPA/LPA) to save time on the load. Although multiple copies of the reentrant module are not brought into storage, each fetch returns a separate pointer. If a module is not reentrant, multiple fetches cause multiple loads into storage. Be aware that if you fetch() a non-reentrant module multiple times, the module may not get deleted by release() until all fetch instances have been released. Also, you should keep in mind that multiple loads of a non-reentrant module can be costly in terms of storage.

Writable statics are, in general, process-scoped. The exception is that, when a thread calls a fetched module, the writable statics are changed for that thread only, that is, thread-scoped.

Under MVS, fetchable (or dynamically loaded) modules must be link-edited and accessible using the standard system search. MVS supports fetching of non-reentrant, serially reusable, and reentrant modules.

Under POSIX, however, the fetchable, dynamically loaded modules cannot be in the HFS (Hierarchical File System). Note also, that the POSIX and XPG4 external variables are propagated. Refer to z/OS XL C/C++ Programming Guide for more information on external variables.

Unless your program is naturally reentrant, each reentrant module has a different copy of writable static. Follow these steps to allow the fetching of your reentrant module that has writable static:

  1. Compile the module to be fetched with the RENT compile-time option.
  2. Using the object module created in step 1, generate a fetchable member. You must specify the entry point as the function you are fetching unless you have included a #pragma linkage(…, FETCHABLE) directive.
See Figure 1 for the program flow of a fetchable module. (FECB refers to a Fetch Control Block, which is a z/OS XL C internal control block used by fetch().)
Figure 1. Program Flow of a Fetchable Module
Program flow of a fetchable module

To dynamically fetch a set of functions with shared writable static, you can use the library function fetchep(). See fetchep() — Share writable static for more details.

Both the module being fetched and the module invoking the fetch() library function can be reentrant.

You can fetch modules without specifying the directive, #pragma linkage(…, FETCHABLE), in the fetched module. If you do, then using the fetch pointer will result in calling the entry point for that module. When you link the module, you must reset the entry point. In addition, you cannot have any writable static.

It follows that fetching a reentrant C module containing writable statics requires that you use the #pragma linkage(… FETCHABLE) preprocessor directive in the fetched module.

If the entry point linkage is not a C linkage, you must use a pragma linkage with a function pointer defined by a typedef. The following sample excerpt would set up a COBOL linkage for a COBOL routine.
typedef int COBOL_FUNC ();
#pragma linkage (COBOL_FUNC, COBOL)
⋮
COBOL_FUNC * fetch_ptr;
fetch_ptr = (COBOL_FUNC *) fetch(module);    /* loads fetched module */
fetch_ptr(args);         /* sets up the proper linkage for the call */

Once the module is fetched, calling the fetched function is similar to making an interlanguage call.

fetch() also supports AMODE switching: when the function call is made, AMODE will be switched; upon return, the AMODE will be restored. Beware of calling fetched modules with AMODE=24 that try to access variables or the library above the line.

Notes:
  1. You cannot call functions through a function pointer that crosses load module boundaries, except through fetchep(). (See fetchep() — Share writable static for more information.) For example, you cannot pass the address of a function to a fetched routine and invoke it from the fetched routine because the z/OS C writable static will not be swapped.
  2. If you need to access code that has to run in a restricted addressing mode (such as a AMODE 24), you can package the code into a module to be fetched. The module can then be linked using the restricted addressing mode, but fetched from a program with an unrestricted addressing mode.
  3. A program that invokes fetch() many times without releasing all of the load modules may run out of memory.

Link considerations: When linking the function to be fetched, you must link in the necessary libraries and specify the entry point as the function you are fetching unless you have included this directive: #pragma linkage(…, FETCHABLE).

When linking the main() z/OS C function, you must specify the necessary libraries to use the functions you are fetching. For example, if you are fetching a COBOL function, specify the COBOL library. This requirement does not apply to Language Environment.

When running main(), specify the runtime libraries you will need for main(), as well as the functions you will fetch. This requirement does not apply to Language Environment.

Special behavior for C++: A z/OS XL C++ program cannot call fetch(). If you attempt to call fetch() from a z/OS XL C++ program, the compiler will issue an error message. There are three alternatives to fetch() under z/OS XL C++:
  • You can replace fetch() with DLL (dynamic link library) calls.
  • You can provide a C DLL module to fetch modules, as shown in examples CELEBF52 and CELEBF53. See Examples.
  • A z/OS XL C++ program may statically call a z/OS XL C function that, in turn, fetches another module.

Returned value

If successful, fetch() returns a pointer to a stub that will call the entry point to the fetched load module.

If the load fails, fetch() returns NULL and may set errno to one of the following values:

Error Code
Definition
ELEFENCE
The DLL contains a member language not supported on this version of the operating system.

Examples

Examples of using the fetch() function with C: The following example demonstrates how to compile, link, and run a program that fetches a function in another object module that contains the directive: pragma linkage(…., FETCHABLE).

Begin with the main program.
#include <stdio.h>
#include <stdlib.h>

typedef int (*funcPtr)();  /* pointer to a function returning an int */

int main(void)
{
    int result;
    funcPtr add;

    printf("fetch module\n");
    add = (funcPtr) fetch("f1a");            /* load module F1A      */

    if (add == NULL) {
        printf("ERROR: fetch failed\n");
    }
    else {
        printf("execute fetched module\n");
        result = (*add)(1,2);                /* execute module F1A   */

        printf("1 + 2 == %d\n", result);
    }
}
Then the fetched function:
#pragma linkage(func1, fetchable)

int func1(int a, int b)
{
   printf("in fetched module\n");

   return(a+b);
}
Next, JCL to compile, link, and run under MVS:
>
//F1A      EXEC EDCC,INFILE='userid.TEST.SOURCE(F1A)'
//         OUTFILE='userid.TEST.OBJ(F1A),DISP=SHR',
//         CPARM='NOSEQ,NOMARGIN,RENT'
//F1B      EXEC EDCPL,INFILE='userid.TEST.OBJ(F1A)'
//         OUTFILE='userid.TEST.LOAD(F1A),DISP=SHR'
//F1       EXEC EDCCLG,INFILE='userid.TEST.SOURCE(F1)'
//GO.STEPLIB DD
//           DD  DSN=userid.TEST.LOAD,DISP=SHR
This example demonstrates the use of fetch() with COBOL and how to compile, link, and run the program.
/* cob1 */
#include <stdlib.h>
#include <stdio.h>

typedef void funcV();           /* function returning void            */
#pragma linkage(funcV, COBOL)   /* establish Cobol linkage            */

int main(void)
{
    int var1 = 1;
    int var2 = 2;
    funcV *add;

    printf("fetch module\n");
    add = (funcV *) fetch("cob1a");           /* load module COB1A    */

    if (add == NULL)
    {
        printf("ERROR: fetch failed\n");
    }
    else
    {
        printf("execute fetched module\n");
        (*add)(&var1, &var2);                 /* execute module COB1A */

        printf("1 + 2 == %d\n", var1);
    }
}
Here is the fetched COBOL subroutine COB1A.
 IDENTIFICATION DIVISION.
 PROGRAM-ID.  COB1A.
****************************************************************
*   This subroutine receives 2 integer parameters.             *
*   The first is added to the second and the result is stored  *
*   back into the first.                                       *
****************************************************************
 ENVIRONMENT DIVISION.
 DATA DIVISION.

 WORKING-STORAGE SECTION.

 LINKAGE SECTION.
 01  VAR1                    PIC S9(9) COMP.
 01  VAR2                    PIC S9(9) COMP.
****************************************************************
*                  PROCEDURE DIVISION                          *
****************************************************************

 PROCEDURE DIVISION USING VAR1 VAR2.

*
*    ADD VAR2 TO VAR1 PLACING THE RESULT IN VAR1.
*

     COMPUTE VAR1 = VAR1 + VAR2.
           GOBACK.
Finally, compile, link, and run under MVS:
//*==================================================================
//COBCL  PROC CREGSIZ='2048K',
//            INFILE=,
// OUTFILE='&&GSET(GO),DISP=(MOD,PASS),UNIT=VIO,SPACE=(512,(50,20,1))'
//*
//*------------------------------------------------------------------
//* COBOL Compile Step
//*------------------------------------------------------------------
//COBCOMP EXEC PGM=IGYCRCTL,REGION=&CREGSIZ;
//STEPLIB  DD  DSNAME=IGY.V1R3M0.SIGYCOMP,DISP=SHR
//SYSPRINT DD  SYSOUT=*
//SYSIN    DD  DSNAME=&INFILE,DISP=SHR
//SYSLIN   DD  DSNAME=&&LOADSET,UNIT=SYSDA,
//             DISP=(MOD,PASS),SPACE=(TRK,(3,3)),
//             DCB=(BLKSIZE=3200)
//SYSUT1   DD  UNIT=SYSDA,SPACE=(CYL,(1,1))
//SYSUT2   DD  UNIT=SYSDA,SPACE=(CYL,(1,1))
//SYSUT3   DD  UNIT=SYSDA,SPACE=(CYL,(1,1))
//SYSUT4   DD  UNIT=SYSDA,SPACE=(CYL,(1,1))
//SYSUT5   DD  UNIT=SYSDA,SPACE=(CYL,(1,1))
//SYSUT6   DD  UNIT=SYSDA,SPACE=(CYL,(1,1))
//SYSUT7   DD  UNIT=SYSDA,SPACE=(CYL,(1,1))
//*
//*------------------------------------------------------------------
//* COBOL Link-Edit Step
//*------------------------------------------------------------------
//COBLINK EXEC PGM=HEWL,COND=(8,LT,COBCOMP),REGION=1024K
//SYSLIB   DD  DSNAME=CEE.V1R3M0.SCEELKED,DISP=SHR
//SYSPRINT DD  SYSOUT=*
//SYSLIN   DD  DSNAME=&&LOADSET,DISP=(OLD,DELETE)
//         DD  DDNAME=SYSIN
//SYSLMOD  DD  DSNAME=&OUTFILE;
//SYSUT1   DD  UNIT=SYSDA,SPACE=(TRK,(10,10))
// PEND
//*
//*==================================================================
//* Compile and Link-Edit COBOL program COB1A
//*------------------------------------------------------------------
//COB1A   EXEC COBCL,
//         INFILE='userid.TEST.SOURCE(COB1A)',
//         OUTFILE='userid.TEST.LOAD(COB1A),DISP=SHR'
//COBLINK.SYSIN DD *
 ENTRY COB1A
/*
//*
//*------------------------------------------------------------------
//* Compile and Link-Edit C program COB1
//*------------------------------------------------------------------
//COB1    EXEC EDCCLG,
//         INFILE='userid.TEST.SOURCE(COB1)',
//         CPARM='OPT(0) NOSEQ NOMAR'
//GO.STEPLIB DD
//           DD DSNAME=userid.TEST.LOAD,DISP=SHR

Examples of alternatives to fetch() under C++: This example shows how to use DLL as an alternative to fetch(). Here, myfunc() is the function to be dynamically loaded using DLL, and main() invokes DLL.

CELEBF52
⁄⁄ CELEBF52-part 1 of 2-other file is CELEBF53.

⁄⁄ This example shows how to use DLL as an alternative to fetch().

⁄⁄ C++ program that invokes myfunc using DLL

#include <stdlib.h>
#include <stdio.h>
#include <dll.h>

extern "C" {           ⁄⁄ needed to indicate C linkage
  typedef int (*funcPtr)(); ⁄⁄ pointer to a function returning an int
}

int main (void)
{
  dllhandle *dllh;
  funcPtr   fptr;

  if ((dllh = dllload( "celebf53" )) == NULL) {
     perror( "failed to load celebf53" );
     exit( -1 );
  }
  if ((fptr = (funcPtr) dllqueryfn( dllh, "myfunc" )) == NULL) {
     perror( "failed to retrieve myfunc" );
     exit( -2 );
  }
  if ( fptr() != 0 ) {
     perror( "failed to execute myfunc" );
     exit( -3 );
  }
  if ( dllfree( dllh ) != 0 ) {
     perror( "failed to free celebf53" );
     exit( -4 );
  }
  return( 0 );
}
CELEBF53
⁄* CELEBF53-part 2 of 2-other file is CELEBF52.

   This example shows how to use DLL as an alternative to fetch().

 *⁄

⁄*

  C function dynamically loaded using DLL

 *⁄

#include <stdio.h>

int myfunc (void)
{
  printf( "Hello world\n" );
  return( 0 );
}

The following example shows how a C++ program can dynamically call a function in a C DLL module, to fetch other C modules.

CELEBF54
// CELEBF54-part 1 of 3-other files are CELEBF55, CELEBF56.
// This example shows how a C++ program can dynamically call a function
// in a C DLL module, to fetch other C modules

// C++ program that dynamically calls a function in a C DLL module

#include <stdio.h>
#include <stdlib.h>
#include <dll.h>
#include <iostream.h>

extern "C" {           // needed to indicate C linkage
  typedef int (*funcPtr)(); // pointer to a function returning an int
}

int main (void)
{
  dllhandle *dllh;
  funcPtr   fptr;

  if ((dllh = dllload( "mydll" )) == NULL) {
     perror( "failed to load mydll" );
     exit( -1 );
  }
  if ((fptr = (funcPtr) dllqueryfn( dllh, "fwrap" )) == NULL) {
     perror( "failed to retrieve fwrap" );
     exit( -2 );
  }
  if ( fptr() != 0 ) {
     perror( "failed to execute fwrap" );
     exit( -3 );
  }
  if ( dllfree( dllh ) != 0 ) {
     perror( "failed to free mydll" );
     exit( -4 );
  }
  return( 0 );
}
CELEBF55
/* CELEBF55-part 2 of 3-other files are CELEBF54, CELEBF56.
   This example shows how a C++ program can dynamically call a function
   in a C DLL module, to fetch other C modules

   fwrap function used in a DLL module-it fetches mymod, which
   contains myfunc
 */
#include <stdio.h>
#include <stdlib.h>

typedef int (*funcPtr)();   /* pointer to a function returning an int */

int fwrap (void)
{
  funcPtr   fptr;

  if ((fptr = (funcPtr) fetch( "mymod" )) == NULL) {
     perror( "failed to fetch mymod" );
     return( -1 );
  }
  else
     return(fptr());
}
CELEBF56
/* CELEBF56-part 3 of 3-other files are CELEBF54, CELEBF55.
   This example shows how a C++ program can dynamically call a function
   in a C DLL module, to fetch other C modules
 */

/*    C function to be fetched   */

#include <stdio.h>
#pragma linkage(myfunc, fetchable)

int myfunc (void)
{
  printf( "in fetched module\n" );
  return( 0 );
}

The following example shows how to statically call a C function that in turn fetches other functions. Here, myfunc() is the function to be fetched, fetcher() is a C function that fetches myfunc(), and main() is a function that statically calls fetcher().

CELEBF57
// CELEBF57-part 1 of 3-other files are CELEBF58, CELEBF59.
// This example shows how to statically call a C function that
// fetches other functions.

// C++ statically calling a C program that uses fetch()

#include <iostream.h>

extern "C" {          //  needed to indicate C linkage
  int fetcher (void);
}

int main (void)
{
  cout << "The fetcher says: ";
  fetcher();
  cout << "and returns";
  return( 0 );
}
CELEBF58
/* CELEBF58-part 2 of 3-other files are CELEBF57, CELEBF59.
   This example shows how to statically call a C function that fetches
   other functions.
 */

/*
   C function that fetches mymod which contains myfunc
 */
#include <stdio.h>
#include <stdlib.h>

typedef int (*funcPtr)();   /* pointer to a function returning an int */

int fetcher (void)
{
  funcPtr fptr;

  if ((fptr = (funcPtr) fetch( "mymod" )) == NULL) {
     perror( "failed to fetch mymod" );
     return( -1 );
  }
  else {
     fptr();                /* invoke fetched function */
     return( 0 );
  }
}
CELEBF59
/* CELEBF59-part 3 of 3-other files are CELEBF57, CELEBF58.
   This example shows how to statically call a C function that fetches
   other functions.
 */

/*    C function to be fetched    */

#include <stdio.h>
#pragma linkage(myfunc, fetchable)

int myfunc (void)
{
  printf( "Hello world " );
  return( 0 );
}

Although fetching and using DLL are functionally comparable, there is one subtle difference. Fresh copies of static and global variables are allocated each time a module is fetched, but not each time a DLL load of the same module is done.

The following example shows that, when a module is fetched multiple times, fresh copies of static and global variables are allocated.

CELEBF60
/* CELEBF60-part 1 of 2-other file is CELEBF61.
   This example shows how copies of variables are allocated when multiple
   fetches are done.
 */

/*
   C program fetching mymod multiple times--mymod contains myfunc.
 */
#include <stdio.h>
#include <stdlib.h>

typedef int (*funcPtr)(int); /*pointer to a function returning an int*/

int main (void)
{
  funcPtr fptr1, fptr2;

  if ((fptr1 = (funcPtr) fetch( "mymod" )) == NULL) {
     perror( "failed to fetch mymod" );
     return( -1 );
  }
  if ( fptr1(100) != 0 ) {
     perror( "failed to execute myfunc" );
     exit( -2 );
  }
  if ((fptr2 = (funcPtr) fetch( "mymod" )) == NULL) {
     perror( "failed to fetch mymod" );
     return( -3 );
  }
  if ( fptr2(100) != 0 ) {
     perror( "failed to execute myfunc" );
     exit( -4 );
  }
  return( 0 );
}
CELEBF61
/* CELEBF61-part 2 of 2-other file is CELEBF60.
   This example shows how copies of variables are allocated when multiple
   fetches are done.
 */

/*     C module mymod    */
#include <stdio.h>
#pragma linkage(myfunc, fetchable)

int globvar = 5;

int myfunc (int x)
{
  globvar += x;
  printf( "%d\n", globvar );
  return( 0 );
}
Running this example would produce the following results:
105
105

The following example shows that fresh copies of static and global variables are not allocated for multiple DLL loads of the same module.

CELEBF62
// CELEBF62-part 1 of 2-other file is CELEBF63.
// This example shows how copies of variables are allocated when
// multiple DLL loads are done.

// C++ program doing multiple DLL loads of the same module

#include <stdlib.h>
#include <stdio.h>
#include <dll.h>

extern "C" {                   //needed to indicate C linkage
  typedef int (*funcPtr)(int); //pointer to a function returning an int
}

int main (void)
{
  dllhandle *dllh1, *dllh2;
  funcPtr fptr;

  if ((dllh1 = dllload( "mydll" )) == NULL) {
     perror( "failed to load mydll" );
     exit( -1 );
  }
  if ((fptr = (funcPtr) dllqueryfn( dllh1, "myfunc" )) == NULL) {
     perror( "failed to retrieve myfunc" );
     exit( -2 );
  }
  if ( fptr(100) != 0 ) {
     perror( "failed to execute myfunc" );
     exit( -3 );
  }
  if ((dllh2 = dllload( "mydll" )) == NULL) {
     perror( "failed to load mydll" );
     exit( -4 );
  }
  if ((fptr = (funcPtr) dllqueryfn( dllh2, "myfunc" )) == NULL) {
     perror( "failed to retrieve myfunc" );
     exit( -5 );
  }
  if ( fptr(100) != 0 ) {
     perror( "failed to execute myfunc" );
     exit( -6 );
  }
  if ( dllfree( dllh1 ) != 0 ) {
     perror( "failed to free mydll" );
     exit( -7 );
  }
  return( 0 );
}
CELEBF63
/* CELEBF63-part 2 of 2-other file is CELEBF62.
   This example shows how copies of variables are allocated when multiple
   DLL loads are done.
 */

/* C function invoked using DLL */

#include <stdio.h>
#include <stdlib.h>

int globvar = 5;
int myfunc (int);

int myfunc (int x)
{
  globvar += x;
  printf( "%d\n", globvar );
  return( 0 );
}
Running this example would produce the following results:
105
205

Related information