HP OpenVMS Linker Utility Manual


Previous Contents Index

2.6.2 HP C++ Examples

The following HP C++ examples demonstrate how symbols are resolved when you link with compiler-generated UNIX-style weak and group symbols.

The examples apply a user-written function template called myswap . Note that you can also use class templates, which are implemented in a similar manner. If you are an experienced C++ programmer, you will also recognize that there is a "swap" function in the HP C++ standard library, which you should use instead of writing your own function.

In the examples, the compiler combines code sections (and other required data) into a group, giving it a unique group name derived from the template instantiation.

The linker includes the first occurrence of this group in the image. All UNIX-style weak definitions obtained from that group are now defined by the module providing this group. All subsequent groups with the same name do not contribute code or data; that is, the linker ignores all subsequent sections. The UNIX-style weak definitions from these ignored sections become references, which are resolved by the definition from the designated instance (that is, first-encountered instance) of the group. In this manner, code (and data) from templates are included only once for the image.

Example 2-3 shows UNIX-Style weak symbols and group symbols.

Example 2-3 UNIX-Style Weak and Group Symbols

 
//  file: my_asc.cxx 
 
template <typename T> (1)
void myswap (T &v1, T &v2) { (2)
        T tmp; 
        tmp = v1; 
        v1 = v2; 
        v2 = tmp; 
} 
 
void ascending (int &v1, int &v2) { 
        if (v2<v1) 
                myswap (v1,v2); (3)
} 
 
 
//  file: my_desc.cxx 
 
template <typename T> (1)
void myswap (T &v1, T &v2) { (2)
        T tmp; 
        tmp = v1; 
        v1 = v2; 
        v2 = tmp; 
} 
 
 
void descending (int &v1, int &v2) { 
        if (v1<v2) 
                myswap (v1,v2); (3)
} 
 
 
//  file: my_main.cxx 
 
#include <cstdlib> 
#include <iostream> 
 
using namespace std; 
 
static int m = 47; 
static int n = 11; 
template <typename T> void myswap (T &v1, T &v2); 
 
extern void ascending (int &v1, int &v2); 
extern void descending (int &v1, int &v2); 
 
int main (void) { 
        cout << "original: " << m << " " << n << endl; 
        myswap (m,n); (4)
        cout << "swapped: " << m << " " << n << endl; 
        ascending (m,n); 
        cout << "ascending: " << m << " " << n << endl; 
        descending (m,n); 
        cout << "descending: " << m << " " << n << endl; 
        return EXIT_SUCCESS; 
} 
 

Example 2-4 shows the compile and link commands.

Example 2-4 Compile and Link Commands

$ CXX/OPTIMIZE=NOINLINE/STANDARD=STRICT_ANSI MY_MAIN  (5)
$ CXX/OPTIMIZE=NOINLINE/STANDARD=STRICT_ANSI MY_ASC  (6)
$ CXX/OPTIMIZE=NOINLINE/STANDARD=STRICT_ANSI MY_DESC  (6)
$ CXXLINK MY_MAIN, MY_ASC, MY_DESC (7)

In the examples, the compiler combines code sections (and other required data) into a group, giving it a unique group name derived from the template instantiation.

The linker includes the first occurrence of this group in the image. All UNIX-style weak definitions obtained from that group are now defined by the module providing this group. All subsequent groups with the same name do not contribute code or data; that is, the subsequent sections are ignored. The UNIX-style weak definitions from these ignored sections become references, which are resolved by the definition from the designated instance (first-encountered) of the group. In this manner, code (and data) from templates are included only once for the image.

  1. To keep the examples simple, the template definitions are included in the sources, usually templates are defined in include files.
  2. C++ mangles symbol names to guarantee unique names for overloaded functions. Therefore, in the linker map or in the output from ANALYZE/OBJECT utility, the string MYSWAP may be part of a longer symbol name and may not be easily identified. Further, the compiler creates more names using the string MYSWAP: the unique group name, code section names, and so on.
  3. The functions "ascending" and "descending" sort a pair of numbers. If necessary the contents are swapped. Swapping is implemented as a function template, which is automatically instantiated with the call inside of the functions "ascending" and "descending".
  4. In the main function, "myswap" is used to demonstrate a strong reference to a UNIX-style weak definition. (As previously mentioned, this is not common practice. Usually, templates are defined in include files and included in all sources.) Note that there is only a reference to the function and that there is no definition. That is, the compiler does not create a group. When compiling the main module, a reference to "myswap<int>" is automatically generated for the call to myswap inside the main function. This strong reference will be resolved by the first UNIX-style weak definition from either MY_ASC.OBJ or MY_DESC.OBJ which define "myswap<int>".
  5. To see the effects of this example, the compiler should not inline code. Because inlining is an optimization, this feature is demonstrated only by omitting optimization.
  6. When both source modules are compiled, both object modules contain the definition of the "myswap<int>" function. The compiler groups the code (and other required data) sections into a group with a unique group name derived from the template instantiation. The compiler generates UNIX-style weak symbols and adds them to the group.
  7. For linking, the CXXLINK command is used in the examples. This command invokes the C++ linker driver, which in turn calls the OpenVMS linker to perform the actual link operation

2.6.3 Compiler-Generated Symbols and Shareable Images

To create a VMS shareable image, you must define the interface in a symbol vector at link time with a SYMBOL_VECTOR option. HP C++ generated objects contain mangled symbols and may contain compiler-generated data, which belongs to a public interface. In the SYMBOL_VECTOR option, the interface is describe with the names from the object modules. Because they contain mangled names, such a relationship may not be obvious from the source code and the symbols as seen in an object module.

If you do not export all parts of an interface, code that is intended to update one data cell may be duplicated in the executable and the shareable image along with the data cell. That is, data can become inconsistent at run-time, producing a severe error condition. This error condition can not be detected at link time nor at image activation time. Conversely, if you export all symbols from an object module, you may export the same symbol which is already public from other shareable images.

A conflict arises when an application is linked with two shareable images that export the same symbol name. In this case, the linker flags the multiple definitions with a MULDEF warning that should not be ignored. This type of error most often results when using templates defined in the C++ standard library but instantiated by the user with common data types. Therefore, HP recommends that you only create a shareable image when you know exactly what belongs to the public interface. In all other cases, use object libraries and let applications link against these libraries.

The HP C++ run-time library contains pre-instantiated templates. The public interfaces for these are known and therefore, the HP C++ run-time library ships as a shareable image. The universal symbols from the HP C++ run-time library and the group symbols take precedence over user instantiated templates with the same data types. As with other shareable images, this design is upwardly compatible and does not require you to recompile or relink to make use of the improved HP C++ run-time library.

2.7 Understanding and Fixing DIFTYPE and RELODIFTYPE Linker Conditions

On OpenVMS I64 systems, if a module defines a variable as data (OBJECT), it must be referenced as data by all other modules. If a module defines a variable as a procedure (FUNC), it must be referenced as a procedure by all other modules.

When data is referenced as a procedure, the linker displays the following informational message:


%ILINK-I-DIFTYPE, symbol symbol-name of type OBJECT cannot be 
referenced as type FUNC 

When a procedure is referenced as data, the following informational message is displayed:


%ILINK-I-DIFTYPE, symbol symbol-name of type FUNC cannot be 
referenced as type OBJECT 

Type checking is performed by the linker on OpenVMS I64 because the linker must create function descriptors. The equivalent procedure descriptor was created by the compiler on OpenVMS Alpha, so this informational message is new for the linker on OpenVMS I64.

This message is informational only and does not require user action. However, if the linker detects data referenced as a procedure, it might issue the following warning message in addition to the DIFTYPE message:


%ILINK-W-RELODIFTYPE, relocation requests the linker to build a 
function descriptor for a non-function type of symbol 

The following example of two modules demonstrates how to fix these conditions:


TYPE1.C 
 
#include <stdio> 
 
int status ;   // Defines status as data. 
extern int sub(); 
 
main () 
{ 
     printf ("Hello World\n"); 
     sub(); 
} 
 
TYPE2.C 
 
 extern int status (int x) ;  // Refers to status as a procedure. 
 
 sub () 
               { 
 int x; 
     x = (int)status; 
     return status (x); 
 } 

When these modules are linked, you get an informational message and a warning message, as follows:


$ CC/EXTERN_MODEL=STRICT_REFDEF TYPE1 
$ CC/EXTERN_MODEL=STRICT_REFDEF TYPE2 
$ LINK TYPE1,TYPE2 
%ILINK-I-DIFTYPE, symbol STATUS of type OBJECT cannot be referenced as 
type FUNC 
       module: TYPE2 
       file: NODE1$:[SMITH]TYPE2.OBJ;6 
%ILINK-W-RELODIFTYPE, relocation requests the linker to build a 
function descriptor for a non-function type of symbol 
        symbol: STATUS 
        relocation section: .rela$CODE$ (section header entry: 18) 
        relocation type: RELA$K_R_IA_64_LTOFF_FPTR22 
        relocation entry: 0 
        module: TYPE2 
        file: NODE1$:[SMITH]TYPE2.OBJ;6 

To correct the problem and avoid the informational and warning messages, correct TYPE1.C to define status as a procedure:


TYPE1.C 
 
#include <stdio> 
 
int status (int x);  // Defines status as a procedure. 
extern int sub(); 
 
main () 
{ 
    printf ("Hello World\n"); 
    sub(); 
} 
 
nt status (int x) { 
   return 1; 
} 
 
$ CC/EXTERN_MODEL=STRICT_REFDEF TYPE1 
$ CC/EXTERN_MODEL=STRICT_REFDEF TYPE2 
$ LINK TYPE1,TYPE2 


Chapter 3
Understanding Image File Creation (I64)

This chapter describes how the linker creates an image on OpenVMS I64 systems. The linker creates images from the input files you specify in a link operaton. You can control image file creation by using linker qualifiers and options.

3.1 Overview

After the linker has resolved all symbolic references between the input files specified in the LINK command (described in Chapter 2), the linker knows all the object modules and shareable images that are required to create the image. For example, the linker has extracted from libraries specified in the LINK command those modules that contain the definitions of symbols required to resolve symbolic references in other modules. The linker must now combine all these modules into an image.

To create an image, the linker must perform the following processing:

After creating segments and filling them with binary code and data, the linker writes the image to an image file. Section 3.4.2 describes this process.

3.2 Creating Sections

Language processors create sections and define their attributes. The number of sections created by a language processor and the attributes of these sections are dependent upon language semantics. For example, some programming languages implement global variables as separate sections with a particular set of attributes. Programmers working in high-level languages typically have little direct control over the sections created by the language processor. Medium- and low-level languages provide programmers with more control over section creation. For more information about the section creation features of a particular programming language, see the language processor documentation.

The I64 linker also creates sections that are combined with the compiler sections to create segments (see Section 3.2.1).

Section Attributes

The language processors define the attributes of the sections they create and communicate these attributes to the linker in the section header table.

Section attributes define various characteristics of the area of memory described by the section, such as the following:

Section attributes are Boolean values, that is, they are either on or off. Table 3-2 lists all section attributes with the keyword you can use to set or clear the attribute, using the PSECT_ATTR= option. (For more information about using the PSECT_ATTR= option, see Section 3.3.7.)

For example, to specify that a section should have write access, specify the writability attribute as WRT. To turn off an attribute, specify the negative keyword. Some attributes have separate keywords that express the negation of the attribute. For example, to turn off the global attribute (GBL), you must specify the local attribute (LCL). Note that the alignment of a section is not strictly considered an attribute of the section. However, because you can set it using the PSECT_ATTR= option, it is included in the table.

To be compatible with Alpha and VAX linkers, the I64 linker retains the user interfaces as much as possible. This information includes the traditional OpenVMS section attribute names (WRT, EXE, and so on) that are used in the PSECT_ATTR= option. However, on I64, the underlying object conforms to the ELF standard. When processing the object module, the linker maps the ELF terms to the OpenVMS terms. For compatibility, only OpenVMS terms are written to the map file. In contrast, other tools, such as the ANALYZE/OBJECT utility, do not use OpenVMS terms; they simply format the contents of the object file and therefore display the ELF terms.

Table 3-1 maps the traditional OpenVMS section attribute names to the ELF names and vice versa.

Table 3-1 Mapping ELF Section Terms to OpenVMS Attributes
ELF Section Attribute1 Traditional OpenVMS
Section Attribute
SHF_WRITE WRT
SHF_EXECINSTR EXE
SHF_VMS_GLOBAL GBL
SHF_VMS_OVERLAID OVR
-- 2 REL
SHF_VMS_SHARED SHR
SHF_VMS_VECTOR VEC
SHF_VMS_ALLOC_64BIT ALLOC_64BIT
SHF_IA_64_SHORT SHORT 3
SHT_NOBITS 4 NOMOD 5


1These ELF section attributes are prefixed with SHDR$V_
2All ELF sections are relative (REL). There is only a conceptual absolute section: the reserved section number SHDR$K_SHN_ABS. Absolute symbols are defined by that mechanism.
3This is a section attribute in I64, with a new OpenVMS attribute name
4This is an ELF section type (prefixed with SHDR$K_), mapped to an OpenVMS section attribute
5SHT_NOBITS/NOMOD is only set by compilers; it reflects uninitialized data.

Table 3-2 lists all section attributes with the keyword you can use to set or clear the attribute, using the PSECT_ATTR= option.

Table 3-2 Section Attributes on I64
Attribute Keyword Description
Alignment -- Specifies the alignment of the section as an integer that represents the power of 2 required to generate the desired alignment. For certain alignments, the linker supports keywords to express the alignment. The following table lists all the alignments supported by the linker with their keywords:
Power of 2 Keyword Meaning
0 BYTE Alignment on byte boundaries.
1 WORD Alignment on word boundaries.
2 LONG Alignment on longword boundaries.
3 QUAD Alignment on quadword (8-byte) boundaries.
4 OCTA Alignment on octaword (16-byte) boundaries.
5 HEXA Alignment on hexadecimal word (32-byte) boundaries.
6 -- Alignment on 64-byte boundaries.
7 -- Alignment on 128-byte boundaries.
8 -- Alignment on 256-byte boundaries.
9 -- Alignment on 512-byte boundaries.
13 -- Alignment on 8 KB boundaries.
14 -- Alignment on 16 KB boundaries.
15 -- Alignment on 32 KB boundaries.
16 -- Alignment on 64 KB boundaries.
-- PAGE Alignment on the default target page size, which is 64 KB for I64 linking. You can override this default by specifying the /BPAGE qualifier.
Position Independence PIC/NOPIC This keyword is ignored by the I64 linker.
Overlaid/Concatenated OVR/CON When set to OVR, specifies that the linker will overlay this section with other sections with the same name and attribute settings. Sections that are overlaid are assigned the same base address. When set to CON, the linker concatenates the sections.
Relocatable/Absolute REL/ABS When set to REL, specifies that the linker can place the section anywhere in virtual memory. Absolute sections are used by compilers primarily to define constants, but in the ELF object language they are not put into an actual section. Setting the section to ABS on I64 is not meaningful, and the ABS keyword is ignored by the I64 linker.
Global/Local GBL/LCL When set to GBL, specifies that the linker should gather contributions to the section from all clusters and place them in the same segment. When set to LCL, the linker gathers sections into the same segment only if they are in the same cluster. The memory for a global section is allocated in the cluster that contains the first contributing module.
Shareability SHR/NOSHR Specifies that the section can be shared between several processes. Only used to sort sections in shareable images.
Executability EXE/NOEXE Specifies that the section contains executable code.
Writability WRT/NOWRT Specifies that the contents of a section can be modified at run time.
Protected Vectors VEC/NOVEC Specifies that the section contains privileged change-mode vectors or message vectors. In shareable images, segments with the VEC attribute are automatically protected.
Solitary SOLITARY Specifies that the linker should place this section in its own segment. Useful for programs that map data into specific locations in their virtual memory space. Note that compilers do not set this attribute. You can set this attribute using the PSECT_ATTR= option.
Unmodified NOMOD/MOD When set, specifies that the section has not been initialized (NOMOD). The I64 linker uses this attribute to create demand zero segments; see Section 3.4.4. Only compilers can set this attribute (in ELF objects, the section type SHT_NOBITS). You can clear this attribute only by specifying the MOD keyword in the PSECT_ATTR= option.
Readability RD This keyword is ignored by the I64 linker.
User/Library USR/LIB This keyword is ignored by the I64 linker.
Short Data SHORT When set this indicates that a data section should be put in one of the short sections. Compilers can set this attribute, in which case the user can not alter it.
Allocate section in P2 space ALLOC_64BIT/NOALLOC_64BIT When set this indicates that the section should be allocated in P2 space instead of P0 space. The program may run but not execute correctly when initialized data is put in P2 space. Code and demand zero data do work properly.


Previous Next Contents Index