[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.
This commit is contained in:
parent
077f90315b
commit
01bc5b7034
|
@ -50,7 +50,16 @@ Error EHFrameEdgeFixer::operator()(LinkGraph &G) {
|
||||||
// Build a map of all blocks and symbols in the text sections. We will use
|
// Build a map of all blocks and symbols in the text sections. We will use
|
||||||
// these for finding / building edge targets when processing FDEs.
|
// these for finding / building edge targets when processing FDEs.
|
||||||
for (auto &Sec : G.sections()) {
|
for (auto &Sec : G.sections()) {
|
||||||
PC.AddrToSyms.addSymbols(Sec.symbols());
|
// Just record the most-canonical symbol (for eh-frame purposes) at each
|
||||||
|
// address.
|
||||||
|
for (auto *Sym : Sec.symbols()) {
|
||||||
|
auto &CurSym = PC.AddrToSym[Sym->getAddress()];
|
||||||
|
if (!CurSym || (std::make_tuple(Sym->getLinkage(), Sym->getScope(),
|
||||||
|
!Sym->hasName(), Sym->getName()) <
|
||||||
|
std::make_tuple(CurSym->getLinkage(), CurSym->getScope(),
|
||||||
|
!CurSym->hasName(), CurSym->getName())))
|
||||||
|
CurSym = Sym;
|
||||||
|
}
|
||||||
if (auto Err = PC.AddrToBlock.addBlocks(Sec.blocks(),
|
if (auto Err = PC.AddrToBlock.addBlocks(Sec.blocks(),
|
||||||
BlockAddressMap::includeNonNull))
|
BlockAddressMap::includeNonNull))
|
||||||
return Err;
|
return Err;
|
||||||
|
@ -609,23 +618,10 @@ EHFrameEdgeFixer::readEncodedPointer(uint8_t PointerEncoding,
|
||||||
|
|
||||||
Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,
|
Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,
|
||||||
orc::ExecutorAddr Addr) {
|
orc::ExecutorAddr Addr) {
|
||||||
Symbol *CanonicalSym = nullptr;
|
// See whether we have a canonical symbol for the given address already.
|
||||||
|
auto CanonicalSymI = PC.AddrToSym.find(Addr);
|
||||||
auto UpdateCanonicalSym = [&](Symbol *Sym) {
|
if (CanonicalSymI != PC.AddrToSym.end())
|
||||||
if (!CanonicalSym || Sym->getLinkage() < CanonicalSym->getLinkage() ||
|
return *CanonicalSymI->second;
|
||||||
Sym->getScope() < CanonicalSym->getScope() ||
|
|
||||||
(Sym->hasName() && !CanonicalSym->hasName()) ||
|
|
||||||
Sym->getName() < CanonicalSym->getName())
|
|
||||||
CanonicalSym = Sym;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (auto *SymbolsAtAddr = PC.AddrToSyms.getSymbolsAt(Addr))
|
|
||||||
for (auto *Sym : *SymbolsAtAddr)
|
|
||||||
UpdateCanonicalSym(Sym);
|
|
||||||
|
|
||||||
// If we found an existing symbol at the given address then use it.
|
|
||||||
if (CanonicalSym)
|
|
||||||
return *CanonicalSym;
|
|
||||||
|
|
||||||
// Otherwise search for a block covering the address and create a new symbol.
|
// Otherwise search for a block covering the address and create a new symbol.
|
||||||
auto *B = PC.AddrToBlock.getBlockCovering(Addr);
|
auto *B = PC.AddrToBlock.getBlockCovering(Addr);
|
||||||
|
@ -633,7 +629,10 @@ Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,
|
||||||
return make_error<JITLinkError>("No symbol or block covering address " +
|
return make_error<JITLinkError>("No symbol or block covering address " +
|
||||||
formatv("{0:x16}", Addr));
|
formatv("{0:x16}", Addr));
|
||||||
|
|
||||||
return PC.G.addAnonymousSymbol(*B, Addr - B->getAddress(), 0, false, false);
|
auto &S =
|
||||||
|
PC.G.addAnonymousSymbol(*B, Addr - B->getAddress(), 0, false, false);
|
||||||
|
PC.AddrToSym[S.getAddress()] = &S;
|
||||||
|
return S;
|
||||||
}
|
}
|
||||||
|
|
||||||
char EHFrameNullTerminator::NullTerminatorBlockContent[4] = {0, 0, 0, 0};
|
char EHFrameNullTerminator::NullTerminatorBlockContent[4] = {0, 0, 0, 0};
|
||||||
|
|
|
@ -72,7 +72,7 @@ private:
|
||||||
LinkGraph &G;
|
LinkGraph &G;
|
||||||
CIEInfosMap CIEInfos;
|
CIEInfosMap CIEInfos;
|
||||||
BlockAddressMap AddrToBlock;
|
BlockAddressMap AddrToBlock;
|
||||||
SymbolAddressMap AddrToSyms;
|
DenseMap<orc::ExecutorAddr, Symbol *> AddrToSym;
|
||||||
};
|
};
|
||||||
|
|
||||||
Error processBlock(ParseContext &PC, Block &B);
|
Error processBlock(ParseContext &PC, Block &B);
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
# REQUIRES: asserts
|
||||||
|
# RUN: llvm-mc -triple=x86_64-apple-macos10.9 -filetype=obj -o %t %s
|
||||||
|
# RUN: llvm-jitlink -noexec %t
|
||||||
|
#
|
||||||
|
# Verify that PC-begin candidate symbols have been sorted correctly when adding
|
||||||
|
# PC-begin edges for FDEs. In this test both _main and _X are at address zero,
|
||||||
|
# however we expect to select _main over _X as _X is common. If the sorting
|
||||||
|
# fails we'll trigger an assert in EHFrameEdgeFixer, otherwise this test will
|
||||||
|
# succeed.
|
||||||
|
|
||||||
|
.section __TEXT,__text,regular,pure_instructions
|
||||||
|
.build_version macos, 12, 0 sdk_version 13, 0
|
||||||
|
.globl _main
|
||||||
|
.p2align 4, 0x90
|
||||||
|
_main:
|
||||||
|
.cfi_startproc
|
||||||
|
pushq %rbp
|
||||||
|
.cfi_def_cfa_offset 16
|
||||||
|
.cfi_offset %rbp, -16
|
||||||
|
movq %rsp, %rbp
|
||||||
|
.cfi_def_cfa_register %rbp
|
||||||
|
xorl %eax, %eax
|
||||||
|
popq %rbp
|
||||||
|
retq
|
||||||
|
.cfi_endproc
|
||||||
|
|
||||||
|
.comm _X,4,2
|
||||||
|
.subsections_via_symbols
|
Loading…
Reference in a new issue