Subprograms & CALL

25.1 Calling a subprogram

Main program (payroll.cob):

Subprogram (calctax.cob):

Parameters are matched by position, not by name. The LINKAGE layouts must match the caller's data exactly — a mismatch silently corrupts memory. Share layouts through copybooks (Chapter 27).

WORKING-STORAGE of the subprogram persists between calls (WS-CALL-COUNT keeps counting) until the caller issues CANCEL "CALCTAX". Use PROGRAM-ID. CALCTAX IS INITIAL. to get fresh storage on every call, or LOCAL-STORAGE.

IDENTIFICATION DIVISION.
       PROGRAM-ID. PAYROLL.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  WS-GROSS             PIC S9(7)V99 COMP-3 VALUE 5250.00.
       01  WS-TAX-RATE          PIC SV9(4)   COMP-3 VALUE .2150.
       01  WS-TAX               PIC S9(7)V99 COMP-3.
       01  ED-TAX               PIC Z,ZZZ,ZZ9.99.
       PROCEDURE DIVISION.
           CALL "CALCTAX" USING BY REFERENCE WS-GROSS
                                BY CONTENT   WS-TAX-RATE
                                BY REFERENCE WS-TAX
               ON EXCEPTION
                   DISPLAY "CALCTAX not found"
                   MOVE 16 TO RETURN-CODE
                   STOP RUN
           END-CALL
           IF RETURN-CODE NOT = 0
               DISPLAY "CALCTAX failed, RC = " RETURN-CODE
           END-IF
           MOVE WS-TAX TO ED-TAX
           DISPLAY "Tax: " ED-TAX
           STOP RUN.
IDENTIFICATION DIVISION.
       PROGRAM-ID. CALCTAX.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  WS-CALL-COUNT        PIC 9(5) VALUE 0.
       LINKAGE SECTION.
       01  LK-GROSS             PIC S9(7)V99 COMP-3.
       01  LK-RATE              PIC SV9(4)   COMP-3.
       01  LK-TAX               PIC S9(7)V99 COMP-3.
       PROCEDURE DIVISION USING LK-GROSS LK-RATE LK-TAX.
           ADD 1 TO WS-CALL-COUNT
           IF LK-GROSS < 0
               MOVE 8 TO RETURN-CODE
               GOBACK
           END-IF
           COMPUTE LK-TAX ROUNDED = LK-GROSS * LK-RATE
           MOVE 0 TO RETURN-CODE
           GOBACK.
cobc -x payroll.cob calctax.cob          # one executable (static)
# or: dynamic loading
cobc -x payroll.cob
cobc -m -o CALCTAX.so calctax.cob            # module named after the PROGRAM-ID
                                             # (.dll on Windows, .dylib/.so on macOS)
export COB_LIBRARY_PATH=.                    # where to find modules
./payroll                                    # Tax:     1,128.75

25.2 Passing modes

What is passed Callee changes visible to caller?

BY REFERENCE (default) Address of the caller's item Normal COBOL-to-COBOL parameters, outputs Address of a temporary copy Protect caller data; pass literals

The value itself (binary integers, pointers) Calling C and system APIs

RETURNING receives a function-style result: CALL "strlen" USING BY REFERENCE WS-CSTR RETURNING WS-LEN.

25.3 Static vs dynamic calls

CALL "LITERAL" compiled with IBM NODYNAM (or GnuCOBOL -fstatic-call)

CALL WS-PGM-NAME (identifier) always; CALL "LITERAL" with IBM DYNAM

Subprogram link-edited into the caller's load module Loaded from a library (STEPLIB/JOBLIB on z/OS, COB_LIBRARY_PATH in GnuCOBOL) at first call

Slightly faster call; single module to deploy Subprogram can be changed without relinking callers; smaller modules; CANCEL frees storage Relink every caller after a change

Load overhead on first call; S806 abend if module is missing

Example of a dynamic call: CALL WS-PGM-NAME USING WS-GROSS WS-TAX-RATE WS-TAX (with WS-PGM-NAME PIC X(8) VALUE "CALCTAX"), followed later by CANCEL WS-PGM-NAME to release it.

25.4 Calling C from GnuCOBOL

COMP-5 matches the native C int representation. On z/OS, COBOL calls C, PL/I, and Assembler through Language Environment (LE) interlanguage communication.

/* addints.c */
int add_ints(int a, int b) { return a + b; }
IDENTIFICATION DIVISION.
       PROGRAM-ID. CALLC.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  WS-A                 PIC S9(9) COMP-5 VALUE 40.
       01  WS-B                 PIC S9(9) COMP-5 VALUE 2.
       01  WS-SUM               PIC S9(9) COMP-5.
       PROCEDURE DIVISION.
           CALL "add_ints" USING BY VALUE WS-A BY VALUE WS-B
                RETURNING WS-SUM
           END-CALL
           DISPLAY "Sum from C: " WS-SUM
           STOP RUN.
cobc -x callc.cob addints.c && ./callc

25.5 Receiving a JCL PARM (z/OS)

with //STEP1 EXEC PGM=MYPROG,PARM='2026-03-31,FULL'.

LINKAGE SECTION.
       01  LK-PARM.
           05  LK-PARM-LEN      PIC S9(4) COMP.
           05  LK-PARM-TEXT     PIC X(100).
       PROCEDURE DIVISION USING LK-PARM.
           IF LK-PARM-LEN > 0
               DISPLAY "PARM = " LK-PARM-TEXT(1:LK-PARM-LEN)
           END-IF

25.6 RETURN-CODE

RETURN-CODE is a special register. In a subprogram it returns a status to the caller; in the main program its final value becomes the step condition code on z/OS (or the process exit status on Linux), which JCL can test with COND or IF (Chapter 35). Conventions: 0 = OK, 4 = warning, 8 = error, 12 = severe, 16 = fatal.