As with any C program, program execution always begins with a function
named main
. The load module containing the main
function
must remain in memory at all times. Each subordinate (dynamically
loaded) load module must contain a function named _dynamn
(which
is a contraction for dynamic main). From the perspective of the
compiler, the _dynamn
function serves the same role in the
subordinate load module as main
serves in the module containing
the main
program.
main
function, or which can
cause the C environment to be created in conjunction with using the
indep
compiler option. A
dynamically loadable module
is one which
contains a _dynamn
function. It is not possible to create a load
module which is of both types. Any attempt to do so will fail at
link time or at execution time. Two consequences of this requirement
are:
main
function and a _dynamn
function into
the same load module. In particular, this means that you
cannot have a source file which includes both these functions.
indep
option
into a load module which includes a _dynamn
function.
main
program module can be loaded
by use of the loadm
and unloadm
functions. The second
argument to loadm
is a pointer to a function pointer in which the
address of the loaded _dynamn
routine will be stored.
In addition to loadm
and unloadm
, the library provides
functions to load and unload modules containing only data (loadd
and unloadd
) and a function that converts a load module entry
point address to a function pointer (buildm
). Two other
functions, addsrch
and delsrch
, are provided, primarily for
CMS, to define the load module search order. The search order
consists of the possible locations of dynamically loaded modules and
the order in which they are processed. Before any of these routines
can be used, the source program must include the header file
<dynam.h>
using the #include
statement.
Transfers of control between load modules are possible only by using
function pointers. However, through the use of appropriate pointers, a
routine in one load module can call a routine in any other load
module. The inability of one load module to call another directly is a
special case of a more general restriction; namely, load modules cannot
share external variables. More precisely, two external variables (or
functions) of the same name in different load modules are independent
of each other. (There are a few special cases such as the variable errno
, which contains the number of the most recent run-time
problem.) See Appendix 4, "Sharing extern Variables among Load
Modules," in the SAS/C Compiler and Library User's Guide, Fourth Edition for
additional information. An external variable or function can be
accessed directly only by functions that have been linked in that
module. All functions in other modules can gain access to them only by
use of pointers.
The functions for dynamic loading, especially addsrch
and
delsrch
, are highly operating-system-dependent. The definition of
each dynamic-loading function highlights aspects of the function that
depend in some way on the operating system. addsrch
and
delsrch
, for example, are of interest to users working under MVS
only when a
program needs to be portable to CMS. For CMS, these functions are
quite useful but are not needed typically in an MVS environment.
#include <dynam.h> SEARCH_P addsrch(int type, const char *loc, const char *prefix);
addsrch
adds a "location" to the list of "locations" from which
modules can be loaded. This list controls the search order for load
modules loaded via a call to loadm
. The search order can be
described additionally by the third argument, prefix
.
The first argument type
must be a module type defined in <dynam.h>
. The module type defines what type of module is loaded and
varies from operating system to operating system. The character string
specified by the second argument loc
names the location. The
format of this string depends on the module type. The third argument
prefix
is a character string of no more than eight characters.
addsrch
is of interest primarily to CMS users and to MVS users
writing programs portable to CMS. The remainder of this discussion,
therefore, focuses on the use of addsrch
under CMS.
loadm
is called.
loadm
is called.
The module type also controls the format of the second argument
loc
, which names the location to be searched by loadm
. If the
module type is
""
.
All location strings may have leading and trailing blanks. The
characters are uppercased. addsrch
does not verify the existence
of the location.
The third argument is a character string of no more than eight
characters. It may be ""
. If it is not null, then it specifies that
the location indicated is searched only if the load module name (as
specified by the first argument to loadm
) begins with the same
character or characters specified in the third argument.
At C program initialization, a default location, defined by the following call, is in effect:
sp = addsrch(CMS_LDLB, "DYNAMC *","");
addsrch
returns a value that can be passed to delsrch
to
delete the input source. Under CMS, this specifically means a value of
the defined type SEARCH_P
, which can be passed to delsrch
to
remove the location from the search order. If an error occurs, a value
of 0
is returned.
addsrch
are defined only under CMS. The
use of addsrch
under MVS with a CMS module type has no effect.
addsrch
does not verify that a location exists (DYNAMC LOADLIB,
for example) or that load modules may be loaded from that location.
The loadm
function searches in the location only if the load
module cannot be loaded from a location higher in the search order.
addsrch
fails only if its parameters are ill-formed.
#include <dynam.h> SEARCH_P mylib; . . . /* Search for modules in a CMS LOADLIB. */ mylib = addsrch(CMS_LDLB, "PRIVATE *", "");
#include <dynam.h> void buildm(const char *name, __remote /* type */ (**fpp)(), const char *ep);
buildm
converts the entry point address in ep
to a
__remote
function
pointer. The created function pointer can then be used to transfer
control to a function or module located at this address. buildm
is normally used to generate a function pointer for a C load module
that has been loaded without the assistance of the SAS/C Library (for
instance, by issuing the MVS LOAD SVC), but it can also be used with a
non-C load module or with code generated by the program. buildm
also assigns a load module name to the entry point address, and use of
this name in subsequent calls to loadm
or unloadm
is
recognized as referring to the address in ep
.
Note that a load module processed with buildm
should always
include a _dynamn
function.
buildm
stores the function pointer in the area addressed by
fpp
.
Note that fpp
may reference a function returning any valid
type of data.
If the function pointer cannot be created, a NULL
value is
stored.
name
points to a name to be assigned to the built load module.
If
name
is ""
,
then a unique name is assigned by buildm
. If
the name is prefixed with an asterisk, then buildm
does not check
to see if the name is the name of a previously loaded module (see
"ERRORS", below).
buildm
stores the function pointer in the area addressed by
fpp
. If an error occurs, buildm
stores NULL
in this area.
name
does not start
with an asterisk and is the same as a
previously built or dynamically loaded module, the request is rejected
unless the value of ep
is the same as the entry point of the
existing load module. If the entry points are the same, a pointer to
the previously loaded or built module is stored in the area addressed
by func
.
name
argument must point to a null-terminated string no more
than eight characters long, not counting a leading asterisk. Leading
and trailing blanks are not allowed.
The fpp
argument must be a pointer to an object declared as
"pointer to function returning (some C data type)".
The example assumes that SIMPLE is a C _dynamn
function returning
void
.
#include <svc.h> #include <code.h> #include <stdio.h> #define LOAD(n,ep) (_ldregs(R0+R1,n,0),_ossvc(8), _stregs(R0,ep)) main() { void (*fp)(); char *ep; /* The name "SIMPLE" must be uppercased, left-adjusted, */ /* and padded to eight characters with blanks when */ /* used by SVC 8. */ LOAD("SIMPLE ",&ep); /* The name passed to buildm does not have to match */ /* the name of the loaded module, but it helps. */ buildm("simple",&fp,ep); if (fp) /* If no errors, call SIMPLE */ (*fp)(); else puts("simple didn't load."); }
#include <dynam.h> void delsrch(SEARCH_P sp);
delsrch
removes the "location" sp
pointed to by the argument
from the load module search order list. sp
is a value returned
previously by addsrch
.
delsrch
is not portable. delsrch
is used primarily in a CMS
environment as a counterpart to addsrch
or by MVS programs that
can port to CMS.
delsrch
under CMS:
#include <dynam.h> SEARCH_P source; char *new_source; . . . /* Delete old search location. */ if (source) delsrch(source); /* Add new search location. */ source = addsrch(CMS_LDLB, new_source, "");
#include <dynam.h> void loadd(const char *name, char **dp, MODULE *mp);
loadd
is similar to loadm
(load executable module) except
that it is intended for data modules. loadd
loads the module
named by the argument name
and stores the address of
the load module's entry point in the location pointed to by the second
argument dp
.
If the module has been loaded already, the pointer returned in the second argument points to the previously loaded copy. If the module name in the first argument string is prefixed with an asterisk, a private copy of the module is loaded.
The third argument addresses a location where a value is stored that
can be used later to remove the module from memory via unloadd
.
loadd
should be used only to load modules that contain data (for
example, translation tables) rather than executable code.
loadd
indirectly returns a value that is stored in the location
addressed by the third argument mp
. This value can be used
later to remove the module from memory via unloadd
. If the
module to be loaded cannot be found, 0
is returned.
loadd
must contain at
least 16 bytes of data following the entry point, or library
validation of the module may fail.
loadd
is not portable. As with other dynamic-loading functions,
be aware of system-specific requirements for the location of modules
to be loaded.
loadd
necessarily varies from operating
system to operating system. Under MVS, modules to be loaded must
reside in STEPLIB or the system link list. Under CMS, modules to be
loaded may reside in DYNAMC LOADLIB or in other locations defined by
use of the addsrch
routine.
Under CICS, modules to be loaded must reside in a library in the DFHRPL concatenation, and must be defined to CICS.
loadd
:
#include <dynam.h> #include <lcstring.h> char *table; char *str; MODULE tabmod; /* Load a translate table named LC3270AE. */ loadd("LC3270AE",&table,&tabmod); str = strxlt(str, table); unloadd(tabmod); /* Unload module after use.*/
#include <dynam.h>; void loadm(const char *name, __remote /* type */ (**fpp)());
loadm
loads an executable module
named by the
argument string name
and stores a C function pointer in the
location pointed to by the argument fpp
.
If the module
has been loaded already, the pointer stored in fpp
points to the previously loaded copy. If the module name in the first
argument string is prefixed with an asterisk, a private copy of the
module is loaded.
Note that fpp
may reference a function returning any valid
type of data.
loadm
provides an indirect return value in the form of a function
pointer that addresses the entry point of the loaded module. If the
module is in C, calling the returned function always transfers control
to the _dynamn
function of the module.
If the module to be loaded cannot be found, a NULL
is stored in
the location addressed by fpp
.
The second argument must be a pointer to an object declared as "pointer to function returning (some C data type)."
Note that a module to be loaded by loadm
cannot have
the entry point defined in the
last 16 bytes of the load module. The library inspects this
portion of the loaded module, and may ABEND if 16 bytes
of data are not present. This situation can arise only if the
entry point is an assembler (or other non-C) routine.
loadm
is not portable. Be aware of system dependencies involving
where load modules may be located and how module names are specified
for your operating system.
loadm
necessarily varies from operating
system to operating system. Under MVS, modules to be loaded must
reside in STEPLIB, a task library, or the system link list. Under
CMS, modules to be loaded may reside in DYNAMC LOADLIB or in other
locations defined by use of the addsrch
routine.
Under CICS, modules to be loaded must reside in a library in the DFHRPL concatenation and must be defined to CICS.
addsrch
does not verify the existence of a location, for example,
DYNAMC LOADLIB. Because in some circumstances the logic of a program
may not require that a location be searched, no verification is done
until loadm
cannot find a load module in any location defined
earlier in the search order. addsrch
fails only if its
parameters are ill-formed.
If loadm
determines that a location is inaccessible (for example,
the LOADLIB does not exist), the location is marked unusable, and no
attempt is made to search it again.
loadm
is illustrated by three examples. The first
demonstrates the use of the command for a very simple situation
without operating-system dependencies, while second and third
examples are designed to run under MVS and CMS respectively.
The second example creates a dynamic load module that includes a table of pointers to functions which may be called dynamically from the calling load module. This example runs under MVS and has been designed to provide a framework that can be expanded upon in complete application.
The third example presents a hypothetical situation under CMS in which
addsrch
)
loadm
)
delsrch
).
#include <dynam.h> int (*fp)(); /* Load a load module named "ADD" and call it. */ loadm("ADD",&fp); sum = (*fp)(1, 3); . . .
STEP I. Put the following declarations in a common header file and name it DYNTABLE:
struct funcdef { /* structure definition for functions */ int (*func1)(); int (*func2)(); /* More functions can go here. */ }; typedef struct funcdef *fptrtable; /* pointer to list of funcdefs */Make sure the header library containing DYNTABLE is allocated so that it will be included when you compile the following source code.
STEP II. Create the following C source file and name it DYNAMIC.
This file will be compiled and linked to create
a dynamic load module.
The _dynamn
function returns to its caller a structure of
function pointers that can be used to call the individual functions of
the load module.
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <lcio.h> #include <dynam.h> #include "dyntable.h" /* _dynamn function that returns a list of function pointers which */ /* can be used to invoke other functions in the load module */ fptrtable _dynamn(void) { /* Initialize function pointer table. */ static struct funcdef dyntab = {&func1, &func2 /* ... */ }; /* Return pointer to table with the new contents. */ return(&dyntab); } int func1() { printf("func1() was successfully dynamically called!!!\n"); return(0); } int func2() { printf("func2() was successfully dynamically called!!!\n"); return(0); }DYNAMIC must be compiled using the
sname
compiler option to
override the default assignment of _dynamn
as the section
name. It may be compiled as re-entrant using the rent
compiler option. (Note that JCL changes are required if norent
compilation is needed.)
During linking, the ENTRY=DYN (or DYNNK for norent
)
parameter must be
specified.
STEP III. Create the following C source file and name it
DYNMLOAD. This code demonstrates how to dynamically load
the DYNAMIC load module and how to call the functions pointed
to by the dyntab
table:
#include <stdio.h> #include <string.h> #include <dynam.h> #include "dyntable.h" fptrtable(*fpdyn)(); /* _dynamn function pointer prototype */ int rc1, rc2; /* return codes from calling func_1 */ /* and func_2 */ fptrtable table; /* table of function pointer and names */ /* returned from _dynamn */ main() { /* Load DYNAMIC. */ loadm("DYNAMIC", &fpdyn); /* Call _dynamn and return table of function pointers and */ /* name of load module. */ table = (*fpdyn)(); /* Call func1 using function pointer from table. */ rc1 = (*table->func1)(); printf("Dynamically called func1() with rc = %d \n", rc1); /* Call func2 using function pointer from table. */ rc2 = (*table->func2)(); printf("Dynamically called func2() with rc = %d \n", rc2); unloadm(fpdyn); return; }STEP IV. Modify the following JCL, which is used to compile and link the DYNAMIC and DYNMLOAD source files and then execute the resulting load module. (Note that site-dependent job statements should be added.)
//* //* COMPILE and LINK module that uses a _dynamn routine that passes //* its caller back a list of function pointers which are used to //* invoke other functions in the load module //* //COMPDYNM EXEC LC370CL,ENTRY=DYN,PARM.C='RENT SNAME(DYNAM)' //C.SYSLIN DD DSN=userid
.SASC.OBJ(DYNAMIC),DISP=OLD //C.SYSIN DD DSN=userid
.SASC.SOURCE(DYNAMIC),DISP=SHR //* //LKED.SYSLMOD DD DSN=userid
.SASC.LOAD(DYNAMIC),DISP=OLD //* //* //* COMPILE and LINK module that dynamically loads the DYNAMIC //* load module and calls functions within the load module //* using the structure of function pointers returned. //* //CLEMAIN EXEC LC370CLG //C.SYSLIN DD DSN=userid
.SASC.OBJ(DYNMLOAD),DISP=OLD //C.SYSIN DD DSN=userid
.SASC.SOURCE(DYNMLOAD),DISP=SHR //* //LKED.SYSLMOD DD DSN=userid
.SASC.LOAD(DYNMLOAD),DISP=OLD //
neptune
.
#include <stdio.h> void neptune(char *p) { puts(p); return; }STEP I. Make the function
neptune
into a separate, loadable
module by link-editing the TEXT file into a CMS LOADLIB file. The
following steps are required:
_dynamn
.
#include <stdio.h> void _dynamn(char *p) { puts(p); return; }All C load modules (except the one that includes
main
, of course)
must define one function named _dynamn
.
sname
compiler option to override
the default assignment of _dynamn
as the sname. See Chapter 7,
"Compiler Options," in the SAS/C Compiler and Library User's Guide, Fourth Edition
for more information about the sname
compiler option.
LKED NEPTUNE (LIBE DYNAMC NAME NEPTUNE
STEP II. The function neptune
now exists in a form loadable
by loadm
. Invoke loadm
to load the module as follows:
#include <dynam.h> main() { int (*fp)(); /* Declare a function pointer */ loadm("NEPTUNE",&fp); /* Load NEPTUNE */ if (fp) { /* Check for errors */ (*fp)("Hello, Neptune, king of the C!"); unloadm(fp); /* Delete NEPTUNE */ } else puts("NEPTUNE failed to load."); exit(0); }STEP III. The previous step used the default search location DYNAMC LOADLIB (see
addsrch
); thus, no call to addsrch
is
required. If you use some other filename for the LOADLIB, specify it
in a call to addsrch
before invoking loadm
. The following
is an example:
#include <dynam.h> main() { SEARCH_P sp; /* Declare a SEARCH_P value */ int (*fp)(); /* specify "NEWLIB LOADLIB *" */ sp = addsrch(CMS_LDLB,"NEWLIB *",""); loadm("NEPTUNE",&fp); if (fp) { (*fp)("Hello, Neptune, king of the C!"); unloadm(fp); } else puts("NEPTUNE failed to load."); delsrch(sp); /* remove NEWLIB LOADLIB from the search order */ exit(0); }Since the NEPTUNE load module is relocatable, it can be loaded as a CMS nucleus extension by the NUCXLOAD command. Then the following calls cause NEPTUNE to be accessed from the nucleus extension:
sp = addsrch(CMS_NUCX,"",""); loadm("NEPTUNE",&fp);The function must exist as a nucleus extension before invoking
loadm
. This facility is useful, for example, in testing a single load
module that you plan to replace in an existing LOADLIB.
#include <dynam.h>; void unloadd(MODULE mp);
unloadd
unloads the data module identified by the argument mp
.
If the module is no longer in use, it deletes the module from
memory.
unloadd
is invalid, a user 1211 ABEND is
issued. Various other ABENDs, such as 1215 or 1216, may occur during
unloadd
if library areas used by dynamic loading have been
overlaid.
loadd
.
#include <dynam.h> void unloadm(__remote /* type */ (*fp)());
unloadm
unloads the executable module containing the function
addressed by the argument fp
. If the module is no longer in use,
unloadm
deletes it from memory.
Note that fp
may reference a function ruturning any valid
type of data.
unloadm
may be used to unload a module that has been built by
buildm
, but unloadm
will not delete the module from memory.
unloadm
is invalid, a user 1211 ABEND is
issued. Various other ABENDs, such as 1215 or 1216, may occur during
unloadm
if library areas used by dynamic loading have been
overlaid.
unloadm
:
#include <dynam.h> int (*fp)(); /* Load a load module named "IEFBR14", */ /* call it, and unload it. */ loadm("iefbr14",&fp); (*fp)(); unloadm(fp);
Copyright (c) 1998 SAS Institute Inc. Cary, NC, USA. All rights reserved.