Skip to content

Commit 7b45dfc

Browse files
committed
[lld-macho] Canonicalize personality pointers in EH frames
We already do this for personality pointers referenced from compact unwind entries; this patch extends that behavior to personalities referenced via EH frames as well. This reduces the number of distinct personalities we need in the final binary, and helps us avoid hitting the "too many personalities" error. I renamed `UnwindInfoSection::prepareRelocations()` to simply `prepare` since we now do some non-reloc-specific stuff within. Fixes #58277. Reviewed By: #lld-macho, oontvoo Differential Revision: https://reviews.llvm.org/D135728
1 parent 41f5bbe commit 7b45dfc

File tree

4 files changed

+75
-7
lines changed

4 files changed

+75
-7
lines changed

lld/MachO/UnwindInfoSection.cpp

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,14 +150,15 @@ class UnwindInfoSectionImpl final : public UnwindInfoSection {
150150
public:
151151
UnwindInfoSectionImpl() : cuOffsets(target->wordSize) {}
152152
uint64_t getSize() const override { return unwindInfoSize; }
153-
void prepareRelocations() override;
153+
void prepare() override;
154154
void finalize() override;
155155
void writeTo(uint8_t *buf) const override;
156156

157157
private:
158158
void prepareRelocations(ConcatInputSection *);
159159
void relocateCompactUnwind(std::vector<CompactUnwindEntry> &);
160160
void encodePersonalities();
161+
Symbol *canonicalizePersonality(Symbol *);
161162

162163
uint64_t unwindInfoSize = 0;
163164
std::vector<decltype(symbols)::value_type> symbolsVec;
@@ -210,14 +211,24 @@ void UnwindInfoSection::addSymbol(const Defined *d) {
210211
}
211212
}
212213

213-
void UnwindInfoSectionImpl::prepareRelocations() {
214+
void UnwindInfoSectionImpl::prepare() {
214215
// This iteration needs to be deterministic, since prepareRelocations may add
215216
// entries to the GOT. Hence the use of a MapVector for
216217
// UnwindInfoSection::symbols.
217218
for (const Defined *d : make_second_range(symbols))
218-
if (d->unwindEntry &&
219-
d->unwindEntry->getName() == section_names::compactUnwind)
220-
prepareRelocations(d->unwindEntry);
219+
if (d->unwindEntry) {
220+
if (d->unwindEntry->getName() == section_names::compactUnwind) {
221+
prepareRelocations(d->unwindEntry);
222+
} else {
223+
// We don't have to add entries to the GOT here because FDEs have
224+
// explicit GOT relocations, so Writer::scanRelocations() will add those
225+
// GOT entries. However, we still need to canonicalize the personality
226+
// pointers (like prepareRelocations() does for CU entries) in order
227+
// to avoid overflowing the 3-personality limit.
228+
FDE &fde = cast<ObjFile>(d->getFile())->fdes[d->unwindEntry];
229+
fde.personality = canonicalizePersonality(fde.personality);
230+
}
231+
}
221232
}
222233

223234
// Compact unwind relocations have different semantics, so we handle them in a
@@ -271,6 +282,7 @@ void UnwindInfoSectionImpl::prepareRelocations(ConcatInputSection *isec) {
271282
continue;
272283
}
273284

285+
// Similar to canonicalizePersonality(), but we also register a GOT entry.
274286
if (auto *defined = dyn_cast<Defined>(s)) {
275287
// Check if we have created a synthetic symbol at the same address.
276288
Symbol *&personality =
@@ -283,6 +295,7 @@ void UnwindInfoSectionImpl::prepareRelocations(ConcatInputSection *isec) {
283295
}
284296
continue;
285297
}
298+
286299
assert(isa<DylibSymbol>(s));
287300
in.got->addEntry(s);
288301
continue;
@@ -312,6 +325,18 @@ void UnwindInfoSectionImpl::prepareRelocations(ConcatInputSection *isec) {
312325
}
313326
}
314327

328+
Symbol *UnwindInfoSectionImpl::canonicalizePersonality(Symbol *personality) {
329+
if (auto *defined = dyn_cast_or_null<Defined>(personality)) {
330+
// Check if we have created a synthetic symbol at the same address.
331+
Symbol *&synth = personalityTable[{defined->isec, defined->value}];
332+
if (synth == nullptr)
333+
synth = defined;
334+
else if (synth != defined)
335+
return synth;
336+
}
337+
return personality;
338+
}
339+
315340
// We need to apply the relocations to the pre-link compact unwind section
316341
// before converting it to post-link form. There should only be absolute
317342
// relocations here: since we are not emitting the pre-link CU section, there

lld/MachO/UnwindInfoSection.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class UnwindInfoSection : public SyntheticSection {
2323
// section entirely.
2424
bool isNeeded() const override { return !allEntriesAreOmitted; }
2525
void addSymbol(const Defined *);
26-
virtual void prepareRelocations() = 0;
26+
virtual void prepare() = 0;
2727

2828
protected:
2929
UnwindInfoSection();

lld/MachO/Writer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -702,7 +702,7 @@ void Writer::scanRelocations() {
702702
}
703703
}
704704

705-
in.unwindInfo->prepareRelocations();
705+
in.unwindInfo->prepare();
706706
}
707707

708708
static void addNonWeakDefinition(const Defined *defined) {
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# REQUIRES: x86
2+
# RUN: rm -rf %t; split-file %s %t
3+
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin19.0.0 %t/eh-frame.s -o %t/eh-frame.o
4+
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin19.0.0 %t/cu.s -o %t/cu.o
5+
# RUN: %lld -dylib %t/cu.o %t/eh-frame.o -o %t/out
6+
7+
## Sanity check: we want our input to contain a section (and not symbol)
8+
## relocation for the personality reference.
9+
# RUN: llvm-readobj --relocations %t/cu.o | FileCheck %s --check-prefix=SECT-RELOC
10+
# SECT-RELOC: Section __compact_unwind {
11+
# SECT-RELOC-NEXT: __text
12+
# SECT-RELOC-NEXT: __text
13+
# SECT-RELOC-NEXT: }
14+
15+
## Verify that the personality referenced via a symbol reloc in eh-frame.s gets
16+
## dedup'ed with the personality referenced via a section reloc in cu.s.
17+
# RUN: llvm-objdump --macho --unwind-info %t/out | FileCheck %s
18+
# CHECK: Personality functions: (count = 1)
19+
20+
#--- eh-frame.s
21+
_fun:
22+
.cfi_startproc
23+
.cfi_personality 155, _my_personality
24+
## cfi_escape cannot be encoded in compact unwind
25+
.cfi_escape 0
26+
ret
27+
.cfi_endproc
28+
29+
.subsections_via_symbols
30+
31+
#--- cu.s
32+
.globl _my_personality
33+
_fun:
34+
.cfi_startproc
35+
.cfi_personality 155, _my_personality
36+
.cfi_def_cfa_offset 16
37+
ret
38+
.cfi_endproc
39+
40+
_my_personality:
41+
nop
42+
43+
.subsections_via_symbols

0 commit comments

Comments
 (0)