How does this test-suite failure manifest?
It manifests as a failure in the following test-case:
elf/check-localplt.out
What is this test for?
GLIBC needs to maintain internal consistency and stability, especially in the libc and libm libaries. If libc accesses it's own symbols via a PLT call then if a user overrides a symbol GLIBC will invoke that overridden symbol and potentially destabilize the library. Therefore, applications are prevented from impacting GLIBC internally by making GLIBC directly call internal, hidden versions of all of its symbols. Only expressly allowed symbols may be overridden, and called from within libc, e.g. malloc.
These expressly allowed symbols are denoted in the following files:
scripts/data/localplt-i386-linux-gnu.data scripts/data/localplt-generic.data scripts/data/localplt-powerpc-linux-gnu.data scripts/data/localplt-powerpc64-linux-gnu.data
Additionally, PLT calls are expensive (more-so on some architectures than other) compared to direct branches/calls to functions so they should be avoided if possible.
The check-localplt test case ensures that no PLT calls from within libc to other libc functions are introduced.
What's a failure look like?
--- ../scripts/data/localplt-i386-linux-gnu.data 2006-01-11 21:06:19.000000000 +0000 +++ - 2008-11-30 20:52:09.962033876 +0000 @@ -1,4 +1,5 @@ libc.so: _Unwind_Find_FDE +libc.so: __bzero libc.so: calloc libc.so: free libc.so: malloc
This indicates that one or more invocations of the symbol __bzero via the PLT have been introduced into GLIBC erroneously.
Potential Causes
There are a few potential causes for this particular error:
- The symbol may be new and not have the proper hidden symbol macros defined for it.
libc should invoke a hidden version of the symbol rather than the PLT version.
- The symbol may not be intended for invocation internally.
Problem Determination
Search through the GLIBC source and look for usage of __bzero().
You may notice that there is no libc_hidden_proto(__bzero) or libc_hidden_def(__bzero) associated with this particular symbol. This means there is no internal hidden symbol.
NOTE: While the use of two leading underscores on a symbol name will often indicate that it is an internal symbol, in the case of __bzero() the header file strings.h provides this is in the external API for GLIBC.
The __bzero() API has been around for some time so we can assume that there probably shouldn't be an internal hidden symbol for it.
Invocation of __bzero() should only be used in the sunrpc code (or other non-libc shared object code), which is in a different library than libc proper, so invocation via the PLT in that library is allowed.
If you find other invocations of the symbol within libc proper then these are problematic.
If the symbol may be invoked from within GLIBC and it doesn't yet have a hidden symbol then use the libc_hidden_proto(__internal_bzero) and libc_hidden_def(__internal_bzero) macros to provide an internal version of the symbol.
Then use a weak_alias(__internal_bzero,__bzero) to provide the external interface. All libc proper invocations should be to the hidden symbol __internal_bzero, not the external interface.
But alas, in the case of __bzero() there isn't supposed to be to a hidden internal symbol because GLIBC proper should invoke memset() instead.
Still can't figure out where the invocation originates?
Macros, and symbol aliasing magic can obscure the invocation of a symbol and sometimes we need to use more arcane methods to find the problematic invocation.
In order to determine where an obscure invocation is originating follow these steps:
> objdump -DR libc.so > libc.dis
Search libc.dis for:
__bzero@plt
You should see a plt call stub, e.g.
00016198 <__bzero@plt>: 16198: ff a3 0c 00 00 00 jmp *0xc(%ebx) 1619e: 68 00 00 00 00 push $0x0 161a3: e9 e0 ff ff ff jmp 16188 <h_errno+0x16168>
Now search for all instances of: call 16198
call 16198 <__bzero@plt>
This should bring you to the disassembly of the function which invoked __bzero via the PLT. You can then go into the C source file and replace this with a memset(). Do this for all calls to the PLT stub address for __bzero@plt.