This is an archive of the discontinued LLVM Phabricator instance.

[ELF] - keep alive all non-text sections referenced by .eh_frame
ClosedPublic

Authored by grimar on Apr 28 2016, 6:35 AM.

Details

Summary

Patch implements one of suggestions from Rafael Ávila de Espíndola,
to fix segfault after section that contains personality being
garbage collected.

Suggestion was just to keep alive all non executable sections
referenced by .eh_frame.

This fixes PR27529.

Diff Detail

Repository
rL LLVM

Event Timeline

grimar updated this revision to Diff 55408.Apr 28 2016, 6:35 AM
grimar retitled this revision from to [ELF] - keep alive all non-text sections referenced by .eh_frame.
grimar updated this object.
grimar added reviewers: ruiu, rafael.
grimar added subscribers: llvm-commits, grimar.
compnerd added inline comments.
ELF/MarkLive.cpp
102 ↗(On Diff #55408)

Unused typedef.

compnerd added inline comments.Apr 28 2016, 10:51 AM
ELF/MarkLive.cpp
190 ↗(On Diff #55408)

Nit: you misspelt referred.

194 ↗(On Diff #55408)

Is there a reason to not just merge this into the loops above? It seems unnecessary to re-iterate the objects and sections within the objects.

test/ELF/eh-frame-gc.s
21 ↗(On Diff #55408)

Might be able to drop the .long 0 as well. Just thought of that, haven't had a chance to try it.

ruiu edited edge metadata.Apr 28 2016, 11:27 AM

This patch seems to be pretty effective for large executables with debug info. r266158 (Rafael's patch to change the way how we apply relocations) caused a temporary performance degradation for such executables, but this patch makes it even faster than before.

Time to link clang with debug info (output size is 1070 MB):

before r266158: 15.312 seconds (0%)
r266158:        17.301 seconds (+13.0%)
Head:           16.484 seconds (+7.7%)
w/patch:        13.166 seconds (-14.0%)
ruiu added a comment.Apr 28 2016, 11:39 AM

Oh, I'm sorry, I added a comment to an unrelated patch. Ignore the above message.

compnerd requested changes to this revision.Apr 28 2016, 1:18 PM
compnerd added a reviewer: compnerd.

This introduces a new crash on x86_64. Ive not had a chance to reduce this to a test case that is easy to work with, but the following seems to demonstrate the issue:

$ cat /tmp/reduced.cc
struct S { static inline long m() { return 0; } };

#if defined(TU_A)
void f(void) { S::m(); }
#elif defined(TU_B)
void g(void) { S::m(); }
#endif

$ clang++ -target x86_64-unknown-linux-gnu -DTU_A -c /tmp/reduced.cc -o /tmp/reduced-0.o
$ clang++ -target x86_64-unknown-linux-gnu -DTU_B -c /tmp/reduced.cc -o /tmp/reduced-1.o
$ lld -flavor gnu --eh-frame-hdr -m elf_x86_64 -shared -o /tmp/reduced.so --gc-sections /tmp/reduced-0.o /tmp/reduced-1.o

This revision now requires changes to proceed.Apr 28 2016, 1:18 PM

This introduces a new crash on x86_64. Ive not had a chance to reduce this to a test case that is easy to work with, but the following seems to demonstrate the issue:

Reproduced, looking at.

ELF/MarkLive.cpp
190 ↗(On Diff #55408)

Thanks !

194 ↗(On Diff #55408)

I tried both ways when wrote that and finally decided to split eh_frame processing as special case just to emphasize its exceptional nature. Have no real preference here.

This introduces a new crash on x86_64. Ive not had a chance to reduce this to a test case that is easy to work with, but the following seems to demonstrate the issue:

$ cat /tmp/reduced.cc
struct S { static inline long m() { return 0; } };

#if defined(TU_A)
void f(void) { S::m(); }
#elif defined(TU_B)
void g(void) { S::m(); }
#endif

$ clang++ -target x86_64-unknown-linux-gnu -DTU_A -c /tmp/reduced.cc -o /tmp/reduced-0.o
$ clang++ -target x86_64-unknown-linux-gnu -DTU_B -c /tmp/reduced.cc -o /tmp/reduced-1.o
$ lld -flavor gnu --eh-frame-hdr -m elf_x86_64 -shared -o /tmp/reduced.so --gc-sections /tmp/reduced-0.o /tmp/reduced-1.o

Just in case, this can be reduced to:
reduced-0.s:

.section .text,"G",@progbits,foo
.type foo,@function
foo:

reduced-1.s:

.section .text,"G",@progbits,foo
.type foo,@function
foo:
 .cfi_startproc
 .cfi_endproc
llvm-mc -filetype=obj -triple=x86_64-pc-linux reduced-0.s -o reduced0.o
llvm-mc -filetype=obj -triple=x86_64-pc-linux reduced-1.s -o reduced1.o
grimar updated this revision to Diff 55609.Apr 29 2016, 9:00 AM
grimar edited edge metadata.
  • Fixed segfault case reported.
  • Addressed review comments.
  • Slightly updated testcase (NFC).
ELF/MarkLive.cpp
102 ↗(On Diff #55408)

Fixed.

194 ↗(On Diff #55408)

After revisiting this, merged into one loop to avoid additional iteration.

test/ELF/eh-frame-gc.s
21 ↗(On Diff #55408)

Done.

rafael accepted this revision.Apr 30 2016, 8:59 AM
rafael edited edge metadata.

LGTM with nits.

I now remember that eh can point to LSDA, but lets get this fixed first.

ELF/MarkLive.cpp
78 ↗(On Diff #55609)

Please use std::function<void(ResolvedReloc<ELFT>)> to mach the declaration of forEachSuccessor.

79 ↗(On Diff #55609)

These now have a single use each, please inline.

94 ↗(On Diff #55609)

Single use typedef.

test/ELF/eh-frame-gc.s
9 ↗(On Diff #55609)

Give the section a more unique name like test_personality_section.

This revision was automatically updated to reflect the committed changes.
grimar marked 4 inline comments as done.
grimar added inline comments.May 2 2016, 7:00 AM
ELF/MarkLive.cpp
78 ↗(On Diff #55609)

Done.

79 ↗(On Diff #55609)

Done.

94 ↗(On Diff #55609)

It was single use, I removed typedef (like was in run()).

test/ELF/eh-frame-gc.s
9 ↗(On Diff #55609)

Done.