public:
UnwindInfoSectionImpl() : cuOffsets(target->wordSize) {}
uint64_t getSize() const override { return unwindInfoSize; }
- void prepareRelocations() override;
+ void prepare() override;
void finalize() override;
void writeTo(uint8_t *buf) const override;
void prepareRelocations(ConcatInputSection *);
void relocateCompactUnwind(std::vector<CompactUnwindEntry> &);
void encodePersonalities();
+ Symbol *canonicalizePersonality(Symbol *);
uint64_t unwindInfoSize = 0;
std::vector<decltype(symbols)::value_type> symbolsVec;
}
}
-void UnwindInfoSectionImpl::prepareRelocations() {
+void UnwindInfoSectionImpl::prepare() {
// This iteration needs to be deterministic, since prepareRelocations may add
// entries to the GOT. Hence the use of a MapVector for
// UnwindInfoSection::symbols.
for (const Defined *d : make_second_range(symbols))
- if (d->unwindEntry &&
- d->unwindEntry->getName() == section_names::compactUnwind)
- prepareRelocations(d->unwindEntry);
+ if (d->unwindEntry) {
+ if (d->unwindEntry->getName() == section_names::compactUnwind) {
+ prepareRelocations(d->unwindEntry);
+ } else {
+ // We don't have to add entries to the GOT here because FDEs have
+ // explicit GOT relocations, so Writer::scanRelocations() will add those
+ // GOT entries. However, we still need to canonicalize the personality
+ // pointers (like prepareRelocations() does for CU entries) in order
+ // to avoid overflowing the 3-personality limit.
+ FDE &fde = cast<ObjFile>(d->getFile())->fdes[d->unwindEntry];
+ fde.personality = canonicalizePersonality(fde.personality);
+ }
+ }
}
// Compact unwind relocations have different semantics, so we handle them in a
continue;
}
+ // Similar to canonicalizePersonality(), but we also register a GOT entry.
if (auto *defined = dyn_cast<Defined>(s)) {
// Check if we have created a synthetic symbol at the same address.
Symbol *&personality =
}
continue;
}
+
assert(isa<DylibSymbol>(s));
in.got->addEntry(s);
continue;
}
}
+Symbol *UnwindInfoSectionImpl::canonicalizePersonality(Symbol *personality) {
+ if (auto *defined = dyn_cast_or_null<Defined>(personality)) {
+ // Check if we have created a synthetic symbol at the same address.
+ Symbol *&synth = personalityTable[{defined->isec, defined->value}];
+ if (synth == nullptr)
+ synth = defined;
+ else if (synth != defined)
+ return synth;
+ }
+ return personality;
+}
+
// We need to apply the relocations to the pre-link compact unwind section
// before converting it to post-link form. There should only be absolute
// relocations here: since we are not emitting the pre-link CU section, there
--- /dev/null
+# REQUIRES: x86
+# RUN: rm -rf %t; split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin19.0.0 %t/eh-frame.s -o %t/eh-frame.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin19.0.0 %t/cu.s -o %t/cu.o
+# RUN: %lld -dylib %t/cu.o %t/eh-frame.o -o %t/out
+
+## Sanity check: we want our input to contain a section (and not symbol)
+## relocation for the personality reference.
+# RUN: llvm-readobj --relocations %t/cu.o | FileCheck %s --check-prefix=SECT-RELOC
+# SECT-RELOC: Section __compact_unwind {
+# SECT-RELOC-NEXT: __text
+# SECT-RELOC-NEXT: __text
+# SECT-RELOC-NEXT: }
+
+## Verify that the personality referenced via a symbol reloc in eh-frame.s gets
+## dedup'ed with the personality referenced via a section reloc in cu.s.
+# RUN: llvm-objdump --macho --unwind-info %t/out | FileCheck %s
+# CHECK: Personality functions: (count = 1)
+
+#--- eh-frame.s
+_fun:
+ .cfi_startproc
+ .cfi_personality 155, _my_personality
+ ## cfi_escape cannot be encoded in compact unwind
+ .cfi_escape 0
+ ret
+ .cfi_endproc
+
+.subsections_via_symbols
+
+#--- cu.s
+.globl _my_personality
+_fun:
+ .cfi_startproc
+ .cfi_personality 155, _my_personality
+ .cfi_def_cfa_offset 16
+ ret
+ .cfi_endproc
+
+_my_personality:
+ nop
+
+.subsections_via_symbols