Here we have an external subroutine called ABS which will compute the absolute value of an integer. It is relatively simple.
ABS has one input parameter, N, and one output parameter, P.
The only problem to address is overflow. Why could we have overflow? Suppose the value of N is -2^32, the largest available negative integer. Its absolute value should be +2^32, but that value is too large and we have overflow. In the event of overflow, we will return the value P = -1.
The documentation for an external subroutine should include its name, a brief description of its purpose, a list of parameters and their purposes, a list of registers and how they are used, and (sometimes) pseudocode to explain how the work is to be done.
Code for calling ABS
In the main program, we have the following in storage:
MAINSAVE DS 18F N DC F'-37' P DS F PLIST DC A(N) DC A(P)
and in its executable code we have:
LA 1,=PLIST Reg.1 : address of PLIST L 15,=V(ABS) Point R15 at ABS BALR 14,15 Branch to ABS
Here the second line uses a V-type constant. The actual value is not available when the code is assembled but instead is supplied at the link-editing stage.
Code for the subroutine ABS
The code for ABS looks like this:
ABS CSECT * These first few lines are "Standard Entry Linkage". STM 14,12,12(13) Save the registers. LR 12,15 Establish 12 as the USING ABS,12 base register. LA 14,ABSSAVE Point R14 at ABSSAVE. ST 13,4(0,14) Save the forward pointer. ST 14,8(0,13) Save the backward pointer. LR 13,14 Point R13 at ABSSAVE. * LM 2,3,0(1) Unload the parameters. * Now we reach the code that actually does the work. L 4,0(2) Now reg. 4 contains N. LPR 4,4 Make it >= 0. BNO DONE If not overflow, skip ahead, L 4,=F'-1' else set reg. 4 to -1. DONE DS 0H ST 4,0(3) Store the value of P. *These last few lines are "Standard Exit Linkage". L 13,4(0,13) Point R13 at caller's save area. LM 14,12,12(13) Restore the registers. BR 14 Return to the caller. * LTORG ABSAVE DS 18F Save area for ABS.
Notes on External Linkage
Notice that some registers are used for very specific purposes, an important programming convention:
Of these, registers 12 and 13 should be left alone and untouched throughout the subroutine's code. If the subroutine itself needed to call another subroutine, we would have the same sequence of events.
We could have a different base register instead of 12, such as 10 or 11.
If your subroutine is itself definitely not going to call any subroutines, you could theoretically get along without a local save area. It is a good programming practice, however, to have a local save area and use standard linkage code in every program.
There are some possible minor variations on entry linkage. For instance, some people like to do this:
STM 14,12,12(13) BAL 14,*+76 SAVEAREA DS 18F ST 13,3(0,14) ST 14,8(0,13) LR 13,14 USING SAVEAREA,13
This has the slight advantage of using 13 as the base register, thus freeing up 12 for other use.
In the exit linkage, we sometimes want to pass information back from a subroutine using register 15 or (less often) 0. The value in register 15 is called the return code, a value between 0 and 4095, and is normally used to report on the success or failure of the subroutine. If we want to do this, we do not to restore the value of that register at the end.
Suppose we want to pass back a return code in register 15. Instead of
LM 14,12,12(13)
we would use code like this:
L 14,12(0,13) LM 0,12,20(13)
skipping over the old value of register 15 stored at 16(0,13).
In IBM software, a return code of 0 usually indicates success, and nonzero values usually indicate unusual events (such as an empty input file) or failures.
In the present example, we might want to handle the remote possibility of overflow by providing a return code of 0 if there is no problem and 4 if overflow occurs (instead of returning P = -1).
One advantage of using external subroutines is that they can more easily be reused. We could have a library of subprograms we could call from our main programs. Another advantage is that we have multiple CSECTs, each of which has its own base register. Remember that implicit addresses involve a base register and a displacement, and the displacement is limited to a range of 0 to 4095 bytes. With multiple CSECTs, we can have much larger programs.
It is also possible to have more than one base register. Suppose register 15 contains the address of a subroutine called SUB and I do the following:
LR 12,15 LA 11,4095(0,12) LA 11(1,11)
Now register 11 contains an address 4096 bytes beyond the address in register 12. I can now say USING SUB,12,11
This gives us two base registers for SUB. Implicit addresses will be calculated using whichever one produces a smaller displacement.