COBOL

COBOL

COBOL

COBOL is responsible for the efficient, reliable, secure, and unseen day-to-day operations of the world's economy.

 View Only
  • 1.  COBOL CALL RETURNING

    Posted Fri July 22, 2016 06:20 PM

    Ran in to an "interesting" behavior that caused me many hours of frustration that I just wanted to bring up.  It's probably "working as designed", so I didn't want to open a PMR.

    In Enterprise COBOL if you do a CALL with the RETURNING phrase there seems to me essentially two (at least?) ways in which the return value is communicated between the caller and the callee.  If the return parameter has certain common attributes the callee will return the value in register 15.  These common attributes appear to be things like numerics up to a certain size (I believe), pointers, and single characters (PIC X(1)).  In other cases the caller passes the address of the return value as the first parameter, and the callee essentially treats it as a pass by reference.

    The problem I ran in to is that my caller defined the return value as a PIC X(4), but the callee treated it as a pointer.  So there was a linkage parameter mismatch.  Grrr...  Obviously the fix is to either have both the caller and callee use DISPLAY PIC X(4) or both use POINTER.  (The reason I had the caller define the field as PIC X(4) instead of pointer is because the caller really is only treating the field as a "token".  Even though the token is in fact an address, the caller really should not need to know that.)

    My guess is that this is long-standing behavior and couldn't be changed now without breaking working programs, but I just wanted to "put it out there" in case anyone wanted to comment on it.  I'm guessing further that if it changed it would break ILC behavior between COBOL and C/C++ and perhaps PL/I.  Or maybe not?  In C you can't really return a four-byte character field as such; you have to return a pointer.

    Anyway... comments?

    fswarbrick


  • 2.  Re: COBOL CALL RETURNING

    Posted Sat July 23, 2016 05:57 AM

    Yes, the compiler will assume that the definitions (if there are any, which of course there are for COBOL) are the same. Remember that everything on the CALL ... USING ... should also match to the PROCEDURE DIVISION USING ..., so nothing different there.

    What is different is the treatment for RETURNING, as you have outlined, depending on what is being returned, see the part starting "when the target is returned" in the following quote:

        RETURNING phrase


        identifier-5
        The RETURNING data item, which can be any data item defined in the DATA DIVISION. The return value of the called program is implicitly stored into identifier-5.


        You can specify the RETURNING phrase for calls to functions written in COBOL, C, or in other programming languages that use C linkage conventions. If you specify the RETURNING phrase on a CALL to a COBOL subprogram:

        v The called subprogram must specify the RETURNING phrase on its PROCEDURE DIVISION header.
        v identifier-5 and the corresponding PROCEDURE DIVISION RETURNING identifier in the target program must have the same PICTURE, USAGE, SIGN, SYNCHRONIZE, JUSTIFIED, and BLANK WHEN ZERO clauses (except that PICTURE clause currency symbols can differ, and periods and commas can be interchanged due to the DECIMAL POINT IS COMMA clause).

        When the target returns, its return value is assigned to identifier-5 using the rules for the SET statement if identifier-6 is of usage INDEX, POINTER, FUNCTION-POINTER, PROCEDURE-POINTER, or OBJECT REFERENCE.
        When identifier-5 is of any other usage, the rules for the MOVE statement are used.
        The CALL ... RETURNING data item is an output-only parameter. On entry to the called program, the initial state of the PROCEDURE DIVISION RETURNING data item has an undefined and unpredictable value. You must initialize the PROCEDURE DIVISION RETURNING data item in the called program before you reference its value. The value that is passed back to the calling program is the final value of the PROCEDURE DIVISION RETURNING data item when the called program returns.


        Note: If a COBOL program returns a doubleword binary item via a PROCEDURE DIVISION RETURNING header to a calling COBOL program with a CALL ... RETURNING statement, an issue occurs if only one of the programs is recompiled with Enterprise COBOL V6. Both the called and calling programs must be recompiled with Enterprise COBOL V6 together, so that the linkage convention for the RETURNING item is consistent.
        If an EXCEPTION or OVERFLOW occurs, identifier-5 is not changed. identifier-5
        must not be reference-modified.
        The RETURN-CODE special register is not set by execution of CALL statements that include the RETURNING phrase.

    I doubt the behaviour can be changed, because it has to match to the C/C++ conventions to be any use. No information on type is passed between CALLer/CALLee on a CALL in Enterprise COBOL, so assumptions have to be made on the data-definitions.

    Note that for other languages, RETURNING on a CALL is only possible if the other language follows C/C++ linkage conventions, also note a change in processing at V5.1, and a further change in V6.1 if you have double-word values (both CALLer and CALLee need to be compiled with V6.1).

    What you describe for numbers and PIC X(1) is relevant in a different context, not for RETURNING (although I don't know what was "wrong" before V5.1, so maybe applies if you have observed that with V4.2). Those limits are on BY VALUE on the CALL ... USING ... and PROCEDURE DIVISION USING ...

     

    RETURNING is an IBM Extension to COBOL 85, as is BY VALUE.

    BillWoodger


  • 3.  Re: COBOL CALL RETURNING

    Posted Tue July 26, 2016 07:57 PM

    Of course I assumed that only a 'size' match was needed.  I mean four bytes is four bytes, right?  I guess not!  If only we had program prototypes the compiler could have saved me from myself!  Eyebrow

    I still wonder if the behavior could be changed simply because I'm not convinced that C/C++ allows returning of a "character array".  I suppose you could wrap it in a struct/union; I think I've done that before (with GCC, not XL C/C++, and not on z/OS) "just for fun".  Anyone out there have XL C/C++ for z/OS want to try this?

    (**Attempt to put example here but this crazy editor keeps giving me fits!!!!)

    Dunno if you can return a union, but hey.  The question is, will the "return" statement place the 4 byte "static_fbf" field in R15?  The more I think about it the more I think either C/C++ would not allow it at all, or it will return it in R15.  I say this because I don't believe there is any C calling convention that behaves in the manner that COBOL does when a return value cannot fit in to registers.  In either case it seems to me that changing COBOL's behavior, while it might break COBOL to COBOL communication (like the change for doubleword), I think it might not break C/C++ communication!

    Is it worth worrying about?  Probably not.  But if someone from IBM compilers sees this and wants to investigate, I fully support that!

     

     

     

     

     

     

    fswarbrick


  • 4.  Re: COBOL CALL RETURNING

    Posted Tue July 26, 2016 08:07 PM

    FWIW, I did know about the double-word returning fix in V5.1. In fact I am fairly certain I was the one who brought the issue to IBM's attention.  I'm not sure that the V6 behavior is different than V5. V5 has the same comment as V6, except it says V5 instead of V6, and the change is only discussed in Changes in Enterprise COBOL V5.1.

    fswarbrick


  • 5.  Re: COBOL CALL RETURNING

    Posted Thu July 28, 2016 03:06 PM

    From the V6.1 Language Reference:

     

    Note: If a COBOL program returns a doubleword binary item via a PROCEDURE DIVISION RETURNING header to a calling COBOL program with a CALL ... RETURNING statement, an issue occurs if only one of the programs is recompiled with Enterprise COBOL V6. Both the called and calling programs must be recompiled with Enterprise COBOL V6 together, so that the linkage convention for the RETURNING item is consistent.

    So, there's something different with V6, even given the awkward "recompile" wording.

    BillWoodger


  • 6.  Re: COBOL CALL RETURNING

    Posted Thu July 28, 2016 03:20 PM

    From the V5.2 Language Reference:

    "Note: If a COBOL program returns a doubleword binary item via a PROCEDURE DIVISION RETURNING header to a calling COBOL program with a CALL ... RETURNING statement, an issue occurs if only one of the programs is recompiled with Enterprise COBOL V5. Both the called and calling programs must be recompiled with Enterprise COBOL V5 together, so that the linkage convention for the RETURNING item is consistent."

    This is why I think that V5 and V6 are compatible.  I think the manual is just slightly incorrect, in that it should say "an issue occurs if only one of the programs is recompiled with Enterprise COBOL V5 or V6 and the other is compiled with a version prior to V5" and "Both the called and calling programs must be recompiled with Enterprise COBOL V5 or V6 together (one as V5 and one as V6 is also valid)". 

    Or something like that.

    fswarbrick


  • 7.  Re: COBOL CALL RETURNING

    Posted Sun July 31, 2016 10:19 AM

    Yes, it is a documentation problem. Text copied from earlier V5 manual, and just changed references to V5 to V6.

    BillWoodger


  • 8.  Re: COBOL CALL RETURNING

    Posted Thu July 28, 2016 03:21 PM

    In the standard linkage (which is what COBOL uses) whenever a struct is to be returned,

    * the caller allocates temporary space for the struct

    * the caller passes the address of that space to the called program as a hidden first parameter

    * the call copies the returned struct to the temporary space (via the pointer that was passed in as a hidden first parameter)

     

    Example program:


    struct S {
       int a;
       int b;
    };

    static struct S s;
    extern struct S dummyExtern(int);
    struct S proc(int dummy) {
       s = dummyExtern(dummy);
       return s;
    }

     

    Part of the listing

                              000010 |       *     s = dummyExtern(dummy);
     0000F0  5810  D0A8        000010 |                 L        r1,#SR_PARM_1(,r13,168)
     0000F4  5800  1004        000010 |                 L        r0,dummy(,r1,4)
     0000F8  4120  D0B0        000010 |                 LA       r2,#wtemp_1(,r13,176)
     0000FC  58F0  3004        000010 |                 L        r15,=V(dummyExtern)(,r3,4)
     000100  4110  D098        000010 |                 LA       r1,#MX_TEMP1(,r13,152)
     000104  5020  D098        000010 |                 ST       r2,#MX_TEMP1(,r13,152)
     000108  5000  D09C        000010 |                 ST       r0,#MX_TEMP1(,r13,156)
     00010C  0DEF              000010 |                 BASR     r14,r15
     00010E  4110  D0B0        000010 |                 LA       r1,#wtemp_1(,r13,176)
     000112  D207  5000  1000  000010 |                 MVC      s(8,r5,0),(*)S(r1,0)
                               000011 |       *     return s;
     000118  5810  D0A8        000011 |                 L        r1,#SR_PARM_1(,r13,168)
     00011C  5810  1000        000011 |                 L        r1,#retvalptr_1(,r1,0)
     000120  D207  1000  5000  000011 |                 MVC      #retval_1(8,r1,0),s(r5,0)
     

     

    Sorry about the formatting.

    ahkielstra


  • 9.  Re: COBOL CALL RETURNING

    Posted Thu July 28, 2016 03:23 PM

    Well that answers that, then!  I didn't think that C allowed for this type of "hidden parameters".

    Thank you.

    fswarbrick