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)



2 kommentarer:

  1. Hi Jens. Have you considered linking the linkage stub into your program as described:

    When you link-edit a program, you can link to the linkage stub. The program can issue a call.
    The linkage stubs are contained in SYS1.CSSLIB. You can specify SYS1.CSSLIB in the //SYSLIB statement of the JCL that is used to invoke the linkage editor. This causes the addresses of all required linkage-assist routines to be automatically resolved, and saves you the trouble of having to specify individual linkage-assist routines in INCLUDE statements.

    SvarSlet
  2. I assume you are referring to page 2 in the manual "Service_name".
    Well, I have actually. I really do not like to link the services into the program, as the load module will be bigger, any PTF will not affect the load module unless relinked and if dynamically loaded into storage with a LOAD is just some extra code.
    Getting the modules from system storage (same manual, Appendix A. System control offsets to callable services) is preferrable because you always know you are running the latest PTF-level, it does not increase the module size, and you also know that everybody runs the same version of the callable service.

    SvarSlet