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 three distinct representations:
.comment
section. The first two forms of relocation information are discussed in this chapter. Note that the discussion of the second form is limited to Section 4.4. The third form is covered in Chapter 6. Figure 4-1 summarizes which kinds of objects contain which kinds of relocation information.
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.
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.
Version 3.13 of the object file format does not introduce any new relocations features.
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
r_symndx
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.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.3 for more information.
R_LITUSE
, this field contains a subtype. See Table 4-3.r_type
r_extern
r_offset
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
r_size
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.
Symbol |
Value |
Description |
|
0 |
no section |
|
1 |
|
|
2 |
|
|
3 |
|
|
4 |
|
|
5 |
|
|
6 |
|
|
7 |
|
|
8 |
|
|
9 |
|
|
10 |
|
|
11 |
|
|
12 |
|
|
13 |
|
|
14 |
for |
|
15 |
|
|
16 |
|
|
17 |
|
|
18 |
|
Symbol |
Value |
Description |
|
0x0 |
Relocation already performed. |
|
0x1 |
Identifies a 32-bit reference to symbol's virtual address. |
|
0x2 |
Identifies a 64-bit reference to symbol's virtual address. |
|
0x3 |
Identifies a 32-bit displacement from the global pointer to a symbol's virtual address. |
|
0x4 |
Identifies a reference to a literal in the literal address pool as an offset from the global pointer. |
|
0x5 |
Identifies an instance of a literal address previously loaded into a register. |
|
0x6 |
Identifies an |
|
0x7 |
Identifies a 21-bit branch reference to the symbol's virtual address. |
|
0x8 |
Identifies a 14-bit |
|
0x9 |
Identifies a 16-bit self-relative reference to symbol's virtual address. |
|
0xa |
Identifies a 32-bit self-relative reference to symbol's virtual address. |
|
0xb |
Identifies a 64-bit self-relative reference to symbol's virtual address. |
|
0xc |
Identifies a 64-bit virtual address to push on the relocation expression stack. |
|
0xd |
Identifies an address to store the value popped from the relocation expression stack. |
|
0xe |
Identifies a symbol's virtual address to subtract from value at the top of the relocation expression stack. |
|
0xf |
Identifies the number of bit positions to shift the value at the top of the relocation expression stack. |
|
0x10 |
Specifies a new gp value to be used for the address range starting with the address specified by the |
|
0x11 |
Identifies the most significant 16 bits of a 32-bit from the global pointer to a symbol's virtual address. |
|
0x12 |
Identifies the least significant 16 bits of a 32-bit from the global pointer to a symbol's virtual address. |
|
0x13 |
Indicates an instruction sequence that calculates an address. |
|
0x14 |
Identifies the instruction that loads the TLS key. |
|
0x15 |
Identifies the most significant 16 bits of a 32-bit from the TLS region pointer to a symbol's virtual address |
|
0x16 |
Identifies the least significant 16 bits of a 32-bit from the TLS region pointer to a symbol's virtual address. |
Table Notes
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.
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.
Symbol |
Value |
Description |
|
1 |
The base register of a memory format instruction (except |
|
2 |
Should not be used. |
|
3 |
The target register of a |
Symbol |
Value |
Description |
|
1 |
16-bit displacement from GP value |
|
2 |
Most significant 16 bits of 32-bit displacement from GP value |
|
3 |
Most significant 16 bits of 32-bit displacement from section start |
|
4 |
Most significant 16 bits of 32-bit displacement from instruction following branch |
|
5 |
Least significant 16 bits of 32-bit displacement specified by last |
.comment
section)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.
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_nrelocs
. If that field overflows, the section header flag S_NRELOCS_OVFL
is set and the first relocation entry's r_symndx
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.
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 drivers, which are object files that are dynamically added to a running kernel. Information is available in the System Administration Guide.
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.
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 whenever necessary to prevent it from becoming outdated. 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.
Relocation entries are used for several purposes:
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 symbols 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.
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.
A local relocation entry has its r_extern
flag cleared and tracks references by section.
Figure 4-6 shows a sample local 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.
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.
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.
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_GP_VALUE
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.
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.
Relocations types can be grouped into the following categories:
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:
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.
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.
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.
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
.
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.
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_32
R_IMMED_SCN_HI32
R_IMMED_BR_HI32
R_IMMED_LO32
R_IMMED_GP_16
and R_IMMED_GP_32
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.
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.
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
GP
GP
value; begins as the contents of aouthdr.gp_value
for the final object. new_scn_addr
old_GP
aouthdr.gp_value
for the input object. old_scn_addr
s_vaddr
in the section header of the input object file for the tracked section of a local relocation entry. [r_vaddr]
r_vaddr
; to be distinguished from the address itself. SEXT
stack
this_new_addr
r_vaddr
will be after relocation .this_new_scn_addr
r_vaddr
will be after relocation, as calculated by the linker.this_old_scn_addr
s_vaddr
in the section header of the input object file for the section containing r_vaddr.
tos
result
r_vaddr
in the object file that the linker is producing. Fields
|
Number of relocation entries if |
|
Unused. |
|
Unused. |
|
Unused. |
|
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>
Fields
|
Points to target address. |
|
External symbol index if |
|
Either 0 or 1. |
|
Unused. |
|
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
Fields
|
Points to target address. |
|
External symbol index if |
|
Either 0 or 1. |
|
Unused. |
|
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 an item 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.
Fields
|
Points to a 32-bit GP-relative value. |
|
External symbol index if |
|
Either 0 or 1. |
|
Unused. |
|
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
Fields
|
Points to a load instruction in the text segment. The value to be relocated is the memory displacement from the |
|
R_SN_LITA |
|
Must be zero; all |
|
Unused. |
|
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
Fields
|
Points to memory-format instruction. |
|
R_LU_BASE |
|
Must be zero; all |
|
Unused. |
|
Unused. |
Operation
Check if displacement is within 16 or 32 bits. The displacement is calculated:
new_lit = [relocated literal belonging to correponding 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_GP16
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
Fields
|
Points to jump instruction (in text segment). |
|
R_LU_JSR |
|
Must be zero; all |
|
Unused. |
|
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:
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. Optimization cannot be done for external symbols that are weak symbols in a dynamic executable, hidden symbols in a shared library, or unresolved.
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
Fields
|
Points to the first of a pair of instructions: |
|
Contains the unsigned byte offset from the instruction indicated in |
|
Must be zero; all |
|
Unused. |
|
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 be a local relocation.
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.
Fields
|
Points to a branch instruction. |
|
External symbol index if |
|
Either 0 or 1. |
|
Unused. |
|
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
An example that will result in production of this type of relocation is a procedure call of a static function:
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
Fields
|
Points to jump-format instruction. |
|
External symbol index if |
|
Either 0 or 1. |
|
Unused. |
|
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.
Fields
|
Points to a 16-bit self-relative value. |
|
External symbol index if |
|
Either 0 or 1. |
|
Unused. |
|
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.
Fields
|
Points to a 32-bit self-relative value. |
|
External symbol index if |
|
Either 0 or 1. |
|
Unused. |
|
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.
Fields
|
Points to a 64-bit self-relative value. |
|
External symbol index if |
|
Either 0 or 1. |
|
Unused. |
|
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.
Fields
|
0 if |
|
External symbol index if |
|
Either 0 or 1. |
|
Unused. |
|
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, withone 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 foo
's code range descriptor:
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)
Fields
|
Location to store calculated bit field. |
|
Section index of containing section. |
|
Must be 0. |
|
Bit offset from |
|
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. It should be noted that bits are numbered differently depending on the endian-ness of the object.
Example
An example of the R_OP_STORE
entry is given in Section 4.3.4.14.
Fields
|
0 if |
|
External symbol index if |
|
Either 0 or 1. |
|
Unused. |
|
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.
Fields
|
0 if |
|
External symbol index if |
|
Either 0 or 1. |
|
Unused. |
|
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 is not currently used by the system compiler. A potential use of this relocation type would be 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 R_SN_ABS 0x0000000000000040 1 STORE 0 14 local .text
Fields
|
Starting virtual address for new GP value. |
|
Constant that is added to the GP value in the |
|
Must be zero; all |
|
Unused. |
|
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
Fields
|
Points to a memory format instruction ( |
|
External symbol index if |
|
Either 0 or 1. |
|
Unused. |
|
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
Fields
|
Points to memory format instruction ( |
|
Must match |
|
Must match |
|
Unused. |
|
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
Fields
|
Points to memory-format instruction. |
|
External symbol index if |
|
Either 0 or 1. |
|
Unused. |
|
|
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
Fields
|
Points to memory-format instruction. |
|
Unused. |
|
Unused. |
|
Unused. |
|
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
Fields
|
Points to memory-format instruction. |
|
Unused. |
|
Unused. |
|
Unused. |
|
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
Fields
|
Points to a memory-format instruction following a branch ( |
|
Specifies a byte offset from |
|
Unused. |
|
Unused. |
|
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
Fields
|
Points to a memory-format instruction. |
|
External symbol index if |
|
Either 0 or 1. |
|
Unused. |
|
|
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
Fields
|
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. |
|
|
|
Must be zero; all |
|
Unused. |
|
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 __tls_offset
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
Fields
|
Points to memory-format instruction. |
|
External symbol index if |
|
Either 0 or 1. |
|
Unused. |
|
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
.
Fields
|
Points to memory-format instruction. |
|
External symbol index if |
|
Either 0 or 1. |
|
Unused. |
|
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
, -om
, or -ncr
. 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.
The current implementation contains only enough relocation information to drive tools that restructure an executable's .text
, .init
, and .fini
sections. It is sufficient for compact relocations to handle text segment relocations only because the current consumers (Atom-based tools) change only these sections. There is currently no algorithm to predict data relocations.
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.
The procedure for creation of compact relocations is as follows:
The procedure for the use of compact relocation records follows:
See Section 4.4.3 for more details.
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:
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.
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 whenever a change in the compact relocation algorithms affects the external interface. For example, adding support for data-related relocation information would require the major version identifier to be incremented. Simple bug fixes that correct problems with the external interface should not cause the major version identifier to be incremented.
The minor version identifier is incremented whenever the compact relocation algorithms change without affecting the external interface. 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 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.
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.
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 :10; } addrtype; 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 :16; } 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, /* unpredicted R_REFLONG */ CMRLC_REFQUAD=2, /* unpredicted R_REFQUAD */ CMRLC_GPREL32=3, /* unpredicted R_GPREL32 */ CMRLC_GPDISP=4, /* unpredicted R_GPDISP */ CMRLC_BRADDR=5, /* unpredicted R_BRADDR */ CMRLC_HINT=6, /* unpredicted R_HINT */ CMRLC_SREL16=7, /* unpredicted R_SREL16 */ CMRLC_SREL32=8, /* unpredicted R_SREL32 */ CMRLC_SREL64=9, /* unpredicted R_SREL64 */ CMRLC_EXPRESSION=10, /* unpredicted R_OP_* expression */ CMRLC_IMMEDHI=11, /* unpredicted R_IMMED for high part */ CMRLC_IMMEDLO=12, /* unpredicted R_IMMED for low part */ CMRLC_NO_RELOC=13, /* correct mispredicted relocation */ CMRLC_VADJUST=14, /* adjust base for succeeding 'v_offset's */ CMRLC_TLS_HIGH=15, /* unpredicted R_TLS_HIGH */ CMRLC_TLS_LOW=16 /* unpredicted R_TLS_LOW */ }; /* * Maximum value for 'count' field in 'addrtype' relocations. */ #define CMRLC_COUNT_MAX ((1<<12) - 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 entrys 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
field is 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
, and R_GPREL32
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 natural size for the relocation type (16 bits for R_SREL16
; 32 bits for R_REFLONG
, R_SREL32
, and R_GPREL32
; and 64 bits for R_REFQUAD
and R_SREL64
). A count
value of zero is not allowed. The count
field reduces the impact of mispredicting the relocations for jump tables.
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.
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.
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:
.text
, .init
, or .fini
sections.
R_REF*
, R_SREL*
,or R_GPREL32
entries.
rlc_sorted
field if the compact relocation entries are stored in a sorted order.The tool should first remove any actual relocation entries that are not needed to describe the .text
, .init
, or .fini
sections. Compact relocation entries describe only these sections, so any others should be removed to save space. In general, any relocation entry relative to one of these sections must be saved. Also, any self-relative relocation entry that points inside one of these sections must be saved. Because R_GPDISP
entries point to instructions that are implicitly relative to text addresses, any R_GPDISP
entries within the .text
, .init
, or .fini
sections must also be preserved. Finally, any R_REFLONG
, R_REFQUAD
, and R_GPREL32
entries in the .text
, .init
, or .fini
sections must be saved because these relocation entries would indicate the presence of address constants in these sections. Note that R_LITERAL
and R_LITUSE
entries describe addresses in the .lita
or .got
section, so they do not need to be saved.
A tool must take special care when analyzing expression stack (R_OP_*
), R_IMMED
, and R_GPRELHIGH/R_GPRELLOW
entries. It is not possible to determine if one of these entries needs to be saved without analyzing it in the context of its other related relocation entries. For instance, an expression stack relocation must be saved if any relocation in its expression is relative to the .text
, .init
, or .fini
sections. The same is true for sequences of R_IMMED
entries or sequences of R_GPRELHIGH/R_GPRELLOW
entries.
Any R_GPVALUE
entries must also 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 second step in the algorithm is to convert any remaining 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 needed. 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 R_SN_*
constant.
The third 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.
Then compare the predicted relocation entries to the actual relocation entries as follows:
CMRLC_NO_RELOC
record to the data file at this virtual address.
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 an 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 fifth step is to compress any sequences of R_REF*
, R_SREL*
, or R_GPREL32
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 the natural size of the relocation type (for example, 8 bytes for REFQUAD
, 2 bytes for 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, 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.
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:
R_REF*
, R_SREL*
, or R_GPREL32
compact relocation entries whose count field is greater than one.
The first step in this algorithm just undoes the compression step (step five) 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:
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.
CMRLC_NO_RELOC
exists at the same virtual address as a predicted relocation entry, report the compact relocation entry.
The basic strategy for compact relocations consumption is to step through both the predicted relocation entries and the stored compact relocation mismatch data for a given section in order to reconstruct the actual relocation entries for that section.
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.