|
|
Any code which is PIC or which makes calls to PIC must follow the standard
procedure call mechanism. In addition, register gr19 (the linkage table pointer
register) must be stored at sp-32 by all PIC routines. This should be done once
upon procedure entry. Register gr19 must also be restored upon return from each
procedure call, even if gr19 is not referenced explicitly before the next
procedure call. The LTP register, gr19, is used by the import stubs and must be
valid at all procedure call points in position independent code. If the PIC
routine makes several procedure calls, it may be wise to copy gr19 into a
callee-saves register as well, to avoid a memory reference when restoring gr19
upon return from each procedure call. As with gr27 (DP), the compilers must
treat gr19 as a reserved register whenever position-independent code is being
generated.
5.3.1 Long Calls
Normally, the compilers generate a single-instruction call sequence using the
BL instruction. The compilers will generate a long call sequence if the user
explicitly requests long branch generation via a command-line option, or if the
module is so large that the BL is not guaranteed to reach the beginning of the
subspace (where a stub can be inserted by the linker). The existing long call
sequence is three instructions, using an absolute target address:
LDIL L'target,r1 ; load target address into r1
BLE R'target(sr4,r1) ; branch to target address
COPY r31,rp ; copy return address (link register)
; into rp
When the PIC option is in effect, the following seven-instruction sequence,
which is PC-relative, must be used:
BL .+8,rp ; get PC into RP
ADDIL L'target - $L0 + 4, rp ; add PC-reI offset to RP
LDO R'target - $L1 + 8(r1), r1
$L0: LDSID (r1), r31
$L1: MTSP r31, sr0
BLE 0(sr0,r1)
COPY r31,rp
5.3.2 Procedure Labels and Dynamic Calls
The HP PA-RISC compilers generate the code sequence required for proper
handling of procedure labels and dynamic procedure calls. Assembler programmers
must use the same code sequence, described below, in order to insure proper
handling of procedure labels and dynamic procedure calls.
A procedure label is a specially-formatted variable that is used to link
dynamic procedure calls. The format of a procedure label is shown below:
The X field in the address section of the procedure label is the XRT flag,
which is used for MPE XL procedure labels to determine whether the call is
local (off) or external (on). On HP-UX the L field is used to flag whether the
procedure label is a pointer to an LT entry (L-field is on) or to the entry
point of the procedure.
The plabel calculation produced by the compilers in both shared libraries and
incomplete executables is modified by the linker, when building shared
libraries and incomplete executables, to load the contents of an LT 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 (Procedure Linkage Table) entry for the target routine, rather than a
procedure address; therefore a utility routine named $$dyncall must be
used when calling a routine via a procedure label. The linker sets the L field
(second-to-last bit) in the procedure label to flag this as a special PLT
procedure label. The $$dyncall routine checks this field to determine
which type of procedure label has been passed, and calls the target procedure
accordingly. The $$dyncall routine assumes that the X field is always 0.
The following pseudo-code sequence shows the process used by $$dyncall
to perform dynamic calls:
IF (L-field in Plabel) = 0 THEN
Perform interspace branch using Plabel as target address;
ELSE BEGIN
Clear L-field;
Load new LTP value into gr19;
Load address of target;
Save RP';
Perform interspace branch to target address;
END.
In order to generate a procedure label that can be used for shared libraries
and incomplete execu tables, assembly code must specify that a procedure
address is being taken (and that a plabel is wanted) by using the P' assembler
fix up mode. For example, to generate an assembly plabel, the following
sequence must be used:
; Take the address of a function
LDIL LP'function,r1
LDO RP'function(r1), r22
This code sequence will generate the necessary PLABEL fixups that the linker
needs in order to generate the proper procedure label. The $$dyncall
millicode routine in /lib/milli.a must be used to call a procedure using this
type of procedure label (i.e. a BL/BV will not work). For example:
; Now to call the routine using a plabel
BL $$dyncall, 31 ; r22 is the input register for $$dyncall
COPY r31, r2
The compilers generate the necessary code sequence required for proper handling
of procedure labels.
|