Skip to content

[JITLink] Allow multiple relocations at same offset in EHFrameEdgeFixer #68252

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 31 additions & 15 deletions llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,16 +126,23 @@ Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
}

// Find the offsets of any existing edges from this block.
BlockEdgeMap BlockEdges;
BlockEdgesInfo BlockEdges;
for (auto &E : B.edges())
if (E.isRelocation()) {
if (BlockEdges.count(E.getOffset()))
return make_error<JITLinkError>(
"Multiple relocations at offset " +
formatv("{0:x16}", E.getOffset()) + " in " + EHFrameSectionName +
" block at address " + formatv("{0:x16}", B.getAddress()));

BlockEdges[E.getOffset()] = EdgeTarget(E);
// Check if we already saw more than one relocation at this offset.
if (BlockEdges.Multiple.contains(E.getOffset()))
continue;

// Otherwise check if we previously had exactly one relocation at this
// offset. If so, we now have a second one and move it from the TargetMap
// into the Multiple set.
auto It = BlockEdges.TargetMap.find(E.getOffset());
if (It != BlockEdges.TargetMap.end()) {
BlockEdges.TargetMap.erase(It);
BlockEdges.Multiple.insert(E.getOffset());
} else {
BlockEdges.TargetMap[E.getOffset()] = EdgeTarget(E);
}
}

BinaryStreamReader BlockReader(
Expand Down Expand Up @@ -172,7 +179,7 @@ Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {

Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B,
size_t CIEDeltaFieldOffset,
const BlockEdgeMap &BlockEdges) {
const BlockEdgesInfo &BlockEdges) {

LLVM_DEBUG(dbgs() << " Record is CIE\n");

Expand Down Expand Up @@ -285,7 +292,7 @@ Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B,
Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
size_t CIEDeltaFieldOffset,
uint32_t CIEDelta,
const BlockEdgeMap &BlockEdges) {
const BlockEdgesInfo &BlockEdges) {
LLVM_DEBUG(dbgs() << " Record is FDE\n");

orc::ExecutorAddr RecordAddress = B.getAddress();
Expand All @@ -303,12 +310,17 @@ Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,

{
// Process the CIE pointer field.
auto CIEEdgeItr = BlockEdges.find(CIEDeltaFieldOffset);
if (BlockEdges.Multiple.contains(CIEDeltaFieldOffset))
return make_error<JITLinkError>(
"CIE pointer field already has multiple edges at " +
formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset));

auto CIEEdgeItr = BlockEdges.TargetMap.find(CIEDeltaFieldOffset);

orc::ExecutorAddr CIEAddress =
RecordAddress + orc::ExecutorAddrDiff(CIEDeltaFieldOffset) -
orc::ExecutorAddrDiff(CIEDelta);
if (CIEEdgeItr == BlockEdges.end()) {
if (CIEEdgeItr == BlockEdges.TargetMap.end()) {
LLVM_DEBUG({
dbgs() << " Adding edge at "
<< (RecordAddress + CIEDeltaFieldOffset)
Expand Down Expand Up @@ -497,7 +509,7 @@ Error EHFrameEdgeFixer::skipEncodedPointer(uint8_t PointerEncoding,
}

Expected<Symbol *> EHFrameEdgeFixer::getOrCreateEncodedPointerEdge(
ParseContext &PC, const BlockEdgeMap &BlockEdges, uint8_t PointerEncoding,
ParseContext &PC, const BlockEdgesInfo &BlockEdges, uint8_t PointerEncoding,
BinaryStreamReader &RecordReader, Block &BlockToFix,
size_t PointerFieldOffset, const char *FieldName) {
using namespace dwarf;
Expand All @@ -508,8 +520,8 @@ Expected<Symbol *> EHFrameEdgeFixer::getOrCreateEncodedPointerEdge(
// If there's already an edge here then just skip the encoded pointer and
// return the edge's target.
{
auto EdgeI = BlockEdges.find(PointerFieldOffset);
if (EdgeI != BlockEdges.end()) {
auto EdgeI = BlockEdges.TargetMap.find(PointerFieldOffset);
if (EdgeI != BlockEdges.TargetMap.end()) {
LLVM_DEBUG({
dbgs() << " Existing edge at "
<< (BlockToFix.getAddress() + PointerFieldOffset) << " to "
Expand All @@ -522,6 +534,10 @@ Expected<Symbol *> EHFrameEdgeFixer::getOrCreateEncodedPointerEdge(
return std::move(Err);
return EdgeI->second.Target;
}

if (BlockEdges.Multiple.contains(PointerFieldOffset))
return make_error<JITLinkError>("Multiple relocations at offset " +
formatv("{0:x16}", PointerFieldOffset));
}

// Switch absptr to corresponding udata encoding.
Expand Down
16 changes: 10 additions & 6 deletions llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@ class EHFrameEdgeFixer {
Edge::AddendT Addend = 0;
};

using BlockEdgeMap = DenseMap<Edge::OffsetT, EdgeTarget>;
struct BlockEdgesInfo {
DenseMap<Edge::OffsetT, EdgeTarget> TargetMap;
DenseSet<Edge::OffsetT> Multiple;
};

using CIEInfosMap = DenseMap<orc::ExecutorAddr, CIEInformation>;

struct ParseContext {
Expand All @@ -82,9 +86,9 @@ class EHFrameEdgeFixer {

Error processBlock(ParseContext &PC, Block &B);
Error processCIE(ParseContext &PC, Block &B, size_t CIEDeltaFieldOffset,
const BlockEdgeMap &BlockEdges);
const BlockEdgesInfo &BlockEdges);
Error processFDE(ParseContext &PC, Block &B, size_t CIEDeltaFieldOffset,
uint32_t CIEDelta, const BlockEdgeMap &BlockEdges);
uint32_t CIEDelta, const BlockEdgesInfo &BlockEdges);

Expected<AugmentationInfo>
parseAugmentationString(BinaryStreamReader &RecordReader);
Expand All @@ -94,9 +98,9 @@ class EHFrameEdgeFixer {
Error skipEncodedPointer(uint8_t PointerEncoding,
BinaryStreamReader &RecordReader);
Expected<Symbol *> getOrCreateEncodedPointerEdge(
ParseContext &PC, const BlockEdgeMap &BlockEdges, uint8_t PointerEncoding,
BinaryStreamReader &RecordReader, Block &BlockToFix,
size_t PointerFieldOffset, const char *FieldName);
ParseContext &PC, const BlockEdgesInfo &BlockEdges,
uint8_t PointerEncoding, BinaryStreamReader &RecordReader,
Block &BlockToFix, size_t PointerFieldOffset, const char *FieldName);

Expected<Symbol &> getOrCreateSymbol(ParseContext &PC,
orc::ExecutorAddr Addr);
Expand Down