Subroutine
Linkage
We now begin discussion of
subroutine linkages for simple subroutines without
large argument blocks.
With the mechanisms discussed
in this lecture, one can use either global variables
or general purpose registers to pass addresses, values, and results.
As the textbook notes,
subroutines may be written to facilitate repetitive tasks.
Indeed, the “Wheeler Jump” (EDSAC,
1952) was developed for just this purpose.
Early operating systems began
as collection of subroutines to facilitate handling
of input and output devices, mainly line printers.
When batch programming became
common, the computer needed a control
program to
automate the processing of a sequence of jobs, read and processed one after
another.
This control program was merged
with a set of subroutines for Input/Output handling
and routines for standard mathematical functions to create the first operating
system.
Subroutines and/or functions
can be invoked for side effect only or in order to compute
and return results. Many of the subroutines
used in the book are called for side effect – to
manage print position on a page and issue a new page command when necessary.
Subroutine
Linkage: Instructions
The language requires two
instructions associated with subroutines: one to call the
subroutine and one to effect a return from the
subroutine.
Calling the subroutine
The instruction used is either BAL (Branch and Link)
or BALR.
The format of the instruction
is BAL Reg,Address
An example of such an
instruction is BAL 8,P10PAGE
The first argument is a
register number to be used for subroutine linkage.
We explain this more fully in just a bit.
The second argument is the
address of the first instruction in the subroutine. There are
other standards for this argument, but this is the one that IBM uses.
Returning from the subroutine
This instruction is used to
return from execution of the subroutine.
It is an unconditional
jump to an address contained in the register.
The format of the instruction
is BR Reg
An example of such an
instruction is BR 8
BAL and BALR
There are two forms of the
Branch and Link instruction.
BAL Branch
and Link
BALR Branch and
Link, Register.
The difference lies in the
handling of the entry point address of the called routine.
The BALR instruction uses an address placed in a
general–purpose register.
Here are two equivalent code
sequences.
Use BAL
BAL R8,P10PAGE
Use BALR
L R9,=A(P10PAGE)
BALR R8,R9
Later, we shall see that
general–purpose registers R14 and R15 are favored
for use by BALR in this context.
Comments on
the Subroutine Linkage
The first thing to note is that
the register used in the BR will, under almost all
circumstances, be that used in the BAL instruction calling the subroutine.
A bit of reflection will show
that this mechanism, by itself, will not allow
the use of recursive subroutines.
Actually, there is a workaround, but it involves
the use of a separate register for each level of subroutine nesting.
Here is an example of
subroutine usage in the standard of this discussion.
OPEN
(FILEIN,(INPUT))
OPEN
(PRINTER,(OUTPUT))
PUT
PRINTER,PRHEAD
GET
FILEIN,RECORDIN
*
A10LOOP BAL 8,B10DOIT
GET
FILEIN,RECORDIN
B
A10LOOP
A90END CLOSE
FILEIN
CLOSE
PRINTER
EXIT
*
B10DOIT MVC
DATAPR,RECORDIN
PUT
PRINTER,PRINT
BR 8
Functions
and Subroutines
The assembly language
programmer will generally speak of “subprograms”.
The concepts of subroutines and
functions are generally associated with higher
level languages, though they are really just programming conventions placed
on the use of the assembly language.
Given a programming language,
such as the IBM Assembler, that provides support for
subprogram linkage, all that is required to support functions is the
designation of one or
more general–purpose registers to return values from the function.
In CDC–7600 FORTRAN, the two
designated registers were X6 and X7. The
usage:
Single–precision results Register
X7 would return the value.
Double–precision results Register
X7 would return the low–order 32 bits
Register
X6 would return the high–order 32 bits.
As a result, any subroutine
could be called as a function. What one
got as a result would be
the value that the subroutine last placed in X7 or both X6 and X7. While this was chancy,
it was predictable.
Control
Section: CSECT
A control section (CSECT) is, by definition, a block of coding that
can be relocated
within the computer address space without affecting the operating logic of the
program.
A large system may comprise a
number of control sections, each independently
assembled and built using a link editor.
Every program contains a large
number of references, either to variables or addresses.
In a large system, individual
control sections may contain references to variables
or addresses not found locally. These
are links to other control sections.
A link editor edits the links; it searches each CSECT for references
that cannot be
resolved locally and attempts to find matches in other CSECTS in the system.
As an example, suppose your HLL
program contains the following line of code.
Y = 100*SIN(X)
It is not likely that your
program contains a function called SIN, presumably the sine.
The linkage editor will find the appropriate function in the RTS library and
resolve the
reference by building the link from your program to the system routine.
Declaring
External References
There are
two possibilities if your code contains a reference that cannot be
found within the local CSECT:
1. You
forgot to declare the reference and have an error in your program.
2. The
reference is to a variable or address in another CSECT.
In order
to distinguish between the two cases, one must explicitly declare a reference
as
external if it is not declared
within the local CSECT.
The data
type for such a reference is V
(external defined address). Recall that
all
“variable” references are really address references that access the contents of
the address.
Presumably,
one could write something like the following.
PROGB DC V‘0000’
But this
seems to be done rarely, if at all.
Invocation
of a subroutine found in a separate CSECT is achieved by use of the standard
system macro, CALL. We give an example,
and its expansion.
CALL PROGB
+ L 15,=V(PROGB) LOAD ADDRESS OF EXTERNAL REFERENCE
+ BALR 14,15 STORE RETURN ADDRESS INTO R14
Call By
Reference vs. Call By Value
Two of the
more common methods for passing data between CSECTs
are call by
reference and call by value. Note that
there are several other common methods.
In call by value, the calling program
delivers the actual values of the data to the
subroutine. This can alter the values of
those data, but the altered values will not
be returned to the calling routine. Some
languages call these “in parameters”.
In call by reference, the calling program
delivers the addresses of the data items to the
subroutine. The values of these data can
be changed by the called subroutine and those
values propagated back to the calling program.
Note that
the return address for the subroutine can also be changed.
This is an
old hacker trick.
The next
question we must ask is how these values and/or addresses
will be passed to the subroutine.
Mechanisms
for Passing
By this
title, we mean either the passing of values or the passing of addresses.
Basically,
there are three mechanisms for passing values to a subroutine.
Each of
these has been used.
1. Pass
the values in registers specifically designated for the purpose.
2. Pass
the values on the stack.
3. Pass
the values in an area of memory and pass a pointer to that area
by one of the other methods.
Remember
that a pointer is really just an
address in memory; it is an unsigned integer.
In some
high–level languages, a pointer may be manipulated as if it were an unsigned
integer (which it is). In others,
standard arithmetic cannot be applied to pointers.
Languages,
such as Java and C#, provide for pointers but do not allow direct arithmetic
manipulation of these addresses. For
that reason, the term “pointer” is not used.
Subroutines,
Separate Assemblies and Linkage
The
first example of a subroutine was the B10DOIT routine a few slides back.
B10DOIT MVC
DATAPR,RECORDIN
PUT
PRINTER,PRINT
BR
8
While
this is a valid subroutine, we note two facts of importance.
1. It
is in the same assembly as the calling module.
2. It
is in the same CSECT as the calling module.
In
general, we would like to link modules that are not assembled at the same time.
It might
even be necessary to link assembled code with code written in a higher–level
language and compiled. Thus COBOL
programs might call assembler language routines.
We have
already encountered the external declaration, which is used to declare that:
1. A
label corresponds to an address declared in another module, and
2. The
linking loader will have to resolve that address by loading the called module,
assigning an address to this
label, and updating that reference in the calling code.
IBM has
established a set of conventions for use by all modules when calling separately
assembled modules. These insure that
each module can work with any other module.
The Save
Areas
One key
design feature when developing subroutines and functions is the minimization
of side effects. One particular
requirement concerns the general purpose registers.
This
design requirement is that after the return from a called subprogram, the
contents of
the general purpose registers be exactly the same as before the call.
The only
exception to this rule is the use of a general purpose register for the return
of a
function value. In this case, each of
the calling routine and the called routine explicitly
allows for the value of that one specified register to be changed.
Save and Restore
The
strategy used is that each routine (including the main program) will save the
contents
of all but one of the general purpose registers on entry and restore those on
exit.
This has
evolved from an earlier strategy in which a developer would save the contents
of
only those registers to be used explicitly in the subprogram.
In the
statically allocated, non–recursive world of IBM assembler programs, each
routine
will declare an 18–fullword “save area”,
used to save important data.
The Save
Area
Each
assembler module should have a save area, which may be declared as follows.
The important feature is that eighteen full words are allocated.
SAVEA DS
18F
The
structure of the save area is shown in the table below.
Word |
Displacement |
Contents of the Word |
1 |
0 |
This is no longer used. It was once used by PL/I programs. |
2 |
4 |
The address of the save area of the calling program. Saved here to facilitate error processing. |
3 |
8 |
The address of the save area of any subprogram called. The subprogram called will update this value. |
4 |
12 |
The contents of general–purpose register 14, which
contains the return address to the calling program. |
5 |
16 |
The contents of general–purpose register 15, which |
6 |
20 |
The contents of general–purpose register 0. |
7 – 18 |
24 |
These twelve fullwords contain the contents of |
Register
Usage in Subprogram Calling
The following
is the Standard Linkage Convention for the use of
general–purpose registers.
Register Use
1 Address
of the parameter list
13 Address
of calling routine’s save area
14 Address
in the calling routine to which
control is
to be returned.
15 The
address of the entry point
in the
called subprogram.
We have
already seen an example of the use of registers 14 and 15.
Consider the following code.
L 15,=V(PROGB) LOAD ADDRESS OF EXTERNAL REFERENCE
BALR 14,15 STORE RETURN ADDRESS INTO R14
The SAVE
Macro
Often
the first executable instruction of a program will be SAVE (14,12). Here is
the actual code from the second lab assignment, in which I chose to expand
macros.
31 LAB02 CSECT
32 SAVE (14,12) SAVE CALLER’S REGISTERS
34+ DS
0H
35+ STM
14,12,12(13)
36 BALR R12,0 ESTABLISH ADDRESSABILITY
37 USING *,R12
38 LA
R2,SAVEAREA
LINK THE SAVE AREAS
39 ST
R2,8(,R13)
40 ST
R13,SAVEAREA+4
41 LR
R13,R2
On
entry, general–purpose register 13 contains the address of the supervisor’s
save area. The SAVE macro is written
under this assumption.
The
program executes as a subprogram of the supervisor (Operating System).
Recall
that the address designated 12(13) corresponds to an offset of 12
from the value stored in register 13.
If R13
contains address S0, then 12(13) corresponds to address (S0 + 12).
The User
Program Saves the Registers
In this
illustration, assume the following.
1. The
save area of the supervisor begins at address S0.
2. The
user main program is PA, with save area starting at address SA.
3. The
user program calls program PB, which has save area starting at SB.
This is
the case on entry to main program PA.
Register 13 points to the start of
the save area for the supervisor and 12(13) points to the start of its register save area.
The
instruction STM 14,12,12(13) is then
executed. The contents
of the
supervisor’s save area is now as follows.
The User
Program Links the Save Areas
The next
step is to establish addressability in the user program, so that addresses
such as that of the save area can be used.
The user program then forward links
the supervisor’s save area. Before that
happens, we just have two save areas.
Here is
the code to do the forward link. The
address of the start of the user save area
is placed in the fullword at offset 8 from the start of the supervisor’s save
area.
38 LA
R2,SA LINK THE SAVE AREAS
39 ST
R2,8(,R13) OFFSET 8 FROM S0
The User
Program Links the Save Areas (Part 2)
The
program now executes the following code to establish the backward link
from the user program to the supervisor’s save area.
40 ST
R13,SA+4
At this
point, register R13 contains the address of the supervisor’s save area.
The result of this instruction is the completion of the two–way links.
Now R2
holds the address of the user save area.
Note that this could have been
any of the registers in the range 2 – 12, excepting 12 which was
used for addressability.
The next
instruction established R13 as once again holding the address of the
save area of the current program.
41 LR
R13,R2
The Chain
Continues
Suppose
the user program calls a subprogram.
The chain is continued.
The Return
Process
The
return process restores the general–purpose registers to their values
before the call of the subroutine.
R13 is
first restored to point to the save area for the calling program.
Then the other general–purpose registers are restored.
Here is
the situation on return from Subprogram PB.
The code
is as follows.
L R13,SB+4 GET ADDRESS OF CALLER’S SAVE AREA
LM R14,R12,12(R13) RELOAD THE REGISTERS. R14 IS
LOADED WITH THE
RETURN ADDRESS
BR R14 RETURN TO THE CALLER
Entry/Exit
Considerations
Consider
how a program or subprogram starts and exits.
The
start code is something like the following.
SUB02
CSECT
SAVE (14,12) SAVE CALLER’S REGISTERS
+ DS
0H
+ STM
14,12,12(13)
BALR R12,0 LOAD R12 WITH THE ADDRESS
USING *,R12 OF THE NEXT INSTRUCTION
Here is
the standard exit code. Assume the save
area is at address SB.
L
R13,SB+4
ADDRESS OF CALLERS SA
LM R14,R12,12(R13) CALLER’S REGISTER VALUES
BR R14 RETURN
Note
that the next to last instruction in the second section causes addressability
in the
called program to be lost. This is due
to the fact that the value that had been loaded into
R12 to serve as the base register for this code’s addressability has been
overwritten.
Setting the
Return Code
The IBM
linkage standard calls for general–purpose register R15 to be loaded with a
return code indicating success or failure.
A value of 0 usually denotes a success.
It is
common to set the return code just before the terminating BR instruction, just
after the restoration of the calling routine’s registers.
The
following is typical code. Here, I am
setting a return code of 3.
L
R13,SB+4
ADDRESS OF CALLERS SA
LM R14,R12,12(R13) CALLER’S REGISTER VALUES
LA R15,3 LOAD CODE INTO R15
BR R14 RETURN
This
uses the LA (Load Address) instruction in its common sense as a way to
load a non–negative constant less than 4,096 into a general–purpose register.
Note
that an instruction such as L R15,=H‘3’ would require access to an element
in the subprogram’s literal pool.
However, the value of the subprogram’s base
register has been overwritten, and addressability has been lost.
Another
way to set the return code to 0 would be to execute the instruction
SR R15,R15.
The Dummy
Section (DSECT)
Recall
that parameters are passed by reference when it is desired to allow the called
program to change the values as stored in the calling program.
Call by
reference involves passing an address for a parameter. This address is then
used as a target for a new value to be passed back to the calling program.
For
passing large quantities of data, it is convenient to use a dummy section.
This
process is best considered as passing a record structure to the called
subprogram.
1. All
the data items to be passed to the called program are grouped in a
contiguous data block.
2. The
address of this data block is passed to the called subprogram.
3. The
called subprogram accesses items in the data block by offset from
the address passed to it.
The
DSECT is used in the called subprogram as a template for the assembler to
generate the proper address offsets to be used in accessing the original data.
Example of
Linkage Using a DSECT
Suppose
that I want to pass customer data from PROGA (the calling program, in
which the data are defined) to subprogram PROGB, in which they are used.
Here is
a sketch of code and declarations in the calling program, which is PROGA.
This uses the calling convention that R1 holds the address of the parameters.
PROGA CSECT
* SECTION TO
CALL PROGB
LA R1,=A(CREC) LOAD
RECORD ADDRESS
L
R15,=V(PROGB)
LOAD ADDRESS OF PROGB
BALR R14,R15 CALL THE SUBPROGRAM
Next Instruction
CREC DS 0CL96
THE RECORD WITH ITS SUBFIELDS
CNAME DS CL30
OFFSET = 0
CADDR1 DS CL20
OFFSET = 30
CADDR2 DS CL20
OFFSET = 50
CCITY DS CL15
OFFSET = 70
CSTATE DS CL2
OFFSET = 85
CZIP DS CL9 OFFSET = 87
The Dummy
Section Itself
The
dummy section will be declared in the called subprogram using a DSECT.
Here is
the proper declaration for our case.
CRECB DSECT
CNAME DS CL30
OFFSET = 0
CADDR1 DS CL20
OFFSET = 30
CADDR2 DS CL20
OFFSET = 50
CCITY DS CL15 OFFSET = 70
CSTATE DS CL2
OFFSET = 85
CZIP DS CL9 OFFSET = 87
The
DSECT is a convenient means that can be used to describe the layout of a
storage area without actually reserving storage.
In use
of a DSECT, it is assumed that the storage has been reserved elsewhere and
that the base address of that storage will be passed as a parameter.
The
DSECT is just a mechanism to instruct the assembler on generation of offsets
from the base address into this shared data area.
Use of the
DSECT in PROGB
Here is
a sketch of the use of the DSECT in PROGB, assembled independently.
Recall
that general–purpose register R1 contains the address of the customer record.
PROGB CSECT
BALR R12,0 ESTABLISH ADDRESSABILITY
USING *,R12
LR R10,R1 GET THE
PARAMETER ADDRESS
USING CRECB,R10 ESTABLISH
ADDRESSABILITY FOR
THE DUMMY
SECTION
MVC OUTC,CCITY THIS ACCESSES THE DATA IN
THE CALLING
PROGRAM
CCITY DS CL15 DATA BELONGING TO PROGB
CRECB DSECT
CNAME DS CL30
OFFSET = 0
CADDR1 DS CL20
OFFSET = 30
CADDR2 DS CL20
OFFSET = 50
CCITY DS CL15
OFFSET = 70
CSTATE DS CL2
OFFSET = 85
CZIP DS CL9 OFFSET = 87
A Detailed
Look at Addresses
Here we
recall two facts relative to the one instruction MVC OUTC,CCITY.
The
label OUTC
belongs to the called subprogram PROGB.
It is accessed using
base register R12, which is the basis for addressability in this subprogram.
The
label CCITY
belongs to the dummy section. It is
accessed using the base
register explicitly associated with the DSECT; here it is R10.
Suppose
that OUTC has
address X‘100’
(decimal 256) within PROGB, it is at that
displacement from the value contained in the base register R12.
From the
DSECT it is clear that the label CCITY is at displacement 70 (X‘46’)
from the beginning of the data record.
The field has length 15, or X‘0F’
The
instruction MVC OUTC,CCITY
could
have been written as MVC 256(15,R12),70(R10).
The
object code is thus D2 0E C1 00 A0 46
D2 is the operation code for MVC. 0E encodes decimal 14,
one less than the length.
C1 00 represents an address at displacement X‘100’ from base
register 12.
A0 46 represents an address at displacement X‘46’ from base
register 10.