[parisc-linux] PIC code generation in gcc/binutils
Cary Coutant
cary@cup.hp.com
Mon, 24 Jul 2000 16:58:47 -0700
>I was hoping to write up a preliminary ABI specification based on the
>64-bit ELF implementation on HP/UX, so I've been trying to find
>detailed specifications on how the ELF64 ABI actually works but so far
>have not come up with much information from HP's documentation. The
>64-bit runtime architecture document has some useful information, but
>I suspect I'll have to look at the actual implementation to nail down
>the details.
As the HP-UX Runtime Architect, I'll be happy to answer any questions you
may have on the runtime architecture. I realize that the 64-bit runtime
architecture is weak in the dynamic loading area, but I'll try to make up
for that by answering questions in this forum.
>One thing I am sure of is that if we try to follow the HP/UX ELF64
>specification for dynamic linking on 32-bit Linux we are going to be
>substantially different from other Linux/ELF platforms. In
>particular, the handling of inter-module calls and function pointers,
>and the management of the GP, are done in a totally different way from
>all the other platforms I've encountered (i386, m68k, alpha).
>(i.e. inter-module calls are handled by another set of stubs, and GP
>management is done by the caller via the function descriptors, rather
>than by the callee with GPDISP and similar relocations)
The model used for PA-RISC is a a consequence of the segmented
architecture, where the text and data segments are not adjacent. Since
the PA-RISC sharing model is based on global virtual addresses, the text
and data segment are loaded in separate quadrants of the address space so
that the text can be shared and the data can be process-private. As a
result, a procedure cannot materialize its own gp, since there is no
fixed pc-relative offset between the text and data. This means that the
caller must materialize the gp prior to the call, or as part of the call.
By the way, this model is also being used for IA-64. You may be able to
leverage some of the work being done for ld.so on that platform.
It shouldn't really complicate the dynamic loader that much, though. A
function pointer is still essentially a function pointer, and behaves the
same as in the other model, even though it points to a 128-bit descriptor
rather than an actual function. The linker needs to allocate a GOT entry
for each import stub (aka "proxy") it creates, and attach a dynamic FPTR
relocation to that GOT entry. The dynamic loader needs to create the
function descriptor when it processes the FPTR relocation.
Lazy binding requires a bit of cleverness. We do it by dynamically
creating lazy-binding stubs that load a module id and a PLT index into
registers, then branch to a common bind-on-reference routine.
Cary Coutant
HP-UX Runtime Architect