Bug 16715 - -Bsymbolic breaks function pointer comparison under ARM
Summary: -Bsymbolic breaks function pointer comparison under ARM
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.22
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-03-17 15:00 UTC by Giuseppe D'Angelo
Modified: 2022-11-24 04:24 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments
testcase (654 bytes, application/x-gzip)
2014-03-17 15:00 UTC, Giuseppe D'Angelo
Details
C-only testcase (620 bytes, application/x-gzip)
2014-03-20 10:12 UTC, Thomas McGuire
Details
C-only testcase (626 bytes, application/x-gzip)
2014-03-20 10:44 UTC, Thomas McGuire
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Giuseppe D'Angelo 2014-03-17 15:00:17 UTC
Created attachment 7474 [details]
testcase

The attached program changes the output from "true" to "false" when the -Bsymbolic / -Bsymbolic-functions options are passed to GCC. This happens on ARM -- on x86-64 output is always "true".

The program involves a comparison, within a shared library, of a PMF defined inside the shared library itself with the same PMF passed by the application.

Compile with:

 > g++ -fPIC -shared -Wall -o libshared.so -Wl,-Bsymbolic shared.cpp
 > g++ -fPIE -Wall -o main main.cpp -L. -lshared

(The long story is that Qt 5 is taking PMFs in its public API, and the comparison failing inside of Qt shared libraries is breaking code on ARM, as -Bsymbolic is set by default there.)

The bug has been acknowledged, and tentative patch has been kindly provided by W. Newton here:

> https://sourceware.org/ml/binutils/2014-01/msg00172.html

but there hasn't been any activity from what I can see, so I'm opening this bug report to keep track of the issue.

References:

> http://lists.linaro.org/pipermail/linaro-toolchain/2014-January/003942.html
> https://bugreports.qt-project.org/browse/QTBUG-36129
Comment 1 Thomas McGuire 2014-03-20 10:12:05 UTC
Created attachment 7483 [details]
C-only testcase
Comment 2 Thomas McGuire 2014-03-20 10:26:11 UTC
Attached a C-only testcase (forgot to rename the files from .cpp to .c, but I don't think that matters). The testcase simply outputs the function pointer of a function in a shared library, and one can see that the address is not the same.

Compile with:
gcc -fPIC -shared -Wall -o libshared.so -Wl,-Bsymbolic shared.cpp
gcc -fPIE -Wall -o main main.cpp -L. -lshared

The output on my machine is:
# ./main 
0x8518
0x2ac595cc

The root of the problem seems to be that main gets the following undefined symbol:
   Num:    Value  Size Type    Bind   Vis      Ndx Name           
    14: 0000853c     0 FUNC    GLOBAL DEFAULT  UND testFunction()

This is a special hack - an undefined symbol that nevertheless has a value! See http://www.airs.com/blog/archives/42 for details on how that hack is supposed to work.
The idea is to use a different symbol value depending on the relocation type - a relocation for R_ARM_JUMP_SLOT should always resolve to the local PLT, but a relocation of type R_ARM_GLOB_DAT should use the symbol value defined in main. The problem is that libshared.so doesn't contain a R_ARM_GLOB_DAT relocation when taking the address of the function, but a R_ARM_RELATIVE relocation, and will therefore never resolve the function address to the value in main.
I guess this is a consequence of using -Bsymbolic - when taking the address of a function, it should still go through the GOT, with a R_ARM_GLOB_DAT relocation, despite -Bsymbolic being set.

Or at least that is what I think is the cause of the problem, I am by no means a Linker export, I only recently started being interested in this topic.
Comment 3 Thomas McGuire 2014-03-20 10:44:58 UTC
Created attachment 7484 [details]
C-only testcase
Comment 4 Thomas McGuire 2014-03-20 10:53:46 UTC
Note that on x86-64, this works, but is *not* solved like the hacky method that Ian Lance Taylor describes in his blog.

Instead of using an undefined symbol with an actual value in main, x86-64 will create a normal undefined symbol with a 0 value:
    12: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND testFunction

This works well: The relocations in libshared.so is a relative relocation that resolves to the actual address of testFunction (not the PLT stub), and the relocation in main is a R_X86_64_GLOB_DAT relocation that resolves to the address of testFunction in libshared.so, and all just works.

This is less hacky, and I think also the proposed patch from the mailing list solves the problem this way.
Comment 5 Sourceware Commits 2014-03-20 11:44:47 UTC
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "gdb and binutils".

The branch, master has been updated
       via  97323ad11305610185a0265392cabcd37510f50e (commit)
      from  e1f8f1b3af798e8af99bffdb695f74c6c916d150 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=97323ad11305610185a0265392cabcd37510f50e

commit 97323ad11305610185a0265392cabcd37510f50e
Author: Will Newton <will.newton@linaro.org>
Date:   Fri Jan 10 14:38:58 2014 +0000

    bfd/elf32-arm.c: Set st_value to zero for undefined symbols
    
    Unless pointer_equality_needed is set then set st_value to be zero
    for undefined symbols.
    
    bfd/ChangeLog:
    
    2014-03-20  Will Newton  <will.newton@linaro.org>
    
    	PR ld/16715
    	* elf32-arm.c (elf32_arm_check_relocs): Set
    	pointer_equality_needed for absolute references within
    	executable links.
    	(elf32_arm_finish_dynamic_symbol): Set st_value to zero
    	unless pointer_equality_needed is set.
    
    ld/testsuite/ChangeLog:
    
    2014-03-20  Will Newton  <will.newton@linaro.org>
    
    	* ld-arm/ifunc-14.rd: Update symbol values.

-----------------------------------------------------------------------

Summary of changes:
 bfd/ChangeLog                   |    9 +++++++++
 bfd/elf32-arm.c                 |    7 ++++++-
 ld/testsuite/ChangeLog          |    4 ++++
 ld/testsuite/ld-arm/ifunc-14.rd |    4 ++--
 4 files changed, 21 insertions(+), 3 deletions(-)
Comment 6 Giuseppe D'Angelo 2014-03-20 21:37:05 UTC
Thanks to Will for merging the patch. I'm not closing this just yet as we got reports of the same kind of breakage on PPC.
Comment 7 Alan Modra 2022-11-24 04:24:09 UTC
Fixed