| United States-English |
|
|
|
![]() |
HP-UX Linker and Libraries User's Guide: HP 9000 Computers > Chapter 7 Position-Independent Code Generating Position-Independent Code |
|
To be position-independent, object code must restrict all references to code and data to either PC-relative or indirect references, where all indirect references are collected in a single linkage table that can be initialized on a per-process basis by dld.sl. Register 19 (%r19) is the designated pointer to the linkage table. The linker generates stubs that ensure %r19 always points to the correct value for the target routine and that handle the inter-space calls needed to branch between shared libraries. The linker generates an import stub for each external reference to a routine. The call to the routine is redirected to branch to the import stub, which obtains the target routine address and the new linkage table pointer value from the current linkage table; it then branches to an export stub for the target routine. In 32-bit mode, the linker generates an export stub for each externally visible routine in a shared library or program file. The export stub is responsible for trapping the return from the target routine in order to handle the inter-space call required between shared libraries and program files.
Shown below is the PIC code generated for import and export stubs. Note that this code is generated automatically by the linker; you don't have to generate the stubs yourself.
The remainder of this section describes how compilers generate PIC for the following addressing situations: You can use these guidelines to write assembly language programs that generate PIC object code. For details on assembly language, refer to the Assembler Reference Manual and PA-RISC 2.0 Architecture. The linkage table pointer register, %r19, must be stored at %sp-32 by all PIC routines. This can be done once on procedure entry. %r19 must also be restored on return from a procedure call. The value should have been stored in %sp-32 (and possibly in a callee-saves register). If the PIC routine makes several procedure calls, the routine should copy %r19 into a callee-saves register as well, to avoid a memory reference when restoring %r19 upon return from each procedure call. Just like %r27 (%dp), the compilers treat %r19 as a reserved register whenever PIC mode is in effect. In general, references to code are handled by the linker, and the compilers act differently only in the few cases where they would have generated long calls or long branches. References to data, however, need a new fixup request to identify indirect references through the linkage table, and the code generated will change slightly.
When linking files produced by the assembler, the linker exports only those assembly language routines that have been explicitly exported as entry (that is, symbols of type ST_ENTRY). Compiler generated assembly code does not explicitly export routines with the entry type specified, so the assembly language programmer must ensure that this is done with the .EXPORT pseudo-op. For example: In assembly language, a symbol is exported using .EXPORT foo, type where type can be code, data, entry, and others. To ensure that foo is exported from a shared library, the assembly statement must be:
Normally, the compilers generate a single-instruction call sequence using the BL instruction. The compilers can be forced to generate a long call sequence when the module is so large that the BL is not guaranteed to reach the beginning of the subspace. In the latter case, the linker can insert a stub. The existing long call sequence is three instructions, using an absolute target address:
When the PIC option is in effect, the compilers must generate the following instruction sequence, which is PC-relative:
Long branches are similar to long calls, but are only two instructions because the return pointer is not needed:
For PIC, these two instructions must be transformed into four instructions, similar to the long call sequence:
The only problem with this sequence occurs when the long branch is in a switch table, where each switch table entry is restricted to two words. A long branch within a switch table must allocate a linkage table entry and make an indirect branch:
Here, the T' operator indicates a new fixup request supported by the linker for linkage table entries. ASSIGN statements in FORTRAN must be converted to a PC-relative form. The existing sequence forms the absolute address in a register before storing it in the variable:
This must be transformed into the following four-instruction sequence:
References to literals in the text space are handled exactly like ASSIGN statements (shown above). The LDO instruction can be replaced with LDW as appropriate. An opportunity for optimization in both cases is to share a single label (L) throughout a procedure, and let the result of BL become a common sub-expression. Thus only the first literal reference within a procedure is expanded to three instructions; the rest remain two instructions. References to global or static variables currently require two instructions either to form the address of a variable, or to load or store the contents of the variable:
These sequences must be converted to equivalent sequences using the linkage table pointer in %r19:
Note that the T' fixup on the LDW instruction allows for a 14-bit signed offset, which restricts the DLT to be 16Kb. Because %r19 points to the middle of the DLT, we can take advantage of both positive and negative offsets. The T' fixup specifier should generate a DLT_REL fixup proceeded by an FSEL override fixup. If the FSEL override fixup is not generated, the linker assumes that the fixup mode is LD/RD for DLT_REL fixups. In order to support larger DLT table sizes, the following long form of the above data reference must be generated to reference tables that are larger. If the DLT table grows beyond the 16Kb limit, the linker emits an error indicating that the user must recompile using the +Z option which produces the following long-load sequences for data reference:
The compilers already mark procedure label constructs so that the linker can process them properly. No changes are needed to the compilers. When building shared libraries and incomplete executables, the linker modifies the plabel calculation (produced by the compilers in both shared libraries and incomplete executables) to load the contents of a DLT entry, which is built for each symbol associated with a CODE_PLABEL fixup. In shared libraries and incomplete executables, a plabel value is the address of a PLT entry for the target routine, rather than a procedure address; therefore $$dyncall must be used when calling a routine with a procedure label. The linker sets the second-to-last bit in the procedure label to flag this as a special PLT procedure label. The $$dyncall routine checks this bit to determine which type of procedure label has been passed, and calls the target procedure accordingly. In order to generate a procedure label that can be used for shared libraries and incomplete executables, assembly code must specify that a procedure address is being taken (and that a plabel is wanted) by using the P' assembler fixup mode. For example, to generate an assembly plabel, the following sequence must be used:
This code sequence generates the necessary PLABEL fixups that the linker needs in order to generate the proper procedure label. The dyncall millicode routine in /usr/lib/milli.a must be used to call a procedure using this type of procedure label; that is, a BL or BV will not work). |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||