HLASM with COBOL: Calling Assembler Routines from COBOL

TT

HLASM with COBOL: Calling Assembler Routines from COBOL

Mixing HLASM and COBOL is extremely common in mainframe production systems. COBOL handles business logic; HLASM handles performance-critical routines, hardware-specific functions, and legacy code. This module explains how to write HLASM routines that COBOL programs can call.

Why Mix COBOL and HLASM?

  • Performance: sorting algorithms, string manipulation, and mathematical routines run significantly faster in HLASM
  • Hardware access: certain z/Architecture instructions (vector, crypto) are only accessible from assembler
  • Legacy integration: existing HLASM routines are called by newer COBOL programs
  • System services: some z/OS services are more naturally accessed from assembler

COBOL CALL Statement

COBOL calls an assembler routine with:

cobol
WORKING-STORAGE SECTION.
01 WS-INPUT-AMOUNT  PIC 9(9)V99 COMP-3.
01 WS-OUTPUT-TEXT   PIC X(15).
01 WS-RETURN-CODE   PIC S9(8) COMP.

PROCEDURE DIVISION.
    CALL 'FMTAMT' USING WS-INPUT-AMOUNT
                        WS-OUTPUT-TEXT
                  GIVING WS-RETURN-CODE.

COBOL passes parameters by reference (addresses). Register 1 contains the parameter list address when the assembler routine is entered.

Writing the HLASM Routine

hlasm
* FMTAMT: Format a packed decimal amount as printable text
* Parameters:
*   Parm 1: 6-byte packed decimal amount (PIC 9(9)V99 COMP-3)
*   Parm 2: 15-byte output text field
* Return code: 0=success, 8=invalid amount
*
FMTAMT   CSECT
FMTAMT   AMODE 31
FMTAMT   RMODE ANY
*
R0       EQU   0
R1       EQU   1
R2       EQU   2
R3       EQU   3
R12      EQU   12
R13      EQU   13
R14      EQU   14
R15      EQU   15
*
         STM   R14,R12,12(R13)
         LR    R12,R15
         USING FMTAMT,R12
         LA    R11,SAVEAREA
         ST    R13,4(R11)
         ST    R11,8(R13)
         LR    R13,R11
*
* Load parameter addresses from parameter list
         L     R2,0(R1)        R2 -> packed decimal input (6 bytes)
         L     R3,4(R1)        R3 -> output text field (15 bytes)
*
* Validate: check it's a valid packed decimal
         TM    5(R2),X'0F'     Check sign nibble of last byte
         BZ    BADSIGN         Zero sign = invalid
*
* Unpack to zoned decimal for formatting
         UNPK  WORKZONE,0(6,R2)    Unpack 6-byte packed to 11-byte zoned
         OI    WORKZONE+10,X'F0'  Fix sign byte
*
* Format: insert decimal point and spaces
         MVC   0(15,R3),=CL15' '  Clear output
         MVC   0(9,R3),WORKZONE+2  Copy 9 integer digits (skip leading)
         MVI   9(R3),C'.'         Decimal point
         MVC   10(2,R3),WORKZONE+9 Copy 2 decimal digits
*
         SR    R15,R15             Return code 0 = success
         B     RETURN
*
BADSIGN  LA    R15,8               Return code 8 = error
*
RETURN   DS    0H
         L     R13,4(R13)
         L     R14,12(R13)
         LM    R0,R12,20(R13)
         BR    R14
*
WORKZONE DS    ZL11
SAVEAREA DS    18F
         END   FMTAMT

AMODE and RMODE Directives

hlasm
MYROUTINE AMODE 31        Addressing mode: 31-bit (above the line)
MYROUTINE RMODE ANY       Residency mode: can load above or below the line

For routines called from modern COBOL (COBOL for z/OS), always use AMODE 31 and RMODE ANY. COBOL programs compiled with ARITH(EXTEND) or large data items require AMODE 31.

Accessing COBOL Data from HLASM

COBOL passes parameters by reference — register 1 contains a list of addresses. Load each address individually:

hlasm
* Three-parameter call
         L     R2,0(R1)        Address of parameter 1
         L     R3,4(R1)        Address of parameter 2
         L     R4,8(R1)        Address of parameter 3

For COBOL COMP-3 (packed decimal) fields, the HLASM routine accesses them directly with CP, AP, etc.:

hlasm
         CP    0(6,R2),=P'0'   Is amount zero?
         BE    ZEROAMT

For COBOL PIC X (character) fields:

hlasm
         MVC   WORKBUF(80),0(R3)   Copy 80 bytes of COBOL field to work area

For COBOL COMP / COMP-4 (binary) fields:

hlasm
         L     R5,0(R4)           Load 4-byte binary (PIC S9(9) COMP)

Returning Values to COBOL

COBOL's GIVING clause maps to register 15 after the call:

cobol
CALL 'MYROUTINE' GIVING WS-RETURN.

Set register 15 to your return code before BR 14. COBOL stores register 15 in the GIVING field.

For returning data, modify the parameter's storage directly (you have its address in R2, R3, etc.):

hlasm
         MVC   0(15,R3),RESULT    Copy result to output parameter

Frequently Asked Questions

Q: Does my HLASM routine need to be compiled separately from the COBOL program? Yes. The HLASM routine is assembled separately with JCL invoking ASMA90, producing an object module. The object module is then link-edited with the COBOL object module (or stored in a load library that the COBOL program's JCL references). The CALL 'FMTAMT' in COBOL becomes an external reference resolved by the linkage editor.

Q: What happens if my HLASM routine changes a register that COBOL is using? COBOL expects the standard linkage convention: on return, registers 2–12 must be restored to their entry values. If your routine modifies a register without restoring it, the COBOL program receives corrupted register values and will likely abend (typically a 0C4 protection exception or 0C1 operation exception). Always use STM at entry and LM at exit to save and restore all registers.

Q: Can COBOL call a reentrant HLASM routine from multiple tasks simultaneously? Yes, provided the HLASM routine is truly reentrant (no modification of static storage). Mark the routine with AMODE 31, RMODE ANY, and the RENT attribute in the linkage editor. Use GETMAIN for all writable work areas rather than static DS fields. IBM's Language Environment (LE) fully supports concurrent calls to reentrant assembler routines from multitasking COBOL programs.


Part of HLASM Mastery Course — Module 18 of 22.