Skip to content

Commit 6afbda7

Browse files
authored
[lld-macho] Fix duplicate GOT entries for personality functions (#95054)
As stated in `UnwindInfoSectionImpl::prepareRelocations`'s comments, the unwind info uses section+addend relocations for personality functions defined in the same file as the function itself. As personality functions are always accessed via the GOT, we need to resolve those to a symbol. Previously, we did this by keeping a map which resolves these to symbols, creating a synthetic symbol if we didn't find it in the map. This approach has an issue: if we process the object file containing the personality function before any external uses, the entry in the map remains unpopulated, so we create a synthetic symbol and a corresponding GOT entry. If we encounter a relocation to it in a later file which requires GOT (such as in `__eh_frame`), we add that symbol to the GOT, too, effectively creating two entries which point to the same piece of code. This commit fixes that by searching the personality function's section for a symbol at that offset which already has a GOT entry, and only creating a synthetic symbol if there is none. As all non-unwind sections are already processed by this point, it ensures no duplication. This should only really affect our tests (and make them clearer), as personality functions are usually defined in platform runtime libraries. Or even if they are local, they are likely not in the first object file to be linked.
1 parent 5752098 commit 6afbda7

File tree

3 files changed

+32
-19
lines changed

3 files changed

+32
-19
lines changed

lld/MachO/UnwindInfoSection.cpp

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -298,19 +298,31 @@ void UnwindInfoSectionImpl::prepareRelocations(ConcatInputSection *isec) {
298298
assert(!isCoalescedWeak(referentIsec));
299299
// Personality functions can be referenced via section relocations
300300
// if they live in the same object file. Create placeholder synthetic
301-
// symbols for them in the GOT.
301+
// symbols for them in the GOT. If the corresponding symbol is already
302+
// in the GOT, use that to avoid creating a duplicate entry. All GOT
303+
// entries needed by non-unwind sections will have already been added
304+
// by this point.
302305
Symbol *&s = personalityTable[{referentIsec, r.addend}];
303306
if (s == nullptr) {
304-
// This runs after dead stripping, so the noDeadStrip argument does not
305-
// matter.
306-
s = make<Defined>("<internal>", /*file=*/nullptr, referentIsec,
307-
r.addend, /*size=*/0, /*isWeakDef=*/false,
308-
/*isExternal=*/false, /*isPrivateExtern=*/false,
309-
/*includeInSymtab=*/true,
310-
/*isReferencedDynamically=*/false,
311-
/*noDeadStrip=*/false);
312-
s->used = true;
313-
in.got->addEntry(s);
307+
Defined *const *gotEntry =
308+
llvm::find_if(referentIsec->symbols, [&](Defined const *d) {
309+
return d->value == static_cast<uint64_t>(r.addend) &&
310+
d->isInGot();
311+
});
312+
if (gotEntry != referentIsec->symbols.end()) {
313+
s = *gotEntry;
314+
} else {
315+
// This runs after dead stripping, so the noDeadStrip argument does
316+
// not matter.
317+
s = make<Defined>("<internal>", /*file=*/nullptr, referentIsec,
318+
r.addend, /*size=*/0, /*isWeakDef=*/false,
319+
/*isExternal=*/false, /*isPrivateExtern=*/false,
320+
/*includeInSymtab=*/true,
321+
/*isReferencedDynamically=*/false,
322+
/*noDeadStrip=*/false);
323+
s->used = true;
324+
in.got->addEntry(s);
325+
}
314326
}
315327
r.referent = s;
316328
r.addend = 0;

lld/test/MachO/compact-unwind-both-local-and-dylib-personality.s

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,19 +42,20 @@
4242

4343
# RUN: llvm-objdump --macho --indirect-symbols --unwind-info --bind %t/d.out | FileCheck %s --check-prefixes=D -D#%x,OFF=0x100000000
4444

45-
# A: Indirect symbols for (__DATA_CONST,__got)
45+
# A: Indirect symbols for (__DATA_CONST,__got) 4 entries
4646
# A-NEXT: address index name
4747
# A: 0x[[#%x,GXX_PERSONALITY_LO:]] [[#]] ___gxx_personality_v0
48+
# A: 0x[[#%x,PERSONALITY_1:]] [[#]] _personality_1
49+
# A: 0x[[#%x,PERSONALITY_2:]] [[#]] _personality_2
4850
# A: 0x[[#%x,GXX_PERSONALITY_HI:]] [[#]] ___gxx_personality_v0
49-
# A: 0x[[#%x,PERSONALITY_1:]] LOCAL
50-
# A: 0x[[#%x,PERSONALITY_2:]] LOCAL
5151

5252
# BC: Indirect symbols for (__DATA_CONST,__got)
5353
# BC-NEXT: address index name
54-
# C: 0x[[#%x,GXX_PERSONALITY_HI:]] LOCAL
5554
# BC: 0x[[#%x,GXX_PERSONALITY_LO:]] LOCAL
56-
# BC: 0x[[#%x,PERSONALITY_1:]] LOCAL
57-
# BC: 0x[[#%x,PERSONALITY_2:]] LOCAL
55+
# C: 0x[[#%x,GXX_PERSONALITY_HI:]] [[#]] ___gxx_personality_v0
56+
# BC: 0x[[#%x,PERSONALITY_1:]] [[#]] _personality_1
57+
# BC: 0x[[#%x,PERSONALITY_2:]] [[#]] _personality_2
58+
# BC-EMPTY:
5859

5960
# CHECK: Personality functions: (count = 3)
6061
# CHECK-DAG: personality[{{[0-9]+}}]: 0x{{0*}}[[#GXX_PERSONALITY_LO-OFF]]
@@ -66,7 +67,7 @@
6667
# A-NEXT: __DATA_CONST __got 0x[[#GXX_PERSONALITY_LO-0]] pointer 0 libc++abi ___gxx_personality_v0
6768

6869

69-
# D: Indirect symbols for (__DATA_CONST,__got)
70+
# D: Indirect symbols for (__DATA_CONST,__got) 6 entries
7071
# D-NEXT: address index name
7172
# D: 0x[[#%x,GXX_PERSONALITY_HI:]] [[#]] ___gxx_personality_v0
7273
# D: 0x[[#%x,PERSONALITY_1:]] [[#]] _personality_1

lld/test/MachO/compact-unwind.s

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
# FIRST: Indirect symbols for (__DATA_CONST,__got)
3030
# FIRST-NEXT: address index name
3131
# FIRST-DAG: 0x[[#%x,GXX_PERSONALITY:]] [[#]] ___gxx_personality_v0
32-
# FIRST-DAG: 0x[[#%x,MY_PERSONALITY:]] LOCAL
32+
# FIRST-DAG: 0x[[#%x,MY_PERSONALITY:]]
3333

3434
# SECOND: Indirect symbols for (__DATA_CONST,__got)
3535
# SECOND-NEXT: address index name

0 commit comments

Comments
 (0)