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 ENDcomments powered by Disqus