Understanding IGZ0033S: Passing Parameters Above 16 MB to AMODE(24) COBOL Programs
Imagine you’re modernizing a core banking or enterprise z/OS application. You compile your main driver program with the latest enterprise compiler settings, fire off a test run, and BAM—your transaction abends with this daunting Language Environment (LE) error:
IGZ0033S: An attempt was made to pass a parameter address above 16 megabytes to AMODE(24) program PXXXX
This error is a classic side-effect of modern COBOL code interacting with legacy infrastructure. In this post, we’ll break down exactly why this happens, look at the architectural memory constraints behind it, and walk through how to fix it.
What Causes IGZ0033S?
The Root Cause: A Tale of Two AMODEs
The issue boils down to a breakdown in communication between a modern “caller” program and a legacy “callee” subprogram.
- The Caller (
PMAIN): Compiled withAMODE(31)andDATA(31). It runs in 31-bit addressing mode, meaning it lives and breathes in the memory space above the historic 16 MB line. - The Callee (
PXXXX): An older, legacy, or vendor-supplied program running inAMODE(24). It is strictly confined to a 24-bit addressing space and can only see memory below the 16 MB line.
When PMAIN attempts to execute a CALL 'PXXXX' USING MY-DATA, it passes a 31-bit memory pointer to a program that literally doesn’t have enough bits to read it. The runtime environment catches this blind spot and triggers IGZ0033S to prevent unpredictable memory corruption.
Visually the Scenario:
- Caller Program: PPXXX (entry
DLITCBL)- ✅ Compiled as AMODE(31)
- ✅ Running correctly
- ❌ Calls an AMODE(24) subprogram
When the caller passes a pointer located above 16 MB to the legacy subprogram, the system triggers IGZ0033S.
What exactly is the 16‑MB line?
It is the boundary between 24‑bit and 31‑bit addressing.
Why 16 MB?
- 24 bits, AMODE (24) can represent:
2^24 = 16,777,216 bytes = 16 MB - Any address that requires more than 24 bits is above this line.
- Thus 16‑MB line is simply the largest address that fits in 24 bits: 2²⁴ bytes.
Key Rule: Never pass a parameter above 16 MB to an AMODE(24) program.
Understanding AMODE vs DATA in z/OS
To fix this issue, it’s important to understand the difference between AMODE and DATA:
| Setting | Purpose | Effect |
|---|---|---|
| AMODE | Addressing mode | Determines how much memory the program can access |
| DATA | Data placement | Determines where the program’s data resides in memory |
Important Distinction:
- AMODE(31) lets a program see memory above 16 MB.
- DATA(31) allows the program’s data to be placed above 16 MB.
- Passing a DATA(31) pointer to an AMODE(24) program causes IGZ0033S.
z/OS VIRTUAL STORAGE ADDRESS SPACE
==================================
31-bit Addressable Space (AMODE(31)) ~2 GB Total
─────────────────────────────────────────────────────
7FFFFFFF ───────────────────────────────────────────
| |
| ABOVE THE 16‑MB LINE |
| (31‑bit addresses) |
| |
| WHAT LIVES HERE |
| • AMODE(31) programs |
| • DATA(31) WORKING‑STORAGE |
| • LE User / Anywhere Heaps |
| • DB2 & IMS buffers |
| • Large arrays & modern workloads |
| |
| WHO CAN ACCESS THIS? |
| ✅ AMODE(31) programs |
| ❌ AMODE(24) programs (BLIND) |
| |
01000000 ────────────── 16‑MB LINE ────────────────
| |
| BELOW THE 16‑MB LINE |
| (24‑bit addresses: 00xxxxxx) |
| |
| WHY THIS EXISTS |
| • Original 24‑bit architecture |
| • Backward compatibility |
| |
| WHAT LIVES HERE |
| • AMODE(24) programs |
| • DATA(24) WORKING‑STORAGE |
| • System control blocks |
| • Legacy exits & interfaces |
| • CEEGTST BELOW heap buffers |
| |
| WHO CAN ACCESS THIS? |
| ✅ AMODE(24) programs |
| ✅ AMODE(31) programs |
| |
00000000 ───────────────────────────────────────────
KEY RULES (MEMORIZE THESE)
=========================
1) AMODE defines how FAR code can address
- AMODE(24): 0 → 16 MB only
- AMODE(31): 0 → ~2 GB
2) DATA defines WHERE data is placed
- DATA(24): below the line
- DATA(31): anywhere (usually above the line)
3) ABSOLUTE SAFETY RULE
❗ Never pass an address ABOVE 16 MB
to an AMODE(24) program
4) CORRECT MODERN PATTERN
- Main program: AMODE(31), DATA(31)
- Legacy call : Copy parameters
↓
BELOW‑THE‑LINE buffer
↓
CALL AMODE(24) program
IF YOU VIOLATE RULE #3:
======================
IGZ0033S
“Attempt was made to pass a parameter
address above 16 MB to an AMODE(24) program”
Mental Model:
AMODE defines what the program can see;
DATA defines where the data lives.
Always respect the 16 MB boundary for AMODE(24) programs.
How to Fix IGZ0033S
There are two practical solutions:
1. Use Bridging
- Use CEEGTST or local DATA(24) buffers to copy parameters below the 16 MB line.
- Create an intermediate wrapper program compiled with
AMODE(31)butDATA(24). Because it usesDATA(24), itsWORKING-STORAGEis guaranteed to be allocated below the 16 MB line.
ID DIVISION.
PROGRAM-ID. BRIDGEPG.
* COMPILER OPTIONS REQUIRED: AMODE(31), DATA(24)
DATA DIVISION.
WORKING-STORAGE SECTION.
01 W-BELOW-LINE-BUFFER PIC X(100).
LINKAGE SECTION.
01 L-ABOVE-LINE-PARAMETER PIC X(100).
PROCEDURE DIVISION USING L-ABOVE-LINE-PARAMETER.
MAIN-PROCESS.
* 1. Copy data from above-the-line to our below-the-line buffer
MOVE L-ABOVE-LINE-PARAMETER TO W-BELOW-LINE-BUFFER.
* 2. Safely call the AMODE(24) legacy program
CALL 'PXXXX' USING W-BELOW-LINE-BUFFER.
* 3. Copy any returned/updated data back to the caller
MOVE W-BELOW-LINE-BUFFER TO L-ABOVE-LINE-PARAMETER.
GOBACK.
2. Recompile the Called Pgm
- If possible, recompile the called program as AMODE(31).
- Ensure DATA(31) for consistency with the caller.
- This approach removes the 16 MB restriction entirely.
Key Takeaways
- AMODE(24) programs cannot access memory above 16 MB.
- AMODE(31) programs + DATA(31) can access memory above 16 MB, but cannot pass those addresses to AMODE(24) programs.
- Use bridging or recompile the callee to avoid IGZ0033S.
Following these guidelines ensures smooth interoperability between modern COBOL programs and legacy AMODE(24) modules.