This is an archive of the discontinued LLVM Phabricator instance.

[ELF] - Drop special flags for empty output sections.
ClosedPublic

Authored by grimar on Mar 12 2018, 3:50 AM.

Details

Summary

This fixes PR36598.

LLD currently crashes when we have empty output section
with SHF_LINK_ORDER flag. This might happen if we place an empty
synthetic section in the linker script, but keep output section alive with the
use of additional symbol, for example.

The patch fixes the issue by dropping all special flags for empty sections.

Diff Detail

Repository
rL LLVM

Event Timeline

grimar created this revision.Mar 12 2018, 3:50 AM
grimar updated this revision to Diff 137983.Mar 12 2018, 3:59 AM
  • Simplified.
grimar updated this revision to Diff 137984.Mar 12 2018, 4:11 AM
  • Improved test case.

George Rimar via Phabricator via llvm-commits
<llvm-commits@lists.llvm.org> writes:

void LinkerScript::adjustSectionsBeforeSorting() {
@@ -839,32 +839,34 @@

// the previous sections. Only a few flags are needed to keep the impact low.
uint64_t Flags = SHF_ALLOC;
  • for (BaseCommand *&Cmd : SectionCommands) {

+ for (BaseCommand *Cmd : SectionCommands) {

auto *Sec = dyn_cast<OutputSection>(Cmd);
if (!Sec)
  continue;
 
// A live output section means that some input section was added to it. It
  • // might have been removed (gc, or empty synthetic section), but we at least

+ // might have been removed (if it was empty synthetic section), but we at least

// know the flags.
if (Sec->Live)
  • Flags = Sec->Flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR);
  • else
  • Sec->Flags = Flags; -
  • if (isDiscardable(*Sec)) {
  • Sec->Live = false;
  • Cmd = nullptr;
  • }

+ Flags = Sec->Flags;
+
+ // We do not want to keep any special flags for output section in case it is empty.
+ bool IsEmpty = getInputSections(Sec).empty();
+ if (IsEmpty)
+ Sec->Flags = Flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR);
+
+ Sec->Live = !IsEmpty || !isDiscardable(*Sec);

I would keep this as

if (IsEmpty && isDiscardable(*Sec)) {
  Sec->Live = false;
  Cmd = nullptr;
}
}
 
// It is common practice to use very generic linker scripts. So for any
// given run some of the output sections in the script will be empty.
// We could create corresponding empty output sections, but that would
// clutter the output.
// We instead remove trivially empty sections. The bfd linker seems even
// more aggressive at removing them.
  • llvm::erase_if(SectionCommands, [&](BaseCommand *Base) { return !Base; });

+ llvm::erase_if(SectionCommands, [&](BaseCommand *Base) {
+ return isa<OutputSection>(Base) && !cast<OutputSection>(Base)->Live;
+ });
}

And this as

llvm::erase_if(SectionCommands, [&](BaseCommand *Base) { return !Base; });

LGTM with that.

Cheers,
Rafael

This revision was not accepted when it landed; it landed in state Needs Review.Mar 13 2018, 1:35 AM
This revision was automatically updated to reflect the committed changes.
ruiu added inline comments.Mar 14 2018, 1:24 PM
lld/trunk/ELF/LinkerScript.cpp
859–862

I believe this patch is correct, but this logic seems a bit weird to me. If an section is empty, we reset the section flag, but we also discard the section. If the section is discarded, why does its flag matter? Why do you have to reset it just before discarding it?

Rui Ueyama via Phabricator <reviews@reviews.llvm.org> writes:

ruiu added inline comments.

Comment at: lld/trunk/ELF/LinkerScript.cpp:859-862
+ if (IsEmpty && isDiscardable(*Sec)) {

  Sec->Live = false;
  Cmd = nullptr;
}

I believe this patch is correct, but this logic seems a bit weird to me. If an section is empty, we reset the section flag, but we also discard the section. If the section is discarded, why does its flag matter? Why do you have to reset it just before discarding it?

To handle the !isDiscardable case. The new code is:

if (IsEmpty)
  Sec->Flags = Flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR);

if (IsEmpty && isDiscardable(*Sec)) {

So if the section is empty but must be kept for some other reason we
update the flags.

Cheers,
Rafael

ruiu added a comment.Mar 14 2018, 1:32 PM

Ah, thanks! I misunderstood "&&" with "||".