This is an archive of the discontinued LLVM Phabricator instance.

[LLD][ARM] Correct ARM TLS GOT entries without dynamic relocations.
AbandonedPublic

Authored by peter.smith on Nov 2 2016, 4:24 AM.

Details

Reviewers
ruiu
rafael
Summary

ARM has three dynamic relocations for TLS:

  • R_ARM_TPOFF32 (Offset of S from Thread Pointer)
  • R_ARM_DTPMOD32 (Module-Id, always 1 for executables)
  • R_ARM_DTPOFF32 (Offset of S from TLS block)

When static linking we must resolve these relocations statically by writing the values directly into the .got. In many ways ARM is similar to Mips:

  • TLS is not relaxable so the linker can't rely on relaxing global and local dynamic away.
  • ARM is type 1 TLS (TLS block is immediately after Thread Pointer and precedes TLS data) so the TCB size has to be accounted for when resolving R_ARM_TPOFF32.
  • The R_ARM_DTPMOD32 needs to be hard coded to 1 in applications.

To implement this I've:

  • Removed the fixme in handleNoRelaxTlsRelocation() which always added dynamic relocations for ARM TLS
  • Recorded where symbols have been relocated by a Target->TlsGotRel, R_ARM_TLS_TPOFF32 for ARM
  • Introduce a writeARMGot(), similar to writeMipsGot() to isolate the special cases from the other Targets.
    • Write the module index to be 1 (from Global Dynamic or Local Dynamic)
    • Account for the Target->TcbSize when writing the value of a symbol that has been recorded as being referenced by R_ARM_TPOFF32.

The changes show up in the existing tests. As we no longer need the dynamic relocation for the module index and the GOT entries that are statically resolved R_ARM_TLS_TPOFF32 relocations include the ARM TcbSize of 8.

The implementation of writeARMGot() is similar to writeMipsGot() in the way it handles TLS.

The Mips implementation uses Config->Pic consistently to use dynamic relocations. For ARM I've used Config->Shared as an executable can still use Pic, and can still be statically linked with Pic.

Diff Detail

Event Timeline

peter.smith updated this revision to Diff 76688.Nov 2 2016, 4:24 AM
peter.smith retitled this revision from to [LLD][ARM] Correct ARM TLS GOT entries without dynamic relocations..
peter.smith updated this object.
peter.smith added reviewers: ruiu, rafael.
peter.smith added a subscriber: llvm-commits.
rafael added inline comments.Nov 16 2016, 12:39 PM
ELF/OutputSections.cpp
394

This is the same value as what R_TLS would compute, no?

now that the got is a synthetic section, it has a Relocations array. Could we maybe use that instead of Entries? So the code for having a non zero value in the got would become something like

In<ELFT>::Got.Relocations.push_back({R_ABS, Target->?, }Body.getGotPltOffset<ELFT>() , 0, &Body})

Do you think that would be better? If not something like this (rebase now that .got is a synthetic section) is probably ok.

Thanks very much for the comments.

I hope to rewrite this and my ifunc patch shortly using the refactored Input Sections.

I've been spending some time using lld on ARM as an ld replacement on a Chromebook running Ubuntu via crouton. Some of the programs I've not been able to execute without some instability problems after linking are the llvm-* tools such llvm-mc etc. One possible source of problems is TLS so I may not have got this completely right yet.

ELF/OutputSections.cpp
394

Yes that is correct. We are in effect resolving the relocation at static link time.

The difficulty with this approach at the time was how to avoid writing the relocation into the file as well as statically resolving it. I thought that this would probably be messier than localising it here. With the new refactoring this might be easier so it will be worth taking another look.

peter.smith abandoned this revision.Jun 22 2017, 7:59 AM

This is no longer needed, it was implemented as part of D27213