Page 1 of 2

I can't get the LINK macro working properly

PostPosted: Fri Aug 21, 2020 10:53 pm
by chong_zhou
Hi guys,

I need to use the LINK macro to call a program with 3 parameters, and my code must support re-entrant, so I believe I must do the following 4 things:

1. Use the list form of LINK to define a "template" in the literals area;
2. Reserve a block of space in the work area of my module;
3. Copy the "template" to the reserved block;
4. Use the execute form of LINK;

The code snippet below is a simplified version of my module:


         MVC   WORK_PLIST,TEMP_PLIST

         LINK  EP=BPXWDYN,                                             +
               PARAM=(PARM1,PARM2,PARM3),VL=1,                         +
               MF=(E,WORK_PLIST)

*        ...literals begin here...

TEMP_PLIST  DS   0H
         LINK EP=BPXWDYN,SF=L
TEMP_PLISTL EQU  *-TEMP_PLIST

*        ...work area's definition begins here...

WORKAREA   DSECT
WORK_PLIST DS    CL(TEMP_PLISTL)
WORKAREA   EQU  *-WORKAREA
 


The code doesn't work. When I checked the listing, I noticed that the parameter list doesn't look right at all. The following is the listing:


2017          LINK  EP=BPXWDYN,                                             +
                    PARAM=(PARM1,PARM2,PARM3),VL=1,                         +
                    MF=(E,WORK_PLIST)
2023+         LA    1,WORK_PLIST                      LOAD PARAMETER REG 1   03-IHBINNRA
2024+         LA    14,PARM1           PICKUP PARAMETER                      02-IHBOPLST
2025+         LA    15,PARM2           PICKUP PARAMETER                      02-IHBOPLST
2026+         LA    0,PARM3            PICKUP PARAMETER                      02-IHBOPLST
2027+         STM   14,0,0(1)                         STORE INTO PARAM. LIST 02-IHBOPLST
2030+         OI    8(1),X'80'                 SET LAST WORD BIT ON @G860P40 02-IHBOPLST
2033+         CNOP  0,4                                                      02-IHBINNRB
2034+         BRAS  15,*+20            BRANCH AROUND CONSTANTS               02-IHBINNRB
2035+         DC    A(*+8)             ADDR. OF PARM. LIST                   02-IHBINNRB
2036+         DC    A(0)                DCB ADDRESS PARAMETER                02-IHBINNRB
2037+         DC    CL8'BPXWDYN'        EP PARAMETER                         02-IHBINNRB
2038+         SVC   6                   ISSUE LINK SVC              @G381P2A 01-LINK

...........

2100 TEMP_PLIST  DS   0H
2101            LINK EP=BPXWDYN,SF=L
2105+         CNOP  0,4                                                      02-IHBINNRB
2106+         DC    A(*+8)             ADDRESS OF EP PARAMETER               02-IHBINNRB
2107+         DC    A(0)           DCB ADDRESS PARAMETER                     02-IHBINNRB
2108+         DC    CL8'BPXWDYN'   EP PARAMETER                              02-IHBINNRB
2109 TEMP_PLISTL EQU  *-TEMP_PLIST
 


As I understand the listing, it only generated one A field for the parameters in the "template", however, in the executable code, it used "STM" instruction to directly write the 12 bytes (R14/R15/R0) into the parameter list block, so the 12 bytes should be placed from the first "DC    A(*+8)" until half of the "DC    CL8'BPXWDYN'". It obviously scewed it up.

I think that is because I misused the list form of the LINK macro. However, I read tht document several times, didn't sort out how to tell the list form how many parameters I will use.

Could you please give me some hints, or some example code of using the LINK macro in re-entrant-able way?

Many thanks!!

Re: I can't get the LINK macro working properly

PostPosted: Sat Aug 22, 2020 1:12 am
by sergeyken
Use the name TEMP_PLIST as the label for LINK SF=L
Using TEMP_PLIST DS 0H is absolutely senseless.

Use WORK_PLIST DS 3A, to reserve space for 3 parameters.

Also, using duplicated EP= parameter in both LINK forms is senseless, and misleading.

Re: I can't get the LINK macro working properly

PostPosted: Sat Aug 22, 2020 2:29 am
by Robert Sample
I think that is because I misused the list form of the LINK macro. However, I read tht document several times, didn't sort out how to tell the list form how many parameters I will use.
Your problem is more basic than the LINK macro or list form format. HLASM, like assemblers before it, uses a parameter list for passing data. Register 1 points to a list of addresses (which are full words). The first address points to the first parameter, the second address points to the second parameter, and so forth. How do you know the end of the parameter list? The first bit of the last address value will have a 1 bit in it (so you'll see DC X'80',Al3(LASTPARM) as one possible way it would be coded). Since 24-bit or 31-bit addresses neither one use the first bit of the word, when it is a 1 that means the end of the parameter list -- period.

Re: I can't get the LINK macro working properly

PostPosted: Sat Aug 22, 2020 4:50 am
by steve-myers
The fundamental problem you are having here is the LINK macro generates two distinct parameter lists -
  • Parameters passed to the program. As Mr. Sample says, the addresses of these parameters are passed as words in a vector. You reserve space for this parameter list using the list form of the CALL macro.
  • Parameters passed to the LINK service. These parameters are passed in two words: the first word specifies the address of the DCB specified in the LINK macro, the second word specifies the address of the 8 byte character constant with the name of the module being linked to. This parameter list is sometimes referred to as a "system" parameter list.
In this example, which is a correctly coded analog of your code, the "system" parameter list is generated within the LINK macro itself; it is reentrant because it is not altered.
        LINK EP=BPXWDYN,PARM=(PARM1,PARM2,PARM3),VL=1,MF=(E,PARMLIST)
         ...
WORKAREA DSECT
         ...
PARMLIST CALL  ,(*-*,*-*,*-*),MF=L
PARM1    DS    ...
PARM2    DS    ...
PARM3    DS    ...

You can use code like this to use both parameter lists.
         LINK PARM=(PARM1,PARM2,PARM3),VL=1,                          X
              EPLOC==CL8'BPXWDYN',DCB=*-*,                            X
              MF=(E,PARMLIST),SF=(E,LINKPARM)
         ...
WORKAREA DSECT
         ...
PARMLIST CALL  ,(*-*,*-*,*-*),MF=L
PARM1    DS    ...
PARM2    DS    ...
PARM3    DS    ...
LINKPS   LINK  EPLOC=*-*,DCB=*-*,SF=L
LINKPARM EQU   LINKPS,*-LINKPS
The rarely used DCB parameter is in LINK macro to ensure a 0 address is inserted into the parameter list. Another way is to add XC LINKPARM,LINKPARM before the execute form of the LINK macro.

This example highlights one of the problems using remote parameter lists: it is undefined whether the macro will clear data that is not specified. This can be useful, too. I have a library sort function that is an analog of the C standard library QSORT function. It is called with several parameters, including the address of a work area, the address of the data area being sorted, and the address of a compare function. If you have used the QSORT C function this should be familiar. In one program QSORT can be called several times. For example,
         CALL QSORT,(DATA,WORKAREA,...,COMPARE1),MF=(E,SORTPARM)
         ...
         CALL QSORT,(XDATA,,...,COMPARE2),MF=(E,SORTPARM)
         ...
SORTPARM CALL ,(*-*,*-*,...,*-*),MF=L
I am using ... to indicate other parameters. The first CALL macro stores the address of the work area in the parameter list. Since it is already in the parameter list, it does not have to be reinserted in the second CALL macro, so it is not specified in the second CALL macro.

Re: I can't get the LINK macro working properly

PostPosted: Sat Aug 22, 2020 6:05 am
by steve-myers
This business about initializing remote parameter lists can get confusing. The OPEN and CLOSE macros are one example.

Fifty years ago, I observed
         OPEN  (ADCB,OUTPUT),MF=(E,OPARM)
         ...
WORKAREA DSECT
         ...
OPARM    OPEN  *-*,MF=L
does not insert the VL bit. Unexpectedly, one day I observed the OPEN macro inserted the VL bit. Yipee, I thought, "IBM finally fixed this problem!" A few weeks later I observed the macro stopped inserting the VL bit. After some thought I realized there was a compatibility problem. The "fix" broke something like this -
         OPEN  (ADCB,OUTPUT),MF=(E,OPARM)
         ...
WORKAREA DSECT
         ...
OPARM    OPEN  (*-*,,BDCB,OUTPUT),MF=L
The VL bit inserted by the "fixed" OPEN macro effectively deleted the second DCB pointer, and IBM corrected this problem by removing the earlier fix.

Several years later I was involved in a similar debacle. For a brief period there were two JES2 products, the "free" JES2 bundled into MVS, and the NJE <expensive> program product which was just JES2 we had come to love with network job entry code added to it. The JCL manual discussed how output priority was set; NJE changed this to a different algorithm. I removed the NJE code in our user mods as the JCL documented algorithm is what we wanted. After it worked I opened a PMR grumbling that NJE broke the JCL manual documentation, and supplied my update. My update was incorporated into a PTF and it was sent out. By the next PTF cycle NJE reverted to the original code, my update was removed. After some thought I realized the NJE code was really the "right" way to set output priority - I no longer remember how NJE changed setting output priority or why the NJE change was really "right," but there it is. Shortly after that NJE was bundled in the "free" JES2 and the separate NJE product was deleted. and it has remained that way since.

Re: I can't get the LINK macro working properly

PostPosted: Mon Aug 24, 2020 7:35 am
by steve-myers
Now let's return to your listing. Remember I said there are two parameter lists in the LINK macro. Part of the code it generated is
         BRAS  15,*+20            BRANCH AROUND PARAMETERS
         DC    A(*+8)             ADDRESS OF PROGRAM NAME
         DC    A(0)               DCB ADDRESS
         DC    CL8'BPXWDYN'       PROGRAM NAME
The comments in the expansion are wrong. My comments are correct, but incomplete.

The BRAS instruction branches around the parameter list and program name. The *+20 is confusing: the 20 comes from 4 (the length of the BRAS instruction) + 8 (bytes in the parameter list) + 8 (bytes in the program name). It also loads the address of the "system" parameter list into register 15 (the two address constants that follow the BRAS instruction), which is not in the comments. The "system" parameter list is the two address constants, followed by the program name.

We discourage writing code like *+20, for two reasons. First, it is all too easy to get the 20 wrong: it's the sum of 4 + 8 + 8. Second, all too often you add or delete something in the 20 bytes, but don't change the constant. Oops.

Re: I can't get the LINK macro working properly

PostPosted: Mon Aug 24, 2020 1:08 pm
by chong_zhou
Thank you so much guys (sergeyken, Mr. Sample, and Mr. Myers)!! Your quick response and very details answer did solved my problem.

Re: I can't get the LINK macro working properly

PostPosted: Mon Aug 24, 2020 1:45 pm
by chong_zhou
steve-myers wrote:The fundamental problem you are having here is the LINK macro generates two distinct parameter lists...

From your first reply, I see what I misunderstood --- I know the main purpose of the list form is to reserve space for the PLIST, but I thought it was done by the list form of LINK. Your code showed me that I should use the list form of CALL to reserve space for the PLIST!

Now I understand that the list form of CALL reserves PLIST space for the system service (BPXWDYN) that I am calling, while the list form of LINK creates parameters block for the LINK SVC (SVC 6) itself! Moreover, as you wrote, since the parameters for the LINK SVC seldom change (at least it doesn't change in my code), I don't even need to make it "re-entrant". It is OK to just let the execute form of LINK embeds the "20 bytes" in my code.

Lastly, I understand your warning about the "20 bytes". The macro can do it without problems because it does calculations at compile time. However, I should avoid directly doing it in my code.

Thank you very much for the detailed explanation and also thank you for sharing the interesting story.

Re: I can't get the LINK macro working properly

PostPosted: Mon Aug 24, 2020 5:36 pm
by steve-myers
chong_zhou wrote:... Now I understand that the list form of CALL reserves PLIST space for the system service (BPXWDYN) that I am calling, while the list form of LINK creates parameters block for the LINK SVC (SVC 6) itself! Moreover, as you wrote, since the parameters for the LINK SVC seldom change (at least it doesn't change in my code), I don't even need to make it "re-entrant". It is OK to just let the execute form of LINK embeds the "20 bytes" in my code..

No. CALL ,...,MF=L reserves space for the parameters sent to BPXWDYN. The DS 3A in your original program would work just fine.

label LINK SF=L,EP=BPXWDYN creates the "system" parameter list for LINK.

LINK MF=(E,PARMLIST),SF=(E,LINKPARM)

generates

LA 1,PARMLIST
LA 15,LINKPARM
SVC 6
... It is OK to just let the execute form of LINK embeds the "20 bytes" in my code..
Again, no. Only SF=I inserts the 20 bytes (and the SVC 6).

Re: I can't get the LINK macro working properly

PostPosted: Wed Aug 26, 2020 7:47 am
by steve-myers
chong_zhou wrote:... Lastly, I understand your warning about the "20 bytes". The macro can do it without problems because it does calculations at compile time. However, I should avoid directly doing it in my code.
The macro itself did not calculate the +20. Some anonymous IBM programmer in the 1960s calculated the +20.

A few other IBM macros calculate a variable *+nn. Some that I can think of include SAVE, WTO, and the inner macro that generates an inline parameter list for the MF=I forms of CALL, LINK and ATTACH. If you work at it I suspect SAVE and WTO will get it wrong!