Skip to main content

     
  TPF : Library : Presentations

TPF Systems Technical Newsletter, Vol. 4 No.4

TPF++


by Bob Kopac, IBM TPF Development

APAR PJ25084 provides support for dynamic link libraries (DLLs) and support for TPF application programs written in C++ programming language.

QUESTION: I have been working on an assembler program for the past 30 years and it almost assembles. I am ready to try some thing new. What is C++?

ANSWER: C++ is a general-purpose, high-level programming language designed to take advantage of object-oriented (OO) program ming concepts. Except for minor details, C++ support is a superset of C language. In addition to the facilities provided by C language, C++ support provides flexible and effective facilities for defining new types. You can partition an application into manageable pieces by defining new types that closely match the logical design of the application. When used well, these techniques result in shorter, easier to understand, and easier to maintain programs. A side benefit of an object-oriented programming language is that you can say "OOPS!" when you make a programming error.

QUESTION: What is a DLL? Does it have anything to do with pickles?

ANSWER: No, a DLL has nothing to do with dill pickles, but a DLL may help you when you find yourself in a pickle. A dynamic link library (DLL) is a collection of one or more functions gathered in a load module and executable or accessible from a separate application load module. The key concept in DLLs is that functions or variables can be executed or referenced dynamically while the application is running rather than statically when the application is built. You can, therefore, call a function or use a variable in a load module other than the one that contains the definition. This allows you greater flexibility in accessing library functions or variables when you find yourself in a pickle. By the way, "find yourself in a pickle" is an American slang expression that creates an interesting picture if you take the saying literally!

QUESTION: How can a DLL execute or reference functions or variables dynamically? Do not side-step this issue!

ANSWER: A DLL does this amazing feat, not by side-stepping, but by using a definition side-deck. A definition side-deck is a directive file that contains an IMPORT control statement for each function and variable exported by the DLL.

When you build a DLL, a definition side-deck is automatically created and written to the ACP.IMPORTS.RELvv SYSDEFSD definition side-deck data set. You must include the ACP.IMPORTS.RELvv SYSDEFSD definition side-deck data set when you prelink a DLL application that imports any functions or variables from a DLL. The C load mod ule build tool (CBLD) includes this data set automatically for you when you code the DLL keyword in the load module build script.

When you link-edit a DLL or DLL application, in addition to specifying the included object files, you must also specify the definition side-deck inputs if the DLL or DLL application imports from other DLLs. The linkage editor resolves external functions in the following search order:

1. Those functions explicitly included in text decks (this is from the original list of included object files in a load modul e build script).

2. Those functions in included EXPORT data set members.

3. Those functions for which static stubs exist in stub data sets concatenated under the SYSLIB data set. These stubs are cr eated with the library interface tool (LIBI) and the DLM stub

Using sample load module FOOG, the following is an example of code that exports functions and variables and its resulting definition side-deck:

   #pragma export(foo)
   #pragma export(goo)
   int foo()
   {
...
}
int goo() {
...
}
int keep_it_hidden() {
...
}
...

#pragma export (hooVar) #pragma export (gooVar) int hooVar; int gooVar; int keep_it_hidden_variable;
Definition Side-Deck produced: IMPORT CODE 'FOOG' foo IMPORT CODE 'FOOG' goo IMPORT DATA 'FOOG' hooVar IMPORT DATA 'FOOG' gooVar

QUESTION: Can you be more explicit about DLLs?

ANSWER: You can use DLLs both implicitly and explicitly. When an application calls an imported function or references an im ported variable, the DLL is implicitly loaded. This is referred to as load-on-call. For an explicit call, the application uses explicit source-level calls to one or more run-time services to connect the reference to the definition. These connections are made at run time.

QUESTION: Do I have to go to a public library to use DLLs?

ANSWER: The CISO run-time library has been updated with several application programming interfaces (APIs) that allow a load module to explicitly call the following run-time services:

  • dllload, which loads the DLL and connects it to the application
  • dllqueryfn, which obtains a pointer to a DLL function
  • dllqueryvar, which obtains a pointer to a DLL variable
  • dllfree, which frees a DLL loaded with dllload.

See theTPF C/C++ Language Support User's Guide for more information about these services.

QUESTION: What is the difference between a DLL and a DLM?

ANSWER: The letter M.

QUESTION: There have got to be more differences than that!

ANSWER: You are correct. The concept of dynamic load module (DLM) was first introduced by APAR PJ17852 (ISO-C Support). A DLM contains one or more functions and has a single entry point that is called with TPF enter/back services. Functions or variables in DLLs can be called or referenced only through DLL linkage. The DLL cannot be called with TPF enter/back services. A function in a DLL may import or export functions or variables.

QUESTION: So a DLM cannot import functions or variables?

ANSWER: Well, yes. A DLM can import functions or variables, but only if it has an import license. If the DLM is written in C language, you must specify the DLL compiler option. If the DLM is written in C++ language, the C++ compiler automatically compiles the source code as a DLL. We call a DLM that can import functions or variables a DLL application.

QUESTION: Can you give a summary of functions and variables?

ANSWER: * Imported functions and variables are those that are not defined in the load module where a reference to them is made, but are defined in a referenced DLL.

* Nonimported functions are those that do not use DLL linkage. Nonimported variables are those that are defined in the same load mod ule where a reference to them is made.

* Exported functions and variables are defined in one load module and can be referenced from another load module.

QUESTION: So I have to learn new terminology, such as DLL application, DLL, definition side-deck, import, and export?

ANSWER: Yes, terminology helps programmers confuse nonprogrammers. SeeTPF Application Programming for program chara cteristics and attributes of DLMs, DLL applications, DLLs, and more information about terminology.

QUESTION: The compiler I am using is 30 years old. How do I know if my compiler supports DLLs?

ANSWER: To use DLLs, you must use one of the following compilers:

* IBM C/C++ for MVS/ESA Version 3 Release 2 * IBM OS/390 C/C++ Version 1 Release 2 or later version.

Notes:

*There is no VM compiler that supports the DLL compiler option.

*There is no RENT compiler option in the family of IBM C++ compilers on the System/390 platform. Source code written in C++ and compi led with a C++ compiler will automatically be compiled as RENT. See theTPF Migration Guide for more information about C/C++ compilers.

QUESTION: Can you give me a description of how a DLL application imports functions or variables?

ANSWER: Let me give you a description of descriptors. A DLL application imports using function descriptors and variable des criptors.

A function descriptor is an internal control block that contains the function address and its associated writable static area (WSA). In the TPF system, a function descriptor can be thought of as a dynamic linkage call stub in contrast to the static linkage call (STUB) and the library interface tool (LIBI) before link-edit time.

A variable descriptor is an internal control block that contains the variable address. This control block is a dynamic linkage call stub.

QUESTION: I crave more information. What else can you tell me about function descriptors?

ANSWER: DLL applications written in C are compiled with the DLL compiler option. For this case, function pointers are point ers to corresponding function descriptors. Therefore, a function pointer that is passed from code compiled without the DLL option to a function in code compiled with the DLL option will not work because the DLL code always expects a function descriptor pointer. Code compiled with the DLL option can still pass a function pointer to code compiled without the DLL option. The special code at the beginning of the function descriptor handles these situations. See the user's guide for the IBM C/C++ compiler on the System/390 platform used by your installation for more information about the DLL compiler option and function descriptors.

Note: There is no DLL compiler option for source code written in C++. It is automatically compiled as a DLL application.

QUESTION: Because of the balance of payments, I would rather export than import. How do I export?

ANSWER: The following are ways to export functions and variables:

* The EXPORTALL compiler option allows a DLL to export all external functions and variables. This also means that no functions or va riables can be hidden; everything in the DLL is accessible to other DLLs and DLL applications. If you use EXPORTALL, you do not need to include the #pragma export directive.

* The #pragma export directive permits you to control specific functions that can be exported when you can code this directive in your source file.

* Using the EXPORT C++ language extension keyword permits you to declare that the function or variable is to be exported.

QUESTION: Okay, what's the catch?

ANSWER: Well, there is no catch support. This APAR does not provide exception handling support for the following keywords:< p>

* try

* catch

* throw.

Also, the TPF lab currently does not ship C++ class libraries. You can, however, create and use your own class libraries.

QUESTION: Can C++ and C programs talk to each other?

ANSWER: Similar to people, C++ and C programs can talk to each other only if they are speaking the same language. The param eter list structure and linkage are different between C and C++. Therefore, functions coded in C and compiled with a C compiler cannot call functions written in C++ unless the C++ function is declared to have C-type linkage. DLL applications are required to have either main or an entry point with the same name as the load module. If your DLL application does not have main, C++ mangles the function name. You must code an extern "C" linkage specification to produce an entry point with the same 4-character uppercase name as the load module. The extern "C" linkage specification allows a C++ application entry point to be called through TPF enter/back services. This linkage specification also forces the linkage to the entry point of the load module to be C linkage instead of C++ linkage. Only the entry point function must have the extern "C" linkage specification. Other functions in a C++ application do not need this linkage specification. A function in the C++ applicat ion that is called by another function in the same load module can have C++ linkage. If you do not code the extern "C" linkage specification, the offline loader (TPFLDR) will provide an error message that the entry point is not found in the program.

In the following example, the extern "C" linkage specification produces a entry point with the same name as the QZZ0 load module name. The call to ReadIt in EmpClass does not require this linkage specification.

   class EmpClass
   {
...
}

extern "C" void QZZ0 (); {
double raise; EmpClass *EmpPtr = new EmpClass<total_employees>; ...
raise = EmpPtr<i>.ReadIt(raise); ...
}

double & EmpClass::ReadIt (double & rate) {
...
...
}

Also, see APAR PJ24541 for additional C header changes needed to support C++.

QUESTION: Can you show me examples of build scripts?

ANSWER: If an @IMPORTDS statement is in the build script, CBLD will include data sets in the output JCL file for definition side-decks.

The following is an example of a build script for a DLL.

######################################################################
#
# SCRIPT NAME..... QZZ2BS #
.
.
.
#
######################################################################

DLL QZZ2RX # Include startup code for DLL

@IMPORTDS CPP140 # Include a definition side-deck @IMPORTDS DLL3RK # Include a definition side-deck

#Object File  Function                           Source Language
#-----------  --------                           ---------------

QZZ2A41 # QZZ2A function C++ QZZ2B41 # QZZ2B function C

Note: With the DLL keyword, CSTDLL startup code is used. The @IMPORTDS statements indicate the definition side-decks from which this DLL imports. @IMPORTDS statements must follow the DLL statement and precede the list of object files to be included.

The following is an example of a build script for a DLM that is a DLL application.

######################################################################
#
# SCRIPT NAME..... QZZ1BS #
.
.
.
#
######################################################################

DLM QZZ1RX # Include startup code for DLM (DLL application)

@IMPORTDS QCCC41 # Include a definition side-deck @IMPORTDS QDDDRX # Include a definition side-deck

#Object File  Function                           Source Language
#-----------  --------                           --------------

QZZ1A41 # QZZ1A function C QZZ1B41 # QZZ1B function C++

Note: DLL applications use the DLM keyword in the build script. CSTRTD startup code is used. The @IMPORTDS statements indicate the definition side-decks this DLL application (DLM) imports from. @IMPORTDS statements must follow the DLM statement and precede the list of object files to be included.

Both the previous DLL and DLL application build script examples show the use of the @IMPORTDS keyword. CBLD takes the load module name that follows this keyword and adds a definition side-deck INCLUDE statement to the list of INCLUDE statements in the JCL output deck. For a DLL only, the JCL will also contain a definition side-deck SYSDEFSD data set, ACP.IMPORTS.RELxx , for exported functions and variables. The following examples show the different JCL output decks generated by CBLD for a DLL and a DLL application:

* For a DLL:

    //$QZZ2BS0 JOB ...
    //PRELINK EXEC EDCPL,COND.LKED=(0,NE),
    // LPARM='AMODE=31,RMODE=ANY,LIST,XREF,MAP',
    // PPARM='DLLNAME(QZZ2)'
    //PLKED.SYSLIB DD DSN=ACP.CLIB.RELxx,DISP=OLD
    //             DD DSN=ACP.STUB.RELxx,DISP=OLD
    //PLKED.OBJLIB DD DSN=ACP.OBJ.RELxx,DISP=SHR
    //*
//PLKED.SYSDEFSD DD DISP=SHR,DSN=ACP.IMPORTS.RELxx(QZZ2RX) //*
//PLKED.DSD DD DISP=SHR,DSN=ACP.IMPORTS.RELxx //PLKED.SYSIN DD * INCLUDE OBJLIB(CSTDLL40) INCLUDE DSD(DLL240) INCLUDE DSD(DLL3RK) ESD @@LM0001 TXT QZZ2A 41 END 1569623400 010195215 INCLUDE OBJLIB(QZZ2A41) ESD @@LM0002 TXT QZZ2B 41 END 1569623400 010195215 INCLUDE OBJLIB(QZZ2B41) ESD @@LM0003 TXT END_OF_LAST_OBJ END 1569623400 010195215 /*
//LKED.SYSLMOD DD DISP=OLD,DSN=ACP.LK.RELxx(QZZ2RX) //

* For a DLL application:

    //$QZZ1BS5 JOB ...
    //PRELINK EXEC EDCPL,COND.LKED=(0,NE),
    // LPARM='AMODE=31,RMODE=ANY,LIST,XREF'
    //PLKED.SYSLIB DD DSN=ACP.CLIB.RELxx,DISP=OLD
    //             DD DSN=ACP.STUB.RELxx,DISP=OLD
    //PLKED.OBJLIB DD DSN=ACP.OBJ.RELxx,DISP=SHR
    //PLKED.DSD DD DISP=SHR,DSN=ACP.IMPORTS.RELxx
    //PLKED.SYSIN DD *
     INCLUDE OBJLIB(CSTRTD40)
     INCLUDE DSD(QCCC41)
     INCLUDE DSD(QDDDRX)
     ESD            @@LM0001
     TXT            QZZ1A 41
     END                            1569623400 010195215
     INCLUDE OBJLIB(QZZ1A41)
     ESD            @@LM0002
     TXT            QZZ1B 41
     END                            1569623400 010195215
     INCLUDE OBJLIB(QZZ1B41)
     ESD            @@LM0003
     TXT            END_OF_LAST_OBJ
     END                            1569623400 010195215
    /*
//LKED.SYSLMOD DD DISP=OLD,DSN=ACP.LK.RELxx(QZZ1RX) //

See the programming guide for the IBM C/C++ compiler used by your installation for more information about DLLs and definition side-decks. SeeTPF System Generation for more information about the ACP.IMPORTS.RELvv definition side-deck data set.

QUESTION: In summary, what is the best benefit of C++?

ANSWER: Being able to say "OOPS!" when you make a programming mistake.