C/C++

C/C++

C/C++

Your one-stop destination to learn and collaborate about the latest innovations in IBM C/C++ for z/OS compilers to develop high-performing C/C++ applications and system programs on z/OS while maximizing hardware use and improving application performance.

 View Only
  • 1.  Calling a Metal C routine from pl/1

    Posted Wed July 05, 2017 10:17 AM

    Hi there.

    I'm a newbie in Metal C and I would like to know if the following is feasible.

    We currently have a couple of home made 64 bits C routines, with multiple entry points, compiled with the Dignus C compiler.
    These routines are called from a pl/1 31 bits application and provide services to store and retrieve data above the bar to the 31 bits pl/1 application.
    Migrating the pl/1 application to 64 bits is currently not an option.

    Would it be feasible to port the C routines (currently compiling with the Dignus C compiler) to Metal C?

    I'm experimenting with very simple test programs and I'm struggling to have a simple pl/1 main program to call a Metal C routine (both in 31 bits mode) and passing some arguments.
    I'm used to call standard C runtime functions from pl/1 and assumed it should not be much different but I can not get it to work.

    Could someone provide a very simple example of 

    1. A pl/1 main program calling a Metal C routine.  Any specific compile and bind option consideration ?

    Here is my test program which is generating a U4083 REASON=0000000F abend when calling the Metal C routine.

    TESTA: PROCEDURE() OPTIONS(MAIN);                                   
                                                                        
      DCL    WRITEMSG             ENTRY(BIN FIXED(31) NONASGN BYVALUE   
                                       ,CHAR(*) NONASGN BYADDR)         
                                  OPTIONS(ASM);                         
                                                                        
      CALL WRITEMSG(11,'Hello world');                                  
                                                                        
    END TESTA;                                                          


    2. A Metal C routine callable from pl/1.  Any specific compile and bind option consideration ?

    Here is my test Metal C routine:

    #pragma filetag("IBM-500")                 
    #include <string.h>                        
                                               
    extern void WRITEMSG(int lenMsg, char *msg)
    {                                          
                                               
       struct WTO_Parm                         
       {                                       
          short    int len;                    
          short    int mcsflags;               
          unsigned char message[100];          
       };                                      
                                               
       unsigned char wrkArea[512];             
       struct WTO_Parm Msg;                    
                                               
       memset(&Msg,0,sizeof(Msg));             
                                               
       Msg.len           = lenMsg+4;           
       Msg.len           = 15;                 
       Msg.mcsflags      = 0;                  
       strcpy(Msg.message,msg);                
                                               
         __asm(" WTO  MF=(E,(%0))"             
         :                                     
         : "r"(&Msg)                           
         : "r0","r1","r14","r15");             
                                               
    }                                          

    And the options I'm using:

    For the compile step

    CPARM='METAL,NOSEARCH,SEARCH(/usr/include/metal/),NORENT,',
    CPARM2='LOCALE(en_BE),LIST',                                    

    For the assemble step

    PARM='NORENT'

    And for the bind step

    PARM='AMODE=31,MAP,NORENT,CASE=MIXED,CALL'

    Any help will be greatly appreciated!
    Cheers,
    Renaud.

     

     

     

    0HU5_Renaud_Giot


  • 2.  Re: Calling a Metal C routine from pl/1

    Posted Thu July 06, 2017 02:01 PM

    Hi,

     

    Judging by the user abend, and its reason code, the savearea chaining is not proper.  I can also reproduce the problem when PL/I calls a very small and simple Metal C source program.

    I will ask one my colleagues, how can I identify to PL/I the Metal C entry point as one that follows MVS linkage convention  --I think that's what is causing the problem.

    I will get back to you.

     

    Visda

    Visda


  • 3.  Re: Calling a Metal C routine from pl/1

    Posted Thu July 06, 2017 03:41 PM

    Hi Visda,

     

    In my PL/1 test program, the Metal C entry is declared with OPTION(ASM).

    Here is what the PL/1 Language Reference Guide says for the ASM option on the entry declare statement:

    A PROCEDURE or ENTRY statement that specifies OPTIONS(ASSEMBLER) will have LINKAGE(SYSTEM) unless a different linkage is explicitly specified. 

    And here is a description of the available linkage options:

    LINKAGE

    This option specifies the calling convention used. The option can be specified on PROCEDURE statements and ENTRY declarations.

       CDECL (INTEL only)

    This option specifies the CDECL linkage convention used by 32-bit C compilers.

    OPTLINK

    This option is the default, and is the fastest linkage convention. It is not standard linkage for most compilers.

       STDCALL (Windows Only)

    This option specifies the STDCALL linkage, which is the standard linkage convention used by all Windows APIs.

    SYSTEM

    This option is the calling convention that should be used for calls to the operating system. Although this option is slower than OPTLINK, it is standard for all MVS and AIX applications. 

    So I assume the linkage convention is correct.

     

    Cheers,

    Renaud.

     

    0HU5_Renaud_Giot


  • 4.  Re: Calling a Metal C routine from pl/1

    Posted Fri July 07, 2017 11:32 AM

    Hi,

     

    Thanks for the mention of option to make the linkage OS compatible.  It helped.  My sample now works.  I have included it below.

    My suggestion to make your source pgoram work is, provide WRITEMSG the same "main" type prolog/epilog.  "main" has a special meaning to the compiler, therefore indicating in the pragma produces a pre-determined HLASM source code.  You can customize by writing your own prolog/epilog, and using the #pragma prolog and #pragma epilog to indicate it to the compiler.

    The documentation, Metal C Programming Guide -> Chapter 1 -> Programming with Metal C -> Prolog and epilog code, provides the necessary information on the topic.


    Visda
    pli source calling CCALL, a routine written in C and built with METAL. 

    *PROCESS
         LIST
      ;

     OSTMBMP:
     PROCEDURE OPTIONS (MAIN);
     DCL CCALL ENTRY OPTIONS(ASM);

     CALL CCALL;

      END OSTMBMP;

     

    C source. a routine written in C and built with METAL. 

    #pragma prolog(CCALL,main)
    #pragma epilog(CCALL,main)
    int CCALL() {
      int x, y;
      x = 1;
      y = 1;
      __asm(" AR %0,%1\n":"+r"(x):"r"(y));
      return x;
    }

     

     

    script that builds each source file, links them together, and runs them in z/OS Unix

    export _BPXK_JOBLOG="STDERR"

    /home/tobey/bin/pli -c pliCaller3.pli

    xlc -S -qMETAL ccall.c

    /bin/as -o ccall.o ccall.s

    xlc -o pliCaller3.out pliCaller3.o ccall.o

    ./pliCaller3.out

    echo $?

     

    screen capture of the run result

    + ./pliCaller3.out
    + echo 0
    0

     

    Visda


  • 5.  Re: Calling a Metal C routine from pl/1

    Posted Fri July 07, 2017 04:49 PM

    Hi Visda,

     

    I now have 3 more questions:

     

    1.  What's the purpose of this line in your test program ?

     __asm(" AR %0,%1\n":"+r"(x):"r"(y));

     

    2.  I complexified a bit your test program by adding an int parameter

    #pragma prolog(CCALL,main)
    #pragma epilog(CCALL,main)
                              
    int CCALL(int x)          
    {                         
      x++;                    
    }    
                        

     

    and changed the pl/1 calling program to supply this parameter on the call

    OSTMBMP: PROCEDURE() OPTIONS(MAIN);                       
                                                              
      DCL    CCALL                ENTRY(BIN FIXED(31) BYVALUE)
                                  OPTIONS(ASM);               
      DCL    VAR01                BIN FIXED(31) INIT(10);     
                                                              
      PUT SKIP DATA(VAR01);                                   
      CALL CCALL(VAR01);                                      
      PUT SKIP DATA(VAR01);                                   
                                                              
    END OSTMBMP;      
                                           

    Interlanguage communication between pl/1 and c is explained in chapter 17 of the pl/1 programming guide (See http://www-01.ibm.com/support/docview.wss?uid=swg27036735 ).

    As described in this chapter, BIN FIXED(31) is the pl/1 type corresponding to int in C, and C is expecting the parameter to be passed by value.

    The result is not as expected:

    VAR01=            10;
    VAR01=            10;  <=== Should be 11 after the Metal C routine call

     

     

    3.  Can I have multiple entries in a metal C routine, all callable from pl/1 ?

    Something like

    #pragma prolog(CCALL,main) 
    #pragma epilog(CCALL,main) 
    #pragma prolog(CCALL2,main)
    #pragma epilog(CCALL2,main)
                               
    int CCALL(int x)           
    {                          
      x++;                     
    }                          
                               
    int CCALL2(int x)          
    {                          
      x--;                     
    }  
                         

     

     Thanks for your help,

    Renaud.

     

    0HU5_Renaud_Giot


  • 6.  Re: Calling a Metal C routine from pl/1

    Posted Tue July 11, 2017 09:06 AM

    Hi, 

     

    One of the useful aspects of Metal C feature is it gives to the high level language the ability to drop to assembly level, ie metal level.  This is done via the __asm interface.  

    I used __asm in my simple Metal C program to demonstrate this.

     

    I would think if you pass BYVALUE, its value is expected to remain unchanged in the caller, e.g the PL/I program OSTMBMP.  Therefore, the result you get is correct.  In order to have the parameter value changed in the callee to be visible in the caller, the parameter needs to be passed by reference.  I have modified my simple PL/I and C routines, below, to do this.

     

    *PROCESS
         LIST
      ;

     OSTMBMP:
     PROCEDURE OPTIONS (MAIN);
     DCL CCALL ENTRY(BIN FIXED(31) BYADDR)
                    OPTIONS(ASM);
     DCL VAR01      BIN FIXED(31) INIT(10);

     PUT SKIP DATA(VAR01);
     CALL CCALL(VAR01);
     PUT SKIP DATA(VAR01);

      END OSTMBMP;

     

    #pragma prolog(CCALL,main)
    #pragma epilog(CCALL,main)
    int CCALL(int* x) {
      return ++(*x);
    }

     

     

    Compile, run with all the options + RENT will yield this message to be printed 

     

    VAR01=            10;
    VAR01=            11;
    + echo 0
    0

     

    There needs to be a purpose behind enabling "main" like prolog/epilog for one or more function entry points.  If that's the intention, then specifying the #pragma prolog/epilog(func, main), will provide you what you need.  The characteristic of the "main" like prolog/epilog is documented in the Metal C Programming Guide  -> Programming with Metal C -> Prolog and epilog code -> Compiler-generated defaullt prolog and epilog code.

     

    Visda

     

    Visda


  • 7.  Re: Calling a Metal C routine from pl/1

    Posted Wed July 12, 2017 10:32 AM

    Thanks Visda! I think I now have all I need to continue my experiments with Metal C.
    And definitely, even an experienced pl/1 programmer like me does not make a decent c programmer!

    Best regards,
    Renaud.

    0HU5_Renaud_Giot