[lld/mac] Don't crash when dead-stripping removes all unwind info

If the input has compact unwind info but all of it is removed
after dead stripping, we would crash. Now we don't write any
__unwind_info section at all, like ld64.

This is a bit awkward to implement because we only know the final
state of unwind info after UnwindInfoSectionImpl<Ptr>::finalize(),
which is called after sections are added. So add a small amount of
bookkeeping to relocateCompactUnwind() instead (which runs earlier)
so that we can predict what finalize() will do before it runs.

Fixes PR51010.

Differential Revision: https://reviews.llvm.org/D105557
This commit is contained in:
Nico Weber 2021-07-07 11:28:27 -04:00
parent d4cb286b05
commit 8a7b5ebf4d
3 changed files with 42 additions and 1 deletions

View file

@ -165,6 +165,14 @@ void UnwindInfoSectionImpl<Ptr>::prepareRelocations(ConcatInputSection *isec) {
for (size_t i = 0; i < isec->relocs.size(); ++i) {
Reloc &r = isec->relocs[i];
assert(target->hasAttr(r.type, RelocAttrBits::UNSIGNED));
if (r.offset % sizeof(CompactUnwindEntry<Ptr>) == 0) {
if (auto *referentIsec = r.referent.dyn_cast<InputSection *>())
if (!cast<ConcatInputSection>(referentIsec)->shouldOmitFromOutput())
allEntriesAreOmitted = false;
continue;
}
if (r.offset % sizeof(CompactUnwindEntry<Ptr>) !=
offsetof(CompactUnwindEntry<Ptr>, personality))
continue;
@ -402,6 +410,13 @@ template <class Ptr> void UnwindInfoSectionImpl<Ptr>::finalize() {
}),
cuPtrVector.end());
// If there are no entries left after adding explicit "no unwind info"
// entries and removing entries for dead-stripped functions, don't write
// an __unwind_info section at all.
assert(allEntriesAreOmitted == cuPtrVector.empty());
if (cuPtrVector.empty())
return;
// Fold adjacent entries with matching encoding+personality+lsda
// We use three iterators on the same cuPtrVector to fold in-situ:
// (1) `foldBegin` is the first of a potential sequence of matching entries
@ -531,6 +546,8 @@ template <class Ptr> void UnwindInfoSectionImpl<Ptr>::finalize() {
template <class Ptr>
void UnwindInfoSectionImpl<Ptr>::writeTo(uint8_t *buf) const {
assert(!cuPtrVector.empty() && "call only if there is unwind info");
// section header
auto *uip = reinterpret_cast<unwind_info_section_header *>(buf);
uip->version = 1;

View file

@ -28,7 +28,7 @@ template <class Ptr> struct CompactUnwindEntry {
class UnwindInfoSection : public SyntheticSection {
public:
bool isNeeded() const override {
return !compactUnwindSection->inputs.empty();
return !compactUnwindSection->inputs.empty() && !allEntriesAreOmitted;
}
uint64_t getSize() const override { return unwindInfoSize; }
virtual void addInput(ConcatInputSection *) = 0;
@ -43,6 +43,7 @@ protected:
ConcatOutputSection *compactUnwindSection;
uint64_t unwindInfoSize = 0;
bool allEntriesAreOmitted = true;
};
UnwindInfoSection *makeUnwindInfoSection();

View file

@ -62,6 +62,16 @@
# CHECK-NEXT: __DATA_CONST __got 0x{{[0-9A-F]*}} pointer
# CHECK-NOT: __TEXT
## Check that we don't create an __unwind_info section if no unwind info
## remains after dead-stripping.
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin19.0.0 \
# RUN: %t/empty-after-dead-strip.s -o %t/x86_64-empty-after-dead-strip.o
# RUN: %lld -dylib -dead_strip -arch x86_64 -lSystem \
# RUN: %t/x86_64-empty-after-dead-strip.o -o %t/x86_64-empty-after-strip.dylib
# RUN: llvm-objdump --macho --unwind-info %t/x86_64-empty-after-strip.dylib | \
# RUN: FileCheck %s --check-prefixes=NOUNWIND --allow-empty
# NOUNWIND-NOT: Contents of __unwind_info section:
#--- my-personality.s
.globl _my_personality, _exception0
.text
@ -146,3 +156,16 @@ _exception1:
.space 1
.subsections_via_symbols
#--- empty-after-dead-strip.s
.text
## Local symbol with unwind info.
## The symbol is removed by -dead_strip.
_foo :
.cfi_startproc
.cfi_def_cfa_offset 16
retq
.cfi_endproc
.subsections_via_symbols