 |
HP OpenVMS Linker Utility Manual
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.
- To keep the examples simple, the template
definitions are included in the sources, usually templates are defined
in include files.
- 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.
- 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".
- 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>".
- 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.
- 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.
- 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.
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.
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.
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:
- Access
Using section attributes, compilers can
prohibit some types of access, such as write access. Using other
section attributes, compilers can allow access to the section by more
than one process.
- Positioning
By specifying certain section
attributes, compilers can specify to the linker how it should position
the section in memory.
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.
|
|