Skip to content

Commit 01bc5b7

Browse files
committed
[JITLink] Fix sorting bug for PC-begin candidate symbols during EH-frame fixup.
The sort should have been lexicographic, but wasn't. This resulted in us choosing a common symbol at address zero over the intended target function, leading to a crash. This patch also moves sorting up to the start of the pass, which means that we only need to hold on to the canonical symbol at each address rather than a list of candidates.
1 parent 077f903 commit 01bc5b7

File tree

3 files changed

+47
-20
lines changed

3 files changed

+47
-20
lines changed

llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,16 @@ Error EHFrameEdgeFixer::operator()(LinkGraph &G) {
5050
// Build a map of all blocks and symbols in the text sections. We will use
5151
// these for finding / building edge targets when processing FDEs.
5252
for (auto &Sec : G.sections()) {
53-
PC.AddrToSyms.addSymbols(Sec.symbols());
53+
// Just record the most-canonical symbol (for eh-frame purposes) at each
54+
// address.
55+
for (auto *Sym : Sec.symbols()) {
56+
auto &CurSym = PC.AddrToSym[Sym->getAddress()];
57+
if (!CurSym || (std::make_tuple(Sym->getLinkage(), Sym->getScope(),
58+
!Sym->hasName(), Sym->getName()) <
59+
std::make_tuple(CurSym->getLinkage(), CurSym->getScope(),
60+
!CurSym->hasName(), CurSym->getName())))
61+
CurSym = Sym;
62+
}
5463
if (auto Err = PC.AddrToBlock.addBlocks(Sec.blocks(),
5564
BlockAddressMap::includeNonNull))
5665
return Err;
@@ -609,31 +618,21 @@ EHFrameEdgeFixer::readEncodedPointer(uint8_t PointerEncoding,
609618

610619
Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,
611620
orc::ExecutorAddr Addr) {
612-
Symbol *CanonicalSym = nullptr;
613-
614-
auto UpdateCanonicalSym = [&](Symbol *Sym) {
615-
if (!CanonicalSym || Sym->getLinkage() < CanonicalSym->getLinkage() ||
616-
Sym->getScope() < CanonicalSym->getScope() ||
617-
(Sym->hasName() && !CanonicalSym->hasName()) ||
618-
Sym->getName() < CanonicalSym->getName())
619-
CanonicalSym = Sym;
620-
};
621-
622-
if (auto *SymbolsAtAddr = PC.AddrToSyms.getSymbolsAt(Addr))
623-
for (auto *Sym : *SymbolsAtAddr)
624-
UpdateCanonicalSym(Sym);
625-
626-
// If we found an existing symbol at the given address then use it.
627-
if (CanonicalSym)
628-
return *CanonicalSym;
621+
// See whether we have a canonical symbol for the given address already.
622+
auto CanonicalSymI = PC.AddrToSym.find(Addr);
623+
if (CanonicalSymI != PC.AddrToSym.end())
624+
return *CanonicalSymI->second;
629625

630626
// Otherwise search for a block covering the address and create a new symbol.
631627
auto *B = PC.AddrToBlock.getBlockCovering(Addr);
632628
if (!B)
633629
return make_error<JITLinkError>("No symbol or block covering address " +
634630
formatv("{0:x16}", Addr));
635631

636-
return PC.G.addAnonymousSymbol(*B, Addr - B->getAddress(), 0, false, false);
632+
auto &S =
633+
PC.G.addAnonymousSymbol(*B, Addr - B->getAddress(), 0, false, false);
634+
PC.AddrToSym[S.getAddress()] = &S;
635+
return S;
637636
}
638637

639638
char EHFrameNullTerminator::NullTerminatorBlockContent[4] = {0, 0, 0, 0};

llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ class EHFrameEdgeFixer {
7272
LinkGraph &G;
7373
CIEInfosMap CIEInfos;
7474
BlockAddressMap AddrToBlock;
75-
SymbolAddressMap AddrToSyms;
75+
DenseMap<orc::ExecutorAddr, Symbol *> AddrToSym;
7676
};
7777

7878
Error processBlock(ParseContext &PC, Block &B);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# REQUIRES: asserts
2+
# RUN: llvm-mc -triple=x86_64-apple-macos10.9 -filetype=obj -o %t %s
3+
# RUN: llvm-jitlink -noexec %t
4+
#
5+
# Verify that PC-begin candidate symbols have been sorted correctly when adding
6+
# PC-begin edges for FDEs. In this test both _main and _X are at address zero,
7+
# however we expect to select _main over _X as _X is common. If the sorting
8+
# fails we'll trigger an assert in EHFrameEdgeFixer, otherwise this test will
9+
# succeed.
10+
11+
.section __TEXT,__text,regular,pure_instructions
12+
.build_version macos, 12, 0 sdk_version 13, 0
13+
.globl _main
14+
.p2align 4, 0x90
15+
_main:
16+
.cfi_startproc
17+
pushq %rbp
18+
.cfi_def_cfa_offset 16
19+
.cfi_offset %rbp, -16
20+
movq %rsp, %rbp
21+
.cfi_def_cfa_register %rbp
22+
xorl %eax, %eax
23+
popq %rbp
24+
retq
25+
.cfi_endproc
26+
27+
.comm _X,4,2
28+
.subsections_via_symbols

0 commit comments

Comments
 (0)