SPRAB89A September 2011 – March 2014
For large programs, load-time symbol resolution can significantly degrade program startup time. Lazy binding is a mechanism that delays resolution of function symbols until they are actually called by the program, thus reducing startup time and improving overall performance since only functions that are actually called need to be resolved.
The general approach is that the first call through a PLT vectors control through a resolver function in the dynamic linker, which performs the resolution and re-routes future calls directly to the function itself.
The resolver requires two arguments. The first is a module id that identifies the current module (the one containing the reference). The representation of the module id is unspecified by the ABI, to be determined by the loader. The second argument specifies the relocation entry corresponding to the target function. The relocation entry in turn provides both the name of the target symbol, and the location of the reference in the GOT. The relocation entry is specified by its byte offset in the object file from the address in the DT_RELPLT tag in the file's .dynamic section.
Since all this happens behind the caller's back, the mechanism must preserve any state that affects the standard function-call interface. In particular, it must not disturb any registers used for argument passing or the return address register, and it must preserve any callee-saved registers it modifies. To avoid disturbing the normal argument registers, the resolver's two arguments are passed in B0 and B1.
Two slots in the Global Offset Table are reserved for use by the dynamic loader to implement lazy binding. GOT[0] is used by the loader to hold the address of the resolver function. GOT[1] is used to hold the module id.
The following sequence describes the mechanism:
Lazy Binding PLT Entry
$sym$plt:
MVK reloc_offset(sym),B0 ;byte offset of GOT reloc entry from DT_RELPLT
MVKH reloc_offset(sym),B0
LDW *+DP($GOT(sym)),tmp ;&PLT0 first time, &sym after that
B tmp
Resolver Stub—PLT0
PLT0:
LDW *+DP($GOT(0)),tmp ; address of resolver
LDW *+DP($GOT(4)),B1 ; module id
B tmp ; tail-call resolver
Global Offset Table
; $GOT(0) reserved, initialized to module id
; $GOT(4) reserved, initialized to &resolver function
; ...
; $GOT(sym) R_C6000_JUMP_SLOT initialized to &PLT0
; updated to &sym by resolver