Skip to content

Commit dd711a9

Browse files
int3tru
authored andcommitted
[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 (cherry picked from commit 7b45dfc)
1 parent 3010b7e commit dd711a9

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
@@ -158,14 +158,15 @@ class UnwindInfoSectionImpl final : public UnwindInfoSection {
158158
public:
159159
UnwindInfoSectionImpl() : cuOffsets(target->wordSize) {}
160160
uint64_t getSize() const override { return unwindInfoSize; }
161-
void prepareRelocations() override;
161+
void prepare() override;
162162
void finalize() override;
163163
void writeTo(uint8_t *buf) const override;
164164

165165
private:
166166
void prepareRelocations(ConcatInputSection *);
167167
void relocateCompactUnwind(std::vector<CompactUnwindEntry> &);
168168
void encodePersonalities();
169+
Symbol *canonicalizePersonality(Symbol *);
169170

170171
uint64_t unwindInfoSize = 0;
171172
std::vector<decltype(symbols)::value_type> symbolsVec;
@@ -218,14 +219,24 @@ void UnwindInfoSection::addSymbol(const Defined *d) {
218219
}
219220
}
220221

221-
void UnwindInfoSectionImpl::prepareRelocations() {
222+
void UnwindInfoSectionImpl::prepare() {
222223
// This iteration needs to be deterministic, since prepareRelocations may add
223224
// entries to the GOT. Hence the use of a MapVector for
224225
// UnwindInfoSection::symbols.
225226
for (const Defined *d : make_second_range(symbols))
226-
if (d->unwindEntry &&
227-
d->unwindEntry->getName() == section_names::compactUnwind)
228-
prepareRelocations(d->unwindEntry);
227+
if (d->unwindEntry) {
228+
if (d->unwindEntry->getName() == section_names::compactUnwind) {
229+
prepareRelocations(d->unwindEntry);
230+
} else {
231+
// We don't have to add entries to the GOT here because FDEs have
232+
// explicit GOT relocations, so Writer::scanRelocations() will add those
233+
// GOT entries. However, we still need to canonicalize the personality
234+
// pointers (like prepareRelocations() does for CU entries) in order
235+
// to avoid overflowing the 3-personality limit.
236+
FDE &fde = cast<ObjFile>(d->getFile())->fdes[d->unwindEntry];
237+
fde.personality = canonicalizePersonality(fde.personality);
238+
}
239+
}
229240
}
230241

231242
// Compact unwind relocations have different semantics, so we handle them in a
@@ -279,6 +290,7 @@ void UnwindInfoSectionImpl::prepareRelocations(ConcatInputSection *isec) {
279290
continue;
280291
}
281292

293+
// Similar to canonicalizePersonality(), but we also register a GOT entry.
282294
if (auto *defined = dyn_cast<Defined>(s)) {
283295
// Check if we have created a synthetic symbol at the same address.
284296
Symbol *&personality =
@@ -291,6 +303,7 @@ void UnwindInfoSectionImpl::prepareRelocations(ConcatInputSection *isec) {
291303
}
292304
continue;
293305
}
306+
294307
assert(isa<DylibSymbol>(s));
295308
in.got->addEntry(s);
296309
continue;
@@ -320,6 +333,18 @@ void UnwindInfoSectionImpl::prepareRelocations(ConcatInputSection *isec) {
320333
}
321334
}
322335

336+
Symbol *UnwindInfoSectionImpl::canonicalizePersonality(Symbol *personality) {
337+
if (auto *defined = dyn_cast_or_null<Defined>(personality)) {
338+
// Check if we have created a synthetic symbol at the same address.
339+
Symbol *&synth = personalityTable[{defined->isec, defined->value}];
340+
if (synth == nullptr)
341+
synth = defined;
342+
else if (synth != defined)
343+
return synth;
344+
}
345+
return personality;
346+
}
347+
323348
// We need to apply the relocations to the pre-link compact unwind section
324349
// before converting it to post-link form. There should only be absolute
325350
// 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
@@ -24,7 +24,7 @@ class UnwindInfoSection : public SyntheticSection {
2424
// section entirely.
2525
bool isNeeded() const override { return !allEntriesAreOmitted; }
2626
void addSymbol(const Defined *);
27-
virtual void prepareRelocations() = 0;
27+
virtual void prepare() = 0;
2828

2929
protected:
3030
UnwindInfoSection();

lld/MachO/Writer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -675,7 +675,7 @@ void Writer::scanRelocations() {
675675
}
676676
}
677677

678-
in.unwindInfo->prepareRelocations();
678+
in.unwindInfo->prepare();
679679
}
680680

681681
void Writer::scanSymbols() {
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)