'GCC: PLT call missing for non-library
Lets say I have a code.c with two ordinary functions outer and inner.outer calls inner.
I use GCC 11.2 on Linux, x86-64.
If I compile a shared lib withgcc -shared -fPIC -O3 code.c
and look at the disassembly ofobjdump -d a.out
I can see that the ´inner´ call withoin outer uses the PLT and is not inlined.
Thats fine and how it should be now even inner-library calls can eg. replaced by LD_PRELOAD.
If I add a main function and compile an executable insteadgcc -fPIE -O3 code.c
the call is inlined (if small enough etc.) an doesn`t use the PlT.
Fine too.
My problem is this call, a non-library executable with fPICgcc -fPIC -O3 code.c
Now the inner´ call does not use the PLT (but is not inline either). The unlinked asm (gcc call with -S) still uses the PLT, just the full binary and its disassembly not anymore. Adding an explicit -fsemantic-interposition` does not help.
Questions
How can I have PLT calls in my program that is not a library so that things like LD_PRELOAD work even for the functions there?
And whats the point of the non-shared fPIC behaviour to prevent inlining without using the PLT?
Solution 1:[1]
I misunderstood some thing about ld.so before. Functions in the main executable (ie. the startable program, not shared libraries) are never replacable, therefore using the PlT is useless.
How ld.so searches for functions
For PLT function calls, it always uses this search order and takes the first function it finds:
- If a function with that name is available in main executable, this one wins
- If a LD_PRELOAD shared lib was specified, it is checked next.
- Then all normal shared libs are checked, in the order that was specified during linking.
(In each case, only functions in dynsym with global/weak visibility are considered).
No PRELOAD and no linking with -lsomething before the main code files will change anything about it, the main program always comes first.
This implies that a PLT lookup from the main program, for a function that exists there already, will always find its own function. Therefore no PLT lookup is necessary, and not doing it improves performance.
Dynsym availability
Unlike shared libraries, startable programs don't need all of their global functions listed in dynsym. There are several reasons why a function might be listed, but usually some are missing too.
As long as this behaviour is kept, a PlT lookup from the main program might not even find its own function, therefore again no PLT is better.
And what about the missing inline optimizations?
Turned out to be sort of trivial:
When compiling with -fPIC, it is not yet clear if that file will later be linked into a startable program or a shared library. Therefore it goes all the way to make it library-suitable: PLT and no inlining.
If it is then linked into a library, that's fine.
For an executable, the linker then removes the PLT indirection again - but it doesn't care about inlining-or-not.
Meanwhile with -fPIE, the compiler already knows that this will not become a library, and can do inlining and calls without PLT (at least some of them, and the linker reconverts the rest).
To have inlining, either pay attention to use fPIC only for libraries and fPiE only for executables, or turn on LTO (-flto) which can fix the "missing" inlining after it was made.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | mount |
