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.
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.
The start and initialization routine must be identical for each program. The routine takes on the following tasks:
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-R12 | Unpredictable |
| R13 | Address of a register save area |
| R14 | Return address |
| R15 | Entry 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
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.
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 bytes | Field name | Description |
|---|---|---|---|
| 0 | 4 | ARGSTRING_PTR | Address of argument 1 |
| 4 | 4 | ARGSTRING_LENGTH | Length of argument 1 |
| 8 | 4 | ARGSTRING_PTR | Address of argument 2 |
| 12 | 4 | ARGSTRING_LENGTH | Length of argument 2 |
| 16 | 4 | ARGSTRING_PTR | Address of argument 3 |
| 20 | 4 | ARGSTRING_LENGTH | Length of argument 3 |
| 24 | 8 | - | 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
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:
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
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
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