Mainframe Path Start learning free
Applied11 min readLesson 1 of 3

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.

StaticDynamic
How writtenCALL 'LITERAL' compiled with NODYNAMCALL identifier, or CALL 'LITERAL' compiled with DYNAM
ResolvedAt bind (link-edit) timeAt run time, on first call
Change the subprogramEvery caller must be rebound to pick it upReplace the one load module; callers pick it up next run
Typical failureOld copy still inside a caller nobody reboundS806 module not found, wrong library concatenation
SpeedNo load costSmall 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.

Three ways to pass an argumentWhat it means
BY REFERENCE WS-ACCOUNT
Default. The subprogram works on the caller's own storage, so changes are visible to the caller.
BY CONTENT WS-RATE
A copy is passed. The subprogram can change it without affecting the caller.
BY VALUE WS-COUNT
The value itself is passed. Used mainly when calling C or other non-COBOL routines.
RETURNING / RETURN-CODE
The subprogram can set RETURN-CODE (or a RETURNING item) to report success or failure.
A caller and a subprogram (illustrative)
      * 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.

Three ways to reach a subprogram
CallerCALL statement
Nestedinside same source
Staticcopied in at bind
Dynamicloaded from STEPLIB at run time

Common mistakes

Mismatched parameter layouts

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.

STOP RUN in a subprogram

It ends the whole run unit, so the caller never gets control back. Subprograms should end with GOBACK.

Forgetting called programs keep their storage

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

Key terms

Check your understanding.
Take this lesson's quiz and save your progress. Free.

Take the lesson quiz
Language Environment and production compiler options →