[ELF] Fix TLS GD against non-preemptible dynamic symbols in DSOs (#207881)

Consider a DSO that uses TLS GD against a dynamic non-preemptible symbol
(e.g.  protected, or linked with -Bsymbolic). The expected meaning of
this is to always reference the DSO's own TLS segment for that symbol,
regardless of any attempts to preempt it at load time, and LLD will
indeed emit a constant offset rather than a symbolic DTPOFF relocation
for the second GOT word. However, for the first GOT word, because we
currently only treat the isLocalInExecutable case as special (where the
module index is 1), we end up creating a symbolic DTPMOD relocation,
rather than a non-symbolic (i.e. against the null symbol) one to get
this DSO's index, and so any load-time preemption will cause us to use a
different module's TLS block. As a result, not only do we have symbol
preemption when we shouldn't, but also the two halves of the TLS GD GOT
entry end up inconsistent, using the offset of the symbol in this
module's TLS block for a different module's.

Fix this by breaking down the two !isLocalInExecutable cases, emitting
the expected non-symbolic DTPMOD relocation for any non-preemptible
symbol references in a DSO. Whilst here, combine the DTPMOD and DTPOFF
code rather than have two different if statements, so it's clearer what
the three cases are and they don't get out of sync.

Note that although, for the existing code, local symbols take the exact same
code paths in postScanRelocations, they do not end up with symbolic DTPMOD
relocations in the output, despite creating them. DynamicReloc::getSymIndex has
the quirk of silently squashing the symbol index to 0 for symbolic relocations
against non-dynamic symbols, which applies to local symbols but not other
non-preemptible symbols, i.e. the case relevant in the first paragraph. This
quirky behaviour of DynamicReloc::getSymIndex is probably something that should
be retired; I can't see a good reason for it, and any case that it squashes
could be hiding similar bugs like this. I take the view that a request to
create a symbolic relocation against a symbol that won't be in the dynamic
symbol table is a strong sign that the code is confused and doing something
wrong, even if it happens to work out.
4 files changed
tree: 4f74520fd90c4e783efe994aca9aa85ca8fc6cb7
  1. .ci/
  2. .github/
  3. bolt/
  4. clang/
  5. clang-tools-extra/
  6. cmake/
  7. compiler-rt/
  8. cross-project-tests/
  9. flang/
  10. flang-rt/
  11. libc/
  12. libclc/
  13. libcxx/
  14. libcxxabi/
  15. libsycl/
  16. libunwind/
  17. lld/
  18. lldb/
  19. llvm/
  20. llvm-libgcc/
  21. mlir/
  22. offload/
  23. openmp/
  24. orc-rt/
  25. polly/
  26. runtimes/
  27. third-party/
  28. utils/
  29. .clang-format
  30. .clang-format-ignore
  31. .clang-tidy
  32. .git-blame-ignore-revs
  33. .gitattributes
  34. .gitignore
  35. .mailmap
  36. CODE_OF_CONDUCT.md
  37. CONTRIBUTING.md
  38. LICENSE.TXT
  39. pyproject.toml
  40. README.md
  41. SECURITY.md
README.md

The LLVM Compiler Infrastructure

OpenSSF Scorecard OpenSSF Best Practices libc++

Welcome to the LLVM project!

This repository contains the source code for LLVM, a toolkit for the construction of highly optimized compilers, optimizers, and run-time environments.

The LLVM project has multiple components. The core of the project is itself called “LLVM”. This contains all of the tools, libraries, and header files needed to process intermediate representations and convert them into object files. Tools include an assembler, disassembler, bitcode analyzer, and bitcode optimizer.

C-like languages use the Clang frontend. This component compiles C, C++, Objective-C, and Objective-C++ code into LLVM bitcode -- and from there into object files, using LLVM.

Other components include: the libc++ C++ standard library, the LLD linker, and more.

Getting the Source Code and Building LLVM

Consult the Getting Started with LLVM page for information on building and running LLVM.

For information on how to contribute to the LLVM project, please take a look at the Contributing to LLVM guide.

Getting in touch

Join the LLVM Discourse forums, Discord chat, LLVM Office Hours or Regular sync-ups.

The LLVM project has adopted a code of conduct for participants to all modes of communication within the project.