Compiler
Writable Static Area - WSA
The writable static area is used for data items in reentrant C or C++ programs. C code is naturally reentrant if it contains no data in the Writable Static Area. The modifiable writable static part of the program contains:
- program variables with extern storage classs
- program variables with static storage class
- writable strings
Reentrant programs are structured to allow multiple users to share a single copy of an executable module or to use an executable module repeatedly without reloading. C and C++ achieve reentrancy by splitting programs into two parts, which are maintained in separate areas of memory.
- The first part, which consists of executable code and constant data, does not change during program execution.
- The second part contains persistent data that can be altered. This part includes the dynamic storage area (DSA) and a piece of storage known as the writable static area.
Constructed Reentrancy for Metal-C Programs
RENT mode support
The RENT option supports constructed reentrancy for C programs with writable static and external variables. This makes Metal C programs with writable static and external variables reentrant.
Runtime RENT support is accomplished by additional calls generated for the function "main" between the prolog/epilog code and the function code. The RENT environment initialization and termination routines are called to establish and terminate the dynamically allocated WSA storage.
For the AMODE 31 "main" function, CCNZINIT and CCNZTERM are the called CCNZQINIand CCNZQTRM are called.
Here's how constructed reentrancy is managed for a Metal-C program:
- The static data and extern data are defined in GOFF classM_WSA.
- The binder builds the WSA image with initialization data fromM_WSA definitions found in all object files.
- The “main” function has a hook after the prolog code to connect to a runtime routine called CCNZINIT.
- CCNZINIT locates theM_WSA class in the program object and passes the address of M_WSA and its size to a user plug-in routine for storage allocation and initialization.
- CCNZINIT returns the address of the allocated WSA storage to “main”.
- “main” saves the returned WSA address .
- All other functions receive the WSA address in GPR 0.
- On exit from “main” CCNZTERM is called for cleanup
Sample C Code - M_WSA class
Below are snippets from the exampleExample 11, Pseudorandom Number Generator (PRNG), the using Mersenne Twister. The static data are highlighted.
#define N 624 #define M 397 #define MATRIX_A 0x9908b0dfUL #define UPPER_MASK 0x80000000UL #define LOWER_MASK 0x7fffffffUL static unsigned long mt[N]; static int mti = N + 1; unsigned long genrand_int32(void) { unsigned long y; static unsigned long mag01[2] = {0x0UL, MATRIX_A}; … …
}
After compiling the Metal-C program, the generated assembler code will have a text class such as the one shown below:
MAIN#C CSECT , M_WSA CATTR RMODE(ANY),PART(MAIN#S),NOTEXECUTABLE,ALIGN(3) $STATIC DS 0D DC (2512)X'00' ORG $STATIC+8 DC XL8'000000009908B0DF' mag01[0,1] = 0x00000000,0x9908b0df ORG $STATIC DC XL4'00000271' mti = 625 ORG , EJECT @@STATICD@@ DSECT DS XL2512 ORG @@STATICD@@ @27mti DS F ORG @@STATICD@@+16 @31mt DS XL2496 mt[N] = 2496 bytes ORG @@STATICD@@+8 @41mag01 DS XL8 END ,(5694A01 ,1D00,15018)
The static data in this program are:
- static unsigned long mt[N] - 2496 bytes
- static int mti - 4 bytes
- static unsigned long mag01[2] - 8 bytes
There also appears to be 4 unused bytes at offset 8.
Retrieving the WSA from an Assembler Program
I wanted to see if it was possible to retrieve the WSA from a Metal-C program from an Assemlber interface. The idea being that an Assembler program calling a Metal-C program would first call this program passing it the name of Metal-C program. This would obviate the need to call CCNZINIT and CCNZTERM. The calling program would be given the address of the WSA which it could then pass to the Metal-C program in GPR 0. The program below shows how this might be possible.
METCBIND CSECT
METCBIND AMODE 31
METCBIND RMODE ANY
SYSSTATE ARCHLVL=2
***********************************************************************
* *
* Purpose: Call the Binder and Retrieve WSA for Metal-C Programs *
* Call : Call METCBIND, (Program Name) *
* *
* R1 Contains address of Parameter List *
* *
* On Return: *
* R15 Contains address of WSA, or 0 if an error occurred. *
* *
* Parameter List Format *
* *
* 1. Program name is required. Eight character load module name *
* to be used to retrieve WSA. *
* *
* 2. WSA Storage Size - Optional input field supplied by user *
* to set the WSA storage size returned. If zero a default *
* value of 128K is used. *
* *
* *
* ParameterList DSECT *
* Input Fields: *
* programName DS CL08 Input *
* WSA_Storage_Size DS F Amount requested by User or *
* or 0 for default *
* Output Fields: *
* Return_Code DS F Return Code *
* Reason_Code DS F Reason Code *
* WSA_StorageAddr DS F WSA Address returned to caller *
* WSA_StorageLength DS F Acquired WSA Storage Length *
* WSA_StorageUsed DS F Actual Storage Length used by WSA *
* WSA_Init_Flag DS CL01 '0' WSA Not Initialied '1' Initialized*
* *
* *
***********************************************************************
Print Gen
J @OFFSET
DC HL2'08'
DC CL8'METCBIND'
DC C'&sysdate'
DC C'&systime'
DC C'&system_id'
@OFFSET DS 0H
STM R14,R12,12(R13) Save Registers
LR R12,R15 Load Base Register
Using METCBIND,R12
***********************************************************************
* Obtain and Initialize DSA for this Program *
***********************************************************************
LR R10,R1 Save Copy of Parameter List Address
Using ParameterList,R10 Address parameter list from Caller
LGFI R2,DSASize Acquire storage for this DSA
LR R11,R13 Save Caller's DSA Pointer
STORAGE OBTAIN,LENGTH=(R2),LOC=(31,64)
ST R0,0(,R1) Store Length in 1st 4 bytes
AHI R1,4 Move past the length field
LR R13,R1 Load this program's DSA Address
Using DSA,R13 Point to this DSA
***********************************************************************
* Clear This Program's DSA Storage *
***********************************************************************
LR R4,R1 Dest Address
LR R5,R0 Dest Length
AHI R5,-4 Less Length Field Length
LHI R6,0 Source Length = 0
LR R7,R6 Source Address, pad = 0
MVCL R4,R6 R4 - Dest R6 - Source
ST R11,SavPrev Store Caller's DSA Pointer
MVHI Return_Code,0 Return Code
MVHI Reason_Code,0 Reason Code
MVHI WSA_StorageAddr,0 WSA Address Returned
MVHI WSA_StorageLength,0 Length of Returned WSA
MVI WSA_Init_Flag,0 Flag to indicate storage initialized
***********************************************************************
* Obtain Storage for WSA for Metal-C Program *
***********************************************************************
LT R2,WSA_Storage_Size User Requested Storage Amount
JNZ LAB0110
LGFI R2,131072 Default Storage Amount
LAB0110 DS 0H
STORAGE OBTAIN,LENGTH=(R2),LOC=(31,64)
LHI R3,0
St R1,WSA_StorageAddr Address of Allocated Storage
St R0,WSA_StorageLength Total Obtained Storage
St R3,WSA_StorageUsed Total Bytes Used by WSA
***********************************************************************
* Clear Acquired Storage for WSA
***********************************************************************
LR R4,R1 Dest Address
LR R5,R0 Dest Length
LHI R6,0 Source Length = 0
LR R7,R6 Source Address, pad = 0
MVCL R4,R6 R4 - Dest R6 - Source
***********************************************************************
* LOAD IEWBFDAT *
* IEWBFDAT - Binder Fast data access API functions *
* Used to inspect or obtain information about an existing program. *
***********************************************************************
LOAD EP=IEWBFDAT Load IEWBFDAT from LPA
St R0,IEWBFDAT
CIJE R15,0,LAB0500
MVHI Return_Code,8 LOAD Failed
ST R15,Reason_Code
J LAB2000 Bad Return Code - Exit.
***********************************************************************
* Contents Supervisor Query Service *
* Used to obtain information about the attributes of a loaded module *
* INEPNAME - Specifies an 8-character variable that contains the *
* name of the name of the entry point. *
* OUTEPTKN - Specifies an optional 8-character variable where *
* CSVQUERY returns the output entry point token. *
***********************************************************************
LAB0500 DS 0H
XC QueryName,QueryName Clear storage
MvC QueryName(8),programName Move in Parm List Pgm Name
LA R3,QueryName Change any x'00's to x'40's
LHI R4,l'QueryName
* Blank Pad Query Name Field on Right
LAB0710 DS 0H
TM 0(R3),B'11111111'
JNE LAB0720
MVI 0(R3),C' '
LAB0720 DS 0H
AHI R3,1
BRCT R4,LAB0710
***********************************************************************
* Load Metal-C Module Into Storage *
***********************************************************************
XC wrkArea,wrkArea
LA R6,QueryName
LOAD EPLOC=QueryName,SF=(E,wrkArea),VL
St R0,LoadPgmMAddr
CIJE R15,0,LAB0700
MVHI Return_Code,8
St R15,Reason_Code
J LAB2000 Bad Return Code - Exit.
LAB0700 DS 0H
XC wrkArea,wrkArea
***********************************************************************
* CSVQUERY Contents Supervisor Query Service *
* Eptoken An eptoken is an 8-byte field returned by CSVQUERY. *
***********************************************************************
CSVQUERY INEPNAME=QueryName,OUTEPTKN=EPTOKEN,MF=(E,wrkArea)
CIJE R15,0,LAB0600
MVHI Return_Code,8
ST R15,Reason_Code
J LAB2000 Bad Return Code - Exit.
LAB0600 DS 0H
XC mtoken,mtoken zero out mtoken
***********************************************************************
* Process SQ - Start Session with a CSVQuery Token *
***********************************************************************
***********************************************************************
* Mtoken The mtoken is common to all interfaces and calls. *
* It is a fullword field provided by the application but with *
* a value set by the fast data access service. *
* *
* The first time the application calls for a particular program *
* it must set the mtoken to 0. The value returned must be used *
* for all subsequent calls up through the call in which the *
* application indicates it is terminating the instance. *
***********************************************************************
L R15,IEWBFDAT
XC parmlist,parmlist
Call (15),(SQ,mtoken,eptoken),VL,MF=(E,parmlist)
***********************************************************************
* Process GD - Get Data from Any Class *
***********************************************************************
* This service is often used to access program text, but can also *
* be used to retrieve data from other compiler-defined or *
* binder-defined classes. *
***********************************************************************
IEWBUFF FUNC=GETBUF,TYPE=TEXT Get Memory for Text Buffer.
IEWBUFF FUNC=INITBUF,TYPE=TEXT INIT Text Buffer
***********************************************************************
* Keep calling fast data while there are more data *
* Append Data for each call to end of buffer. *
* Update Counters and Pointers. *
***********************************************************************
MvC CurrentBufferPtr,WSA_StorageAddr
IEWBTXT_BASE Equ R2 Header DSECT Register Equate
TXT_BASE Equ R8 Text Buffer DSECT Equate
XC Cursor,Cursor Zero Out Cursor
XR R3,R3 Accumulate Full Size
MVHI TotalBufferCount,0
LAB0200 DS 0H
L R15,IEWBFDAT Load the Binder
XC parmlist,parmlist
***********************************************************************
* Issue GD - Get Data from Any Class *
***********************************************************************
Call (15),(GD,mtoken,b_text_vstring,0,(IEWBTXT_Base),Cursor, x
Count,0),VL,MF=(E,parmlist)
ST R15,Return_Code
ST R0,Reason_Code
***********************************************************************
* FDAT_END_OF_DATA DC X'10800002' SYS1.MACLIB(IEWBFZP) *
***********************************************************************
CIJE R15,IEWB_RC_OK,LAB0100 Return Code = 4 &
C R0,FDAT_END_OF_DATA Reason Code = EOD
JNE LAB0300 End of Data Reached
LAB0100 DS 0H Any other reason - error
CIJH R15,IEWB_RC_WARNING,LAB0300 Reason Code > 4
L R4,CurrentBufferPtr Dest Address
L R5,count Dest Length
LLGTR R6,TXT_BASE Source Address
LGR R7,R5 Source Length
MVCL R4,R6
L R4,CurrentBufferPtr Dest Address
A R4,count Add Size of Data Obtained
A R3,count Add Size of Data Obtained
ST R4,CurrentBufferPtr Store Full Size
C R0,FDAT_BUFFER_IS_FULL
JE LAB0200 Get Another Buffer
C R0,FDAT_END_OF_DATA
JNE LAB0300
* Good Return Code / Reason Code FDAT_END_OF_DATA
LAB0250 DS 0H
ST R3,TotalBufferCount
ST R3,WSA_StorageUsed
* Bad Return Code / Reason Code
LAB0300 DS 0H
IEWBUFF FUNC=FREEBUF,TYPE=TEXT Free Text Buffer
***********************************************************************
* Process RC - Get return code information *
***********************************************************************
L R15,IEWBFDAT
Call (15),(RC,mtoken,Return_Code,Reason_Code), x
VL,MF=(E,parmlist)
***********************************************************************
* Process EN - End session *
***********************************************************************
L R15,IEWBFDAT
Call (15),(EN,mtoken),VL,MF=(E,parmlist)
***********************************************************************
* Successful End of Processing *
***********************************************************************
XR R9,R9
DELETE EP=IEWBFDAT
***********************************************************************
* Return to Caller *
***********************************************************************
MVI WSA_Init_Flag,1
LAB2000 DS 0H
L R7,WSA_StorageAddr Save WSA Address
L R6,savearea+4 Get Caller's DSA Pointer
LR R3,R13 This program's DSA Pointer
AHI R3,-4 Position to Length Field
L R2,0(,R3) Load Length Field
STORAGE RELEASE,ADDR=(R3),LENGTH=(R2)
LR R15,R7 WSA Address to Return
LR R13,R6 Restore R13
L R14,12(R13) Restore R14
LM R0,R12,20(R13) Restore R0-R12
BR R14 Return To Caller
***********************************************************************
* *
***********************************************************************
DS 0FD
Copy IEWBCRS
DS 0FD
Copy IEWBFZP
***********************************************************************
* Fast data access request codes *
***********************************************************************
SB DC C'SB',X'0001'
SJ DC C'SJ',X'0001'
SQ DC C'SQ',X'0001'
GC DC C'GC',X'0001'
GD DC C'GD',X'0001'
GE DC C'GE',X'0001'
GN DC C'GN',X'0001'
RC DC C'RC',X'0001'
EN DC C'EN',X'0001'
***********************************************************************
* Fast data mappings and buffer templates *
***********************************************************************
TXTBUF IEWBUFF FUNC=MAPBUF,TYPE=TEXT,VERSION=6,BYTES=16384
***********************************************************************
* B_TEXT class name represented as vstring *
***********************************************************************
b_text_vstring DC H'5',C'M_WSA'
LtOrg
***********************************************************************
* Program Called Parameter List *
***********************************************************************
ParameterList DSECT
programName DS CL08 Input
WSA_Storage_Size DS F Amount Request by User or 0 for default
Return_Code DS F Return Code
Reason_Code DS F Reason Code
WSA_StorageAddr DS F WSA Address returned to caller
WSA_StorageLength DS F WSA Length
WSA_StorageUsed DS F Actual Storage Length
WSA_Init_Flag DS CL01 Output
***********************************************************************
* Dynamic Save Area (DSA) *
***********************************************************************
DSA DSECT
Savearea DS 0FD
SavPLI DS F +00
SavPrev DS F +04
SavNext DS F +08
SavGRS14 DS F +12
SavGRS15 DS F +16
SavGRS0 DS F +20
SavGRS1 DS F +24
SavGRS2 DS F +28
SavGRS3 DS F +32
SavGRS4 DS F +36
SavGRS5 DS F +40
SavGRS6 DS F +44
SavGRS7 DS F +48
SavGRS8 DS F +52
SavGRS9 DS F +56
SavGRS10 DS F +60
SavGRS11 DS F +64
SavGRS12 DS F +68
parmlist DS 32F Common area for passing parameters.
IEWBFDAT DS F Fast data entry point.
mtoken DS F Current session identifier.
Cursor DS F Fast data cursor position.
Count DS F Number of entries obtained.
QueryName DS CL64 Member, path or entry point name.
eptoken DS CL08 CSVQuery Token.
CurrentBufferPtr DS F
TotalBufferCount DS F
LoadPgmMAddr DS F
wrkArea DS XL256
DSASize Equ *-DSA
***********************************************************************
* IEWBTXT DSECT Binder TXT buffer header. *
* This DSECT is based on a register *
* equated to the symbol named IEWBTXT_BASE. *
* *
* A Binder buffer consists of a header section, followed by *
* a table of fixed size entries and an area for symbol names. *
* Each name in the names list area consists of a halfword *
* length followed by up to 64 characters. *
* *
* TXT_ENTRY DSECT *
* TXT buffer entry. Repeated the number of *
* times specified by TXTH_ENTRY_COUNT. This *
* DSECT is based on a register equated to the *
* symbol TXT_BASE. *
***********************************************************************
R0 Equ 0
R1 Equ 1
R2 Equ 2
R3 Equ 3
R4 Equ 4
R5 Equ 5
R6 Equ 6
R7 Equ 7
R8 Equ 8
R9 Equ 9
R10 Equ 10
R11 Equ 11
R12 Equ 12
R13 Equ 13
R14 Equ 14
R15 Equ 15
END
References
- z/OS Metal C Programming Guide and Reference
- z/OS XL C/C++ Language Reference
- z/OS XL C/C++ Programming Guide/li>
- z/OS Version 2 Release 3 MVS Program Management - Advanced Facilities
- What is New in Enterprise PL/I 4.1 and z/OS XL C/C++ V1R12 IBM Corporation August 2, 2010
All references copyright© IBM Corporation.