This is an archive of the discontinued LLVM Phabricator instance.

[LLD][ELF] Fix ARM TLS global dynamic TlsOffsetRel for non-preemptible symbols
AbandonedPublic

Authored by peter.smith on Apr 4 2017, 9:49 AM.

Details

Reviewers
ruiu
rafael
Summary

When the target of the TlsOffsetRel is non-preemptible we can write the offset directly into the GOT without needing a dynamic relocation. This is optional for dynamically linked executables but is required for static linking.

We used to rely on the GOTSection::writeTo member function to get the TLS offset of the symbol when writing the VA of the symbol. However in r288107 the GOTSection::writeTo was changed to only use relocations for writing values. Unfortunately we were missing the GOT relocation so all TLS offsets were being written as 0. This change adds the relocation to the GOT entry and a test case for non-0 offsets.

This was found as a result of investigating D31274

Diff Detail

Event Timeline

peter.smith created this revision.Apr 4 2017, 9:49 AM
ruiu added inline comments.Apr 4 2017, 5:12 PM
ELF/Relocations.cpp
122

The new code is probably fine, but as a whole I think I don't fully understand this piece of code because it is entangled and complicated. What is this for?

132

Format.

ELF/Target.cpp
1845

Instead of adding Target->TlsOffsetRel, can you add R_ARM_ABS32, so that it is obvious that it is just an abs relocation?

peter.smith updated this revision to Diff 94244.Apr 5 2017, 9:27 AM

I think at least some of the difficulty in understanding the code here is that there are too many somewhat arbitrary ARM and Mips specific bits of code here. I've updated the diff to split handleNoRelaxTlsRelocation() into an ARM and Mips specific function, this allows us to take out some of the special cases.

In the ARM case I've kept the relocation in Target as it allows the same relocation code to be given to the AddTlsReloc function.

I've also found out why the Body.isPreemptible() is for! When we are writing the module index we should only write a 1 if we know the symbol came from the executable. In the case when we are linking an executable but the TLS Symbol is defined in a Shared Library we still need a dynamic relocation for the module index.

Does this make the code any easier to follow? A relatively short but fairly complete description of ARM TLS can be found in Section 3 of http://infocenter.arm.com/help/topic/com.arm.doc.ihi0045e/IHI0045E_ABI_addenda.pdf

rafael edited edge metadata.Apr 5 2017, 3:24 PM

It is now hard to read the fix. Can you split this in a refactoring patch and a fix patch?

ELF/Relocations.cpp
140

copy and paste of MIPS.

ruiu edited edge metadata.Apr 5 2017, 4:32 PM

Currently, we add a relocation to a GOT section to set a GOT slot for a TLS variable to 1. But that is an intricate way of setting it to 1, because when we add a relocation, we already have a reference to GOT. We should be able to directly set it to 1, instead of doing it indirectly using relocate().

What I was trying to do is to separate the GOT class into two classes -- one for the regular GOT and the other is for TLS variables. TLS variables use GOT slots very differently than regular variables, I think that will reduce complexity. (But doing that isn't easy as I don't understand some parts of MIPS/AArch64 TLS variables ABIs.)

peter.smith abandoned this revision.Apr 6 2017, 3:40 AM

I've split this into 3 reviews:
D31748 Split handleNoRelaxTlsRelocation into ARM and Mips specific impls
D31749 Fix ARM TLS global dynamic TlsOffsetRel for non-preemtible symbols
D31751 Tidy up handleARMTlsRelocation [NFC]
To separate out the refactoring from the fix.

I've also put some extra comments in the handleARMTlsRelocation to explain a bit more about what the ABI requires.

My understanding is that only ARM and Mips need to write TLS entries directly into the GOT this way is because the Local and Global Dynamic TLS can't be relaxed to Initial Exec and Local Exec, on all other Targets including AArch64 (ARM != AArch64) we never have to use the GOT for the cases where it is required on ARM and Mips (static linking) as it is these cases that can be relaxed. A possibility is to have an ARMGotSection as well as a MipsGotSection that handles TLS Entries separately. This would mean that ARM and Mips could probably share the same handleNoRelaxTlsRelocation without many extra conditions. It would mean duplicating some of the code in GotSection for ARM which is what put me off doing so at the time.