I've read this article about Position Independent Code, and this is what I got (focusing on function calls): When a shared library is built and linked, it is unknown to what memory address it will be loaded, and that's why we use Position Independent Code (PIC).
One of the mechanisms in PIC is the use of PLT (Procedure Linkage Table) for calling functions in a way that our code remains position independent, and it works basically like this: For each function we call (func
) in our library, there's a func@plt
small procedure, which is the one actually being called. This procedure then jumps to an address stored in a corresponding entry in the GOT. First, this address will point back to the PLT entry which will then call the dynamic linker resolver to resolve the actual function's address. The dynamic linker will now override the entry in the GOT to point to the correct actual function.
Now, all this is possible since when linking the shared library, the distance between the instruction that calls func
and the func@plt
is known, and also the distance to the entry in the GOT. All relative and great !
My question is: I can understand why wanting to have this mechanism for function calls in the file linking against the shared library: this is in order to only resolve function addresses when they are requested. But I don't understand why is this needed within the shared library itself!
Imagine we have a function func
in the shared library, calling func2
. The distance between func
and func2
is known at the stage of static linking, so we can compute the position of func2
relatively to the instruction pointer, just as we do to find the func2@plt
.