Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lld] After 46453119335, internal linker error: wrote incorrect addend value 0x74C08500 instead of 0x0 for dynamic relocation R_386_32 at offset 0x4016C7 against symbol __gxx_personality_v0 #59381

Closed
DimitryAndric opened this issue Dec 7, 2022 · 13 comments
Labels

Comments

@DimitryAndric
Copy link
Collaborator

DimitryAndric commented Dec 7, 2022

As reported in https://pkg-status.freebsd.org/gohan05/data/maini386PR265425-default/2022-12-06_12h24m32s/logs/errors/openal-soft-1.21.1_3.log, linking openal-soft'ssofa-info and makemhr tools while targeting i386-freebsd results in errors of the form:

: && /usr/bin/c++ -O2 -pipe -fstack-protector-strong -fno-strict-aliasing -O2 -pipe -fstack-protector-strong -fno-strict-aliasing   -DNDEBUG -Wl,--as-needed -fstack-protector-strong -Wl,-z,notext CMakeFiles/makemhr.dir/utils/makemhr/loaddef.cpp.o CMakeFiles/makemhr.dir/utils/makemhr/loadsofa.cpp.o CMakeFiles/makemhr.dir/utils/makemhr/makemhr.cpp.o -o makemhr  -Wl,-rpath,/usr/local/lib:  -pthread  libsofa-support.a  -pthread  libcommon.a  /usr/local/lib/libmysofa.so  /usr/lib/libz.so  -lm && :
ld: error: makemhr:(.eh_frame+0x14cf): internal linker error: wrote incorrect addend value 0x3400 instead of 0x0 for dynamic relocation R_386_32 at offset 0x408417 against symbol __gxx_personality_v0

Bisecting shows that this starts appearing after 4645311 ("[ELF] --emit-relocs: adjust offsets of .rel[a].eh_frame relocations").

Reproduction tarball: openal-soft-repro.tar.gz

@llvmbot
Copy link
Collaborator

llvmbot commented Dec 7, 2022

@llvm/issue-subscribers-lld-elf

@DimitryAndric
Copy link
Collaborator Author

@MaskRay might lld be running into some sort of wrapping or overflow issue? I have seen a few other port failures with clang & lld 15 on i386 due to this type of error, so it could also be a problem in the object files emitted by clang 15.

@DimitryAndric
Copy link
Collaborator Author

FWIW adding --no-check-dynamic-relocations indeed papers over the error, the resulting executable seems to run, but it's questionable if it is correct.

@MaskRay
Copy link
Member

MaskRay commented Dec 18, 2022

--check-dynamic-relocations is the default only when LLVM_ENABLE_ASSERTIONS=on (and the machine is one of the supported). You can ignore the diagnostic. The output is good.

openal-soft-repro.tar.gz uses text relocations (-z notext). If you remove -z notext, the --check-dynamic-relocations error will go away as well.

A minimal reproduce is:

echo 'void bar(); int main() { try { bar(); } catch (...) {} }' > a.cc
echo 'void bar() {}' > b.cc
clang++ -m32 -fno-pic -no-pie -fuse-ld=lld -z notext a.cc b.cc

Compared with GNU ld, lld prefers to use more text relocations than canonical PLT/copy relocations.
Changing this will likely be unnecessary work.

I think we should just find a way to ignore .eh_frame dynamic relocation (in .rel.dyn, instead of .rel.eh_frame) in OutputSection::checkDynRelAddends.

@DimitryAndric
Copy link
Collaborator Author

Hmm that's a good one. I don't really know why the port added -z notext; I assume this was to suppress yet another warning or error. I will investigate.

@DimitryAndric
Copy link
Collaborator Author

Ah yes, the -z notext option was added via https://bugs.freebsd.org/242307, because otherwise lld would complain about not being able to preempt symbols, i.e.:

FAILED: openal-info
: && /usr/bin/cc -O2 -pipe  -fstack-protector-strong -fno-strict-aliasing -O2 -pipe  -fstack-protector-strong -fno-strict-aliasing  -DNDEBUG -Wl,--as-needed -fstack-protector-strong CMakeFiles/openal-info.dir/utils/openal-info.c.o -o openal-info  -Wl,-rpath,/wrkdirs/share/dim/ports/audio/openal-soft/work/.build:  -pthread  libopenal.so.1.21.1 && :
ld: error: cannot preempt symbol: alcIsExtensionPresent
>>> defined in libopenal.so.1.21.1
>>> referenced by openal-info.c
>>>               CMakeFiles/openal-info.dir/utils/openal-info.c.o:(main)

ld: error: cannot preempt symbol: alcGetString
>>> defined in libopenal.so.1.21.1
>>> referenced by openal-info.c
>>>               CMakeFiles/openal-info.dir/utils/openal-info.c.o:(main)

ld: error: cannot preempt symbol: alcGetString
>>> defined in libopenal.so.1.21.1
>>> referenced by openal-info.c
>>>               CMakeFiles/openal-info.dir/utils/openal-info.c.o:(main)

ld: error: cannot preempt symbol: alcGetString
>>> defined in libopenal.so.1.21.1
>>> referenced by openal-info.c
>>>               CMakeFiles/openal-info.dir/utils/openal-info.c.o:(main)

ld: error: cannot preempt symbol: alcIsExtensionPresent
>>> defined in libopenal.so.1.21.1
>>> referenced by openal-info.c
>>>               CMakeFiles/openal-info.dir/utils/openal-info.c.o:(main)

ld: error: cannot preempt symbol: alcGetString
>>> defined in libopenal.so.1.21.1
>>> referenced by openal-info.c
>>>               CMakeFiles/openal-info.dir/utils/openal-info.c.o:(main)

ld: error: cannot preempt symbol: alcGetString
>>> defined in libopenal.so.1.21.1
>>> referenced by openal-info.c
>>>               CMakeFiles/openal-info.dir/utils/openal-info.c.o:(main)

ld: error: cannot preempt symbol: alcOpenDevice
>>> defined in libopenal.so.1.21.1
>>> referenced by openal-info.c
>>>               CMakeFiles/openal-info.dir/utils/openal-info.c.o:(main)

ld: error: cannot preempt symbol: alcOpenDevice
>>> defined in libopenal.so.1.21.1
>>> referenced by openal-info.c
>>>               CMakeFiles/openal-info.dir/utils/openal-info.c.o:(main)

ld: error: cannot preempt symbol: alcIsExtensionPresent
>>> defined in libopenal.so.1.21.1
>>> referenced by openal-info.c
>>>               CMakeFiles/openal-info.dir/utils/openal-info.c.o:(main)

ld: error: cannot preempt symbol: alcGetProcAddress
>>> defined in libopenal.so.1.21.1
>>> referenced by openal-info.c
>>>               CMakeFiles/openal-info.dir/utils/openal-info.c.o:(main)

ld: error: cannot preempt symbol: alcGetIntegerv
>>> defined in libopenal.so.1.21.1
>>> referenced by openal-info.c
>>>               CMakeFiles/openal-info.dir/utils/openal-info.c.o:(main)

ld: error: cannot preempt symbol: alcGetError
>>> defined in libopenal.so.1.21.1
>>> referenced by openal-info.c
>>>               CMakeFiles/openal-info.dir/utils/openal-info.c.o:(main)

ld: error: cannot preempt symbol: alcGetString
>>> defined in libopenal.so.1.21.1
>>> referenced by openal-info.c
>>>               CMakeFiles/openal-info.dir/utils/openal-info.c.o:(main)

ld: error: cannot preempt symbol: alcCreateContext
>>> defined in libopenal.so.1.21.1
>>> referenced by openal-info.c
>>>               CMakeFiles/openal-info.dir/utils/openal-info.c.o:(main)

ld: error: cannot preempt symbol: alcMakeContextCurrent
>>> defined in libopenal.so.1.21.1
>>> referenced by openal-info.c
>>>               CMakeFiles/openal-info.dir/utils/openal-info.c.o:(main)

ld: error: cannot preempt symbol: alGetString
>>> defined in libopenal.so.1.21.1
>>> referenced by openal-info.c
>>>               CMakeFiles/openal-info.dir/utils/openal-info.c.o:(main)

ld: error: cannot preempt symbol: alGetString
>>> defined in libopenal.so.1.21.1
>>> referenced by openal-info.c
>>>               CMakeFiles/openal-info.dir/utils/openal-info.c.o:(main)

ld: error: cannot preempt symbol: alGetString
>>> defined in libopenal.so.1.21.1
>>> referenced by openal-info.c
>>>               CMakeFiles/openal-info.dir/utils/openal-info.c.o:(main)

ld: error: cannot preempt symbol: alGetString
>>> defined in libopenal.so.1.21.1
>>> referenced by openal-info.c
>>>               CMakeFiles/openal-info.dir/utils/openal-info.c.o:(main)

ld: error: too many errors emitted, stopping now (use --error-limit=0 to see all errors)

I'm unsure whether just blindly slapping -z notext on this was the correct solution, though. It seems to be used for a number of other ports too, specifically for i386.

@DimitryAndric
Copy link
Collaborator Author

Ah, and those errors seem to be caused by the symbols having 'protected' visibility:

$ % readelf -aW .build/libopenal.so.1.21.1
...
Symbol table '.dynsym' contains 417 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
...
   414: 0006f1f0   500 FUNC    GLOBAL PROTECTED   14 alcIsExtensionPresent

It seems to be on purpose: https://github.com/kcat/openal-soft/blob/master/CMakeLists.txt#L338, but I'm not sure why the openal-soft library wants this particular visibility.

@emaste
Copy link
Member

emaste commented Dec 18, 2022

I'm unsure whether just blindly slapping -z notext on this was the correct solution, though. It seems to be used for a number of other ports too, specifically for i386.

We added a lot of -z notexts to mimic the default that GNU ld 2.17.50 provided (although as you point out that's not the case for this specific port). In general it's better to fix the underlying ports of course.

@DimitryAndric
Copy link
Collaborator Author

Well, in this particular case the libopenal CMake stuff explicitly wants to enable protected visibility (for reasons unknown), and that apparently doesn't work with lld, at least on i386? I am unsure as to why it would be necessary to preempt the symbol, if the goal is simply to link the openal-info executable to the libopenal.so.1.21.1 shared library. I don't really see why that wouldn't work.

@DimitryAndric
Copy link
Collaborator Author

The protected visibility stuff has a history with lld: see #30308, #30842, or even #26954 which is pretty old...

The gist of those bugs was mostly that BFD ld seem to ignore the protected visibility in these cases, while lld complains and stops. Note that lld still does that, but only for i386, not x86_64!

The workarounds are to link the executable with -fPIE (works) or to add -Wl,--ignore-function-address-equality (also works), and possibly others. Or maybe hack the original software so it doesn't use protected visibility, but as I don't know the reason for that, I would hesitate to do that. :)

@MaskRay
Copy link
Member

MaskRay commented Dec 18, 2022

The gist of those bugs was mostly that BFD ld seem to ignore the protected visibility in these cases [...]

I have changed latest GNU ld aarch64/x86 to disallow copy relocation/canonical PLT on protected symbol.

-fno-pic code traditionally uses direct reference relocation for external data/function accesses, which are incompatible with protected symbols. The port can use -fPIE or -fPIC to avoid the issue.

[...] Note that lld still does that, but only for i386, not x86_64!

Because of the overly strict --check-dynamic-relocations default in a LLVM_ENABLE_ASSERTIONS=on build.

The workarounds are to link the executable with -fPIE (works) or to add -Wl,--ignore-function-address-equality (also works), and possibly others.

-fPIE is likely preferable (matching most other OS) now that FreeBSD supports ASLR...

Or maybe hack the original software so it doesn't use protected visibility, but as I don't know the reason for that, I would hesitate to do that. :)

If lib/libopenal.so can guarantee it doesn't have -fno-pic user direct referencing its STV_PROTECTED symbols, using protected visibility is fine; otherwise it is not.

@MaskRay
Copy link
Member

MaskRay commented Feb 4, 2023

08c915f fixed this on the lld side as well. I requested release/16.x cherry-pick in #60392

@MaskRay MaskRay closed this as completed Feb 4, 2023
@MaskRay
Copy link
Member

MaskRay commented Feb 4, 2023

Perhaps we should use DW_EH_PE_indirect for x86-32 personality/typeinfo as well?
Jakub from GCC doesn't seem to want to change GCC (https://gcc.gnu.org/pipermail/gcc-patches/2023-February/611146.html) but I don't think there are so many users who still use -fno-pic -fexceptions care about the slight .eh_frame``/.gcc_except_table size increase... So Clang doesn't necessarily follow GCC's -fno-pic decision.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants