This is an archive of the discontinued LLVM Phabricator instance.

[ELF] Fix placement of a sentinel entry in the .ARM.exidx section.
ClosedPublic

Authored by ikudrin on Dec 14 2017, 5:45 AM.

Diff Detail

Repository
rL LLVM

Event Timeline

ikudrin created this revision.Dec 14 2017, 5:45 AM

This looks sensible to me. One minor nit with the comment as the ABI does not mention a sentinel. We add it as some recent versions of libunwind depend on it being there (due to gold and ld.bfd generating one).

ELF/Writer.cpp
1187 ↗(On Diff #126937)

Strictly speaking the ABI doesn't require the .ARM.exidx to be terminated by a sentinel, but without one it does mean that the address range of the last entry would only be terminated by the end of the address space. Until recently libunwind depended on the presence of a sentinel.

ruiu added inline comments.Dec 14 2017, 2:40 PM
ELF/OutputSections.h
85 ↗(On Diff #126937)

I don't think we should change this function just fixing an edge case for .ARM.exidx and linker script. Isn't there any way that is less intrusive? Also, please avoid using a parameter with a default value in lld as much as possible.

ruiu added a comment.Dec 14 2017, 2:44 PM

I think a better way would be to add a terminator before processing linker scripts.

ikudrin updated this revision to Diff 127104.Dec 15 2017, 4:55 AM
  • Add a sentinel entry earlier so that it can be arranged in a regular way.
ikudrin updated this revision to Diff 127311.Dec 18 2017, 2:25 AM

Thanks for the comments!

  • Rebased on the top to embrace changes to deduplicate entries.
  • Implemented method {{empty()}} to remove a sentinel if there are no other entries.
  • Added a test to check that a sentinel is not removed by deduplication.
}

+ if (Sections.empty())
+ continue;

This is never true because of the sentinel, no?

I still have similar checks as a precaution for malicious linker scripts. See {{arm-data-prel.s}} as the example.

ikudrin updated this revision to Diff 127464.Dec 18 2017, 9:21 PM

Thanks for the review, @rafael!

  • RUN: ld.lld --no-merge-exidx-entries -T %t.script %t.o -shared -o %t.so
  • RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t.so | FileCheck %s

+// REQUIRES: arm

Why the change from // to #?

I see that you have unified the comment style, so, in this update I use the same, minimizing the diff.

+// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t.so | FileCheck %s --check-prefix=DUMP

Please use a prefix on the new FileCheck run instead to reduce the diff
(or commit the prefix change first).

Fixed.

+ if (!Sections.empty() && isa<ARMExidxSentinelSection>(Sections.back())) {

All tests pass if I move the !Sections.empty() to an assert.

As removeUnusedSyntheticSections() is not perfect, I can cook up a malicious script like this:

--- a/test/ELF/arm-data-prel.s
+++ b/test/ELF/arm-data-prel.s
@@ -1,7 +1,8 @@
 // RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj -o %t.o
 // RUN: echo "SECTIONS { \
-// RUN:          .text : { *(.text) } \
-// RUN:          .prel.test : { *(.ARM.exidx) } \
+// RUN:          .text : { *(.text.0) } \
+// RUN:          .prel.test : { *(.ARM.exidx.0) } \
+// RUN:          .trap : { *(.ARM.exidx) *(.dummy) } \
 // RUN:          .prel.test.TEST1 : { *(.ARM.exidx.TEST1) } \
 // RUN:          .TEST1 : { *(.TEST1) } } " > %t.script
 // RUN: ld.lld --script %t.script %t.o -o %t
@@ -32,7 +33,7 @@ _start:
  mov     pc, lr
  .fnend
 
- .section .text, "ax",%progbits
+ .section .text.0, "ax",%progbits
 // The generated .ARM.exidx section will refer to the personality
 // routine __aeabi_unwind_cpp_pr0. Provide a dummy implementation
 // to stop an undefined symbol error

Generally, I prefer my code to be safe. Although I must admit, that, with this script, lld still crashes, just a bit later, in OutputSection::finalize().

+ARMExidxSentinelSection *ARMExidxSentinelSection::create() {
+ if (Config->Relocatable)
+ return nullptr;
+
+ return make<ARMExidxSentinelSection>();
+}

This is now trivial, please inline.

Done.

LGTM with that.

Thanks! I'll commit this if there will be no further comments.

This revision was not accepted when it landed; it landed in state Needs Review.Dec 20 2017, 12:56 AM
This revision was automatically updated to reflect the committed changes.
ruiu added inline comments.Dec 27 2017, 12:20 AM
lld/trunk/ELF/SyntheticSections.cpp
2573

It looks like this function returns true if the parent section of this section is empty. That's different from what you'd expect for emptyfunction. empty should return true if this is empty, not other object.

lld/trunk/ELF/SyntheticSections.h
790

= 0 is too C-ish. Please use nullptr. Also this needs comment because it is not obvious what this member is. What is Highest?