COBOL GnuCOBOL 3.2 ·
✓ verified by execution on 2026-08-16
As your COBOL applications grow, keeping everything inside a single monolithic program becomes unmanageable. Just like modern languages use functions or methods, COBOL uses subprograms to divide logic into reusable, bite-sized pieces.
To pass data between a main calling program and a subprogram, COBOL provides the CALL statement and a special memory area known as the LINKAGE SECTION.
The Architecture of a Call
When a main program issues a CALL, it passes memory addresses to the subprogram. The subprogram catches these addresses using its LINKAGE SECTION.
The LINKAGE SECTION does not allocate memory itself. It merely acts as a map to memory that was allocated by the calling program. Let’s see how a simple string passes from the caller to the subprogram.
cobol✓ verified output
IDENTIFICATION DIVISION. PROGRAM-ID. CALLER. DATA DIVISION. WORKING-STORAGE SECTION. 01 WS-NAME PIC X(10) VALUE 'WORLD'. PROCEDURE DIVISION. CALL 'GREET' USING WS-NAME STOP RUN. END PROGRAM CALLER. IDENTIFICATION DIVISION. PROGRAM-ID. GREET. DATA DIVISION. LINKAGE SECTION. 01 LS-NAME PIC X(10). PROCEDURE DIVISION USING LS-NAME. DISPLAY 'Hello, ' LS-NAME EXIT PROGRAM. END PROGRAM GREET.
Output
Hello, WORLD
Your output
Notice that the variable names (WS-NAME and LS-NAME) don’t have to match. The binding is done strictly by position: the first variable in CALL USING maps to the first variable in PROCEDURE DIVISION USING.
BY REFERENCE vs BY CONTENT
COBOL provides two main ways to pass data:
BY REFERENCE (Default): Passes the exact memory address. If the subprogram changes the value, the caller’s variable is also permanently changed.
BY CONTENT: Passes a copy of the data. If the subprogram changes the value, it only changes its local copy, keeping the caller’s variable safe.
Modifying Data (BY REFERENCE)
If you want the subprogram to calculate a value and hand it back, use BY REFERENCE (or let it default, since BY REFERENCE is the default behavior).
cobol✓ verified output
IDENTIFICATION DIVISION. PROGRAM-ID. MAINPGM. DATA DIVISION. WORKING-STORAGE SECTION. 01 WS-NUM PIC 99 VALUE 10. PROCEDURE DIVISION. DISPLAY 'Before: ' WS-NUM CALL 'SUBPGM' USING BY REFERENCE WS-NUM DISPLAY 'After: ' WS-NUM STOP RUN. END PROGRAM MAINPGM. IDENTIFICATION DIVISION. PROGRAM-ID. SUBPGM. DATA DIVISION. LINKAGE SECTION. 01 LS-NUM PIC 99. PROCEDURE DIVISION USING LS-NUM. ADD 5 TO LS-NUM EXIT PROGRAM. END PROGRAM SUBPGM.
Output
Before: 10
After: 15
Your output
Protecting Data (BY CONTENT)
Sometimes, you need to pass a variable that the subprogram needs to read, but you don’t want the subprogram to accidentally mangle it. By using BY CONTENT, you guarantee safety.
cobol✓ verified output
IDENTIFICATION DIVISION. PROGRAM-ID. MAINPGM. DATA DIVISION. WORKING-STORAGE SECTION. 01 WS-NUM PIC 99 VALUE 10. PROCEDURE DIVISION. CALL 'SUBPGM' USING BY CONTENT WS-NUM DISPLAY WS-NUM STOP RUN. END PROGRAM MAINPGM. IDENTIFICATION DIVISION. PROGRAM-ID. SUBPGM. DATA DIVISION. LINKAGE SECTION. 01 LS-NUM PIC 99. PROCEDURE DIVISION USING LS-NUM. ADD 5 TO LS-NUM EXIT PROGRAM. END PROGRAM SUBPGM.
Output
10
Your output
Notice that the value of WS-NUM in the main program remains 10, because BY CONTENT creates a protective copy.
Passing Literals
Because BY CONTENT creates an ephemeral copy for the subprogram, you can actually use it to pass raw string or numeric literals directly to the subprogram!
Predict the outputcobol
Read the code. What exactly will it print? Commit to an answer before you look.
ID DIVISION. PROGRAM-ID. M. PROCEDURE DIVISION. CALL 'S' USING BY CONTENT 4. END PROGRAM M. ID DIVISION. PROGRAM-ID. S. DATA DIVISION. LINKAGE SECTION. 01 X PIC 9. PROCEDURE DIVISION USING X. ADD 3 TO X DISPLAY X. END PROGRAM S.
Output
7
You predicted
What do you predict the program M will output?
It will output 7 because numeric literals passed by content can be safely modified.
It will output 4 because BY CONTENT prevents modifications to the original value.
It will crash because M does not have a variable to store the result.
The correct answer is 7, as BY CONTENT allocates temporary memory for the literal which the subprogram can modify without crashing.
Check yourself
What does the LINKAGE SECTION do?
Reveal answer
Maps to memory that already exists in the calling program — The LINKAGE SECTION does not allocate its own memory. It provides a map for accessing memory passed by the caller.
What happens if a subprogram modifies a parameter passed BY CONTENT?
Reveal answer
Only the subprogram\'s local copy is modified — BY CONTENT makes a copy of the argument before the subprogram executes, preventing modification of the original.
Can you pass string literals directly to a subprogram?
Reveal answer
Yes, you can pass literals by using BY CONTENT — Because BY CONTENT creates a copy of the data, you can pass literals directly without defining them in WORKING-STORAGE first.
Challenges
Challenge 1 +50 XP
The subprogram is supposed to return a calculated tax amount to the main program, but the main program still shows zero! Fix the CALL statement so the subprogram can modify the original variable.
cobol✓ solution verified at build time
COBOL has no in-browser runtime, so this one is pen-and-paper: work out what the
fixed code should be, then open the solution and compare. The expected output
below is real — it came from compiling the solution with GnuCOBOL when this page
was built.
Test 1 — expects "Tax is: 010"
Show solution (0 XP)
IDENTIFICATION DIVISION.PROGRAM-ID. MAIN.DATA DIVISION.WORKING-STORAGE SECTION.01 WS-PRICE PIC 999 VALUE 100.01 WS-TAX PIC 999 VALUE 000.PROCEDURE DIVISION. CALL 'CALC' USING BY CONTENT WS-PRICE BY REFERENCE WS-TAX DISPLAY 'Tax is: ' WS-TAX STOP RUN.END PROGRAM MAIN.IDENTIFICATION DIVISION.PROGRAM-ID. CALC.DATA DIVISION.LINKAGE SECTION.01 LS-PRICE PIC 999.01 LS-TAX PIC 999.PROCEDURE DIVISION USING LS-PRICE, LS-TAX. COMPUTE LS-TAX = LS-PRICE * 0.10 EXIT PROGRAM.END PROGRAM CALC.
Challenge 2 +50 XP
The SUBROUTINE needs to receive two PIC 9 arguments: IN-A and IN-B. Complete its LINKAGE SECTION and PROCEDURE DIVISION USING clause so it can print their sum.
cobol✓ solution verified at build time
COBOL has no in-browser runtime, so this one is pen-and-paper: work out what the
fixed code should be, then open the solution and compare. The expected output
below is real — it came from compiling the solution with GnuCOBOL when this page
was built.
Test 1 — expects "Sum: 4+5"
Show solution (0 XP)
IDENTIFICATION DIVISION.PROGRAM-ID. MAIN.DATA DIVISION.WORKING-STORAGE SECTION.01 WS-A PIC 9 VALUE 4.01 WS-B PIC 9 VALUE 5.PROCEDURE DIVISION. CALL 'SUB' USING WS-A WS-B STOP RUN.END PROGRAM MAIN.IDENTIFICATION DIVISION.PROGRAM-ID. SUB.DATA DIVISION.LINKAGE SECTION.01 IN-A PIC 9.01 IN-B PIC 9.PROCEDURE DIVISION USING IN-A, IN-B. DISPLAY 'Sum: ' IN-A '+' IN-B EXIT PROGRAM.END PROGRAM SUB.
🐞 Bug Hunt+25 XP
This developer tried to create a local variable `LS-TEMP` with a `VALUE` clause, but they placed it in the `LINKAGE SECTION`. Because it is in the `LINKAGE SECTION`, COBOL assumes the caller will provide the memory. Since the caller doesn't pass it, the program crashes with an `invalid memory address` when trying to display it. Move `LS-TEMP` to the correct section so it is allocated its own memory.
This code runs. It just does the wrong thing. Read it, find the defect,
fix it — the tests below decide when you are right.
cobol✓ solution verified at build time
COBOL has no in-browser runtime, so this one is pen-and-paper: work out what the
fixed code should be, then open the solution and compare. The expected output
below is real — it came from compiling the solution with GnuCOBOL when this page
was built.
Test 1 — expects "Temp is: 42\n"
Need a hint? (−25% XP)
Change `LINKAGE SECTION.` to `WORKING-STORAGE SECTION.` in the subprogram.
Show solution (0 XP)
IDENTIFICATION DIVISION.PROGRAM-ID. MAIN.PROCEDURE DIVISION. CALL 'SUB' STOP RUN.END PROGRAM MAIN.IDENTIFICATION DIVISION.PROGRAM-ID. SUB.DATA DIVISION.WORKING-STORAGE SECTION.01 LS-TEMP PIC 99 VALUE 42.PROCEDURE DIVISION. DISPLAY 'Temp is: ' LS-TEMP EXIT PROGRAM.END PROGRAM SUB.