tirsdag den 29. december 2015

Unix from assembler (1) - Introduction

Introduction to Unix Callable Services

I start a small series of articles regarding Unix System Services (USS) and how to access Unix properties from an assembler program, either started from JCL or in the Unix shell. I start by showing how to access services and later the File System (zFS).


If you have no idea what I am talking about, please read the article linked to below. Even if you know something about USS you might benefit from reading it:

Crossing the border

Programming between native z/OS and zOS UNIX Systems Services
I have borrowed some of the examples in the article.

Calling the services

In the Unix society the programming language C is what assembler is for z/OS. So it can be no surprise that z/OS offers all services in Unix C to assembler. These services are the same modules that is used by C. There are (at least) three ways to find these Callable Services:
  1. by static linking each module into your load module and CALL it
  2. by loading the module into storage and CALL it
  3. by finding the address of the preloaded module in a control block and CALL it
I will definitely recommend the latter and that is what my examples will do.
       L     R15,16              R15 -> Common Vector Table
       L     R15,CVTCSRT-CVT(15) R15 -> CSRTABLE
       L     R15,24(R15)         R15 -> CSR slot
       L     R15,276(R15)        R15 = Address of service svc
       BALR  14,15                                               
There is a table of addresses of each module. At offset 276 is the address of “getpid” (get process id).

Parameters

You pass parameters in a list of addresses to the module exactly as you would to any other module.
PARM      DS   F
PROCESSID DS   F
        ...
        ...
        LA    R15,PROCESSID
        ST    R15,PARM     
        OI    PARM,X'80'
        LA    1,PARM    
This example passes only one parameter, PROCESSID but we will later handle several parameters

MACRO to USS Callable Service
I am a macro guy so I have of course made a macro to facilitate the call of a Unix Callable Service. It is supposed to be extended with offsets to more Unix Callable Services.

        MACRO                                      
.***************************************************
.**                                                 
.** Macro USSSERV - Call USS Callable Services    **
.**                                                 
.***************************************************
&LABEL   USSSERV &SERVICE,&PARMS                    
        GBLC  &PARM_LABEL                          
.***************************************************
.** Storage definitions                           **
.***************************************************
        AIF   ('&SERVICE' EQ 'PARM').PARM          
        AIF   ('&SERVICE' EQ 'DSECT').DSECT        
.***************************************************
.** Callable Services                             **
.***************************************************
        AIF   ('&SERVICE' EQ 'GETPID').GETPID      
        AIF   ('&SERVICE' EQ 'OPEN').OPEN          
        AIF   ('&SERVICE' EQ 'CLOSE').CLOSE        
        AIF   ('&SERVICE' EQ 'READ').READ          
        MNOTE 8,'Wrong SERVICE'                    
        AGO   .END                                 
.***************************************************
.** Define parm list                              **
.***************************************************
.PARM    ANOP                                       
&LABEL   DS    &PARMS.F                             
&PARM_LABEL SETC '&LABEL'                           
&PARM_LABEL._LENGTH EQU *-&LABEL                    
        AGO   .END                                 
.***************************************************
.** Define DSECT for the BPX-services             **
.***************************************************
.DSECT ANOP                                         
        PUSH  PRINT                                
        PRINT NOGEN                                
        CVT   DSECT=YES                            
        BPXYMODE LIST=NO                           
        BPXYOPNF LIST=NO                           
        POP   PRINT                                
        AGO   .END                                 
.***************************************************
.** Get Process id                                **
.***************************************************
.GETPID  ANOP                                       
&OFFSET  SETC  '276'                                
        AGO   .MAKECODE                            
.***************************************************
.** Open file                                     **
.***************************************************
.OPEN    ANOP                                       
&OFFSET  SETC  '156' BPX1OPN                        
        AGO   .MAKECODE                            
.***************************************************
.** Read a file                                   **
.***************************************************
.READ    ANOP                                       
&OFFSET  SETC  '176' BPX1RED                        
        AGO   .MAKECODE                            
.***************************************************
.** Close a file                                  **
.***************************************************
.CLOSE   ANOP                                       
&OFFSET  SETC  '72'  BPX1CLO                        
        AGO   .MAKECODE                            
.***************************************************
.** Make the code to set the parm and the address **
.** of the Service                                **
.***************************************************
.MAKECODE ANOP                                      
&N       SETA  N'&PARMS                             
&I       SETA  0                                    
.LOOP_PARMS ANOP                                    
        LA    R15,&PARMS(&I+1)                     
        ST    R15,&PARM_LABEL+(4*&I)
&I       SETA  &I+1
        AIF   (&I LT &N).LOOP_PARMS
        OI    &PARM_LABEL+(4*(&N-1)),X'80'
.**************************************
.** Find the Callable Service        **
.************************************** 
        L     15,16              R15 -> Common Vector Table
        L     15,CVTCSRT-CVT(15) R15 -> CSRTABLE
        L     15,24(R15)         R15 -> CSR slot
        L     15,&OFFSET.(15)    R15 = Address of service svc
        LA    1,&PARM_LABEL 
        BALR  14,15 .***************************************************
.** End-Of-Macro                                  **
.***************************************************
.END     ANOP
        MEND

The macro has a “Service” called “CVTDSECT”. That must be placed outside any DSECT or CSECT. It is used to calculate an offset.


I will change this macro as I need more services and parameters.

Exampel program
        PROGRAM EQU                     
*************************                
WS       PROGRAM STORAGE                 
WSEC     DS    CL16                      
PARM     DS    f                         
PROCESSID DS   F                         
PID_PACKED DS  PL8                       
PID_CHAR DS    CL16      
WTO      DS    0f                        
WTOLGD   DS    H                         
WTOTEXT  DS    CL70                      
        PROGRAM STORAGE                 
        USSSERV CSVDSECT                
*************************                
PGM12    PROGRAM START                   
        MVC   WSEC,=CL(L'WSEC)'PGM12-WS'
        USSSERV GETPID,PROCESSID        
        l     R1,processid              
        CVD   R1,PID_PACKED             
        MVC   PID_CHAR,EDIT_FIELD                 
        ED    PID_CHAR,PID_PACKED                 
        MVC   WTOTEXT(10),=C'Processid:'          
        MVC   WTOTEXT+10(l'PID_CHAR),PID_CHAR     
        MVC   WTOLGD,=Y(l'WTOTEXT)                
        WTO   TEXT=WTO,ROUTCDE=11                 
        B     RETURN                              
EDIT_FIELD DC  C' ',(L'PID_CHAR-1)X'20'            
NO_STORAGE_OBTAINED DS 0H                          
        WTO   'PGM12 - Return med fejl',ROUTCDE=11
        L     R13,SAVEAREA+4                      
        LM    R14,R12,12(R13)                     
        RETURN RC=8                               
*************************                          
* End of program
*************************                          
RETURN   PROGRAM END                               
        LTORG                                     
        END

Manual

z/OS V1R13.0 UNIX System Services Programming: 
Assembler Callable Services Reference - SA22-7803-14
List of offsets on page 1011 (Table 24. System control offsets to callable services)



fredag den 25. december 2015

Language Environment in Assembler (2)

Callable Services

I assumed that the term Language Environment is referring to the different programming languages that are available for you on z/OS. It is probably so but, on the other hand, there are several services you can call that makes your program independent of human languages. There are several more but let me show you some of them:
  • CEE3LNG - Set national language
  • CEE3MCS - Get default currency symbol
  • CEE3MDS - Get default decimal separator
  • CEE3MTS - Get Default thousands separator


Along with the human language specialities are the geographical specialities, - most important is the current time.
  • CEEDYWK - Calculate day of week from Lilian date
  • CEEFMDA - Get default date format
  • CEEFMDT - Get default date and time format
  • CEEFMTM - Get default time format
  • CEEFTDS - Format time and date into character string
  • CEEGMT - Get current Greenwich Mean Time
  • CEEGMTO - Get offset from Greenwich Mean Time to local time
  • CEELOCT - Get current local date or time


All these services are callable services but, as opposed to CEEENTRY and CEETERM, there are no assembler macro equivalent. I do not know why. These services must be called as regular programs with a parm and a BALR.
I have made two macroes that will do most of the job for you. You can find the at the bottom of this blog article.


I will show you an example of a macro to get the current time. The other are called in a similar way.
        CEELOCT MF=(E,TS),RESULT=TIMESTAMP
TS       CEELOCT MF=L
TIMESTAMP DS    CL17


MACROES

All macroes must have the List and Execute for in order to make the programs, using them, can be reentrant.

CEELOCT - Get current local date or time

This macro does not use all possibilities in the the call to CEELOCT. It returns 17 byte in an area in the form of YYYYMMDDHHMISSMIL.

Excecute form

CEELOCT [TYPE=[TIMESTAMP],]MF=(E,[label_on_list])      
                         RESULT=label_to_CL17


TYPE= Type of result. Only TIMESTAMP is available right now
MF= E is Execute form of the macro
RESULT= Label of a 17 bytes area where the result is placed


Example

         CEELOCT MF=(E,TS),RESULT=TIMESTAMP
+         LA    1,TS_LILIAN                 
+         ST    1,TS_PARM                   
+         LA    1,TS_SECONDS                
+         ST    1,TS_PARM+4                 
+         LA    1,TIMESTAMP                 
+         ST    1,TS_parm+8                 
+         LA    1,TS_fc                     
+         ST    1,TS_parm+12                
+         OI    TS_PARM+12,X'80'            
+         LA    1,TS_PARM                   
+         L     15,=V(CEELOCT)              
+         BALR  14,15                      


List form

prefix CEELOCT MF=L
prefix used as prefix for labels in the macro so you can use it more than once

Example

TS       CEELOCT MF=L
+TS_PARM       DS  4F             
+TS_LILIAN     DS  F               
+TS_SECONDS    DS  D              
+TS_FC         DS  XL12           
+***********************************
TIMESTAMP     DS  CL17     


CEEMOUT

This is very similar to WTO. It writes a text to SYSOUT and not to any log (yet)

Excecute form

CEEMOUT label of text,MF=(E,label of list form)
label of text The text must be prefixed with a halfword containing the length of text
label of list form address of the CEEMOUT listform

Example

         CEEMOUT MOUT,MF=(E,PARM)
+         LA    1,MOUT             
+         ST    1,PARM             
+         LA    1,=A(2)            
+         St    1,PARM+4           
+         MVC   PARM+8,=X'80000000'
+         LA    1,PARM             
+         L     15,=V(CEEMOUT)     
+         BALR  14,15


List form

label of list form CEEMOUT MF=L
Label of list form is used as the label for four fullwords that are used as a parameter list.


You must also define the area that will be written to SYSOUT.

Example

PARM     CEEMOUT MF=L
+PARM     DS    4F

MOUT     DS     0F    
MOUTL    DS     H     
MOUTT    DS     0CL70

CEELOCT macro

This is the macro that you can copy directly into your maclib and use it
        MACRO        
&LABEL   CEELOCT &TYPE=TIMESTAMP,&MF=,&RESULT=
.******************************************************
.** Interface to LE subroutine CEELOCT -
.** Get current local date or time
.** [label]  CEELOCT [TYPE=TIMESTAMP,] MF=([E|L],
.**                                   [label_on_list]        
.**                  RESULT=label_to_CL17
.*****************************************************
        AIF   ('&TYPE' EQ 'TIMESTAMP').TIMESTAMP
        MNOTE 8,'Wrong type'
        ANO   .END
.*****************************************************
.TIMESTAMP ANOP               
        AIF   ('&MF(1)' EQ 'E').EXECUTE
        AIF   ('&MF(1)' EQ 'L').LIST
        MNOTE 8,'Wrong MF'
        AGO   .END
.*****************************************************
.EXECUTE ANOP
        LA    1,&MF(2)._LILIAN    
        ST    1,&MF(2)._PARM   
        LA    1,&MF(2)._SECONDS  
        ST    1,&MF(2)._PARM+4
        LA    1,&RESULT    
        ST    1,&MF(2)._parm+8    
        LA    1,&MF(2)._fc  
        ST    1,&MF(2)._parm+12      
        OI    &MF(2)._PARM+12,X'80'     
        LA    1,&MF(2)._PARM        
        L     15,=V(CEELOCT)       
        BALR  14,15    
        AGO   .END       
.*****************************************************
.LIST    ANOP        
&LABEL._PARM    DS  4F        
&LABEL._LILIAN  DS  F       
&LABEL._SECONDS DS  D       
&LABEL._FC      DS  XL12
.****************************************************
        AGO   .END
.END     ANOP
        MEND


CEEMOUT macro

You can copy this macro directly into your maclib and use it.
        MACRO                          
&LABEL   CEEMOUT &TEXT,&MF=             
        GBLC  &PARM                    
        AIF   ('&MF(1)' EQ 'E').EXECUTE
        AIF   ('&MF(1)' EQ 'L').LIST   
        MNOTE 8,'Wrong MF'             
        AGO   .END                     
.LIST    ANOP                           
&LABEL   DS    4F                       
        AGO   .END                     
.EXECUTE ANOP                           
        LA    1,&TEXT                  
        ST    1,&MF(2)                 
        LA    1,=A(2)                  
        St    1,&MF(2)+4               
        MVC   &MF(2)+8,=X'80000000'    
        LA    1,&MF(2)                 
        L     15,=V(CEEMOUT)           
        BALR  14,15                    
.END     ANOP                           
        MEND