This is an archive of the discontinued LLVM Phabricator instance.

[ELF] - Fix for "LLD crashes with --emit-relocs when trying to proccess .eh_frame"
AbandonedPublic

Authored by grimar on Mar 19 2018, 6:25 AM.

Details

Summary

This fixes PR36367 which is about segfault when --emit-relocs is
used together with .eh_frame sections.

That happens because we reorder .eh_frame sections and corresponding
.rela.eh_frame sections when combining .eh_frames.
Usually, objects do not do that and we error out on such objects (I added the test case),
so the situation with .eh_frame is unique.

The patch fixes it.

Diff Detail

Event Timeline

grimar created this revision.Mar 19 2018, 6:25 AM
grimar retitled this revision from [ELF] - Fix for LLD crashes with --emit-relocs when trying to proccess .eh_frame to [ELF] - Fix for "LLD crashes with --emit-relocs when trying to proccess .eh_frame".Mar 19 2018, 6:25 AM
grimar added a subscriber: dstolfa.

Seems to apply cleanly and works on FreeBSD. Thanks @grimar!

espindola added inline comments.Mar 19 2018, 2:08 PM
ELF/Writer.cpp
161

This is a useful invariant. Could we do this even when Config->EmitRelocs is false?

1391

This comment is now out of date.

test/ELF/emit-relocs-eh-frame.s
17

I think you can delete the .size and the .Lfunc_end0.

The crash is from

// This is for --emit-relocs. If .text.foo is emitted as .text.bar, we want
// to emit .rela.text.foo as .rela.text.bar for consistency (this is not
// technically required, but not doing it is odd). This code guarantees that.
if ((S->Type == SHT_REL || S->Type == SHT_RELA) &&
    !isa<SyntheticSection>(S)) {
  OutputSection *Out =
      cast<InputSection>(S)->getRelocatedSection()->getOutputSection();

Where Out is null because we call this for the relocation section before .eh_frame. The caller is

std::vector<OutputSection *> V;
for (InputSectionBase *S : InputSections) {
  if (!S->Live || S->Parent)
    continue;

  StringRef Name = getOutputSectionName(S);

So this suggests two options that might be simpler.

  • Just handle Out being null. We are just trying to get a better looking output section name. It is not critical.
  • Do two passes over the input section in LinkerScript::addOrphanSections.

The crash is from

// This is for --emit-relocs. If .text.foo is emitted as .text.bar, we want
// to emit .rela.text.foo as .rela.text.bar for consistency (this is not
// technically required, but not doing it is odd). This code guarantees that.
if ((S->Type == SHT_REL || S->Type == SHT_RELA) &&
    !isa<SyntheticSection>(S)) {
  OutputSection *Out =
      cast<InputSection>(S)->getRelocatedSection()->getOutputSection();

Where Out is null because we call this for the relocation section before .eh_frame. The caller is

std::vector<OutputSection *> V;
for (InputSectionBase *S : InputSections) {
  if (!S->Live || S->Parent)
    continue;

  StringRef Name = getOutputSectionName(S);

So this suggests two options that might be simpler.

  • Just handle Out being null. We are just trying to get a better looking output section name. It is not critical.
  • Do two passes over the input section in LinkerScript::addOrphanSections.

This is the approach I've taken in https://reviews.llvm.org/D44601 (though it was still a workaround at that point). @arichardson pointed out that we should probably have an output similar to ld.bfd and gold, so I suppose the fix should be guided by that as well as where it would be best to handle this case?

Domagoj Stolfa via Phabricator via llvm-commits
<llvm-commits@lists.llvm.org> writes:

dstolfa added a comment.

In https://reviews.llvm.org/D44622#1042429, @espindola wrote:

The crash is from

// This is for --emit-relocs. If .text.foo is emitted as .text.bar, we want
// to emit .rela.text.foo as .rela.text.bar for consistency (this is not
// technically required, but not doing it is odd). This code guarantees that.
if ((S->Type == SHT_REL || S->Type == SHT_RELA) &&
    !isa<SyntheticSection>(S)) {
  OutputSection *Out =
      cast<InputSection>(S)->getRelocatedSection()->getOutputSection();

Where Out is null because we call this for the relocation section before .eh_frame. The caller is

std::vector<OutputSection *> V;
for (InputSectionBase *S : InputSections) {
  if (!S->Live || S->Parent)
    continue;

  StringRef Name = getOutputSectionName(S);

So this suggests two options that might be simpler.

  • Just handle Out being null. We are just trying to get a better looking output section name. It is not critical.
  • Do two passes over the input section in LinkerScript::addOrphanSections.

This is the approach I've taken in https://reviews.llvm.org/D44601 (though it was still a workaround at that point). @arichardson pointed out that we should probably have an output similar to ld.bfd and gold, so I suppose the fix should be guided by that as well as where it would be best to handle this case?

Instead of returning "" it could return S->Name and that would handle
all real world cases I think.

I think doing two passes in LinkerScript::addOrphanSections might be the
best solution as it is simple and handles even synthetic tests like using
a linker script to assign .eh_frame to an output section with a
different name.

Cheers,
Rafael

Domagoj Stolfa via Phabricator via llvm-commits
<llvm-commits@lists.llvm.org> writes:

dstolfa added a comment.

In https://reviews.llvm.org/D44622#1042429, @espindola wrote:

The crash is from

// This is for --emit-relocs. If .text.foo is emitted as .text.bar, we want
// to emit .rela.text.foo as .rela.text.bar for consistency (this is not
// technically required, but not doing it is odd). This code guarantees that.
if ((S->Type == SHT_REL || S->Type == SHT_RELA) &&
    !isa<SyntheticSection>(S)) {
  OutputSection *Out =
      cast<InputSection>(S)->getRelocatedSection()->getOutputSection();

Where Out is null because we call this for the relocation section before .eh_frame. The caller is

std::vector<OutputSection *> V;
for (InputSectionBase *S : InputSections) {
  if (!S->Live || S->Parent)
    continue;

  StringRef Name = getOutputSectionName(S);

So this suggests two options that might be simpler.

  • Just handle Out being null. We are just trying to get a better looking output section name. It is not critical.
  • Do two passes over the input section in LinkerScript::addOrphanSections.

This is the approach I've taken in https://reviews.llvm.org/D44601 (though it was still a workaround at that point). @arichardson pointed out that we should probably have an output similar to ld.bfd and gold, so I suppose the fix should be guided by that as well as where it would be best to handle this case?

Instead of returning "" it could return S->Name and that would handle
all real world cases I think.

I think doing two passes in LinkerScript::addOrphanSections might be the
best solution as it is simple and handles even synthetic tests like using
a linker script to assign .eh_frame to an output section with a
different name.

Cheers,
Rafael

I believe the change I've just added in the review fixes the issue in the most minimal way possible.

I think doing two passes in LinkerScript::addOrphanSections might be the
best solution as it is simple and handles even synthetic tests like using
a linker script to assign .eh_frame to an output section with a
different name.

Cheers,
Rafael

I tried to do this while investigated the ways to fix an issue.
What I did not like with such approach was:

  1. Amount of changes was larger than in this patch.
  2. Changes were in a generic code, but --emit-relocs + .eh_frame is a very specific corner case.

And I think it can not be used for something else because we
explicitly do not support reordered objects.
So I tried to find a way to isolate the fix from the common flow.
(like this patch do)

I'll post the patch for above to demonstrate results I had though.

I also tried one more way: during combining of eh_frames I moved
synthetic EhFrame in place of the first .eh_frame. With that, it also guaranteed
the proper order, though broke a large number of test cases and particularly
moved EhFrame before EhFrameHdr. So I refused from such approach too.

grimar abandoned this revision.Mar 23 2018, 2:15 AM

Abandoning, going to commit D44679.