Running valgrind on a binary using gcc ifunc attribute result in an infinite loop. When running valgrind --trace-syscalls=yes --trace-symtab=yes ./a.out , the following is printed endlessly: canonicaliseSymtab: 0 symbols merged overlapping address ranges in symbol table 1: TI 0x 400568 .. 0x 400572 (11) test 2: T- 0x 400568 .. 0x 400572 (11) resolve_test Reproducible: Always Steps to Reproduce: Build the attached sample program and run it inside valgrind.
Created attachment 71599 [details] testcase
If I build with -Wl,-x , valgrind works fine on the resulting binary. Binary linked with -Wl,-x : % readelf -Ws ./a.out | grep test 20: 0000000000400568 11 IFUNC GLOBAL DEFAULT 14 test Binary linked with default ldflags : % readelf -Ws ./a.out | grep test 11: 0000000000400544 36 FUNC LOCAL DEFAULT 14 mytest 12: 0000000000400568 11 FUNC LOCAL DEFAULT 14 resolve_test 37: 0000000000400568 11 IFUNC GLOBAL DEFAULT 14 test Versions used: valgrind-3.7.0 gcc (Debian 4.6.3-1) 4.6.3 GNU gold (GNU Binutils for Debian 2.22) 1.11
Thanks for the testcase. I've looked at it and the issue is that in coregrind/m_debuginfo/storage.c:1466 there is the belief that the code @ cleanup_more will merge the symbols that have the same address and size. But the code @ cleanup_more will only do so only if they agree in their ifunc'ness. Which in this case they do not. Hence, the infinite loop. This patch fixes the issue but I'm not at all sure it's the right thing. Index: coregrind/m_debuginfo/storage.c =================================================================== --- coregrind/m_debuginfo/storage.c (revision 12704) +++ coregrind/m_debuginfo/storage.c (working copy) @@ -1370,7 +1370,7 @@ if ( di->symtab[w].addr == di->symtab[r].addr && di->symtab[w].size == di->symtab[r].size && !!di->symtab[w].isText == !!di->symtab[r].isText - && !!di->symtab[w].isIFunc == !!di->symtab[r].isIFunc) { + && 1) { /* merge the two into one */ n_merged++; /* Add r names to w if r has secondary names
We need somebody who understands ifunc stuff to tell us the significance of an address which has both normal and ifunc symbol. TomH, or JakubJ ?
It seems to be normal, at least if you follow the details in the gcc documentation on how to declare an ifunc. The ifunc symbol, and the normal symbol for the underlying resolver function, will be at the same address. Obviously glibc is doing something different, as the ifunc routines in glibc don't seem to have a visible symbol for the underlying resolver.
I've committed a change (r12711) that allows an IFunc symbol to be merged with a non-IFunc symbol, which should fix this.