[llvm] 43acef4 - [JITLink] Refactor and expand DWARF pointer encoding support.
Lang Hames via llvm-commits
llvm-commits at lists.llvm.org
Fri Apr 15 12:51:51 PDT 2022
Author: Lang Hames
Date: 2022-04-15T12:51:46-07:00
New Revision: 43acef48d38ec0dd391f212144d4a25095e4fc5f
URL: https://github.com/llvm/llvm-project/commit/43acef48d38ec0dd391f212144d4a25095e4fc5f
DIFF: https://github.com/llvm/llvm-project/commit/43acef48d38ec0dd391f212144d4a25095e4fc5f.diff
LOG: [JITLink] Refactor and expand DWARF pointer encoding support.
Adds support for pointer encodings commonly used in large/static models,
including non-pcrel, sdata/udata8, indirect, and omit.
Also refactors pointer-encoding handling to consolidate error generation inside
common functions, rather than callees of those functions.
Added:
llvm/test/ExecutionEngine/JITLink/X86/ELF_ehframe_large_static_personality_encodings.s
Modified:
llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h
llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp
llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp
llvm/test/ExecutionEngine/JITLink/AArch64/MachO_arm64_ehframe.s
Removed:
################################################################################
diff --git a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
index cdf9277e58265..9427b93acdd5e 100644
--- a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
@@ -20,10 +20,12 @@ namespace llvm {
namespace jitlink {
EHFrameEdgeFixer::EHFrameEdgeFixer(StringRef EHFrameSectionName,
- unsigned PointerSize, Edge::Kind Delta64,
- Edge::Kind Delta32, Edge::Kind NegDelta32)
+ unsigned PointerSize, Edge::Kind Pointer32,
+ Edge::Kind Pointer64, Edge::Kind Delta32,
+ Edge::Kind Delta64, Edge::Kind NegDelta32)
: EHFrameSectionName(EHFrameSectionName), PointerSize(PointerSize),
- Delta64(Delta64), Delta32(Delta32), NegDelta32(NegDelta32) {}
+ Pointer32(Pointer32), Pointer64(Pointer64), Delta32(Delta32),
+ Delta64(Delta64), NegDelta32(NegDelta32) {}
Error EHFrameEdgeFixer::operator()(LinkGraph &G) {
auto *EHFrame = G.findSectionByName(EHFrameSectionName);
@@ -84,10 +86,7 @@ Error EHFrameEdgeFixer::operator()(LinkGraph &G) {
Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
- LLVM_DEBUG({
- dbgs() << " Processing block at " << formatv("{0:x16}", B.getAddress())
- << "\n";
- });
+ LLVM_DEBUG(dbgs() << " Processing block at " << B.getAddress() << "\n");
// eh-frame should not contain zero-fill blocks.
if (B.isZeroFill())
@@ -121,7 +120,7 @@ Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
LLVM_DEBUG({
dbgs() << " Processing CFI record at "
- << formatv("{0:x16}", B.getAddress() + RecordStartOffset) << "\n";
+ << (B.getAddress() + RecordStartOffset) << "\n";
});
// Get the record length.
@@ -156,7 +155,7 @@ Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
if (CIEDelta == 0) {
if (auto Err = processCIE(PC, B, RecordStartOffset,
CIEDeltaFieldOffset + RecordRemaining,
- CIEDeltaFieldOffset))
+ CIEDeltaFieldOffset, BlockEdges))
return Err;
} else {
if (auto Err = processFDE(PC, B, RecordStartOffset,
@@ -175,7 +174,8 @@ Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B,
size_t RecordOffset, size_t RecordLength,
- size_t CIEDeltaFieldOffset) {
+ size_t CIEDeltaFieldOffset,
+ const BlockEdgeMap &BlockEdges) {
LLVM_DEBUG(dbgs() << " Record is CIE\n");
@@ -234,66 +234,59 @@ Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B,
if (auto Err = RecordReader.skip(1))
return Err;
- uint64_t AugmentationDataLength = 0;
- if (auto Err = RecordReader.readULEB128(AugmentationDataLength))
- return Err;
+ if (AugInfo->AugmentationDataPresent) {
- uint32_t AugmentationDataStartOffset = RecordReader.getOffset();
+ CIEInfo.AugmentationDataPresent = true;
- uint8_t *NextField = &AugInfo->Fields[0];
- while (uint8_t Field = *NextField++) {
- switch (Field) {
- case 'L': {
- CIEInfo.FDEsHaveLSDAField = true;
- uint8_t LSDAPointerEncoding;
- if (auto Err = RecordReader.readInteger(LSDAPointerEncoding))
- return Err;
- if (!isSupportedPointerEncoding(LSDAPointerEncoding))
- return make_error<JITLinkError>(
- "Unsupported LSDA pointer encoding " +
- formatv("{0:x2}", LSDAPointerEncoding) + " in CIE at " +
- formatv("{0:x16}", CIESymbol.getAddress()));
- CIEInfo.LSDAPointerEncoding = LSDAPointerEncoding;
- break;
- }
- case 'P': {
- uint8_t PersonalityPointerEncoding = 0;
- if (auto Err = RecordReader.readInteger(PersonalityPointerEncoding))
- return Err;
- if (PersonalityPointerEncoding !=
- (dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
- dwarf::DW_EH_PE_sdata4))
- return make_error<JITLinkError>(
- "Unspported personality pointer "
- "encoding " +
- formatv("{0:x2}", PersonalityPointerEncoding) + " in CIE at " +
- formatv("{0:x16}", CIESymbol.getAddress()));
- uint32_t PersonalityPointerAddress;
- if (auto Err = RecordReader.readInteger(PersonalityPointerAddress))
- return Err;
- break;
- }
- case 'R': {
- uint8_t FDEPointerEncoding;
- if (auto Err = RecordReader.readInteger(FDEPointerEncoding))
- return Err;
- if (!isSupportedPointerEncoding(FDEPointerEncoding))
- return make_error<JITLinkError>(
- "Unsupported FDE pointer encoding " +
- formatv("{0:x2}", FDEPointerEncoding) + " in CIE at " +
- formatv("{0:x16}", CIESymbol.getAddress()));
- CIEInfo.FDEPointerEncoding = FDEPointerEncoding;
- break;
- }
- default:
- llvm_unreachable("Invalid augmentation string field");
+ uint64_t AugmentationDataLength = 0;
+ if (auto Err = RecordReader.readULEB128(AugmentationDataLength))
+ return Err;
+
+ uint32_t AugmentationDataStartOffset = RecordReader.getOffset();
+
+ uint8_t *NextField = &AugInfo->Fields[0];
+ while (uint8_t Field = *NextField++) {
+ switch (Field) {
+ case 'L':
+ CIEInfo.LSDAPresent = true;
+ if (auto PE = readPointerEncoding(RecordReader, B, "LSDA"))
+ CIEInfo.LSDAEncoding = *PE;
+ else
+ return PE.takeError();
+ break;
+ case 'P': {
+ auto PersonalityPointerEncoding =
+ readPointerEncoding(RecordReader, B, "personality");
+ if (!PersonalityPointerEncoding)
+ return PersonalityPointerEncoding.takeError();
+ if (auto Err =
+ getOrCreateEncodedPointerEdge(
+ PC, BlockEdges, *PersonalityPointerEncoding, RecordReader,
+ B, RecordOffset + RecordReader.getOffset(), "personality")
+ .takeError())
+ return Err;
+ break;
+ }
+ case 'R':
+ if (auto PE = readPointerEncoding(RecordReader, B, "address")) {
+ CIEInfo.AddressEncoding = *PE;
+ if (CIEInfo.AddressEncoding == dwarf::DW_EH_PE_omit)
+ return make_error<JITLinkError>(
+ "Invalid address encoding DW_EH_PE_omit in CIE at " +
+ formatv("{0:x}", (B.getAddress() + RecordOffset).getValue()));
+ } else
+ return PE.takeError();
+ break;
+ default:
+ llvm_unreachable("Invalid augmentation string field");
+ }
}
- }
- if (RecordReader.getOffset() - AugmentationDataStartOffset >
- AugmentationDataLength)
- return make_error<JITLinkError>("Read past the end of the augmentation "
- "data while parsing fields");
+ if (RecordReader.getOffset() - AugmentationDataStartOffset >
+ AugmentationDataLength)
+ return make_error<JITLinkError>("Read past the end of the augmentation "
+ "data while parsing fields");
+ }
assert(!PC.CIEInfos.count(CIESymbol.getAddress()) &&
"Multiple CIEs recorded at the same address?");
@@ -306,7 +299,7 @@ Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
size_t RecordOffset, size_t RecordLength,
size_t CIEDeltaFieldOffset,
uint32_t CIEDelta,
- BlockEdgeMap &BlockEdges) {
+ const BlockEdgeMap &BlockEdges) {
LLVM_DEBUG(dbgs() << " Record is FDE\n");
orc::ExecutorAddr RecordAddress = B.getAddress() + RecordOffset;
@@ -334,8 +327,8 @@ Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
LLVM_DEBUG({
dbgs() << " Adding edge at "
- << formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset)
- << " to CIE at: " << formatv("{0:x16}", CIEAddress) << "\n";
+ << (RecordAddress + CIEDeltaFieldOffset)
+ << " to CIE at: " << CIEAddress << "\n";
});
if (auto CIEInfoOrErr = PC.findCIEInfo(CIEAddress))
CIEInfo = *CIEInfoOrErr;
@@ -347,8 +340,8 @@ Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
} else {
LLVM_DEBUG({
dbgs() << " Already has edge at "
- << formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset)
- << " to CIE at " << formatv("{0:x16}", CIEAddress) << "\n";
+ << (RecordAddress + CIEDeltaFieldOffset) << " to CIE at "
+ << CIEAddress << "\n";
});
auto &EI = CIEEdgeItr->second;
if (EI.Addend)
@@ -363,107 +356,41 @@ Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
}
}
- {
- // Process the PC-Begin field.
- Block *PCBeginBlock = nullptr;
- orc::ExecutorAddrDiff PCBeginFieldOffset = RecordReader.getOffset();
- auto PCEdgeItr = BlockEdges.find(RecordOffset + PCBeginFieldOffset);
- if (PCEdgeItr == BlockEdges.end()) {
- auto PCBeginPtrInfo =
- readEncodedPointer(CIEInfo->FDEPointerEncoding,
- RecordAddress + PCBeginFieldOffset, RecordReader);
- if (!PCBeginPtrInfo)
- return PCBeginPtrInfo.takeError();
- orc::ExecutorAddr PCBegin = PCBeginPtrInfo->first;
- Edge::Kind PCBeginEdgeKind = PCBeginPtrInfo->second;
- LLVM_DEBUG({
- dbgs() << " Adding edge at "
- << (RecordAddress + PCBeginFieldOffset) << " to PC at "
- << formatv("{0:x16}", PCBegin) << "\n";
- });
- auto PCBeginSym = getOrCreateSymbol(PC, PCBegin);
- if (!PCBeginSym)
- return PCBeginSym.takeError();
- B.addEdge(PCBeginEdgeKind, RecordOffset + PCBeginFieldOffset, *PCBeginSym,
- 0);
- PCBeginBlock = &PCBeginSym->getBlock();
- } else {
- auto &EI = PCEdgeItr->second;
- LLVM_DEBUG({
- dbgs() << " Already has edge at "
- << formatv("{0:x16}", RecordAddress + PCBeginFieldOffset)
- << " to PC at " << formatv("{0:x16}", EI.Target->getAddress());
- if (EI.Addend)
- dbgs() << " + " << formatv("{0:x16}", EI.Addend);
- dbgs() << "\n";
- });
-
- // Make sure the existing edge points at a defined block.
- if (!EI.Target->isDefined()) {
- auto EdgeAddr = RecordAddress + PCBeginFieldOffset;
- return make_error<JITLinkError>("FDE edge at " +
- formatv("{0:x16}", EdgeAddr) +
- " points at external block");
- }
- PCBeginBlock = &EI.Target->getBlock();
- if (auto Err = RecordReader.skip(
- getPointerEncodingDataSize(CIEInfo->FDEPointerEncoding)))
- return Err;
- }
-
+ // Process the PC-Begin field.
+ LLVM_DEBUG({
+ dbgs() << " Processing PC-begin at "
+ << (RecordAddress + RecordReader.getOffset()) << "\n";
+ });
+ if (auto PCBegin = getOrCreateEncodedPointerEdge(
+ PC, BlockEdges, CIEInfo->AddressEncoding, RecordReader, B,
+ RecordReader.getOffset(), "PC begin")) {
+ assert(*PCBegin && "PC-begin symbol not set");
// Add a keep-alive edge from the FDE target to the FDE to ensure that the
// FDE is kept alive if its target is.
- assert(PCBeginBlock && "PC-begin block not recorded");
LLVM_DEBUG({
dbgs() << " Adding keep-alive edge from target at "
- << formatv("{0:x16}", PCBeginBlock->getAddress()) << " to FDE at "
- << formatv("{0:x16}", RecordAddress) << "\n";
+ << (*PCBegin)->getBlock().getAddress() << " to FDE at "
+ << RecordAddress << "\n";
});
- PCBeginBlock->addEdge(Edge::KeepAlive, 0, FDESymbol, 0);
- }
+ (*PCBegin)->getBlock().addEdge(Edge::KeepAlive, 0, FDESymbol, 0);
+ } else
+ return PCBegin.takeError();
// Skip over the PC range size field.
- if (auto Err = RecordReader.skip(
- getPointerEncodingDataSize(CIEInfo->FDEPointerEncoding)))
+ if (auto Err = skipEncodedPointer(CIEInfo->AddressEncoding, RecordReader))
return Err;
- if (CIEInfo->FDEsHaveLSDAField) {
+ if (CIEInfo->AugmentationDataPresent) {
uint64_t AugmentationDataSize;
if (auto Err = RecordReader.readULEB128(AugmentationDataSize))
return Err;
- orc::ExecutorAddrDiff LSDAFieldOffset = RecordReader.getOffset();
- auto LSDAEdgeItr = BlockEdges.find(RecordOffset + LSDAFieldOffset);
- if (LSDAEdgeItr == BlockEdges.end()) {
- auto LSDAPointerInfo =
- readEncodedPointer(CIEInfo->LSDAPointerEncoding,
- RecordAddress + LSDAFieldOffset, RecordReader);
- if (!LSDAPointerInfo)
- return LSDAPointerInfo.takeError();
- orc::ExecutorAddr LSDA = LSDAPointerInfo->first;
- Edge::Kind LSDAEdgeKind = LSDAPointerInfo->second;
- auto LSDASym = getOrCreateSymbol(PC, LSDA);
- if (!LSDASym)
- return LSDASym.takeError();
- LLVM_DEBUG({
- dbgs() << " Adding edge at "
- << formatv("{0:x16}", RecordAddress + LSDAFieldOffset)
- << " to LSDA at " << formatv("{0:x16}", LSDA) << "\n";
- });
- B.addEdge(LSDAEdgeKind, RecordOffset + LSDAFieldOffset, *LSDASym, 0);
- } else {
- LLVM_DEBUG({
- auto &EI = LSDAEdgeItr->second;
- dbgs() << " Already has edge at "
- << formatv("{0:x16}", RecordAddress + LSDAFieldOffset)
- << " to LSDA at " << formatv("{0:x16}", EI.Target->getAddress());
- if (EI.Addend)
- dbgs() << " + " << formatv("{0:x16}", EI.Addend);
- dbgs() << "\n";
- });
- if (auto Err = RecordReader.skip(AugmentationDataSize))
+ if (CIEInfo->LSDAPresent)
+ if (auto Err = getOrCreateEncodedPointerEdge(
+ PC, BlockEdges, CIEInfo->LSDAEncoding, RecordReader, B,
+ RecordReader.getOffset(), "LSDA")
+ .takeError())
return Err;
- }
} else {
LLVM_DEBUG(dbgs() << " Record does not have LSDA field.\n");
}
@@ -512,108 +439,155 @@ EHFrameEdgeFixer::parseAugmentationString(BinaryStreamReader &RecordReader) {
return std::move(AugInfo);
}
-bool EHFrameEdgeFixer::isSupportedPointerEncoding(uint8_t PointerEncoding) {
+Expected<uint8_t> EHFrameEdgeFixer::readPointerEncoding(BinaryStreamReader &R,
+ Block &InBlock,
+ const char *FieldName) {
using namespace dwarf;
- // We only support PC-rel for now.
- if ((PointerEncoding & 0x70) != DW_EH_PE_pcrel)
- return false;
-
- // readEncodedPointer does not handle indirect.
- if (PointerEncoding & DW_EH_PE_indirect)
- return false;
+ uint8_t PointerEncoding;
+ if (auto Err = R.readInteger(PointerEncoding))
+ return Err;
- // Supported datatypes.
+ bool Supported = true;
switch (PointerEncoding & 0xf) {
- case DW_EH_PE_absptr:
- case DW_EH_PE_udata4:
- case DW_EH_PE_udata8:
- case DW_EH_PE_sdata4:
- case DW_EH_PE_sdata8:
- return true;
+ case DW_EH_PE_uleb128:
+ case DW_EH_PE_udata2:
+ case DW_EH_PE_sleb128:
+ case DW_EH_PE_sdata2:
+ Supported = false;
+ break;
+ }
+ if (Supported) {
+ switch (PointerEncoding & 0x70) {
+ case DW_EH_PE_textrel:
+ case DW_EH_PE_datarel:
+ case DW_EH_PE_funcrel:
+ case DW_EH_PE_aligned:
+ Supported = false;
+ break;
+ }
}
- return false;
+ if (Supported)
+ return PointerEncoding;
+
+ return make_error<JITLinkError>("Unsupported pointer encoding " +
+ formatv("{0:x2}", PointerEncoding) + " for " +
+ FieldName + "in CFI record at " +
+ formatv("{0:x16}", InBlock.getAddress()));
}
-unsigned EHFrameEdgeFixer::getPointerEncodingDataSize(uint8_t PointerEncoding) {
+Error EHFrameEdgeFixer::skipEncodedPointer(uint8_t PointerEncoding,
+ BinaryStreamReader &RecordReader) {
using namespace dwarf;
- assert(isSupportedPointerEncoding(PointerEncoding) &&
- "Unsupported pointer encoding");
+ // Switch absptr to corresponding udata encoding.
+ if ((PointerEncoding & 0xf) == DW_EH_PE_absptr)
+ PointerEncoding |= (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4;
+
switch (PointerEncoding & 0xf) {
- case DW_EH_PE_absptr:
- return PointerSize;
case DW_EH_PE_udata4:
case DW_EH_PE_sdata4:
- return 4;
+ if (auto Err = RecordReader.skip(4))
+ return Err;
+ break;
case DW_EH_PE_udata8:
case DW_EH_PE_sdata8:
- return 8;
+ if (auto Err = RecordReader.skip(8))
+ return Err;
+ break;
default:
- llvm_unreachable("Unsupported encoding");
+ llvm_unreachable("Unrecognized encoding");
}
+ return Error::success();
}
-Expected<std::pair<orc::ExecutorAddr, Edge::Kind>>
-EHFrameEdgeFixer::readEncodedPointer(uint8_t PointerEncoding,
- orc::ExecutorAddr PointerFieldAddress,
- BinaryStreamReader &RecordReader) {
- assert(isSupportedPointerEncoding(PointerEncoding) &&
- "Unsupported pointer encoding");
-
+Expected<Symbol *> EHFrameEdgeFixer::getOrCreateEncodedPointerEdge(
+ ParseContext &PC, const BlockEdgeMap &BlockEdges, uint8_t PointerEncoding,
+ BinaryStreamReader &RecordReader, Block &BlockToFix,
+ size_t PointerFieldOffset, const char *FieldName) {
using namespace dwarf;
- // Isolate data type, remap absptr to udata4 or udata8. This relies on us
- // having verified that the graph uses 32-bit or 64-bit pointers only at the
- // start of this pass.
- uint8_t EffectiveType = PointerEncoding & 0xf;
- if (EffectiveType == DW_EH_PE_absptr)
- EffectiveType = (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4;
+ if (PointerEncoding == DW_EH_PE_omit)
+ return nullptr;
- orc::ExecutorAddr Addr;
- Edge::Kind PointerEdgeKind = Edge::Invalid;
- switch (EffectiveType) {
+ // 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()) {
+ LLVM_DEBUG({
+ dbgs() << " Existing edge at "
+ << (BlockToFix.getAddress() + PointerFieldOffset) << " to "
+ << FieldName << " at " << EdgeI->second.Target->getAddress();
+ if (EdgeI->second.Target->hasName())
+ dbgs() << " (" << EdgeI->second.Target->getName() << ")";
+ dbgs() << "\n";
+ });
+ if (auto Err = skipEncodedPointer(PointerEncoding, RecordReader))
+ return Err;
+ return EdgeI->second.Target;
+ }
+ }
+
+ // Switch absptr to corresponding udata encoding.
+ if ((PointerEncoding & 0xf) == DW_EH_PE_absptr)
+ PointerEncoding |= (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4;
+
+ // We need to create an edge. Start by reading the field value.
+ uint64_t FieldValue;
+ bool Is64Bit = false;
+ switch (PointerEncoding & 0xf) {
case DW_EH_PE_udata4: {
uint32_t Val;
if (auto Err = RecordReader.readInteger(Val))
return std::move(Err);
- Addr = PointerFieldAddress + Val;
- PointerEdgeKind = Delta32;
- break;
- }
- case DW_EH_PE_udata8: {
- uint64_t Val;
- if (auto Err = RecordReader.readInteger(Val))
- return std::move(Err);
- Addr = PointerFieldAddress + Val;
- PointerEdgeKind = Delta64;
+ FieldValue = Val;
break;
}
case DW_EH_PE_sdata4: {
- int32_t Val;
+ uint32_t Val;
if (auto Err = RecordReader.readInteger(Val))
return std::move(Err);
- Addr = PointerFieldAddress + Val;
- PointerEdgeKind = Delta32;
+ FieldValue = Val;
break;
}
- case DW_EH_PE_sdata8: {
- int64_t Val;
- if (auto Err = RecordReader.readInteger(Val))
+ case DW_EH_PE_udata8:
+ case DW_EH_PE_sdata8:
+ Is64Bit = true;
+ if (auto Err = RecordReader.readInteger(FieldValue))
return std::move(Err);
- Addr = PointerFieldAddress + Val;
- PointerEdgeKind = Delta64;
break;
- }
+ default:
+ llvm_unreachable("Unsupported encoding");
}
- if (PointerEdgeKind == Edge::Invalid)
- return make_error<JITLinkError>(
- "Unspported edge kind for encoded pointer at " +
- formatv("{0:x}", PointerFieldAddress));
+ // Find the edge target and edge kind to use.
+ orc::ExecutorAddr Target;
+ Edge::Kind PtrEdgeKind = Edge::Invalid;
+ if ((PointerEncoding & 0x70) == DW_EH_PE_pcrel) {
+ Target = BlockToFix.getAddress() + PointerFieldOffset;
+ PtrEdgeKind = Is64Bit ? Delta64 : Delta32;
+ } else
+ PtrEdgeKind = Is64Bit ? Pointer64 : Pointer32;
+ Target += FieldValue;
+
+ // Find or create a symbol to point the edge at.
+ auto TargetSym = getOrCreateSymbol(PC, Target);
+ if (!TargetSym)
+ return TargetSym.takeError();
+ BlockToFix.addEdge(PtrEdgeKind, PointerFieldOffset, *TargetSym, 0);
+
+ LLVM_DEBUG({
+ dbgs() << " Adding edge at "
+ << (BlockToFix.getAddress() + PointerFieldOffset) << " to "
+ << FieldName << " at " << TargetSym->getAddress();
+ if (TargetSym->hasName())
+ dbgs() << " (" << TargetSym->getName() << ")";
+ dbgs() << "\n";
+ });
- return std::make_pair(Addr, Delta64);
+ return &*TargetSym;
}
Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,
diff --git a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h
index 66e1e8eccf0c3..55cf7fc63ee79 100644
--- a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h
+++ b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h
@@ -25,8 +25,12 @@ namespace jitlink {
/// edges.
class EHFrameEdgeFixer {
public:
+ /// Create an eh-frame edge fixer.
+ /// If a given edge-kind is not supported on the target architecture then
+ /// Edge::Invalid should be used.
EHFrameEdgeFixer(StringRef EHFrameSectionName, unsigned PointerSize,
- Edge::Kind Delta64, Edge::Kind Delta32,
+ Edge::Kind Pointer32, Edge::Kind Pointer64,
+ Edge::Kind Delta32, Edge::Kind Delta64,
Edge::Kind NegDelta32);
Error operator()(LinkGraph &G);
@@ -42,9 +46,10 @@ class EHFrameEdgeFixer {
CIEInformation() = default;
CIEInformation(Symbol &CIESymbol) : CIESymbol(&CIESymbol) {}
Symbol *CIESymbol = nullptr;
- bool FDEsHaveLSDAField = false;
- uint8_t FDEPointerEncoding = 0;
- uint8_t LSDAPointerEncoding = 0;
+ bool AugmentationDataPresent = false;
+ bool LSDAPresent = false;
+ uint8_t LSDAEncoding = 0;
+ uint8_t AddressEncoding = 0;
};
struct EdgeTarget {
@@ -77,28 +82,33 @@ class EHFrameEdgeFixer {
Error processBlock(ParseContext &PC, Block &B);
Error processCIE(ParseContext &PC, Block &B, size_t RecordOffset,
- size_t RecordLength, size_t CIEDeltaFieldOffset);
+ size_t RecordLength, size_t CIEDeltaFieldOffset,
+ const BlockEdgeMap &BlockEdges);
Error processFDE(ParseContext &PC, Block &B, size_t RecordOffset,
size_t RecordLength, size_t CIEDeltaFieldOffset,
- uint32_t CIEDelta, BlockEdgeMap &BlockEdges);
+ uint32_t CIEDelta, const BlockEdgeMap &BlockEdges);
Expected<AugmentationInfo>
parseAugmentationString(BinaryStreamReader &RecordReader);
- static bool isSupportedPointerEncoding(uint8_t PointerEncoding);
- unsigned getPointerEncodingDataSize(uint8_t PointerEncoding);
- Expected<std::pair<orc::ExecutorAddr, Edge::Kind>>
- readEncodedPointer(uint8_t PointerEncoding,
- orc::ExecutorAddr PointerFieldAddress,
- BinaryStreamReader &RecordReader);
+ Expected<uint8_t> readPointerEncoding(BinaryStreamReader &RecordReader,
+ Block &InBlock, const char *FieldName);
+ 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);
Expected<Symbol &> getOrCreateSymbol(ParseContext &PC,
orc::ExecutorAddr Addr);
StringRef EHFrameSectionName;
unsigned PointerSize;
- Edge::Kind Delta64;
+ Edge::Kind Pointer32;
+ Edge::Kind Pointer64;
Edge::Kind Delta32;
+ Edge::Kind Delta64;
Edge::Kind NegDelta32;
};
diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
index 7648ad6e9730c..ca9a2964ff146 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
@@ -381,9 +381,9 @@ void link_ELF_x86_64(std::unique_ptr<LinkGraph> G,
if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
Config.PrePrunePasses.push_back(DWARFRecordSectionSplitter(".eh_frame"));
- Config.PrePrunePasses.push_back(
- EHFrameEdgeFixer(".eh_frame", x86_64::PointerSize, x86_64::Delta64,
- x86_64::Delta32, x86_64::NegDelta32));
+ Config.PrePrunePasses.push_back(EHFrameEdgeFixer(
+ ".eh_frame", x86_64::PointerSize, x86_64::Pointer32, x86_64::Pointer64,
+ x86_64::Delta32, x86_64::Delta64, x86_64::NegDelta32));
Config.PrePrunePasses.push_back(EHFrameNullTerminator(".eh_frame"));
// Construct a JITLinker and run the link function.
diff --git a/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp b/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp
index d3db3d1e5d151..873c820e5be49 100644
--- a/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp
@@ -716,7 +716,8 @@ void link_MachO_arm64(std::unique_ptr<LinkGraph> G,
Config.PrePrunePasses.push_back(
DWARFRecordSectionSplitter("__TEXT,__eh_frame"));
Config.PrePrunePasses.push_back(
- EHFrameEdgeFixer("__TEXT,__eh_frame", 8, Delta64, Delta32, NegDelta32));
+ EHFrameEdgeFixer("__TEXT,__eh_frame", 8, Pointer32, Pointer64, Delta32,
+ Delta64, NegDelta32));
// Add an in-place GOT/Stubs pass.
Config.PostPrunePasses.push_back(
diff --git a/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp b/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp
index 21b815856598f..2f61b31ae3832 100644
--- a/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp
@@ -510,7 +510,8 @@ LinkGraphPassFunction createEHFrameSplitterPass_MachO_x86_64() {
LinkGraphPassFunction createEHFrameEdgeFixerPass_MachO_x86_64() {
return EHFrameEdgeFixer("__TEXT,__eh_frame", x86_64::PointerSize,
- x86_64::Delta64, x86_64::Delta32, x86_64::NegDelta32);
+ x86_64::Pointer32, x86_64::Pointer64, x86_64::Delta32,
+ x86_64::Delta64, x86_64::NegDelta32);
}
} // end namespace jitlink
diff --git a/llvm/test/ExecutionEngine/JITLink/AArch64/MachO_arm64_ehframe.s b/llvm/test/ExecutionEngine/JITLink/AArch64/MachO_arm64_ehframe.s
index 425f981c48471..6ae5973fb8230 100644
--- a/llvm/test/ExecutionEngine/JITLink/AArch64/MachO_arm64_ehframe.s
+++ b/llvm/test/ExecutionEngine/JITLink/AArch64/MachO_arm64_ehframe.s
@@ -19,9 +19,9 @@
# CHECK: Processing CFI record at
# CHECK: Record is FDE
# CHECK: Adding edge at {{.*}} to CIE at: {{.*}}
-# CHECK: Already has edge at {{.*}} to PC at {{.*}}
+# CHECK: Existing edge at {{.*}} to PC begin at {{.*}}
# CHECK: Adding keep-alive edge from target at {{.*}} to FDE at {{.*}}
-# CHECK: Already has edge at {{.*}} to LSDA at {{.*}}
+# CHECK: Existing edge at {{.*}} to LSDA at {{.*}}
.section __TEXT,__text,regular,pure_instructions
.globl _main
diff --git a/llvm/test/ExecutionEngine/JITLink/X86/ELF_ehframe_large_static_personality_encodings.s b/llvm/test/ExecutionEngine/JITLink/X86/ELF_ehframe_large_static_personality_encodings.s
new file mode 100644
index 0000000000000..83e46f8a12d42
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/X86/ELF_ehframe_large_static_personality_encodings.s
@@ -0,0 +1,203 @@
+# REQUIRES: asserts
+# UNSUPPORTED: system-windows
+# RUN: llvm-mc -triple=x86_64-pc-linux-gnu -large-code-model \
+# RUN: -filetype=obj -o %t %s
+# RUN: llvm-jitlink -debug-only=jitlink -noexec %t 2>&1 | FileCheck %s
+#
+# Check handling of pointer encodings for personality functions when compiling
+# with `-mcmodel=large -static`.
+#
+
+# CHECK: Record is CIE
+# CHECK-NEXT: edge at {{.*}} to personality at {{.*}} (DW.ref.__gxx_personality_v0)
+# CHECK: Record is CIE
+# CHECK-NEXT: edge at {{.*}} to personality at {{.*}} (__gxx_personality_v0)
+
+ .text
+ .file "eh.cpp"
+
+ .globl main
+ .p2align 4, 0x90
+ .type main, at function
+main:
+ xorl %eax, %eax
+ retq
+.Lfunc_end_main:
+ .size main, .Lfunc_end_main-main
+
+# pe_absptr uses absptr encoding for __gxx_personality_v0
+ .text
+ .globl pe_absptr
+ .p2align 4, 0x90
+ .type pe_absptr, at function
+pe_absptr:
+.Lfunc_begin0:
+ .cfi_startproc
+ .cfi_personality 0, __gxx_personality_v0
+ .cfi_lsda 0, .Lexception0
+ pushq %rax
+ .cfi_def_cfa_offset 16
+ movabsq $__cxa_allocate_exception, %rax
+ movl $4, %edi
+ callq *%rax
+ movl $42, (%rax)
+.Ltmp0:
+ movabsq $_ZTIi, %rsi
+ movabsq $__cxa_throw, %rcx
+ movq %rax, %rdi
+ xorl %edx, %edx
+ callq *%rcx
+.Ltmp1:
+.LBB0_2:
+.Ltmp2:
+ movabsq $__cxa_begin_catch, %rcx
+ movq %rax, %rdi
+ callq *%rcx
+ movabsq $__cxa_end_catch, %rax
+ popq %rcx
+ .cfi_def_cfa_offset 8
+ jmpq *%rax
+.Lfunc_end0:
+ .size pe_absptr, .Lfunc_end0-pe_absptr
+ .cfi_endproc
+ .section .gcc_except_table,"a", at progbits
+ .p2align 2
+GCC_except_table0:
+.Lexception0:
+ .byte 255 # @LPStart Encoding = omit
+ .byte 0 # @TType Encoding = absptr
+ .uleb128 .Lttbase0-.Lttbaseref0
+.Lttbaseref0:
+ .byte 1 # Call site Encoding = uleb128
+ .uleb128 .Lcst_end0-.Lcst_begin0
+.Lcst_begin0:
+ .uleb128 .Lfunc_begin0-.Lfunc_begin0 # >> Call Site 1 <<
+ .uleb128 .Ltmp0-.Lfunc_begin0 # Call between .Lfunc_begin0 and .Ltmp0
+ .byte 0 # has no landing pad
+ .byte 0 # On action: cleanup
+ .uleb128 .Ltmp0-.Lfunc_begin0 # >> Call Site 2 <<
+ .uleb128 .Ltmp1-.Ltmp0 # Call between .Ltmp0 and .Ltmp1
+ .uleb128 .Ltmp2-.Lfunc_begin0 # jumps to .Ltmp2
+ .byte 1 # On action: 1
+ .uleb128 .Ltmp1-.Lfunc_begin0 # >> Call Site 3 <<
+ .uleb128 .Lfunc_end0-.Ltmp1 # Call between .Ltmp1 and .Lfunc_end0
+ .byte 0 # has no landing pad
+ .byte 0 # On action: cleanup
+.Lcst_end0:
+ .byte 1 # >> Action Record 1 <<
+ # Catch TypeInfo 1
+ .byte 0 # No further actions
+ .p2align 2
+ # >> Catch TypeInfos <<
+ .quad _ZTIi # TypeInfo 1
+.Lttbase0:
+ .p2align 2
+ # -- End function
+
+# pe_indir_pcrel_sdata8 uses 0x9C -- Indirect, pc-rel, sdata8 encoding to
+# DW.ref.__gxx_personality_v0
+ .text
+ .globl pe_indir_pcrel_sdata8
+ .p2align 4, 0x90
+ .type pe_indir_pcrel_sdata8, at function
+pe_indir_pcrel_sdata8:
+.Lfunc_begin1:
+ .cfi_startproc
+ .cfi_personality 156, DW.ref.__gxx_personality_v0
+ .cfi_lsda 28, .Lexception1
+ pushq %r14
+ .cfi_def_cfa_offset 16
+ pushq %rbx
+ .cfi_def_cfa_offset 24
+ pushq %rax
+ .cfi_def_cfa_offset 32
+ .cfi_offset %rbx, -24
+ .cfi_offset %r14, -16
+.L1$pb:
+ leaq .L1$pb(%rip), %rax
+ movabsq $_GLOBAL_OFFSET_TABLE_-.L1$pb, %rbx
+ addq %rax, %rbx
+ movabsq $__cxa_allocate_exception at GOT, %rax
+ movl $4, %edi
+ callq *(%rbx,%rax)
+ movl $42, (%rax)
+.Ltmp4:
+ movabsq $_ZTIi at GOT, %rcx
+ movq (%rbx,%rcx), %rsi
+ movabsq $__cxa_throw at GOT, %rcx
+ movq %rax, %rdi
+ xorl %edx, %edx
+ movq %rbx, %r14
+ callq *(%rbx,%rcx)
+.Ltmp5:
+.LBB1_2:
+.Ltmp6:
+ movabsq $__cxa_begin_catch at GOT, %rcx
+ movq %rax, %rdi
+ callq *(%r14,%rcx)
+ movabsq $__cxa_end_catch at GOT, %rax
+ movq %r14, %rcx
+ addq $8, %rsp
+ .cfi_def_cfa_offset 24
+ popq %rbx
+ .cfi_def_cfa_offset 16
+ popq %r14
+ .cfi_def_cfa_offset 8
+ jmpq *(%rcx,%rax)
+.Lfunc_end1:
+ .size pe_indir_pcrel_sdata8, .Lfunc_end1-pe_indir_pcrel_sdata8
+ .cfi_endproc
+ .section .gcc_except_table,"a", at progbits
+ .p2align 2
+GCC_except_table1:
+.Lexception1:
+ .byte 255 # @LPStart Encoding = omit
+ .byte 156 # @TType Encoding = indirect pcrel sdata8
+ .uleb128 .Lttbase1-.Lttbaseref1
+.Lttbaseref1:
+ .byte 1 # Call site Encoding = uleb128
+ .uleb128 .Lcst_end1-.Lcst_begin1
+.Lcst_begin1:
+ .uleb128 .Lfunc_begin1-.Lfunc_begin1 # >> Call Site 1 <<
+ .uleb128 .Ltmp4-.Lfunc_begin1 # Call between .Lfunc_begin1 and .Ltmp4
+ .byte 0 # has no landing pad
+ .byte 0 # On action: cleanup
+ .uleb128 .Ltmp4-.Lfunc_begin1 # >> Call Site 2 <<
+ .uleb128 .Ltmp5-.Ltmp4 # Call between .Ltmp4 and .Ltmp5
+ .uleb128 .Ltmp6-.Lfunc_begin1 # jumps to .Ltmp6
+ .byte 1 # On action: 1
+ .uleb128 .Ltmp5-.Lfunc_begin1 # >> Call Site 3 <<
+ .uleb128 .Lfunc_end1-.Ltmp5 # Call between .Ltmp5 and .Lfunc_end1
+ .byte 0 # has no landing pad
+ .byte 0 # On action: cleanup
+.Lcst_end1:
+ .byte 1 # >> Action Record 1 <<
+ # Catch TypeInfo 1
+ .byte 0 # No further actions
+ .p2align 2
+ # >> Catch TypeInfos <<
+.Ltmp7: # TypeInfo 1
+ .quad .L_ZTIi.DW.stub-.Ltmp7
+.Lttbase1:
+ .p2align 2
+ # -- End function
+
+ .data
+ .p2align 3
+.L_ZTIi.DW.stub:
+ .quad _ZTIi
+ .hidden DW.ref.__gxx_personality_v0
+ .weak DW.ref.__gxx_personality_v0
+
+ .section .data.DW.ref.__gxx_personality_v0,"aGw", at progbits,DW.ref.__gxx_personality_v0,comdat
+ .p2align 3
+ .type DW.ref.__gxx_personality_v0, at object
+ .size DW.ref.__gxx_personality_v0, 8
+DW.ref.__gxx_personality_v0:
+ .quad __gxx_personality_v0
+
+ .ident "clang version 13.0.1"
+ .section ".note.GNU-stack","", at progbits
+ .addrsig
+ .addrsig_sym __gxx_personality_v0
+ .addrsig_sym _ZTIi
More information about the llvm-commits
mailing list