The purpose of relocation is to identify and update storage locations that need to be adjusted when an executable image is created from input object files at link time. Relocation information enables the linker to patch addresses where necessary by providing the location of those addresses and indicating the type of adjustments to be performed. Relocation entries in the section relocation information are created by the assembler, compiler, or other object producer, and the address adjustments are performed by the linker.
The linker performs relocation fixups after determining the linked object's memory layout and selecting starting addresses for its segments. During partial links, relocation information is updated and preserved for subsequent links. Relocation updates for partial links include converting external relocation entries to local relocation entries and retargeting relocation entries to new section addresses. See Section 4.3.2.1 for details.
Relocation information contained in an object file can have four distinct representations:
Relocation entries identified in section headers. These are the relocation entries referred to in this document as "normal" or "actual".
Compact relocation records, produced by the linker and consumed
by
om
,
spike
, and profiling tools.
Compact relocations are stored
in the
.comment
section.
Linkerdef entries which are produced by the linker to identify
all uses of linker-defined
symbols.
Linkerdef entries are stored in the
.comment
section.
Version Note Linkerdef entries are supported in Tru64 UNIX V5.1 and greater for object format V3.13 and greater.
Dynamic relocations, which are present only in shared objects. Dynamic relocation may be performed for shared objects at load time.
The first three forms of relocation information are discussed in this chapter. Compact relocations are discussed in Section 4.4 and linkerdef relocations are covered in Section 4.5. The fourth form is covered in Chapter 6. Figure 4-1 summarizes which kinds of objects contain which kinds of relocation information.
Figure 4-1: Kinds of Relocations
Actual relocation entries are organized by raw data section. Not all object file sections necessarily have relocation entries associated with them. For example, bss sections do not have relocation entries because they do not have raw data to relocate. Section headers for sections with relocation entries contain pointers to the appropriate section relocation information, as shown in Figure 4-2.
Figure 4-2: Section Relocation Information in an Object File
Note that the ordering of section headers does not necessarily correspond
to the ordering of raw data and section relocation information.
Consumers
should rely on the section header to
access this information.
4.1 New or Changed Relocations Features
Tru64 UNIX V5.1 introduces the following new or changed features:
Full compact relocations. See Section 4.4.
Linkerdef relocations. See Section 4.5.
4.2 Structures, Fields, and Values for Relocations
4.2.1 Relocation Entry (
reloc.h
)
struct reloc { coff_addr r_vaddr; coff_uint r_symndx; coff_uint r_type : 8; coff_uint r_extern: 1; coff_uint r_offset:6; coff_uint r_reserved:11; coff_uint r_size:6; };
SIZE - 16 bytes, ALIGNMENT - 8 bytes
Relocation Entry Fields
r_vaddr
Virtual address of an item to be relocated.
If the
s_nreloc
field in the section header overflows, this field contains
the number of relocation entries for the section.
This possibility applies
only to the first entry in a section's relocation information.
See
Section 4.2.4
for more information.
r_symndx
For an external
relocation
entry,
r_symndx
is an index into external
symbols.
For a local relocation entry,
r_symndx
is the number of the section containing the symbol.
Table 4-1
lists the section numbering.
For entries of type
R_LITUSE
,
this field contains a subtype.
See
Table 4-3.
r_type
Relocation type code. Table 4-2 lists all possible values.
r_extern
Set to 1 for an external relocation entry. Set to 0 for a local relocation entry.
r_offset
For an entry
of type
R_OP_STORE
,
r_offset
is the bit offset of a field within a quadword.
For
other
relocation types, the field is unused and must be zero.
r_reserved
Must be zero.
r_size
For an entry
of type
R_OP_STORE
,
r_size
is the bit size of a field.
For
R_IMMED_*
entries, it is a subtype.
See
Table 4-4.
For other relocation types, the field is unused and must be zero.
Table 4-1: Section Numbers for Local Relocation Entries
Symbol | Value | Description |
R_SN_NULL |
0 | no section |
R_SN_TEXT |
1 | .text
section |
R_SN_RDATA |
2 | .rdata
section |
R_SN_DATA |
3 | .data
section |
R_SN_SDATA |
4 | .sdata
section |
R_SN_SBSS |
5 | .sbss
section |
R_SN_BSS |
6 | .bss
section |
R_SN_INIT |
7 | .init
section |
R_SN_LIT8 |
8 | .lit8
section |
R_SN_LIT4 |
9 | .lit4
section |
R_SN_XDATA |
10 | .xdata
section |
R_SN_PDATA |
11 | .pdata
section |
R_SN_FINI |
12 | .fini
section |
R_SN_LITA |
13 | .lita
section |
R_SN_ABS |
14 | for
R_OP_ xxxx
constants |
R_SN_RCONST |
15 | .rconst
section |
R_SN_TLSDATA |
16 | .tlsdata
section |
R_SN_TLSBSS |
17 | .tlsbss
section |
R_SN_TLSINIT |
18 | .tlsinit section |
R_SN_RESTEXT |
19 | (not supported)
.restext
section |
R_SN_GOT |
20 | (V5.1 - ).got
section |
Version Note The
R_SN_RESTEXT
value is reserved for Tandem big-endian systems. It is not used on Tru64 UNIX.
Symbol | Value | Description |
R_ABS |
0x0 | Relocation already performed |
R_REFLONG |
0x1 | A 32-bit reference to symbol's virtual address |
R_REFQUAD |
0x2 | A 64-bit reference to symbol's virtual address |
R_GPREL32 |
0x3 | A 32-bit displacement from the global pointer to a symbol's virtual address |
R_LITERAL |
0x4 | A reference to a literal in the literal address pool as an offset from the global pointer |
R_LITUSE 1 |
0x5 | An instance of a literal address previously loaded into a register |
R_GPDISP |
0x6 | An
lda/ldah
instruction pair that
is used to initialize a procedure's global-pointer register |
R_BRADDR |
0x7 | A 21-bit branch reference to the symbol's virtual address |
R_HINT |
0x8 | A 14-bit
jsr
hint reference to symbol's
virtual address |
R_SREL16 |
0x9 | A 16-bit self-relative reference to symbol's virtual address |
R_SREL32 |
0xa | A 32-bit self-relative reference to symbol's virtual address |
R_SREL64 |
0xb | A 64-bit self-relative reference to symbol's virtual address |
R_OP_PUSH |
0xc | A 64-bit virtual address to push on the relocation expression stack |
R_OP_STORE |
0xd | An address to store the value popped from the relocation expression stack |
R_OP_PSUB |
0xe | A symbol's virtual address to subtract from value at the top of the relocation expression stack |
R_OP_PRSHIFT |
0xf | The number of bit positions to shift the value at the top of the relocation expression stack |
R_GPVALUE |
0x10 | A new GP value to be used for the address range starting
with the address specified by the
r_vaddr
field |
R_GPRELHIGH |
0x11 | The most significant 16 bits of a 32-bit from the global pointer to a symbol's virtual address |
R_GPRELLOW |
0x12 | The least significant 16 bits of a 32-bit from the global pointer to a symbol's virtual address |
R_IMMED 2 |
0x13 | An instruction sequence that calculates an address |
R_TLS_LITERAL |
0x14 | The instruction that loads the TLS key |
R_TLS_HIGH |
0x15 | The most significant 16 bits of a 32-bit from the TLS region pointer to a symbol's virtual address |
R_TLS_LOW |
0x16 | The least significant 16 bits of a 32-bit from the TLS region pointer to a symbol's virtual address |
Table Notes
The
r_symndx
field for the relocation
type
R_LITUSE
is a subtype.
The valid entries for
this field and their meanings are summarized in
Table 4-3.
The
r_size
field for the relocation
type
R_IMMED
is a subtype.
The valid entries for this field
and their meanings are summarized in
Table 4-4.
Table 4-3: Literal Usage Types
Symbol | Value | Description |
R_LU_BASE |
1 | The base register of a memory format instruction (except
ldah ) contains a literal address |
R_LU_BYTOFF |
2 | Should not be used |
R_LU_JSR |
3 | The target register of a
jsr
instruction
contains a literal address |
Table 4-4: Immediate Relocation Types
Symbol | Value | Description |
R_IMMED_GP_16 |
1 | 16-bit displacement from GP value |
R_IMMED_GP_HI32 |
2 | Most significant 16 bits of 32-bit displacement from GP value |
R_IMMED_SCN_HI32 |
3 | Most significant 16 bits of 32-bit displacement from section start |
R_IMMED_BR_HI32 |
4 | Most significant 16 bits of 32-bit displacement from instruction following branch |
R_IMMED_LO32 |
5 | Least significant 16 bits of 32-bit displacement specified
by last
R_IMMED_*_HI32 |
4.2.2 Compact Relocation Records)
Compact relocation records are written into the free-form data area
of the comment section.
They
are identified by a tag type of
CM_COMPACT_RLC
in the comment header.
The public versions of
compact relocation interfaces for
producers and consumers are located in the header file
cmplrs/cmrlc.h
.
See
Section 4.4
and
Chapter 7
for
more information.
4.2.3 Linkerdef Relocation Records (
scncomment.h
)
Linkerdef relocation records are written into the free-form data area
of the comment section.
They
are identified by a tag type of
CM_LINKDERDEF
in the comment header.
The Linkerdef
comment subsection is an array of
linker_data
structures
that contain information similar to the
reloc
structure.
See
Section 4.5
and
Chapter 7
for more information.
Version Note The
linker_data
structure is supported on Tru64 UNIX V5.1 and greater.
struct linker_data { unsigned int ld_scnptr; unsigned int ld_base : 6; unsigned int ld_symbol : 6; unsigned int ld_type : 8; unsigned int ld_size : 6; unsigned int ld_offset : 6; };
SIZE - 8 bytes, ALIGNMENT - 4 bytes
Linkerdef Relocation Entry Fields
ld_scnptr
A byte offset
relative to the starting file offset of the section identified by
ld_base
.
Together, these fields identify the target address
for the relocation.
ld_base
The number of the section containing the target address. See Table 4-1 for a list of valid section numbers.
ld_symbol
An enumeration value identifying a linker-defined symbol. See Section 4.2.3.1 for a list of valid values.
ld_type
A relocation type. See Table 4-2 for a list of relocation types.
ld_size
The size of
a bitfield for the
R_OP_STORE
relocation.
ld_offset
The bit offset
of a bitfield for the
R_OP_STORE
relocation.
4.2.3.1 Linkerdef Symbol Enumeration
Linker-defined symbols are identified by the following enumeration.
Each enumeration value
corresponds to the linker-defined symbol of the same name (excluding the
"LDEF_"
prefix).
Version Note The
LD_SYMBOL
enumeration is supported on Tru64 UNIX V5.1 and greater.
enum LD_SYMBOL { LDEF__BASE_ADDRESS = 0, LDEF__cobol_main = 1, LDEF__DYNAMIC = 2, LDEF__DYNAMIC_LINK = 3, LDEF__ebss = 4, LDEF__edata = 5, LDEF_edata = 6, LDEF__end = 7, LDEF_end = 8, LDEF__etext = 9, LDEF_etext = 10, LDEF__fbss = 11, LDEF__fdata = 12, LDEF__fpdata = 13, LDEF__fpdata_size = 14, LDEF___fstart = 15, LDEF__ftext = 16, LDEF__ftlsinit = 17, LDEF_GOT_OFFSET = 18, LDEF__gp = 19, LDEF__gpinfo = 20, LDEF___istart = 21, LDEF__procedure_string_table = 22, LDEF__procedure_table = 23, LDEF__procedure_table_size = 24, LDEF___tlsbsize = 25, LDEF___tlsdsize = 26, LDEF___tlskey = 27, LDEF___tlsoffset = 28, LDEF___tlsregions = 29, LDEF_MAX };
The section header contains
a file pointer to the section's relocation information and the number of entries.
(See
Section 2.2.3
for the declaration.) The number of relocation
entries for a section is contained in the section header field
s_nreloc
.
If that field overflows, the section header flag
S_NRELOCS_OVFL
is set and the first relocation
entry's
r_vaddr
field stores the actual number
of relocation entries for the section.
That relocation entry has a type of
R_ABS
and all other fields are zero, causing
it to be ignored during relocation.
4.3 Relocations Usage
4.3.1 Relocatable Objects
An object is relocatable if it contains enough relocation information for the linker to successfully relocate it. Relocatable objects can be produced by compiling without linking or by partial linking.
Compilers
and assemblers always produce relocatable objects.
By default,
the relocatable object files produced are passed
to the linker to produce a non-relocatable executable object.
Most compilers
recognize a
-c
option.
The
-c
option suppresses
the link operation
and
writes the object file in its relocatable form.
For example, the following
command produces a non-executable
OMAGIC
file named
pgm.o
.
$ cc -c pgm.c
By means of partial linking, the linker can also produce a relocatable
object.
By default, the linker attempts to produce an executable
ZMAGIC
file for which all relocation entries have been processed and removed.
To
preserve relocation information, the linker's
-r
switch should
be selected.
For example, the following command produces a non-executable
OMAGIC
file named
a.out
.
$ ld -r pgm.o
Selection of the -r switch has other effects: common storage class symbol allocation is deferred until final link and undefined symbol error messages are suppressed.
Relocatable objects have various uses.
The most obvious is as input
to a subsequent partial or final link operation.
All objects input to the
linker are relocatable objects, regardless of how they are produced.
Multiple
relocatable objects can be combined during a final link to produce an executable
object.
The typical example of this process is when several separately compiled
modules are created at different times and later linked together to produce
the final executable program.
For example, the following steps produce an
executable
ZMAGIC
file named
a.out
.
$cc -c part1.c
$cc -c part2.c
$cc -c part3.c
$cc part1.o part2.o part3.o
Relocatable objects are also used for archives.
Although files of any
type may be archived, one important use of archives is for user or system
libraries.
An example is the system library
libc.a
, which
is linked with many C programs.
Objects in archive libraries must be relocatable
to be linked with other object files to make executable programs.
Relocatable objects may be used as loadable device drivers, which are object files that are dynamically added to a running kernel. See Reference Pages, Section 9r, Device Drivers (Volume 1) and Reference Pages, Section 9s, 9u, and 9v, Device Drivers (Volume 2) for more information.
Relocatable objects can also be used by the bootlinker, which builds the kernel from object files at boot time. Information is available in the System Administration guide.
Some profiling tools
require relocatable objects as input because they rebuild the object and require
the capability of rearranging raw data.
However,
on Tru64 UNIX, these tools rely on compact
relocations, which are an alternate form of relocation information.
Compact
relocations are described in
Section 4.4.
4.3.2 Relocation Processing
This section describes the generic process of relocating object files from a high-level viewpoint. It does not include details of address calculations, nor does it take into account the substantial variations in the contents of a relocation entry's fields. For specifics, see Section 4.3.4.
Relocation involves tracking and updating references as the referenced
items move in memory.
At a minimum, one relocation entry is required for each
reference made to an item whose address may potentially change.
This address,
pointed to by the
reloc
structure field
r_vaddr
, is the target address of the relocation.
This address
is adjusted when relocation records are preserved at link time.
The target
address is located in one of the
raw data sections of the object file.
The target address points to another item in the raw data. This item can be a data item, procedure, or any program element that will potentially be mapped to a new memory location when the linker builds the executable object.
Note that a many-to-one relationship may exist between relocation entries and target items. A target item may be addressed multiple times in an object file's raw data, and a single target address reference may be described by multiple relocation entries.
Taken together, the
r_symndx
field and
r_extern
bit track the position of the target item.
If it is
moved to a new location, the target address is updated accordingly.
The value of the relocation is the distance that the tracked item will
move in memory.
4.3.2.1 Local and External Entries
Relocation entries are used for several purposes:
Address references to unresolved symbols that will be imported from other objects.
References to addresses within an object that may change when the object is linked at a different base address or linked with other object files.
Identification of address references that may be optimized at link time.
Relocation entries may be local or external. Local relocation entries are used for references to addresses within an object. External relocation entries are used for references to any external symbols. In particular, unresolved symbol references can only be represented by external relocation entries.
The
r_extern
flag is set in external relocation
entries.
This flag determines the interpretation of the
r_symndx
field.
For external entries, this field provides the external
symbol table index of the referenced symbol.
Figure 4-4 shows a sample external relocation entry.
Figure 4-4: External Relocation Entry
For an external entry, the value for relocation is the run-time address of the referenced external symbol. In cases where the symbol is undefined in an input object, it must first be resolved. Figure 4-5 depicts this process.
Figure 4-5: Processing an External Relocation Entry
A local
relocation entry has its
r_extern
flag cleared
and tracks references by section.
Figure 4-6 shows a sample local entry.
Figure 4-6: Local Relocation Entry
For a local entry, the value for relocation is the difference between
a section's address in the input object and the address of that section's
data after
linking.
The section is identified by a relocation section type in
r_symndx
.
Figure 4-7
depicts this situation.
Figure 4-7: Processing a Local Relocation Entry
To complete relocation for all entries, the base address for the final
process
image is required.
The linker can then use that address to patch all relocatable
entries.
4.3.2.2 Relocation Entry Ordering
The ordering of relocation entries is sometimes significant. The diagram below shows the optional relocation entry count and grouping of relocation entries according to GP range.
Figure 4-8: Relocation Entry Ordering Requirements
If a section requires an optional relocation entry overflow count, it must be in the first relocation entry.
Relocation processing tools require GP-relative relocations to be grouped
by GP range.
R_GPVALUE
entries will
effectively separate the groups of GP-relative relocation entries for each
GP range.
For a list of GP-relative relocation types, see
Section 4.3.3.2.
Some relocation types can only be used when paired with other relocation types. These relocation groupings are:
R_GPRELHIGH
,
R_GPRELLOW
R_TLSHIGH
,
R_TLSLOW
R_LITERAL
,
R_LITUSE
R_OP_PUSH
,
R_OP_PSUB
,
R_OP_PRSHIFT
,
R_OP_STORE
An
R_GPRELHIGH
entry must
be followed by one or more
R_GPRELLOW
entries.
An
R_TLSHIGH
entry must be followed by one or more
R_TLSLOW
entries.
An
R_LITERAL
entry may be
followed by zero or more
R_LITUSE
entries.
An
R_OP_PUSH
entry must be
followed by exactly one
R_OP_STORE
entry.
Zero or more
R_OP_PSUB
and
R_OP_PRSHIFT
entries may be located between
the
R_OP_PUSH
and
R_OP_STORE
entries.
4.3.2.3 Shared Object Transformation
Part of the linker's preparation of loading information for shared objects is to create dynamic relocation entries from some of the actual relocation entries.
The linker must determine
which relocation entries need to be converted to dynamic relocation entries.
Data references (
R_REFQUAD
and
R_REFLONG
relocation types) must be represented
in the
.rel.dyn
section if they are not in the
.lita
section.
The
.lita
section is an exception because its contents are mapped directly
into the GOT.
All other
R_REFQUAD
or
R_REFLONG
entries have an associated
dynamic relocation entry in the
shared object file.
Dynamic relocation entries are not permitted for text addresses.
The
text segment is not mapped with
write permission, so text relocation fixups
cannot be performed by the dynamic loader.
4.3.3 Kinds of Relocations
Relocations types can be grouped into the following categories:
Direct Relocations
GP-relative Relocations
Self-relative Relocations
Literal Relocations
Relocations Stack Expressions
Immediate Relocations
The categories often overlap.
4.3.3.1 Direct Relocations
Direct relocations are independent entries; all of the information necessary
to process them is self-contained.
The relocation target contains either the
address of a relocatable symbol or an offset from that address.
They are used
for simple address adjustments; addresses in the literal address pool (.lita
section),
for example, will have associated direct relocation entries.
R_REFQUAD
and
R_REFLONG
are direct relocation types.
R_REFQUAD
indicates a 64-bit address and thus
is normally used on Alpha systems.
R_REFLONG
indicates a 32-bit address and most often occurs when the xtaso
environment is in effect.
These types of relocations are processed in the
manner described in
Section 4.3.2.
The following special requirements exist for direct relocation entries
for the
.lita
section:
Only entries of type
R_REFQUAD
or
R_REFLONG
are permitted.
R_REFLONG
entries
pertain to the bottom 4 bytes of a
.lita
entry.
The size
of the entry is unchanged, but an error is generated if the result overflows
4 bytes.
All external entries must correspond to symbols whose value is zero prior to relocation.
4.3.3.2 GP-Relative Relocations
This class of relocations requires use of the GP value as a factor in the calculation. Note that the literal relocations in Section 4.3.3.4 and Section 4.3.3.7 also fit this category.
The
R_GPREL32
,
R_GPRELHIGH
,
R_GPRELLOW
, and
R_GPDISP
relocation
types
are GP-relative.
They typically point to instructions that calculate or load
addresses using a GP value.
The
R_GPRELHIGH
and
R_GPRELLOW
relocation types
must be used together.
The
R_GPDISP
relocation
type is used for instruction pairs that load the GP value.
A special-purpose GP-relative relocation entry specifies that a new
GP range is in effect.
The relocation
type for this entry is
R_GPVALUE
.
The linker inserts
R_GPVALUE
entries at object module boundaries during a partial link (ld
-r) when the
.lita
section it is building would otherwise overflow.
Entries
of this type appear in the
.text
section or the
.rdata
section.
These entries are local
entries because they are not tied to any symbol.
4.3.3.3 Self-Relative (PC-Relative) Relocations
This class of relocations require adjustments based on the current position in the text or data. Self-relative relocations are also referred to as PC-relative relocations.
The
R_SREL16
,
R_SREL32
, and
R_SREL64
relocation types apply to 16, 32, and 64 bit target
addresses, respectively.
Two more self-relative relocation types are
R_BRADDR
and
R_HINT
.
R_BRADDR
is used to identify branching instructions
whose targets are known at link time.
R_HINT
is used to adjust
the branch-prediction hint bits in jump instructions.
4.3.3.4 Literal Relocations
This category of relocations encompasses both literal relocations (type
R_LITERAL
) and literal-usage relocations (type
R_LITUSE
), which work together to describe text
references.
A literal relocation (type
R_LITERAL
) occurs on a load of an address from the
.lita
section.
Any associated
R_LITUSE
entries always directly follow the
R_LITERAL
entry.
The literal-usage entries are used for linker optimizations. Processing for these relocation entries is optional. The linker and other tools may ignore these relocation entries with no risk of producing an improperly relocated object file.
The advantage of literal-usage entries is that they enable link-time
memory-access optimizations.
These relocation entries identify instructions
which use a previously loaded literal.
With this knowledge, the linker is
able to determine that certain instructions are unnecessary or can be altered
to improve performance.
Optimization
is performed only during final link and with an optimization level setting
of at least
-O1.
4.3.3.5 Relocation Stack Expressions
Relocation stack expressions constitute a sequence of relocation entries that must be evaluated as a group. The purpose of stack expressions is to provide a way to represent complex relationships between relocatable addresses and store results with bit field granularity. They are currently used only for exception-handling sections.
An additional advantage of stack expressions is that they provide the
capability
to describe a new relocation type without requiring tool support or code modification
to recognize and execute a new
r_type
.
However,
the greater flexibility of relocations expressions is offset by the fact that
multiple entries are necessary to describe a single fix-up.
Special relocation types are used to build relocation expressions. The types are:
R_OP_PUSH
R_OP_STORE
R_OP_PSUB
R_OP_PRSHIFT
An
R_OP_PUSH
entry marks the
beginning of a sequence of relocation stack expressions and an
R_OP_STORE
marks the end.
The types of any intervening
relocation entries should be either
R_OP_PRSHIFT
to shift the top of stack value right or
R_OP_PSUB
to subtract an address from the top of stack value.
An
R_OP_STORE
entry pops the
value
from the top of the expression stack and stores selected bits into a field
in a word in memory.
The
r_offset
and
r_size
fields of a relocation entry are used to specify the
target bit field.
It is an error to cause stack underflow or to have values left on the stack when section relocation is complete.
Currently, these relocation types are used exclusively for relocating
the exception-handling data in
.xdata
and
.pdata
.
The reason this relocation is performed using the stack expression
types is the need to shift the address by two bits.
Bit field granularity
cannot be specified with other relocation types unless it is implicit in the
relocation type.
4.3.3.6 Immediate Relocations
Immediate relocations are used to describe the linker's optimization
of literal pool references.
If optimization
options are in effect, the linker will replace
R_LITERAL
and
R_LITUSE
entries with
R_IMMED
entries wherever possible.
This information
is then used to generate compact
relocations that sufficiently describe all relocatable storage
locations.
Immediate relocations can describe instruction sequences that calculate
addresses by adding either a 16-bit or 32-bit immediate displacement to a
base address.
R_IMMED
entries always point to memory-access
instructions.
The displacement is obtained from the instruction.
There are five types of immediate relocations.
Subcodes in the
r_size
field identify them.
The types are:
R_IMMED_GP_16
R_IMMED_GP_HI32
R_IMMED_SCN_HI32
R_IMMED_BR_HI32
R_IMMED_LO32
R_IMMED_GP_16
and
R_IMMED_GP_HI32
entries identify address calculations
performed by adding an offset to the global pointer.
An
R_IMMED_SCN_HI32
entry is paired with an
R_IMMED_LO32
entry to identify a pair of instructions which add
a 32 bit displacement to the starting address of a section.
An
R_IMMED_BR_HI32
entry is paired with an
R_IMMED_LO32
entry to identify a pair of instructions
which add a 32 bit displacement to the address of an instruction following
a branch.
4.3.3.7 TLS Relocations
The types
R_TLS_LITERAL
,
R_TLS_LOW
, and
R_TLS_HIGH
are TLS-specific relocation types.
R_TLS_LITERAL
is very similar
to
R_LITERAL
, except it relates
to
a literal in the TLS data storage area, the TSD array.
R_TLS_LOW
and
R_TLS_HIGH
entries are used as a pair to identify instructions which load a TLS data
address by adding a 32 bit offset to the TLS region pointer.
These relocation
types are identical to the
R_GPRELHIGH
and
R_GPRELLOW
relocation types
except for the fact that the target instructions for the TLS relocation entries
calculate addresses using the TLS region
pointer instead of the GP value.
4.3.4 Relocation Entry Types
The type of a relocation entry (stored in the
r_type
field) describes the action the linker
must perform.
This section discusses the purposes of the different types and
provides examples of their use.
Relocation entry fields are interpreted differently based on relocation type. There also may be constraints on fields' contents depending on the type. Some relocation entries are context sensitive and must be preceded or followed by a particular entry. Some are size specific and the computed address must fall within a specified range. Moreover, some types are constrained to be local entries only or are associated with particular object file sections.
To describe the calculations performed by the linker, the following notation is used in the detailed descriptions for each relocation type:
*_disp
The displacement field of whatever instruction is indicated.
GP
Current GP value; begins as the contents of
AOUTHDR
.gp_value
for the final object.
new_scn_addr
The address of the tracked section of a local relocation entry, as calculated by the linker.
old_GP
GP value in the input
object; begins as
AOUTHDR
.gp_value
for the input object.
old_scn_addr
The contents of
s_vaddr
in the
section header of the input object file for the tracked section of a local
relocation entry.
[r_vaddr]
The contents at the
address
r_vaddr
; to be distinguished from the address
itself.
SEXT
The constant immediately following is sign-extended.
stack
this_new_addr
Where
r_vaddr
will be after relocation .
this_new_scn_addr
Where the
section containing
r_vaddr
will be after relocation,
as calculated by the linker.
this_old_scn_addr
The contents
of
s_vaddr
in the section header of the input object
file for the section containing
r_vaddr
.
tos
Top of relocation expression stack.
result
The result of the relocation,
which is written back into the relocated
r_vaddr
in the object file that the linker is producing.
r_vaddr
Number of relocation
entries if
s_nreloc
section header field has overflowed.
This number includes itself
in the count.
Otherwise, unused.
r_symndx
Unused.
r_extern
Unused.
r_offset
Unused.
r_size
Unused.
Operation
N/A
Restrictions
N/A
Description
This relocation entry is used to indicate a relocation has already been performed or should not be performed. No calculation is associated with such an entry.
The first entry in a relocation section is of type
R_ABS
if it contains the number of relocation entries in that
section (which is the case when the section header field
s_nreloc
overflows).
This type can also be used to pad relocation data
or to delete relocation entries in place.
In-place deletions of relocation
entries are likely to be performed
during a partial link.
Example
An object file
produced during a partial link has 99993 relocations associated with its
.text
section.
A listing of the entries begins with an
R_ABS
because the total number overflows
s_nreloc
:
Vaddr Symndx Type Off Size Extern Name
.text:
0x0000000000018699 0 ABS local <null>
r_vaddr
Points to target address.
r_symndx
External symbol
index if
r_extern
is 1; section number if
r_extern
is 0.
r_extern
Either 0 or 1.
r_offset
Unused.
r_size
Unused.
Operation
if (r_extern == 0) result = (new_scn_addr - old_scn_addr) + (int)[r_vaddr] else result = EXTR.asym.value + (int)[r_vaddr]
Restrictions
Result after relocation must not overflow 32 bits.
Description
A relocation entry of this type describes a simple address adjustment
to the 32-bit value pointed to by
r_vaddr
.
R_REFLONG
entries are most likely to occur when
the compilation option
-xtaso_short
is specified.
The relocated value may be unaligned.
Example 1
C code fragment:
extern int i; void *p = (void *)(&i + 1);
Compile as follows:
$ cc -c -xtaso_short pgmname.c
Produces the following
R_REFLONG
entry:
***RELOCATION INFORMATION***
Vaddr Symndx Type Off Size Extern Name
.sdata:
0x0000000000000000 0 REFLONG extern I
This relocation entry is necessary because the value of the pointer
p
depends
on the address of the global (common storage class) symbol
i
,
whose address is yet to be determined.
At the location indicated by
s_vaddr
, the value 4 is stored, which will be added to the resolved
address of
i
.
The "4" represents the 4 bytes to the next
integer storage location in memory after
i
's.
Example 2
From assembly code, the following declaration produces the same relocation entry as the previous example.
.long I
r_vaddr
Points to target address.
r_symndx
External symbol
index if
r_extern
is 1; section number if
r_extern
is 0.
r_extern
Either 0 or 1.
r_offset
Unused.
r_size
Unused.
Operation
if (r_extern == 0) result = (new_scn_addr - old_scn_addr) + (long)[r_vaddr] else result = EXTR.asym.value + (long)[r_vaddr]
Restrictions
None.
Description
A relocation entry of this type describes a simple address adjustment
to the 64-bit value pointed to by
r_vaddr
.
R_REFQUAD
entries are most likely to occur in
data sections and almost always are used for relocation of the
.lita
section.
The relocated value may be unaligned.
Example 1
Small program:
#include <stdio.h> main(){ printf("printing!\n"); }
Relocation entries produced for its
.lita
section:
***RELOCATION INFORMATION***
Vaddr Symndx Type Off Size Extern Name
.lita:
0x0000000000000070 1 REFQUAD extern printf
0x0000000000000078 3 REFQUAD local .data
The
.lita
section consists of two entries, and each
is relocated.
One entry is external, tracking the routine name
printf()
, and one local, tracking the address of the string literal
in the
.data
section.
Example 2
A
R_REFQUAD
entry can also
be produced by an assembly language statement such as:
.globl y .data b: .quad y
Relocation entry produced:
***RELOCATION INFORMATION***
Vaddr Symndx Type Off Size Extern Name
.data:
0x0000000000000000 0 REFQUAD extern y
The variable
b
is allocated at
s_vaddr
in the
.data
section and will be updated
by adding the address of
y
when the symbol
y
is resolved.
4.3.4.4
R_GPREL32
Fields
r_vaddr
Points to a 32-bit GP-relative value.
r_symndx
External symbol
index if
r_extern
is 1; section number if
r_extern
is 0.
r_extern
Either 0 or 1.
r_offset
Unused.
r_size
Unused.
Operation
if (r_extern == 0) result = (new_scn_addr - old_scn_addr) + old_GP - GP + SEXT((int)[r_vaddr] else result = EXTR.asym.value - GP + SEXT((int)[r_vaddr]
Restrictions
Signed result after relocation must not overflow 32 bits.
Description
A relocation entry of this type indicates a 32-bit GP-relative value
that must be updated.
If it is a local entry, this value must be biased by
the GP value for the input object file.
In both cases, the current
GP value is subtracted to produce a result that is an offset from the GP.
Example 1
Local
R_GPREL32
entries are
produced for a many-case switch statement.
For example, consider the following
C program:
main(){ int i; scanf("%d",&i); switch(i) { case 0:i++; break; case 1:i--; break; case 2:i+=2; break; case 3:i-=2; break; case 4:i+=3; break; case 5:i-=3; break; case 6:i++; break; default: i=0; } }
A compiler may implement a switch statement with a "jump table", that is a code sequence containing labels for each case and a jump statement selecting between them. For each case label, a relocation entry is produced:
Vaddr Symndx Type Off Size Extern Name
.rconst:
0x00000000000000d0 1 GPREL32 local .text
0x00000000000000d4 1 GPREL32 local .text
0x00000000000000d8 1 GPREL32 local .text
0x00000000000000dc 1 GPREL32 local .text
0x00000000000000e0 1 GPREL32 local .text
0x00000000000000e4 1 GPREL32 local .text
0x00000000000000e8 1 GPREL32 local .text
Example 2
The following assembly code sequence also produces a
R_GPREL32
entry:
.globl z .data a: .gprel32 z
Relocation entry produced:
***RELOCATION INFORMATION***
Vaddr Symndx Type Off Size Extern Name
gprel32.o:
.data:
0x0000000000000000 0 GPREL32 extern z
r_vaddr
Points to a
load instruction in the text segment.
The value to be relocated is the memory displacement from the
$gp
in the instruction.
r_symndx
R_SN_LITA
r_extern
Must be zero;
all
R_LITERAL
entries are local.
r_offset
Unused.
r_size
Unused.
Operation
result = (new_scn_addr - old_scn_addr) + (SEXT((short)[r_vaddr]) + old_GP) - GP
Restrictions
The result after relocation for an
R_LITERAL
entry must not overflow 16 bits.
.
R_LITERAL
entries must be
local and relative to the
.lita
section.
Description
A relocation entry of this type is produced when an instruction attempts
to reference values in the literal-address pool (.lita
section).
The instruction containing the reference accesses a
.lita
entry using the
GP value in effect and a signed 16-bit constant.
The original address of the
item has to be reconstructed and then adjusted for the new location of the
address table.
The new address then has to be reconverted into a GP displacement
using the new GP value.
An
R_LITERAL
entry may or
may not be followed by corresponding
R_LITUSE
entries.
The
R_LITERAL
entry is required but the
R_LITUSE
entries are not.
Example
R_LITERAL
entries are used
when an address is loaded from the literal address pool:
ldq t12, -32664(gp)
Relocation entry produced:
***RELOCATION INFORMATION***
Vaddr Symndx Type Off Size Extern Name
.text:
0x0000000000000038 13 LITERAL local .lita
4.3.4.6
R_LITUSE: R_LU_BASE
Fields
r_vaddr
Points to memory-format instruction.
r_symndx
R_LU_BASE
r_extern
Must be zero;
all
R_LITUSE
entries are local.
r_offset
Unused.
r_size
Unused.
Operation
Check if displacement is within 16 or 32 bits. The displacement is calculated:
new_lit = [relocated literal belonging to corresponding R_LITERAL] disp = new_lit + lituse_disp - GP
Restrictions
A relocation entry of this type must follow either an
R_LITERAL
or another
R_LITUSE
entry with no other types intervening.
r_vaddr
must be aligned on a byte boundary.
Ignored if optimization level is not at least -O1.
Cannot remove the first load instruction unless this is the only corresponding
R_LITUSE
entry.
Description
This relocation entry is informational and indicates that the base register
of the indicated instruction holds a literal address.
Note that a
R_LITERAL
entry, corresponding to an
ldq
instruction, precedes this entry.
Possible optimizations depend on the distance of the memory displacement from the GP value. If the displacement is less than 16 bits from the GP, a single instruction suffices to describe the location. The code sequence can be changed as shown:
ldq rx, disp(gp) R_LITERAL ldq/stq ry, disp2(rx) R_LITUSE(R_LU_BASE) -- ldq/stq ry, disp3(gp)
The linker converts
the
R_LITUSE
entry to an
R_IMMED_GP_16
for the transformed instructions.
If the displacement is within 32 bits of the GP, one memory access can
be saved by replacing the first load instruction with the faster
ldah
instruction.
ldq rx, disp(gp) R_LITERAL ldq/stq ry, disp2(rx) R_LITUSE(R_LU_BASE) -- ldah rx, disp3(gp) ldq/stq ry, disp4(rx)
The linker will convert the
R_LITERAL
and the
R_LITUSE
, respectively,
to entries of type
R_IMMED_GP_HI32
and
R_IMMED_GPLOW32
.
This can currently only be done if exactly one
R_LITUSE
exists for the
R_LITERAL
.
Example 1
The following instructions represent a single use of an address literal:
0x100: ldq a1, -32656(gp) // R_LITERAL 0x104: lda a1, 32(a1) // R_LU_BASE
Relocation entries produced:
***RELOCATION INFORMATION***
Vaddr Symndx Type Off Size Extern Name
.text:
0x0000000000000100 13 LITERAL local .lita
0x0000000000000104 1 LITUSE local R_LU_BASE
The potential optimization indicated by this
R_LU_BASE
is that the two instructions could possibly be replaced
by a single
ldq
instruction of the form:
ldq a1, <disp>(gp)
Example 2
The following instructions illustrate multiple
R_LITUSE
entries following an
R_LITERAL
entry:
0x130: ldq t0, -32736(gp) // R_LITERAL 0x134: ldq t1, 0(t0) // R_LU_BASE 0x138: zap t1, 0x2, t1 0x13c: insbl v0, 0x1, v0 0x140: bis t1, v0, t1 0x144: stq t1, 0(t0) // R_LU_BASE
Relocation entries produced are:
***RELOCATION INFORMATION***
Vaddr Symndx Type Off Size Extern Name
0x0000000000000130 13 LITERAL local .lita
0x0000000000000134 1 LITUSE local R_LU_BASE
0x0000000000000144 1 LITUSE local R_LU_BASE
4.3.4.7
R_LITUSE: R_LU_JSR
Fields
r_vaddr
r_symndx
R_LU_JSR
r_extern
Must be zero;
all
R_LITUSE
entries are local.
r_offset
Unused.
r_size
Unused.
Operation
new_lit = [relocated literal belonging to correponding R_LITERAL] this_new_addr = r_vaddr - this_old_scn_addr + this_new_scn_addr branch_disp = prologue_size + new_lit - this_new_addr + 4 result = branch_disp / 4
Restrictions
Must follow either an
R_LITERAL
or another
R_LITUSE
entry with no
other types intervening.
Result after relocation must not overflow 21 bits (size of branch displacement
field in the branch instruction format).
Description
A relocation entry of this type is informational only.
It informs the
linker that the indicated jump instruction
is jumping to an address previously loaded out of the literal address pool.
The load instruction had an associated
R_LITERAL
entry that precedes this relocation entry.
Under the right circumstances, the linker can optimize this sequence in several ways:
The procedure prologue can be skipped if it is not needed to load a GP value for the procedure.
The branch can be calculated and the instruction changed to a branch instruction.
The preceding
ldq
can be removed.
The first two actions may be performed but not the last if other
R_LITUSE
entries correspond to the same
R_LITERAL
.
These optimization are performed
by the linker for optimization level 1 and greater.
In order to preserve
preemptibility of symbol references, this optimization can only be done for
non-weak global symbols in a
static and dynamic executable.
References to
static
or hidden symbols can be optimized in executables or shared libraries.
Example
The following instructions illustrate the use of a literal as the target of a jump instruction:
0x8: ldq t12, -32736(gp) // R_LITERAL 0xc: lda sp, -16(sp) 0x10: stq ra, 0(sp) 0x14: jsr ra, (t12) // R_LU_JSR
Relocation entries produced:
***RELOCATION INFORMATION***
Vaddr Symndx Type Off Size Extern Name
.text:
0x0000000000000008 13 LITERAL local .lita
0x0000000000000014 3 LITUSE local R_LU_JSR
The instructions identified by the
R_LITERAL
and
R_LU_JSR
entries
in this example can be optimized.
The
ldq
instruction can
be replaced with a
NOP
instruction and the
jsr
can be replaced with a
bsr
yielding:
0x1200011a8: ldq_u zero, 0(sp) // NOP 0x1200011ac: lda sp, -16(sp) 0x120001110: stq ra, 0(sp) 0x120001114: bsr ra, 0x1200011d8
r_vaddr
Points to the
first of a pair of instructions:
lda
and
ldah
.
Either instruction may occur first.
r_symndx
Contains the
unsigned byte offset from the instruction indicated in
r_vaddr
to the other
instruction used to load the GP value.
r_extern
Must be zero;
all
R_GPDISP
entries are local.
r_offset
Unused.
r_size
Unused.
Operation
result = (old_GP - GP) + (this_old_scn_addr - this_new_scn_addr) + (65536 * high_disp) + low_disp
The result after relocation is written back into the instruction pair.
lda_disp = result ldah_disp = (result + 32768) / 65536
Restrictions
Must describe an
lda/ldah
instruction pair.
Result after relocation must not overflow 32 bits.
Description
A relocation entry of this type corresponds to two instructions in the
code.
The field
r_vaddr
points to one instruction
and the address of the other is computed by adding the value of
r_symndx
to
r_vaddr
.
This relocation
entry occurs for each instruction sequence that loads the GP value.
For instance,
procedure entry points typically
include instructions which load their effective
GP value.
They are normally
the first instructions in a procedure's prologue.
Example
A simple example of an occurrence of the
R_GPDISP
entry is the program entry point:
main() { }
Instructions generated:
0x0: ldah gp, 1(t12) // R_GPDISP (r_vaddr) 0x4: lda gp, -32704(gp) // R_GPDISP (r_vaddr + r_symndx)
Relocation entry produced:
Vaddr Symndx Type Off Size Extern Name
.text:
0x0000000000000000 4 GPDISP local
There are situations where a procedure is called but the
R_GPDISP
entry is not required.
In this case,
the
gp_used
field of the procedure's descriptor
will be zero, and an
R_LU_JSR
optimization
may cause the prologue to be skipped.
See the
Calling Standard for Alpha Systems
for details
on when a procedure requires calculation of a GP value.
4.3.4.9
R_BRADDR
Fields
r_vaddr
Points to a branch instruction.
r_symndx
External symbol
index if
r_extern
is 1; section number if
r_extern
is 0.
r_extern
Either 0 or 1.
r_offset
Unused.
r_size
Unused.
Operation
if (r_extern == 0) this_new_addr = r_vaddr - this_old_scn_addr + this_new_scn_addr result = ((new_scn_addr - old_scn_addr) + (branch_displacement * 4) + r_vaddr + 4 - this_new_addr) / 4 else this_new_addr = r_vaddr - this_old_scn_addr + this_new_scn_addr result = (EXTR.asym.value + (branch_displacement * 4) - this_new_addr) / 4
Restrictions
After relocation the result should be aligned on a 4-byte boundary.
The signed result must not overflow the 21-bit branch displacement field.
Description
A relocation entry of this type identifies a branch instruction in the code. The branch displacement is treated as a longword (32-bit, or one instruction) offset. The branch target's virtual address is computed:
va <- PC + (4 * branch_displacement)
The branch displacement must be relocated.
The
R_BRADDR
relocation can
only be used for local or static references because the displacement is fixed
at link time.
Updating it at run
time would require writing to the text segment, which is not permitted.
Without
the ability to update at run time, symbol
preemption for shared objects will not function.
Example
A relocation of this type is used for a call of a static procedure:
static bar(){ int q =1; printf ("the value of q is %d\n", q); } main (){ bar(); }
Instruction generated:
0x4c: bsr ra, 0x8(zero) // R_BRADDR
Relocation entry produced:
Vaddr Symndx Type Off Size Extern Name
.text:
0x000000000000004c 1 BRADDR local .text
r_vaddr
Points to jump-format instruction.
r_symndx
External symbol
index if
r_extern
is 1; section number if
r_extern
is 0.
r_extern
Either 0 or 1.
r_offset
Unused.
r_size
Unused.
Operation
if (r_extern == 0) this_new_addr = r_vaddr - this_old_scn_addr + this_new_scn_addr result = ((new_scn_addr - old_scn_addr) + (jump_disp * 4) + r_vaddr + 4 - this_new_addr) / 4 else this_new_addr = r_vaddr - this_old_scn_addr + this_new_scn_addr result = (EXTR.asym.value + (jump_displacement * 4) - this_new_addr) / 4
Restrictions
Result after relocation should be aligned on a 4-byte (instruction-size)
boundary.
Description
Jump instructions are memory-format instructions where the 14 bits of the displacement field serve as a hint for determining the jump target. The hint is PC-relative and must be relocated to remain relevant. Note that the use of hints is for optimization purposes only and takes advantage of branch-prediction logic built into the architecture. If the hint values were not relocated, a correct executable program would still be produced but potential performance improvements would be lost.
A characteristic of
R_HINT
entry processing is that instead of checking for overflow of the 14-bit result
after relocation, the linker truncates
the result and writes it back without issuing an error or warning.
Example
Subroutine calls often cause
R_HINT
entries.
main() { printf("hello\n"); }
Instructions generated:
0x14: ldq t12, -32752(gp) // R_LITERAL 0x18: jsr ra, (t12), printf // R_HINT
Relocation entries produced:
Vaddr Symndx Type Off Size Extern Name
.text:
0x0000000000000018 3 LITUSE local R_LU_JSR
0x0000000000000018 0 HINT extern printf
Note that the same source line and corresponding instruction produce
a second relocation entry of type
R_LITUSE_JSR
.
This second entry is also informational only.
It indicates
that the target register of the jump instruction contains a previously loaded
literal address.
4.3.4.11
R_SREL16
Fields
r_vaddr
Points to a 16-bit self-relative value.
r_symndx
External symbol
index if
r_extern
is 1; section number if
r_extern
is 0.
r_extern
Either 0 or 1.
r_offset
Unused.
r_size
Unused.
Operation
if (r_extern == 0) this_new_addr = r_vaddr - this_old_scn_addr + this_new_scn_addr result = (new_scn_addr - old_scn_addr) + SEXT((short)[r_vaddr]) + r_vaddr - this_new_addr else this_new_addr = r_vaddr - this_old_scn_addr + this_new_scn_addr result = EXTR.asym.value - this_new_addr
Restrictions
The result after relocation must not overflow 16 bits.
Description
A relocation entry of this type is identical to an
R_SREL32
entry except for the size of the value being adjusted.
Example
This type is currently not used by the compilation system.
4.3.4.12
R_SREL32
Fields
r_vaddr
Points to a 32-bit self-relative value.
r_symndx
External symbol
index if
r_extern
is 1; section number if
r_extern
is 0.
r_extern
Either 0 or 1.
r_offset
Unused.
r_size
Unused.
Operation
if (r_extern == 0) this_new_addr = r_vaddr - this_old_scn_addr + this_new_scn_addr result = (new_scn_addr - old_scn_addr) + SEXT((int)[r_vaddr]) + r_vaddr - this_new_addr else this_new_addr = r_vaddr - this_old_scn_addr + this_new_scn_addr result = EXTR.asym.value - this_new_addr
Restrictions
The result after relocation must not overflow 32 bits.
Description
A relocation entry of this type indicates a value that describes a reference
as an offset to its own location.
In other words, the target address is computed
by adding the contents of the relocation address ([r_vaddr]
)
to the address of the relocation (r_vaddr
).
To
perform this relocation, the new location of
r_vaddr
must be computed and subtracted from the new target address to provide the
correctly adjusted self-relative, offset which is then written back into the
raw data.
Example
The code range descriptors that are generated
for each object contain a 32-bit self-relative offset in the
rpd_offset
field.
See
Section 3.2.1.
The
rpd_offset
field contains an offset to the associated
run-time procedure descriptor in the
.xdata
section.
The
R_SREL32
entry identifies this value.
main(){ printf("Printing\n"); }
Relocation entry produced:
Vaddr Symndx Type Off Size Extern Name
.pdata:
0x0000000000000054 10 SREL32 local .xdata
Note that this relationship between the
.xdata
and
.pdata
sections imposes a restriction on the distance between the
text and data segments.
The run-time procedures in the .xdata section must
be within reach of a 32-bit signed offset from the code range descriptors
in .pdata.
4.3.4.13
R_SREL64
Fields
r_vaddr
Points to a 64-bit self-relative value.
r_symndx
External symbol
index if
r_extern
is 1; section number if
r_extern
is 0.
r_extern
Either 0 or 1.
r_offset
Unused.
r_size
Unused.
Operation
if (r_extern == 0) this_new_addr = r_vaddr - this_old_scn_addr + this_new_scn_addr result = (new_scn_addr - old_scn_addr) + (long)[r_vaddr] + r_vaddr - this_new_addr else this_new_addr = r_vaddr - this_old_scn_addr + this_new_scn_addr result = EXTR.asym.value - this_new_addr
Restrictions
None.
Description
A relocation entry of this type is identical to an
R_SREL32
entry except for the size of the value being adjusted.
Example
This type is currently not used by the compilation system.
4.3.4.14
R_OP_PUSH
Fields
r_vaddr
0 if
r_extern
is 1; an unsigned offset within a section if
r_extern
is 0.
r_symndx
External symbol
index if
r_extern
is 1; section number if
r_extern
is 0.
r_extern
Either 0 or 1.
r_offset
Unused.
r_size
Unused.
Operation
if (r_extern == 0) stack[++tos] = (new_scn_addr - old_scn_addr) + r_vaddr else stack[++tos] = EXTR.asym.value
Restrictions
This relocation entry must be followed by an
R_OP_STORE
entry, with one or more
R_OP_PSUB
or
R_OP_PRSHIFT
entries in between.
Stack can hold a maximum of 20 entries.
Description
A relocation entry of this type causes a value to be pushed onto the
relocation stack.
The value is generally the target address of the relocation,
which will be adjusted using subsequent
R_OP_PSUB
and
R_OP_PRSHIFT
relocation
calculations.
Example
A code range descriptor in the
.pdata
section contains a 32-bit field,
begin_address
, which is the offset of the associated code range address from
the beginning of the code range descriptor table.
See
Section 3.2.1.
This value is calculated by subtracting two addresses and storing the least
significant 32 bits.
A series of three stack relocation entries is used to
represent this offset calculation.
main(){ foo(); } foo(){ printf("Printing\n"); }
Relocation entries produced for use in calculating the
begin_address
in the code range descriptor for
foo()
:
Vaddr Symndx Type Off Size Extern Name
.pdata:
0x0000000000000030 1 PUSH local .text
0x0000000000000000 3 PSUB extern _fpdata
0x0000000000000078 11 STORE 0 32 local .pdata
The following series of relocation entries will effectively perform the calculation:
(.pdata+0x78) = (long)(((.text+0x30)-&_fpdata) & 0xffffffff)
r_vaddr
Location to store calculated bit field.
r_symndx
Section index of containing section.
r_extern
Must be 0.
r_offset
Bit offset
from
r_vaddr
.
(Bit 0 is the least significant
bit in little-endian objects and the most
significant bit in big-endian objects.
See
Section 1.7.)
r_size
Number of bits to store.
Operation
if (little_endian) rshift = r_offset else rshift = 64 - (r_offset + r_size) bitfield = ((long)[r_vaddr] >> r_offset) & ((1 << r_size) - 1) bitfield <- stack[tos--]
Restrictions
Stack cannot be empty.
Description
A relocation entry of this type causes the value currently on the top
of the relocation stack to be written into a bit field specified by the entry.
The bit field is described using a bit position and size in bits.
Note that
bit numbering is reversed in a big-endian representation.
Example
An example of the
R_OP_STORE
entry is given in
Section 4.3.4.14.
4.3.4.16
R_OP_PSUB
Fields
r_vaddr
0 if
r_extern
is 1; an unsigned offset within a section if
r_extern
is 0.
r_symndx
External symbol
index if
r_extern
is 1; section number if
r_extern
is 0.
r_extern
Either 0 or 1.
r_offset
Unused.
r_size
Unused.
Operation
if (r_extern == 0) result = (new_scn_addr - old_scn_addr) + r_vaddr stack[tos] = stack[tos] - result else result = EXTR.asym.value stack[tos] = stack[tos] - result
Restrictions
The relocation stack cannot be empty.
This entry must fall somewhere
between an
R_OP_PUSH
entry and an
R_OP_STORE
entry.
Description
A relocation entry of this type causes the value at the top of the relocation
expression
stack to be popped, adjusted by subtracting the address described by
r_extern
and
r_symndx
, and pushed
back on the stack.
Example
An example of the
R_OP_STORE
entry is given in
Section 4.3.4.14.
4.3.4.17
R_OP_PRSHIFT
Fields
r_vaddr
0 if
r_extern
is 1; an unsigned offset within a section if
r_extern
is 0.
r_symndx
External symbol
index if
r_extern
is 1; section number if
r_extern
is 0.
r_extern
Either 0 or 1.
r_offset
Unused.
r_size
Unused.
Operation
if (r_extern == 0) result = (new_scn_addr - old_scn_addr) + r_vaddr stack[tos] = stack[tos] >> result else result = EXTR.asym.value stack[tos] = stack[tos] >> result
Restrictions
The stack cannot be empty.
So this entry must fall somewhere between
an
R_OP_PUSH
and an
R_OP_STORE
.
Description
A relocation entry of this type causes the value at the top of the relocation
expression
stack to be popped, adjusted by right shifting the value by the number of
bits described by
r_extern
and
r_symndx
, and pushed back on the stack.
Example
This relocation type can be used to convert a byte offset into an instruction offset. Right shifting a byte offset by two bits will produce an instruction offset because Alpha instructions are 4 bytes wide.
The following assembly code will result in an
R_HINT
entry for the 14-bit instruction offset contained in the
hint field of a
jsr
instruction.
See
Section 4.3.4.10
for a description of the
R_HINT
entry.
0x3c ldq t12, -32752(gp) /* &printf */ 0x40 jsr ra, (t12)
The
R_HINT
entry for the instruction
at
0x40
could also be accomplished with a series of stack
relocation options:
.text:
0x0000000000000000 2 PUSH extern printf
0x0000000000000044 1 PSUB local .text
0x0000000000000002 14 PRSHIFT local .abs
0x0000000000000040 1 STORE 0 14 local .text
r_vaddr
r_symndx
Constant that
is added to the GP value in the
a.out
header to obtain the new GP value.
r_extern
Must be zero;
all
R_GPVALUE
entries are local.
r_offset
Unused.
r_size
Unused.
Operation
new GP = AOUTHDR.gp_value + r_symndx
Restrictions
This type of relocation entry cannot be external.
Description
A relocation entry of this type identifies the position in the code
where a new GP value takes effect.
R_GPVALUE
entries are
inserted by the linker during partial links.
Example
A linked program that
references 20,000 external symbols will have at
least 3 GOT entries with 3 corresponding GP values.
See
Section 2.3.4.
If the program has GP-relative relocation entries in both
.text
and
.rdata
sections, two
R_GPVALUE
entries would be reported for each of these sections.
Vaddr Symndx Type Off Size Extern Name
.text:
0x0000000010084cf0 64000 GPVALUE local
0x00000000100cb190 111984 GPVALUE local
.rdata:
0x000000001000fa00 64000 GPVALUE local
0x000000001001b570 111984 GPVALUE local
r_vaddr
Points to a
memory format instruction (ldah
).
r_symndx
External symbol
index if
r_extern
is 1; section number if
r_extern
is 0.
r_extern
Either 0 or 1.
r_offset
Unused.
r_size
Unused.
Operation
See
R_GPRELLOW
relocation
type.
Restrictions
Must be followed by at least one
R_GPRELLOW
.
Relocated result must
not overflow unsigned 32-bit range.
Description
A relocation entry of this type is invalid unless it is followed by
at least one
R_GPRELLOW
entry.
When
an
R_GPRELHIGH
entry is encountered,
no calculation is performed.
The relocation calculation is deferred until
the
R_GPRELLOW
entry is processed.
See the
R_GPRELLOW
description for
more information.
Example
See
R_GPRELLOW
.
4.3.4.20
R_GPRELLOW
Fields
r_vaddr
Points to memory
format instruction (ld*
or
st*
).
r_symndx
Must match
R_GPRELHIGH
.
r_extern
Must match
R_GPRELHIGH
.
r_offset
Unused.
r_size
Unused.
Operation
low_disp = [r_vaddr].displacement high_disp = [R_GPRELHIGH->r_vaddr].displacement displacement = high_disp * 65536 + low_disp if (r_extern = 0) result = displacement + (new_scn_addr - old_scn_addr) + (old_GP - GP) else result = displacement + EXTR.asym.value + (old_GP - GP) [R_GPRELHIGH->r_vaddr].displacement = (result+32768) >> 16 [r_vaddr].displacement = result & 0xFFFF
Restrictions
The
R_GPRELHIGH
/
R_GPRELLOW
relocations must be used as a pair
or set.
At least one
R_GPRELLOW
entry follows each
R_GPRELHIGH
entry.
After relocation, the result must not overflow 32 bits.
The memory displacement for all
R_GPRELLOW
entries corresponding to the same
R_GPRELHIGH
must match.
Description
The
R_GPRELHIGH
/
R_GPRELLOW
entry pair is used to describe GP-relative
memory accesses.
The
R_GPRELHIGH
entry indicates an
ldah
instruction.
The
R_GPRELLOW
entry (or entries) indicates a load or store instruction.
If multiple
R_GPRELLOW
entries are
associated with an
R_GPRELHIGH
,
they must all describe the same memory location.
A relocatable address can
be formed with the following computation:
addr = 65536 * high_disp + SEXT (low_disp)
To relocate this code sequence, the memory displacement fields in each instruction must be adjusted to reflect changes in the target address they compute and in the GP value.
The reason these entries are treated as a pair is that sign extension of the low instruction's displacement field can result in an off-by-one error that must be fixed by adding one to the high instruction's displacement. This situation can only be detected if the instructions are considered together.
These relocation entries describe instructions that are primarily used
for computing addresses in kernel code..
The kernel is built without a
.lita
section, and kernel performance is enhanced
by code that calculates addresses directly instead of loading addresses from
a
.lita
memory location.
The code size, on average, is
unaffected by the kernel's use of this addressing method.
Example
Use the kernel build option -Wb,-static to compile the following sample code.
static int a; foo(){ a++; }
Code generated for loading the address of
"a"
:
0x0: ldah t0, 0(gp) 0x4: lda t0, 16(t0)
Relocation entries produced are:
Vaddr Symndx Type Off Size Extern Name
.text:
0x0000000000000000 5 GPHIGH local .sbss
0x0000000000000004 5 GPLOW local .sbss
r_vaddr
Points to memory-format instruction.
r_symndx
External symbol
index if
r_extern
is 1; section number if
r_extern
is 0.
r_extern
Either 0 or 1.
r_offset
Unused.
r_size
R_IMMED_GP_16
.
Operation
N/A
Restrictions
N/A
Description
A relocation entry of this type identifies an instruction that adds
a 16-bit displacement to the GP value,
obtaining an address.
The
r_extern
and
r_symndx
fields specify
the
external symbol or section to which the calculated address is relative.
This relocation entry
is created by the linker to indicate that an optimization has taken place
because the displacement is within 16-bits of the GP value.
Example
N/A
4.3.4.22
R_IMMED: GP_HI32
Fields
r_vaddr
Points to memory-format instruction.
r_symndx
Unused.
r_extern
Unused.
r_offset
Unused.
r_size
R_IMMED_GP_HI32
.
Operation
N/A
Restrictions
N/A
Description
A relocation entry of this type identifies an instruction that is part
of a pair of instructions that add
a 32-bit displacement to the GP value.
This instruction adds the high portion
of the 32-bit displacement.
The next
R_IMMED_LO32
entry identifies the instruction containing the low portion
of the displacement.
More than one subsequent
R_IMMED_LO32
entry can share the same
R_IMMED_GP_HI32
entry.
Example
N/A
4.3.4.23
R_IMMED: SCN_HI32
Fields
r_vaddr
Points to memory-format instruction.
r_symndx
Unused.
r_extern
Unused.
r_offset
Unused.
r_size
R_IMMED_SCNHI32
.
Operation
N/A
Restrictions
N/A
Description
A relocation entry of this type identifies an instruction that is part
of a pair of instructions that add a 32-bit displacement to the starting address
of the current section.
This instruction adds the high portion of the displacement.
The next
R_IMMED_LO32
entry identifies
the instruction with the low portion.
Example
N/A
4.3.4.24
R_IMMED: BR_HI32
Fields
r_vaddr
Points to a
memory-format instruction following a branch (br
,
bsr
,
jsr
, or
jmp
) instruction.
r_symndx
Specifies
a byte offset from
r_vaddr
to the branch instruction.
r_extern
Unused.
r_offset
Unused.
r_size
R_IMMED_BRHI32
.
Operation
N/A
Restrictions
N/A
Description
A relocation entry of this type identifies an instruction that is part
of a pair of instructions that add a 32-bit displacement to the address of
the instruction following a branch (br
,
bsr
,
jsr
, or
jmp
).
The branch must precede this instruction.
The
r_symndx
field specifies a byte offset from
r_vaddr
to the branch instruction.
The instruction identified
by this relocation entry adds the high portion of the displacement.
The next
R_IMMED_LO32
entry identifies the instruction
with the low portion of the displacement.
Example
N/A
4.3.4.25
R_IMMED: LO32
Fields
r_vaddr
Points to a memory-format instruction.
r_symndx
External symbol
index if
r_extern
is 1; section number if
r_extern
is 0.
r_extern
Either 0 or 1.
r_offset
Unused.
r_size
R_IMMED_LO32
.
Operation
N/A
Restrictions
N/A
Description
A relocation entry of this type identifies an instruction that is part
of a pair of instructions that add a 32-bit displacement to a base address.
This instruction adds the low portion of the displacement.
This relocation
entry is combined with the previous
R_IMMED_GP_HI32
,
R_IMMED_SCN_HI32
,
or
R_IMMED_BR_HI32
entry.
The
r_extern
and
r_symndx
fields specify
the external symbol or section to which
the calculated address is relative.
Example
N/A
4.3.4.26
R_TLS_LITERAL
Fields
r_vaddr
Points to an instruction that loads the TSD key for initiating a thread local storage reference actually, not the key itself but key * 8, which gives the offset of the TLS pointer in the TSD array.
r_symndx
R_SN_LITA
r_extern
Must be zero;
all
R_TLS_LITERAL
entries are local.
r_offset
Unused.
r_size
Unused.
Operation
result = (new_scn_addr - old_scn_addr) + (SEXT((short)[r_vaddr]) +old_GP) - GP
Restrictions
The result after relocation for an
R_TLS_LITERAL
entry must not overflow 16 bits.
R_TLS_LITERAL
entries must
be local and relative to the
.lita
section.
Description
A relocation entry of this type is very similar to an
R_LITERAL
entry.
An
R_TLS_LITERAL
entry identifies an instruction that uses a GP displacement
to load an the address of the symbol
__tlsoffset
from the
.lita
section.
The value of the
__tlsoffset
symbol is fixed at run
time to be the TSD array offset of the TLS pointer.
The symbol can occur anywhere
in the GOT or .lita section.
The linker-defined symbol
__tlskey
points to one of the instances of the
__tlsoffset
symbol.
The linker processes
the
R_TLS_LITERAL
relocation by
adjusting the GP offset in the displacement of the target instruction.
Example
Routines that reference TLS addresses will have at least one
R_TLS_LITERAL
entry for the load of the
__tlsoffset
value.
__declspec(thread) long foo; main(){ foo = 2; }
Code generated will include the instruction:
0x14: ldq at, -32752(gp)
Relocation entry produced:
Vaddr Symndx Type Off Size Extern Name
.text:
0x0000000000000014 13 TLSLITE local .lita
r_vaddr
Points to memory-format instruction.
r_symndx
External symbol
index if
r_extern
is 1; section number if
r_extern
is 0.
r_extern
Either 0 or 1.
r_offset
Unused.
r_size
Unused.
Operation
See
R_TLS_LOW
description.
Restrictions
Must be followed by
R_TLS_LOW
entry.
Description
See
R_TLS_LOW
.
Example
See
R_TLS_LOW
.
4.3.4.28
R_TLS_LOW
Fields
r_vaddr
Points to memory-format instruction.
r_symndx
External symbol
index if
r_extern
is 1; section number if
r_extern
is 0.
r_extern
Either 0 or 1.
r_offset
Unused.
r_size
Unused.
Operation
low_disp = [r_vaddr].displacement high_disp = [R_TLS_HIGH->r_vaddr].displacement displacement = high_disp * 65536 + low_disp if (r_extern = 0) result = displacement + (new_scn_addr - old_scn_addr) else result = displacement + EXTR.asym.value [R_TLS_HIGH->r_vaddr].displacement = (result+32768) >> 16 [r_vaddr].displacement = result & 0xFFFF
Restrictions
External relocation entries of this type are limited to TLS symbols.
Local relocation entries of this type are restricted to the TLS sections
.tlsdata
and
.tlsbss
.
The relocated result must not exceed 32 bits.
Description
The linker must handle
R_TLS_HIGH
and
R_TLS_LOW
entries as a pair.
The pairs of relocation entries
must be in sequence starting with
R_TLS_HIGH
.
The order and location of the instructions associated with
these relocation entries are not restricted.
Example
The load of a TLS symbol's address requires an
R_TLS_HIGH
/
R_TLS_LOW
entry pair.
__declspec(thread) long foo; main(){ foo = 2; }
Code generated:
0x0c: call_pal rduniq
0x10: ldq v0, 96(v0)
0x14: ldq at, -32752(gp)
0x18: addq v0, at, v0
0x1c: ldq v0, 0(v0)
0x20: ldah v0, 0(v0)
0x24: stq t0, 0(v0)
Relocation entries produced:
Vaddr Symndx Type Off Size Extern Name
.text:
0x0000000000000020 0 TLSHIGH extern foo
0x0000000000000024 0 TLSLOW extern foo
Compact relocations are a highly compressed form of relocation records
designed for the use of profiling
tools and object restructuring tools.
By
default, they are generated by the linker for all fully linked
executable objects and recorded in the object's
.comment
section.
The linker produces
this information using
libmld.a
APIs,
which implement the reading and writing
of compact relocations.
Compact relocations are not produced for images linked
with the following linker options:
-r,
-s.
The
strip
utility will remove the comment subsection that contains compact relocations.
See
Chapter 7
for the format of the
.comment
section.
Compact relocations must provide crucial relocation information in much less space than the space required for actual relocation entries. This goal is accomplished by employing a heuristic function to predict relocations. For some sections, this heuristic is highly accurate. Detailing many records in the object file becomes unnecessary because the algorithm can be used instead to recreate many of the actual relocation entries.
Version Note In releases of Tru64 UNIX prior to V5.1, compact relocations contained only enough relocation information to drive tools that restructure an executable's
.text
,.init
, and.fini
sections. From Tru64 UNIX V5.1 onward, executables contain full compact relocation information including relocation records for text and data segment addresses in all mapped object sections.
The interfaces for compact relocations continue to evolve.
These interfaces
are defined and described in the header file
cmplrs/cmrlc.h
.
This section describes the on-disk file format of compact relocations and
the producer and consumer algorithms.
4.4.1 Overview
The procedure for creation of compact relocations is as follows:
Generate a list of predicted relocations using heuristics.
Compare the predicted relocations to the actual relocation entries (which are input data to the compact relocations producer).
Wherever a "miss" occurs (that is, the predicted and actual entries do not match) output a compact relocation record.
The procedure for the use of compact relocation records follows:
Generate the list of predicted relocations using the same heuristics as the compact relocations producer.
Compare the expanded compact relocations data with predicted relocations to reconstruct the actual relocation entries.
See
Section 4.4.3
for more details.
4.4.2 File Format
Compact relocations are stored in a subsection of the
.comment
section.
The linker and other tools
do not need to be aware of
the details of the internal structure of the compact relocation
subsection.
This knowledge is encapsulated in the
cmrlc_*
routines found in
libmld.a
.
The on-disk format of the compact relocations data consists of the following components, in order:
Version identifier
Compact relocations tables (for each section)
Expression stack relocations tables (for each section)
Code may only assume that the version and the file header are contiguous.
To access other structures, it is necessary to rely on the location information
in the file header.
4.4.2.1 Compact Relocations Version
The compact relocation section begins with a version identifier, which has the following structure:
struct { unsigned int version_major; unsigned int version_minor; };
SIZE - 8 bytes, ALIGNMENT - 4 bytes
The version identifier allows the format of the compact relocations to change from one release to another while providing a mechanism for tools to work on binaries with either the old or new formats. The version identifiers are separate from the header because the format of the header itself may change from release to release.
The major version identifier is incremented for changes in the format of the compact relocation data that affect the most basic access to the data. For example, changes in structure sizes or structure layout are likely to cause failures in existing code that simply reads the raw compact relocation data.
The minor version identifier is incremented whenever the compact relocation data is modified without impacting the format of the data. For example, changing the heuristic to further compact the stored relocation information would require the minor version identifier to be incremented. If the consumer routines see that an object has an old minor version number, they can call a matching version of the heuristic to correctly reconstruct the relocation information.
The major and minor version identifiers that have been used for compact
relocation data are described in
Table 4-5.
Enumeration values
for supported versions can be found in the header file
/usr/include/cmplrs/cmrlc.h
.
Table 4-5: Compact Relocation Version Identifiers
Major | Minor | OS Version | Description |
0 | 0 | V3.0 | Initial version |
1 | 0 | V3.2 | Fix for dynsym relocations |
2 | 0 | V4.0 | Miscellaneous bug fixes |
2 | 3 | V5.1 | Full compact relocations |
4.4.2.2 Compact Relocations File Header
The version identifier is followed by a high-level header structure that stores the sizes and locations of the other tables with compact relocations information:
struct cmrlc_file_header { /* * Total number of elements in each sub-table. */ unsigned long scn_num; /* section header table */ unsigned long rlc_num; /* compact relocation table */ unsigned long expr_num; /* expression relocation table */ unsigned long gpval_num; /* GP value table */ /* * Relative file offset from start of compact relocation data * to each sub-table. */ unsigned long scn_off; unsigned long rlc_off; unsigned long expr_off; unsigned long gpval_off; };
SIZE - 64 bytes, ALIGNMENT - 8 bytes
Each of the
*_num
fields indicates the number
of entries in the corresponding tables.
Each of the
*_off
fields contains a relative file offset from
the start of the compact relocations
.comment
subsection
to the start of the corresponding table.
If any of the tables are not present
for a particular program, the
*_num
and
*_off
fields should be set to zero.
4.4.2.3 Compact Relocations Section Header
One or more compact relocations section headers follow the compact relocations file header. Each section header has the following structure:
struct cmrlc_file_scnhdr { char name[8]; /* section name */ /* * Number of elements for this section in each sub-table. */ unsigned long rlc_snum; unsigned long expr_snum; unsigned long gpval_snum; /* * Index from start of table to this section's elements. * (This is an element index, not a byte offset.) */ unsigned long rlc_indx; unsigned long expr_indx; unsigned long gpval_indx; /* * Flag: True if compact relocation table is sorted by * increasing virtual address. */ unsigned long rlc_sorted:1; unsigned long :63; };
SIZE - 64 bytes, ALIGNMENT - 8 bytes
One compact relocation section header is created for each eCOFF object file section for which compact relocation data is stored. This section header is unrelated to the eCOFF section header structure except for the name field, which connects the two.
Each of the
*_num
fields indicates the number
of entries in the corresponding table for this object file section.
If the
*_num
field is non-zero, the corresponding
*_indx
field contains the index of the start of that section's entries
within the table.
The
rlc_sorted
field indicates whether the
compact relocation table entries for this section are sorted by virtual address.
If an object file section does not have entries in one of the tables
for a particular program, the corresponding fields should be set to zero.
4.4.2.4 Compact Relocations Table
Compact relocation tables follow the compact relocation section headers. Each compact relocation table consists of an array of structures:
struct cmrlc_file_rlc { unsigned v_offset; union { unsigned word; struct { unsigned type:5; unsigned :27; } common; struct { /* GPDISP */ unsigned type:5; unsigned lda_offset:27; } gpdisp; struct { /* EXPRESSION */ unsigned type:5; unsigned index:27; } expr; struct { /* REF*, SREL*, GPREL32 */ unsigned type:5; unsigned rel_scn:5; unsigned count:12; unsigned dist:4; (V5.0 - ) unsigned :6; } addrtype; struct { /* External REF */ (V5.1 - ) unsigned type:5; (V5.1 - ) unsigned r_symndx:27; (V5.1 - ) } eref; (V5.1 - ) struct { /* LITERAL */ (V5.1 - ) unsigned type:5; (V5.1 - ) unsigned rel_scn:5; (V5.1 - ) unsigned count:12; (V5.1 - ) unsigned dist:4; (V5.1 - ) unsigned :6; (V5.1 - ) } literal; (V5.1 - ) struct { /* LITUSE */ (V5.1 - ) unsigned type:5; (V5.1 - ) unsigned rel_scn:5; (V5.1 - ) unsigned lit_type:5; (V5.1 - ) unsigned litOFFSET:17; (V5.1 - ) } lituse; (V5.1 - ) struct { /* NO_RELOC, NO_LITUSE */ (V5.0 - ) unsigned type:5; (V5.0 - ) unsigned count:12; (V5.0 - ) unsigned dist:4; (V5.0 - ) unsigned :11; (V5.0 - ) } noreloc; (V5.0 - ) struct { /* IMMED: GP_HI32, SCN_HI32, BR_HI32 */ unsigned type:5; unsigned subop:6; unsigned br_offset:21; } immedhi; struct { /* IMMED: all other sub-opcodes */ unsigned type:5; unsigned subop:6; unsigned rel_scn:5; unsigned hi_offset:16; (V5.1 - ) } immedlo; struct { /* VADJUST */ unsigned type:5; signed adjust:27; } vadjust; struct { /* BRADDR, HINT */ unsigned type:5; unsigned rel_scn:5; unsigned :22; } other; } info; };
SIZE - 8 bytes, ALIGNMENT - 4 bytes
/* * Values for 'type' field. */ enum cmrlc_rlctypes { CMRLC_REFLONG=1, CMRLC_REFQUAD=2, CMRLC_GPREL32=3, CMRLC_GPDISP=4, CMRLC_BRADDR=5, CMRLC_HINT=6, CMRLC_SREL16=7, CMRLC_SREL32=8, CMRLC_SREL64=9, CMRLC_EXPRESSION=10, /* R_OP_* expression */ CMRLC_IMMEDHI=11, /* R_IMMED for high part */ CMRLC_IMMEDLO=12, /* R_IMMED for low part */ CMRLC_NO_RELOC=13, /* correct mispredicted relocation */ CMRLC_VADJUST=14, /* adjust base for succeeding 'v_offset's */ CMRLC_LITERAL=15, (V5.1 - ) CMRLC_LITUSE=16, (V5.1 - ) CMRLC_NO_LITUSE=17, (V5.1 - ) CMRLC_REFQUAD_EXTERN=18 /* external REFQUAD */ (V5.1 - ) }; /* * Maximum value for 'count' field in 'addrtype' relocations. */ #define CMRLC_COUNT_MAX ((1<<12) - 1) /* * Maximum value for 'dist' field in 'addrtype' and 'noreloc' relocations. */ #define CMRLC_DIST_MAX ((1<<4) - 1)
The number of elements in the array is determined by the corresponding
*_num
field
in the section header.
The
v_offset
field specifies the virtual
address of each relocation entry as a byte offset from a base address.
Initially,
the base is the starting virtual address of the current section.
If relocations
are required at addresses that cannot be expressed as a 32-bit offset from
the section's start address,
CMRLC_VADJUST
relocation entries are used to extend
the addressing range.
However, this feature is not fully supported.
The value of the
type
field determines how
to interpret the remainder of a compact relocation structure.
The
lda_offset
field specifies an instruction
offset (byte offset divided by 4) from the relocation entry's virtual address
to the
lda
instruction in an
R_GPDISP
entry's
ldah
/lda
pair.
This design does not support
ldah
/lda
pairs that are separated by more than 2^29 bytes.
The
rel_scn
field indicates the ID of the
section to which this relocation is relative.
It uses the
R_SN_*
values from the header file
reloc.h
.
The
count
and
dist
fields are used to specify consecutive relocation entries that are identical.
The
count
field can be used in this manner for
R_REFLONG
,
R_REFQUAD
,
R_SREL16
,
R_SREL32
,
R_SREL64
,
R_GPREL32
, and
R_LITERAL
entries.
Two relocation entries are
identical if they have the same type and relative section.
Two relocation
entries are consecutive if the difference in their virtual addresses is equal
to the
same multiple of the natural size for the relocation type (16 bits for
R_SREL16
; 32 bits for
R_REFLONG
,
R_SREL32
,
R_GPREL32
; and
R_LITERAL
, and 64 bits for
R_REFQUAD
and
R_SREL64
).
The
dist
field multiplied by the natural size of the relocation
type gives the byte distance between repetitions of the relocation.
A
count
value of zero is not allowed.
These fields reduce the
impact of mispredicting the relocations for jump tables.
4.4.2.5 Stack Relocation Table
Expression stack relocation information is stored separately. Each stack relocation table entry has the following structure:
struct cmrlc_file_expr { unsigned long vaddr; unsigned type:5; unsigned rel_scn:5; unsigned offset:6; /* CMRLC_EXPR_STORE only */ unsigned size:6; /* CMRLC_EXPR_STORE only */ unsigned last:1; /* true for last reloc in expr */ unsigned :9; unsigned reserved; };
SIZE - 16 bytes, ALIGNMENT - 8 bytes
/* * Values for 'type' field. */ enum cmrlc_exprtypes { CMRLC_EXPR_PUSH=1, /* R_OP_PUSH */ CMRLC_EXPR_PSUB=2, /* R_OP_PSUB */ CMRLC_EXPR_PRSHIFT=3, /* R_OP_PRSHIFT */ CMRLC_EXPR_STORE=4 /* R_OP_STORE */ };
Expression
stack compact relocation records are stored in a separate table because each
record requires more space than other types of compact relocation records.
Entries in this table are grouped into sequences of relocation entries that
form a single expression.
The first entry in each table starts a sequence.
The last entry in each sequence has its
last
field
set to one.
A new sequence starts immediately after the end of the previous
sequence.
The start of each sequence is referenced by a
CMRLC_EXPRESSION
entry in the section's compact relocation table.
The index field of that entry points
to the first entry in a stack relocation sequence.
All sequences in the stack
relocation table should have a corresponding
CMRLC_EXPRESSION
entry in the compact relocation table.
4.4.2.6 GP Value Tables
Additional tables called GP value tables are used to store GP range information. GP values are kept in tables separate from other compact relocations to reduce the processing required to map a virtual address to the corresponding active GP value.
Each GP value table consists of an array of these structures:
struct { unsigned long vaddr unsigned gp_offset unsigned reserved };
SIZE - 16 bytes, ALIGNMENT - 8 bytes
Each additional GP range after the first range has an entry in the table.
(The first range is described by the GP value in the file's
a.out
header.) Therefore,
a single-GOT program will have no entries in its GP value tables.
If an executable's sections have different numbers of GP ranges,
gpval_num
should be set to describe the section with the largest
number of ranges.
eCOFF sections with fewer GP ranges must still have GP value
tables with
gpval_num
entries.
Sections with short
GP value tables can duplicate their last GP value table entry until the table
is the proper length.
The
vaddr
field contains the virtual address
where the new range starts.
vaddr
must point within
the section to which this GP value table corresponds.
The new GP value is
computed by adding
gp_offset
to the GP value in
the file's
a.out
header.
4.4.3 Basic Algorithm for Compact Relocations Production
In order to produce compact relocations, a tool must have a set of actual relocation entries and the raw data to which those relocation entries apply. It should then apply the following algorithm to create a set of matching compact relocations:
Convert the external relocation entries to local relocation entries.
Run the prediction heuristic function to construct a set of predicted relocation entries from the raw data.
Compare the predicted relocation entries to the remaining actual relocation entries and create a compact relocation record for any mismatches.
Compress any sequences of consecutive, identical
R_REF*
,
R_SREL*
,
R_GPREL32
, or
R_LITERAL
entries.
Set the
rlc_sorted
field if the
compact relocation entries are stored in a sorted order.
Any
R_GPVALUE
entries must
be handled specially.
These relocation entries must be added to their section's
GP value table.
They should then be
removed from the list of actual relocation entries used to create compact
relocations.
The first step in the algorithm is to convert actual relocation entries
from external to local.
The compact relocations only exist in fully linked
executables with no undefined symbols.
Thus, external relocation entries
are not
usually needed.
(The compact relocation types include a type for retaining
external
R_REFQUAD
relocations wherever
symbol correspondence might be needed for post-link processing.) An external
relocation entry is converted to a local relocation entry by setting its
r_extern
field to zero and changing its
r_symndx
field to the appropriate relocation section constant (see
Table 4-1).
The second step is to run the prediction heuristic function over the raw data for which these actual relocation entries apply. This produces a set of predicted relocation entries.
Step three compares the predicted relocation entries to the actual relocation entries as follows:
If a match exists between a predicted relocation entry and an actual relocation entry at the same virtual address, do nothing.
If a predicted relocation entry and an actual relocation entry at the same virtual address do not match, write a compact form of the actual relocation entry to the compact relocation data file.
If only a predicted relocation entry exists for a particular
virtual address, write a compact
CMRLC_NO_RELOC
record to the data file at this virtual address.
If only an actual relocation entry exists for a particular virtual address, write a compact form of the actual relocation entry to the compact relocation data file.
Creating a compact relocation entry from an actual relocation entry
is
fairly straightforward except in the case of an expression stack relocation
sequence.
First, create entries in the stack relocation table for each relocation
entry in the sequence.
Normally, this sequence starts with an
R_OP_PUSH
entry and ends with an
R_OP_STORE
entry.
The last entry should have
the
last
field set to one.
Then create a
CMRLC_EXPRESSION
compact relocation entry whose
index field points to the first entry in the stack relocation table for this
expression.
(This can only be done for a sequence that describes a complete
expression.)
The fourth step is to compress any sequences of
R_REF*
,
R_SREL*
,
R_GPREL32
, or
R_LITERAL
entries that are consecutive and identical .
Such a
sequence exists if all relocation entries in the sequence have the same relocation
type,
are relative to the same rel_scn value (
R_SN_*
constant), and have v_offset fields that increase by a multiple
of the natural size of the relocation type (for example, 8 bytes for
R_REFQUAD
, 2 bytes for
R_SREL16
).
Such sequences can be replaced with a single compact
relocation entry that has the sequence's
type
and
rel_scn
value.
The
v_offset
field
should be that of the first relocation entry in the sequence.
The
dist
field should be set to the distance between repeated relocations
in natural size increments, and the
count
field
should be set to the number of relocation entries in the sequence.
The final step is to set the
rlc_sorted
field
in the compact relocation section header.
If the compact relocations are stored in order of increasing
v_offset
values, this field should be set to one.
Otherwise,
it should be set to zero.
4.4.4 Basic Algorithm for Compact Relocations Consumption
A consumer tool can read back the compact relocation entries if it has the compact relocation information and the raw data that they describe. The consumer tool can use this information to regenerate the actual relocation entries by following this algorithm:
Expand any
R_REF*
,
R_SREL*
,
R_GPREL32
, or
R_LITERAL
compact
relocation entries whose
count
field is greater
than one.
Run the prediction heuristic function to construct a set of predicted relocation entries from the raw data.
Compare the predicted relocation entries to the compact relocation entries and reconstruct the actual relocation entries.
The first step in this algorithm just undoes the compression step (step four) in the production algorithm.
The second step runs the same prediction heuristic that was used in the production algorithm. To guarantee that the generated predicted relocation entries are the same as when the compact relocation entries were produced, it is critical that the heuristic function is the same. It is also critical that the raw data is the same as when the compact relocation entries were produced.
The final step compares the predicted relocation entries with the stored compact relocation entries as follows:
If only a predicted relocation entry exists for a particular virtual address, report the predicted relocation entry.
If a
CMRLC_NO_RELOC
entry exists at the same virtual address as a predicted relocation entry,
do not report a relocation entry at this virtual address.
If a compact relocation entry other than
CMRLC_NO_RELOC
exists at the same virtual address as a predicted
relocation entry, report the compact relocation entry.
If only a compact relocation entry exists for a particular virtual address, report the compact relocation entry.
Version Note Linkerdef relocations are supported in Tru64 UNIX V5.1 and greater for symbol table format V3.13 and greater.
Linkerdef relocations
are generated by the linker for all fully linked
executable objects and shared libraries.
They
are not produced for images linked with the following linker options:
-r,
-s.
The
strip
utility will remove the comment subsection that
contains linkerdef relocations.
See
Chapter 7
for the format
of the
.comment
section.
The linkerdef
relocations supplement compact relocation information.
They provide relocation information
for all uses of linker-defined symbol values within the section data of an
object.
This information is not currently accessible in compact relocation
information.
Compact relocations are generally
stored as local relocations with no symbolic
information.
Linkerdef relocations
are also unique because they contain relocations for absolute
symbols with literal values such as
_DYNAMIC_LINK
and
_procedure_table_size
.
Tools that modify linked objects, such as
om
and
spike
, can use linkerdef relocations to update
references to linker-defined symbol values that are necessarily changed as
a result of other changes made to the linked object.
4.6 Language-Specific Relocations Features
Relocation entries may be generated for language-specific compiler-generated
external symbols.
For example, they are
often generated in Fortran programs for the procedure
for_set_reentrancy()
and in C++ programs for exception-handling labels.