This is an archive of the discontinued LLVM Phabricator instance.

[ELF] Refactor DynamicReloc to fix incorrect relocation addends
ClosedPublic

Authored by arichardson on Apr 14 2021, 9:08 AM.

Details

Summary

This patch changes the DynamicReloc class to store an enum instead
of the overloaded useSymVA member to make it easier to understand
and fix incorrect addends being written in some corner cases. The
change is motivated by a follow-up review that checks the value of
implicit Elf_Rel addends written to the output file.

This patch fixes an incorrect output when using -z rela for i386 files
with R_386_GOT32 relocations (not that this really matters since it's an
unsupported configuration).
Storing the relocation expression kind also addresses an incorrect addend
FIXME in ppc64-abs64-dyn.s introduced in D63383.

DynamicReloc now also has a special case for the MIPS TLS relocations
(DynamicReloc::AgainstSymbolWithTargetVA) since the
R_MIPS_TLS_TPREL{32/64} the symbol VA to the GOT for preemptible
symbols. I'm not sure if the symbol value actually should be written
for R_MIPS_TLS_TPREL32, but this patch does not attempt to change
that behaviour.

Diff Detail

Event Timeline

arichardson created this revision.Apr 14 2021, 9:08 AM
arichardson requested review of this revision.Apr 14 2021, 9:08 AM
Herald added a project: Restricted Project. · View Herald TranscriptApr 14 2021, 9:08 AM

The getImplicitAddend enhancement (-z rel) can be moved to a separate patch, but the dynamic only relocation types (JUMP_SLOT, RELATIVE, IRELATIVE, etc) should be removed since they can't be input.

useSymVA is subtle and I need time to grok it. I wonder whether the new member can improve https://bugs.llvm.org/show_bug.cgi?id=47009 TLSDESC for -z rel?

MaskRay added inline comments.Apr 14 2021, 4:05 PM
lld/test/ELF/got32-i386-pie-rw.s
3

For non-disassembly ELF dumping, prefer llvm-readelf/llvm-readobj. llvm-objdump output tends to have BFD specific stuff. In binutils, readelf does not link against BFD and is immune to the BFD internals.

The getImplicitAddend enhancement (-z rel) can be moved to a separate patch, but the dynamic only relocation types (JUMP_SLOT, RELATIVE, IRELATIVE, etc) should be removed since they can't be input.

useSymVA is subtle and I need time to grok it. I wonder whether the new member can improve https://bugs.llvm.org/show_bug.cgi?id=47009 TLSDESC for -z rel?

Yes, it appears this new error triggers for the test case from that bug:

arch64-tlsdesc-rel.s.tmp-rel.so:(.got+0x10): wrote incorrect addend for dynamic relocation: value is 0x0 but expected 0x4 for R_AARCH64_TLSDESC against y at 0x203C8

Will update to handle that case.

arichardson added inline comments.Apr 15 2021, 3:34 AM
lld/test/ELF/got32-i386-pie-rw.s
3

Sure, I can change this to only dump the relocations, the disassembly is not important for the .o file.

The getImplicitAddend enhancement (-z rel) can be moved to a separate patch, but the dynamic only relocation types (JUMP_SLOT, RELATIVE, IRELATIVE, etc) should be removed since they can't be input.

useSymVA is subtle and I need time to grok it. I wonder whether the new member can improve https://bugs.llvm.org/show_bug.cgi?id=47009 TLSDESC for -z rel?

I've added support for R_AARCH64_TLSDESC in D100544.

Thanks for sending the patch; I'm planning to take a look tomorrow (Friday).

The Arm relocations look correct to me. I've got a few suggestions, but no objections.

lld/ELF/OutputSections.cpp
548 ↗(On Diff #337477)

Would it be possible to assert that we are not linking with -r and make sure we don't call checkDynRelAddends() for ld -r?

566 ↗(On Diff #337477)

Although harder to read than an instance of the error message, it took a second reading to work out which value was the addend. Perhaps "wrote incorrect addend value 0x... but expected 0x..."

567 ↗(On Diff #337477)

If I've understood this correctly if we get here then it is an internal LLD error rather than a user error? If I'm right it would be useful to prefix with something along the lines "Internal error, please contact your supplier etc." Otherwise if I'm just using LLD I might wonder if it is something that I've done wrong.

lld/ELF/SyntheticSections.h
484

I found it difficult from the comments what the interaction between the combinations of useSymVA and mustRetainSymbol are. Especially reading the two comments at the same time.

Is there scope for combining the two booleans into 1 enumeration, essentially capturing the valid combinations with a name? I think once set they aren't changed.

The getImplicitAddend enhancement (-z rel) can be moved to a separate patch, but the dynamic only relocation types (JUMP_SLOT, RELATIVE, IRELATIVE, etc) should be removed since they can't be input.

useSymVA is subtle and I need time to grok it. I wonder whether the new member can improve https://bugs.llvm.org/show_bug.cgi?id=47009 TLSDESC for -z rel?

Regarding the JUMP_SLOT, RELATIVE, IRELATIVE relocations: I could add a separate target->getImplicitDynRelAddend() that handles the dynamic-only relocation, so that we still get an error message if we see one of the dynamic-only relocations in an input file?

It might also be nice to check the value of the JUMP_SLOT relocations (probably in a follow-up patch) instead of skipping them. This should be easy once the DynamicReloc useSymVA member been changed to an enum.

Longer-term I think it would be nice if the implicit addend code could be moved to LLVM instead so that llvm-readelf/llvm-readobj can also make use of it.

lld/ELF/OutputSections.cpp
548 ↗(On Diff #337477)

Yes, that sounds like a better approach, will update.

567 ↗(On Diff #337477)

Yes, this should only ever be triggered if there is either a missing case in target->getImplicitAddend() (i.e. using -z rel on an architecture where getImplicitAddend() is not implemented) or if we failed to write the implicit addend correctly.

lld/ELF/SyntheticSections.h
484

It also took me a long time to understand what is going on here. Will submit a new version that uses an enum instead.

arichardson marked 5 inline comments as done.

Use an enum instead of the highly overloaded useSymVA. Hopefully the logic is easier to follow now.

@MaskRay Would you like me to move handling of linker-generated relocations out of Target::getImplicitAddend() and into a new function instead of handling all in one function?

Herald added a project: Restricted Project. · View Herald Transcript
Herald added a reviewer: Restricted Project. · View Herald Transcript
Herald added a subscriber: mgorny. · View Herald Transcript
arichardson added inline comments.Apr 21 2021, 3:25 AM
lld/ELF/OutputSections.cpp
548 ↗(On Diff #337477)

Actually, this also happens for --emit-relocs, so I think it's probably better to skip them. I've updated the comment.

567 ↗(On Diff #337477)

The new warning is

ld.lld: error: /Users/alex/cheri/upstream-llvm-project/cmake-build-debug/tools/lld/test/ELF/Output/got32-i386-pie-rw.s.tmp:(.got+0x0): internal linker error: wrote incorrect addend value 0x0 instead of 0x1180 for dynamic R_386_RELATIVE relocation against foo at offset 0x31F0
PLEASE submit a bug report to https://bugs.llvm.org/ and include the crash backtrace.
arichardson added inline comments.Apr 21 2021, 3:27 AM
lld/ELF/SyntheticSections.cpp
1105

Will split this unrelated change out into a separate commit, just noticed that the link no longer works.

thakis added a subscriber: thakis.Apr 21 2021, 6:11 AM
thakis added inline comments.
lld/MachO/CMakeLists.txt
58 ↗(On Diff #339165)

If you're adding this here (why?), should you remove it from lld/tools/lld/CMakeLists.txt ?

arichardson added inline comments.Apr 21 2021, 6:13 AM
lld/MachO/CMakeLists.txt
58 ↗(On Diff #339165)

Sorry that should not be part of this review. Looks like I accidentally squashed another commit into this one.
LLD was failing to build for me -DBUILD_SHARED_LIBS=ON and that seemed like the appropriate fix. Will see if this is still needed with the latest HEAD commit.

Drop unrelated changes

I'm aiming to take a look tomorrow. Sorry for the delay.

I've had a quick read through and I like where this is going. There's a lot to check through and I've run out of time today. I've left a couple of small suggestions. Will need to come back and look in more detail, probably next week to see if I've got anything else to add.

lld/ELF/SyntheticSections.h
455–456

Could we add a similar comment to the MIPS multi-GOT implementation?
// This constructor records a relative relocation with no symbol

526

Is there scope to rename this so that it is easier to see at the call site? Like addRelativeReloc(). For example addSymbolReloc() or addAgainstSymbolReloc();

I've had a quick read through and I like where this is going. There's a lot to check through and I've run out of time today. I've left a couple of small suggestions. Will need to come back and look in more detail, probably next week to see if I've got anything else to add.

Thanks for reviewing! I noticed there is one larger issue that needs to be addressed: If we use -z rel / --apply-dynamic-relocs, this may report false-positive errors for architectures with missing getImplicitAddend() cases (e.g. AArch64).
I wonder if there needs to be a per-architecture default for checking the addends so that we can gradually enable this by default (starting with ARM, MIPS, and i386). I can then split out the X86_64 getImplicitAddend() changes to a separate review.
Maybe there should be an internal testing option --[no-]check-dynamic-reloc-addends until getImplicitAddend() is implemented for all architectures?

lld/ELF/SyntheticSections.h
526

Sounds good, will do in next version of this patch.

Maybe OutputSection::checkDynRelAddends() should be moved to a separate patch and this one just does the DynamicReloc refactoring that fixes ppc64-abs64-dyn.s and got32-i386-pie-rw.s with -z rela.
@MaskRay would that make reviewing the patch easier?

Maybe OutputSection::checkDynRelAddends() should be moved to a separate patch and this one just does the DynamicReloc refactoring that fixes ppc64-abs64-dyn.s and got32-i386-pie-rw.s with -z rela.
@MaskRay would that make reviewing the patch easier?

I am still unclear that we want to do OutputSection::checkDynRelAddends() unconditionally. It is probably a good addition for LLVM_ENABLE_ASSERTIONS=on builds.

The improvement bits should definitely be separate from the check bits.

arichardson planned changes to this revision.Apr 27 2021, 2:51 PM

Maybe OutputSection::checkDynRelAddends() should be moved to a separate patch and this one just does the DynamicReloc refactoring that fixes ppc64-abs64-dyn.s and got32-i386-pie-rw.s with -z rela.
@MaskRay would that make reviewing the patch easier?

I am still unclear that we want to do OutputSection::checkDynRelAddends() unconditionally. It is probably a good addition for LLVM_ENABLE_ASSERTIONS=on builds.

The improvement bits should definitely be separate from the check bits.

Will try to split this into separate revisions tomorrow.

int3 resigned from this revision.Apr 27 2021, 3:54 PM
smeenai removed a project: Restricted Project.Apr 27 2021, 3:57 PM
smeenai removed a reviewer: Restricted Project.

Split the addend checking into a separate review, this now only include fixes for incorrect addends plus the DynamicReloc refactoring.

arichardson retitled this revision from [ELF] Check the Elf_Rel addends for dynamic relocations to [ELF] Refactor DynamicReloc to fix incorrect relocation addends.Apr 28 2021, 6:31 AM
arichardson edited the summary of this revision. (Show Details)
arichardson removed a reviewer: int3.
arichardson marked an inline comment as done.Apr 28 2021, 7:04 AM
arichardson added inline comments.
lld/ELF/InputSection.cpp
1021 ↗(On Diff #341173)

This is needed now to avoid UB caused by`*rel.sym` if rel.sym is NULL.

  • Add addSymbolReloc() as suggested
arichardson marked an inline comment as done.Apr 28 2021, 7:06 AM

Thanks for the update, and sorry for the delay in reviewing - bit of a busy week. I'm happy with this approach, but I think it is worth getting the go ahead from MaskRay.

lld/ELF/SyntheticSections.h
453

The default parameters look to be used in very few places. I'm wondering if it would make sense to make 0 and R_ABS explicit at the call site as they are not obvious.

MaskRay added inline comments.Apr 30 2021, 2:17 PM
lld/ELF/InputSection.cpp
1021 ↗(On Diff #341173)

If I delete this block, all tests pass.

lld/ELF/SyntheticSections.cpp
1592

This is unneeded

lld/ELF/SyntheticSections.h
432

is a relative relocation

Not accurate.
tlsModuleIndexRel uses RelativeNoSymbol, however, the DTPMOD relocation type has nothing to do with R_*_RELATIVE.

/// This dynamic relocation

A bit verbose to repeat this for every value. Just omit the phrase?

Perhaps rename to AddendOnly, with a comment like /// Use 0 as the symbol value ...

437

be a relative relocation

Not accurate. TLS-IE emitted dynamic R_X86_64_TPOFF64 uses this kind as well.

Perhaps AddendOnlyWithTargetVA?

/// Use 0 as the symbol value ... The addend is computed with getRelocTargetVA().

No need to emphasize Elf_Rel/Elf_Rela/

461

This constructor is only called once, in MIPS multi-GOT code. The constructor should be deleted.

470

Possible to use kind only and don't check sym?

This is a good change. Hope you can find time to finish it:)

arichardson marked 5 inline comments as done.Jul 2 2021, 4:40 AM

Apologies for the delay, I was away on holiday and then working on non-LLVM tasks for the past two months. I've uploaded a new version that should hopefully address the remaining comments.

lld/ELF/InputSection.cpp
1021 ↗(On Diff #341173)

I got UBSan failures before but it might just be because of further local changes after this patch. Will drop if it isn't needed after all.
I believe the sym == nullptr case can only happen for the MIPS GOT and that shouldn't call relocateAlloc right now as it writes addends explicitly (I had a follow-up change to use relocateAlloc instead, so it's probably only needed for that patch).

lld/ELF/SyntheticSections.cpp
1592

I feel like I needed this to make GCC happy. I can remove it and see if CI complains.

lld/ELF/SyntheticSections.h
461

The other constructors can't be used here since they are missing the OutputSection* parameter.
I could add it to the constructor above if you prefer, but since it's only needed for MIPS I think having a separate one is slightly cleaner.

arichardson marked 2 inline comments as done.
MaskRay accepted this revision.Jul 2 2021, 8:19 PM

Looks great!

This revision is now accepted and ready to land.Jul 2 2021, 8:19 PM