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