Subprograms, CALL linkage and nested programs
Real COBOL systems are hundreds of small programs calling each other. How a call is resolved (static, dynamic or nested) decides what has to be relinked when something changes, and how parameters are passed decides whether a caller's data can be damaged.
Why programs are split up
A payment system is rarely one program. A driver reads the input, then CALLs small subprograms: one validates the account, one calculates interest, one formats the audit record. Splitting the work this way means a date routine is written once and shared by hundreds of programs, and a fix to it does not mean touching every caller. The cost is that you now need to understand how the caller finds the subprogram and how data moves between them.
Static versus dynamic calls
A static call is resolved by the binder: the subprogram's object code is copied into the caller's load module. A dynamic call is resolved at run time: the first time the CALL runs, the module is loaded from the step's program search order: STEPLIB (or JOBLIB if the step has no STEPLIB), then the system libraries such as LPA and the link list.
| Static | Dynamic | |
|---|---|---|
| How written | CALL 'LITERAL' compiled with NODYNAM | CALL identifier, or CALL 'LITERAL' compiled with DYNAM |
| Resolved | At bind (link-edit) time | At run time, on first call |
| Change the subprogram | Every caller must be rebound to pick it up | Replace the one load module; callers pick it up next run |
| Typical failure | Old copy still inside a caller nobody rebound | S806 module not found, wrong library concatenation |
| Speed | No load cost | Small cost on first call; later calls are fast |
Most large shops standardise on one approach, often dynamic for shared routines, so that a fix can be promoted as a single module. Ask which convention your site uses before you change compile options.
Passing parameters
The caller lists arguments on the CALL; the subprogram describes them in its LINKAGE SECTION and names them on PROCEDURE DIVISION USING. Nothing checks that the two descriptions match. The subprogram simply maps its layout over whatever address it is given.
BY REFERENCE WS-ACCOUNTBY CONTENT WS-RATEBY VALUE WS-COUNTRETURNING / RETURN-CODE * Caller
CALL 'ACCTVAL' USING WS-ACCT-REC WS-RESULT
IF RETURN-CODE NOT = 0
PERFORM 9000-REJECT
END-IF
* Subprogram ACCTVAL
LINKAGE SECTION.
01 LK-ACCT-REC. COPY ACCTREC.
01 LK-RESULT PIC X(2).
PROCEDURE DIVISION USING LK-ACCT-REC LK-RESULT.
...
GOBACK.Sharing the record layout through a single copybook is the best defence against mismatches. End subprograms with GOBACK, not STOP RUN: STOP RUN ends the whole run unit, including the caller.
State between calls, CANCEL and INITIAL
A called program keeps its WORKING-STORAGE between calls. That is useful for caching, and dangerous when a counter or switch from the previous call leaks into the next. CANCEL 'ACCTVAL' releases a dynamically called program so the next call starts fresh. Declaring PROGRAM-ID. ACCTVAL IS INITIAL. makes every call start from initial values.
Nested programs
A nested program is a complete program coded inside another one, ended with its own END PROGRAM marker. It is compiled with its parent and can only be called from within that compile unit. Data marked GLOBAL in the parent is visible to the nested programs; a nested program marked COMMON can be called by its siblings. Nested programs give you private helper routines without publishing another load module.
Common mistakes
If caller and subprogram describe the data differently, fields land in the wrong place and you get bad data or S0C4. Share one copybook for every interface.
It ends the whole run unit, so the caller never gets control back. Subprograms should end with GOBACK.
Flags and counters persist between calls. Initialise them at the start of each call, use IS INITIAL, or CANCEL the program when a fresh state is needed.
What you will see at work
- Change reviews ask whether a modified subprogram is called statically, because that decides how many modules must be rebound and promoted.
- An S806 in a new job usually means the subprogram's load library is missing from STEPLIB or the module was never promoted to that environment.
- Interface copybooks are treated as contracts: changing one usually means recompiling every program that includes it.
Key terms
Check your understanding.
Take this lesson's quiz and save your progress. Free.