Summary: | Unnecessary error on linking STV_PROTECTED library: relocation R_X86_64_PC32 against protected symbol `f' can not be used when making a shared object | ||
---|---|---|---|
Product: | binutils | Reporter: | Thiago Macieira <thiago> |
Component: | ld | Assignee: | Not yet assigned to anyone <unassigned> |
Status: | WAITING --- | ||
Severity: | normal | CC: | fabian, fweimer, hjl.tools, mliska |
Priority: | P2 | ||
Version: | 2.35 | ||
Target Milestone: | --- | ||
Host: | Target: | ||
Build: | Last reconfirmed: | 2020-10-30 00:00:00 |
Description
Thiago Macieira
2020-10-29 20:28:32 UTC
Protected function pointer should be treated as normal symbol: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=19520 You can override it with linker options: -Bsymbolic Bind global references locally -Bsymbolic-functions Bind global function references locally (In reply to H.J. Lu from comment #1) > You can override it with linker options: > > -Bsymbolic Bind global references locally > -Bsymbolic-functions Bind global function references locally Those options shouldn't be needed. The protected visibility already implies them. Either way, the fact that gold and ld.bfd behave different is a problem. And so is the fact that passing an empty --dynamic-list file causes it to work. (In reply to Thiago Macieira from comment #2) > (In reply to H.J. Lu from comment #1) > > You can override it with linker options: > > > > -Bsymbolic Bind global references locally > > -Bsymbolic-functions Bind global function references locally > > Those options shouldn't be needed. The protected visibility already implies > them. > GOT relocation is needed for function pointer comparison. > Either way, the fact that gold and ld.bfd behave different is a problem. And > so is the fact that passing an empty --dynamic-list file causes it to work. An empty --dynamic-list file is the same as -Bsymbolic. (In reply to H.J. Lu from comment #3) > GOT relocation is needed for function pointer comparison. > > > Either way, the fact that gold and ld.bfd behave different is a problem. And > > so is the fact that passing an empty --dynamic-list file causes it to work. > > An empty --dynamic-list file is the same as -Bsymbolic. I see. Then this is an incompatibility between compiler and linker: the compiler sees a protected symbol and emits a relocation assuming it doesn't need indirect access via the GOT to do a pointer comparison, but ld.bfd says it should. Anyway, this is what I am asking to change: when a symbol is protected, the compiler optimisation should be allowed and pointer comparison still works provided ALL users use the GOT too. That includes the executable. (In reply to Thiago Macieira from comment #4) > (In reply to H.J. Lu from comment #3) > > GOT relocation is needed for function pointer comparison. > > > > > Either way, the fact that gold and ld.bfd behave different is a problem. And > > > so is the fact that passing an empty --dynamic-list file causes it to work. > > > > An empty --dynamic-list file is the same as -Bsymbolic. > > I see. > > Then this is an incompatibility between compiler and linker: the compiler > sees a protected symbol and emits a relocation assuming it doesn't need > indirect access via the GOT to do a pointer comparison, but ld.bfd says it > should. > > Anyway, this is what I am asking to change: when a symbol is protected, the > compiler optimisation should be allowed and pointer comparison still works > provided ALL users use the GOT too. That includes the executable. This is an ABI change. We have 2 choices 1. Extend GNU_PROPERTY_NO_COPY_ON_PROTECTED to cover protected function pointers. We can rename it to GNU_PROPERTY_LOCAL_PROTECTED, Or 2. Add a new property for protected function pointers. Please raise the issue at https://gitlab.com/x86-psABIs/Linux-ABI This will require support in GCC, linker and ld.so. A bit more testing shows that we'd need a compiler update too, to tell the compiler that a variable should be accessed via the GOT regardless (equiv. to Windows __declspec(dllimport)). We can accomplish that by always compiling everything with -fPIC, though. lib.c: long variable = 0; void *addr() { ++variable; return &variable; } main.c: #include <stdio.h> void *addr(void); extern long variable; __auto_type ptr2 = &variable; int main() { variable++; printf("addr() = %p, &variable = %p\n", addr(), ptr2); } $ gcc -O2 -shared -fPIC -fvisibility=protected -fuse-ld=gold -o lib.so lib.c Now the error comes from Gold: $ gcc -O2 -pie -fPIE -fuse-ld=gold main.c ./lib.so /usr/bin/ld.gold: error: /tmp/ccUGJmAG.o: cannot make copy relocation for protected symbol 'variable', defined in ./lib.so collect2: error: ld returned 1 exit status ld.bfd can link it: $ gcc -O2 -pie -fPIE main.c ./lib.so When run, this particular example appears to work but the variable was actually copy-relocated: $ ./a.out addr() = 0x555555558050, &variable = 0x555555558050 When linking the library with ld.bfd instead: # gcc -O2 -shared -fPIC -fvisibility=protected -Wl,--dynamic-list,empty.dynlist -o lib.so lib.c Then we get a mismatch: $ ./a.out addr() = 0x7ffa8cabc028, &variable = 0x556094d36050 All these problems go away when the main application is compiled with -fPIC. Disabling the use of the feature in Qt 6.4 because it's still broken. Oops, these tests aren't using -mno-direct-extern-access at all. When using them: $ gcc -O2 -shared -fPIC -mno-direct-extern-access -fvisibility=protected -Wl,--dynamic-list,empty.dynlist -o lib.so lib.c $ gcc -mno-direct-extern-access -O2 -pie -fPIE main.c ./lib.so $ ./a.out addr() = 0x7f932637a028, &variable = 0x7f932637a028 So this is actually working right. Should this be closed by -mno-direct-extern-access change in GCC? (In reply to H.J. Lu from comment #9) > Should this be closed by -mno-direct-extern-access change in GCC? Yes. making that the default and getting rid of copy relocations would be better, though. |