Previous | Contents | Index |
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.
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 |
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:
Figure 3-1 Communication of Image Memory Requirements on I64 Systems
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).
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.
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 |
Table 3-2 lists all section attributes with the keyword you can use to set or clear the attribute, using the PSECT_ATTR= option.
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:
|
||||||||||||||||||||||||||||||||||||||||||||||||
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 |