Using the indep Option for Interlanguage Communication |
The
following paragraphs discuss an example of calling
C
indep
code from PL/I. The C code in turn calls PL/I. Sample L$URTOP Routine manipulates bits in PL/I
save areas to prevent inspection of C save areas for ON-units. Although this
manipulation keeps PL/I from getting confused in most cases, it cannot be
guaranteed to work in all cases or with all versions of the PL/I library.
First, the L$UCENV macro is modified to locate the user
word of the PL/I TCA (TUSR). The address of TUSR is returned in register 12,
which, after completion of L$UCENV, is expected to contain the address of
the word in which L$UPREP should store the CRAB address. This modified version
of L$UCENV also performs a secondary function, namely, storing the address
of the most recent PL/I save area in a CRAB user word so it can be used later
when reentering the PL/I execution framework.
L$UCENV Macro for PL/I to C shows this version of L$UCENV.
L$UCENV Macro for PL/I to C
MACRO
&L L$UCENV
&L LA R12,X'11C'(,R12) Access TCA user word.
CLC 0(4,R12),=F'0' CRAB address known yet?
BE CENV&SYSNDX If NO, no place
to save SAVE area
ST R12,8(,R13) Save R12 for a moment.
L R12,0(,R12) Find the CRAB.
USING CRAB,R12
ST R13,CRABUSR1 Save SAVE area addr in CRAB.
DROP R12
L R12,8(,R13) Restore CRAB pointer address.
CENV&SYSNDX DS 0H
MEND
Second, the L$UPENV macro must be provided. The example
L$UPENV works fine in this context since L$UPENV REG=12 retrieves the PL/I
TCA address.
Finally, an assembler routine must be written to allow
calls from C to PL/I. A sample routine to perform this service, PLISUB, is
shown in Sample PLISUB Routine.
The first argument to the procedure is the address of the PL/I routine; the
remaining arguments are those to be passed to PL/I. The PLISUB routine must
-
locate the PL/I routine's actual entry
point
-
switch to the PL/I execution framework by using
L$UPENV
-
build a save area for itself that looks enough
like a PL/I DSA to avoid confusing the PL/I library.
When the PL/I routine returns, PLISUB must put everything
back before returning. A sample call to PLISUB to perform the equivalent of
the PL/I call CALL TRANS(I, 2); follows:
extern trans();
plisub(&trans, @i, @2);
Sample PLISUB Routine
PLISUB@ CSECT
CREGS
USING CRAB,R12
PLISUB CENTRY DSA=DSALEN
L R2,0(,R1) Address PL/I "function pointer."
L R2,0(,R2) Address PL/I entry point.
LA R3,4(,R1) Address PL/I program's parms.
LR R4,R12 Save CRAB address.
DROP R12
USING CRAB,R4
L$UPENV REG=12 Find the PL/I TCA.
LR R6,R13 Save our DSA address.
USING DSA,R6 Establish DSA addressability.
MVC 0(2,R6),=X'8200' Mark it as a dummy PL/I DSA.
LA R13,PLIDSA Find a save area for PL/I to use.
XC 0(96,R13),0(R13)
ST R6,4(,R13) Link to our SAVE area.
MVC 0(4,R13),=X'80000000' INIT SAVE area for PL/I
MVC 86(2,R13),=X'91C0' as described in PL/I doc
ICM R7,15,CRABUSR1 Find last PL/I SAVE area
BNZ OK
L R7,CRABPENV or save area on entry to C.
OK DS 0H
MVC 72(8,R13),72(R7) Copy PL/I storage management O
LR R15,R2 Set up regs for call.
LR R1,R3 Put address of parms where
PL/I expects.
BALR R14,R15 Call PL/I.
LR R13,R6 Restore our own SAVE area
LR R12,R4 and R12.
ST R7,CRABUSR1 Restore CRAB PL/I SAVE area ptr.
CEXIT , Return to C.
SPACE
LTORG
COPY CRAB
SPACE
COPY DSA
SPACE
PLIDSA DS CL96 Space for PL/I SAVE area.
SPACE
DSALEN EQU *-DSA
END
Copyright © 2001
by SAS Institute Inc., Cary, NC, USA. All rights reserved.