Miscellaneous Topics in Linkage

Miscellaneous Topics in Linkage

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