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
Expand all | Collapse all

calling __malloc31 from 64 bit METAL C

  • 1.  calling __malloc31 from 64 bit METAL C

    Posted Tue May 17, 2016 08:56 AM

    I get a runtime error when calling __malloc31 from metal-c.

     

    Steps:

    xlc  -Wc,metal,longname,lp64 -S -qnosearch -I/usr/include/metal b.c
    as -mgoff b.s
    xlc  -Wc,lp64 -c a.c
    xlc  -Wl,lp64 a.o b.o

     

    Output:

    ./a.out

    CEE3204S The system detected a protection exception (System Completion Code=0C4).
             From entry point main at compile unit offset +0000000000000001 at entry offset -000000002610A12F at address 0000000000000001.
             Possible Bad Branch:  Statement:   Offset: -E36D3F92
    Segmentation fault

     

    Source:

    ### a.c ###

    #include <stdio.h>
    #pragma linkage(metal_function,OS)

    void metal_function(int*, int*, void*, int*);

    int main() {
        int a, b, c, d;
        metal_function(&a, &b, &c, &d);
        printf("Result: %d\n", a);

        return 0;
    }

     

    ### b.c ###

    #pragma prolog(metal_function,main)
    #pragma epilog(metal_function,main)
    #pragma linkage(metal_function,OS)

    #include <stdlib.h>

    void metal_function(int* a, int* b, void* c, int* d) {
            __malloc31(4);
    }

     

     

     

     

    John Barboza


  • 2.  Re: calling __malloc31 from 64 bit METAL C

    Posted Tue May 17, 2016 03:36 PM

    John,

    I assume you are using the Metal C library as shipped, and you are not replacing the memory allocation functions.

    Likewise I assume you used the Metal C dynamic (default) library, and not the static library.

    If  these assumptions are true, check the link edit references for unresolved references, and verify that the AMODE is as you expect.

    I'd guess you intended AMODE 31, and RMODE any. Make sure the link does not say AMODE 24, or 64.

     

    A few notes of caution. The default Metal C prolog, and epilog do not detect the end of stack frame, and therefore if your code uses unbounded recursion, you can see unpredictable results when the stack overflows.

    I usually replace both macros when working in Metal C. Second, the metal C library HEAP management routines (the last time I looked) were not safe for multithreaded execution. So if you have multiple threads

    running concurrently, make sure that each calls __cinit() on it's own. Do not share the env-token across threads.

    Frank Myers

    DB2 Tools.

    Frank_O_Myers@IBM


  • 3.  Re: calling __malloc31 from 64 bit METAL C

    Posted Sat June 04, 2016 10:21 AM

    Frank,

     

    John is invoking the binder via the xlc utility. 

    xlc only supports AMODE 31 and 64.  So in his scenario, xlc  -Wl,lp64 a.o b.o,  he is using the defaults; AMODE is 64 and RMODE is ANY.

     

    Thanks,

    Visda

    Visda


  • 4.  Re: calling __malloc31 from 64 bit METAL C

    Posted Sat June 04, 2016 10:18 AM

    John,

     

    Thanks for asking the question.  I used your testcases and added the requirements, according to the z/OS Metal C Programming Guide - Chapter 3, below.  This program runs successfully to completion.  One needs to initialize the MetalC run-time environment, and assign the address of that block R12.  Therefore R12 should not be re-used for the entire life of application.  Also, the metal_function should be identified as OS linkage to/in the caller only.

     

    /*metalCallee.c*/

    #pragma prolog(metal_function,main)
    #pragma epilog(metal_function,main)

    #include <stdlib.h>
    #include <metal.h>
    #include <string.h>

    register void * env_tkn __asm("r12");

    void metal_function(int* a, int* b, int* c, int* d) {
      struct __csysenv_s  metal_env;
      int* stg31;

      memset(&metal_env, 0, sizeof(metal_env));

      metal_env.__cseversion = __CSE_VERSION_1;

      env_tkn = (void*) __cinit(&metal_env);

       /*The 31-bit address allocated on heap is local this function and fred

          upon return to the caller*/

      stg31 = (int*) __malloc31(4);
      c = stg31;
      *stg31 = 5;

      __asm(" AR %0,%1\n":"+r"(*a):"r"(*c));

      __cterm((__csysenv_t) env_tkn);

    }

     

    /*xplinkCaller.c*/

    #include <stdio.h>
    #pragma linkage(metal_function,OS)

    void metal_function(int*, int*, int*, int*);

    int main() {
        int a, b, c, d;
        a = b = c = d = 1;
        metal_function(&a, &b, &c, &d);

        /*Expect to see

           Sum = 6  c = 1;

         */
        printf("Sum = %d c = %d\n", a, c);    

        return 0;
    }

     

    xlc -qMETAL -S -q64 -qlongname -qnosearch -I/usr/include/metal -o metalCallee.s metalCallee.c     //-qnosearch to clear the default include path
    xlc -c -q64 -qlongname xplinkCaller.c
    as -mgoff -I CBC.SCCNSAM metalCallee.s                                  //Include SCCNSAM if you are using the sample PROLOG/EPILOG macros
    xlc -q64 -o a.out xplinkCaller.o metalCallee.o
    a.out

     

    Visda