[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.
This commit is contained in:
Lang Hames
2022-04-15 11:22:26 -07:00
parent 4d85859ff4
commit 43acef48d3
7 changed files with 431 additions and 242 deletions

View File

@@ -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,67 +234,60 @@ 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?");
PC.CIEInfos[CIESymbol.getAddress()] = std::move(CIEInfo);
@@ -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;
uint8_t PointerEncoding;
if (auto Err = R.readInteger(PointerEncoding))
return Err;
// readEncodedPointer does not handle indirect.
if (PointerEncoding & DW_EH_PE_indirect)
return false;
// 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;
return std::make_pair(Addr, Delta64);
// 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 &*TargetSym;
}
Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,

View File

@@ -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 @@ private:
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 @@ private:
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;
};

View File

@@ -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.

View File

@@ -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(

View File

@@ -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

View File

@@ -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

View File

@@ -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,@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,@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",@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,@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@GOT, %rax
movl $4, %edi
callq *(%rbx,%rax)
movl $42, (%rax)
.Ltmp4:
movabsq $_ZTIi@GOT, %rcx
movq (%rbx,%rcx), %rsi
movabsq $__cxa_throw@GOT, %rcx
movq %rax, %rdi
xorl %edx, %edx
movq %rbx, %r14
callq *(%rbx,%rcx)
.Ltmp5:
.LBB1_2:
.Ltmp6:
movabsq $__cxa_begin_catch@GOT, %rcx
movq %rax, %rdi
callq *(%r14,%rcx)
movabsq $__cxa_end_catch@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",@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",@progbits,DW.ref.__gxx_personality_v0,comdat
.p2align 3
.type DW.ref.__gxx_personality_v0,@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","",@progbits
.addrsig
.addrsig_sym __gxx_personality_v0
.addrsig_sym _ZTIi