diff --git a/lld/MachO/UnwindInfoSection.h b/lld/MachO/UnwindInfoSection.h --- a/lld/MachO/UnwindInfoSection.h +++ b/lld/MachO/UnwindInfoSection.h @@ -28,7 +28,7 @@ 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 @@ ConcatOutputSection *compactUnwindSection; uint64_t unwindInfoSize = 0; + bool allEntriesAreOmitted = true; }; UnwindInfoSection *makeUnwindInfoSection(); diff --git a/lld/MachO/UnwindInfoSection.cpp b/lld/MachO/UnwindInfoSection.cpp --- a/lld/MachO/UnwindInfoSection.cpp +++ b/lld/MachO/UnwindInfoSection.cpp @@ -165,6 +165,14 @@ 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) == 0) { + if (auto *referentIsec = r.referent.dyn_cast()) + if (!cast(referentIsec)->shouldOmitFromOutput()) + allEntriesAreOmitted = false; + continue; + } + if (r.offset % sizeof(CompactUnwindEntry) != offsetof(CompactUnwindEntry, personality)) continue; @@ -402,6 +410,13 @@ }), 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 void UnwindInfoSectionImpl::writeTo(uint8_t *buf) const { + assert(!cuPtrVector.empty() && "call only if there is unwind info"); + // section header auto *uip = reinterpret_cast(buf); uip->version = 1; diff --git a/lld/test/MachO/compact-unwind.s b/lld/test/MachO/compact-unwind.s --- a/lld/test/MachO/compact-unwind.s +++ b/lld/test/MachO/compact-unwind.s @@ -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 @@ .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