Miscellaneous Topics in Linkage
Usually when we call an external subprogram, it is already in
memory because it has been linked into our load module. That is, the
load module usually contains all the subprograms we plan to call.
This is not always practical, for several reasons. Perhaps the
subprogram we call is large and we don’t want to make the load module
larger by including it. Perhaps we are not sure ahead of time which
subprograms we are going to call.
It is possible to make a dynamic call to a subprogram using the
LINK and LOAD macros. The subprogram will be fetched from the load library into memory and executed. It is also possible to have the
subprogram removed from memory later.
Usually when we call a subprogram, execution begins at the CSECT. It is also possible to start execution at a label inside the CSECT,
which is known as an alternate entry point.
------
Linkage-Related Macros
Several of the macros have some parameters in common.
EP parameter (LINK, LOAD, DELETE, ATTACH)
This is coded as:
EP=_entry_point_name_
where the entry point name may be the CSECT name of the subprogram or
may be an alternate entry point inside the subprogram.
EPLOC parameter (LINK, LOAD, DELETE, ATTACH)
Instead of EP, we can sometimes use EPLOC:
EPLOC=_entry_point_address_
where the entry point address is the address of an entry point.
DE parameter (LINK, LOAD, DELETE, ATTACH)
In some cases, before using another macro, we have just located
the load module for ourselves using the BLDL macro to perform the
search. In that case, instead of using EP, we can use DE:
DE=_list_entry_address_
where the list entry address is the address of a name field inside a
62-byte list entry as constructed by BLDL.
PARAM parameter (LINK, ATTACH)
The PARAM parameter is used to provide a parameter list for a
subprogram call. This is coded as:
PARAM=(list of addresses)
That is, a parameter list is a list of the addresses of the
arguments which are being passed.
ERRET parameter (LINK, LOAD)
The ERRET parameter is used to provide the label or address of an
error routine to be executed if anything goes wrong, as in:
ERRET=MYERROR
If this is used, upon entry to the error routine, register 1 will
have been set to the ABEND code that would have resulted if there was
no ERRET and register 15 will contain the reason code.
CALL macro
The CALL macro is an IBM macro used for passing control to a
subprogram. It is used for static linkage, not dynamic linkage, and
the code generated is the same ordinary code we might otherwise use to
do the same thing.
The format is as follows:
CALL _entry_name_
or
CALL _entry_name_,(parameter list)
or
CALL _entry_name_,(parameter list),id
or
CALL _entry_name_,PARMLIST
where:
entry name = a label or a D(B) address such as 0(15), providing
the address of the subprogram.
(parameter list) = the addresses of the arguments to be passed
to the subprogram.
PARMLIST = a list of addresses we have created for ourselves.
If we use the first form of the parameter list (in parentheses),
the CALL macro will define storage in-line to hold the addresses in
question and then branch around it.
It is possible to define the parameter list as a literal:
CALL _entry_name_,=A(P1,P2)
If there are no arguments to be passed, there is no need for a
parameter list.
An option is to add VL at the end, where VL indicates that the
subprogram may be passed a variable number of parameters and that the
last address in PARMLIST has its leftmost bit = 1.
Another option is to add id at the end, where id = a 2-byte
identifier for debugging purposes only; this appears as the last 2
bytes in the macro expansion. (Specifically, id will be the last two
bytes of a NOP instruction at the end of the macro expansion.)
Thus we could have:
CALL MYSUB,(ABC,DEF,GHI),VL
or
CALL YOURSUB,(JKL,MNO),id=HH
where MYSUB can accept a variable number of arguments and is getting 3
this time, and YOURSUB accepts exactly two arguments.
Note about the VL option: The idea here is that if the program
does not know how many parameters have been passed, it can identify
the end of the parameter list by inspecting the leftmost bit of each
address in turn. This is not always necessary; if the program expects
a fixed number of arguments, not a variable number, there is no need
to code VL. This is an old convention and is basically why we have
31-bit rather than 32-bit addressing (i.e., to maintain backwards
compatibility).
The return code in register 15 after using the CALL macro is from
the subprogram; the CALL macro does not itself generate a return code.
LOAD macro
The LOAD macro makes use of SVC 8 and is used to bring a load
module into memory if no usable copy is already loaded. (If the load
module is already present and is usable, no additional copy is
loaded.) The load module will be found as a member of a PDS, i.e., a
load library, which may be one of the system libraries or may be
listed in the JCL in a STEPLIB or JOBLIB DD statement.
The LOAD macro is thus involved in dynamic linkage, not static
linkage.
The module remains in memory until the task terminates or the
task executes a DELETE macro to remove it.
Control is not passed to the module, but its address is returned
in register 0. (Store it somewhere.)
The syntax for this is:
LOAD EP=_entry_point_name_
or
LOAD EP=_entry_point_address_
The LOAD macro can also use ERRET. Thus we might have:
LOAD EP=MYMOD,ERRET=MYERROR
LOAD provides a return code in register 15 which is 0 for success
and a nonzero value for failure.
Once we have brought the load module into memory with LOAD, we
can execute it using the CALL macro or our own equivalent code. If
the module has been marked as “serially reusable”, it can be executed
repeatedly.
Link Macro
The LINK macro makes use of SVC 6 and does the following:
(a) it will bring a load module into memory if no usable copy is
alreadyloaded; and
(b) it passes control to the module.
The LINK macro is thus used for dynamic linkage. It could be
used for static linkage, but it would be more than is needed: use the
CALL macro instead.
The syntax for this is:
LINK EP=_entry_point_name_
or
LINK EPLOC=_entry_point_address_
LINK can also have ERRET, and it usually will have PARAM. An
example of this might be:
LINK EP=MYSUB,PARAM=((3),(4))
or
LINK EP=YOURSUB,PARAM=(THISARG,THATARG),ERRET=MYBAD
The return code in register 15 after using the LINK macro is from
the subprogram; the LINK macro does not itself generate a return code.
DELETE macro
The DELETE macro is used to remove from memory a module put there
earlier by a LOAD macro.
The syntax for this is:
DELETE EP=_entry_point_name_
or
DELETE EPLOC=_entry_point_address_
An option is RELATED=value. This is for documentation only.
The DELETE macro provides a return code in register 15 which is 0
for success or a nonzero value for failure.
If there are multiple copies of a load module in memory, each
summoned there using the LOAD macro, they will be unloaded in reverse
order, that is "last-in, first-out".
------
How do I make a dynamic call to an external subprogram?
In a dynamic call, the external subprogram is not part of the
calling program's load module. It exists as a separate load module,
stored as a member of a load library (a PDS), and before it can be
executed, it must be brought into memory. There are at least two
ways to do this.
Method 1: The LOAD macro will cause the subprogram's load module to
be located and brought into memory (if no usable copy is already
available), and it returns the address of the desired entry point in
register 0. It does not transfer control to the subprogram. When we
want to call the subprogram, we use the address of the entry point in
more or less the same code used for a static call. We could instead
use the CALL macro or the LINK macro, once we have the entry point
address.
Once a load module has been brought into memory, it remains there
(unless we unload it using the DELETE macro). However, we may want to
use it more than once, and by default, the linkage editor marks the
load module as "not reusable", which means that if we need it again,
another copy will be brought into memory. To avoid this, we need to
use a linkage editor option: REUS(SERIAL). This will cause the
module to be marked as "serially reusable".
Example using the LOAD and CALL macros:
Suppose a program named BOSS wants to call an external subprogram
named MINION, passing it the addresses of arguments P1 and P2. It can
do this as follows:
LOAD EP=MINION
ST 0,MADDR
and later:
L 15,MADDR
CALL 0(15),(P1,P2)
Here the LOAD macro brings the load module for MINION into
memory (if necessary) and returns the address of the entry point in
register 0. We store the address to save it for later use, and then
use the CALL macro or LINK macro or write our own code for the call.
(Do not leave your only copy of a valuable address--or anything else
valuable--in register 0.)
Method 2: The LINK macro will cause the subprogram's load module to
be located and brought into memory (if no usable copy is already
available) and it then transfers control to the subprogram. When the
subprogram terminates, control returns to the statement immediately
after the LINK.
Example using the LINK macro:
LINK EP=MINION,PARAM=(P1,P2)
------
How and why do I unload a dynamically loaded subprogram?
If we have brought a load module into memory using the LOAD
macro, and we have used it, we may well want to have it removed from
memory.
We can unload the load module by using the DELETE macro.
Example:
Suppose a program named BOSS has called a subprogram named MINION
dynamically using the LOAD macro. As a result, there is a copy of
MINION's load module in memory. BOSS can cause that load module to be
removed from memory:
DELETE EP=MINION
The most obvious reason to do this is that memory is valuable and
we may want to load some other subprogram next. Another possible
reason is that we may have modified the module's contents in a
previous call. If so, and if the module is marked as serially
reusable, then to obtain a fresh copy, we need to remove the existing
copy and re-load the subprogram.
If there are multiple copies of a load module in memory, each
summoned there using the LOAD macro, they will be unloaded in reverse
order, that is "last-in, first-out".
------
How do I decide: static call or dynamic call?
If we are designing a new program from scratch, we have a choice:
we can call external subprograms statically or dynamically. How do we
choose between these?
With a static call:
(a) We have a larger load module (because the subprogram’s
module is included in it).
(b) Even if the subprogram is called only once, the overall load
module remains large.
(c) When we call the subprogram, we are branching to another
location already provided, and the call runs quickly.
(d) If we decide to make a change to the subprogram, it will be
necessary to recompile the subprogram and then redo the link-
editing of the calling program’s load module.
With a dynamic call:
(a) We have a smaller load module to begin with, but we will
need more memory later when the subprogram’s load module is
loaded.
(b) If we wish, we can delete the subprogram’s load module from
memory when we are done with it.
(c) The first call to the subprogram will be slow, as it will
involve disk I/O to locate and load the subprogram’s load module.
After that, it is already in memory.
(d) If we decide to make a change to the subprogram, it will be
necessary to recompile and link-edit the subprogram, but the
calling program’s load module is unaffected.
An analogy might be the following: You hire a handyman to do
some work in your home. He arrives in his truck and carries in a
toolbox. The tools in the toolbox are immediately at hand, easy to
use. At some point, he discovers he needs a tool not in the toolbox,
so he pauses, goes out to his truck, and brings in the tool he needs.
That tool is then also immediately at hand, easy to use. Why not put
everything in the toolbox initially? If he did so, the toolbox might
be too heavy to carry.
Suppose we are engaged in maintenance. In that case, it will be
much easier to make the necessary changes to subprograms if they are
called dynamically, especially if the subprogram is used by dozens of
calling programs. See item (d) on each list above.) For this reason,
some shop standards require that all calls to subprograms should be
dynamic, not static.
Suppose a new system is being designed. In that case, the choice
of static versus dynamic calls is up to the designer, who may or may
not know or care about some of these issues. Thus it is desirable to
be able to understand and write the code either way.
------
How do I create an alternate entry point in a program?
A program can have more than one entry point, that is, more than
one point at which execution can begin. The name on a CSECT or START
instruction is always an entry point. We can create additional entry
points using the ENTRY instruction:
ENTRY NAME
Here “NAME” is an alternate entry point. The assembler will list
it in the External Symbol Dictionary (ESD). When the linkage editor
creates the load module and stores it in a load library (a PDS), there
will be an extra entry in the PDS directory listing “NAME” and its
relative location within the load module.
Why is this needed? Why should we not be able to start execution
at any labeled address just by using the label? The answer is that if
we do not use ENTRY, the label “NAME” will disappear in the assembly
process, replaced wherever it is used by its address. The effect of
ENTRY is that the label is stored so others can refer to it later.
Of course, each alternate entry point will need the usual entry
linkage.
------
How do I use an alternate entry point in a program?
Suppose I am writing a program named MAIN and I want to call an
alternate entry point called ODDBALL which is contained in another
program called JUNIOR. (That is, in JUNIOR, we have an ENTRY statement
for ODDBALL.) Assume the source code for JUNIOR is in some other
source code module which will be assembled separately. My intention
is that JUNIOR will be included in the load module when we link-edit
MAIN, so this will be a static call. At some point, I call ODDBALL:
CALL ODDBALL,PARMLIST
To make this work, we need to announce to the assembler in
advance that we are going to refer to this name (ODDBALL) which is not
part of the same source code module. We do this with an EXTRN
statement:
EXTRN ODDBALL
This is not needed if all the source code for MAIN and JUNIOR is
in the same source code module, as all the entry points will be listed
in the same External Symbol Dictionary, but it is needed if we are
working with multiple source code modules. (It would be probably be a
good practice in any case.)
Also see the preceding section.
------
How do I make use of an EXEC PARM?
The PARM on the EXEC line is a string up to 100 characters
long. It is normally enclosed in parentheses or single quotation
marks, as in
PARM='THIS,THAT'
or
PARM=(THIS,THAT)
or if it is very simple (a single word or number), it may be written
without delimiters, as in
PARM=THIS
In any case, the delimiters (if present) are not part of the value.
They are stripped off by the Job Entry System (JES) or one of the
programs it invokes.
While we can easily have a PARM shorter than 100 characters, or
none at all, it cannot be expanded to more than 100 characters for the
simple reason that it is stored in an MVS control block which has
exactly that many bytes of space reserved for it. (The 100-byte
limitation is unlikely to be changed anytime soon. If you need to
pass more than 100 characters to a program, put them in a file and
have your program read the file.)
There are two pieces of information we need about the PARM value:
its length and the address of the string itself. These are stored in
a contiguous block of storage as follows:
first 2 bytes = the length of the string as a signed binary
halfword
later bytes = the string itself
Suppose we have an EXEC statement:
//STEP4 EXEC PGM=ASMMAIN,PARM='ABC,123'
This is a parameter being passed to an assembly-language program,
so we have a parameter list, and its address will be in register 1.
That is, register 1 contains the address of the parameter list, and
the parameter list itself contains one fullword, the address of the
block described above. (That is, we have a pointer to a pointer.)
In ASMMAIN, we unload the parameter list as follows:
L 2,0(1) Point register 2 at the block.
LH 3,0(2) Load the length in register 3.
LA 4,2(2) Point register 4 at the string.
Now we can now parse the string and use its contents. (Of
course, we could use registers other than 2 through 4 here.)
------
How does a program receive a variable number of parameters?
Sometimes we may want to have a program which may be used with
different number of parameters on different occasions. For instance,
we could have a program called FINDMAX with parameters MAX, A, B, C,
D, etc., which computes MAX = the largest of the other values. We may
call it as
CALL FINDMAX,(MAX,A,B,C)
or
CALL FINDMAX,(MAX,A,B)
where we do not always have the same number of parameters. Will this
work? As it stands, no: FINDMAX may try to unload the parameter
list, expecting to find four addresses (MAX, A, B and C) instead of
three (MAX, A and B). This will cause trouble, perhaps an ABEND due
to a protection exception--and it may be more trouble if it does not
cause an ABEND.
To make it work, FINDMAX needs to have some way to count its