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.