lørdag den 29. august 2015

How to make your assembler program reentable

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.
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 ReferenceBinder 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.
------------------------------------------------------------------------------------------------------
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
I have collected som links if wish to read some mode on the subject:

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

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 ....

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
         ........
         ........
SA       DSECT
SAVEAREA DS    18F

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:
         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                                          

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.
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.

2 kommentarer: