Write an assembler program that is called by REXX

Overview

When programming with REXX sometimes you get to a point where it is necessary to invoke system routines. At this point you can not avoid the use of assembly language.
However, the creation of an assembler program that can be called from REXX is not as complicated as it looks at first glance. The assembler program contains, like any computer program, 4 parts.

  1. Start or initialization routine
  2. Main program
  3. Completion routine
  4. Data area

Each program should follow the calling program’s conventions as well as the called program’s conventions.
The following code is based on the template of Lindy Mayfield lilliana.eu/downloads/RXTEMPL.txt.

Start or initialization routine

The start and initialization routine must be identical for each program. The routine takes on the following tasks:

  • Save the contents of registers 0 – 12, 14 and 15 in the save area provided by the calling program.
  • Set a base register.
  • Chain the save areas together.

The following table describe the contents of the registers when the function gets control.

R0 Address of the environment block of the exec that invoked the external function or subroutine.
R1 Address of the external function parameter list (EFPL)
R2-R12Unpredictable
R13 Address of a register save area
R14 Return address
R15Entry point address

Source: Interface for writing external function and subroutine code 

The registers are saved in a 18-word (72 byte) save area provided by the calling program and pointed to on entry by register 13. Registers can be saved using either the store-multiple (STM) instruction or with the SAVE macro. The store-multiple instruction, STM R14,R12,12(13), places the contents of all registers except register 13 in the proper locations (words) of the save area. The save area and the pointer to the environment block are defined in the data area.
Based on the requirements the code of the routine is the following:

*-------------------------------------------------------------*  
* Standard starting (house holding) sequence                       
* - save the contents of registers 0-12, 14 and 15 in            
*   the save area                                                
* - set a base register                                          
*-------------------------------------------------------------*  
BEGIN    DS    0H                                                
         STM   R14,R12,12(R13)    Save entry regs in callers area
         LR    R3,R15             R3 is base register                 
         USING *,R3                                              
         ST    R0,ENVA            Save address of ENVBLOCK       
         ST    R1,EFPLA           Save address of EFPL           
         LA    R1,SAVEAREA        Get address of save area       
         ST    R13,4(,R1)         Save R13                       
         ST    R1,8(,R13)         Backchain save areas           
         LR    R13,R1

Main program

As the name suggests, the real work is done in the main program. If parameters are passed, they must be checked at this point. Necessary to check the number of parameters and possibly the length of each parameter. It makes sense to outsource these tasks and to call these routines in the main program.

Argument list

Most functions get values passed as arguments by which they are to fulfill certain tasks. The number and length of the individual arguments are provided in a list of arguments to the routine.
The following table shows the format of the parsed list example of three arguments the function receives at offset +16 (decimal) in the external function parameter list. For ease of use TSO/E provides a mapping macro IRXARGTB in SYS1.MACLIB.

Offset (dec)Number of bytesField nameDescription
04ARGSTRING_PTRAddress of argument 1
44ARGSTRING_LENGTHLength of argument 1
84ARGSTRING_PTRAddress of argument 2
124ARGSTRING_LENGTHLength of argument 2
164ARGSTRING_PTRAddress of argument 3
204ARGSTRING_LENGTHLength of argument 3
248-X'FFFFFFFFFFFFFFFF'

Source: Interface for writing external function and subroutine code

This subroutine will count the number of Rexx parms passed and return the number in R15.

PARMCNT  DS    0H
         L     R6,=A(ARGTABLE_)        Get address of Argtable
         BAKR  0,R6                    Returns addr in R15
         LR    R4,R15                  Swap for USING
         USING ARGTABLE_ENTRY,R4
         XR    R15,R15                 Zero return value
PRMLOOP  DS    0H
         CLC   ARGTABLE_ARGSTRING_PTR,=2F'-1' End of args?
         BE    PRMEND
         LA    R15,1(R15)              Increment R15
         LA    R4,ARGTABLE_NEXT        Point to next one
         B     PRMLOOP                 Loop
PRMEND   DS    0H                      Done
         PR                            Return
         DROP  R4

This subroutine will return the length of a specified parm in R15. R0 contains the number of the parm.

PARMLEN  DS    0H
         XR    R15,R15
         LTR   R0,R0
         BE    PRMLNEN
         L     R4,EFPLA
         USING EFPL,R4
         L     R4,EFPLARG
         DROP  R4
         USING ARGTABLE_ENTRY,R4
PRMLNLP  DS    0H
         CLC   ARGTABLE_ARGSTRING_PTR,=2F'-1'
         BE    PRMLNEN
         BCT   R0,PRMLNNX
         L     R15,ARGTABLE_ARGSTRING_LENGTH
         B     PRMLNEN
PRMLNNX  DS    0H
         LA    R4,ARGTABLE_NEXT
         B     PRMLNLP
PRMLNEN  DS    0H
         PR
         DROP  R4

This subroutine will return the address of a specified parm in R15.  R0 contains the number of the parm.

PARMPTR  DS    0H
         XR    R15,R15            Zero return value
         LTR   R0,R0              Is R0 = 0?
         BE    PRMPTEN            Yes, quit.
         L     R4,EFPLA           Get address of EFPL
         USING EFPL,R4
         L     R4,EFPLARG         Get address of arg table
         DROP  R4
         USING ARGTABLE_ENTRY,R4
PRMPTLP  DS    0H                 Loop through parms
         CLC   ARGTABLE_ARGSTRING_PTR,=2F'-1' End of args?
         BE    PRMPTEN
         BCT   R0,PRMPTNX         Move down the table
         L     R15,ARGTABLE_ARGSTRING_PTR    Move to R15
         B     PRMPTEN            Go to end of routine
PRMPTNX  DS    0H
         LA    R4,ARGTABLE_NEXT   Point to next one
         B     PRMPTLP            Loop
PRMPTEN  DS    0H                 Done
         PR                       Return
         DROP  R4

Completion routine

The completion routine is as important as the initialization routine and must be present in this or a similar form in each program. As the initialization routine, this routine also takes a number of tasks before control is returned to the calling program.
These tasks are as follows:

  • Restore registers 0 – 12 and 14.
  • Unchain current save area from calling program save area. Address of calling program save area is placed in register 13.
  • Place a return code in register 15

The return code in register 15 is NOT the result of the routine, it is the state if the routine was successful (0) or not (> 0).
The resulting code for the completion routine looks like this:

*-------------------------------------------------------------*
* Standard exiting sequence                                    
*-------------------------------------------------------------*
EXIT     DS    0H                                              
         L     R13,4(,R13)        Ptr to entry reg save area   
         LM    R14,R12,12(R13)    Reload registers             
         XR    R15,R15            Exit R15=0, successful       
         BR    R14                Return to caller             
*                                                              
*                                                              
EXITERR  DS    0H                                              
         L     R13,4(,R13)        Ptr to entry reg save area   
         LM    R14,R12,12(R13)    Reload registers             
         LA    R15,40             Exit R15=40, syntax error    
         BR    R14                Return to caller             
*                                                              
         EJECT

Function results

Before the function or subroutine code is called, the language processor allocates a control block called the evaluation block (EVALBLOCK). The function or subroutine code computes the result and returns the result in the evaluation block. TSO/E provides a mapping macro IRXEVALB for the evaluation block. The mapping macro is in SYS1.MACLIB.

*-------------------------------------------------------------*       
* This subroutine will set the return value for a function or         
* subroutine.  R0 contains the length, R1 the address of              
* the data.                                                           
*                                                                     
* R15=16 if length > 250                                              
*-------------------------------------------------------------*       
RETVAL   DS    0H                                                     
         LTR   R0,R0                   Is R0 = 0?                     
         BE    SREND                   Yes, quit.                     
         LA    R15,16                  Set R15 for error              
         C     R0,=F'250'              Is > 250?                      
         BH    SREND                   Then quit                      
         XR    R15,R15                 Good return                    
         L     R4,EFPLA                Get address of EFPL            
         USING EFPL,R4                                                
         L     R4,EFPLEVAL             Get prt to addr of EVALBLOCK   
         L     R4,0(R4)                Get addr of EVALBLOCK          
         DROP  R4                                                     
         USING EVALBLOCK,R4                                           
         ST    R0,EVALBLOCK_EVLEN      Move length of return data     
         BCTR  R0,0                    Subtract 1 from length formove
         LA    R2,EVALBLOCK_EVDATA     Address of Data (max 250)      
         LR    R10,R0                  Cant use R0 for EX             
         EX    R10,MOVERET             Execute Move                   
SREND    DS    0H                      Done                           
         PR                            Return                         
         DROP  R4                                                     
MOVERET  MVC   0(0,R2),0(R1)           Variable Move

Data area

These area of the program contains data, not instructions. To make live easer some useful mapping macros are also included.

*-------------------------------------------------------------*    
* Definiton area.                                                  
*-------------------------------------------------------------*    
         DS    0F                                                  
ENVA     DS    A                    address of ENVBLOCK            
EFPLA    DS    A                    address of EFPL                
SAVEAREA DC    18F'0'               LOCAL SAVE AREA                
         EJECT                                                     
         IRXENVB                  ; ENVIRONMENT BLOCK (R0 ON ENTRY)
         IRXEFPL DSECT=YES        ; EXTERNAL FUNCTION PLIST (R1)   
         IRXARGTB                 ; MAP THE ARGUMENT LIST.         
         IRXSHVB                  ; SHARED VARIABLES BLOCK         
         IRXEVALB                 ; EVALBLOCK TO RETURN RESULT.    
         IRXEXTE                  ; EXTERNAL ENTRY POINTS          
         END
comments powered by Disqus