05 September 2012

An interesting way to implement a multi-entry-point API for an LE assembler module

Today I came up with an idea for implementing an API assembler module when LE is involved. Let me first say that although  LE is very functional and usually makes life easier for high-level languages, when assembler gets involved it complicates things until you get used to LE thinking.

The original code had an entry point which did the STM for the save area and then loaded a function code into a register. Unfortunately, this does not work well with LE because the CEEENTRY macro has the STM in it. So I came up with this interesting implementation to get the function code and have only one CEEENTRY macro. Here is a very simple example, without the required CEEPPA, CEEDSA, CEECAA, and CEETERM macros:

INIT     DC    0H
         J     LEENTRY
READ     DC    0H
         J     LEENTRY
WRITE    DC    0H
         J     LEENTRY
TERM     DC    0H
         J     LEENTRY
API      CEEENTRY MAIN=NO,BASE=R11 (default base)
         L     R15,4(,R13)        Backchain save area
         L     R15,16(,R15)       Get R15 at call
* R15 now is the address of the entry point
         LA    R14,0(,R11)        Clear out HOB just in case (SEE BELOW)
         LA    R15,4(,R15)        Clear out HOB and make 1-based 
         SR    R14,R15            Calculate offset from beginning of CSECT 
         SRA   R14,2              Divide by 4, preserving sign (allows use of JM BAD)
* R14 now has a function code ranging from 1 to 4
* Obviously we add some additional checking of R14 to make sure
* it is valid for our purposes.

So now GPR14 has a value ranging from 1 to 4, with 1 being INIT, 2 being READ, etc.. Good programmers will test GPR14 for falling within the required boundaries. You could also forgo the SRA and use the value of 4, 8, 12, or 16. In current releases of z/OS, CEEENTRY uses LARL to load the base register with the address of API, so the LA of GPR14 from GPR11 could just be an LR. This also works with non-LE assembler code; if you have a base register use LA, and if "baseless" use an LARL of the CSECT name. Just make sure that if you have a standard entry macro (most shops do) that generates a CSECT, the CSECT name used at the beginning of the module has to match that generated by your macro.