How to make your assembler program reentable
The Linkage Editor or Binder
When I learned assembly language a generation ago, there were two steps in the translation: the assembly and linkage editing. I had no idea what the last one did. I did not consider it important, but in short, Linkage Editor makes your program to the final (load) module, so it can be used by z / Os. Today called the Binder, which corresponds very well to what we call the same function on other platforms. However, there are some important parameters for binder, as you have to keep track of, if not you will have problems.One of them is reusability, which tells the operating system how the program can be re-used by the operating system. The operating system has many simultaneous "tasks" running, so it is important that the program does not change itself. It might even change its code or values, or others could. If the assembler programmer guarantees that his program does not modify itself (or is modified by others), it could have the label "Reentable". It is a very fine predicate, which tells the operating system that it can load the program into a piece of memory which can be read only. If the program or another, violate the rule, that person thrown by an Abendkode "S0C4".
The operating system looks at "reusability" of each module as it loads it into memory and decides whether to enter the "read only" memory or modifiable memory.
Experienced system programmers will probably remember that one could put more of these predicates on a module, for example. both the "reusable" and "reentable". It should be no more. A load module can only get one predicate:
-------------------------------------------------------------------------------------------------------
Reusability (REUS, RENT and REFR) is handled differently by the binder. While the linkage editor processes the attributes independently, the binder stores them as a single value. The binder assumes that reenterable programs are also serially reusable, and the refreshable programs are also reenterable. This should not cause any processing difficulties.
Reusability (REUS, RENT and REFR) is handled differently by the binder. While the linkage editor processes the attributes independently, the binder stores them as a single value. The binder assumes that reenterable programs are also serially reusable, and the refreshable programs are also reenterable. This should not cause any processing difficulties.
The binder was designed to always accept an explicit override of a module attribute, whereas the linkage editor sometimes does not. For example, although the JCL can specify RENT in the parm list, when one CSECT being bound into a load module is reusable and the rest are reentrant, the linkage editor ignores the external parameter and assigns the module as reusable. The binder will allow the explicit override of RENT on the JCL to take priority.
------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------
From the manual z/OS MVS Program Management: User's Guide and Reference, Binder processing differences from the linkage editor
If your program is modified anyway during the execution, you should "bind / link" with the REUSE = SERIAL or NONE. In this example, I have said that the module is serial reusable. So it is up to the programmer to manage the changes in the module code or values.
SETOPT PARM (LET LIST XREF, NCAL, REUS = SERIAL)
MODE AMODE (24), RMODE (24) NAME [modulename] (R)
The binder writes a list of the values and predicates the module has received. In the example below, the results from the parameters above.
------------------------------------------------------------------------------------------------------SETOPT PARM (LET LIST XREF, NCAL, REUS = SERIAL)
MODE AMODE (24), RMODE (24) NAME [modulename] (R)
The binder writes a list of the values and predicates the module has received. In the example below, the results from the parameters above.
AC 000
AMODE 24
COMPRESSION NONE
DC NO EDITABLE YES
EXCEEDS 16MB NO
EXECUTABLE YES
LONGPARM NO
MIGRATABLE YES
OL NO
OVLY NO
PACK,PRIME NO,NO
PAGE ALIGN NO
REFR NO
RENT NO
REUS YES
RMODE 24
SCTR NO
SIGN NO
SSI
SYM GENERATED NO
TEST NO
XPLINK NO
MODULE SIZE (HEX) 000001A0
------------------------------------------------------------------------------------------------------
Note that there are still several lines out regarding reusability, but that is really only in order to be backward compatible. The same also applies if you go into LOADLIB and find the module. Here are also more fields set aside to Reusable, but again, it's just to be backward compatible.
-------------------------------------------------------------------------
MITPGM1 RU
MITPGM2
MITPGM3 RN RU
MITPGM4 RN RU
--------------------------------------------------------------------------
Program MITPGM3 og MITPGM4 are both Reentable, where MITPGM1 is "only" Serial Reusable
In the last chapter I wrote at the end of the article "So it is up to the programmer to manage the changes in the module code or values." I will show how it's done. We must ensure that nothing in the program will be changed. This means that all variables must be located in storage, for each individual process outside of the program; We must therefore make a so-called Getmain - ie retrieve main storage.
Somewhere in the program outside the control section (the CSECT the one with instructions), insert a DSECT describing your work area.
You start to getmaine the area with a length which is calculated by the last instruction in the DSECT. Then you check if there is an address in register 1 (R1) with the OR instruction. If not, then go to the error routine NO_STORAGE_OBTAINED. In the next instruction you move the address into the R10 and then say that when you refer to the fields in this storage, R10 is used. Eventually move a so-called Eye Catcher in front of the area. It's nice if the program will dump its storage. So you can make a "Find" on the Eye Catch Eren, to find the area.
The DSECT describes the look of your space. It starts with DSECT and the name of this DSECT so you can refer to it in the USING. Then come your variables and finally the length of the area is calculated. So we are running ....
However, we're a program our self that is called - perhaps by the operating system, perhaps by another program. Therefore, we must save the caller's registers. Fortunately, a Macro will do most of it.
SAVE (14,12),,'PGM2 - &SYSDATE..&SYSTIME'
The latter is a comment that tells the program name (PGM2) and the time of program assembling. It is not just not recommended, but required that you use it!. It helps tremendously in many cases to make sure we got the right version of the program in a troubleshooting situation. After saving the caller's registers, we need to have a storage area for our registres, if we were to call another program.
We pick up 72 bytes, or 18 fullwords (18F). That's all we need. The two Store Instructions (ST) makes a concatenation of register save areas and eventually we let R13 point to our Register Save Area and create adressability to it with USING. Just before we leave the program, we must re-establish the caller's registeres. This is done as follows:
Your program is fully reentable and can be laid in the Link Pack Area (LPA). It is a read-only-area, which is accessible to all address spaces (regions). It can also be used simultaneously to multiple tasks / threads. In the next chapter we talk about calling other programs if you still want your program to be reentable. It's not quite that simple as it sounds.
More reading:
In my PGM1 I make a LINK to PGM2. I call it with a parameter. Notice the last three instructions that the parameter definition. It is embedded in the program itself. It is required by the LINK macro, because it generates the address of Parm in A (PARM + X'80000000 '). If I had no PARM or it was a constant in the program, I could have used the standard LINK in a reentrant program.
Instead of using one standard LINK, use two - a LIST form and EXEC form. LIST form describes constants and variable fields to the LINK called. The EXEC form performs the actual LINK, just as standard LINK. This means that you define your LIST form along with your other constants and defines an area in your Getmained storage where you can move it up before performing the EXEC form. The macro parameter MF = L says that you want the LIST form and MF = E that you make EXEC form. Note that in MF = E comes the name of the field where you moved LIST form to. It may be a little tricky, but your program is reentrant. And that is beautiful.
-------------------------------------------------------------------------
MITPGM1 RU
MITPGM2
MITPGM3 RN RU
MITPGM4 RN RU
--------------------------------------------------------------------------
Program MITPGM3 og MITPGM4 are both Reentable, where MITPGM1 is "only" Serial Reusable
I have collected som links if wish to read some mode on the subject:
 Binder processing differences from the linkage editor
- Module reusability- Binder options
- Binder options, REUSE - Reusability options
- Module reusability- Binder options
- Binder options, REUSE - Reusability options
To be or not to be reentable
In the last chapter I wrote at the end of the article "So it is up to the programmer to manage the changes in the module code or values." I will show how it's done. We must ensure that nothing in the program will be changed. This means that all variables must be located in storage, for each individual process outside of the program; We must therefore make a so-called Getmain - ie retrieve main storage.
          GETMAIN RC,LV=STOR_LGD
          OR R1,R1
          BZ NO_STORAGE_OBTAINED
          LR R10,R1
          USING STORAGE,R10
          MVC EC,=CL(L’EC)’PGM2-STORAGE’
Somewhere in the program outside the control section (the CSECT the one with instructions), insert a DSECT describing your work area.
STORAGE   DSECT
EC        DS     CL16                 EYE CATCHER
VALUE1    DS     F
VALUE2    DS     H
VALUE3    DS     CL120
VALUE4    DS     F
STOR_LGD EQU *-STORAGE
The DSECT describes the look of your space. It starts with DSECT and the name of this DSECT so you can refer to it in the USING. Then come your variables and finally the length of the area is calculated. So we are running ....
Linkage Convensions
Or, in other words, - it was the easy part. There will be more, but right now we issue yet another Getmain which must come very first in the program. It will be needed if we call other programs, so that they can save their registers (R14 to R12) in order to be able to restore them before returning to us. In other operating systems it is called to put on the stack, and retrieve from the stack. In z/OS it is called to comply with Linkage Conventions.However, we're a program our self that is called - perhaps by the operating system, perhaps by another program. Therefore, we must save the caller's registers. Fortunately, a Macro will do most of it.
SAVE (14,12),,'PGM2 - &SYSDATE..&SYSTIME'
The latter is a comment that tells the program name (PGM2) and the time of program assembling. It is not just not recommended, but required that you use it!. It helps tremendously in many cases to make sure we got the right version of the program in a troubleshooting situation. After saving the caller's registers, we need to have a storage area for our registres, if we were to call another program.
RSA      GETMAIN RC,LV=72
OR R1,R1
BZ NO_STORAGE_OBTAINED
ST R1,8(,R13)
ST R13,4(,R1)
LR R13,R1
USING SA,R13
OR R1,R1
BZ NO_STORAGE_OBTAINED
ST R1,8(,R13)
ST R13,4(,R1)
LR R13,R1
USING SA,R13
         ........
         ........
SA       DSECT
SAVEAREA DS 18F
SAVEAREA DS 18F
         L     R13,SAVEAREA+4
         LM    R14,R12,12(R13)
         RETURN RC=0
First, R13 points to the callers Register Save Area. Then all registers from this area are fetched - except R13 of course. Finally, we return to the caller. Your program is fully reentable and can be laid in the Link Pack Area (LPA). It is a read-only-area, which is accessible to all address spaces (regions). It can also be used simultaneously to multiple tasks / threads. In the next chapter we talk about calling other programs if you still want your program to be reentable. It's not quite that simple as it sounds.
More reading:
Even more about reentable
In last chapter we made a reentrant program and you thought maybe it was everything, but it is not. It turns out that if you have to use some built-in features such as to call another program (LINK), then some of these features actually modify themselves in the program that uses them. I will review an example with LINK.In my PGM1 I make a LINK to PGM2. I call it with a parameter. Notice the last three instructions that the parameter definition. It is embedded in the program itself. It is required by the LINK macro, because it generates the address of Parm in A (PARM + X'80000000 '). If I had no PARM or it was a constant in the program, I could have used the standard LINK in a reentrant program.
         STH   R3,PARMLGD               
*************************************** 
** FLYT VARIABEL LÆNGDE AF TEKST        
*************************************** 
         BCTR  R3,0                     
         EX    R3,MVC                   
         B     MVC+L'MVC                
MVC      MVC   PARMTXT(0),2(R2)         
PGM2     LINK  EP=PGM2,PARAM=PARM,VL=1                         
PGM2     DS    0H                                              
         CNOP  0,4                                             
         LA    1,IHB0011                         LIST ADDRESS  
         B     IHB0011A                          BYPASS LIST   
IHB0011  EQU   *                                               
         DC    A(PARM+X'80000000')                             
IHB0011A EQU   *                                               
         CNOP  0,4                                             
         BAL   15,*+20            BRANCH AROUND CONSTANTS      
         DC    A(*+8)             ADDR. OF PARM. LIST          
         DC    A(0)                DCB ADDRESS PARAMETER       
         DC    CL8'PGM2'           EP PARAMETER                
         SVC   6                   ISSUE LINK SVC              
         B     RETURN                                          
PARM     DS    0F                                              
PARMLGD  DS    H                                               
PARMTXT  DS    CL120                                           
 | 
STORAGE   DSECT                                      
STORAGE_EYE_CATCHER DS CL16            EYE CATCHER  
PARM      DS    0F                                   
PARMLGD   DS    H                                    
PARMTXT   DS    CL120                                
STOR_LGD  EQU   *-STORAGE                            
PGM2_EXEC DS   XL(PGM2_LGD)  
 | 
         STH   R3,PARMLGD                  
****************************************** 
** FLYT VARIABEL LÆNGDE AF TEKST        ** 
****************************************** 
         BCTR  R3,0                        
         EX    R3,MVC                      
         B     MVC+L'MVC                   
MVC      MVC   PARMTXT(0),2(R2)  
******************************************                               
         MVC   PGM2_EXEC,PGM2_LIST                                       
PGM2     LINK  EP=PGM2,PARAM=PARM,VL=1,MF=(E,PGM2_EXEC)                  
PGM2     DS    0H                                                        
*                                                                 1ØL1D  
*                                                                 1ØL1D  
         LA    1,PGM2_EXEC                       LOAD PARAMETER REG 1    
         LA    14,PARM            PICKUP PARAMETER                       
         ST    14,0(0,1)                         STORE INTO PARAM. LIST  
         OI    0(1),X'80'                 SET LAST WORD BIT ON ØG860P40  
         CNOP  0,4                                                       
         BAL   15,*+20            BRANCH AROUND CONSTANTS                
         DC    A(*+8)             ADDR. OF PARM. LIST                    
         DC    A(0)                DCB ADDRESS PARAMETER                 
         DC    CL8'PGM2'           EP PARAMETER                          
         SVC   6                   ISSUE LINK SVC              ØG381P2A  
         B     RETURN                                                    
PGM2_LIST LINK EP=PGM2,SF=L                                              
         CNOP  0,4                                                       
PGM2_LIST DC   A(*+8)             ADDRESS OF EP PARAMETER                
         DC    A(0)           DCB ADDRESS PARAMETER                      
         DC    CL8'PGM2'      EP PARAMETER                               
PGM2_LGD EQU   *-PGM2_LIST                                               
 | 
I do not know if you have noticed it, but there's a little wrinkle in my program that I had to use to move the parameter, which can be of variable length. That is the little EX command. It takes the right aligned byte in the register and put it in the second byte of the instruction, as it points to - here MVC. It is a kind of modification of the code, but it is in the CPU and NOT in the program. I could also have used MVCL (Move Long), but it would be too boring and cumbersome.
That was what I know about Reentable programs. Feel free to add notes and idears of how to improve a program regarding reentable. I would really have been pleased if someone had writen such an article for 30 years ago.
Sehr gut.
SvarSletThank you for this article
SvarSlet